fullcourtdefense-cli 1.21.8 → 1.21.10

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.
@@ -22,18 +22,30 @@ const deterministicGuard_1 = require("./deterministicGuard");
22
22
  * token.
23
23
  */
24
24
  const LONE_TOKEN = /^[A-Za-z0-9_\-+/=]{24,256}$/;
25
+ function asClipboardFinding(finding) {
26
+ if (!finding)
27
+ return undefined;
28
+ // The underlying engine phrases reasons for tool responses ("Blocked tool
29
+ // response containing …"). Re-word for the clipboard/paste context without
30
+ // changing rule id, category, evidence, or toggles.
31
+ return {
32
+ ...finding,
33
+ ruleId: 'local-clipboard-secret',
34
+ reason: 'Secret detected on the clipboard — do not paste it into an unprotected AI chat.',
35
+ };
36
+ }
25
37
  function scanDeterministicClipboard(text, options) {
26
38
  const trimmed = (text || '').trim();
27
39
  if (!trimmed)
28
40
  return undefined;
29
41
  const direct = (0, deterministicGuard_1.scanDeterministicTextResponse)(trimmed, options);
30
42
  if (direct)
31
- return direct;
43
+ return asClipboardFinding(direct);
32
44
  if (LONE_TOKEN.test(trimmed)) {
33
45
  // Inject a canonical keyword so the contextual detector's proximity check
34
46
  // passes; its high-entropy gate still does the real work. The synthetic
35
47
  // prefix is never surfaced — the finding's evidence comes from the token.
36
- return (0, deterministicGuard_1.scanDeterministicTextResponse)(`api key ${trimmed}`, options);
48
+ return asClipboardFinding((0, deterministicGuard_1.scanDeterministicTextResponse)(`api key ${trimmed}`, options));
37
49
  }
38
50
  return undefined;
39
51
  }
@@ -1061,6 +1061,30 @@ function writeJsonMcpServer(file, serverName, nodeExe, commandArgs) {
1061
1061
  fs.mkdirSync(path.dirname(file), { recursive: true });
1062
1062
  fs.writeFileSync(file, `${JSON.stringify(json, null, 2)}\n`, 'utf8');
1063
1063
  }
1064
+ // VS Code uses a DIFFERENT MCP schema than Cursor/Claude/Windsurf:
1065
+ // - .vscode/mcp.json (and the user-profile mcp.json): top-level `servers` key.
1066
+ // - settings.json: nested under `mcp.servers`.
1067
+ // Writing `mcpServers` (the Cursor/Claude key) leaves VS Code silently ignoring
1068
+ // the config, so the gateway never actually runs. These writers target the
1069
+ // correct key for each VS Code file shape.
1070
+ function writeVscodeMcpServer(file, serverName, nodeExe, commandArgs) {
1071
+ const json = readJsonObject(file);
1072
+ const isSettings = file.endsWith('settings.json');
1073
+ if (isSettings) {
1074
+ if (!json.mcp || typeof json.mcp !== 'object')
1075
+ json.mcp = {};
1076
+ if (!json.mcp.servers || typeof json.mcp.servers !== 'object')
1077
+ json.mcp.servers = {};
1078
+ json.mcp.servers[serverName] = { type: 'stdio', command: nodeExe, args: commandArgs };
1079
+ }
1080
+ else {
1081
+ if (!json.servers || typeof json.servers !== 'object')
1082
+ json.servers = {};
1083
+ json.servers[serverName] = { type: 'stdio', command: nodeExe, args: commandArgs };
1084
+ }
1085
+ fs.mkdirSync(path.dirname(file), { recursive: true });
1086
+ fs.writeFileSync(file, `${JSON.stringify(json, null, 2)}\n`, 'utf8');
1087
+ }
1064
1088
  function removeTomlSection(content, tableName) {
1065
1089
  const lines = content.split(/\r?\n/);
1066
1090
  const out = [];
@@ -2206,10 +2230,7 @@ async function installVscodeMcpGatewayCommand(args, config) {
2206
2230
  if (targets.length === 0)
2207
2231
  targets.push(vscodeMcpPath(true));
2208
2232
  for (const file of targets) {
2209
- if (file.endsWith('settings.json'))
2210
- writeJsonMcpServer(file, serverName, nodeExe, commandArgs);
2211
- else
2212
- writeMcpServerConfig(file, serverName, nodeExe, commandArgs);
2233
+ writeVscodeMcpServer(file, serverName, nodeExe, commandArgs);
2213
2234
  }
2214
2235
  console.log('AgentGuard MCP Gateway installed for VS Code.');
2215
2236
  for (const file of targets)
package/dist/notify.js CHANGED
@@ -7,7 +7,13 @@ const child_process_1 = require("child_process");
7
7
  function spawnDetached(command, args, opts) {
8
8
  try {
9
9
  const child = (0, child_process_1.spawn)(command, args, {
10
- detached: true,
10
+ // detached:true is BROKEN for PowerShell on the bundled Node/Windows
11
+ // runtime — the child gets a PID but never executes a single line, so
12
+ // every toast/alert was silently lost. Our callers (the long-lived
13
+ // daemon guard, and hooks running in wait/fail-closed mode) outlive the
14
+ // notification anyway, so a non-detached child renders and completes.
15
+ // Keep detached on POSIX where it works and short-lived CLIs benefit.
16
+ detached: process.platform !== 'win32',
11
17
  stdio: 'ignore',
12
18
  // windowsHide sets the process show-state to SW_HIDE, which a GUI child's
13
19
  // FIRST top-level window inherits — that silently hid the alert form.
package/dist/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "1.21.8"
2
+ "version": "1.21.10"
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fullcourtdefense-cli",
3
- "version": "1.21.8",
3
+ "version": "1.21.10",
4
4
  "description": "Full Court Defense CLI — security scanning for AI agents from your terminal",
5
5
  "main": "dist/index.js",
6
6
  "bin": {