@synkro-sh/cli 1.3.27 → 1.3.29
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 +128 -25
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -571,34 +571,49 @@ refresh_jwt() {
|
|
|
571
571
|
return 0
|
|
572
572
|
}
|
|
573
573
|
|
|
574
|
-
# Resolve tier (cached 60 min) \u2014 server is canonical via /cli/me
|
|
574
|
+
# Resolve tier + capture_depth (cached 60 min) \u2014 server is canonical via /cli/me.
|
|
575
575
|
TIER_CACHE_FILE="$HOME/.synkro/.tier-cache-\${SYNKRO_USER_ID:-default}"
|
|
576
|
+
CD_CACHE_FILE="\${TIER_CACHE_FILE}.cd"
|
|
576
577
|
SYNKRO_INFERENCE_TIER=""
|
|
578
|
+
SYNKRO_CAPTURE_DEPTH=""
|
|
577
579
|
if find "$TIER_CACHE_FILE" -mmin -60 2>/dev/null | grep -q .; then
|
|
578
580
|
SYNKRO_INFERENCE_TIER=$(cat "$TIER_CACHE_FILE" 2>/dev/null)
|
|
581
|
+
SYNKRO_CAPTURE_DEPTH=$(cat "$CD_CACHE_FILE" 2>/dev/null)
|
|
579
582
|
fi
|
|
580
583
|
if [ -z "$SYNKRO_INFERENCE_TIER" ]; then
|
|
581
584
|
ME_RESP=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 2 2>/dev/null || echo "")
|
|
582
585
|
if [ -n "$ME_RESP" ]; then
|
|
583
586
|
SYNKRO_INFERENCE_TIER=$(echo "$ME_RESP" | jq -r '.tier // empty' 2>/dev/null)
|
|
584
587
|
[ -n "$SYNKRO_INFERENCE_TIER" ] && printf '%s' "$SYNKRO_INFERENCE_TIER" > "$TIER_CACHE_FILE" 2>/dev/null || true
|
|
588
|
+
SYNKRO_CAPTURE_DEPTH=$(echo "$ME_RESP" | jq -r '.capture_depth // empty' 2>/dev/null)
|
|
589
|
+
[ -n "$SYNKRO_CAPTURE_DEPTH" ] && printf '%s' "$SYNKRO_CAPTURE_DEPTH" > "$CD_CACHE_FILE" 2>/dev/null || true
|
|
585
590
|
fi
|
|
586
591
|
fi
|
|
587
592
|
SYNKRO_INFERENCE_TIER="\${SYNKRO_INFERENCE_TIER:-fast}"
|
|
593
|
+
SYNKRO_CAPTURE_DEPTH="\${SYNKRO_CAPTURE_DEPTH:-full}"
|
|
588
594
|
|
|
595
|
+
USE_LOCAL=false
|
|
596
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ] && command -v claude >/dev/null 2>&1; then
|
|
597
|
+
USE_LOCAL=true
|
|
598
|
+
elif [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v claude >/dev/null 2>&1; then
|
|
599
|
+
USE_LOCAL=true
|
|
600
|
+
fi
|
|
589
601
|
|
|
590
|
-
if [ "$
|
|
602
|
+
if [ "$USE_LOCAL" = "true" ]; then
|
|
591
603
|
# \u2500\u2500\u2500 FREE TIER: grade via the persistent claude daemon (mode=bash). \u2500\u2500\u2500
|
|
592
604
|
|
|
593
|
-
# Fetch org guardrail rules relevant to this command (
|
|
594
|
-
ORG_RULES
|
|
595
|
-
|
|
596
|
-
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
605
|
+
# Fetch org guardrail rules relevant to this command (skip in local_only \u2014 no content leaves device).
|
|
606
|
+
ORG_RULES="[]"
|
|
607
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" != "local_only" ]; then
|
|
608
|
+
ORG_RULES=$(printf '%s' "$COMMAND" | head -c 4000 \\
|
|
609
|
+
| jq -Rs '{content: .}' \\
|
|
610
|
+
| curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules?top_k=15" \\
|
|
611
|
+
-X POST -H "Content-Type: application/json" \\
|
|
612
|
+
-H "Authorization: Bearer $JWT" \\
|
|
613
|
+
-d @- --max-time 2 2>/dev/null \\
|
|
614
|
+
| jq -c '[.rules[]? | {rule_id, text, severity, category}]' 2>/dev/null || echo "[]")
|
|
615
|
+
if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
|
|
616
|
+
fi
|
|
602
617
|
|
|
603
618
|
GRADER_PROMPT_FILE=$(mktemp -t synkro-bash-prompt.XXXXXX)
|
|
604
619
|
trap "rm -f \\"$GRADER_PROMPT_FILE\\"" EXIT
|
|
@@ -711,6 +726,36 @@ case "$SEVERITY" in
|
|
|
711
726
|
;;
|
|
712
727
|
esac
|
|
713
728
|
|
|
729
|
+
# Fire-and-forget anonymized telemetry for local_only mode
|
|
730
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ] && [ -n "$VERDICT_KIND" ]; then
|
|
731
|
+
(
|
|
732
|
+
ANON_BODY=$(jq -n \\
|
|
733
|
+
--arg event_id "$(uuidgen 2>/dev/null || echo "evt_$(date +%s)_$$")" \\
|
|
734
|
+
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \\
|
|
735
|
+
--arg hook_type "bash" \\
|
|
736
|
+
--arg verdict "$VERDICT_KIND" \\
|
|
737
|
+
--arg severity "$SEVERITY" \\
|
|
738
|
+
--arg category "$CATEGORY" \\
|
|
739
|
+
--arg model "\${CC_MODEL:-claude-sonnet-4-6}" \\
|
|
740
|
+
--arg tool_name "$TOOL_NAME" \\
|
|
741
|
+
'{
|
|
742
|
+
event_id: $event_id,
|
|
743
|
+
timestamp: $timestamp,
|
|
744
|
+
hook_type: $hook_type,
|
|
745
|
+
verdict: $verdict,
|
|
746
|
+
severity: $severity,
|
|
747
|
+
category: $category,
|
|
748
|
+
model: $model,
|
|
749
|
+
tool_name: $tool_name
|
|
750
|
+
}')
|
|
751
|
+
curl -sS -X POST "\${GATEWAY_URL}/api/v1/events/local-verdict" \\
|
|
752
|
+
-H "Content-Type: application/json" \\
|
|
753
|
+
-H "Authorization: Bearer $JWT" \\
|
|
754
|
+
-d "$ANON_BODY" \\
|
|
755
|
+
--max-time 2 >/dev/null 2>&1
|
|
756
|
+
) &
|
|
757
|
+
fi
|
|
758
|
+
|
|
714
759
|
exit 0
|
|
715
760
|
`;
|
|
716
761
|
CC_EDIT_PRECHECK_SCRIPT = `#!/bin/bash
|
|
@@ -938,31 +983,47 @@ refresh_jwt() {
|
|
|
938
983
|
}
|
|
939
984
|
|
|
940
985
|
|
|
941
|
-
# Resolve tier (cached 60 min) \u2014 server is canonical via /cli/me
|
|
986
|
+
# Resolve tier + capture_depth (cached 60 min) \u2014 server is canonical via /cli/me.
|
|
942
987
|
TIER_CACHE_FILE="$HOME/.synkro/.tier-cache-\${SYNKRO_USER_ID:-default}"
|
|
988
|
+
CD_CACHE_FILE="\${TIER_CACHE_FILE}.cd"
|
|
943
989
|
SYNKRO_INFERENCE_TIER=""
|
|
990
|
+
SYNKRO_CAPTURE_DEPTH=""
|
|
944
991
|
if find "$TIER_CACHE_FILE" -mmin -60 2>/dev/null | grep -q .; then
|
|
945
992
|
SYNKRO_INFERENCE_TIER=$(cat "$TIER_CACHE_FILE" 2>/dev/null)
|
|
993
|
+
SYNKRO_CAPTURE_DEPTH=$(cat "$CD_CACHE_FILE" 2>/dev/null)
|
|
946
994
|
fi
|
|
947
995
|
if [ -z "$SYNKRO_INFERENCE_TIER" ]; then
|
|
948
996
|
ME_RESP=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 2 2>/dev/null || echo "")
|
|
949
997
|
if [ -n "$ME_RESP" ]; then
|
|
950
998
|
SYNKRO_INFERENCE_TIER=$(echo "$ME_RESP" | jq -r '.tier // empty' 2>/dev/null)
|
|
951
999
|
[ -n "$SYNKRO_INFERENCE_TIER" ] && printf '%s' "$SYNKRO_INFERENCE_TIER" > "$TIER_CACHE_FILE" 2>/dev/null || true
|
|
1000
|
+
SYNKRO_CAPTURE_DEPTH=$(echo "$ME_RESP" | jq -r '.capture_depth // empty' 2>/dev/null)
|
|
1001
|
+
[ -n "$SYNKRO_CAPTURE_DEPTH" ] && printf '%s' "$SYNKRO_CAPTURE_DEPTH" > "$CD_CACHE_FILE" 2>/dev/null || true
|
|
952
1002
|
fi
|
|
953
1003
|
fi
|
|
954
1004
|
SYNKRO_INFERENCE_TIER="\${SYNKRO_INFERENCE_TIER:-fast}"
|
|
1005
|
+
SYNKRO_CAPTURE_DEPTH="\${SYNKRO_CAPTURE_DEPTH:-full}"
|
|
955
1006
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1007
|
+
USE_LOCAL=false
|
|
1008
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ] && command -v claude >/dev/null 2>&1; then
|
|
1009
|
+
USE_LOCAL=true
|
|
1010
|
+
elif [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v claude >/dev/null 2>&1; then
|
|
1011
|
+
USE_LOCAL=true
|
|
1012
|
+
fi
|
|
1013
|
+
|
|
1014
|
+
if [ "$USE_LOCAL" = "true" ]; then
|
|
1015
|
+
# \u2500\u2500\u2500 LOCAL GRADING: grade via the persistent claude daemon (Python helper).
|
|
1016
|
+
ORG_RULES="[]"
|
|
1017
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" != "local_only" ]; then
|
|
1018
|
+
ORG_RULES=$(printf '%s' "$PROPOSED" | head -c 8000 \\
|
|
1019
|
+
| jq -Rs '{content: .}' \\
|
|
1020
|
+
| curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules?top_k=20" \\
|
|
1021
|
+
-X POST -H "Content-Type: application/json" \\
|
|
1022
|
+
-H "Authorization: Bearer $JWT" \\
|
|
1023
|
+
-d @- --max-time 2 2>/dev/null \\
|
|
1024
|
+
| jq -c '[.rules[]? | {rule_id, text, severity, category, mode}]' 2>/dev/null || echo "[]")
|
|
1025
|
+
if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
|
|
1026
|
+
fi
|
|
966
1027
|
|
|
967
1028
|
GRADER_PROMPT_FILE=$(mktemp -t synkro-grade.XXXXXX)
|
|
968
1029
|
trap "rm -f \\"$GRADER_PROMPT_FILE\\"" EXIT
|
|
@@ -1088,6 +1149,44 @@ else
|
|
|
1088
1149
|
echo "$RESP_WITH_MSG"
|
|
1089
1150
|
fi
|
|
1090
1151
|
|
|
1152
|
+
# Fire-and-forget anonymized telemetry for local_only mode
|
|
1153
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ] && [ -n "$DECISION" ]; then
|
|
1154
|
+
LOCAL_VERDICT="allow"
|
|
1155
|
+
LOCAL_SEVERITY="audit"
|
|
1156
|
+
LOCAL_CATEGORY="edit_pass"
|
|
1157
|
+
if [ "$DECISION" = "deny" ]; then
|
|
1158
|
+
LOCAL_VERDICT="warn"
|
|
1159
|
+
LOCAL_SEVERITY="block"
|
|
1160
|
+
LOCAL_CATEGORY="edit_violation"
|
|
1161
|
+
fi
|
|
1162
|
+
(
|
|
1163
|
+
ANON_BODY=$(jq -n \\
|
|
1164
|
+
--arg event_id "$(uuidgen 2>/dev/null || echo "evt_$(date +%s)_$$")" \\
|
|
1165
|
+
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \\
|
|
1166
|
+
--arg hook_type "edit" \\
|
|
1167
|
+
--arg verdict "$LOCAL_VERDICT" \\
|
|
1168
|
+
--arg severity "$LOCAL_SEVERITY" \\
|
|
1169
|
+
--arg category "$LOCAL_CATEGORY" \\
|
|
1170
|
+
--arg model "\${CC_MODEL:-claude-sonnet-4-6}" \\
|
|
1171
|
+
--arg tool_name "$TOOL_NAME" \\
|
|
1172
|
+
'{
|
|
1173
|
+
event_id: $event_id,
|
|
1174
|
+
timestamp: $timestamp,
|
|
1175
|
+
hook_type: $hook_type,
|
|
1176
|
+
verdict: $verdict,
|
|
1177
|
+
severity: $severity,
|
|
1178
|
+
category: $category,
|
|
1179
|
+
model: $model,
|
|
1180
|
+
tool_name: $tool_name
|
|
1181
|
+
}')
|
|
1182
|
+
curl -sS -X POST "\${GATEWAY_URL}/api/v1/events/local-verdict" \\
|
|
1183
|
+
-H "Content-Type: application/json" \\
|
|
1184
|
+
-H "Authorization: Bearer $JWT" \\
|
|
1185
|
+
-d "$ANON_BODY" \\
|
|
1186
|
+
--max-time 2 >/dev/null 2>&1
|
|
1187
|
+
) &
|
|
1188
|
+
fi
|
|
1189
|
+
|
|
1091
1190
|
exit 0
|
|
1092
1191
|
`;
|
|
1093
1192
|
CC_EDIT_CAPTURE_SCRIPT = `#!/bin/bash
|
|
@@ -2373,7 +2472,7 @@ async function refreshToken() {
|
|
|
2373
2472
|
const creds = loadCredentials();
|
|
2374
2473
|
if (!creds?.refresh_token) return false;
|
|
2375
2474
|
try {
|
|
2376
|
-
const response = await fetch(`${
|
|
2475
|
+
const response = await fetch(`${SYNKRO_API_URL}/api/auth/refresh`, {
|
|
2377
2476
|
method: "POST",
|
|
2378
2477
|
headers: { "Content-Type": "application/json" },
|
|
2379
2478
|
body: JSON.stringify({ refresh_token: creds.refresh_token })
|
|
@@ -2382,6 +2481,7 @@ async function refreshToken() {
|
|
|
2382
2481
|
const data = await response.json();
|
|
2383
2482
|
if (data.access_token) {
|
|
2384
2483
|
saveCredentials({
|
|
2484
|
+
...creds,
|
|
2385
2485
|
access_token: data.access_token,
|
|
2386
2486
|
refresh_token: data.refresh_token || creds.refresh_token
|
|
2387
2487
|
});
|
|
@@ -2413,7 +2513,7 @@ function clearCredentials() {
|
|
|
2413
2513
|
unlinkSync2(AUTH_FILE);
|
|
2414
2514
|
}
|
|
2415
2515
|
}
|
|
2416
|
-
var PORT, RAW_WEB_AUTH_URL, SYNKRO_WEB_AUTH_URL, AUTH_FILE, ERROR_HTML, refreshPromise;
|
|
2516
|
+
var PORT, RAW_WEB_AUTH_URL, SYNKRO_WEB_AUTH_URL, AUTH_FILE, RAW_API_URL, SYNKRO_API_URL, ERROR_HTML, refreshPromise;
|
|
2417
2517
|
var init_stub = __esm({
|
|
2418
2518
|
"cli/auth/stub.ts"() {
|
|
2419
2519
|
"use strict";
|
|
@@ -2421,6 +2521,8 @@ var init_stub = __esm({
|
|
|
2421
2521
|
RAW_WEB_AUTH_URL = process.env.SYNKRO_WEB_AUTH_URL;
|
|
2422
2522
|
SYNKRO_WEB_AUTH_URL = RAW_WEB_AUTH_URL && /^https?:\/\//.test(RAW_WEB_AUTH_URL) ? RAW_WEB_AUTH_URL : "https://app.synkro.sh";
|
|
2423
2523
|
AUTH_FILE = process.env.SYNKRO_AUTH_FILE || join3(homedir3(), ".synkro", "credentials.json");
|
|
2524
|
+
RAW_API_URL = process.env.SYNKRO_CRUD_URL || process.env.SYNKRO_API_URL;
|
|
2525
|
+
SYNKRO_API_URL = RAW_API_URL && /^https?:\/\//.test(RAW_API_URL) ? RAW_API_URL : "https://api.synkro.sh";
|
|
2424
2526
|
ERROR_HTML = `
|
|
2425
2527
|
<!DOCTYPE html>
|
|
2426
2528
|
<html>
|
|
@@ -3368,7 +3470,7 @@ function writeConfigEnv(opts) {
|
|
|
3368
3470
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3369
3471
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3370
3472
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3371
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.3.
|
|
3473
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.3.29")}`
|
|
3372
3474
|
];
|
|
3373
3475
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
3374
3476
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|
|
@@ -4035,6 +4137,7 @@ async function statusCommand() {
|
|
|
4035
4137
|
const gatewayUrl = (config.SYNKRO_GATEWAY_URL || "https://api.synkro.sh").replace(/^['"]|['"]$/g, "");
|
|
4036
4138
|
let serverTier = config.SYNKRO_TIER || "(unset)";
|
|
4037
4139
|
let serverInference = config.SYNKRO_INFERENCE || "fast";
|
|
4140
|
+
await ensureValidToken();
|
|
4038
4141
|
const token = getAccessToken();
|
|
4039
4142
|
if (token) {
|
|
4040
4143
|
try {
|