fullcourtdefense-cli 1.36.4 → 1.37.0
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/dist/askDialog.d.ts +1 -0
- package/dist/askDialog.js +20 -3
- package/dist/callerEnv.d.ts +29 -2
- package/dist/callerEnv.js +48 -2
- package/dist/commands/daemon.d.ts +10 -0
- package/dist/commands/daemon.js +348 -170
- package/dist/commands/desktopChatGuard.js +2 -0
- package/dist/commands/discoverPaths.d.ts +12 -9
- package/dist/commands/discoverPaths.js +30 -0
- package/dist/commands/ephemeralStack.js +7 -0
- package/dist/commands/flushSpool.d.ts +2 -0
- package/dist/commands/flushSpool.js +9 -2
- package/dist/commands/hook.d.ts +14 -0
- package/dist/commands/hook.js +302 -101
- package/dist/commands/httpGatewayCommand.d.ts +1 -0
- package/dist/commands/httpGatewayCommand.js +7 -1
- package/dist/commands/installClaudeHook.js +32 -10
- package/dist/commands/installCursorHook.js +20 -9
- package/dist/commands/login.js +8 -1
- package/dist/commands/mcpGateway.d.ts +21 -0
- package/dist/commands/mcpGateway.js +90 -32
- package/dist/commands/refreshPolicyCache.d.ts +28 -0
- package/dist/commands/refreshPolicyCache.js +59 -0
- package/dist/commands/watchdog.d.ts +2 -0
- package/dist/commands/watchdog.js +30 -5
- package/dist/config.d.ts +36 -0
- package/dist/config.js +78 -12
- package/dist/daemonDetectorBoot.d.ts +1 -0
- package/dist/daemonDetectorBoot.js +12 -0
- package/dist/daemonForensics.d.ts +14 -1
- package/dist/daemonForensics.js +32 -0
- package/dist/detectorInProcess.d.ts +18 -0
- package/dist/detectorInProcess.js +234 -0
- package/dist/detectorInThread.d.ts +15 -0
- package/dist/detectorInThread.js +129 -0
- package/dist/distress.d.ts +2 -0
- package/dist/distress.js +2 -0
- package/dist/fileWriteCanon.d.ts +17 -0
- package/dist/fileWriteCanon.js +141 -0
- package/dist/gateReports.d.ts +144 -0
- package/dist/gateReports.js +488 -0
- package/dist/hookIo.d.ts +59 -0
- package/dist/hookIo.js +319 -9
- package/dist/hookSlim.d.ts +15 -8
- package/dist/hookSlim.js +187 -25
- package/dist/housekeeping.d.ts +64 -0
- package/dist/housekeeping.js +384 -0
- package/dist/housekeepingOps.d.ts +150 -0
- package/dist/housekeepingOps.js +218 -0
- package/dist/housekeepingWorker.d.ts +1 -0
- package/dist/housekeepingWorker.js +113 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +19 -0
- package/dist/localDetectionData.d.ts +10 -0
- package/dist/localDetectionData.js +48 -0
- package/dist/localDetectionUpdates.d.ts +2 -2
- package/dist/localDetectionUpdates.js +4 -4
- package/dist/localSafetySnapshot.d.ts +48 -2
- package/dist/localSafetySnapshot.js +241 -25
- package/dist/machineIdentity.d.ts +7 -0
- package/dist/machineIdentity.js +20 -2
- package/dist/monitorFastPath.d.ts +191 -0
- package/dist/monitorFastPath.js +1198 -0
- package/dist/nativeHook.js +9 -2
- package/dist/pendingDrain.d.ts +82 -0
- package/dist/pendingDrain.js +215 -0
- package/dist/pendingDrainer.d.ts +30 -0
- package/dist/pendingDrainer.js +217 -0
- package/dist/perfSnapshot.d.ts +1 -1
- package/dist/perfSnapshot.js +28 -4
- package/dist/policyCacheFiles.d.ts +73 -0
- package/dist/policyCacheFiles.js +320 -0
- package/dist/policyGateHealth.d.ts +8 -0
- package/dist/policyGateHealth.js +17 -0
- package/dist/policyRefresh.d.ts +28 -0
- package/dist/policyRefresh.js +69 -0
- package/dist/protectionMaintenance.d.ts +15 -0
- package/dist/protectionMaintenance.js +43 -1
- package/dist/runtimeConfig.d.ts +77 -20
- package/dist/runtimeConfig.js +278 -57
- package/dist/selfTest.d.ts +6 -1
- package/dist/selfTest.js +11 -4
- package/dist/telemetry.d.ts +136 -4
- package/dist/telemetry.js +493 -96
- package/dist/verdictIpc.d.ts +60 -0
- package/dist/verdictIpc.js +504 -19
- package/dist/verdictIpcClient.d.ts +175 -18
- package/dist/verdictIpcClient.js +277 -59
- package/dist/version.json +1 -1
- package/package.json +2 -2
|
@@ -460,6 +460,8 @@ function startDesktopChatGuard(runtime) {
|
|
|
460
460
|
shieldKey: runtime.shieldKey,
|
|
461
461
|
developerName: snapshotIdentity.developerName,
|
|
462
462
|
machineName: snapshotIdentity.machineName,
|
|
463
|
+
// Read what the daemon poll keeps current — no re-download per tick.
|
|
464
|
+
hotPath: true,
|
|
463
465
|
});
|
|
464
466
|
scanOptions = (0, localSafetySnapshot_1.snapshotToScanOptions)(snapshot);
|
|
465
467
|
}
|
|
@@ -38,6 +38,16 @@ export declare function claudeDesktopInstallTargets(configPath?: string): Claude
|
|
|
38
38
|
export declare function candidateConfigPaths(cwd: string, extra?: string): ConfigPathCandidate[];
|
|
39
39
|
/** Common places developers keep code, used by `--scan-root auto`. */
|
|
40
40
|
export declare function defaultScanRoots(): string[];
|
|
41
|
+
type ProjectConfigScan = {
|
|
42
|
+
candidates: ConfigPathCandidate[];
|
|
43
|
+
scannedDirs: number;
|
|
44
|
+
excludedDirs: number;
|
|
45
|
+
truncated: boolean;
|
|
46
|
+
truncatedReason?: ScanTruncationReason;
|
|
47
|
+
maxDepth: number;
|
|
48
|
+
maxDirs: number;
|
|
49
|
+
};
|
|
50
|
+
export declare function setProjectConfigScanPass(key: string | undefined): void;
|
|
41
51
|
/**
|
|
42
52
|
* Bounded walk of developer folders looking for project-scoped MCP configs
|
|
43
53
|
* (`--scan-root`). Depth- and volume-capped so it stays fast and predictable —
|
|
@@ -48,15 +58,7 @@ export declare function scanRootsForProjectConfigs(roots: string[], options?: {
|
|
|
48
58
|
maxDepth?: number;
|
|
49
59
|
maxDirs?: number;
|
|
50
60
|
excludedRoots?: string[];
|
|
51
|
-
}):
|
|
52
|
-
candidates: ConfigPathCandidate[];
|
|
53
|
-
scannedDirs: number;
|
|
54
|
-
excludedDirs: number;
|
|
55
|
-
truncated: boolean;
|
|
56
|
-
truncatedReason?: ScanTruncationReason;
|
|
57
|
-
maxDepth: number;
|
|
58
|
-
maxDirs: number;
|
|
59
|
-
};
|
|
61
|
+
}): ProjectConfigScan;
|
|
60
62
|
export interface FolderCatalogEntry {
|
|
61
63
|
path: string;
|
|
62
64
|
/** Depth relative to its walk root (home or a dev root) — lets the UI indent. */
|
|
@@ -85,3 +87,4 @@ export declare function discoverScanTargets(cwd: string, extra?: string): Config
|
|
|
85
87
|
* `~/.codex` / `~/.cursor` without Cursor.exe must not count as installed.
|
|
86
88
|
*/
|
|
87
89
|
export declare function detectIdeAppInstalled(clientKey: string, env?: NodeJS.ProcessEnv, home?: string, platform?: NodeJS.Platform): boolean;
|
|
90
|
+
export {};
|
|
@@ -46,6 +46,7 @@ exports.claudeDesktopLikelyInstalled = claudeDesktopLikelyInstalled;
|
|
|
46
46
|
exports.claudeDesktopInstallTargets = claudeDesktopInstallTargets;
|
|
47
47
|
exports.candidateConfigPaths = candidateConfigPaths;
|
|
48
48
|
exports.defaultScanRoots = defaultScanRoots;
|
|
49
|
+
exports.setProjectConfigScanPass = setProjectConfigScanPass;
|
|
49
50
|
exports.scanRootsForProjectConfigs = scanRootsForProjectConfigs;
|
|
50
51
|
exports.buildFolderCatalog = buildFolderCatalog;
|
|
51
52
|
exports.resolveScanRoots = resolveScanRoots;
|
|
@@ -297,6 +298,23 @@ function defaultScanRoots() {
|
|
|
297
298
|
}
|
|
298
299
|
});
|
|
299
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* Reuse of one walk across a single daemon protection pass. A pass inspects,
|
|
303
|
+
* repairs, rescans and verifies, and each step walked every scan root again
|
|
304
|
+
* (4-7 walks of up to 25,000 folders). Only the daemon's housekeeping sets a
|
|
305
|
+
* pass key; every other caller (and work between a pass's steps) walks fresh.
|
|
306
|
+
*/
|
|
307
|
+
let scanPassKey;
|
|
308
|
+
const scanPassResults = new Map();
|
|
309
|
+
const SCAN_PASSES_KEPT = 4;
|
|
310
|
+
function setProjectConfigScanPass(key) {
|
|
311
|
+
scanPassKey = key;
|
|
312
|
+
if (key === undefined || scanPassResults.has(key))
|
|
313
|
+
return;
|
|
314
|
+
scanPassResults.set(key, new Map());
|
|
315
|
+
while (scanPassResults.size > SCAN_PASSES_KEPT)
|
|
316
|
+
scanPassResults.delete(scanPassResults.keys().next().value);
|
|
317
|
+
}
|
|
300
318
|
/**
|
|
301
319
|
* Bounded walk of developer folders looking for project-scoped MCP configs
|
|
302
320
|
* (`--scan-root`). Depth- and volume-capped so it stays fast and predictable —
|
|
@@ -304,6 +322,18 @@ function defaultScanRoots() {
|
|
|
304
322
|
* are pruned; only the known project config filenames are checked.
|
|
305
323
|
*/
|
|
306
324
|
function scanRootsForProjectConfigs(roots, options = {}) {
|
|
325
|
+
const pass = scanPassKey === undefined ? undefined : scanPassResults.get(scanPassKey);
|
|
326
|
+
if (!pass)
|
|
327
|
+
return walkProjectConfigs(roots, options);
|
|
328
|
+
const memoKey = JSON.stringify([roots, options.maxDepth, options.maxDirs, options.excludedRoots]);
|
|
329
|
+
const cached = pass.get(memoKey);
|
|
330
|
+
if (cached)
|
|
331
|
+
return { ...cached, candidates: cached.candidates.map(candidate => ({ ...candidate })) };
|
|
332
|
+
const result = walkProjectConfigs(roots, options);
|
|
333
|
+
pass.set(memoKey, result);
|
|
334
|
+
return { ...result, candidates: result.candidates.map(candidate => ({ ...candidate })) };
|
|
335
|
+
}
|
|
336
|
+
function walkProjectConfigs(roots, options) {
|
|
307
337
|
const maxDepth = options.maxDepth ?? 4;
|
|
308
338
|
const maxDirs = options.maxDirs ?? 25000;
|
|
309
339
|
const candidates = [];
|
|
@@ -51,6 +51,7 @@ const config_1 = require("../config");
|
|
|
51
51
|
const child_process_1 = require("child_process");
|
|
52
52
|
const installClaudeHook_1 = require("./installClaudeHook");
|
|
53
53
|
const mcpGateway_1 = require("./mcpGateway");
|
|
54
|
+
const refreshPolicyCache_1 = require("./refreshPolicyCache");
|
|
54
55
|
/**
|
|
55
56
|
* Written by `ci-protect` / `workload-protect` next to the credentials they
|
|
56
57
|
* save. Its presence says "the enrollment on this machine is EPHEMERAL", so a
|
|
@@ -214,6 +215,12 @@ async function startDetachedHttpGateway(input) {
|
|
|
214
215
|
*/
|
|
215
216
|
async function installEphemeralProtectionStack(options, config) {
|
|
216
217
|
const sendLog = options.sendLog || exports.silentLogSink;
|
|
218
|
+
// Seed both policy caches before the agent's first action, as login does:
|
|
219
|
+
// hooks and gateways never fetch policy while a cache exists, and a job or
|
|
220
|
+
// container has no daemon to poll. Callers export the ephemeral identity
|
|
221
|
+
// (FCD_MACHINE_ID) first, so the seed carries it. Best-effort and silent —
|
|
222
|
+
// on failure the hot path's single-flight no-cache attempt still applies.
|
|
223
|
+
await (0, refreshPolicyCache_1.refreshPolicyCachesInBackground)({ apiUrl: options.apiUrl, shieldId: options.shieldId, shieldKey: options.shieldKey });
|
|
217
224
|
// The Claude-format hook covers Claude Code, VS Code agent mode, and
|
|
218
225
|
// Copilot CLI — the common agents on runners and in containers.
|
|
219
226
|
if (options.hooks !== 'false') {
|
|
@@ -4,6 +4,8 @@ export interface FlushSpoolArgs {
|
|
|
4
4
|
shieldId?: string;
|
|
5
5
|
shieldKey?: string;
|
|
6
6
|
heartbeat?: string;
|
|
7
|
+
/** `false`: leave the terminal guard rule files alone (the daemon keeps their 30 s cadence). */
|
|
8
|
+
guardRules?: string;
|
|
7
9
|
}
|
|
8
10
|
/**
|
|
9
11
|
* `fullcourtdefense flush-spool` — drain the local telemetry spool to the backend
|
|
@@ -16,12 +16,19 @@ async function flushSpoolCommand(args, config) {
|
|
|
16
16
|
});
|
|
17
17
|
if (!creds.shieldId)
|
|
18
18
|
return; // nothing to attribute to
|
|
19
|
-
|
|
19
|
+
// Drains in batches and records completion for the hooks that coalesced
|
|
20
|
+
// onto this flusher. `--heartbeat liveness` (hook-requested flushes):
|
|
21
|
+
// liveness only, no diagnostic payload, and a short linger for the rest of
|
|
22
|
+
// the burst that requested it.
|
|
23
|
+
const hookRequested = args.heartbeat === 'liveness';
|
|
24
|
+
const result = await (0, telemetry_1.drainSpool)({
|
|
20
25
|
apiUrl: creds.apiUrl,
|
|
21
26
|
shieldId: creds.shieldId,
|
|
22
27
|
shieldKey: creds.shieldKey,
|
|
23
28
|
heartbeat: args.heartbeat !== 'false',
|
|
24
|
-
|
|
29
|
+
livenessOnly: hookRequested,
|
|
30
|
+
refreshGuardRules: args.guardRules !== 'false',
|
|
31
|
+
}, { linger: hookRequested });
|
|
25
32
|
if (result) {
|
|
26
33
|
console.log(`Flushed ${result.accepted} event(s)${result.deduped ? `, ${result.deduped} deduped` : ''}.`);
|
|
27
34
|
}
|
package/dist/commands/hook.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ export interface HookArgs {
|
|
|
34
34
|
approvalMode?: string;
|
|
35
35
|
approvalTimeoutMs?: string;
|
|
36
36
|
approvalPollMs?: string;
|
|
37
|
+
ideTimeout?: string;
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
40
|
* `post` = a post-execution hook (Cursor afterShellExecution / afterMCPExecution, Claude
|
|
@@ -209,6 +210,14 @@ export interface HookIo {
|
|
|
209
210
|
* mode, where `exit` only unwinds the evaluation and the process lives on.
|
|
210
211
|
*/
|
|
211
212
|
exitsProcess: boolean;
|
|
213
|
+
/**
|
|
214
|
+
* Native hooks (Codex, Gemini CLI, Windsurf, Kiro): a block-mode local-first
|
|
215
|
+
* allow queues its check-tool-call report (gateReports.ts) instead of
|
|
216
|
+
* spooling it. These processes used to send that report themselves and
|
|
217
|
+
* wait for it; its answer still ends a gate-failure streak and feeds the
|
|
218
|
+
* server's behavior baseline, only after the verdict and off this process.
|
|
219
|
+
*/
|
|
220
|
+
deferGateReports?: boolean;
|
|
212
221
|
/** Evaluated inside the resident daemon for a thin client (see DaemonDeclined). */
|
|
213
222
|
viaDaemon?: boolean;
|
|
214
223
|
/** Set when this evaluation's verdict is a stop still being settled (approval wait). */
|
|
@@ -245,9 +254,14 @@ export declare function crashVerdictForProcess(event: string | undefined, messag
|
|
|
245
254
|
* snapshot, policy engine) is warm here — verdicts resolve in milliseconds.
|
|
246
255
|
* Mirrors hookCommand's fail-open contract: any unexpected exception yields
|
|
247
256
|
* an allow verdict, never an error the thin client would surface.
|
|
257
|
+
* `exitsProcess`: the caller is a one-shot hook process that ends with this
|
|
258
|
+
* verdict (the slim entry's fallback, native hooks) — see HookIo.exitsProcess.
|
|
259
|
+
* `deferGateReports`: native hooks — see HookIo.deferGateReports.
|
|
248
260
|
*/
|
|
249
261
|
export declare function evaluateHookRequest(args: HookArgs, stdinRaw: string, config: BotGuardConfig, opts?: {
|
|
250
262
|
viaDaemon?: boolean;
|
|
263
|
+
exitsProcess?: boolean;
|
|
264
|
+
deferGateReports?: boolean;
|
|
251
265
|
}): Promise<{
|
|
252
266
|
stdout: string;
|
|
253
267
|
stderr: string;
|