@synkro-sh/cli 1.5.0 → 1.5.2

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
@@ -51,18 +51,6 @@ function detectAgents() {
51
51
  version: claudeBinary ? getVersion("claude") : void 0
52
52
  });
53
53
  }
54
- const codexBinary = which("codex");
55
- const codexConfigDir = join(home, ".codex");
56
- if (codexBinary || existsSync(codexConfigDir)) {
57
- agents.push({
58
- kind: "codex",
59
- name: "Codex",
60
- binaryPath: codexBinary,
61
- configDir: codexConfigDir,
62
- settingsPath: join(codexConfigDir, "config.toml"),
63
- version: codexBinary ? getVersion("codex") : void 0
64
- });
65
- }
66
54
  const cursorBinary = which("cursor");
67
55
  const cursorConfigDir = join(home, ".cursor");
68
56
  if (cursorBinary || existsSync(cursorConfigDir)) {
@@ -5645,6 +5633,30 @@ function parseArgs(argv) {
5645
5633
  }
5646
5634
  return opts;
5647
5635
  }
5636
+ async function promptAgentSelection(detected) {
5637
+ if (detected.length <= 1) return detected;
5638
+ console.log("Multiple coding agents detected. Which ones do you want Synkro guardrails installed for?");
5639
+ detected.forEach((a, i) => console.log(` ${i + 1}. ${a.name}`));
5640
+ console.log(` ${detected.length + 1}. Both / all (default)`);
5641
+ const rl = createInterface3({ input: process.stdin, output: process.stdout });
5642
+ const ask2 = () => new Promise((resolve3) => {
5643
+ rl.question(`Pick [1-${detected.length + 1}] (default: all): `, (answer) => {
5644
+ const t = answer.trim().toLowerCase();
5645
+ if (t === "" || t === String(detected.length + 1) || t === "both" || t === "all") {
5646
+ rl.close();
5647
+ return resolve3(detected);
5648
+ }
5649
+ const n = parseInt(t, 10);
5650
+ if (Number.isInteger(n) && n >= 1 && n <= detected.length) {
5651
+ rl.close();
5652
+ return resolve3([detected[n - 1]]);
5653
+ }
5654
+ console.log("Invalid choice. Try again.");
5655
+ resolve3(ask2());
5656
+ });
5657
+ });
5658
+ return ask2();
5659
+ }
5648
5660
  function ensureSynkroDir() {
5649
5661
  mkdirSync8(SYNKRO_DIR4, { recursive: true });
5650
5662
  mkdirSync8(HOOKS_DIR, { recursive: true });
@@ -5746,7 +5758,7 @@ function writeConfigEnv(opts) {
5746
5758
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
5747
5759
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
5748
5760
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
5749
- `SYNKRO_VERSION=${shellQuoteSingle("1.5.0")}`
5761
+ `SYNKRO_VERSION=${shellQuoteSingle("1.5.2")}`
5750
5762
  ];
5751
5763
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
5752
5764
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
@@ -5872,34 +5884,6 @@ function assertGatewayAllowed(gatewayUrl) {
5872
5884
  throw new Error(`Gateway host not in allowlist (synkro.sh or *.synkro.sh): ${host}`);
5873
5885
  }
5874
5886
  }
5875
- function isAlreadyInstalled() {
5876
- const requiredScripts = [
5877
- join8(HOOKS_DIR, "cc-bash-judge.ts"),
5878
- join8(HOOKS_DIR, "cc-bash-followup.ts"),
5879
- join8(HOOKS_DIR, "cc-edit-precheck.ts"),
5880
- join8(HOOKS_DIR, "cc-cve-precheck.ts"),
5881
- join8(HOOKS_DIR, "cc-plan-judge.ts"),
5882
- join8(HOOKS_DIR, "cc-stop-summary.ts"),
5883
- join8(HOOKS_DIR, "cc-session-start.ts")
5884
- ];
5885
- if (!requiredScripts.every((p) => existsSync9(p))) return false;
5886
- if (!existsSync9(CONFIG_PATH2)) return false;
5887
- const settingsPath = join8(homedir8(), ".claude", "settings.json");
5888
- if (!existsSync9(settingsPath)) return false;
5889
- try {
5890
- const settings = JSON.parse(readFileSync7(settingsPath, "utf-8"));
5891
- const hooks = settings?.hooks;
5892
- if (!hooks || typeof hooks !== "object") return false;
5893
- const hasManaged = (kind) => Array.isArray(hooks[kind]) && hooks[kind].some((entry) => entry?.__synkro_managed__ === true);
5894
- if (!hasManaged("PreToolUse")) return false;
5895
- if (!hasManaged("PostToolUse")) return false;
5896
- if (!hasManaged("SessionEnd")) return false;
5897
- if (!hasManaged("SessionStart")) return false;
5898
- } catch {
5899
- return false;
5900
- }
5901
- return true;
5902
- }
5903
5887
  async function installCommand(opts = {}) {
5904
5888
  const gatewayUrl = opts.gatewayUrl || sanitizeGatewayCandidate(process.env.SYNKRO_GATEWAY_URL) || "https://api.synkro.sh";
5905
5889
  try {
@@ -5908,29 +5892,6 @@ async function installCommand(opts = {}) {
5908
5892
  console.error(err.message);
5909
5893
  process.exit(1);
5910
5894
  }
5911
- if (!opts.force && isAuthenticated() && isAlreadyInstalled()) {
5912
- setApiBaseUrl(`${gatewayUrl}/api`);
5913
- await ensureValidToken();
5914
- const currentRepo = detectGitRepo2();
5915
- if (currentRepo) {
5916
- try {
5917
- const projects = await listProjects();
5918
- const alreadyLinked = projects.some(
5919
- (p) => p.repos?.some((r) => r.full_name === currentRepo)
5920
- );
5921
- if (!alreadyLinked) {
5922
- console.log(`Synkro is installed. This repo (${currentRepo}) is not linked yet.
5923
- `);
5924
- await promptRepoConnection();
5925
- return;
5926
- }
5927
- } catch {
5928
- }
5929
- }
5930
- console.log("\u2713 Synkro is already installed and configured.");
5931
- console.log(" Run `synkro install --force` to reinstall from scratch.");
5932
- return;
5933
- }
5934
5895
  console.log("Synkro install starting...\n");
5935
5896
  if (!isAuthenticated()) {
5936
5897
  console.log("Opening browser for Synkro auth...");
@@ -5989,16 +5950,21 @@ async function installCommand(opts = {}) {
5989
5950
  }
5990
5951
  setApiBaseUrl(`${gatewayUrl}/api`);
5991
5952
  await promptRepoConnection({ linkRepo: opts.linkRepo });
5992
- const agents = detectAgents();
5993
- if (agents.length === 0) {
5994
- console.error("No AI coding agents detected. Install Claude Code first: https://docs.claude.com/claude-code");
5953
+ const detected = detectAgents();
5954
+ if (detected.length === 0) {
5955
+ console.error("No supported coding agents detected. Install Claude Code or Cursor first.");
5995
5956
  process.exit(1);
5996
5957
  }
5997
5958
  console.log("Detected agents:");
5998
- for (const a of agents) {
5959
+ for (const a of detected) {
5999
5960
  console.log(` \u2713 ${a.name}${a.version ? ` (${a.version})` : ""}`);
6000
5961
  }
6001
5962
  console.log();
5963
+ const agents = await promptAgentSelection(detected);
5964
+ if (agents.length < detected.length) {
5965
+ console.log(`Installing hooks for: ${agents.map((a) => a.name).join(", ")}
5966
+ `);
5967
+ }
6002
5968
  ensureSynkroDir();
6003
5969
  const scripts = writeHookScripts();
6004
5970
  console.log("Wrote hook scripts:");
@@ -7182,7 +7148,7 @@ var args = process.argv.slice(2);
7182
7148
  var cmd = args[0] || "";
7183
7149
  var subArgs = args.slice(1);
7184
7150
  function printVersion() {
7185
- console.log("1.5.0");
7151
+ console.log("1.5.2");
7186
7152
  }
7187
7153
  function printHelp() {
7188
7154
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents