@synkro-sh/cli 1.4.57 → 1.4.59

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
@@ -834,7 +834,7 @@ var init_hookScriptsTs = __esm({
834
834
  "use strict";
835
835
  SYNKRO_COMMON_TS = `
836
836
  // Shared Synkro hook utilities \u2014 imported by all hook scripts.
837
- import { readFileSync, writeFileSync, mkdirSync, rmdirSync, existsSync, renameSync } from 'node:fs';
837
+ import { readFileSync, writeFileSync, appendFileSync, mkdirSync, rmdirSync, existsSync, renameSync } from 'node:fs';
838
838
  import { join, dirname, basename, extname } from 'node:path';
839
839
  import { homedir } from 'node:os';
840
840
  import { execSync, spawn } from 'node:child_process';
@@ -1014,6 +1014,7 @@ export interface HookConfig {
1014
1014
  silent: boolean;
1015
1015
  policyName: string;
1016
1016
  rules: Rule[];
1017
+ scanExemptions: string[];
1017
1018
  }
1018
1019
 
1019
1020
  export async function loadConfig(jwt: string, query?: string): Promise<HookConfig> {
@@ -1023,6 +1024,7 @@ export async function loadConfig(jwt: string, query?: string): Promise<HookConfi
1023
1024
  silent: false,
1024
1025
  policyName: '',
1025
1026
  rules: [],
1027
+ scanExemptions: [],
1026
1028
  };
1027
1029
  try {
1028
1030
  const url = GATEWAY_URL + '/api/v1/hook/config' + (query ? '?' + query : '');
@@ -1035,6 +1037,9 @@ export async function loadConfig(jwt: string, query?: string): Promise<HookConfi
1035
1037
  config.tier = data.tier || 'standard';
1036
1038
  config.silent = data.silent_mode === true || data.silent_mode === 'true';
1037
1039
  config.policyName = data.active_policy_name || '';
1040
+ if (Array.isArray(data.scan_exemptions)) {
1041
+ config.scanExemptions = data.scan_exemptions.filter((s: any) => typeof s === 'string');
1042
+ }
1038
1043
  if (Array.isArray(data.rules)) {
1039
1044
  config.rules = data.rules
1040
1045
  .filter((r: any) => r.hook_stage === 'pre' || r.hook_stage === 'both' || r.hook_stage == null)
@@ -1250,6 +1255,8 @@ export function dispatchCapture(
1250
1255
  if (opts.recentUserMessages) body.recent_user_messages = opts.recentUserMessages;
1251
1256
  }
1252
1257
 
1258
+ appendLocalTelemetry(body);
1259
+
1253
1260
  fetch(GATEWAY_URL + '/api/v1/hook/capture', {
1254
1261
  method: 'POST',
1255
1262
  headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + jwt },
@@ -1258,6 +1265,13 @@ export function dispatchCapture(
1258
1265
  }).catch(() => {});
1259
1266
  }
1260
1267
 
1268
+ export function appendLocalTelemetry(body: Record<string, any>): void {
1269
+ try {
1270
+ const telPath = join(HOME, '.synkro', 'telemetry.jsonl');
1271
+ appendFileSync(telPath, JSON.stringify({ ...body, _ts: new Date().toISOString() }) + '\\n', 'utf-8');
1272
+ } catch {}
1273
+ }
1274
+
1261
1275
  // \u2500\u2500\u2500 Rule Mode Lookup \u2500\u2500\u2500
1262
1276
 
1263
1277
  export function ruleMode(ruleId: string, rules: Rule[]): 'blocking' | 'audit' {
@@ -1827,6 +1841,11 @@ async function main() {
1827
1841
  const config = await loadConfig(jwt);
1828
1842
  const rt = await cweRoute(config);
1829
1843
 
1844
+ // Check scan exemptions from server
1845
+ if (config.scanExemptions.length > 0 && config.scanExemptions.some(ex => filePath.includes(ex))) {
1846
+ outputEmpty(); return;
1847
+ }
1848
+
1830
1849
  if (config.silent) {
1831
1850
  outputJson({ systemMessage: '[synkro:' + rt + ':cweScan] ' + fileShort + ' \\u2192 skipped (silent mode)' });
1832
1851
  return;
@@ -2008,7 +2027,8 @@ async function main() {
2008
2027
  const pkg = f.package || '?';
2009
2028
  const ver = f.version || '?';
2010
2029
  const title = f.title || f.summary || 'vulnerable';
2011
- return '[' + id + '] ' + pkg + '@' + ver + ': ' + title;
2030
+ const fix = f.fixed ? ' (fix: >=' + f.fixed + ')' : ' (no safe version \u2014 use an alternative)';
2031
+ return '[' + id + '] ' + pkg + '@' + ver + ': ' + title + fix;
2012
2032
  }).join('; ');
2013
2033
 
2014
2034
  const count = findings.length;
@@ -5093,7 +5113,7 @@ function writeConfigEnv(opts) {
5093
5113
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
5094
5114
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
5095
5115
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
5096
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.57")}`
5116
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.59")}`
5097
5117
  ];
5098
5118
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
5099
5119
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);