fullcourtdefense-cli 1.6.11 → 1.6.12
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.
|
@@ -63,5 +63,5 @@ async function installAllCommand(args, config) {
|
|
|
63
63
|
await (0, discover_1.discoverCommand)(discoverArgs, config);
|
|
64
64
|
}
|
|
65
65
|
console.log('\n\x1b[32mDone.\x1b[0m Run \x1b[1mfullcourtdefense protect-all --dry-run true\x1b[0m to verify gateways.');
|
|
66
|
-
(0, restartNotice_1.
|
|
66
|
+
await (0, restartNotice_1.promptRestartNotice)();
|
|
67
67
|
}
|
|
@@ -1,9 +1,109 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.printRestartNotice = printRestartNotice;
|
|
4
|
+
exports.promptRestartNotice = promptRestartNotice;
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
4
6
|
function printRestartNotice(clients = 'Cursor, Claude, Codex, VS Code, Windsurf, Gemini') {
|
|
5
7
|
console.log('');
|
|
6
8
|
console.log('\x1b[33m\x1b[1mACTION REQUIRED: restart your AI clients\x1b[0m');
|
|
7
9
|
console.log(`\x1b[33mRestart/reload ${clients} so they load the protected MCP gateway and hooks.\x1b[0m`);
|
|
8
10
|
console.log('\x1b[2mAlready-running MCP servers may keep using old unprotected processes until the client restarts.\x1b[0m');
|
|
9
11
|
}
|
|
12
|
+
function shouldPrompt() {
|
|
13
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
14
|
+
return false;
|
|
15
|
+
if (process.env.CI === 'true' || process.env.FCD_NO_RESTART_PROMPT === 'true')
|
|
16
|
+
return false;
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
function parseJsonArray(raw) {
|
|
20
|
+
const trimmed = raw.trim();
|
|
21
|
+
if (!trimmed)
|
|
22
|
+
return [];
|
|
23
|
+
const parsed = JSON.parse(trimmed);
|
|
24
|
+
const rows = Array.isArray(parsed) ? parsed : [parsed];
|
|
25
|
+
return rows
|
|
26
|
+
.map((row) => row)
|
|
27
|
+
.map((row) => ({
|
|
28
|
+
pid: Number(row.ProcessId || row.pid),
|
|
29
|
+
name: String(row.Name || row.name || ''),
|
|
30
|
+
executablePath: typeof row.ExecutablePath === 'string' ? row.ExecutablePath : undefined,
|
|
31
|
+
}))
|
|
32
|
+
.filter((row) => Number.isFinite(row.pid) && row.pid > 0 && row.name);
|
|
33
|
+
}
|
|
34
|
+
function detectWindowsClients() {
|
|
35
|
+
const script = [
|
|
36
|
+
"$names=@('Cursor.exe','Claude.exe','Code.exe','Windsurf.exe');",
|
|
37
|
+
'Get-CimInstance Win32_Process |',
|
|
38
|
+
'Where-Object { $names -contains $_.Name } |',
|
|
39
|
+
'Select-Object ProcessId,Name,ExecutablePath |',
|
|
40
|
+
'ConvertTo-Json -Compress',
|
|
41
|
+
].join(' ');
|
|
42
|
+
try {
|
|
43
|
+
return parseJsonArray((0, child_process_1.execFileSync)('powershell.exe', ['-NoProfile', '-Command', script], { encoding: 'utf8' }));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function detectRestartableClients() {
|
|
50
|
+
if (process.platform === 'win32')
|
|
51
|
+
return detectWindowsClients();
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
async function askRestart(clients) {
|
|
55
|
+
const names = [...new Set(clients.map(client => client.name.replace(/\.exe$/i, '')))].join(', ');
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
process.stdout.write(`\n\x1b[1mRestart detected AI clients now (${names})? Press r then Enter to restart, or Enter to skip.\x1b[0m `);
|
|
58
|
+
process.stdin.resume();
|
|
59
|
+
process.stdin.once('data', (chunk) => {
|
|
60
|
+
process.stdin.pause();
|
|
61
|
+
resolve(String(chunk).trim().toLowerCase() === 'r');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async function restartWindowsClients(clients) {
|
|
66
|
+
const launchPaths = [...new Set(clients.map(client => client.executablePath).filter((value) => !!value))];
|
|
67
|
+
for (const client of clients) {
|
|
68
|
+
try {
|
|
69
|
+
(0, child_process_1.execFileSync)('taskkill.exe', ['/PID', String(client.pid), '/T', '/F'], { stdio: 'ignore' });
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// The process may already be gone.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
await new Promise(resolve => setTimeout(resolve, 1200));
|
|
76
|
+
for (const exePath of launchPaths) {
|
|
77
|
+
try {
|
|
78
|
+
const child = (0, child_process_1.spawn)(exePath, [], { detached: true, stdio: 'ignore' });
|
|
79
|
+
child.unref();
|
|
80
|
+
console.log(`Restarted ${exePath}`);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.log(`Could not restart ${exePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function restartClients(clients) {
|
|
88
|
+
if (process.platform === 'win32') {
|
|
89
|
+
await restartWindowsClients(clients);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
console.log('Automatic restart is not supported on this OS yet. Please restart your AI clients manually.');
|
|
93
|
+
}
|
|
94
|
+
async function promptRestartNotice(clients = 'Cursor, Claude, Codex, VS Code, Windsurf, Gemini') {
|
|
95
|
+
printRestartNotice(clients);
|
|
96
|
+
if (!shouldPrompt())
|
|
97
|
+
return;
|
|
98
|
+
const runningClients = detectRestartableClients();
|
|
99
|
+
if (runningClients.length === 0) {
|
|
100
|
+
console.log('\n\x1b[2mNo running GUI AI clients detected. Start them again to load protection.\x1b[0m');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (await askRestart(runningClients)) {
|
|
104
|
+
await restartClients(runningClients);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
console.log('Skipped automatic restart. Protection applies after you restart/reload the clients.');
|
|
108
|
+
}
|
|
109
|
+
}
|
package/dist/version.json
CHANGED