@synkro-sh/cli 1.4.66 → 1.4.67
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 +213 -143
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -2
package/dist/bootstrap.js
CHANGED
|
@@ -283,22 +283,32 @@ var init_ccHookConfig = __esm({
|
|
|
283
283
|
});
|
|
284
284
|
|
|
285
285
|
// cli/installer/cursorHookConfig.ts
|
|
286
|
-
import {
|
|
287
|
-
import { dirname as dirname2 } from "path";
|
|
288
|
-
|
|
289
|
-
|
|
286
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync as renameSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
287
|
+
import { dirname as dirname2, resolve, normalize } from "path";
|
|
288
|
+
import { homedir as homedir2 } from "os";
|
|
289
|
+
function validateHooksPath(path) {
|
|
290
|
+
const resolved = resolve(normalize(path));
|
|
291
|
+
if (!ALLOWED_PARENT_DIRS.some((dir) => resolved.startsWith(dir + "/") || resolved === dir)) {
|
|
292
|
+
throw new Error(`Hooks path must be under ~/.cursor or ~/.config/cursor, got: ${resolved}`);
|
|
293
|
+
}
|
|
294
|
+
return resolved;
|
|
295
|
+
}
|
|
296
|
+
function readHooksFile(rawPath) {
|
|
297
|
+
const safePath = validateHooksPath(rawPath);
|
|
290
298
|
try {
|
|
291
|
-
const raw = readFileSync2(
|
|
299
|
+
const raw = readFileSync2(safePath, "utf-8");
|
|
292
300
|
return JSON.parse(raw);
|
|
293
301
|
} catch (err) {
|
|
294
|
-
|
|
302
|
+
if (err?.code === "ENOENT") return { version: 1, hooks: {} };
|
|
303
|
+
throw new Error(`Failed to parse ${safePath}: ${err.message}`);
|
|
295
304
|
}
|
|
296
305
|
}
|
|
297
|
-
function writeHooksFileAtomic(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
306
|
+
function writeHooksFileAtomic(rawPath, data) {
|
|
307
|
+
const safePath = validateHooksPath(rawPath);
|
|
308
|
+
mkdirSync2(dirname2(safePath), { recursive: true });
|
|
309
|
+
const tmpPath = `${safePath}.synkro.tmp`;
|
|
310
|
+
writeFileSync2(tmpPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
311
|
+
renameSync2(tmpPath, safePath);
|
|
302
312
|
}
|
|
303
313
|
function isSynkroEntry2(entry) {
|
|
304
314
|
if (entry?.[SYNKRO_MARKER2]) return true;
|
|
@@ -314,10 +324,15 @@ function installCursorHooks(hooksJsonPath, config) {
|
|
|
314
324
|
const file = readHooksFile(hooksJsonPath);
|
|
315
325
|
file.version = file.version ?? 1;
|
|
316
326
|
file.hooks = file.hooks ?? {};
|
|
317
|
-
const
|
|
318
|
-
for (const evt of events) {
|
|
327
|
+
for (const evt of ALL_EVENTS) {
|
|
319
328
|
removeSynkroEntries2(file.hooks, evt);
|
|
320
329
|
}
|
|
330
|
+
file.hooks.sessionStart = file.hooks.sessionStart ?? [];
|
|
331
|
+
file.hooks.sessionStart.push({
|
|
332
|
+
command: config.sessionStartScriptPath,
|
|
333
|
+
timeout: 5,
|
|
334
|
+
[SYNKRO_MARKER2]: true
|
|
335
|
+
});
|
|
321
336
|
file.hooks.beforeShellExecution = file.hooks.beforeShellExecution ?? [];
|
|
322
337
|
file.hooks.beforeShellExecution.push({
|
|
323
338
|
command: config.bashJudgeScriptPath,
|
|
@@ -346,14 +361,17 @@ function installCursorHooks(hooksJsonPath, config) {
|
|
|
346
361
|
writeHooksFileAtomic(hooksJsonPath, file);
|
|
347
362
|
}
|
|
348
363
|
function uninstallCursorHooks(hooksJsonPath) {
|
|
349
|
-
|
|
350
|
-
|
|
364
|
+
let file;
|
|
365
|
+
try {
|
|
366
|
+
file = readHooksFile(hooksJsonPath);
|
|
367
|
+
} catch {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
351
370
|
if (!file.hooks) return false;
|
|
352
|
-
const
|
|
353
|
-
for (const evt of events) {
|
|
371
|
+
for (const evt of ALL_EVENTS) {
|
|
354
372
|
removeSynkroEntries2(file.hooks, evt);
|
|
355
373
|
}
|
|
356
|
-
for (const evt of
|
|
374
|
+
for (const evt of ALL_EVENTS) {
|
|
357
375
|
if (Array.isArray(file.hooks[evt]) && file.hooks[evt].length === 0) {
|
|
358
376
|
delete file.hooks[evt];
|
|
359
377
|
}
|
|
@@ -365,37 +383,46 @@ function uninstallCursorHooks(hooksJsonPath) {
|
|
|
365
383
|
return true;
|
|
366
384
|
}
|
|
367
385
|
function inspectCursorHooks(hooksJsonPath) {
|
|
368
|
-
|
|
369
|
-
|
|
386
|
+
let file;
|
|
387
|
+
try {
|
|
388
|
+
file = readHooksFile(hooksJsonPath);
|
|
389
|
+
} catch {
|
|
390
|
+
return { installed: false, sessionStart: false, beforeShellExecution: false, preToolUse: false, afterFileEdit: false, postToolUse: false };
|
|
370
391
|
}
|
|
371
|
-
const file = readHooksFile(hooksJsonPath);
|
|
372
392
|
const h = file.hooks ?? {};
|
|
393
|
+
const sessionStart = (h.sessionStart ?? []).some((e) => isSynkroEntry2(e));
|
|
373
394
|
const beforeShellExecution = (h.beforeShellExecution ?? []).some((e) => isSynkroEntry2(e));
|
|
374
395
|
const preToolUse = (h.preToolUse ?? []).some((e) => isSynkroEntry2(e));
|
|
375
396
|
const afterFileEdit = (h.afterFileEdit ?? []).some((e) => isSynkroEntry2(e));
|
|
376
397
|
const postToolUse = (h.postToolUse ?? []).some((e) => isSynkroEntry2(e));
|
|
377
398
|
return {
|
|
378
|
-
installed: beforeShellExecution || preToolUse || afterFileEdit || postToolUse,
|
|
399
|
+
installed: sessionStart || beforeShellExecution || preToolUse || afterFileEdit || postToolUse,
|
|
400
|
+
sessionStart,
|
|
379
401
|
beforeShellExecution,
|
|
380
402
|
preToolUse,
|
|
381
403
|
afterFileEdit,
|
|
382
404
|
postToolUse
|
|
383
405
|
};
|
|
384
406
|
}
|
|
385
|
-
var SYNKRO_MARKER2;
|
|
407
|
+
var SYNKRO_MARKER2, ALLOWED_PARENT_DIRS, ALL_EVENTS;
|
|
386
408
|
var init_cursorHookConfig = __esm({
|
|
387
409
|
"cli/installer/cursorHookConfig.ts"() {
|
|
388
410
|
"use strict";
|
|
389
411
|
SYNKRO_MARKER2 = "__synkro_managed__";
|
|
412
|
+
ALLOWED_PARENT_DIRS = [
|
|
413
|
+
resolve(homedir2(), ".cursor"),
|
|
414
|
+
resolve(homedir2(), ".config", "cursor")
|
|
415
|
+
];
|
|
416
|
+
ALL_EVENTS = ["sessionStart", "beforeShellExecution", "preToolUse", "afterFileEdit", "postToolUse"];
|
|
390
417
|
}
|
|
391
418
|
});
|
|
392
419
|
|
|
393
420
|
// cli/installer/mcpConfig.ts
|
|
394
|
-
import { existsSync as
|
|
395
|
-
import { homedir as
|
|
421
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3, renameSync as renameSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
422
|
+
import { homedir as homedir3 } from "os";
|
|
396
423
|
import { dirname as dirname3, join as join2 } from "path";
|
|
397
424
|
function readClaudeJson() {
|
|
398
|
-
if (!
|
|
425
|
+
if (!existsSync3(CC_CONFIG_PATH)) return {};
|
|
399
426
|
try {
|
|
400
427
|
const raw = readFileSync3(CC_CONFIG_PATH, "utf-8");
|
|
401
428
|
return JSON.parse(raw);
|
|
@@ -417,7 +444,7 @@ function installMcpConfig(opts) {
|
|
|
417
444
|
}
|
|
418
445
|
if (opts.local) {
|
|
419
446
|
const url2 = "http://127.0.0.1:8931/";
|
|
420
|
-
const tokenPath = join2(
|
|
447
|
+
const tokenPath = join2(homedir3(), ".synkro", ".mcp-local-token");
|
|
421
448
|
let localToken = "";
|
|
422
449
|
try {
|
|
423
450
|
localToken = readFileSync3(tokenPath, "utf-8").trim();
|
|
@@ -443,7 +470,7 @@ function installMcpConfig(opts) {
|
|
|
443
470
|
return { path: CC_CONFIG_PATH, url };
|
|
444
471
|
}
|
|
445
472
|
function uninstallMcpConfig() {
|
|
446
|
-
if (!
|
|
473
|
+
if (!existsSync3(CC_CONFIG_PATH)) return false;
|
|
447
474
|
const config = readClaudeJson();
|
|
448
475
|
if (!config.mcpServers || Object.keys(config.mcpServers).length === 0) return false;
|
|
449
476
|
let removed = false;
|
|
@@ -459,7 +486,7 @@ function uninstallMcpConfig() {
|
|
|
459
486
|
return true;
|
|
460
487
|
}
|
|
461
488
|
function inspectMcpConfig() {
|
|
462
|
-
if (!
|
|
489
|
+
if (!existsSync3(CC_CONFIG_PATH)) {
|
|
463
490
|
return { installed: false, configPath: CC_CONFIG_PATH };
|
|
464
491
|
}
|
|
465
492
|
const config = readClaudeJson();
|
|
@@ -475,7 +502,7 @@ var init_mcpConfig = __esm({
|
|
|
475
502
|
"use strict";
|
|
476
503
|
SYNKRO_MARKER3 = "__synkro_managed__";
|
|
477
504
|
SYNKRO_SERVER_NAME = "synkro-guardrails";
|
|
478
|
-
CC_CONFIG_PATH = join2(
|
|
505
|
+
CC_CONFIG_PATH = join2(homedir3(), ".claude.json");
|
|
479
506
|
}
|
|
480
507
|
});
|
|
481
508
|
|
|
@@ -675,7 +702,7 @@ synkro_post_with_retry() {
|
|
|
675
702
|
});
|
|
676
703
|
|
|
677
704
|
// cli/installer/hookScriptsTs.ts
|
|
678
|
-
var SYNKRO_COMMON_TS, EDIT_PRECHECK_TS, CWE_PRECHECK_TS, CVE_PRECHECK_TS, BASH_JUDGE_TS, AGENT_JUDGE_TS, PLAN_JUDGE_TS, STOP_SUMMARY_TS, SESSION_START_TS, BASH_FOLLOWUP_TS, TRANSCRIPT_SYNC_TS, USER_PROMPT_SUBMIT_TS, CURSOR_BASH_JUDGE_TS, CURSOR_EDIT_PRECHECK_TS, CURSOR_EDIT_CAPTURE_TS, CURSOR_BASH_FOLLOWUP_TS;
|
|
705
|
+
var SYNKRO_COMMON_TS, EDIT_PRECHECK_TS, CWE_PRECHECK_TS, CVE_PRECHECK_TS, BASH_JUDGE_TS, AGENT_JUDGE_TS, PLAN_JUDGE_TS, STOP_SUMMARY_TS, SESSION_START_TS, BASH_FOLLOWUP_TS, TRANSCRIPT_SYNC_TS, USER_PROMPT_SUBMIT_TS, CURSOR_BASH_JUDGE_TS, CURSOR_EDIT_PRECHECK_TS, CURSOR_EDIT_CAPTURE_TS, CURSOR_BASH_FOLLOWUP_TS, CURSOR_SESSION_START_TS;
|
|
679
706
|
var init_hookScriptsTs = __esm({
|
|
680
707
|
"cli/installer/hookScriptsTs.ts"() {
|
|
681
708
|
"use strict";
|
|
@@ -855,7 +882,7 @@ export async function ensureFreshJwt(jwt: string): Promise<string> {
|
|
|
855
882
|
|
|
856
883
|
export function detectRepo(cwd: string): string {
|
|
857
884
|
try {
|
|
858
|
-
const url = execSync('git remote get-url origin', { cwd, timeout: 3000, encoding: 'utf-8' }).trim();
|
|
885
|
+
const url = execSync('git remote get-url origin 2>/dev/null', { cwd, timeout: 3000, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
|
|
859
886
|
if (!url) return '';
|
|
860
887
|
return url
|
|
861
888
|
.replace(/^git@[^:]+:/, '')
|
|
@@ -2261,7 +2288,7 @@ async function main() {
|
|
|
2261
2288
|
let installScanMsg = '';
|
|
2262
2289
|
if (toolName === 'Bash') {
|
|
2263
2290
|
const pkgInstallMatch = command.match(
|
|
2264
|
-
/(?:npm\\s+(?:install|i|add)|pnpm\\s+(?:add|install|i)|yarn\\s+add|bun\\s+(?:add|install|i)|(?:uv\\s+)?pip3?\\s+install|go\\s+get|cargo\\s+add|gem\\s+install|composer\\s+require)\\s+(
|
|
2291
|
+
/(?:npm\\s+(?:install|i|add)|pnpm\\s+(?:add|install|i)|yarn\\s+add|bun\\s+(?:add|install|i)|(?:uv\\s+)?pip3?\\s+install|go\\s+get|cargo\\s+add|gem\\s+install|composer\\s+require)\\s+([^|;&><]+)/
|
|
2265
2292
|
);
|
|
2266
2293
|
const isPip = /(?:uv\\s+)?pip3?\\s+install/.test(command);
|
|
2267
2294
|
const isGo = command.match(/^go\\s+get/);
|
|
@@ -2275,6 +2302,7 @@ async function main() {
|
|
|
2275
2302
|
let skipNext = false;
|
|
2276
2303
|
for (const token of tokens) {
|
|
2277
2304
|
if (skipNext) { skipNext = false; continue; }
|
|
2305
|
+
if (!token || !/^[@a-zA-Z]/.test(token)) continue;
|
|
2278
2306
|
if (token.startsWith('-')) {
|
|
2279
2307
|
if (/^--(python|target|prefix|root|constraint|requirement|index-url|extra-index-url|find-links|build|src|cache-dir|filter|workspace)$/.test(token)) skipNext = true;
|
|
2280
2308
|
continue;
|
|
@@ -2313,8 +2341,9 @@ async function main() {
|
|
|
2313
2341
|
warnings.push('\\u26a0 ' + pkg + ': package not found on PyPI \\u2014 may not exist');
|
|
2314
2342
|
}
|
|
2315
2343
|
} else {
|
|
2344
|
+
const verSlug = deps[pkg] !== '*' ? deps[pkg] : 'latest';
|
|
2316
2345
|
const [metaResp, dlResp] = await Promise.all([
|
|
2317
|
-
fetch('https://registry.npmjs.org/' + encodeURIComponent(pkg) + '/
|
|
2346
|
+
fetch('https://registry.npmjs.org/' + encodeURIComponent(pkg) + '/' + verSlug, { signal: AbortSignal.timeout(4000) }),
|
|
2318
2347
|
fetch('https://api.npmjs.org/downloads/point/last-week/' + encodeURIComponent(pkg), { signal: AbortSignal.timeout(4000) }),
|
|
2319
2348
|
]);
|
|
2320
2349
|
if (metaResp.ok) {
|
|
@@ -3737,6 +3766,42 @@ async function main() {
|
|
|
3737
3766
|
}
|
|
3738
3767
|
}
|
|
3739
3768
|
|
|
3769
|
+
main();
|
|
3770
|
+
`;
|
|
3771
|
+
CURSOR_SESSION_START_TS = `#!/usr/bin/env bun
|
|
3772
|
+
import {
|
|
3773
|
+
loadJwt, loadConfig, readStdin,
|
|
3774
|
+
type HookConfig,
|
|
3775
|
+
} from './_synkro-common.ts';
|
|
3776
|
+
|
|
3777
|
+
async function main() {
|
|
3778
|
+
try {
|
|
3779
|
+
const input = await readStdin();
|
|
3780
|
+
|
|
3781
|
+
let jwt = loadJwt();
|
|
3782
|
+
const config: HookConfig = jwt ? await loadConfig(jwt) : {
|
|
3783
|
+
captureDepth: 'local_only', tier: 'standard', silent: false,
|
|
3784
|
+
policyName: '', rules: [], scanExemptions: [],
|
|
3785
|
+
};
|
|
3786
|
+
|
|
3787
|
+
const policyName = config.policyName || 'default';
|
|
3788
|
+
const ruleCount = config.rules.length;
|
|
3789
|
+
const mode = config.silent ? 'silent' : 'active';
|
|
3790
|
+
|
|
3791
|
+
const context = [
|
|
3792
|
+
'This session is monitored by Synkro (' + mode + ' mode, policy: "' + policyName + '", ' + ruleCount + ' rules).',
|
|
3793
|
+
'Synkro enforces security and compliance rules on tool calls (shell commands, file edits).',
|
|
3794
|
+
'If a tool call is blocked, Synkro will explain which rule was violated and why.',
|
|
3795
|
+
'Do not suggest workarounds to bypass Synkro hooks \u2014 fix the underlying issue instead.',
|
|
3796
|
+
].join(' ');
|
|
3797
|
+
|
|
3798
|
+
const result = { additional_context: context };
|
|
3799
|
+
process.stdout.write(JSON.stringify(result) + '\\n');
|
|
3800
|
+
} catch {
|
|
3801
|
+
process.stdout.write('{}\\n');
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
|
|
3740
3805
|
main();
|
|
3741
3806
|
`;
|
|
3742
3807
|
}
|
|
@@ -3744,8 +3809,8 @@ main();
|
|
|
3744
3809
|
|
|
3745
3810
|
// cli/auth/stub.ts
|
|
3746
3811
|
import { createServer } from "http";
|
|
3747
|
-
import { writeFileSync as writeFileSync4, readFileSync as readFileSync4, existsSync as
|
|
3748
|
-
import { homedir as
|
|
3812
|
+
import { writeFileSync as writeFileSync4, readFileSync as readFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
3813
|
+
import { homedir as homedir4, platform } from "os";
|
|
3749
3814
|
import { join as join3, dirname as dirname4 } from "path";
|
|
3750
3815
|
import { execFile } from "child_process";
|
|
3751
3816
|
import jwt from "jsonwebtoken";
|
|
@@ -3775,13 +3840,13 @@ function openBrowser(url) {
|
|
|
3775
3840
|
}
|
|
3776
3841
|
function saveCredentials(data) {
|
|
3777
3842
|
const dir = dirname4(AUTH_FILE);
|
|
3778
|
-
if (!
|
|
3843
|
+
if (!existsSync4(dir)) {
|
|
3779
3844
|
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
3780
3845
|
}
|
|
3781
3846
|
writeFileSync4(AUTH_FILE, JSON.stringify(data, null, 2), { mode: 384 });
|
|
3782
3847
|
}
|
|
3783
3848
|
function loadCredentials() {
|
|
3784
|
-
if (!
|
|
3849
|
+
if (!existsSync4(AUTH_FILE)) {
|
|
3785
3850
|
return null;
|
|
3786
3851
|
}
|
|
3787
3852
|
try {
|
|
@@ -3798,7 +3863,7 @@ function createCallbackServer() {
|
|
|
3798
3863
|
"Access-Control-Allow-Headers": "Content-Type",
|
|
3799
3864
|
"Vary": "Origin"
|
|
3800
3865
|
};
|
|
3801
|
-
return new Promise((
|
|
3866
|
+
return new Promise((resolve3, reject) => {
|
|
3802
3867
|
const server = createServer((req, res) => {
|
|
3803
3868
|
if (req.method === "OPTIONS") {
|
|
3804
3869
|
const origin = req.headers.origin;
|
|
@@ -3887,7 +3952,7 @@ function createCallbackServer() {
|
|
|
3887
3952
|
res.end(JSON.stringify({ ok: true }));
|
|
3888
3953
|
setTimeout(() => {
|
|
3889
3954
|
server.close();
|
|
3890
|
-
|
|
3955
|
+
resolve3(authData);
|
|
3891
3956
|
}, 200);
|
|
3892
3957
|
});
|
|
3893
3958
|
req.on("error", (e) => {
|
|
@@ -4029,7 +4094,7 @@ async function ensureValidToken() {
|
|
|
4029
4094
|
return true;
|
|
4030
4095
|
}
|
|
4031
4096
|
function clearCredentials() {
|
|
4032
|
-
if (
|
|
4097
|
+
if (existsSync4(AUTH_FILE)) {
|
|
4033
4098
|
unlinkSync2(AUTH_FILE);
|
|
4034
4099
|
}
|
|
4035
4100
|
}
|
|
@@ -4040,7 +4105,7 @@ var init_stub = __esm({
|
|
|
4040
4105
|
PORT = 8100;
|
|
4041
4106
|
RAW_WEB_AUTH_URL = process.env.SYNKRO_WEB_AUTH_URL;
|
|
4042
4107
|
SYNKRO_WEB_AUTH_URL = RAW_WEB_AUTH_URL && /^https?:\/\//.test(RAW_WEB_AUTH_URL) ? RAW_WEB_AUTH_URL : "https://app.synkro.sh";
|
|
4043
|
-
AUTH_FILE = process.env.SYNKRO_AUTH_FILE || join3(
|
|
4108
|
+
AUTH_FILE = process.env.SYNKRO_AUTH_FILE || join3(homedir4(), ".synkro", "credentials.json");
|
|
4044
4109
|
RAW_API_URL = process.env.SYNKRO_CRUD_URL || process.env.SYNKRO_API_URL;
|
|
4045
4110
|
SYNKRO_API_URL = RAW_API_URL && /^https?:\/\//.test(RAW_API_URL) ? RAW_API_URL : "https://api.synkro.sh";
|
|
4046
4111
|
ERROR_HTML = `
|
|
@@ -4203,7 +4268,7 @@ jobs:
|
|
|
4203
4268
|
});
|
|
4204
4269
|
|
|
4205
4270
|
// cli/installer/githubSetup.ts
|
|
4206
|
-
import { existsSync as
|
|
4271
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
4207
4272
|
import { execSync as execSync2 } from "child_process";
|
|
4208
4273
|
import { join as join4 } from "path";
|
|
4209
4274
|
function ghSecretSet(token, owner, repo, name, value) {
|
|
@@ -4260,7 +4325,7 @@ function writeWorkflowFile(repoRootPath) {
|
|
|
4260
4325
|
function findGitRoot(startCwd) {
|
|
4261
4326
|
let cur = startCwd;
|
|
4262
4327
|
while (cur && cur !== "/") {
|
|
4263
|
-
if (
|
|
4328
|
+
if (existsSync5(join4(cur, ".git"))) return cur;
|
|
4264
4329
|
const parent = join4(cur, "..");
|
|
4265
4330
|
if (parent === cur) break;
|
|
4266
4331
|
cur = parent;
|
|
@@ -4298,10 +4363,10 @@ function detectGitRepo() {
|
|
|
4298
4363
|
}
|
|
4299
4364
|
}
|
|
4300
4365
|
function ask(rl, question) {
|
|
4301
|
-
return new Promise((
|
|
4366
|
+
return new Promise((resolve3) => rl.question(question, resolve3));
|
|
4302
4367
|
}
|
|
4303
4368
|
function waitForGithubToken() {
|
|
4304
|
-
return new Promise((
|
|
4369
|
+
return new Promise((resolve3, reject) => {
|
|
4305
4370
|
const server = createServer2((req, res) => {
|
|
4306
4371
|
if (req.method === "OPTIONS") {
|
|
4307
4372
|
res.writeHead(204, {
|
|
@@ -4338,7 +4403,7 @@ function waitForGithubToken() {
|
|
|
4338
4403
|
});
|
|
4339
4404
|
res.end(JSON.stringify({ ok: true }));
|
|
4340
4405
|
setTimeout(() => server.close(), 200);
|
|
4341
|
-
|
|
4406
|
+
resolve3(parsed.github_token);
|
|
4342
4407
|
} catch {
|
|
4343
4408
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
4344
4409
|
res.end(JSON.stringify({ error: "invalid json" }));
|
|
@@ -4503,12 +4568,12 @@ __export(setupGithub_exports, {
|
|
|
4503
4568
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
4504
4569
|
import { stdin as input, stdout as output } from "process";
|
|
4505
4570
|
import { execSync as execSync4, spawn as nodeSpawn } from "child_process";
|
|
4506
|
-
import { existsSync as
|
|
4507
|
-
import { homedir as
|
|
4571
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, unlinkSync as unlinkSync3 } from "fs";
|
|
4572
|
+
import { homedir as homedir5, platform as platform2 } from "os";
|
|
4508
4573
|
import { join as join5 } from "path";
|
|
4509
4574
|
import { execFile as execFile2 } from "child_process";
|
|
4510
4575
|
function readConfig() {
|
|
4511
|
-
if (!
|
|
4576
|
+
if (!existsSync6(CONFIG_PATH)) return {};
|
|
4512
4577
|
const out = {};
|
|
4513
4578
|
for (const line of readFileSync5(CONFIG_PATH, "utf-8").split("\n")) {
|
|
4514
4579
|
const t = line.trim();
|
|
@@ -4523,7 +4588,7 @@ async function prompt(rl, q, opts = {}) {
|
|
|
4523
4588
|
process.stdout.write(q);
|
|
4524
4589
|
const wasRaw = process.stdin.isRaw;
|
|
4525
4590
|
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
4526
|
-
return await new Promise((
|
|
4591
|
+
return await new Promise((resolve3) => {
|
|
4527
4592
|
let chunk = "";
|
|
4528
4593
|
const onData = (data) => {
|
|
4529
4594
|
const s = data.toString("utf-8");
|
|
@@ -4531,7 +4596,7 @@ async function prompt(rl, q, opts = {}) {
|
|
|
4531
4596
|
process.stdin.removeListener("data", onData);
|
|
4532
4597
|
if (process.stdin.setRawMode) process.stdin.setRawMode(wasRaw ?? false);
|
|
4533
4598
|
process.stdout.write("\n");
|
|
4534
|
-
|
|
4599
|
+
resolve3(chunk);
|
|
4535
4600
|
return;
|
|
4536
4601
|
}
|
|
4537
4602
|
if (s === "") process.exit(130);
|
|
@@ -4572,7 +4637,7 @@ function sleep(ms) {
|
|
|
4572
4637
|
}
|
|
4573
4638
|
function captureClaudeSetupToken() {
|
|
4574
4639
|
const tmpFile = join5(SYNKRO_DIR, `token-capture-${Date.now()}.raw`);
|
|
4575
|
-
return new Promise((
|
|
4640
|
+
return new Promise((resolve3, reject) => {
|
|
4576
4641
|
const proc = nodeSpawn("script", ["-q", tmpFile, "claude", "setup-token"], {
|
|
4577
4642
|
stdio: "inherit"
|
|
4578
4643
|
});
|
|
@@ -4602,7 +4667,7 @@ function captureClaudeSetupToken() {
|
|
|
4602
4667
|
reject(new Error(`Could not find token in claude setup-token output (file=${raw.length}b, yellow=${yellow.length}b)`));
|
|
4603
4668
|
return;
|
|
4604
4669
|
}
|
|
4605
|
-
|
|
4670
|
+
resolve3(token[0]);
|
|
4606
4671
|
});
|
|
4607
4672
|
});
|
|
4608
4673
|
}
|
|
@@ -4852,7 +4917,7 @@ var init_setupGithub = __esm({
|
|
|
4852
4917
|
"use strict";
|
|
4853
4918
|
init_githubSetup();
|
|
4854
4919
|
init_stub();
|
|
4855
|
-
SYNKRO_DIR = join5(
|
|
4920
|
+
SYNKRO_DIR = join5(homedir5(), ".synkro");
|
|
4856
4921
|
CONFIG_PATH = join5(SYNKRO_DIR, "config.env");
|
|
4857
4922
|
}
|
|
4858
4923
|
});
|
|
@@ -4881,11 +4946,11 @@ var init_promptFetcher = __esm({
|
|
|
4881
4946
|
});
|
|
4882
4947
|
|
|
4883
4948
|
// cli/local-cc/settings.ts
|
|
4884
|
-
import { existsSync as
|
|
4885
|
-
import { homedir as
|
|
4949
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
|
|
4950
|
+
import { homedir as homedir6 } from "os";
|
|
4886
4951
|
import { join as join6 } from "path";
|
|
4887
4952
|
function isLocalCCEnabled() {
|
|
4888
|
-
if (!
|
|
4953
|
+
if (!existsSync7(CONFIG_PATH2)) return false;
|
|
4889
4954
|
try {
|
|
4890
4955
|
const content = readFileSync6(CONFIG_PATH2, "utf-8");
|
|
4891
4956
|
const match = content.match(/^SYNKRO_LOCAL_INFERENCE='([^']*)'/m);
|
|
@@ -4898,7 +4963,7 @@ var CONFIG_PATH2;
|
|
|
4898
4963
|
var init_settings = __esm({
|
|
4899
4964
|
"cli/local-cc/settings.ts"() {
|
|
4900
4965
|
"use strict";
|
|
4901
|
-
CONFIG_PATH2 = join6(
|
|
4966
|
+
CONFIG_PATH2 = join6(homedir6(), ".synkro", "config.env");
|
|
4902
4967
|
}
|
|
4903
4968
|
});
|
|
4904
4969
|
|
|
@@ -5052,9 +5117,9 @@ await mcp.connect(new StdioServerTransport());
|
|
|
5052
5117
|
});
|
|
5053
5118
|
|
|
5054
5119
|
// cli/local-cc/install.ts
|
|
5055
|
-
import { existsSync as
|
|
5120
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readFileSync as readFileSync7, chmodSync, copyFileSync, renameSync as renameSync4, unlinkSync as unlinkSync4, openSync, fsyncSync, closeSync } from "fs";
|
|
5056
5121
|
import { join as join7 } from "path";
|
|
5057
|
-
import { homedir as
|
|
5122
|
+
import { homedir as homedir7 } from "os";
|
|
5058
5123
|
import { spawnSync } from "child_process";
|
|
5059
5124
|
function writePluginFiles() {
|
|
5060
5125
|
mkdirSync6(SESSION_DIR, { recursive: true });
|
|
@@ -5103,7 +5168,7 @@ function runBunInstall() {
|
|
|
5103
5168
|
}
|
|
5104
5169
|
}
|
|
5105
5170
|
function safelyMutateClaudeJson(mutator) {
|
|
5106
|
-
if (!
|
|
5171
|
+
if (!existsSync8(CLAUDE_JSON_PATH)) {
|
|
5107
5172
|
return;
|
|
5108
5173
|
}
|
|
5109
5174
|
const originalText = readFileSync7(CLAUDE_JSON_PATH, "utf-8");
|
|
@@ -5256,17 +5321,17 @@ var init_install = __esm({
|
|
|
5256
5321
|
"cli/local-cc/install.ts"() {
|
|
5257
5322
|
"use strict";
|
|
5258
5323
|
init_channelSource();
|
|
5259
|
-
CLAUDE_JSON_BACKUP_PATH = join7(
|
|
5260
|
-
SESSION_DIR = join7(
|
|
5324
|
+
CLAUDE_JSON_BACKUP_PATH = join7(homedir7(), ".claude.json.synkro-bak");
|
|
5325
|
+
SESSION_DIR = join7(homedir7(), ".synkro", "cc_sessions");
|
|
5261
5326
|
PLUGIN_PATH = join7(SESSION_DIR, "synkro-channel.ts");
|
|
5262
5327
|
PLUGIN_PKG_PATH = join7(SESSION_DIR, "package.json");
|
|
5263
5328
|
PLUGIN_SETTINGS_DIR = join7(SESSION_DIR, ".claude");
|
|
5264
5329
|
PLUGIN_SETTINGS_PATH = join7(PLUGIN_SETTINGS_DIR, "settings.json");
|
|
5265
5330
|
PROJECT_MCP_PATH = join7(SESSION_DIR, ".mcp.json");
|
|
5266
|
-
CLAUDE_JSON_PATH = join7(
|
|
5331
|
+
CLAUDE_JSON_PATH = join7(homedir7(), ".claude.json");
|
|
5267
5332
|
RUN_SCRIPT_PATH = join7(SESSION_DIR, "run-claude.sh");
|
|
5268
5333
|
TMUX_SESSION_NAME = "synkro-local-cc";
|
|
5269
|
-
SESSION_DIR_2 = join7(
|
|
5334
|
+
SESSION_DIR_2 = join7(homedir7(), ".synkro", "cc_sessions_2");
|
|
5270
5335
|
PLUGIN_PATH_2 = join7(SESSION_DIR_2, "synkro-channel.ts");
|
|
5271
5336
|
PLUGIN_PKG_PATH_2 = join7(SESSION_DIR_2, "package.json");
|
|
5272
5337
|
PLUGIN_SETTINGS_DIR_2 = join7(SESSION_DIR_2, ".claude");
|
|
@@ -5425,7 +5490,7 @@ log "tmux session ended."
|
|
|
5425
5490
|
|
|
5426
5491
|
// cli/local-cc/pueue.ts
|
|
5427
5492
|
import { execFileSync, spawnSync as spawnSync2, spawn } from "child_process";
|
|
5428
|
-
import { homedir as
|
|
5493
|
+
import { homedir as homedir8 } from "os";
|
|
5429
5494
|
import { join as join8 } from "path";
|
|
5430
5495
|
import { connect } from "net";
|
|
5431
5496
|
function pueueAvailable() {
|
|
@@ -5542,14 +5607,14 @@ function ensureRunning(opts = {}) {
|
|
|
5542
5607
|
return startTask(opts);
|
|
5543
5608
|
}
|
|
5544
5609
|
function probePort(host, port, timeoutMs = 500) {
|
|
5545
|
-
return new Promise((
|
|
5610
|
+
return new Promise((resolve3) => {
|
|
5546
5611
|
const sock = connect(port, host);
|
|
5547
5612
|
const done = (ok) => {
|
|
5548
5613
|
try {
|
|
5549
5614
|
sock.destroy();
|
|
5550
5615
|
} catch {
|
|
5551
5616
|
}
|
|
5552
|
-
|
|
5617
|
+
resolve3(ok);
|
|
5553
5618
|
};
|
|
5554
5619
|
sock.once("connect", () => done(true));
|
|
5555
5620
|
sock.once("error", () => done(false));
|
|
@@ -5622,10 +5687,10 @@ var init_pueue = __esm({
|
|
|
5622
5687
|
"use strict";
|
|
5623
5688
|
TASK_LABEL = "synkro-local-cc";
|
|
5624
5689
|
TMUX_SESSION = "synkro-local-cc";
|
|
5625
|
-
SESSION_DIR2 = join8(
|
|
5690
|
+
SESSION_DIR2 = join8(homedir8(), ".synkro", "cc_sessions");
|
|
5626
5691
|
TASK_LABEL_2 = "synkro-local-cc-2";
|
|
5627
5692
|
TMUX_SESSION_2 = "synkro-local-cc-2";
|
|
5628
|
-
SESSION_DIR_22 = join8(
|
|
5693
|
+
SESSION_DIR_22 = join8(homedir8(), ".synkro", "cc_sessions_2");
|
|
5629
5694
|
PueueError = class extends Error {
|
|
5630
5695
|
constructor(message, cause) {
|
|
5631
5696
|
super(message);
|
|
@@ -5641,7 +5706,7 @@ var init_pueue = __esm({
|
|
|
5641
5706
|
|
|
5642
5707
|
// cli/local-cc/prompts.ts
|
|
5643
5708
|
import { readFileSync as readFileSync8 } from "fs";
|
|
5644
|
-
import { homedir as
|
|
5709
|
+
import { homedir as homedir9 } from "os";
|
|
5645
5710
|
import { join as join9 } from "path";
|
|
5646
5711
|
async function fetchPrimers() {
|
|
5647
5712
|
let jwt2 = "";
|
|
@@ -5684,7 +5749,7 @@ var CREDS_PATH, CHANNEL_REPLY_INSTRUCTIONS;
|
|
|
5684
5749
|
var init_prompts = __esm({
|
|
5685
5750
|
"cli/local-cc/prompts.ts"() {
|
|
5686
5751
|
"use strict";
|
|
5687
|
-
CREDS_PATH = join9(
|
|
5752
|
+
CREDS_PATH = join9(homedir9(), ".synkro", "credentials.json");
|
|
5688
5753
|
CHANNEL_REPLY_INSTRUCTIONS = `
|
|
5689
5754
|
DELIVERY METHOD \u2014 MANDATORY, OVERRIDES ALL OTHER OUTPUT RULES:
|
|
5690
5755
|
You are running inside a Synkro MCP channel. Do NOT output your verdict as text.
|
|
@@ -5696,9 +5761,9 @@ Any text output is silently discarded. Only the reply tool call is captured.`;
|
|
|
5696
5761
|
});
|
|
5697
5762
|
|
|
5698
5763
|
// cli/local-cc/turnLog.ts
|
|
5699
|
-
import { appendFileSync, existsSync as
|
|
5764
|
+
import { appendFileSync, existsSync as existsSync9, mkdirSync as mkdirSync7, openSync as openSync2, readFileSync as readFileSync9, readSync, closeSync as closeSync2, statSync, watchFile, unwatchFile } from "fs";
|
|
5700
5765
|
import { dirname as dirname5, join as join10 } from "path";
|
|
5701
|
-
import { homedir as
|
|
5766
|
+
import { homedir as homedir10 } from "os";
|
|
5702
5767
|
function truncate(s, max = PREVIEW_MAX) {
|
|
5703
5768
|
if (s.length <= max) return s;
|
|
5704
5769
|
return s.slice(0, max) + "\u2026 [+" + (s.length - max) + " chars]";
|
|
@@ -5734,7 +5799,7 @@ function appendTurn(args2) {
|
|
|
5734
5799
|
}
|
|
5735
5800
|
}
|
|
5736
5801
|
function readRecentTurns(n = 20) {
|
|
5737
|
-
if (!
|
|
5802
|
+
if (!existsSync9(TURN_LOG_PATH)) return [];
|
|
5738
5803
|
try {
|
|
5739
5804
|
const size = statSync(TURN_LOG_PATH).size;
|
|
5740
5805
|
if (size === 0) return [];
|
|
@@ -5755,7 +5820,7 @@ function readRecentTurns(n = 20) {
|
|
|
5755
5820
|
function followTurns(onEntry) {
|
|
5756
5821
|
try {
|
|
5757
5822
|
mkdirSync7(dirname5(TURN_LOG_PATH), { recursive: true });
|
|
5758
|
-
if (!
|
|
5823
|
+
if (!existsSync9(TURN_LOG_PATH)) {
|
|
5759
5824
|
appendFileSync(TURN_LOG_PATH, "", "utf-8");
|
|
5760
5825
|
}
|
|
5761
5826
|
} catch {
|
|
@@ -5817,7 +5882,7 @@ var TURN_LOG_PATH, PREVIEW_MAX;
|
|
|
5817
5882
|
var init_turnLog = __esm({
|
|
5818
5883
|
"cli/local-cc/turnLog.ts"() {
|
|
5819
5884
|
"use strict";
|
|
5820
|
-
TURN_LOG_PATH = join10(
|
|
5885
|
+
TURN_LOG_PATH = join10(homedir10(), ".synkro", "cc_sessions", "turns.log");
|
|
5821
5886
|
PREVIEW_MAX = 400;
|
|
5822
5887
|
}
|
|
5823
5888
|
});
|
|
@@ -5832,7 +5897,7 @@ async function submitToChannel(role, payload, opts = {}) {
|
|
|
5832
5897
|
const port = opts.port ?? CHANNEL_PORT;
|
|
5833
5898
|
const startedAt = Date.now();
|
|
5834
5899
|
try {
|
|
5835
|
-
const result = await new Promise((
|
|
5900
|
+
const result = await new Promise((resolve3, reject) => {
|
|
5836
5901
|
const req = httpRequest({
|
|
5837
5902
|
host: CHANNEL_HOST,
|
|
5838
5903
|
port,
|
|
@@ -5858,7 +5923,7 @@ async function submitToChannel(role, payload, opts = {}) {
|
|
|
5858
5923
|
reject(new LocalCCError(parsed.error));
|
|
5859
5924
|
return;
|
|
5860
5925
|
}
|
|
5861
|
-
|
|
5926
|
+
resolve3(String(parsed.result ?? ""));
|
|
5862
5927
|
} catch (err) {
|
|
5863
5928
|
reject(new LocalCCError(`malformed channel response: ${text.slice(0, 200)}`, err));
|
|
5864
5929
|
}
|
|
@@ -5884,14 +5949,14 @@ async function submitToChannel(role, payload, opts = {}) {
|
|
|
5884
5949
|
}
|
|
5885
5950
|
}
|
|
5886
5951
|
function isChannelAvailable(port = CHANNEL_PORT, timeoutMs = 500) {
|
|
5887
|
-
return new Promise((
|
|
5952
|
+
return new Promise((resolve3) => {
|
|
5888
5953
|
const sock = connect2(port, CHANNEL_HOST);
|
|
5889
5954
|
const done = (ok) => {
|
|
5890
5955
|
try {
|
|
5891
5956
|
sock.destroy();
|
|
5892
5957
|
} catch {
|
|
5893
5958
|
}
|
|
5894
|
-
|
|
5959
|
+
resolve3(ok);
|
|
5895
5960
|
};
|
|
5896
5961
|
sock.once("connect", () => done(true));
|
|
5897
5962
|
sock.once("error", () => done(false));
|
|
@@ -5924,8 +5989,8 @@ __export(install_exports, {
|
|
|
5924
5989
|
installCommand: () => installCommand,
|
|
5925
5990
|
parseArgs: () => parseArgs
|
|
5926
5991
|
});
|
|
5927
|
-
import { existsSync as
|
|
5928
|
-
import { homedir as
|
|
5992
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync8, writeFileSync as writeFileSync7, chmodSync as chmodSync2, readFileSync as readFileSync10, readdirSync, appendFileSync as appendFileSync2, renameSync as renameSync5 } from "fs";
|
|
5993
|
+
import { homedir as homedir11 } from "os";
|
|
5929
5994
|
import { join as join11 } from "path";
|
|
5930
5995
|
import { execSync as execSync5, spawnSync as spawnSync3, spawn as spawn2 } from "child_process";
|
|
5931
5996
|
import { createInterface as createInterface3 } from "readline";
|
|
@@ -5951,13 +6016,13 @@ function parseArgs(argv) {
|
|
|
5951
6016
|
}
|
|
5952
6017
|
async function promptTranscriptConsent() {
|
|
5953
6018
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
5954
|
-
return new Promise((
|
|
6019
|
+
return new Promise((resolve3) => {
|
|
5955
6020
|
rl.question(
|
|
5956
6021
|
"Would you like Synkro to use Claude Code session transcripts\nto generate guardrail rules and policies for your team? (Y/n) ",
|
|
5957
6022
|
(answer) => {
|
|
5958
6023
|
rl.close();
|
|
5959
6024
|
const trimmed = answer.trim().toLowerCase();
|
|
5960
|
-
|
|
6025
|
+
resolve3(trimmed === "" || trimmed === "y" || trimmed === "yes");
|
|
5961
6026
|
}
|
|
5962
6027
|
);
|
|
5963
6028
|
});
|
|
@@ -5986,6 +6051,7 @@ function writeHookScripts() {
|
|
|
5986
6051
|
const cursorEditPrecheckPath = join11(HOOKS_DIR, "cursor-edit-precheck.ts");
|
|
5987
6052
|
const cursorEditCapturePath = join11(HOOKS_DIR, "cursor-edit-capture.ts");
|
|
5988
6053
|
const cursorBashFollowupPath = join11(HOOKS_DIR, "cursor-bash-followup.ts");
|
|
6054
|
+
const cursorSessionStartPath = join11(HOOKS_DIR, "cursor-session-start.ts");
|
|
5989
6055
|
const mcpLocalServerPath = join11(HOOKS_DIR, "mcp-local-server.ts");
|
|
5990
6056
|
writeFileSync7(bashScriptPath, BASH_JUDGE_TS, "utf-8");
|
|
5991
6057
|
writeFileSync7(bashFollowupScriptPath, BASH_FOLLOWUP_TS, "utf-8");
|
|
@@ -6004,6 +6070,7 @@ function writeHookScripts() {
|
|
|
6004
6070
|
writeFileSync7(cursorEditPrecheckPath, CURSOR_EDIT_PRECHECK_TS, "utf-8");
|
|
6005
6071
|
writeFileSync7(cursorEditCapturePath, CURSOR_EDIT_CAPTURE_TS, "utf-8");
|
|
6006
6072
|
writeFileSync7(cursorBashFollowupPath, CURSOR_BASH_FOLLOWUP_TS, "utf-8");
|
|
6073
|
+
writeFileSync7(cursorSessionStartPath, CURSOR_SESSION_START_TS, "utf-8");
|
|
6007
6074
|
writeFileSync7(mcpLocalServerPath, `#!/usr/bin/env bun
|
|
6008
6075
|
/**
|
|
6009
6076
|
* Local MCP guardrails server \u2014 runs on port 8931, stores rules in ~/.synkro/rules.json.
|
|
@@ -6827,6 +6894,7 @@ console.log(\`[synkro] local MCP guardrails server listening on http://127.0.0.1
|
|
|
6827
6894
|
chmodSync2(cursorEditPrecheckPath, 493);
|
|
6828
6895
|
chmodSync2(cursorEditCapturePath, 493);
|
|
6829
6896
|
chmodSync2(cursorBashFollowupPath, 493);
|
|
6897
|
+
chmodSync2(cursorSessionStartPath, 493);
|
|
6830
6898
|
chmodSync2(mcpLocalServerPath, 493);
|
|
6831
6899
|
return {
|
|
6832
6900
|
bashScript: bashScriptPath,
|
|
@@ -6844,6 +6912,7 @@ console.log(\`[synkro] local MCP guardrails server listening on http://127.0.0.1
|
|
|
6844
6912
|
cursorEditPrecheckScript: cursorEditPrecheckPath,
|
|
6845
6913
|
cursorEditCaptureScript: cursorEditCapturePath,
|
|
6846
6914
|
cursorBashFollowupScript: cursorBashFollowupPath,
|
|
6915
|
+
cursorSessionStartScript: cursorSessionStartPath,
|
|
6847
6916
|
mcpLocalServerScript: mcpLocalServerPath
|
|
6848
6917
|
};
|
|
6849
6918
|
}
|
|
@@ -6856,7 +6925,7 @@ function shellQuoteSingle(value) {
|
|
|
6856
6925
|
}
|
|
6857
6926
|
function resolveSynkroBundle() {
|
|
6858
6927
|
const scriptPath = process.argv[1];
|
|
6859
|
-
if (scriptPath &&
|
|
6928
|
+
if (scriptPath && existsSync10(scriptPath)) return scriptPath;
|
|
6860
6929
|
return null;
|
|
6861
6930
|
}
|
|
6862
6931
|
function writeConfigEnv(opts) {
|
|
@@ -6876,7 +6945,7 @@ function writeConfigEnv(opts) {
|
|
|
6876
6945
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
6877
6946
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
6878
6947
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
6879
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.4.
|
|
6948
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.4.67")}`
|
|
6880
6949
|
];
|
|
6881
6950
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
6882
6951
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -6891,7 +6960,7 @@ function writeConfigEnv(opts) {
|
|
|
6891
6960
|
chmodSync2(CONFIG_PATH3, 384);
|
|
6892
6961
|
}
|
|
6893
6962
|
function updateLocalInferenceFlag(enabled) {
|
|
6894
|
-
if (!
|
|
6963
|
+
if (!existsSync10(CONFIG_PATH3)) return;
|
|
6895
6964
|
let content = readFileSync10(CONFIG_PATH3, "utf-8");
|
|
6896
6965
|
const flag = enabled ? "yes" : "no";
|
|
6897
6966
|
if (content.includes("SYNKRO_LOCAL_INFERENCE=")) {
|
|
@@ -6921,7 +6990,7 @@ function collectLocalMetadata() {
|
|
|
6921
6990
|
meta.cc_version = execSync5("claude --version", { encoding: "utf-8", timeout: 5e3 }).trim().split("\n")[0];
|
|
6922
6991
|
} catch {
|
|
6923
6992
|
}
|
|
6924
|
-
const claudeDir = join11(
|
|
6993
|
+
const claudeDir = join11(homedir11(), ".claude");
|
|
6925
6994
|
try {
|
|
6926
6995
|
const settings = JSON.parse(readFileSync10(join11(claudeDir, "settings.json"), "utf-8"));
|
|
6927
6996
|
const plugins = Object.keys(settings.enabledPlugins ?? {}).filter((k) => settings.enabledPlugins[k]);
|
|
@@ -7011,10 +7080,10 @@ function isAlreadyInstalled() {
|
|
|
7011
7080
|
join11(HOOKS_DIR, "cc-stop-summary.ts"),
|
|
7012
7081
|
join11(HOOKS_DIR, "cc-session-start.ts")
|
|
7013
7082
|
];
|
|
7014
|
-
if (!requiredScripts.every((p) =>
|
|
7015
|
-
if (!
|
|
7016
|
-
const settingsPath = join11(
|
|
7017
|
-
if (!
|
|
7083
|
+
if (!requiredScripts.every((p) => existsSync10(p))) return false;
|
|
7084
|
+
if (!existsSync10(CONFIG_PATH3)) return false;
|
|
7085
|
+
const settingsPath = join11(homedir11(), ".claude", "settings.json");
|
|
7086
|
+
if (!existsSync10(settingsPath)) return false;
|
|
7018
7087
|
try {
|
|
7019
7088
|
const settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
7020
7089
|
const hooks = settings?.hooks;
|
|
@@ -7048,8 +7117,8 @@ function printChannelDiagnostics() {
|
|
|
7048
7117
|
}
|
|
7049
7118
|
}
|
|
7050
7119
|
}
|
|
7051
|
-
const logPath = join11(
|
|
7052
|
-
if (
|
|
7120
|
+
const logPath = join11(homedir11(), ".synkro", "cc_sessions", "run-claude.log");
|
|
7121
|
+
if (existsSync10(logPath)) {
|
|
7053
7122
|
const logContent = readFileSync10(logPath, "utf-8").trim().split("\n").slice(-10);
|
|
7054
7123
|
console.warn(` run-claude.log:`);
|
|
7055
7124
|
for (const line of logContent) console.warn(` ${line}`);
|
|
@@ -7059,7 +7128,7 @@ function printChannelDiagnostics() {
|
|
|
7059
7128
|
console.warn(` Run \`synkro local-cc status\` and \`synkro local-cc logs --tmux\` to debug.`);
|
|
7060
7129
|
}
|
|
7061
7130
|
async function backfillLocalRules(gatewayUrl, token) {
|
|
7062
|
-
if (
|
|
7131
|
+
if (existsSync10(RULES_PATH)) {
|
|
7063
7132
|
console.log(" Local rules already exist \u2014 skipping cloud backfill.");
|
|
7064
7133
|
return;
|
|
7065
7134
|
}
|
|
@@ -7123,7 +7192,7 @@ async function backfillLocalRules(gatewayUrl, token) {
|
|
|
7123
7192
|
}
|
|
7124
7193
|
async function startLocalMcpServer() {
|
|
7125
7194
|
const serverScript = join11(HOOKS_DIR, "mcp-local-server.ts");
|
|
7126
|
-
if (!
|
|
7195
|
+
if (!existsSync10(serverScript)) {
|
|
7127
7196
|
console.warn(" \u26A0 Local MCP server script not found \u2014 skipping.");
|
|
7128
7197
|
return;
|
|
7129
7198
|
}
|
|
@@ -7329,7 +7398,8 @@ async function installCommand(opts = {}) {
|
|
|
7329
7398
|
bashJudgeScriptPath: scripts.cursorBashJudgeScript,
|
|
7330
7399
|
editPrecheckScriptPath: scripts.cursorEditPrecheckScript,
|
|
7331
7400
|
editCaptureScriptPath: scripts.cursorEditCaptureScript,
|
|
7332
|
-
bashFollowupScriptPath: scripts.cursorBashFollowupScript
|
|
7401
|
+
bashFollowupScriptPath: scripts.cursorBashFollowupScript,
|
|
7402
|
+
sessionStartScriptPath: scripts.cursorSessionStartScript
|
|
7333
7403
|
});
|
|
7334
7404
|
console.log(`Configured ${agent.name} hooks at ${agent.settingsPath}`);
|
|
7335
7405
|
}
|
|
@@ -7542,8 +7612,8 @@ function detectGitRepo2() {
|
|
|
7542
7612
|
function getClaudeProjectsFolder() {
|
|
7543
7613
|
const cwd = process.cwd();
|
|
7544
7614
|
const sanitized = "-" + cwd.replace(/\//g, "-");
|
|
7545
|
-
const projectsDir = join11(
|
|
7546
|
-
return
|
|
7615
|
+
const projectsDir = join11(homedir11(), ".claude", "projects", sanitized);
|
|
7616
|
+
return existsSync10(projectsDir) ? projectsDir : null;
|
|
7547
7617
|
}
|
|
7548
7618
|
function extractSessionInsights(projectsDir) {
|
|
7549
7619
|
const insights = [];
|
|
@@ -7738,7 +7808,7 @@ var init_install2 = __esm({
|
|
|
7738
7808
|
init_install();
|
|
7739
7809
|
init_pueue();
|
|
7740
7810
|
init_client();
|
|
7741
|
-
SYNKRO_DIR2 = join11(
|
|
7811
|
+
SYNKRO_DIR2 = join11(homedir11(), ".synkro");
|
|
7742
7812
|
HOOKS_DIR = join11(SYNKRO_DIR2, "hooks");
|
|
7743
7813
|
BIN_DIR = join11(SYNKRO_DIR2, "bin");
|
|
7744
7814
|
CONFIG_PATH3 = join11(SYNKRO_DIR2, "config.env");
|
|
@@ -7820,11 +7890,11 @@ var status_exports = {};
|
|
|
7820
7890
|
__export(status_exports, {
|
|
7821
7891
|
statusCommand: () => statusCommand
|
|
7822
7892
|
});
|
|
7823
|
-
import { existsSync as
|
|
7824
|
-
import { homedir as
|
|
7893
|
+
import { existsSync as existsSync11, readFileSync as readFileSync11 } from "fs";
|
|
7894
|
+
import { homedir as homedir12 } from "os";
|
|
7825
7895
|
import { join as join12 } from "path";
|
|
7826
7896
|
function readConfigEnv() {
|
|
7827
|
-
if (!
|
|
7897
|
+
if (!existsSync11(CONFIG_PATH4)) return {};
|
|
7828
7898
|
const out = {};
|
|
7829
7899
|
const raw = readFileSync11(CONFIG_PATH4, "utf-8");
|
|
7830
7900
|
for (const line of raw.split("\n")) {
|
|
@@ -7933,12 +8003,12 @@ async function statusCommand() {
|
|
|
7933
8003
|
console.log("Hook scripts (Claude Code):");
|
|
7934
8004
|
for (const f of ccHooks) {
|
|
7935
8005
|
const p = join12(HOOKS_DIR2, f);
|
|
7936
|
-
console.log(` ${
|
|
8006
|
+
console.log(` ${existsSync11(p) ? "\u2713" : "\u2717"} ${p}`);
|
|
7937
8007
|
}
|
|
7938
8008
|
console.log("Hook scripts (Cursor):");
|
|
7939
8009
|
for (const f of cursorHooks) {
|
|
7940
8010
|
const p = join12(HOOKS_DIR2, f);
|
|
7941
|
-
console.log(` ${
|
|
8011
|
+
console.log(` ${existsSync11(p) ? "\u2713" : "\u2717"} ${p}`);
|
|
7942
8012
|
}
|
|
7943
8013
|
console.log();
|
|
7944
8014
|
if (localInference) {
|
|
@@ -7981,7 +8051,7 @@ var init_status = __esm({
|
|
|
7981
8051
|
init_cursorHookConfig();
|
|
7982
8052
|
init_mcpConfig();
|
|
7983
8053
|
init_pueue();
|
|
7984
|
-
SYNKRO_DIR3 = join12(
|
|
8054
|
+
SYNKRO_DIR3 = join12(homedir12(), ".synkro");
|
|
7985
8055
|
CONFIG_PATH4 = join12(SYNKRO_DIR3, "config.env");
|
|
7986
8056
|
}
|
|
7987
8057
|
});
|
|
@@ -8014,7 +8084,7 @@ __export(unlink_exports, {
|
|
|
8014
8084
|
});
|
|
8015
8085
|
import { createInterface as createInterface4 } from "readline";
|
|
8016
8086
|
function ask2(rl, question) {
|
|
8017
|
-
return new Promise((
|
|
8087
|
+
return new Promise((resolve3) => rl.question(question, resolve3));
|
|
8018
8088
|
}
|
|
8019
8089
|
async function unlinkCommand() {
|
|
8020
8090
|
if (!isAuthenticated()) {
|
|
@@ -8071,11 +8141,11 @@ var config_exports = {};
|
|
|
8071
8141
|
__export(config_exports, {
|
|
8072
8142
|
configCommand: () => configCommand
|
|
8073
8143
|
});
|
|
8074
|
-
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as
|
|
8144
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync12 } from "fs";
|
|
8075
8145
|
import { join as join13 } from "path";
|
|
8076
|
-
import { homedir as
|
|
8146
|
+
import { homedir as homedir13 } from "os";
|
|
8077
8147
|
function readConfigEnv2() {
|
|
8078
|
-
if (!
|
|
8148
|
+
if (!existsSync12(CONFIG_PATH5)) return {};
|
|
8079
8149
|
const out = {};
|
|
8080
8150
|
for (const line of readFileSync12(CONFIG_PATH5, "utf-8").split("\n")) {
|
|
8081
8151
|
const t = line.trim();
|
|
@@ -8086,7 +8156,7 @@ function readConfigEnv2() {
|
|
|
8086
8156
|
return out;
|
|
8087
8157
|
}
|
|
8088
8158
|
function updateConfigValue(key, value) {
|
|
8089
|
-
if (!
|
|
8159
|
+
if (!existsSync12(CONFIG_PATH5)) {
|
|
8090
8160
|
console.error("No config found. Run `synkro install` first.");
|
|
8091
8161
|
process.exit(1);
|
|
8092
8162
|
}
|
|
@@ -8157,7 +8227,7 @@ var init_config = __esm({
|
|
|
8157
8227
|
"cli/commands/config.ts"() {
|
|
8158
8228
|
"use strict";
|
|
8159
8229
|
init_stub();
|
|
8160
|
-
SYNKRO_DIR4 = join13(
|
|
8230
|
+
SYNKRO_DIR4 = join13(homedir13(), ".synkro");
|
|
8161
8231
|
CONFIG_PATH5 = join13(SYNKRO_DIR4, "config.env");
|
|
8162
8232
|
}
|
|
8163
8233
|
});
|
|
@@ -8168,7 +8238,7 @@ __export(scanPr_exports, {
|
|
|
8168
8238
|
scanPrCommand: () => scanPrCommand
|
|
8169
8239
|
});
|
|
8170
8240
|
import { execSync as execSync6, spawn as spawn3 } from "child_process";
|
|
8171
|
-
import { readFileSync as readFileSync13, existsSync as
|
|
8241
|
+
import { readFileSync as readFileSync13, existsSync as existsSync13 } from "fs";
|
|
8172
8242
|
import { join as join14 } from "path";
|
|
8173
8243
|
function parseMatchSpec(condition) {
|
|
8174
8244
|
if (!condition.startsWith("match_spec:")) return null;
|
|
@@ -8376,7 +8446,7 @@ function spawnClaudeJudge(file, claudeToken, promptHeader) {
|
|
|
8376
8446
|
Diff:
|
|
8377
8447
|
${hunks}`;
|
|
8378
8448
|
const fullPrompt = promptHeader + userMessage;
|
|
8379
|
-
return new Promise((
|
|
8449
|
+
return new Promise((resolve3) => {
|
|
8380
8450
|
const t0 = Date.now();
|
|
8381
8451
|
const proc = spawn3(
|
|
8382
8452
|
"claude",
|
|
@@ -8404,7 +8474,7 @@ ${hunks}`;
|
|
|
8404
8474
|
const latencyMs = Date.now() - t0;
|
|
8405
8475
|
if (code !== 0) {
|
|
8406
8476
|
console.warn(` claude exited ${code}: ${(stderr || stdout).slice(0, 500)}`);
|
|
8407
|
-
|
|
8477
|
+
resolve3({ findings: [], latencyMs });
|
|
8408
8478
|
return;
|
|
8409
8479
|
}
|
|
8410
8480
|
try {
|
|
@@ -8423,10 +8493,10 @@ ${hunks}`;
|
|
|
8423
8493
|
description: f.description,
|
|
8424
8494
|
fix: f.fix
|
|
8425
8495
|
}));
|
|
8426
|
-
|
|
8496
|
+
resolve3({ findings, latencyMs });
|
|
8427
8497
|
} catch (parseErr) {
|
|
8428
8498
|
console.warn(` failed to parse claude response: ${stdout.slice(0, 300)}`);
|
|
8429
|
-
|
|
8499
|
+
resolve3({ findings: [], latencyMs });
|
|
8430
8500
|
}
|
|
8431
8501
|
});
|
|
8432
8502
|
});
|
|
@@ -8475,7 +8545,7 @@ ${JSON.stringify(findings, null, 2)}
|
|
|
8475
8545
|
`;
|
|
8476
8546
|
}
|
|
8477
8547
|
function spawnOpusConsolidator(findings, claudeToken) {
|
|
8478
|
-
return new Promise((
|
|
8548
|
+
return new Promise((resolve3) => {
|
|
8479
8549
|
const prompt2 = buildConsolidationPrompt(findings);
|
|
8480
8550
|
const proc = spawn3(
|
|
8481
8551
|
"claude",
|
|
@@ -8502,7 +8572,7 @@ function spawnOpusConsolidator(findings, claudeToken) {
|
|
|
8502
8572
|
proc.on("close", (code) => {
|
|
8503
8573
|
if (code !== 0) {
|
|
8504
8574
|
console.warn(` opus consolidation exited ${code}: ${(stderr || stdout).slice(0, 300)}`);
|
|
8505
|
-
|
|
8575
|
+
resolve3(fallbackReview(findings));
|
|
8506
8576
|
return;
|
|
8507
8577
|
}
|
|
8508
8578
|
try {
|
|
@@ -8523,10 +8593,10 @@ function spawnOpusConsolidator(findings, claudeToken) {
|
|
|
8523
8593
|
const order = ["low", "medium", "high", "critical"];
|
|
8524
8594
|
return order.indexOf(f.severity) > order.indexOf(max) ? f.severity : max;
|
|
8525
8595
|
}, "low");
|
|
8526
|
-
|
|
8596
|
+
resolve3({ summary: review.summary || "", comments, severity: maxSeverity });
|
|
8527
8597
|
} catch {
|
|
8528
8598
|
console.warn(` failed to parse opus response, using fallback`);
|
|
8529
|
-
|
|
8599
|
+
resolve3(fallbackReview(findings));
|
|
8530
8600
|
}
|
|
8531
8601
|
});
|
|
8532
8602
|
});
|
|
@@ -8649,7 +8719,7 @@ function shouldFail(findings, threshold) {
|
|
|
8649
8719
|
}
|
|
8650
8720
|
function readRepoDeps() {
|
|
8651
8721
|
const pkgPath = join14(process.cwd(), "package.json");
|
|
8652
|
-
if (!
|
|
8722
|
+
if (!existsSync13(pkgPath)) return {};
|
|
8653
8723
|
try {
|
|
8654
8724
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
|
|
8655
8725
|
return { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
@@ -8913,8 +8983,8 @@ var disconnect_exports = {};
|
|
|
8913
8983
|
__export(disconnect_exports, {
|
|
8914
8984
|
disconnectCommand: () => disconnectCommand
|
|
8915
8985
|
});
|
|
8916
|
-
import { existsSync as
|
|
8917
|
-
import { homedir as
|
|
8986
|
+
import { existsSync as existsSync14, rmSync } from "fs";
|
|
8987
|
+
import { homedir as homedir14 } from "os";
|
|
8918
8988
|
import { join as join15 } from "path";
|
|
8919
8989
|
function tearDownLocalCC() {
|
|
8920
8990
|
let hadTask = false;
|
|
@@ -8951,13 +9021,13 @@ function disconnectCommand(args2 = []) {
|
|
|
8951
9021
|
console.log(`${mcpRemoved ? "\u2713" : "\xB7"} MCP guardrails server: ${mcpRemoved ? "removed entry from ~/.claude.json" : "no Synkro MCP entry found"}`);
|
|
8952
9022
|
}
|
|
8953
9023
|
if (purge) {
|
|
8954
|
-
if (
|
|
9024
|
+
if (existsSync14(SYNKRO_DIR5)) {
|
|
8955
9025
|
rmSync(SYNKRO_DIR5, { recursive: true, force: true });
|
|
8956
9026
|
console.log(`\u2713 Removed ${SYNKRO_DIR5}`);
|
|
8957
9027
|
} else {
|
|
8958
9028
|
console.log(`\xB7 ${SYNKRO_DIR5} already gone, nothing to remove`);
|
|
8959
9029
|
}
|
|
8960
|
-
} else if (
|
|
9030
|
+
} else if (existsSync14(SYNKRO_DIR5)) {
|
|
8961
9031
|
console.log(`Config preserved at ${SYNKRO_DIR5}. Run with --purge to remove.`);
|
|
8962
9032
|
}
|
|
8963
9033
|
console.log("\nSynkro disconnected.");
|
|
@@ -8972,7 +9042,7 @@ var init_disconnect = __esm({
|
|
|
8972
9042
|
init_mcpConfig();
|
|
8973
9043
|
init_pueue();
|
|
8974
9044
|
init_install();
|
|
8975
|
-
SYNKRO_DIR5 = join15(
|
|
9045
|
+
SYNKRO_DIR5 = join15(homedir14(), ".synkro");
|
|
8976
9046
|
}
|
|
8977
9047
|
});
|
|
8978
9048
|
|
|
@@ -9019,9 +9089,9 @@ __export(localCc_exports, {
|
|
|
9019
9089
|
localCcCommand: () => localCcCommand
|
|
9020
9090
|
});
|
|
9021
9091
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
9022
|
-
import { homedir as
|
|
9092
|
+
import { homedir as homedir15 } from "os";
|
|
9023
9093
|
import { join as join16 } from "path";
|
|
9024
|
-
import { existsSync as
|
|
9094
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "fs";
|
|
9025
9095
|
function printHelp() {
|
|
9026
9096
|
console.log(`synkro local-cc \u2014 manage the local Claude Code inference session
|
|
9027
9097
|
|
|
@@ -9111,14 +9181,14 @@ TROUBLESHOOTING
|
|
|
9111
9181
|
`);
|
|
9112
9182
|
}
|
|
9113
9183
|
function readGatewayUrl() {
|
|
9114
|
-
if (
|
|
9184
|
+
if (existsSync15(CONFIG_PATH6)) {
|
|
9115
9185
|
const m = readFileSync14(CONFIG_PATH6, "utf-8").match(/^SYNKRO_GATEWAY_URL='([^']*)'/m);
|
|
9116
9186
|
if (m) return m[1];
|
|
9117
9187
|
}
|
|
9118
9188
|
return "https://api.synkro.sh";
|
|
9119
9189
|
}
|
|
9120
9190
|
function updateLocalInferenceFlag2(enabled) {
|
|
9121
|
-
if (!
|
|
9191
|
+
if (!existsSync15(CONFIG_PATH6)) return;
|
|
9122
9192
|
let content = readFileSync14(CONFIG_PATH6, "utf-8");
|
|
9123
9193
|
const flag = enabled ? "yes" : "no";
|
|
9124
9194
|
if (content.includes("SYNKRO_LOCAL_INFERENCE=")) {
|
|
@@ -9348,7 +9418,7 @@ function cmdLogs(rest) {
|
|
|
9348
9418
|
if (!raw) console.log(" " + colorize("(use --raw / -r to see full payloads, --live / -f to follow)", 90));
|
|
9349
9419
|
return;
|
|
9350
9420
|
}
|
|
9351
|
-
return new Promise((
|
|
9421
|
+
return new Promise((resolve3) => {
|
|
9352
9422
|
console.log(" " + colorize("\u2014 following new turns (Ctrl-C to exit) \u2014", 90));
|
|
9353
9423
|
const stop = followTurns((t) => {
|
|
9354
9424
|
console.log(" " + formatTurn(t, raw));
|
|
@@ -9356,7 +9426,7 @@ function cmdLogs(rest) {
|
|
|
9356
9426
|
const onSigint = () => {
|
|
9357
9427
|
stop();
|
|
9358
9428
|
process.removeListener("SIGINT", onSigint);
|
|
9359
|
-
|
|
9429
|
+
resolve3();
|
|
9360
9430
|
};
|
|
9361
9431
|
process.on("SIGINT", onSigint);
|
|
9362
9432
|
});
|
|
@@ -9453,7 +9523,7 @@ var init_localCc = __esm({
|
|
|
9453
9523
|
init_settings();
|
|
9454
9524
|
init_client();
|
|
9455
9525
|
init_stub();
|
|
9456
|
-
CONFIG_PATH6 = join16(
|
|
9526
|
+
CONFIG_PATH6 = join16(homedir15(), ".synkro", "config.env");
|
|
9457
9527
|
}
|
|
9458
9528
|
});
|
|
9459
9529
|
|
|
@@ -9463,10 +9533,10 @@ __export(grade_exports, {
|
|
|
9463
9533
|
gradeCommand: () => gradeCommand
|
|
9464
9534
|
});
|
|
9465
9535
|
async function readStdin() {
|
|
9466
|
-
return new Promise((
|
|
9536
|
+
return new Promise((resolve3, reject) => {
|
|
9467
9537
|
const chunks = [];
|
|
9468
9538
|
process.stdin.on("data", (c) => chunks.push(c));
|
|
9469
|
-
process.stdin.on("end", () =>
|
|
9539
|
+
process.stdin.on("end", () => resolve3(Buffer.concat(chunks).toString("utf-8")));
|
|
9470
9540
|
process.stdin.on("error", reject);
|
|
9471
9541
|
});
|
|
9472
9542
|
}
|
|
@@ -9507,14 +9577,14 @@ var init_grade = __esm({
|
|
|
9507
9577
|
});
|
|
9508
9578
|
|
|
9509
9579
|
// cli/bootstrap.js
|
|
9510
|
-
import { readFileSync as readFileSync15, existsSync as
|
|
9511
|
-
import { resolve } from "path";
|
|
9580
|
+
import { readFileSync as readFileSync15, existsSync as existsSync16 } from "fs";
|
|
9581
|
+
import { resolve as resolve2 } from "path";
|
|
9512
9582
|
var envCandidates = [
|
|
9513
|
-
|
|
9514
|
-
|
|
9583
|
+
resolve2(process.cwd(), ".env"),
|
|
9584
|
+
resolve2(process.env.HOME ?? "", ".synkro", "config.env")
|
|
9515
9585
|
];
|
|
9516
9586
|
for (const envPath of envCandidates) {
|
|
9517
|
-
if (!
|
|
9587
|
+
if (!existsSync16(envPath)) continue;
|
|
9518
9588
|
const envContent = readFileSync15(envPath, "utf-8");
|
|
9519
9589
|
for (const line of envContent.split("\n")) {
|
|
9520
9590
|
const trimmed = line.trim();
|