@synkro-sh/cli 1.4.32 → 1.4.34
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 +199 -19
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -148,6 +148,17 @@ function installCCHooks(settingsPath, config) {
|
|
|
148
148
|
],
|
|
149
149
|
[SYNKRO_MARKER]: true
|
|
150
150
|
});
|
|
151
|
+
settings.hooks.PreToolUse.push({
|
|
152
|
+
matcher: "ExitPlanMode",
|
|
153
|
+
hooks: [
|
|
154
|
+
{
|
|
155
|
+
type: "command",
|
|
156
|
+
command: config.planJudgeScriptPath,
|
|
157
|
+
timeout: 45
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
[SYNKRO_MARKER]: true
|
|
161
|
+
});
|
|
151
162
|
settings.hooks.PostToolUse.push({
|
|
152
163
|
matcher: "Edit|Write|MultiEdit|NotebookEdit",
|
|
153
164
|
hooks: [
|
|
@@ -432,7 +443,7 @@ var init_mcpConfig = __esm({
|
|
|
432
443
|
});
|
|
433
444
|
|
|
434
445
|
// cli/installer/hookScripts.ts
|
|
435
|
-
var SYNKRO_COMMON_SCRIPT, CC_BASH_JUDGE_SCRIPT, CC_EDIT_PRECHECK_SCRIPT, CC_EDIT_CAPTURE_SCRIPT, CC_STOP_SUMMARY_SCRIPT, CC_SESSION_START_SCRIPT, CC_BASH_FOLLOWUP_SCRIPT, CC_TRANSCRIPT_SYNC_SCRIPT, CURSOR_BASH_JUDGE_SCRIPT, CURSOR_EDIT_PRECHECK_SCRIPT, CURSOR_EDIT_CAPTURE_SCRIPT, CURSOR_BASH_FOLLOWUP_SCRIPT;
|
|
446
|
+
var SYNKRO_COMMON_SCRIPT, CC_BASH_JUDGE_SCRIPT, CC_EDIT_PRECHECK_SCRIPT, CC_EDIT_CAPTURE_SCRIPT, CC_PLAN_JUDGE_SCRIPT, CC_STOP_SUMMARY_SCRIPT, CC_SESSION_START_SCRIPT, CC_BASH_FOLLOWUP_SCRIPT, CC_TRANSCRIPT_SYNC_SCRIPT, CURSOR_BASH_JUDGE_SCRIPT, CURSOR_EDIT_PRECHECK_SCRIPT, CURSOR_EDIT_CAPTURE_SCRIPT, CURSOR_BASH_FOLLOWUP_SCRIPT;
|
|
436
447
|
var init_hookScripts = __esm({
|
|
437
448
|
"cli/installer/hookScripts.ts"() {
|
|
438
449
|
"use strict";
|
|
@@ -581,6 +592,49 @@ synkro_capture_local() {
|
|
|
581
592
|
) &
|
|
582
593
|
}
|
|
583
594
|
|
|
595
|
+
# Fire full-content telemetry for local verdicts (used when capture_depth is full or evidence_on_violation).
|
|
596
|
+
synkro_capture_local_full() {
|
|
597
|
+
local hook_type="$1" verdict="$2" severity="$3" category="$4" tool_name="$5" repo="$6" session_id="$7"
|
|
598
|
+
local command="$8" reasoning="$9" rules_checked="\${10:-[]}" violated_rules="\${11:-[]}" recent_user_messages="\${12:-[]}"
|
|
599
|
+
(
|
|
600
|
+
BODY=$(jq -n \\
|
|
601
|
+
--arg eid "$(uuidgen 2>/dev/null || echo "evt_$(date +%s)_$$")" \\
|
|
602
|
+
--arg ht "$hook_type" --arg v "$verdict" --arg s "$severity" --arg c "$category" \\
|
|
603
|
+
--arg tn "$tool_name" --arg r "$repo" --arg sid "$session_id" \\
|
|
604
|
+
--arg cmd "$command" --arg rsn "$reasoning" --arg cd "$SYNKRO_CAPTURE_DEPTH" \\
|
|
605
|
+
--argjson rc "$rules_checked" --argjson vr "$violated_rules" --argjson rum "$recent_user_messages" \\
|
|
606
|
+
'{capture_type:"local_verdict",event_id:$eid,hook_type:$ht,verdict:$v,severity:$s,category:$c,
|
|
607
|
+
model:"claude-sonnet-4-6",tool_name:$tn,capture_depth:$cd,
|
|
608
|
+
command:(if ($cmd|length) > 0 then $cmd else null end),
|
|
609
|
+
reasoning:(if ($rsn|length) > 0 then $rsn else null end),
|
|
610
|
+
rules_checked:$rc, violated_rules:$vr, recent_user_messages:$rum}
|
|
611
|
+
+ (if $r != "" then {repo:$r} else {} end)
|
|
612
|
+
+ (if $sid != "" then {session_id:$sid} else {} end)')
|
|
613
|
+
curl -sS -X POST "\${GATEWAY_URL}/api/v1/hook/capture" \\
|
|
614
|
+
-H "Content-Type: application/json" -H "Authorization: Bearer $JWT" \\
|
|
615
|
+
-d "$BODY" --max-time 3 >/dev/null 2>&1
|
|
616
|
+
) &
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
# Dispatch local verdict capture based on capture_depth privacy setting.
|
|
620
|
+
# For full: always send full content. For evidence_on_violation: full only on violations. For local_only: anonymized only.
|
|
621
|
+
synkro_dispatch_capture() {
|
|
622
|
+
local hook_type="$1" verdict="$2" severity="$3" category="$4" tool_name="$5" repo="$6" session_id="$7"
|
|
623
|
+
local command="$8" reasoning="$9" rules_checked="\${10:-[]}" violated_rules="\${11:-[]}" recent_user_messages="\${12:-[]}"
|
|
624
|
+
local send_full=false
|
|
625
|
+
case "\${SYNKRO_CAPTURE_DEPTH:-local_only}" in
|
|
626
|
+
full) send_full=true ;;
|
|
627
|
+
evidence_on_violation)
|
|
628
|
+
case "$verdict" in block|warning|deny) send_full=true ;; esac ;;
|
|
629
|
+
esac
|
|
630
|
+
if [ "$send_full" = "true" ]; then
|
|
631
|
+
synkro_capture_local_full "$hook_type" "$verdict" "$severity" "$category" "$tool_name" "$repo" "$session_id" \\
|
|
632
|
+
"$command" "$reasoning" "$rules_checked" "$violated_rules" "$recent_user_messages"
|
|
633
|
+
else
|
|
634
|
+
synkro_capture_local "$hook_type" "$verdict" "$severity" "$category" "$tool_name" "$repo" "$session_id"
|
|
635
|
+
fi
|
|
636
|
+
}
|
|
637
|
+
|
|
584
638
|
# Look up a rule's mode from cached rules. Returns "blocking" or "audit".
|
|
585
639
|
synkro_rule_mode() {
|
|
586
640
|
local rid="$1"
|
|
@@ -700,18 +754,24 @@ if [ "$ROUTE" = "local" ]; then
|
|
|
700
754
|
fi
|
|
701
755
|
synkro_parse_local_verdict "$CC_RESP"
|
|
702
756
|
|
|
757
|
+
# Build violated rules JSON for full-content capture
|
|
758
|
+
VIOLATED_JSON="[]"
|
|
759
|
+
[ -n "$LOCAL_RULE_ID" ] && VIOLATED_JSON=$(jq -n --arg r "$LOCAL_RULE_ID" '[$r]')
|
|
760
|
+
|
|
703
761
|
if [ "$LOCAL_OK" = "false" ]; then
|
|
704
762
|
RULE_MODE="\${LOCAL_RULE_MODE:-$(synkro_rule_mode "\${LOCAL_RULE_ID}")}"
|
|
705
763
|
if [ "$RULE_MODE" = "audit" ]; then
|
|
706
764
|
REASON="[synkro:local] bashGuard \u2192 warning\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
|
|
707
765
|
jq -n --arg m "$REASON" '{systemMessage: $m}'
|
|
708
|
-
|
|
766
|
+
synkro_dispatch_capture "bash" "warning" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
767
|
+
"$COMMAND" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "$VIOLATED_JSON" "\${RECENT_USER_MESSAGES:-[]}"
|
|
709
768
|
else
|
|
710
769
|
CMD_HASH=$(printf '%s' "$COMMAND" | shasum -a 256 | cut -c1-16)
|
|
711
770
|
if [ -n "$SESSION_ID" ] && synkro_consent_has_active "$SESSION_ID" "$CMD_HASH"; then
|
|
712
771
|
REASON="[synkro:local] bashGuard \u2192 pass (consented retry): \${LOCAL_REASON:-retrying previously consented command}"
|
|
713
772
|
jq -n --arg m "$REASON" '{systemMessage: $m}'
|
|
714
|
-
|
|
773
|
+
synkro_dispatch_capture "bash" "pass" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
774
|
+
"$COMMAND" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "$VIOLATED_JSON" "\${RECENT_USER_MESSAGES:-[]}"
|
|
715
775
|
else
|
|
716
776
|
if [ -n "$SESSION_ID" ] && synkro_consent_has_consumed "$SESSION_ID" "$CMD_HASH"; then
|
|
717
777
|
synkro_consent_clear_consumed "$SESSION_ID" "$CMD_HASH"
|
|
@@ -720,12 +780,14 @@ if [ "$ROUTE" = "local" ]; then
|
|
|
720
780
|
REASON="[synkro:local] bashGuard \u2192 block\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
|
|
721
781
|
jq -n --arg dec "$DEC" --arg reason "$REASON" --arg ctx "$REASON" \\
|
|
722
782
|
'{systemMessage:$reason,hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:$dec,permissionDecisionReason:$reason,additionalContext:$ctx}}'
|
|
723
|
-
|
|
783
|
+
synkro_dispatch_capture "bash" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
784
|
+
"$COMMAND" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "$VIOLATED_JSON" "\${RECENT_USER_MESSAGES:-[]}"
|
|
724
785
|
fi
|
|
725
786
|
fi
|
|
726
787
|
else
|
|
727
788
|
jq -n --arg m "[synkro:local] bashGuard \u2192 pass: \${LOCAL_REASON:-no policy violations detected}" '{systemMessage: $m}'
|
|
728
|
-
|
|
789
|
+
synkro_dispatch_capture "bash" "pass" "audit" "\${LOCAL_CAT:-trivial_utility}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
790
|
+
"$COMMAND" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "[]" "\${RECENT_USER_MESSAGES:-[]}"
|
|
729
791
|
fi
|
|
730
792
|
exit 0
|
|
731
793
|
fi
|
|
@@ -893,22 +955,30 @@ if [ "$ROUTE" = "local" ]; then
|
|
|
893
955
|
fi
|
|
894
956
|
synkro_parse_local_verdict "$CC_RESP"
|
|
895
957
|
|
|
958
|
+
# Build edit content description and violated rules for full-content capture
|
|
959
|
+
EDIT_CONTENT="file=$FILE_PATH content=$(printf '%s' "$PROPOSED" | head -c 2000)"
|
|
960
|
+
VIOLATED_JSON="[]"
|
|
961
|
+
[ -n "$LOCAL_RULE_ID" ] && VIOLATED_JSON=$(jq -n --arg r "$LOCAL_RULE_ID" '[$r]')
|
|
962
|
+
|
|
896
963
|
if [ "$LOCAL_OK" = "false" ]; then
|
|
897
964
|
RULE_MODE="\${LOCAL_RULE_MODE:-$(synkro_rule_mode "\${LOCAL_RULE_ID}")}"
|
|
898
965
|
if [ "$RULE_MODE" = "audit" ]; then
|
|
899
966
|
REASON="[synkro:local] editGuard $FILE_SHORT \u2192 warning\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
|
|
900
967
|
jq -n --arg m "$REASON" '{systemMessage: $m}'
|
|
901
|
-
|
|
968
|
+
synkro_dispatch_capture "edit" "warning" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
969
|
+
"$EDIT_CONTENT" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "$VIOLATED_JSON" "[]"
|
|
902
970
|
else
|
|
903
971
|
if [ "$IS_HEADLESS" = "1" ]; then DEC="deny"; else DEC="ask"; fi
|
|
904
972
|
REASON="[synkro:local] editGuard $FILE_SHORT \u2192 block\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
|
|
905
973
|
jq -n --arg dec "$DEC" --arg reason "$REASON" --arg ctx "$REASON" \\
|
|
906
974
|
'{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:$dec,permissionDecisionReason:$reason,additionalContext:$ctx}}'
|
|
907
|
-
|
|
975
|
+
synkro_dispatch_capture "edit" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
976
|
+
"$EDIT_CONTENT" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "$VIOLATED_JSON" "[]"
|
|
908
977
|
fi
|
|
909
978
|
else
|
|
910
979
|
jq -n --arg m "[synkro:local] editGuard $FILE_SHORT \u2192 pass: \${LOCAL_REASON:-no policy violations detected}" '{systemMessage: $m}'
|
|
911
|
-
|
|
980
|
+
synkro_dispatch_capture "edit" "pass" "audit" "\${LOCAL_CAT:-trivial_edit}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
981
|
+
"$EDIT_CONTENT" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "[]" "[]"
|
|
912
982
|
fi
|
|
913
983
|
exit 0
|
|
914
984
|
fi
|
|
@@ -1045,20 +1115,27 @@ if [ "$ROUTE" = "local" ]; then
|
|
|
1045
1115
|
fi
|
|
1046
1116
|
synkro_parse_local_verdict "$CC_RESP"
|
|
1047
1117
|
|
|
1118
|
+
SCAN_CONTENT="file=$FILE_PATH"
|
|
1119
|
+
SCAN_VIOLATED="[]"
|
|
1120
|
+
[ -n "$LOCAL_RULE_ID" ] && SCAN_VIOLATED=$(jq -n --arg r "$LOCAL_RULE_ID" '[$r]')
|
|
1121
|
+
|
|
1048
1122
|
if [ "$LOCAL_OK" = "false" ]; then
|
|
1049
1123
|
RULE_MODE="\${LOCAL_RULE_MODE:-$(synkro_rule_mode "\${LOCAL_RULE_ID}")}"
|
|
1050
1124
|
if [ "$RULE_MODE" = "audit" ]; then
|
|
1051
1125
|
REASON="[synkro:local] editScan $BASENAME \u2192 warning\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
|
|
1052
1126
|
jq -n --arg m "$REASON" '{systemMessage: $m}'
|
|
1053
|
-
|
|
1127
|
+
synkro_dispatch_capture "edit_scan" "warning" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
1128
|
+
"$SCAN_CONTENT" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "$SCAN_VIOLATED" "[]"
|
|
1054
1129
|
else
|
|
1055
1130
|
REASON="[synkro:local] editScan $BASENAME \u2192 block: \${LOCAL_REASON:-policy violation}"
|
|
1056
1131
|
jq -n --arg m "$REASON" '{systemMessage: $m, additionalContext: $m}'
|
|
1057
|
-
|
|
1132
|
+
synkro_dispatch_capture "edit_scan" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
1133
|
+
"$SCAN_CONTENT" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "$SCAN_VIOLATED" "[]"
|
|
1058
1134
|
fi
|
|
1059
1135
|
else
|
|
1060
1136
|
jq -n --arg m "[synkro:local] editScan $BASENAME \u2192 pass: \${LOCAL_REASON:-no policy violations detected}" '{systemMessage: $m}'
|
|
1061
|
-
|
|
1137
|
+
synkro_dispatch_capture "edit_scan" "pass" "audit" "\${LOCAL_CAT:-trivial_edit}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID" \\
|
|
1138
|
+
"$SCAN_CONTENT" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "[]" "[]"
|
|
1062
1139
|
fi
|
|
1063
1140
|
exit 0
|
|
1064
1141
|
fi
|
|
@@ -1104,6 +1181,103 @@ else
|
|
|
1104
1181
|
echo '{}'
|
|
1105
1182
|
fi
|
|
1106
1183
|
exit 0
|
|
1184
|
+
`;
|
|
1185
|
+
CC_PLAN_JUDGE_SCRIPT = `#!/bin/bash
|
|
1186
|
+
SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
1187
|
+
. "$SCRIPT_DIR/_synkro-common.sh"
|
|
1188
|
+
|
|
1189
|
+
JWT=$(synkro_load_jwt)
|
|
1190
|
+
if [ -z "$JWT" ]; then echo '{}'; exit 0; fi
|
|
1191
|
+
synkro_ensure_fresh_jwt
|
|
1192
|
+
|
|
1193
|
+
PAYLOAD=$(cat)
|
|
1194
|
+
if [ -z "$PAYLOAD" ]; then echo '{}'; exit 0; fi
|
|
1195
|
+
|
|
1196
|
+
TOOL_NAME=$(echo "$PAYLOAD" | jq -r '.tool_name // empty' 2>/dev/null)
|
|
1197
|
+
if [ "$TOOL_NAME" != "ExitPlanMode" ]; then echo '{}'; exit 0; fi
|
|
1198
|
+
|
|
1199
|
+
PLAN=$(echo "$PAYLOAD" | jq -r '.tool_input.plan // empty' 2>/dev/null)
|
|
1200
|
+
if [ -z "$PLAN" ] || [ \${#PLAN} -lt 20 ]; then echo '{}'; exit 0; fi
|
|
1201
|
+
|
|
1202
|
+
SESSION_ID=$(echo "$PAYLOAD" | jq -r '.session_id // empty' 2>/dev/null)
|
|
1203
|
+
CWD=$(echo "$PAYLOAD" | jq -r '.cwd // empty' 2>/dev/null)
|
|
1204
|
+
GIT_REPO=$(synkro_detect_repo "\${CWD:-.}")
|
|
1205
|
+
|
|
1206
|
+
PLAN_SHORT=$(printf '%s' "$PLAN" | head -c 80)
|
|
1207
|
+
synkro_log "planReview checking: $PLAN_SHORT..."
|
|
1208
|
+
|
|
1209
|
+
synkro_load_config
|
|
1210
|
+
ROUTE=$(synkro_route)
|
|
1211
|
+
|
|
1212
|
+
if [ "$ROUTE" = "local" ]; then
|
|
1213
|
+
GRADER_FILE=$(mktemp -t synkro-plan.XXXXXX)
|
|
1214
|
+
trap "rm -f \\"$GRADER_FILE\\"" EXIT
|
|
1215
|
+
printf 'Plan:\\n%s\\nOrg rules: %s\\n' "$(printf '%s' "$PLAN" | head -c 8000)" "\${SYNKRO_RULES:-[]}" > "$GRADER_FILE"
|
|
1216
|
+
|
|
1217
|
+
CC_RESP=$(synkro_local_grade plan < "$GRADER_FILE" 2>&1)
|
|
1218
|
+
if [ $? -ne 0 ]; then
|
|
1219
|
+
echo '{}'; exit 0
|
|
1220
|
+
fi
|
|
1221
|
+
synkro_parse_local_verdict "$CC_RESP"
|
|
1222
|
+
|
|
1223
|
+
PLAN_CONTENT=$(printf '%s' "$PLAN" | head -c 2000)
|
|
1224
|
+
PLAN_VIOLATED="[]"
|
|
1225
|
+
[ -n "$LOCAL_RULE_ID" ] && PLAN_VIOLATED=$(jq -n --arg r "$LOCAL_RULE_ID" '[$r]')
|
|
1226
|
+
|
|
1227
|
+
if [ "$LOCAL_OK" = "false" ]; then
|
|
1228
|
+
VCOUNT=$(printf '%s' "$CC_RESP" | grep -c '<violation>' 2>/dev/null || echo "0")
|
|
1229
|
+
[ "$VCOUNT" = "0" ] && VCOUNT="1"
|
|
1230
|
+
MSG="[synkro:local] planReview \u2192 \${VCOUNT} rule(s) relevant\${LOCAL_RULE_ID:+ (first: $LOCAL_RULE_ID)}: \${LOCAL_REASON:-check org rules during implementation}"
|
|
1231
|
+
jq -n --arg m "$MSG" '{systemMessage: $m}'
|
|
1232
|
+
synkro_dispatch_capture "plan_review" "advisory" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "ExitPlanMode" "$GIT_REPO" "$SESSION_ID" \\
|
|
1233
|
+
"$PLAN_CONTENT" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "$PLAN_VIOLATED" "[]"
|
|
1234
|
+
else
|
|
1235
|
+
jq -n --arg m "[synkro:local] planReview \u2192 clean: \${LOCAL_REASON:-no relevant org rules for this plan}" '{systemMessage: $m}'
|
|
1236
|
+
synkro_dispatch_capture "plan_review" "clean" "audit" "\${LOCAL_CAT:-general}" "ExitPlanMode" "$GIT_REPO" "$SESSION_ID" \\
|
|
1237
|
+
"$PLAN_CONTENT" "$LOCAL_REASON" "\${SYNKRO_RULES:-[]}" "[]" "[]"
|
|
1238
|
+
fi
|
|
1239
|
+
exit 0
|
|
1240
|
+
fi
|
|
1241
|
+
|
|
1242
|
+
# \u2500\u2500\u2500 Cloud grading \u2500\u2500\u2500
|
|
1243
|
+
BODY=$(jq -n \\
|
|
1244
|
+
--arg hook_event "PreToolUse" \\
|
|
1245
|
+
--arg tool_name "ExitPlanMode" \\
|
|
1246
|
+
--arg plan "$(printf '%s' "$PLAN" | head -c 16000)" \\
|
|
1247
|
+
--arg session_id "$SESSION_ID" \\
|
|
1248
|
+
--arg cwd "$CWD" \\
|
|
1249
|
+
--arg repo "$GIT_REPO" \\
|
|
1250
|
+
'{
|
|
1251
|
+
hook_event: $hook_event,
|
|
1252
|
+
tool_name: $tool_name,
|
|
1253
|
+
tool_input: {plan: $plan},
|
|
1254
|
+
session_id: (if ($session_id | length) > 0 then $session_id else null end),
|
|
1255
|
+
cwd: (if ($cwd | length) > 0 then $cwd else null end),
|
|
1256
|
+
repo: (if ($repo | length) > 0 then $repo else null end)
|
|
1257
|
+
}')
|
|
1258
|
+
|
|
1259
|
+
RESP=$(synkro_post_with_retry "\${GATEWAY_URL}/api/v1/hook/judge" "$BODY" 12)
|
|
1260
|
+
|
|
1261
|
+
if [ -z "$RESP" ]; then
|
|
1262
|
+
synkro_log "planReview \u2192 error (timeout)"
|
|
1263
|
+
echo '{}'
|
|
1264
|
+
exit 0
|
|
1265
|
+
fi
|
|
1266
|
+
|
|
1267
|
+
if ! echo "$RESP" | jq -e '.hook_response' >/dev/null 2>&1; then
|
|
1268
|
+
echo '{}'
|
|
1269
|
+
exit 0
|
|
1270
|
+
fi
|
|
1271
|
+
|
|
1272
|
+
# Force advisory: convert any blocking decision to systemMessage
|
|
1273
|
+
HR=$(echo "$RESP" | jq -c '.hook_response')
|
|
1274
|
+
if echo "$HR" | jq -e '.hookSpecificOutput.permissionDecision' >/dev/null 2>&1; then
|
|
1275
|
+
REASON=$(echo "$HR" | jq -r '.hookSpecificOutput.permissionDecisionReason // "check org rules"' 2>/dev/null)
|
|
1276
|
+
jq -n --arg m "[synkro:cloud] planReview \u2192 advisory: $REASON" '{systemMessage: $m}'
|
|
1277
|
+
else
|
|
1278
|
+
echo "$HR"
|
|
1279
|
+
fi
|
|
1280
|
+
exit 0
|
|
1107
1281
|
`;
|
|
1108
1282
|
CC_STOP_SUMMARY_SCRIPT = `#!/bin/bash
|
|
1109
1283
|
SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
|
|
@@ -1200,20 +1374,18 @@ RESP=$(curl -sS -G "\${GATEWAY_URL}/api/v1/hook/config" \\
|
|
|
1200
1374
|
--data-urlencode "repo=\${GIT_REPO:-}" \\
|
|
1201
1375
|
-H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null || echo "")
|
|
1202
1376
|
|
|
1203
|
-
PLAN_NUDGE="Before implementing any multi-step plan, call the synkro-guardrails analyze_plan tool with your implementation plan to check for relevant org coding rules."
|
|
1204
|
-
|
|
1205
1377
|
OPEN=0
|
|
1206
1378
|
if [ -n "$RESP" ]; then
|
|
1207
1379
|
OPEN=$(echo "$RESP" | jq -r '.session_context.open_findings // 0' 2>/dev/null)
|
|
1208
1380
|
fi
|
|
1209
1381
|
|
|
1210
1382
|
if [ "$OPEN" = "0" ] || [ -z "$OPEN" ]; then
|
|
1211
|
-
jq -n --arg m "$ROUTE_LINE"
|
|
1383
|
+
jq -n --arg m "$ROUTE_LINE" '{systemMessage: $m}'
|
|
1212
1384
|
else
|
|
1213
1385
|
if [ "$OPEN" = "1" ]; then
|
|
1214
|
-
SYS_MSG="$ROUTE_LINE"$'\\n'"[synkro] session start \u2192 1 open finding in this repo from a prior session.
|
|
1386
|
+
SYS_MSG="$ROUTE_LINE"$'\\n'"[synkro] session start \u2192 1 open finding in this repo from a prior session."
|
|
1215
1387
|
else
|
|
1216
|
-
SYS_MSG="$ROUTE_LINE"$'\\n'"[synkro] session start \u2192 \${OPEN} open findings in this repo from prior sessions.
|
|
1388
|
+
SYS_MSG="$ROUTE_LINE"$'\\n'"[synkro] session start \u2192 \${OPEN} open findings in this repo from prior sessions."
|
|
1217
1389
|
fi
|
|
1218
1390
|
jq -n --arg m "$SYS_MSG" '{systemMessage: $m}'
|
|
1219
1391
|
fi
|
|
@@ -3349,7 +3521,7 @@ async function fetchPrimers() {
|
|
|
3349
3521
|
}
|
|
3350
3522
|
async function getPrimer(role) {
|
|
3351
3523
|
const prompts = await fetchPrimers();
|
|
3352
|
-
const primer = role === "grade-edit" ? prompts.grader_primer_edit : prompts.grader_primer_bash;
|
|
3524
|
+
const primer = role === "grade-edit" ? prompts.grader_primer_edit : role === "grade-plan" ? prompts.grader_primer_plan : prompts.grader_primer_bash;
|
|
3353
3525
|
if (!primer) {
|
|
3354
3526
|
throw new Error(`No primer for role "${role}" returned from API.`);
|
|
3355
3527
|
}
|
|
@@ -3658,6 +3830,7 @@ function writeHookScripts() {
|
|
|
3658
3830
|
const bashFollowupScriptPath = join11(HOOKS_DIR, "cc-bash-followup.sh");
|
|
3659
3831
|
const editCaptureScriptPath = join11(HOOKS_DIR, "cc-edit-capture.sh");
|
|
3660
3832
|
const editPrecheckScriptPath = join11(HOOKS_DIR, "cc-edit-precheck.sh");
|
|
3833
|
+
const planJudgeScriptPath = join11(HOOKS_DIR, "cc-plan-judge.sh");
|
|
3661
3834
|
const stopSummaryScriptPath = join11(HOOKS_DIR, "cc-stop-summary.sh");
|
|
3662
3835
|
const sessionStartScriptPath = join11(HOOKS_DIR, "cc-session-start.sh");
|
|
3663
3836
|
const transcriptSyncScriptPath = join11(HOOKS_DIR, "cc-transcript-sync.sh");
|
|
@@ -3670,6 +3843,7 @@ function writeHookScripts() {
|
|
|
3670
3843
|
writeFileSync7(bashFollowupScriptPath, CC_BASH_FOLLOWUP_SCRIPT, "utf-8");
|
|
3671
3844
|
writeFileSync7(editCaptureScriptPath, CC_EDIT_CAPTURE_SCRIPT, "utf-8");
|
|
3672
3845
|
writeFileSync7(editPrecheckScriptPath, CC_EDIT_PRECHECK_SCRIPT, "utf-8");
|
|
3846
|
+
writeFileSync7(planJudgeScriptPath, CC_PLAN_JUDGE_SCRIPT, "utf-8");
|
|
3673
3847
|
writeFileSync7(stopSummaryScriptPath, CC_STOP_SUMMARY_SCRIPT, "utf-8");
|
|
3674
3848
|
writeFileSync7(sessionStartScriptPath, CC_SESSION_START_SCRIPT, "utf-8");
|
|
3675
3849
|
writeFileSync7(transcriptSyncScriptPath, CC_TRANSCRIPT_SYNC_SCRIPT, "utf-8");
|
|
@@ -3682,6 +3856,7 @@ function writeHookScripts() {
|
|
|
3682
3856
|
chmodSync2(bashFollowupScriptPath, 493);
|
|
3683
3857
|
chmodSync2(editCaptureScriptPath, 493);
|
|
3684
3858
|
chmodSync2(editPrecheckScriptPath, 493);
|
|
3859
|
+
chmodSync2(planJudgeScriptPath, 493);
|
|
3685
3860
|
chmodSync2(stopSummaryScriptPath, 493);
|
|
3686
3861
|
chmodSync2(sessionStartScriptPath, 493);
|
|
3687
3862
|
chmodSync2(transcriptSyncScriptPath, 493);
|
|
@@ -3695,6 +3870,7 @@ function writeHookScripts() {
|
|
|
3695
3870
|
bashFollowupScript: bashFollowupScriptPath,
|
|
3696
3871
|
editCaptureScript: editCaptureScriptPath,
|
|
3697
3872
|
editPrecheckScript: editPrecheckScriptPath,
|
|
3873
|
+
planJudgeScript: planJudgeScriptPath,
|
|
3698
3874
|
stopSummaryScript: stopSummaryScriptPath,
|
|
3699
3875
|
sessionStartScript: sessionStartScriptPath,
|
|
3700
3876
|
transcriptSyncScript: transcriptSyncScriptPath,
|
|
@@ -3733,7 +3909,7 @@ function writeConfigEnv(opts) {
|
|
|
3733
3909
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3734
3910
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3735
3911
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3736
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.4.
|
|
3912
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.4.34")}`
|
|
3737
3913
|
];
|
|
3738
3914
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
3739
3915
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -3862,6 +4038,7 @@ function isAlreadyInstalled() {
|
|
|
3862
4038
|
join11(HOOKS_DIR, "cc-bash-followup.sh"),
|
|
3863
4039
|
join11(HOOKS_DIR, "cc-edit-precheck.sh"),
|
|
3864
4040
|
join11(HOOKS_DIR, "cc-edit-capture.sh"),
|
|
4041
|
+
join11(HOOKS_DIR, "cc-plan-judge.sh"),
|
|
3865
4042
|
join11(HOOKS_DIR, "cc-stop-summary.sh"),
|
|
3866
4043
|
join11(HOOKS_DIR, "cc-session-start.sh")
|
|
3867
4044
|
];
|
|
@@ -4000,6 +4177,7 @@ async function installCommand(opts = {}) {
|
|
|
4000
4177
|
console.log(` ${scripts.bashFollowupScript}`);
|
|
4001
4178
|
console.log(` ${scripts.editCaptureScript}`);
|
|
4002
4179
|
console.log(` ${scripts.editPrecheckScript}`);
|
|
4180
|
+
console.log(` ${scripts.planJudgeScript}`);
|
|
4003
4181
|
console.log(` ${scripts.stopSummaryScript}`);
|
|
4004
4182
|
console.log(` ${scripts.sessionStartScript}`);
|
|
4005
4183
|
console.log(` ${scripts.transcriptSyncScript}
|
|
@@ -4034,6 +4212,7 @@ async function installCommand(opts = {}) {
|
|
|
4034
4212
|
bashFollowupScriptPath: scripts.bashFollowupScript,
|
|
4035
4213
|
editCaptureScriptPath: scripts.editCaptureScript,
|
|
4036
4214
|
editPrecheckScriptPath: scripts.editPrecheckScript,
|
|
4215
|
+
planJudgeScriptPath: scripts.planJudgeScript,
|
|
4037
4216
|
stopSummaryScriptPath: scripts.stopSummaryScript,
|
|
4038
4217
|
sessionStartScriptPath: scripts.sessionStartScript,
|
|
4039
4218
|
transcriptSyncScriptPath: scripts.transcriptSyncScript,
|
|
@@ -6079,8 +6258,9 @@ async function gradeCommand(args2) {
|
|
|
6079
6258
|
let role;
|
|
6080
6259
|
if (mode === "edit") role = "grade-edit";
|
|
6081
6260
|
else if (mode === "bash") role = "grade-bash";
|
|
6261
|
+
else if (mode === "plan") role = "grade-plan";
|
|
6082
6262
|
else {
|
|
6083
|
-
console.error("Usage: synkro grade <edit|bash>");
|
|
6263
|
+
console.error("Usage: synkro grade <edit|bash|plan>");
|
|
6084
6264
|
process.exit(2);
|
|
6085
6265
|
}
|
|
6086
6266
|
const payload = await readStdin();
|