@synkro-sh/cli 1.6.6 → 1.6.8

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
@@ -3162,6 +3162,8 @@ async function main() {
3162
3162
  command: command.slice(0, 200),
3163
3163
  session_id: sessionId,
3164
3164
  repo: cwd,
3165
+ cc_model: transcript.ccModel,
3166
+ reasoning: 'Safe in-repo read — auto-allowed without an LLM grade.',
3165
3167
  });
3166
3168
  outputJson({
3167
3169
  systemMessage: tagStr + ' bashGuard → pass: safe in-repo read',
@@ -4294,6 +4296,8 @@ async function main() {
4294
4296
  capture_type: 'local_verdict', verdict: 'pass', hook_type: 'bash',
4295
4297
  category: 'safe_read', tool_name: toolName, command: command.slice(0, 200),
4296
4298
  session_id: sessionId, repo: cwd,
4299
+ cc_model: model,
4300
+ reasoning: 'Safe in-repo read \u2014 auto-allowed without an LLM grade.',
4297
4301
  });
4298
4302
  finishAllow();
4299
4303
  }
@@ -5858,6 +5862,7 @@ __export(dockerInstall_exports, {
5858
5862
  dockerStop: () => dockerStop,
5859
5863
  dockerUpdate: () => dockerUpdate,
5860
5864
  imageTag: () => imageTag,
5865
+ readContainerConfig: () => readContainerConfig,
5861
5866
  resolveWorkerConfig: () => resolveWorkerConfig,
5862
5867
  splitWorkers: () => splitWorkers,
5863
5868
  waitForContainerReady: () => waitForContainerReady
@@ -6091,6 +6096,34 @@ function dockerStatus() {
6091
6096
  healthz: `http://127.0.0.1:${HOST_MCP_PORT}/`
6092
6097
  };
6093
6098
  }
6099
+ function readContainerConfig() {
6100
+ const r = spawnSync2("docker", ["inspect", "--format", "{{json .Config.Env}}", CONTAINER_NAME], {
6101
+ encoding: "utf-8",
6102
+ timeout: 5e3
6103
+ });
6104
+ if (r.status !== 0 || !r.stdout) return null;
6105
+ let env;
6106
+ try {
6107
+ env = JSON.parse(r.stdout.trim());
6108
+ } catch {
6109
+ return null;
6110
+ }
6111
+ if (!Array.isArray(env)) return null;
6112
+ const get = (k) => {
6113
+ const hit = env.find((e) => typeof e === "string" && e.startsWith(k + "="));
6114
+ return hit ? hit.slice(k.length + 1) : void 0;
6115
+ };
6116
+ const num = (s) => {
6117
+ if (s === void 0) return void 0;
6118
+ const n = parseInt(s, 10);
6119
+ return Number.isFinite(n) ? n : void 0;
6120
+ };
6121
+ return {
6122
+ claudeWorkers: num(get("CLAUDE_WORKERS")),
6123
+ cursorWorkers: num(get("CURSOR_WORKERS")),
6124
+ connectedRepo: get("SYNKRO_CONNECTED_REPO") || void 0
6125
+ };
6126
+ }
6094
6127
  async function dockerSafeStop() {
6095
6128
  const status = dockerStatus();
6096
6129
  if (!status.running) {
@@ -6417,7 +6450,7 @@ function writeConfigEnv(opts) {
6417
6450
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
6418
6451
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
6419
6452
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
6420
- `SYNKRO_VERSION=${shellQuoteSingle("1.6.6")}`
6453
+ `SYNKRO_VERSION=${shellQuoteSingle("1.6.8")}`
6421
6454
  ];
6422
6455
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
6423
6456
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -7540,22 +7573,22 @@ import { existsSync as existsSync11, rmSync, readdirSync as readdirSync3 } from
7540
7573
  import { homedir as homedir10 } from "os";
7541
7574
  import { join as join10 } from "path";
7542
7575
  import { spawnSync as spawnSync4 } from "child_process";
7543
- async function tearDownLocalCC(purge) {
7576
+ import { createInterface as createInterface4 } from "readline";
7577
+ async function tearDownLocalCC() {
7544
7578
  const docker = dockerStatus();
7545
7579
  if (docker.running) {
7546
7580
  await dockerSafeStop();
7547
- console.log("\u2713 stopped synkro-server container (data snapshot saved)");
7581
+ console.log("\u2713 stopped synkro-server container");
7548
7582
  } else {
7549
7583
  console.log("\xB7 no synkro-server container running");
7550
7584
  }
7551
7585
  dockerRemove();
7552
- if (purge) {
7553
- try {
7554
- const image = imageTag();
7555
- spawnSync4("docker", ["rmi", image], { encoding: "utf-8", timeout: 3e4 });
7556
- console.log(`\u2713 removed Docker image ${image}`);
7557
- } catch {
7558
- }
7586
+ console.log("\u2713 removed synkro-server container");
7587
+ try {
7588
+ const image = imageTag();
7589
+ const r = spawnSync4("docker", ["rmi", "-f", image], { encoding: "utf-8", timeout: 3e4 });
7590
+ console.log(r.status === 0 ? `\u2713 removed Docker image ${image}` : "\xB7 no Docker image to remove");
7591
+ } catch {
7559
7592
  }
7560
7593
  if (needsKeychainBridge()) {
7561
7594
  try {
@@ -7567,10 +7600,31 @@ async function tearDownLocalCC(purge) {
7567
7600
  uninstallLocalCC();
7568
7601
  console.log("\u2713 cleaned ~/.claude.json entries");
7569
7602
  }
7603
+ function confirmPurge() {
7604
+ console.log("\u26A0 WARNING \u2014 synkro uninstall --purge");
7605
+ console.log(" This permanently deletes ALL Synkro data on this machine,");
7606
+ console.log(" including every scan finding, telemetry record, and backup in");
7607
+ console.log(" ~/.synkro/pgdata and ~/.synkro/pgdata-backups. It cannot be undone.\n");
7608
+ if (!process.stdin.isTTY) {
7609
+ console.log(" Non-interactive shell \u2014 re-run in a terminal to confirm.");
7610
+ return Promise.resolve(false);
7611
+ }
7612
+ const rl = createInterface4({ input: process.stdin, output: process.stdout });
7613
+ return new Promise((resolve3) => {
7614
+ rl.question(" Type 'yes' to wipe everything (anything else cancels): ", (answer) => {
7615
+ rl.close();
7616
+ resolve3(answer.trim().toLowerCase() === "yes");
7617
+ });
7618
+ });
7619
+ }
7570
7620
  async function disconnectCommand(args2 = []) {
7571
7621
  const purge = args2.includes("--purge");
7572
- console.log("Synkro disconnect starting...\n");
7573
- await tearDownLocalCC(purge);
7622
+ if (purge && !await confirmPurge()) {
7623
+ console.log("\nAborted \u2014 nothing was removed.");
7624
+ return;
7625
+ }
7626
+ console.log("\nSynkro uninstall starting...\n");
7627
+ await tearDownLocalCC();
7574
7628
  const agents = detectAgents();
7575
7629
  let sawClaudeCode = false;
7576
7630
  for (const agent of agents) {
@@ -7591,31 +7645,32 @@ async function disconnectCommand(args2 = []) {
7591
7645
  const cursorMcpRemoved = uninstallCursorMcpConfig();
7592
7646
  console.log(`${cursorMcpRemoved ? "\u2713" : "\xB7"} MCP guardrails (Cursor): ${cursorMcpRemoved ? "removed from ~/.cursor/mcp.json" : "no entry found"}`);
7593
7647
  }
7594
- if (purge) {
7595
- if (existsSync11(SYNKRO_DIR5)) {
7596
- const pgdataPath = join10(SYNKRO_DIR5, "pgdata");
7597
- const backupsPath = join10(SYNKRO_DIR5, "pgdata-backups");
7648
+ if (existsSync11(SYNKRO_DIR5)) {
7649
+ if (purge) {
7650
+ rmSync(SYNKRO_DIR5, { recursive: true, force: true });
7651
+ console.log(`\u2713 wiped ${SYNKRO_DIR5} entirely \u2014 including all scan data and backups`);
7652
+ } else {
7653
+ const keep = /* @__PURE__ */ new Set([join10(SYNKRO_DIR5, "pgdata"), join10(SYNKRO_DIR5, "pgdata-backups")]);
7598
7654
  const preserved = [];
7599
7655
  for (const entry of readdirSync3(SYNKRO_DIR5)) {
7600
7656
  const full = join10(SYNKRO_DIR5, entry);
7601
- if (full === pgdataPath || full === backupsPath) {
7657
+ if (keep.has(full)) {
7602
7658
  preserved.push(entry);
7603
7659
  continue;
7604
7660
  }
7605
7661
  rmSync(full, { recursive: true, force: true });
7606
7662
  }
7607
7663
  if (preserved.length > 0) {
7608
- console.log(`\u2713 Removed ${SYNKRO_DIR5} config (preserved: ${preserved.join(", ")} \u2014 your data is safe)`);
7664
+ console.log(`\u2713 removed Synkro config from ${SYNKRO_DIR5} (kept your scan data: ${preserved.join(", ")})`);
7665
+ console.log(" run `synkro uninstall --purge` to delete that too");
7609
7666
  } else {
7610
- console.log(`\u2713 Removed ${SYNKRO_DIR5}`);
7667
+ console.log(`\u2713 removed ${SYNKRO_DIR5}`);
7611
7668
  }
7612
- } else {
7613
- console.log(`\xB7 ${SYNKRO_DIR5} already gone, nothing to remove`);
7614
7669
  }
7615
- } else if (existsSync11(SYNKRO_DIR5)) {
7616
- console.log(`Config preserved at ${SYNKRO_DIR5}. Run with --purge to remove.`);
7670
+ } else {
7671
+ console.log(`\xB7 ${SYNKRO_DIR5} already gone`);
7617
7672
  }
7618
- console.log("\nSynkro disconnected.");
7673
+ console.log(purge ? "\nSynkro fully removed \u2014 this machine is clean, as if it was never installed." : "\nSynkro uninstalled. Your scan data is preserved.");
7619
7674
  }
7620
7675
  var SYNKRO_DIR5;
7621
7676
  var init_disconnect = __esm({
@@ -7812,7 +7867,8 @@ var lifecycle_exports = {};
7812
7867
  __export(lifecycle_exports, {
7813
7868
  restartCommand: () => restartCommand,
7814
7869
  startCommand: () => startCommand,
7815
- stopCommand: () => stopCommand
7870
+ stopCommand: () => stopCommand,
7871
+ updateCommand: () => updateCommand
7816
7872
  });
7817
7873
  async function stopCommand() {
7818
7874
  assertDockerAvailable();
@@ -7848,6 +7904,26 @@ Start failed: ${result.error}`);
7848
7904
  }
7849
7905
  console.log("\nServer is running.");
7850
7906
  }
7907
+ async function updateCommand() {
7908
+ assertDockerAvailable();
7909
+ const cfg = readContainerConfig();
7910
+ if (!cfg) {
7911
+ console.error("No synkro-server container found. Run `synkro install` first.");
7912
+ process.exit(1);
7913
+ }
7914
+ const claudeWorkers = cfg.claudeWorkers ?? 8;
7915
+ const cursorWorkers = cfg.cursorWorkers ?? 0;
7916
+ console.log("Synkro: updating to the latest container image");
7917
+ console.log(` preserving pool: ${claudeWorkers} claude + ${cursorWorkers} cursor worker(s)
7918
+ `);
7919
+ await dockerUpdate({ claudeWorkers, cursorWorkers, connectedRepo: cfg.connectedRepo });
7920
+ const ready = await waitForContainerReady(9e4);
7921
+ if (!ready) {
7922
+ console.error("\n\u26A0 container did not pass its health check within 90s \u2014 check: docker logs synkro-server");
7923
+ process.exit(1);
7924
+ }
7925
+ console.log("\nSynkro updated \u2014 now running the latest version.");
7926
+ }
7851
7927
  async function restartCommand(rest = []) {
7852
7928
  assertDockerAvailable();
7853
7929
  const cfg = resolveWorkerConfig(rest);
@@ -7904,7 +7980,7 @@ var args = process.argv.slice(2);
7904
7980
  var cmd = args[0] || "";
7905
7981
  var subArgs = args.slice(1);
7906
7982
  function printVersion() {
7907
- console.log("1.6.6");
7983
+ console.log("1.6.8");
7908
7984
  }
7909
7985
  function printHelp() {
7910
7986
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
@@ -7914,10 +7990,11 @@ Usage:
7914
7990
 
7915
7991
  Commands:
7916
7992
  install [--force] Install or update Synkro
7917
- uninstall [--purge] Remove Synkro hooks (--purge also removes ~/.synkro)
7993
+ uninstall [--purge] Remove Synkro (keeps scan data; --purge wipes that too)
7918
7994
  stop Gracefully stop the server (snapshot + checkpoint)
7919
7995
  start [opts] Start the server (with pgdata integrity check)
7920
7996
  restart [opts] Safe restart (stop \u2192 start, data preserved)
7997
+ update Pull the latest container image and safely restart
7921
7998
  version Show version
7922
7999
 
7923
8000
  start/restart opts (recreate the worker pool):
@@ -7976,6 +8053,11 @@ async function main() {
7976
8053
  await restartCommand2(args.slice(1));
7977
8054
  break;
7978
8055
  }
8056
+ case "update": {
8057
+ const { updateCommand: updateCommand2 } = await Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports));
8058
+ await updateCommand2();
8059
+ break;
8060
+ }
7979
8061
  default: {
7980
8062
  console.error(`Unknown command: ${cmd}`);
7981
8063
  printHelp();