@synkro-sh/cli 1.7.64 → 1.7.66
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 +352 -398
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -132,7 +132,7 @@ function getIdentity() {
|
|
|
132
132
|
if (cached2) return cached2;
|
|
133
133
|
let cliVersion = "0.0.0";
|
|
134
134
|
try {
|
|
135
|
-
cliVersion = "1.7.
|
|
135
|
+
cliVersion = "1.7.66";
|
|
136
136
|
} catch {
|
|
137
137
|
}
|
|
138
138
|
const creds = loadCredentialsIdentity();
|
|
@@ -2252,7 +2252,13 @@ function loadMcpJwt(): string {
|
|
|
2252
2252
|
|
|
2253
2253
|
let _cfgCache: Record<string, string> | null = null;
|
|
2254
2254
|
function cfgVal(key: string): string {
|
|
2255
|
-
|
|
2255
|
+
// ~/.synkro/config.env (written by "synkro install") is AUTHORITATIVE for the keys it
|
|
2256
|
+
// defines. This hook runs under bun, which AUTO-LOADS a .env/.env.local from the repo
|
|
2257
|
+
// cwd into process.env — so a repo's own dev vars (e.g. SYNKRO_GATEWAY_URL=localhost for a
|
|
2258
|
+
// local "wrangler dev") would otherwise hijack the installed config and silently redirect
|
|
2259
|
+
// cloud grades to a dead gateway (fail-open, "nothing fires"). So read config.env FIRST and
|
|
2260
|
+
// only fall back to process.env for keys config.env doesn't set (e.g. SYNKRO_HOOK_FORMAT,
|
|
2261
|
+
// which is passed on the cursor hook command, never written to config.env).
|
|
2256
2262
|
if (!_cfgCache) {
|
|
2257
2263
|
_cfgCache = {};
|
|
2258
2264
|
try {
|
|
@@ -2263,7 +2269,8 @@ function cfgVal(key: string): string {
|
|
|
2263
2269
|
}
|
|
2264
2270
|
} catch {}
|
|
2265
2271
|
}
|
|
2266
|
-
|
|
2272
|
+
if (_cfgCache[key]) return _cfgCache[key];
|
|
2273
|
+
return process.env[key] || '';
|
|
2267
2274
|
}
|
|
2268
2275
|
function deployIsCloud(): boolean { return cfgVal('SYNKRO_DEPLOY_LOCATION') === 'cloud'; }
|
|
2269
2276
|
|
|
@@ -5863,87 +5870,6 @@ var init_setupToken = __esm({
|
|
|
5863
5870
|
}
|
|
5864
5871
|
});
|
|
5865
5872
|
|
|
5866
|
-
// cli/local-cc/codexCloudSetup.ts
|
|
5867
|
-
var codexCloudSetup_exports = {};
|
|
5868
|
-
__export(codexCloudSetup_exports, {
|
|
5869
|
-
setupCodexCloud: () => setupCodexCloud
|
|
5870
|
-
});
|
|
5871
|
-
import { spawn as nodeSpawn2, spawnSync as spawnSync4 } from "child_process";
|
|
5872
|
-
import { readFileSync as readFileSync16, mkdirSync as mkdirSync12, rmSync, existsSync as existsSync19 } from "fs";
|
|
5873
|
-
import { homedir as homedir16 } from "os";
|
|
5874
|
-
import { join as join16 } from "path";
|
|
5875
|
-
function findCodexBinary() {
|
|
5876
|
-
if (process.env.SYNKRO_CODEX_BIN) return process.env.SYNKRO_CODEX_BIN;
|
|
5877
|
-
const r = spawnSync4("which", ["codex"], { encoding: "utf-8" });
|
|
5878
|
-
const p = (r.stdout || "").trim().split("\n")[0];
|
|
5879
|
-
return p || null;
|
|
5880
|
-
}
|
|
5881
|
-
function runCodexLogin(codexBin) {
|
|
5882
|
-
mkdirSync12(CODEX_CLOUD_HOME, { recursive: true, mode: 448 });
|
|
5883
|
-
return new Promise((resolve4, reject) => {
|
|
5884
|
-
const proc = nodeSpawn2(codexBin, ["login"], {
|
|
5885
|
-
stdio: "inherit",
|
|
5886
|
-
env: { ...process.env, CODEX_HOME: CODEX_CLOUD_HOME }
|
|
5887
|
-
});
|
|
5888
|
-
proc.on("error", (err) => reject(new Error(`failed to spawn codex login: ${err.message}`)));
|
|
5889
|
-
proc.on("close", (code) => code === 0 ? resolve4() : reject(new Error(`codex login exited with code ${code}`)));
|
|
5890
|
-
});
|
|
5891
|
-
}
|
|
5892
|
-
async function setupCodexCloud(gatewayUrl, bearerToken, onStatus) {
|
|
5893
|
-
const codexBin = findCodexBinary();
|
|
5894
|
-
if (!codexBin) {
|
|
5895
|
-
return { ok: false, error: "Codex CLI not found on PATH. Install Codex (https://developers.openai.com/codex), then re-run `synkro install`. (Set SYNKRO_CODEX_BIN to override the binary path.)" };
|
|
5896
|
-
}
|
|
5897
|
-
onStatus?.("Opening your browser to authorize your Codex subscription for Synkro Cloud\u2026");
|
|
5898
|
-
try {
|
|
5899
|
-
await runCodexLogin(codexBin);
|
|
5900
|
-
} catch (e) {
|
|
5901
|
-
return { ok: false, error: `Codex login failed: ${e.message}` };
|
|
5902
|
-
}
|
|
5903
|
-
const authPath = join16(CODEX_CLOUD_HOME, "auth.json");
|
|
5904
|
-
if (!existsSync19(authPath)) {
|
|
5905
|
-
return { ok: false, error: "codex login completed but no auth.json was written \u2014 did the browser approval finish?" };
|
|
5906
|
-
}
|
|
5907
|
-
let auth;
|
|
5908
|
-
try {
|
|
5909
|
-
auth = JSON.parse(readFileSync16(authPath, "utf-8"));
|
|
5910
|
-
} catch (e) {
|
|
5911
|
-
return { ok: false, error: `could not read codex auth.json: ${e.message}` };
|
|
5912
|
-
}
|
|
5913
|
-
if (!auth || typeof auth !== "object" || !auth.tokens?.refresh_token) {
|
|
5914
|
-
return { ok: false, error: "codex auth.json has no refresh token \u2014 cloud refresh would fail. Re-run login." };
|
|
5915
|
-
}
|
|
5916
|
-
onStatus?.("Connecting your Codex session to Synkro Cloud\u2026");
|
|
5917
|
-
let resp;
|
|
5918
|
-
try {
|
|
5919
|
-
resp = await fetch(`${gatewayUrl.replace(/\/+$/, "")}/codex/seed`, {
|
|
5920
|
-
method: "POST",
|
|
5921
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearerToken}` },
|
|
5922
|
-
body: JSON.stringify({ auth })
|
|
5923
|
-
});
|
|
5924
|
-
} catch (e) {
|
|
5925
|
-
return { ok: false, error: `failed to reach Synkro API: ${e.message}` };
|
|
5926
|
-
}
|
|
5927
|
-
if (!resp.ok) {
|
|
5928
|
-
const detail = await resp.text().catch(() => "");
|
|
5929
|
-
return { ok: false, error: `seed rejected (${resp.status}): ${detail.slice(0, 200)}` };
|
|
5930
|
-
}
|
|
5931
|
-
try {
|
|
5932
|
-
rmSync(CODEX_CLOUD_HOME, { recursive: true, force: true });
|
|
5933
|
-
} catch {
|
|
5934
|
-
}
|
|
5935
|
-
onStatus?.("\u2713 Codex subscription connected to Synkro Cloud.");
|
|
5936
|
-
return { ok: true };
|
|
5937
|
-
}
|
|
5938
|
-
var SYNKRO_DIR9, CODEX_CLOUD_HOME;
|
|
5939
|
-
var init_codexCloudSetup = __esm({
|
|
5940
|
-
"cli/local-cc/codexCloudSetup.ts"() {
|
|
5941
|
-
"use strict";
|
|
5942
|
-
SYNKRO_DIR9 = join16(homedir16(), ".synkro");
|
|
5943
|
-
CODEX_CLOUD_HOME = join16(SYNKRO_DIR9, "codex-cloud-session");
|
|
5944
|
-
}
|
|
5945
|
-
});
|
|
5946
|
-
|
|
5947
5873
|
// cli/commands/setupGithub.ts
|
|
5948
5874
|
var setupGithub_exports = {};
|
|
5949
5875
|
__export(setupGithub_exports, {
|
|
@@ -5953,14 +5879,14 @@ __export(setupGithub_exports, {
|
|
|
5953
5879
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
5954
5880
|
import { stdin as input, stdout as output } from "process";
|
|
5955
5881
|
import { execSync as execSync5 } from "child_process";
|
|
5956
|
-
import { existsSync as
|
|
5957
|
-
import { homedir as
|
|
5958
|
-
import { join as
|
|
5882
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
|
|
5883
|
+
import { homedir as homedir16, platform as platform5 } from "os";
|
|
5884
|
+
import { join as join16 } from "path";
|
|
5959
5885
|
import { execFile as execFile2 } from "child_process";
|
|
5960
5886
|
function readConfig() {
|
|
5961
|
-
if (!
|
|
5887
|
+
if (!existsSync19(CONFIG_PATH3)) return {};
|
|
5962
5888
|
const out = {};
|
|
5963
|
-
for (const line of
|
|
5889
|
+
for (const line of readFileSync16(CONFIG_PATH3, "utf-8").split("\n")) {
|
|
5964
5890
|
const t = line.trim();
|
|
5965
5891
|
if (!t || t.startsWith("#")) continue;
|
|
5966
5892
|
const eq = t.indexOf("=");
|
|
@@ -6260,15 +6186,15 @@ Will push secrets to ${selected.length} repo(s):`);
|
|
|
6260
6186
|
console.log(`Secrets pushed: ${SECRET_NAMES.CLAUDE_OAUTH}, ${SECRET_NAMES.SYNKRO_API_KEY}`);
|
|
6261
6187
|
console.log("Open a PR on any selected repo to trigger your first Synkro scan.");
|
|
6262
6188
|
}
|
|
6263
|
-
var
|
|
6189
|
+
var SYNKRO_DIR9, CONFIG_PATH3;
|
|
6264
6190
|
var init_setupGithub = __esm({
|
|
6265
6191
|
"cli/commands/setupGithub.ts"() {
|
|
6266
6192
|
"use strict";
|
|
6267
6193
|
init_githubSetup();
|
|
6268
6194
|
init_stub();
|
|
6269
6195
|
init_setupToken();
|
|
6270
|
-
|
|
6271
|
-
CONFIG_PATH3 =
|
|
6196
|
+
SYNKRO_DIR9 = join16(homedir16(), ".synkro");
|
|
6197
|
+
CONFIG_PATH3 = join16(SYNKRO_DIR9, "config.env");
|
|
6272
6198
|
}
|
|
6273
6199
|
});
|
|
6274
6200
|
|
|
@@ -6287,9 +6213,9 @@ __export(install_exports, {
|
|
|
6287
6213
|
syncSkillFiles: () => syncSkillFiles,
|
|
6288
6214
|
writeHookScripts: () => writeHookScripts
|
|
6289
6215
|
});
|
|
6290
|
-
import { existsSync as
|
|
6291
|
-
import { homedir as
|
|
6292
|
-
import { join as
|
|
6216
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync12, writeFileSync as writeFileSync13, chmodSync as chmodSync3, readFileSync as readFileSync17, readdirSync as readdirSync3, unlinkSync as unlinkSync6, statSync as statSync2 } from "fs";
|
|
6217
|
+
import { homedir as homedir17 } from "os";
|
|
6218
|
+
import { join as join17 } from "path";
|
|
6293
6219
|
import { execSync as execSync6 } from "child_process";
|
|
6294
6220
|
import { createInterface as createInterface3 } from "readline";
|
|
6295
6221
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -6376,15 +6302,20 @@ async function promptCursorApiKey(opts) {
|
|
|
6376
6302
|
console.log(" \u26A0 Skipped \u2014 Cursor workers will be idle. Re-run install or pass --cursor-api-key=\u2026 later.");
|
|
6377
6303
|
}
|
|
6378
6304
|
}
|
|
6379
|
-
async function promptDeployLocation() {
|
|
6380
|
-
if (!process.stdin.isTTY) return
|
|
6305
|
+
async function promptDeployLocation(current = "local") {
|
|
6306
|
+
if (!process.stdin.isTTY) return current;
|
|
6307
|
+
const other = current === "cloud" ? "local" : "cloud";
|
|
6381
6308
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
6382
6309
|
return new Promise((resolve4) => {
|
|
6383
6310
|
rl.question(
|
|
6384
|
-
|
|
6311
|
+
`Where should Synkro run?
|
|
6312
|
+
local \u2014 a grading container on this machine (Docker)
|
|
6313
|
+
cloud \u2014 a private container hosted by Synkro (Cloudflare)
|
|
6314
|
+
Both use your own Claude key. Choose [${current}] / ${other}: `,
|
|
6385
6315
|
(answer) => {
|
|
6386
6316
|
rl.close();
|
|
6387
|
-
|
|
6317
|
+
const a = answer.trim().toLowerCase();
|
|
6318
|
+
resolve4(a === "cloud" ? "cloud" : a === "local" ? "local" : current);
|
|
6388
6319
|
}
|
|
6389
6320
|
);
|
|
6390
6321
|
});
|
|
@@ -6419,52 +6350,38 @@ coding patterns and the dashboard shows full history. (Y/n) `
|
|
|
6419
6350
|
rl.close();
|
|
6420
6351
|
}
|
|
6421
6352
|
}
|
|
6422
|
-
async function promptCodexCloudSetup() {
|
|
6423
|
-
if (!process.stdin.isTTY) return false;
|
|
6424
|
-
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
6425
|
-
return new Promise((resolve4) => {
|
|
6426
|
-
rl.question(
|
|
6427
|
-
"Connect a Codex (ChatGPT subscription) session for cloud grading? This opens a\nbrowser to authorize; your subscription is stored securely and refreshed for you. (y/N) ",
|
|
6428
|
-
(answer) => {
|
|
6429
|
-
rl.close();
|
|
6430
|
-
const a = answer.trim().toLowerCase();
|
|
6431
|
-
resolve4(a === "y" || a === "yes");
|
|
6432
|
-
}
|
|
6433
|
-
);
|
|
6434
|
-
});
|
|
6435
|
-
}
|
|
6436
6353
|
function ensureSynkroDir() {
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6354
|
+
mkdirSync12(SYNKRO_DIR10, { recursive: true });
|
|
6355
|
+
mkdirSync12(HOOKS_DIR, { recursive: true });
|
|
6356
|
+
mkdirSync12(BIN_DIR, { recursive: true });
|
|
6357
|
+
mkdirSync12(OFFSETS_DIR, { recursive: true });
|
|
6358
|
+
mkdirSync12(join17(SYNKRO_DIR10, "sessions"), { recursive: true });
|
|
6442
6359
|
}
|
|
6443
6360
|
function writeHookScripts() {
|
|
6444
|
-
const installExtractCorePath =
|
|
6445
|
-
const bashScriptPath =
|
|
6446
|
-
const skillJudgeScriptPath =
|
|
6447
|
-
const cursorSkillJudgePath =
|
|
6448
|
-
const bashFollowupScriptPath =
|
|
6449
|
-
const editPrecheckScriptPath =
|
|
6450
|
-
const cwePrecheckScriptPath =
|
|
6451
|
-
const cvePrecheckScriptPath =
|
|
6452
|
-
const planJudgeScriptPath =
|
|
6453
|
-
const agentJudgeScriptPath =
|
|
6454
|
-
const stopSummaryScriptPath =
|
|
6455
|
-
const sessionStartScriptPath =
|
|
6456
|
-
const transcriptSyncScriptPath =
|
|
6457
|
-
const userPromptSubmitScriptPath =
|
|
6458
|
-
const commonScriptPath =
|
|
6459
|
-
const commonBashScriptPath =
|
|
6460
|
-
const installScanScriptPath =
|
|
6461
|
-
const cursorBashJudgePath =
|
|
6462
|
-
const cursorEditCapturePath =
|
|
6463
|
-
const cursorAgentCapturePath =
|
|
6464
|
-
const mcpStdioProxyPath =
|
|
6465
|
-
const taskActivateIntentScriptPath =
|
|
6466
|
-
const mcpGateScriptPath =
|
|
6467
|
-
const stubCommonPath =
|
|
6361
|
+
const installExtractCorePath = join17(HOOKS_DIR, "installExtractCore.ts");
|
|
6362
|
+
const bashScriptPath = join17(HOOKS_DIR, "cc-bash-judge.ts");
|
|
6363
|
+
const skillJudgeScriptPath = join17(HOOKS_DIR, "cc-skill-judge.ts");
|
|
6364
|
+
const cursorSkillJudgePath = join17(HOOKS_DIR, "cursor-skill-judge.ts");
|
|
6365
|
+
const bashFollowupScriptPath = join17(HOOKS_DIR, "cc-bash-followup.ts");
|
|
6366
|
+
const editPrecheckScriptPath = join17(HOOKS_DIR, "cc-edit-precheck.ts");
|
|
6367
|
+
const cwePrecheckScriptPath = join17(HOOKS_DIR, "cc-cwe-precheck.ts");
|
|
6368
|
+
const cvePrecheckScriptPath = join17(HOOKS_DIR, "cc-cve-precheck.ts");
|
|
6369
|
+
const planJudgeScriptPath = join17(HOOKS_DIR, "cc-plan-judge.ts");
|
|
6370
|
+
const agentJudgeScriptPath = join17(HOOKS_DIR, "cc-agent-judge.ts");
|
|
6371
|
+
const stopSummaryScriptPath = join17(HOOKS_DIR, "cc-stop-summary.ts");
|
|
6372
|
+
const sessionStartScriptPath = join17(HOOKS_DIR, "cc-session-start.ts");
|
|
6373
|
+
const transcriptSyncScriptPath = join17(HOOKS_DIR, "cc-transcript-sync.ts");
|
|
6374
|
+
const userPromptSubmitScriptPath = join17(HOOKS_DIR, "cc-user-prompt-submit.ts");
|
|
6375
|
+
const commonScriptPath = join17(HOOKS_DIR, "_synkro-common.ts");
|
|
6376
|
+
const commonBashScriptPath = join17(HOOKS_DIR, "_synkro-common.sh");
|
|
6377
|
+
const installScanScriptPath = join17(HOOKS_DIR, "cc-install-scan.ts");
|
|
6378
|
+
const cursorBashJudgePath = join17(HOOKS_DIR, "cursor-bash-judge.ts");
|
|
6379
|
+
const cursorEditCapturePath = join17(HOOKS_DIR, "cursor-edit-capture.ts");
|
|
6380
|
+
const cursorAgentCapturePath = join17(HOOKS_DIR, "cursor-agent-capture.ts");
|
|
6381
|
+
const mcpStdioProxyPath = join17(HOOKS_DIR, "mcp-stdio-proxy.ts");
|
|
6382
|
+
const taskActivateIntentScriptPath = join17(HOOKS_DIR, "cc-task-activate-intent.ts");
|
|
6383
|
+
const mcpGateScriptPath = join17(HOOKS_DIR, "cc-mcp-gate.ts");
|
|
6384
|
+
const stubCommonPath = join17(HOOKS_DIR, "_synkro-stub-common.ts");
|
|
6468
6385
|
const stubFiles = [
|
|
6469
6386
|
[stubCommonPath, STUB_COMMON_TS],
|
|
6470
6387
|
[bashScriptPath, STUB_BASH_JUDGE_TS],
|
|
@@ -6495,7 +6412,7 @@ function writeHookScripts() {
|
|
|
6495
6412
|
chmodSync3(mcpStdioProxyPath, 493);
|
|
6496
6413
|
for (const stale of ["_synkro-common.ts", "_synkro-common.sh", "installExtractCore.ts"]) {
|
|
6497
6414
|
try {
|
|
6498
|
-
unlinkSync6(
|
|
6415
|
+
unlinkSync6(join17(HOOKS_DIR, stale));
|
|
6499
6416
|
} catch {
|
|
6500
6417
|
}
|
|
6501
6418
|
}
|
|
@@ -6530,11 +6447,11 @@ function shellQuoteSingle2(value) {
|
|
|
6530
6447
|
}
|
|
6531
6448
|
function resolveSynkroBundle() {
|
|
6532
6449
|
const scriptPath = process.argv[1];
|
|
6533
|
-
if (scriptPath &&
|
|
6450
|
+
if (scriptPath && existsSync20(scriptPath)) return scriptPath;
|
|
6534
6451
|
return null;
|
|
6535
6452
|
}
|
|
6536
6453
|
function writeConfigEnv(opts) {
|
|
6537
|
-
const credsPath =
|
|
6454
|
+
const credsPath = join17(SYNKRO_DIR10, "credentials.json");
|
|
6538
6455
|
const safeGateway = sanitizeConfigValue(opts.gatewayUrl);
|
|
6539
6456
|
const safeUserId = sanitizeConfigValue(opts.userId);
|
|
6540
6457
|
const safeOrgId = sanitizeConfigValue(opts.orgId);
|
|
@@ -6550,7 +6467,7 @@ function writeConfigEnv(opts) {
|
|
|
6550
6467
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle2(credsPath)}`,
|
|
6551
6468
|
`SYNKRO_TIER=${shellQuoteSingle2(safeTier)}`,
|
|
6552
6469
|
`SYNKRO_INFERENCE=${shellQuoteSingle2(safeInference)}`,
|
|
6553
|
-
`SYNKRO_VERSION=${shellQuoteSingle2("1.7.
|
|
6470
|
+
`SYNKRO_VERSION=${shellQuoteSingle2("1.7.66")}`
|
|
6554
6471
|
];
|
|
6555
6472
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle2(safeSynkroBin)}`);
|
|
6556
6473
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle2(safeUserId)}`);
|
|
@@ -6583,7 +6500,7 @@ async function getOrMintCloudToken(gatewayUrl) {
|
|
|
6583
6500
|
assertGatewayAllowed(gatewayUrl);
|
|
6584
6501
|
let stored = "";
|
|
6585
6502
|
try {
|
|
6586
|
-
stored =
|
|
6503
|
+
stored = readFileSync17(CLOUD_JWT_PATH, "utf-8").trim();
|
|
6587
6504
|
} catch {
|
|
6588
6505
|
}
|
|
6589
6506
|
if (stored && !jwtExpired(stored)) return stored;
|
|
@@ -6614,23 +6531,39 @@ async function provisionCloudContainer(opts) {
|
|
|
6614
6531
|
process.exit(1);
|
|
6615
6532
|
}
|
|
6616
6533
|
console.log(" Validating Claude token...");
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6534
|
+
let validated = false;
|
|
6535
|
+
let authRejected = null;
|
|
6536
|
+
let lastErr = "";
|
|
6537
|
+
for (let attempt = 1; attempt <= 2 && !validated; attempt++) {
|
|
6538
|
+
try {
|
|
6539
|
+
const out = execSync6('claude --print --output-format json "say ok"', {
|
|
6540
|
+
env: { ...process.env, CLAUDE_CODE_OAUTH_TOKEN: setupToken },
|
|
6541
|
+
encoding: "utf-8",
|
|
6542
|
+
timeout: 6e4,
|
|
6543
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
6544
|
+
});
|
|
6545
|
+
const result = JSON.parse(out);
|
|
6546
|
+
if (result.is_error) {
|
|
6547
|
+
authRejected = result.result || "auth failed";
|
|
6548
|
+
break;
|
|
6549
|
+
}
|
|
6550
|
+
validated = true;
|
|
6551
|
+
} catch (err) {
|
|
6552
|
+
lastErr = err instanceof Error ? err.message : String(err);
|
|
6553
|
+
if (attempt < 2) console.log(` \u23F3 validation slow (${lastErr.slice(0, 30)}\u2026) \u2014 retrying once...`);
|
|
6554
|
+
}
|
|
6555
|
+
}
|
|
6556
|
+
if (authRejected) {
|
|
6557
|
+
console.error(` \u2717 Claude token rejected: ${authRejected}`);
|
|
6558
|
+
console.error(" Re-run install to re-authorize (wrong account or no API credits) \u2014 nothing was stored.");
|
|
6632
6559
|
process.exit(1);
|
|
6633
6560
|
}
|
|
6561
|
+
if (validated) {
|
|
6562
|
+
console.log(" \u2713 Claude token validated.\n");
|
|
6563
|
+
} else {
|
|
6564
|
+
console.warn(` \u26A0 Couldn't confirm the token locally in time (${lastErr.slice(0, 50)}).`);
|
|
6565
|
+
console.warn(" Proceeding \u2014 the cloud smoke-grade below verifies it end-to-end in the container.\n");
|
|
6566
|
+
}
|
|
6634
6567
|
const repo = detectGitRepo2() || void 0;
|
|
6635
6568
|
const sf = readFullSynkroFile();
|
|
6636
6569
|
const harness = [];
|
|
@@ -6642,7 +6575,7 @@ async function provisionCloudContainer(opts) {
|
|
|
6642
6575
|
let cursorApiKey = "";
|
|
6643
6576
|
if (cursorTotal > 0) {
|
|
6644
6577
|
try {
|
|
6645
|
-
cursorApiKey =
|
|
6578
|
+
cursorApiKey = readFileSync17(join17(SYNKRO_DIR10, "cursor-creds", "api-key"), "utf-8").trim();
|
|
6646
6579
|
} catch {
|
|
6647
6580
|
}
|
|
6648
6581
|
}
|
|
@@ -6799,8 +6732,8 @@ async function verifyCloudGrader(jwt2) {
|
|
|
6799
6732
|
}
|
|
6800
6733
|
function readPersistedDeployLocation() {
|
|
6801
6734
|
try {
|
|
6802
|
-
if (
|
|
6803
|
-
const m =
|
|
6735
|
+
if (existsSync20(CONFIG_PATH4)) {
|
|
6736
|
+
const m = readFileSync17(CONFIG_PATH4, "utf-8").match(/^SYNKRO_DEPLOY_LOCATION='([^']*)'/m);
|
|
6804
6737
|
if (m?.[1] === "cloud") return "cloud";
|
|
6805
6738
|
}
|
|
6806
6739
|
} catch {
|
|
@@ -6808,8 +6741,8 @@ function readPersistedDeployLocation() {
|
|
|
6808
6741
|
return "local";
|
|
6809
6742
|
}
|
|
6810
6743
|
function updateConfigEnvLocation(location) {
|
|
6811
|
-
if (!
|
|
6812
|
-
let env =
|
|
6744
|
+
if (!existsSync20(CONFIG_PATH4)) return;
|
|
6745
|
+
let env = readFileSync17(CONFIG_PATH4, "utf-8");
|
|
6813
6746
|
const set = (k, v) => {
|
|
6814
6747
|
const re = new RegExp(`^${k}=.*$`, "m");
|
|
6815
6748
|
const line = `${k}='${v}'`;
|
|
@@ -6824,7 +6757,7 @@ async function applyMcpConfig(opts) {
|
|
|
6824
6757
|
if (!opts.hasClaudeCode && !opts.hasCursor) return;
|
|
6825
6758
|
let mcpJwt = "";
|
|
6826
6759
|
try {
|
|
6827
|
-
mcpJwt =
|
|
6760
|
+
mcpJwt = readFileSync17(join17(SYNKRO_DIR10, ".mcp-jwt"), "utf-8").trim();
|
|
6828
6761
|
} catch {
|
|
6829
6762
|
}
|
|
6830
6763
|
if (!mcpJwt) {
|
|
@@ -6859,13 +6792,15 @@ async function applyMcpConfig(opts) {
|
|
|
6859
6792
|
}
|
|
6860
6793
|
async function reconcileDeployLocation() {
|
|
6861
6794
|
const sf = readFullSynkroFile();
|
|
6862
|
-
const
|
|
6795
|
+
const tomlLoc = sf?.grader.location === "cloud" ? "cloud" : "local";
|
|
6863
6796
|
const current = readPersistedDeployLocation();
|
|
6797
|
+
const desired = await promptDeployLocation(current || tomlLoc);
|
|
6798
|
+
if (desired !== tomlLoc) updateSynkroTomlLocation(desired);
|
|
6864
6799
|
if (desired === current) return { location: desired, changed: false };
|
|
6865
6800
|
const hasClaudeCode = sf ? sf.harness.includes("claude-code") : true;
|
|
6866
6801
|
const hasCursor = sf ? sf.harness.includes("cursor") : false;
|
|
6867
6802
|
console.log(`
|
|
6868
|
-
|
|
6803
|
+
Deploy location: ${current || "(none)"} \u2192 ${desired}
|
|
6869
6804
|
`);
|
|
6870
6805
|
if (!isAuthenticated()) {
|
|
6871
6806
|
console.log(" Opening browser for Synkro auth...");
|
|
@@ -6942,8 +6877,8 @@ function resolveDeploymentMode() {
|
|
|
6942
6877
|
const envOverride = process.env.SYNKRO_DEPLOYMENT_MODE?.toLowerCase();
|
|
6943
6878
|
if (envOverride === "bare-host" || envOverride === "docker") return envOverride;
|
|
6944
6879
|
try {
|
|
6945
|
-
if (
|
|
6946
|
-
const m =
|
|
6880
|
+
if (existsSync20(CONFIG_PATH4)) {
|
|
6881
|
+
const m = readFileSync17(CONFIG_PATH4, "utf-8").match(/^SYNKRO_DEPLOYMENT_MODE='([^']*)'/m);
|
|
6947
6882
|
const val = m?.[1]?.toLowerCase();
|
|
6948
6883
|
if (val === "bare-host" || val === "docker") return val;
|
|
6949
6884
|
}
|
|
@@ -6970,16 +6905,16 @@ function collectLocalMetadata(includeClaudeCode = true) {
|
|
|
6970
6905
|
meta.cc_version = execSync6("claude --version", { encoding: "utf-8", timeout: 5e3 }).trim().split("\n")[0];
|
|
6971
6906
|
} catch {
|
|
6972
6907
|
}
|
|
6973
|
-
const claudeDir =
|
|
6908
|
+
const claudeDir = join17(homedir17(), ".claude");
|
|
6974
6909
|
try {
|
|
6975
|
-
const settings = JSON.parse(
|
|
6910
|
+
const settings = JSON.parse(readFileSync17(join17(claudeDir, "settings.json"), "utf-8"));
|
|
6976
6911
|
const plugins = Object.keys(settings.enabledPlugins ?? {}).filter((k) => settings.enabledPlugins[k]);
|
|
6977
6912
|
if (plugins.length) meta.enabled_plugins = plugins;
|
|
6978
6913
|
if (settings.permissions?.defaultMode) meta.permissions_mode = settings.permissions.defaultMode;
|
|
6979
6914
|
} catch {
|
|
6980
6915
|
}
|
|
6981
6916
|
try {
|
|
6982
|
-
const mcpCache = JSON.parse(
|
|
6917
|
+
const mcpCache = JSON.parse(readFileSync17(join17(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
|
|
6983
6918
|
const mcpNames = Object.keys(mcpCache);
|
|
6984
6919
|
if (mcpNames.length) meta.mcp_servers = mcpNames;
|
|
6985
6920
|
} catch {
|
|
@@ -6991,10 +6926,10 @@ function collectLocalMetadata(includeClaudeCode = true) {
|
|
|
6991
6926
|
} catch {
|
|
6992
6927
|
}
|
|
6993
6928
|
try {
|
|
6994
|
-
const sessionsDir =
|
|
6929
|
+
const sessionsDir = join17(claudeDir, "sessions");
|
|
6995
6930
|
const files = readdirSync3(sessionsDir).filter((f) => f.endsWith(".json")).slice(-5);
|
|
6996
6931
|
for (const f of files) {
|
|
6997
|
-
const s = JSON.parse(
|
|
6932
|
+
const s = JSON.parse(readFileSync17(join17(sessionsDir, f), "utf-8"));
|
|
6998
6933
|
if (s.version) {
|
|
6999
6934
|
meta.cc_version = meta.cc_version || s.version;
|
|
7000
6935
|
break;
|
|
@@ -7127,9 +7062,11 @@ async function installCommand(opts = {}) {
|
|
|
7127
7062
|
(a) => a.kind === "claude_code" && wantCC || a.kind === "cursor" && wantCursor
|
|
7128
7063
|
);
|
|
7129
7064
|
if (agents.length === 0 && detected.length > 0) agents = detected;
|
|
7130
|
-
deployLocation = existingSynkro.grader.location === "cloud" ? "cloud" : "local";
|
|
7131
7065
|
gradingMode = existingSynkro.grader.mode === "byok" ? "byok" : "local";
|
|
7066
|
+
const tomlLocation = existingSynkro.grader.location === "cloud" ? "cloud" : "local";
|
|
7067
|
+
deployLocation = await promptDeployLocation(tomlLocation);
|
|
7132
7068
|
storageMode = deployLocation === "cloud" ? "cloud" : "local";
|
|
7069
|
+
if (deployLocation !== tomlLocation) updateSynkroTomlLocation(deployLocation);
|
|
7133
7070
|
console.log(`Using .synkro config:`);
|
|
7134
7071
|
for (const w of existingSynkro.warnings) console.warn(` \u26A0 ${w}`);
|
|
7135
7072
|
console.log(` harness: ${existingSynkro.harness.join(", ")}`);
|
|
@@ -7190,7 +7127,7 @@ async function installCommand(opts = {}) {
|
|
|
7190
7127
|
await setTelemetryState({ enabled: true, remoteFlushEnabled: telemetryConsent });
|
|
7191
7128
|
emit("install", {
|
|
7192
7129
|
phase: "started",
|
|
7193
|
-
cli_version_to: "1.7.
|
|
7130
|
+
cli_version_to: "1.7.66",
|
|
7194
7131
|
agents_detected: agents.map((a) => a.kind),
|
|
7195
7132
|
with_github: false,
|
|
7196
7133
|
with_local_cc: false,
|
|
@@ -7202,9 +7139,9 @@ async function installCommand(opts = {}) {
|
|
|
7202
7139
|
const scripts = writeHookScripts();
|
|
7203
7140
|
console.log("Wrote hook scripts to ~/.synkro/hooks/\n");
|
|
7204
7141
|
for (const mode of ["edit", "bash"]) {
|
|
7205
|
-
const pidFile =
|
|
7142
|
+
const pidFile = join17(SYNKRO_DIR10, "daemon", mode, "daemon.pid");
|
|
7206
7143
|
try {
|
|
7207
|
-
const pid = parseInt(
|
|
7144
|
+
const pid = parseInt(readFileSync17(pidFile, "utf-8").trim(), 10);
|
|
7208
7145
|
if (pid > 0) {
|
|
7209
7146
|
process.kill(pid, "SIGTERM");
|
|
7210
7147
|
console.log(`Stopped stale ${mode} grader daemon (pid ${pid})`);
|
|
@@ -7289,7 +7226,7 @@ async function installCommand(opts = {}) {
|
|
|
7289
7226
|
if (mintResp.ok) {
|
|
7290
7227
|
const minted = await mintResp.json();
|
|
7291
7228
|
mcpJwt = minted.token;
|
|
7292
|
-
writeFileSync13(
|
|
7229
|
+
writeFileSync13(join17(SYNKRO_DIR10, ".mcp-jwt"), mcpJwt + "\n", { mode: 384 });
|
|
7293
7230
|
} else {
|
|
7294
7231
|
console.warn(" \u26A0 Could not mint MCP token \u2014 local server will reject requests until re-installed.");
|
|
7295
7232
|
}
|
|
@@ -7317,7 +7254,7 @@ async function installCommand(opts = {}) {
|
|
|
7317
7254
|
throw new Error(`mcp-token mint failed (${mintResp.status}): ${errText.slice(0, 200)}`);
|
|
7318
7255
|
}
|
|
7319
7256
|
const minted = await mintResp.json();
|
|
7320
|
-
writeFileSync13(
|
|
7257
|
+
writeFileSync13(join17(SYNKRO_DIR10, ".mcp-jwt"), minted.token + "\n", { mode: 384 });
|
|
7321
7258
|
const mcp = installMcpConfig({ gatewayUrl, bearerToken: minted.token });
|
|
7322
7259
|
console.log(`Registered Synkro guardrails MCP server in ${mcp.path}`);
|
|
7323
7260
|
console.log(` url: ${mcp.url}`);
|
|
@@ -7334,8 +7271,8 @@ async function installCommand(opts = {}) {
|
|
|
7334
7271
|
if (hasCursor && !opts.noMcp) {
|
|
7335
7272
|
try {
|
|
7336
7273
|
if (useLocalMcp) {
|
|
7337
|
-
const jwtPath =
|
|
7338
|
-
if (!
|
|
7274
|
+
const jwtPath = join17(SYNKRO_DIR10, ".mcp-jwt");
|
|
7275
|
+
if (!existsSync20(jwtPath)) {
|
|
7339
7276
|
const mintResp = await fetch(`${gatewayUrl}/api/v1/cli/mcp-token`, {
|
|
7340
7277
|
method: "POST",
|
|
7341
7278
|
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
@@ -7363,7 +7300,7 @@ async function installCommand(opts = {}) {
|
|
|
7363
7300
|
throw new Error(`mcp-token mint failed (${mintResp.status}): ${errText.slice(0, 200)}`);
|
|
7364
7301
|
}
|
|
7365
7302
|
const minted = await mintResp.json();
|
|
7366
|
-
writeFileSync13(
|
|
7303
|
+
writeFileSync13(join17(SYNKRO_DIR10, ".mcp-jwt"), minted.token + "\n", { mode: 384 });
|
|
7367
7304
|
const mcp = installCursorMcpConfig({ gatewayUrl, bearerToken: minted.token });
|
|
7368
7305
|
console.log(`Registered Synkro guardrails MCP server in ${mcp.path}`);
|
|
7369
7306
|
console.log(` url: ${mcp.url}`);
|
|
@@ -7456,7 +7393,7 @@ async function installCommand(opts = {}) {
|
|
|
7456
7393
|
const ready = await waitForContainerReady(6e4);
|
|
7457
7394
|
if (ready) {
|
|
7458
7395
|
console.log(" \u2713 container ready");
|
|
7459
|
-
const mcpJwt =
|
|
7396
|
+
const mcpJwt = readFileSync17(join17(SYNKRO_DIR10, ".mcp-jwt"), "utf-8").trim();
|
|
7460
7397
|
try {
|
|
7461
7398
|
const ingestResp = await fetch(`http://127.0.0.1:${hostMcpPort}/api/ingest`, {
|
|
7462
7399
|
method: "POST",
|
|
@@ -7491,11 +7428,6 @@ async function installCommand(opts = {}) {
|
|
|
7491
7428
|
if (graderUsesCursor) await promptCursorApiKey(opts);
|
|
7492
7429
|
await provisionCloudContainer({ gatewayUrl, jwt: token, orgId, userId, email, hasClaudeCode, hasCursor });
|
|
7493
7430
|
cloudGradeOk = await verifyCloudGrader(token);
|
|
7494
|
-
if (await promptCodexCloudSetup()) {
|
|
7495
|
-
const { setupCodexCloud: setupCodexCloud2 } = await Promise.resolve().then(() => (init_codexCloudSetup(), codexCloudSetup_exports));
|
|
7496
|
-
const res = await setupCodexCloud2(gatewayUrl, token, (m) => console.log(` ${m}`));
|
|
7497
|
-
if (!res.ok) console.warn(` \u26A0 Codex cloud setup skipped: ${res.error}`);
|
|
7498
|
-
}
|
|
7499
7431
|
}
|
|
7500
7432
|
if (transcriptConsent) {
|
|
7501
7433
|
const repo = detectGitRepo2();
|
|
@@ -7504,7 +7436,7 @@ async function installCommand(opts = {}) {
|
|
|
7504
7436
|
try {
|
|
7505
7437
|
let mcpToken = "";
|
|
7506
7438
|
try {
|
|
7507
|
-
mcpToken =
|
|
7439
|
+
mcpToken = readFileSync17(join17(SYNKRO_DIR10, ".mcp-jwt"), "utf-8").trim();
|
|
7508
7440
|
} catch {
|
|
7509
7441
|
}
|
|
7510
7442
|
if (mcpToken) {
|
|
@@ -7640,8 +7572,8 @@ function writeSynkroFileIfMissing(opts) {
|
|
|
7640
7572
|
try {
|
|
7641
7573
|
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7642
7574
|
if (!root) return;
|
|
7643
|
-
if (root ===
|
|
7644
|
-
const fp =
|
|
7575
|
+
if (root === homedir17()) return;
|
|
7576
|
+
const fp = join17(root, "synkro.toml");
|
|
7645
7577
|
let hasFile = false;
|
|
7646
7578
|
try {
|
|
7647
7579
|
hasFile = statSync2(fp).isFile();
|
|
@@ -7682,13 +7614,35 @@ function writeSynkroFileIfMissing(opts) {
|
|
|
7682
7614
|
} catch {
|
|
7683
7615
|
}
|
|
7684
7616
|
}
|
|
7617
|
+
function updateSynkroTomlLocation(location) {
|
|
7618
|
+
try {
|
|
7619
|
+
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7620
|
+
if (!root || root === homedir17()) return;
|
|
7621
|
+
const fp = join17(root, "synkro.toml");
|
|
7622
|
+
let txt = "";
|
|
7623
|
+
try {
|
|
7624
|
+
if (!statSync2(fp).isFile()) return;
|
|
7625
|
+
txt = readFileSync17(fp, "utf-8");
|
|
7626
|
+
} catch {
|
|
7627
|
+
return;
|
|
7628
|
+
}
|
|
7629
|
+
const re = /^(\s*location\s*=\s*).*$/m;
|
|
7630
|
+
if (!re.test(txt)) return;
|
|
7631
|
+
const next = txt.replace(re, `$1"${location}"`);
|
|
7632
|
+
if (next !== txt) {
|
|
7633
|
+
writeFileSync13(fp, next, "utf-8");
|
|
7634
|
+
console.log(` synkro.toml: [grader] location = "${location}"`);
|
|
7635
|
+
}
|
|
7636
|
+
} catch {
|
|
7637
|
+
}
|
|
7638
|
+
}
|
|
7685
7639
|
function readFullSynkroFile() {
|
|
7686
7640
|
try {
|
|
7687
7641
|
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7688
7642
|
if (!root) return null;
|
|
7689
|
-
const fp =
|
|
7690
|
-
if (!
|
|
7691
|
-
const parsed = parseSynkroToml2(
|
|
7643
|
+
const fp = join17(root, "synkro.toml");
|
|
7644
|
+
if (!existsSync20(fp)) return null;
|
|
7645
|
+
const parsed = parseSynkroToml2(readFileSync17(fp, "utf-8"));
|
|
7692
7646
|
const valid = ["claude-code", "cursor"];
|
|
7693
7647
|
const harness = Array.isArray(parsed.harness) ? parsed.harness.filter((h) => valid.includes(h)) : ["claude-code", "cursor"];
|
|
7694
7648
|
const resolved = resolveGraderPool(parsed);
|
|
@@ -7726,7 +7680,7 @@ function reconcileHarness() {
|
|
|
7726
7680
|
console.log(`synkro.toml: harness=[${sf.harness.join(", ")}] pool=${poolLabel(sf.grader.pool)} mode=${sf.grader.mode}`);
|
|
7727
7681
|
const scripts = writeHookScripts();
|
|
7728
7682
|
console.log("Wrote hook scripts to ~/.synkro/hooks/");
|
|
7729
|
-
const ccSettings =
|
|
7683
|
+
const ccSettings = join17(homedir17(), ".claude", "settings.json");
|
|
7730
7684
|
if (wantCC) {
|
|
7731
7685
|
installCCHooks(ccSettings, {
|
|
7732
7686
|
bashJudgeScriptPath: scripts.bashScript,
|
|
@@ -7747,7 +7701,7 @@ function reconcileHarness() {
|
|
|
7747
7701
|
});
|
|
7748
7702
|
console.log(" \u2713 Claude Code hooks registered");
|
|
7749
7703
|
try {
|
|
7750
|
-
const mcpJwt =
|
|
7704
|
+
const mcpJwt = readFileSync17(join17(SYNKRO_DIR10, ".mcp-jwt"), "utf-8").trim();
|
|
7751
7705
|
if (mcpJwt) {
|
|
7752
7706
|
installMcpConfig({ gatewayUrl: "", bearerToken: mcpJwt, local: true });
|
|
7753
7707
|
console.log(" \u2713 Claude Code MCP registered");
|
|
@@ -7759,7 +7713,7 @@ function reconcileHarness() {
|
|
|
7759
7713
|
if (uninstallMcpConfig()) console.log(" \u2717 Claude Code MCP removed");
|
|
7760
7714
|
if (uninstallClaudeDesktopMcpConfig()) console.log(" \u2717 Claude Desktop MCP removed");
|
|
7761
7715
|
}
|
|
7762
|
-
const cursorHooks =
|
|
7716
|
+
const cursorHooks = join17(homedir17(), ".cursor", "hooks.json");
|
|
7763
7717
|
if (wantCursor) {
|
|
7764
7718
|
installCursorHooks(cursorHooks, {
|
|
7765
7719
|
bashJudgeScriptPath: scripts.cursorBashJudgeScript,
|
|
@@ -7842,7 +7796,7 @@ async function syncSkillFiles() {
|
|
|
7842
7796
|
if (resolved.length === 0) return;
|
|
7843
7797
|
const mcpPort = process.env.SYNKRO_MCP_PORT || "18931";
|
|
7844
7798
|
const tasks = resolved.map((fp) => {
|
|
7845
|
-
const content =
|
|
7799
|
+
const content = readFileSync17(fp, "utf-8");
|
|
7846
7800
|
const source = `skill:${fp.split("/").pop()}`;
|
|
7847
7801
|
if (!content.trim()) {
|
|
7848
7802
|
console.log(` \u2298 skill ${source}: empty file, skipped`);
|
|
@@ -7863,15 +7817,15 @@ function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNam
|
|
|
7863
7817
|
const roots = [];
|
|
7864
7818
|
const add = (p) => {
|
|
7865
7819
|
try {
|
|
7866
|
-
if (p &&
|
|
7820
|
+
if (p && existsSync20(p) && statSync2(p).isDirectory()) roots.push(p);
|
|
7867
7821
|
} catch {
|
|
7868
7822
|
}
|
|
7869
7823
|
};
|
|
7870
|
-
add(
|
|
7871
|
-
add(
|
|
7824
|
+
add(join17(homedir17(), ".claude", "skills"));
|
|
7825
|
+
add(join17(homedir17(), ".agents", "skills"));
|
|
7872
7826
|
if (repoRoot) {
|
|
7873
|
-
add(
|
|
7874
|
-
add(
|
|
7827
|
+
add(join17(repoRoot, ".claude", "skills"));
|
|
7828
|
+
add(join17(repoRoot, ".agents", "skills"));
|
|
7875
7829
|
}
|
|
7876
7830
|
const out = [];
|
|
7877
7831
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -7882,7 +7836,7 @@ function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNam
|
|
|
7882
7836
|
try {
|
|
7883
7837
|
const st = statSync2(file);
|
|
7884
7838
|
if (!st.isFile() || st.size > 2e5) return;
|
|
7885
|
-
content =
|
|
7839
|
+
content = readFileSync17(file, "utf-8");
|
|
7886
7840
|
} catch {
|
|
7887
7841
|
return;
|
|
7888
7842
|
}
|
|
@@ -7902,7 +7856,7 @@ function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNam
|
|
|
7902
7856
|
}
|
|
7903
7857
|
for (const entry of entries) {
|
|
7904
7858
|
if (entry.startsWith(".")) continue;
|
|
7905
|
-
const full =
|
|
7859
|
+
const full = join17(root, entry);
|
|
7906
7860
|
let st;
|
|
7907
7861
|
try {
|
|
7908
7862
|
st = statSync2(full);
|
|
@@ -7910,8 +7864,8 @@ function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNam
|
|
|
7910
7864
|
continue;
|
|
7911
7865
|
}
|
|
7912
7866
|
if (st.isDirectory()) {
|
|
7913
|
-
const skillMd =
|
|
7914
|
-
if (
|
|
7867
|
+
const skillMd = join17(full, "SKILL.md");
|
|
7868
|
+
if (existsSync20(skillMd)) consider(skillMd, entry);
|
|
7915
7869
|
} else if (/\.mdx?$/i.test(entry) && entry.toUpperCase() !== "README.MD") {
|
|
7916
7870
|
consider(full, entry.replace(/\.mdx?$/i, ""));
|
|
7917
7871
|
}
|
|
@@ -7960,7 +7914,7 @@ async function discoverAndIngestSkills() {
|
|
|
7960
7914
|
if (sf?.skills?.length) {
|
|
7961
7915
|
for (const fp of resolveSkillPaths(sf.skills, sf._repoRoot)) {
|
|
7962
7916
|
try {
|
|
7963
|
-
excludeHashes.add(createHash2("sha256").update(
|
|
7917
|
+
excludeHashes.add(createHash2("sha256").update(readFileSync17(fp, "utf-8")).digest("hex"));
|
|
7964
7918
|
} catch {
|
|
7965
7919
|
}
|
|
7966
7920
|
}
|
|
@@ -7991,7 +7945,7 @@ async function discoverAndIngestSkills() {
|
|
|
7991
7945
|
const setHash = discoverySetHash(selectable);
|
|
7992
7946
|
let prev = "";
|
|
7993
7947
|
try {
|
|
7994
|
-
prev =
|
|
7948
|
+
prev = readFileSync17(SKILLS_DISCOVERED_PATH, "utf-8").trim();
|
|
7995
7949
|
} catch {
|
|
7996
7950
|
}
|
|
7997
7951
|
if (prev === setHash) return;
|
|
@@ -8031,17 +7985,17 @@ function detectGitRepo2() {
|
|
|
8031
7985
|
function getClaudeProjectsFolder() {
|
|
8032
7986
|
const cwd = process.cwd();
|
|
8033
7987
|
const sanitized = "-" + cwd.replace(/\//g, "-");
|
|
8034
|
-
const projectsDir =
|
|
8035
|
-
return
|
|
7988
|
+
const projectsDir = join17(homedir17(), ".claude", "projects", sanitized);
|
|
7989
|
+
return existsSync20(projectsDir) ? projectsDir : null;
|
|
8036
7990
|
}
|
|
8037
7991
|
function extractSessionInsights(projectsDir) {
|
|
8038
7992
|
const insights = [];
|
|
8039
7993
|
const files = readdirSync3(projectsDir).filter((f) => f.endsWith(".jsonl"));
|
|
8040
7994
|
for (const file of files) {
|
|
8041
7995
|
const sessionId = file.replace(".jsonl", "");
|
|
8042
|
-
const filePath =
|
|
7996
|
+
const filePath = join17(projectsDir, file);
|
|
8043
7997
|
try {
|
|
8044
|
-
const content =
|
|
7998
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
8045
7999
|
const lines = content.split("\n").filter(Boolean);
|
|
8046
8000
|
for (let i = 0; i < lines.length; i++) {
|
|
8047
8001
|
try {
|
|
@@ -8120,14 +8074,14 @@ function cursorProjectSlug(workspaceRoot) {
|
|
|
8120
8074
|
return workspaceRoot.replace(/^[/]+/, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
8121
8075
|
}
|
|
8122
8076
|
function getCursorTranscriptsDir() {
|
|
8123
|
-
const dir =
|
|
8124
|
-
return
|
|
8077
|
+
const dir = join17(homedir17(), ".cursor", "projects", cursorProjectSlug(process.cwd()), "agent-transcripts");
|
|
8078
|
+
return existsSync20(dir) ? dir : null;
|
|
8125
8079
|
}
|
|
8126
8080
|
function isSafeConvId(id) {
|
|
8127
8081
|
return /^[A-Za-z0-9_-]+$/.test(id);
|
|
8128
8082
|
}
|
|
8129
8083
|
function parseCursorTranscriptFile(filePath) {
|
|
8130
|
-
const content =
|
|
8084
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
8131
8085
|
const lines = content.split("\n").filter(Boolean);
|
|
8132
8086
|
const messages = [];
|
|
8133
8087
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8159,8 +8113,8 @@ async function syncCursorTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8159
8113
|
for (let i = 0; i < convDirs.length; i++) {
|
|
8160
8114
|
const convId = convDirs[i];
|
|
8161
8115
|
if (!isSafeConvId(convId)) continue;
|
|
8162
|
-
const filePath =
|
|
8163
|
-
if (!
|
|
8116
|
+
const filePath = join17(dir, convId, `${convId}.jsonl`);
|
|
8117
|
+
if (!existsSync20(filePath)) continue;
|
|
8164
8118
|
try {
|
|
8165
8119
|
const all = parseCursorTranscriptFile(filePath);
|
|
8166
8120
|
const messages = all.length > 500 ? all.slice(-500) : all;
|
|
@@ -8182,8 +8136,8 @@ async function syncCursorTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8182
8136
|
process.stdout.write(`\r Progress: ${i + 1}/${convDirs.length} sessions (${totalMessages} messages embedded) `);
|
|
8183
8137
|
}
|
|
8184
8138
|
try {
|
|
8185
|
-
const lc =
|
|
8186
|
-
writeFileSync13(
|
|
8139
|
+
const lc = readFileSync17(filePath, "utf-8").split("\n").filter(Boolean).length;
|
|
8140
|
+
writeFileSync13(join17(OFFSETS_DIR, convId), String(lc), "utf-8");
|
|
8187
8141
|
} catch {
|
|
8188
8142
|
}
|
|
8189
8143
|
}
|
|
@@ -8191,7 +8145,7 @@ async function syncCursorTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8191
8145
|
return { sessions: totalSessions, messages: totalMessages };
|
|
8192
8146
|
}
|
|
8193
8147
|
function parseTranscriptFile(filePath) {
|
|
8194
|
-
const content =
|
|
8148
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
8195
8149
|
const lines = content.split("\n").filter(Boolean);
|
|
8196
8150
|
const messages = [];
|
|
8197
8151
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8239,7 +8193,7 @@ async function syncTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8239
8193
|
for (let i = 0; i < files.length; i++) {
|
|
8240
8194
|
const file = files[i];
|
|
8241
8195
|
const sessionId = file.replace(".jsonl", "");
|
|
8242
|
-
const filePath =
|
|
8196
|
+
const filePath = join17(projectsDir, file);
|
|
8243
8197
|
try {
|
|
8244
8198
|
const allMessages = parseTranscriptFile(filePath);
|
|
8245
8199
|
const messages = allMessages.length > 500 ? allMessages.slice(-500) : allMessages;
|
|
@@ -8261,9 +8215,9 @@ async function syncTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8261
8215
|
process.stdout.write(`\r Progress: ${i + 1}/${files.length} sessions (${totalMessages} messages embedded) `);
|
|
8262
8216
|
}
|
|
8263
8217
|
try {
|
|
8264
|
-
const content =
|
|
8218
|
+
const content = readFileSync17(join17(projectsDir, file), "utf-8");
|
|
8265
8219
|
const lineCount = content.split("\n").filter(Boolean).length;
|
|
8266
|
-
writeFileSync13(
|
|
8220
|
+
writeFileSync13(join17(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
|
|
8267
8221
|
} catch {
|
|
8268
8222
|
}
|
|
8269
8223
|
}
|
|
@@ -8284,7 +8238,7 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
|
|
|
8284
8238
|
const sessions = [];
|
|
8285
8239
|
for (const file of batch) {
|
|
8286
8240
|
const sessionId = file.replace(".jsonl", "");
|
|
8287
|
-
const filePath =
|
|
8241
|
+
const filePath = join17(projectsDir, file);
|
|
8288
8242
|
try {
|
|
8289
8243
|
const allMessages = parseTranscriptFile(filePath);
|
|
8290
8244
|
const messages = allMessages.length > maxMessagesPerSession ? allMessages.slice(-maxMessagesPerSession) : allMessages;
|
|
@@ -8313,18 +8267,18 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
|
|
|
8313
8267
|
}
|
|
8314
8268
|
for (const file of batch) {
|
|
8315
8269
|
const sessionId = file.replace(".jsonl", "");
|
|
8316
|
-
const filePath =
|
|
8270
|
+
const filePath = join17(projectsDir, file);
|
|
8317
8271
|
try {
|
|
8318
|
-
const content =
|
|
8272
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
8319
8273
|
const lineCount = content.split("\n").filter(Boolean).length;
|
|
8320
|
-
writeFileSync13(
|
|
8274
|
+
writeFileSync13(join17(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
|
|
8321
8275
|
} catch {
|
|
8322
8276
|
}
|
|
8323
8277
|
}
|
|
8324
8278
|
}
|
|
8325
8279
|
return { sessions: totalSessions, messages: totalMessages };
|
|
8326
8280
|
}
|
|
8327
|
-
var
|
|
8281
|
+
var SYNKRO_DIR10, HOOKS_DIR, BIN_DIR, CONFIG_PATH4, MCP_STDIO_PROXY_SRC, OFFSETS_DIR, CLOUD_JWT_PATH, SKILLS_DISCOVERED_PATH;
|
|
8328
8282
|
var init_install = __esm({
|
|
8329
8283
|
"cli/commands/install.ts"() {
|
|
8330
8284
|
"use strict";
|
|
@@ -8342,10 +8296,10 @@ var init_install = __esm({
|
|
|
8342
8296
|
init_claudeDesktopTap();
|
|
8343
8297
|
init_dockerInstall();
|
|
8344
8298
|
init_setupToken();
|
|
8345
|
-
|
|
8346
|
-
HOOKS_DIR =
|
|
8347
|
-
BIN_DIR =
|
|
8348
|
-
CONFIG_PATH4 =
|
|
8299
|
+
SYNKRO_DIR10 = join17(homedir17(), ".synkro");
|
|
8300
|
+
HOOKS_DIR = join17(SYNKRO_DIR10, "hooks");
|
|
8301
|
+
BIN_DIR = join17(SYNKRO_DIR10, "bin");
|
|
8302
|
+
CONFIG_PATH4 = join17(SYNKRO_DIR10, "config.env");
|
|
8349
8303
|
MCP_STDIO_PROXY_SRC = `#!/usr/bin/env bun
|
|
8350
8304
|
import { readFileSync } from 'node:fs';
|
|
8351
8305
|
import { homedir } from 'node:os';
|
|
@@ -8456,21 +8410,21 @@ rl.on('line', async (line) => {
|
|
|
8456
8410
|
}
|
|
8457
8411
|
});
|
|
8458
8412
|
`;
|
|
8459
|
-
OFFSETS_DIR =
|
|
8460
|
-
CLOUD_JWT_PATH =
|
|
8461
|
-
SKILLS_DISCOVERED_PATH =
|
|
8413
|
+
OFFSETS_DIR = join17(SYNKRO_DIR10, ".transcript-offsets");
|
|
8414
|
+
CLOUD_JWT_PATH = join17(SYNKRO_DIR10, ".cloud-jwt");
|
|
8415
|
+
SKILLS_DISCOVERED_PATH = join17(SYNKRO_DIR10, ".skills-discovered");
|
|
8462
8416
|
}
|
|
8463
8417
|
});
|
|
8464
8418
|
|
|
8465
8419
|
// cli/local-cc/install.ts
|
|
8466
|
-
import { existsSync as
|
|
8467
|
-
import { join as
|
|
8468
|
-
import { homedir as
|
|
8469
|
-
import { spawnSync as
|
|
8420
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, readFileSync as readFileSync18, chmodSync as chmodSync4, copyFileSync as copyFileSync2, renameSync as renameSync6, unlinkSync as unlinkSync7, openSync as openSync2, fsyncSync, closeSync as closeSync2 } from "fs";
|
|
8421
|
+
import { join as join18 } from "path";
|
|
8422
|
+
import { homedir as homedir18 } from "os";
|
|
8423
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
8470
8424
|
function writePluginFiles() {
|
|
8471
8425
|
for (const c of CHANNELS) {
|
|
8472
|
-
|
|
8473
|
-
|
|
8426
|
+
mkdirSync13(c.sessionDir, { recursive: true });
|
|
8427
|
+
mkdirSync13(c.pluginSettingsDir, { recursive: true });
|
|
8474
8428
|
writeFileSync14(c.pluginPkgPath, PLUGIN_PACKAGE_JSON, "utf-8");
|
|
8475
8429
|
writeFileSync14(
|
|
8476
8430
|
c.pluginSettingsPath,
|
|
@@ -8493,7 +8447,7 @@ function writePluginFiles() {
|
|
|
8493
8447
|
}
|
|
8494
8448
|
function runBunInstall() {
|
|
8495
8449
|
for (const c of CHANNELS) {
|
|
8496
|
-
const r =
|
|
8450
|
+
const r = spawnSync5("bun", ["install", "--silent"], {
|
|
8497
8451
|
cwd: c.sessionDir,
|
|
8498
8452
|
encoding: "utf-8",
|
|
8499
8453
|
timeout: 12e4
|
|
@@ -8506,10 +8460,10 @@ function runBunInstall() {
|
|
|
8506
8460
|
}
|
|
8507
8461
|
}
|
|
8508
8462
|
function safelyMutateClaudeJson(mutator) {
|
|
8509
|
-
if (!
|
|
8463
|
+
if (!existsSync21(CLAUDE_JSON_PATH)) {
|
|
8510
8464
|
return;
|
|
8511
8465
|
}
|
|
8512
|
-
const originalText =
|
|
8466
|
+
const originalText = readFileSync18(CLAUDE_JSON_PATH, "utf-8");
|
|
8513
8467
|
let parsed;
|
|
8514
8468
|
try {
|
|
8515
8469
|
parsed = JSON.parse(originalText);
|
|
@@ -8609,15 +8563,15 @@ function patchClaudeJson() {
|
|
|
8609
8563
|
});
|
|
8610
8564
|
}
|
|
8611
8565
|
function installLocalCC() {
|
|
8612
|
-
let bunCheck =
|
|
8566
|
+
let bunCheck = spawnSync5("bun", ["--version"], { encoding: "utf-8" });
|
|
8613
8567
|
if (bunCheck.status !== 0) {
|
|
8614
8568
|
if (process.platform === "darwin") {
|
|
8615
8569
|
console.log(" Installing bun via brew...");
|
|
8616
|
-
const brewR =
|
|
8570
|
+
const brewR = spawnSync5("brew", ["install", "oven-sh/bun/bun"], { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
|
|
8617
8571
|
if (brewR.status !== 0) {
|
|
8618
8572
|
throw new LocalCCInstallError("bun auto-install failed. Install manually: curl -fsSL https://bun.sh/install | bash");
|
|
8619
8573
|
}
|
|
8620
|
-
bunCheck =
|
|
8574
|
+
bunCheck = spawnSync5("bun", ["--version"], { encoding: "utf-8" });
|
|
8621
8575
|
if (bunCheck.status !== 0) {
|
|
8622
8576
|
throw new LocalCCInstallError("bun installed but not found on PATH. Restart your terminal and re-run install.");
|
|
8623
8577
|
}
|
|
@@ -8651,42 +8605,42 @@ var CLAUDE_JSON_BACKUP_PATH, SESSION_DIR, PLUGIN_PATH, PLUGIN_PKG_PATH, PLUGIN_S
|
|
|
8651
8605
|
var init_install2 = __esm({
|
|
8652
8606
|
"cli/local-cc/install.ts"() {
|
|
8653
8607
|
"use strict";
|
|
8654
|
-
CLAUDE_JSON_BACKUP_PATH =
|
|
8655
|
-
SESSION_DIR =
|
|
8656
|
-
PLUGIN_PATH =
|
|
8657
|
-
PLUGIN_PKG_PATH =
|
|
8658
|
-
PLUGIN_SETTINGS_DIR =
|
|
8659
|
-
PLUGIN_SETTINGS_PATH =
|
|
8660
|
-
PROJECT_MCP_PATH =
|
|
8661
|
-
CLAUDE_JSON_PATH =
|
|
8662
|
-
RUN_SCRIPT_PATH =
|
|
8608
|
+
CLAUDE_JSON_BACKUP_PATH = join18(homedir18(), ".claude.json.synkro-bak");
|
|
8609
|
+
SESSION_DIR = join18(homedir18(), ".synkro", "cc_sessions");
|
|
8610
|
+
PLUGIN_PATH = join18(SESSION_DIR, "synkro-channel.ts");
|
|
8611
|
+
PLUGIN_PKG_PATH = join18(SESSION_DIR, "package.json");
|
|
8612
|
+
PLUGIN_SETTINGS_DIR = join18(SESSION_DIR, ".claude");
|
|
8613
|
+
PLUGIN_SETTINGS_PATH = join18(PLUGIN_SETTINGS_DIR, "settings.json");
|
|
8614
|
+
PROJECT_MCP_PATH = join18(SESSION_DIR, ".mcp.json");
|
|
8615
|
+
CLAUDE_JSON_PATH = join18(homedir18(), ".claude.json");
|
|
8616
|
+
RUN_SCRIPT_PATH = join18(SESSION_DIR, "run-claude.sh");
|
|
8663
8617
|
TMUX_SESSION_NAME = "synkro-local-cc";
|
|
8664
8618
|
CHANNEL_1_PORT = 8941;
|
|
8665
|
-
SESSION_DIR_2 =
|
|
8666
|
-
PLUGIN_PATH_2 =
|
|
8667
|
-
PLUGIN_PKG_PATH_2 =
|
|
8668
|
-
PLUGIN_SETTINGS_DIR_2 =
|
|
8669
|
-
PLUGIN_SETTINGS_PATH_2 =
|
|
8670
|
-
PROJECT_MCP_PATH_2 =
|
|
8671
|
-
RUN_SCRIPT_PATH_2 =
|
|
8619
|
+
SESSION_DIR_2 = join18(homedir18(), ".synkro", "cc_sessions_2");
|
|
8620
|
+
PLUGIN_PATH_2 = join18(SESSION_DIR_2, "synkro-channel.ts");
|
|
8621
|
+
PLUGIN_PKG_PATH_2 = join18(SESSION_DIR_2, "package.json");
|
|
8622
|
+
PLUGIN_SETTINGS_DIR_2 = join18(SESSION_DIR_2, ".claude");
|
|
8623
|
+
PLUGIN_SETTINGS_PATH_2 = join18(PLUGIN_SETTINGS_DIR_2, "settings.json");
|
|
8624
|
+
PROJECT_MCP_PATH_2 = join18(SESSION_DIR_2, ".mcp.json");
|
|
8625
|
+
RUN_SCRIPT_PATH_2 = join18(SESSION_DIR_2, "run-claude.sh");
|
|
8672
8626
|
TMUX_SESSION_NAME_2 = "synkro-local-cc-2";
|
|
8673
8627
|
CHANNEL_2_PORT = 8951;
|
|
8674
|
-
SESSION_DIR_3 =
|
|
8675
|
-
PLUGIN_PATH_3 =
|
|
8676
|
-
PLUGIN_PKG_PATH_3 =
|
|
8677
|
-
PLUGIN_SETTINGS_DIR_3 =
|
|
8678
|
-
PLUGIN_SETTINGS_PATH_3 =
|
|
8679
|
-
PROJECT_MCP_PATH_3 =
|
|
8680
|
-
RUN_SCRIPT_PATH_3 =
|
|
8628
|
+
SESSION_DIR_3 = join18(homedir18(), ".synkro", "cc_sessions_3");
|
|
8629
|
+
PLUGIN_PATH_3 = join18(SESSION_DIR_3, "synkro-channel.ts");
|
|
8630
|
+
PLUGIN_PKG_PATH_3 = join18(SESSION_DIR_3, "package.json");
|
|
8631
|
+
PLUGIN_SETTINGS_DIR_3 = join18(SESSION_DIR_3, ".claude");
|
|
8632
|
+
PLUGIN_SETTINGS_PATH_3 = join18(PLUGIN_SETTINGS_DIR_3, "settings.json");
|
|
8633
|
+
PROJECT_MCP_PATH_3 = join18(SESSION_DIR_3, ".mcp.json");
|
|
8634
|
+
RUN_SCRIPT_PATH_3 = join18(SESSION_DIR_3, "run-claude.sh");
|
|
8681
8635
|
TMUX_SESSION_NAME_3 = "synkro-local-cc-3";
|
|
8682
8636
|
CHANNEL_3_PORT = 8942;
|
|
8683
|
-
SESSION_DIR_4 =
|
|
8684
|
-
PLUGIN_PATH_4 =
|
|
8685
|
-
PLUGIN_PKG_PATH_4 =
|
|
8686
|
-
PLUGIN_SETTINGS_DIR_4 =
|
|
8687
|
-
PLUGIN_SETTINGS_PATH_4 =
|
|
8688
|
-
PROJECT_MCP_PATH_4 =
|
|
8689
|
-
RUN_SCRIPT_PATH_4 =
|
|
8637
|
+
SESSION_DIR_4 = join18(homedir18(), ".synkro", "cc_sessions_4");
|
|
8638
|
+
PLUGIN_PATH_4 = join18(SESSION_DIR_4, "synkro-channel.ts");
|
|
8639
|
+
PLUGIN_PKG_PATH_4 = join18(SESSION_DIR_4, "package.json");
|
|
8640
|
+
PLUGIN_SETTINGS_DIR_4 = join18(SESSION_DIR_4, ".claude");
|
|
8641
|
+
PLUGIN_SETTINGS_PATH_4 = join18(PLUGIN_SETTINGS_DIR_4, "settings.json");
|
|
8642
|
+
PROJECT_MCP_PATH_4 = join18(SESSION_DIR_4, ".mcp.json");
|
|
8643
|
+
RUN_SCRIPT_PATH_4 = join18(SESSION_DIR_4, "run-claude.sh");
|
|
8690
8644
|
TMUX_SESSION_NAME_4 = "synkro-local-cc-4";
|
|
8691
8645
|
CHANNEL_4_PORT = 8952;
|
|
8692
8646
|
RUN_SCRIPT_SOURCE = `#!/usr/bin/env bash
|
|
@@ -8960,10 +8914,10 @@ var disconnect_exports = {};
|
|
|
8960
8914
|
__export(disconnect_exports, {
|
|
8961
8915
|
disconnectCommand: () => disconnectCommand
|
|
8962
8916
|
});
|
|
8963
|
-
import { existsSync as
|
|
8964
|
-
import { homedir as
|
|
8965
|
-
import { join as
|
|
8966
|
-
import { spawnSync as
|
|
8917
|
+
import { existsSync as existsSync22, rmSync, readdirSync as readdirSync4 } from "fs";
|
|
8918
|
+
import { homedir as homedir19 } from "os";
|
|
8919
|
+
import { join as join19 } from "path";
|
|
8920
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
8967
8921
|
import { createInterface as createInterface4 } from "readline";
|
|
8968
8922
|
async function tearDownLocalCC() {
|
|
8969
8923
|
const docker = dockerStatus();
|
|
@@ -8977,7 +8931,7 @@ async function tearDownLocalCC() {
|
|
|
8977
8931
|
console.log("\u2713 removed synkro-server container");
|
|
8978
8932
|
try {
|
|
8979
8933
|
const image = imageTag();
|
|
8980
|
-
const r =
|
|
8934
|
+
const r = spawnSync6("docker", ["rmi", "-f", image], { encoding: "utf-8", timeout: 3e4 });
|
|
8981
8935
|
console.log(r.status === 0 ? `\u2713 removed Docker image ${image}` : "\xB7 no Docker image to remove");
|
|
8982
8936
|
} catch {
|
|
8983
8937
|
}
|
|
@@ -9048,7 +9002,7 @@ async function disconnectCommand(args2 = [], opts = {}) {
|
|
|
9048
9002
|
if (desktopMcpRemoved) removed.mcp = true;
|
|
9049
9003
|
console.log(`${desktopMcpRemoved ? "\u2713" : "\xB7"} MCP guardrails (Claude Desktop): ${desktopMcpRemoved ? "removed from claude_desktop_config.json" : "no entry found"}`);
|
|
9050
9004
|
}
|
|
9051
|
-
if (
|
|
9005
|
+
if (existsSync22(SYNKRO_DIR11)) {
|
|
9052
9006
|
if (purge2) {
|
|
9053
9007
|
emit("uninstall", {
|
|
9054
9008
|
flavor,
|
|
@@ -9057,41 +9011,41 @@ async function disconnectCommand(args2 = [], opts = {}) {
|
|
|
9057
9011
|
duration_ms: Date.now() - startedAt
|
|
9058
9012
|
});
|
|
9059
9013
|
await flush({ force: true });
|
|
9060
|
-
|
|
9014
|
+
rmSync(SYNKRO_DIR11, { recursive: true, force: true });
|
|
9061
9015
|
removed.config = true;
|
|
9062
|
-
console.log(`\u2713 wiped ${
|
|
9016
|
+
console.log(`\u2713 wiped ${SYNKRO_DIR11} entirely \u2014 including all scan data and backups`);
|
|
9063
9017
|
} else {
|
|
9064
9018
|
const keep = /* @__PURE__ */ new Set([
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
|
|
9019
|
+
join19(SYNKRO_DIR11, "pgdata"),
|
|
9020
|
+
join19(SYNKRO_DIR11, "pgdata-backups"),
|
|
9021
|
+
join19(SYNKRO_DIR11, ".transcript-offsets")
|
|
9068
9022
|
]);
|
|
9069
9023
|
const preserved = [];
|
|
9070
|
-
for (const entry of readdirSync4(
|
|
9071
|
-
const full =
|
|
9024
|
+
for (const entry of readdirSync4(SYNKRO_DIR11)) {
|
|
9025
|
+
const full = join19(SYNKRO_DIR11, entry);
|
|
9072
9026
|
if (keep.has(full)) {
|
|
9073
9027
|
preserved.push(entry);
|
|
9074
9028
|
continue;
|
|
9075
9029
|
}
|
|
9076
|
-
|
|
9030
|
+
rmSync(full, { recursive: true, force: true });
|
|
9077
9031
|
}
|
|
9078
9032
|
removed.config = true;
|
|
9079
9033
|
if (preserved.length > 0) {
|
|
9080
|
-
console.log(`\u2713 removed Synkro config from ${
|
|
9034
|
+
console.log(`\u2713 removed Synkro config from ${SYNKRO_DIR11} (kept your scan data: ${preserved.join(", ")})`);
|
|
9081
9035
|
console.log(" run `synkro uninstall --purge` to delete that too");
|
|
9082
9036
|
} else {
|
|
9083
|
-
console.log(`\u2713 removed ${
|
|
9037
|
+
console.log(`\u2713 removed ${SYNKRO_DIR11}`);
|
|
9084
9038
|
}
|
|
9085
9039
|
}
|
|
9086
9040
|
} else {
|
|
9087
|
-
console.log(`\xB7 ${
|
|
9041
|
+
console.log(`\xB7 ${SYNKRO_DIR11} already gone`);
|
|
9088
9042
|
}
|
|
9089
9043
|
if (!purge2) {
|
|
9090
9044
|
emit("uninstall", { flavor, purge: purge2, removed, duration_ms: Date.now() - startedAt });
|
|
9091
9045
|
}
|
|
9092
9046
|
console.log(purge2 ? "\nSynkro fully removed \u2014 this machine is clean, as if it was never installed." : "\nSynkro uninstalled. Your scan data is preserved.");
|
|
9093
9047
|
}
|
|
9094
|
-
var
|
|
9048
|
+
var SYNKRO_DIR11;
|
|
9095
9049
|
var init_disconnect = __esm({
|
|
9096
9050
|
"cli/commands/disconnect.ts"() {
|
|
9097
9051
|
"use strict";
|
|
@@ -9103,14 +9057,14 @@ var init_disconnect = __esm({
|
|
|
9103
9057
|
init_dockerInstall();
|
|
9104
9058
|
init_macKeychain();
|
|
9105
9059
|
init_telemetry();
|
|
9106
|
-
|
|
9060
|
+
SYNKRO_DIR11 = join19(homedir19(), ".synkro");
|
|
9107
9061
|
}
|
|
9108
9062
|
});
|
|
9109
9063
|
|
|
9110
9064
|
// cli/local-cc/turnLog.ts
|
|
9111
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
9112
|
-
import { dirname as dirname6, join as
|
|
9113
|
-
import { homedir as
|
|
9065
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync23, mkdirSync as mkdirSync14, openSync as openSync3, readFileSync as readFileSync19, readSync, closeSync as closeSync3, statSync as statSync3, watchFile, unwatchFile } from "fs";
|
|
9066
|
+
import { dirname as dirname6, join as join20 } from "path";
|
|
9067
|
+
import { homedir as homedir20 } from "os";
|
|
9114
9068
|
function truncate(s, max = PREVIEW_MAX) {
|
|
9115
9069
|
if (s.length <= max) return s;
|
|
9116
9070
|
return s.slice(0, max) + "\u2026 [+" + (s.length - max) + " chars]";
|
|
@@ -9130,7 +9084,7 @@ function extractSeverity(result) {
|
|
|
9130
9084
|
}
|
|
9131
9085
|
function appendTurn(args2) {
|
|
9132
9086
|
try {
|
|
9133
|
-
|
|
9087
|
+
mkdirSync14(dirname6(TURN_LOG_PATH), { recursive: true });
|
|
9134
9088
|
const entry = {
|
|
9135
9089
|
ts: new Date(args2.startedAt).toISOString(),
|
|
9136
9090
|
role: args2.role,
|
|
@@ -9146,11 +9100,11 @@ function appendTurn(args2) {
|
|
|
9146
9100
|
}
|
|
9147
9101
|
}
|
|
9148
9102
|
function readRecentTurns(n = 20) {
|
|
9149
|
-
if (!
|
|
9103
|
+
if (!existsSync23(TURN_LOG_PATH)) return [];
|
|
9150
9104
|
try {
|
|
9151
9105
|
const size = statSync3(TURN_LOG_PATH).size;
|
|
9152
9106
|
if (size === 0) return [];
|
|
9153
|
-
const text =
|
|
9107
|
+
const text = readFileSync19(TURN_LOG_PATH, "utf-8");
|
|
9154
9108
|
const lines = text.split("\n").filter(Boolean);
|
|
9155
9109
|
const lastN = lines.slice(-n).reverse();
|
|
9156
9110
|
return lastN.map((line) => {
|
|
@@ -9166,8 +9120,8 @@ function readRecentTurns(n = 20) {
|
|
|
9166
9120
|
}
|
|
9167
9121
|
function followTurns(onEntry) {
|
|
9168
9122
|
try {
|
|
9169
|
-
|
|
9170
|
-
if (!
|
|
9123
|
+
mkdirSync14(dirname6(TURN_LOG_PATH), { recursive: true });
|
|
9124
|
+
if (!existsSync23(TURN_LOG_PATH)) {
|
|
9171
9125
|
appendFileSync3(TURN_LOG_PATH, "", "utf-8");
|
|
9172
9126
|
}
|
|
9173
9127
|
} catch {
|
|
@@ -9229,7 +9183,7 @@ var TURN_LOG_PATH, PREVIEW_MAX;
|
|
|
9229
9183
|
var init_turnLog = __esm({
|
|
9230
9184
|
"cli/local-cc/turnLog.ts"() {
|
|
9231
9185
|
"use strict";
|
|
9232
|
-
TURN_LOG_PATH =
|
|
9186
|
+
TURN_LOG_PATH = join20(homedir20(), ".synkro", "cc_sessions", "turns.log");
|
|
9233
9187
|
PREVIEW_MAX = 400;
|
|
9234
9188
|
}
|
|
9235
9189
|
});
|
|
@@ -9378,19 +9332,19 @@ var init_grade = __esm({
|
|
|
9378
9332
|
});
|
|
9379
9333
|
|
|
9380
9334
|
// cli/local-cc/pueue.ts
|
|
9381
|
-
import { execFileSync as execFileSync4, spawnSync as
|
|
9382
|
-
import { homedir as
|
|
9383
|
-
import { join as
|
|
9335
|
+
import { execFileSync as execFileSync4, spawnSync as spawnSync7, spawn as spawn3 } from "child_process";
|
|
9336
|
+
import { homedir as homedir21 } from "os";
|
|
9337
|
+
import { join as join21 } from "path";
|
|
9384
9338
|
import { connect as connect2 } from "net";
|
|
9385
9339
|
function pueueAvailable() {
|
|
9386
|
-
const r =
|
|
9340
|
+
const r = spawnSync7("pueue", ["--version"], { encoding: "utf-8" });
|
|
9387
9341
|
if (r.status !== 0) {
|
|
9388
9342
|
throw new PueueError("pueue CLI not found on PATH. Install pueue (https://github.com/Nukesor/pueue) and start `pueued`.");
|
|
9389
9343
|
}
|
|
9390
9344
|
}
|
|
9391
9345
|
function statusJson() {
|
|
9392
9346
|
pueueAvailable();
|
|
9393
|
-
const r =
|
|
9347
|
+
const r = spawnSync7("pueue", ["status", "--json"], { encoding: "utf-8" });
|
|
9394
9348
|
if (r.status !== 0) {
|
|
9395
9349
|
throw new PueueError(`pueue status failed: ${r.stderr || r.stdout || "unknown error"} \u2014 is pueued running?`);
|
|
9396
9350
|
}
|
|
@@ -9435,18 +9389,18 @@ function startTask(opts = {}) {
|
|
|
9435
9389
|
let existing = findTask(ch);
|
|
9436
9390
|
while (existing) {
|
|
9437
9391
|
if (existing.status === "Running" || existing.status === "Queued") {
|
|
9438
|
-
|
|
9439
|
-
|
|
9392
|
+
spawnSync7("tmux", ["kill-session", "-t", `=${ch.tmuxSession}`], { encoding: "utf-8" });
|
|
9393
|
+
spawnSync7("pueue", ["kill", String(existing.id)], { encoding: "utf-8" });
|
|
9440
9394
|
for (let i = 0; i < 10; i++) {
|
|
9441
9395
|
const check = findTask(ch);
|
|
9442
9396
|
if (!check || check.id !== existing.id || check.status !== "Running" && check.status !== "Queued") break;
|
|
9443
|
-
|
|
9397
|
+
spawnSync7("sleep", ["0.5"], { encoding: "utf-8" });
|
|
9444
9398
|
}
|
|
9445
9399
|
}
|
|
9446
|
-
|
|
9400
|
+
spawnSync7("pueue", ["remove", String(existing.id)], { encoding: "utf-8" });
|
|
9447
9401
|
existing = findTask(ch);
|
|
9448
9402
|
}
|
|
9449
|
-
const runScript =
|
|
9403
|
+
const runScript = join21(cwd, "run-claude.sh");
|
|
9450
9404
|
const args2 = [
|
|
9451
9405
|
"add",
|
|
9452
9406
|
"--label",
|
|
@@ -9457,7 +9411,7 @@ function startTask(opts = {}) {
|
|
|
9457
9411
|
"bash",
|
|
9458
9412
|
runScript
|
|
9459
9413
|
];
|
|
9460
|
-
const r =
|
|
9414
|
+
const r = spawnSync7("pueue", args2, { encoding: "utf-8" });
|
|
9461
9415
|
if (r.status !== 0) {
|
|
9462
9416
|
throw new PueueError(`pueue add failed: ${r.stderr || r.stdout}`);
|
|
9463
9417
|
}
|
|
@@ -9468,25 +9422,25 @@ function startTask(opts = {}) {
|
|
|
9468
9422
|
return created;
|
|
9469
9423
|
}
|
|
9470
9424
|
function stopTask(channel = CHANNEL_PRIMARY) {
|
|
9471
|
-
|
|
9425
|
+
spawnSync7("tmux", ["kill-session", "-t", `=${channel.tmuxSession}`], { encoding: "utf-8" });
|
|
9472
9426
|
let t = findTask(channel);
|
|
9473
9427
|
while (t) {
|
|
9474
9428
|
if (t.status === "Running" || t.status === "Queued") {
|
|
9475
|
-
|
|
9429
|
+
spawnSync7("pueue", ["kill", String(t.id)], { encoding: "utf-8" });
|
|
9476
9430
|
for (let i = 0; i < 10; i++) {
|
|
9477
9431
|
const check = findTask(channel);
|
|
9478
9432
|
if (!check || check.id !== t.id || check.status !== "Running" && check.status !== "Queued") break;
|
|
9479
|
-
|
|
9433
|
+
spawnSync7("sleep", ["0.5"], { encoding: "utf-8" });
|
|
9480
9434
|
}
|
|
9481
9435
|
}
|
|
9482
|
-
|
|
9436
|
+
spawnSync7("pueue", ["remove", String(t.id)], { encoding: "utf-8" });
|
|
9483
9437
|
t = findTask(channel);
|
|
9484
9438
|
}
|
|
9485
9439
|
}
|
|
9486
9440
|
function tailLogs(lines = 80, channel = CHANNEL_PRIMARY) {
|
|
9487
9441
|
const t = findTask(channel);
|
|
9488
9442
|
if (!t) return `(no ${channel.taskLabel} task)`;
|
|
9489
|
-
const r =
|
|
9443
|
+
const r = spawnSync7("pueue", ["log", "--lines", String(lines), String(t.id)], { encoding: "utf-8" });
|
|
9490
9444
|
return r.stdout || r.stderr || "(no output)";
|
|
9491
9445
|
}
|
|
9492
9446
|
function ensureRunning(opts = {}) {
|
|
@@ -9511,8 +9465,8 @@ function probePort(host, port, timeoutMs = 500) {
|
|
|
9511
9465
|
});
|
|
9512
9466
|
}
|
|
9513
9467
|
function tmuxDismissPrompts(tmuxSession = TMUX_SESSION) {
|
|
9514
|
-
|
|
9515
|
-
|
|
9468
|
+
spawnSync7("tmux", ["send-keys", "-t", tmuxSession, "1"], { encoding: "utf-8" });
|
|
9469
|
+
spawnSync7("tmux", ["send-keys", "-t", tmuxSession, "Enter"], { encoding: "utf-8" });
|
|
9516
9470
|
}
|
|
9517
9471
|
async function waitForChannelReady(port, timeoutMs = 6e4, host = "127.0.0.1", tmuxSession = TMUX_SESSION) {
|
|
9518
9472
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -9524,46 +9478,46 @@ async function waitForChannelReady(port, timeoutMs = 6e4, host = "127.0.0.1", tm
|
|
|
9524
9478
|
return probePort(host, port);
|
|
9525
9479
|
}
|
|
9526
9480
|
function brewInstall(pkg) {
|
|
9527
|
-
const brew =
|
|
9481
|
+
const brew = spawnSync7("brew", ["--version"], { encoding: "utf-8" });
|
|
9528
9482
|
if (brew.status !== 0) return false;
|
|
9529
9483
|
console.log(` Installing ${pkg} via brew...`);
|
|
9530
|
-
const r =
|
|
9484
|
+
const r = spawnSync7("brew", ["install", pkg], { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
|
|
9531
9485
|
return r.status === 0;
|
|
9532
9486
|
}
|
|
9533
9487
|
function assertPueueInstalled() {
|
|
9534
|
-
let r =
|
|
9488
|
+
let r = spawnSync7("pueue", ["--version"], { encoding: "utf-8" });
|
|
9535
9489
|
if (r.status !== 0) {
|
|
9536
9490
|
if (process.platform === "darwin" && brewInstall("pueue")) {
|
|
9537
|
-
r =
|
|
9491
|
+
r = spawnSync7("pueue", ["--version"], { encoding: "utf-8" });
|
|
9538
9492
|
if (r.status !== 0) throw new PueueError("pueue install succeeded but binary not found on PATH.");
|
|
9539
9493
|
} else {
|
|
9540
9494
|
throw new PueueError("pueue not found. Install it: brew install pueue (macOS) or https://github.com/Nukesor/pueue");
|
|
9541
9495
|
}
|
|
9542
9496
|
}
|
|
9543
|
-
const status =
|
|
9497
|
+
const status = spawnSync7("pueue", ["status", "--json"], { encoding: "utf-8", timeout: 5e3 });
|
|
9544
9498
|
if (status.status !== 0) {
|
|
9545
9499
|
console.log(" Starting pueued daemon...");
|
|
9546
9500
|
const child = spawn3("pueued", ["-d"], { stdio: "ignore", detached: true });
|
|
9547
9501
|
child.unref();
|
|
9548
|
-
|
|
9549
|
-
const retry =
|
|
9502
|
+
spawnSync7("sleep", ["1"]);
|
|
9503
|
+
const retry = spawnSync7("pueue", ["status", "--json"], { encoding: "utf-8", timeout: 5e3 });
|
|
9550
9504
|
if (retry.status !== 0) {
|
|
9551
9505
|
throw new PueueError("pueue daemon not reachable after starting pueued. Check `pueued` manually.");
|
|
9552
9506
|
}
|
|
9553
9507
|
}
|
|
9554
|
-
|
|
9508
|
+
spawnSync7("pueue", ["parallel", "2"], { encoding: "utf-8" });
|
|
9555
9509
|
}
|
|
9556
9510
|
function assertClaudeInstalled() {
|
|
9557
|
-
const r =
|
|
9511
|
+
const r = spawnSync7("claude", ["--version"], { encoding: "utf-8" });
|
|
9558
9512
|
if (r.status !== 0) {
|
|
9559
9513
|
throw new PueueError("claude CLI not found on PATH. Install Claude Code first: https://docs.claude.com/claude-code");
|
|
9560
9514
|
}
|
|
9561
9515
|
}
|
|
9562
9516
|
function assertTmuxInstalled() {
|
|
9563
|
-
let r =
|
|
9517
|
+
let r = spawnSync7("tmux", ["-V"], { encoding: "utf-8" });
|
|
9564
9518
|
if (r.status !== 0) {
|
|
9565
9519
|
if (process.platform === "darwin" && brewInstall("tmux")) {
|
|
9566
|
-
r =
|
|
9520
|
+
r = spawnSync7("tmux", ["-V"], { encoding: "utf-8" });
|
|
9567
9521
|
if (r.status !== 0) throw new PueueError("tmux install succeeded but binary not found on PATH.");
|
|
9568
9522
|
} else {
|
|
9569
9523
|
throw new PueueError("tmux not found. Install it: brew install tmux (macOS) or apt install tmux (Linux)");
|
|
@@ -9576,12 +9530,12 @@ var init_pueue = __esm({
|
|
|
9576
9530
|
"use strict";
|
|
9577
9531
|
TASK_LABEL = "synkro-local-cc";
|
|
9578
9532
|
TMUX_SESSION = "synkro-local-cc";
|
|
9579
|
-
SESSION_DIR2 =
|
|
9533
|
+
SESSION_DIR2 = join21(homedir21(), ".synkro", "cc_sessions");
|
|
9580
9534
|
TASK_LABEL_2 = "synkro-local-cc-2";
|
|
9581
9535
|
TMUX_SESSION_2 = "synkro-local-cc-2";
|
|
9582
|
-
SESSION_DIR_22 =
|
|
9583
|
-
SESSION_DIR_32 =
|
|
9584
|
-
SESSION_DIR_42 =
|
|
9536
|
+
SESSION_DIR_22 = join21(homedir21(), ".synkro", "cc_sessions_2");
|
|
9537
|
+
SESSION_DIR_32 = join21(homedir21(), ".synkro", "cc_sessions_3");
|
|
9538
|
+
SESSION_DIR_42 = join21(homedir21(), ".synkro", "cc_sessions_4");
|
|
9585
9539
|
PueueError = class extends Error {
|
|
9586
9540
|
constructor(message, cause) {
|
|
9587
9541
|
super(message);
|
|
@@ -9596,13 +9550,13 @@ var init_pueue = __esm({
|
|
|
9596
9550
|
});
|
|
9597
9551
|
|
|
9598
9552
|
// cli/local-cc/settings.ts
|
|
9599
|
-
import { existsSync as
|
|
9600
|
-
import { homedir as
|
|
9601
|
-
import { join as
|
|
9553
|
+
import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
|
|
9554
|
+
import { homedir as homedir22 } from "os";
|
|
9555
|
+
import { join as join22 } from "path";
|
|
9602
9556
|
function isLocalCCEnabled() {
|
|
9603
|
-
if (!
|
|
9557
|
+
if (!existsSync24(CONFIG_PATH5)) return false;
|
|
9604
9558
|
try {
|
|
9605
|
-
const content =
|
|
9559
|
+
const content = readFileSync20(CONFIG_PATH5, "utf-8");
|
|
9606
9560
|
const match = content.match(/^SYNKRO_LOCAL_INFERENCE='([^']*)'/m);
|
|
9607
9561
|
return match?.[1] === "yes";
|
|
9608
9562
|
} catch {
|
|
@@ -9613,7 +9567,7 @@ var CONFIG_PATH5;
|
|
|
9613
9567
|
var init_settings = __esm({
|
|
9614
9568
|
"cli/local-cc/settings.ts"() {
|
|
9615
9569
|
"use strict";
|
|
9616
|
-
CONFIG_PATH5 =
|
|
9570
|
+
CONFIG_PATH5 = join22(homedir22(), ".synkro", "config.env");
|
|
9617
9571
|
}
|
|
9618
9572
|
});
|
|
9619
9573
|
|
|
@@ -9622,11 +9576,11 @@ var localCc_exports = {};
|
|
|
9622
9576
|
__export(localCc_exports, {
|
|
9623
9577
|
localCcCommand: () => localCcCommand
|
|
9624
9578
|
});
|
|
9625
|
-
import { spawnSync as
|
|
9626
|
-
import { homedir as
|
|
9627
|
-
import { join as
|
|
9579
|
+
import { spawnSync as spawnSync8 } from "child_process";
|
|
9580
|
+
import { homedir as homedir23 } from "os";
|
|
9581
|
+
import { join as join23 } from "path";
|
|
9628
9582
|
import { readFileSync as fsReadFileSync, existsSync as fsExistsSync } from "fs";
|
|
9629
|
-
import { existsSync as
|
|
9583
|
+
import { existsSync as existsSync25, readFileSync as readFileSync21, writeFileSync as writeFileSync15 } from "fs";
|
|
9630
9584
|
function deploymentMode() {
|
|
9631
9585
|
const env = (process.env.SYNKRO_DEPLOYMENT_MODE || "").toLowerCase();
|
|
9632
9586
|
if (env === "docker") return "docker";
|
|
@@ -9732,15 +9686,15 @@ TROUBLESHOOTING
|
|
|
9732
9686
|
`);
|
|
9733
9687
|
}
|
|
9734
9688
|
function readGatewayUrl() {
|
|
9735
|
-
if (
|
|
9736
|
-
const m =
|
|
9689
|
+
if (existsSync25(CONFIG_PATH6)) {
|
|
9690
|
+
const m = readFileSync21(CONFIG_PATH6, "utf-8").match(/^SYNKRO_GATEWAY_URL='([^']*)'/m);
|
|
9737
9691
|
if (m) return m[1];
|
|
9738
9692
|
}
|
|
9739
9693
|
return "https://api.synkro.sh";
|
|
9740
9694
|
}
|
|
9741
9695
|
function updateLocalInferenceFlag(enabled) {
|
|
9742
|
-
if (!
|
|
9743
|
-
let content =
|
|
9696
|
+
if (!existsSync25(CONFIG_PATH6)) return;
|
|
9697
|
+
let content = readFileSync21(CONFIG_PATH6, "utf-8");
|
|
9744
9698
|
const flag = enabled ? "yes" : "no";
|
|
9745
9699
|
if (content.includes("SYNKRO_LOCAL_INFERENCE=")) {
|
|
9746
9700
|
content = content.replace(/^SYNKRO_LOCAL_INFERENCE='[^']*'/m, `SYNKRO_LOCAL_INFERENCE='${flag}'`);
|
|
@@ -9803,7 +9757,7 @@ async function cmdStatus() {
|
|
|
9803
9757
|
}
|
|
9804
9758
|
const ch1Up = await isChannelAvailable();
|
|
9805
9759
|
console.log(`Channel 1 ${CHANNEL_HOST}:${CHANNEL_PORT}: ${ch1Up ? "reachable" : "unreachable"}`);
|
|
9806
|
-
const tmux1 =
|
|
9760
|
+
const tmux1 = spawnSync8("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME}`], { encoding: "utf-8" });
|
|
9807
9761
|
console.log(`tmux '${TMUX_SESSION_NAME}': ${tmux1.status === 0 ? "live" : "absent"}`);
|
|
9808
9762
|
const t2 = findTask(CHANNEL_SECONDARY);
|
|
9809
9763
|
if (!t2) {
|
|
@@ -9813,7 +9767,7 @@ async function cmdStatus() {
|
|
|
9813
9767
|
}
|
|
9814
9768
|
const ch2Up = await isChannelAvailable(CHANNEL_2_PORT);
|
|
9815
9769
|
console.log(`Channel 2 ${CHANNEL_HOST}:${CHANNEL_2_PORT}: ${ch2Up ? "reachable" : "unreachable"}`);
|
|
9816
|
-
const tmux2 =
|
|
9770
|
+
const tmux2 = spawnSync8("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME_2}`], { encoding: "utf-8" });
|
|
9817
9771
|
console.log(`tmux '${TMUX_SESSION_NAME_2}': ${tmux2.status === 0 ? "live" : "absent"}`);
|
|
9818
9772
|
}
|
|
9819
9773
|
async function cmdEnable() {
|
|
@@ -10019,7 +9973,7 @@ function cmdLogs(rest) {
|
|
|
10019
9973
|
}
|
|
10020
9974
|
return "200";
|
|
10021
9975
|
})();
|
|
10022
|
-
|
|
9976
|
+
spawnSync8("docker", ["logs", "--tail", tailArg, ...followFlag, "synkro-server"], { stdio: "inherit" });
|
|
10023
9977
|
return;
|
|
10024
9978
|
}
|
|
10025
9979
|
for (const arg of rest) {
|
|
@@ -10067,7 +10021,7 @@ function cmdLogs(rest) {
|
|
|
10067
10021
|
function cmdAttach(rest) {
|
|
10068
10022
|
assertTmuxInstalled();
|
|
10069
10023
|
const readonly = rest.some((a) => a === "--readonly" || a === "-r");
|
|
10070
|
-
const has =
|
|
10024
|
+
const has = spawnSync8("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME}`], { encoding: "utf-8" });
|
|
10071
10025
|
if (has.status !== 0) {
|
|
10072
10026
|
console.error(`No tmux session '${TMUX_SESSION_NAME}' running. Start it with: synkro local-cc start`);
|
|
10073
10027
|
process.exit(1);
|
|
@@ -10080,7 +10034,7 @@ function cmdAttach(rest) {
|
|
|
10080
10034
|
console.log("Detach with Ctrl-B then D. (Do not press Ctrl-C \u2014 that would interrupt claude.)");
|
|
10081
10035
|
console.log();
|
|
10082
10036
|
const args2 = readonly ? ["attach-session", "-r", "-t", TMUX_SESSION_NAME] : ["attach-session", "-t", TMUX_SESSION_NAME];
|
|
10083
|
-
const r =
|
|
10037
|
+
const r = spawnSync8("tmux", args2, { stdio: "inherit" });
|
|
10084
10038
|
process.exit(r.status ?? 0);
|
|
10085
10039
|
}
|
|
10086
10040
|
async function cmdTest() {
|
|
@@ -10181,8 +10135,8 @@ var init_localCc = __esm({
|
|
|
10181
10135
|
init_install();
|
|
10182
10136
|
init_client2();
|
|
10183
10137
|
init_stub();
|
|
10184
|
-
SYNKRO_CONFIG_PATH =
|
|
10185
|
-
CONFIG_PATH6 =
|
|
10138
|
+
SYNKRO_CONFIG_PATH = join23(homedir23(), ".synkro", "config.env");
|
|
10139
|
+
CONFIG_PATH6 = join23(homedir23(), ".synkro", "config.env");
|
|
10186
10140
|
}
|
|
10187
10141
|
});
|
|
10188
10142
|
|
|
@@ -10191,15 +10145,15 @@ var import_exports = {};
|
|
|
10191
10145
|
__export(import_exports, {
|
|
10192
10146
|
importCommand: () => importCommand
|
|
10193
10147
|
});
|
|
10194
|
-
import { existsSync as
|
|
10195
|
-
import { homedir as
|
|
10196
|
-
import { join as
|
|
10148
|
+
import { existsSync as existsSync26, readFileSync as readFileSync22, readdirSync as readdirSync5 } from "fs";
|
|
10149
|
+
import { homedir as homedir24 } from "os";
|
|
10150
|
+
import { join as join24 } from "path";
|
|
10197
10151
|
import { execSync as execSync7 } from "child_process";
|
|
10198
10152
|
import { createInterface as createInterface5 } from "readline";
|
|
10199
10153
|
function readConfigEnv2() {
|
|
10200
10154
|
const out = {};
|
|
10201
10155
|
try {
|
|
10202
|
-
for (const line of
|
|
10156
|
+
for (const line of readFileSync22(CONFIG_PATH7, "utf-8").split("\n")) {
|
|
10203
10157
|
const t = line.trim();
|
|
10204
10158
|
if (!t || t.startsWith("#")) continue;
|
|
10205
10159
|
const eq = t.indexOf("=");
|
|
@@ -10211,8 +10165,8 @@ function readConfigEnv2() {
|
|
|
10211
10165
|
}
|
|
10212
10166
|
function projectsFolder() {
|
|
10213
10167
|
const sanitized = process.cwd().replace(/\//g, "-");
|
|
10214
|
-
const dir =
|
|
10215
|
-
return
|
|
10168
|
+
const dir = join24(homedir24(), ".claude", "projects", sanitized);
|
|
10169
|
+
return existsSync26(dir) ? dir : null;
|
|
10216
10170
|
}
|
|
10217
10171
|
function repoName() {
|
|
10218
10172
|
try {
|
|
@@ -10235,7 +10189,7 @@ function extractText(content) {
|
|
|
10235
10189
|
return "";
|
|
10236
10190
|
}
|
|
10237
10191
|
function parseSession(filePath, sessionId) {
|
|
10238
|
-
const lines =
|
|
10192
|
+
const lines = readFileSync22(filePath, "utf-8").split("\n").filter(Boolean);
|
|
10239
10193
|
const messages = [];
|
|
10240
10194
|
const actions = [];
|
|
10241
10195
|
let step = 0;
|
|
@@ -10308,7 +10262,7 @@ async function importCommand() {
|
|
|
10308
10262
|
return;
|
|
10309
10263
|
}
|
|
10310
10264
|
}
|
|
10311
|
-
const sessions = files.map((f) => parseSession(
|
|
10265
|
+
const sessions = files.map((f) => parseSession(join24(dir, f), f.replace(".jsonl", ""))).filter((s) => s.messages.length > 0);
|
|
10312
10266
|
const totalMsgs = sessions.reduce((n, s) => n + s.messages.length, 0);
|
|
10313
10267
|
let ok = 0, fail = 0;
|
|
10314
10268
|
if (isCloud) {
|
|
@@ -10368,7 +10322,7 @@ var init_import = __esm({
|
|
|
10368
10322
|
"cli/commands/import.ts"() {
|
|
10369
10323
|
"use strict";
|
|
10370
10324
|
init_stub();
|
|
10371
|
-
CONFIG_PATH7 =
|
|
10325
|
+
CONFIG_PATH7 = join24(homedir24(), ".synkro", "config.env");
|
|
10372
10326
|
}
|
|
10373
10327
|
});
|
|
10374
10328
|
|
|
@@ -10410,10 +10364,10 @@ var init_packVerify = __esm({
|
|
|
10410
10364
|
});
|
|
10411
10365
|
|
|
10412
10366
|
// cli/installer/lockfile.ts
|
|
10413
|
-
import { existsSync as
|
|
10414
|
-
import { join as
|
|
10367
|
+
import { existsSync as existsSync27, readFileSync as readFileSync23, writeFileSync as writeFileSync16 } from "fs";
|
|
10368
|
+
import { join as join25 } from "path";
|
|
10415
10369
|
function lockPath(repoRoot) {
|
|
10416
|
-
return
|
|
10370
|
+
return join25(repoRoot, LOCK_FILE);
|
|
10417
10371
|
}
|
|
10418
10372
|
function writeLockfile(repoRoot, entries) {
|
|
10419
10373
|
const sorted = [...entries].sort((a, b) => a.ref.localeCompare(b.ref));
|
|
@@ -10446,9 +10400,9 @@ var sync_exports = {};
|
|
|
10446
10400
|
__export(sync_exports, {
|
|
10447
10401
|
syncCommand: () => syncCommand
|
|
10448
10402
|
});
|
|
10449
|
-
import { existsSync as
|
|
10450
|
-
import { homedir as
|
|
10451
|
-
import { join as
|
|
10403
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync15, readdirSync as readdirSync6, rmSync as rmSync2, writeFileSync as writeFileSync17 } from "fs";
|
|
10404
|
+
import { homedir as homedir25 } from "os";
|
|
10405
|
+
import { join as join26 } from "path";
|
|
10452
10406
|
function cacheKey(ref, version) {
|
|
10453
10407
|
return ref.replace(/\//g, "__").replace(/[^\w.@-]/g, "_") + "@" + version + ".json";
|
|
10454
10408
|
}
|
|
@@ -10479,8 +10433,8 @@ async function syncCommand(_args = []) {
|
|
|
10479
10433
|
}
|
|
10480
10434
|
const gateway = (process.env.SYNKRO_GATEWAY_URL || "https://api.synkro.sh").replace(/\/$/, "");
|
|
10481
10435
|
const cloud = process.env.SYNKRO_DEPLOY_LOCATION === "cloud";
|
|
10482
|
-
const cacheDir =
|
|
10483
|
-
if (!cloud)
|
|
10436
|
+
const cacheDir = join26(homedir25(), ".synkro", "cache", "packs");
|
|
10437
|
+
if (!cloud) mkdirSync15(cacheDir, { recursive: true });
|
|
10484
10438
|
console.log(`Syncing ${refs.length} standard(s) from the registry\u2026`);
|
|
10485
10439
|
const lock = [];
|
|
10486
10440
|
const keptCacheFiles = /* @__PURE__ */ new Set();
|
|
@@ -10508,7 +10462,7 @@ async function syncCommand(_args = []) {
|
|
|
10508
10462
|
if (!cloud) {
|
|
10509
10463
|
const fname = cacheKey(ref, data.version);
|
|
10510
10464
|
keptCacheFiles.add(fname);
|
|
10511
|
-
writeFileSync17(
|
|
10465
|
+
writeFileSync17(join26(cacheDir, fname), JSON.stringify({
|
|
10512
10466
|
ref,
|
|
10513
10467
|
version: data.version,
|
|
10514
10468
|
digest: data.digest,
|
|
@@ -10520,11 +10474,11 @@ async function syncCommand(_args = []) {
|
|
|
10520
10474
|
const ruleCount = Array.isArray(pack.rules) ? pack.rules.length : 0;
|
|
10521
10475
|
console.log(` \u2713 ${ref}:${data.version} \u2014 verified (${ruleCount} rule${ruleCount === 1 ? "" : "s"})`);
|
|
10522
10476
|
}
|
|
10523
|
-
if (!cloud &&
|
|
10477
|
+
if (!cloud && existsSync28(cacheDir)) {
|
|
10524
10478
|
for (const f of readdirSync6(cacheDir)) {
|
|
10525
10479
|
if (f.endsWith(".json") && !keptCacheFiles.has(f)) {
|
|
10526
10480
|
try {
|
|
10527
|
-
|
|
10481
|
+
rmSync2(join26(cacheDir, f));
|
|
10528
10482
|
} catch {
|
|
10529
10483
|
}
|
|
10530
10484
|
}
|
|
@@ -10660,13 +10614,13 @@ var config_exports = {};
|
|
|
10660
10614
|
__export(config_exports, {
|
|
10661
10615
|
configCommand: () => configCommand
|
|
10662
10616
|
});
|
|
10663
|
-
import { readFileSync as
|
|
10664
|
-
import { join as
|
|
10665
|
-
import { homedir as
|
|
10617
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync18, existsSync as existsSync29 } from "fs";
|
|
10618
|
+
import { join as join27 } from "path";
|
|
10619
|
+
import { homedir as homedir26 } from "os";
|
|
10666
10620
|
function readConfigEnv3() {
|
|
10667
|
-
if (!
|
|
10621
|
+
if (!existsSync29(CONFIG_PATH8)) return {};
|
|
10668
10622
|
const out = {};
|
|
10669
|
-
for (const line of
|
|
10623
|
+
for (const line of readFileSync24(CONFIG_PATH8, "utf-8").split("\n")) {
|
|
10670
10624
|
const t = line.trim();
|
|
10671
10625
|
if (!t || t.startsWith("#")) continue;
|
|
10672
10626
|
const eq = t.indexOf("=");
|
|
@@ -10675,11 +10629,11 @@ function readConfigEnv3() {
|
|
|
10675
10629
|
return out;
|
|
10676
10630
|
}
|
|
10677
10631
|
function updateConfigValue(key, value) {
|
|
10678
|
-
if (!
|
|
10632
|
+
if (!existsSync29(CONFIG_PATH8)) {
|
|
10679
10633
|
console.error("No config found. Run `synkro install` first.");
|
|
10680
10634
|
process.exit(1);
|
|
10681
10635
|
}
|
|
10682
|
-
const lines =
|
|
10636
|
+
const lines = readFileSync24(CONFIG_PATH8, "utf-8").split("\n");
|
|
10683
10637
|
const pattern = new RegExp(`^${key}=`);
|
|
10684
10638
|
let found = false;
|
|
10685
10639
|
const updated = lines.map((line) => {
|
|
@@ -10842,14 +10796,14 @@ To change:`);
|
|
|
10842
10796
|
}
|
|
10843
10797
|
if (inferenceValue !== "cloud") await reconcileContainer();
|
|
10844
10798
|
}
|
|
10845
|
-
var
|
|
10799
|
+
var SYNKRO_DIR12, CONFIG_PATH8;
|
|
10846
10800
|
var init_config = __esm({
|
|
10847
10801
|
"cli/commands/config.ts"() {
|
|
10848
10802
|
"use strict";
|
|
10849
10803
|
init_stub();
|
|
10850
10804
|
init_optout();
|
|
10851
|
-
|
|
10852
|
-
CONFIG_PATH8 =
|
|
10805
|
+
SYNKRO_DIR12 = join27(homedir26(), ".synkro");
|
|
10806
|
+
CONFIG_PATH8 = join27(SYNKRO_DIR12, "config.env");
|
|
10853
10807
|
}
|
|
10854
10808
|
});
|
|
10855
10809
|
|
|
@@ -11038,14 +10992,14 @@ Usage:
|
|
|
11038
10992
|
});
|
|
11039
10993
|
|
|
11040
10994
|
// cli/bootstrap.js
|
|
11041
|
-
import { readFileSync as
|
|
10995
|
+
import { readFileSync as readFileSync25, existsSync as existsSync30 } from "fs";
|
|
11042
10996
|
import { resolve as resolve3 } from "path";
|
|
11043
10997
|
var envCandidates = [
|
|
11044
10998
|
resolve3(process.env.HOME ?? "", ".synkro", "config.env")
|
|
11045
10999
|
];
|
|
11046
11000
|
for (const envPath of envCandidates) {
|
|
11047
|
-
if (!
|
|
11048
|
-
const envContent =
|
|
11001
|
+
if (!existsSync30(envPath)) continue;
|
|
11002
|
+
const envContent = readFileSync25(envPath, "utf-8");
|
|
11049
11003
|
for (const line of envContent.split("\n")) {
|
|
11050
11004
|
const trimmed = line.trim();
|
|
11051
11005
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -11062,7 +11016,7 @@ var subArgs = args.slice(1);
|
|
|
11062
11016
|
var isDetachedChild = process.env.SYNKRO_TELEMETRY_DETACHED === "1";
|
|
11063
11017
|
var FLUSH_SKIP = /* @__PURE__ */ new Set(["grade", "version", "--version", "-v", "help", "--help", "-h", ""]);
|
|
11064
11018
|
function printVersion() {
|
|
11065
|
-
console.log("1.7.
|
|
11019
|
+
console.log("1.7.66");
|
|
11066
11020
|
}
|
|
11067
11021
|
function printHelp2() {
|
|
11068
11022
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|