@synkro-sh/cli 1.4.0 → 1.4.1

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,87 +3370,6 @@ var init_promptFetcher = __esm({
3370
3370
  }
3371
3371
  });
3372
3372
 
3373
- // cli/storage/local.ts
3374
- import Database from "better-sqlite3";
3375
- import { existsSync as existsSync8, mkdirSync as mkdirSync6 } from "fs";
3376
- import { homedir as homedir6 } from "os";
3377
- import { join as join7 } from "path";
3378
- function getSetting(key) {
3379
- const row = db.prepare("SELECT value FROM settings WHERE key = ?").get(key);
3380
- return row?.value ?? null;
3381
- }
3382
- function setSetting(key, value) {
3383
- db.prepare(
3384
- `INSERT INTO settings (key, value, updated_at) VALUES (?, ?, datetime('now'))
3385
- ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`
3386
- ).run(key, value);
3387
- }
3388
- var SYNKRO_DIR2, DB_PATH, db;
3389
- var init_local = __esm({
3390
- "cli/storage/local.ts"() {
3391
- "use strict";
3392
- SYNKRO_DIR2 = join7(homedir6(), ".synkro");
3393
- DB_PATH = join7(SYNKRO_DIR2, "sessions.db");
3394
- if (!existsSync8(SYNKRO_DIR2)) {
3395
- mkdirSync6(SYNKRO_DIR2, { recursive: true });
3396
- }
3397
- try {
3398
- db = new Database(DB_PATH);
3399
- } catch (err) {
3400
- const msg = err instanceof Error ? err.message : String(err);
3401
- console.error(`Failed to initialize database at ${DB_PATH}: ${msg}`);
3402
- console.error("Check that ~/.synkro/ is writable and disk is not full.");
3403
- process.exit(1);
3404
- }
3405
- db.exec(`
3406
- CREATE TABLE IF NOT EXISTS command_history (
3407
- id INTEGER PRIMARY KEY AUTOINCREMENT,
3408
- command TEXT NOT NULL,
3409
- created_at TEXT DEFAULT (datetime('now'))
3410
- );
3411
- `);
3412
- db.exec(`
3413
- CREATE TABLE IF NOT EXISTS project_keys (
3414
- slug TEXT PRIMARY KEY,
3415
- project_id TEXT NOT NULL,
3416
- project_name TEXT NOT NULL,
3417
- api_key TEXT NOT NULL,
3418
- created_at TEXT DEFAULT (datetime('now'))
3419
- );
3420
- `);
3421
- db.exec(`
3422
- CREATE TABLE IF NOT EXISTS settings (
3423
- key TEXT PRIMARY KEY,
3424
- value TEXT NOT NULL,
3425
- updated_at TEXT DEFAULT (datetime('now'))
3426
- );
3427
- `);
3428
- process.on("exit", () => {
3429
- db.close();
3430
- });
3431
- }
3432
- });
3433
-
3434
- // cli/local-cc/settings.ts
3435
- function getInferenceProvider() {
3436
- const raw = getSetting(KEY);
3437
- return raw === "local-cc" ? "local-cc" : "inngest";
3438
- }
3439
- function setInferenceProvider(value) {
3440
- setSetting(KEY, value);
3441
- }
3442
- function isLocalCCEnabled() {
3443
- return getInferenceProvider() === "local-cc";
3444
- }
3445
- var KEY;
3446
- var init_settings = __esm({
3447
- "cli/local-cc/settings.ts"() {
3448
- "use strict";
3449
- init_local();
3450
- KEY = "inference_provider";
3451
- }
3452
- });
3453
-
3454
3373
  // cli/local-cc/channelSource.ts
3455
3374
  var CHANNEL_PLUGIN_SOURCE;
3456
3375
  var init_channelSource = __esm({
@@ -3601,13 +3520,13 @@ await mcp.connect(new StdioServerTransport());
3601
3520
  });
3602
3521
 
3603
3522
  // cli/local-cc/install.ts
3604
- import { existsSync as existsSync9, mkdirSync as mkdirSync7, writeFileSync as writeFileSync6, readFileSync as readFileSync6, chmodSync, copyFileSync, renameSync as renameSync3, unlinkSync as unlinkSync4, openSync, fsyncSync, closeSync } from "fs";
3605
- import { join as join8 } from "path";
3606
- import { homedir as homedir7 } from "os";
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";
3607
3526
  import { spawnSync } from "child_process";
3608
3527
  function writePluginFiles() {
3609
- mkdirSync7(SESSION_DIR, { recursive: true });
3610
- mkdirSync7(PLUGIN_SETTINGS_DIR, { recursive: true });
3528
+ mkdirSync6(SESSION_DIR, { recursive: true });
3529
+ mkdirSync6(PLUGIN_SETTINGS_DIR, { recursive: true });
3611
3530
  writeFileSync6(PLUGIN_PATH, CHANNEL_PLUGIN_SOURCE, "utf-8");
3612
3531
  chmodSync(PLUGIN_PATH, 493);
3613
3532
  writeFileSync6(PLUGIN_PKG_PATH, PLUGIN_PACKAGE_JSON, "utf-8");
@@ -3639,7 +3558,7 @@ function runBunInstall() {
3639
3558
  }
3640
3559
  }
3641
3560
  function safelyMutateClaudeJson(mutator) {
3642
- if (!existsSync9(CLAUDE_JSON_PATH)) {
3561
+ if (!existsSync8(CLAUDE_JSON_PATH)) {
3643
3562
  return;
3644
3563
  }
3645
3564
  const originalText = readFileSync6(CLAUDE_JSON_PATH, "utf-8");
@@ -3767,15 +3686,15 @@ var init_install = __esm({
3767
3686
  "cli/local-cc/install.ts"() {
3768
3687
  "use strict";
3769
3688
  init_channelSource();
3770
- CLAUDE_JSON_BACKUP_PATH = join8(homedir7(), ".claude.json.synkro-bak");
3771
- SESSION_DIR = join8(homedir7(), ".synkro", "cc_sessions");
3772
- PLUGIN_PATH = join8(SESSION_DIR, "synkro-channel.ts");
3773
- PLUGIN_PKG_PATH = join8(SESSION_DIR, "package.json");
3774
- PLUGIN_SETTINGS_DIR = join8(SESSION_DIR, ".claude");
3775
- PLUGIN_SETTINGS_PATH = join8(PLUGIN_SETTINGS_DIR, "settings.json");
3776
- PROJECT_MCP_PATH = join8(SESSION_DIR, ".mcp.json");
3777
- CLAUDE_JSON_PATH = join8(homedir7(), ".claude.json");
3778
- RUN_SCRIPT_PATH = join8(SESSION_DIR, "run-claude.sh");
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");
3779
3698
  TMUX_SESSION_NAME = "synkro-local-cc";
3780
3699
  RUN_SCRIPT_SOURCE = `#!/usr/bin/env bash
3781
3700
  # Auto-generated by \`synkro install\`. Do not edit.
@@ -3827,8 +3746,8 @@ done
3827
3746
 
3828
3747
  // cli/local-cc/pueue.ts
3829
3748
  import { execFileSync, spawnSync as spawnSync2 } from "child_process";
3830
- import { homedir as homedir8 } from "os";
3831
- import { join as join9 } from "path";
3749
+ import { homedir as homedir7 } from "os";
3750
+ import { join as join8 } from "path";
3832
3751
  import { connect } from "net";
3833
3752
  function pueueAvailable() {
3834
3753
  const r = spawnSync2("pueue", ["--version"], { encoding: "utf-8" });
@@ -3883,7 +3802,7 @@ function startTask(opts = {}) {
3883
3802
  if (existing) {
3884
3803
  spawnSync2("pueue", ["remove", String(existing.id)], { encoding: "utf-8" });
3885
3804
  }
3886
- const runScript = join9(cwd, "run-claude.sh");
3805
+ const runScript = join8(cwd, "run-claude.sh");
3887
3806
  const args2 = [
3888
3807
  "add",
3889
3808
  "--label",
@@ -3975,7 +3894,7 @@ var init_pueue = __esm({
3975
3894
  "use strict";
3976
3895
  TASK_LABEL = "synkro-local-cc";
3977
3896
  TMUX_SESSION = "synkro-local-cc";
3978
- SESSION_DIR2 = join9(homedir8(), ".synkro", "cc_sessions");
3897
+ SESSION_DIR2 = join8(homedir7(), ".synkro", "cc_sessions");
3979
3898
  PueueError = class extends Error {
3980
3899
  constructor(message, cause) {
3981
3900
  super(message);
@@ -3993,9 +3912,9 @@ __export(install_exports, {
3993
3912
  installCommand: () => installCommand,
3994
3913
  parseArgs: () => parseArgs
3995
3914
  });
3996
- import { existsSync as existsSync10, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, chmodSync as chmodSync2, readFileSync as readFileSync7, readdirSync } from "fs";
3997
- import { homedir as homedir9 } from "os";
3998
- import { join as join10 } from "path";
3915
+ import { existsSync as existsSync9, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7, chmodSync as chmodSync2, readFileSync as readFileSync7, readdirSync } from "fs";
3916
+ import { homedir as homedir8 } from "os";
3917
+ import { join as join9 } from "path";
3999
3918
  import { execSync as execSync5 } from "child_process";
4000
3919
  import { createInterface as createInterface3 } from "readline";
4001
3920
  function sanitizeGatewayCandidate(raw) {
@@ -4032,19 +3951,19 @@ async function promptTranscriptConsent() {
4032
3951
  });
4033
3952
  }
4034
3953
  function ensureSynkroDir() {
4035
- mkdirSync8(SYNKRO_DIR3, { recursive: true });
4036
- mkdirSync8(HOOKS_DIR, { recursive: true });
4037
- mkdirSync8(BIN_DIR, { recursive: true });
4038
- mkdirSync8(OFFSETS_DIR, { recursive: true });
3954
+ mkdirSync7(SYNKRO_DIR2, { recursive: true });
3955
+ mkdirSync7(HOOKS_DIR, { recursive: true });
3956
+ mkdirSync7(BIN_DIR, { recursive: true });
3957
+ mkdirSync7(OFFSETS_DIR, { recursive: true });
4039
3958
  }
4040
3959
  function writeHookScripts() {
4041
- const bashScriptPath = join10(HOOKS_DIR, "cc-bash-judge.sh");
4042
- const bashFollowupScriptPath = join10(HOOKS_DIR, "cc-bash-followup.sh");
4043
- const editCaptureScriptPath = join10(HOOKS_DIR, "cc-edit-capture.sh");
4044
- const editPrecheckScriptPath = join10(HOOKS_DIR, "cc-edit-precheck.sh");
4045
- const stopSummaryScriptPath = join10(HOOKS_DIR, "cc-stop-summary.sh");
4046
- const sessionStartScriptPath = join10(HOOKS_DIR, "cc-session-start.sh");
4047
- const transcriptSyncScriptPath = join10(HOOKS_DIR, "cc-transcript-sync.sh");
3960
+ const bashScriptPath = join9(HOOKS_DIR, "cc-bash-judge.sh");
3961
+ const bashFollowupScriptPath = join9(HOOKS_DIR, "cc-bash-followup.sh");
3962
+ const editCaptureScriptPath = join9(HOOKS_DIR, "cc-edit-capture.sh");
3963
+ const editPrecheckScriptPath = join9(HOOKS_DIR, "cc-edit-precheck.sh");
3964
+ const stopSummaryScriptPath = join9(HOOKS_DIR, "cc-stop-summary.sh");
3965
+ const sessionStartScriptPath = join9(HOOKS_DIR, "cc-session-start.sh");
3966
+ const transcriptSyncScriptPath = join9(HOOKS_DIR, "cc-transcript-sync.sh");
4048
3967
  writeFileSync7(bashScriptPath, CC_BASH_JUDGE_SCRIPT, "utf-8");
4049
3968
  writeFileSync7(bashFollowupScriptPath, CC_BASH_FOLLOWUP_SCRIPT, "utf-8");
4050
3969
  writeFileSync7(editCaptureScriptPath, CC_EDIT_CAPTURE_SCRIPT, "utf-8");
@@ -4078,11 +3997,11 @@ function shellQuoteSingle(value) {
4078
3997
  }
4079
3998
  function resolveSynkroBundle() {
4080
3999
  const scriptPath = process.argv[1];
4081
- if (scriptPath && existsSync10(scriptPath)) return scriptPath;
4000
+ if (scriptPath && existsSync9(scriptPath)) return scriptPath;
4082
4001
  return null;
4083
4002
  }
4084
4003
  function writeConfigEnv(opts) {
4085
- const credsPath = join10(SYNKRO_DIR3, "credentials.json");
4004
+ const credsPath = join9(SYNKRO_DIR2, "credentials.json");
4086
4005
  const safeGateway = sanitizeConfigValue(opts.gatewayUrl);
4087
4006
  const safeUserId = sanitizeConfigValue(opts.userId);
4088
4007
  const safeOrgId = sanitizeConfigValue(opts.orgId);
@@ -4098,7 +4017,7 @@ function writeConfigEnv(opts) {
4098
4017
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
4099
4018
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
4100
4019
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
4101
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.0")}`
4020
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.1")}`
4102
4021
  ];
4103
4022
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
4104
4023
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -4107,6 +4026,7 @@ function writeConfigEnv(opts) {
4107
4026
  if (opts.transcriptConsent !== void 0) {
4108
4027
  lines.push(`SYNKRO_TRANSCRIPT_CONSENT=${shellQuoteSingle(opts.transcriptConsent ? "yes" : "no")}`);
4109
4028
  }
4029
+ lines.push(`SYNKRO_LOCAL_INFERENCE=${shellQuoteSingle(opts.localInference ? "yes" : "no")}`);
4110
4030
  lines.push("");
4111
4031
  writeFileSync7(CONFIG_PATH2, lines.join("\n"), "utf-8");
4112
4032
  chmodSync2(CONFIG_PATH2, 384);
@@ -4129,16 +4049,16 @@ function collectLocalMetadata() {
4129
4049
  meta.cc_version = execSync5("claude --version", { encoding: "utf-8", timeout: 5e3 }).trim().split("\n")[0];
4130
4050
  } catch {
4131
4051
  }
4132
- const claudeDir = join10(homedir9(), ".claude");
4052
+ const claudeDir = join9(homedir8(), ".claude");
4133
4053
  try {
4134
- const settings = JSON.parse(readFileSync7(join10(claudeDir, "settings.json"), "utf-8"));
4054
+ const settings = JSON.parse(readFileSync7(join9(claudeDir, "settings.json"), "utf-8"));
4135
4055
  const plugins = Object.keys(settings.enabledPlugins ?? {}).filter((k) => settings.enabledPlugins[k]);
4136
4056
  if (plugins.length) meta.enabled_plugins = plugins;
4137
4057
  if (settings.permissions?.defaultMode) meta.permissions_mode = settings.permissions.defaultMode;
4138
4058
  } catch {
4139
4059
  }
4140
4060
  try {
4141
- const mcpCache = JSON.parse(readFileSync7(join10(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
4061
+ const mcpCache = JSON.parse(readFileSync7(join9(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
4142
4062
  const mcpNames = Object.keys(mcpCache);
4143
4063
  if (mcpNames.length) meta.mcp_servers = mcpNames;
4144
4064
  } catch {
@@ -4150,10 +4070,10 @@ function collectLocalMetadata() {
4150
4070
  } catch {
4151
4071
  }
4152
4072
  try {
4153
- const sessionsDir = join10(claudeDir, "sessions");
4073
+ const sessionsDir = join9(claudeDir, "sessions");
4154
4074
  const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).slice(-5);
4155
4075
  for (const f of files) {
4156
- const s = JSON.parse(readFileSync7(join10(sessionsDir, f), "utf-8"));
4076
+ const s = JSON.parse(readFileSync7(join9(sessionsDir, f), "utf-8"));
4157
4077
  if (s.version) {
4158
4078
  meta.cc_version = meta.cc_version || s.version;
4159
4079
  break;
@@ -4168,7 +4088,7 @@ async function fetchUserProfile(gatewayUrl, token) {
4168
4088
  const resp = await fetch(`${gatewayUrl}/api/v1/cli/me`, {
4169
4089
  headers: { "Authorization": `Bearer ${token}` }
4170
4090
  });
4171
- if (!resp.ok) return { tier: "pro", inference: "fast" };
4091
+ if (!resp.ok) return { tier: "pro", inference: "fast", localInference: false };
4172
4092
  const data = await resp.json();
4173
4093
  const meta = collectLocalMetadata();
4174
4094
  fetch(`${gatewayUrl}/api/v1/cli/me`, {
@@ -4179,10 +4099,11 @@ async function fetchUserProfile(gatewayUrl, token) {
4179
4099
  });
4180
4100
  return {
4181
4101
  tier: data.plan_tier ?? "pro",
4182
- inference: data.fast_inference ? "fast" : "standard"
4102
+ inference: data.fast_inference ? "fast" : "standard",
4103
+ localInference: !!data.local_inference
4183
4104
  };
4184
4105
  } catch {
4185
- return { tier: "pro", inference: "fast" };
4106
+ return { tier: "pro", inference: "fast", localInference: false };
4186
4107
  }
4187
4108
  }
4188
4109
  function assertGatewayAllowed(gatewayUrl) {
@@ -4208,17 +4129,17 @@ function assertGatewayAllowed(gatewayUrl) {
4208
4129
  }
4209
4130
  function isAlreadyInstalled() {
4210
4131
  const requiredScripts = [
4211
- join10(HOOKS_DIR, "cc-bash-judge.sh"),
4212
- join10(HOOKS_DIR, "cc-bash-followup.sh"),
4213
- join10(HOOKS_DIR, "cc-edit-precheck.sh"),
4214
- join10(HOOKS_DIR, "cc-edit-capture.sh"),
4215
- join10(HOOKS_DIR, "cc-stop-summary.sh"),
4216
- join10(HOOKS_DIR, "cc-session-start.sh")
4132
+ join9(HOOKS_DIR, "cc-bash-judge.sh"),
4133
+ join9(HOOKS_DIR, "cc-bash-followup.sh"),
4134
+ join9(HOOKS_DIR, "cc-edit-precheck.sh"),
4135
+ join9(HOOKS_DIR, "cc-edit-capture.sh"),
4136
+ join9(HOOKS_DIR, "cc-stop-summary.sh"),
4137
+ join9(HOOKS_DIR, "cc-session-start.sh")
4217
4138
  ];
4218
- if (!requiredScripts.every((p) => existsSync10(p))) return false;
4219
- if (!existsSync10(CONFIG_PATH2)) return false;
4220
- const settingsPath = join10(homedir9(), ".claude", "settings.json");
4221
- if (!existsSync10(settingsPath)) return false;
4139
+ if (!requiredScripts.every((p) => existsSync9(p))) return false;
4140
+ if (!existsSync9(CONFIG_PATH2)) return false;
4141
+ const settingsPath = join9(homedir8(), ".claude", "settings.json");
4142
+ if (!existsSync9(settingsPath)) return false;
4222
4143
  try {
4223
4144
  const settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
4224
4145
  const hooks = settings?.hooks;
@@ -4328,7 +4249,7 @@ async function installCommand(opts = {}) {
4328
4249
  console.log(` ${scripts.transcriptSyncScript}
4329
4250
  `);
4330
4251
  for (const mode of ["edit", "bash"]) {
4331
- const pidFile = join10(SYNKRO_DIR3, "daemon", mode, "daemon.pid");
4252
+ const pidFile = join9(SYNKRO_DIR2, "daemon", mode, "daemon.pid");
4332
4253
  try {
4333
4254
  const pid = parseInt(readFileSync7(pidFile, "utf-8").trim(), 10);
4334
4255
  if (pid > 0) {
@@ -4338,20 +4259,6 @@ async function installCommand(opts = {}) {
4338
4259
  } catch {
4339
4260
  }
4340
4261
  }
4341
- if (isLocalCCEnabled()) {
4342
- try {
4343
- assertClaudeInstalled();
4344
- assertPueueInstalled();
4345
- const r = installLocalCC();
4346
- console.log(`Installed local-CC channel plugin at ${r.pluginPath}`);
4347
- const t = ensureRunning();
4348
- console.log(`Local-CC pueue task: id=${t.id} status=${t.status}
4349
- `);
4350
- } catch (err) {
4351
- console.warn(` \u26A0 Local-CC setup skipped: ${err.message}`);
4352
- console.warn(" Run `synkro local-cc enable` after fixing the issue.\n");
4353
- }
4354
- }
4355
4262
  let transcriptConsent = true;
4356
4263
  if (process.stdin.isTTY) {
4357
4264
  transcriptConsent = await promptTranscriptConsent();
@@ -4418,9 +4325,10 @@ async function installCommand(opts = {}) {
4418
4325
  }
4419
4326
  const profile = await fetchUserProfile(gatewayUrl, token);
4420
4327
  const synkroBundle = resolveSynkroBundle();
4421
- writeConfigEnv({ gatewayUrl, userId, orgId, email, tier: profile.tier, inference: profile.inference, synkroBin: synkroBundle, transcriptConsent });
4328
+ writeConfigEnv({ gatewayUrl, userId, orgId, email, tier: profile.tier, inference: profile.inference, synkroBin: synkroBundle, transcriptConsent, localInference: profile.localInference });
4422
4329
  console.log(`Wrote config to ${CONFIG_PATH2}`);
4423
4330
  console.log(` inference: ${profile.inference} (server-side grading)`);
4331
+ if (profile.localInference) console.log(` local inference: enabled (gradingProvider=claude-code)`);
4424
4332
  if (synkroBundle) console.log(` SYNKRO_CLI_BIN=${synkroBundle}`);
4425
4333
  else console.warn(" \u26A0 Could not resolve synkro bundle path; hooks will fall back to PATH lookup of `synkro`.");
4426
4334
  try {
@@ -4430,6 +4338,20 @@ async function installCommand(opts = {}) {
4430
4338
  console.warn(` \u26A0 Could not cache judge prompts: ${err.message}`);
4431
4339
  }
4432
4340
  console.log();
4341
+ if (profile.localInference) {
4342
+ try {
4343
+ assertClaudeInstalled();
4344
+ assertPueueInstalled();
4345
+ const r = installLocalCC();
4346
+ console.log(`Installed local-CC channel plugin at ${r.pluginPath}`);
4347
+ const t = ensureRunning();
4348
+ console.log(`Local-CC pueue task: id=${t.id} status=${t.status}
4349
+ `);
4350
+ } catch (err) {
4351
+ console.warn(` \u26A0 Local-CC setup skipped: ${err.message}`);
4352
+ console.warn(" Set gradingProvider in your inference settings and re-run install.\n");
4353
+ }
4354
+ }
4433
4355
  if (transcriptConsent) {
4434
4356
  try {
4435
4357
  const repo = detectGitRepo2();
@@ -4476,15 +4398,15 @@ function detectGitRepo2() {
4476
4398
  function getClaudeProjectsFolder() {
4477
4399
  const cwd = process.cwd();
4478
4400
  const sanitized = "-" + cwd.replace(/\//g, "-");
4479
- const projectsDir = join10(homedir9(), ".claude", "projects", sanitized);
4480
- return existsSync10(projectsDir) ? projectsDir : null;
4401
+ const projectsDir = join9(homedir8(), ".claude", "projects", sanitized);
4402
+ return existsSync9(projectsDir) ? projectsDir : null;
4481
4403
  }
4482
4404
  function extractSessionInsights(projectsDir) {
4483
4405
  const insights = [];
4484
4406
  const files = readdirSync(projectsDir).filter((f) => f.endsWith(".jsonl"));
4485
4407
  for (const file of files) {
4486
4408
  const sessionId = file.replace(".jsonl", "");
4487
- const filePath = join10(projectsDir, file);
4409
+ const filePath = join9(projectsDir, file);
4488
4410
  try {
4489
4411
  const content = readFileSync7(filePath, "utf-8");
4490
4412
  const lines = content.split("\n").filter(Boolean);
@@ -4613,7 +4535,7 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
4613
4535
  const sessions = [];
4614
4536
  for (const file of batch) {
4615
4537
  const sessionId = file.replace(".jsonl", "");
4616
- const filePath = join10(projectsDir, file);
4538
+ const filePath = join9(projectsDir, file);
4617
4539
  try {
4618
4540
  const allMessages = parseTranscriptFile(filePath);
4619
4541
  const messages = allMessages.length > maxMessagesPerSession ? allMessages.slice(-maxMessagesPerSession) : allMessages;
@@ -4642,18 +4564,18 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
4642
4564
  }
4643
4565
  for (const file of batch) {
4644
4566
  const sessionId = file.replace(".jsonl", "");
4645
- const filePath = join10(projectsDir, file);
4567
+ const filePath = join9(projectsDir, file);
4646
4568
  try {
4647
4569
  const content = readFileSync7(filePath, "utf-8");
4648
4570
  const lineCount = content.split("\n").filter(Boolean).length;
4649
- writeFileSync7(join10(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
4571
+ writeFileSync7(join9(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
4650
4572
  } catch {
4651
4573
  }
4652
4574
  }
4653
4575
  }
4654
4576
  return { sessions: totalSessions, messages: totalMessages };
4655
4577
  }
4656
- var SYNKRO_DIR3, HOOKS_DIR, BIN_DIR, CONFIG_PATH2, OFFSETS_DIR;
4578
+ var SYNKRO_DIR2, HOOKS_DIR, BIN_DIR, CONFIG_PATH2, OFFSETS_DIR;
4657
4579
  var init_install2 = __esm({
4658
4580
  "cli/commands/install.ts"() {
4659
4581
  "use strict";
@@ -4666,14 +4588,13 @@ var init_install2 = __esm({
4666
4588
  init_projects();
4667
4589
  init_setupGithub();
4668
4590
  init_promptFetcher();
4669
- init_settings();
4670
4591
  init_install();
4671
4592
  init_pueue();
4672
- SYNKRO_DIR3 = join10(homedir9(), ".synkro");
4673
- HOOKS_DIR = join10(SYNKRO_DIR3, "hooks");
4674
- BIN_DIR = join10(SYNKRO_DIR3, "bin");
4675
- CONFIG_PATH2 = join10(SYNKRO_DIR3, "config.env");
4676
- OFFSETS_DIR = join10(SYNKRO_DIR3, ".transcript-offsets");
4593
+ SYNKRO_DIR2 = join9(homedir8(), ".synkro");
4594
+ HOOKS_DIR = join9(SYNKRO_DIR2, "hooks");
4595
+ BIN_DIR = join9(SYNKRO_DIR2, "bin");
4596
+ CONFIG_PATH2 = join9(SYNKRO_DIR2, "config.env");
4597
+ OFFSETS_DIR = join9(SYNKRO_DIR2, ".transcript-offsets");
4677
4598
  }
4678
4599
  });
4679
4600
 
@@ -4749,11 +4670,11 @@ var status_exports = {};
4749
4670
  __export(status_exports, {
4750
4671
  statusCommand: () => statusCommand
4751
4672
  });
4752
- import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
4753
- import { homedir as homedir10 } from "os";
4754
- import { join as join11 } from "path";
4673
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
4674
+ import { homedir as homedir9 } from "os";
4675
+ import { join as join10 } from "path";
4755
4676
  function readConfigEnv() {
4756
- if (!existsSync11(CONFIG_PATH3)) return {};
4677
+ if (!existsSync10(CONFIG_PATH3)) return {};
4757
4678
  const out = {};
4758
4679
  const raw = readFileSync8(CONFIG_PATH3, "utf-8");
4759
4680
  for (const line of raw.split("\n")) {
@@ -4828,19 +4749,19 @@ async function statusCommand() {
4828
4749
  }
4829
4750
  }
4830
4751
  console.log();
4831
- const bashScript = join11(SYNKRO_DIR4, "hooks", "cc-bash-judge.sh");
4832
- const bashFollowupScript = join11(SYNKRO_DIR4, "hooks", "cc-bash-followup.sh");
4833
- const editPrecheckScript = join11(SYNKRO_DIR4, "hooks", "cc-edit-precheck.sh");
4834
- const editCaptureScript = join11(SYNKRO_DIR4, "hooks", "cc-edit-capture.sh");
4835
- const stopSummaryScript = join11(SYNKRO_DIR4, "hooks", "cc-stop-summary.sh");
4836
- const sessionStartScript = join11(SYNKRO_DIR4, "hooks", "cc-session-start.sh");
4752
+ const bashScript = join10(SYNKRO_DIR3, "hooks", "cc-bash-judge.sh");
4753
+ const bashFollowupScript = join10(SYNKRO_DIR3, "hooks", "cc-bash-followup.sh");
4754
+ const editPrecheckScript = join10(SYNKRO_DIR3, "hooks", "cc-edit-precheck.sh");
4755
+ const editCaptureScript = join10(SYNKRO_DIR3, "hooks", "cc-edit-capture.sh");
4756
+ const stopSummaryScript = join10(SYNKRO_DIR3, "hooks", "cc-stop-summary.sh");
4757
+ const sessionStartScript = join10(SYNKRO_DIR3, "hooks", "cc-session-start.sh");
4837
4758
  console.log("Hook scripts:");
4838
- console.log(` ${existsSync11(bashScript) ? "\u2713" : "\u2717"} ${bashScript}`);
4839
- console.log(` ${existsSync11(bashFollowupScript) ? "\u2713" : "\u2717"} ${bashFollowupScript}`);
4840
- console.log(` ${existsSync11(editPrecheckScript) ? "\u2713" : "\u2717"} ${editPrecheckScript}`);
4841
- console.log(` ${existsSync11(editCaptureScript) ? "\u2713" : "\u2717"} ${editCaptureScript}`);
4842
- console.log(` ${existsSync11(stopSummaryScript) ? "\u2713" : "\u2717"} ${stopSummaryScript}`);
4843
- console.log(` ${existsSync11(sessionStartScript) ? "\u2713" : "\u2717"} ${sessionStartScript}`);
4759
+ console.log(` ${existsSync10(bashScript) ? "\u2713" : "\u2717"} ${bashScript}`);
4760
+ console.log(` ${existsSync10(bashFollowupScript) ? "\u2713" : "\u2717"} ${bashFollowupScript}`);
4761
+ console.log(` ${existsSync10(editPrecheckScript) ? "\u2713" : "\u2717"} ${editPrecheckScript}`);
4762
+ console.log(` ${existsSync10(editCaptureScript) ? "\u2713" : "\u2717"} ${editCaptureScript}`);
4763
+ console.log(` ${existsSync10(stopSummaryScript) ? "\u2713" : "\u2717"} ${stopSummaryScript}`);
4764
+ console.log(` ${existsSync10(sessionStartScript) ? "\u2713" : "\u2717"} ${sessionStartScript}`);
4844
4765
  console.log();
4845
4766
  const mcp = inspectMcpConfig();
4846
4767
  console.log("Guardrails MCP server (Claude Code):");
@@ -4852,7 +4773,7 @@ async function statusCommand() {
4852
4773
  console.log(` expected at ${mcp.configPath} \u2192 mcpServers.synkro-guardrails`);
4853
4774
  }
4854
4775
  }
4855
- var SYNKRO_DIR4, CONFIG_PATH3;
4776
+ var SYNKRO_DIR3, CONFIG_PATH3;
4856
4777
  var init_status = __esm({
4857
4778
  "cli/commands/status.ts"() {
4858
4779
  "use strict";
@@ -4860,8 +4781,8 @@ var init_status = __esm({
4860
4781
  init_agentDetect();
4861
4782
  init_ccHookConfig();
4862
4783
  init_mcpConfig();
4863
- SYNKRO_DIR4 = join11(homedir10(), ".synkro");
4864
- CONFIG_PATH3 = join11(SYNKRO_DIR4, "config.env");
4784
+ SYNKRO_DIR3 = join10(homedir9(), ".synkro");
4785
+ CONFIG_PATH3 = join10(SYNKRO_DIR3, "config.env");
4865
4786
  }
4866
4787
  });
4867
4788
 
@@ -4950,11 +4871,11 @@ var config_exports = {};
4950
4871
  __export(config_exports, {
4951
4872
  configCommand: () => configCommand
4952
4873
  });
4953
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync12 } from "fs";
4954
- import { join as join12 } from "path";
4955
- import { homedir as homedir11 } from "os";
4874
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync11 } from "fs";
4875
+ import { join as join11 } from "path";
4876
+ import { homedir as homedir10 } from "os";
4956
4877
  function readConfigEnv2() {
4957
- if (!existsSync12(CONFIG_PATH4)) return {};
4878
+ if (!existsSync11(CONFIG_PATH4)) return {};
4958
4879
  const out = {};
4959
4880
  for (const line of readFileSync9(CONFIG_PATH4, "utf-8").split("\n")) {
4960
4881
  const t = line.trim();
@@ -4965,7 +4886,7 @@ function readConfigEnv2() {
4965
4886
  return out;
4966
4887
  }
4967
4888
  function updateConfigValue(key, value) {
4968
- if (!existsSync12(CONFIG_PATH4)) {
4889
+ if (!existsSync11(CONFIG_PATH4)) {
4969
4890
  console.error("No config found. Run `synkro install` first.");
4970
4891
  process.exit(1);
4971
4892
  }
@@ -5031,13 +4952,13 @@ To change: synkro config --inference fast|standard`);
5031
4952
  updateConfigValue("SYNKRO_INFERENCE", inferenceValue);
5032
4953
  console.log(`\u2713 Inference set to '${inferenceValue}'.`);
5033
4954
  }
5034
- var SYNKRO_DIR5, CONFIG_PATH4;
4955
+ var SYNKRO_DIR4, CONFIG_PATH4;
5035
4956
  var init_config = __esm({
5036
4957
  "cli/commands/config.ts"() {
5037
4958
  "use strict";
5038
4959
  init_stub();
5039
- SYNKRO_DIR5 = join12(homedir11(), ".synkro");
5040
- CONFIG_PATH4 = join12(SYNKRO_DIR5, "config.env");
4960
+ SYNKRO_DIR4 = join11(homedir10(), ".synkro");
4961
+ CONFIG_PATH4 = join11(SYNKRO_DIR4, "config.env");
5041
4962
  }
5042
4963
  });
5043
4964
 
@@ -5047,8 +4968,8 @@ __export(scanPr_exports, {
5047
4968
  scanPrCommand: () => scanPrCommand
5048
4969
  });
5049
4970
  import { execSync as execSync6, spawn } from "child_process";
5050
- import { readFileSync as readFileSync10, existsSync as existsSync13 } from "fs";
5051
- import { join as join13 } from "path";
4971
+ import { readFileSync as readFileSync10, existsSync as existsSync12 } from "fs";
4972
+ import { join as join12 } from "path";
5052
4973
  function parseMatchSpec(condition) {
5053
4974
  if (!condition.startsWith("match_spec:")) return null;
5054
4975
  try {
@@ -5527,8 +5448,8 @@ function shouldFail(findings, threshold) {
5527
5448
  return findings.some((f) => order.indexOf(f.severity) >= thresholdIdx);
5528
5449
  }
5529
5450
  function readRepoDeps() {
5530
- const pkgPath = join13(process.cwd(), "package.json");
5531
- if (!existsSync13(pkgPath)) return {};
5451
+ const pkgPath = join12(process.cwd(), "package.json");
5452
+ if (!existsSync12(pkgPath)) return {};
5532
5453
  try {
5533
5454
  const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
5534
5455
  return { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
@@ -5792,9 +5713,9 @@ var disconnect_exports = {};
5792
5713
  __export(disconnect_exports, {
5793
5714
  disconnectCommand: () => disconnectCommand
5794
5715
  });
5795
- import { existsSync as existsSync14, rmSync } from "fs";
5796
- import { homedir as homedir12 } from "os";
5797
- import { join as join14 } from "path";
5716
+ import { existsSync as existsSync13, rmSync } from "fs";
5717
+ import { homedir as homedir11 } from "os";
5718
+ import { join as join13 } from "path";
5798
5719
  function tearDownLocalCC() {
5799
5720
  let hadTask = false;
5800
5721
  try {
@@ -5824,18 +5745,18 @@ function disconnectCommand(args2 = []) {
5824
5745
  console.log(`${mcpRemoved ? "\u2713" : "\xB7"} MCP guardrails server: ${mcpRemoved ? "removed entry from ~/.claude.json" : "no Synkro MCP entry found"}`);
5825
5746
  }
5826
5747
  if (purge) {
5827
- if (existsSync14(SYNKRO_DIR6)) {
5828
- rmSync(SYNKRO_DIR6, { recursive: true, force: true });
5829
- console.log(`\u2713 Removed ${SYNKRO_DIR6}`);
5748
+ if (existsSync13(SYNKRO_DIR5)) {
5749
+ rmSync(SYNKRO_DIR5, { recursive: true, force: true });
5750
+ console.log(`\u2713 Removed ${SYNKRO_DIR5}`);
5830
5751
  } else {
5831
- console.log(`\xB7 ${SYNKRO_DIR6} already gone, nothing to remove`);
5752
+ console.log(`\xB7 ${SYNKRO_DIR5} already gone, nothing to remove`);
5832
5753
  }
5833
- } else if (existsSync14(SYNKRO_DIR6)) {
5834
- console.log(`Config preserved at ${SYNKRO_DIR6}. Run with --purge to remove.`);
5754
+ } else if (existsSync13(SYNKRO_DIR5)) {
5755
+ console.log(`Config preserved at ${SYNKRO_DIR5}. Run with --purge to remove.`);
5835
5756
  }
5836
5757
  console.log("\nSynkro disconnected.");
5837
5758
  }
5838
- var SYNKRO_DIR6;
5759
+ var SYNKRO_DIR5;
5839
5760
  var init_disconnect = __esm({
5840
5761
  "cli/commands/disconnect.ts"() {
5841
5762
  "use strict";
@@ -5844,7 +5765,7 @@ var init_disconnect = __esm({
5844
5765
  init_mcpConfig();
5845
5766
  init_pueue();
5846
5767
  init_install();
5847
- SYNKRO_DIR6 = join14(homedir12(), ".synkro");
5768
+ SYNKRO_DIR5 = join13(homedir11(), ".synkro");
5848
5769
  }
5849
5770
  });
5850
5771
 
@@ -5886,9 +5807,9 @@ var init_reinstall = __esm({
5886
5807
  });
5887
5808
 
5888
5809
  // cli/local-cc/turnLog.ts
5889
- import { appendFileSync, existsSync as existsSync15, mkdirSync as mkdirSync9, openSync as openSync2, readFileSync as readFileSync11, readSync, closeSync as closeSync2, statSync, watchFile, unwatchFile } from "fs";
5890
- import { dirname as dirname5, join as join15 } from "path";
5891
- import { homedir as homedir13 } from "os";
5810
+ import { appendFileSync, existsSync as existsSync14, mkdirSync as mkdirSync8, openSync as openSync2, readFileSync as readFileSync11, readSync, closeSync as closeSync2, statSync, watchFile, unwatchFile } from "fs";
5811
+ import { dirname as dirname5, join as join14 } from "path";
5812
+ import { homedir as homedir12 } from "os";
5892
5813
  function truncate(s, max = PREVIEW_MAX) {
5893
5814
  if (s.length <= max) return s;
5894
5815
  return s.slice(0, max) + "\u2026 [+" + (s.length - max) + " chars]";
@@ -5908,7 +5829,7 @@ function extractSeverity(result) {
5908
5829
  }
5909
5830
  function appendTurn(args2) {
5910
5831
  try {
5911
- mkdirSync9(dirname5(TURN_LOG_PATH), { recursive: true });
5832
+ mkdirSync8(dirname5(TURN_LOG_PATH), { recursive: true });
5912
5833
  const entry = {
5913
5834
  ts: new Date(args2.startedAt).toISOString(),
5914
5835
  role: args2.role,
@@ -5924,7 +5845,7 @@ function appendTurn(args2) {
5924
5845
  }
5925
5846
  }
5926
5847
  function readRecentTurns(n = 20) {
5927
- if (!existsSync15(TURN_LOG_PATH)) return [];
5848
+ if (!existsSync14(TURN_LOG_PATH)) return [];
5928
5849
  try {
5929
5850
  const size = statSync(TURN_LOG_PATH).size;
5930
5851
  if (size === 0) return [];
@@ -5944,8 +5865,8 @@ function readRecentTurns(n = 20) {
5944
5865
  }
5945
5866
  function followTurns(onEntry) {
5946
5867
  try {
5947
- mkdirSync9(dirname5(TURN_LOG_PATH), { recursive: true });
5948
- if (!existsSync15(TURN_LOG_PATH)) {
5868
+ mkdirSync8(dirname5(TURN_LOG_PATH), { recursive: true });
5869
+ if (!existsSync14(TURN_LOG_PATH)) {
5949
5870
  appendFileSync(TURN_LOG_PATH, "", "utf-8");
5950
5871
  }
5951
5872
  } catch {
@@ -6007,13 +5928,35 @@ var TURN_LOG_PATH, PREVIEW_MAX;
6007
5928
  var init_turnLog = __esm({
6008
5929
  "cli/local-cc/turnLog.ts"() {
6009
5930
  "use strict";
6010
- TURN_LOG_PATH = join15(homedir13(), ".synkro", "cc_sessions", "turns.log");
5931
+ TURN_LOG_PATH = join14(homedir12(), ".synkro", "cc_sessions", "turns.log");
6011
5932
  PREVIEW_MAX = 400;
6012
5933
  }
6013
5934
  });
6014
5935
 
5936
+ // cli/local-cc/settings.ts
5937
+ import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
5938
+ import { homedir as homedir13 } from "os";
5939
+ import { join as join15 } from "path";
5940
+ function isLocalCCEnabled() {
5941
+ if (!existsSync15(CONFIG_PATH5)) return false;
5942
+ try {
5943
+ const content = readFileSync12(CONFIG_PATH5, "utf-8");
5944
+ const match = content.match(/^SYNKRO_LOCAL_INFERENCE='([^']*)'/m);
5945
+ return match?.[1] === "yes";
5946
+ } catch {
5947
+ return false;
5948
+ }
5949
+ }
5950
+ var CONFIG_PATH5;
5951
+ var init_settings = __esm({
5952
+ "cli/local-cc/settings.ts"() {
5953
+ "use strict";
5954
+ CONFIG_PATH5 = join15(homedir13(), ".synkro", "config.env");
5955
+ }
5956
+ });
5957
+
6015
5958
  // cli/local-cc/prompts.ts
6016
- import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
5959
+ import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
6017
5960
  import { homedir as homedir14 } from "os";
6018
5961
  import { join as join16 } from "path";
6019
5962
  function loadCachedPrompts() {
@@ -6022,7 +5965,7 @@ function loadCachedPrompts() {
6022
5965
  throw new Error("Prompts cache not found. Run `synkro install` or `synkro update` first.");
6023
5966
  }
6024
5967
  try {
6025
- _cached = JSON.parse(readFileSync12(CACHE_PATH2, "utf-8"));
5968
+ _cached = JSON.parse(readFileSync13(CACHE_PATH2, "utf-8"));
6026
5969
  return _cached;
6027
5970
  } catch {
6028
5971
  throw new Error("Prompts cache is corrupted. Run `synkro update` to refresh.");
@@ -6156,8 +6099,8 @@ __export(localCc_exports, {
6156
6099
  import { spawnSync as spawnSync3 } from "child_process";
6157
6100
  import { homedir as homedir15 } from "os";
6158
6101
  import { join as join17 } from "path";
6102
+ import { existsSync as existsSync17, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "fs";
6159
6103
  function printHelp() {
6160
- const dbPath = join17(homedir15(), ".synkro", "sessions.db");
6161
6104
  console.log(`synkro local-cc \u2014 manage the local Claude Code inference session
6162
6105
 
6163
6106
  OVERVIEW
@@ -6199,11 +6142,10 @@ SUBCOMMANDS
6199
6142
  help Show this message
6200
6143
 
6201
6144
  CONFIGURATION
6202
- Provider toggle (single global switch, default 'inngest'):
6203
- Stored in ${dbPath} (settings table, key='inference_provider').
6145
+ Provider toggle:
6146
+ Stored server-side in your inference settings (gradingProvider).
6204
6147
  Toggle via: synkro local-cc enable / disable
6205
- Or directly via SQL:
6206
- INSERT OR REPLACE INTO settings (key, value) VALUES ('inference_provider', 'local-cc');
6148
+ Or via dashboard inference settings (set grading provider to claude-code).
6207
6149
 
6208
6150
  Claude Code session settings (scoped to ~/.synkro/cc_sessions only):
6209
6151
  ${PLUGIN_SETTINGS_PATH}
@@ -6246,8 +6188,44 @@ TROUBLESHOOTING
6246
6188
  synkro local-cc attach
6247
6189
  `);
6248
6190
  }
6191
+ function readGatewayUrl() {
6192
+ if (existsSync17(CONFIG_PATH6)) {
6193
+ const m = readFileSync14(CONFIG_PATH6, "utf-8").match(/^SYNKRO_GATEWAY_URL='([^']*)'/m);
6194
+ if (m) return m[1];
6195
+ }
6196
+ return "https://api.synkro.sh";
6197
+ }
6198
+ function updateLocalInferenceFlag(enabled) {
6199
+ if (!existsSync17(CONFIG_PATH6)) return;
6200
+ let content = readFileSync14(CONFIG_PATH6, "utf-8");
6201
+ const flag = enabled ? "yes" : "no";
6202
+ if (content.includes("SYNKRO_LOCAL_INFERENCE=")) {
6203
+ content = content.replace(/^SYNKRO_LOCAL_INFERENCE='[^']*'/m, `SYNKRO_LOCAL_INFERENCE='${flag}'`);
6204
+ } else {
6205
+ content = content.trimEnd() + `
6206
+ SYNKRO_LOCAL_INFERENCE='${flag}'
6207
+ `;
6208
+ }
6209
+ writeFileSync9(CONFIG_PATH6, content, "utf-8");
6210
+ }
6211
+ async function setServerGradingProvider(provider) {
6212
+ await ensureValidToken();
6213
+ const jwt2 = getAccessToken();
6214
+ if (!jwt2) throw new Error("Not authenticated. Run `synkro install` first.");
6215
+ const gatewayUrl = readGatewayUrl();
6216
+ const body = provider ? { roles: { grading: { provider, model: "default" } } } : { roles: { grading: { provider: null, model: null } } };
6217
+ const resp = await fetch(`${gatewayUrl}/api/settings/inference?scope=user`, {
6218
+ method: "PUT",
6219
+ headers: { "Authorization": `Bearer ${jwt2}`, "Content-Type": "application/json" },
6220
+ body: JSON.stringify(body)
6221
+ });
6222
+ if (!resp.ok) {
6223
+ const text = await resp.text().catch(() => "");
6224
+ throw new Error(`Failed to update inference settings: ${resp.status} ${text.slice(0, 200)}`);
6225
+ }
6226
+ }
6249
6227
  async function cmdStatus() {
6250
- console.log(`Inference provider: ${getInferenceProvider()}`);
6228
+ console.log(`Local inference: ${isLocalCCEnabled() ? "enabled" : "disabled"}`);
6251
6229
  try {
6252
6230
  assertPueueInstalled();
6253
6231
  } catch (err) {
@@ -6281,12 +6259,16 @@ async function cmdEnable() {
6281
6259
  const ready = await waitForChannelReady(CHANNEL_PORT, 6e4, CHANNEL_HOST);
6282
6260
  if (ready) console.log(` channel ready at ${CHANNEL_HOST}:${CHANNEL_PORT}`);
6283
6261
  else console.warn(` \u26A0 channel did not come up within 60s \u2014 check \`synkro local-cc logs\``);
6284
- setInferenceProvider("local-cc");
6285
- console.log("Inference provider set to local-cc.");
6262
+ console.log("Updating inference settings...");
6263
+ await setServerGradingProvider("claude-code");
6264
+ updateLocalInferenceFlag(true);
6265
+ console.log("Grading provider set to claude-code (local inference enabled).");
6286
6266
  }
6287
- function cmdDisable() {
6288
- setInferenceProvider("inngest");
6289
- console.log("Inference provider set to inngest. (Pueue task left running \u2014 use `synkro local-cc stop` to terminate.)");
6267
+ async function cmdDisable() {
6268
+ console.log("Updating inference settings...");
6269
+ await setServerGradingProvider(null);
6270
+ updateLocalInferenceFlag(false);
6271
+ console.log("Grading provider cleared (remote inference restored). Pueue task left running \u2014 use `synkro local-cc stop` to terminate.");
6290
6272
  }
6291
6273
  async function cmdStart() {
6292
6274
  assertClaudeInstalled();
@@ -6489,6 +6471,7 @@ async function localCcCommand(args2) {
6489
6471
  process.exit(1);
6490
6472
  }
6491
6473
  }
6474
+ var CONFIG_PATH6;
6492
6475
  var init_localCc = __esm({
6493
6476
  "cli/commands/localCc.ts"() {
6494
6477
  "use strict";
@@ -6497,6 +6480,8 @@ var init_localCc = __esm({
6497
6480
  init_pueue();
6498
6481
  init_settings();
6499
6482
  init_client();
6483
+ init_stub();
6484
+ CONFIG_PATH6 = join17(homedir15(), ".synkro", "config.env");
6500
6485
  }
6501
6486
  });
6502
6487
 
@@ -6548,15 +6533,15 @@ var init_grade = __esm({
6548
6533
  });
6549
6534
 
6550
6535
  // cli/bootstrap.js
6551
- import { readFileSync as readFileSync13, existsSync as existsSync17 } from "fs";
6536
+ import { readFileSync as readFileSync15, existsSync as existsSync18 } from "fs";
6552
6537
  import { resolve } from "path";
6553
6538
  var envCandidates = [
6554
6539
  resolve(process.cwd(), ".env"),
6555
6540
  resolve(process.env.HOME ?? "", ".synkro", "config.env")
6556
6541
  ];
6557
6542
  for (const envPath of envCandidates) {
6558
- if (!existsSync17(envPath)) continue;
6559
- const envContent = readFileSync13(envPath, "utf-8");
6543
+ if (!existsSync18(envPath)) continue;
6544
+ const envContent = readFileSync15(envPath, "utf-8");
6560
6545
  for (const line of envContent.split("\n")) {
6561
6546
  const trimmed = line.trim();
6562
6547
  if (!trimmed || trimmed.startsWith("#")) continue;