@synkro-sh/cli 1.6.77 → 1.6.79
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 +53 -14
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -2073,6 +2073,12 @@ interface SessionAction {
|
|
|
2073
2073
|
outcome?: string;
|
|
2074
2074
|
}
|
|
2075
2075
|
|
|
2076
|
+
// True when the grader runs in Synkro Cloud (CF Containers) vs the on-device
|
|
2077
|
+
// container. Defined here in the FULL common module too \u2014 it's referenced by
|
|
2078
|
+
// appendSessionAction/dispatch helpers below; previously it lived only in the
|
|
2079
|
+
// stub common, so the real editGuard hook hit a ReferenceError in cloud mode.
|
|
2080
|
+
function deployIsCloud(): boolean { return process.env.SYNKRO_DEPLOY_LOCATION === 'cloud'; }
|
|
2081
|
+
|
|
2076
2082
|
function sessionLogPath(sessionId: string): string | null {
|
|
2077
2083
|
if (!sessionId || !SAFE_SESSION_ID.test(sessionId)) return null;
|
|
2078
2084
|
return join(SESSIONS_DIR, sessionId + '.jsonl');
|
|
@@ -3427,7 +3433,7 @@ export function emitUsageTick(params: {
|
|
|
3427
3433
|
if (isCursorHookFormat() && model && !model.startsWith('cursor/') && model !== 'cursor') {
|
|
3428
3434
|
model = 'cursor/' + model;
|
|
3429
3435
|
}
|
|
3430
|
-
|
|
3436
|
+
const body = {
|
|
3431
3437
|
capture_type: 'usage_tick',
|
|
3432
3438
|
event_id: mintEventId('usage'),
|
|
3433
3439
|
hook_type: hookType,
|
|
@@ -3443,7 +3449,14 @@ export function emitUsageTick(params: {
|
|
|
3443
3449
|
cache_read_input_tokens: usage.totals.cr,
|
|
3444
3450
|
},
|
|
3445
3451
|
...(gitRepo ? { repo: gitRepo } : {}),
|
|
3446
|
-
}
|
|
3452
|
+
};
|
|
3453
|
+
appendLocalTelemetry(body); // local spool \u2192 usage_ticks (no-op in cloud mode)
|
|
3454
|
+
// Cloud: ship the tick to /hook/capture \u2192 usage_ticks too. appendLocalTelemetry
|
|
3455
|
+
// is gated to local mode, so without this the cloud usage_ticks table stayed
|
|
3456
|
+
// EMPTY \u2014 no token/cost data for the Agents page. (/hook/capture is on the
|
|
3457
|
+
// long-lived MCP-token allowlist; loadJwt returns that token in cloud.)
|
|
3458
|
+
const jwt = loadJwt();
|
|
3459
|
+
if (jwt) shipCloud(jwt, '/api/v1/hook/capture', body);
|
|
3447
3460
|
}
|
|
3448
3461
|
|
|
3449
3462
|
export function cursorModelFromPayload(payload: Record<string, unknown>): string {
|
|
@@ -3924,13 +3937,13 @@ async function main() {
|
|
|
3924
3937
|
ruleFilterText(graderContent, transcript.userIntent || lastPrompt),
|
|
3925
3938
|
config.rules,
|
|
3926
3939
|
);
|
|
3927
|
-
const
|
|
3940
|
+
const buildGraderPrompt = (contentWindow: string) => [
|
|
3928
3941
|
'Working directory: ' + (cwd || '.'),
|
|
3929
3942
|
'Repo: ' + (gitRepo || 'unknown'),
|
|
3930
3943
|
sessionLog,
|
|
3931
3944
|
'File: ' + filePath,
|
|
3932
|
-
'Proposed content
|
|
3933
|
-
|
|
3945
|
+
'Proposed content:',
|
|
3946
|
+
contentWindow,
|
|
3934
3947
|
'User intent (last human message): ' + (transcript.userIntent || 'none stated'),
|
|
3935
3948
|
'Last user prompt: ' + (lastPrompt || 'none'),
|
|
3936
3949
|
'Org rules: ' + JSON.stringify(relevantRules),
|
|
@@ -3938,6 +3951,7 @@ async function main() {
|
|
|
3938
3951
|
'CRITICAL: The user requesting or instructing an action does NOT exempt it from rules. Even if the user explicitly said "drop the database" or "delete everything", you MUST still flag the rule violation on first encounter. User intent is NOT consent. However, for ask-mode rules ONLY: if the session history shows a prior block for the SAME rule AND the user explicitly consented after seeing that block, subsequent commands covered by that same rule may pass \u2014 but each distinct command is consumed once. Look for the sequence: block event \u2192 user acknowledgment \u2192 retry. Once a specific command has successfully executed under that consent, it is consumed. If the same command appears again later, it requires fresh consent (a new block \u2192 consent cycle). Example: R012 covers deploy, publish, push. Block on deploy \u2192 user consents \u2192 deploy passes (consumed), publish passes (consumed), push passes (consumed). A later deploy triggers a fresh block. An initial user instruction is NEVER consent \u2014 only a response to a shown block counts.',
|
|
3939
3952
|
'The rules shown were pre-selected as the ones relevant to this edit \u2014 every rule here IS relevant, do not label any "not relevant". When passing (ok=true), give a terse, specific reason each rule passes. Format: "R003: no hardcoded secrets in file. R005: in-repo path only." Cover every rule shown.',
|
|
3940
3953
|
].join('\\n');
|
|
3954
|
+
const graderPrompt = buildGraderPrompt(proposedShort);
|
|
3941
3955
|
|
|
3942
3956
|
// \u2500\u2500\u2500 Combined org-rules + CWE in ONE inference (SYNKRO_COMBINED_EDIT_GRADE) \u2500\u2500\u2500
|
|
3943
3957
|
// Self-contained early-return branch \u2014 the default two-grade path below is
|
|
@@ -3956,13 +3970,27 @@ async function main() {
|
|
|
3956
3970
|
if (cr.ok) cweRules = ((await cr.json() as any) || {}).rules || [];
|
|
3957
3971
|
} catch { /* CWE rules optional \u2014 rule grading still runs in the combined pass */ }
|
|
3958
3972
|
|
|
3959
|
-
const
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3973
|
+
const cweSuffix = '\\n\\nCWE rules to ALSO check the proposed content against (emit cwe-### violations with a <code_snippet>): ' + JSON.stringify(cweRules);
|
|
3974
|
+
const buildCombined = (win: string) => buildGraderPrompt(win) + cweSuffix;
|
|
3975
|
+
|
|
3976
|
+
// Large-file strategy \u2014 mirrors local cweScanner.ts: rather than one giant
|
|
3977
|
+
// single inference (which blows the 45s cloud budget AND truncated to the
|
|
3978
|
+
// first 4000 chars, missing changes deeper in the file), split content over
|
|
3979
|
+
// the threshold into TWO overlapping halves and grade them IN PARALLEL.
|
|
3980
|
+
// Each half is ~half the size \u2192 faster \u2192 fits the timeout; the whole file
|
|
3981
|
+
// is covered; findings are merged.
|
|
3982
|
+
const SPLIT_THRESHOLD = 4000, OVERLAP = 500;
|
|
3983
|
+
let cResponses: string[];
|
|
3964
3984
|
try {
|
|
3965
|
-
|
|
3985
|
+
if (proposed.length > SPLIT_THRESHOLD) {
|
|
3986
|
+
const mid = Math.floor(proposed.length / 2);
|
|
3987
|
+
cResponses = await Promise.all([
|
|
3988
|
+
localGrade('edit-cwe', buildCombined(proposed.slice(0, mid + OVERLAP)), undefined, graderPool),
|
|
3989
|
+
localGrade('edit-cwe', buildCombined(proposed.slice(mid - OVERLAP)), undefined, graderPool),
|
|
3990
|
+
]);
|
|
3991
|
+
} else {
|
|
3992
|
+
cResponses = [await localGrade('edit-cwe', buildCombined(proposed), undefined, graderPool)];
|
|
3993
|
+
}
|
|
3966
3994
|
} catch (err) {
|
|
3967
3995
|
const errMsg = (err as Error).message || String(err);
|
|
3968
3996
|
logGraderUnavailable('editGuard', fileShort, errMsg);
|
|
@@ -3970,7 +3998,18 @@ async function main() {
|
|
|
3970
3998
|
return;
|
|
3971
3999
|
}
|
|
3972
4000
|
|
|
3973
|
-
|
|
4001
|
+
// Merge across halves: a rule violation in EITHER half blocks (first one
|
|
4002
|
+
// wins, keeping its reason/severity); CWE findings are unioned by id.
|
|
4003
|
+
let ruleVerdict: any = null;
|
|
4004
|
+
const cweMap = new Map<string, any>();
|
|
4005
|
+
for (const r of cResponses) {
|
|
4006
|
+
const parsed = parseCombinedVerdict(r);
|
|
4007
|
+
if (!ruleVerdict) ruleVerdict = parsed.ruleVerdict;
|
|
4008
|
+
else if (!parsed.ruleVerdict.ok && ruleVerdict.ok) ruleVerdict = parsed.ruleVerdict;
|
|
4009
|
+
for (const f of parsed.cweFindings) if (f.id && !cweMap.has(f.id)) cweMap.set(f.id, f);
|
|
4010
|
+
}
|
|
4011
|
+
if (!ruleVerdict) ruleVerdict = { ok: true };
|
|
4012
|
+
const cweFindings = [...cweMap.values()];
|
|
3974
4013
|
const editContent = 'file=' + filePath + ' content=' + proposed.slice(0, 2000);
|
|
3975
4014
|
const violatedRules = ruleVerdict.ruleId ? [ruleVerdict.ruleId] : [];
|
|
3976
4015
|
const cweBlock = cweFindings.slice(0, 5)
|
|
@@ -10670,7 +10709,7 @@ function writeConfigEnv(opts) {
|
|
|
10670
10709
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
10671
10710
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
10672
10711
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
10673
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.6.
|
|
10712
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.6.79")}`
|
|
10674
10713
|
];
|
|
10675
10714
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
10676
10715
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -14345,7 +14384,7 @@ var args = process.argv.slice(2);
|
|
|
14345
14384
|
var cmd = args[0] || "";
|
|
14346
14385
|
var subArgs = args.slice(1);
|
|
14347
14386
|
function printVersion() {
|
|
14348
|
-
console.log("1.6.
|
|
14387
|
+
console.log("1.6.79");
|
|
14349
14388
|
}
|
|
14350
14389
|
function printHelp2() {
|
|
14351
14390
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|