@synkro-sh/cli 1.4.3 → 1.4.5

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",
@@ -3868,12 +3890,31 @@ async function waitForChannelReady(port, timeoutMs = 6e4, host = "127.0.0.1") {
3868
3890
  }
3869
3891
  return probePort(host, port);
3870
3892
  }
3893
+ function brewInstall(pkg) {
3894
+ const brew = spawnSync2("brew", ["--version"], { encoding: "utf-8" });
3895
+ if (brew.status !== 0) return false;
3896
+ console.log(` Installing ${pkg} via brew...`);
3897
+ const r = spawnSync2("brew", ["install", pkg], { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
3898
+ return r.status === 0;
3899
+ }
3871
3900
  function assertPueueInstalled() {
3872
- pueueAvailable();
3873
- try {
3874
- statusJson();
3875
- } catch (err) {
3876
- throw new PueueError(`pueue daemon not reachable: ${err.message}`);
3901
+ let r = spawnSync2("pueue", ["--version"], { encoding: "utf-8" });
3902
+ if (r.status !== 0) {
3903
+ if (process.platform === "darwin" && brewInstall("pueue")) {
3904
+ r = spawnSync2("pueue", ["--version"], { encoding: "utf-8" });
3905
+ if (r.status !== 0) throw new PueueError("pueue install succeeded but binary not found on PATH.");
3906
+ } else {
3907
+ throw new PueueError("pueue not found. Install it: brew install pueue (macOS) or https://github.com/Nukesor/pueue");
3908
+ }
3909
+ }
3910
+ const status = spawnSync2("pueue", ["status", "--json"], { encoding: "utf-8" });
3911
+ if (status.status !== 0) {
3912
+ console.log(" Starting pueued daemon...");
3913
+ spawnSync2("pueued", ["-d"], { encoding: "utf-8" });
3914
+ const retry = spawnSync2("pueue", ["status", "--json"], { encoding: "utf-8" });
3915
+ if (retry.status !== 0) {
3916
+ throw new PueueError("pueue daemon not reachable after starting pueued. Check `pueued` manually.");
3917
+ }
3877
3918
  }
3878
3919
  }
3879
3920
  function assertClaudeInstalled() {
@@ -3883,9 +3924,14 @@ function assertClaudeInstalled() {
3883
3924
  }
3884
3925
  }
3885
3926
  function assertTmuxInstalled() {
3886
- const r = spawnSync2("tmux", ["-V"], { encoding: "utf-8" });
3927
+ let r = spawnSync2("tmux", ["-V"], { encoding: "utf-8" });
3887
3928
  if (r.status !== 0) {
3888
- throw new PueueError("tmux not found on PATH. Install tmux (brew install tmux) and retry.");
3929
+ if (process.platform === "darwin" && brewInstall("tmux")) {
3930
+ r = spawnSync2("tmux", ["-V"], { encoding: "utf-8" });
3931
+ if (r.status !== 0) throw new PueueError("tmux install succeeded but binary not found on PATH.");
3932
+ } else {
3933
+ throw new PueueError("tmux not found. Install it: brew install tmux (macOS) or apt install tmux (Linux)");
3934
+ }
3889
3935
  }
3890
3936
  }
3891
3937
  var TASK_LABEL, TMUX_SESSION, SESSION_DIR2, PueueError;
@@ -3894,7 +3940,7 @@ var init_pueue = __esm({
3894
3940
  "use strict";
3895
3941
  TASK_LABEL = "synkro-local-cc";
3896
3942
  TMUX_SESSION = "synkro-local-cc";
3897
- SESSION_DIR2 = join8(homedir7(), ".synkro", "cc_sessions");
3943
+ SESSION_DIR2 = join9(homedir8(), ".synkro", "cc_sessions");
3898
3944
  PueueError = class extends Error {
3899
3945
  constructor(message, cause) {
3900
3946
  super(message);
@@ -3907,16 +3953,16 @@ var init_pueue = __esm({
3907
3953
  });
3908
3954
 
3909
3955
  // 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";
3956
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
3957
+ import { homedir as homedir9 } from "os";
3958
+ import { join as join10 } from "path";
3913
3959
  function loadCachedPrompts() {
3914
3960
  if (_cached) return _cached;
3915
- if (!existsSync9(CACHE_PATH2)) {
3961
+ if (!existsSync10(CACHE_PATH2)) {
3916
3962
  throw new Error("Prompts cache not found. Run `synkro install` or `synkro update` first.");
3917
3963
  }
3918
3964
  try {
3919
- _cached = JSON.parse(readFileSync7(CACHE_PATH2, "utf-8"));
3965
+ _cached = JSON.parse(readFileSync8(CACHE_PATH2, "utf-8"));
3920
3966
  return _cached;
3921
3967
  } catch {
3922
3968
  throw new Error("Prompts cache is corrupted. Run `synkro update` to refresh.");
@@ -3942,15 +3988,15 @@ var CACHE_PATH2, _cached;
3942
3988
  var init_prompts = __esm({
3943
3989
  "cli/local-cc/prompts.ts"() {
3944
3990
  "use strict";
3945
- CACHE_PATH2 = join9(homedir8(), ".synkro", "prompts", "judge-prompts.json");
3991
+ CACHE_PATH2 = join10(homedir9(), ".synkro", "prompts", "judge-prompts.json");
3946
3992
  _cached = null;
3947
3993
  }
3948
3994
  });
3949
3995
 
3950
3996
  // 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";
3997
+ import { appendFileSync, existsSync as existsSync11, mkdirSync as mkdirSync7, openSync as openSync2, readFileSync as readFileSync9, readSync, closeSync as closeSync2, statSync, watchFile, unwatchFile } from "fs";
3998
+ import { dirname as dirname4, join as join11 } from "path";
3999
+ import { homedir as homedir10 } from "os";
3954
4000
  function truncate(s, max = PREVIEW_MAX) {
3955
4001
  if (s.length <= max) return s;
3956
4002
  return s.slice(0, max) + "\u2026 [+" + (s.length - max) + " chars]";
@@ -3986,11 +4032,11 @@ function appendTurn(args2) {
3986
4032
  }
3987
4033
  }
3988
4034
  function readRecentTurns(n = 20) {
3989
- if (!existsSync10(TURN_LOG_PATH)) return [];
4035
+ if (!existsSync11(TURN_LOG_PATH)) return [];
3990
4036
  try {
3991
4037
  const size = statSync(TURN_LOG_PATH).size;
3992
4038
  if (size === 0) return [];
3993
- const text = readFileSync8(TURN_LOG_PATH, "utf-8");
4039
+ const text = readFileSync9(TURN_LOG_PATH, "utf-8");
3994
4040
  const lines = text.split("\n").filter(Boolean);
3995
4041
  const lastN = lines.slice(-n).reverse();
3996
4042
  return lastN.map((line) => {
@@ -4007,7 +4053,7 @@ function readRecentTurns(n = 20) {
4007
4053
  function followTurns(onEntry) {
4008
4054
  try {
4009
4055
  mkdirSync7(dirname4(TURN_LOG_PATH), { recursive: true });
4010
- if (!existsSync10(TURN_LOG_PATH)) {
4056
+ if (!existsSync11(TURN_LOG_PATH)) {
4011
4057
  appendFileSync(TURN_LOG_PATH, "", "utf-8");
4012
4058
  }
4013
4059
  } catch {
@@ -4069,7 +4115,7 @@ var TURN_LOG_PATH, PREVIEW_MAX;
4069
4115
  var init_turnLog = __esm({
4070
4116
  "cli/local-cc/turnLog.ts"() {
4071
4117
  "use strict";
4072
- TURN_LOG_PATH = join10(homedir9(), ".synkro", "cc_sessions", "turns.log");
4118
+ TURN_LOG_PATH = join11(homedir10(), ".synkro", "cc_sessions", "turns.log");
4073
4119
  PREVIEW_MAX = 400;
4074
4120
  }
4075
4121
  });
@@ -4175,9 +4221,9 @@ __export(install_exports, {
4175
4221
  installCommand: () => installCommand,
4176
4222
  parseArgs: () => parseArgs
4177
4223
  });
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";
4224
+ import { existsSync as existsSync12, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, chmodSync as chmodSync2, readFileSync as readFileSync10, readdirSync } from "fs";
4225
+ import { homedir as homedir11 } from "os";
4226
+ import { join as join12 } from "path";
4181
4227
  import { execSync as execSync5 } from "child_process";
4182
4228
  import { createInterface as createInterface3 } from "readline";
4183
4229
  function sanitizeGatewayCandidate(raw) {
@@ -4220,13 +4266,13 @@ function ensureSynkroDir() {
4220
4266
  mkdirSync8(OFFSETS_DIR, { recursive: true });
4221
4267
  }
4222
4268
  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");
4269
+ const bashScriptPath = join12(HOOKS_DIR, "cc-bash-judge.sh");
4270
+ const bashFollowupScriptPath = join12(HOOKS_DIR, "cc-bash-followup.sh");
4271
+ const editCaptureScriptPath = join12(HOOKS_DIR, "cc-edit-capture.sh");
4272
+ const editPrecheckScriptPath = join12(HOOKS_DIR, "cc-edit-precheck.sh");
4273
+ const stopSummaryScriptPath = join12(HOOKS_DIR, "cc-stop-summary.sh");
4274
+ const sessionStartScriptPath = join12(HOOKS_DIR, "cc-session-start.sh");
4275
+ const transcriptSyncScriptPath = join12(HOOKS_DIR, "cc-transcript-sync.sh");
4230
4276
  writeFileSync7(bashScriptPath, CC_BASH_JUDGE_SCRIPT, "utf-8");
4231
4277
  writeFileSync7(bashFollowupScriptPath, CC_BASH_FOLLOWUP_SCRIPT, "utf-8");
4232
4278
  writeFileSync7(editCaptureScriptPath, CC_EDIT_CAPTURE_SCRIPT, "utf-8");
@@ -4260,11 +4306,11 @@ function shellQuoteSingle(value) {
4260
4306
  }
4261
4307
  function resolveSynkroBundle() {
4262
4308
  const scriptPath = process.argv[1];
4263
- if (scriptPath && existsSync11(scriptPath)) return scriptPath;
4309
+ if (scriptPath && existsSync12(scriptPath)) return scriptPath;
4264
4310
  return null;
4265
4311
  }
4266
4312
  function writeConfigEnv(opts) {
4267
- const credsPath = join11(SYNKRO_DIR2, "credentials.json");
4313
+ const credsPath = join12(SYNKRO_DIR2, "credentials.json");
4268
4314
  const safeGateway = sanitizeConfigValue(opts.gatewayUrl);
4269
4315
  const safeUserId = sanitizeConfigValue(opts.userId);
4270
4316
  const safeOrgId = sanitizeConfigValue(opts.orgId);
@@ -4280,7 +4326,7 @@ function writeConfigEnv(opts) {
4280
4326
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
4281
4327
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
4282
4328
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
4283
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.3")}`
4329
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.5")}`
4284
4330
  ];
4285
4331
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
4286
4332
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -4291,8 +4337,21 @@ function writeConfigEnv(opts) {
4291
4337
  }
4292
4338
  lines.push(`SYNKRO_LOCAL_INFERENCE=${shellQuoteSingle(opts.localInference ? "yes" : "no")}`);
4293
4339
  lines.push("");
4294
- writeFileSync7(CONFIG_PATH2, lines.join("\n"), "utf-8");
4295
- chmodSync2(CONFIG_PATH2, 384);
4340
+ writeFileSync7(CONFIG_PATH3, lines.join("\n"), "utf-8");
4341
+ chmodSync2(CONFIG_PATH3, 384);
4342
+ }
4343
+ function updateLocalInferenceFlag(enabled) {
4344
+ if (!existsSync12(CONFIG_PATH3)) return;
4345
+ let content = readFileSync10(CONFIG_PATH3, "utf-8");
4346
+ const flag = enabled ? "yes" : "no";
4347
+ if (content.includes("SYNKRO_LOCAL_INFERENCE=")) {
4348
+ content = content.replace(/^SYNKRO_LOCAL_INFERENCE='[^']*'/m, `SYNKRO_LOCAL_INFERENCE='${flag}'`);
4349
+ } else {
4350
+ content = content.trimEnd() + `
4351
+ SYNKRO_LOCAL_INFERENCE='${flag}'
4352
+ `;
4353
+ }
4354
+ writeFileSync7(CONFIG_PATH3, content, "utf-8");
4296
4355
  }
4297
4356
  function collectLocalMetadata() {
4298
4357
  const meta = { platform: process.platform };
@@ -4312,16 +4371,16 @@ function collectLocalMetadata() {
4312
4371
  meta.cc_version = execSync5("claude --version", { encoding: "utf-8", timeout: 5e3 }).trim().split("\n")[0];
4313
4372
  } catch {
4314
4373
  }
4315
- const claudeDir = join11(homedir10(), ".claude");
4374
+ const claudeDir = join12(homedir11(), ".claude");
4316
4375
  try {
4317
- const settings = JSON.parse(readFileSync9(join11(claudeDir, "settings.json"), "utf-8"));
4376
+ const settings = JSON.parse(readFileSync10(join12(claudeDir, "settings.json"), "utf-8"));
4318
4377
  const plugins = Object.keys(settings.enabledPlugins ?? {}).filter((k) => settings.enabledPlugins[k]);
4319
4378
  if (plugins.length) meta.enabled_plugins = plugins;
4320
4379
  if (settings.permissions?.defaultMode) meta.permissions_mode = settings.permissions.defaultMode;
4321
4380
  } catch {
4322
4381
  }
4323
4382
  try {
4324
- const mcpCache = JSON.parse(readFileSync9(join11(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
4383
+ const mcpCache = JSON.parse(readFileSync10(join12(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
4325
4384
  const mcpNames = Object.keys(mcpCache);
4326
4385
  if (mcpNames.length) meta.mcp_servers = mcpNames;
4327
4386
  } catch {
@@ -4333,10 +4392,10 @@ function collectLocalMetadata() {
4333
4392
  } catch {
4334
4393
  }
4335
4394
  try {
4336
- const sessionsDir = join11(claudeDir, "sessions");
4395
+ const sessionsDir = join12(claudeDir, "sessions");
4337
4396
  const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).slice(-5);
4338
4397
  for (const f of files) {
4339
- const s = JSON.parse(readFileSync9(join11(sessionsDir, f), "utf-8"));
4398
+ const s = JSON.parse(readFileSync10(join12(sessionsDir, f), "utf-8"));
4340
4399
  if (s.version) {
4341
4400
  meta.cc_version = meta.cc_version || s.version;
4342
4401
  break;
@@ -4392,19 +4451,19 @@ function assertGatewayAllowed(gatewayUrl) {
4392
4451
  }
4393
4452
  function isAlreadyInstalled() {
4394
4453
  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")
4454
+ join12(HOOKS_DIR, "cc-bash-judge.sh"),
4455
+ join12(HOOKS_DIR, "cc-bash-followup.sh"),
4456
+ join12(HOOKS_DIR, "cc-edit-precheck.sh"),
4457
+ join12(HOOKS_DIR, "cc-edit-capture.sh"),
4458
+ join12(HOOKS_DIR, "cc-stop-summary.sh"),
4459
+ join12(HOOKS_DIR, "cc-session-start.sh")
4401
4460
  ];
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;
4461
+ if (!requiredScripts.every((p) => existsSync12(p))) return false;
4462
+ if (!existsSync12(CONFIG_PATH3)) return false;
4463
+ const settingsPath = join12(homedir11(), ".claude", "settings.json");
4464
+ if (!existsSync12(settingsPath)) return false;
4406
4465
  try {
4407
- const settings = JSON.parse(readFileSync9(settingsPath, "utf-8"));
4466
+ const settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
4408
4467
  const hooks = settings?.hooks;
4409
4468
  if (!hooks || typeof hooks !== "object") return false;
4410
4469
  const hasManaged = (kind) => Array.isArray(hooks[kind]) && hooks[kind].some((entry) => entry?.__synkro_managed__ === true);
@@ -4444,6 +4503,29 @@ async function installCommand(opts = {}) {
4444
4503
  } catch {
4445
4504
  }
4446
4505
  }
4506
+ const token2 = getAccessToken();
4507
+ if (token2) {
4508
+ const profile2 = await fetchUserProfile(gatewayUrl, token2);
4509
+ if (profile2.localInference && !isLocalCCEnabled()) {
4510
+ console.log("Local inference enabled in your profile \u2014 setting up local-CC channel...");
4511
+ try {
4512
+ assertClaudeInstalled();
4513
+ assertPueueInstalled();
4514
+ assertTmuxInstalled();
4515
+ installLocalCC();
4516
+ const t = ensureRunning();
4517
+ console.log(` pueue task: id=${t.id} status=${t.status}`);
4518
+ console.log(" Waiting for channel...");
4519
+ const ready = await waitForChannelReady(CHANNEL_PORT, 6e4, CHANNEL_HOST);
4520
+ if (ready) console.log(` channel ready at ${CHANNEL_HOST}:${CHANNEL_PORT}`);
4521
+ else console.warn(" \u26A0 channel did not come up within 60s \u2014 check `synkro local-cc logs`");
4522
+ updateLocalInferenceFlag(true);
4523
+ } catch (err) {
4524
+ console.warn(` \u26A0 Local-CC setup skipped: ${err.message}`);
4525
+ console.warn(" Install pueue, tmux, and claude, then re-run install.");
4526
+ }
4527
+ }
4528
+ }
4447
4529
  console.log("\u2713 Synkro is already installed and configured.");
4448
4530
  console.log(" Run `synkro-cli update` to refresh hook scripts and judge prompts.");
4449
4531
  console.log(" Run `synkro-cli install --force` to reinstall from scratch.");
@@ -4512,9 +4594,9 @@ async function installCommand(opts = {}) {
4512
4594
  console.log(` ${scripts.transcriptSyncScript}
4513
4595
  `);
4514
4596
  for (const mode of ["edit", "bash"]) {
4515
- const pidFile = join11(SYNKRO_DIR2, "daemon", mode, "daemon.pid");
4597
+ const pidFile = join12(SYNKRO_DIR2, "daemon", mode, "daemon.pid");
4516
4598
  try {
4517
- const pid = parseInt(readFileSync9(pidFile, "utf-8").trim(), 10);
4599
+ const pid = parseInt(readFileSync10(pidFile, "utf-8").trim(), 10);
4518
4600
  if (pid > 0) {
4519
4601
  process.kill(pid, "SIGTERM");
4520
4602
  console.log(`Stopped stale ${mode} grader daemon (pid ${pid})`);
@@ -4589,7 +4671,7 @@ async function installCommand(opts = {}) {
4589
4671
  const profile = await fetchUserProfile(gatewayUrl, token);
4590
4672
  const synkroBundle = resolveSynkroBundle();
4591
4673
  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}`);
4674
+ console.log(`Wrote config to ${CONFIG_PATH3}`);
4593
4675
  console.log(` inference: ${profile.inference} (server-side grading)`);
4594
4676
  if (profile.localInference) console.log(` local inference: enabled (gradingProvider=claude-code)`);
4595
4677
  if (synkroBundle) console.log(` SYNKRO_CLI_BIN=${synkroBundle}`);
@@ -4667,17 +4749,17 @@ function detectGitRepo2() {
4667
4749
  function getClaudeProjectsFolder() {
4668
4750
  const cwd = process.cwd();
4669
4751
  const sanitized = "-" + cwd.replace(/\//g, "-");
4670
- const projectsDir = join11(homedir10(), ".claude", "projects", sanitized);
4671
- return existsSync11(projectsDir) ? projectsDir : null;
4752
+ const projectsDir = join12(homedir11(), ".claude", "projects", sanitized);
4753
+ return existsSync12(projectsDir) ? projectsDir : null;
4672
4754
  }
4673
4755
  function extractSessionInsights(projectsDir) {
4674
4756
  const insights = [];
4675
4757
  const files = readdirSync(projectsDir).filter((f) => f.endsWith(".jsonl"));
4676
4758
  for (const file of files) {
4677
4759
  const sessionId = file.replace(".jsonl", "");
4678
- const filePath = join11(projectsDir, file);
4760
+ const filePath = join12(projectsDir, file);
4679
4761
  try {
4680
- const content = readFileSync9(filePath, "utf-8");
4762
+ const content = readFileSync10(filePath, "utf-8");
4681
4763
  const lines = content.split("\n").filter(Boolean);
4682
4764
  for (let i = 0; i < lines.length; i++) {
4683
4765
  try {
@@ -4753,7 +4835,7 @@ function extractTextContent(content) {
4753
4835
  return "";
4754
4836
  }
4755
4837
  function parseTranscriptFile(filePath) {
4756
- const content = readFileSync9(filePath, "utf-8");
4838
+ const content = readFileSync10(filePath, "utf-8");
4757
4839
  const lines = content.split("\n").filter(Boolean);
4758
4840
  const messages = [];
4759
4841
  for (let i = 0; i < lines.length; i++) {
@@ -4804,7 +4886,7 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
4804
4886
  const sessions = [];
4805
4887
  for (const file of batch) {
4806
4888
  const sessionId = file.replace(".jsonl", "");
4807
- const filePath = join11(projectsDir, file);
4889
+ const filePath = join12(projectsDir, file);
4808
4890
  try {
4809
4891
  const allMessages = parseTranscriptFile(filePath);
4810
4892
  const messages = allMessages.length > maxMessagesPerSession ? allMessages.slice(-maxMessagesPerSession) : allMessages;
@@ -4833,18 +4915,18 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
4833
4915
  }
4834
4916
  for (const file of batch) {
4835
4917
  const sessionId = file.replace(".jsonl", "");
4836
- const filePath = join11(projectsDir, file);
4918
+ const filePath = join12(projectsDir, file);
4837
4919
  try {
4838
- const content = readFileSync9(filePath, "utf-8");
4920
+ const content = readFileSync10(filePath, "utf-8");
4839
4921
  const lineCount = content.split("\n").filter(Boolean).length;
4840
- writeFileSync7(join11(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
4922
+ writeFileSync7(join12(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
4841
4923
  } catch {
4842
4924
  }
4843
4925
  }
4844
4926
  }
4845
4927
  return { sessions: totalSessions, messages: totalMessages };
4846
4928
  }
4847
- var SYNKRO_DIR2, HOOKS_DIR, BIN_DIR, CONFIG_PATH2, OFFSETS_DIR;
4929
+ var SYNKRO_DIR2, HOOKS_DIR, BIN_DIR, CONFIG_PATH3, OFFSETS_DIR;
4848
4930
  var init_install2 = __esm({
4849
4931
  "cli/commands/install.ts"() {
4850
4932
  "use strict";
@@ -4857,14 +4939,15 @@ var init_install2 = __esm({
4857
4939
  init_projects();
4858
4940
  init_setupGithub();
4859
4941
  init_promptFetcher();
4942
+ init_settings();
4860
4943
  init_install();
4861
4944
  init_pueue();
4862
4945
  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");
4946
+ SYNKRO_DIR2 = join12(homedir11(), ".synkro");
4947
+ HOOKS_DIR = join12(SYNKRO_DIR2, "hooks");
4948
+ BIN_DIR = join12(SYNKRO_DIR2, "bin");
4949
+ CONFIG_PATH3 = join12(SYNKRO_DIR2, "config.env");
4950
+ OFFSETS_DIR = join12(SYNKRO_DIR2, ".transcript-offsets");
4868
4951
  }
4869
4952
  });
4870
4953
 
@@ -4940,13 +5023,13 @@ var status_exports = {};
4940
5023
  __export(status_exports, {
4941
5024
  statusCommand: () => statusCommand
4942
5025
  });
4943
- import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
4944
- import { homedir as homedir11 } from "os";
4945
- import { join as join12 } from "path";
5026
+ import { existsSync as existsSync13, readFileSync as readFileSync11 } from "fs";
5027
+ import { homedir as homedir12 } from "os";
5028
+ import { join as join13 } from "path";
4946
5029
  function readConfigEnv() {
4947
- if (!existsSync12(CONFIG_PATH3)) return {};
5030
+ if (!existsSync13(CONFIG_PATH4)) return {};
4948
5031
  const out = {};
4949
- const raw = readFileSync10(CONFIG_PATH3, "utf-8");
5032
+ const raw = readFileSync11(CONFIG_PATH4, "utf-8");
4950
5033
  for (const line of raw.split("\n")) {
4951
5034
  const trimmed = line.trim();
4952
5035
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -5019,19 +5102,19 @@ async function statusCommand() {
5019
5102
  }
5020
5103
  }
5021
5104
  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");
5105
+ const bashScript = join13(SYNKRO_DIR3, "hooks", "cc-bash-judge.sh");
5106
+ const bashFollowupScript = join13(SYNKRO_DIR3, "hooks", "cc-bash-followup.sh");
5107
+ const editPrecheckScript = join13(SYNKRO_DIR3, "hooks", "cc-edit-precheck.sh");
5108
+ const editCaptureScript = join13(SYNKRO_DIR3, "hooks", "cc-edit-capture.sh");
5109
+ const stopSummaryScript = join13(SYNKRO_DIR3, "hooks", "cc-stop-summary.sh");
5110
+ const sessionStartScript = join13(SYNKRO_DIR3, "hooks", "cc-session-start.sh");
5028
5111
  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}`);
5112
+ console.log(` ${existsSync13(bashScript) ? "\u2713" : "\u2717"} ${bashScript}`);
5113
+ console.log(` ${existsSync13(bashFollowupScript) ? "\u2713" : "\u2717"} ${bashFollowupScript}`);
5114
+ console.log(` ${existsSync13(editPrecheckScript) ? "\u2713" : "\u2717"} ${editPrecheckScript}`);
5115
+ console.log(` ${existsSync13(editCaptureScript) ? "\u2713" : "\u2717"} ${editCaptureScript}`);
5116
+ console.log(` ${existsSync13(stopSummaryScript) ? "\u2713" : "\u2717"} ${stopSummaryScript}`);
5117
+ console.log(` ${existsSync13(sessionStartScript) ? "\u2713" : "\u2717"} ${sessionStartScript}`);
5035
5118
  console.log();
5036
5119
  const mcp = inspectMcpConfig();
5037
5120
  console.log("Guardrails MCP server (Claude Code):");
@@ -5043,7 +5126,7 @@ async function statusCommand() {
5043
5126
  console.log(` expected at ${mcp.configPath} \u2192 mcpServers.synkro-guardrails`);
5044
5127
  }
5045
5128
  }
5046
- var SYNKRO_DIR3, CONFIG_PATH3;
5129
+ var SYNKRO_DIR3, CONFIG_PATH4;
5047
5130
  var init_status = __esm({
5048
5131
  "cli/commands/status.ts"() {
5049
5132
  "use strict";
@@ -5051,8 +5134,8 @@ var init_status = __esm({
5051
5134
  init_agentDetect();
5052
5135
  init_ccHookConfig();
5053
5136
  init_mcpConfig();
5054
- SYNKRO_DIR3 = join12(homedir11(), ".synkro");
5055
- CONFIG_PATH3 = join12(SYNKRO_DIR3, "config.env");
5137
+ SYNKRO_DIR3 = join13(homedir12(), ".synkro");
5138
+ CONFIG_PATH4 = join13(SYNKRO_DIR3, "config.env");
5056
5139
  }
5057
5140
  });
5058
5141
 
@@ -5141,13 +5224,13 @@ var config_exports = {};
5141
5224
  __export(config_exports, {
5142
5225
  configCommand: () => configCommand
5143
5226
  });
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";
5227
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync14 } from "fs";
5228
+ import { join as join14 } from "path";
5229
+ import { homedir as homedir13 } from "os";
5147
5230
  function readConfigEnv2() {
5148
- if (!existsSync13(CONFIG_PATH4)) return {};
5231
+ if (!existsSync14(CONFIG_PATH5)) return {};
5149
5232
  const out = {};
5150
- for (const line of readFileSync11(CONFIG_PATH4, "utf-8").split("\n")) {
5233
+ for (const line of readFileSync12(CONFIG_PATH5, "utf-8").split("\n")) {
5151
5234
  const t = line.trim();
5152
5235
  if (!t || t.startsWith("#")) continue;
5153
5236
  const eq = t.indexOf("=");
@@ -5156,11 +5239,11 @@ function readConfigEnv2() {
5156
5239
  return out;
5157
5240
  }
5158
5241
  function updateConfigValue(key, value) {
5159
- if (!existsSync13(CONFIG_PATH4)) {
5242
+ if (!existsSync14(CONFIG_PATH5)) {
5160
5243
  console.error("No config found. Run `synkro install` first.");
5161
5244
  process.exit(1);
5162
5245
  }
5163
- const lines = readFileSync11(CONFIG_PATH4, "utf-8").split("\n");
5246
+ const lines = readFileSync12(CONFIG_PATH5, "utf-8").split("\n");
5164
5247
  const pattern = new RegExp(`^${key}=`);
5165
5248
  let found = false;
5166
5249
  const updated = lines.map((line) => {
@@ -5171,7 +5254,7 @@ function updateConfigValue(key, value) {
5171
5254
  return line;
5172
5255
  });
5173
5256
  if (!found) updated.splice(updated.length - 1, 0, `${key}='${value}'`);
5174
- writeFileSync8(CONFIG_PATH4, updated.join("\n"), "utf-8");
5257
+ writeFileSync8(CONFIG_PATH5, updated.join("\n"), "utf-8");
5175
5258
  }
5176
5259
  async function configCommand(args2) {
5177
5260
  if (args2.length === 0) {
@@ -5222,13 +5305,13 @@ To change: synkro config --inference fast|standard`);
5222
5305
  updateConfigValue("SYNKRO_INFERENCE", inferenceValue);
5223
5306
  console.log(`\u2713 Inference set to '${inferenceValue}'.`);
5224
5307
  }
5225
- var SYNKRO_DIR4, CONFIG_PATH4;
5308
+ var SYNKRO_DIR4, CONFIG_PATH5;
5226
5309
  var init_config = __esm({
5227
5310
  "cli/commands/config.ts"() {
5228
5311
  "use strict";
5229
5312
  init_stub();
5230
- SYNKRO_DIR4 = join13(homedir12(), ".synkro");
5231
- CONFIG_PATH4 = join13(SYNKRO_DIR4, "config.env");
5313
+ SYNKRO_DIR4 = join14(homedir13(), ".synkro");
5314
+ CONFIG_PATH5 = join14(SYNKRO_DIR4, "config.env");
5232
5315
  }
5233
5316
  });
5234
5317
 
@@ -5238,8 +5321,8 @@ __export(scanPr_exports, {
5238
5321
  scanPrCommand: () => scanPrCommand
5239
5322
  });
5240
5323
  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";
5324
+ import { readFileSync as readFileSync13, existsSync as existsSync15 } from "fs";
5325
+ import { join as join15 } from "path";
5243
5326
  function parseMatchSpec(condition) {
5244
5327
  if (!condition.startsWith("match_spec:")) return null;
5245
5328
  try {
@@ -5718,10 +5801,10 @@ function shouldFail(findings, threshold) {
5718
5801
  return findings.some((f) => order.indexOf(f.severity) >= thresholdIdx);
5719
5802
  }
5720
5803
  function readRepoDeps() {
5721
- const pkgPath = join14(process.cwd(), "package.json");
5722
- if (!existsSync14(pkgPath)) return {};
5804
+ const pkgPath = join15(process.cwd(), "package.json");
5805
+ if (!existsSync15(pkgPath)) return {};
5723
5806
  try {
5724
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
5807
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
5725
5808
  return { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
5726
5809
  } catch {
5727
5810
  return {};
@@ -5983,9 +6066,9 @@ var disconnect_exports = {};
5983
6066
  __export(disconnect_exports, {
5984
6067
  disconnectCommand: () => disconnectCommand
5985
6068
  });
5986
- import { existsSync as existsSync15, rmSync } from "fs";
5987
- import { homedir as homedir13 } from "os";
5988
- import { join as join15 } from "path";
6069
+ import { existsSync as existsSync16, rmSync } from "fs";
6070
+ import { homedir as homedir14 } from "os";
6071
+ import { join as join16 } from "path";
5989
6072
  function tearDownLocalCC() {
5990
6073
  let hadTask = false;
5991
6074
  try {
@@ -6015,13 +6098,13 @@ function disconnectCommand(args2 = []) {
6015
6098
  console.log(`${mcpRemoved ? "\u2713" : "\xB7"} MCP guardrails server: ${mcpRemoved ? "removed entry from ~/.claude.json" : "no Synkro MCP entry found"}`);
6016
6099
  }
6017
6100
  if (purge) {
6018
- if (existsSync15(SYNKRO_DIR5)) {
6101
+ if (existsSync16(SYNKRO_DIR5)) {
6019
6102
  rmSync(SYNKRO_DIR5, { recursive: true, force: true });
6020
6103
  console.log(`\u2713 Removed ${SYNKRO_DIR5}`);
6021
6104
  } else {
6022
6105
  console.log(`\xB7 ${SYNKRO_DIR5} already gone, nothing to remove`);
6023
6106
  }
6024
- } else if (existsSync15(SYNKRO_DIR5)) {
6107
+ } else if (existsSync16(SYNKRO_DIR5)) {
6025
6108
  console.log(`Config preserved at ${SYNKRO_DIR5}. Run with --purge to remove.`);
6026
6109
  }
6027
6110
  console.log("\nSynkro disconnected.");
@@ -6035,7 +6118,7 @@ var init_disconnect = __esm({
6035
6118
  init_mcpConfig();
6036
6119
  init_pueue();
6037
6120
  init_install();
6038
- SYNKRO_DIR5 = join15(homedir13(), ".synkro");
6121
+ SYNKRO_DIR5 = join16(homedir14(), ".synkro");
6039
6122
  }
6040
6123
  });
6041
6124
 
@@ -6076,28 +6159,6 @@ var init_reinstall = __esm({
6076
6159
  }
6077
6160
  });
6078
6161
 
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
6162
  // cli/commands/localCc.ts
6102
6163
  var localCc_exports = {};
6103
6164
  __export(localCc_exports, {
@@ -6202,7 +6263,7 @@ function readGatewayUrl() {
6202
6263
  }
6203
6264
  return "https://api.synkro.sh";
6204
6265
  }
6205
- function updateLocalInferenceFlag(enabled) {
6266
+ function updateLocalInferenceFlag2(enabled) {
6206
6267
  if (!existsSync17(CONFIG_PATH6)) return;
6207
6268
  let content = readFileSync14(CONFIG_PATH6, "utf-8");
6208
6269
  const flag = enabled ? "yes" : "no";
@@ -6268,13 +6329,13 @@ async function cmdEnable() {
6268
6329
  else console.warn(` \u26A0 channel did not come up within 60s \u2014 check \`synkro local-cc logs\``);
6269
6330
  console.log("Updating inference settings...");
6270
6331
  await setServerGradingProvider("claude-code");
6271
- updateLocalInferenceFlag(true);
6332
+ updateLocalInferenceFlag2(true);
6272
6333
  console.log("Grading provider set to claude-code (local inference enabled).");
6273
6334
  }
6274
6335
  async function cmdDisable() {
6275
6336
  console.log("Updating inference settings...");
6276
6337
  await setServerGradingProvider(null);
6277
- updateLocalInferenceFlag(false);
6338
+ updateLocalInferenceFlag2(false);
6278
6339
  console.log("Grading provider cleared (remote inference restored). Pueue task left running \u2014 use `synkro local-cc stop` to terminate.");
6279
6340
  }
6280
6341
  async function cmdStart() {