@synkro-sh/cli 1.4.2 → 1.4.4

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
@@ -3370,6 +3370,28 @@ var init_promptFetcher = __esm({
3370
3370
  }
3371
3371
  });
3372
3372
 
3373
+ // cli/local-cc/settings.ts
3374
+ import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
3375
+ import { homedir as homedir6 } from "os";
3376
+ import { join as join7 } from "path";
3377
+ function isLocalCCEnabled() {
3378
+ if (!existsSync8(CONFIG_PATH2)) return false;
3379
+ try {
3380
+ const content = readFileSync6(CONFIG_PATH2, "utf-8");
3381
+ const match = content.match(/^SYNKRO_LOCAL_INFERENCE='([^']*)'/m);
3382
+ return match?.[1] === "yes";
3383
+ } catch {
3384
+ return false;
3385
+ }
3386
+ }
3387
+ var CONFIG_PATH2;
3388
+ var init_settings = __esm({
3389
+ "cli/local-cc/settings.ts"() {
3390
+ "use strict";
3391
+ CONFIG_PATH2 = join7(homedir6(), ".synkro", "config.env");
3392
+ }
3393
+ });
3394
+
3373
3395
  // cli/local-cc/channelSource.ts
3374
3396
  var CHANNEL_PLUGIN_SOURCE;
3375
3397
  var init_channelSource = __esm({
@@ -3520,9 +3542,9 @@ await mcp.connect(new StdioServerTransport());
3520
3542
  });
3521
3543
 
3522
3544
  // cli/local-cc/install.ts
3523
- import { existsSync as existsSync8, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readFileSync as readFileSync6, chmodSync, copyFileSync, renameSync as renameSync3, unlinkSync as unlinkSync4, openSync, fsyncSync, closeSync } from "fs";
3524
- import { join as join7 } from "path";
3525
- import { homedir as homedir6 } from "os";
3545
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readFileSync as readFileSync7, chmodSync, copyFileSync, renameSync as renameSync3, unlinkSync as unlinkSync4, openSync, fsyncSync, closeSync } from "fs";
3546
+ import { join as join8 } from "path";
3547
+ import { homedir as homedir7 } from "os";
3526
3548
  import { spawnSync } from "child_process";
3527
3549
  function writePluginFiles() {
3528
3550
  mkdirSync6(SESSION_DIR, { recursive: true });
@@ -3558,10 +3580,10 @@ function runBunInstall() {
3558
3580
  }
3559
3581
  }
3560
3582
  function safelyMutateClaudeJson(mutator) {
3561
- if (!existsSync8(CLAUDE_JSON_PATH)) {
3583
+ if (!existsSync9(CLAUDE_JSON_PATH)) {
3562
3584
  return;
3563
3585
  }
3564
- const originalText = readFileSync6(CLAUDE_JSON_PATH, "utf-8");
3586
+ const originalText = readFileSync7(CLAUDE_JSON_PATH, "utf-8");
3565
3587
  let parsed;
3566
3588
  try {
3567
3589
  parsed = JSON.parse(originalText);
@@ -3686,15 +3708,15 @@ var init_install = __esm({
3686
3708
  "cli/local-cc/install.ts"() {
3687
3709
  "use strict";
3688
3710
  init_channelSource();
3689
- CLAUDE_JSON_BACKUP_PATH = join7(homedir6(), ".claude.json.synkro-bak");
3690
- SESSION_DIR = join7(homedir6(), ".synkro", "cc_sessions");
3691
- PLUGIN_PATH = join7(SESSION_DIR, "synkro-channel.ts");
3692
- PLUGIN_PKG_PATH = join7(SESSION_DIR, "package.json");
3693
- PLUGIN_SETTINGS_DIR = join7(SESSION_DIR, ".claude");
3694
- PLUGIN_SETTINGS_PATH = join7(PLUGIN_SETTINGS_DIR, "settings.json");
3695
- PROJECT_MCP_PATH = join7(SESSION_DIR, ".mcp.json");
3696
- CLAUDE_JSON_PATH = join7(homedir6(), ".claude.json");
3697
- RUN_SCRIPT_PATH = join7(SESSION_DIR, "run-claude.sh");
3711
+ CLAUDE_JSON_BACKUP_PATH = join8(homedir7(), ".claude.json.synkro-bak");
3712
+ SESSION_DIR = join8(homedir7(), ".synkro", "cc_sessions");
3713
+ PLUGIN_PATH = join8(SESSION_DIR, "synkro-channel.ts");
3714
+ PLUGIN_PKG_PATH = join8(SESSION_DIR, "package.json");
3715
+ PLUGIN_SETTINGS_DIR = join8(SESSION_DIR, ".claude");
3716
+ PLUGIN_SETTINGS_PATH = join8(PLUGIN_SETTINGS_DIR, "settings.json");
3717
+ PROJECT_MCP_PATH = join8(SESSION_DIR, ".mcp.json");
3718
+ CLAUDE_JSON_PATH = join8(homedir7(), ".claude.json");
3719
+ RUN_SCRIPT_PATH = join8(SESSION_DIR, "run-claude.sh");
3698
3720
  TMUX_SESSION_NAME = "synkro-local-cc";
3699
3721
  RUN_SCRIPT_SOURCE = `#!/usr/bin/env bash
3700
3722
  # Auto-generated by \`synkro install\`. Do not edit.
@@ -3746,8 +3768,8 @@ done
3746
3768
 
3747
3769
  // cli/local-cc/pueue.ts
3748
3770
  import { execFileSync, spawnSync as spawnSync2 } from "child_process";
3749
- import { homedir as homedir7 } from "os";
3750
- import { join as join8 } from "path";
3771
+ import { homedir as homedir8 } from "os";
3772
+ import { join as join9 } from "path";
3751
3773
  import { connect } from "net";
3752
3774
  function pueueAvailable() {
3753
3775
  const r = spawnSync2("pueue", ["--version"], { encoding: "utf-8" });
@@ -3802,7 +3824,7 @@ function startTask(opts = {}) {
3802
3824
  if (existing) {
3803
3825
  spawnSync2("pueue", ["remove", String(existing.id)], { encoding: "utf-8" });
3804
3826
  }
3805
- const runScript = join8(cwd, "run-claude.sh");
3827
+ const runScript = join9(cwd, "run-claude.sh");
3806
3828
  const args2 = [
3807
3829
  "add",
3808
3830
  "--label",
@@ -3894,7 +3916,7 @@ var init_pueue = __esm({
3894
3916
  "use strict";
3895
3917
  TASK_LABEL = "synkro-local-cc";
3896
3918
  TMUX_SESSION = "synkro-local-cc";
3897
- SESSION_DIR2 = join8(homedir7(), ".synkro", "cc_sessions");
3919
+ SESSION_DIR2 = join9(homedir8(), ".synkro", "cc_sessions");
3898
3920
  PueueError = class extends Error {
3899
3921
  constructor(message, cause) {
3900
3922
  super(message);
@@ -3907,16 +3929,16 @@ var init_pueue = __esm({
3907
3929
  });
3908
3930
 
3909
3931
  // cli/local-cc/prompts.ts
3910
- import { existsSync as existsSync9, readFileSync as readFileSync7 } from "fs";
3911
- import { homedir as homedir8 } from "os";
3912
- import { join as join9 } from "path";
3932
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
3933
+ import { homedir as homedir9 } from "os";
3934
+ import { join as join10 } from "path";
3913
3935
  function loadCachedPrompts() {
3914
3936
  if (_cached) return _cached;
3915
- if (!existsSync9(CACHE_PATH2)) {
3937
+ if (!existsSync10(CACHE_PATH2)) {
3916
3938
  throw new Error("Prompts cache not found. Run `synkro install` or `synkro update` first.");
3917
3939
  }
3918
3940
  try {
3919
- _cached = JSON.parse(readFileSync7(CACHE_PATH2, "utf-8"));
3941
+ _cached = JSON.parse(readFileSync8(CACHE_PATH2, "utf-8"));
3920
3942
  return _cached;
3921
3943
  } catch {
3922
3944
  throw new Error("Prompts cache is corrupted. Run `synkro update` to refresh.");
@@ -3942,15 +3964,15 @@ var CACHE_PATH2, _cached;
3942
3964
  var init_prompts = __esm({
3943
3965
  "cli/local-cc/prompts.ts"() {
3944
3966
  "use strict";
3945
- CACHE_PATH2 = join9(homedir8(), ".synkro", "prompts", "judge-prompts.json");
3967
+ CACHE_PATH2 = join10(homedir9(), ".synkro", "prompts", "judge-prompts.json");
3946
3968
  _cached = null;
3947
3969
  }
3948
3970
  });
3949
3971
 
3950
3972
  // cli/local-cc/turnLog.ts
3951
- import { appendFileSync, existsSync as existsSync10, mkdirSync as mkdirSync7, openSync as openSync2, readFileSync as readFileSync8, readSync, closeSync as closeSync2, statSync, watchFile, unwatchFile } from "fs";
3952
- import { dirname as dirname4, join as join10 } from "path";
3953
- import { homedir as homedir9 } from "os";
3973
+ import { appendFileSync, existsSync as existsSync11, mkdirSync as mkdirSync7, openSync as openSync2, readFileSync as readFileSync9, readSync, closeSync as closeSync2, statSync, watchFile, unwatchFile } from "fs";
3974
+ import { dirname as dirname4, join as join11 } from "path";
3975
+ import { homedir as homedir10 } from "os";
3954
3976
  function truncate(s, max = PREVIEW_MAX) {
3955
3977
  if (s.length <= max) return s;
3956
3978
  return s.slice(0, max) + "\u2026 [+" + (s.length - max) + " chars]";
@@ -3986,11 +4008,11 @@ function appendTurn(args2) {
3986
4008
  }
3987
4009
  }
3988
4010
  function readRecentTurns(n = 20) {
3989
- if (!existsSync10(TURN_LOG_PATH)) return [];
4011
+ if (!existsSync11(TURN_LOG_PATH)) return [];
3990
4012
  try {
3991
4013
  const size = statSync(TURN_LOG_PATH).size;
3992
4014
  if (size === 0) return [];
3993
- const text = readFileSync8(TURN_LOG_PATH, "utf-8");
4015
+ const text = readFileSync9(TURN_LOG_PATH, "utf-8");
3994
4016
  const lines = text.split("\n").filter(Boolean);
3995
4017
  const lastN = lines.slice(-n).reverse();
3996
4018
  return lastN.map((line) => {
@@ -4007,7 +4029,7 @@ function readRecentTurns(n = 20) {
4007
4029
  function followTurns(onEntry) {
4008
4030
  try {
4009
4031
  mkdirSync7(dirname4(TURN_LOG_PATH), { recursive: true });
4010
- if (!existsSync10(TURN_LOG_PATH)) {
4032
+ if (!existsSync11(TURN_LOG_PATH)) {
4011
4033
  appendFileSync(TURN_LOG_PATH, "", "utf-8");
4012
4034
  }
4013
4035
  } catch {
@@ -4069,7 +4091,7 @@ var TURN_LOG_PATH, PREVIEW_MAX;
4069
4091
  var init_turnLog = __esm({
4070
4092
  "cli/local-cc/turnLog.ts"() {
4071
4093
  "use strict";
4072
- TURN_LOG_PATH = join10(homedir9(), ".synkro", "cc_sessions", "turns.log");
4094
+ TURN_LOG_PATH = join11(homedir10(), ".synkro", "cc_sessions", "turns.log");
4073
4095
  PREVIEW_MAX = 400;
4074
4096
  }
4075
4097
  });
@@ -4175,9 +4197,9 @@ __export(install_exports, {
4175
4197
  installCommand: () => installCommand,
4176
4198
  parseArgs: () => parseArgs
4177
4199
  });
4178
- import { existsSync as existsSync11, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, chmodSync as chmodSync2, readFileSync as readFileSync9, readdirSync } from "fs";
4179
- import { homedir as homedir10 } from "os";
4180
- import { join as join11 } from "path";
4200
+ import { existsSync as existsSync12, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, chmodSync as chmodSync2, readFileSync as readFileSync10, readdirSync } from "fs";
4201
+ import { homedir as homedir11 } from "os";
4202
+ import { join as join12 } from "path";
4181
4203
  import { execSync as execSync5 } from "child_process";
4182
4204
  import { createInterface as createInterface3 } from "readline";
4183
4205
  function sanitizeGatewayCandidate(raw) {
@@ -4220,13 +4242,13 @@ function ensureSynkroDir() {
4220
4242
  mkdirSync8(OFFSETS_DIR, { recursive: true });
4221
4243
  }
4222
4244
  function writeHookScripts() {
4223
- const bashScriptPath = join11(HOOKS_DIR, "cc-bash-judge.sh");
4224
- const bashFollowupScriptPath = join11(HOOKS_DIR, "cc-bash-followup.sh");
4225
- const editCaptureScriptPath = join11(HOOKS_DIR, "cc-edit-capture.sh");
4226
- const editPrecheckScriptPath = join11(HOOKS_DIR, "cc-edit-precheck.sh");
4227
- const stopSummaryScriptPath = join11(HOOKS_DIR, "cc-stop-summary.sh");
4228
- const sessionStartScriptPath = join11(HOOKS_DIR, "cc-session-start.sh");
4229
- const transcriptSyncScriptPath = join11(HOOKS_DIR, "cc-transcript-sync.sh");
4245
+ const bashScriptPath = join12(HOOKS_DIR, "cc-bash-judge.sh");
4246
+ const bashFollowupScriptPath = join12(HOOKS_DIR, "cc-bash-followup.sh");
4247
+ const editCaptureScriptPath = join12(HOOKS_DIR, "cc-edit-capture.sh");
4248
+ const editPrecheckScriptPath = join12(HOOKS_DIR, "cc-edit-precheck.sh");
4249
+ const stopSummaryScriptPath = join12(HOOKS_DIR, "cc-stop-summary.sh");
4250
+ const sessionStartScriptPath = join12(HOOKS_DIR, "cc-session-start.sh");
4251
+ const transcriptSyncScriptPath = join12(HOOKS_DIR, "cc-transcript-sync.sh");
4230
4252
  writeFileSync7(bashScriptPath, CC_BASH_JUDGE_SCRIPT, "utf-8");
4231
4253
  writeFileSync7(bashFollowupScriptPath, CC_BASH_FOLLOWUP_SCRIPT, "utf-8");
4232
4254
  writeFileSync7(editCaptureScriptPath, CC_EDIT_CAPTURE_SCRIPT, "utf-8");
@@ -4260,11 +4282,11 @@ function shellQuoteSingle(value) {
4260
4282
  }
4261
4283
  function resolveSynkroBundle() {
4262
4284
  const scriptPath = process.argv[1];
4263
- if (scriptPath && existsSync11(scriptPath)) return scriptPath;
4285
+ if (scriptPath && existsSync12(scriptPath)) return scriptPath;
4264
4286
  return null;
4265
4287
  }
4266
4288
  function writeConfigEnv(opts) {
4267
- const credsPath = join11(SYNKRO_DIR2, "credentials.json");
4289
+ const credsPath = join12(SYNKRO_DIR2, "credentials.json");
4268
4290
  const safeGateway = sanitizeConfigValue(opts.gatewayUrl);
4269
4291
  const safeUserId = sanitizeConfigValue(opts.userId);
4270
4292
  const safeOrgId = sanitizeConfigValue(opts.orgId);
@@ -4280,7 +4302,7 @@ function writeConfigEnv(opts) {
4280
4302
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
4281
4303
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
4282
4304
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
4283
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.2")}`
4305
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.4")}`
4284
4306
  ];
4285
4307
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
4286
4308
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -4291,8 +4313,21 @@ function writeConfigEnv(opts) {
4291
4313
  }
4292
4314
  lines.push(`SYNKRO_LOCAL_INFERENCE=${shellQuoteSingle(opts.localInference ? "yes" : "no")}`);
4293
4315
  lines.push("");
4294
- writeFileSync7(CONFIG_PATH2, lines.join("\n"), "utf-8");
4295
- chmodSync2(CONFIG_PATH2, 384);
4316
+ writeFileSync7(CONFIG_PATH3, lines.join("\n"), "utf-8");
4317
+ chmodSync2(CONFIG_PATH3, 384);
4318
+ }
4319
+ function updateLocalInferenceFlag(enabled) {
4320
+ if (!existsSync12(CONFIG_PATH3)) return;
4321
+ let content = readFileSync10(CONFIG_PATH3, "utf-8");
4322
+ const flag = enabled ? "yes" : "no";
4323
+ if (content.includes("SYNKRO_LOCAL_INFERENCE=")) {
4324
+ content = content.replace(/^SYNKRO_LOCAL_INFERENCE='[^']*'/m, `SYNKRO_LOCAL_INFERENCE='${flag}'`);
4325
+ } else {
4326
+ content = content.trimEnd() + `
4327
+ SYNKRO_LOCAL_INFERENCE='${flag}'
4328
+ `;
4329
+ }
4330
+ writeFileSync7(CONFIG_PATH3, content, "utf-8");
4296
4331
  }
4297
4332
  function collectLocalMetadata() {
4298
4333
  const meta = { platform: process.platform };
@@ -4312,16 +4347,16 @@ function collectLocalMetadata() {
4312
4347
  meta.cc_version = execSync5("claude --version", { encoding: "utf-8", timeout: 5e3 }).trim().split("\n")[0];
4313
4348
  } catch {
4314
4349
  }
4315
- const claudeDir = join11(homedir10(), ".claude");
4350
+ const claudeDir = join12(homedir11(), ".claude");
4316
4351
  try {
4317
- const settings = JSON.parse(readFileSync9(join11(claudeDir, "settings.json"), "utf-8"));
4352
+ const settings = JSON.parse(readFileSync10(join12(claudeDir, "settings.json"), "utf-8"));
4318
4353
  const plugins = Object.keys(settings.enabledPlugins ?? {}).filter((k) => settings.enabledPlugins[k]);
4319
4354
  if (plugins.length) meta.enabled_plugins = plugins;
4320
4355
  if (settings.permissions?.defaultMode) meta.permissions_mode = settings.permissions.defaultMode;
4321
4356
  } catch {
4322
4357
  }
4323
4358
  try {
4324
- const mcpCache = JSON.parse(readFileSync9(join11(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
4359
+ const mcpCache = JSON.parse(readFileSync10(join12(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
4325
4360
  const mcpNames = Object.keys(mcpCache);
4326
4361
  if (mcpNames.length) meta.mcp_servers = mcpNames;
4327
4362
  } catch {
@@ -4333,10 +4368,10 @@ function collectLocalMetadata() {
4333
4368
  } catch {
4334
4369
  }
4335
4370
  try {
4336
- const sessionsDir = join11(claudeDir, "sessions");
4371
+ const sessionsDir = join12(claudeDir, "sessions");
4337
4372
  const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).slice(-5);
4338
4373
  for (const f of files) {
4339
- const s = JSON.parse(readFileSync9(join11(sessionsDir, f), "utf-8"));
4374
+ const s = JSON.parse(readFileSync10(join12(sessionsDir, f), "utf-8"));
4340
4375
  if (s.version) {
4341
4376
  meta.cc_version = meta.cc_version || s.version;
4342
4377
  break;
@@ -4392,19 +4427,19 @@ function assertGatewayAllowed(gatewayUrl) {
4392
4427
  }
4393
4428
  function isAlreadyInstalled() {
4394
4429
  const requiredScripts = [
4395
- join11(HOOKS_DIR, "cc-bash-judge.sh"),
4396
- join11(HOOKS_DIR, "cc-bash-followup.sh"),
4397
- join11(HOOKS_DIR, "cc-edit-precheck.sh"),
4398
- join11(HOOKS_DIR, "cc-edit-capture.sh"),
4399
- join11(HOOKS_DIR, "cc-stop-summary.sh"),
4400
- join11(HOOKS_DIR, "cc-session-start.sh")
4430
+ join12(HOOKS_DIR, "cc-bash-judge.sh"),
4431
+ join12(HOOKS_DIR, "cc-bash-followup.sh"),
4432
+ join12(HOOKS_DIR, "cc-edit-precheck.sh"),
4433
+ join12(HOOKS_DIR, "cc-edit-capture.sh"),
4434
+ join12(HOOKS_DIR, "cc-stop-summary.sh"),
4435
+ join12(HOOKS_DIR, "cc-session-start.sh")
4401
4436
  ];
4402
- if (!requiredScripts.every((p) => existsSync11(p))) return false;
4403
- if (!existsSync11(CONFIG_PATH2)) return false;
4404
- const settingsPath = join11(homedir10(), ".claude", "settings.json");
4405
- if (!existsSync11(settingsPath)) return false;
4437
+ if (!requiredScripts.every((p) => existsSync12(p))) return false;
4438
+ if (!existsSync12(CONFIG_PATH3)) return false;
4439
+ const settingsPath = join12(homedir11(), ".claude", "settings.json");
4440
+ if (!existsSync12(settingsPath)) return false;
4406
4441
  try {
4407
- const settings = JSON.parse(readFileSync9(settingsPath, "utf-8"));
4442
+ const settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
4408
4443
  const hooks = settings?.hooks;
4409
4444
  if (!hooks || typeof hooks !== "object") return false;
4410
4445
  const hasManaged = (kind) => Array.isArray(hooks[kind]) && hooks[kind].some((entry) => entry?.__synkro_managed__ === true);
@@ -4444,6 +4479,29 @@ async function installCommand(opts = {}) {
4444
4479
  } catch {
4445
4480
  }
4446
4481
  }
4482
+ const token2 = getAccessToken();
4483
+ if (token2) {
4484
+ const profile2 = await fetchUserProfile(gatewayUrl, token2);
4485
+ if (profile2.localInference && !isLocalCCEnabled()) {
4486
+ console.log("Local inference enabled in your profile \u2014 setting up local-CC channel...");
4487
+ try {
4488
+ assertClaudeInstalled();
4489
+ assertPueueInstalled();
4490
+ assertTmuxInstalled();
4491
+ installLocalCC();
4492
+ const t = ensureRunning();
4493
+ console.log(` pueue task: id=${t.id} status=${t.status}`);
4494
+ console.log(" Waiting for channel...");
4495
+ const ready = await waitForChannelReady(CHANNEL_PORT, 6e4, CHANNEL_HOST);
4496
+ if (ready) console.log(` channel ready at ${CHANNEL_HOST}:${CHANNEL_PORT}`);
4497
+ else console.warn(" \u26A0 channel did not come up within 60s \u2014 check `synkro local-cc logs`");
4498
+ updateLocalInferenceFlag(true);
4499
+ } catch (err) {
4500
+ console.warn(` \u26A0 Local-CC setup skipped: ${err.message}`);
4501
+ console.warn(" Install pueue, tmux, and claude, then re-run install.");
4502
+ }
4503
+ }
4504
+ }
4447
4505
  console.log("\u2713 Synkro is already installed and configured.");
4448
4506
  console.log(" Run `synkro-cli update` to refresh hook scripts and judge prompts.");
4449
4507
  console.log(" Run `synkro-cli install --force` to reinstall from scratch.");
@@ -4512,9 +4570,9 @@ async function installCommand(opts = {}) {
4512
4570
  console.log(` ${scripts.transcriptSyncScript}
4513
4571
  `);
4514
4572
  for (const mode of ["edit", "bash"]) {
4515
- const pidFile = join11(SYNKRO_DIR2, "daemon", mode, "daemon.pid");
4573
+ const pidFile = join12(SYNKRO_DIR2, "daemon", mode, "daemon.pid");
4516
4574
  try {
4517
- const pid = parseInt(readFileSync9(pidFile, "utf-8").trim(), 10);
4575
+ const pid = parseInt(readFileSync10(pidFile, "utf-8").trim(), 10);
4518
4576
  if (pid > 0) {
4519
4577
  process.kill(pid, "SIGTERM");
4520
4578
  console.log(`Stopped stale ${mode} grader daemon (pid ${pid})`);
@@ -4589,7 +4647,7 @@ async function installCommand(opts = {}) {
4589
4647
  const profile = await fetchUserProfile(gatewayUrl, token);
4590
4648
  const synkroBundle = resolveSynkroBundle();
4591
4649
  writeConfigEnv({ gatewayUrl, userId, orgId, email, tier: profile.tier, inference: profile.inference, synkroBin: synkroBundle, transcriptConsent, localInference: profile.localInference });
4592
- console.log(`Wrote config to ${CONFIG_PATH2}`);
4650
+ console.log(`Wrote config to ${CONFIG_PATH3}`);
4593
4651
  console.log(` inference: ${profile.inference} (server-side grading)`);
4594
4652
  if (profile.localInference) console.log(` local inference: enabled (gradingProvider=claude-code)`);
4595
4653
  if (synkroBundle) console.log(` SYNKRO_CLI_BIN=${synkroBundle}`);
@@ -4667,17 +4725,17 @@ function detectGitRepo2() {
4667
4725
  function getClaudeProjectsFolder() {
4668
4726
  const cwd = process.cwd();
4669
4727
  const sanitized = "-" + cwd.replace(/\//g, "-");
4670
- const projectsDir = join11(homedir10(), ".claude", "projects", sanitized);
4671
- return existsSync11(projectsDir) ? projectsDir : null;
4728
+ const projectsDir = join12(homedir11(), ".claude", "projects", sanitized);
4729
+ return existsSync12(projectsDir) ? projectsDir : null;
4672
4730
  }
4673
4731
  function extractSessionInsights(projectsDir) {
4674
4732
  const insights = [];
4675
4733
  const files = readdirSync(projectsDir).filter((f) => f.endsWith(".jsonl"));
4676
4734
  for (const file of files) {
4677
4735
  const sessionId = file.replace(".jsonl", "");
4678
- const filePath = join11(projectsDir, file);
4736
+ const filePath = join12(projectsDir, file);
4679
4737
  try {
4680
- const content = readFileSync9(filePath, "utf-8");
4738
+ const content = readFileSync10(filePath, "utf-8");
4681
4739
  const lines = content.split("\n").filter(Boolean);
4682
4740
  for (let i = 0; i < lines.length; i++) {
4683
4741
  try {
@@ -4753,7 +4811,7 @@ function extractTextContent(content) {
4753
4811
  return "";
4754
4812
  }
4755
4813
  function parseTranscriptFile(filePath) {
4756
- const content = readFileSync9(filePath, "utf-8");
4814
+ const content = readFileSync10(filePath, "utf-8");
4757
4815
  const lines = content.split("\n").filter(Boolean);
4758
4816
  const messages = [];
4759
4817
  for (let i = 0; i < lines.length; i++) {
@@ -4804,7 +4862,7 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
4804
4862
  const sessions = [];
4805
4863
  for (const file of batch) {
4806
4864
  const sessionId = file.replace(".jsonl", "");
4807
- const filePath = join11(projectsDir, file);
4865
+ const filePath = join12(projectsDir, file);
4808
4866
  try {
4809
4867
  const allMessages = parseTranscriptFile(filePath);
4810
4868
  const messages = allMessages.length > maxMessagesPerSession ? allMessages.slice(-maxMessagesPerSession) : allMessages;
@@ -4833,18 +4891,18 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
4833
4891
  }
4834
4892
  for (const file of batch) {
4835
4893
  const sessionId = file.replace(".jsonl", "");
4836
- const filePath = join11(projectsDir, file);
4894
+ const filePath = join12(projectsDir, file);
4837
4895
  try {
4838
- const content = readFileSync9(filePath, "utf-8");
4896
+ const content = readFileSync10(filePath, "utf-8");
4839
4897
  const lineCount = content.split("\n").filter(Boolean).length;
4840
- writeFileSync7(join11(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
4898
+ writeFileSync7(join12(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
4841
4899
  } catch {
4842
4900
  }
4843
4901
  }
4844
4902
  }
4845
4903
  return { sessions: totalSessions, messages: totalMessages };
4846
4904
  }
4847
- var SYNKRO_DIR2, HOOKS_DIR, BIN_DIR, CONFIG_PATH2, OFFSETS_DIR;
4905
+ var SYNKRO_DIR2, HOOKS_DIR, BIN_DIR, CONFIG_PATH3, OFFSETS_DIR;
4848
4906
  var init_install2 = __esm({
4849
4907
  "cli/commands/install.ts"() {
4850
4908
  "use strict";
@@ -4857,14 +4915,15 @@ var init_install2 = __esm({
4857
4915
  init_projects();
4858
4916
  init_setupGithub();
4859
4917
  init_promptFetcher();
4918
+ init_settings();
4860
4919
  init_install();
4861
4920
  init_pueue();
4862
4921
  init_client();
4863
- SYNKRO_DIR2 = join11(homedir10(), ".synkro");
4864
- HOOKS_DIR = join11(SYNKRO_DIR2, "hooks");
4865
- BIN_DIR = join11(SYNKRO_DIR2, "bin");
4866
- CONFIG_PATH2 = join11(SYNKRO_DIR2, "config.env");
4867
- OFFSETS_DIR = join11(SYNKRO_DIR2, ".transcript-offsets");
4922
+ SYNKRO_DIR2 = join12(homedir11(), ".synkro");
4923
+ HOOKS_DIR = join12(SYNKRO_DIR2, "hooks");
4924
+ BIN_DIR = join12(SYNKRO_DIR2, "bin");
4925
+ CONFIG_PATH3 = join12(SYNKRO_DIR2, "config.env");
4926
+ OFFSETS_DIR = join12(SYNKRO_DIR2, ".transcript-offsets");
4868
4927
  }
4869
4928
  });
4870
4929
 
@@ -4940,13 +4999,13 @@ var status_exports = {};
4940
4999
  __export(status_exports, {
4941
5000
  statusCommand: () => statusCommand
4942
5001
  });
4943
- import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
4944
- import { homedir as homedir11 } from "os";
4945
- import { join as join12 } from "path";
5002
+ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
5003
+ import { homedir as homedir12 } from "os";
5004
+ import { join as join13 } from "path";
4946
5005
  function readConfigEnv() {
4947
- if (!existsSync12(CONFIG_PATH3)) return {};
5006
+ if (!existsSync13(CONFIG_PATH4)) return {};
4948
5007
  const out = {};
4949
- const raw = readFileSync10(CONFIG_PATH3, "utf-8");
5008
+ const raw = readFileSync11(CONFIG_PATH4, "utf-8");
4950
5009
  for (const line of raw.split("\n")) {
4951
5010
  const trimmed = line.trim();
4952
5011
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -5019,19 +5078,19 @@ async function statusCommand() {
5019
5078
  }
5020
5079
  }
5021
5080
  console.log();
5022
- const bashScript = join12(SYNKRO_DIR3, "hooks", "cc-bash-judge.sh");
5023
- const bashFollowupScript = join12(SYNKRO_DIR3, "hooks", "cc-bash-followup.sh");
5024
- const editPrecheckScript = join12(SYNKRO_DIR3, "hooks", "cc-edit-precheck.sh");
5025
- const editCaptureScript = join12(SYNKRO_DIR3, "hooks", "cc-edit-capture.sh");
5026
- const stopSummaryScript = join12(SYNKRO_DIR3, "hooks", "cc-stop-summary.sh");
5027
- const sessionStartScript = join12(SYNKRO_DIR3, "hooks", "cc-session-start.sh");
5081
+ const bashScript = join13(SYNKRO_DIR3, "hooks", "cc-bash-judge.sh");
5082
+ const bashFollowupScript = join13(SYNKRO_DIR3, "hooks", "cc-bash-followup.sh");
5083
+ const editPrecheckScript = join13(SYNKRO_DIR3, "hooks", "cc-edit-precheck.sh");
5084
+ const editCaptureScript = join13(SYNKRO_DIR3, "hooks", "cc-edit-capture.sh");
5085
+ const stopSummaryScript = join13(SYNKRO_DIR3, "hooks", "cc-stop-summary.sh");
5086
+ const sessionStartScript = join13(SYNKRO_DIR3, "hooks", "cc-session-start.sh");
5028
5087
  console.log("Hook scripts:");
5029
- console.log(` ${existsSync12(bashScript) ? "\u2713" : "\u2717"} ${bashScript}`);
5030
- console.log(` ${existsSync12(bashFollowupScript) ? "\u2713" : "\u2717"} ${bashFollowupScript}`);
5031
- console.log(` ${existsSync12(editPrecheckScript) ? "\u2713" : "\u2717"} ${editPrecheckScript}`);
5032
- console.log(` ${existsSync12(editCaptureScript) ? "\u2713" : "\u2717"} ${editCaptureScript}`);
5033
- console.log(` ${existsSync12(stopSummaryScript) ? "\u2713" : "\u2717"} ${stopSummaryScript}`);
5034
- console.log(` ${existsSync12(sessionStartScript) ? "\u2713" : "\u2717"} ${sessionStartScript}`);
5088
+ console.log(` ${existsSync13(bashScript) ? "\u2713" : "\u2717"} ${bashScript}`);
5089
+ console.log(` ${existsSync13(bashFollowupScript) ? "\u2713" : "\u2717"} ${bashFollowupScript}`);
5090
+ console.log(` ${existsSync13(editPrecheckScript) ? "\u2713" : "\u2717"} ${editPrecheckScript}`);
5091
+ console.log(` ${existsSync13(editCaptureScript) ? "\u2713" : "\u2717"} ${editCaptureScript}`);
5092
+ console.log(` ${existsSync13(stopSummaryScript) ? "\u2713" : "\u2717"} ${stopSummaryScript}`);
5093
+ console.log(` ${existsSync13(sessionStartScript) ? "\u2713" : "\u2717"} ${sessionStartScript}`);
5035
5094
  console.log();
5036
5095
  const mcp = inspectMcpConfig();
5037
5096
  console.log("Guardrails MCP server (Claude Code):");
@@ -5043,7 +5102,7 @@ async function statusCommand() {
5043
5102
  console.log(` expected at ${mcp.configPath} \u2192 mcpServers.synkro-guardrails`);
5044
5103
  }
5045
5104
  }
5046
- var SYNKRO_DIR3, CONFIG_PATH3;
5105
+ var SYNKRO_DIR3, CONFIG_PATH4;
5047
5106
  var init_status = __esm({
5048
5107
  "cli/commands/status.ts"() {
5049
5108
  "use strict";
@@ -5051,8 +5110,8 @@ var init_status = __esm({
5051
5110
  init_agentDetect();
5052
5111
  init_ccHookConfig();
5053
5112
  init_mcpConfig();
5054
- SYNKRO_DIR3 = join12(homedir11(), ".synkro");
5055
- CONFIG_PATH3 = join12(SYNKRO_DIR3, "config.env");
5113
+ SYNKRO_DIR3 = join13(homedir12(), ".synkro");
5114
+ CONFIG_PATH4 = join13(SYNKRO_DIR3, "config.env");
5056
5115
  }
5057
5116
  });
5058
5117
 
@@ -5141,13 +5200,13 @@ var config_exports = {};
5141
5200
  __export(config_exports, {
5142
5201
  configCommand: () => configCommand
5143
5202
  });
5144
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, existsSync as existsSync13 } from "fs";
5145
- import { join as join13 } from "path";
5146
- import { homedir as homedir12 } from "os";
5203
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync14 } from "fs";
5204
+ import { join as join14 } from "path";
5205
+ import { homedir as homedir13 } from "os";
5147
5206
  function readConfigEnv2() {
5148
- if (!existsSync13(CONFIG_PATH4)) return {};
5207
+ if (!existsSync14(CONFIG_PATH5)) return {};
5149
5208
  const out = {};
5150
- for (const line of readFileSync11(CONFIG_PATH4, "utf-8").split("\n")) {
5209
+ for (const line of readFileSync12(CONFIG_PATH5, "utf-8").split("\n")) {
5151
5210
  const t = line.trim();
5152
5211
  if (!t || t.startsWith("#")) continue;
5153
5212
  const eq = t.indexOf("=");
@@ -5156,11 +5215,11 @@ function readConfigEnv2() {
5156
5215
  return out;
5157
5216
  }
5158
5217
  function updateConfigValue(key, value) {
5159
- if (!existsSync13(CONFIG_PATH4)) {
5218
+ if (!existsSync14(CONFIG_PATH5)) {
5160
5219
  console.error("No config found. Run `synkro install` first.");
5161
5220
  process.exit(1);
5162
5221
  }
5163
- const lines = readFileSync11(CONFIG_PATH4, "utf-8").split("\n");
5222
+ const lines = readFileSync12(CONFIG_PATH5, "utf-8").split("\n");
5164
5223
  const pattern = new RegExp(`^${key}=`);
5165
5224
  let found = false;
5166
5225
  const updated = lines.map((line) => {
@@ -5171,7 +5230,7 @@ function updateConfigValue(key, value) {
5171
5230
  return line;
5172
5231
  });
5173
5232
  if (!found) updated.splice(updated.length - 1, 0, `${key}='${value}'`);
5174
- writeFileSync8(CONFIG_PATH4, updated.join("\n"), "utf-8");
5233
+ writeFileSync8(CONFIG_PATH5, updated.join("\n"), "utf-8");
5175
5234
  }
5176
5235
  async function configCommand(args2) {
5177
5236
  if (args2.length === 0) {
@@ -5222,13 +5281,13 @@ To change: synkro config --inference fast|standard`);
5222
5281
  updateConfigValue("SYNKRO_INFERENCE", inferenceValue);
5223
5282
  console.log(`\u2713 Inference set to '${inferenceValue}'.`);
5224
5283
  }
5225
- var SYNKRO_DIR4, CONFIG_PATH4;
5284
+ var SYNKRO_DIR4, CONFIG_PATH5;
5226
5285
  var init_config = __esm({
5227
5286
  "cli/commands/config.ts"() {
5228
5287
  "use strict";
5229
5288
  init_stub();
5230
- SYNKRO_DIR4 = join13(homedir12(), ".synkro");
5231
- CONFIG_PATH4 = join13(SYNKRO_DIR4, "config.env");
5289
+ SYNKRO_DIR4 = join14(homedir13(), ".synkro");
5290
+ CONFIG_PATH5 = join14(SYNKRO_DIR4, "config.env");
5232
5291
  }
5233
5292
  });
5234
5293
 
@@ -5238,8 +5297,8 @@ __export(scanPr_exports, {
5238
5297
  scanPrCommand: () => scanPrCommand
5239
5298
  });
5240
5299
  import { execSync as execSync6, spawn } from "child_process";
5241
- import { readFileSync as readFileSync12, existsSync as existsSync14 } from "fs";
5242
- import { join as join14 } from "path";
5300
+ import { readFileSync as readFileSync13, existsSync as existsSync15 } from "fs";
5301
+ import { join as join15 } from "path";
5243
5302
  function parseMatchSpec(condition) {
5244
5303
  if (!condition.startsWith("match_spec:")) return null;
5245
5304
  try {
@@ -5718,10 +5777,10 @@ function shouldFail(findings, threshold) {
5718
5777
  return findings.some((f) => order.indexOf(f.severity) >= thresholdIdx);
5719
5778
  }
5720
5779
  function readRepoDeps() {
5721
- const pkgPath = join14(process.cwd(), "package.json");
5722
- if (!existsSync14(pkgPath)) return {};
5780
+ const pkgPath = join15(process.cwd(), "package.json");
5781
+ if (!existsSync15(pkgPath)) return {};
5723
5782
  try {
5724
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
5783
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
5725
5784
  return { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
5726
5785
  } catch {
5727
5786
  return {};
@@ -5983,9 +6042,9 @@ var disconnect_exports = {};
5983
6042
  __export(disconnect_exports, {
5984
6043
  disconnectCommand: () => disconnectCommand
5985
6044
  });
5986
- import { existsSync as existsSync15, rmSync } from "fs";
5987
- import { homedir as homedir13 } from "os";
5988
- import { join as join15 } from "path";
6045
+ import { existsSync as existsSync16, rmSync } from "fs";
6046
+ import { homedir as homedir14 } from "os";
6047
+ import { join as join16 } from "path";
5989
6048
  function tearDownLocalCC() {
5990
6049
  let hadTask = false;
5991
6050
  try {
@@ -6015,13 +6074,13 @@ function disconnectCommand(args2 = []) {
6015
6074
  console.log(`${mcpRemoved ? "\u2713" : "\xB7"} MCP guardrails server: ${mcpRemoved ? "removed entry from ~/.claude.json" : "no Synkro MCP entry found"}`);
6016
6075
  }
6017
6076
  if (purge) {
6018
- if (existsSync15(SYNKRO_DIR5)) {
6077
+ if (existsSync16(SYNKRO_DIR5)) {
6019
6078
  rmSync(SYNKRO_DIR5, { recursive: true, force: true });
6020
6079
  console.log(`\u2713 Removed ${SYNKRO_DIR5}`);
6021
6080
  } else {
6022
6081
  console.log(`\xB7 ${SYNKRO_DIR5} already gone, nothing to remove`);
6023
6082
  }
6024
- } else if (existsSync15(SYNKRO_DIR5)) {
6083
+ } else if (existsSync16(SYNKRO_DIR5)) {
6025
6084
  console.log(`Config preserved at ${SYNKRO_DIR5}. Run with --purge to remove.`);
6026
6085
  }
6027
6086
  console.log("\nSynkro disconnected.");
@@ -6035,7 +6094,7 @@ var init_disconnect = __esm({
6035
6094
  init_mcpConfig();
6036
6095
  init_pueue();
6037
6096
  init_install();
6038
- SYNKRO_DIR5 = join15(homedir13(), ".synkro");
6097
+ SYNKRO_DIR5 = join16(homedir14(), ".synkro");
6039
6098
  }
6040
6099
  });
6041
6100
 
@@ -6076,28 +6135,6 @@ var init_reinstall = __esm({
6076
6135
  }
6077
6136
  });
6078
6137
 
6079
- // cli/local-cc/settings.ts
6080
- import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
6081
- import { homedir as homedir14 } from "os";
6082
- import { join as join16 } from "path";
6083
- function isLocalCCEnabled() {
6084
- if (!existsSync16(CONFIG_PATH5)) return false;
6085
- try {
6086
- const content = readFileSync13(CONFIG_PATH5, "utf-8");
6087
- const match = content.match(/^SYNKRO_LOCAL_INFERENCE='([^']*)'/m);
6088
- return match?.[1] === "yes";
6089
- } catch {
6090
- return false;
6091
- }
6092
- }
6093
- var CONFIG_PATH5;
6094
- var init_settings = __esm({
6095
- "cli/local-cc/settings.ts"() {
6096
- "use strict";
6097
- CONFIG_PATH5 = join16(homedir14(), ".synkro", "config.env");
6098
- }
6099
- });
6100
-
6101
6138
  // cli/commands/localCc.ts
6102
6139
  var localCc_exports = {};
6103
6140
  __export(localCc_exports, {
@@ -6202,7 +6239,7 @@ function readGatewayUrl() {
6202
6239
  }
6203
6240
  return "https://api.synkro.sh";
6204
6241
  }
6205
- function updateLocalInferenceFlag(enabled) {
6242
+ function updateLocalInferenceFlag2(enabled) {
6206
6243
  if (!existsSync17(CONFIG_PATH6)) return;
6207
6244
  let content = readFileSync14(CONFIG_PATH6, "utf-8");
6208
6245
  const flag = enabled ? "yes" : "no";
@@ -6268,13 +6305,13 @@ async function cmdEnable() {
6268
6305
  else console.warn(` \u26A0 channel did not come up within 60s \u2014 check \`synkro local-cc logs\``);
6269
6306
  console.log("Updating inference settings...");
6270
6307
  await setServerGradingProvider("claude-code");
6271
- updateLocalInferenceFlag(true);
6308
+ updateLocalInferenceFlag2(true);
6272
6309
  console.log("Grading provider set to claude-code (local inference enabled).");
6273
6310
  }
6274
6311
  async function cmdDisable() {
6275
6312
  console.log("Updating inference settings...");
6276
6313
  await setServerGradingProvider(null);
6277
- updateLocalInferenceFlag(false);
6314
+ updateLocalInferenceFlag2(false);
6278
6315
  console.log("Grading provider cleared (remote inference restored). Pueue task left running \u2014 use `synkro local-cc stop` to terminate.");
6279
6316
  }
6280
6317
  async function cmdStart() {