@synkro-sh/cli 1.4.50 → 1.4.52

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
@@ -4291,7 +4291,7 @@ log "Starting local-CC session..."
4291
4291
  log "claude version: $(claude --version 2>&1 | head -1)"
4292
4292
 
4293
4293
  # Kill any previous session so restarts come up clean.
4294
- tmux kill-session -t "$SESSION" 2>/dev/null || true
4294
+ tmux kill-session -t "=$SESSION" 2>/dev/null || true
4295
4295
 
4296
4296
  # Start claude inside a detached tmux session so it has a real pty.
4297
4297
  # Redirect stderr to the log so we can see why it dies.
@@ -4302,7 +4302,7 @@ tmux new-session -d -s "$SESSION" \\
4302
4302
  # prompt: option 1 = "I am using this for local development" (accept),
4303
4303
  # option 2 = "Exit". Auto-accept by sending '1' + Enter.
4304
4304
  sleep 3
4305
- if tmux has-session -t "$SESSION" 2>/dev/null; then
4305
+ if tmux has-session -t "=$SESSION" 2>/dev/null; then
4306
4306
  tmux send-keys -t "$SESSION" '1' 2>/dev/null || true
4307
4307
  sleep 1
4308
4308
  tmux send-keys -t "$SESSION" Enter 2>/dev/null || true
@@ -4322,7 +4322,7 @@ fi
4322
4322
  log "tmux session started successfully."
4323
4323
 
4324
4324
  # Block on the tmux session so pueue's task lifetime tracks claude's.
4325
- while tmux has-session -t "$SESSION" 2>/dev/null; do
4325
+ while tmux has-session -t "=$SESSION" 2>/dev/null; do
4326
4326
  sleep 5
4327
4327
  done
4328
4328
 
@@ -4355,13 +4355,13 @@ fi
4355
4355
  log "Starting local-CC channel 2 (port ${CHANNEL_2_PORT})..."
4356
4356
  log "claude version: $(claude --version 2>&1 | head -1)"
4357
4357
 
4358
- tmux kill-session -t "$SESSION" 2>/dev/null || true
4358
+ tmux kill-session -t "=$SESSION" 2>/dev/null || true
4359
4359
 
4360
4360
  tmux new-session -d -s "$SESSION" \\
4361
4361
  "SYNKRO_CHANNEL_PORT=${CHANNEL_2_PORT} claude --dangerously-load-development-channels server:synkro-local --dangerously-skip-permissions --setting-sources project,local --model claude-sonnet-4-6 2>>$LOG; echo 'claude exited with code '$'?' >> $LOG"
4362
4362
 
4363
4363
  sleep 3
4364
- if tmux has-session -t "$SESSION" 2>/dev/null; then
4364
+ if tmux has-session -t "=$SESSION" 2>/dev/null; then
4365
4365
  tmux send-keys -t "$SESSION" '1' 2>/dev/null || true
4366
4366
  sleep 1
4367
4367
  tmux send-keys -t "$SESSION" Enter 2>/dev/null || true
@@ -4378,7 +4378,7 @@ fi
4378
4378
 
4379
4379
  log "tmux session started successfully (port ${CHANNEL_2_PORT})."
4380
4380
 
4381
- while tmux has-session -t "$SESSION" 2>/dev/null; do
4381
+ while tmux has-session -t "=$SESSION" 2>/dev/null; do
4382
4382
  sleep 5
4383
4383
  done
4384
4384
 
@@ -4467,7 +4467,7 @@ function startTask(opts = {}) {
4467
4467
  let existing = findTask(ch);
4468
4468
  while (existing) {
4469
4469
  if (existing.status === "Running" || existing.status === "Queued") {
4470
- spawnSync2("tmux", ["kill-session", "-t", ch.tmuxSession], { encoding: "utf-8" });
4470
+ spawnSync2("tmux", ["kill-session", "-t", `=${ch.tmuxSession}`], { encoding: "utf-8" });
4471
4471
  spawnSync2("pueue", ["kill", String(existing.id)], { encoding: "utf-8" });
4472
4472
  for (let i = 0; i < 10; i++) {
4473
4473
  const check = findTask(ch);
@@ -4500,7 +4500,7 @@ function startTask(opts = {}) {
4500
4500
  return created;
4501
4501
  }
4502
4502
  function stopTask(channel = CHANNEL_PRIMARY) {
4503
- spawnSync2("tmux", ["kill-session", "-t", channel.tmuxSession], { encoding: "utf-8" });
4503
+ spawnSync2("tmux", ["kill-session", "-t", `=${channel.tmuxSession}`], { encoding: "utf-8" });
4504
4504
  let t = findTask(channel);
4505
4505
  while (t) {
4506
4506
  if (t.status === "Running" || t.status === "Queued") {
@@ -5049,7 +5049,7 @@ function writeConfigEnv(opts) {
5049
5049
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
5050
5050
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
5051
5051
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
5052
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.50")}`
5052
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.52")}`
5053
5053
  ];
5054
5054
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
5055
5055
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -5261,7 +5261,7 @@ async function installCommand(opts = {}) {
5261
5261
  if (token2) {
5262
5262
  const profile2 = await fetchUserProfile(gatewayUrl, token2);
5263
5263
  if (profile2.localInference && !isLocalCCEnabled()) {
5264
- console.log("Local inference enabled in your profile \u2014 setting up local-CC channel...");
5264
+ console.log("Local inference enabled \u2014 setting up local-CC channels...");
5265
5265
  try {
5266
5266
  assertClaudeInstalled();
5267
5267
  assertPueueInstalled();
@@ -5448,6 +5448,14 @@ async function installCommand(opts = {}) {
5448
5448
  } catch {
5449
5449
  }
5450
5450
  const profile = await fetchUserProfile(gatewayUrl, token);
5451
+ const priorLocalFlag = (() => {
5452
+ try {
5453
+ const content = readFileSync10(CONFIG_PATH3, "utf-8");
5454
+ return content.includes("SYNKRO_LOCAL_INFERENCE='yes'");
5455
+ } catch {
5456
+ return false;
5457
+ }
5458
+ })();
5451
5459
  const synkroBundle = resolveSynkroBundle();
5452
5460
  writeConfigEnv({ gatewayUrl, userId, orgId, email, tier: profile.tier, inference: profile.inference, synkroBin: synkroBundle, transcriptConsent, localInference: profile.localInference });
5453
5461
  console.log(`Wrote config to ${CONFIG_PATH3}`);
@@ -5488,15 +5496,7 @@ async function installCommand(opts = {}) {
5488
5496
  console.warn(` \u26A0 Some dependencies missing \u2014 \`synkro local-cc enable\` may not work until they're installed.`);
5489
5497
  }
5490
5498
  console.log();
5491
- const priorLocalFlag = (() => {
5492
- try {
5493
- const content = readFileSync10(CONFIG_PATH3, "utf-8");
5494
- return content.includes("SYNKRO_LOCAL_INFERENCE='yes'");
5495
- } catch {
5496
- return false;
5497
- }
5498
- })();
5499
- if (profile.localInference || priorLocalFlag && localCcDeps.length === 3) {
5499
+ if (profile.localInference && localCcDeps.length === 3) {
5500
5500
  try {
5501
5501
  stopTask();
5502
5502
  stopTask(CHANNEL_SECONDARY);
@@ -5909,7 +5909,8 @@ async function statusCommand() {
5909
5909
  const config = readConfigEnv();
5910
5910
  const gatewayUrl = (config.SYNKRO_GATEWAY_URL || "https://api.synkro.sh").replace(/^['"]|['"]$/g, "");
5911
5911
  let serverTier = config.SYNKRO_TIER || "(unset)";
5912
- let serverInference = config.SYNKRO_INFERENCE || "fast";
5912
+ let serverInference = config.SYNKRO_INFERENCE || "(unset)";
5913
+ let localInference = false;
5913
5914
  await ensureValidToken();
5914
5915
  const token = getAccessToken();
5915
5916
  if (token) {
@@ -5921,6 +5922,7 @@ async function statusCommand() {
5921
5922
  if (resp.ok) {
5922
5923
  const data = await resp.json();
5923
5924
  serverInference = data.fast_inference ? "fast" : "standard";
5925
+ localInference = !!data.local_inference;
5924
5926
  serverTier = data.plan_tier ?? data.tier ?? serverTier;
5925
5927
  }
5926
5928
  } catch {
@@ -5930,7 +5932,7 @@ async function statusCommand() {
5930
5932
  console.log(` gateway: ${gatewayUrl}`);
5931
5933
  console.log(` credentials: ${config.SYNKRO_CREDENTIALS_PATH ?? "(unset)"}`);
5932
5934
  console.log(` tier: ${serverTier}`);
5933
- const inferenceLabel = serverInference === "fast" ? "'fast' (server-side grading)" : "'standard' (local grading)";
5935
+ const inferenceLabel = localInference ? "'local' (grading via Claude Code channels)" : "'server' (grading via provider keys)";
5934
5936
  console.log(` inference: ${inferenceLabel}`);
5935
5937
  console.log(` version: ${config.SYNKRO_VERSION ?? "(unset)"}`);
5936
5938
  console.log();
@@ -5946,10 +5948,10 @@ async function statusCommand() {
5946
5948
  const hooks = inspectCCHooks(a.settingsPath);
5947
5949
  console.log(` hooks installed: ${hooks.installed ? "\u2713" : "\u2717"}`);
5948
5950
  if (hooks.installed) {
5949
- console.log(` \u2022 PreToolUse Bash: ${hooks.preToolUseBash ? "\u2713" : "\u2717"}`);
5950
- console.log(` \u2022 PostToolUse Edit: ${hooks.postToolUseEdit ? "\u2713" : "\u2717"}`);
5951
- console.log(` \u2022 SessionEnd summary: ${hooks.sessionEnd ? "\u2713" : "\u2717"}`);
5952
- console.log(` \u2022 SessionStart: ${hooks.sessionStart ? "\u2713" : "\u2717"}`);
5951
+ console.log(` \u2022 PreToolUse Bash: ${hooks.preToolUseBash ? "\u2713" : "\u2717"}`);
5952
+ console.log(` \u2022 PreToolUse Edit: ${hooks.postToolUseEdit ? "\u2713" : "\u2717"}`);
5953
+ console.log(` \u2022 SessionEnd summary: ${hooks.sessionEnd ? "\u2713" : "\u2717"}`);
5954
+ console.log(` \u2022 SessionStart: ${hooks.sessionStart ? "\u2713" : "\u2717"}`);
5953
5955
  }
5954
5956
  } else if (a.kind === "cursor") {
5955
5957
  const hooks = inspectCursorHooks(a.settingsPath);
@@ -5964,30 +5966,57 @@ async function statusCommand() {
5964
5966
  }
5965
5967
  }
5966
5968
  console.log();
5967
- const bashScript = join12(SYNKRO_DIR3, "hooks", "cc-bash-judge.sh");
5968
- const bashFollowupScript = join12(SYNKRO_DIR3, "hooks", "cc-bash-followup.sh");
5969
- const editPrecheckScript = join12(SYNKRO_DIR3, "hooks", "cc-edit-precheck.sh");
5970
- const editCaptureScript = join12(SYNKRO_DIR3, "hooks", "cc-edit-capture.sh");
5971
- const stopSummaryScript = join12(SYNKRO_DIR3, "hooks", "cc-stop-summary.sh");
5972
- const sessionStartScript = join12(SYNKRO_DIR3, "hooks", "cc-session-start.sh");
5973
- const cursorBashJudgeScript = join12(SYNKRO_DIR3, "hooks", "cursor-bash-judge.sh");
5974
- const cursorEditPrecheckScript = join12(SYNKRO_DIR3, "hooks", "cursor-edit-precheck.sh");
5975
- const cursorEditCaptureScript = join12(SYNKRO_DIR3, "hooks", "cursor-edit-capture.sh");
5976
- const cursorBashFollowupScript = join12(SYNKRO_DIR3, "hooks", "cursor-bash-followup.sh");
5977
- const commonScript = join12(SYNKRO_DIR3, "hooks", "_synkro-common.sh");
5978
- console.log("Hook scripts:");
5979
- console.log(` ${existsSync12(bashScript) ? "\u2713" : "\u2717"} ${bashScript}`);
5980
- console.log(` ${existsSync12(bashFollowupScript) ? "\u2713" : "\u2717"} ${bashFollowupScript}`);
5981
- console.log(` ${existsSync12(editPrecheckScript) ? "\u2713" : "\u2717"} ${editPrecheckScript}`);
5982
- console.log(` ${existsSync12(editCaptureScript) ? "\u2713" : "\u2717"} ${editCaptureScript}`);
5983
- console.log(` ${existsSync12(stopSummaryScript) ? "\u2713" : "\u2717"} ${stopSummaryScript}`);
5984
- console.log(` ${existsSync12(sessionStartScript) ? "\u2713" : "\u2717"} ${sessionStartScript}`);
5985
- console.log(` ${existsSync12(commonScript) ? "\u2713" : "\u2717"} ${commonScript}`);
5986
- console.log(` ${existsSync12(cursorBashJudgeScript) ? "\u2713" : "\u2717"} ${cursorBashJudgeScript}`);
5987
- console.log(` ${existsSync12(cursorEditPrecheckScript) ? "\u2713" : "\u2717"} ${cursorEditPrecheckScript}`);
5988
- console.log(` ${existsSync12(cursorEditCaptureScript) ? "\u2713" : "\u2717"} ${cursorEditCaptureScript}`);
5989
- console.log(` ${existsSync12(cursorBashFollowupScript) ? "\u2713" : "\u2717"} ${cursorBashFollowupScript}`);
5969
+ const HOOKS_DIR2 = join12(SYNKRO_DIR3, "hooks");
5970
+ const ccHooks = [
5971
+ "cc-bash-judge.ts",
5972
+ "cc-bash-followup.ts",
5973
+ "cc-edit-precheck.ts",
5974
+ "cc-cwe-precheck.ts",
5975
+ "cc-cve-precheck.ts",
5976
+ "cc-plan-judge.ts",
5977
+ "cc-stop-summary.ts",
5978
+ "cc-session-start.ts",
5979
+ "cc-transcript-sync.ts",
5980
+ "cc-user-prompt-submit.ts",
5981
+ "_synkro-common.ts"
5982
+ ];
5983
+ const cursorHooks = [
5984
+ "cursor-bash-judge.sh",
5985
+ "cursor-edit-precheck.sh",
5986
+ "cursor-bash-followup.sh",
5987
+ "_synkro-common.sh"
5988
+ ];
5989
+ console.log("Hook scripts (Claude Code):");
5990
+ for (const f of ccHooks) {
5991
+ const p = join12(HOOKS_DIR2, f);
5992
+ console.log(` ${existsSync12(p) ? "\u2713" : "\u2717"} ${p}`);
5993
+ }
5994
+ console.log("Hook scripts (Cursor):");
5995
+ for (const f of cursorHooks) {
5996
+ const p = join12(HOOKS_DIR2, f);
5997
+ console.log(` ${existsSync12(p) ? "\u2713" : "\u2717"} ${p}`);
5998
+ }
5990
5999
  console.log();
6000
+ if (localInference) {
6001
+ console.log("Local-CC channels:");
6002
+ try {
6003
+ const t1 = findTask(CHANNEL_PRIMARY);
6004
+ if (t1) {
6005
+ console.log(` Channel 1 (org rules): pueue id=${t1.id} status=${t1.status}`);
6006
+ } else {
6007
+ console.log(" Channel 1 (org rules): not running");
6008
+ }
6009
+ const t2 = findTask(CHANNEL_SECONDARY);
6010
+ if (t2) {
6011
+ console.log(` Channel 2 (CWE scan): pueue id=${t2.id} status=${t2.status}`);
6012
+ } else {
6013
+ console.log(" Channel 2 (CWE scan): not running");
6014
+ }
6015
+ } catch {
6016
+ console.log(" (pueue not available)");
6017
+ }
6018
+ console.log();
6019
+ }
5991
6020
  const mcp = inspectMcpConfig();
5992
6021
  console.log("Guardrails MCP server (Claude Code):");
5993
6022
  if (mcp.installed) {
@@ -6007,6 +6036,7 @@ var init_status = __esm({
6007
6036
  init_ccHookConfig();
6008
6037
  init_cursorHookConfig();
6009
6038
  init_mcpConfig();
6039
+ init_pueue();
6010
6040
  SYNKRO_DIR3 = join12(homedir11(), ".synkro");
6011
6041
  CONFIG_PATH4 = join12(SYNKRO_DIR3, "config.env");
6012
6042
  }
@@ -6945,11 +6975,14 @@ import { join as join15 } from "path";
6945
6975
  function tearDownLocalCC() {
6946
6976
  let hadTask = false;
6947
6977
  try {
6948
- hadTask = !!findTask();
6978
+ const t1 = findTask();
6979
+ const t2 = findTask(CHANNEL_SECONDARY);
6980
+ hadTask = !!(t1 || t2);
6949
6981
  stopTask();
6982
+ stopTask(CHANNEL_SECONDARY);
6950
6983
  } catch {
6951
6984
  }
6952
- console.log(`${hadTask ? "\u2713" : "\xB7"} local-cc runtime: ${hadTask ? "stopped pueue task + tmux session" : "no live task"}`);
6985
+ console.log(`${hadTask ? "\u2713" : "\xB7"} local-cc runtime: ${hadTask ? "stopped both channels" : "no live tasks"}`);
6953
6986
  uninstallLocalCC();
6954
6987
  console.log("\u2713 local-cc config: cleaned ~/.claude.json entries");
6955
6988
  }
@@ -7185,7 +7218,7 @@ async function cmdStatus() {
7185
7218
  }
7186
7219
  const ch1Up = await isChannelAvailable();
7187
7220
  console.log(`Channel 1 ${CHANNEL_HOST}:${CHANNEL_PORT}: ${ch1Up ? "reachable" : "unreachable"}`);
7188
- const tmux1 = spawnSync4("tmux", ["has-session", "-t", TMUX_SESSION_NAME], { encoding: "utf-8" });
7221
+ const tmux1 = spawnSync4("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME}`], { encoding: "utf-8" });
7189
7222
  console.log(`tmux '${TMUX_SESSION_NAME}': ${tmux1.status === 0 ? "live" : "absent"}`);
7190
7223
  const t2 = findTask(CHANNEL_SECONDARY);
7191
7224
  if (!t2) {
@@ -7195,7 +7228,7 @@ async function cmdStatus() {
7195
7228
  }
7196
7229
  const ch2Up = await isChannelAvailable(CHANNEL_2_PORT);
7197
7230
  console.log(`Channel 2 ${CHANNEL_HOST}:${CHANNEL_2_PORT}: ${ch2Up ? "reachable" : "unreachable"}`);
7198
- const tmux2 = spawnSync4("tmux", ["has-session", "-t", TMUX_SESSION_NAME_2], { encoding: "utf-8" });
7231
+ const tmux2 = spawnSync4("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME_2}`], { encoding: "utf-8" });
7199
7232
  console.log(`tmux '${TMUX_SESSION_NAME_2}': ${tmux2.status === 0 ? "live" : "absent"}`);
7200
7233
  }
7201
7234
  async function cmdEnable() {
@@ -7387,7 +7420,7 @@ function cmdLogs(rest) {
7387
7420
  function cmdAttach(rest) {
7388
7421
  assertTmuxInstalled();
7389
7422
  const readonly = rest.some((a) => a === "--readonly" || a === "-r");
7390
- const has = spawnSync4("tmux", ["has-session", "-t", TMUX_SESSION_NAME], { encoding: "utf-8" });
7423
+ const has = spawnSync4("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME}`], { encoding: "utf-8" });
7391
7424
  if (has.status !== 0) {
7392
7425
  console.error(`No tmux session '${TMUX_SESSION_NAME}' running. Start it with: synkro local-cc start`);
7393
7426
  process.exit(1);