@synkro-sh/cli 1.3.17 → 1.3.18

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
@@ -102,7 +102,7 @@ function removeSynkroEntries(events, eventName) {
102
102
  if (!Array.isArray(arr)) return;
103
103
  events[eventName] = arr.filter((entry) => !isSynkroEntry(entry));
104
104
  }
105
- function installCCHooks(settingsPath, config2) {
105
+ function installCCHooks(settingsPath, config) {
106
106
  const settings = readSettings(settingsPath);
107
107
  settings.hooks = settings.hooks ?? {};
108
108
  removeSynkroEntries(settings.hooks, "PreToolUse");
@@ -119,7 +119,7 @@ function installCCHooks(settingsPath, config2) {
119
119
  hooks: [
120
120
  {
121
121
  type: "command",
122
- command: config2.bashJudgeScriptPath,
122
+ command: config.bashJudgeScriptPath,
123
123
  timeout: 15
124
124
  }
125
125
  ],
@@ -130,7 +130,7 @@ function installCCHooks(settingsPath, config2) {
130
130
  hooks: [
131
131
  {
132
132
  type: "command",
133
- command: config2.editPrecheckScriptPath,
133
+ command: config.editPrecheckScriptPath,
134
134
  timeout: 15
135
135
  }
136
136
  ],
@@ -141,7 +141,7 @@ function installCCHooks(settingsPath, config2) {
141
141
  hooks: [
142
142
  {
143
143
  type: "command",
144
- command: config2.editCaptureScriptPath,
144
+ command: config.editCaptureScriptPath,
145
145
  timeout: 20
146
146
  }
147
147
  ],
@@ -152,7 +152,7 @@ function installCCHooks(settingsPath, config2) {
152
152
  hooks: [
153
153
  {
154
154
  type: "command",
155
- command: config2.bashFollowupScriptPath
155
+ command: config.bashFollowupScriptPath
156
156
  }
157
157
  ],
158
158
  [SYNKRO_MARKER]: true
@@ -161,7 +161,7 @@ function installCCHooks(settingsPath, config2) {
161
161
  hooks: [
162
162
  {
163
163
  type: "command",
164
- command: config2.stopSummaryScriptPath
164
+ command: config.stopSummaryScriptPath
165
165
  }
166
166
  ],
167
167
  [SYNKRO_MARKER]: true
@@ -170,19 +170,19 @@ function installCCHooks(settingsPath, config2) {
170
170
  hooks: [
171
171
  {
172
172
  type: "command",
173
- command: config2.sessionStartScriptPath
173
+ command: config.sessionStartScriptPath
174
174
  }
175
175
  ],
176
176
  [SYNKRO_MARKER]: true
177
177
  });
178
- if (!config2.skipTranscriptSync) {
178
+ if (!config.skipTranscriptSync) {
179
179
  settings.hooks.Stop = settings.hooks.Stop ?? [];
180
180
  removeSynkroEntries(settings.hooks, "Stop");
181
181
  settings.hooks.Stop.push({
182
182
  hooks: [
183
183
  {
184
184
  type: "command",
185
- command: config2.transcriptSyncScriptPath,
185
+ command: config.transcriptSyncScriptPath,
186
186
  timeout: 3
187
187
  }
188
188
  ],
@@ -252,50 +252,50 @@ function readClaudeJson() {
252
252
  throw new Error(`Failed to parse ${CC_CONFIG_PATH}: ${err.message}`);
253
253
  }
254
254
  }
255
- function writeClaudeJsonAtomic(config2) {
255
+ function writeClaudeJsonAtomic(config) {
256
256
  mkdirSync2(dirname2(CC_CONFIG_PATH), { recursive: true });
257
257
  const tmpPath = `${CC_CONFIG_PATH}.synkro.tmp`;
258
- writeFileSync2(tmpPath, JSON.stringify(config2, null, 2) + "\n", "utf-8");
258
+ writeFileSync2(tmpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
259
259
  renameSync2(tmpPath, CC_CONFIG_PATH);
260
260
  }
261
261
  function installMcpConfig(opts) {
262
- const config2 = readClaudeJson();
263
- config2.mcpServers = config2.mcpServers ?? {};
264
- for (const [name, entry] of Object.entries(config2.mcpServers)) {
265
- if (entry?.[SYNKRO_MARKER2] === true) delete config2.mcpServers[name];
262
+ const config = readClaudeJson();
263
+ config.mcpServers = config.mcpServers ?? {};
264
+ for (const [name, entry] of Object.entries(config.mcpServers)) {
265
+ if (entry?.[SYNKRO_MARKER2] === true) delete config.mcpServers[name];
266
266
  }
267
267
  const url = `${opts.gatewayUrl.replace(/\/$/, "")}/api/v1/mcp/guardrails`;
268
- config2.mcpServers[SYNKRO_SERVER_NAME] = {
268
+ config.mcpServers[SYNKRO_SERVER_NAME] = {
269
269
  type: "http",
270
270
  url,
271
271
  headers: { Authorization: `Bearer ${opts.bearerToken}` },
272
272
  [SYNKRO_MARKER2]: true
273
273
  };
274
- writeClaudeJsonAtomic(config2);
274
+ writeClaudeJsonAtomic(config);
275
275
  return { path: CC_CONFIG_PATH, url };
276
276
  }
277
277
  function uninstallMcpConfig() {
278
278
  if (!existsSync3(CC_CONFIG_PATH)) return false;
279
- const config2 = readClaudeJson();
280
- if (!config2.mcpServers || Object.keys(config2.mcpServers).length === 0) return false;
279
+ const config = readClaudeJson();
280
+ if (!config.mcpServers || Object.keys(config.mcpServers).length === 0) return false;
281
281
  let removed = false;
282
- for (const [name, entry] of Object.entries(config2.mcpServers)) {
282
+ for (const [name, entry] of Object.entries(config.mcpServers)) {
283
283
  if (entry?.[SYNKRO_MARKER2] === true) {
284
- delete config2.mcpServers[name];
284
+ delete config.mcpServers[name];
285
285
  removed = true;
286
286
  }
287
287
  }
288
288
  if (!removed) return false;
289
- if (Object.keys(config2.mcpServers).length === 0) delete config2.mcpServers;
290
- writeClaudeJsonAtomic(config2);
289
+ if (Object.keys(config.mcpServers).length === 0) delete config.mcpServers;
290
+ writeClaudeJsonAtomic(config);
291
291
  return true;
292
292
  }
293
293
  function inspectMcpConfig() {
294
294
  if (!existsSync3(CC_CONFIG_PATH)) {
295
295
  return { installed: false, configPath: CC_CONFIG_PATH };
296
296
  }
297
- const config2 = readClaudeJson();
298
- const entry = config2.mcpServers?.[SYNKRO_SERVER_NAME];
297
+ const config = readClaudeJson();
298
+ const entry = config.mcpServers?.[SYNKRO_SERVER_NAME];
299
299
  if (!entry || entry[SYNKRO_MARKER2] !== true) {
300
300
  return { installed: false, configPath: CC_CONFIG_PATH };
301
301
  }
@@ -2440,10 +2440,12 @@ var init_auth = __esm({
2440
2440
  });
2441
2441
 
2442
2442
  // cli/api/projects.ts
2443
- import { config } from "dotenv";
2443
+ function setApiBaseUrl(url) {
2444
+ API_URL = url;
2445
+ }
2444
2446
  async function callApi(method, endpoint, body) {
2445
2447
  if (!API_URL) {
2446
- throw new Error("SYNKRO_CRUD_URL (or SYNKRO_API_URL) is not set. Add it to your .env file.");
2448
+ throw new Error("API URL not configured. Run `synkro install` first.");
2447
2449
  }
2448
2450
  const url = `${API_URL}${endpoint}`;
2449
2451
  const accessToken = getAccessToken();
@@ -2480,8 +2482,7 @@ var init_projects = __esm({
2480
2482
  "cli/api/projects.ts"() {
2481
2483
  "use strict";
2482
2484
  init_auth();
2483
- config({ quiet: true });
2484
- API_URL = process.env.SYNKRO_CRUD_URL || process.env.SYNKRO_API_URL;
2485
+ API_URL = "https://api.synkro.sh/api";
2485
2486
  }
2486
2487
  });
2487
2488
 
@@ -2935,8 +2936,8 @@ async function setupGithubCommand(opts = {}) {
2935
2936
  console.error("Not authenticated. Run `synkro-cli login` first.");
2936
2937
  process.exit(1);
2937
2938
  }
2938
- const config2 = readConfig();
2939
- const gatewayUrl = (config2.SYNKRO_GATEWAY_URL || process.env.SYNKRO_GATEWAY_URL || "https://api.synkro.sh").replace(/\/$/, "");
2939
+ const config = readConfig();
2940
+ const gatewayUrl = (config.SYNKRO_GATEWAY_URL || process.env.SYNKRO_GATEWAY_URL || "https://api.synkro.sh").replace(/\/$/, "");
2940
2941
  const jwt2 = getAccessToken();
2941
2942
  if (!jwt2) {
2942
2943
  console.error("Could not load access token from ~/.synkro/credentials.json. Run `synkro-cli login`.");
@@ -3230,7 +3231,7 @@ function writeConfigEnv(opts) {
3230
3231
  `SYNKRO_GATEWAY_URL=${shellQuoteSingle(safeGateway)}`,
3231
3232
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
3232
3233
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
3233
- `SYNKRO_VERSION=${shellQuoteSingle("1.3.17")}`
3234
+ `SYNKRO_VERSION=${shellQuoteSingle("1.3.18")}`
3234
3235
  ];
3235
3236
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
3236
3237
  if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
@@ -3299,6 +3300,24 @@ async function installCommand(opts = {}) {
3299
3300
  process.exit(1);
3300
3301
  }
3301
3302
  if (!opts.force && isAuthenticated() && isAlreadyInstalled()) {
3303
+ setApiBaseUrl(`${gatewayUrl}/api`);
3304
+ await ensureValidToken();
3305
+ const currentRepo = detectGitRepo2();
3306
+ if (currentRepo) {
3307
+ try {
3308
+ const projects = await listProjects();
3309
+ const alreadyLinked = projects.some(
3310
+ (p) => p.repos?.some((r) => r.full_name === currentRepo)
3311
+ );
3312
+ if (!alreadyLinked) {
3313
+ console.log(`Synkro is installed. This repo (${currentRepo}) is not linked yet.
3314
+ `);
3315
+ await promptRepoConnection();
3316
+ return;
3317
+ }
3318
+ } catch {
3319
+ }
3320
+ }
3302
3321
  console.log("\u2713 Synkro is already installed and configured.");
3303
3322
  console.log(" Run `synkro-cli update` to refresh hook scripts and judge prompts.");
3304
3323
  console.log(" Run `synkro-cli install --force` to reinstall from scratch.");
@@ -3336,6 +3355,7 @@ async function installCommand(opts = {}) {
3336
3355
  console.error("No access token available after auth.");
3337
3356
  process.exit(1);
3338
3357
  }
3358
+ setApiBaseUrl(`${gatewayUrl}/api`);
3339
3359
  await promptRepoConnection({ linkRepo: opts.linkRepo });
3340
3360
  const agents = detectAgents();
3341
3361
  if (agents.length === 0) {
@@ -3683,6 +3703,7 @@ var init_install = __esm({
3683
3703
  init_graderDaemon();
3684
3704
  init_stub();
3685
3705
  init_repoConnect();
3706
+ init_projects();
3686
3707
  SYNKRO_DIR2 = join6(homedir5(), ".synkro");
3687
3708
  HOOKS_DIR = join6(SYNKRO_DIR2, "hooks");
3688
3709
  BIN_DIR = join6(SYNKRO_DIR2, "bin");
@@ -3796,21 +3817,21 @@ function statusCommand() {
3796
3817
  console.log("Authentication: \u2717 not logged in (run: synkro-cli login)");
3797
3818
  }
3798
3819
  console.log();
3799
- const config2 = readConfigEnv();
3820
+ const config = readConfigEnv();
3800
3821
  console.log("Config:");
3801
- console.log(` gateway: ${config2.SYNKRO_GATEWAY_URL ?? "(unset)"}`);
3802
- console.log(` credentials: ${config2.SYNKRO_CREDENTIALS_PATH ?? "(unset)"}`);
3803
- console.log(` tier: ${config2.SYNKRO_TIER ?? "(unset)"}`);
3822
+ console.log(` gateway: ${config.SYNKRO_GATEWAY_URL ?? "(unset)"}`);
3823
+ console.log(` credentials: ${config.SYNKRO_CREDENTIALS_PATH ?? "(unset)"}`);
3824
+ console.log(` tier: ${config.SYNKRO_TIER ?? "(unset)"}`);
3804
3825
  const info2 = getUserInfo();
3805
- const userId = info2?.id ?? config2.SYNKRO_USER_ID ?? "default";
3826
+ const userId = info2?.id ?? config.SYNKRO_USER_ID ?? "default";
3806
3827
  const tierCacheFile = join7(SYNKRO_DIR3, `.tier-cache-${userId}`);
3807
- let inferenceTier = config2.SYNKRO_INFERENCE_TIER || null;
3828
+ let inferenceTier = config.SYNKRO_INFERENCE_TIER || null;
3808
3829
  if (!inferenceTier && existsSync8(tierCacheFile)) {
3809
3830
  inferenceTier = readFileSync6(tierCacheFile, "utf-8").trim() || null;
3810
3831
  }
3811
3832
  const tierLabel = inferenceTier === "fast" ? "'fast' (server-side grading)" : inferenceTier === "free" ? "'free' (local daemon grading)" : "(unknown \u2014 fires on next hook)";
3812
3833
  console.log(` inference: ${tierLabel}`);
3813
- console.log(` version: ${config2.SYNKRO_VERSION ?? "(unset)"}`);
3834
+ console.log(` version: ${config.SYNKRO_VERSION ?? "(unset)"}`);
3814
3835
  console.log();
3815
3836
  const agents = detectAgents();
3816
3837
  console.log("Detected agents:");