@synkro-sh/cli 1.6.60 → 1.6.61

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
@@ -1593,6 +1593,13 @@ export async function loadConfig(jwt: string, query?: string): Promise<HookConfi
1593
1593
  export async function route(config: HookConfig, synkroFile?: SynkroFileConfig): Promise<'local' | 'cloud'> {
1594
1594
  const gradingMode = synkroFile?.grader?.mode || process.env.SYNKRO_GRADING_MODE || config.gradingMode || 'local';
1595
1595
  if (gradingMode === 'byok') return 'cloud';
1596
+ // Cloud-container deploy ([grader] location = cloud): grade via localGrade(),
1597
+ // which routes to the hosted container (containers.synkro.sh) and emits the
1598
+ // same rich systemMessage. Return 'local' so the hook takes that branch \u2014 NOT
1599
+ // the legacy BYOK 'cloud' branch (which a non-BYOK org can't use, so it would
1600
+ // silently produce no verdict / no system message). channelUp() is false in
1601
+ // cloud (no local container), so without this it would wrongly fall to 'cloud'.
1602
+ if (process.env.SYNKRO_DEPLOY_LOCATION === 'cloud') return 'local';
1596
1603
  if (config.captureDepth === 'local_only') return 'local';
1597
1604
  if (await channelUp()) return 'local';
1598
1605
  return 'cloud';
@@ -1601,6 +1608,10 @@ export async function route(config: HookConfig, synkroFile?: SynkroFileConfig):
1601
1608
  export async function cweRoute(config: HookConfig, synkroFile?: SynkroFileConfig): Promise<'local' | 'byok' | 'skip'> {
1602
1609
  const gradingMode = synkroFile?.grader?.mode || process.env.SYNKRO_GRADING_MODE || config.gradingMode || 'local';
1603
1610
  if (gradingMode === 'byok') return 'byok';
1611
+ // Cloud-container: CWE scanning runs on the hosted container via localGradeCwe()
1612
+ // (which honors SYNKRO_DEPLOY_LOCATION). Without this, cweChannelUp() is false in
1613
+ // cloud and we'd fall to 'skip' \u2014 silently disabling CWE scanning in cloud mode.
1614
+ if (process.env.SYNKRO_DEPLOY_LOCATION === 'cloud') return 'local';
1604
1615
  if (await cweChannelUp()) return 'local';
1605
1616
  return 'skip';
1606
1617
  }
@@ -5671,7 +5682,8 @@ async function main() {
5671
5682
  const isChannelUp = await channelUp();
5672
5683
  const synkroFile = loadSynkroFile(cwd);
5673
5684
  const gradingMode = synkroFile.grader.mode || process.env.SYNKRO_GRADING_MODE || 'local';
5674
- const rt = gradingMode === 'byok' ? 'cloud' : (isChannelUp ? 'local' : 'cloud');
5685
+ const deployCloud = process.env.SYNKRO_DEPLOY_LOCATION === 'cloud';
5686
+ const rt = gradingMode === 'byok' ? 'cloud' : (isChannelUp || deployCloud ? 'local' : 'cloud');
5675
5687
 
5676
5688
  let policyName = '';
5677
5689
  let silent = false;
@@ -5705,7 +5717,7 @@ async function main() {
5705
5717
 
5706
5718
  const fakeConfig: HookConfig = { captureDepth: 'local_only', tier: 'standard', silent, policyName, rules: [], scanExemptions: [], gradingMode, storageMode: process.env.SYNKRO_STORAGE_MODE || 'local' };
5707
5719
  const tagStr = tag(rt, fakeConfig);
5708
- const routeLine = tagStr + ' inference: ' + (gradingMode === 'byok' ? 'cloud (BYOK)' : isChannelUp ? 'local-cc (channel reachable on 127.0.0.1:18929)' : 'cloud (local-cc channel not reachable)');
5720
+ const routeLine = tagStr + ' inference: ' + (gradingMode === 'byok' ? 'cloud (BYOK)' : deployCloud ? 'cloud container (containers.synkro.sh)' : isChannelUp ? 'local-cc (channel reachable on 127.0.0.1:18929)' : 'cloud (local-cc channel not reachable)');
5709
5721
 
5710
5722
  if (!jwt) {
5711
5723
  outputJson({ systemMessage: routeLine });
@@ -10305,7 +10317,7 @@ function writeConfigEnv(opts) {
10305
10317
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
10306
10318
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
10307
10319
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
10308
- `SYNKRO_VERSION=${shellQuoteSingle("1.6.60")}`
10320
+ `SYNKRO_VERSION=${shellQuoteSingle("1.6.61")}`
10309
10321
  ];
10310
10322
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
10311
10323
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -10373,6 +10385,52 @@ async function provisionCloudContainer(opts) {
10373
10385
  setupToken = "";
10374
10386
  }
10375
10387
  }
10388
+ async function verifyCloudGrader(jwt2) {
10389
+ const base = (process.env.SYNKRO_CONTAINERS_URL || "https://containers.synkro.sh").replace(/\/$/, "");
10390
+ console.log(" Warming the cloud grader (booting container + checking workers)...");
10391
+ const deadline = Date.now() + 18e4;
10392
+ let healthy = 0;
10393
+ while (Date.now() < deadline) {
10394
+ try {
10395
+ const r = await fetch(`${base}/diag`, { headers: { Authorization: `Bearer ${jwt2}` }, signal: AbortSignal.timeout(6e4) });
10396
+ if (r.ok) {
10397
+ const j = await r.json();
10398
+ healthy = j.claude_code?.healthy ?? 0;
10399
+ if (healthy >= 1) break;
10400
+ }
10401
+ } catch {
10402
+ }
10403
+ await new Promise((res) => setTimeout(res, 5e3));
10404
+ }
10405
+ if (healthy < 1) {
10406
+ console.warn(" \u26A0 cloud grader did not report a healthy worker within ~3m.");
10407
+ console.warn(" Grading is NOT verified \u2014 check the container or re-run `synkro install`.\n");
10408
+ return false;
10409
+ }
10410
+ console.log(` \u2713 ${healthy} Claude worker(s) healthy`);
10411
+ try {
10412
+ const probe = 'Grade this edit. File: t.py. Change: os.system(request.args["cmd"])';
10413
+ const r = await fetch(`${base}/grade/submit`, {
10414
+ method: "POST",
10415
+ headers: { Authorization: `Bearer ${jwt2}`, "Content-Type": "application/json" },
10416
+ body: JSON.stringify({ role: "grade-edit", payload: probe, content: probe, agent_kind: "claude_code" }),
10417
+ signal: AbortSignal.timeout(12e4)
10418
+ });
10419
+ const body = await r.json().catch(() => ({}));
10420
+ if (r.ok && typeof body.result === "string" && body.result.includes("<synkro-verdict>")) {
10421
+ console.log(" \u2713 smoke grade passed \u2014 cloud grading is live\n");
10422
+ return true;
10423
+ }
10424
+ console.warn(` \u26A0 smoke grade did not return a verdict (HTTP ${r.status}).`);
10425
+ console.warn(" The container is provisioned but grading is not healthy \u2014 likely the Claude");
10426
+ console.warn(" setup-token. Re-run `synkro install` to re-authorize the hosted worker.\n");
10427
+ return false;
10428
+ } catch {
10429
+ console.warn(" \u26A0 smoke grade timed out / connection dropped \u2014 grading is not responding.");
10430
+ console.warn(" The container is provisioned but not grading; re-run `synkro install`.\n");
10431
+ return false;
10432
+ }
10433
+ }
10376
10434
  function readPersistedDeployLocation() {
10377
10435
  try {
10378
10436
  if (existsSync11(CONFIG_PATH2)) {
@@ -10483,6 +10541,7 @@ synkro.toml: deploy location changed ${current} \u2192 ${desired}
10483
10541
  await provisionCloudContainer({ gatewayUrl, jwt: token, orgId, userId, email, hasClaudeCode, hasCursor });
10484
10542
  updateConfigEnvLocation("cloud");
10485
10543
  await applyMcpConfig({ gatewayUrl, jwt: token, hasClaudeCode, hasCursor, local: false });
10544
+ await verifyCloudGrader(token);
10486
10545
  console.log(" \u2713 grading + rules/MCP now served from Synkro Cloud\n");
10487
10546
  } else {
10488
10547
  updateConfigEnvLocation("local");
@@ -10996,6 +11055,7 @@ async function installCommand(opts = {}) {
10996
11055
  console.log();
10997
11056
  } else if (target === "cloud-container") {
10998
11057
  await provisionCloudContainer({ gatewayUrl, jwt: token, orgId, userId, email, hasClaudeCode, hasCursor });
11058
+ await verifyCloudGrader(token);
10999
11059
  }
11000
11060
  if (transcriptConsent) {
11001
11061
  const repo = detectGitRepo2();
@@ -13753,7 +13813,7 @@ var args = process.argv.slice(2);
13753
13813
  var cmd = args[0] || "";
13754
13814
  var subArgs = args.slice(1);
13755
13815
  function printVersion() {
13756
- console.log("1.6.60");
13816
+ console.log("1.6.61");
13757
13817
  }
13758
13818
  function printHelp2() {
13759
13819
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents