@synkro-sh/cli 1.3.18 → 1.3.20
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 +195 -35
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -2652,7 +2652,9 @@ import { createInterface } from "readline";
|
|
|
2652
2652
|
function detectGitRepo() {
|
|
2653
2653
|
try {
|
|
2654
2654
|
const remoteUrl = execSync2("git remote get-url origin", { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
2655
|
-
const
|
|
2655
|
+
const sshMatch = remoteUrl.match(/^git@[^:]+:(.+?)(?:\.git)?$/);
|
|
2656
|
+
const httpMatch = remoteUrl.match(/^https?:\/\/[^/]+\/(.+?)(?:\.git)?$/);
|
|
2657
|
+
const match = sshMatch || httpMatch;
|
|
2656
2658
|
if (!match) return null;
|
|
2657
2659
|
const fullName = match[1];
|
|
2658
2660
|
return { fullName, shortName: fullName.split("/").pop() || fullName };
|
|
@@ -2721,9 +2723,12 @@ function waitForGithubToken() {
|
|
|
2721
2723
|
function openBrowser2(url) {
|
|
2722
2724
|
const { execFile: execFile2 } = __require("child_process");
|
|
2723
2725
|
const plat = process.platform;
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2726
|
+
const cb = (err) => {
|
|
2727
|
+
if (err) console.log(` Open this URL manually: ${url}`);
|
|
2728
|
+
};
|
|
2729
|
+
if (plat === "darwin") execFile2("open", [url], cb);
|
|
2730
|
+
else if (plat === "win32") execFile2("cmd", ["/c", "start", "", url], cb);
|
|
2731
|
+
else execFile2("xdg-open", [url], cb);
|
|
2727
2732
|
}
|
|
2728
2733
|
async function connectGithubAndSelectRepos() {
|
|
2729
2734
|
const url = `${SYNKRO_WEB_AUTH_URL2}/cli-github?port=${GITHUB_PORT}`;
|
|
@@ -3224,6 +3229,7 @@ function writeConfigEnv(opts) {
|
|
|
3224
3229
|
const safeOrgId = sanitizeConfigValue(opts.orgId);
|
|
3225
3230
|
const safeEmail = sanitizeConfigValue(opts.email);
|
|
3226
3231
|
const safeTier = sanitizeConfigValue(opts.tier ?? "pro", 32);
|
|
3232
|
+
const safeInference = sanitizeConfigValue(opts.inference ?? "fast", 16);
|
|
3227
3233
|
const lines = [
|
|
3228
3234
|
"# Synkro CLI config (managed by synkro install)",
|
|
3229
3235
|
"# JWT auth \u2014 the hook scripts read SYNKRO_CREDENTIALS_PATH at runtime",
|
|
@@ -3231,7 +3237,8 @@ function writeConfigEnv(opts) {
|
|
|
3231
3237
|
`SYNKRO_GATEWAY_URL=${shellQuoteSingle(safeGateway)}`,
|
|
3232
3238
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3233
3239
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3234
|
-
`
|
|
3240
|
+
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3241
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.3.20")}`
|
|
3235
3242
|
];
|
|
3236
3243
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
3237
3244
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|
|
@@ -3243,6 +3250,42 @@ function writeConfigEnv(opts) {
|
|
|
3243
3250
|
writeFileSync5(CONFIG_PATH2, lines.join("\n"), "utf-8");
|
|
3244
3251
|
chmodSync(CONFIG_PATH2, 384);
|
|
3245
3252
|
}
|
|
3253
|
+
function collectLocalMetadata() {
|
|
3254
|
+
const meta = { platform: process.platform };
|
|
3255
|
+
try {
|
|
3256
|
+
meta.display_name = execSync4("git config user.name", { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
3257
|
+
} catch {
|
|
3258
|
+
}
|
|
3259
|
+
try {
|
|
3260
|
+
const remote = execSync4("git remote get-url origin", { encoding: "utf-8", timeout: 3e3 }).trim();
|
|
3261
|
+
const m = remote.match(/(?:github\.com)[:/](.+?)(?:\.git)?$/);
|
|
3262
|
+
if (m) meta.active_repo = m[1];
|
|
3263
|
+
} catch {
|
|
3264
|
+
}
|
|
3265
|
+
return meta;
|
|
3266
|
+
}
|
|
3267
|
+
async function fetchUserProfile(gatewayUrl, token) {
|
|
3268
|
+
try {
|
|
3269
|
+
const resp = await fetch(`${gatewayUrl}/api/v1/cli/me`, {
|
|
3270
|
+
headers: { "Authorization": `Bearer ${token}` }
|
|
3271
|
+
});
|
|
3272
|
+
if (!resp.ok) return { tier: "pro", inference: "fast" };
|
|
3273
|
+
const data = await resp.json();
|
|
3274
|
+
const meta = collectLocalMetadata();
|
|
3275
|
+
fetch(`${gatewayUrl}/api/v1/cli/me`, {
|
|
3276
|
+
method: "PATCH",
|
|
3277
|
+
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
3278
|
+
body: JSON.stringify(meta)
|
|
3279
|
+
}).catch(() => {
|
|
3280
|
+
});
|
|
3281
|
+
return {
|
|
3282
|
+
tier: data.plan_tier ?? "pro",
|
|
3283
|
+
inference: data.fast_inference ? "fast" : "standard"
|
|
3284
|
+
};
|
|
3285
|
+
} catch {
|
|
3286
|
+
return { tier: "pro", inference: "fast" };
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3246
3289
|
function assertGatewayAllowed(gatewayUrl) {
|
|
3247
3290
|
let parsed;
|
|
3248
3291
|
try {
|
|
@@ -3459,8 +3502,10 @@ async function installCommand(opts = {}) {
|
|
|
3459
3502
|
email = info.email;
|
|
3460
3503
|
} catch {
|
|
3461
3504
|
}
|
|
3462
|
-
|
|
3463
|
-
|
|
3505
|
+
const profile = await fetchUserProfile(gatewayUrl, token);
|
|
3506
|
+
writeConfigEnv({ gatewayUrl, userId, orgId, email, tier: profile.tier, inference: profile.inference, transcriptConsent });
|
|
3507
|
+
console.log(`Wrote config to ${CONFIG_PATH2}`);
|
|
3508
|
+
console.log(` inference: ${profile.inference} (server-side grading)
|
|
3464
3509
|
`);
|
|
3465
3510
|
if (transcriptConsent) {
|
|
3466
3511
|
try {
|
|
@@ -3506,7 +3551,9 @@ async function installCommand(opts = {}) {
|
|
|
3506
3551
|
function detectGitRepo2() {
|
|
3507
3552
|
try {
|
|
3508
3553
|
const remoteUrl = execSync4("git remote get-url origin", { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
3509
|
-
const
|
|
3554
|
+
const sshMatch = remoteUrl.match(/^git@[^:]+:(.+?)(?:\.git)?$/);
|
|
3555
|
+
const httpMatch = remoteUrl.match(/^https?:\/\/[^/]+\/(.+?)(?:\.git)?$/);
|
|
3556
|
+
const match = sshMatch || httpMatch;
|
|
3510
3557
|
return match ? match[1] : null;
|
|
3511
3558
|
} catch {
|
|
3512
3559
|
return null;
|
|
@@ -3806,7 +3853,7 @@ function readConfigEnv() {
|
|
|
3806
3853
|
}
|
|
3807
3854
|
return out;
|
|
3808
3855
|
}
|
|
3809
|
-
function statusCommand() {
|
|
3856
|
+
async function statusCommand() {
|
|
3810
3857
|
console.log("Synkro CLI status\n");
|
|
3811
3858
|
if (isAuthenticated()) {
|
|
3812
3859
|
const info = getUserInfo();
|
|
@@ -3818,19 +3865,30 @@ function statusCommand() {
|
|
|
3818
3865
|
}
|
|
3819
3866
|
console.log();
|
|
3820
3867
|
const config = readConfigEnv();
|
|
3868
|
+
const gatewayUrl = (config.SYNKRO_GATEWAY_URL || "https://api.synkro.sh").replace(/^['"]|['"]$/g, "");
|
|
3869
|
+
let serverTier = config.SYNKRO_TIER || "(unset)";
|
|
3870
|
+
let serverInference = config.SYNKRO_INFERENCE || "fast";
|
|
3871
|
+
const token = getAccessToken();
|
|
3872
|
+
if (token) {
|
|
3873
|
+
try {
|
|
3874
|
+
const resp = await fetch(`${gatewayUrl}/api/v1/cli/me`, {
|
|
3875
|
+
headers: { "Authorization": `Bearer ${token}` },
|
|
3876
|
+
signal: AbortSignal.timeout(5e3)
|
|
3877
|
+
});
|
|
3878
|
+
if (resp.ok) {
|
|
3879
|
+
const data = await resp.json();
|
|
3880
|
+
serverInference = data.fast_inference ? "fast" : "standard";
|
|
3881
|
+
serverTier = data.plan_tier ?? data.tier ?? serverTier;
|
|
3882
|
+
}
|
|
3883
|
+
} catch {
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3821
3886
|
console.log("Config:");
|
|
3822
|
-
console.log(` gateway: ${
|
|
3887
|
+
console.log(` gateway: ${gatewayUrl}`);
|
|
3823
3888
|
console.log(` credentials: ${config.SYNKRO_CREDENTIALS_PATH ?? "(unset)"}`);
|
|
3824
|
-
console.log(` tier: ${
|
|
3825
|
-
const
|
|
3826
|
-
|
|
3827
|
-
const tierCacheFile = join7(SYNKRO_DIR3, `.tier-cache-${userId}`);
|
|
3828
|
-
let inferenceTier = config.SYNKRO_INFERENCE_TIER || null;
|
|
3829
|
-
if (!inferenceTier && existsSync8(tierCacheFile)) {
|
|
3830
|
-
inferenceTier = readFileSync6(tierCacheFile, "utf-8").trim() || null;
|
|
3831
|
-
}
|
|
3832
|
-
const tierLabel = inferenceTier === "fast" ? "'fast' (server-side grading)" : inferenceTier === "free" ? "'free' (local daemon grading)" : "(unknown \u2014 fires on next hook)";
|
|
3833
|
-
console.log(` inference: ${tierLabel}`);
|
|
3889
|
+
console.log(` tier: ${serverTier}`);
|
|
3890
|
+
const inferenceLabel = serverInference === "fast" ? "'fast' (server-side grading)" : "'standard' (local grading)";
|
|
3891
|
+
console.log(` inference: ${inferenceLabel}`);
|
|
3834
3892
|
console.log(` version: ${config.SYNKRO_VERSION ?? "(unset)"}`);
|
|
3835
3893
|
console.log();
|
|
3836
3894
|
const agents = detectAgents();
|
|
@@ -3971,6 +4029,102 @@ var init_unlink = __esm({
|
|
|
3971
4029
|
}
|
|
3972
4030
|
});
|
|
3973
4031
|
|
|
4032
|
+
// cli/commands/config.ts
|
|
4033
|
+
var config_exports = {};
|
|
4034
|
+
__export(config_exports, {
|
|
4035
|
+
configCommand: () => configCommand
|
|
4036
|
+
});
|
|
4037
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, existsSync as existsSync9 } from "fs";
|
|
4038
|
+
import { join as join8 } from "path";
|
|
4039
|
+
import { homedir as homedir7 } from "os";
|
|
4040
|
+
function readConfigEnv2() {
|
|
4041
|
+
if (!existsSync9(CONFIG_PATH4)) return {};
|
|
4042
|
+
const out = {};
|
|
4043
|
+
for (const line of readFileSync7(CONFIG_PATH4, "utf-8").split("\n")) {
|
|
4044
|
+
const t = line.trim();
|
|
4045
|
+
if (!t || t.startsWith("#")) continue;
|
|
4046
|
+
const eq = t.indexOf("=");
|
|
4047
|
+
if (eq > 0) out[t.slice(0, eq).trim()] = t.slice(eq + 1).trim().replace(/^['"]|['"]$/g, "");
|
|
4048
|
+
}
|
|
4049
|
+
return out;
|
|
4050
|
+
}
|
|
4051
|
+
function updateConfigValue(key, value) {
|
|
4052
|
+
if (!existsSync9(CONFIG_PATH4)) {
|
|
4053
|
+
console.error("No config found. Run `synkro install` first.");
|
|
4054
|
+
process.exit(1);
|
|
4055
|
+
}
|
|
4056
|
+
const lines = readFileSync7(CONFIG_PATH4, "utf-8").split("\n");
|
|
4057
|
+
const pattern = new RegExp(`^${key}=`);
|
|
4058
|
+
let found = false;
|
|
4059
|
+
const updated = lines.map((line) => {
|
|
4060
|
+
if (pattern.test(line.trim())) {
|
|
4061
|
+
found = true;
|
|
4062
|
+
return `${key}='${value}'`;
|
|
4063
|
+
}
|
|
4064
|
+
return line;
|
|
4065
|
+
});
|
|
4066
|
+
if (!found) updated.splice(updated.length - 1, 0, `${key}='${value}'`);
|
|
4067
|
+
writeFileSync6(CONFIG_PATH4, updated.join("\n"), "utf-8");
|
|
4068
|
+
}
|
|
4069
|
+
async function configCommand(args2) {
|
|
4070
|
+
if (args2.length === 0) {
|
|
4071
|
+
const config2 = readConfigEnv2();
|
|
4072
|
+
console.log("Synkro config:\n");
|
|
4073
|
+
console.log(` inference: ${config2.SYNKRO_INFERENCE || "fast"}`);
|
|
4074
|
+
console.log(` tier: ${config2.SYNKRO_TIER || "pro"}`);
|
|
4075
|
+
console.log(` gateway: ${config2.SYNKRO_GATEWAY_URL || "https://api.synkro.sh"}`);
|
|
4076
|
+
console.log(` version: ${config2.SYNKRO_VERSION || "?"}`);
|
|
4077
|
+
console.log(`
|
|
4078
|
+
To change: synkro config --inference fast|standard`);
|
|
4079
|
+
return;
|
|
4080
|
+
}
|
|
4081
|
+
let inferenceValue;
|
|
4082
|
+
for (const a of args2) {
|
|
4083
|
+
if (a.startsWith("--inference=")) inferenceValue = a.slice("--inference=".length);
|
|
4084
|
+
else if (a === "--inference" && args2.indexOf(a) + 1 < args2.length) inferenceValue = args2[args2.indexOf(a) + 1];
|
|
4085
|
+
}
|
|
4086
|
+
if (!inferenceValue || !["fast", "standard"].includes(inferenceValue)) {
|
|
4087
|
+
console.error("Usage: synkro config --inference fast|standard");
|
|
4088
|
+
process.exit(1);
|
|
4089
|
+
}
|
|
4090
|
+
if (!isAuthenticated()) {
|
|
4091
|
+
console.error("Not authenticated. Run `synkro login` first.");
|
|
4092
|
+
process.exit(1);
|
|
4093
|
+
}
|
|
4094
|
+
const token = getAccessToken();
|
|
4095
|
+
const config = readConfigEnv2();
|
|
4096
|
+
const gatewayUrl = (config.SYNKRO_GATEWAY_URL || "https://api.synkro.sh").replace(/\/$/, "");
|
|
4097
|
+
try {
|
|
4098
|
+
const resp = await fetch(`${gatewayUrl}/api/v1/cli/me`, {
|
|
4099
|
+
method: "PATCH",
|
|
4100
|
+
headers: {
|
|
4101
|
+
"Authorization": `Bearer ${token}`,
|
|
4102
|
+
"Content-Type": "application/json"
|
|
4103
|
+
},
|
|
4104
|
+
body: JSON.stringify({ fast_inference: inferenceValue === "fast" })
|
|
4105
|
+
});
|
|
4106
|
+
if (!resp.ok) {
|
|
4107
|
+
const errText = await resp.text().catch(() => "");
|
|
4108
|
+
console.error(`Failed to update: ${resp.status} ${errText.slice(0, 200)}`);
|
|
4109
|
+
process.exit(1);
|
|
4110
|
+
}
|
|
4111
|
+
} catch (err) {
|
|
4112
|
+
console.error(`Failed to reach server: ${err.message}`);
|
|
4113
|
+
process.exit(1);
|
|
4114
|
+
}
|
|
4115
|
+
updateConfigValue("SYNKRO_INFERENCE", inferenceValue);
|
|
4116
|
+
console.log(`\u2713 Inference set to '${inferenceValue}'.`);
|
|
4117
|
+
}
|
|
4118
|
+
var SYNKRO_DIR4, CONFIG_PATH4;
|
|
4119
|
+
var init_config = __esm({
|
|
4120
|
+
"cli/commands/config.ts"() {
|
|
4121
|
+
"use strict";
|
|
4122
|
+
init_stub();
|
|
4123
|
+
SYNKRO_DIR4 = join8(homedir7(), ".synkro");
|
|
4124
|
+
CONFIG_PATH4 = join8(SYNKRO_DIR4, "config.env");
|
|
4125
|
+
}
|
|
4126
|
+
});
|
|
4127
|
+
|
|
3974
4128
|
// cli/commands/scanPr.ts
|
|
3975
4129
|
var scanPr_exports = {};
|
|
3976
4130
|
__export(scanPr_exports, {
|
|
@@ -4563,9 +4717,9 @@ var disconnect_exports = {};
|
|
|
4563
4717
|
__export(disconnect_exports, {
|
|
4564
4718
|
disconnectCommand: () => disconnectCommand
|
|
4565
4719
|
});
|
|
4566
|
-
import { existsSync as
|
|
4567
|
-
import { homedir as
|
|
4568
|
-
import { join as
|
|
4720
|
+
import { existsSync as existsSync10, rmSync } from "fs";
|
|
4721
|
+
import { homedir as homedir8 } from "os";
|
|
4722
|
+
import { join as join9 } from "path";
|
|
4569
4723
|
function disconnectCommand(args2 = []) {
|
|
4570
4724
|
const purge = args2.includes("--purge");
|
|
4571
4725
|
console.log("Synkro disconnect starting...\n");
|
|
@@ -4583,25 +4737,25 @@ function disconnectCommand(args2 = []) {
|
|
|
4583
4737
|
console.log(`${mcpRemoved ? "\u2713" : "\xB7"} MCP guardrails server: ${mcpRemoved ? "removed entry from ~/.claude.json" : "no Synkro MCP entry found"}`);
|
|
4584
4738
|
}
|
|
4585
4739
|
if (purge) {
|
|
4586
|
-
if (
|
|
4587
|
-
rmSync(
|
|
4588
|
-
console.log(`\u2713 Removed ${
|
|
4740
|
+
if (existsSync10(SYNKRO_DIR5)) {
|
|
4741
|
+
rmSync(SYNKRO_DIR5, { recursive: true, force: true });
|
|
4742
|
+
console.log(`\u2713 Removed ${SYNKRO_DIR5}`);
|
|
4589
4743
|
} else {
|
|
4590
|
-
console.log(`\xB7 ${
|
|
4744
|
+
console.log(`\xB7 ${SYNKRO_DIR5} already gone, nothing to remove`);
|
|
4591
4745
|
}
|
|
4592
|
-
} else if (
|
|
4593
|
-
console.log(`Config preserved at ${
|
|
4746
|
+
} else if (existsSync10(SYNKRO_DIR5)) {
|
|
4747
|
+
console.log(`Config preserved at ${SYNKRO_DIR5}. Run with --purge to remove.`);
|
|
4594
4748
|
}
|
|
4595
4749
|
console.log("\nSynkro disconnected.");
|
|
4596
4750
|
}
|
|
4597
|
-
var
|
|
4751
|
+
var SYNKRO_DIR5;
|
|
4598
4752
|
var init_disconnect = __esm({
|
|
4599
4753
|
"cli/commands/disconnect.ts"() {
|
|
4600
4754
|
"use strict";
|
|
4601
4755
|
init_agentDetect();
|
|
4602
4756
|
init_ccHookConfig();
|
|
4603
4757
|
init_mcpConfig();
|
|
4604
|
-
|
|
4758
|
+
SYNKRO_DIR5 = join9(homedir8(), ".synkro");
|
|
4605
4759
|
}
|
|
4606
4760
|
});
|
|
4607
4761
|
|
|
@@ -4643,15 +4797,15 @@ var init_reinstall = __esm({
|
|
|
4643
4797
|
});
|
|
4644
4798
|
|
|
4645
4799
|
// cli/bootstrap.js
|
|
4646
|
-
import { readFileSync as
|
|
4800
|
+
import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
|
|
4647
4801
|
import { resolve } from "path";
|
|
4648
4802
|
var envCandidates = [
|
|
4649
4803
|
resolve(process.cwd(), ".env"),
|
|
4650
4804
|
resolve(process.env.HOME ?? "", ".synkro", "config.env")
|
|
4651
4805
|
];
|
|
4652
4806
|
for (const envPath of envCandidates) {
|
|
4653
|
-
if (!
|
|
4654
|
-
const envContent =
|
|
4807
|
+
if (!existsSync11(envPath)) continue;
|
|
4808
|
+
const envContent = readFileSync8(envPath, "utf-8");
|
|
4655
4809
|
for (const line of envContent.split("\n")) {
|
|
4656
4810
|
const trimmed = line.trim();
|
|
4657
4811
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -4679,6 +4833,7 @@ Commands:
|
|
|
4679
4833
|
status Show current setup state
|
|
4680
4834
|
link Link repos to a Synkro project (local git or GitHub OAuth)
|
|
4681
4835
|
unlink Remove repo links from Synkro projects
|
|
4836
|
+
config View or change settings (e.g. --inference fast|standard)
|
|
4682
4837
|
setup-github Configure GitHub PR scanning (push secrets + workflow file)
|
|
4683
4838
|
update Refresh hook configs and judge prompts
|
|
4684
4839
|
disconnect [--purge] Remove Synkro hooks from agents (--purge also removes ~/.synkro)
|
|
@@ -4713,7 +4868,7 @@ async function main() {
|
|
|
4713
4868
|
}
|
|
4714
4869
|
case "status": {
|
|
4715
4870
|
const { statusCommand: statusCommand2 } = await Promise.resolve().then(() => (init_status(), status_exports));
|
|
4716
|
-
statusCommand2();
|
|
4871
|
+
await statusCommand2();
|
|
4717
4872
|
break;
|
|
4718
4873
|
}
|
|
4719
4874
|
case "link": {
|
|
@@ -4726,6 +4881,11 @@ async function main() {
|
|
|
4726
4881
|
await unlinkCommand2();
|
|
4727
4882
|
break;
|
|
4728
4883
|
}
|
|
4884
|
+
case "config": {
|
|
4885
|
+
const { configCommand: configCommand2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4886
|
+
await configCommand2(subArgs);
|
|
4887
|
+
break;
|
|
4888
|
+
}
|
|
4729
4889
|
case "setup-github": {
|
|
4730
4890
|
const { setupGithubCommand: setupGithubCommand2 } = await Promise.resolve().then(() => (init_setupGithub(), setupGithub_exports));
|
|
4731
4891
|
const ghOpts = {};
|