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 +4 -0
- package/dist/commands/mcpGateway.js +78 -8
- package/dist/index.js +3 -1
- package/package.json +1 -1
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 ||
|
|
142
|
+
agentName: args.agentName || process.env.FCD_AGENT_NAME || defaultAgentName(agentClient, developerName, defaults),
|
|
94
143
|
agentClient,
|
|
95
|
-
developerName
|
|
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 ||
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|