@synkro-sh/cli 1.3.31 → 1.3.33
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 +134 -56
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -1118,51 +1118,68 @@ if [ "$USE_LOCAL" = "true" ]; then
|
|
|
1118
1118
|
VERDICT_JSON='{"ok":true,"violations":[]}'
|
|
1119
1119
|
fi
|
|
1120
1120
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1121
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then
|
|
1122
|
+
# No file content / diff / intent / actions leave the device. Synthesize
|
|
1123
|
+
# the hook response from the local verdict only.
|
|
1124
|
+
OK=$(echo "$VERDICT_JSON" | jq -r '.ok // true' 2>/dev/null)
|
|
1125
|
+
if [ "$OK" = "false" ]; then
|
|
1126
|
+
FIRST_REASON=$(echo "$VERDICT_JSON" | jq -r '.violations[0].reason // "policy violation"' 2>/dev/null)
|
|
1127
|
+
RULE_ID=$(echo "$VERDICT_JSON" | jq -r '.violations[0].rule_id // "local_violation"' 2>/dev/null)
|
|
1128
|
+
if [ "$IS_HEADLESS" = "1" ]; then DEC="deny"; else DEC="ask"; fi
|
|
1129
|
+
RESP=$(jq -n \\
|
|
1130
|
+
--arg dec "$DEC" \\
|
|
1131
|
+
--arg reason "[synkro] $RULE_ID: $FIRST_REASON" \\
|
|
1132
|
+
'{ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: $dec, permissionDecisionReason: $reason, additionalContext: $reason }, reason: $reason }')
|
|
1133
|
+
else
|
|
1134
|
+
RESP=$(jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "allow" }, reason: "" }')
|
|
1135
|
+
fi
|
|
1136
|
+
else
|
|
1137
|
+
LOCAL_BODY=$(jq -n \\
|
|
1138
|
+
--argjson verdict "$VERDICT_JSON" \\
|
|
1139
|
+
--arg file_path "$FILE_PATH" \\
|
|
1140
|
+
--arg tool_name "$TOOL_NAME" \\
|
|
1141
|
+
--arg content "$PROPOSED" \\
|
|
1142
|
+
--arg file_before "$FILE_BEFORE" \\
|
|
1143
|
+
--argjson diff "$DIFF_FIELD" \\
|
|
1144
|
+
--arg user_intent "$USER_INTENT" \\
|
|
1145
|
+
--argjson recent_actions "$RECENT_ACTIONS" \\
|
|
1146
|
+
--arg session_id "$SESSION_ID" \\
|
|
1147
|
+
--arg tool_use_id "$TOOL_USE_ID" \\
|
|
1148
|
+
--arg cwd "$CWD" \\
|
|
1149
|
+
--arg permission_mode "$PERMISSION_MODE" \\
|
|
1150
|
+
--arg headless_flag "$HEADLESS_FLAG" \\
|
|
1151
|
+
--arg repo "$GIT_REPO" \\
|
|
1152
|
+
'{
|
|
1153
|
+
verdict: $verdict,
|
|
1154
|
+
file_path: $file_path,
|
|
1155
|
+
tool_name: $tool_name,
|
|
1156
|
+
content: $content,
|
|
1157
|
+
file_before: (if ($file_before | length) > 0 then $file_before else null end),
|
|
1158
|
+
diff: $diff,
|
|
1159
|
+
user_intent: (if ($user_intent | length) > 0 then $user_intent else null end),
|
|
1160
|
+
recent_actions: $recent_actions,
|
|
1161
|
+
session_id: (if ($session_id | length) > 0 then $session_id else null end),
|
|
1162
|
+
tool_use_id: (if ($tool_use_id | length) > 0 then $tool_use_id else null end),
|
|
1163
|
+
cwd: (if ($cwd | length) > 0 then $cwd else null end),
|
|
1164
|
+
permission_mode: (if ($permission_mode | length) > 0 then $permission_mode else null end),
|
|
1165
|
+
headless: ($headless_flag == "1"),
|
|
1166
|
+
repo: (if ($repo | length) > 0 then $repo else null end)
|
|
1167
|
+
}')
|
|
1158
1168
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1169
|
+
RESP=$(curl -sS -X POST "\${GATEWAY_URL}/api/v1/precheck-edit/local-verdict" \\
|
|
1170
|
+
-H "Content-Type: application/json" \\
|
|
1171
|
+
-H "Authorization: Bearer $JWT" \\
|
|
1172
|
+
-d "$LOCAL_BODY" \\
|
|
1173
|
+
--max-time 5 2>/dev/null || echo "")
|
|
1174
|
+
|
|
1175
|
+
if echo "$RESP" | grep -qE '"detail":"Token has expired|"detail":"Invalid or expired token'; then
|
|
1176
|
+
if refresh_jwt; then
|
|
1177
|
+
RESP=$(curl -sS -X POST "\${GATEWAY_URL}/api/v1/precheck-edit/local-verdict" \\
|
|
1178
|
+
-H "Content-Type: application/json" \\
|
|
1179
|
+
-H "Authorization: Bearer $JWT" \\
|
|
1180
|
+
-d "$LOCAL_BODY" \\
|
|
1181
|
+
--max-time 5 2>/dev/null || echo "")
|
|
1182
|
+
fi
|
|
1166
1183
|
fi
|
|
1167
1184
|
fi
|
|
1168
1185
|
else
|
|
@@ -1402,32 +1419,57 @@ if [ -n "$SESSION_ID" ] && [ -n "$TOOL_USE_ID" ]; then
|
|
|
1402
1419
|
) &
|
|
1403
1420
|
fi
|
|
1404
1421
|
|
|
1405
|
-
# Resolve tier (cached 60 min)
|
|
1422
|
+
# Resolve tier + capture_depth (cached 60 min).
|
|
1406
1423
|
TIER_CACHE_FILE="$HOME/.synkro/.tier-cache-\${SYNKRO_USER_ID:-default}"
|
|
1424
|
+
CD_CACHE_FILE="\${TIER_CACHE_FILE}.cd"
|
|
1407
1425
|
SYNKRO_INFERENCE_TIER=""
|
|
1426
|
+
SYNKRO_CAPTURE_DEPTH=""
|
|
1408
1427
|
if find "$TIER_CACHE_FILE" -mmin -60 2>/dev/null | grep -q .; then
|
|
1409
1428
|
SYNKRO_INFERENCE_TIER=$(cat "$TIER_CACHE_FILE" 2>/dev/null || true)
|
|
1429
|
+
SYNKRO_CAPTURE_DEPTH=$(cat "$CD_CACHE_FILE" 2>/dev/null || true)
|
|
1410
1430
|
fi
|
|
1411
1431
|
if [ -z "$SYNKRO_INFERENCE_TIER" ]; then
|
|
1412
1432
|
ME_RESP=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 2 2>/dev/null || echo "")
|
|
1413
1433
|
if [ -n "$ME_RESP" ]; then
|
|
1414
1434
|
SYNKRO_INFERENCE_TIER=$(echo "$ME_RESP" | jq -r '.tier // empty' 2>/dev/null || true)
|
|
1415
1435
|
[ -n "$SYNKRO_INFERENCE_TIER" ] && printf '%s' "$SYNKRO_INFERENCE_TIER" > "$TIER_CACHE_FILE" 2>/dev/null || true
|
|
1436
|
+
SYNKRO_CAPTURE_DEPTH=$(echo "$ME_RESP" | jq -r '.capture_depth // empty' 2>/dev/null || true)
|
|
1437
|
+
[ -n "$SYNKRO_CAPTURE_DEPTH" ] && printf '%s' "$SYNKRO_CAPTURE_DEPTH" > "$CD_CACHE_FILE" 2>/dev/null || true
|
|
1416
1438
|
fi
|
|
1417
1439
|
fi
|
|
1418
1440
|
SYNKRO_INFERENCE_TIER="\${SYNKRO_INFERENCE_TIER:-fast}"
|
|
1441
|
+
SYNKRO_CAPTURE_DEPTH="\${SYNKRO_CAPTURE_DEPTH:-full}"
|
|
1419
1442
|
|
|
1420
|
-
|
|
1421
|
-
|
|
1443
|
+
USE_LOCAL=false
|
|
1444
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ] && command -v claude >/dev/null 2>&1; then
|
|
1445
|
+
USE_LOCAL=true
|
|
1446
|
+
elif [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v claude >/dev/null 2>&1; then
|
|
1447
|
+
USE_LOCAL=true
|
|
1448
|
+
fi
|
|
1422
1449
|
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1450
|
+
if [ "$USE_LOCAL" = "true" ]; then
|
|
1451
|
+
# \u2500\u2500\u2500 LOCAL GRADING: grade via the persistent claude daemon (mode=edit). \u2500\u2500\u2500
|
|
1452
|
+
|
|
1453
|
+
# In local_only: GET all rules (no content sent), cache 1h. Otherwise POST with content.
|
|
1454
|
+
RULES_CACHE="$HOME/.synkro/.rules-cache-edit-capture"
|
|
1455
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then
|
|
1456
|
+
if find "$RULES_CACHE" -mmin -60 2>/dev/null | grep -q .; then
|
|
1457
|
+
ORG_RULES=$(cat "$RULES_CACHE" 2>/dev/null || echo "[]")
|
|
1458
|
+
else
|
|
1459
|
+
ORG_RULES=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" \\
|
|
1460
|
+
-H "Authorization: Bearer $JWT" --max-time 2 2>/dev/null \\
|
|
1461
|
+
| jq -c '[.rules[]? | {rule_id, text, severity, category}]' 2>/dev/null || echo "[]")
|
|
1462
|
+
[ -n "$ORG_RULES" ] && [ "$ORG_RULES" != "null" ] && printf '%s' "$ORG_RULES" > "$RULES_CACHE" 2>/dev/null || true
|
|
1463
|
+
fi
|
|
1464
|
+
else
|
|
1465
|
+
ORG_RULES=$(printf '%s' "$FILE_CONTENT" | head -c 8000 \\
|
|
1466
|
+
| jq -Rs '{content: .}' \\
|
|
1467
|
+
| curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules?top_k=20" \\
|
|
1468
|
+
-X POST -H "Content-Type: application/json" \\
|
|
1469
|
+
-H "Authorization: Bearer $JWT" \\
|
|
1470
|
+
-d @- --max-time 2 2>/dev/null \\
|
|
1471
|
+
| jq -c '[.rules[]? | {rule_id, text, severity, category}]' 2>/dev/null || echo "[]")
|
|
1472
|
+
fi
|
|
1431
1473
|
if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
|
|
1432
1474
|
|
|
1433
1475
|
GRADER_PROMPT_FILE=$(mktemp -t synkro-edit-capture.XXXXXX)
|
|
@@ -1478,6 +1520,36 @@ SEVERITY=$(echo "$RESP" | jq -r '.severity // "low"' 2>/dev/null)
|
|
|
1478
1520
|
CATEGORY=$(echo "$RESP" | jq -r '.category // "unspecified"' 2>/dev/null)
|
|
1479
1521
|
REASON=$(echo "$RESP" | jq -r '.reason // ""' 2>/dev/null)
|
|
1480
1522
|
|
|
1523
|
+
# Fire-and-forget anonymized telemetry for local_only mode (post-edit grading verdict).
|
|
1524
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then
|
|
1525
|
+
if [ "$OK" = "false" ]; then
|
|
1526
|
+
LOCAL_VERDICT="warn"; LOCAL_SEVERITY="block"; LOCAL_RISK="high"
|
|
1527
|
+
else
|
|
1528
|
+
LOCAL_VERDICT="allow"; LOCAL_SEVERITY="audit"; LOCAL_RISK="low"
|
|
1529
|
+
fi
|
|
1530
|
+
(
|
|
1531
|
+
ANON_BODY=$(jq -n \\
|
|
1532
|
+
--arg event_id "$(uuidgen 2>/dev/null || echo "evt_$(date +%s)_$$")" \\
|
|
1533
|
+
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \\
|
|
1534
|
+
--arg hook_type "edit_capture" \\
|
|
1535
|
+
--arg verdict "$LOCAL_VERDICT" \\
|
|
1536
|
+
--arg severity "$LOCAL_SEVERITY" \\
|
|
1537
|
+
--arg risk_level "$LOCAL_RISK" \\
|
|
1538
|
+
--arg category "$CATEGORY" \\
|
|
1539
|
+
--arg model "\${CC_MODEL:-claude-sonnet-4-6}" \\
|
|
1540
|
+
--arg tool_name "$TOOL_NAME" \\
|
|
1541
|
+
'{
|
|
1542
|
+
event_id: $event_id, timestamp: $timestamp, hook_type: $hook_type,
|
|
1543
|
+
verdict: $verdict, severity: $severity, risk_level: $risk_level,
|
|
1544
|
+
category: $category, model: $model, tool_name: $tool_name
|
|
1545
|
+
}')
|
|
1546
|
+
curl -sS -X POST "\${GATEWAY_URL}/api/v1/events/local-verdict" \\
|
|
1547
|
+
-H "Content-Type: application/json" \\
|
|
1548
|
+
-H "Authorization: Bearer $JWT" \\
|
|
1549
|
+
-d "$ANON_BODY" --max-time 2 >/dev/null 2>&1
|
|
1550
|
+
) &
|
|
1551
|
+
fi
|
|
1552
|
+
|
|
1481
1553
|
if [ "$OK" = "false" ] && [ -n "$REASON" ]; then
|
|
1482
1554
|
synkro_log "editScan $BASENAME \u2192 FAIL ($CATEGORY): $REASON"
|
|
1483
1555
|
SYS_MSG="[synkro] editScan $BASENAME \u2192 FAIL: \${REASON}"
|
|
@@ -1701,6 +1773,12 @@ CREDS_PATH="\${SYNKRO_CREDENTIALS_PATH:-$HOME/.synkro/credentials.json}"
|
|
|
1701
1773
|
|
|
1702
1774
|
if [ ! -f "$CREDS_PATH" ]; then echo '{}'; exit 0; fi
|
|
1703
1775
|
if [ "\${SYNKRO_TRANSCRIPT_CONSENT:-yes}" = "no" ]; then echo '{}'; exit 0; fi
|
|
1776
|
+
|
|
1777
|
+
# Hard-skip in local_only privacy mode \u2014 conversation content must never leave the device.
|
|
1778
|
+
CD_CACHE_FILE="$HOME/.synkro/.tier-cache-\${SYNKRO_USER_ID:-default}.cd"
|
|
1779
|
+
SYNKRO_CAPTURE_DEPTH=$(cat "$CD_CACHE_FILE" 2>/dev/null || echo "full")
|
|
1780
|
+
if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then echo '{}'; exit 0; fi
|
|
1781
|
+
|
|
1704
1782
|
JWT=$(jq -r '.access_token // empty' "$CREDS_PATH" 2>/dev/null)
|
|
1705
1783
|
if [ -z "$JWT" ]; then echo '{}'; exit 0; fi
|
|
1706
1784
|
|
|
@@ -3554,7 +3632,7 @@ function writeConfigEnv(opts) {
|
|
|
3554
3632
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3555
3633
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3556
3634
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3557
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.3.
|
|
3635
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.3.33")}`
|
|
3558
3636
|
];
|
|
3559
3637
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
3560
3638
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|