@synkro-sh/cli 1.3.21 → 1.3.23
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 +104 -65
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -2871,6 +2871,7 @@ var init_repoConnect = __esm({
|
|
|
2871
2871
|
// cli/commands/setupGithub.ts
|
|
2872
2872
|
var setupGithub_exports = {};
|
|
2873
2873
|
__export(setupGithub_exports, {
|
|
2874
|
+
connectGitHub: () => connectGitHub,
|
|
2874
2875
|
setupGithubCommand: () => setupGithubCommand
|
|
2875
2876
|
});
|
|
2876
2877
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
@@ -2983,6 +2984,53 @@ async function apiCall(gatewayUrl, jwt2, path, opts = {}) {
|
|
|
2983
2984
|
}
|
|
2984
2985
|
return resp.json();
|
|
2985
2986
|
}
|
|
2987
|
+
async function connectGitHub(gatewayUrl, jwt2, opts = {}) {
|
|
2988
|
+
try {
|
|
2989
|
+
const result = await apiCall(
|
|
2990
|
+
gatewayUrl,
|
|
2991
|
+
jwt2,
|
|
2992
|
+
"/api/v1/cli/github-token"
|
|
2993
|
+
);
|
|
2994
|
+
if (result.connected && result.token) {
|
|
2995
|
+
if (!opts.silent) console.log(" \u2713 GitHub already connected via Synkro.");
|
|
2996
|
+
return result.token;
|
|
2997
|
+
}
|
|
2998
|
+
} catch {
|
|
2999
|
+
}
|
|
3000
|
+
if (!opts.silent) console.log(" Opening browser to authorize GitHub...");
|
|
3001
|
+
try {
|
|
3002
|
+
const authResp = await apiCall(
|
|
3003
|
+
gatewayUrl,
|
|
3004
|
+
jwt2,
|
|
3005
|
+
"/api/pipes-widget/authorize/github",
|
|
3006
|
+
{ method: "POST", body: "{}" }
|
|
3007
|
+
);
|
|
3008
|
+
openBrowser3(authResp.url);
|
|
3009
|
+
if (!opts.silent) console.log(" Waiting for authorization...");
|
|
3010
|
+
} catch (err) {
|
|
3011
|
+
if (!opts.silent) console.error(` Failed to start GitHub authorization: ${err.message}`);
|
|
3012
|
+
return null;
|
|
3013
|
+
}
|
|
3014
|
+
const deadline = Date.now() + 12e4;
|
|
3015
|
+
while (Date.now() < deadline) {
|
|
3016
|
+
await sleep(2e3);
|
|
3017
|
+
try {
|
|
3018
|
+
const result = await apiCall(
|
|
3019
|
+
gatewayUrl,
|
|
3020
|
+
jwt2,
|
|
3021
|
+
"/api/v1/cli/github-token"
|
|
3022
|
+
);
|
|
3023
|
+
if (result.connected && result.token) {
|
|
3024
|
+
if (!opts.silent) console.log("\n \u2713 GitHub connected!");
|
|
3025
|
+
return result.token;
|
|
3026
|
+
}
|
|
3027
|
+
} catch {
|
|
3028
|
+
}
|
|
3029
|
+
if (!opts.silent) process.stdout.write(".");
|
|
3030
|
+
}
|
|
3031
|
+
if (!opts.silent) console.error("\n Timed out waiting for GitHub authorization.");
|
|
3032
|
+
return null;
|
|
3033
|
+
}
|
|
2986
3034
|
async function setupGithubCommand(opts = {}) {
|
|
2987
3035
|
if (!isAuthenticated()) {
|
|
2988
3036
|
console.error("Not authenticated. Run `synkro-cli login` first.");
|
|
@@ -3035,59 +3083,13 @@ async function setupGithubCommand(opts = {}) {
|
|
|
3035
3083
|
}
|
|
3036
3084
|
} else {
|
|
3037
3085
|
console.log("\nConnecting to GitHub...");
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
jwt2,
|
|
3043
|
-
"/api/v1/cli/github-token"
|
|
3044
|
-
);
|
|
3045
|
-
if (result.connected && result.token) {
|
|
3046
|
-
ghToken = result.token;
|
|
3047
|
-
connected = true;
|
|
3048
|
-
console.log(" \u2713 GitHub already connected via Synkro.\n");
|
|
3049
|
-
}
|
|
3050
|
-
} catch {
|
|
3051
|
-
}
|
|
3052
|
-
if (!connected) {
|
|
3053
|
-
console.log(" Opening browser to authorize GitHub...");
|
|
3054
|
-
try {
|
|
3055
|
-
const authResp = await apiCall(
|
|
3056
|
-
gatewayUrl,
|
|
3057
|
-
jwt2,
|
|
3058
|
-
"/api/pipes-widget/authorize/github",
|
|
3059
|
-
{ method: "POST", body: "{}" }
|
|
3060
|
-
);
|
|
3061
|
-
openBrowser3(authResp.url);
|
|
3062
|
-
console.log(" Waiting for authorization...");
|
|
3063
|
-
} catch (err) {
|
|
3064
|
-
console.error(`Failed to start GitHub authorization: ${err.message}`);
|
|
3065
|
-
process.exit(1);
|
|
3066
|
-
}
|
|
3067
|
-
const deadline = Date.now() + 12e4;
|
|
3068
|
-
ghToken = "";
|
|
3069
|
-
while (Date.now() < deadline) {
|
|
3070
|
-
await sleep(2e3);
|
|
3071
|
-
try {
|
|
3072
|
-
const result = await apiCall(
|
|
3073
|
-
gatewayUrl,
|
|
3074
|
-
jwt2,
|
|
3075
|
-
"/api/v1/cli/github-token"
|
|
3076
|
-
);
|
|
3077
|
-
if (result.connected && result.token) {
|
|
3078
|
-
ghToken = result.token;
|
|
3079
|
-
break;
|
|
3080
|
-
}
|
|
3081
|
-
} catch {
|
|
3082
|
-
}
|
|
3083
|
-
process.stdout.write(".");
|
|
3084
|
-
}
|
|
3085
|
-
if (!ghToken) {
|
|
3086
|
-
console.error("\n Timed out waiting for GitHub authorization. Try again.");
|
|
3087
|
-
process.exit(1);
|
|
3088
|
-
}
|
|
3089
|
-
console.log("\n \u2713 GitHub connected!\n");
|
|
3086
|
+
const token = await connectGitHub(gatewayUrl, jwt2);
|
|
3087
|
+
if (!token) {
|
|
3088
|
+
console.error("GitHub connection failed. Try again.");
|
|
3089
|
+
process.exit(1);
|
|
3090
3090
|
}
|
|
3091
|
+
ghToken = token;
|
|
3092
|
+
console.log();
|
|
3091
3093
|
}
|
|
3092
3094
|
let claudeToken;
|
|
3093
3095
|
if (!opts.skipClaudeToken) {
|
|
@@ -3242,7 +3244,6 @@ function parseArgs(argv) {
|
|
|
3242
3244
|
else if (a === "--no-mcp") opts.noMcp = true;
|
|
3243
3245
|
else if (a === "--force" || a === "-f") opts.force = true;
|
|
3244
3246
|
else if (a === "--link-repo") opts.linkRepo = true;
|
|
3245
|
-
else if (a === "--pr-scan") opts.prScan = true;
|
|
3246
3247
|
}
|
|
3247
3248
|
if (!opts.gatewayUrl) {
|
|
3248
3249
|
const fromEnv = sanitizeGatewayCandidate(process.env.SYNKRO_GATEWAY_URL);
|
|
@@ -3332,7 +3333,7 @@ function writeConfigEnv(opts) {
|
|
|
3332
3333
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3333
3334
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3334
3335
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3335
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.3.
|
|
3336
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.3.23")}`
|
|
3336
3337
|
];
|
|
3337
3338
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
3338
3339
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|
|
@@ -3530,6 +3531,13 @@ async function installCommand(opts = {}) {
|
|
|
3530
3531
|
console.error("No access token available after auth.");
|
|
3531
3532
|
process.exit(1);
|
|
3532
3533
|
}
|
|
3534
|
+
console.log("\nConnecting to GitHub...");
|
|
3535
|
+
const ghToken = await connectGitHub(gatewayUrl, token);
|
|
3536
|
+
if (!ghToken) {
|
|
3537
|
+
console.error("GitHub connection is required. Re-run `synkro-cli install` to try again.");
|
|
3538
|
+
process.exit(1);
|
|
3539
|
+
}
|
|
3540
|
+
console.log();
|
|
3533
3541
|
setApiBaseUrl(`${gatewayUrl}/api`);
|
|
3534
3542
|
await promptRepoConnection({ linkRepo: opts.linkRepo });
|
|
3535
3543
|
const agents = detectAgents();
|
|
@@ -3667,18 +3675,9 @@ async function installCommand(opts = {}) {
|
|
|
3667
3675
|
`);
|
|
3668
3676
|
}
|
|
3669
3677
|
}
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
const { setupGithubCommand: setupGithubCommand2 } = await Promise.resolve().then(() => (init_setupGithub(), setupGithub_exports));
|
|
3673
|
-
await setupGithubCommand2({ nonInteractive: true });
|
|
3674
|
-
}
|
|
3678
|
+
const { setupGithubCommand: setupGithubCommand2 } = await Promise.resolve().then(() => (init_setupGithub(), setupGithub_exports));
|
|
3679
|
+
await setupGithubCommand2({ nonInteractive: true, githubToken: ghToken });
|
|
3675
3680
|
console.log("\u2713 Synkro installed.");
|
|
3676
|
-
console.log();
|
|
3677
|
-
if (!opts.prScan) {
|
|
3678
|
-
console.log("Next steps:");
|
|
3679
|
-
console.log(" \u2022 synkro-cli setup-github (enable PR scanning)");
|
|
3680
|
-
console.log(" \u2022 synkro-cli status (check what is configured)");
|
|
3681
|
-
}
|
|
3682
3681
|
}
|
|
3683
3682
|
function detectGitRepo2() {
|
|
3684
3683
|
try {
|
|
@@ -3883,6 +3882,7 @@ var init_install = __esm({
|
|
|
3883
3882
|
init_stub();
|
|
3884
3883
|
init_repoConnect();
|
|
3885
3884
|
init_projects();
|
|
3885
|
+
init_setupGithub();
|
|
3886
3886
|
SYNKRO_DIR2 = join6(homedir5(), ".synkro");
|
|
3887
3887
|
HOOKS_DIR = join6(SYNKRO_DIR2, "hooks");
|
|
3888
3888
|
BIN_DIR = join6(SYNKRO_DIR2, "bin");
|
|
@@ -4381,6 +4381,22 @@ function getPrFiles(repo, prNumber) {
|
|
|
4381
4381
|
]);
|
|
4382
4382
|
return data;
|
|
4383
4383
|
}
|
|
4384
|
+
async function fetchScanContext(gatewayUrl, apiKey, repo, prNumber, sha) {
|
|
4385
|
+
try {
|
|
4386
|
+
const url = `${gatewayUrl.replace(/\/$/, "")}/api/pr-scans/scan-context?repo=${encodeURIComponent(repo)}&pr_number=${prNumber}&sha=${sha}`;
|
|
4387
|
+
const headers = { "x-synkro-api-key": apiKey };
|
|
4388
|
+
const ghToken = process.env.GH_TOKEN || process.env.GITHUB_TOKEN || "";
|
|
4389
|
+
if (ghToken) headers["x-github-token"] = ghToken;
|
|
4390
|
+
const resp = await fetch(url, {
|
|
4391
|
+
headers,
|
|
4392
|
+
signal: AbortSignal.timeout(15e3)
|
|
4393
|
+
});
|
|
4394
|
+
if (!resp.ok) return { scan_all: true };
|
|
4395
|
+
return await resp.json();
|
|
4396
|
+
} catch {
|
|
4397
|
+
return { scan_all: true };
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4384
4400
|
function getFileDiffWithLines(file) {
|
|
4385
4401
|
if (!file.patch) return { hunks: "", newFileLineMap: /* @__PURE__ */ new Map() };
|
|
4386
4402
|
const lines = file.patch.split("\n");
|
|
@@ -4741,11 +4757,34 @@ async function scanPrCommand() {
|
|
|
4741
4757
|
console.error("Failed to fetch PR files:", err.message);
|
|
4742
4758
|
process.exit(2);
|
|
4743
4759
|
}
|
|
4760
|
+
const scanCtx = await fetchScanContext(gatewayUrl, synkroApiKey, repo, prNumber, sha);
|
|
4761
|
+
if (scanCtx.skip) {
|
|
4762
|
+
console.log(`Already scanned at ${sha.slice(0, 7)}, skipping.
|
|
4763
|
+
`);
|
|
4764
|
+
postCheckRun(repo, sha, "success", []);
|
|
4765
|
+
await postEventToBackend({
|
|
4766
|
+
gatewayUrl,
|
|
4767
|
+
apiKey: synkroApiKey,
|
|
4768
|
+
repo,
|
|
4769
|
+
prNumber,
|
|
4770
|
+
sha,
|
|
4771
|
+
findings: [],
|
|
4772
|
+
filesScanned: 0,
|
|
4773
|
+
totalLatencyMs: 0
|
|
4774
|
+
});
|
|
4775
|
+
return;
|
|
4776
|
+
}
|
|
4777
|
+
const changedFiles = !scanCtx.scan_all && scanCtx.files ? new Set(scanCtx.files) : null;
|
|
4778
|
+
if (changedFiles) {
|
|
4779
|
+
console.log(`Incremental scan: ${changedFiles.size} file(s) changed since last scan (${scanCtx.last_sha?.slice(0, 7)}).
|
|
4780
|
+
`);
|
|
4781
|
+
}
|
|
4744
4782
|
const eligible = files.filter((f) => {
|
|
4745
4783
|
if (f.status === "removed") return false;
|
|
4746
4784
|
if (shouldSkipFile(f.filename)) return false;
|
|
4747
4785
|
if (f.additions + f.deletions > MAX_DIFF_LINES_PER_FILE) return false;
|
|
4748
4786
|
if (!f.patch) return false;
|
|
4787
|
+
if (changedFiles && !changedFiles.has(f.filename)) return false;
|
|
4749
4788
|
return true;
|
|
4750
4789
|
});
|
|
4751
4790
|
console.log(`${files.length} files in PR, ${eligible.length} eligible for scan.
|