@synkro-sh/cli 1.6.50 → 1.6.51
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 +99 -38
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -1239,6 +1239,29 @@ function parseSynkroYaml(raw: string): Record<string, any> {
|
|
|
1239
1239
|
|
|
1240
1240
|
let _synkroFileCache: SynkroFileConfig | undefined;
|
|
1241
1241
|
|
|
1242
|
+
/** Map any provider alias to the internal pool token. */
|
|
1243
|
+
function normalizePoolToken(p: unknown): 'auto' | 'claude' | 'cursor' {
|
|
1244
|
+
if (p === 'cursor') return 'cursor';
|
|
1245
|
+
if (p === 'claude' || p === 'claude-code' || p === 'cc' || p === 'claude_code') return 'claude';
|
|
1246
|
+
return 'auto';
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
/**
|
|
1250
|
+
* Pull an explicit worker count for a provider, accepting both the unified
|
|
1251
|
+
* grader-block form (grader: claude-code: N) and the legacy workers block
|
|
1252
|
+
* (workers: claude: N). Provider aliases (claude / claude-code / cc) all match.
|
|
1253
|
+
*/
|
|
1254
|
+
function pickWorkerCount(parsed: any, kind: 'claude_code' | 'cursor'): number | undefined {
|
|
1255
|
+
const keys = kind === 'cursor' ? ['cursor'] : ['claude-code', 'claude', 'cc', 'claude_code'];
|
|
1256
|
+
for (const src of [parsed?.grader, parsed?.workers]) {
|
|
1257
|
+
if (!src || typeof src !== 'object') continue;
|
|
1258
|
+
for (const k of keys) {
|
|
1259
|
+
if (typeof src[k] === 'number') return Math.max(0, Math.floor(src[k]));
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
return undefined;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1242
1265
|
export function loadSynkroFile(cwd?: string): SynkroFileConfig {
|
|
1243
1266
|
if (_synkroFileCache) return _synkroFileCache;
|
|
1244
1267
|
const root = cwd ? findGitRoot(cwd) : '';
|
|
@@ -1256,12 +1279,14 @@ export function loadSynkroFile(cwd?: string): SynkroFileConfig {
|
|
|
1256
1279
|
version: parsed.version || 1,
|
|
1257
1280
|
harness: harness.length > 0 ? harness : ['claude-code', 'cursor'],
|
|
1258
1281
|
grader: {
|
|
1259
|
-
pool:
|
|
1282
|
+
pool: normalizePoolToken(parsed.grader?.pool),
|
|
1260
1283
|
mode: ['local', 'byok'].includes(parsed.grader?.mode) ? parsed.grader.mode : undefined,
|
|
1261
1284
|
},
|
|
1262
1285
|
workers: {
|
|
1263
|
-
|
|
1264
|
-
|
|
1286
|
+
// Counts may live under the grader block (unified form) or the legacy
|
|
1287
|
+
// workers block, keyed by claude / claude-code / cc / cursor.
|
|
1288
|
+
...(pickWorkerCount(parsed, 'claude_code') != null ? { claude: pickWorkerCount(parsed, 'claude_code') } : {}),
|
|
1289
|
+
...(pickWorkerCount(parsed, 'cursor') != null ? { cursor: pickWorkerCount(parsed, 'cursor') } : {}),
|
|
1265
1290
|
},
|
|
1266
1291
|
ruleset: typeof parsed.ruleset === 'string' ? parsed.ruleset : 'default',
|
|
1267
1292
|
skills: Array.isArray(parsed.skills) ? parsed.skills.filter((s: unknown) => typeof s === 'string') : [],
|
|
@@ -1278,8 +1303,9 @@ export function loadSynkroFile(cwd?: string): SynkroFileConfig {
|
|
|
1278
1303
|
}
|
|
1279
1304
|
|
|
1280
1305
|
export function effectiveGraderPool(synkroFile: SynkroFileConfig, hookAgentKind: AgentKind): AgentKind {
|
|
1281
|
-
|
|
1282
|
-
if (
|
|
1306
|
+
const pool = normalizePoolToken(synkroFile.grader.pool);
|
|
1307
|
+
if (pool === 'auto') return hookAgentKind;
|
|
1308
|
+
if (pool === 'claude') return 'claude_code';
|
|
1283
1309
|
return 'cursor';
|
|
1284
1310
|
}
|
|
1285
1311
|
|
|
@@ -1294,7 +1320,16 @@ export function synkroFilePresent(cwd?: string): boolean {
|
|
|
1294
1320
|
try {
|
|
1295
1321
|
const root = cwd ? findGitRoot(cwd) : '';
|
|
1296
1322
|
if (!root) return false;
|
|
1297
|
-
|
|
1323
|
+
// ~/.synkro is Synkro's CONFIG DIRECTORY, not a repo marker. If the git root
|
|
1324
|
+
// resolves to HOME (dotfiles tracked in git, or working in a non-git folder
|
|
1325
|
+
// under ~), never treat it as onboarded \u2014 otherwise grading fires in every
|
|
1326
|
+
// directory under home.
|
|
1327
|
+
if (root === HOME) return false;
|
|
1328
|
+
// A repo is onboarded ONLY via a regular .synkro FILE at its root. statSync +
|
|
1329
|
+
// isFile is required because existsSync also matches a DIRECTORY named
|
|
1330
|
+
// .synkro (exactly what ~/.synkro is) \u2014 the root cause of grading running in
|
|
1331
|
+
// repos that have no .synkro file.
|
|
1332
|
+
return statSync(root + '/.synkro').isFile();
|
|
1298
1333
|
} catch { return false; }
|
|
1299
1334
|
}
|
|
1300
1335
|
|
|
@@ -7396,7 +7431,10 @@ __export(dockerInstall_exports, {
|
|
|
7396
7431
|
dockerStop: () => dockerStop,
|
|
7397
7432
|
dockerUpdate: () => dockerUpdate,
|
|
7398
7433
|
imageTag: () => imageTag,
|
|
7434
|
+
normalizeProvider: () => normalizeProvider,
|
|
7435
|
+
poolLabel: () => poolLabel,
|
|
7399
7436
|
readContainerConfig: () => readContainerConfig,
|
|
7437
|
+
resolveGraderPool: () => resolveGraderPool,
|
|
7400
7438
|
resolveWorkerConfig: () => resolveWorkerConfig,
|
|
7401
7439
|
splitWorkers: () => splitWorkers,
|
|
7402
7440
|
waitForContainerReady: () => waitForContainerReady,
|
|
@@ -7423,6 +7461,39 @@ function normalizeProvider(p) {
|
|
|
7423
7461
|
if (v === "cursor") return "cursor";
|
|
7424
7462
|
return null;
|
|
7425
7463
|
}
|
|
7464
|
+
function resolveGraderPool(parsed) {
|
|
7465
|
+
const warnings = [];
|
|
7466
|
+
const grader = parsed?.grader && typeof parsed.grader === "object" ? parsed.grader : {};
|
|
7467
|
+
const counts = {};
|
|
7468
|
+
const collect = (obj, where, flagUnknown) => {
|
|
7469
|
+
if (!obj || typeof obj !== "object") return;
|
|
7470
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
7471
|
+
if (typeof v !== "number") continue;
|
|
7472
|
+
const np = normalizeProvider(k);
|
|
7473
|
+
if (np === "claude_code") counts.claude_code = Math.max(0, Math.floor(v));
|
|
7474
|
+
else if (np === "cursor") counts.cursor = Math.max(0, Math.floor(v));
|
|
7475
|
+
else if (flagUnknown) {
|
|
7476
|
+
warnings.push(`.synkro: ${where}.${k} is not a known provider (use claude-code or cursor) \u2014 ignored`);
|
|
7477
|
+
}
|
|
7478
|
+
}
|
|
7479
|
+
};
|
|
7480
|
+
collect(grader, "grader", true);
|
|
7481
|
+
collect(parsed?.workers, "workers", false);
|
|
7482
|
+
let pool = "auto";
|
|
7483
|
+
const rawPool = grader.pool;
|
|
7484
|
+
if (rawPool != null && rawPool !== "auto") {
|
|
7485
|
+
const np = normalizeProvider(String(rawPool));
|
|
7486
|
+
if (np) pool = np;
|
|
7487
|
+
else warnings.push(`.synkro: grader.pool="${rawPool}" is not recognized (use auto | claude-code | cursor) \u2014 falling back to auto`);
|
|
7488
|
+
}
|
|
7489
|
+
if (counts.claude_code != null || counts.cursor != null) {
|
|
7490
|
+
return { claudeWorkers: counts.claude_code, cursorWorkers: counts.cursor, pool, warnings };
|
|
7491
|
+
}
|
|
7492
|
+
return { pool, warnings };
|
|
7493
|
+
}
|
|
7494
|
+
function poolLabel(pool) {
|
|
7495
|
+
return pool === "claude_code" ? "claude-code" : pool;
|
|
7496
|
+
}
|
|
7426
7497
|
function parseSynkroYaml(raw) {
|
|
7427
7498
|
const result = {};
|
|
7428
7499
|
const lines = raw.split("\n");
|
|
@@ -7469,18 +7540,15 @@ function parseSynkroYaml(raw) {
|
|
|
7469
7540
|
function readSynkroFileConfig() {
|
|
7470
7541
|
try {
|
|
7471
7542
|
const root = execSync4("git rev-parse --show-toplevel 2>/dev/null", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7472
|
-
if (!root) return { pool: "auto" };
|
|
7543
|
+
if (!root) return { pool: "auto", warnings: [] };
|
|
7473
7544
|
const fp = join6(root, ".synkro");
|
|
7474
|
-
if (!existsSync8(fp)) return { pool: "auto" };
|
|
7545
|
+
if (!existsSync8(fp)) return { pool: "auto", warnings: [] };
|
|
7475
7546
|
const raw = readFileSync6(fp, "utf-8");
|
|
7476
7547
|
const parsed = raw.trimStart().startsWith("{") ? JSON.parse(raw) : parseSynkroYaml(raw);
|
|
7477
|
-
|
|
7478
|
-
const cw = typeof parsed?.workers?.claude === "number" ? Math.max(0, Math.floor(parsed.workers.claude)) : void 0;
|
|
7479
|
-
const curw = typeof parsed?.workers?.cursor === "number" ? Math.max(0, Math.floor(parsed.workers.cursor)) : void 0;
|
|
7480
|
-
return { pool, claudeWorkers: cw, cursorWorkers: curw };
|
|
7548
|
+
return resolveGraderPool(parsed);
|
|
7481
7549
|
} catch {
|
|
7482
7550
|
}
|
|
7483
|
-
return { pool: "auto" };
|
|
7551
|
+
return { pool: "auto", warnings: [] };
|
|
7484
7552
|
}
|
|
7485
7553
|
function resolveWorkerConfig(rest) {
|
|
7486
7554
|
let workers = 8;
|
|
@@ -7516,6 +7584,7 @@ function resolveWorkerConfig(rest) {
|
|
|
7516
7584
|
let provs = providers;
|
|
7517
7585
|
if (provs.length === 0) {
|
|
7518
7586
|
const sc = readSynkroFileConfig();
|
|
7587
|
+
for (const w of sc.warnings) console.warn(` \u26A0 ${w}`);
|
|
7519
7588
|
if (sc.claudeWorkers != null || sc.cursorWorkers != null) {
|
|
7520
7589
|
const cw = sc.claudeWorkers || 0;
|
|
7521
7590
|
const curw = sc.cursorWorkers || 0;
|
|
@@ -7523,7 +7592,7 @@ function resolveWorkerConfig(rest) {
|
|
|
7523
7592
|
}
|
|
7524
7593
|
if (sc.pool === "cursor") {
|
|
7525
7594
|
provs = ["cursor"];
|
|
7526
|
-
} else if (sc.pool === "
|
|
7595
|
+
} else if (sc.pool === "claude_code") {
|
|
7527
7596
|
provs = ["claude_code"];
|
|
7528
7597
|
} else {
|
|
7529
7598
|
provs = detectAgents().map((a) => a.kind);
|
|
@@ -8647,7 +8716,7 @@ function writeConfigEnv(opts) {
|
|
|
8647
8716
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
8648
8717
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
8649
8718
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
8650
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.6.
|
|
8719
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.6.51")}`
|
|
8651
8720
|
];
|
|
8652
8721
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
8653
8722
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -8842,8 +8911,9 @@ async function installCommand(opts = {}) {
|
|
|
8842
8911
|
gradingMode = existingSynkro.grader.mode === "byok" ? "byok" : "local";
|
|
8843
8912
|
storageMode = "local";
|
|
8844
8913
|
console.log(`Using .synkro config:`);
|
|
8914
|
+
for (const w of existingSynkro.warnings) console.warn(` \u26A0 ${w}`);
|
|
8845
8915
|
console.log(` harness: ${existingSynkro.harness.join(", ")}`);
|
|
8846
|
-
console.log(` grading: ${gradingMode} pool: ${existingSynkro.grader.pool}`);
|
|
8916
|
+
console.log(` grading: ${gradingMode} pool: ${poolLabel(existingSynkro.grader.pool)}`);
|
|
8847
8917
|
for (const a of agents) {
|
|
8848
8918
|
console.log(` \u2713 ${a.name}${a.version ? ` (${a.version})` : ""}`);
|
|
8849
8919
|
}
|
|
@@ -9092,6 +9162,7 @@ async function installCommand(opts = {}) {
|
|
|
9092
9162
|
}
|
|
9093
9163
|
console.log("Installing Synkro server container...");
|
|
9094
9164
|
const sf = readFullSynkroFile();
|
|
9165
|
+
for (const w of sf?.warnings || []) console.warn(` \u26A0 ${w}`);
|
|
9095
9166
|
let claudeWorkers;
|
|
9096
9167
|
let cursorWorkers;
|
|
9097
9168
|
if (sf && (sf.workers.claude != null || sf.workers.cursor != null)) {
|
|
@@ -9104,18 +9175,18 @@ async function installCommand(opts = {}) {
|
|
|
9104
9175
|
console.log(` .synkro: explicit workers \u2014 ${claudeWorkers} claude + ${cursorWorkers} cursor`);
|
|
9105
9176
|
} else {
|
|
9106
9177
|
const totalWorkers = parseInt(process.env.SYNKRO_WORKERS_PER_POOL || "8", 10);
|
|
9107
|
-
const synkroFilePool = sf?.grader?.pool ||
|
|
9178
|
+
const synkroFilePool = sf?.grader?.pool || "auto";
|
|
9108
9179
|
let providers = [];
|
|
9109
9180
|
if (synkroFilePool === "cursor") {
|
|
9110
9181
|
providers = ["cursor"];
|
|
9111
|
-
} else if (synkroFilePool === "
|
|
9182
|
+
} else if (synkroFilePool === "claude_code") {
|
|
9112
9183
|
providers = ["claude_code"];
|
|
9113
9184
|
} else {
|
|
9114
9185
|
if (hasClaudeCode) providers.push("claude_code");
|
|
9115
9186
|
if (hasCursor) providers.push("cursor");
|
|
9116
9187
|
}
|
|
9117
9188
|
({ claudeWorkers, cursorWorkers } = splitWorkers(totalWorkers, providers));
|
|
9118
|
-
if (synkroFilePool !== "auto") console.log(` .synkro: grader pool set to ${synkroFilePool}`);
|
|
9189
|
+
if (synkroFilePool !== "auto") console.log(` .synkro: grader pool set to ${poolLabel(synkroFilePool)}`);
|
|
9119
9190
|
}
|
|
9120
9191
|
console.log(` worker pool: ${claudeWorkers} claude + ${cursorWorkers} cursor`);
|
|
9121
9192
|
const connectedRepo = detectGitRepo2() || void 0;
|
|
@@ -9336,19 +9407,6 @@ function writeSynkroFileIfMissing(opts) {
|
|
|
9336
9407
|
} catch {
|
|
9337
9408
|
}
|
|
9338
9409
|
}
|
|
9339
|
-
function readSynkroFilePool() {
|
|
9340
|
-
try {
|
|
9341
|
-
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
9342
|
-
if (!root) return "auto";
|
|
9343
|
-
const fp = join8(root, ".synkro");
|
|
9344
|
-
if (!existsSync10(fp)) return "auto";
|
|
9345
|
-
const parsed = parseSynkroFileRaw(readFileSync8(fp, "utf-8"));
|
|
9346
|
-
const pool = parsed?.grader?.pool;
|
|
9347
|
-
if (pool === "cursor" || pool === "claude") return pool;
|
|
9348
|
-
} catch {
|
|
9349
|
-
}
|
|
9350
|
-
return "auto";
|
|
9351
|
-
}
|
|
9352
9410
|
function readFullSynkroFile() {
|
|
9353
9411
|
try {
|
|
9354
9412
|
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
@@ -9358,16 +9416,18 @@ function readFullSynkroFile() {
|
|
|
9358
9416
|
const parsed = parseSynkroFileRaw(readFileSync8(fp, "utf-8"));
|
|
9359
9417
|
const valid = ["claude-code", "cursor"];
|
|
9360
9418
|
const harness = Array.isArray(parsed.harness) ? parsed.harness.filter((h) => valid.includes(h)) : ["claude-code", "cursor"];
|
|
9419
|
+
const resolved = resolveGraderPool(parsed);
|
|
9361
9420
|
return {
|
|
9362
9421
|
harness: harness.length > 0 ? harness : ["claude-code", "cursor"],
|
|
9363
9422
|
grader: {
|
|
9364
|
-
pool:
|
|
9423
|
+
pool: resolved.pool,
|
|
9365
9424
|
mode: ["local", "byok"].includes(parsed.grader?.mode) ? parsed.grader.mode : "local"
|
|
9366
9425
|
},
|
|
9367
9426
|
workers: {
|
|
9368
|
-
...
|
|
9369
|
-
...
|
|
9427
|
+
...resolved.claudeWorkers != null ? { claude: resolved.claudeWorkers } : {},
|
|
9428
|
+
...resolved.cursorWorkers != null ? { cursor: resolved.cursorWorkers } : {}
|
|
9370
9429
|
},
|
|
9430
|
+
warnings: resolved.warnings,
|
|
9371
9431
|
ruleset: parsed.ruleset || "default",
|
|
9372
9432
|
skills: Array.isArray(parsed.skills) ? parsed.skills.filter((s) => typeof s === "string" && s.endsWith(".md")) : [],
|
|
9373
9433
|
scanning: { cwe: parsed.scanning?.cwe !== false, cve: parsed.scanning?.cve !== false },
|
|
@@ -9385,7 +9445,8 @@ function reconcileHarness() {
|
|
|
9385
9445
|
}
|
|
9386
9446
|
const wantCC = sf.harness.includes("claude-code");
|
|
9387
9447
|
const wantCursor = sf.harness.includes("cursor");
|
|
9388
|
-
|
|
9448
|
+
for (const w of sf.warnings) console.warn(` \u26A0 ${w}`);
|
|
9449
|
+
console.log(`.synkro: harness=[${sf.harness.join(", ")}] pool=${poolLabel(sf.grader.pool)} mode=${sf.grader.mode}`);
|
|
9389
9450
|
const scripts = writeHookScripts(resolvePersistedHookMode());
|
|
9390
9451
|
console.log("Wrote hook scripts to ~/.synkro/hooks/");
|
|
9391
9452
|
const ccSettings = join8(homedir8(), ".claude", "settings.json");
|
|
@@ -9454,7 +9515,7 @@ function reconcileHarness() {
|
|
|
9454
9515
|
const providers = [];
|
|
9455
9516
|
if (sf.grader.pool === "cursor") {
|
|
9456
9517
|
providers.push("cursor");
|
|
9457
|
-
} else if (sf.grader.pool === "
|
|
9518
|
+
} else if (sf.grader.pool === "claude_code") {
|
|
9458
9519
|
providers.push("claude_code");
|
|
9459
9520
|
} else {
|
|
9460
9521
|
if (wantCC) providers.push("claude_code");
|
|
@@ -11839,7 +11900,7 @@ var args = process.argv.slice(2);
|
|
|
11839
11900
|
var cmd = args[0] || "";
|
|
11840
11901
|
var subArgs = args.slice(1);
|
|
11841
11902
|
function printVersion() {
|
|
11842
|
-
console.log("1.6.
|
|
11903
|
+
console.log("1.6.51");
|
|
11843
11904
|
}
|
|
11844
11905
|
function printHelp2() {
|
|
11845
11906
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|