@synkro-sh/cli 1.4.92 → 1.4.93

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 CHANGED
@@ -2297,12 +2297,14 @@ async function main() {
2297
2297
  if (!proposed) { outputEmpty(); return; }
2298
2298
 
2299
2299
  let cweContent: string;
2300
+ let cweDiffSection = '';
2300
2301
  if (toolName === 'Edit' || toolName === 'MultiEdit' || toolName === 'edit_file' || toolName === 'reapply' || toolName === 'ApplyPatch' || toolName === 'apply_patch') {
2301
2302
  const newStr = toolName === 'Edit' || toolName === 'edit_file' || toolName === 'reapply'
2302
2303
  ? (toolInput.new_string || '')
2303
2304
  : toolName === 'ApplyPatch' || toolName === 'apply_patch'
2304
2305
  ? (toolInput.patch || toolInput.content || toolInput.code_edit || '')
2305
2306
  : (Array.isArray(toolInput.edits) ? toolInput.edits.map((e: any) => e?.new_string || '').join('\n') : '');
2307
+ cweDiffSection = newStr.slice(0, 4000);
2306
2308
  const changeIdx = proposed.indexOf(newStr);
2307
2309
  if (changeIdx >= 0 && proposed.length > 6000) {
2308
2310
  const start = Math.max(0, changeIdx - 2000);
@@ -2333,14 +2335,28 @@ async function main() {
2333
2335
 
2334
2336
  if (rt === 'local') {
2335
2337
  let cweRules: any[] = [];
2338
+ let cweRuleFetchFailed = false;
2336
2339
  try {
2337
2340
  const resp = await fetch(GATEWAY_URL + '/api/v1/cwe-rules?ext=' + encodeURIComponent(fileExt), {
2338
2341
  headers: { Authorization: 'Bearer ' + jwt },
2339
2342
  signal: AbortSignal.timeout(4000),
2340
2343
  });
2341
- const data = await resp.json() as any;
2342
- cweRules = data.rules || [];
2343
- } catch {}
2344
+ if (!resp.ok) {
2345
+ log('CWE rules fetch failed: HTTP ' + resp.status);
2346
+ cweRuleFetchFailed = true;
2347
+ } else {
2348
+ const data = await resp.json() as any;
2349
+ cweRules = data.rules || [];
2350
+ }
2351
+ } catch (fetchErr: any) {
2352
+ log('CWE rules fetch error: ' + (fetchErr?.message || String(fetchErr)));
2353
+ cweRuleFetchFailed = true;
2354
+ }
2355
+
2356
+ if (cweRuleFetchFailed) {
2357
+ outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 CWE rules unavailable \u2014 scan skipped' });
2358
+ return;
2359
+ }
2344
2360
 
2345
2361
  if (cweRules.length === 0) {
2346
2362
  outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 clean (no CWE rules for ' + fileExt + ')' });
@@ -2359,40 +2375,86 @@ async function main() {
2359
2375
  }
2360
2376
  }
2361
2377
 
2362
- const graderPrompt = [
2363
- 'File: ' + filePath,
2364
- 'Content:',
2365
- cweContent,
2366
- '',
2367
- 'CWE rules to check against:',
2368
- JSON.stringify(cweRules),
2369
- ].join('\n') + localPkgContext;
2370
-
2371
- let gradeResp: string;
2372
- try {
2373
- gradeResp = await localGradeCwe(graderPrompt);
2374
- } catch (gradeErr: any) {
2375
- const reason = gradeErr?.message || String(gradeErr);
2376
- outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 grader unavailable (' + reason + '), skipped' });
2377
- return;
2378
+ const exemptionNote = exemptedCwes.size > 0
2379
+ ? '\n\nEXEMPTED CWEs (already known, DO NOT report these — focus on NEW weaknesses only): ' + [...exemptedCwes].join(', ')
2380
+ : '';
2381
+
2382
+ function buildCwePrompt(content: string): string {
2383
+ const diffBlock = cweDiffSection
2384
+ ? '\n\n=== NEW/CHANGED CODE (evaluate THIS for CWE weaknesses) ===\n' + cweDiffSection + '\n=== END NEW CODE ===\n\nThe surrounding content below is CONTEXT ONLY to help you understand imports, variables, and scope. Do NOT report issues found only in the context section.\n'
2385
+ : '';
2386
+ return [
2387
+ 'File: ' + filePath,
2388
+ diffBlock,
2389
+ 'Full content window:',
2390
+ content,
2391
+ '',
2392
+ 'CWE rules to check against:',
2393
+ JSON.stringify(cweRules),
2394
+ ].join('\n') + localPkgContext + exemptionNote;
2378
2395
  }
2379
2396
 
2380
- const verdict = parseVerdict(gradeResp);
2397
+ const SPLIT_THRESHOLD = 4000;
2398
+ const OVERLAP = 500;
2399
+ let gradeResponses: string[] = [];
2381
2400
 
2382
- if (!verdict.ok) {
2383
- const ruleIdMatches = gradeResp.match(/<rule_id>([^<]+)<\/rule_id>/g) || [];
2384
- const cweIds: string[] = [];
2385
- for (const match of ruleIdMatches.slice(0, 5)) {
2386
- const id = match.replace(/<\/?rule_id>/g, '').trim().replace(/^cwe-/, 'CWE-');
2387
- if (id && !cweIds.includes(id)) cweIds.push(id);
2401
+ if (cweContent.length > SPLIT_THRESHOLD) {
2402
+ const mid = Math.floor(cweContent.length / 2);
2403
+ const chunk1 = cweContent.slice(0, mid + OVERLAP);
2404
+ const chunk2 = cweContent.slice(mid - OVERLAP);
2405
+ try {
2406
+ const [resp1, resp2] = await Promise.all([
2407
+ localGradeCwe(buildCwePrompt(chunk1)),
2408
+ localGradeCwe(buildCwePrompt(chunk2)),
2409
+ ]);
2410
+ gradeResponses = [resp1, resp2];
2411
+ } catch (gradeErr: any) {
2412
+ const reason = gradeErr?.message || String(gradeErr);
2413
+ outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 grader unavailable (' + reason + '), skipped' });
2414
+ return;
2415
+ }
2416
+ } else {
2417
+ try {
2418
+ gradeResponses = [await localGradeCwe(buildCwePrompt(cweContent))];
2419
+ } catch (gradeErr: any) {
2420
+ const reason = gradeErr?.message || String(gradeErr);
2421
+ outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 grader unavailable (' + reason + '), skipped' });
2422
+ return;
2388
2423
  }
2424
+ }
2389
2425
 
2390
- const fixMatches = gradeResp.match(/<suggested_fix>([^<]+)<\/suggested_fix>/g) || [];
2391
- const fixes: Record<string, string> = {};
2392
- for (let i = 0; i < Math.min(cweIds.length, fixMatches.length); i++) {
2393
- fixes[cweIds[i]] = fixMatches[i].replace(/<\/?suggested_fix>/g, '').trim();
2426
+ const cweIds: string[] = [];
2427
+ const fixes: Record<string, string> = {};
2428
+ let mergedReason = '';
2429
+ let mergedSeverity = '';
2430
+ let mergedCategory = '';
2431
+ let anyFailed = false;
2432
+
2433
+ for (const gradeResp of gradeResponses) {
2434
+ const v = parseVerdict(gradeResp);
2435
+ if (!v.ok) {
2436
+ anyFailed = true;
2437
+ if (v.reason) mergedReason = mergedReason || v.reason;
2438
+ if (v.severity) mergedSeverity = mergedSeverity || v.severity;
2439
+ if (v.category) mergedCategory = mergedCategory || v.category;
2440
+ const ruleIdMatches = gradeResp.match(/<rule_id>([^<]+)<\/rule_id>/g) || [];
2441
+ for (const m of ruleIdMatches.slice(0, 5)) {
2442
+ const id = m.replace(/<\/?rule_id>/g, '').trim().replace(/^cwe-/, 'CWE-');
2443
+ if (id && !cweIds.includes(id)) cweIds.push(id);
2444
+ }
2445
+ const fMatches = gradeResp.match(/<suggested_fix>([^<]+)<\/suggested_fix>/g) || [];
2446
+ const respIds = ruleIdMatches.map(rm => rm.replace(/<\/?rule_id>/g, '').trim().replace(/^cwe-/, 'CWE-'));
2447
+ for (let i = 0; i < Math.min(respIds.length, fMatches.length); i++) {
2448
+ if (!fixes[respIds[i]]) fixes[respIds[i]] = fMatches[i].replace(/<\/?suggested_fix>/g, '').trim();
2449
+ }
2394
2450
  }
2451
+ }
2452
+
2453
+ const verdict = anyFailed
2454
+ ? { ok: false, reason: mergedReason, severity: mergedSeverity, category: mergedCategory }
2455
+ : { ok: true, reason: '', severity: '', category: '' };
2395
2456
 
2457
+ if (!verdict.ok) {
2396
2458
  const activeCweIds = cweIds.filter(id => !exemptedCwes.has(id.toUpperCase()));
2397
2459
 
2398
2460
  if (activeCweIds.length === 0) {
@@ -5660,7 +5722,7 @@ function writeConfigEnv(opts) {
5660
5722
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
5661
5723
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
5662
5724
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
5663
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.92")}`
5725
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.93")}`
5664
5726
  ];
5665
5727
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
5666
5728
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -5677,12 +5739,13 @@ function writeConfigEnv(opts) {
5677
5739
  chmodSync2(CONFIG_PATH2, 384);
5678
5740
  }
5679
5741
  function resolveDeploymentMode() {
5680
- const envOverride = process.env.SYNKRO_DEPLOYMENT_MODE;
5681
- if (envOverride) return envOverride.toLowerCase();
5742
+ const envOverride = process.env.SYNKRO_DEPLOYMENT_MODE?.toLowerCase();
5743
+ if (envOverride === "bare-host" || envOverride === "docker") return envOverride;
5682
5744
  try {
5683
5745
  if (existsSync9(CONFIG_PATH2)) {
5684
5746
  const m = readFileSync7(CONFIG_PATH2, "utf-8").match(/^SYNKRO_DEPLOYMENT_MODE='([^']*)'/m);
5685
- if (m && m[1]) return m[1].toLowerCase();
5747
+ const val = m?.[1]?.toLowerCase();
5748
+ if (val === "bare-host" || val === "docker") return val;
5686
5749
  }
5687
5750
  } catch {
5688
5751
  }
@@ -7095,7 +7158,7 @@ var args = process.argv.slice(2);
7095
7158
  var cmd = args[0] || "";
7096
7159
  var subArgs = args.slice(1);
7097
7160
  function printVersion() {
7098
- console.log("1.4.92");
7161
+ console.log("1.4.93");
7099
7162
  }
7100
7163
  function printHelp() {
7101
7164
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents