@synkro-sh/cli 1.4.92 → 1.4.94
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 +115 -42
- package/dist/bootstrap.js.map +1 -1
- package/package.json +2 -3
package/dist/bootstrap.js
CHANGED
|
@@ -1661,8 +1661,12 @@ export function extractTranscript(transcriptPath: string | undefined): Transcrip
|
|
|
1661
1661
|
|
|
1662
1662
|
// \u2500\u2500\u2500 Last Prompt \u2500\u2500\u2500
|
|
1663
1663
|
|
|
1664
|
-
export function readLastPrompt(): string {
|
|
1664
|
+
export function readLastPrompt(sessionId?: string): string {
|
|
1665
1665
|
try {
|
|
1666
|
+
if (sessionId) {
|
|
1667
|
+
const perSession = join(SESSIONS_DIR, sessionId + '.last-prompt');
|
|
1668
|
+
if (existsSync(perSession)) return readFileSync(perSession, 'utf-8').trim();
|
|
1669
|
+
}
|
|
1666
1670
|
if (!existsSync(LAST_PROMPT_FILE)) return '';
|
|
1667
1671
|
return readFileSync(LAST_PROMPT_FILE, 'utf-8').trim();
|
|
1668
1672
|
} catch {
|
|
@@ -1986,7 +1990,7 @@ async function main() {
|
|
|
1986
1990
|
|
|
1987
1991
|
// Extract transcript context
|
|
1988
1992
|
const transcript = extractTranscript(transcriptPath);
|
|
1989
|
-
const lastPrompt = readLastPrompt();
|
|
1993
|
+
const lastPrompt = readLastPrompt(sessionId);
|
|
1990
1994
|
|
|
1991
1995
|
// Load config and decide route
|
|
1992
1996
|
const config = await loadConfig(jwt);
|
|
@@ -2297,12 +2301,14 @@ async function main() {
|
|
|
2297
2301
|
if (!proposed) { outputEmpty(); return; }
|
|
2298
2302
|
|
|
2299
2303
|
let cweContent: string;
|
|
2304
|
+
let cweDiffSection = '';
|
|
2300
2305
|
if (toolName === 'Edit' || toolName === 'MultiEdit' || toolName === 'edit_file' || toolName === 'reapply' || toolName === 'ApplyPatch' || toolName === 'apply_patch') {
|
|
2301
2306
|
const newStr = toolName === 'Edit' || toolName === 'edit_file' || toolName === 'reapply'
|
|
2302
2307
|
? (toolInput.new_string || '')
|
|
2303
2308
|
: toolName === 'ApplyPatch' || toolName === 'apply_patch'
|
|
2304
2309
|
? (toolInput.patch || toolInput.content || toolInput.code_edit || '')
|
|
2305
2310
|
: (Array.isArray(toolInput.edits) ? toolInput.edits.map((e: any) => e?.new_string || '').join('\n') : '');
|
|
2311
|
+
cweDiffSection = newStr.slice(0, 4000);
|
|
2306
2312
|
const changeIdx = proposed.indexOf(newStr);
|
|
2307
2313
|
if (changeIdx >= 0 && proposed.length > 6000) {
|
|
2308
2314
|
const start = Math.max(0, changeIdx - 2000);
|
|
@@ -2333,14 +2339,28 @@ async function main() {
|
|
|
2333
2339
|
|
|
2334
2340
|
if (rt === 'local') {
|
|
2335
2341
|
let cweRules: any[] = [];
|
|
2342
|
+
let cweRuleFetchFailed = false;
|
|
2336
2343
|
try {
|
|
2337
2344
|
const resp = await fetch(GATEWAY_URL + '/api/v1/cwe-rules?ext=' + encodeURIComponent(fileExt), {
|
|
2338
2345
|
headers: { Authorization: 'Bearer ' + jwt },
|
|
2339
2346
|
signal: AbortSignal.timeout(4000),
|
|
2340
2347
|
});
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2348
|
+
if (!resp.ok) {
|
|
2349
|
+
log('CWE rules fetch failed: HTTP ' + resp.status);
|
|
2350
|
+
cweRuleFetchFailed = true;
|
|
2351
|
+
} else {
|
|
2352
|
+
const data = await resp.json() as any;
|
|
2353
|
+
cweRules = data.rules || [];
|
|
2354
|
+
}
|
|
2355
|
+
} catch (fetchErr: any) {
|
|
2356
|
+
log('CWE rules fetch error: ' + (fetchErr?.message || String(fetchErr)));
|
|
2357
|
+
cweRuleFetchFailed = true;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
if (cweRuleFetchFailed) {
|
|
2361
|
+
outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 CWE rules unavailable \u2014 scan skipped' });
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2344
2364
|
|
|
2345
2365
|
if (cweRules.length === 0) {
|
|
2346
2366
|
outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 clean (no CWE rules for ' + fileExt + ')' });
|
|
@@ -2359,40 +2379,86 @@ async function main() {
|
|
|
2359
2379
|
}
|
|
2360
2380
|
}
|
|
2361
2381
|
|
|
2362
|
-
const
|
|
2363
|
-
'
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2382
|
+
const exemptionNote = exemptedCwes.size > 0
|
|
2383
|
+
? '\n\nEXEMPTED CWEs (already known, DO NOT report these — focus on NEW weaknesses only): ' + [...exemptedCwes].join(', ')
|
|
2384
|
+
: '';
|
|
2385
|
+
|
|
2386
|
+
function buildCwePrompt(content: string): string {
|
|
2387
|
+
const diffBlock = cweDiffSection
|
|
2388
|
+
? '\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'
|
|
2389
|
+
: '';
|
|
2390
|
+
return [
|
|
2391
|
+
'File: ' + filePath,
|
|
2392
|
+
diffBlock,
|
|
2393
|
+
'Full content window:',
|
|
2394
|
+
content,
|
|
2395
|
+
'',
|
|
2396
|
+
'CWE rules to check against:',
|
|
2397
|
+
JSON.stringify(cweRules),
|
|
2398
|
+
].join('\n') + localPkgContext + exemptionNote;
|
|
2378
2399
|
}
|
|
2379
2400
|
|
|
2380
|
-
const
|
|
2401
|
+
const SPLIT_THRESHOLD = 4000;
|
|
2402
|
+
const OVERLAP = 500;
|
|
2403
|
+
let gradeResponses: string[] = [];
|
|
2381
2404
|
|
|
2382
|
-
if (
|
|
2383
|
-
const
|
|
2384
|
-
const
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2405
|
+
if (cweContent.length > SPLIT_THRESHOLD) {
|
|
2406
|
+
const mid = Math.floor(cweContent.length / 2);
|
|
2407
|
+
const chunk1 = cweContent.slice(0, mid + OVERLAP);
|
|
2408
|
+
const chunk2 = cweContent.slice(mid - OVERLAP);
|
|
2409
|
+
try {
|
|
2410
|
+
const [resp1, resp2] = await Promise.all([
|
|
2411
|
+
localGradeCwe(buildCwePrompt(chunk1)),
|
|
2412
|
+
localGradeCwe(buildCwePrompt(chunk2)),
|
|
2413
|
+
]);
|
|
2414
|
+
gradeResponses = [resp1, resp2];
|
|
2415
|
+
} catch (gradeErr: any) {
|
|
2416
|
+
const reason = gradeErr?.message || String(gradeErr);
|
|
2417
|
+
outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 grader unavailable (' + reason + '), skipped' });
|
|
2418
|
+
return;
|
|
2419
|
+
}
|
|
2420
|
+
} else {
|
|
2421
|
+
try {
|
|
2422
|
+
gradeResponses = [await localGradeCwe(buildCwePrompt(cweContent))];
|
|
2423
|
+
} catch (gradeErr: any) {
|
|
2424
|
+
const reason = gradeErr?.message || String(gradeErr);
|
|
2425
|
+
outputJson({ systemMessage: cweTag + ' ' + fileShort + ' \u2192 grader unavailable (' + reason + '), skipped' });
|
|
2426
|
+
return;
|
|
2388
2427
|
}
|
|
2428
|
+
}
|
|
2389
2429
|
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2430
|
+
const cweIds: string[] = [];
|
|
2431
|
+
const fixes: Record<string, string> = {};
|
|
2432
|
+
let mergedReason = '';
|
|
2433
|
+
let mergedSeverity = '';
|
|
2434
|
+
let mergedCategory = '';
|
|
2435
|
+
let anyFailed = false;
|
|
2436
|
+
|
|
2437
|
+
for (const gradeResp of gradeResponses) {
|
|
2438
|
+
const v = parseVerdict(gradeResp);
|
|
2439
|
+
if (!v.ok) {
|
|
2440
|
+
anyFailed = true;
|
|
2441
|
+
if (v.reason) mergedReason = mergedReason || v.reason;
|
|
2442
|
+
if (v.severity) mergedSeverity = mergedSeverity || v.severity;
|
|
2443
|
+
if (v.category) mergedCategory = mergedCategory || v.category;
|
|
2444
|
+
const ruleIdMatches = gradeResp.match(/<rule_id>([^<]+)<\/rule_id>/g) || [];
|
|
2445
|
+
for (const m of ruleIdMatches.slice(0, 5)) {
|
|
2446
|
+
const id = m.replace(/<\/?rule_id>/g, '').trim().replace(/^cwe-/, 'CWE-');
|
|
2447
|
+
if (id && !cweIds.includes(id)) cweIds.push(id);
|
|
2448
|
+
}
|
|
2449
|
+
const fMatches = gradeResp.match(/<suggested_fix>([^<]+)<\/suggested_fix>/g) || [];
|
|
2450
|
+
const respIds = ruleIdMatches.map(rm => rm.replace(/<\/?rule_id>/g, '').trim().replace(/^cwe-/, 'CWE-'));
|
|
2451
|
+
for (let i = 0; i < Math.min(respIds.length, fMatches.length); i++) {
|
|
2452
|
+
if (!fixes[respIds[i]]) fixes[respIds[i]] = fMatches[i].replace(/<\/?suggested_fix>/g, '').trim();
|
|
2453
|
+
}
|
|
2394
2454
|
}
|
|
2455
|
+
}
|
|
2395
2456
|
|
|
2457
|
+
const verdict = anyFailed
|
|
2458
|
+
? { ok: false, reason: mergedReason, severity: mergedSeverity, category: mergedCategory }
|
|
2459
|
+
: { ok: true, reason: '', severity: '', category: '' };
|
|
2460
|
+
|
|
2461
|
+
if (!verdict.ok) {
|
|
2396
2462
|
const activeCweIds = cweIds.filter(id => !exemptedCwes.has(id.toUpperCase()));
|
|
2397
2463
|
|
|
2398
2464
|
if (activeCweIds.length === 0) {
|
|
@@ -2876,7 +2942,7 @@ async function main() {
|
|
|
2876
2942
|
}
|
|
2877
2943
|
}
|
|
2878
2944
|
|
|
2879
|
-
const lastPrompt = readLastPrompt();
|
|
2945
|
+
const lastPrompt = readLastPrompt(sessionId);
|
|
2880
2946
|
|
|
2881
2947
|
const config = await loadConfig(jwt);
|
|
2882
2948
|
const rt = await route(config);
|
|
@@ -3057,7 +3123,7 @@ async function main() {
|
|
|
3057
3123
|
jwt = await ensureFreshJwt(jwt);
|
|
3058
3124
|
|
|
3059
3125
|
const transcript = extractTranscript(transcriptPath);
|
|
3060
|
-
const lastPrompt = readLastPrompt();
|
|
3126
|
+
const lastPrompt = readLastPrompt(sessionId);
|
|
3061
3127
|
|
|
3062
3128
|
const config = await loadConfig(jwt);
|
|
3063
3129
|
const rt = await route(config);
|
|
@@ -3741,8 +3807,14 @@ async function main() {
|
|
|
3741
3807
|
const msg = payload.message || payload.prompt || payload.content || '';
|
|
3742
3808
|
if (msg) {
|
|
3743
3809
|
const promptFile = join(homedir(), '.synkro', '.last-prompt');
|
|
3744
|
-
mkdirSync(dirname(promptFile), { recursive: true });
|
|
3745
|
-
writeFileSync(promptFile, msg, 'utf-8');
|
|
3810
|
+
mkdirSync(dirname(promptFile), { recursive: true, mode: 0o700 });
|
|
3811
|
+
writeFileSync(promptFile, msg, { encoding: 'utf-8', mode: 0o600 });
|
|
3812
|
+
const sid = hookSessionId(payload);
|
|
3813
|
+
if (sid) {
|
|
3814
|
+
const sessDir = join(homedir(), '.synkro', 'sessions');
|
|
3815
|
+
mkdirSync(sessDir, { recursive: true, mode: 0o700 });
|
|
3816
|
+
writeFileSync(join(sessDir, sid + '.last-prompt'), msg, { encoding: 'utf-8', mode: 0o600 });
|
|
3817
|
+
}
|
|
3746
3818
|
}
|
|
3747
3819
|
|
|
3748
3820
|
const sessionId = hookSessionId(payload);
|
|
@@ -3891,7 +3963,7 @@ async function main() {
|
|
|
3891
3963
|
jwt = await ensureFreshJwt(jwt);
|
|
3892
3964
|
|
|
3893
3965
|
const transcript = extractTranscript(transcriptPath);
|
|
3894
|
-
const lastPrompt = readLastPrompt();
|
|
3966
|
+
const lastPrompt = readLastPrompt(sessionId);
|
|
3895
3967
|
|
|
3896
3968
|
const config = await loadConfig(jwt);
|
|
3897
3969
|
if (config.silent) finishAllow();
|
|
@@ -5660,7 +5732,7 @@ function writeConfigEnv(opts) {
|
|
|
5660
5732
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
5661
5733
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
5662
5734
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
5663
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.4.
|
|
5735
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.4.94")}`
|
|
5664
5736
|
];
|
|
5665
5737
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
5666
5738
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -5677,12 +5749,13 @@ function writeConfigEnv(opts) {
|
|
|
5677
5749
|
chmodSync2(CONFIG_PATH2, 384);
|
|
5678
5750
|
}
|
|
5679
5751
|
function resolveDeploymentMode() {
|
|
5680
|
-
const envOverride = process.env.SYNKRO_DEPLOYMENT_MODE;
|
|
5681
|
-
if (envOverride) return envOverride
|
|
5752
|
+
const envOverride = process.env.SYNKRO_DEPLOYMENT_MODE?.toLowerCase();
|
|
5753
|
+
if (envOverride === "bare-host" || envOverride === "docker") return envOverride;
|
|
5682
5754
|
try {
|
|
5683
5755
|
if (existsSync9(CONFIG_PATH2)) {
|
|
5684
5756
|
const m = readFileSync7(CONFIG_PATH2, "utf-8").match(/^SYNKRO_DEPLOYMENT_MODE='([^']*)'/m);
|
|
5685
|
-
|
|
5757
|
+
const val = m?.[1]?.toLowerCase();
|
|
5758
|
+
if (val === "bare-host" || val === "docker") return val;
|
|
5686
5759
|
}
|
|
5687
5760
|
} catch {
|
|
5688
5761
|
}
|
|
@@ -7095,7 +7168,7 @@ var args = process.argv.slice(2);
|
|
|
7095
7168
|
var cmd = args[0] || "";
|
|
7096
7169
|
var subArgs = args.slice(1);
|
|
7097
7170
|
function printVersion() {
|
|
7098
|
-
console.log("1.4.
|
|
7171
|
+
console.log("1.4.94");
|
|
7099
7172
|
}
|
|
7100
7173
|
function printHelp() {
|
|
7101
7174
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|