fullcourtdefense-cli 1.1.12 → 1.1.14

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/README.md CHANGED
@@ -167,6 +167,8 @@ Local scans run from the customer machine or VPN and only send captured text out
167
167
  | `--mcp-api-key <key>` | HTTP/SSE MCP API-key auth | API key value. | prompt |
168
168
  | `--progress <mode>` | MCP | Console progress: `verbose`, `compact`, or `silent`. | `verbose` |
169
169
  | `--server-name <name>` | MCP gateway installers | MCP server name to write into the client config. | `agentguard-gateway` |
170
+ | `--developer-name <name>` | MCP gateway installers | Runtime identity used for user-scoped Action Policies. Auto-detected from `FCD_DEVELOPER_NAME`, git email, npm username, or OS username. | auto |
171
+ | `--agent-name <name>` | MCP gateway installers | Runtime agent name shown in AI Users. Auto-generated from runtime identity plus client, e.g. `boaz.lautman-claude-desktop`. | auto |
170
172
  | `--scope <scope>` | Claude Code gateway installer | Claude Code MCP scope: `local`, `project`, or `user`. | `local` |
171
173
  | `--config-path <path>` | Claude Desktop gateway installer | Override path to `claude_desktop_config.json`. | OS default |
172
174
 
@@ -328,6 +330,8 @@ Claude Desktop install:
328
330
  fullcourtdefense install-claude-desktop-mcp-gateway --shield-id "sh_..." --shield-key "shsk_..." --mcp-command npm --mcp-args "run mcp"
329
331
  ```
330
332
 
333
+ The gateway auto-detects runtime identity when `--developer-name` is omitted. Detection order is `FCD_DEVELOPER_NAME`, `FULLCOURTDEFENSE_DEVELOPER_NAME`, `AGENTGUARD_DEVELOPER_NAME`, `USER_EMAIL`, `git config user.email`, `npm whoami`, then OS username. Use `--developer-name` only when you want to override the detected employee/runtime identity.
334
+
331
335
  Direct gateway run for debugging:
332
336
 
333
337
  ```powershell
@@ -80,19 +80,68 @@ function normalizeAgentClient(value, fallback) {
80
80
  return value;
81
81
  return fallback;
82
82
  }
83
+ /**
84
+ * Detect which agent client spawned this gateway process at runtime.
85
+ *
86
+ * Claude Code sets `CLAUDECODE=1` and `CLAUDE_CODE_SESSION_ID` in every stdio
87
+ * MCP subprocess it starts, so a gateway launched by Claude Code can self-label
88
+ * even when it was installed with no explicit `--agent-client`. Cursor and
89
+ * Claude Desktop don't expose a runtime marker, so they fall through to the
90
+ * install-time default baked into the MCP config.
91
+ */
92
+ function detectRuntimeAgentClient() {
93
+ if (process.env.CLAUDECODE === '1' || process.env.CLAUDE_CODE_SESSION_ID)
94
+ return 'claude-code';
95
+ return undefined;
96
+ }
97
+ /** Claude Code passes the session id to spawned MCP servers for correlation. */
98
+ function runtimeSessionId() {
99
+ return firstNonEmpty(process.env.CLAUDE_CODE_SESSION_ID, process.env.FCD_SESSION_ID);
100
+ }
101
+ function firstNonEmpty(...values) {
102
+ return values.map(value => value?.trim()).find(Boolean);
103
+ }
104
+ function safeIdentityPart(value) {
105
+ return value
106
+ .trim()
107
+ .replace(/@.*$/, '')
108
+ .replace(/[^a-zA-Z0-9._-]+/g, '-')
109
+ .replace(/^-+|-+$/g, '')
110
+ .toLowerCase() || 'local-user';
111
+ }
112
+ /**
113
+ * Resolve the developer identity for runtime attribution.
114
+ *
115
+ * Same behavior for Cursor, Claude Code, and Claude Desktop: prefer an explicit
116
+ * name (flag or env var IT can set per machine), otherwise fall back to
117
+ * `username@hostname` — exactly like the Cursor hook. We intentionally do NOT
118
+ * guess from git email / npm whoami: neither Cursor nor Claude exposes the
119
+ * account email, so the machine-scoped login is the one stable, predictable,
120
+ * collision-free identity.
121
+ */
122
+ function detectedDeveloperName(args) {
123
+ return firstNonEmpty(args.developerName, process.env.FCD_DEVELOPER_NAME, process.env.FULLCOURTDEFENSE_DEVELOPER_NAME, process.env.AGENTGUARD_DEVELOPER_NAME, machineScopedUser()) || 'unknown';
124
+ }
125
+ function defaultAgentName(agentClient, developerName, defaults) {
126
+ if (defaults.agentName)
127
+ return defaults.agentName;
128
+ const prefix = defaults.agentNamePrefix || agentClient;
129
+ return `${safeIdentityPart(developerName)}-${prefix}`;
130
+ }
83
131
  function resolveGatewayConfig(args, config, defaults = {}) {
84
132
  const home = loadHomeShield();
85
133
  const shieldId = args.shieldId || process.env.FCD_SHIELD_ID || process.env.FULLCOURTDEFENSE_SHIELD_ID || process.env.AGENTGUARD_SHIELD_ID || config.shieldId || home.shieldId;
86
134
  if (!shieldId)
87
135
  throw new Error('Missing Shield ID. Pass --shield-id or run fullcourtdefense configure.');
88
- const agentClient = normalizeAgentClient(args.agentClient || process.env.FCD_AGENT_CLIENT, defaults.agentClient || 'cursor');
136
+ const agentClient = normalizeAgentClient(args.agentClient || process.env.FCD_AGENT_CLIENT || detectRuntimeAgentClient(), defaults.agentClient || 'cursor');
137
+ const developerName = detectedDeveloperName(args);
89
138
  return {
90
139
  shieldId,
91
140
  shieldKey: args.shieldKey || process.env.FCD_SHIELD_KEY || process.env.FULLCOURTDEFENSE_SHIELD_KEY || process.env.AGENTGUARD_SHIELD_KEY || config.shieldKey || home.shieldKey,
92
141
  apiUrl: (args.apiUrl || process.env.FCD_API_URL || process.env.FULLCOURTDEFENSE_API_URL || config.apiUrl || home.apiUrl || DEFAULT_API_URL).replace(/\/$/, ''),
93
- agentName: args.agentName || process.env.FCD_AGENT_NAME || defaults.agentName || 'cursor-local-agent',
142
+ agentName: args.agentName || process.env.FCD_AGENT_NAME || defaultAgentName(agentClient, developerName, defaults),
94
143
  agentClient,
95
- developerName: args.developerName || process.env.FCD_DEVELOPER_NAME || process.env.USER_EMAIL || safeUserName(),
144
+ developerName,
96
145
  environment: args.environment || process.env.FCD_ENVIRONMENT || 'developer-workstation',
97
146
  userObjective: args.userObjective || process.env.FCD_USER_OBJECTIVE || defaults.userObjective || 'Developer requested this action from Cursor.',
98
147
  authority: args.authority || process.env.FCD_AUTHORITY || 'developer',
@@ -104,15 +153,17 @@ function resolveGatewayConfig(args, config, defaults = {}) {
104
153
  };
105
154
  }
106
155
  function machineMetadata(developerName, agentClient = 'cursor') {
156
+ const sessionId = runtimeSessionId();
107
157
  return {
108
- developerName: developerName || safeUserName(),
158
+ developerName: developerName || machineScopedUser(),
109
159
  machineName: os.hostname(),
110
160
  os: `${os.platform()} ${os.release()}`,
111
161
  username: safeUserName(),
112
162
  ipAddress: firstPrivateIp(),
113
163
  cwd: process.cwd(),
114
- workspacePath: process.env.WORKSPACE_PATH || process.cwd(),
164
+ workspacePath: process.env.WORKSPACE_PATH || process.env.CLAUDE_PROJECT_DIR || process.cwd(),
115
165
  agentClient,
166
+ ...(sessionId ? { sessionId } : {}),
116
167
  gateway: 'agentguard-mcp-gateway',
117
168
  };
118
169
  }
@@ -134,6 +185,25 @@ function safeUserName() {
134
185
  return 'unknown';
135
186
  }
136
187
  }
188
+ /**
189
+ * Machine-scoped identity: `username@hostname` (e.g. `boazl@BOAZ-PC`).
190
+ *
191
+ * Bare OS usernames collide across machines (every laptop has an `admin` /
192
+ * `user`), which breaks per-person attribution and fails SOC 2 CC6.1
193
+ * non-repudiation. Pairing the login with the hostname makes the identity
194
+ * unique per device with zero config, and matches the Cursor hook's format.
195
+ * For verified corporate identity, set `FCD_DEVELOPER_NAME` (e.g. via MDM/IdP).
196
+ */
197
+ function machineScopedUser() {
198
+ const user = safeUserName();
199
+ try {
200
+ const host = os.hostname();
201
+ return host ? `${user}@${host}` : user;
202
+ }
203
+ catch {
204
+ return user;
205
+ }
206
+ }
137
207
  function summarizeToolArgs(args, developerName, agentClient = 'cursor') {
138
208
  const out = { ...machineMetadata(developerName, agentClient) };
139
209
  for (const [key, value] of Object.entries(args || {})) {
@@ -613,7 +683,7 @@ function normalizeClaudeCodeScope(scope) {
613
683
  async function installCursorMcpGatewayCommand(args, config) {
614
684
  const gatewayConfig = resolveGatewayConfig(args, config, {
615
685
  agentClient: 'cursor',
616
- agentName: 'cursor-local-agent',
686
+ agentNamePrefix: 'cursor',
617
687
  userObjective: 'Developer requested this action from Cursor.',
618
688
  });
619
689
  const projectScope = args.project === 'true';
@@ -635,7 +705,7 @@ async function installCursorMcpGatewayCommand(args, config) {
635
705
  async function installClaudeCodeMcpGatewayCommand(args, config) {
636
706
  const gatewayConfig = resolveGatewayConfig(args, config, {
637
707
  agentClient: 'claude-code',
638
- agentName: 'claude-code-local-agent',
708
+ agentNamePrefix: 'claude-code',
639
709
  userObjective: 'Developer requested this action from Claude Code.',
640
710
  });
641
711
  const scope = normalizeClaudeCodeScope(args.scope);
@@ -680,7 +750,7 @@ async function installClaudeCodeMcpGatewayCommand(args, config) {
680
750
  async function installClaudeDesktopMcpGatewayCommand(args, config) {
681
751
  const gatewayConfig = resolveGatewayConfig(args, config, {
682
752
  agentClient: 'claude-desktop',
683
- agentName: 'claude-desktop-local-agent',
753
+ agentNamePrefix: 'claude-desktop',
684
754
  userObjective: 'Developer requested this action from Claude Desktop.',
685
755
  });
686
756
  const file = args.configPath ? path.resolve(args.configPath) : claudeDesktopMcpPath();
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ const discover_1 = require("./commands/discover");
11
11
  const hook_1 = require("./commands/hook");
12
12
  const installCursorHook_1 = require("./commands/installCursorHook");
13
13
  const mcpGateway_1 = require("./commands/mcpGateway");
14
- const VERSION = '1.1.12';
14
+ const VERSION = '1.1.14';
15
15
  function parseArgs(argv) {
16
16
  const flags = {};
17
17
  let command = '';
@@ -148,6 +148,8 @@ function printHelp() {
148
148
  --mcp-args <args> MCP server args/path, for example ./server.js
149
149
  --mcp-tool <tool> MCP tool to test, or all
150
150
  --server-name <name> MCP gateway server name for client installers
151
+ --developer-name <name> Runtime identity for user-scoped policies (auto-detected if omitted)
152
+ --agent-name <name> Runtime agent name (auto-generated from identity + client if omitted)
151
153
  --scope <scope> Claude Code MCP scope: local, project, or user
152
154
  --config-path <path> Claude Desktop config override path
153
155
  --mcp-auth-type <type> HTTP MCP auth: none, bearer, basic, api-key
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fullcourtdefense-cli",
3
- "version": "1.1.12",
3
+ "version": "1.1.14",
4
4
  "description": "Full Court Defense CLI — security scanning for AI agents from your terminal",
5
5
  "main": "dist/index.js",
6
6
  "bin": {