@synkro-sh/cli 1.4.1 → 1.4.3

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
@@ -3906,15 +3906,278 @@ var init_pueue = __esm({
3906
3906
  }
3907
3907
  });
3908
3908
 
3909
+ // 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";
3913
+ function loadCachedPrompts() {
3914
+ if (_cached) return _cached;
3915
+ if (!existsSync9(CACHE_PATH2)) {
3916
+ throw new Error("Prompts cache not found. Run `synkro install` or `synkro update` first.");
3917
+ }
3918
+ try {
3919
+ _cached = JSON.parse(readFileSync7(CACHE_PATH2, "utf-8"));
3920
+ return _cached;
3921
+ } catch {
3922
+ throw new Error("Prompts cache is corrupted. Run `synkro update` to refresh.");
3923
+ }
3924
+ }
3925
+ function getPrimer(role) {
3926
+ const cache = loadCachedPrompts();
3927
+ const primer = role === "grade-edit" ? cache.grader_primer_edit : cache.grader_primer_bash;
3928
+ if (!primer) {
3929
+ throw new Error(`No cached primer for role "${role}". Run \`synkro update\` to refresh prompts.`);
3930
+ }
3931
+ return primer;
3932
+ }
3933
+ function buildChannelContent(role, payload) {
3934
+ return `${getPrimer(role)}
3935
+
3936
+ ---
3937
+ PAYLOAD (the input to evaluate):
3938
+
3939
+ ${payload}`;
3940
+ }
3941
+ var CACHE_PATH2, _cached;
3942
+ var init_prompts = __esm({
3943
+ "cli/local-cc/prompts.ts"() {
3944
+ "use strict";
3945
+ CACHE_PATH2 = join9(homedir8(), ".synkro", "prompts", "judge-prompts.json");
3946
+ _cached = null;
3947
+ }
3948
+ });
3949
+
3950
+ // 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";
3954
+ function truncate(s, max = PREVIEW_MAX) {
3955
+ if (s.length <= max) return s;
3956
+ return s.slice(0, max) + "\u2026 [+" + (s.length - max) + " chars]";
3957
+ }
3958
+ function extractSeverity(result) {
3959
+ const m = result.match(/<synkro-(?:verdict|intent)>([\s\S]*?)<\/synkro-(?:verdict|intent)>/);
3960
+ if (!m) return void 0;
3961
+ try {
3962
+ const obj = JSON.parse(m[1]);
3963
+ if (obj.severity) return String(obj.severity);
3964
+ if (typeof obj.ok === "boolean") return obj.ok ? "ok" : "violations";
3965
+ if (obj.type) return String(obj.type);
3966
+ if (obj.verdict) return String(obj.verdict);
3967
+ } catch {
3968
+ }
3969
+ return void 0;
3970
+ }
3971
+ function appendTurn(args2) {
3972
+ try {
3973
+ mkdirSync7(dirname4(TURN_LOG_PATH), { recursive: true });
3974
+ const entry = {
3975
+ ts: new Date(args2.startedAt).toISOString(),
3976
+ role: args2.role,
3977
+ duration_ms: Date.now() - args2.startedAt,
3978
+ status: args2.status,
3979
+ request_preview: truncate(args2.request),
3980
+ response_preview: args2.result ? truncate(args2.result) : "",
3981
+ severity: args2.result ? extractSeverity(args2.result) : void 0,
3982
+ error: args2.error
3983
+ };
3984
+ appendFileSync(TURN_LOG_PATH, JSON.stringify(entry) + "\n", "utf-8");
3985
+ } catch {
3986
+ }
3987
+ }
3988
+ function readRecentTurns(n = 20) {
3989
+ if (!existsSync10(TURN_LOG_PATH)) return [];
3990
+ try {
3991
+ const size = statSync(TURN_LOG_PATH).size;
3992
+ if (size === 0) return [];
3993
+ const text = readFileSync8(TURN_LOG_PATH, "utf-8");
3994
+ const lines = text.split("\n").filter(Boolean);
3995
+ const lastN = lines.slice(-n).reverse();
3996
+ return lastN.map((line) => {
3997
+ try {
3998
+ return JSON.parse(line);
3999
+ } catch {
4000
+ return null;
4001
+ }
4002
+ }).filter((x) => x !== null);
4003
+ } catch {
4004
+ return [];
4005
+ }
4006
+ }
4007
+ function followTurns(onEntry) {
4008
+ try {
4009
+ mkdirSync7(dirname4(TURN_LOG_PATH), { recursive: true });
4010
+ if (!existsSync10(TURN_LOG_PATH)) {
4011
+ appendFileSync(TURN_LOG_PATH, "", "utf-8");
4012
+ }
4013
+ } catch {
4014
+ }
4015
+ let lastSize = (() => {
4016
+ try {
4017
+ return statSync(TURN_LOG_PATH).size;
4018
+ } catch {
4019
+ return 0;
4020
+ }
4021
+ })();
4022
+ let pendingPartial = "";
4023
+ const drainNewBytes = (from, to) => {
4024
+ if (to <= from) return;
4025
+ let fd = null;
4026
+ try {
4027
+ fd = openSync2(TURN_LOG_PATH, "r");
4028
+ const len = to - from;
4029
+ const buf = Buffer.alloc(len);
4030
+ readSync(fd, buf, 0, len, from);
4031
+ const text = pendingPartial + buf.toString("utf-8");
4032
+ const lastNewline = text.lastIndexOf("\n");
4033
+ if (lastNewline === -1) {
4034
+ pendingPartial = text;
4035
+ return;
4036
+ }
4037
+ const complete = text.slice(0, lastNewline);
4038
+ pendingPartial = text.slice(lastNewline + 1);
4039
+ for (const line of complete.split("\n")) {
4040
+ if (!line) continue;
4041
+ try {
4042
+ onEntry(JSON.parse(line));
4043
+ } catch {
4044
+ }
4045
+ }
4046
+ } catch {
4047
+ } finally {
4048
+ if (fd !== null) {
4049
+ try {
4050
+ closeSync2(fd);
4051
+ } catch {
4052
+ }
4053
+ }
4054
+ }
4055
+ };
4056
+ watchFile(TURN_LOG_PATH, { interval: 250 }, (curr, prev) => {
4057
+ if (curr.size < lastSize) {
4058
+ lastSize = 0;
4059
+ pendingPartial = "";
4060
+ }
4061
+ if (curr.size > lastSize) {
4062
+ drainNewBytes(lastSize, curr.size);
4063
+ lastSize = curr.size;
4064
+ }
4065
+ });
4066
+ return () => unwatchFile(TURN_LOG_PATH);
4067
+ }
4068
+ var TURN_LOG_PATH, PREVIEW_MAX;
4069
+ var init_turnLog = __esm({
4070
+ "cli/local-cc/turnLog.ts"() {
4071
+ "use strict";
4072
+ TURN_LOG_PATH = join10(homedir9(), ".synkro", "cc_sessions", "turns.log");
4073
+ PREVIEW_MAX = 400;
4074
+ }
4075
+ });
4076
+
4077
+ // cli/local-cc/client.ts
4078
+ import { request as httpRequest } from "http";
4079
+ import { connect as connect2 } from "net";
4080
+ async function submitToChannel(role, payload, opts = {}) {
4081
+ const content = buildChannelContent(role, payload);
4082
+ const body = JSON.stringify({ role, content });
4083
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
4084
+ const startedAt = Date.now();
4085
+ try {
4086
+ const result = await new Promise((resolve2, reject) => {
4087
+ const req = httpRequest({
4088
+ host: CHANNEL_HOST,
4089
+ port: CHANNEL_PORT,
4090
+ method: "POST",
4091
+ path: "/submit",
4092
+ headers: {
4093
+ "Content-Type": "application/json",
4094
+ "Content-Length": Buffer.byteLength(body)
4095
+ },
4096
+ timeout: timeoutMs
4097
+ }, (res) => {
4098
+ const chunks = [];
4099
+ res.on("data", (c) => chunks.push(c));
4100
+ res.on("end", () => {
4101
+ const text = Buffer.concat(chunks).toString("utf-8");
4102
+ if (res.statusCode !== 200) {
4103
+ reject(new LocalCCError(`channel returned ${res.statusCode}: ${text.slice(0, 500)}`));
4104
+ return;
4105
+ }
4106
+ try {
4107
+ const parsed = JSON.parse(text);
4108
+ if (parsed.error) {
4109
+ reject(new LocalCCError(parsed.error));
4110
+ return;
4111
+ }
4112
+ resolve2(String(parsed.result ?? ""));
4113
+ } catch (err) {
4114
+ reject(new LocalCCError(`malformed channel response: ${text.slice(0, 200)}`, err));
4115
+ }
4116
+ });
4117
+ });
4118
+ req.on("timeout", () => {
4119
+ req.destroy(new LocalCCError(`channel request timed out after ${timeoutMs}ms`));
4120
+ });
4121
+ req.on("error", (err) => {
4122
+ const msg = err.code === "ECONNREFUSED" ? `channel connection refused at ${CHANNEL_HOST}:${CHANNEL_PORT} (is the pueue task running?)` : `channel request failed: ${err.message}`;
4123
+ reject(new LocalCCError(msg, err));
4124
+ });
4125
+ req.write(body);
4126
+ req.end();
4127
+ });
4128
+ appendTurn({ startedAt, role, request: payload, result, status: "ok" });
4129
+ return result;
4130
+ } catch (err) {
4131
+ const message = err.message ?? String(err);
4132
+ const status = /timed out/i.test(message) ? "timeout" : "error";
4133
+ appendTurn({ startedAt, role, request: payload, status, error: message });
4134
+ throw err;
4135
+ }
4136
+ }
4137
+ function isChannelAvailable(timeoutMs = 500) {
4138
+ return new Promise((resolve2) => {
4139
+ const sock = connect2(CHANNEL_PORT, CHANNEL_HOST);
4140
+ const done = (ok) => {
4141
+ try {
4142
+ sock.destroy();
4143
+ } catch {
4144
+ }
4145
+ resolve2(ok);
4146
+ };
4147
+ sock.once("connect", () => done(true));
4148
+ sock.once("error", () => done(false));
4149
+ sock.setTimeout(timeoutMs, () => done(false));
4150
+ });
4151
+ }
4152
+ var CHANNEL_HOST, CHANNEL_PORT, DEFAULT_TIMEOUT_MS, LocalCCError;
4153
+ var init_client = __esm({
4154
+ "cli/local-cc/client.ts"() {
4155
+ "use strict";
4156
+ init_prompts();
4157
+ init_turnLog();
4158
+ CHANNEL_HOST = "127.0.0.1";
4159
+ CHANNEL_PORT = parseInt(process.env.SYNKRO_CHANNEL_PORT || "8929", 10);
4160
+ DEFAULT_TIMEOUT_MS = 9e4;
4161
+ LocalCCError = class extends Error {
4162
+ constructor(message, cause) {
4163
+ super(message);
4164
+ this.cause = cause;
4165
+ this.name = "LocalCCError";
4166
+ }
4167
+ cause;
4168
+ };
4169
+ }
4170
+ });
4171
+
3909
4172
  // cli/commands/install.ts
3910
4173
  var install_exports = {};
3911
4174
  __export(install_exports, {
3912
4175
  installCommand: () => installCommand,
3913
4176
  parseArgs: () => parseArgs
3914
4177
  });
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";
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";
3918
4181
  import { execSync as execSync5 } from "child_process";
3919
4182
  import { createInterface as createInterface3 } from "readline";
3920
4183
  function sanitizeGatewayCandidate(raw) {
@@ -3951,19 +4214,19 @@ async function promptTranscriptConsent() {
3951
4214
  });
3952
4215
  }
3953
4216
  function ensureSynkroDir() {
3954
- mkdirSync7(SYNKRO_DIR2, { recursive: true });
3955
- mkdirSync7(HOOKS_DIR, { recursive: true });
3956
- mkdirSync7(BIN_DIR, { recursive: true });
3957
- mkdirSync7(OFFSETS_DIR, { recursive: true });
4217
+ mkdirSync8(SYNKRO_DIR2, { recursive: true });
4218
+ mkdirSync8(HOOKS_DIR, { recursive: true });
4219
+ mkdirSync8(BIN_DIR, { recursive: true });
4220
+ mkdirSync8(OFFSETS_DIR, { recursive: true });
3958
4221
  }
3959
4222
  function writeHookScripts() {
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");
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");
3967
4230
  writeFileSync7(bashScriptPath, CC_BASH_JUDGE_SCRIPT, "utf-8");
3968
4231
  writeFileSync7(bashFollowupScriptPath, CC_BASH_FOLLOWUP_SCRIPT, "utf-8");
3969
4232
  writeFileSync7(editCaptureScriptPath, CC_EDIT_CAPTURE_SCRIPT, "utf-8");
@@ -3997,11 +4260,11 @@ function shellQuoteSingle(value) {
3997
4260
  }
3998
4261
  function resolveSynkroBundle() {
3999
4262
  const scriptPath = process.argv[1];
4000
- if (scriptPath && existsSync9(scriptPath)) return scriptPath;
4263
+ if (scriptPath && existsSync11(scriptPath)) return scriptPath;
4001
4264
  return null;
4002
4265
  }
4003
4266
  function writeConfigEnv(opts) {
4004
- const credsPath = join9(SYNKRO_DIR2, "credentials.json");
4267
+ const credsPath = join11(SYNKRO_DIR2, "credentials.json");
4005
4268
  const safeGateway = sanitizeConfigValue(opts.gatewayUrl);
4006
4269
  const safeUserId = sanitizeConfigValue(opts.userId);
4007
4270
  const safeOrgId = sanitizeConfigValue(opts.orgId);
@@ -4017,7 +4280,7 @@ function writeConfigEnv(opts) {
4017
4280
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
4018
4281
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
4019
4282
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
4020
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.1")}`
4283
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.3")}`
4021
4284
  ];
4022
4285
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
4023
4286
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -4049,16 +4312,16 @@ function collectLocalMetadata() {
4049
4312
  meta.cc_version = execSync5("claude --version", { encoding: "utf-8", timeout: 5e3 }).trim().split("\n")[0];
4050
4313
  } catch {
4051
4314
  }
4052
- const claudeDir = join9(homedir8(), ".claude");
4315
+ const claudeDir = join11(homedir10(), ".claude");
4053
4316
  try {
4054
- const settings = JSON.parse(readFileSync7(join9(claudeDir, "settings.json"), "utf-8"));
4317
+ const settings = JSON.parse(readFileSync9(join11(claudeDir, "settings.json"), "utf-8"));
4055
4318
  const plugins = Object.keys(settings.enabledPlugins ?? {}).filter((k) => settings.enabledPlugins[k]);
4056
4319
  if (plugins.length) meta.enabled_plugins = plugins;
4057
4320
  if (settings.permissions?.defaultMode) meta.permissions_mode = settings.permissions.defaultMode;
4058
4321
  } catch {
4059
4322
  }
4060
4323
  try {
4061
- const mcpCache = JSON.parse(readFileSync7(join9(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
4324
+ const mcpCache = JSON.parse(readFileSync9(join11(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
4062
4325
  const mcpNames = Object.keys(mcpCache);
4063
4326
  if (mcpNames.length) meta.mcp_servers = mcpNames;
4064
4327
  } catch {
@@ -4070,10 +4333,10 @@ function collectLocalMetadata() {
4070
4333
  } catch {
4071
4334
  }
4072
4335
  try {
4073
- const sessionsDir = join9(claudeDir, "sessions");
4336
+ const sessionsDir = join11(claudeDir, "sessions");
4074
4337
  const files = readdirSync(sessionsDir).filter((f) => f.endsWith(".json")).slice(-5);
4075
4338
  for (const f of files) {
4076
- const s = JSON.parse(readFileSync7(join9(sessionsDir, f), "utf-8"));
4339
+ const s = JSON.parse(readFileSync9(join11(sessionsDir, f), "utf-8"));
4077
4340
  if (s.version) {
4078
4341
  meta.cc_version = meta.cc_version || s.version;
4079
4342
  break;
@@ -4129,19 +4392,19 @@ function assertGatewayAllowed(gatewayUrl) {
4129
4392
  }
4130
4393
  function isAlreadyInstalled() {
4131
4394
  const requiredScripts = [
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")
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")
4138
4401
  ];
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;
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;
4143
4406
  try {
4144
- const settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
4407
+ const settings = JSON.parse(readFileSync9(settingsPath, "utf-8"));
4145
4408
  const hooks = settings?.hooks;
4146
4409
  if (!hooks || typeof hooks !== "object") return false;
4147
4410
  const hasManaged = (kind) => Array.isArray(hooks[kind]) && hooks[kind].some((entry) => entry?.__synkro_managed__ === true);
@@ -4249,9 +4512,9 @@ async function installCommand(opts = {}) {
4249
4512
  console.log(` ${scripts.transcriptSyncScript}
4250
4513
  `);
4251
4514
  for (const mode of ["edit", "bash"]) {
4252
- const pidFile = join9(SYNKRO_DIR2, "daemon", mode, "daemon.pid");
4515
+ const pidFile = join11(SYNKRO_DIR2, "daemon", mode, "daemon.pid");
4253
4516
  try {
4254
- const pid = parseInt(readFileSync7(pidFile, "utf-8").trim(), 10);
4517
+ const pid = parseInt(readFileSync9(pidFile, "utf-8").trim(), 10);
4255
4518
  if (pid > 0) {
4256
4519
  process.kill(pid, "SIGTERM");
4257
4520
  console.log(`Stopped stale ${mode} grader daemon (pid ${pid})`);
@@ -4342,14 +4605,20 @@ async function installCommand(opts = {}) {
4342
4605
  try {
4343
4606
  assertClaudeInstalled();
4344
4607
  assertPueueInstalled();
4608
+ assertTmuxInstalled();
4345
4609
  const r = installLocalCC();
4346
4610
  console.log(`Installed local-CC channel plugin at ${r.pluginPath}`);
4347
4611
  const t = ensureRunning();
4348
- console.log(`Local-CC pueue task: id=${t.id} status=${t.status}
4612
+ console.log(`Local-CC pueue task: id=${t.id} status=${t.status}`);
4613
+ console.log("Waiting for channel...");
4614
+ const ready = await waitForChannelReady(CHANNEL_PORT, 6e4, CHANNEL_HOST);
4615
+ if (ready) console.log(` channel ready at ${CHANNEL_HOST}:${CHANNEL_PORT}
4616
+ `);
4617
+ else console.warn(` \u26A0 channel did not come up within 60s \u2014 check \`synkro local-cc logs\`
4349
4618
  `);
4350
4619
  } catch (err) {
4351
4620
  console.warn(` \u26A0 Local-CC setup skipped: ${err.message}`);
4352
- console.warn(" Set gradingProvider in your inference settings and re-run install.\n");
4621
+ console.warn(" Install pueue, tmux, and claude, then re-run install.\n");
4353
4622
  }
4354
4623
  }
4355
4624
  if (transcriptConsent) {
@@ -4398,17 +4667,17 @@ function detectGitRepo2() {
4398
4667
  function getClaudeProjectsFolder() {
4399
4668
  const cwd = process.cwd();
4400
4669
  const sanitized = "-" + cwd.replace(/\//g, "-");
4401
- const projectsDir = join9(homedir8(), ".claude", "projects", sanitized);
4402
- return existsSync9(projectsDir) ? projectsDir : null;
4670
+ const projectsDir = join11(homedir10(), ".claude", "projects", sanitized);
4671
+ return existsSync11(projectsDir) ? projectsDir : null;
4403
4672
  }
4404
4673
  function extractSessionInsights(projectsDir) {
4405
4674
  const insights = [];
4406
4675
  const files = readdirSync(projectsDir).filter((f) => f.endsWith(".jsonl"));
4407
4676
  for (const file of files) {
4408
4677
  const sessionId = file.replace(".jsonl", "");
4409
- const filePath = join9(projectsDir, file);
4678
+ const filePath = join11(projectsDir, file);
4410
4679
  try {
4411
- const content = readFileSync7(filePath, "utf-8");
4680
+ const content = readFileSync9(filePath, "utf-8");
4412
4681
  const lines = content.split("\n").filter(Boolean);
4413
4682
  for (let i = 0; i < lines.length; i++) {
4414
4683
  try {
@@ -4484,7 +4753,7 @@ function extractTextContent(content) {
4484
4753
  return "";
4485
4754
  }
4486
4755
  function parseTranscriptFile(filePath) {
4487
- const content = readFileSync7(filePath, "utf-8");
4756
+ const content = readFileSync9(filePath, "utf-8");
4488
4757
  const lines = content.split("\n").filter(Boolean);
4489
4758
  const messages = [];
4490
4759
  for (let i = 0; i < lines.length; i++) {
@@ -4535,7 +4804,7 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
4535
4804
  const sessions = [];
4536
4805
  for (const file of batch) {
4537
4806
  const sessionId = file.replace(".jsonl", "");
4538
- const filePath = join9(projectsDir, file);
4807
+ const filePath = join11(projectsDir, file);
4539
4808
  try {
4540
4809
  const allMessages = parseTranscriptFile(filePath);
4541
4810
  const messages = allMessages.length > maxMessagesPerSession ? allMessages.slice(-maxMessagesPerSession) : allMessages;
@@ -4564,11 +4833,11 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
4564
4833
  }
4565
4834
  for (const file of batch) {
4566
4835
  const sessionId = file.replace(".jsonl", "");
4567
- const filePath = join9(projectsDir, file);
4836
+ const filePath = join11(projectsDir, file);
4568
4837
  try {
4569
- const content = readFileSync7(filePath, "utf-8");
4838
+ const content = readFileSync9(filePath, "utf-8");
4570
4839
  const lineCount = content.split("\n").filter(Boolean).length;
4571
- writeFileSync7(join9(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
4840
+ writeFileSync7(join11(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
4572
4841
  } catch {
4573
4842
  }
4574
4843
  }
@@ -4590,11 +4859,12 @@ var init_install2 = __esm({
4590
4859
  init_promptFetcher();
4591
4860
  init_install();
4592
4861
  init_pueue();
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");
4862
+ 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");
4598
4868
  }
4599
4869
  });
4600
4870
 
@@ -4670,13 +4940,13 @@ var status_exports = {};
4670
4940
  __export(status_exports, {
4671
4941
  statusCommand: () => statusCommand
4672
4942
  });
4673
- import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
4674
- import { homedir as homedir9 } from "os";
4675
- import { join as join10 } from "path";
4943
+ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
4944
+ import { homedir as homedir11 } from "os";
4945
+ import { join as join12 } from "path";
4676
4946
  function readConfigEnv() {
4677
- if (!existsSync10(CONFIG_PATH3)) return {};
4947
+ if (!existsSync12(CONFIG_PATH3)) return {};
4678
4948
  const out = {};
4679
- const raw = readFileSync8(CONFIG_PATH3, "utf-8");
4949
+ const raw = readFileSync10(CONFIG_PATH3, "utf-8");
4680
4950
  for (const line of raw.split("\n")) {
4681
4951
  const trimmed = line.trim();
4682
4952
  if (!trimmed || trimmed.startsWith("#")) continue;
@@ -4749,19 +5019,19 @@ async function statusCommand() {
4749
5019
  }
4750
5020
  }
4751
5021
  console.log();
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");
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");
4758
5028
  console.log("Hook scripts:");
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}`);
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}`);
4765
5035
  console.log();
4766
5036
  const mcp = inspectMcpConfig();
4767
5037
  console.log("Guardrails MCP server (Claude Code):");
@@ -4781,8 +5051,8 @@ var init_status = __esm({
4781
5051
  init_agentDetect();
4782
5052
  init_ccHookConfig();
4783
5053
  init_mcpConfig();
4784
- SYNKRO_DIR3 = join10(homedir9(), ".synkro");
4785
- CONFIG_PATH3 = join10(SYNKRO_DIR3, "config.env");
5054
+ SYNKRO_DIR3 = join12(homedir11(), ".synkro");
5055
+ CONFIG_PATH3 = join12(SYNKRO_DIR3, "config.env");
4786
5056
  }
4787
5057
  });
4788
5058
 
@@ -4871,13 +5141,13 @@ var config_exports = {};
4871
5141
  __export(config_exports, {
4872
5142
  configCommand: () => configCommand
4873
5143
  });
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";
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";
4877
5147
  function readConfigEnv2() {
4878
- if (!existsSync11(CONFIG_PATH4)) return {};
5148
+ if (!existsSync13(CONFIG_PATH4)) return {};
4879
5149
  const out = {};
4880
- for (const line of readFileSync9(CONFIG_PATH4, "utf-8").split("\n")) {
5150
+ for (const line of readFileSync11(CONFIG_PATH4, "utf-8").split("\n")) {
4881
5151
  const t = line.trim();
4882
5152
  if (!t || t.startsWith("#")) continue;
4883
5153
  const eq = t.indexOf("=");
@@ -4886,11 +5156,11 @@ function readConfigEnv2() {
4886
5156
  return out;
4887
5157
  }
4888
5158
  function updateConfigValue(key, value) {
4889
- if (!existsSync11(CONFIG_PATH4)) {
5159
+ if (!existsSync13(CONFIG_PATH4)) {
4890
5160
  console.error("No config found. Run `synkro install` first.");
4891
5161
  process.exit(1);
4892
5162
  }
4893
- const lines = readFileSync9(CONFIG_PATH4, "utf-8").split("\n");
5163
+ const lines = readFileSync11(CONFIG_PATH4, "utf-8").split("\n");
4894
5164
  const pattern = new RegExp(`^${key}=`);
4895
5165
  let found = false;
4896
5166
  const updated = lines.map((line) => {
@@ -4957,8 +5227,8 @@ var init_config = __esm({
4957
5227
  "cli/commands/config.ts"() {
4958
5228
  "use strict";
4959
5229
  init_stub();
4960
- SYNKRO_DIR4 = join11(homedir10(), ".synkro");
4961
- CONFIG_PATH4 = join11(SYNKRO_DIR4, "config.env");
5230
+ SYNKRO_DIR4 = join13(homedir12(), ".synkro");
5231
+ CONFIG_PATH4 = join13(SYNKRO_DIR4, "config.env");
4962
5232
  }
4963
5233
  });
4964
5234
 
@@ -4968,8 +5238,8 @@ __export(scanPr_exports, {
4968
5238
  scanPrCommand: () => scanPrCommand
4969
5239
  });
4970
5240
  import { execSync as execSync6, spawn } from "child_process";
4971
- import { readFileSync as readFileSync10, existsSync as existsSync12 } from "fs";
4972
- import { join as join12 } from "path";
5241
+ import { readFileSync as readFileSync12, existsSync as existsSync14 } from "fs";
5242
+ import { join as join14 } from "path";
4973
5243
  function parseMatchSpec(condition) {
4974
5244
  if (!condition.startsWith("match_spec:")) return null;
4975
5245
  try {
@@ -5448,10 +5718,10 @@ function shouldFail(findings, threshold) {
5448
5718
  return findings.some((f) => order.indexOf(f.severity) >= thresholdIdx);
5449
5719
  }
5450
5720
  function readRepoDeps() {
5451
- const pkgPath = join12(process.cwd(), "package.json");
5452
- if (!existsSync12(pkgPath)) return {};
5721
+ const pkgPath = join14(process.cwd(), "package.json");
5722
+ if (!existsSync14(pkgPath)) return {};
5453
5723
  try {
5454
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
5724
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
5455
5725
  return { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
5456
5726
  } catch {
5457
5727
  return {};
@@ -5713,9 +5983,9 @@ var disconnect_exports = {};
5713
5983
  __export(disconnect_exports, {
5714
5984
  disconnectCommand: () => disconnectCommand
5715
5985
  });
5716
- import { existsSync as existsSync13, rmSync } from "fs";
5717
- import { homedir as homedir11 } from "os";
5718
- import { join as join13 } from "path";
5986
+ import { existsSync as existsSync15, rmSync } from "fs";
5987
+ import { homedir as homedir13 } from "os";
5988
+ import { join as join15 } from "path";
5719
5989
  function tearDownLocalCC() {
5720
5990
  let hadTask = false;
5721
5991
  try {
@@ -5745,13 +6015,13 @@ function disconnectCommand(args2 = []) {
5745
6015
  console.log(`${mcpRemoved ? "\u2713" : "\xB7"} MCP guardrails server: ${mcpRemoved ? "removed entry from ~/.claude.json" : "no Synkro MCP entry found"}`);
5746
6016
  }
5747
6017
  if (purge) {
5748
- if (existsSync13(SYNKRO_DIR5)) {
6018
+ if (existsSync15(SYNKRO_DIR5)) {
5749
6019
  rmSync(SYNKRO_DIR5, { recursive: true, force: true });
5750
6020
  console.log(`\u2713 Removed ${SYNKRO_DIR5}`);
5751
6021
  } else {
5752
6022
  console.log(`\xB7 ${SYNKRO_DIR5} already gone, nothing to remove`);
5753
6023
  }
5754
- } else if (existsSync13(SYNKRO_DIR5)) {
6024
+ } else if (existsSync15(SYNKRO_DIR5)) {
5755
6025
  console.log(`Config preserved at ${SYNKRO_DIR5}. Run with --purge to remove.`);
5756
6026
  }
5757
6027
  console.log("\nSynkro disconnected.");
@@ -5765,7 +6035,7 @@ var init_disconnect = __esm({
5765
6035
  init_mcpConfig();
5766
6036
  init_pueue();
5767
6037
  init_install();
5768
- SYNKRO_DIR5 = join13(homedir11(), ".synkro");
6038
+ SYNKRO_DIR5 = join15(homedir13(), ".synkro");
5769
6039
  }
5770
6040
  });
5771
6041
 
@@ -5806,141 +6076,14 @@ var init_reinstall = __esm({
5806
6076
  }
5807
6077
  });
5808
6078
 
5809
- // cli/local-cc/turnLog.ts
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";
5813
- function truncate(s, max = PREVIEW_MAX) {
5814
- if (s.length <= max) return s;
5815
- return s.slice(0, max) + "\u2026 [+" + (s.length - max) + " chars]";
5816
- }
5817
- function extractSeverity(result) {
5818
- const m = result.match(/<synkro-(?:verdict|intent)>([\s\S]*?)<\/synkro-(?:verdict|intent)>/);
5819
- if (!m) return void 0;
5820
- try {
5821
- const obj = JSON.parse(m[1]);
5822
- if (obj.severity) return String(obj.severity);
5823
- if (typeof obj.ok === "boolean") return obj.ok ? "ok" : "violations";
5824
- if (obj.type) return String(obj.type);
5825
- if (obj.verdict) return String(obj.verdict);
5826
- } catch {
5827
- }
5828
- return void 0;
5829
- }
5830
- function appendTurn(args2) {
5831
- try {
5832
- mkdirSync8(dirname5(TURN_LOG_PATH), { recursive: true });
5833
- const entry = {
5834
- ts: new Date(args2.startedAt).toISOString(),
5835
- role: args2.role,
5836
- duration_ms: Date.now() - args2.startedAt,
5837
- status: args2.status,
5838
- request_preview: truncate(args2.request),
5839
- response_preview: args2.result ? truncate(args2.result) : "",
5840
- severity: args2.result ? extractSeverity(args2.result) : void 0,
5841
- error: args2.error
5842
- };
5843
- appendFileSync(TURN_LOG_PATH, JSON.stringify(entry) + "\n", "utf-8");
5844
- } catch {
5845
- }
5846
- }
5847
- function readRecentTurns(n = 20) {
5848
- if (!existsSync14(TURN_LOG_PATH)) return [];
5849
- try {
5850
- const size = statSync(TURN_LOG_PATH).size;
5851
- if (size === 0) return [];
5852
- const text = readFileSync11(TURN_LOG_PATH, "utf-8");
5853
- const lines = text.split("\n").filter(Boolean);
5854
- const lastN = lines.slice(-n).reverse();
5855
- return lastN.map((line) => {
5856
- try {
5857
- return JSON.parse(line);
5858
- } catch {
5859
- return null;
5860
- }
5861
- }).filter((x) => x !== null);
5862
- } catch {
5863
- return [];
5864
- }
5865
- }
5866
- function followTurns(onEntry) {
5867
- try {
5868
- mkdirSync8(dirname5(TURN_LOG_PATH), { recursive: true });
5869
- if (!existsSync14(TURN_LOG_PATH)) {
5870
- appendFileSync(TURN_LOG_PATH, "", "utf-8");
5871
- }
5872
- } catch {
5873
- }
5874
- let lastSize = (() => {
5875
- try {
5876
- return statSync(TURN_LOG_PATH).size;
5877
- } catch {
5878
- return 0;
5879
- }
5880
- })();
5881
- let pendingPartial = "";
5882
- const drainNewBytes = (from, to) => {
5883
- if (to <= from) return;
5884
- let fd = null;
5885
- try {
5886
- fd = openSync2(TURN_LOG_PATH, "r");
5887
- const len = to - from;
5888
- const buf = Buffer.alloc(len);
5889
- readSync(fd, buf, 0, len, from);
5890
- const text = pendingPartial + buf.toString("utf-8");
5891
- const lastNewline = text.lastIndexOf("\n");
5892
- if (lastNewline === -1) {
5893
- pendingPartial = text;
5894
- return;
5895
- }
5896
- const complete = text.slice(0, lastNewline);
5897
- pendingPartial = text.slice(lastNewline + 1);
5898
- for (const line of complete.split("\n")) {
5899
- if (!line) continue;
5900
- try {
5901
- onEntry(JSON.parse(line));
5902
- } catch {
5903
- }
5904
- }
5905
- } catch {
5906
- } finally {
5907
- if (fd !== null) {
5908
- try {
5909
- closeSync2(fd);
5910
- } catch {
5911
- }
5912
- }
5913
- }
5914
- };
5915
- watchFile(TURN_LOG_PATH, { interval: 250 }, (curr, prev) => {
5916
- if (curr.size < lastSize) {
5917
- lastSize = 0;
5918
- pendingPartial = "";
5919
- }
5920
- if (curr.size > lastSize) {
5921
- drainNewBytes(lastSize, curr.size);
5922
- lastSize = curr.size;
5923
- }
5924
- });
5925
- return () => unwatchFile(TURN_LOG_PATH);
5926
- }
5927
- var TURN_LOG_PATH, PREVIEW_MAX;
5928
- var init_turnLog = __esm({
5929
- "cli/local-cc/turnLog.ts"() {
5930
- "use strict";
5931
- TURN_LOG_PATH = join14(homedir12(), ".synkro", "cc_sessions", "turns.log");
5932
- PREVIEW_MAX = 400;
5933
- }
5934
- });
5935
-
5936
6079
  // 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";
6080
+ import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
6081
+ import { homedir as homedir14 } from "os";
6082
+ import { join as join16 } from "path";
5940
6083
  function isLocalCCEnabled() {
5941
- if (!existsSync15(CONFIG_PATH5)) return false;
6084
+ if (!existsSync16(CONFIG_PATH5)) return false;
5942
6085
  try {
5943
- const content = readFileSync12(CONFIG_PATH5, "utf-8");
6086
+ const content = readFileSync13(CONFIG_PATH5, "utf-8");
5944
6087
  const match = content.match(/^SYNKRO_LOCAL_INFERENCE='([^']*)'/m);
5945
6088
  return match?.[1] === "yes";
5946
6089
  } catch {
@@ -5951,143 +6094,7 @@ var CONFIG_PATH5;
5951
6094
  var init_settings = __esm({
5952
6095
  "cli/local-cc/settings.ts"() {
5953
6096
  "use strict";
5954
- CONFIG_PATH5 = join15(homedir13(), ".synkro", "config.env");
5955
- }
5956
- });
5957
-
5958
- // cli/local-cc/prompts.ts
5959
- import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
5960
- import { homedir as homedir14 } from "os";
5961
- import { join as join16 } from "path";
5962
- function loadCachedPrompts() {
5963
- if (_cached) return _cached;
5964
- if (!existsSync16(CACHE_PATH2)) {
5965
- throw new Error("Prompts cache not found. Run `synkro install` or `synkro update` first.");
5966
- }
5967
- try {
5968
- _cached = JSON.parse(readFileSync13(CACHE_PATH2, "utf-8"));
5969
- return _cached;
5970
- } catch {
5971
- throw new Error("Prompts cache is corrupted. Run `synkro update` to refresh.");
5972
- }
5973
- }
5974
- function getPrimer(role) {
5975
- const cache = loadCachedPrompts();
5976
- const primer = role === "grade-edit" ? cache.grader_primer_edit : cache.grader_primer_bash;
5977
- if (!primer) {
5978
- throw new Error(`No cached primer for role "${role}". Run \`synkro update\` to refresh prompts.`);
5979
- }
5980
- return primer;
5981
- }
5982
- function buildChannelContent(role, payload) {
5983
- return `${getPrimer(role)}
5984
-
5985
- ---
5986
- PAYLOAD (the input to evaluate):
5987
-
5988
- ${payload}`;
5989
- }
5990
- var CACHE_PATH2, _cached;
5991
- var init_prompts = __esm({
5992
- "cli/local-cc/prompts.ts"() {
5993
- "use strict";
5994
- CACHE_PATH2 = join16(homedir14(), ".synkro", "prompts", "judge-prompts.json");
5995
- _cached = null;
5996
- }
5997
- });
5998
-
5999
- // cli/local-cc/client.ts
6000
- import { request as httpRequest } from "http";
6001
- import { connect as connect2 } from "net";
6002
- async function submitToChannel(role, payload, opts = {}) {
6003
- const content = buildChannelContent(role, payload);
6004
- const body = JSON.stringify({ role, content });
6005
- const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
6006
- const startedAt = Date.now();
6007
- try {
6008
- const result = await new Promise((resolve2, reject) => {
6009
- const req = httpRequest({
6010
- host: CHANNEL_HOST,
6011
- port: CHANNEL_PORT,
6012
- method: "POST",
6013
- path: "/submit",
6014
- headers: {
6015
- "Content-Type": "application/json",
6016
- "Content-Length": Buffer.byteLength(body)
6017
- },
6018
- timeout: timeoutMs
6019
- }, (res) => {
6020
- const chunks = [];
6021
- res.on("data", (c) => chunks.push(c));
6022
- res.on("end", () => {
6023
- const text = Buffer.concat(chunks).toString("utf-8");
6024
- if (res.statusCode !== 200) {
6025
- reject(new LocalCCError(`channel returned ${res.statusCode}: ${text.slice(0, 500)}`));
6026
- return;
6027
- }
6028
- try {
6029
- const parsed = JSON.parse(text);
6030
- if (parsed.error) {
6031
- reject(new LocalCCError(parsed.error));
6032
- return;
6033
- }
6034
- resolve2(String(parsed.result ?? ""));
6035
- } catch (err) {
6036
- reject(new LocalCCError(`malformed channel response: ${text.slice(0, 200)}`, err));
6037
- }
6038
- });
6039
- });
6040
- req.on("timeout", () => {
6041
- req.destroy(new LocalCCError(`channel request timed out after ${timeoutMs}ms`));
6042
- });
6043
- req.on("error", (err) => {
6044
- const msg = err.code === "ECONNREFUSED" ? `channel connection refused at ${CHANNEL_HOST}:${CHANNEL_PORT} (is the pueue task running?)` : `channel request failed: ${err.message}`;
6045
- reject(new LocalCCError(msg, err));
6046
- });
6047
- req.write(body);
6048
- req.end();
6049
- });
6050
- appendTurn({ startedAt, role, request: payload, result, status: "ok" });
6051
- return result;
6052
- } catch (err) {
6053
- const message = err.message ?? String(err);
6054
- const status = /timed out/i.test(message) ? "timeout" : "error";
6055
- appendTurn({ startedAt, role, request: payload, status, error: message });
6056
- throw err;
6057
- }
6058
- }
6059
- function isChannelAvailable(timeoutMs = 500) {
6060
- return new Promise((resolve2) => {
6061
- const sock = connect2(CHANNEL_PORT, CHANNEL_HOST);
6062
- const done = (ok) => {
6063
- try {
6064
- sock.destroy();
6065
- } catch {
6066
- }
6067
- resolve2(ok);
6068
- };
6069
- sock.once("connect", () => done(true));
6070
- sock.once("error", () => done(false));
6071
- sock.setTimeout(timeoutMs, () => done(false));
6072
- });
6073
- }
6074
- var CHANNEL_HOST, CHANNEL_PORT, DEFAULT_TIMEOUT_MS, LocalCCError;
6075
- var init_client = __esm({
6076
- "cli/local-cc/client.ts"() {
6077
- "use strict";
6078
- init_prompts();
6079
- init_turnLog();
6080
- CHANNEL_HOST = "127.0.0.1";
6081
- CHANNEL_PORT = parseInt(process.env.SYNKRO_CHANNEL_PORT || "8929", 10);
6082
- DEFAULT_TIMEOUT_MS = 9e4;
6083
- LocalCCError = class extends Error {
6084
- constructor(message, cause) {
6085
- super(message);
6086
- this.cause = cause;
6087
- this.name = "LocalCCError";
6088
- }
6089
- cause;
6090
- };
6097
+ CONFIG_PATH5 = join16(homedir14(), ".synkro", "config.env");
6091
6098
  }
6092
6099
  });
6093
6100