@synkro-sh/cli 1.6.91 → 1.6.92

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
@@ -1415,8 +1415,19 @@ export function loadSynkroFile(cwd?: string): SynkroFileConfig {
1415
1415
  }
1416
1416
  }
1417
1417
 
1418
- export function effectiveGraderPool(synkroFile: SynkroFileConfig, hookAgentKind: AgentKind): AgentKind {
1419
- const pool = normalizePoolToken(synkroFile.grader.pool);
1418
+ export function effectiveGraderPool(synkroFile: SynkroFileConfig, hookAgentKind: AgentKind, config?: HookConfig): AgentKind {
1419
+ // Source of truth for the pool SPLIT depends on grading location:
1420
+ // \u2022 cloud / byok \u2192 SERVER-managed (the user's dashboard choice, delivered as
1421
+ // config.graderPool from /v1/hook/config). synkro.toml isn't even written
1422
+ // for cloud installs, so it can't be the source there.
1423
+ // \u2022 local \u2192 synkro.toml [grader] pool (on-device, user-owned).
1424
+ // Falls back to synkro.toml whenever the server pool is absent, so a missing
1425
+ // value never breaks grading \u2014 it just reverts to today's behavior.
1426
+ const managed = process.env.SYNKRO_DEPLOY_LOCATION === 'cloud'
1427
+ || (process.env.SYNKRO_GRADING_MODE || synkroFile.grader?.mode || config?.gradingMode) === 'byok';
1428
+ const pool = (managed && config?.graderPool)
1429
+ ? normalizePoolToken(config.graderPool)
1430
+ : normalizePoolToken(synkroFile.grader.pool);
1420
1431
  if (pool === 'auto') return hookAgentKind;
1421
1432
  if (pool === 'claude') return 'claude_code';
1422
1433
  return 'cursor';
@@ -1517,6 +1528,11 @@ export interface HookConfig {
1517
1528
  // value from /v1/hook/config is only a fallback when the env var is unset.
1518
1529
  gradingMode: string;
1519
1530
  storageMode: string;
1531
+ // Server-managed pool SPLIT (auto | claude | cursor) + canonical grading
1532
+ // location, from /v1/hook/config. Authoritative ONLY for cloud/byok grading
1533
+ // (synkro.toml governs local). Undefined when the gateway didn't report one.
1534
+ graderPool?: string;
1535
+ inferenceMode?: string;
1520
1536
  }
1521
1537
 
1522
1538
  /** True when telemetry + rules must stay on-machine (PGLite). Default: local. */
@@ -1597,6 +1613,9 @@ export async function loadConfig(jwt: string, query?: string): Promise<HookConfi
1597
1613
  config.silent = data.silent_mode === true || data.silent_mode === 'true';
1598
1614
  if (!process.env.SYNKRO_GRADING_MODE && data.grading_mode) config.gradingMode = data.grading_mode;
1599
1615
  if (!process.env.SYNKRO_STORAGE_MODE && data.storage_mode) config.storageMode = data.storage_mode;
1616
+ // Server-managed pool split + location (cloud/byok only \u2014 see effectiveGraderPool).
1617
+ if (data.grader_pool) config.graderPool = data.grader_pool;
1618
+ if (data.inference_mode) config.inferenceMode = data.inference_mode;
1600
1619
  config.policyName = data.active_policy_name || '';
1601
1620
  if (Array.isArray(data.scan_exemptions)) {
1602
1621
  config.scanExemptions = data.scan_exemptions
@@ -4364,7 +4383,7 @@ async function main() {
4364
4383
  // Load config and decide route
4365
4384
  const config = await loadConfig(jwt);
4366
4385
  const synkroFile = loadSynkroFile(cwd);
4367
- const graderPool = effectiveGraderPool(synkroFile, agentKind);
4386
+ const graderPool = effectiveGraderPool(synkroFile, agentKind, config);
4368
4387
  const rt = await route(config, synkroFile);
4369
4388
  const tagStr = tag(rt, config, graderPool);
4370
4389
 
@@ -4858,7 +4877,7 @@ async function main() {
4858
4877
 
4859
4878
  const config = await loadConfig(jwt);
4860
4879
  const synkroFile = loadSynkroFile(cwd);
4861
- const graderPool = effectiveGraderPool(synkroFile, agentKind);
4880
+ const graderPool = effectiveGraderPool(synkroFile, agentKind, config);
4862
4881
  const rt = await cweRoute(config, synkroFile);
4863
4882
 
4864
4883
  // Combined-grade mode: the edit-precheck hook runs CWE inside its single
@@ -5586,7 +5605,7 @@ async function main() {
5586
5605
  const config = await loadConfig(jwt);
5587
5606
  const isCursor = isCursorHookFormat();
5588
5607
  const synkroFile = loadSynkroFile(cwd);
5589
- const graderPool = effectiveGraderPool(synkroFile, isCursor ? 'cursor' : 'claude_code');
5608
+ const graderPool = effectiveGraderPool(synkroFile, isCursor ? 'cursor' : 'claude_code', config);
5590
5609
  const rt = await route(config, synkroFile);
5591
5610
  const tagStr = tag(rt, config, graderPool);
5592
5611
 
@@ -5768,7 +5787,7 @@ async function main() {
5768
5787
 
5769
5788
  const config = await loadConfig(jwt);
5770
5789
  const synkroFile = loadSynkroFile(cwd);
5771
- const graderPool = effectiveGraderPool(synkroFile, 'claude_code');
5790
+ const graderPool = effectiveGraderPool(synkroFile, 'claude_code', config);
5772
5791
  const rt = await route(config, synkroFile);
5773
5792
  const tagStr = tag(rt, config, graderPool);
5774
5793
 
@@ -6058,7 +6077,7 @@ async function main() {
6058
6077
 
6059
6078
  const config = await loadConfig(jwt);
6060
6079
  const synkroFile = loadSynkroFile(cwd);
6061
- const graderPool = effectiveGraderPool(synkroFile, agentKind);
6080
+ const graderPool = effectiveGraderPool(synkroFile, agentKind, config);
6062
6081
  const rt = await route(config, synkroFile);
6063
6082
  const tagStr = tag(rt, config, graderPool);
6064
6083
 
@@ -6277,7 +6296,7 @@ async function main() {
6277
6296
 
6278
6297
  const config = await loadConfig(jwt);
6279
6298
  const synkroFile = loadSynkroFile(cwd);
6280
- const graderPool = effectiveGraderPool(synkroFile, agentKind);
6299
+ const graderPool = effectiveGraderPool(synkroFile, agentKind, config);
6281
6300
  const rt = await route(config, synkroFile);
6282
6301
  const tagStr = tag(rt, config, graderPool);
6283
6302
 
@@ -6513,12 +6532,15 @@ async function main() {
6513
6532
  return;
6514
6533
  }
6515
6534
 
6516
- // Sync grading mode to API profile so the dashboard reflects the actual config
6517
- const fastInference = gradingMode === 'byok';
6535
+ // Sync the canonical 3-state grading location to the API profile so the
6536
+ // dashboard reflects the machine's ACTUAL config. byok (own API key) wins;
6537
+ // else the cloud worker pool; else on-device workers. The API derives the
6538
+ // legacy fast_inference boolean from this, so we only send one field.
6539
+ const inferenceMode = gradingMode === 'byok' ? 'byok' : (deployCloud ? 'cloud' : 'local');
6518
6540
  fetch(GATEWAY_URL + '/api/v1/cli/me', {
6519
6541
  method: 'PATCH',
6520
6542
  headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + jwt },
6521
- body: JSON.stringify({ fast_inference: fastInference }),
6543
+ body: JSON.stringify({ inference_mode: inferenceMode }),
6522
6544
  signal: AbortSignal.timeout(3000),
6523
6545
  }).catch(() => {});
6524
6546
 
@@ -6873,7 +6895,7 @@ async function main() {
6873
6895
  if (config.silent) finishAllow();
6874
6896
 
6875
6897
  const synkroFile = loadSynkroFile(cwd);
6876
- const graderPool = effectiveGraderPool(synkroFile, 'cursor');
6898
+ const graderPool = effectiveGraderPool(synkroFile, 'cursor', config);
6877
6899
  const rt = await route(config, synkroFile);
6878
6900
  const tagStr = tag(rt, config, graderPool);
6879
6901
 
@@ -11208,7 +11230,7 @@ function writeConfigEnv(opts) {
11208
11230
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
11209
11231
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
11210
11232
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
11211
- `SYNKRO_VERSION=${shellQuoteSingle("1.6.91")}`
11233
+ `SYNKRO_VERSION=${shellQuoteSingle("1.6.92")}`
11212
11234
  ];
11213
11235
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
11214
11236
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -15115,6 +15137,11 @@ function updateConfigValue(key, value) {
15115
15137
  if (!found) updated.splice(updated.length - 1, 0, `${key}='${value}'`);
15116
15138
  writeFileSync13(CONFIG_PATH6, updated.join("\n"), "utf-8");
15117
15139
  }
15140
+ function resolveInferenceMode(cfg) {
15141
+ if ((cfg.SYNKRO_GRADING_MODE || "local") === "byok") return "byok";
15142
+ if (cfg.SYNKRO_DEPLOY_LOCATION === "cloud") return "cloud";
15143
+ return "local";
15144
+ }
15118
15145
  async function reconcileContainer() {
15119
15146
  const cfg = readConfigEnv2();
15120
15147
  const cloudOnly = (cfg.SYNKRO_GRADING_MODE || "local") === "byok" && (cfg.SYNKRO_STORAGE_MODE || "local") === "cloud";
@@ -15142,17 +15169,18 @@ async function configCommand(args2) {
15142
15169
  if (args2.length === 0) {
15143
15170
  const config2 = readConfigEnv2();
15144
15171
  console.log("Synkro config:\n");
15145
- console.log(` grading: ${config2.SYNKRO_GRADING_MODE || "local"}`);
15172
+ console.log(` inference: ${resolveInferenceMode(config2)}`);
15146
15173
  console.log(` storage: ${config2.SYNKRO_STORAGE_MODE || "local"}`);
15147
- console.log(` inference: ${config2.SYNKRO_INFERENCE || "fast"}`);
15148
15174
  console.log(` tier: ${config2.SYNKRO_TIER || "pro"}`);
15149
15175
  console.log(` gateway: ${config2.SYNKRO_GATEWAY_URL || "https://api.synkro.sh"}`);
15150
15176
  console.log(` version: ${config2.SYNKRO_VERSION || "?"}`);
15151
15177
  console.log(`
15152
15178
  To change:`);
15153
- console.log(` synkro config grading <local|byok> \u2014 where grading runs`);
15154
- console.log(` synkro config storage <local|cloud> \u2014 where telemetry is stored`);
15155
- console.log(` synkro config --inference fast|standard`);
15179
+ console.log(` synkro config --inference <local|cloud|byok> \u2014 where grading runs`);
15180
+ console.log(` local \u2014 Claude/Cursor workers on this machine (your subscription)`);
15181
+ console.log(` cloud \u2014 Claude/Cursor workers in the Synkro cloud pool`);
15182
+ console.log(` byok \u2014 graded via your own provider API key`);
15183
+ console.log(` synkro config storage <local|cloud> \u2014 where telemetry is stored`);
15156
15184
  return;
15157
15185
  }
15158
15186
  if (args2[0] === "grading") {
@@ -15186,8 +15214,8 @@ To change:`);
15186
15214
  if (a.startsWith("--inference=")) inferenceValue = a.slice("--inference=".length);
15187
15215
  else if (a === "--inference" && args2.indexOf(a) + 1 < args2.length) inferenceValue = args2[args2.indexOf(a) + 1];
15188
15216
  }
15189
- if (!inferenceValue || !["fast", "standard"].includes(inferenceValue)) {
15190
- console.error("Usage: synkro config --inference fast|standard");
15217
+ if (!inferenceValue || !["local", "cloud", "byok"].includes(inferenceValue)) {
15218
+ console.error("Usage: synkro config --inference <local|cloud|byok>");
15191
15219
  process.exit(1);
15192
15220
  }
15193
15221
  if (!isAuthenticated()) {
@@ -15204,7 +15232,7 @@ To change:`);
15204
15232
  "Authorization": `Bearer ${token}`,
15205
15233
  "Content-Type": "application/json"
15206
15234
  },
15207
- body: JSON.stringify({ fast_inference: inferenceValue === "fast" })
15235
+ body: JSON.stringify({ inference_mode: inferenceValue })
15208
15236
  });
15209
15237
  if (!resp.ok) {
15210
15238
  const errText = await resp.text().catch(() => "");
@@ -15215,8 +15243,24 @@ To change:`);
15215
15243
  console.error(`Failed to reach server: ${err.message}`);
15216
15244
  process.exit(1);
15217
15245
  }
15218
- updateConfigValue("SYNKRO_INFERENCE", inferenceValue);
15246
+ if (inferenceValue === "byok") {
15247
+ updateConfigValue("SYNKRO_GRADING_MODE", "byok");
15248
+ updateConfigValue("SYNKRO_DEPLOY_LOCATION", "local");
15249
+ } else if (inferenceValue === "cloud") {
15250
+ updateConfigValue("SYNKRO_GRADING_MODE", "local");
15251
+ updateConfigValue("SYNKRO_DEPLOY_LOCATION", "cloud");
15252
+ } else {
15253
+ updateConfigValue("SYNKRO_GRADING_MODE", "local");
15254
+ updateConfigValue("SYNKRO_DEPLOY_LOCATION", "local");
15255
+ }
15219
15256
  console.log(`\u2713 Inference set to '${inferenceValue}'.`);
15257
+ if (inferenceValue === "byok") {
15258
+ console.log(" BYOK grading uses your own provider key \u2014 register one in the");
15259
+ console.log(" dashboard under Settings \u2192 Provider Keys if you have not already.");
15260
+ } else if (inferenceValue === "cloud") {
15261
+ console.log(" Grading runs on the Synkro cloud worker pool (containers.synkro.sh).");
15262
+ }
15263
+ if (inferenceValue !== "cloud") await reconcileContainer();
15220
15264
  }
15221
15265
  var SYNKRO_DIR7, CONFIG_PATH6;
15222
15266
  var init_config = __esm({
@@ -15251,7 +15295,7 @@ var args = process.argv.slice(2);
15251
15295
  var cmd = args[0] || "";
15252
15296
  var subArgs = args.slice(1);
15253
15297
  function printVersion() {
15254
- console.log("1.6.91");
15298
+ console.log("1.6.92");
15255
15299
  }
15256
15300
  function printHelp2() {
15257
15301
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents