@synkro-sh/cli 1.6.29 → 1.6.31
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 +123 -20
- package/dist/bootstrap.js.map +1 -1
- package/package.json +2 -2
package/dist/bootstrap.js
CHANGED
|
@@ -1906,6 +1906,21 @@ export function appendLocalTelemetry(body: Record<string, any>): void {
|
|
|
1906
1906
|
try {
|
|
1907
1907
|
appendFileSync(TELEMETRY_SPOOL, JSON.stringify(event) + '\\n');
|
|
1908
1908
|
} catch {}
|
|
1909
|
+
// Realtime: fire-and-forget POST to the local server so events appear
|
|
1910
|
+
// in the dashboard immediately. Spool file remains the durable fallback.
|
|
1911
|
+
try {
|
|
1912
|
+
const port = process.env.SYNKRO_MCP_PORT || '18931';
|
|
1913
|
+
let token = '';
|
|
1914
|
+
try { token = readFileSync(join(HOME, '.synkro', '.mcp-jwt'), 'utf-8').trim(); } catch {}
|
|
1915
|
+
if (token) {
|
|
1916
|
+
fetch('http://127.0.0.1:' + port + '/api/ingest', {
|
|
1917
|
+
method: 'POST',
|
|
1918
|
+
headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + token },
|
|
1919
|
+
body: JSON.stringify(event),
|
|
1920
|
+
signal: AbortSignal.timeout(3000),
|
|
1921
|
+
}).catch(() => {});
|
|
1922
|
+
}
|
|
1923
|
+
} catch {}
|
|
1909
1924
|
}
|
|
1910
1925
|
|
|
1911
1926
|
function tryAcquireDrainLock(): boolean {
|
|
@@ -2336,12 +2351,10 @@ export async function pushConversationMessage(
|
|
|
2336
2351
|
type: role,
|
|
2337
2352
|
content: text,
|
|
2338
2353
|
ts: new Date().toISOString(),
|
|
2354
|
+
message_index: seq,
|
|
2339
2355
|
patch_redacted: opts.patchRedacted ?? true,
|
|
2340
2356
|
}],
|
|
2341
2357
|
};
|
|
2342
|
-
if (!opts.patchRedacted) {
|
|
2343
|
-
(body.messages as Record<string, unknown>[])[0].message_index = seq;
|
|
2344
|
-
}
|
|
2345
2358
|
const resp = await fetch('http://127.0.0.1:' + mcpPort + '/api/conversation-sync', {
|
|
2346
2359
|
method: 'POST',
|
|
2347
2360
|
headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + mcpToken },
|
|
@@ -2478,10 +2491,13 @@ export async function syncConversationTranscript(
|
|
|
2478
2491
|
} catch {}
|
|
2479
2492
|
}
|
|
2480
2493
|
|
|
2481
|
-
|
|
2482
|
-
|
|
2494
|
+
if (messages.length === 0) {
|
|
2495
|
+
writeFileSync(offsetFile, String(totalLines), 'utf-8');
|
|
2496
|
+
return { ingested: 0, messages: [] };
|
|
2497
|
+
}
|
|
2483
2498
|
|
|
2484
|
-
const
|
|
2499
|
+
const rawPort = parseInt(process.env.SYNKRO_MCP_PORT || '18931', 10);
|
|
2500
|
+
const mcpPort = (rawPort > 0 && rawPort < 65536) ? rawPort : 18931;
|
|
2485
2501
|
let mcpToken = '';
|
|
2486
2502
|
try { mcpToken = readFileSync(join(HOME, '.synkro', '.mcp-jwt'), 'utf-8').trim(); } catch {}
|
|
2487
2503
|
if (!mcpToken) return { ingested: 0, messages };
|
|
@@ -2494,6 +2510,7 @@ export async function syncConversationTranscript(
|
|
|
2494
2510
|
signal: AbortSignal.timeout(5000),
|
|
2495
2511
|
});
|
|
2496
2512
|
if (resp.ok) {
|
|
2513
|
+
writeFileSync(offsetFile, String(totalLines), 'utf-8');
|
|
2497
2514
|
const data = await resp.json() as { ingested?: number };
|
|
2498
2515
|
return { ingested: data.ingested ?? messages.length, messages };
|
|
2499
2516
|
}
|
|
@@ -3027,7 +3044,17 @@ export function hookSessionId(payload: Record<string, unknown>): string {
|
|
|
3027
3044
|
}
|
|
3028
3045
|
|
|
3029
3046
|
export function isCursorHookFormat(): boolean {
|
|
3030
|
-
return process.env.SYNKRO_HOOK_FORMAT === 'cursor';
|
|
3047
|
+
return process.env.SYNKRO_HOOK_FORMAT === 'cursor' || process.argv.includes('--cursor');
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
// Cursor reads CC hooks from ~/.claude/settings.json and fires them alongside
|
|
3051
|
+
// its own ~/.cursor/hooks.json entries. When that happens, agentKind is
|
|
3052
|
+
// 'claude_code' but the payload model is non-Claude (e.g. gpt-5.5).
|
|
3053
|
+
// Return true so the CC hook can bail out and let Cursor's hooks handle it.
|
|
3054
|
+
export function isCursorInvokingCcHook(agentKind: string, model: string): boolean {
|
|
3055
|
+
if (agentKind === 'cursor') return false;
|
|
3056
|
+
if (!model || model === 'unknown' || model === '') return false;
|
|
3057
|
+
return !model.startsWith('claude-');
|
|
3031
3058
|
}
|
|
3032
3059
|
|
|
3033
3060
|
let cursorHookExited = false;
|
|
@@ -3127,13 +3154,13 @@ import {
|
|
|
3127
3154
|
appendSessionAction, readSessionLog, compressSessionLog, log,
|
|
3128
3155
|
outputJson, outputEmpty, setupCursorHookSignals, isEditTool, hookSessionId, GATEWAY_URL,
|
|
3129
3156
|
logGraderUnavailable, filterRules, ruleFilterText, normalizeMode, countEditLineDelta,
|
|
3130
|
-
captureLineMetrics, cursorModelFromPayload, resolveTranscriptPath,
|
|
3157
|
+
captureLineMetrics, cursorModelFromPayload, resolveTranscriptPath, isCursorInvokingCcHook,
|
|
3131
3158
|
type HookConfig, type Rule,
|
|
3132
3159
|
} from './_synkro-common.ts';
|
|
3133
3160
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3134
3161
|
import { basename, join } from 'node:path';
|
|
3135
3162
|
|
|
3136
|
-
const agentKind = process.env.SYNKRO_HOOK_FORMAT === 'cursor' ? 'cursor' : 'claude_code';
|
|
3163
|
+
const agentKind = (process.env.SYNKRO_HOOK_FORMAT === 'cursor' || process.argv.includes('--cursor')) ? 'cursor' : 'claude_code';
|
|
3137
3164
|
|
|
3138
3165
|
async function main() {
|
|
3139
3166
|
setupCursorHookSignals();
|
|
@@ -3220,6 +3247,8 @@ async function main() {
|
|
|
3220
3247
|
? cursorModelFromPayload(payload)
|
|
3221
3248
|
: (transcript.ccModel || String(payload.model ?? payload.model_id ?? ''));
|
|
3222
3249
|
|
|
3250
|
+
if (isCursorInvokingCcHook(agentKind, captureModel)) { outputEmpty(); return; }
|
|
3251
|
+
|
|
3223
3252
|
// Model detection: prefer transcript (CC), fall back to payload (Cursor)
|
|
3224
3253
|
if (!transcript.ccModel) {
|
|
3225
3254
|
transcript.ccModel = captureModel;
|
|
@@ -3377,12 +3406,12 @@ import {
|
|
|
3377
3406
|
localGradeCwe, parseVerdict, reconstructContent, readStdin, log,
|
|
3378
3407
|
outputJson, outputEmpty, setupCursorHookSignals, isEditTool, isShellTool, isCursorHookFormat,
|
|
3379
3408
|
extractShellCodeWrites, hookSessionId, filePathFromToolInput, emitBlockScanFindings, dispatchFinding, dispatchCapture, GATEWAY_URL,
|
|
3380
|
-
logGraderUnavailable, resolveTranscriptPath,
|
|
3409
|
+
logGraderUnavailable, resolveTranscriptPath, isCursorInvokingCcHook,
|
|
3381
3410
|
} from './_synkro-common.ts';
|
|
3382
3411
|
import { basename, extname, resolve, join, dirname } from 'node:path';
|
|
3383
3412
|
import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
3384
3413
|
|
|
3385
|
-
const agentKind = process.env.SYNKRO_HOOK_FORMAT === 'cursor' ? 'cursor' : 'claude_code';
|
|
3414
|
+
const agentKind = (process.env.SYNKRO_HOOK_FORMAT === 'cursor' || process.argv.includes('--cursor')) ? 'cursor' : 'claude_code';
|
|
3386
3415
|
|
|
3387
3416
|
function detectModel(payload: Record<string, unknown>): string {
|
|
3388
3417
|
const raw = String(payload.model ?? payload.model_id ?? '');
|
|
@@ -3528,6 +3557,8 @@ async function main() {
|
|
|
3528
3557
|
const shellCommand = typeof payload.command === 'string' ? payload.command.trim() : '';
|
|
3529
3558
|
const ccModel = detectModel(payload);
|
|
3530
3559
|
|
|
3560
|
+
if (isCursorInvokingCcHook(agentKind, ccModel)) { outputEmpty(); return; }
|
|
3561
|
+
|
|
3531
3562
|
const targets: CweScanTarget[] = [];
|
|
3532
3563
|
|
|
3533
3564
|
if (isCursorHookFormat() && (shellCommand || isShellTool(toolName))) {
|
|
@@ -3931,6 +3962,7 @@ import {
|
|
|
3931
3962
|
loadJwt, ensureFreshJwt, detectRepo, loadConfig, route, tag,
|
|
3932
3963
|
reconstructContent, readStdin, findNearestDeps, filePathFromToolInput, log,
|
|
3933
3964
|
outputJson, outputEmpty, setupCursorHookSignals, isEditTool, hookSessionId, dispatchFinding, dispatchCapture, dispatchScanResult, extractTranscript, emitBlockScanFindings, resolveTranscriptPath, GATEWAY_URL,
|
|
3965
|
+
isCursorHookFormat,
|
|
3934
3966
|
} from './_synkro-common.ts';
|
|
3935
3967
|
import { basename } from 'node:path';
|
|
3936
3968
|
import { readFileSync } from 'node:fs';
|
|
@@ -3961,6 +3993,9 @@ async function main() {
|
|
|
3961
3993
|
return;
|
|
3962
3994
|
}
|
|
3963
3995
|
|
|
3996
|
+
const _m = String(payload.model ?? payload.model_id ?? '');
|
|
3997
|
+
if (!isCursorHookFormat() && _m && !_m.startsWith('claude-')) { outputEmpty(); return; }
|
|
3998
|
+
|
|
3964
3999
|
const toolInput = payload.tool_input || {};
|
|
3965
4000
|
const sessionId = hookSessionId(payload);
|
|
3966
4001
|
const workspaceRoots = Array.isArray(payload.workspace_roots) ? payload.workspace_roots as string[] : [];
|
|
@@ -4165,11 +4200,16 @@ async function main() {
|
|
|
4165
4200
|
const cveIds = findings.slice(0, 10).map((f: any) =>
|
|
4166
4201
|
(f.aliases || []).find((a: string) => a.startsWith('CVE-')) || f.id || 'unknown'
|
|
4167
4202
|
);
|
|
4203
|
+
let cveCcModel: string | undefined = String(payload.model ?? payload.model_id ?? '') || undefined;
|
|
4204
|
+
if (!cveCcModel && transcriptPath) {
|
|
4205
|
+
try { cveCcModel = extractTranscript(transcriptPath).ccModel || undefined; } catch {}
|
|
4206
|
+
}
|
|
4168
4207
|
dispatchCapture(jwt, 'cve', 'block', 'critical', 'security',
|
|
4169
4208
|
toolName, gitRepo, sessionId, config.captureDepth, {
|
|
4170
4209
|
command: 'edit ' + filePath,
|
|
4171
4210
|
reasoning: top3,
|
|
4172
4211
|
violatedRules: cveIds,
|
|
4212
|
+
ccModel: cveCcModel,
|
|
4173
4213
|
});
|
|
4174
4214
|
dispatchScanResult(jwt, {
|
|
4175
4215
|
session_id: sessionId, file_path: filePath, scan_type: 'cve',
|
|
@@ -4218,6 +4258,9 @@ async function main() {
|
|
|
4218
4258
|
if (!input.trim()) { outputEmpty(); return; }
|
|
4219
4259
|
|
|
4220
4260
|
const payload = JSON.parse(input);
|
|
4261
|
+
const _m = String(payload.model ?? payload.model_id ?? '');
|
|
4262
|
+
if (!isCursorHookFormat() && _m && !_m.startsWith('claude-')) { outputEmpty(); return; }
|
|
4263
|
+
|
|
4221
4264
|
const toolInput = payload.tool_input || {};
|
|
4222
4265
|
const command = typeof payload.command === 'string' ? payload.command : (toolInput.command || '');
|
|
4223
4266
|
if (!command) { outputEmpty(); return; }
|
|
@@ -4320,7 +4363,7 @@ import {
|
|
|
4320
4363
|
extractTranscript, readLastPrompt, appendSessionAction, readSessionLog, compressSessionLog, log,
|
|
4321
4364
|
outputJson, outputEmpty, setupCursorHookSignals, isShellTool, hookSessionId, GATEWAY_URL,
|
|
4322
4365
|
logGraderUnavailable, filterRules, ruleFilterText, normalizeMode, appendLocalTelemetry, isSafeInRepoRead,
|
|
4323
|
-
hashCommand, resolveTranscriptPath,
|
|
4366
|
+
hashCommand, resolveTranscriptPath, isCursorHookFormat,
|
|
4324
4367
|
type HookConfig, type Rule,
|
|
4325
4368
|
} from './_synkro-common.ts';
|
|
4326
4369
|
import { createHash } from 'node:crypto';
|
|
@@ -4371,6 +4414,9 @@ async function main() {
|
|
|
4371
4414
|
return;
|
|
4372
4415
|
}
|
|
4373
4416
|
|
|
4417
|
+
const _m = String(payload.model ?? payload.model_id ?? '');
|
|
4418
|
+
if (!isCursorHookFormat() && _m && !_m.startsWith('claude-')) { outputEmpty(); return; }
|
|
4419
|
+
|
|
4374
4420
|
const toolInput = payload.tool_input || {};
|
|
4375
4421
|
const sessionId = hookSessionId(payload);
|
|
4376
4422
|
const toolUseId = payload.tool_use_id || '';
|
|
@@ -4610,11 +4656,11 @@ import {
|
|
|
4610
4656
|
parseVerdict, dispatchCapture, ruleMode, postWithRetry, readStdin,
|
|
4611
4657
|
extractTranscript, readLastPrompt, appendSessionAction, readSessionLog, compressSessionLog, log,
|
|
4612
4658
|
outputJson, outputEmpty, setupCursorHookSignals, isAgentTool, hookSessionId, GATEWAY_URL,
|
|
4613
|
-
logGraderUnavailable, filterRules, normalizeMode, resolveTranscriptPath,
|
|
4659
|
+
logGraderUnavailable, filterRules, normalizeMode, resolveTranscriptPath, isCursorInvokingCcHook,
|
|
4614
4660
|
type HookConfig, type Rule,
|
|
4615
4661
|
} from './_synkro-common.ts';
|
|
4616
4662
|
|
|
4617
|
-
const agentKind = process.env.SYNKRO_HOOK_FORMAT === 'cursor' ? 'cursor' : 'claude_code';
|
|
4663
|
+
const agentKind = (process.env.SYNKRO_HOOK_FORMAT === 'cursor' || process.argv.includes('--cursor')) ? 'cursor' : 'claude_code';
|
|
4618
4664
|
|
|
4619
4665
|
async function main() {
|
|
4620
4666
|
setupCursorHookSignals();
|
|
@@ -4629,6 +4675,9 @@ async function main() {
|
|
|
4629
4675
|
return;
|
|
4630
4676
|
}
|
|
4631
4677
|
|
|
4678
|
+
const _m = String(payload.model ?? payload.model_id ?? '');
|
|
4679
|
+
if (isCursorInvokingCcHook(agentKind, _m)) { outputEmpty(); return; }
|
|
4680
|
+
|
|
4632
4681
|
const toolInput = payload.tool_input || {};
|
|
4633
4682
|
const sessionId = hookSessionId(payload);
|
|
4634
4683
|
const toolUseId = payload.tool_use_id || '';
|
|
@@ -4789,13 +4838,13 @@ import {
|
|
|
4789
4838
|
loadJwt, ensureFreshJwt, detectRepo, loadConfig, route, tag, localGrade,
|
|
4790
4839
|
parseVerdict, dispatchCapture, appendSessionAction, readSessionLog, compressSessionLog, postWithRetry, readStdin, log,
|
|
4791
4840
|
outputJson, outputEmpty, setupCursorHookSignals, isPlanTool, hookSessionId, GATEWAY_URL,
|
|
4792
|
-
filterRules, resolveTranscriptPath,
|
|
4841
|
+
filterRules, resolveTranscriptPath, isCursorInvokingCcHook,
|
|
4793
4842
|
} from './_synkro-common.ts';
|
|
4794
4843
|
import { existsSync, readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
|
|
4795
4844
|
import { join } from 'node:path';
|
|
4796
4845
|
import { homedir } from 'node:os';
|
|
4797
4846
|
|
|
4798
|
-
const agentKind = process.env.SYNKRO_HOOK_FORMAT === 'cursor' ? 'cursor' : 'claude_code';
|
|
4847
|
+
const agentKind = (process.env.SYNKRO_HOOK_FORMAT === 'cursor' || process.argv.includes('--cursor')) ? 'cursor' : 'claude_code';
|
|
4799
4848
|
|
|
4800
4849
|
function findLatestPlanInDir(plansDir: string): string | null {
|
|
4801
4850
|
if (!existsSync(plansDir)) return null;
|
|
@@ -4847,6 +4896,9 @@ async function main() {
|
|
|
4847
4896
|
const toolName = payload.tool_name || '';
|
|
4848
4897
|
if (!isPlanTool(toolName)) { outputEmpty(); return; }
|
|
4849
4898
|
|
|
4899
|
+
const _m = String(payload.model ?? payload.model_id ?? '');
|
|
4900
|
+
if (isCursorInvokingCcHook(agentKind, _m)) { outputEmpty(); return; }
|
|
4901
|
+
|
|
4850
4902
|
const planFile = findLatestPlan();
|
|
4851
4903
|
if (!planFile) { outputEmpty(); return; }
|
|
4852
4904
|
const plan = readFileSync(planFile, 'utf-8');
|
|
@@ -5754,6 +5806,21 @@ main();
|
|
|
5754
5806
|
});
|
|
5755
5807
|
|
|
5756
5808
|
// cli/auth/stub.ts
|
|
5809
|
+
var stub_exports = {};
|
|
5810
|
+
__export(stub_exports, {
|
|
5811
|
+
authenticate: () => authenticate,
|
|
5812
|
+
clearCredentials: () => clearCredentials,
|
|
5813
|
+
ensureValidToken: () => ensureValidToken,
|
|
5814
|
+
getAccessToken: () => getAccessToken,
|
|
5815
|
+
getCurrentUserId: () => getCurrentUserId,
|
|
5816
|
+
getSecrets: () => getSecrets,
|
|
5817
|
+
getUserInfo: () => getUserInfo,
|
|
5818
|
+
isAuthenticated: () => isAuthenticated,
|
|
5819
|
+
isTokenExpired: () => isTokenExpired,
|
|
5820
|
+
loadCredentials: () => loadCredentials,
|
|
5821
|
+
refreshToken: () => refreshToken,
|
|
5822
|
+
saveCredentials: () => saveCredentials
|
|
5823
|
+
});
|
|
5757
5824
|
import { createServer } from "http";
|
|
5758
5825
|
import { writeFileSync as writeFileSync4, readFileSync as readFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync2 } from "fs";
|
|
5759
5826
|
import { homedir as homedir4, platform } from "os";
|
|
@@ -5960,6 +6027,17 @@ function isAuthenticated() {
|
|
|
5960
6027
|
return true;
|
|
5961
6028
|
}
|
|
5962
6029
|
}
|
|
6030
|
+
function getCurrentUserId() {
|
|
6031
|
+
const creds = loadCredentials();
|
|
6032
|
+
if (!creds) {
|
|
6033
|
+
throw new Error("Not authenticated");
|
|
6034
|
+
}
|
|
6035
|
+
const decoded = jwt.decode(creds.access_token);
|
|
6036
|
+
if (!decoded?.sub) {
|
|
6037
|
+
throw new Error("Invalid token");
|
|
6038
|
+
}
|
|
6039
|
+
return decoded.sub;
|
|
6040
|
+
}
|
|
5963
6041
|
function getUserInfo() {
|
|
5964
6042
|
const creds = loadCredentials();
|
|
5965
6043
|
if (!creds) {
|
|
@@ -6044,6 +6122,15 @@ function clearCredentials() {
|
|
|
6044
6122
|
unlinkSync2(AUTH_FILE);
|
|
6045
6123
|
}
|
|
6046
6124
|
}
|
|
6125
|
+
async function getSecrets(userId, integrationId) {
|
|
6126
|
+
return {
|
|
6127
|
+
AWS_ACCESS_KEY_ID: process.env.USER_AWS_KEY || "",
|
|
6128
|
+
AWS_SECRET_ACCESS_KEY: process.env.USER_AWS_SECRET || "",
|
|
6129
|
+
AWS_REGION: process.env.USER_AWS_REGION || "us-east-1",
|
|
6130
|
+
HF_TOKEN: process.env.USER_HF_TOKEN || "",
|
|
6131
|
+
LANGSMITH_API_KEY: process.env.USER_LANGSMITH_KEY || ""
|
|
6132
|
+
};
|
|
6133
|
+
}
|
|
6047
6134
|
var PORT, RAW_WEB_AUTH_URL, SYNKRO_WEB_AUTH_URL, AUTH_FILE, RAW_API_URL, SYNKRO_API_URL, ERROR_HTML, refreshPromise;
|
|
6048
6135
|
var init_stub = __esm({
|
|
6049
6136
|
"cli/auth/stub.ts"() {
|
|
@@ -7889,7 +7976,7 @@ function writeConfigEnv(opts) {
|
|
|
7889
7976
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
7890
7977
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
7891
7978
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
7892
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.6.
|
|
7979
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.6.31")}`
|
|
7893
7980
|
];
|
|
7894
7981
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
7895
7982
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -8325,7 +8412,7 @@ async function installCommand(opts = {}) {
|
|
|
8325
8412
|
const ingestResp = await fetch(`http://127.0.0.1:${hostMcpPort}/api/ingest`, {
|
|
8326
8413
|
method: "POST",
|
|
8327
8414
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${mcpJwt}` },
|
|
8328
|
-
body: JSON.stringify({ capture_type: "
|
|
8415
|
+
body: JSON.stringify({ capture_type: "healthcheck", event_id: `healthcheck_${Date.now()}` }),
|
|
8329
8416
|
signal: AbortSignal.timeout(5e3)
|
|
8330
8417
|
});
|
|
8331
8418
|
if (ingestResp.ok) {
|
|
@@ -10641,7 +10728,6 @@ var init_config = __esm({
|
|
|
10641
10728
|
import { readFileSync as readFileSync13, existsSync as existsSync16 } from "fs";
|
|
10642
10729
|
import { resolve as resolve2 } from "path";
|
|
10643
10730
|
var envCandidates = [
|
|
10644
|
-
resolve2(process.cwd(), ".env"),
|
|
10645
10731
|
resolve2(process.env.HOME ?? "", ".synkro", "config.env")
|
|
10646
10732
|
];
|
|
10647
10733
|
for (const envPath of envCandidates) {
|
|
@@ -10661,7 +10747,7 @@ var args = process.argv.slice(2);
|
|
|
10661
10747
|
var cmd = args[0] || "";
|
|
10662
10748
|
var subArgs = args.slice(1);
|
|
10663
10749
|
function printVersion() {
|
|
10664
|
-
console.log("1.6.
|
|
10750
|
+
console.log("1.6.31");
|
|
10665
10751
|
}
|
|
10666
10752
|
function printHelp2() {
|
|
10667
10753
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|
|
@@ -10707,6 +10793,23 @@ async function main() {
|
|
|
10707
10793
|
disconnectCommand2(subArgs);
|
|
10708
10794
|
break;
|
|
10709
10795
|
}
|
|
10796
|
+
case "login": {
|
|
10797
|
+
const { authenticate: authenticate2, isAuthenticated: isAuthenticated2 } = await Promise.resolve().then(() => (init_stub(), stub_exports));
|
|
10798
|
+
if (isAuthenticated2()) {
|
|
10799
|
+
console.log("Already authenticated.");
|
|
10800
|
+
} else {
|
|
10801
|
+
console.log("Opening browser for Synkro auth...");
|
|
10802
|
+
const result = await authenticate2((status) => {
|
|
10803
|
+
if (status.phase === "success") console.log(" \u2713 Authenticated");
|
|
10804
|
+
else if (status.phase === "error") console.error(" \u2717 " + status.message);
|
|
10805
|
+
});
|
|
10806
|
+
if (!result) {
|
|
10807
|
+
console.error("Authentication failed.");
|
|
10808
|
+
process.exit(1);
|
|
10809
|
+
}
|
|
10810
|
+
}
|
|
10811
|
+
break;
|
|
10812
|
+
}
|
|
10710
10813
|
case "grade": {
|
|
10711
10814
|
const { gradeCommand: gradeCommand2 } = await Promise.resolve().then(() => (init_grade(), grade_exports));
|
|
10712
10815
|
await gradeCommand2(subArgs);
|