@synkro-sh/cli 1.7.64 → 1.7.65
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 +321 -383
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -132,7 +132,7 @@ function getIdentity() {
|
|
|
132
132
|
if (cached2) return cached2;
|
|
133
133
|
let cliVersion = "0.0.0";
|
|
134
134
|
try {
|
|
135
|
-
cliVersion = "1.7.
|
|
135
|
+
cliVersion = "1.7.65";
|
|
136
136
|
} catch {
|
|
137
137
|
}
|
|
138
138
|
const creds = loadCredentialsIdentity();
|
|
@@ -2252,7 +2252,13 @@ function loadMcpJwt(): string {
|
|
|
2252
2252
|
|
|
2253
2253
|
let _cfgCache: Record<string, string> | null = null;
|
|
2254
2254
|
function cfgVal(key: string): string {
|
|
2255
|
-
|
|
2255
|
+
// ~/.synkro/config.env (written by "synkro install") is AUTHORITATIVE for the keys it
|
|
2256
|
+
// defines. This hook runs under bun, which AUTO-LOADS a .env/.env.local from the repo
|
|
2257
|
+
// cwd into process.env — so a repo's own dev vars (e.g. SYNKRO_GATEWAY_URL=localhost for a
|
|
2258
|
+
// local "wrangler dev") would otherwise hijack the installed config and silently redirect
|
|
2259
|
+
// cloud grades to a dead gateway (fail-open, "nothing fires"). So read config.env FIRST and
|
|
2260
|
+
// only fall back to process.env for keys config.env doesn't set (e.g. SYNKRO_HOOK_FORMAT,
|
|
2261
|
+
// which is passed on the cursor hook command, never written to config.env).
|
|
2256
2262
|
if (!_cfgCache) {
|
|
2257
2263
|
_cfgCache = {};
|
|
2258
2264
|
try {
|
|
@@ -2263,7 +2269,8 @@ function cfgVal(key: string): string {
|
|
|
2263
2269
|
}
|
|
2264
2270
|
} catch {}
|
|
2265
2271
|
}
|
|
2266
|
-
|
|
2272
|
+
if (_cfgCache[key]) return _cfgCache[key];
|
|
2273
|
+
return process.env[key] || '';
|
|
2267
2274
|
}
|
|
2268
2275
|
function deployIsCloud(): boolean { return cfgVal('SYNKRO_DEPLOY_LOCATION') === 'cloud'; }
|
|
2269
2276
|
|
|
@@ -5863,87 +5870,6 @@ var init_setupToken = __esm({
|
|
|
5863
5870
|
}
|
|
5864
5871
|
});
|
|
5865
5872
|
|
|
5866
|
-
// cli/local-cc/codexCloudSetup.ts
|
|
5867
|
-
var codexCloudSetup_exports = {};
|
|
5868
|
-
__export(codexCloudSetup_exports, {
|
|
5869
|
-
setupCodexCloud: () => setupCodexCloud
|
|
5870
|
-
});
|
|
5871
|
-
import { spawn as nodeSpawn2, spawnSync as spawnSync4 } from "child_process";
|
|
5872
|
-
import { readFileSync as readFileSync16, mkdirSync as mkdirSync12, rmSync, existsSync as existsSync19 } from "fs";
|
|
5873
|
-
import { homedir as homedir16 } from "os";
|
|
5874
|
-
import { join as join16 } from "path";
|
|
5875
|
-
function findCodexBinary() {
|
|
5876
|
-
if (process.env.SYNKRO_CODEX_BIN) return process.env.SYNKRO_CODEX_BIN;
|
|
5877
|
-
const r = spawnSync4("which", ["codex"], { encoding: "utf-8" });
|
|
5878
|
-
const p = (r.stdout || "").trim().split("\n")[0];
|
|
5879
|
-
return p || null;
|
|
5880
|
-
}
|
|
5881
|
-
function runCodexLogin(codexBin) {
|
|
5882
|
-
mkdirSync12(CODEX_CLOUD_HOME, { recursive: true, mode: 448 });
|
|
5883
|
-
return new Promise((resolve4, reject) => {
|
|
5884
|
-
const proc = nodeSpawn2(codexBin, ["login"], {
|
|
5885
|
-
stdio: "inherit",
|
|
5886
|
-
env: { ...process.env, CODEX_HOME: CODEX_CLOUD_HOME }
|
|
5887
|
-
});
|
|
5888
|
-
proc.on("error", (err) => reject(new Error(`failed to spawn codex login: ${err.message}`)));
|
|
5889
|
-
proc.on("close", (code) => code === 0 ? resolve4() : reject(new Error(`codex login exited with code ${code}`)));
|
|
5890
|
-
});
|
|
5891
|
-
}
|
|
5892
|
-
async function setupCodexCloud(gatewayUrl, bearerToken, onStatus) {
|
|
5893
|
-
const codexBin = findCodexBinary();
|
|
5894
|
-
if (!codexBin) {
|
|
5895
|
-
return { ok: false, error: "Codex CLI not found on PATH. Install Codex (https://developers.openai.com/codex), then re-run `synkro install`. (Set SYNKRO_CODEX_BIN to override the binary path.)" };
|
|
5896
|
-
}
|
|
5897
|
-
onStatus?.("Opening your browser to authorize your Codex subscription for Synkro Cloud\u2026");
|
|
5898
|
-
try {
|
|
5899
|
-
await runCodexLogin(codexBin);
|
|
5900
|
-
} catch (e) {
|
|
5901
|
-
return { ok: false, error: `Codex login failed: ${e.message}` };
|
|
5902
|
-
}
|
|
5903
|
-
const authPath = join16(CODEX_CLOUD_HOME, "auth.json");
|
|
5904
|
-
if (!existsSync19(authPath)) {
|
|
5905
|
-
return { ok: false, error: "codex login completed but no auth.json was written \u2014 did the browser approval finish?" };
|
|
5906
|
-
}
|
|
5907
|
-
let auth;
|
|
5908
|
-
try {
|
|
5909
|
-
auth = JSON.parse(readFileSync16(authPath, "utf-8"));
|
|
5910
|
-
} catch (e) {
|
|
5911
|
-
return { ok: false, error: `could not read codex auth.json: ${e.message}` };
|
|
5912
|
-
}
|
|
5913
|
-
if (!auth || typeof auth !== "object" || !auth.tokens?.refresh_token) {
|
|
5914
|
-
return { ok: false, error: "codex auth.json has no refresh token \u2014 cloud refresh would fail. Re-run login." };
|
|
5915
|
-
}
|
|
5916
|
-
onStatus?.("Connecting your Codex session to Synkro Cloud\u2026");
|
|
5917
|
-
let resp;
|
|
5918
|
-
try {
|
|
5919
|
-
resp = await fetch(`${gatewayUrl.replace(/\/+$/, "")}/codex/seed`, {
|
|
5920
|
-
method: "POST",
|
|
5921
|
-
headers: { "Content-Type": "application/json", Authorization: `Bearer ${bearerToken}` },
|
|
5922
|
-
body: JSON.stringify({ auth })
|
|
5923
|
-
});
|
|
5924
|
-
} catch (e) {
|
|
5925
|
-
return { ok: false, error: `failed to reach Synkro API: ${e.message}` };
|
|
5926
|
-
}
|
|
5927
|
-
if (!resp.ok) {
|
|
5928
|
-
const detail = await resp.text().catch(() => "");
|
|
5929
|
-
return { ok: false, error: `seed rejected (${resp.status}): ${detail.slice(0, 200)}` };
|
|
5930
|
-
}
|
|
5931
|
-
try {
|
|
5932
|
-
rmSync(CODEX_CLOUD_HOME, { recursive: true, force: true });
|
|
5933
|
-
} catch {
|
|
5934
|
-
}
|
|
5935
|
-
onStatus?.("\u2713 Codex subscription connected to Synkro Cloud.");
|
|
5936
|
-
return { ok: true };
|
|
5937
|
-
}
|
|
5938
|
-
var SYNKRO_DIR9, CODEX_CLOUD_HOME;
|
|
5939
|
-
var init_codexCloudSetup = __esm({
|
|
5940
|
-
"cli/local-cc/codexCloudSetup.ts"() {
|
|
5941
|
-
"use strict";
|
|
5942
|
-
SYNKRO_DIR9 = join16(homedir16(), ".synkro");
|
|
5943
|
-
CODEX_CLOUD_HOME = join16(SYNKRO_DIR9, "codex-cloud-session");
|
|
5944
|
-
}
|
|
5945
|
-
});
|
|
5946
|
-
|
|
5947
5873
|
// cli/commands/setupGithub.ts
|
|
5948
5874
|
var setupGithub_exports = {};
|
|
5949
5875
|
__export(setupGithub_exports, {
|
|
@@ -5953,14 +5879,14 @@ __export(setupGithub_exports, {
|
|
|
5953
5879
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
5954
5880
|
import { stdin as input, stdout as output } from "process";
|
|
5955
5881
|
import { execSync as execSync5 } from "child_process";
|
|
5956
|
-
import { existsSync as
|
|
5957
|
-
import { homedir as
|
|
5958
|
-
import { join as
|
|
5882
|
+
import { existsSync as existsSync19, readFileSync as readFileSync16 } from "fs";
|
|
5883
|
+
import { homedir as homedir16, platform as platform5 } from "os";
|
|
5884
|
+
import { join as join16 } from "path";
|
|
5959
5885
|
import { execFile as execFile2 } from "child_process";
|
|
5960
5886
|
function readConfig() {
|
|
5961
|
-
if (!
|
|
5887
|
+
if (!existsSync19(CONFIG_PATH3)) return {};
|
|
5962
5888
|
const out = {};
|
|
5963
|
-
for (const line of
|
|
5889
|
+
for (const line of readFileSync16(CONFIG_PATH3, "utf-8").split("\n")) {
|
|
5964
5890
|
const t = line.trim();
|
|
5965
5891
|
if (!t || t.startsWith("#")) continue;
|
|
5966
5892
|
const eq = t.indexOf("=");
|
|
@@ -6260,15 +6186,15 @@ Will push secrets to ${selected.length} repo(s):`);
|
|
|
6260
6186
|
console.log(`Secrets pushed: ${SECRET_NAMES.CLAUDE_OAUTH}, ${SECRET_NAMES.SYNKRO_API_KEY}`);
|
|
6261
6187
|
console.log("Open a PR on any selected repo to trigger your first Synkro scan.");
|
|
6262
6188
|
}
|
|
6263
|
-
var
|
|
6189
|
+
var SYNKRO_DIR9, CONFIG_PATH3;
|
|
6264
6190
|
var init_setupGithub = __esm({
|
|
6265
6191
|
"cli/commands/setupGithub.ts"() {
|
|
6266
6192
|
"use strict";
|
|
6267
6193
|
init_githubSetup();
|
|
6268
6194
|
init_stub();
|
|
6269
6195
|
init_setupToken();
|
|
6270
|
-
|
|
6271
|
-
CONFIG_PATH3 =
|
|
6196
|
+
SYNKRO_DIR9 = join16(homedir16(), ".synkro");
|
|
6197
|
+
CONFIG_PATH3 = join16(SYNKRO_DIR9, "config.env");
|
|
6272
6198
|
}
|
|
6273
6199
|
});
|
|
6274
6200
|
|
|
@@ -6287,9 +6213,9 @@ __export(install_exports, {
|
|
|
6287
6213
|
syncSkillFiles: () => syncSkillFiles,
|
|
6288
6214
|
writeHookScripts: () => writeHookScripts
|
|
6289
6215
|
});
|
|
6290
|
-
import { existsSync as
|
|
6291
|
-
import { homedir as
|
|
6292
|
-
import { join as
|
|
6216
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync12, writeFileSync as writeFileSync13, chmodSync as chmodSync3, readFileSync as readFileSync17, readdirSync as readdirSync3, unlinkSync as unlinkSync6, statSync as statSync2 } from "fs";
|
|
6217
|
+
import { homedir as homedir17 } from "os";
|
|
6218
|
+
import { join as join17 } from "path";
|
|
6293
6219
|
import { execSync as execSync6 } from "child_process";
|
|
6294
6220
|
import { createInterface as createInterface3 } from "readline";
|
|
6295
6221
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -6376,15 +6302,20 @@ async function promptCursorApiKey(opts) {
|
|
|
6376
6302
|
console.log(" \u26A0 Skipped \u2014 Cursor workers will be idle. Re-run install or pass --cursor-api-key=\u2026 later.");
|
|
6377
6303
|
}
|
|
6378
6304
|
}
|
|
6379
|
-
async function promptDeployLocation() {
|
|
6380
|
-
if (!process.stdin.isTTY) return
|
|
6305
|
+
async function promptDeployLocation(current = "local") {
|
|
6306
|
+
if (!process.stdin.isTTY) return current;
|
|
6307
|
+
const other = current === "cloud" ? "local" : "cloud";
|
|
6381
6308
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
6382
6309
|
return new Promise((resolve4) => {
|
|
6383
6310
|
rl.question(
|
|
6384
|
-
|
|
6311
|
+
`Where should Synkro run?
|
|
6312
|
+
local \u2014 a grading container on this machine (Docker)
|
|
6313
|
+
cloud \u2014 a private container hosted by Synkro (Cloudflare)
|
|
6314
|
+
Both use your own Claude key. Choose [${current}] / ${other}: `,
|
|
6385
6315
|
(answer) => {
|
|
6386
6316
|
rl.close();
|
|
6387
|
-
|
|
6317
|
+
const a = answer.trim().toLowerCase();
|
|
6318
|
+
resolve4(a === "cloud" ? "cloud" : a === "local" ? "local" : current);
|
|
6388
6319
|
}
|
|
6389
6320
|
);
|
|
6390
6321
|
});
|
|
@@ -6419,52 +6350,38 @@ coding patterns and the dashboard shows full history. (Y/n) `
|
|
|
6419
6350
|
rl.close();
|
|
6420
6351
|
}
|
|
6421
6352
|
}
|
|
6422
|
-
async function promptCodexCloudSetup() {
|
|
6423
|
-
if (!process.stdin.isTTY) return false;
|
|
6424
|
-
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
6425
|
-
return new Promise((resolve4) => {
|
|
6426
|
-
rl.question(
|
|
6427
|
-
"Connect a Codex (ChatGPT subscription) session for cloud grading? This opens a\nbrowser to authorize; your subscription is stored securely and refreshed for you. (y/N) ",
|
|
6428
|
-
(answer) => {
|
|
6429
|
-
rl.close();
|
|
6430
|
-
const a = answer.trim().toLowerCase();
|
|
6431
|
-
resolve4(a === "y" || a === "yes");
|
|
6432
|
-
}
|
|
6433
|
-
);
|
|
6434
|
-
});
|
|
6435
|
-
}
|
|
6436
6353
|
function ensureSynkroDir() {
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6354
|
+
mkdirSync12(SYNKRO_DIR10, { recursive: true });
|
|
6355
|
+
mkdirSync12(HOOKS_DIR, { recursive: true });
|
|
6356
|
+
mkdirSync12(BIN_DIR, { recursive: true });
|
|
6357
|
+
mkdirSync12(OFFSETS_DIR, { recursive: true });
|
|
6358
|
+
mkdirSync12(join17(SYNKRO_DIR10, "sessions"), { recursive: true });
|
|
6442
6359
|
}
|
|
6443
6360
|
function writeHookScripts() {
|
|
6444
|
-
const installExtractCorePath =
|
|
6445
|
-
const bashScriptPath =
|
|
6446
|
-
const skillJudgeScriptPath =
|
|
6447
|
-
const cursorSkillJudgePath =
|
|
6448
|
-
const bashFollowupScriptPath =
|
|
6449
|
-
const editPrecheckScriptPath =
|
|
6450
|
-
const cwePrecheckScriptPath =
|
|
6451
|
-
const cvePrecheckScriptPath =
|
|
6452
|
-
const planJudgeScriptPath =
|
|
6453
|
-
const agentJudgeScriptPath =
|
|
6454
|
-
const stopSummaryScriptPath =
|
|
6455
|
-
const sessionStartScriptPath =
|
|
6456
|
-
const transcriptSyncScriptPath =
|
|
6457
|
-
const userPromptSubmitScriptPath =
|
|
6458
|
-
const commonScriptPath =
|
|
6459
|
-
const commonBashScriptPath =
|
|
6460
|
-
const installScanScriptPath =
|
|
6461
|
-
const cursorBashJudgePath =
|
|
6462
|
-
const cursorEditCapturePath =
|
|
6463
|
-
const cursorAgentCapturePath =
|
|
6464
|
-
const mcpStdioProxyPath =
|
|
6465
|
-
const taskActivateIntentScriptPath =
|
|
6466
|
-
const mcpGateScriptPath =
|
|
6467
|
-
const stubCommonPath =
|
|
6361
|
+
const installExtractCorePath = join17(HOOKS_DIR, "installExtractCore.ts");
|
|
6362
|
+
const bashScriptPath = join17(HOOKS_DIR, "cc-bash-judge.ts");
|
|
6363
|
+
const skillJudgeScriptPath = join17(HOOKS_DIR, "cc-skill-judge.ts");
|
|
6364
|
+
const cursorSkillJudgePath = join17(HOOKS_DIR, "cursor-skill-judge.ts");
|
|
6365
|
+
const bashFollowupScriptPath = join17(HOOKS_DIR, "cc-bash-followup.ts");
|
|
6366
|
+
const editPrecheckScriptPath = join17(HOOKS_DIR, "cc-edit-precheck.ts");
|
|
6367
|
+
const cwePrecheckScriptPath = join17(HOOKS_DIR, "cc-cwe-precheck.ts");
|
|
6368
|
+
const cvePrecheckScriptPath = join17(HOOKS_DIR, "cc-cve-precheck.ts");
|
|
6369
|
+
const planJudgeScriptPath = join17(HOOKS_DIR, "cc-plan-judge.ts");
|
|
6370
|
+
const agentJudgeScriptPath = join17(HOOKS_DIR, "cc-agent-judge.ts");
|
|
6371
|
+
const stopSummaryScriptPath = join17(HOOKS_DIR, "cc-stop-summary.ts");
|
|
6372
|
+
const sessionStartScriptPath = join17(HOOKS_DIR, "cc-session-start.ts");
|
|
6373
|
+
const transcriptSyncScriptPath = join17(HOOKS_DIR, "cc-transcript-sync.ts");
|
|
6374
|
+
const userPromptSubmitScriptPath = join17(HOOKS_DIR, "cc-user-prompt-submit.ts");
|
|
6375
|
+
const commonScriptPath = join17(HOOKS_DIR, "_synkro-common.ts");
|
|
6376
|
+
const commonBashScriptPath = join17(HOOKS_DIR, "_synkro-common.sh");
|
|
6377
|
+
const installScanScriptPath = join17(HOOKS_DIR, "cc-install-scan.ts");
|
|
6378
|
+
const cursorBashJudgePath = join17(HOOKS_DIR, "cursor-bash-judge.ts");
|
|
6379
|
+
const cursorEditCapturePath = join17(HOOKS_DIR, "cursor-edit-capture.ts");
|
|
6380
|
+
const cursorAgentCapturePath = join17(HOOKS_DIR, "cursor-agent-capture.ts");
|
|
6381
|
+
const mcpStdioProxyPath = join17(HOOKS_DIR, "mcp-stdio-proxy.ts");
|
|
6382
|
+
const taskActivateIntentScriptPath = join17(HOOKS_DIR, "cc-task-activate-intent.ts");
|
|
6383
|
+
const mcpGateScriptPath = join17(HOOKS_DIR, "cc-mcp-gate.ts");
|
|
6384
|
+
const stubCommonPath = join17(HOOKS_DIR, "_synkro-stub-common.ts");
|
|
6468
6385
|
const stubFiles = [
|
|
6469
6386
|
[stubCommonPath, STUB_COMMON_TS],
|
|
6470
6387
|
[bashScriptPath, STUB_BASH_JUDGE_TS],
|
|
@@ -6495,7 +6412,7 @@ function writeHookScripts() {
|
|
|
6495
6412
|
chmodSync3(mcpStdioProxyPath, 493);
|
|
6496
6413
|
for (const stale of ["_synkro-common.ts", "_synkro-common.sh", "installExtractCore.ts"]) {
|
|
6497
6414
|
try {
|
|
6498
|
-
unlinkSync6(
|
|
6415
|
+
unlinkSync6(join17(HOOKS_DIR, stale));
|
|
6499
6416
|
} catch {
|
|
6500
6417
|
}
|
|
6501
6418
|
}
|
|
@@ -6530,11 +6447,11 @@ function shellQuoteSingle2(value) {
|
|
|
6530
6447
|
}
|
|
6531
6448
|
function resolveSynkroBundle() {
|
|
6532
6449
|
const scriptPath = process.argv[1];
|
|
6533
|
-
if (scriptPath &&
|
|
6450
|
+
if (scriptPath && existsSync20(scriptPath)) return scriptPath;
|
|
6534
6451
|
return null;
|
|
6535
6452
|
}
|
|
6536
6453
|
function writeConfigEnv(opts) {
|
|
6537
|
-
const credsPath =
|
|
6454
|
+
const credsPath = join17(SYNKRO_DIR10, "credentials.json");
|
|
6538
6455
|
const safeGateway = sanitizeConfigValue(opts.gatewayUrl);
|
|
6539
6456
|
const safeUserId = sanitizeConfigValue(opts.userId);
|
|
6540
6457
|
const safeOrgId = sanitizeConfigValue(opts.orgId);
|
|
@@ -6550,7 +6467,7 @@ function writeConfigEnv(opts) {
|
|
|
6550
6467
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle2(credsPath)}`,
|
|
6551
6468
|
`SYNKRO_TIER=${shellQuoteSingle2(safeTier)}`,
|
|
6552
6469
|
`SYNKRO_INFERENCE=${shellQuoteSingle2(safeInference)}`,
|
|
6553
|
-
`SYNKRO_VERSION=${shellQuoteSingle2("1.7.
|
|
6470
|
+
`SYNKRO_VERSION=${shellQuoteSingle2("1.7.65")}`
|
|
6554
6471
|
];
|
|
6555
6472
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle2(safeSynkroBin)}`);
|
|
6556
6473
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle2(safeUserId)}`);
|
|
@@ -6583,7 +6500,7 @@ async function getOrMintCloudToken(gatewayUrl) {
|
|
|
6583
6500
|
assertGatewayAllowed(gatewayUrl);
|
|
6584
6501
|
let stored = "";
|
|
6585
6502
|
try {
|
|
6586
|
-
stored =
|
|
6503
|
+
stored = readFileSync17(CLOUD_JWT_PATH, "utf-8").trim();
|
|
6587
6504
|
} catch {
|
|
6588
6505
|
}
|
|
6589
6506
|
if (stored && !jwtExpired(stored)) return stored;
|
|
@@ -6642,7 +6559,7 @@ async function provisionCloudContainer(opts) {
|
|
|
6642
6559
|
let cursorApiKey = "";
|
|
6643
6560
|
if (cursorTotal > 0) {
|
|
6644
6561
|
try {
|
|
6645
|
-
cursorApiKey =
|
|
6562
|
+
cursorApiKey = readFileSync17(join17(SYNKRO_DIR10, "cursor-creds", "api-key"), "utf-8").trim();
|
|
6646
6563
|
} catch {
|
|
6647
6564
|
}
|
|
6648
6565
|
}
|
|
@@ -6799,8 +6716,8 @@ async function verifyCloudGrader(jwt2) {
|
|
|
6799
6716
|
}
|
|
6800
6717
|
function readPersistedDeployLocation() {
|
|
6801
6718
|
try {
|
|
6802
|
-
if (
|
|
6803
|
-
const m =
|
|
6719
|
+
if (existsSync20(CONFIG_PATH4)) {
|
|
6720
|
+
const m = readFileSync17(CONFIG_PATH4, "utf-8").match(/^SYNKRO_DEPLOY_LOCATION='([^']*)'/m);
|
|
6804
6721
|
if (m?.[1] === "cloud") return "cloud";
|
|
6805
6722
|
}
|
|
6806
6723
|
} catch {
|
|
@@ -6808,8 +6725,8 @@ function readPersistedDeployLocation() {
|
|
|
6808
6725
|
return "local";
|
|
6809
6726
|
}
|
|
6810
6727
|
function updateConfigEnvLocation(location) {
|
|
6811
|
-
if (!
|
|
6812
|
-
let env =
|
|
6728
|
+
if (!existsSync20(CONFIG_PATH4)) return;
|
|
6729
|
+
let env = readFileSync17(CONFIG_PATH4, "utf-8");
|
|
6813
6730
|
const set = (k, v) => {
|
|
6814
6731
|
const re = new RegExp(`^${k}=.*$`, "m");
|
|
6815
6732
|
const line = `${k}='${v}'`;
|
|
@@ -6824,7 +6741,7 @@ async function applyMcpConfig(opts) {
|
|
|
6824
6741
|
if (!opts.hasClaudeCode && !opts.hasCursor) return;
|
|
6825
6742
|
let mcpJwt = "";
|
|
6826
6743
|
try {
|
|
6827
|
-
mcpJwt =
|
|
6744
|
+
mcpJwt = readFileSync17(join17(SYNKRO_DIR10, ".mcp-jwt"), "utf-8").trim();
|
|
6828
6745
|
} catch {
|
|
6829
6746
|
}
|
|
6830
6747
|
if (!mcpJwt) {
|
|
@@ -6859,13 +6776,15 @@ async function applyMcpConfig(opts) {
|
|
|
6859
6776
|
}
|
|
6860
6777
|
async function reconcileDeployLocation() {
|
|
6861
6778
|
const sf = readFullSynkroFile();
|
|
6862
|
-
const
|
|
6779
|
+
const tomlLoc = sf?.grader.location === "cloud" ? "cloud" : "local";
|
|
6863
6780
|
const current = readPersistedDeployLocation();
|
|
6781
|
+
const desired = await promptDeployLocation(current || tomlLoc);
|
|
6782
|
+
if (desired !== tomlLoc) updateSynkroTomlLocation(desired);
|
|
6864
6783
|
if (desired === current) return { location: desired, changed: false };
|
|
6865
6784
|
const hasClaudeCode = sf ? sf.harness.includes("claude-code") : true;
|
|
6866
6785
|
const hasCursor = sf ? sf.harness.includes("cursor") : false;
|
|
6867
6786
|
console.log(`
|
|
6868
|
-
|
|
6787
|
+
Deploy location: ${current || "(none)"} \u2192 ${desired}
|
|
6869
6788
|
`);
|
|
6870
6789
|
if (!isAuthenticated()) {
|
|
6871
6790
|
console.log(" Opening browser for Synkro auth...");
|
|
@@ -6942,8 +6861,8 @@ function resolveDeploymentMode() {
|
|
|
6942
6861
|
const envOverride = process.env.SYNKRO_DEPLOYMENT_MODE?.toLowerCase();
|
|
6943
6862
|
if (envOverride === "bare-host" || envOverride === "docker") return envOverride;
|
|
6944
6863
|
try {
|
|
6945
|
-
if (
|
|
6946
|
-
const m =
|
|
6864
|
+
if (existsSync20(CONFIG_PATH4)) {
|
|
6865
|
+
const m = readFileSync17(CONFIG_PATH4, "utf-8").match(/^SYNKRO_DEPLOYMENT_MODE='([^']*)'/m);
|
|
6947
6866
|
const val = m?.[1]?.toLowerCase();
|
|
6948
6867
|
if (val === "bare-host" || val === "docker") return val;
|
|
6949
6868
|
}
|
|
@@ -6970,16 +6889,16 @@ function collectLocalMetadata(includeClaudeCode = true) {
|
|
|
6970
6889
|
meta.cc_version = execSync6("claude --version", { encoding: "utf-8", timeout: 5e3 }).trim().split("\n")[0];
|
|
6971
6890
|
} catch {
|
|
6972
6891
|
}
|
|
6973
|
-
const claudeDir =
|
|
6892
|
+
const claudeDir = join17(homedir17(), ".claude");
|
|
6974
6893
|
try {
|
|
6975
|
-
const settings = JSON.parse(
|
|
6894
|
+
const settings = JSON.parse(readFileSync17(join17(claudeDir, "settings.json"), "utf-8"));
|
|
6976
6895
|
const plugins = Object.keys(settings.enabledPlugins ?? {}).filter((k) => settings.enabledPlugins[k]);
|
|
6977
6896
|
if (plugins.length) meta.enabled_plugins = plugins;
|
|
6978
6897
|
if (settings.permissions?.defaultMode) meta.permissions_mode = settings.permissions.defaultMode;
|
|
6979
6898
|
} catch {
|
|
6980
6899
|
}
|
|
6981
6900
|
try {
|
|
6982
|
-
const mcpCache = JSON.parse(
|
|
6901
|
+
const mcpCache = JSON.parse(readFileSync17(join17(claudeDir, "mcp-needs-auth-cache.json"), "utf-8"));
|
|
6983
6902
|
const mcpNames = Object.keys(mcpCache);
|
|
6984
6903
|
if (mcpNames.length) meta.mcp_servers = mcpNames;
|
|
6985
6904
|
} catch {
|
|
@@ -6991,10 +6910,10 @@ function collectLocalMetadata(includeClaudeCode = true) {
|
|
|
6991
6910
|
} catch {
|
|
6992
6911
|
}
|
|
6993
6912
|
try {
|
|
6994
|
-
const sessionsDir =
|
|
6913
|
+
const sessionsDir = join17(claudeDir, "sessions");
|
|
6995
6914
|
const files = readdirSync3(sessionsDir).filter((f) => f.endsWith(".json")).slice(-5);
|
|
6996
6915
|
for (const f of files) {
|
|
6997
|
-
const s = JSON.parse(
|
|
6916
|
+
const s = JSON.parse(readFileSync17(join17(sessionsDir, f), "utf-8"));
|
|
6998
6917
|
if (s.version) {
|
|
6999
6918
|
meta.cc_version = meta.cc_version || s.version;
|
|
7000
6919
|
break;
|
|
@@ -7127,9 +7046,11 @@ async function installCommand(opts = {}) {
|
|
|
7127
7046
|
(a) => a.kind === "claude_code" && wantCC || a.kind === "cursor" && wantCursor
|
|
7128
7047
|
);
|
|
7129
7048
|
if (agents.length === 0 && detected.length > 0) agents = detected;
|
|
7130
|
-
deployLocation = existingSynkro.grader.location === "cloud" ? "cloud" : "local";
|
|
7131
7049
|
gradingMode = existingSynkro.grader.mode === "byok" ? "byok" : "local";
|
|
7050
|
+
const tomlLocation = existingSynkro.grader.location === "cloud" ? "cloud" : "local";
|
|
7051
|
+
deployLocation = await promptDeployLocation(tomlLocation);
|
|
7132
7052
|
storageMode = deployLocation === "cloud" ? "cloud" : "local";
|
|
7053
|
+
if (deployLocation !== tomlLocation) updateSynkroTomlLocation(deployLocation);
|
|
7133
7054
|
console.log(`Using .synkro config:`);
|
|
7134
7055
|
for (const w of existingSynkro.warnings) console.warn(` \u26A0 ${w}`);
|
|
7135
7056
|
console.log(` harness: ${existingSynkro.harness.join(", ")}`);
|
|
@@ -7190,7 +7111,7 @@ async function installCommand(opts = {}) {
|
|
|
7190
7111
|
await setTelemetryState({ enabled: true, remoteFlushEnabled: telemetryConsent });
|
|
7191
7112
|
emit("install", {
|
|
7192
7113
|
phase: "started",
|
|
7193
|
-
cli_version_to: "1.7.
|
|
7114
|
+
cli_version_to: "1.7.65",
|
|
7194
7115
|
agents_detected: agents.map((a) => a.kind),
|
|
7195
7116
|
with_github: false,
|
|
7196
7117
|
with_local_cc: false,
|
|
@@ -7202,9 +7123,9 @@ async function installCommand(opts = {}) {
|
|
|
7202
7123
|
const scripts = writeHookScripts();
|
|
7203
7124
|
console.log("Wrote hook scripts to ~/.synkro/hooks/\n");
|
|
7204
7125
|
for (const mode of ["edit", "bash"]) {
|
|
7205
|
-
const pidFile =
|
|
7126
|
+
const pidFile = join17(SYNKRO_DIR10, "daemon", mode, "daemon.pid");
|
|
7206
7127
|
try {
|
|
7207
|
-
const pid = parseInt(
|
|
7128
|
+
const pid = parseInt(readFileSync17(pidFile, "utf-8").trim(), 10);
|
|
7208
7129
|
if (pid > 0) {
|
|
7209
7130
|
process.kill(pid, "SIGTERM");
|
|
7210
7131
|
console.log(`Stopped stale ${mode} grader daemon (pid ${pid})`);
|
|
@@ -7289,7 +7210,7 @@ async function installCommand(opts = {}) {
|
|
|
7289
7210
|
if (mintResp.ok) {
|
|
7290
7211
|
const minted = await mintResp.json();
|
|
7291
7212
|
mcpJwt = minted.token;
|
|
7292
|
-
writeFileSync13(
|
|
7213
|
+
writeFileSync13(join17(SYNKRO_DIR10, ".mcp-jwt"), mcpJwt + "\n", { mode: 384 });
|
|
7293
7214
|
} else {
|
|
7294
7215
|
console.warn(" \u26A0 Could not mint MCP token \u2014 local server will reject requests until re-installed.");
|
|
7295
7216
|
}
|
|
@@ -7317,7 +7238,7 @@ async function installCommand(opts = {}) {
|
|
|
7317
7238
|
throw new Error(`mcp-token mint failed (${mintResp.status}): ${errText.slice(0, 200)}`);
|
|
7318
7239
|
}
|
|
7319
7240
|
const minted = await mintResp.json();
|
|
7320
|
-
writeFileSync13(
|
|
7241
|
+
writeFileSync13(join17(SYNKRO_DIR10, ".mcp-jwt"), minted.token + "\n", { mode: 384 });
|
|
7321
7242
|
const mcp = installMcpConfig({ gatewayUrl, bearerToken: minted.token });
|
|
7322
7243
|
console.log(`Registered Synkro guardrails MCP server in ${mcp.path}`);
|
|
7323
7244
|
console.log(` url: ${mcp.url}`);
|
|
@@ -7334,8 +7255,8 @@ async function installCommand(opts = {}) {
|
|
|
7334
7255
|
if (hasCursor && !opts.noMcp) {
|
|
7335
7256
|
try {
|
|
7336
7257
|
if (useLocalMcp) {
|
|
7337
|
-
const jwtPath =
|
|
7338
|
-
if (!
|
|
7258
|
+
const jwtPath = join17(SYNKRO_DIR10, ".mcp-jwt");
|
|
7259
|
+
if (!existsSync20(jwtPath)) {
|
|
7339
7260
|
const mintResp = await fetch(`${gatewayUrl}/api/v1/cli/mcp-token`, {
|
|
7340
7261
|
method: "POST",
|
|
7341
7262
|
headers: { "Authorization": `Bearer ${token}`, "Content-Type": "application/json" },
|
|
@@ -7363,7 +7284,7 @@ async function installCommand(opts = {}) {
|
|
|
7363
7284
|
throw new Error(`mcp-token mint failed (${mintResp.status}): ${errText.slice(0, 200)}`);
|
|
7364
7285
|
}
|
|
7365
7286
|
const minted = await mintResp.json();
|
|
7366
|
-
writeFileSync13(
|
|
7287
|
+
writeFileSync13(join17(SYNKRO_DIR10, ".mcp-jwt"), minted.token + "\n", { mode: 384 });
|
|
7367
7288
|
const mcp = installCursorMcpConfig({ gatewayUrl, bearerToken: minted.token });
|
|
7368
7289
|
console.log(`Registered Synkro guardrails MCP server in ${mcp.path}`);
|
|
7369
7290
|
console.log(` url: ${mcp.url}`);
|
|
@@ -7456,7 +7377,7 @@ async function installCommand(opts = {}) {
|
|
|
7456
7377
|
const ready = await waitForContainerReady(6e4);
|
|
7457
7378
|
if (ready) {
|
|
7458
7379
|
console.log(" \u2713 container ready");
|
|
7459
|
-
const mcpJwt =
|
|
7380
|
+
const mcpJwt = readFileSync17(join17(SYNKRO_DIR10, ".mcp-jwt"), "utf-8").trim();
|
|
7460
7381
|
try {
|
|
7461
7382
|
const ingestResp = await fetch(`http://127.0.0.1:${hostMcpPort}/api/ingest`, {
|
|
7462
7383
|
method: "POST",
|
|
@@ -7491,11 +7412,6 @@ async function installCommand(opts = {}) {
|
|
|
7491
7412
|
if (graderUsesCursor) await promptCursorApiKey(opts);
|
|
7492
7413
|
await provisionCloudContainer({ gatewayUrl, jwt: token, orgId, userId, email, hasClaudeCode, hasCursor });
|
|
7493
7414
|
cloudGradeOk = await verifyCloudGrader(token);
|
|
7494
|
-
if (await promptCodexCloudSetup()) {
|
|
7495
|
-
const { setupCodexCloud: setupCodexCloud2 } = await Promise.resolve().then(() => (init_codexCloudSetup(), codexCloudSetup_exports));
|
|
7496
|
-
const res = await setupCodexCloud2(gatewayUrl, token, (m) => console.log(` ${m}`));
|
|
7497
|
-
if (!res.ok) console.warn(` \u26A0 Codex cloud setup skipped: ${res.error}`);
|
|
7498
|
-
}
|
|
7499
7415
|
}
|
|
7500
7416
|
if (transcriptConsent) {
|
|
7501
7417
|
const repo = detectGitRepo2();
|
|
@@ -7504,7 +7420,7 @@ async function installCommand(opts = {}) {
|
|
|
7504
7420
|
try {
|
|
7505
7421
|
let mcpToken = "";
|
|
7506
7422
|
try {
|
|
7507
|
-
mcpToken =
|
|
7423
|
+
mcpToken = readFileSync17(join17(SYNKRO_DIR10, ".mcp-jwt"), "utf-8").trim();
|
|
7508
7424
|
} catch {
|
|
7509
7425
|
}
|
|
7510
7426
|
if (mcpToken) {
|
|
@@ -7640,8 +7556,8 @@ function writeSynkroFileIfMissing(opts) {
|
|
|
7640
7556
|
try {
|
|
7641
7557
|
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7642
7558
|
if (!root) return;
|
|
7643
|
-
if (root ===
|
|
7644
|
-
const fp =
|
|
7559
|
+
if (root === homedir17()) return;
|
|
7560
|
+
const fp = join17(root, "synkro.toml");
|
|
7645
7561
|
let hasFile = false;
|
|
7646
7562
|
try {
|
|
7647
7563
|
hasFile = statSync2(fp).isFile();
|
|
@@ -7682,13 +7598,35 @@ function writeSynkroFileIfMissing(opts) {
|
|
|
7682
7598
|
} catch {
|
|
7683
7599
|
}
|
|
7684
7600
|
}
|
|
7601
|
+
function updateSynkroTomlLocation(location) {
|
|
7602
|
+
try {
|
|
7603
|
+
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7604
|
+
if (!root || root === homedir17()) return;
|
|
7605
|
+
const fp = join17(root, "synkro.toml");
|
|
7606
|
+
let txt = "";
|
|
7607
|
+
try {
|
|
7608
|
+
if (!statSync2(fp).isFile()) return;
|
|
7609
|
+
txt = readFileSync17(fp, "utf-8");
|
|
7610
|
+
} catch {
|
|
7611
|
+
return;
|
|
7612
|
+
}
|
|
7613
|
+
const re = /^(\s*location\s*=\s*).*$/m;
|
|
7614
|
+
if (!re.test(txt)) return;
|
|
7615
|
+
const next = txt.replace(re, `$1"${location}"`);
|
|
7616
|
+
if (next !== txt) {
|
|
7617
|
+
writeFileSync13(fp, next, "utf-8");
|
|
7618
|
+
console.log(` synkro.toml: [grader] location = "${location}"`);
|
|
7619
|
+
}
|
|
7620
|
+
} catch {
|
|
7621
|
+
}
|
|
7622
|
+
}
|
|
7685
7623
|
function readFullSynkroFile() {
|
|
7686
7624
|
try {
|
|
7687
7625
|
const root = execSync6("git rev-parse --show-toplevel", { encoding: "utf-8", timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
7688
7626
|
if (!root) return null;
|
|
7689
|
-
const fp =
|
|
7690
|
-
if (!
|
|
7691
|
-
const parsed = parseSynkroToml2(
|
|
7627
|
+
const fp = join17(root, "synkro.toml");
|
|
7628
|
+
if (!existsSync20(fp)) return null;
|
|
7629
|
+
const parsed = parseSynkroToml2(readFileSync17(fp, "utf-8"));
|
|
7692
7630
|
const valid = ["claude-code", "cursor"];
|
|
7693
7631
|
const harness = Array.isArray(parsed.harness) ? parsed.harness.filter((h) => valid.includes(h)) : ["claude-code", "cursor"];
|
|
7694
7632
|
const resolved = resolveGraderPool(parsed);
|
|
@@ -7726,7 +7664,7 @@ function reconcileHarness() {
|
|
|
7726
7664
|
console.log(`synkro.toml: harness=[${sf.harness.join(", ")}] pool=${poolLabel(sf.grader.pool)} mode=${sf.grader.mode}`);
|
|
7727
7665
|
const scripts = writeHookScripts();
|
|
7728
7666
|
console.log("Wrote hook scripts to ~/.synkro/hooks/");
|
|
7729
|
-
const ccSettings =
|
|
7667
|
+
const ccSettings = join17(homedir17(), ".claude", "settings.json");
|
|
7730
7668
|
if (wantCC) {
|
|
7731
7669
|
installCCHooks(ccSettings, {
|
|
7732
7670
|
bashJudgeScriptPath: scripts.bashScript,
|
|
@@ -7747,7 +7685,7 @@ function reconcileHarness() {
|
|
|
7747
7685
|
});
|
|
7748
7686
|
console.log(" \u2713 Claude Code hooks registered");
|
|
7749
7687
|
try {
|
|
7750
|
-
const mcpJwt =
|
|
7688
|
+
const mcpJwt = readFileSync17(join17(SYNKRO_DIR10, ".mcp-jwt"), "utf-8").trim();
|
|
7751
7689
|
if (mcpJwt) {
|
|
7752
7690
|
installMcpConfig({ gatewayUrl: "", bearerToken: mcpJwt, local: true });
|
|
7753
7691
|
console.log(" \u2713 Claude Code MCP registered");
|
|
@@ -7759,7 +7697,7 @@ function reconcileHarness() {
|
|
|
7759
7697
|
if (uninstallMcpConfig()) console.log(" \u2717 Claude Code MCP removed");
|
|
7760
7698
|
if (uninstallClaudeDesktopMcpConfig()) console.log(" \u2717 Claude Desktop MCP removed");
|
|
7761
7699
|
}
|
|
7762
|
-
const cursorHooks =
|
|
7700
|
+
const cursorHooks = join17(homedir17(), ".cursor", "hooks.json");
|
|
7763
7701
|
if (wantCursor) {
|
|
7764
7702
|
installCursorHooks(cursorHooks, {
|
|
7765
7703
|
bashJudgeScriptPath: scripts.cursorBashJudgeScript,
|
|
@@ -7842,7 +7780,7 @@ async function syncSkillFiles() {
|
|
|
7842
7780
|
if (resolved.length === 0) return;
|
|
7843
7781
|
const mcpPort = process.env.SYNKRO_MCP_PORT || "18931";
|
|
7844
7782
|
const tasks = resolved.map((fp) => {
|
|
7845
|
-
const content =
|
|
7783
|
+
const content = readFileSync17(fp, "utf-8");
|
|
7846
7784
|
const source = `skill:${fp.split("/").pop()}`;
|
|
7847
7785
|
if (!content.trim()) {
|
|
7848
7786
|
console.log(` \u2298 skill ${source}: empty file, skipped`);
|
|
@@ -7863,15 +7801,15 @@ function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNam
|
|
|
7863
7801
|
const roots = [];
|
|
7864
7802
|
const add = (p) => {
|
|
7865
7803
|
try {
|
|
7866
|
-
if (p &&
|
|
7804
|
+
if (p && existsSync20(p) && statSync2(p).isDirectory()) roots.push(p);
|
|
7867
7805
|
} catch {
|
|
7868
7806
|
}
|
|
7869
7807
|
};
|
|
7870
|
-
add(
|
|
7871
|
-
add(
|
|
7808
|
+
add(join17(homedir17(), ".claude", "skills"));
|
|
7809
|
+
add(join17(homedir17(), ".agents", "skills"));
|
|
7872
7810
|
if (repoRoot) {
|
|
7873
|
-
add(
|
|
7874
|
-
add(
|
|
7811
|
+
add(join17(repoRoot, ".claude", "skills"));
|
|
7812
|
+
add(join17(repoRoot, ".agents", "skills"));
|
|
7875
7813
|
}
|
|
7876
7814
|
const out = [];
|
|
7877
7815
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -7882,7 +7820,7 @@ function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNam
|
|
|
7882
7820
|
try {
|
|
7883
7821
|
const st = statSync2(file);
|
|
7884
7822
|
if (!st.isFile() || st.size > 2e5) return;
|
|
7885
|
-
content =
|
|
7823
|
+
content = readFileSync17(file, "utf-8");
|
|
7886
7824
|
} catch {
|
|
7887
7825
|
return;
|
|
7888
7826
|
}
|
|
@@ -7902,7 +7840,7 @@ function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNam
|
|
|
7902
7840
|
}
|
|
7903
7841
|
for (const entry of entries) {
|
|
7904
7842
|
if (entry.startsWith(".")) continue;
|
|
7905
|
-
const full =
|
|
7843
|
+
const full = join17(root, entry);
|
|
7906
7844
|
let st;
|
|
7907
7845
|
try {
|
|
7908
7846
|
st = statSync2(full);
|
|
@@ -7910,8 +7848,8 @@ function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNam
|
|
|
7910
7848
|
continue;
|
|
7911
7849
|
}
|
|
7912
7850
|
if (st.isDirectory()) {
|
|
7913
|
-
const skillMd =
|
|
7914
|
-
if (
|
|
7851
|
+
const skillMd = join17(full, "SKILL.md");
|
|
7852
|
+
if (existsSync20(skillMd)) consider(skillMd, entry);
|
|
7915
7853
|
} else if (/\.mdx?$/i.test(entry) && entry.toUpperCase() !== "README.MD") {
|
|
7916
7854
|
consider(full, entry.replace(/\.mdx?$/i, ""));
|
|
7917
7855
|
}
|
|
@@ -7960,7 +7898,7 @@ async function discoverAndIngestSkills() {
|
|
|
7960
7898
|
if (sf?.skills?.length) {
|
|
7961
7899
|
for (const fp of resolveSkillPaths(sf.skills, sf._repoRoot)) {
|
|
7962
7900
|
try {
|
|
7963
|
-
excludeHashes.add(createHash2("sha256").update(
|
|
7901
|
+
excludeHashes.add(createHash2("sha256").update(readFileSync17(fp, "utf-8")).digest("hex"));
|
|
7964
7902
|
} catch {
|
|
7965
7903
|
}
|
|
7966
7904
|
}
|
|
@@ -7991,7 +7929,7 @@ async function discoverAndIngestSkills() {
|
|
|
7991
7929
|
const setHash = discoverySetHash(selectable);
|
|
7992
7930
|
let prev = "";
|
|
7993
7931
|
try {
|
|
7994
|
-
prev =
|
|
7932
|
+
prev = readFileSync17(SKILLS_DISCOVERED_PATH, "utf-8").trim();
|
|
7995
7933
|
} catch {
|
|
7996
7934
|
}
|
|
7997
7935
|
if (prev === setHash) return;
|
|
@@ -8031,17 +7969,17 @@ function detectGitRepo2() {
|
|
|
8031
7969
|
function getClaudeProjectsFolder() {
|
|
8032
7970
|
const cwd = process.cwd();
|
|
8033
7971
|
const sanitized = "-" + cwd.replace(/\//g, "-");
|
|
8034
|
-
const projectsDir =
|
|
8035
|
-
return
|
|
7972
|
+
const projectsDir = join17(homedir17(), ".claude", "projects", sanitized);
|
|
7973
|
+
return existsSync20(projectsDir) ? projectsDir : null;
|
|
8036
7974
|
}
|
|
8037
7975
|
function extractSessionInsights(projectsDir) {
|
|
8038
7976
|
const insights = [];
|
|
8039
7977
|
const files = readdirSync3(projectsDir).filter((f) => f.endsWith(".jsonl"));
|
|
8040
7978
|
for (const file of files) {
|
|
8041
7979
|
const sessionId = file.replace(".jsonl", "");
|
|
8042
|
-
const filePath =
|
|
7980
|
+
const filePath = join17(projectsDir, file);
|
|
8043
7981
|
try {
|
|
8044
|
-
const content =
|
|
7982
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
8045
7983
|
const lines = content.split("\n").filter(Boolean);
|
|
8046
7984
|
for (let i = 0; i < lines.length; i++) {
|
|
8047
7985
|
try {
|
|
@@ -8120,14 +8058,14 @@ function cursorProjectSlug(workspaceRoot) {
|
|
|
8120
8058
|
return workspaceRoot.replace(/^[/]+/, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
8121
8059
|
}
|
|
8122
8060
|
function getCursorTranscriptsDir() {
|
|
8123
|
-
const dir =
|
|
8124
|
-
return
|
|
8061
|
+
const dir = join17(homedir17(), ".cursor", "projects", cursorProjectSlug(process.cwd()), "agent-transcripts");
|
|
8062
|
+
return existsSync20(dir) ? dir : null;
|
|
8125
8063
|
}
|
|
8126
8064
|
function isSafeConvId(id) {
|
|
8127
8065
|
return /^[A-Za-z0-9_-]+$/.test(id);
|
|
8128
8066
|
}
|
|
8129
8067
|
function parseCursorTranscriptFile(filePath) {
|
|
8130
|
-
const content =
|
|
8068
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
8131
8069
|
const lines = content.split("\n").filter(Boolean);
|
|
8132
8070
|
const messages = [];
|
|
8133
8071
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8159,8 +8097,8 @@ async function syncCursorTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8159
8097
|
for (let i = 0; i < convDirs.length; i++) {
|
|
8160
8098
|
const convId = convDirs[i];
|
|
8161
8099
|
if (!isSafeConvId(convId)) continue;
|
|
8162
|
-
const filePath =
|
|
8163
|
-
if (!
|
|
8100
|
+
const filePath = join17(dir, convId, `${convId}.jsonl`);
|
|
8101
|
+
if (!existsSync20(filePath)) continue;
|
|
8164
8102
|
try {
|
|
8165
8103
|
const all = parseCursorTranscriptFile(filePath);
|
|
8166
8104
|
const messages = all.length > 500 ? all.slice(-500) : all;
|
|
@@ -8182,8 +8120,8 @@ async function syncCursorTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8182
8120
|
process.stdout.write(`\r Progress: ${i + 1}/${convDirs.length} sessions (${totalMessages} messages embedded) `);
|
|
8183
8121
|
}
|
|
8184
8122
|
try {
|
|
8185
|
-
const lc =
|
|
8186
|
-
writeFileSync13(
|
|
8123
|
+
const lc = readFileSync17(filePath, "utf-8").split("\n").filter(Boolean).length;
|
|
8124
|
+
writeFileSync13(join17(OFFSETS_DIR, convId), String(lc), "utf-8");
|
|
8187
8125
|
} catch {
|
|
8188
8126
|
}
|
|
8189
8127
|
}
|
|
@@ -8191,7 +8129,7 @@ async function syncCursorTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8191
8129
|
return { sessions: totalSessions, messages: totalMessages };
|
|
8192
8130
|
}
|
|
8193
8131
|
function parseTranscriptFile(filePath) {
|
|
8194
|
-
const content =
|
|
8132
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
8195
8133
|
const lines = content.split("\n").filter(Boolean);
|
|
8196
8134
|
const messages = [];
|
|
8197
8135
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8239,7 +8177,7 @@ async function syncTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8239
8177
|
for (let i = 0; i < files.length; i++) {
|
|
8240
8178
|
const file = files[i];
|
|
8241
8179
|
const sessionId = file.replace(".jsonl", "");
|
|
8242
|
-
const filePath =
|
|
8180
|
+
const filePath = join17(projectsDir, file);
|
|
8243
8181
|
try {
|
|
8244
8182
|
const allMessages = parseTranscriptFile(filePath);
|
|
8245
8183
|
const messages = allMessages.length > 500 ? allMessages.slice(-500) : allMessages;
|
|
@@ -8261,9 +8199,9 @@ async function syncTranscriptsLocal(mcpPort, mcpToken, repo) {
|
|
|
8261
8199
|
process.stdout.write(`\r Progress: ${i + 1}/${files.length} sessions (${totalMessages} messages embedded) `);
|
|
8262
8200
|
}
|
|
8263
8201
|
try {
|
|
8264
|
-
const content =
|
|
8202
|
+
const content = readFileSync17(join17(projectsDir, file), "utf-8");
|
|
8265
8203
|
const lineCount = content.split("\n").filter(Boolean).length;
|
|
8266
|
-
writeFileSync13(
|
|
8204
|
+
writeFileSync13(join17(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
|
|
8267
8205
|
} catch {
|
|
8268
8206
|
}
|
|
8269
8207
|
}
|
|
@@ -8284,7 +8222,7 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
|
|
|
8284
8222
|
const sessions = [];
|
|
8285
8223
|
for (const file of batch) {
|
|
8286
8224
|
const sessionId = file.replace(".jsonl", "");
|
|
8287
|
-
const filePath =
|
|
8225
|
+
const filePath = join17(projectsDir, file);
|
|
8288
8226
|
try {
|
|
8289
8227
|
const allMessages = parseTranscriptFile(filePath);
|
|
8290
8228
|
const messages = allMessages.length > maxMessagesPerSession ? allMessages.slice(-maxMessagesPerSession) : allMessages;
|
|
@@ -8313,18 +8251,18 @@ async function syncTranscriptsBulk(gatewayUrl, token, repo) {
|
|
|
8313
8251
|
}
|
|
8314
8252
|
for (const file of batch) {
|
|
8315
8253
|
const sessionId = file.replace(".jsonl", "");
|
|
8316
|
-
const filePath =
|
|
8254
|
+
const filePath = join17(projectsDir, file);
|
|
8317
8255
|
try {
|
|
8318
|
-
const content =
|
|
8256
|
+
const content = readFileSync17(filePath, "utf-8");
|
|
8319
8257
|
const lineCount = content.split("\n").filter(Boolean).length;
|
|
8320
|
-
writeFileSync13(
|
|
8258
|
+
writeFileSync13(join17(OFFSETS_DIR, sessionId), String(lineCount), "utf-8");
|
|
8321
8259
|
} catch {
|
|
8322
8260
|
}
|
|
8323
8261
|
}
|
|
8324
8262
|
}
|
|
8325
8263
|
return { sessions: totalSessions, messages: totalMessages };
|
|
8326
8264
|
}
|
|
8327
|
-
var
|
|
8265
|
+
var SYNKRO_DIR10, HOOKS_DIR, BIN_DIR, CONFIG_PATH4, MCP_STDIO_PROXY_SRC, OFFSETS_DIR, CLOUD_JWT_PATH, SKILLS_DISCOVERED_PATH;
|
|
8328
8266
|
var init_install = __esm({
|
|
8329
8267
|
"cli/commands/install.ts"() {
|
|
8330
8268
|
"use strict";
|
|
@@ -8342,10 +8280,10 @@ var init_install = __esm({
|
|
|
8342
8280
|
init_claudeDesktopTap();
|
|
8343
8281
|
init_dockerInstall();
|
|
8344
8282
|
init_setupToken();
|
|
8345
|
-
|
|
8346
|
-
HOOKS_DIR =
|
|
8347
|
-
BIN_DIR =
|
|
8348
|
-
CONFIG_PATH4 =
|
|
8283
|
+
SYNKRO_DIR10 = join17(homedir17(), ".synkro");
|
|
8284
|
+
HOOKS_DIR = join17(SYNKRO_DIR10, "hooks");
|
|
8285
|
+
BIN_DIR = join17(SYNKRO_DIR10, "bin");
|
|
8286
|
+
CONFIG_PATH4 = join17(SYNKRO_DIR10, "config.env");
|
|
8349
8287
|
MCP_STDIO_PROXY_SRC = `#!/usr/bin/env bun
|
|
8350
8288
|
import { readFileSync } from 'node:fs';
|
|
8351
8289
|
import { homedir } from 'node:os';
|
|
@@ -8456,21 +8394,21 @@ rl.on('line', async (line) => {
|
|
|
8456
8394
|
}
|
|
8457
8395
|
});
|
|
8458
8396
|
`;
|
|
8459
|
-
OFFSETS_DIR =
|
|
8460
|
-
CLOUD_JWT_PATH =
|
|
8461
|
-
SKILLS_DISCOVERED_PATH =
|
|
8397
|
+
OFFSETS_DIR = join17(SYNKRO_DIR10, ".transcript-offsets");
|
|
8398
|
+
CLOUD_JWT_PATH = join17(SYNKRO_DIR10, ".cloud-jwt");
|
|
8399
|
+
SKILLS_DISCOVERED_PATH = join17(SYNKRO_DIR10, ".skills-discovered");
|
|
8462
8400
|
}
|
|
8463
8401
|
});
|
|
8464
8402
|
|
|
8465
8403
|
// cli/local-cc/install.ts
|
|
8466
|
-
import { existsSync as
|
|
8467
|
-
import { join as
|
|
8468
|
-
import { homedir as
|
|
8469
|
-
import { spawnSync as
|
|
8404
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, readFileSync as readFileSync18, chmodSync as chmodSync4, copyFileSync as copyFileSync2, renameSync as renameSync6, unlinkSync as unlinkSync7, openSync as openSync2, fsyncSync, closeSync as closeSync2 } from "fs";
|
|
8405
|
+
import { join as join18 } from "path";
|
|
8406
|
+
import { homedir as homedir18 } from "os";
|
|
8407
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
8470
8408
|
function writePluginFiles() {
|
|
8471
8409
|
for (const c of CHANNELS) {
|
|
8472
|
-
|
|
8473
|
-
|
|
8410
|
+
mkdirSync13(c.sessionDir, { recursive: true });
|
|
8411
|
+
mkdirSync13(c.pluginSettingsDir, { recursive: true });
|
|
8474
8412
|
writeFileSync14(c.pluginPkgPath, PLUGIN_PACKAGE_JSON, "utf-8");
|
|
8475
8413
|
writeFileSync14(
|
|
8476
8414
|
c.pluginSettingsPath,
|
|
@@ -8493,7 +8431,7 @@ function writePluginFiles() {
|
|
|
8493
8431
|
}
|
|
8494
8432
|
function runBunInstall() {
|
|
8495
8433
|
for (const c of CHANNELS) {
|
|
8496
|
-
const r =
|
|
8434
|
+
const r = spawnSync5("bun", ["install", "--silent"], {
|
|
8497
8435
|
cwd: c.sessionDir,
|
|
8498
8436
|
encoding: "utf-8",
|
|
8499
8437
|
timeout: 12e4
|
|
@@ -8506,10 +8444,10 @@ function runBunInstall() {
|
|
|
8506
8444
|
}
|
|
8507
8445
|
}
|
|
8508
8446
|
function safelyMutateClaudeJson(mutator) {
|
|
8509
|
-
if (!
|
|
8447
|
+
if (!existsSync21(CLAUDE_JSON_PATH)) {
|
|
8510
8448
|
return;
|
|
8511
8449
|
}
|
|
8512
|
-
const originalText =
|
|
8450
|
+
const originalText = readFileSync18(CLAUDE_JSON_PATH, "utf-8");
|
|
8513
8451
|
let parsed;
|
|
8514
8452
|
try {
|
|
8515
8453
|
parsed = JSON.parse(originalText);
|
|
@@ -8609,15 +8547,15 @@ function patchClaudeJson() {
|
|
|
8609
8547
|
});
|
|
8610
8548
|
}
|
|
8611
8549
|
function installLocalCC() {
|
|
8612
|
-
let bunCheck =
|
|
8550
|
+
let bunCheck = spawnSync5("bun", ["--version"], { encoding: "utf-8" });
|
|
8613
8551
|
if (bunCheck.status !== 0) {
|
|
8614
8552
|
if (process.platform === "darwin") {
|
|
8615
8553
|
console.log(" Installing bun via brew...");
|
|
8616
|
-
const brewR =
|
|
8554
|
+
const brewR = spawnSync5("brew", ["install", "oven-sh/bun/bun"], { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
|
|
8617
8555
|
if (brewR.status !== 0) {
|
|
8618
8556
|
throw new LocalCCInstallError("bun auto-install failed. Install manually: curl -fsSL https://bun.sh/install | bash");
|
|
8619
8557
|
}
|
|
8620
|
-
bunCheck =
|
|
8558
|
+
bunCheck = spawnSync5("bun", ["--version"], { encoding: "utf-8" });
|
|
8621
8559
|
if (bunCheck.status !== 0) {
|
|
8622
8560
|
throw new LocalCCInstallError("bun installed but not found on PATH. Restart your terminal and re-run install.");
|
|
8623
8561
|
}
|
|
@@ -8651,42 +8589,42 @@ var CLAUDE_JSON_BACKUP_PATH, SESSION_DIR, PLUGIN_PATH, PLUGIN_PKG_PATH, PLUGIN_S
|
|
|
8651
8589
|
var init_install2 = __esm({
|
|
8652
8590
|
"cli/local-cc/install.ts"() {
|
|
8653
8591
|
"use strict";
|
|
8654
|
-
CLAUDE_JSON_BACKUP_PATH =
|
|
8655
|
-
SESSION_DIR =
|
|
8656
|
-
PLUGIN_PATH =
|
|
8657
|
-
PLUGIN_PKG_PATH =
|
|
8658
|
-
PLUGIN_SETTINGS_DIR =
|
|
8659
|
-
PLUGIN_SETTINGS_PATH =
|
|
8660
|
-
PROJECT_MCP_PATH =
|
|
8661
|
-
CLAUDE_JSON_PATH =
|
|
8662
|
-
RUN_SCRIPT_PATH =
|
|
8592
|
+
CLAUDE_JSON_BACKUP_PATH = join18(homedir18(), ".claude.json.synkro-bak");
|
|
8593
|
+
SESSION_DIR = join18(homedir18(), ".synkro", "cc_sessions");
|
|
8594
|
+
PLUGIN_PATH = join18(SESSION_DIR, "synkro-channel.ts");
|
|
8595
|
+
PLUGIN_PKG_PATH = join18(SESSION_DIR, "package.json");
|
|
8596
|
+
PLUGIN_SETTINGS_DIR = join18(SESSION_DIR, ".claude");
|
|
8597
|
+
PLUGIN_SETTINGS_PATH = join18(PLUGIN_SETTINGS_DIR, "settings.json");
|
|
8598
|
+
PROJECT_MCP_PATH = join18(SESSION_DIR, ".mcp.json");
|
|
8599
|
+
CLAUDE_JSON_PATH = join18(homedir18(), ".claude.json");
|
|
8600
|
+
RUN_SCRIPT_PATH = join18(SESSION_DIR, "run-claude.sh");
|
|
8663
8601
|
TMUX_SESSION_NAME = "synkro-local-cc";
|
|
8664
8602
|
CHANNEL_1_PORT = 8941;
|
|
8665
|
-
SESSION_DIR_2 =
|
|
8666
|
-
PLUGIN_PATH_2 =
|
|
8667
|
-
PLUGIN_PKG_PATH_2 =
|
|
8668
|
-
PLUGIN_SETTINGS_DIR_2 =
|
|
8669
|
-
PLUGIN_SETTINGS_PATH_2 =
|
|
8670
|
-
PROJECT_MCP_PATH_2 =
|
|
8671
|
-
RUN_SCRIPT_PATH_2 =
|
|
8603
|
+
SESSION_DIR_2 = join18(homedir18(), ".synkro", "cc_sessions_2");
|
|
8604
|
+
PLUGIN_PATH_2 = join18(SESSION_DIR_2, "synkro-channel.ts");
|
|
8605
|
+
PLUGIN_PKG_PATH_2 = join18(SESSION_DIR_2, "package.json");
|
|
8606
|
+
PLUGIN_SETTINGS_DIR_2 = join18(SESSION_DIR_2, ".claude");
|
|
8607
|
+
PLUGIN_SETTINGS_PATH_2 = join18(PLUGIN_SETTINGS_DIR_2, "settings.json");
|
|
8608
|
+
PROJECT_MCP_PATH_2 = join18(SESSION_DIR_2, ".mcp.json");
|
|
8609
|
+
RUN_SCRIPT_PATH_2 = join18(SESSION_DIR_2, "run-claude.sh");
|
|
8672
8610
|
TMUX_SESSION_NAME_2 = "synkro-local-cc-2";
|
|
8673
8611
|
CHANNEL_2_PORT = 8951;
|
|
8674
|
-
SESSION_DIR_3 =
|
|
8675
|
-
PLUGIN_PATH_3 =
|
|
8676
|
-
PLUGIN_PKG_PATH_3 =
|
|
8677
|
-
PLUGIN_SETTINGS_DIR_3 =
|
|
8678
|
-
PLUGIN_SETTINGS_PATH_3 =
|
|
8679
|
-
PROJECT_MCP_PATH_3 =
|
|
8680
|
-
RUN_SCRIPT_PATH_3 =
|
|
8612
|
+
SESSION_DIR_3 = join18(homedir18(), ".synkro", "cc_sessions_3");
|
|
8613
|
+
PLUGIN_PATH_3 = join18(SESSION_DIR_3, "synkro-channel.ts");
|
|
8614
|
+
PLUGIN_PKG_PATH_3 = join18(SESSION_DIR_3, "package.json");
|
|
8615
|
+
PLUGIN_SETTINGS_DIR_3 = join18(SESSION_DIR_3, ".claude");
|
|
8616
|
+
PLUGIN_SETTINGS_PATH_3 = join18(PLUGIN_SETTINGS_DIR_3, "settings.json");
|
|
8617
|
+
PROJECT_MCP_PATH_3 = join18(SESSION_DIR_3, ".mcp.json");
|
|
8618
|
+
RUN_SCRIPT_PATH_3 = join18(SESSION_DIR_3, "run-claude.sh");
|
|
8681
8619
|
TMUX_SESSION_NAME_3 = "synkro-local-cc-3";
|
|
8682
8620
|
CHANNEL_3_PORT = 8942;
|
|
8683
|
-
SESSION_DIR_4 =
|
|
8684
|
-
PLUGIN_PATH_4 =
|
|
8685
|
-
PLUGIN_PKG_PATH_4 =
|
|
8686
|
-
PLUGIN_SETTINGS_DIR_4 =
|
|
8687
|
-
PLUGIN_SETTINGS_PATH_4 =
|
|
8688
|
-
PROJECT_MCP_PATH_4 =
|
|
8689
|
-
RUN_SCRIPT_PATH_4 =
|
|
8621
|
+
SESSION_DIR_4 = join18(homedir18(), ".synkro", "cc_sessions_4");
|
|
8622
|
+
PLUGIN_PATH_4 = join18(SESSION_DIR_4, "synkro-channel.ts");
|
|
8623
|
+
PLUGIN_PKG_PATH_4 = join18(SESSION_DIR_4, "package.json");
|
|
8624
|
+
PLUGIN_SETTINGS_DIR_4 = join18(SESSION_DIR_4, ".claude");
|
|
8625
|
+
PLUGIN_SETTINGS_PATH_4 = join18(PLUGIN_SETTINGS_DIR_4, "settings.json");
|
|
8626
|
+
PROJECT_MCP_PATH_4 = join18(SESSION_DIR_4, ".mcp.json");
|
|
8627
|
+
RUN_SCRIPT_PATH_4 = join18(SESSION_DIR_4, "run-claude.sh");
|
|
8690
8628
|
TMUX_SESSION_NAME_4 = "synkro-local-cc-4";
|
|
8691
8629
|
CHANNEL_4_PORT = 8952;
|
|
8692
8630
|
RUN_SCRIPT_SOURCE = `#!/usr/bin/env bash
|
|
@@ -8960,10 +8898,10 @@ var disconnect_exports = {};
|
|
|
8960
8898
|
__export(disconnect_exports, {
|
|
8961
8899
|
disconnectCommand: () => disconnectCommand
|
|
8962
8900
|
});
|
|
8963
|
-
import { existsSync as
|
|
8964
|
-
import { homedir as
|
|
8965
|
-
import { join as
|
|
8966
|
-
import { spawnSync as
|
|
8901
|
+
import { existsSync as existsSync22, rmSync, readdirSync as readdirSync4 } from "fs";
|
|
8902
|
+
import { homedir as homedir19 } from "os";
|
|
8903
|
+
import { join as join19 } from "path";
|
|
8904
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
8967
8905
|
import { createInterface as createInterface4 } from "readline";
|
|
8968
8906
|
async function tearDownLocalCC() {
|
|
8969
8907
|
const docker = dockerStatus();
|
|
@@ -8977,7 +8915,7 @@ async function tearDownLocalCC() {
|
|
|
8977
8915
|
console.log("\u2713 removed synkro-server container");
|
|
8978
8916
|
try {
|
|
8979
8917
|
const image = imageTag();
|
|
8980
|
-
const r =
|
|
8918
|
+
const r = spawnSync6("docker", ["rmi", "-f", image], { encoding: "utf-8", timeout: 3e4 });
|
|
8981
8919
|
console.log(r.status === 0 ? `\u2713 removed Docker image ${image}` : "\xB7 no Docker image to remove");
|
|
8982
8920
|
} catch {
|
|
8983
8921
|
}
|
|
@@ -9048,7 +8986,7 @@ async function disconnectCommand(args2 = [], opts = {}) {
|
|
|
9048
8986
|
if (desktopMcpRemoved) removed.mcp = true;
|
|
9049
8987
|
console.log(`${desktopMcpRemoved ? "\u2713" : "\xB7"} MCP guardrails (Claude Desktop): ${desktopMcpRemoved ? "removed from claude_desktop_config.json" : "no entry found"}`);
|
|
9050
8988
|
}
|
|
9051
|
-
if (
|
|
8989
|
+
if (existsSync22(SYNKRO_DIR11)) {
|
|
9052
8990
|
if (purge2) {
|
|
9053
8991
|
emit("uninstall", {
|
|
9054
8992
|
flavor,
|
|
@@ -9057,41 +8995,41 @@ async function disconnectCommand(args2 = [], opts = {}) {
|
|
|
9057
8995
|
duration_ms: Date.now() - startedAt
|
|
9058
8996
|
});
|
|
9059
8997
|
await flush({ force: true });
|
|
9060
|
-
|
|
8998
|
+
rmSync(SYNKRO_DIR11, { recursive: true, force: true });
|
|
9061
8999
|
removed.config = true;
|
|
9062
|
-
console.log(`\u2713 wiped ${
|
|
9000
|
+
console.log(`\u2713 wiped ${SYNKRO_DIR11} entirely \u2014 including all scan data and backups`);
|
|
9063
9001
|
} else {
|
|
9064
9002
|
const keep = /* @__PURE__ */ new Set([
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
|
|
9003
|
+
join19(SYNKRO_DIR11, "pgdata"),
|
|
9004
|
+
join19(SYNKRO_DIR11, "pgdata-backups"),
|
|
9005
|
+
join19(SYNKRO_DIR11, ".transcript-offsets")
|
|
9068
9006
|
]);
|
|
9069
9007
|
const preserved = [];
|
|
9070
|
-
for (const entry of readdirSync4(
|
|
9071
|
-
const full =
|
|
9008
|
+
for (const entry of readdirSync4(SYNKRO_DIR11)) {
|
|
9009
|
+
const full = join19(SYNKRO_DIR11, entry);
|
|
9072
9010
|
if (keep.has(full)) {
|
|
9073
9011
|
preserved.push(entry);
|
|
9074
9012
|
continue;
|
|
9075
9013
|
}
|
|
9076
|
-
|
|
9014
|
+
rmSync(full, { recursive: true, force: true });
|
|
9077
9015
|
}
|
|
9078
9016
|
removed.config = true;
|
|
9079
9017
|
if (preserved.length > 0) {
|
|
9080
|
-
console.log(`\u2713 removed Synkro config from ${
|
|
9018
|
+
console.log(`\u2713 removed Synkro config from ${SYNKRO_DIR11} (kept your scan data: ${preserved.join(", ")})`);
|
|
9081
9019
|
console.log(" run `synkro uninstall --purge` to delete that too");
|
|
9082
9020
|
} else {
|
|
9083
|
-
console.log(`\u2713 removed ${
|
|
9021
|
+
console.log(`\u2713 removed ${SYNKRO_DIR11}`);
|
|
9084
9022
|
}
|
|
9085
9023
|
}
|
|
9086
9024
|
} else {
|
|
9087
|
-
console.log(`\xB7 ${
|
|
9025
|
+
console.log(`\xB7 ${SYNKRO_DIR11} already gone`);
|
|
9088
9026
|
}
|
|
9089
9027
|
if (!purge2) {
|
|
9090
9028
|
emit("uninstall", { flavor, purge: purge2, removed, duration_ms: Date.now() - startedAt });
|
|
9091
9029
|
}
|
|
9092
9030
|
console.log(purge2 ? "\nSynkro fully removed \u2014 this machine is clean, as if it was never installed." : "\nSynkro uninstalled. Your scan data is preserved.");
|
|
9093
9031
|
}
|
|
9094
|
-
var
|
|
9032
|
+
var SYNKRO_DIR11;
|
|
9095
9033
|
var init_disconnect = __esm({
|
|
9096
9034
|
"cli/commands/disconnect.ts"() {
|
|
9097
9035
|
"use strict";
|
|
@@ -9103,14 +9041,14 @@ var init_disconnect = __esm({
|
|
|
9103
9041
|
init_dockerInstall();
|
|
9104
9042
|
init_macKeychain();
|
|
9105
9043
|
init_telemetry();
|
|
9106
|
-
|
|
9044
|
+
SYNKRO_DIR11 = join19(homedir19(), ".synkro");
|
|
9107
9045
|
}
|
|
9108
9046
|
});
|
|
9109
9047
|
|
|
9110
9048
|
// cli/local-cc/turnLog.ts
|
|
9111
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
9112
|
-
import { dirname as dirname6, join as
|
|
9113
|
-
import { homedir as
|
|
9049
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync23, mkdirSync as mkdirSync14, openSync as openSync3, readFileSync as readFileSync19, readSync, closeSync as closeSync3, statSync as statSync3, watchFile, unwatchFile } from "fs";
|
|
9050
|
+
import { dirname as dirname6, join as join20 } from "path";
|
|
9051
|
+
import { homedir as homedir20 } from "os";
|
|
9114
9052
|
function truncate(s, max = PREVIEW_MAX) {
|
|
9115
9053
|
if (s.length <= max) return s;
|
|
9116
9054
|
return s.slice(0, max) + "\u2026 [+" + (s.length - max) + " chars]";
|
|
@@ -9130,7 +9068,7 @@ function extractSeverity(result) {
|
|
|
9130
9068
|
}
|
|
9131
9069
|
function appendTurn(args2) {
|
|
9132
9070
|
try {
|
|
9133
|
-
|
|
9071
|
+
mkdirSync14(dirname6(TURN_LOG_PATH), { recursive: true });
|
|
9134
9072
|
const entry = {
|
|
9135
9073
|
ts: new Date(args2.startedAt).toISOString(),
|
|
9136
9074
|
role: args2.role,
|
|
@@ -9146,11 +9084,11 @@ function appendTurn(args2) {
|
|
|
9146
9084
|
}
|
|
9147
9085
|
}
|
|
9148
9086
|
function readRecentTurns(n = 20) {
|
|
9149
|
-
if (!
|
|
9087
|
+
if (!existsSync23(TURN_LOG_PATH)) return [];
|
|
9150
9088
|
try {
|
|
9151
9089
|
const size = statSync3(TURN_LOG_PATH).size;
|
|
9152
9090
|
if (size === 0) return [];
|
|
9153
|
-
const text =
|
|
9091
|
+
const text = readFileSync19(TURN_LOG_PATH, "utf-8");
|
|
9154
9092
|
const lines = text.split("\n").filter(Boolean);
|
|
9155
9093
|
const lastN = lines.slice(-n).reverse();
|
|
9156
9094
|
return lastN.map((line) => {
|
|
@@ -9166,8 +9104,8 @@ function readRecentTurns(n = 20) {
|
|
|
9166
9104
|
}
|
|
9167
9105
|
function followTurns(onEntry) {
|
|
9168
9106
|
try {
|
|
9169
|
-
|
|
9170
|
-
if (!
|
|
9107
|
+
mkdirSync14(dirname6(TURN_LOG_PATH), { recursive: true });
|
|
9108
|
+
if (!existsSync23(TURN_LOG_PATH)) {
|
|
9171
9109
|
appendFileSync3(TURN_LOG_PATH, "", "utf-8");
|
|
9172
9110
|
}
|
|
9173
9111
|
} catch {
|
|
@@ -9229,7 +9167,7 @@ var TURN_LOG_PATH, PREVIEW_MAX;
|
|
|
9229
9167
|
var init_turnLog = __esm({
|
|
9230
9168
|
"cli/local-cc/turnLog.ts"() {
|
|
9231
9169
|
"use strict";
|
|
9232
|
-
TURN_LOG_PATH =
|
|
9170
|
+
TURN_LOG_PATH = join20(homedir20(), ".synkro", "cc_sessions", "turns.log");
|
|
9233
9171
|
PREVIEW_MAX = 400;
|
|
9234
9172
|
}
|
|
9235
9173
|
});
|
|
@@ -9378,19 +9316,19 @@ var init_grade = __esm({
|
|
|
9378
9316
|
});
|
|
9379
9317
|
|
|
9380
9318
|
// cli/local-cc/pueue.ts
|
|
9381
|
-
import { execFileSync as execFileSync4, spawnSync as
|
|
9382
|
-
import { homedir as
|
|
9383
|
-
import { join as
|
|
9319
|
+
import { execFileSync as execFileSync4, spawnSync as spawnSync7, spawn as spawn3 } from "child_process";
|
|
9320
|
+
import { homedir as homedir21 } from "os";
|
|
9321
|
+
import { join as join21 } from "path";
|
|
9384
9322
|
import { connect as connect2 } from "net";
|
|
9385
9323
|
function pueueAvailable() {
|
|
9386
|
-
const r =
|
|
9324
|
+
const r = spawnSync7("pueue", ["--version"], { encoding: "utf-8" });
|
|
9387
9325
|
if (r.status !== 0) {
|
|
9388
9326
|
throw new PueueError("pueue CLI not found on PATH. Install pueue (https://github.com/Nukesor/pueue) and start `pueued`.");
|
|
9389
9327
|
}
|
|
9390
9328
|
}
|
|
9391
9329
|
function statusJson() {
|
|
9392
9330
|
pueueAvailable();
|
|
9393
|
-
const r =
|
|
9331
|
+
const r = spawnSync7("pueue", ["status", "--json"], { encoding: "utf-8" });
|
|
9394
9332
|
if (r.status !== 0) {
|
|
9395
9333
|
throw new PueueError(`pueue status failed: ${r.stderr || r.stdout || "unknown error"} \u2014 is pueued running?`);
|
|
9396
9334
|
}
|
|
@@ -9435,18 +9373,18 @@ function startTask(opts = {}) {
|
|
|
9435
9373
|
let existing = findTask(ch);
|
|
9436
9374
|
while (existing) {
|
|
9437
9375
|
if (existing.status === "Running" || existing.status === "Queued") {
|
|
9438
|
-
|
|
9439
|
-
|
|
9376
|
+
spawnSync7("tmux", ["kill-session", "-t", `=${ch.tmuxSession}`], { encoding: "utf-8" });
|
|
9377
|
+
spawnSync7("pueue", ["kill", String(existing.id)], { encoding: "utf-8" });
|
|
9440
9378
|
for (let i = 0; i < 10; i++) {
|
|
9441
9379
|
const check = findTask(ch);
|
|
9442
9380
|
if (!check || check.id !== existing.id || check.status !== "Running" && check.status !== "Queued") break;
|
|
9443
|
-
|
|
9381
|
+
spawnSync7("sleep", ["0.5"], { encoding: "utf-8" });
|
|
9444
9382
|
}
|
|
9445
9383
|
}
|
|
9446
|
-
|
|
9384
|
+
spawnSync7("pueue", ["remove", String(existing.id)], { encoding: "utf-8" });
|
|
9447
9385
|
existing = findTask(ch);
|
|
9448
9386
|
}
|
|
9449
|
-
const runScript =
|
|
9387
|
+
const runScript = join21(cwd, "run-claude.sh");
|
|
9450
9388
|
const args2 = [
|
|
9451
9389
|
"add",
|
|
9452
9390
|
"--label",
|
|
@@ -9457,7 +9395,7 @@ function startTask(opts = {}) {
|
|
|
9457
9395
|
"bash",
|
|
9458
9396
|
runScript
|
|
9459
9397
|
];
|
|
9460
|
-
const r =
|
|
9398
|
+
const r = spawnSync7("pueue", args2, { encoding: "utf-8" });
|
|
9461
9399
|
if (r.status !== 0) {
|
|
9462
9400
|
throw new PueueError(`pueue add failed: ${r.stderr || r.stdout}`);
|
|
9463
9401
|
}
|
|
@@ -9468,25 +9406,25 @@ function startTask(opts = {}) {
|
|
|
9468
9406
|
return created;
|
|
9469
9407
|
}
|
|
9470
9408
|
function stopTask(channel = CHANNEL_PRIMARY) {
|
|
9471
|
-
|
|
9409
|
+
spawnSync7("tmux", ["kill-session", "-t", `=${channel.tmuxSession}`], { encoding: "utf-8" });
|
|
9472
9410
|
let t = findTask(channel);
|
|
9473
9411
|
while (t) {
|
|
9474
9412
|
if (t.status === "Running" || t.status === "Queued") {
|
|
9475
|
-
|
|
9413
|
+
spawnSync7("pueue", ["kill", String(t.id)], { encoding: "utf-8" });
|
|
9476
9414
|
for (let i = 0; i < 10; i++) {
|
|
9477
9415
|
const check = findTask(channel);
|
|
9478
9416
|
if (!check || check.id !== t.id || check.status !== "Running" && check.status !== "Queued") break;
|
|
9479
|
-
|
|
9417
|
+
spawnSync7("sleep", ["0.5"], { encoding: "utf-8" });
|
|
9480
9418
|
}
|
|
9481
9419
|
}
|
|
9482
|
-
|
|
9420
|
+
spawnSync7("pueue", ["remove", String(t.id)], { encoding: "utf-8" });
|
|
9483
9421
|
t = findTask(channel);
|
|
9484
9422
|
}
|
|
9485
9423
|
}
|
|
9486
9424
|
function tailLogs(lines = 80, channel = CHANNEL_PRIMARY) {
|
|
9487
9425
|
const t = findTask(channel);
|
|
9488
9426
|
if (!t) return `(no ${channel.taskLabel} task)`;
|
|
9489
|
-
const r =
|
|
9427
|
+
const r = spawnSync7("pueue", ["log", "--lines", String(lines), String(t.id)], { encoding: "utf-8" });
|
|
9490
9428
|
return r.stdout || r.stderr || "(no output)";
|
|
9491
9429
|
}
|
|
9492
9430
|
function ensureRunning(opts = {}) {
|
|
@@ -9511,8 +9449,8 @@ function probePort(host, port, timeoutMs = 500) {
|
|
|
9511
9449
|
});
|
|
9512
9450
|
}
|
|
9513
9451
|
function tmuxDismissPrompts(tmuxSession = TMUX_SESSION) {
|
|
9514
|
-
|
|
9515
|
-
|
|
9452
|
+
spawnSync7("tmux", ["send-keys", "-t", tmuxSession, "1"], { encoding: "utf-8" });
|
|
9453
|
+
spawnSync7("tmux", ["send-keys", "-t", tmuxSession, "Enter"], { encoding: "utf-8" });
|
|
9516
9454
|
}
|
|
9517
9455
|
async function waitForChannelReady(port, timeoutMs = 6e4, host = "127.0.0.1", tmuxSession = TMUX_SESSION) {
|
|
9518
9456
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -9524,46 +9462,46 @@ async function waitForChannelReady(port, timeoutMs = 6e4, host = "127.0.0.1", tm
|
|
|
9524
9462
|
return probePort(host, port);
|
|
9525
9463
|
}
|
|
9526
9464
|
function brewInstall(pkg) {
|
|
9527
|
-
const brew =
|
|
9465
|
+
const brew = spawnSync7("brew", ["--version"], { encoding: "utf-8" });
|
|
9528
9466
|
if (brew.status !== 0) return false;
|
|
9529
9467
|
console.log(` Installing ${pkg} via brew...`);
|
|
9530
|
-
const r =
|
|
9468
|
+
const r = spawnSync7("brew", ["install", pkg], { encoding: "utf-8", stdio: "inherit", timeout: 12e4 });
|
|
9531
9469
|
return r.status === 0;
|
|
9532
9470
|
}
|
|
9533
9471
|
function assertPueueInstalled() {
|
|
9534
|
-
let r =
|
|
9472
|
+
let r = spawnSync7("pueue", ["--version"], { encoding: "utf-8" });
|
|
9535
9473
|
if (r.status !== 0) {
|
|
9536
9474
|
if (process.platform === "darwin" && brewInstall("pueue")) {
|
|
9537
|
-
r =
|
|
9475
|
+
r = spawnSync7("pueue", ["--version"], { encoding: "utf-8" });
|
|
9538
9476
|
if (r.status !== 0) throw new PueueError("pueue install succeeded but binary not found on PATH.");
|
|
9539
9477
|
} else {
|
|
9540
9478
|
throw new PueueError("pueue not found. Install it: brew install pueue (macOS) or https://github.com/Nukesor/pueue");
|
|
9541
9479
|
}
|
|
9542
9480
|
}
|
|
9543
|
-
const status =
|
|
9481
|
+
const status = spawnSync7("pueue", ["status", "--json"], { encoding: "utf-8", timeout: 5e3 });
|
|
9544
9482
|
if (status.status !== 0) {
|
|
9545
9483
|
console.log(" Starting pueued daemon...");
|
|
9546
9484
|
const child = spawn3("pueued", ["-d"], { stdio: "ignore", detached: true });
|
|
9547
9485
|
child.unref();
|
|
9548
|
-
|
|
9549
|
-
const retry =
|
|
9486
|
+
spawnSync7("sleep", ["1"]);
|
|
9487
|
+
const retry = spawnSync7("pueue", ["status", "--json"], { encoding: "utf-8", timeout: 5e3 });
|
|
9550
9488
|
if (retry.status !== 0) {
|
|
9551
9489
|
throw new PueueError("pueue daemon not reachable after starting pueued. Check `pueued` manually.");
|
|
9552
9490
|
}
|
|
9553
9491
|
}
|
|
9554
|
-
|
|
9492
|
+
spawnSync7("pueue", ["parallel", "2"], { encoding: "utf-8" });
|
|
9555
9493
|
}
|
|
9556
9494
|
function assertClaudeInstalled() {
|
|
9557
|
-
const r =
|
|
9495
|
+
const r = spawnSync7("claude", ["--version"], { encoding: "utf-8" });
|
|
9558
9496
|
if (r.status !== 0) {
|
|
9559
9497
|
throw new PueueError("claude CLI not found on PATH. Install Claude Code first: https://docs.claude.com/claude-code");
|
|
9560
9498
|
}
|
|
9561
9499
|
}
|
|
9562
9500
|
function assertTmuxInstalled() {
|
|
9563
|
-
let r =
|
|
9501
|
+
let r = spawnSync7("tmux", ["-V"], { encoding: "utf-8" });
|
|
9564
9502
|
if (r.status !== 0) {
|
|
9565
9503
|
if (process.platform === "darwin" && brewInstall("tmux")) {
|
|
9566
|
-
r =
|
|
9504
|
+
r = spawnSync7("tmux", ["-V"], { encoding: "utf-8" });
|
|
9567
9505
|
if (r.status !== 0) throw new PueueError("tmux install succeeded but binary not found on PATH.");
|
|
9568
9506
|
} else {
|
|
9569
9507
|
throw new PueueError("tmux not found. Install it: brew install tmux (macOS) or apt install tmux (Linux)");
|
|
@@ -9576,12 +9514,12 @@ var init_pueue = __esm({
|
|
|
9576
9514
|
"use strict";
|
|
9577
9515
|
TASK_LABEL = "synkro-local-cc";
|
|
9578
9516
|
TMUX_SESSION = "synkro-local-cc";
|
|
9579
|
-
SESSION_DIR2 =
|
|
9517
|
+
SESSION_DIR2 = join21(homedir21(), ".synkro", "cc_sessions");
|
|
9580
9518
|
TASK_LABEL_2 = "synkro-local-cc-2";
|
|
9581
9519
|
TMUX_SESSION_2 = "synkro-local-cc-2";
|
|
9582
|
-
SESSION_DIR_22 =
|
|
9583
|
-
SESSION_DIR_32 =
|
|
9584
|
-
SESSION_DIR_42 =
|
|
9520
|
+
SESSION_DIR_22 = join21(homedir21(), ".synkro", "cc_sessions_2");
|
|
9521
|
+
SESSION_DIR_32 = join21(homedir21(), ".synkro", "cc_sessions_3");
|
|
9522
|
+
SESSION_DIR_42 = join21(homedir21(), ".synkro", "cc_sessions_4");
|
|
9585
9523
|
PueueError = class extends Error {
|
|
9586
9524
|
constructor(message, cause) {
|
|
9587
9525
|
super(message);
|
|
@@ -9596,13 +9534,13 @@ var init_pueue = __esm({
|
|
|
9596
9534
|
});
|
|
9597
9535
|
|
|
9598
9536
|
// cli/local-cc/settings.ts
|
|
9599
|
-
import { existsSync as
|
|
9600
|
-
import { homedir as
|
|
9601
|
-
import { join as
|
|
9537
|
+
import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
|
|
9538
|
+
import { homedir as homedir22 } from "os";
|
|
9539
|
+
import { join as join22 } from "path";
|
|
9602
9540
|
function isLocalCCEnabled() {
|
|
9603
|
-
if (!
|
|
9541
|
+
if (!existsSync24(CONFIG_PATH5)) return false;
|
|
9604
9542
|
try {
|
|
9605
|
-
const content =
|
|
9543
|
+
const content = readFileSync20(CONFIG_PATH5, "utf-8");
|
|
9606
9544
|
const match = content.match(/^SYNKRO_LOCAL_INFERENCE='([^']*)'/m);
|
|
9607
9545
|
return match?.[1] === "yes";
|
|
9608
9546
|
} catch {
|
|
@@ -9613,7 +9551,7 @@ var CONFIG_PATH5;
|
|
|
9613
9551
|
var init_settings = __esm({
|
|
9614
9552
|
"cli/local-cc/settings.ts"() {
|
|
9615
9553
|
"use strict";
|
|
9616
|
-
CONFIG_PATH5 =
|
|
9554
|
+
CONFIG_PATH5 = join22(homedir22(), ".synkro", "config.env");
|
|
9617
9555
|
}
|
|
9618
9556
|
});
|
|
9619
9557
|
|
|
@@ -9622,11 +9560,11 @@ var localCc_exports = {};
|
|
|
9622
9560
|
__export(localCc_exports, {
|
|
9623
9561
|
localCcCommand: () => localCcCommand
|
|
9624
9562
|
});
|
|
9625
|
-
import { spawnSync as
|
|
9626
|
-
import { homedir as
|
|
9627
|
-
import { join as
|
|
9563
|
+
import { spawnSync as spawnSync8 } from "child_process";
|
|
9564
|
+
import { homedir as homedir23 } from "os";
|
|
9565
|
+
import { join as join23 } from "path";
|
|
9628
9566
|
import { readFileSync as fsReadFileSync, existsSync as fsExistsSync } from "fs";
|
|
9629
|
-
import { existsSync as
|
|
9567
|
+
import { existsSync as existsSync25, readFileSync as readFileSync21, writeFileSync as writeFileSync15 } from "fs";
|
|
9630
9568
|
function deploymentMode() {
|
|
9631
9569
|
const env = (process.env.SYNKRO_DEPLOYMENT_MODE || "").toLowerCase();
|
|
9632
9570
|
if (env === "docker") return "docker";
|
|
@@ -9732,15 +9670,15 @@ TROUBLESHOOTING
|
|
|
9732
9670
|
`);
|
|
9733
9671
|
}
|
|
9734
9672
|
function readGatewayUrl() {
|
|
9735
|
-
if (
|
|
9736
|
-
const m =
|
|
9673
|
+
if (existsSync25(CONFIG_PATH6)) {
|
|
9674
|
+
const m = readFileSync21(CONFIG_PATH6, "utf-8").match(/^SYNKRO_GATEWAY_URL='([^']*)'/m);
|
|
9737
9675
|
if (m) return m[1];
|
|
9738
9676
|
}
|
|
9739
9677
|
return "https://api.synkro.sh";
|
|
9740
9678
|
}
|
|
9741
9679
|
function updateLocalInferenceFlag(enabled) {
|
|
9742
|
-
if (!
|
|
9743
|
-
let content =
|
|
9680
|
+
if (!existsSync25(CONFIG_PATH6)) return;
|
|
9681
|
+
let content = readFileSync21(CONFIG_PATH6, "utf-8");
|
|
9744
9682
|
const flag = enabled ? "yes" : "no";
|
|
9745
9683
|
if (content.includes("SYNKRO_LOCAL_INFERENCE=")) {
|
|
9746
9684
|
content = content.replace(/^SYNKRO_LOCAL_INFERENCE='[^']*'/m, `SYNKRO_LOCAL_INFERENCE='${flag}'`);
|
|
@@ -9803,7 +9741,7 @@ async function cmdStatus() {
|
|
|
9803
9741
|
}
|
|
9804
9742
|
const ch1Up = await isChannelAvailable();
|
|
9805
9743
|
console.log(`Channel 1 ${CHANNEL_HOST}:${CHANNEL_PORT}: ${ch1Up ? "reachable" : "unreachable"}`);
|
|
9806
|
-
const tmux1 =
|
|
9744
|
+
const tmux1 = spawnSync8("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME}`], { encoding: "utf-8" });
|
|
9807
9745
|
console.log(`tmux '${TMUX_SESSION_NAME}': ${tmux1.status === 0 ? "live" : "absent"}`);
|
|
9808
9746
|
const t2 = findTask(CHANNEL_SECONDARY);
|
|
9809
9747
|
if (!t2) {
|
|
@@ -9813,7 +9751,7 @@ async function cmdStatus() {
|
|
|
9813
9751
|
}
|
|
9814
9752
|
const ch2Up = await isChannelAvailable(CHANNEL_2_PORT);
|
|
9815
9753
|
console.log(`Channel 2 ${CHANNEL_HOST}:${CHANNEL_2_PORT}: ${ch2Up ? "reachable" : "unreachable"}`);
|
|
9816
|
-
const tmux2 =
|
|
9754
|
+
const tmux2 = spawnSync8("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME_2}`], { encoding: "utf-8" });
|
|
9817
9755
|
console.log(`tmux '${TMUX_SESSION_NAME_2}': ${tmux2.status === 0 ? "live" : "absent"}`);
|
|
9818
9756
|
}
|
|
9819
9757
|
async function cmdEnable() {
|
|
@@ -10019,7 +9957,7 @@ function cmdLogs(rest) {
|
|
|
10019
9957
|
}
|
|
10020
9958
|
return "200";
|
|
10021
9959
|
})();
|
|
10022
|
-
|
|
9960
|
+
spawnSync8("docker", ["logs", "--tail", tailArg, ...followFlag, "synkro-server"], { stdio: "inherit" });
|
|
10023
9961
|
return;
|
|
10024
9962
|
}
|
|
10025
9963
|
for (const arg of rest) {
|
|
@@ -10067,7 +10005,7 @@ function cmdLogs(rest) {
|
|
|
10067
10005
|
function cmdAttach(rest) {
|
|
10068
10006
|
assertTmuxInstalled();
|
|
10069
10007
|
const readonly = rest.some((a) => a === "--readonly" || a === "-r");
|
|
10070
|
-
const has =
|
|
10008
|
+
const has = spawnSync8("tmux", ["has-session", "-t", `=${TMUX_SESSION_NAME}`], { encoding: "utf-8" });
|
|
10071
10009
|
if (has.status !== 0) {
|
|
10072
10010
|
console.error(`No tmux session '${TMUX_SESSION_NAME}' running. Start it with: synkro local-cc start`);
|
|
10073
10011
|
process.exit(1);
|
|
@@ -10080,7 +10018,7 @@ function cmdAttach(rest) {
|
|
|
10080
10018
|
console.log("Detach with Ctrl-B then D. (Do not press Ctrl-C \u2014 that would interrupt claude.)");
|
|
10081
10019
|
console.log();
|
|
10082
10020
|
const args2 = readonly ? ["attach-session", "-r", "-t", TMUX_SESSION_NAME] : ["attach-session", "-t", TMUX_SESSION_NAME];
|
|
10083
|
-
const r =
|
|
10021
|
+
const r = spawnSync8("tmux", args2, { stdio: "inherit" });
|
|
10084
10022
|
process.exit(r.status ?? 0);
|
|
10085
10023
|
}
|
|
10086
10024
|
async function cmdTest() {
|
|
@@ -10181,8 +10119,8 @@ var init_localCc = __esm({
|
|
|
10181
10119
|
init_install();
|
|
10182
10120
|
init_client2();
|
|
10183
10121
|
init_stub();
|
|
10184
|
-
SYNKRO_CONFIG_PATH =
|
|
10185
|
-
CONFIG_PATH6 =
|
|
10122
|
+
SYNKRO_CONFIG_PATH = join23(homedir23(), ".synkro", "config.env");
|
|
10123
|
+
CONFIG_PATH6 = join23(homedir23(), ".synkro", "config.env");
|
|
10186
10124
|
}
|
|
10187
10125
|
});
|
|
10188
10126
|
|
|
@@ -10191,15 +10129,15 @@ var import_exports = {};
|
|
|
10191
10129
|
__export(import_exports, {
|
|
10192
10130
|
importCommand: () => importCommand
|
|
10193
10131
|
});
|
|
10194
|
-
import { existsSync as
|
|
10195
|
-
import { homedir as
|
|
10196
|
-
import { join as
|
|
10132
|
+
import { existsSync as existsSync26, readFileSync as readFileSync22, readdirSync as readdirSync5 } from "fs";
|
|
10133
|
+
import { homedir as homedir24 } from "os";
|
|
10134
|
+
import { join as join24 } from "path";
|
|
10197
10135
|
import { execSync as execSync7 } from "child_process";
|
|
10198
10136
|
import { createInterface as createInterface5 } from "readline";
|
|
10199
10137
|
function readConfigEnv2() {
|
|
10200
10138
|
const out = {};
|
|
10201
10139
|
try {
|
|
10202
|
-
for (const line of
|
|
10140
|
+
for (const line of readFileSync22(CONFIG_PATH7, "utf-8").split("\n")) {
|
|
10203
10141
|
const t = line.trim();
|
|
10204
10142
|
if (!t || t.startsWith("#")) continue;
|
|
10205
10143
|
const eq = t.indexOf("=");
|
|
@@ -10211,8 +10149,8 @@ function readConfigEnv2() {
|
|
|
10211
10149
|
}
|
|
10212
10150
|
function projectsFolder() {
|
|
10213
10151
|
const sanitized = process.cwd().replace(/\//g, "-");
|
|
10214
|
-
const dir =
|
|
10215
|
-
return
|
|
10152
|
+
const dir = join24(homedir24(), ".claude", "projects", sanitized);
|
|
10153
|
+
return existsSync26(dir) ? dir : null;
|
|
10216
10154
|
}
|
|
10217
10155
|
function repoName() {
|
|
10218
10156
|
try {
|
|
@@ -10235,7 +10173,7 @@ function extractText(content) {
|
|
|
10235
10173
|
return "";
|
|
10236
10174
|
}
|
|
10237
10175
|
function parseSession(filePath, sessionId) {
|
|
10238
|
-
const lines =
|
|
10176
|
+
const lines = readFileSync22(filePath, "utf-8").split("\n").filter(Boolean);
|
|
10239
10177
|
const messages = [];
|
|
10240
10178
|
const actions = [];
|
|
10241
10179
|
let step = 0;
|
|
@@ -10308,7 +10246,7 @@ async function importCommand() {
|
|
|
10308
10246
|
return;
|
|
10309
10247
|
}
|
|
10310
10248
|
}
|
|
10311
|
-
const sessions = files.map((f) => parseSession(
|
|
10249
|
+
const sessions = files.map((f) => parseSession(join24(dir, f), f.replace(".jsonl", ""))).filter((s) => s.messages.length > 0);
|
|
10312
10250
|
const totalMsgs = sessions.reduce((n, s) => n + s.messages.length, 0);
|
|
10313
10251
|
let ok = 0, fail = 0;
|
|
10314
10252
|
if (isCloud) {
|
|
@@ -10368,7 +10306,7 @@ var init_import = __esm({
|
|
|
10368
10306
|
"cli/commands/import.ts"() {
|
|
10369
10307
|
"use strict";
|
|
10370
10308
|
init_stub();
|
|
10371
|
-
CONFIG_PATH7 =
|
|
10309
|
+
CONFIG_PATH7 = join24(homedir24(), ".synkro", "config.env");
|
|
10372
10310
|
}
|
|
10373
10311
|
});
|
|
10374
10312
|
|
|
@@ -10410,10 +10348,10 @@ var init_packVerify = __esm({
|
|
|
10410
10348
|
});
|
|
10411
10349
|
|
|
10412
10350
|
// cli/installer/lockfile.ts
|
|
10413
|
-
import { existsSync as
|
|
10414
|
-
import { join as
|
|
10351
|
+
import { existsSync as existsSync27, readFileSync as readFileSync23, writeFileSync as writeFileSync16 } from "fs";
|
|
10352
|
+
import { join as join25 } from "path";
|
|
10415
10353
|
function lockPath(repoRoot) {
|
|
10416
|
-
return
|
|
10354
|
+
return join25(repoRoot, LOCK_FILE);
|
|
10417
10355
|
}
|
|
10418
10356
|
function writeLockfile(repoRoot, entries) {
|
|
10419
10357
|
const sorted = [...entries].sort((a, b) => a.ref.localeCompare(b.ref));
|
|
@@ -10446,9 +10384,9 @@ var sync_exports = {};
|
|
|
10446
10384
|
__export(sync_exports, {
|
|
10447
10385
|
syncCommand: () => syncCommand
|
|
10448
10386
|
});
|
|
10449
|
-
import { existsSync as
|
|
10450
|
-
import { homedir as
|
|
10451
|
-
import { join as
|
|
10387
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync15, readdirSync as readdirSync6, rmSync as rmSync2, writeFileSync as writeFileSync17 } from "fs";
|
|
10388
|
+
import { homedir as homedir25 } from "os";
|
|
10389
|
+
import { join as join26 } from "path";
|
|
10452
10390
|
function cacheKey(ref, version) {
|
|
10453
10391
|
return ref.replace(/\//g, "__").replace(/[^\w.@-]/g, "_") + "@" + version + ".json";
|
|
10454
10392
|
}
|
|
@@ -10479,8 +10417,8 @@ async function syncCommand(_args = []) {
|
|
|
10479
10417
|
}
|
|
10480
10418
|
const gateway = (process.env.SYNKRO_GATEWAY_URL || "https://api.synkro.sh").replace(/\/$/, "");
|
|
10481
10419
|
const cloud = process.env.SYNKRO_DEPLOY_LOCATION === "cloud";
|
|
10482
|
-
const cacheDir =
|
|
10483
|
-
if (!cloud)
|
|
10420
|
+
const cacheDir = join26(homedir25(), ".synkro", "cache", "packs");
|
|
10421
|
+
if (!cloud) mkdirSync15(cacheDir, { recursive: true });
|
|
10484
10422
|
console.log(`Syncing ${refs.length} standard(s) from the registry\u2026`);
|
|
10485
10423
|
const lock = [];
|
|
10486
10424
|
const keptCacheFiles = /* @__PURE__ */ new Set();
|
|
@@ -10508,7 +10446,7 @@ async function syncCommand(_args = []) {
|
|
|
10508
10446
|
if (!cloud) {
|
|
10509
10447
|
const fname = cacheKey(ref, data.version);
|
|
10510
10448
|
keptCacheFiles.add(fname);
|
|
10511
|
-
writeFileSync17(
|
|
10449
|
+
writeFileSync17(join26(cacheDir, fname), JSON.stringify({
|
|
10512
10450
|
ref,
|
|
10513
10451
|
version: data.version,
|
|
10514
10452
|
digest: data.digest,
|
|
@@ -10520,11 +10458,11 @@ async function syncCommand(_args = []) {
|
|
|
10520
10458
|
const ruleCount = Array.isArray(pack.rules) ? pack.rules.length : 0;
|
|
10521
10459
|
console.log(` \u2713 ${ref}:${data.version} \u2014 verified (${ruleCount} rule${ruleCount === 1 ? "" : "s"})`);
|
|
10522
10460
|
}
|
|
10523
|
-
if (!cloud &&
|
|
10461
|
+
if (!cloud && existsSync28(cacheDir)) {
|
|
10524
10462
|
for (const f of readdirSync6(cacheDir)) {
|
|
10525
10463
|
if (f.endsWith(".json") && !keptCacheFiles.has(f)) {
|
|
10526
10464
|
try {
|
|
10527
|
-
|
|
10465
|
+
rmSync2(join26(cacheDir, f));
|
|
10528
10466
|
} catch {
|
|
10529
10467
|
}
|
|
10530
10468
|
}
|
|
@@ -10660,13 +10598,13 @@ var config_exports = {};
|
|
|
10660
10598
|
__export(config_exports, {
|
|
10661
10599
|
configCommand: () => configCommand
|
|
10662
10600
|
});
|
|
10663
|
-
import { readFileSync as
|
|
10664
|
-
import { join as
|
|
10665
|
-
import { homedir as
|
|
10601
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync18, existsSync as existsSync29 } from "fs";
|
|
10602
|
+
import { join as join27 } from "path";
|
|
10603
|
+
import { homedir as homedir26 } from "os";
|
|
10666
10604
|
function readConfigEnv3() {
|
|
10667
|
-
if (!
|
|
10605
|
+
if (!existsSync29(CONFIG_PATH8)) return {};
|
|
10668
10606
|
const out = {};
|
|
10669
|
-
for (const line of
|
|
10607
|
+
for (const line of readFileSync24(CONFIG_PATH8, "utf-8").split("\n")) {
|
|
10670
10608
|
const t = line.trim();
|
|
10671
10609
|
if (!t || t.startsWith("#")) continue;
|
|
10672
10610
|
const eq = t.indexOf("=");
|
|
@@ -10675,11 +10613,11 @@ function readConfigEnv3() {
|
|
|
10675
10613
|
return out;
|
|
10676
10614
|
}
|
|
10677
10615
|
function updateConfigValue(key, value) {
|
|
10678
|
-
if (!
|
|
10616
|
+
if (!existsSync29(CONFIG_PATH8)) {
|
|
10679
10617
|
console.error("No config found. Run `synkro install` first.");
|
|
10680
10618
|
process.exit(1);
|
|
10681
10619
|
}
|
|
10682
|
-
const lines =
|
|
10620
|
+
const lines = readFileSync24(CONFIG_PATH8, "utf-8").split("\n");
|
|
10683
10621
|
const pattern = new RegExp(`^${key}=`);
|
|
10684
10622
|
let found = false;
|
|
10685
10623
|
const updated = lines.map((line) => {
|
|
@@ -10842,14 +10780,14 @@ To change:`);
|
|
|
10842
10780
|
}
|
|
10843
10781
|
if (inferenceValue !== "cloud") await reconcileContainer();
|
|
10844
10782
|
}
|
|
10845
|
-
var
|
|
10783
|
+
var SYNKRO_DIR12, CONFIG_PATH8;
|
|
10846
10784
|
var init_config = __esm({
|
|
10847
10785
|
"cli/commands/config.ts"() {
|
|
10848
10786
|
"use strict";
|
|
10849
10787
|
init_stub();
|
|
10850
10788
|
init_optout();
|
|
10851
|
-
|
|
10852
|
-
CONFIG_PATH8 =
|
|
10789
|
+
SYNKRO_DIR12 = join27(homedir26(), ".synkro");
|
|
10790
|
+
CONFIG_PATH8 = join27(SYNKRO_DIR12, "config.env");
|
|
10853
10791
|
}
|
|
10854
10792
|
});
|
|
10855
10793
|
|
|
@@ -11038,14 +10976,14 @@ Usage:
|
|
|
11038
10976
|
});
|
|
11039
10977
|
|
|
11040
10978
|
// cli/bootstrap.js
|
|
11041
|
-
import { readFileSync as
|
|
10979
|
+
import { readFileSync as readFileSync25, existsSync as existsSync30 } from "fs";
|
|
11042
10980
|
import { resolve as resolve3 } from "path";
|
|
11043
10981
|
var envCandidates = [
|
|
11044
10982
|
resolve3(process.env.HOME ?? "", ".synkro", "config.env")
|
|
11045
10983
|
];
|
|
11046
10984
|
for (const envPath of envCandidates) {
|
|
11047
|
-
if (!
|
|
11048
|
-
const envContent =
|
|
10985
|
+
if (!existsSync30(envPath)) continue;
|
|
10986
|
+
const envContent = readFileSync25(envPath, "utf-8");
|
|
11049
10987
|
for (const line of envContent.split("\n")) {
|
|
11050
10988
|
const trimmed = line.trim();
|
|
11051
10989
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -11062,7 +11000,7 @@ var subArgs = args.slice(1);
|
|
|
11062
11000
|
var isDetachedChild = process.env.SYNKRO_TELEMETRY_DETACHED === "1";
|
|
11063
11001
|
var FLUSH_SKIP = /* @__PURE__ */ new Set(["grade", "version", "--version", "-v", "help", "--help", "-h", ""]);
|
|
11064
11002
|
function printVersion() {
|
|
11065
|
-
console.log("1.7.
|
|
11003
|
+
console.log("1.7.65");
|
|
11066
11004
|
}
|
|
11067
11005
|
function printHelp2() {
|
|
11068
11006
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|