@synkro-sh/cli 1.4.64 → 1.4.65
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/bootstrap.js +256 -14
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -160,6 +160,17 @@ function installCCHooks(settingsPath, config) {
|
|
|
160
160
|
],
|
|
161
161
|
[SYNKRO_MARKER]: true
|
|
162
162
|
});
|
|
163
|
+
settings.hooks.PreToolUse.push({
|
|
164
|
+
matcher: "Agent",
|
|
165
|
+
hooks: [
|
|
166
|
+
{
|
|
167
|
+
type: "command",
|
|
168
|
+
command: config.agentJudgeScriptPath,
|
|
169
|
+
timeout: 30
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
[SYNKRO_MARKER]: true
|
|
173
|
+
});
|
|
163
174
|
settings.hooks.PreToolUse.push({
|
|
164
175
|
matcher: "ExitPlanMode",
|
|
165
176
|
hooks: [
|
|
@@ -828,7 +839,7 @@ exit 0
|
|
|
828
839
|
});
|
|
829
840
|
|
|
830
841
|
// cli/installer/hookScriptsTs.ts
|
|
831
|
-
var SYNKRO_COMMON_TS, EDIT_PRECHECK_TS, CWE_PRECHECK_TS, CVE_PRECHECK_TS, BASH_JUDGE_TS, PLAN_JUDGE_TS, STOP_SUMMARY_TS, SESSION_START_TS, BASH_FOLLOWUP_TS, TRANSCRIPT_SYNC_TS, USER_PROMPT_SUBMIT_TS;
|
|
842
|
+
var SYNKRO_COMMON_TS, EDIT_PRECHECK_TS, CWE_PRECHECK_TS, CVE_PRECHECK_TS, BASH_JUDGE_TS, AGENT_JUDGE_TS, PLAN_JUDGE_TS, STOP_SUMMARY_TS, SESSION_START_TS, BASH_FOLLOWUP_TS, TRANSCRIPT_SYNC_TS, USER_PROMPT_SUBMIT_TS;
|
|
832
843
|
var init_hookScriptsTs = __esm({
|
|
833
844
|
"cli/installer/hookScriptsTs.ts"() {
|
|
834
845
|
"use strict";
|
|
@@ -1134,7 +1145,7 @@ const PRIMER_KEY: Record<GradeRole, string> = {
|
|
|
1134
1145
|
let primerCache: { data: Record<string, string>; ts: number } | null = null;
|
|
1135
1146
|
|
|
1136
1147
|
async function fetchPrimer(role: GradeRole, jwt: string): Promise<string> {
|
|
1137
|
-
if (primerCache && Date.now() - primerCache.ts <
|
|
1148
|
+
if (primerCache && Date.now() - primerCache.ts < 300_000) {
|
|
1138
1149
|
const cached = primerCache.data[PRIMER_KEY[role]];
|
|
1139
1150
|
if (cached) return cached;
|
|
1140
1151
|
}
|
|
@@ -1188,7 +1199,7 @@ export async function localGrade(surface: string, prompt: string): Promise<strin
|
|
|
1188
1199
|
export async function localGradeCwe(prompt: string): Promise<string> {
|
|
1189
1200
|
const jwt = loadJwt();
|
|
1190
1201
|
if (!jwt) throw new Error('NO_JWT');
|
|
1191
|
-
return channelGrade('grade-cwe', prompt, jwt, 8930,
|
|
1202
|
+
return channelGrade('grade-cwe', prompt, jwt, 8930, 45000);
|
|
1192
1203
|
}
|
|
1193
1204
|
|
|
1194
1205
|
// \u2500\u2500\u2500 Verdict Parsing \u2500\u2500\u2500
|
|
@@ -2266,7 +2277,7 @@ main();
|
|
|
2266
2277
|
BASH_JUDGE_TS = `#!/usr/bin/env bun
|
|
2267
2278
|
import {
|
|
2268
2279
|
loadJwt, ensureFreshJwt, detectRepo, loadConfig, route, tag, localGrade,
|
|
2269
|
-
parseVerdict, dispatchCapture, ruleMode, postWithRetry, readStdin,
|
|
2280
|
+
parseVerdict, dispatchCapture, dispatchFinding, ruleMode, postWithRetry, readStdin,
|
|
2270
2281
|
extractTranscript, readLastPrompt, log,
|
|
2271
2282
|
outputJson, outputEmpty, GATEWAY_URL,
|
|
2272
2283
|
type HookConfig, type Rule,
|
|
@@ -2309,6 +2320,7 @@ async function main() {
|
|
|
2309
2320
|
jwt = await ensureFreshJwt(jwt);
|
|
2310
2321
|
|
|
2311
2322
|
// \u2500\u2500\u2500 CVE scan for package install commands \u2500\u2500\u2500
|
|
2323
|
+
let cveScanMsg = '';
|
|
2312
2324
|
if (toolName === 'Bash') {
|
|
2313
2325
|
const pkgInstallMatch = command.match(
|
|
2314
2326
|
/(?:npm\\s+(?:install|i|add)|pnpm\\s+(?:add|install|i)|yarn\\s+add|bun\\s+(?:add|install|i)|(?:uv\\s+)?pip3?\\s+install|go\\s+get|cargo\\s+add|gem\\s+install|composer\\s+require)\\s+(.+)/
|
|
@@ -2326,7 +2338,7 @@ async function main() {
|
|
|
2326
2338
|
for (const token of tokens) {
|
|
2327
2339
|
if (skipNext) { skipNext = false; continue; }
|
|
2328
2340
|
if (token.startsWith('-')) {
|
|
2329
|
-
if (/^--(python|target|prefix|root|constraint|requirement|index-url|extra-index-url|find-links|build|src|cache-dir)$/.test(token)) skipNext = true;
|
|
2341
|
+
if (/^--(python|target|prefix|root|constraint|requirement|index-url|extra-index-url|find-links|build|src|cache-dir|filter|workspace)$/.test(token)) skipNext = true;
|
|
2330
2342
|
continue;
|
|
2331
2343
|
}
|
|
2332
2344
|
if (isPip) {
|
|
@@ -2344,6 +2356,23 @@ async function main() {
|
|
|
2344
2356
|
deps[token] = '*';
|
|
2345
2357
|
}
|
|
2346
2358
|
}
|
|
2359
|
+
const unversioned = Object.keys(deps).filter(k => deps[k] === '*');
|
|
2360
|
+
if (unversioned.length > 0) {
|
|
2361
|
+
const lookups = unversioned.map(async (pkg) => {
|
|
2362
|
+
try {
|
|
2363
|
+
let ver: string | null = null;
|
|
2364
|
+
if (isPip) {
|
|
2365
|
+
const r = await fetch('https://pypi.org/pypi/' + encodeURIComponent(pkg) + '/json', { signal: AbortSignal.timeout(4000) });
|
|
2366
|
+
if (r.ok) { const d = await r.json() as any; ver = d?.info?.version || null; }
|
|
2367
|
+
} else {
|
|
2368
|
+
const r = await fetch('https://registry.npmjs.org/' + encodeURIComponent(pkg) + '/latest', { signal: AbortSignal.timeout(4000) });
|
|
2369
|
+
if (r.ok) { const d = await r.json() as any; ver = d?.version || null; }
|
|
2370
|
+
}
|
|
2371
|
+
if (ver) deps[pkg] = ver;
|
|
2372
|
+
} catch {}
|
|
2373
|
+
});
|
|
2374
|
+
await Promise.all(lookups);
|
|
2375
|
+
}
|
|
2347
2376
|
const manifestFile = isPip ? 'requirements.txt'
|
|
2348
2377
|
: isGo ? 'go.mod'
|
|
2349
2378
|
: isCargo ? 'Cargo.toml'
|
|
@@ -2364,7 +2393,11 @@ async function main() {
|
|
|
2364
2393
|
}).then(r => r.json()) as any;
|
|
2365
2394
|
|
|
2366
2395
|
const findings = Array.isArray(cveResp?.findings) ? cveResp.findings : [];
|
|
2367
|
-
|
|
2396
|
+
const scannedPkgs = Object.entries(deps).map(([k, v]) => k + '@' + v).join(', ');
|
|
2397
|
+
if (findings.length === 0) {
|
|
2398
|
+
cveScanMsg = '[synkro:cveScan] ' + scannedPkgs + ' \\u2192 clean, no known vulnerabilities';
|
|
2399
|
+
}
|
|
2400
|
+
else if (findings.length > 0) {
|
|
2368
2401
|
const top3 = findings.slice(0, 3).map((f: any) => {
|
|
2369
2402
|
const id = f.cve || f.id || '?';
|
|
2370
2403
|
const pkg = f.package || '?';
|
|
@@ -2376,6 +2409,26 @@ async function main() {
|
|
|
2376
2409
|
const label = count === 1 ? 'advisory' : 'advisories';
|
|
2377
2410
|
const cveMsg = '[synkro:cveScan] ' + cmdShort + ' \\u2192 ' + count + ' ' + label;
|
|
2378
2411
|
const ctx = 'CVE: ' + top3 + '\\nDo NOT install packages with known vulnerabilities. Use a patched version or a different package.';
|
|
2412
|
+
|
|
2413
|
+
const config = await loadConfig(jwt);
|
|
2414
|
+
for (const f of findings) {
|
|
2415
|
+
dispatchFinding(jwt, {
|
|
2416
|
+
session_id: sessionId,
|
|
2417
|
+
file_path: command,
|
|
2418
|
+
finding_type: 'cve',
|
|
2419
|
+
finding_id: f.cve || f.id || f.package,
|
|
2420
|
+
severity: typeof f.severity === 'number' ? (f.severity >= 9 ? 'critical' : f.severity >= 7 ? 'high' : f.severity >= 4 ? 'medium' : 'low') : (f.severity || 'medium'),
|
|
2421
|
+
status: 'open',
|
|
2422
|
+
detail: f.details || f.summary || null,
|
|
2423
|
+
description: f.summary || null,
|
|
2424
|
+
package_name: f.package || null,
|
|
2425
|
+
package_version: f.version || null,
|
|
2426
|
+
fixed_version: f.fixed || null,
|
|
2427
|
+
aliases: f.aliases || [],
|
|
2428
|
+
references: f.references || [],
|
|
2429
|
+
}, config.captureDepth);
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2379
2432
|
outputJson({
|
|
2380
2433
|
systemMessage: cveMsg,
|
|
2381
2434
|
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: ctx, additionalContext: ctx },
|
|
@@ -2397,7 +2450,8 @@ async function main() {
|
|
|
2397
2450
|
const tagStr = tag(rt, config);
|
|
2398
2451
|
|
|
2399
2452
|
if (config.silent) {
|
|
2400
|
-
|
|
2453
|
+
const msg = (cveScanMsg ? cveScanMsg + '\\n' : '') + tagStr + ' bashGuard \\u2192 skipped (silent mode)';
|
|
2454
|
+
outputJson({ systemMessage: msg, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: msg } });
|
|
2401
2455
|
return;
|
|
2402
2456
|
}
|
|
2403
2457
|
|
|
@@ -2428,7 +2482,8 @@ async function main() {
|
|
|
2428
2482
|
|
|
2429
2483
|
if (mode === 'audit') {
|
|
2430
2484
|
const reason = tagStr + ' bashGuard \\u2192 warning' + (verdict.ruleId ? ' (' + verdict.ruleId + ')' : '') + ': ' + (verdict.reason || 'policy violation');
|
|
2431
|
-
|
|
2485
|
+
const combined = (cveScanMsg ? cveScanMsg + '\\n' : '') + reason;
|
|
2486
|
+
outputJson({ systemMessage: combined, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: combined } });
|
|
2432
2487
|
dispatchCapture(jwt, 'bash', 'warning', verdict.severity || 'medium', verdict.category || 'security',
|
|
2433
2488
|
toolName, gitRepo, sessionId, config.captureDepth, {
|
|
2434
2489
|
command, reasoning: guardReason, rulesChecked: config.rules, violatedRules,
|
|
@@ -2436,9 +2491,10 @@ async function main() {
|
|
|
2436
2491
|
});
|
|
2437
2492
|
} else {
|
|
2438
2493
|
const reason = tagStr + ' bashGuard \\u2192 blocked' + (verdict.ruleId ? ' (' + verdict.ruleId + ')' : '') + ': ' + (verdict.reason || 'policy violation') + '. Ask the user for explicit consent before retrying.';
|
|
2494
|
+
const combined = (cveScanMsg ? cveScanMsg + '\\n' : '') + reason;
|
|
2439
2495
|
outputJson({
|
|
2440
|
-
systemMessage:
|
|
2441
|
-
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason, additionalContext:
|
|
2496
|
+
systemMessage: combined,
|
|
2497
|
+
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason, additionalContext: combined },
|
|
2442
2498
|
});
|
|
2443
2499
|
dispatchCapture(jwt, 'bash', 'block', verdict.severity || 'critical', verdict.category || 'security',
|
|
2444
2500
|
toolName, gitRepo, sessionId, config.captureDepth, {
|
|
@@ -2447,7 +2503,9 @@ async function main() {
|
|
|
2447
2503
|
});
|
|
2448
2504
|
}
|
|
2449
2505
|
} else {
|
|
2450
|
-
|
|
2506
|
+
const reason = tagStr + ' bashGuard \\u2192 pass: ' + (verdict.reason || 'no policy violations detected');
|
|
2507
|
+
const combined = (cveScanMsg ? cveScanMsg + '\\n' : '') + reason;
|
|
2508
|
+
outputJson({ systemMessage: combined, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: combined } });
|
|
2451
2509
|
dispatchCapture(jwt, 'bash', 'pass', 'audit', verdict.category || 'trivial_utility',
|
|
2452
2510
|
toolName, gitRepo, sessionId, config.captureDepth, {
|
|
2453
2511
|
command, reasoning: verdict.reason || 'no policy violations detected',
|
|
@@ -2486,16 +2544,30 @@ async function main() {
|
|
|
2486
2544
|
|
|
2487
2545
|
if (!resp) {
|
|
2488
2546
|
log('bashGuard ' + cmdShort + ' \\u2192 error (timeout)');
|
|
2489
|
-
|
|
2547
|
+
if (cveScanMsg) {
|
|
2548
|
+
outputJson({ systemMessage: cveScanMsg, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: cveScanMsg } });
|
|
2549
|
+
} else { outputEmpty(); }
|
|
2490
2550
|
return;
|
|
2491
2551
|
}
|
|
2492
2552
|
|
|
2493
2553
|
if (!resp.hook_response || typeof resp.hook_response !== 'object') {
|
|
2494
2554
|
log('bashGuard ' + cmdShort + ' \\u2192 pass (no hook_response)');
|
|
2495
|
-
|
|
2555
|
+
if (cveScanMsg) {
|
|
2556
|
+
outputJson({ systemMessage: cveScanMsg, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: cveScanMsg } });
|
|
2557
|
+
} else { outputEmpty(); }
|
|
2496
2558
|
return;
|
|
2497
2559
|
}
|
|
2498
2560
|
|
|
2561
|
+
if (cveScanMsg) {
|
|
2562
|
+
const existing = resp.hook_response.systemMessage || '';
|
|
2563
|
+
resp.hook_response.systemMessage = cveScanMsg + (existing ? '\\n' + existing : '');
|
|
2564
|
+
if (resp.hook_response.hookSpecificOutput) {
|
|
2565
|
+
const existingCtx = resp.hook_response.hookSpecificOutput.additionalContext || '';
|
|
2566
|
+
resp.hook_response.hookSpecificOutput.additionalContext = cveScanMsg + (existingCtx ? '\\n' + existingCtx : '');
|
|
2567
|
+
} else {
|
|
2568
|
+
resp.hook_response.hookSpecificOutput = { hookEventName: 'PreToolUse', additionalContext: resp.hook_response.systemMessage };
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2499
2571
|
outputJson(resp.hook_response);
|
|
2500
2572
|
} catch (err) {
|
|
2501
2573
|
process.stderr.write('[synkro] bashGuard error: ' + String(err) + '\\n');
|
|
@@ -2503,6 +2575,170 @@ async function main() {
|
|
|
2503
2575
|
}
|
|
2504
2576
|
}
|
|
2505
2577
|
|
|
2578
|
+
main();
|
|
2579
|
+
`;
|
|
2580
|
+
AGENT_JUDGE_TS = `#!/usr/bin/env bun
|
|
2581
|
+
import {
|
|
2582
|
+
loadJwt, ensureFreshJwt, detectRepo, loadConfig, route, tag, localGrade,
|
|
2583
|
+
parseVerdict, dispatchCapture, ruleMode, postWithRetry, readStdin,
|
|
2584
|
+
extractTranscript, readLastPrompt, log,
|
|
2585
|
+
outputJson, outputEmpty, GATEWAY_URL,
|
|
2586
|
+
type HookConfig, type Rule,
|
|
2587
|
+
} from './_synkro-common.ts';
|
|
2588
|
+
|
|
2589
|
+
async function main() {
|
|
2590
|
+
try {
|
|
2591
|
+
const input = await readStdin();
|
|
2592
|
+
if (!input.trim()) { outputEmpty(); return; }
|
|
2593
|
+
|
|
2594
|
+
const payload = JSON.parse(input);
|
|
2595
|
+
const toolName = payload.tool_name || '';
|
|
2596
|
+
if (toolName !== 'Agent') {
|
|
2597
|
+
outputEmpty();
|
|
2598
|
+
return;
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
const toolInput = payload.tool_input || {};
|
|
2602
|
+
const sessionId = payload.session_id || '';
|
|
2603
|
+
const toolUseId = payload.tool_use_id || '';
|
|
2604
|
+
const cwd = payload.cwd || '';
|
|
2605
|
+
const permissionMode = payload.permission_mode || '';
|
|
2606
|
+
const transcriptPath = payload.transcript_path || '';
|
|
2607
|
+
const gitRepo = detectRepo(cwd || '.');
|
|
2608
|
+
|
|
2609
|
+
const prompt = toolInput.prompt || '';
|
|
2610
|
+
const description = toolInput.description || '';
|
|
2611
|
+
const subagentType = toolInput.subagent_type || 'general-purpose';
|
|
2612
|
+
if (!prompt) { outputEmpty(); return; }
|
|
2613
|
+
|
|
2614
|
+
const promptShort = prompt.slice(0, 80);
|
|
2615
|
+
log('agentGuard checking: ' + description + ' (' + subagentType + ')');
|
|
2616
|
+
|
|
2617
|
+
let jwt = loadJwt();
|
|
2618
|
+
if (!jwt) { outputEmpty(); return; }
|
|
2619
|
+
jwt = await ensureFreshJwt(jwt);
|
|
2620
|
+
|
|
2621
|
+
const transcript = extractTranscript(transcriptPath);
|
|
2622
|
+
const lastPrompt = readLastPrompt();
|
|
2623
|
+
|
|
2624
|
+
const config = await loadConfig(jwt);
|
|
2625
|
+
const rt = await route(config);
|
|
2626
|
+
const tagStr = tag(rt, config);
|
|
2627
|
+
|
|
2628
|
+
if (config.silent) {
|
|
2629
|
+
const msg = tagStr + ' agentGuard \\u2192 skipped (silent mode)';
|
|
2630
|
+
outputJson({ systemMessage: msg, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: msg } });
|
|
2631
|
+
return;
|
|
2632
|
+
}
|
|
2633
|
+
|
|
2634
|
+
if (rt === 'local') {
|
|
2635
|
+
const graderPrompt = [
|
|
2636
|
+
'Working directory: ' + (cwd || '.'),
|
|
2637
|
+
'Repo: ' + (gitRepo || 'unknown'),
|
|
2638
|
+
'Tool: Agent (subagent spawn)',
|
|
2639
|
+
'Subagent type: ' + subagentType,
|
|
2640
|
+
'Description: ' + description,
|
|
2641
|
+
'Subagent prompt (first 4000 chars):',
|
|
2642
|
+
prompt.slice(0, 4000),
|
|
2643
|
+
'User intent (last human message): ' + (transcript.userIntent || 'none stated'),
|
|
2644
|
+
'Last user prompt: ' + (lastPrompt || 'none'),
|
|
2645
|
+
'Org rules: ' + JSON.stringify(config.rules),
|
|
2646
|
+
].join('\\n');
|
|
2647
|
+
|
|
2648
|
+
let gradeResp: string;
|
|
2649
|
+
try {
|
|
2650
|
+
gradeResp = await localGrade('bash', graderPrompt);
|
|
2651
|
+
} catch {
|
|
2652
|
+
outputEmpty();
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
const verdict = parseVerdict(gradeResp);
|
|
2657
|
+
const agentContent = 'agent=' + subagentType + ' desc=' + description + ' prompt=' + prompt.slice(0, 2000);
|
|
2658
|
+
const violatedRules = verdict.ruleId ? [verdict.ruleId] : [];
|
|
2659
|
+
|
|
2660
|
+
if (!verdict.ok) {
|
|
2661
|
+
const mode = verdict.ruleMode || ruleMode(verdict.ruleId, config.rules);
|
|
2662
|
+
const guardReason = (verdict.ruleId ? '(' + verdict.ruleId + ') ' : '') + (verdict.reason || 'policy violation');
|
|
2663
|
+
|
|
2664
|
+
if (mode === 'audit') {
|
|
2665
|
+
const reason = tagStr + ' agentGuard \\u2192 warning' + (verdict.ruleId ? ' (' + verdict.ruleId + ')' : '') + ': ' + (verdict.reason || 'policy violation');
|
|
2666
|
+
outputJson({ systemMessage: reason, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: reason } });
|
|
2667
|
+
dispatchCapture(jwt, 'agent', 'warning', verdict.severity || 'medium', verdict.category || 'security',
|
|
2668
|
+
toolName, gitRepo, sessionId, config.captureDepth, {
|
|
2669
|
+
command: agentContent, reasoning: guardReason, rulesChecked: config.rules, violatedRules,
|
|
2670
|
+
recentUserMessages: transcript.recentUserMessages, ccModel: transcript.ccModel,
|
|
2671
|
+
});
|
|
2672
|
+
} else {
|
|
2673
|
+
const reason = tagStr + ' agentGuard \\u2192 blocked' + (verdict.ruleId ? ' (' + verdict.ruleId + ')' : '') + ': ' + (verdict.reason || 'policy violation') + '. Ask the user for explicit consent before retrying.';
|
|
2674
|
+
outputJson({
|
|
2675
|
+
systemMessage: reason,
|
|
2676
|
+
hookSpecificOutput: { hookEventName: 'PreToolUse', permissionDecision: 'deny', permissionDecisionReason: reason, additionalContext: reason },
|
|
2677
|
+
});
|
|
2678
|
+
dispatchCapture(jwt, 'agent', 'block', verdict.severity || 'critical', verdict.category || 'security',
|
|
2679
|
+
toolName, gitRepo, sessionId, config.captureDepth, {
|
|
2680
|
+
command: agentContent, reasoning: guardReason, rulesChecked: config.rules, violatedRules,
|
|
2681
|
+
recentUserMessages: transcript.recentUserMessages, ccModel: transcript.ccModel,
|
|
2682
|
+
});
|
|
2683
|
+
}
|
|
2684
|
+
} else {
|
|
2685
|
+
const reason = tagStr + ' agentGuard \\u2192 pass: ' + (verdict.reason || 'no policy violations detected');
|
|
2686
|
+
outputJson({ systemMessage: reason, hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext: reason } });
|
|
2687
|
+
dispatchCapture(jwt, 'agent', 'pass', 'audit', verdict.category || 'subagent_spawn',
|
|
2688
|
+
toolName, gitRepo, sessionId, config.captureDepth, {
|
|
2689
|
+
command: agentContent, reasoning: verdict.reason || 'no policy violations detected',
|
|
2690
|
+
rulesChecked: config.rules, violatedRules: [],
|
|
2691
|
+
recentUserMessages: transcript.recentUserMessages, ccModel: transcript.ccModel,
|
|
2692
|
+
});
|
|
2693
|
+
}
|
|
2694
|
+
return;
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2697
|
+
// \u2500\u2500\u2500 Cloud grading \u2500\u2500\u2500
|
|
2698
|
+
const isHeadless = ['acceptEdits', 'bypassPermissions', 'plan', 'auto'].includes(permissionMode)
|
|
2699
|
+
|| process.env.SYNKRO_HEADLESS === '1';
|
|
2700
|
+
|
|
2701
|
+
const body: Record<string, any> = {
|
|
2702
|
+
hook_event: 'PreToolUse',
|
|
2703
|
+
tool_name: toolName,
|
|
2704
|
+
tool_input: toolInput,
|
|
2705
|
+
user_intent: transcript.userIntent || null,
|
|
2706
|
+
last_user_message: lastPrompt || null,
|
|
2707
|
+
recent_user_messages: transcript.recentUserMessages,
|
|
2708
|
+
recent_messages: transcript.recentMessages,
|
|
2709
|
+
recent_actions: transcript.recentActions,
|
|
2710
|
+
session_id: sessionId || null,
|
|
2711
|
+
tool_use_id: toolUseId || null,
|
|
2712
|
+
cwd: cwd || null,
|
|
2713
|
+
repo: gitRepo || null,
|
|
2714
|
+
permission_mode: permissionMode || null,
|
|
2715
|
+
headless: isHeadless,
|
|
2716
|
+
cc_model: transcript.ccModel || null,
|
|
2717
|
+
cc_usage: transcript.ccUsage || {},
|
|
2718
|
+
session_summary: transcript.sessionSummary || null,
|
|
2719
|
+
};
|
|
2720
|
+
|
|
2721
|
+
const resp = await postWithRetry(GATEWAY_URL + '/api/v1/hook/judge', body, jwt, 8000);
|
|
2722
|
+
|
|
2723
|
+
if (!resp) {
|
|
2724
|
+
log('agentGuard ' + promptShort + ' \\u2192 error (timeout)');
|
|
2725
|
+
outputEmpty();
|
|
2726
|
+
return;
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
if (!resp.hook_response || typeof resp.hook_response !== 'object') {
|
|
2730
|
+
log('agentGuard ' + promptShort + ' \\u2192 pass (no hook_response)');
|
|
2731
|
+
outputEmpty();
|
|
2732
|
+
return;
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
outputJson(resp.hook_response);
|
|
2736
|
+
} catch (err) {
|
|
2737
|
+
process.stderr.write('[synkro] agentGuard error: ' + String(err) + '\\n');
|
|
2738
|
+
outputEmpty();
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2506
2742
|
main();
|
|
2507
2743
|
`;
|
|
2508
2744
|
PLAN_JUDGE_TS = `#!/usr/bin/env bun
|
|
@@ -5292,6 +5528,7 @@ function writeHookScripts() {
|
|
|
5292
5528
|
const cwePrecheckScriptPath = join11(HOOKS_DIR, "cc-cwe-precheck.ts");
|
|
5293
5529
|
const cvePrecheckScriptPath = join11(HOOKS_DIR, "cc-cve-precheck.ts");
|
|
5294
5530
|
const planJudgeScriptPath = join11(HOOKS_DIR, "cc-plan-judge.ts");
|
|
5531
|
+
const agentJudgeScriptPath = join11(HOOKS_DIR, "cc-agent-judge.ts");
|
|
5295
5532
|
const stopSummaryScriptPath = join11(HOOKS_DIR, "cc-stop-summary.ts");
|
|
5296
5533
|
const sessionStartScriptPath = join11(HOOKS_DIR, "cc-session-start.ts");
|
|
5297
5534
|
const transcriptSyncScriptPath = join11(HOOKS_DIR, "cc-transcript-sync.ts");
|
|
@@ -5308,6 +5545,7 @@ function writeHookScripts() {
|
|
|
5308
5545
|
writeFileSync7(cwePrecheckScriptPath, CWE_PRECHECK_TS, "utf-8");
|
|
5309
5546
|
writeFileSync7(cvePrecheckScriptPath, CVE_PRECHECK_TS, "utf-8");
|
|
5310
5547
|
writeFileSync7(planJudgeScriptPath, PLAN_JUDGE_TS, "utf-8");
|
|
5548
|
+
writeFileSync7(agentJudgeScriptPath, AGENT_JUDGE_TS, "utf-8");
|
|
5311
5549
|
writeFileSync7(stopSummaryScriptPath, STOP_SUMMARY_TS, "utf-8");
|
|
5312
5550
|
writeFileSync7(sessionStartScriptPath, SESSION_START_TS, "utf-8");
|
|
5313
5551
|
writeFileSync7(transcriptSyncScriptPath, TRANSCRIPT_SYNC_TS, "utf-8");
|
|
@@ -5324,6 +5562,7 @@ function writeHookScripts() {
|
|
|
5324
5562
|
chmodSync2(cwePrecheckScriptPath, 493);
|
|
5325
5563
|
chmodSync2(cvePrecheckScriptPath, 493);
|
|
5326
5564
|
chmodSync2(planJudgeScriptPath, 493);
|
|
5565
|
+
chmodSync2(agentJudgeScriptPath, 493);
|
|
5327
5566
|
chmodSync2(stopSummaryScriptPath, 493);
|
|
5328
5567
|
chmodSync2(sessionStartScriptPath, 493);
|
|
5329
5568
|
chmodSync2(transcriptSyncScriptPath, 493);
|
|
@@ -5341,6 +5580,7 @@ function writeHookScripts() {
|
|
|
5341
5580
|
cwePrecheckScript: cwePrecheckScriptPath,
|
|
5342
5581
|
cvePrecheckScript: cvePrecheckScriptPath,
|
|
5343
5582
|
planJudgeScript: planJudgeScriptPath,
|
|
5583
|
+
agentJudgeScript: agentJudgeScriptPath,
|
|
5344
5584
|
stopSummaryScript: stopSummaryScriptPath,
|
|
5345
5585
|
sessionStartScript: sessionStartScriptPath,
|
|
5346
5586
|
transcriptSyncScript: transcriptSyncScriptPath,
|
|
@@ -5380,7 +5620,7 @@ function writeConfigEnv(opts) {
|
|
|
5380
5620
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
5381
5621
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
5382
5622
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
5383
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.4.
|
|
5623
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.4.65")}`
|
|
5384
5624
|
];
|
|
5385
5625
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
5386
5626
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -5686,6 +5926,7 @@ async function installCommand(opts = {}) {
|
|
|
5686
5926
|
console.log(` ${scripts.bashFollowupScript}`);
|
|
5687
5927
|
console.log(` ${scripts.editPrecheckScript}`);
|
|
5688
5928
|
console.log(` ${scripts.planJudgeScript}`);
|
|
5929
|
+
console.log(` ${scripts.agentJudgeScript}`);
|
|
5689
5930
|
console.log(` ${scripts.stopSummaryScript}`);
|
|
5690
5931
|
console.log(` ${scripts.sessionStartScript}`);
|
|
5691
5932
|
console.log(` ${scripts.transcriptSyncScript}
|
|
@@ -5722,6 +5963,7 @@ async function installCommand(opts = {}) {
|
|
|
5722
5963
|
cwePrecheckScriptPath: scripts.cwePrecheckScript,
|
|
5723
5964
|
cvePrecheckScriptPath: scripts.cvePrecheckScript,
|
|
5724
5965
|
planJudgeScriptPath: scripts.planJudgeScript,
|
|
5966
|
+
agentJudgeScriptPath: scripts.agentJudgeScript,
|
|
5725
5967
|
stopSummaryScriptPath: scripts.stopSummaryScript,
|
|
5726
5968
|
sessionStartScriptPath: scripts.sessionStartScript,
|
|
5727
5969
|
transcriptSyncScriptPath: scripts.transcriptSyncScript,
|