@synkro-sh/cli 1.4.71 → 1.4.73
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 +313 -13
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -147,6 +147,11 @@ function installCCHooks(settingsPath, config) {
|
|
|
147
147
|
command: config.editPrecheckScriptPath,
|
|
148
148
|
timeout: 30
|
|
149
149
|
},
|
|
150
|
+
{
|
|
151
|
+
type: "command",
|
|
152
|
+
command: config.cwePrecheckScriptPath,
|
|
153
|
+
timeout: 30
|
|
154
|
+
},
|
|
150
155
|
{
|
|
151
156
|
type: "command",
|
|
152
157
|
command: config.cvePrecheckScriptPath,
|
|
@@ -6249,6 +6254,7 @@ function writeHookScripts() {
|
|
|
6249
6254
|
const bashScriptPath = join11(HOOKS_DIR, "cc-bash-judge.ts");
|
|
6250
6255
|
const bashFollowupScriptPath = join11(HOOKS_DIR, "cc-bash-followup.ts");
|
|
6251
6256
|
const editPrecheckScriptPath = join11(HOOKS_DIR, "cc-edit-precheck.ts");
|
|
6257
|
+
const cwePrecheckScriptPath = join11(HOOKS_DIR, "cc-cwe-precheck.ts");
|
|
6252
6258
|
const cvePrecheckScriptPath = join11(HOOKS_DIR, "cc-cve-precheck.ts");
|
|
6253
6259
|
const planJudgeScriptPath = join11(HOOKS_DIR, "cc-plan-judge.ts");
|
|
6254
6260
|
const agentJudgeScriptPath = join11(HOOKS_DIR, "cc-agent-judge.ts");
|
|
@@ -6264,6 +6270,7 @@ function writeHookScripts() {
|
|
|
6264
6270
|
writeFileSync7(bashScriptPath, BASH_JUDGE_TS, "utf-8");
|
|
6265
6271
|
writeFileSync7(bashFollowupScriptPath, BASH_FOLLOWUP_TS, "utf-8");
|
|
6266
6272
|
writeFileSync7(editPrecheckScriptPath, EDIT_PRECHECK_TS, "utf-8");
|
|
6273
|
+
writeFileSync7(cwePrecheckScriptPath, CWE_PRECHECK_TS, "utf-8");
|
|
6267
6274
|
writeFileSync7(cvePrecheckScriptPath, CVE_PRECHECK_TS, "utf-8");
|
|
6268
6275
|
writeFileSync7(planJudgeScriptPath, PLAN_JUDGE_TS, "utf-8");
|
|
6269
6276
|
writeFileSync7(agentJudgeScriptPath, AGENT_JUDGE_TS, "utf-8");
|
|
@@ -6279,7 +6286,7 @@ function writeHookScripts() {
|
|
|
6279
6286
|
/**
|
|
6280
6287
|
* Local MCP guardrails server \u2014 runs on port 8931, stores rules in ~/.synkro/rules.json.
|
|
6281
6288
|
* JSON-RPC 2.0 over HTTP, same protocol as the cloud MCP server.
|
|
6282
|
-
*
|
|
6289
|
+
* Bearer token auth (file-based shared secret), localhost only, no embedding API, no Inngest.
|
|
6283
6290
|
*/
|
|
6284
6291
|
import { existsSync, readFileSync, writeFileSync, renameSync, appendFileSync, mkdirSync } from 'node:fs';
|
|
6285
6292
|
import { homedir } from 'node:os';
|
|
@@ -6296,15 +6303,29 @@ const TOKEN_PATH = join(HOME, '.synkro', '.mcp-local-token');
|
|
|
6296
6303
|
// File-based shared secret \u2014 generated once, required on all POST requests.
|
|
6297
6304
|
function getOrCreateToken(): string {
|
|
6298
6305
|
try {
|
|
6299
|
-
|
|
6306
|
+
return readFileSync(TOKEN_PATH, 'utf-8').trim();
|
|
6300
6307
|
} catch {}
|
|
6301
6308
|
const token = randomBytes(32).toString('hex');
|
|
6302
6309
|
mkdirSync(join(HOME, '.synkro'), { recursive: true });
|
|
6303
|
-
|
|
6304
|
-
|
|
6310
|
+
try {
|
|
6311
|
+
writeFileSync(TOKEN_PATH, token + '\\n', { mode: 0o600, flag: 'wx' });
|
|
6312
|
+
return token;
|
|
6313
|
+
} catch {
|
|
6314
|
+
return readFileSync(TOKEN_PATH, 'utf-8').trim();
|
|
6315
|
+
}
|
|
6305
6316
|
}
|
|
6306
6317
|
|
|
6307
6318
|
const SERVER_TOKEN = getOrCreateToken();
|
|
6319
|
+
const MAX_BODY_BYTES = 1_048_576;
|
|
6320
|
+
|
|
6321
|
+
let _writeLock: Promise<void> = Promise.resolve();
|
|
6322
|
+
function serialized<T>(fn: () => T | Promise<T>): Promise<T> {
|
|
6323
|
+
let release: () => void;
|
|
6324
|
+
const next = new Promise<void>(r => { release = r; });
|
|
6325
|
+
const prev = _writeLock;
|
|
6326
|
+
_writeLock = next;
|
|
6327
|
+
return prev.then(() => fn()).finally(() => release!());
|
|
6328
|
+
}
|
|
6308
6329
|
|
|
6309
6330
|
// \u2500\u2500\u2500 Storage \u2500\u2500\u2500
|
|
6310
6331
|
|
|
@@ -6691,6 +6712,219 @@ function handleListExemptions(): any {
|
|
|
6691
6712
|
return { exemptions: data.scanExemptions, total: data.scanExemptions.length };
|
|
6692
6713
|
}
|
|
6693
6714
|
|
|
6715
|
+
// \u2500\u2500\u2500 Findings \u2500\u2500\u2500
|
|
6716
|
+
|
|
6717
|
+
const CONFIG_PATH = join(HOME, '.synkro', 'config.json');
|
|
6718
|
+
const JWT_PATH = join(HOME, '.synkro', '.jwt');
|
|
6719
|
+
|
|
6720
|
+
interface Finding {
|
|
6721
|
+
id: string;
|
|
6722
|
+
session_id: string;
|
|
6723
|
+
file_path: string;
|
|
6724
|
+
finding_type: string;
|
|
6725
|
+
finding_id: string;
|
|
6726
|
+
severity: string;
|
|
6727
|
+
status: string;
|
|
6728
|
+
detail?: string;
|
|
6729
|
+
package_name?: string;
|
|
6730
|
+
package_version?: string;
|
|
6731
|
+
fixed_version?: string;
|
|
6732
|
+
created_at: string;
|
|
6733
|
+
resolved_at?: string;
|
|
6734
|
+
}
|
|
6735
|
+
|
|
6736
|
+
function getCloudConfig(): { apiUrl: string; jwt: string } | null {
|
|
6737
|
+
try {
|
|
6738
|
+
const jwt = readFileSync(JWT_PATH, 'utf-8').trim();
|
|
6739
|
+
if (!jwt) return null;
|
|
6740
|
+
let apiUrl = process.env.SYNKRO_API_URL || '';
|
|
6741
|
+
if (!apiUrl) {
|
|
6742
|
+
try {
|
|
6743
|
+
const cfg = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
|
|
6744
|
+
apiUrl = cfg.api_url || cfg.apiUrl || '';
|
|
6745
|
+
} catch {}
|
|
6746
|
+
}
|
|
6747
|
+
if (!apiUrl) apiUrl = 'https://api.synkro.sh';
|
|
6748
|
+
return { apiUrl, jwt };
|
|
6749
|
+
} catch {
|
|
6750
|
+
return null;
|
|
6751
|
+
}
|
|
6752
|
+
}
|
|
6753
|
+
|
|
6754
|
+
function readLocalFindings(): Finding[] {
|
|
6755
|
+
if (!existsSync(TELEMETRY_PATH)) return [];
|
|
6756
|
+
let lines: string[];
|
|
6757
|
+
try {
|
|
6758
|
+
lines = readFileSync(TELEMETRY_PATH, 'utf-8').split('\\n').filter(Boolean);
|
|
6759
|
+
} catch { return []; }
|
|
6760
|
+
const findingMap = new Map<string, Finding>();
|
|
6761
|
+
|
|
6762
|
+
for (const line of lines) {
|
|
6763
|
+
try {
|
|
6764
|
+
const event = JSON.parse(line);
|
|
6765
|
+
if (event.capture_type !== 'scan_finding') continue;
|
|
6766
|
+
const key = \`\${event.file_path}:\${event.finding_id}\`;
|
|
6767
|
+
const existing = findingMap.get(key);
|
|
6768
|
+
const ts = event._ts || event.created_at || '';
|
|
6769
|
+
|
|
6770
|
+
findingMap.set(key, {
|
|
6771
|
+
id: event.id || existing?.id || \`sf_\${event.session_id}_\${event.finding_id}_\${Date.now()}\`,
|
|
6772
|
+
session_id: event.session_id || existing?.session_id || '',
|
|
6773
|
+
file_path: event.file_path,
|
|
6774
|
+
finding_type: event.finding_type,
|
|
6775
|
+
finding_id: event.finding_id,
|
|
6776
|
+
severity: event.severity || 'unknown',
|
|
6777
|
+
status: event.status || 'open',
|
|
6778
|
+
detail: event.detail || existing?.detail,
|
|
6779
|
+
package_name: event.package_name || existing?.package_name,
|
|
6780
|
+
package_version: event.package_version || existing?.package_version,
|
|
6781
|
+
fixed_version: event.fixed_version || existing?.fixed_version,
|
|
6782
|
+
created_at: existing?.created_at || ts,
|
|
6783
|
+
resolved_at: event.status === 'resolved' ? ts : existing?.resolved_at,
|
|
6784
|
+
});
|
|
6785
|
+
} catch {}
|
|
6786
|
+
}
|
|
6787
|
+
|
|
6788
|
+
return Array.from(findingMap.values());
|
|
6789
|
+
}
|
|
6790
|
+
|
|
6791
|
+
async function fetchCloudFindings(params: Record<string, string>): Promise<Finding[] | null> {
|
|
6792
|
+
const cloud = getCloudConfig();
|
|
6793
|
+
if (!cloud) return null;
|
|
6794
|
+
try {
|
|
6795
|
+
const qs = new URLSearchParams(params).toString();
|
|
6796
|
+
const resp = await fetch(\`\${cloud.apiUrl}/api/v1/scan-findings?\${qs}\`, {
|
|
6797
|
+
headers: { Authorization: \`Bearer \${cloud.jwt}\` },
|
|
6798
|
+
signal: AbortSignal.timeout(5000),
|
|
6799
|
+
});
|
|
6800
|
+
if (!resp.ok) return null;
|
|
6801
|
+
const data = await resp.json() as any;
|
|
6802
|
+
return data.findings || data.data || [];
|
|
6803
|
+
} catch {
|
|
6804
|
+
return null;
|
|
6805
|
+
}
|
|
6806
|
+
}
|
|
6807
|
+
|
|
6808
|
+
function dispatchResolution(finding: Finding): void {
|
|
6809
|
+
const cloud = getCloudConfig();
|
|
6810
|
+
if (!cloud) return;
|
|
6811
|
+
fetch(\`\${cloud.apiUrl}/api/v1/hook/finding\`, {
|
|
6812
|
+
method: 'POST',
|
|
6813
|
+
headers: { Authorization: \`Bearer \${cloud.jwt}\`, 'Content-Type': 'application/json' },
|
|
6814
|
+
body: JSON.stringify({
|
|
6815
|
+
session_id: finding.session_id,
|
|
6816
|
+
file_path: finding.file_path,
|
|
6817
|
+
finding_type: finding.finding_type,
|
|
6818
|
+
finding_id: finding.finding_id,
|
|
6819
|
+
severity: finding.severity,
|
|
6820
|
+
status: 'resolved',
|
|
6821
|
+
}),
|
|
6822
|
+
signal: AbortSignal.timeout(3000),
|
|
6823
|
+
}).catch(() => {});
|
|
6824
|
+
}
|
|
6825
|
+
|
|
6826
|
+
async function handleListFindings(args: any): Promise<any> {
|
|
6827
|
+
const cloudParams: Record<string, string> = {};
|
|
6828
|
+
if (args.status) cloudParams.status = args.status;
|
|
6829
|
+
if (args.finding_type) cloudParams.finding_type = args.finding_type;
|
|
6830
|
+
if (args.severity) cloudParams.severity = args.severity;
|
|
6831
|
+
if (args.file_path) cloudParams.file_path = args.file_path;
|
|
6832
|
+
if (args.limit) cloudParams.limit = String(args.limit);
|
|
6833
|
+
|
|
6834
|
+
const cloudFindings = await fetchCloudFindings(cloudParams);
|
|
6835
|
+
|
|
6836
|
+
let findings: Finding[];
|
|
6837
|
+
let source: string;
|
|
6838
|
+
if (cloudFindings) {
|
|
6839
|
+
findings = cloudFindings;
|
|
6840
|
+
source = 'cloud';
|
|
6841
|
+
} else {
|
|
6842
|
+
findings = readLocalFindings();
|
|
6843
|
+
source = 'local';
|
|
6844
|
+
if (args.status) findings = findings.filter(f => f.status === args.status);
|
|
6845
|
+
if (args.finding_type) findings = findings.filter(f => f.finding_type === args.finding_type);
|
|
6846
|
+
if (args.severity) findings = findings.filter(f => f.severity === args.severity);
|
|
6847
|
+
if (args.file_path) findings = findings.filter(f => f.file_path.includes(args.file_path));
|
|
6848
|
+
}
|
|
6849
|
+
|
|
6850
|
+
findings.sort((a, b) => (b.created_at || '').localeCompare(a.created_at || ''));
|
|
6851
|
+
const limit = Math.min(args.limit || 25, 50);
|
|
6852
|
+
return {
|
|
6853
|
+
source,
|
|
6854
|
+
findings: findings.slice(0, limit).map(f => ({
|
|
6855
|
+
id: f.id,
|
|
6856
|
+
finding_type: f.finding_type,
|
|
6857
|
+
finding_id: f.finding_id,
|
|
6858
|
+
file_path: f.file_path,
|
|
6859
|
+
severity: f.severity,
|
|
6860
|
+
status: f.status,
|
|
6861
|
+
package_name: f.package_name,
|
|
6862
|
+
package_version: f.package_version,
|
|
6863
|
+
created_at: f.created_at,
|
|
6864
|
+
})),
|
|
6865
|
+
total: findings.length,
|
|
6866
|
+
open: findings.filter(f => f.status === 'open').length,
|
|
6867
|
+
resolved: findings.filter(f => f.status === 'resolved').length,
|
|
6868
|
+
};
|
|
6869
|
+
}
|
|
6870
|
+
|
|
6871
|
+
async function handleGetFindingDetail(args: any): Promise<any> {
|
|
6872
|
+
const findings = readLocalFindings();
|
|
6873
|
+
const match = findings.find(f => {
|
|
6874
|
+
if (args.id && f.id === args.id) return true;
|
|
6875
|
+
if (args.file_path && args.finding_id) {
|
|
6876
|
+
return f.file_path.includes(args.file_path) && f.finding_id.toUpperCase() === (args.finding_id || '').toUpperCase();
|
|
6877
|
+
}
|
|
6878
|
+
return false;
|
|
6879
|
+
});
|
|
6880
|
+
if (!match) return { found: false, error: 'Finding not found' };
|
|
6881
|
+
return { found: true, ...match };
|
|
6882
|
+
}
|
|
6883
|
+
|
|
6884
|
+
async function handleResolveFinding(args: any): Promise<any> {
|
|
6885
|
+
const findings = readLocalFindings();
|
|
6886
|
+
const toResolve = findings.filter(f => {
|
|
6887
|
+
if (f.status !== 'open') return false;
|
|
6888
|
+
if (args.id && f.id === args.id) return true;
|
|
6889
|
+
if (args.file_path && args.finding_id) {
|
|
6890
|
+
return f.file_path.includes(args.file_path) && f.finding_id.toUpperCase() === (args.finding_id || '').toUpperCase();
|
|
6891
|
+
}
|
|
6892
|
+
if (args.file_path) return f.file_path.includes(args.file_path);
|
|
6893
|
+
return false;
|
|
6894
|
+
});
|
|
6895
|
+
|
|
6896
|
+
if (toResolve.length === 0) return { resolved: 0, error: 'No matching open findings' };
|
|
6897
|
+
|
|
6898
|
+
const now = new Date().toISOString();
|
|
6899
|
+
for (const f of toResolve) {
|
|
6900
|
+
const event = {
|
|
6901
|
+
capture_type: 'scan_finding',
|
|
6902
|
+
id: f.id,
|
|
6903
|
+
session_id: f.session_id,
|
|
6904
|
+
file_path: f.file_path,
|
|
6905
|
+
finding_type: f.finding_type,
|
|
6906
|
+
finding_id: f.finding_id,
|
|
6907
|
+
severity: f.severity,
|
|
6908
|
+
status: 'resolved',
|
|
6909
|
+
detail: f.detail,
|
|
6910
|
+
package_name: f.package_name,
|
|
6911
|
+
package_version: f.package_version,
|
|
6912
|
+
fixed_version: f.fixed_version,
|
|
6913
|
+
resolved_at: now,
|
|
6914
|
+
_ts: now,
|
|
6915
|
+
};
|
|
6916
|
+
try {
|
|
6917
|
+
appendFileSync(TELEMETRY_PATH, JSON.stringify(event) + '\\n', 'utf-8');
|
|
6918
|
+
} catch {}
|
|
6919
|
+
dispatchResolution(f);
|
|
6920
|
+
}
|
|
6921
|
+
|
|
6922
|
+
return {
|
|
6923
|
+
resolved: toResolve.length,
|
|
6924
|
+
findings: toResolve.map(f => ({ finding_id: f.finding_id, file_path: f.file_path })),
|
|
6925
|
+
};
|
|
6926
|
+
}
|
|
6927
|
+
|
|
6694
6928
|
// \u2500\u2500\u2500 Tool Descriptors \u2500\u2500\u2500
|
|
6695
6929
|
|
|
6696
6930
|
const TOOL_DESCRIPTORS = [
|
|
@@ -6854,6 +7088,47 @@ const TOOL_DESCRIPTORS = [
|
|
|
6854
7088
|
description: "List all scan exemptions.",
|
|
6855
7089
|
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
6856
7090
|
},
|
|
7091
|
+
{
|
|
7092
|
+
name: 'list_findings',
|
|
7093
|
+
description: "List CWE/CVE scan findings. Shows security issues found by Synkro hooks. Use to review what needs fixing.",
|
|
7094
|
+
inputSchema: {
|
|
7095
|
+
type: 'object',
|
|
7096
|
+
properties: {
|
|
7097
|
+
status: { type: 'string', enum: ['open', 'resolved', 'exempted'], description: 'Filter by status (default: all).' },
|
|
7098
|
+
finding_type: { type: 'string', enum: ['cwe', 'cve'], description: 'Filter by finding type.' },
|
|
7099
|
+
severity: { type: 'string', enum: ['critical', 'high', 'medium', 'low'] },
|
|
7100
|
+
file_path: { type: 'string', description: 'Filter by file path substring.' },
|
|
7101
|
+
limit: { type: 'integer', default: 25, description: 'Max results (default 25, max 50).' },
|
|
7102
|
+
},
|
|
7103
|
+
required: [],
|
|
7104
|
+
},
|
|
7105
|
+
},
|
|
7106
|
+
{
|
|
7107
|
+
name: 'get_finding_detail',
|
|
7108
|
+
description: "Get full detail of a specific finding including remediation context.",
|
|
7109
|
+
inputSchema: {
|
|
7110
|
+
type: 'object',
|
|
7111
|
+
properties: {
|
|
7112
|
+
id: { type: 'string', description: 'Finding ID (e.g. sf_...).' },
|
|
7113
|
+
file_path: { type: 'string', description: 'File path (used with finding_id).' },
|
|
7114
|
+
finding_id: { type: 'string', description: 'CWE/CVE ID like CWE-89 or CVE-2024-1234.' },
|
|
7115
|
+
},
|
|
7116
|
+
required: [],
|
|
7117
|
+
},
|
|
7118
|
+
},
|
|
7119
|
+
{
|
|
7120
|
+
name: 'resolve_finding',
|
|
7121
|
+
description: "Mark finding(s) as resolved after the underlying issue is fixed. Can target by ID, file+finding_id, or all findings for a file.",
|
|
7122
|
+
inputSchema: {
|
|
7123
|
+
type: 'object',
|
|
7124
|
+
properties: {
|
|
7125
|
+
id: { type: 'string', description: 'Specific finding ID to resolve.' },
|
|
7126
|
+
file_path: { type: 'string', description: 'Resolve all open findings matching this file path.' },
|
|
7127
|
+
finding_id: { type: 'string', description: 'CWE/CVE ID (used with file_path for targeted resolution).' },
|
|
7128
|
+
},
|
|
7129
|
+
required: [],
|
|
7130
|
+
},
|
|
7131
|
+
},
|
|
6857
7132
|
];
|
|
6858
7133
|
|
|
6859
7134
|
const MCP_INSTRUCTIONS =
|
|
@@ -6864,7 +7139,12 @@ const MCP_INSTRUCTIONS =
|
|
|
6864
7139
|
"'we need a rule about\u2026' \u2014 route to THIS server's tools.\\n\\n" +
|
|
6865
7140
|
"TOOL ROUTING:\\n" +
|
|
6866
7141
|
" \u2022 get_guardrails(query) \u2014 keyword search. Use to check if a rule exists.\\n" +
|
|
6867
|
-
" \u2022 list_guardrails \u2014 full enumeration. Use for listings.\\n
|
|
7142
|
+
" \u2022 list_guardrails \u2014 full enumeration. Use for listings.\\n" +
|
|
7143
|
+
" \u2022 list_findings \u2014 show CWE/CVE scan findings (open, resolved, all).\\n" +
|
|
7144
|
+
" \u2022 get_finding_detail \u2014 get full detail + remediation context for a finding.\\n" +
|
|
7145
|
+
" \u2022 resolve_finding \u2014 mark findings resolved after fixing the code.\\n\\n" +
|
|
7146
|
+
"When the user asks about security issues, vulnerabilities, or scan results, " +
|
|
7147
|
+
"use list_findings first. After fixing code, call resolve_finding to update status.\\n\\n" +
|
|
6868
7148
|
"Do NOT use Claude Code's \`update-config\` skill for these requests.\\n\\n" +
|
|
6869
7149
|
"Rules are stored locally in ~/.synkro/rules.json and enforced by hooks.";
|
|
6870
7150
|
|
|
@@ -6917,6 +7197,9 @@ async function handleRpc(body: any): Promise<any> {
|
|
|
6917
7197
|
case 'exempt_path': result = handleExemptPath(args); break;
|
|
6918
7198
|
case 'remove_exemption': result = handleRemoveExemption(args); break;
|
|
6919
7199
|
case 'list_exemptions': result = handleListExemptions(); break;
|
|
7200
|
+
case 'list_findings': result = await handleListFindings(args); break;
|
|
7201
|
+
case 'get_finding_detail': result = await handleGetFindingDetail(args); break;
|
|
7202
|
+
case 'resolve_finding': result = await handleResolveFinding(args); break;
|
|
6920
7203
|
default: return jsonRpcError(id, -32601, \`Unknown tool: \${toolName}\`);
|
|
6921
7204
|
}
|
|
6922
7205
|
return jsonRpcOk(id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
|
|
@@ -7056,14 +7339,25 @@ const server = Bun.serve({
|
|
|
7056
7339
|
}
|
|
7057
7340
|
|
|
7058
7341
|
if (req.method === 'POST') {
|
|
7059
|
-
|
|
7060
|
-
|
|
7061
|
-
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7065
|
-
|
|
7342
|
+
const authHeader = req.headers.get('authorization') || '';
|
|
7343
|
+
const bearer = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : '';
|
|
7344
|
+
if (bearer !== SERVER_TOKEN) {
|
|
7345
|
+
return Response.json({ error: 'Unauthorized' }, { status: 401, headers: cors });
|
|
7346
|
+
}
|
|
7347
|
+
const raw = await req.arrayBuffer();
|
|
7348
|
+
if (raw.byteLength > MAX_BODY_BYTES) {
|
|
7349
|
+
return Response.json(jsonRpcError(null, -32600, 'Request too large'), { status: 413, headers: cors });
|
|
7066
7350
|
}
|
|
7351
|
+
return serialized(async () => {
|
|
7352
|
+
try {
|
|
7353
|
+
const body = JSON.parse(new TextDecoder().decode(raw));
|
|
7354
|
+
const result = await handleRpc(body);
|
|
7355
|
+
if (result === null) return new Response('', { status: 204, headers: cors });
|
|
7356
|
+
return Response.json(result, { headers: cors });
|
|
7357
|
+
} catch {
|
|
7358
|
+
return Response.json(jsonRpcError(null, -32700, 'Parse error'), { status: 400, headers: cors });
|
|
7359
|
+
}
|
|
7360
|
+
});
|
|
7067
7361
|
}
|
|
7068
7362
|
|
|
7069
7363
|
if (req.method === 'OPTIONS') {
|
|
@@ -7079,6 +7373,7 @@ console.log(\`[synkro] local MCP guardrails server listening on http://127.0.0.1
|
|
|
7079
7373
|
chmodSync2(bashScriptPath, 493);
|
|
7080
7374
|
chmodSync2(bashFollowupScriptPath, 493);
|
|
7081
7375
|
chmodSync2(editPrecheckScriptPath, 493);
|
|
7376
|
+
chmodSync2(cwePrecheckScriptPath, 493);
|
|
7082
7377
|
chmodSync2(cvePrecheckScriptPath, 493);
|
|
7083
7378
|
chmodSync2(planJudgeScriptPath, 493);
|
|
7084
7379
|
chmodSync2(agentJudgeScriptPath, 493);
|
|
@@ -7095,6 +7390,7 @@ console.log(\`[synkro] local MCP guardrails server listening on http://127.0.0.1
|
|
|
7095
7390
|
bashScript: bashScriptPath,
|
|
7096
7391
|
bashFollowupScript: bashFollowupScriptPath,
|
|
7097
7392
|
editPrecheckScript: editPrecheckScriptPath,
|
|
7393
|
+
cwePrecheckScript: cwePrecheckScriptPath,
|
|
7098
7394
|
cvePrecheckScript: cvePrecheckScriptPath,
|
|
7099
7395
|
planJudgeScript: planJudgeScriptPath,
|
|
7100
7396
|
agentJudgeScript: agentJudgeScriptPath,
|
|
@@ -7136,7 +7432,7 @@ function writeConfigEnv(opts) {
|
|
|
7136
7432
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
7137
7433
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
7138
7434
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
7139
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.4.
|
|
7435
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.4.73")}`
|
|
7140
7436
|
];
|
|
7141
7437
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
7142
7438
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -7536,6 +7832,8 @@ async function installCommand(opts = {}) {
|
|
|
7536
7832
|
console.log(` ${scripts.bashScript}`);
|
|
7537
7833
|
console.log(` ${scripts.bashFollowupScript}`);
|
|
7538
7834
|
console.log(` ${scripts.editPrecheckScript}`);
|
|
7835
|
+
console.log(` ${scripts.cwePrecheckScript}`);
|
|
7836
|
+
console.log(` ${scripts.cvePrecheckScript}`);
|
|
7539
7837
|
console.log(` ${scripts.planJudgeScript}`);
|
|
7540
7838
|
console.log(` ${scripts.agentJudgeScript}`);
|
|
7541
7839
|
console.log(` ${scripts.stopSummaryScript}`);
|
|
@@ -7571,6 +7869,7 @@ async function installCommand(opts = {}) {
|
|
|
7571
7869
|
bashJudgeScriptPath: scripts.bashScript,
|
|
7572
7870
|
bashFollowupScriptPath: scripts.bashFollowupScript,
|
|
7573
7871
|
editPrecheckScriptPath: scripts.editPrecheckScript,
|
|
7872
|
+
cwePrecheckScriptPath: scripts.cwePrecheckScript,
|
|
7574
7873
|
cvePrecheckScriptPath: scripts.cvePrecheckScript,
|
|
7575
7874
|
planJudgeScriptPath: scripts.planJudgeScript,
|
|
7576
7875
|
agentJudgeScriptPath: scripts.agentJudgeScript,
|
|
@@ -7588,6 +7887,7 @@ async function installCommand(opts = {}) {
|
|
|
7588
7887
|
editCaptureScriptPath: scripts.cursorEditCaptureScript,
|
|
7589
7888
|
bashFollowupScriptPath: scripts.bashFollowupScript,
|
|
7590
7889
|
editPrecheckScriptPath: scripts.editPrecheckScript,
|
|
7890
|
+
cwePrecheckScriptPath: scripts.cwePrecheckScript,
|
|
7591
7891
|
cvePrecheckScriptPath: scripts.cvePrecheckScript,
|
|
7592
7892
|
planJudgeScriptPath: scripts.planJudgeScript,
|
|
7593
7893
|
agentJudgeScriptPath: scripts.agentJudgeScript,
|