fullcourtdefense-cli 1.1.0 → 1.1.1
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/commands/hook.js +21 -32
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/commands/hook.js
CHANGED
|
@@ -206,11 +206,6 @@ function sessionId(p) {
|
|
|
206
206
|
return fromPayload;
|
|
207
207
|
return `cursor-${os.hostname()}`;
|
|
208
208
|
}
|
|
209
|
-
function emit(decision, blocked) {
|
|
210
|
-
process.stdout.write(JSON.stringify(decision));
|
|
211
|
-
// Exit 2 is the universal "block" signal across all hook events.
|
|
212
|
-
process.exit(blocked ? 2 : 0);
|
|
213
|
-
}
|
|
214
209
|
async function hookCommand(args, config) {
|
|
215
210
|
const shadow = args.shadow === 'true';
|
|
216
211
|
const failClosed = args.failClosed === 'true';
|
|
@@ -236,15 +231,26 @@ async function hookCommand(args, config) {
|
|
|
236
231
|
}
|
|
237
232
|
const event = inferEvent(args.event, payload);
|
|
238
233
|
const text = extractText(event, payload).trim();
|
|
234
|
+
// Emit the verdict in the shape Cursor expects for THIS event, then exit.
|
|
235
|
+
// beforeSubmitPrompt blocks via { continue: false }; the execution hooks
|
|
236
|
+
// (shell/mcp/read) block via { permission: "deny" }. Exit 2 reinforces it.
|
|
237
|
+
const respond = (blocked, userMsg, agentMsg) => {
|
|
238
|
+
const decision = event === 'prompt'
|
|
239
|
+
? (blocked ? { continue: false } : { continue: true })
|
|
240
|
+
: { permission: blocked ? 'deny' : 'allow' };
|
|
241
|
+
if (userMsg)
|
|
242
|
+
decision.user_message = userMsg;
|
|
243
|
+
if (agentMsg)
|
|
244
|
+
decision.agent_message = agentMsg;
|
|
245
|
+
process.stdout.write(JSON.stringify(decision));
|
|
246
|
+
process.exit(blocked ? 2 : 0);
|
|
247
|
+
};
|
|
239
248
|
// Nothing to scan, or no Shield configured → allow (fail-open by design here:
|
|
240
249
|
// a misconfigured machine must not brick the developer's IDE).
|
|
241
250
|
if (!text)
|
|
242
|
-
|
|
251
|
+
respond(false);
|
|
243
252
|
if (!shieldId) {
|
|
244
|
-
|
|
245
|
-
permission: 'allow',
|
|
246
|
-
agent_message: 'FullCourtDefense hook installed but no Shield ID configured (run `fullcourtdefense configure`).',
|
|
247
|
-
}, false);
|
|
253
|
+
respond(false, undefined, 'FullCourtDefense hook installed but no Shield ID configured (run `fullcourtdefense configure`).');
|
|
248
254
|
}
|
|
249
255
|
try {
|
|
250
256
|
const controller = new AbortController();
|
|
@@ -269,12 +275,7 @@ async function hookCommand(args, config) {
|
|
|
269
275
|
clearTimeout(timer);
|
|
270
276
|
if (!resp.ok) {
|
|
271
277
|
// Backend rejected (quota, bad shield, etc.) — fail open unless told otherwise.
|
|
272
|
-
|
|
273
|
-
emit({
|
|
274
|
-
permission: blocked ? 'deny' : 'allow',
|
|
275
|
-
user_message: blocked ? `FullCourtDefense gate unavailable (HTTP ${resp.status}) — blocked by fail-closed policy.` : undefined,
|
|
276
|
-
agent_message: `FullCourtDefense gate returned HTTP ${resp.status}.`,
|
|
277
|
-
}, blocked);
|
|
278
|
+
respond(failClosed, failClosed ? `FullCourtDefense gate unavailable (HTTP ${resp.status}) — blocked by fail-closed policy.` : undefined, `FullCourtDefense gate returned HTTP ${resp.status}.`);
|
|
278
279
|
}
|
|
279
280
|
const data = await resp.json().catch(() => ({}));
|
|
280
281
|
const sh = (data._shield || {});
|
|
@@ -285,28 +286,16 @@ async function hookCommand(args, config) {
|
|
|
285
286
|
const reason = String(sh.reason || 'policy_violation');
|
|
286
287
|
const explanation = String(sh.reason || 'Flagged by FullCourtDefense.');
|
|
287
288
|
if (!isBlocked) {
|
|
288
|
-
|
|
289
|
+
respond(false);
|
|
289
290
|
}
|
|
290
291
|
// Blocked verdict. In shadow mode we annotate but let it through.
|
|
291
292
|
if (shadow) {
|
|
292
|
-
|
|
293
|
-
permission: 'allow',
|
|
294
|
-
agent_message: `[FullCourtDefense shadow] would block ${event} (${reason}): ${explanation}`,
|
|
295
|
-
}, false);
|
|
293
|
+
respond(false, undefined, `[FullCourtDefense shadow] would block ${event} (${reason}): ${explanation}`);
|
|
296
294
|
}
|
|
297
|
-
|
|
298
|
-
permission: 'deny',
|
|
299
|
-
user_message: `Blocked by FullCourtDefense — ${reason}. ${explanation}`,
|
|
300
|
-
agent_message: `FullCourtDefense blocked this ${event} as "${reason}". Do not retry; revise to remove the flagged content.`,
|
|
301
|
-
}, true);
|
|
295
|
+
respond(true, `Blocked by FullCourtDefense — ${reason}.`, `FullCourtDefense blocked this ${event} as "${reason}". Do not retry; revise to remove the flagged content.`);
|
|
302
296
|
}
|
|
303
297
|
catch (err) {
|
|
304
298
|
// Network error / timeout.
|
|
305
|
-
|
|
306
|
-
emit({
|
|
307
|
-
permission: blocked ? 'deny' : 'allow',
|
|
308
|
-
user_message: blocked ? 'FullCourtDefense gate unreachable — blocked by fail-closed policy.' : undefined,
|
|
309
|
-
agent_message: `FullCourtDefense hook error: ${err instanceof Error ? err.message : String(err)}.`,
|
|
310
|
-
}, blocked);
|
|
299
|
+
respond(failClosed, failClosed ? 'FullCourtDefense gate unreachable — blocked by fail-closed policy.' : undefined, `FullCourtDefense hook error: ${err instanceof Error ? err.message : String(err)}.`);
|
|
311
300
|
}
|
|
312
301
|
}
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ const configure_1 = require("./commands/configure");
|
|
|
10
10
|
const discover_1 = require("./commands/discover");
|
|
11
11
|
const hook_1 = require("./commands/hook");
|
|
12
12
|
const installCursorHook_1 = require("./commands/installCursorHook");
|
|
13
|
-
const VERSION = '1.1.
|
|
13
|
+
const VERSION = '1.1.1';
|
|
14
14
|
function parseArgs(argv) {
|
|
15
15
|
const flags = {};
|
|
16
16
|
let command = '';
|