@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 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.64";
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
- if (process.env[key]) return process.env[key] as string;
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
- return _cfgCache[key] || '';
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 existsSync20, readFileSync as readFileSync17 } from "fs";
5957
- import { homedir as homedir17, platform as platform5 } from "os";
5958
- import { join as join17 } from "path";
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 (!existsSync20(CONFIG_PATH3)) return {};
5887
+ if (!existsSync19(CONFIG_PATH3)) return {};
5962
5888
  const out = {};
5963
- for (const line of readFileSync17(CONFIG_PATH3, "utf-8").split("\n")) {
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 SYNKRO_DIR10, CONFIG_PATH3;
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
- SYNKRO_DIR10 = join17(homedir17(), ".synkro");
6271
- CONFIG_PATH3 = join17(SYNKRO_DIR10, "config.env");
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 existsSync21, mkdirSync as mkdirSync13, writeFileSync as writeFileSync13, chmodSync as chmodSync3, readFileSync as readFileSync18, readdirSync as readdirSync3, unlinkSync as unlinkSync6, statSync as statSync2 } from "fs";
6291
- import { homedir as homedir18 } from "os";
6292
- import { join as join18 } from "path";
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 "local";
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
- "Where should Synkro run?\n local \u2014 a grading container on this machine (Docker) (default)\n cloud \u2014 a private container hosted by Synkro (Cloudflare)\nBoth use your own Claude key. Choose [local] / cloud: ",
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
- resolve4(answer.trim().toLowerCase() === "cloud" ? "cloud" : "local");
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
- mkdirSync13(SYNKRO_DIR11, { recursive: true });
6438
- mkdirSync13(HOOKS_DIR, { recursive: true });
6439
- mkdirSync13(BIN_DIR, { recursive: true });
6440
- mkdirSync13(OFFSETS_DIR, { recursive: true });
6441
- mkdirSync13(join18(SYNKRO_DIR11, "sessions"), { recursive: true });
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 = join18(HOOKS_DIR, "installExtractCore.ts");
6445
- const bashScriptPath = join18(HOOKS_DIR, "cc-bash-judge.ts");
6446
- const skillJudgeScriptPath = join18(HOOKS_DIR, "cc-skill-judge.ts");
6447
- const cursorSkillJudgePath = join18(HOOKS_DIR, "cursor-skill-judge.ts");
6448
- const bashFollowupScriptPath = join18(HOOKS_DIR, "cc-bash-followup.ts");
6449
- const editPrecheckScriptPath = join18(HOOKS_DIR, "cc-edit-precheck.ts");
6450
- const cwePrecheckScriptPath = join18(HOOKS_DIR, "cc-cwe-precheck.ts");
6451
- const cvePrecheckScriptPath = join18(HOOKS_DIR, "cc-cve-precheck.ts");
6452
- const planJudgeScriptPath = join18(HOOKS_DIR, "cc-plan-judge.ts");
6453
- const agentJudgeScriptPath = join18(HOOKS_DIR, "cc-agent-judge.ts");
6454
- const stopSummaryScriptPath = join18(HOOKS_DIR, "cc-stop-summary.ts");
6455
- const sessionStartScriptPath = join18(HOOKS_DIR, "cc-session-start.ts");
6456
- const transcriptSyncScriptPath = join18(HOOKS_DIR, "cc-transcript-sync.ts");
6457
- const userPromptSubmitScriptPath = join18(HOOKS_DIR, "cc-user-prompt-submit.ts");
6458
- const commonScriptPath = join18(HOOKS_DIR, "_synkro-common.ts");
6459
- const commonBashScriptPath = join18(HOOKS_DIR, "_synkro-common.sh");
6460
- const installScanScriptPath = join18(HOOKS_DIR, "cc-install-scan.ts");
6461
- const cursorBashJudgePath = join18(HOOKS_DIR, "cursor-bash-judge.ts");
6462
- const cursorEditCapturePath = join18(HOOKS_DIR, "cursor-edit-capture.ts");
6463
- const cursorAgentCapturePath = join18(HOOKS_DIR, "cursor-agent-capture.ts");
6464
- const mcpStdioProxyPath = join18(HOOKS_DIR, "mcp-stdio-proxy.ts");
6465
- const taskActivateIntentScriptPath = join18(HOOKS_DIR, "cc-task-activate-intent.ts");
6466
- const mcpGateScriptPath = join18(HOOKS_DIR, "cc-mcp-gate.ts");
6467
- const stubCommonPath = join18(HOOKS_DIR, "_synkro-stub-common.ts");
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(join18(HOOKS_DIR, stale));
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 && existsSync21(scriptPath)) return scriptPath;
6450
+ if (scriptPath && existsSync20(scriptPath)) return scriptPath;
6534
6451
  return null;
6535
6452
  }
6536
6453
  function writeConfigEnv(opts) {
6537
- const credsPath = join18(SYNKRO_DIR11, "credentials.json");
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.64")}`
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 = readFileSync18(CLOUD_JWT_PATH, "utf-8").trim();
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
- try {
6618
- const out = execSync6('claude --print --output-format json "say ok"', {
6619
- env: { ...process.env, CLAUDE_CODE_OAUTH_TOKEN: setupToken },
6620
- encoding: "utf-8",
6621
- timeout: 3e4,
6622
- stdio: ["ignore", "pipe", "pipe"]
6623
- });
6624
- const result = JSON.parse(out);
6625
- if (result.is_error) throw new Error(result.result || "auth failed");
6626
- console.log(" \u2713 Claude token validated.\n");
6627
- } catch (err) {
6628
- const msg = err instanceof Error ? err.message : String(err);
6629
- console.error(` \u2717 Claude token failed validation: ${msg}`);
6630
- console.error(" The captured token can't authenticate (truncated capture, wrong account, or no API credits).");
6631
- console.error(" Re-run install to re-authorize \u2014 nothing was stored.");
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 = readFileSync18(join18(SYNKRO_DIR11, "cursor-creds", "api-key"), "utf-8").trim();
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 (existsSync21(CONFIG_PATH4)) {
6803
- const m = readFileSync18(CONFIG_PATH4, "utf-8").match(/^SYNKRO_DEPLOY_LOCATION='([^']*)'/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 (!existsSync21(CONFIG_PATH4)) return;
6812
- let env = readFileSync18(CONFIG_PATH4, "utf-8");
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 = readFileSync18(join18(SYNKRO_DIR11, ".mcp-jwt"), "utf-8").trim();
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 desired = sf?.grader.location === "cloud" ? "cloud" : "local";
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
- synkro.toml: deploy location changed ${current} \u2192 ${desired}
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 (existsSync21(CONFIG_PATH4)) {
6946
- const m = readFileSync18(CONFIG_PATH4, "utf-8").match(/^SYNKRO_DEPLOYMENT_MODE='([^']*)'/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 = join18(homedir18(), ".claude");
6908
+ const claudeDir = join17(homedir17(), ".claude");
6974
6909
  try {
6975
- const settings = JSON.parse(readFileSync18(join18(claudeDir, "settings.json"), "utf-8"));
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(readFileSync18(join18(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
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 = join18(claudeDir, "sessions");
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(readFileSync18(join18(sessionsDir, f), "utf-8"));
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.64",
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 = join18(SYNKRO_DIR11, "daemon", mode, "daemon.pid");
7142
+ const pidFile = join17(SYNKRO_DIR10, "daemon", mode, "daemon.pid");
7206
7143
  try {
7207
- const pid = parseInt(readFileSync18(pidFile, "utf-8").trim(), 10);
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(join18(SYNKRO_DIR11, ".mcp-jwt"), mcpJwt + "\n", { mode: 384 });
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(join18(SYNKRO_DIR11, ".mcp-jwt"), minted.token + "\n", { mode: 384 });
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 = join18(SYNKRO_DIR11, ".mcp-jwt");
7338
- if (!existsSync21(jwtPath)) {
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(join18(SYNKRO_DIR11, ".mcp-jwt"), minted.token + "\n", { mode: 384 });
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 = readFileSync18(join18(SYNKRO_DIR11, ".mcp-jwt"), "utf-8").trim();
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 = readFileSync18(join18(SYNKRO_DIR11, ".mcp-jwt"), "utf-8").trim();
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 === homedir18()) return;
7644
- const fp = join18(root, "synkro.toml");
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 = join18(root, "synkro.toml");
7690
- if (!existsSync21(fp)) return null;
7691
- const parsed = parseSynkroToml2(readFileSync18(fp, "utf-8"));
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 = join18(homedir18(), ".claude", "settings.json");
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 = readFileSync18(join18(SYNKRO_DIR11, ".mcp-jwt"), "utf-8").trim();
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 = join18(homedir18(), ".cursor", "hooks.json");
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 = readFileSync18(fp, "utf-8");
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 && existsSync21(p) && statSync2(p).isDirectory()) roots.push(p);
7820
+ if (p && existsSync20(p) && statSync2(p).isDirectory()) roots.push(p);
7867
7821
  } catch {
7868
7822
  }
7869
7823
  };
7870
- add(join18(homedir18(), ".claude", "skills"));
7871
- add(join18(homedir18(), ".agents", "skills"));
7824
+ add(join17(homedir17(), ".claude", "skills"));
7825
+ add(join17(homedir17(), ".agents", "skills"));
7872
7826
  if (repoRoot) {
7873
- add(join18(repoRoot, ".claude", "skills"));
7874
- add(join18(repoRoot, ".agents", "skills"));
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 = readFileSync18(file, "utf-8");
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 = join18(root, entry);
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 = join18(full, "SKILL.md");
7914
- if (existsSync21(skillMd)) consider(skillMd, entry);
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(readFileSync18(fp, "utf-8")).digest("hex"));
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 = readFileSync18(SKILLS_DISCOVERED_PATH, "utf-8").trim();
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 = join18(homedir18(), ".claude", "projects", sanitized);
8035
- return existsSync21(projectsDir) ? projectsDir : null;
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 = join18(projectsDir, file);
7996
+ const filePath = join17(projectsDir, file);
8043
7997
  try {
8044
- const content = readFileSync18(filePath, "utf-8");
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 = join18(homedir18(), ".cursor", "projects", cursorProjectSlug(process.cwd()), "agent-transcripts");
8124
- return existsSync21(dir) ? dir : null;
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 = readFileSync18(filePath, "utf-8");
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 = join18(dir, convId, `${convId}.jsonl`);
8163
- if (!existsSync21(filePath)) continue;
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 = readFileSync18(filePath, "utf-8").split("\n").filter(Boolean).length;
8186
- writeFileSync13(join18(OFFSETS_DIR, convId), String(lc), "utf-8");
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 = readFileSync18(filePath, "utf-8");
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 = join18(projectsDir, file);
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 = readFileSync18(join18(projectsDir, file), "utf-8");
8218
+ const content = readFileSync17(join17(projectsDir, file), "utf-8");
8265
8219
  const lineCount = content.split("\n").filter(Boolean).length;
8266
- writeFileSync13(join18(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
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 = join18(projectsDir, file);
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 = join18(projectsDir, file);
8270
+ const filePath = join17(projectsDir, file);
8317
8271
  try {
8318
- const content = readFileSync18(filePath, "utf-8");
8272
+ const content = readFileSync17(filePath, "utf-8");
8319
8273
  const lineCount = content.split("\n").filter(Boolean).length;
8320
- writeFileSync13(join18(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
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 SYNKRO_DIR11, HOOKS_DIR, BIN_DIR, CONFIG_PATH4, MCP_STDIO_PROXY_SRC, OFFSETS_DIR, CLOUD_JWT_PATH, SKILLS_DISCOVERED_PATH;
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
- SYNKRO_DIR11 = join18(homedir18(), ".synkro");
8346
- HOOKS_DIR = join18(SYNKRO_DIR11, "hooks");
8347
- BIN_DIR = join18(SYNKRO_DIR11, "bin");
8348
- CONFIG_PATH4 = join18(SYNKRO_DIR11, "config.env");
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 = join18(SYNKRO_DIR11, ".transcript-offsets");
8460
- CLOUD_JWT_PATH = join18(SYNKRO_DIR11, ".cloud-jwt");
8461
- SKILLS_DISCOVERED_PATH = join18(SYNKRO_DIR11, ".skills-discovered");
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 existsSync22, mkdirSync as mkdirSync14, writeFileSync as writeFileSync14, readFileSync as readFileSync19, chmodSync as chmodSync4, copyFileSync as copyFileSync2, renameSync as renameSync6, unlinkSync as unlinkSync7, openSync as openSync2, fsyncSync, closeSync as closeSync2 } from "fs";
8467
- import { join as join19 } from "path";
8468
- import { homedir as homedir19 } from "os";
8469
- import { spawnSync as spawnSync6 } from "child_process";
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
- mkdirSync14(c.sessionDir, { recursive: true });
8473
- mkdirSync14(c.pluginSettingsDir, { recursive: true });
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 = spawnSync6("bun", ["install", "--silent"], {
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 (!existsSync22(CLAUDE_JSON_PATH)) {
8463
+ if (!existsSync21(CLAUDE_JSON_PATH)) {
8510
8464
  return;
8511
8465
  }
8512
- const originalText = readFileSync19(CLAUDE_JSON_PATH, "utf-8");
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 = spawnSync6("bun", ["--version"], { encoding: "utf-8" });
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 = spawnSync6("brew", ["install", "oven-sh/bun/bun"], { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
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 = spawnSync6("bun", ["--version"], { encoding: "utf-8" });
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 = join19(homedir19(), ".claude.json.synkro-bak");
8655
- SESSION_DIR = join19(homedir19(), ".synkro", "cc_sessions");
8656
- PLUGIN_PATH = join19(SESSION_DIR, "synkro-channel.ts");
8657
- PLUGIN_PKG_PATH = join19(SESSION_DIR, "package.json");
8658
- PLUGIN_SETTINGS_DIR = join19(SESSION_DIR, ".claude");
8659
- PLUGIN_SETTINGS_PATH = join19(PLUGIN_SETTINGS_DIR, "settings.json");
8660
- PROJECT_MCP_PATH = join19(SESSION_DIR, ".mcp.json");
8661
- CLAUDE_JSON_PATH = join19(homedir19(), ".claude.json");
8662
- RUN_SCRIPT_PATH = join19(SESSION_DIR, "run-claude.sh");
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 = join19(homedir19(), ".synkro", "cc_sessions_2");
8666
- PLUGIN_PATH_2 = join19(SESSION_DIR_2, "synkro-channel.ts");
8667
- PLUGIN_PKG_PATH_2 = join19(SESSION_DIR_2, "package.json");
8668
- PLUGIN_SETTINGS_DIR_2 = join19(SESSION_DIR_2, ".claude");
8669
- PLUGIN_SETTINGS_PATH_2 = join19(PLUGIN_SETTINGS_DIR_2, "settings.json");
8670
- PROJECT_MCP_PATH_2 = join19(SESSION_DIR_2, ".mcp.json");
8671
- RUN_SCRIPT_PATH_2 = join19(SESSION_DIR_2, "run-claude.sh");
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 = join19(homedir19(), ".synkro", "cc_sessions_3");
8675
- PLUGIN_PATH_3 = join19(SESSION_DIR_3, "synkro-channel.ts");
8676
- PLUGIN_PKG_PATH_3 = join19(SESSION_DIR_3, "package.json");
8677
- PLUGIN_SETTINGS_DIR_3 = join19(SESSION_DIR_3, ".claude");
8678
- PLUGIN_SETTINGS_PATH_3 = join19(PLUGIN_SETTINGS_DIR_3, "settings.json");
8679
- PROJECT_MCP_PATH_3 = join19(SESSION_DIR_3, ".mcp.json");
8680
- RUN_SCRIPT_PATH_3 = join19(SESSION_DIR_3, "run-claude.sh");
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 = join19(homedir19(), ".synkro", "cc_sessions_4");
8684
- PLUGIN_PATH_4 = join19(SESSION_DIR_4, "synkro-channel.ts");
8685
- PLUGIN_PKG_PATH_4 = join19(SESSION_DIR_4, "package.json");
8686
- PLUGIN_SETTINGS_DIR_4 = join19(SESSION_DIR_4, ".claude");
8687
- PLUGIN_SETTINGS_PATH_4 = join19(PLUGIN_SETTINGS_DIR_4, "settings.json");
8688
- PROJECT_MCP_PATH_4 = join19(SESSION_DIR_4, ".mcp.json");
8689
- RUN_SCRIPT_PATH_4 = join19(SESSION_DIR_4, "run-claude.sh");
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 existsSync23, rmSync as rmSync2, readdirSync as readdirSync4 } from "fs";
8964
- import { homedir as homedir20 } from "os";
8965
- import { join as join20 } from "path";
8966
- import { spawnSync as spawnSync7 } from "child_process";
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 = spawnSync7("docker", ["rmi", "-f", image], { encoding: "utf-8", timeout: 3e4 });
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 (existsSync23(SYNKRO_DIR12)) {
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
- rmSync2(SYNKRO_DIR12, { recursive: true, force: true });
9014
+ rmSync(SYNKRO_DIR11, { recursive: true, force: true });
9061
9015
  removed.config = true;
9062
- console.log(`\u2713 wiped ${SYNKRO_DIR12} entirely \u2014 including all scan data and backups`);
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
- join20(SYNKRO_DIR12, "pgdata"),
9066
- join20(SYNKRO_DIR12, "pgdata-backups"),
9067
- join20(SYNKRO_DIR12, ".transcript-offsets")
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(SYNKRO_DIR12)) {
9071
- const full = join20(SYNKRO_DIR12, entry);
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
- rmSync2(full, { recursive: true, force: true });
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 ${SYNKRO_DIR12} (kept your scan data: ${preserved.join(", ")})`);
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 ${SYNKRO_DIR12}`);
9037
+ console.log(`\u2713 removed ${SYNKRO_DIR11}`);
9084
9038
  }
9085
9039
  }
9086
9040
  } else {
9087
- console.log(`\xB7 ${SYNKRO_DIR12} already gone`);
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 SYNKRO_DIR12;
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
- SYNKRO_DIR12 = join20(homedir20(), ".synkro");
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 existsSync24, mkdirSync as mkdirSync15, openSync as openSync3, readFileSync as readFileSync20, readSync, closeSync as closeSync3, statSync as statSync3, watchFile, unwatchFile } from "fs";
9112
- import { dirname as dirname6, join as join21 } from "path";
9113
- import { homedir as homedir21 } from "os";
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
- mkdirSync15(dirname6(TURN_LOG_PATH), { recursive: true });
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 (!existsSync24(TURN_LOG_PATH)) return [];
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 = readFileSync20(TURN_LOG_PATH, "utf-8");
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
- mkdirSync15(dirname6(TURN_LOG_PATH), { recursive: true });
9170
- if (!existsSync24(TURN_LOG_PATH)) {
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 = join21(homedir21(), ".synkro", "cc_sessions", "turns.log");
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 spawnSync8, spawn as spawn3 } from "child_process";
9382
- import { homedir as homedir22 } from "os";
9383
- import { join as join22 } from "path";
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 = spawnSync8("pueue", ["--version"], { encoding: "utf-8" });
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 = spawnSync8("pueue", ["status", "--json"], { encoding: "utf-8" });
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
- spawnSync8("tmux", ["kill-session", "-t", `=${ch.tmuxSession}`], { encoding: "utf-8" });
9439
- spawnSync8("pueue", ["kill", String(existing.id)], { encoding: "utf-8" });
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
- spawnSync8("sleep", ["0.5"], { encoding: "utf-8" });
9397
+ spawnSync7("sleep", ["0.5"], { encoding: "utf-8" });
9444
9398
  }
9445
9399
  }
9446
- spawnSync8("pueue", ["remove", String(existing.id)], { encoding: "utf-8" });
9400
+ spawnSync7("pueue", ["remove", String(existing.id)], { encoding: "utf-8" });
9447
9401
  existing = findTask(ch);
9448
9402
  }
9449
- const runScript = join22(cwd, "run-claude.sh");
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 = spawnSync8("pueue", args2, { encoding: "utf-8" });
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
- spawnSync8("tmux", ["kill-session", "-t", `=${channel.tmuxSession}`], { encoding: "utf-8" });
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
- spawnSync8("pueue", ["kill", String(t.id)], { encoding: "utf-8" });
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
- spawnSync8("sleep", ["0.5"], { encoding: "utf-8" });
9433
+ spawnSync7("sleep", ["0.5"], { encoding: "utf-8" });
9480
9434
  }
9481
9435
  }
9482
- spawnSync8("pueue", ["remove", String(t.id)], { encoding: "utf-8" });
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 = spawnSync8("pueue", ["log", "--lines", String(lines), String(t.id)], { encoding: "utf-8" });
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
- spawnSync8("tmux", ["send-keys", "-t", tmuxSession, "1"], { encoding: "utf-8" });
9515
- spawnSync8("tmux", ["send-keys", "-t", tmuxSession, "Enter"], { encoding: "utf-8" });
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 = spawnSync8("brew", ["--version"], { encoding: "utf-8" });
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 = spawnSync8("brew", ["install", pkg], { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
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 = spawnSync8("pueue", ["--version"], { encoding: "utf-8" });
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 = spawnSync8("pueue", ["--version"], { encoding: "utf-8" });
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 = spawnSync8("pueue", ["status", "--json"], { encoding: "utf-8", timeout: 5e3 });
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
- spawnSync8("sleep", ["1"]);
9549
- const retry = spawnSync8("pueue", ["status", "--json"], { encoding: "utf-8", timeout: 5e3 });
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
- spawnSync8("pueue", ["parallel", "2"], { encoding: "utf-8" });
9508
+ spawnSync7("pueue", ["parallel", "2"], { encoding: "utf-8" });
9555
9509
  }
9556
9510
  function assertClaudeInstalled() {
9557
- const r = spawnSync8("claude", ["--version"], { encoding: "utf-8" });
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 = spawnSync8("tmux", ["-V"], { encoding: "utf-8" });
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 = spawnSync8("tmux", ["-V"], { encoding: "utf-8" });
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 = join22(homedir22(), ".synkro", "cc_sessions");
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 = join22(homedir22(), ".synkro", "cc_sessions_2");
9583
- SESSION_DIR_32 = join22(homedir22(), ".synkro", "cc_sessions_3");
9584
- SESSION_DIR_42 = join22(homedir22(), ".synkro", "cc_sessions_4");
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 existsSync25, readFileSync as readFileSync21 } from "fs";
9600
- import { homedir as homedir23 } from "os";
9601
- import { join as join23 } from "path";
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 (!existsSync25(CONFIG_PATH5)) return false;
9557
+ if (!existsSync24(CONFIG_PATH5)) return false;
9604
9558
  try {
9605
- const content = readFileSync21(CONFIG_PATH5, "utf-8");
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 = join23(homedir23(), ".synkro", "config.env");
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 spawnSync9 } from "child_process";
9626
- import { homedir as homedir24 } from "os";
9627
- import { join as join24 } from "path";
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 existsSync26, readFileSync as readFileSync22, writeFileSync as writeFileSync15 } from "fs";
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 (existsSync26(CONFIG_PATH6)) {
9736
- const m = readFileSync22(CONFIG_PATH6, "utf-8").match(/^SYNKRO_GATEWAY_URL='([^']*)'/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 (!existsSync26(CONFIG_PATH6)) return;
9743
- let content = readFileSync22(CONFIG_PATH6, "utf-8");
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 = spawnSync9("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME}`], { encoding: "utf-8" });
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 = spawnSync9("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME_2}`], { encoding: "utf-8" });
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
- spawnSync9("docker", ["logs", "--tail", tailArg, ...followFlag, "synkro-server"], { stdio: "inherit" });
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 = spawnSync9("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME}`], { encoding: "utf-8" });
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 = spawnSync9("tmux", args2, { stdio: "inherit" });
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 = join24(homedir24(), ".synkro", "config.env");
10185
- CONFIG_PATH6 = join24(homedir24(), ".synkro", "config.env");
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 existsSync27, readFileSync as readFileSync23, readdirSync as readdirSync5 } from "fs";
10195
- import { homedir as homedir25 } from "os";
10196
- import { join as join25 } from "path";
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 readFileSync23(CONFIG_PATH7, "utf-8").split("\n")) {
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 = join25(homedir25(), ".claude", "projects", sanitized);
10215
- return existsSync27(dir) ? dir : null;
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 = readFileSync23(filePath, "utf-8").split("\n").filter(Boolean);
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(join25(dir, f), f.replace(".jsonl", ""))).filter((s) => s.messages.length > 0);
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 = join25(homedir25(), ".synkro", "config.env");
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 existsSync28, readFileSync as readFileSync24, writeFileSync as writeFileSync16 } from "fs";
10414
- import { join as join26 } from "path";
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 join26(repoRoot, LOCK_FILE);
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 existsSync29, mkdirSync as mkdirSync16, readdirSync as readdirSync6, rmSync as rmSync3, writeFileSync as writeFileSync17 } from "fs";
10450
- import { homedir as homedir26 } from "os";
10451
- import { join as join27 } from "path";
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 = join27(homedir26(), ".synkro", "cache", "packs");
10483
- if (!cloud) mkdirSync16(cacheDir, { recursive: true });
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(join27(cacheDir, fname), JSON.stringify({
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 && existsSync29(cacheDir)) {
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
- rmSync3(join27(cacheDir, f));
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 readFileSync25, writeFileSync as writeFileSync18, existsSync as existsSync30 } from "fs";
10664
- import { join as join28 } from "path";
10665
- import { homedir as homedir27 } from "os";
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 (!existsSync30(CONFIG_PATH8)) return {};
10621
+ if (!existsSync29(CONFIG_PATH8)) return {};
10668
10622
  const out = {};
10669
- for (const line of readFileSync25(CONFIG_PATH8, "utf-8").split("\n")) {
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 (!existsSync30(CONFIG_PATH8)) {
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 = readFileSync25(CONFIG_PATH8, "utf-8").split("\n");
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 SYNKRO_DIR13, CONFIG_PATH8;
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
- SYNKRO_DIR13 = join28(homedir27(), ".synkro");
10852
- CONFIG_PATH8 = join28(SYNKRO_DIR13, "config.env");
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 readFileSync26, existsSync as existsSync31 } from "fs";
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 (!existsSync31(envPath)) continue;
11048
- const envContent = readFileSync26(envPath, "utf-8");
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.64");
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