@synkro-sh/cli 1.6.35 → 1.6.37
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 +112 -112
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -602,54 +602,14 @@ var init_mcpConfig = __esm({
|
|
|
602
602
|
});
|
|
603
603
|
|
|
604
604
|
// cli/installer/skillParser.ts
|
|
605
|
-
import {
|
|
606
|
-
import { resolve as resolve2
|
|
607
|
-
function parseSection(heading, body) {
|
|
608
|
-
const lines = body.split("\n");
|
|
609
|
-
const meta = {};
|
|
610
|
-
const textLines = [];
|
|
611
|
-
for (const line of lines) {
|
|
612
|
-
const m = line.match(/^(mode|severity|category)\s*:\s*(.+)/i);
|
|
613
|
-
if (m && META_KEYS.has(m[1].toLowerCase())) {
|
|
614
|
-
meta[m[1].toLowerCase()] = m[2].trim();
|
|
615
|
-
} else if (line.trim()) {
|
|
616
|
-
textLines.push(line.trim());
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
const description = textLines.join(" ").trim();
|
|
620
|
-
const text = description ? `${heading}: ${description}` : heading;
|
|
621
|
-
return {
|
|
622
|
-
text,
|
|
623
|
-
mode: meta.mode || "ask",
|
|
624
|
-
severity: meta.severity || "medium",
|
|
625
|
-
category: meta.category || "custom"
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
function parseSkillFile(filePath) {
|
|
629
|
-
if (!existsSync4(filePath)) return null;
|
|
630
|
-
const content = readFileSync4(filePath, "utf-8");
|
|
631
|
-
const source = `skill:${basename(filePath)}`;
|
|
632
|
-
const sections = content.split(/^## /m).slice(1);
|
|
633
|
-
if (sections.length === 0) return null;
|
|
634
|
-
const rules = [];
|
|
635
|
-
for (const section of sections) {
|
|
636
|
-
const newlineIdx = section.indexOf("\n");
|
|
637
|
-
if (newlineIdx === -1) continue;
|
|
638
|
-
const heading = section.slice(0, newlineIdx).trim();
|
|
639
|
-
const body = section.slice(newlineIdx + 1);
|
|
640
|
-
if (!heading) continue;
|
|
641
|
-
rules.push(parseSection(heading, body));
|
|
642
|
-
}
|
|
643
|
-
return rules.length > 0 ? { source, rules } : null;
|
|
644
|
-
}
|
|
605
|
+
import { existsSync as existsSync4 } from "fs";
|
|
606
|
+
import { resolve as resolve2 } from "path";
|
|
645
607
|
function resolveSkillPaths(skills, repoRoot) {
|
|
646
608
|
return skills.filter((s) => s.endsWith(".md")).map((s) => resolve2(repoRoot, s)).filter((p) => existsSync4(p));
|
|
647
609
|
}
|
|
648
|
-
var META_KEYS;
|
|
649
610
|
var init_skillParser = __esm({
|
|
650
611
|
"cli/installer/skillParser.ts"() {
|
|
651
612
|
"use strict";
|
|
652
|
-
META_KEYS = /* @__PURE__ */ new Set(["mode", "severity", "category"]);
|
|
653
613
|
}
|
|
654
614
|
});
|
|
655
615
|
|
|
@@ -1198,6 +1158,7 @@ export interface SynkroFileConfig {
|
|
|
1198
1158
|
version: number;
|
|
1199
1159
|
harness: ('claude-code' | 'cursor')[];
|
|
1200
1160
|
grader: { pool: 'auto' | 'claude' | 'cursor'; mode?: string };
|
|
1161
|
+
workers: { claude?: number; cursor?: number };
|
|
1201
1162
|
ruleset: string;
|
|
1202
1163
|
skills: string[];
|
|
1203
1164
|
scanning: { cwe: boolean; cve: boolean };
|
|
@@ -1207,6 +1168,7 @@ const SYNKRO_FILE_DEFAULTS: SynkroFileConfig = {
|
|
|
1207
1168
|
version: 1,
|
|
1208
1169
|
harness: ['claude-code', 'cursor'],
|
|
1209
1170
|
grader: { pool: 'auto' },
|
|
1171
|
+
workers: {},
|
|
1210
1172
|
ruleset: 'default',
|
|
1211
1173
|
skills: [],
|
|
1212
1174
|
scanning: { cwe: true, cve: true },
|
|
@@ -1282,6 +1244,10 @@ export function loadSynkroFile(cwd?: string): SynkroFileConfig {
|
|
|
1282
1244
|
pool: ['auto', 'claude', 'cursor'].includes(parsed.grader?.pool) ? parsed.grader.pool : 'auto',
|
|
1283
1245
|
mode: ['local', 'byok'].includes(parsed.grader?.mode) ? parsed.grader.mode : undefined,
|
|
1284
1246
|
},
|
|
1247
|
+
workers: {
|
|
1248
|
+
...(typeof parsed.workers?.claude === 'number' ? { claude: parsed.workers.claude } : {}),
|
|
1249
|
+
...(typeof parsed.workers?.cursor === 'number' ? { cursor: parsed.workers.cursor } : {}),
|
|
1250
|
+
},
|
|
1285
1251
|
ruleset: typeof parsed.ruleset === 'string' ? parsed.ruleset : 'default',
|
|
1286
1252
|
skills: Array.isArray(parsed.skills) ? parsed.skills.filter((s: unknown) => typeof s === 'string') : [],
|
|
1287
1253
|
scanning: {
|
|
@@ -6050,7 +6016,7 @@ __export(stub_exports, {
|
|
|
6050
6016
|
saveCredentials: () => saveCredentials
|
|
6051
6017
|
});
|
|
6052
6018
|
import { createServer } from "http";
|
|
6053
|
-
import { writeFileSync as writeFileSync4, readFileSync as
|
|
6019
|
+
import { writeFileSync as writeFileSync4, readFileSync as readFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
6054
6020
|
import { homedir as homedir4, platform } from "os";
|
|
6055
6021
|
import { join as join3, dirname as dirname4 } from "path";
|
|
6056
6022
|
import { execFile } from "child_process";
|
|
@@ -6091,7 +6057,7 @@ function loadCredentials() {
|
|
|
6091
6057
|
return null;
|
|
6092
6058
|
}
|
|
6093
6059
|
try {
|
|
6094
|
-
const content =
|
|
6060
|
+
const content = readFileSync4(AUTH_FILE, "utf8");
|
|
6095
6061
|
return JSON.parse(content);
|
|
6096
6062
|
} catch (error) {
|
|
6097
6063
|
return null;
|
|
@@ -6949,7 +6915,7 @@ __export(macKeychain_exports, {
|
|
|
6949
6915
|
writeCursorApiKey: () => writeCursorApiKey,
|
|
6950
6916
|
writeRefreshAgent: () => writeRefreshAgent
|
|
6951
6917
|
});
|
|
6952
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, chmodSync, readFileSync as
|
|
6918
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, chmodSync, readFileSync as readFileSync5, statSync } from "fs";
|
|
6953
6919
|
import { homedir as homedir5, platform as platform2 } from "os";
|
|
6954
6920
|
import { join as join5 } from "path";
|
|
6955
6921
|
import { spawnSync } from "child_process";
|
|
@@ -6977,7 +6943,7 @@ function exportKeychainCreds() {
|
|
|
6977
6943
|
}
|
|
6978
6944
|
function cursorApiKeyConfigured() {
|
|
6979
6945
|
try {
|
|
6980
|
-
return existsSync7(CURSOR_API_KEY_FILE) &&
|
|
6946
|
+
return existsSync7(CURSOR_API_KEY_FILE) && readFileSync5(CURSOR_API_KEY_FILE, "utf-8").trim().length > 0;
|
|
6981
6947
|
} catch {
|
|
6982
6948
|
return false;
|
|
6983
6949
|
}
|
|
@@ -6993,7 +6959,7 @@ function writeCursorApiKey(key) {
|
|
|
6993
6959
|
async function validateCursorApiKey() {
|
|
6994
6960
|
let key;
|
|
6995
6961
|
try {
|
|
6996
|
-
key =
|
|
6962
|
+
key = readFileSync5(CURSOR_API_KEY_FILE, "utf-8").trim();
|
|
6997
6963
|
} catch {
|
|
6998
6964
|
return null;
|
|
6999
6965
|
}
|
|
@@ -7087,7 +7053,7 @@ function refreshCreds() {
|
|
|
7087
7053
|
}
|
|
7088
7054
|
function readExportedCreds() {
|
|
7089
7055
|
try {
|
|
7090
|
-
return
|
|
7056
|
+
return readFileSync5(CLAUDE_CREDS_FILE, "utf-8");
|
|
7091
7057
|
} catch {
|
|
7092
7058
|
return null;
|
|
7093
7059
|
}
|
|
@@ -7136,7 +7102,7 @@ __export(dockerInstall_exports, {
|
|
|
7136
7102
|
splitWorkers: () => splitWorkers,
|
|
7137
7103
|
waitForContainerReady: () => waitForContainerReady
|
|
7138
7104
|
});
|
|
7139
|
-
import { copyFileSync, existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as
|
|
7105
|
+
import { copyFileSync, existsSync as existsSync8, mkdirSync as mkdirSync7, readFileSync as readFileSync6, readdirSync as readdirSync2 } from "fs";
|
|
7140
7106
|
import { homedir as homedir6 } from "os";
|
|
7141
7107
|
import { join as join6 } from "path";
|
|
7142
7108
|
import { execSync as execSync4, spawnSync as spawnSync2 } from "child_process";
|
|
@@ -7200,19 +7166,21 @@ function parseSynkroYaml(raw) {
|
|
|
7200
7166
|
if (currentArr && currentKey) result[currentKey] = currentArr;
|
|
7201
7167
|
return result;
|
|
7202
7168
|
}
|
|
7203
|
-
function
|
|
7169
|
+
function readSynkroFileConfig() {
|
|
7204
7170
|
try {
|
|
7205
7171
|
const root = execSync4("git rev-parse --show-toplevel 2>/dev/null", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7206
|
-
if (!root) return "auto";
|
|
7172
|
+
if (!root) return { pool: "auto" };
|
|
7207
7173
|
const fp = join6(root, ".synkro");
|
|
7208
|
-
if (!existsSync8(fp)) return "auto";
|
|
7209
|
-
const raw =
|
|
7174
|
+
if (!existsSync8(fp)) return { pool: "auto" };
|
|
7175
|
+
const raw = readFileSync6(fp, "utf-8");
|
|
7210
7176
|
const parsed = raw.trimStart().startsWith("{") ? JSON.parse(raw) : parseSynkroYaml(raw);
|
|
7211
|
-
const pool = parsed?.grader?.pool;
|
|
7212
|
-
|
|
7177
|
+
const pool = ["auto", "claude", "cursor"].includes(parsed?.grader?.pool) ? parsed.grader.pool : "auto";
|
|
7178
|
+
const cw = typeof parsed?.workers?.claude === "number" ? Math.max(0, Math.floor(parsed.workers.claude)) : void 0;
|
|
7179
|
+
const curw = typeof parsed?.workers?.cursor === "number" ? Math.max(0, Math.floor(parsed.workers.cursor)) : void 0;
|
|
7180
|
+
return { pool, claudeWorkers: cw, cursorWorkers: curw };
|
|
7213
7181
|
} catch {
|
|
7214
7182
|
}
|
|
7215
|
-
return "auto";
|
|
7183
|
+
return { pool: "auto" };
|
|
7216
7184
|
}
|
|
7217
7185
|
function resolveWorkerConfig(rest) {
|
|
7218
7186
|
let workers = 8;
|
|
@@ -7247,10 +7215,15 @@ function resolveWorkerConfig(rest) {
|
|
|
7247
7215
|
workers = Math.min(workers, 64);
|
|
7248
7216
|
let provs = providers;
|
|
7249
7217
|
if (provs.length === 0) {
|
|
7250
|
-
const
|
|
7251
|
-
if (
|
|
7218
|
+
const sc = readSynkroFileConfig();
|
|
7219
|
+
if (sc.claudeWorkers != null || sc.cursorWorkers != null) {
|
|
7220
|
+
const cw = sc.claudeWorkers || 0;
|
|
7221
|
+
const curw = sc.cursorWorkers || 0;
|
|
7222
|
+
if (cw + curw > 0) return { claudeWorkers: cw, cursorWorkers: curw, explicit };
|
|
7223
|
+
}
|
|
7224
|
+
if (sc.pool === "cursor") {
|
|
7252
7225
|
provs = ["cursor"];
|
|
7253
|
-
} else if (
|
|
7226
|
+
} else if (sc.pool === "claude") {
|
|
7254
7227
|
provs = ["claude_code"];
|
|
7255
7228
|
} else {
|
|
7256
7229
|
provs = detectAgents().map((a) => a.kind);
|
|
@@ -7661,14 +7634,14 @@ __export(setupGithub_exports, {
|
|
|
7661
7634
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
7662
7635
|
import { stdin as input, stdout as output } from "process";
|
|
7663
7636
|
import { execSync as execSync5, spawn as nodeSpawn } from "child_process";
|
|
7664
|
-
import { existsSync as existsSync9, readFileSync as
|
|
7637
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, unlinkSync as unlinkSync3 } from "fs";
|
|
7665
7638
|
import { homedir as homedir7, platform as platform3 } from "os";
|
|
7666
7639
|
import { join as join7 } from "path";
|
|
7667
7640
|
import { execFile as execFile2 } from "child_process";
|
|
7668
7641
|
function readConfig() {
|
|
7669
7642
|
if (!existsSync9(CONFIG_PATH)) return {};
|
|
7670
7643
|
const out = {};
|
|
7671
|
-
for (const line of
|
|
7644
|
+
for (const line of readFileSync7(CONFIG_PATH, "utf-8").split("\n")) {
|
|
7672
7645
|
const t = line.trim();
|
|
7673
7646
|
if (!t || t.startsWith("#")) continue;
|
|
7674
7647
|
const eq = t.indexOf("=");
|
|
@@ -7738,7 +7711,7 @@ function captureClaudeSetupToken() {
|
|
|
7738
7711
|
proc.on("close", (code) => {
|
|
7739
7712
|
let raw = "";
|
|
7740
7713
|
try {
|
|
7741
|
-
raw =
|
|
7714
|
+
raw = readFileSync7(tmpFile, "utf-8");
|
|
7742
7715
|
} catch (e) {
|
|
7743
7716
|
reject(new Error(`Could not read script output file: ${e.message}`));
|
|
7744
7717
|
return;
|
|
@@ -8025,7 +7998,7 @@ __export(install_exports, {
|
|
|
8025
7998
|
syncSkillFiles: () => syncSkillFiles,
|
|
8026
7999
|
writeHookScripts: () => writeHookScripts
|
|
8027
8000
|
});
|
|
8028
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, chmodSync as chmodSync2, readFileSync as
|
|
8001
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, chmodSync as chmodSync2, readFileSync as readFileSync8, readdirSync as readdirSync3 } from "fs";
|
|
8029
8002
|
import { homedir as homedir8 } from "os";
|
|
8030
8003
|
import { join as join8 } from "path";
|
|
8031
8004
|
import { execSync as execSync6, spawnSync as spawnSync3 } from "child_process";
|
|
@@ -8271,7 +8244,7 @@ function writeConfigEnv(opts) {
|
|
|
8271
8244
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
8272
8245
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
8273
8246
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
8274
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.6.
|
|
8247
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.6.37")}`
|
|
8275
8248
|
];
|
|
8276
8249
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
8277
8250
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -8294,7 +8267,7 @@ function resolveDeploymentMode() {
|
|
|
8294
8267
|
if (envOverride === "bare-host" || envOverride === "docker") return envOverride;
|
|
8295
8268
|
try {
|
|
8296
8269
|
if (existsSync10(CONFIG_PATH2)) {
|
|
8297
|
-
const m =
|
|
8270
|
+
const m = readFileSync8(CONFIG_PATH2, "utf-8").match(/^SYNKRO_DEPLOYMENT_MODE='([^']*)'/m);
|
|
8298
8271
|
const val = m?.[1]?.toLowerCase();
|
|
8299
8272
|
if (val === "bare-host" || val === "docker") return val;
|
|
8300
8273
|
}
|
|
@@ -8323,14 +8296,14 @@ function collectLocalMetadata(includeClaudeCode = true) {
|
|
|
8323
8296
|
}
|
|
8324
8297
|
const claudeDir = join8(homedir8(), ".claude");
|
|
8325
8298
|
try {
|
|
8326
|
-
const settings = JSON.parse(
|
|
8299
|
+
const settings = JSON.parse(readFileSync8(join8(claudeDir, "settings.json"), "utf-8"));
|
|
8327
8300
|
const plugins = Object.keys(settings.enabledPlugins ?? {}).filter((k) => settings.enabledPlugins[k]);
|
|
8328
8301
|
if (plugins.length) meta.enabled_plugins = plugins;
|
|
8329
8302
|
if (settings.permissions?.defaultMode) meta.permissions_mode = settings.permissions.defaultMode;
|
|
8330
8303
|
} catch {
|
|
8331
8304
|
}
|
|
8332
8305
|
try {
|
|
8333
|
-
const mcpCache = JSON.parse(
|
|
8306
|
+
const mcpCache = JSON.parse(readFileSync8(join8(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
|
|
8334
8307
|
const mcpNames = Object.keys(mcpCache);
|
|
8335
8308
|
if (mcpNames.length) meta.mcp_servers = mcpNames;
|
|
8336
8309
|
} catch {
|
|
@@ -8345,7 +8318,7 @@ function collectLocalMetadata(includeClaudeCode = true) {
|
|
|
8345
8318
|
const sessionsDir = join8(claudeDir, "sessions");
|
|
8346
8319
|
const files = readdirSync3(sessionsDir).filter((f) => f.endsWith(".json")).slice(-5);
|
|
8347
8320
|
for (const f of files) {
|
|
8348
|
-
const s = JSON.parse(
|
|
8321
|
+
const s = JSON.parse(readFileSync8(join8(sessionsDir, f), "utf-8"));
|
|
8349
8322
|
if (s.version) {
|
|
8350
8323
|
meta.cc_version = meta.cc_version || s.version;
|
|
8351
8324
|
break;
|
|
@@ -8477,7 +8450,7 @@ async function installCommand(opts = {}) {
|
|
|
8477
8450
|
for (const mode of ["edit", "bash"]) {
|
|
8478
8451
|
const pidFile = join8(SYNKRO_DIR4, "daemon", mode, "daemon.pid");
|
|
8479
8452
|
try {
|
|
8480
|
-
const pid = parseInt(
|
|
8453
|
+
const pid = parseInt(readFileSync8(pidFile, "utf-8").trim(), 10);
|
|
8481
8454
|
if (pid > 0) {
|
|
8482
8455
|
process.kill(pid, "SIGTERM");
|
|
8483
8456
|
console.log(`Stopped stale ${mode} grader daemon (pid ${pid})`);
|
|
@@ -8679,19 +8652,32 @@ async function installCommand(opts = {}) {
|
|
|
8679
8652
|
await promptCursorApiKey(opts);
|
|
8680
8653
|
}
|
|
8681
8654
|
console.log("Installing Synkro server container...");
|
|
8682
|
-
const
|
|
8683
|
-
|
|
8684
|
-
let
|
|
8685
|
-
if (
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8655
|
+
const sf = readFullSynkroFile();
|
|
8656
|
+
let claudeWorkers;
|
|
8657
|
+
let cursorWorkers;
|
|
8658
|
+
if (sf && (sf.workers.claude != null || sf.workers.cursor != null)) {
|
|
8659
|
+
claudeWorkers = Math.max(0, Math.floor(sf.workers.claude || 0));
|
|
8660
|
+
cursorWorkers = Math.max(0, Math.floor(sf.workers.cursor || 0));
|
|
8661
|
+
if (claudeWorkers + cursorWorkers === 0) {
|
|
8662
|
+
claudeWorkers = 0;
|
|
8663
|
+
cursorWorkers = 8;
|
|
8664
|
+
}
|
|
8665
|
+
console.log(` .synkro: explicit workers \u2014 ${claudeWorkers} claude + ${cursorWorkers} cursor`);
|
|
8689
8666
|
} else {
|
|
8690
|
-
|
|
8691
|
-
|
|
8667
|
+
const totalWorkers = parseInt(process.env.SYNKRO_WORKERS_PER_POOL || "8", 10);
|
|
8668
|
+
const synkroFilePool = sf?.grader?.pool || readSynkroFilePool();
|
|
8669
|
+
let providers = [];
|
|
8670
|
+
if (synkroFilePool === "cursor") {
|
|
8671
|
+
providers = ["cursor"];
|
|
8672
|
+
} else if (synkroFilePool === "claude") {
|
|
8673
|
+
providers = ["claude_code"];
|
|
8674
|
+
} else {
|
|
8675
|
+
if (hasClaudeCode) providers.push("claude_code");
|
|
8676
|
+
if (hasCursor) providers.push("cursor");
|
|
8677
|
+
}
|
|
8678
|
+
({ claudeWorkers, cursorWorkers } = splitWorkers(totalWorkers, providers));
|
|
8679
|
+
if (synkroFilePool !== "auto") console.log(` .synkro: grader pool set to ${synkroFilePool}`);
|
|
8692
8680
|
}
|
|
8693
|
-
const { claudeWorkers, cursorWorkers } = splitWorkers(totalWorkers, providers);
|
|
8694
|
-
if (synkroFilePool !== "auto") console.log(` .synkro: grader pool set to ${synkroFilePool}`);
|
|
8695
8681
|
console.log(` worker pool: ${claudeWorkers} claude + ${cursorWorkers} cursor`);
|
|
8696
8682
|
const connectedRepo = detectGitRepo2() || void 0;
|
|
8697
8683
|
const { image, hostMcpPort, hostGraderPort, hostCwePort, hostPglitePort } = await dockerInstall({ claudeWorkers, cursorWorkers, connectedRepo });
|
|
@@ -8701,7 +8687,7 @@ async function installCommand(opts = {}) {
|
|
|
8701
8687
|
const ready = await waitForContainerReady(6e4);
|
|
8702
8688
|
if (ready) {
|
|
8703
8689
|
console.log(" \u2713 container ready");
|
|
8704
|
-
const mcpJwt =
|
|
8690
|
+
const mcpJwt = readFileSync8(join8(SYNKRO_DIR4, ".mcp-jwt"), "utf-8").trim();
|
|
8705
8691
|
try {
|
|
8706
8692
|
const ingestResp = await fetch(`http://127.0.0.1:${hostMcpPort}/api/ingest`, {
|
|
8707
8693
|
method: "POST",
|
|
@@ -8733,7 +8719,7 @@ async function installCommand(opts = {}) {
|
|
|
8733
8719
|
try {
|
|
8734
8720
|
let mcpToken = "";
|
|
8735
8721
|
try {
|
|
8736
|
-
mcpToken =
|
|
8722
|
+
mcpToken = readFileSync8(join8(SYNKRO_DIR4, ".mcp-jwt"), "utf-8").trim();
|
|
8737
8723
|
} catch {
|
|
8738
8724
|
}
|
|
8739
8725
|
if (mcpToken) {
|
|
@@ -8887,13 +8873,13 @@ function writeSynkroFileIfMissing(opts) {
|
|
|
8887
8873
|
} catch {
|
|
8888
8874
|
}
|
|
8889
8875
|
}
|
|
8890
|
-
function
|
|
8876
|
+
function readSynkroFilePool() {
|
|
8891
8877
|
try {
|
|
8892
8878
|
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
8893
8879
|
if (!root) return "auto";
|
|
8894
8880
|
const fp = join8(root, ".synkro");
|
|
8895
8881
|
if (!existsSync10(fp)) return "auto";
|
|
8896
|
-
const parsed = parseSynkroFileRaw(
|
|
8882
|
+
const parsed = parseSynkroFileRaw(readFileSync8(fp, "utf-8"));
|
|
8897
8883
|
const pool = parsed?.grader?.pool;
|
|
8898
8884
|
if (pool === "cursor" || pool === "claude") return pool;
|
|
8899
8885
|
} catch {
|
|
@@ -8906,7 +8892,7 @@ function readFullSynkroFile() {
|
|
|
8906
8892
|
if (!root) return null;
|
|
8907
8893
|
const fp = join8(root, ".synkro");
|
|
8908
8894
|
if (!existsSync10(fp)) return null;
|
|
8909
|
-
const parsed = parseSynkroFileRaw(
|
|
8895
|
+
const parsed = parseSynkroFileRaw(readFileSync8(fp, "utf-8"));
|
|
8910
8896
|
const valid = ["claude-code", "cursor"];
|
|
8911
8897
|
const harness = Array.isArray(parsed.harness) ? parsed.harness.filter((h) => valid.includes(h)) : ["claude-code", "cursor"];
|
|
8912
8898
|
return {
|
|
@@ -8915,6 +8901,10 @@ function readFullSynkroFile() {
|
|
|
8915
8901
|
pool: ["auto", "claude", "cursor"].includes(parsed.grader?.pool) ? parsed.grader.pool : "auto",
|
|
8916
8902
|
mode: ["local", "byok"].includes(parsed.grader?.mode) ? parsed.grader.mode : "local"
|
|
8917
8903
|
},
|
|
8904
|
+
workers: {
|
|
8905
|
+
...typeof parsed.workers?.claude === "number" ? { claude: parsed.workers.claude } : {},
|
|
8906
|
+
...typeof parsed.workers?.cursor === "number" ? { cursor: parsed.workers.cursor } : {}
|
|
8907
|
+
},
|
|
8918
8908
|
ruleset: parsed.ruleset || "default",
|
|
8919
8909
|
skills: Array.isArray(parsed.skills) ? parsed.skills.filter((s) => typeof s === "string" && s.endsWith(".md")) : [],
|
|
8920
8910
|
scanning: { cwe: parsed.scanning?.cwe !== false, cve: parsed.scanning?.cve !== false },
|
|
@@ -8953,7 +8943,7 @@ function reconcileHarness() {
|
|
|
8953
8943
|
});
|
|
8954
8944
|
console.log(" \u2713 Claude Code hooks registered");
|
|
8955
8945
|
try {
|
|
8956
|
-
const mcpJwt =
|
|
8946
|
+
const mcpJwt = readFileSync8(join8(SYNKRO_DIR4, ".mcp-jwt"), "utf-8").trim();
|
|
8957
8947
|
if (mcpJwt) {
|
|
8958
8948
|
installMcpConfig({ gatewayUrl: "", bearerToken: mcpJwt, local: true });
|
|
8959
8949
|
console.log(" \u2713 Claude Code MCP registered");
|
|
@@ -8992,6 +8982,11 @@ function reconcileHarness() {
|
|
|
8992
8982
|
if (uninstallCursorHooks(cursorHooks)) console.log(" \u2717 Cursor hooks removed");
|
|
8993
8983
|
if (uninstallCursorMcpConfig()) console.log(" \u2717 Cursor MCP removed");
|
|
8994
8984
|
}
|
|
8985
|
+
if (sf.workers.claude != null || sf.workers.cursor != null) {
|
|
8986
|
+
const cw = Math.max(0, Math.floor(sf.workers.claude || 0));
|
|
8987
|
+
const curw = Math.max(0, Math.floor(sf.workers.cursor || 0));
|
|
8988
|
+
if (cw + curw > 0) return { claudeWorkers: cw, cursorWorkers: curw };
|
|
8989
|
+
}
|
|
8995
8990
|
const total = parseInt(process.env.SYNKRO_WORKERS_PER_POOL || "8", 10);
|
|
8996
8991
|
const providers = [];
|
|
8997
8992
|
if (sf.grader.pool === "cursor") {
|
|
@@ -9012,23 +9007,28 @@ async function syncSkillFiles() {
|
|
|
9012
9007
|
if (resolved.length === 0) return;
|
|
9013
9008
|
const mcpPort = process.env.SYNKRO_MCP_PORT || "18931";
|
|
9014
9009
|
for (const fp of resolved) {
|
|
9015
|
-
const
|
|
9016
|
-
if (!
|
|
9010
|
+
const content = readFileSync8(fp, "utf-8");
|
|
9011
|
+
if (!content.trim()) continue;
|
|
9012
|
+
const source = `skill:${fp.split("/").pop()}`;
|
|
9017
9013
|
try {
|
|
9018
9014
|
const resp = await fetch(`http://127.0.0.1:${mcpPort}/api/local/skills/sync`, {
|
|
9019
9015
|
method: "POST",
|
|
9020
9016
|
headers: { "Content-Type": "application/json" },
|
|
9021
|
-
body: JSON.stringify(
|
|
9022
|
-
signal: AbortSignal.timeout(
|
|
9017
|
+
body: JSON.stringify({ source, content }),
|
|
9018
|
+
signal: AbortSignal.timeout(65e3)
|
|
9023
9019
|
});
|
|
9024
9020
|
if (resp.ok) {
|
|
9025
9021
|
const result = await resp.json();
|
|
9026
|
-
|
|
9022
|
+
if (result.created > 0) {
|
|
9023
|
+
console.log(` \u2713 skill ${source}: ${result.created} new rules added`);
|
|
9024
|
+
} else {
|
|
9025
|
+
console.log(` \u2713 skill ${source}: ${result.message || "up to date"}`);
|
|
9026
|
+
}
|
|
9027
9027
|
} else {
|
|
9028
|
-
console.warn(` \u26A0 skill ${
|
|
9028
|
+
console.warn(` \u26A0 skill ${source}: sync failed (${resp.status})`);
|
|
9029
9029
|
}
|
|
9030
9030
|
} catch (e) {
|
|
9031
|
-
console.warn(` \u26A0 skill ${
|
|
9031
|
+
console.warn(` \u26A0 skill ${source}: ${e.message}`);
|
|
9032
9032
|
}
|
|
9033
9033
|
}
|
|
9034
9034
|
}
|
|
@@ -9060,7 +9060,7 @@ function extractSessionInsights(projectsDir) {
|
|
|
9060
9060
|
const sessionId = file.replace(".jsonl", "");
|
|
9061
9061
|
const filePath = join8(projectsDir, file);
|
|
9062
9062
|
try {
|
|
9063
|
-
const content =
|
|
9063
|
+
const content = readFileSync8(filePath, "utf-8");
|
|
9064
9064
|
const lines = content.split("\n").filter(Boolean);
|
|
9065
9065
|
for (let i = 0; i < lines.length; i++) {
|
|
9066
9066
|
try {
|
|
@@ -9136,7 +9136,7 @@ function extractTextContent(content) {
|
|
|
9136
9136
|
return "";
|
|
9137
9137
|
}
|
|
9138
9138
|
function parseTranscriptFile(filePath) {
|
|
9139
|
-
const content =
|
|
9139
|
+
const content = readFileSync8(filePath, "utf-8");
|
|
9140
9140
|
const lines = content.split("\n").filter(Boolean);
|
|
9141
9141
|
const messages = [];
|
|
9142
9142
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -9206,7 +9206,7 @@ async function syncTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
9206
9206
|
process.stdout.write(`\r Progress: ${i + 1}/${files.length} sessions (${totalMessages} messages embedded) `);
|
|
9207
9207
|
}
|
|
9208
9208
|
try {
|
|
9209
|
-
const content =
|
|
9209
|
+
const content = readFileSync8(join8(projectsDir, file), "utf-8");
|
|
9210
9210
|
const lineCount = content.split("\n").filter(Boolean).length;
|
|
9211
9211
|
writeFileSync7(join8(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
|
|
9212
9212
|
} catch {
|
|
@@ -9260,7 +9260,7 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
|
|
|
9260
9260
|
const sessionId = file.replace(".jsonl", "");
|
|
9261
9261
|
const filePath = join8(projectsDir, file);
|
|
9262
9262
|
try {
|
|
9263
|
-
const content =
|
|
9263
|
+
const content = readFileSync8(filePath, "utf-8");
|
|
9264
9264
|
const lineCount = content.split("\n").filter(Boolean).length;
|
|
9265
9265
|
writeFileSync7(join8(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
|
|
9266
9266
|
} catch {
|
|
@@ -9340,7 +9340,7 @@ rl.on('line', async (line) => {
|
|
|
9340
9340
|
});
|
|
9341
9341
|
|
|
9342
9342
|
// cli/local-cc/install.ts
|
|
9343
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as
|
|
9343
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync9, chmodSync as chmodSync3, copyFileSync as copyFileSync2, renameSync as renameSync4, unlinkSync as unlinkSync4, openSync, fsyncSync, closeSync } from "fs";
|
|
9344
9344
|
import { join as join9 } from "path";
|
|
9345
9345
|
import { homedir as homedir9 } from "os";
|
|
9346
9346
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
@@ -9379,7 +9379,7 @@ function safelyMutateClaudeJson(mutator) {
|
|
|
9379
9379
|
if (!existsSync11(CLAUDE_JSON_PATH)) {
|
|
9380
9380
|
return;
|
|
9381
9381
|
}
|
|
9382
|
-
const originalText =
|
|
9382
|
+
const originalText = readFileSync9(CLAUDE_JSON_PATH, "utf-8");
|
|
9383
9383
|
let parsed;
|
|
9384
9384
|
try {
|
|
9385
9385
|
parsed = JSON.parse(originalText);
|
|
@@ -9949,7 +9949,7 @@ var init_disconnect = __esm({
|
|
|
9949
9949
|
});
|
|
9950
9950
|
|
|
9951
9951
|
// cli/local-cc/turnLog.ts
|
|
9952
|
-
import { appendFileSync, existsSync as existsSync13, mkdirSync as mkdirSync10, openSync as openSync2, readFileSync as
|
|
9952
|
+
import { appendFileSync, existsSync as existsSync13, mkdirSync as mkdirSync10, openSync as openSync2, readFileSync as readFileSync10, readSync, closeSync as closeSync2, statSync as statSync2, watchFile, unwatchFile } from "fs";
|
|
9953
9953
|
import { dirname as dirname6, join as join11 } from "path";
|
|
9954
9954
|
import { homedir as homedir11 } from "os";
|
|
9955
9955
|
function truncate(s, max = PREVIEW_MAX) {
|
|
@@ -9991,7 +9991,7 @@ function readRecentTurns(n = 20) {
|
|
|
9991
9991
|
try {
|
|
9992
9992
|
const size = statSync2(TURN_LOG_PATH).size;
|
|
9993
9993
|
if (size === 0) return [];
|
|
9994
|
-
const text =
|
|
9994
|
+
const text = readFileSync10(TURN_LOG_PATH, "utf-8");
|
|
9995
9995
|
const lines = text.split("\n").filter(Boolean);
|
|
9996
9996
|
const lastN = lines.slice(-n).reverse();
|
|
9997
9997
|
return lastN.map((line) => {
|
|
@@ -10437,13 +10437,13 @@ var init_pueue = __esm({
|
|
|
10437
10437
|
});
|
|
10438
10438
|
|
|
10439
10439
|
// cli/local-cc/settings.ts
|
|
10440
|
-
import { existsSync as existsSync14, readFileSync as
|
|
10440
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
10441
10441
|
import { homedir as homedir13 } from "os";
|
|
10442
10442
|
import { join as join13 } from "path";
|
|
10443
10443
|
function isLocalCCEnabled() {
|
|
10444
10444
|
if (!existsSync14(CONFIG_PATH3)) return false;
|
|
10445
10445
|
try {
|
|
10446
|
-
const content =
|
|
10446
|
+
const content = readFileSync11(CONFIG_PATH3, "utf-8");
|
|
10447
10447
|
const match = content.match(/^SYNKRO_LOCAL_INFERENCE='([^']*)'/m);
|
|
10448
10448
|
return match?.[1] === "yes";
|
|
10449
10449
|
} catch {
|
|
@@ -10467,7 +10467,7 @@ import { spawnSync as spawnSync7 } from "child_process";
|
|
|
10467
10467
|
import { homedir as homedir14 } from "os";
|
|
10468
10468
|
import { join as join14 } from "path";
|
|
10469
10469
|
import { readFileSync as fsReadFileSync, existsSync as fsExistsSync } from "fs";
|
|
10470
|
-
import { existsSync as existsSync15, readFileSync as
|
|
10470
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
|
|
10471
10471
|
function deploymentMode() {
|
|
10472
10472
|
const env = (process.env.SYNKRO_DEPLOYMENT_MODE || "").toLowerCase();
|
|
10473
10473
|
if (env === "docker") return "docker";
|
|
@@ -10574,14 +10574,14 @@ TROUBLESHOOTING
|
|
|
10574
10574
|
}
|
|
10575
10575
|
function readGatewayUrl() {
|
|
10576
10576
|
if (existsSync15(CONFIG_PATH4)) {
|
|
10577
|
-
const m =
|
|
10577
|
+
const m = readFileSync12(CONFIG_PATH4, "utf-8").match(/^SYNKRO_GATEWAY_URL='([^']*)'/m);
|
|
10578
10578
|
if (m) return m[1];
|
|
10579
10579
|
}
|
|
10580
10580
|
return "https://api.synkro.sh";
|
|
10581
10581
|
}
|
|
10582
10582
|
function updateLocalInferenceFlag(enabled) {
|
|
10583
10583
|
if (!existsSync15(CONFIG_PATH4)) return;
|
|
10584
|
-
let content =
|
|
10584
|
+
let content = readFileSync12(CONFIG_PATH4, "utf-8");
|
|
10585
10585
|
const flag = enabled ? "yes" : "no";
|
|
10586
10586
|
if (content.includes("SYNKRO_LOCAL_INFERENCE=")) {
|
|
10587
10587
|
content = content.replace(/^SYNKRO_LOCAL_INFERENCE='[^']*'/m, `SYNKRO_LOCAL_INFERENCE='${flag}'`);
|
|
@@ -11124,13 +11124,13 @@ var config_exports = {};
|
|
|
11124
11124
|
__export(config_exports, {
|
|
11125
11125
|
configCommand: () => configCommand
|
|
11126
11126
|
});
|
|
11127
|
-
import { readFileSync as
|
|
11127
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, existsSync as existsSync16 } from "fs";
|
|
11128
11128
|
import { join as join15 } from "path";
|
|
11129
11129
|
import { homedir as homedir15 } from "os";
|
|
11130
11130
|
function readConfigEnv() {
|
|
11131
11131
|
if (!existsSync16(CONFIG_PATH5)) return {};
|
|
11132
11132
|
const out = {};
|
|
11133
|
-
for (const line of
|
|
11133
|
+
for (const line of readFileSync13(CONFIG_PATH5, "utf-8").split("\n")) {
|
|
11134
11134
|
const t = line.trim();
|
|
11135
11135
|
if (!t || t.startsWith("#")) continue;
|
|
11136
11136
|
const eq = t.indexOf("=");
|
|
@@ -11143,7 +11143,7 @@ function updateConfigValue(key, value) {
|
|
|
11143
11143
|
console.error("No config found. Run `synkro install` first.");
|
|
11144
11144
|
process.exit(1);
|
|
11145
11145
|
}
|
|
11146
|
-
const lines =
|
|
11146
|
+
const lines = readFileSync13(CONFIG_PATH5, "utf-8").split("\n");
|
|
11147
11147
|
const pattern = new RegExp(`^${key}=`);
|
|
11148
11148
|
let found = false;
|
|
11149
11149
|
const updated = lines.map((line) => {
|
|
@@ -11270,14 +11270,14 @@ var init_config = __esm({
|
|
|
11270
11270
|
});
|
|
11271
11271
|
|
|
11272
11272
|
// cli/bootstrap.js
|
|
11273
|
-
import { readFileSync as
|
|
11273
|
+
import { readFileSync as readFileSync14, existsSync as existsSync17 } from "fs";
|
|
11274
11274
|
import { resolve as resolve3 } from "path";
|
|
11275
11275
|
var envCandidates = [
|
|
11276
11276
|
resolve3(process.env.HOME ?? "", ".synkro", "config.env")
|
|
11277
11277
|
];
|
|
11278
11278
|
for (const envPath of envCandidates) {
|
|
11279
11279
|
if (!existsSync17(envPath)) continue;
|
|
11280
|
-
const envContent =
|
|
11280
|
+
const envContent = readFileSync14(envPath, "utf-8");
|
|
11281
11281
|
for (const line of envContent.split("\n")) {
|
|
11282
11282
|
const trimmed = line.trim();
|
|
11283
11283
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -11292,7 +11292,7 @@ var args = process.argv.slice(2);
|
|
|
11292
11292
|
var cmd = args[0] || "";
|
|
11293
11293
|
var subArgs = args.slice(1);
|
|
11294
11294
|
function printVersion() {
|
|
11295
|
-
console.log("1.6.
|
|
11295
|
+
console.log("1.6.37");
|
|
11296
11296
|
}
|
|
11297
11297
|
function printHelp2() {
|
|
11298
11298
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|