@synkro-sh/cli 1.4.18 → 1.4.19

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 CHANGED
@@ -576,6 +576,16 @@ synkro_capture_local() {
576
576
  ) &
577
577
  }
578
578
 
579
+ # Look up a rule's mode from cached rules. Returns "blocking" or "audit".
580
+ synkro_rule_mode() {
581
+ local rid="$1"
582
+ [ -z "$rid" ] || [ -z "\${SYNKRO_RULES:-}" ] && echo "blocking" && return
583
+ local m
584
+ m=$(printf '%s' "$SYNKRO_RULES" | jq -r --arg r "$rid" '[.[] | select(.rule_id == $r) | .mode] | .[0] // "blocking"' 2>/dev/null)
585
+ [ -z "$m" ] || [ "$m" = "null" ] && m="blocking"
586
+ echo "$m"
587
+ }
588
+
579
589
  synkro_post_with_retry() {
580
590
  local url="$1" body="$2" timeout="\${3:-8}"
581
591
  local resp
@@ -651,14 +661,21 @@ if [ "$ROUTE" = "local" ]; then
651
661
  synkro_parse_local_verdict "$CC_RESP"
652
662
 
653
663
  if [ "$LOCAL_OK" = "false" ]; then
654
- if [ "$IS_HEADLESS" = "1" ]; then DEC="deny"; else DEC="ask"; fi
655
- REASON="[synkro:local] bashGuard \u2192 block\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
656
- jq -n --arg dec "$DEC" --arg reason "$REASON" --arg ctx "$REASON" \\
657
- '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:$dec,permissionDecisionReason:$reason,additionalContext:$ctx}}'
658
- synkro_capture_local "bash" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
664
+ RULE_MODE=$(synkro_rule_mode "\${LOCAL_RULE_ID}")
665
+ if [ "$RULE_MODE" = "audit" ]; then
666
+ REASON="[synkro:local] bashGuard \u2192 warning\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
667
+ jq -n --arg m "$REASON" '{systemMessage: $m}'
668
+ synkro_capture_local "bash" "warning" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
669
+ else
670
+ if [ "$IS_HEADLESS" = "1" ]; then DEC="deny"; else DEC="ask"; fi
671
+ REASON="[synkro:local] bashGuard \u2192 block\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
672
+ jq -n --arg dec "$DEC" --arg reason "$REASON" --arg ctx "$REASON" \\
673
+ '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:$dec,permissionDecisionReason:$reason,additionalContext:$ctx}}'
674
+ synkro_capture_local "bash" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
675
+ fi
659
676
  else
660
677
  jq -n --arg m "[synkro:local] bashGuard \u2192 pass: \${LOCAL_REASON:-no policy violations detected}" '{systemMessage: $m}'
661
- synkro_capture_local "bash" "allow" "audit" "\${LOCAL_CAT:-trivial_utility}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
678
+ synkro_capture_local "bash" "pass" "audit" "\${LOCAL_CAT:-trivial_utility}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
662
679
  fi
663
680
  exit 0
664
681
  fi
@@ -823,11 +840,18 @@ if [ "$ROUTE" = "local" ]; then
823
840
  synkro_parse_local_verdict "$CC_RESP"
824
841
 
825
842
  if [ "$LOCAL_OK" = "false" ]; then
826
- if [ "$IS_HEADLESS" = "1" ]; then DEC="deny"; else DEC="ask"; fi
827
- REASON="[synkro:local] editGuard $FILE_SHORT \u2192 block\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
828
- jq -n --arg dec "$DEC" --arg reason "$REASON" --arg ctx "$REASON" \\
829
- '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:$dec,permissionDecisionReason:$reason,additionalContext:$ctx}}'
830
- synkro_capture_local "edit" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
843
+ RULE_MODE=$(synkro_rule_mode "\${LOCAL_RULE_ID}")
844
+ if [ "$RULE_MODE" = "audit" ]; then
845
+ REASON="[synkro:local] editGuard $FILE_SHORT \u2192 warning\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
846
+ jq -n --arg m "$REASON" '{systemMessage: $m}'
847
+ synkro_capture_local "edit" "warning" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
848
+ else
849
+ if [ "$IS_HEADLESS" = "1" ]; then DEC="deny"; else DEC="ask"; fi
850
+ REASON="[synkro:local] editGuard $FILE_SHORT \u2192 block\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
851
+ jq -n --arg dec "$DEC" --arg reason "$REASON" --arg ctx "$REASON" \\
852
+ '{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:$dec,permissionDecisionReason:$reason,additionalContext:$ctx}}'
853
+ synkro_capture_local "edit" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
854
+ fi
831
855
  else
832
856
  jq -n --arg m "[synkro:local] editGuard $FILE_SHORT \u2192 pass: \${LOCAL_REASON:-no policy violations detected}" '{systemMessage: $m}'
833
857
  synkro_capture_local "edit" "pass" "audit" "\${LOCAL_CAT:-trivial_edit}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
@@ -965,9 +989,16 @@ if [ "$ROUTE" = "local" ]; then
965
989
  synkro_parse_local_verdict "$CC_RESP"
966
990
 
967
991
  if [ "$LOCAL_OK" = "false" ]; then
968
- REASON="[synkro:local] editScan $BASENAME \u2192 block: \${LOCAL_REASON:-policy violation}"
969
- jq -n --arg m "$REASON" '{systemMessage: $m, additionalContext: $m}'
970
- synkro_capture_local "edit_scan" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
992
+ RULE_MODE=$(synkro_rule_mode "\${LOCAL_RULE_ID}")
993
+ if [ "$RULE_MODE" = "audit" ]; then
994
+ REASON="[synkro:local] editScan $BASENAME \u2192 warning\${LOCAL_RULE_ID:+ ($LOCAL_RULE_ID)}: \${LOCAL_REASON:-policy violation}"
995
+ jq -n --arg m "$REASON" '{systemMessage: $m}'
996
+ synkro_capture_local "edit_scan" "warning" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
997
+ else
998
+ REASON="[synkro:local] editScan $BASENAME \u2192 block: \${LOCAL_REASON:-policy violation}"
999
+ jq -n --arg m "$REASON" '{systemMessage: $m, additionalContext: $m}'
1000
+ synkro_capture_local "edit_scan" "block" "\${LOCAL_SEV}" "\${LOCAL_CAT}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
1001
+ fi
971
1002
  else
972
1003
  jq -n --arg m "[synkro:local] editScan $BASENAME \u2192 pass: \${LOCAL_REASON:-no policy violations detected}" '{systemMessage: $m}'
973
1004
  synkro_capture_local "edit_scan" "pass" "audit" "\${LOCAL_CAT:-trivial_edit}" "$TOOL_NAME" "$GIT_REPO" "$SESSION_ID"
@@ -1146,8 +1177,17 @@ SESSION_ID=$(echo "$PAYLOAD" | jq -r '.session_id // empty' 2>/dev/null)
1146
1177
  TOOL_USE_ID=$(echo "$PAYLOAD" | jq -r '.tool_use_id // empty' 2>/dev/null)
1147
1178
  if [ -z "$SESSION_ID" ] || [ -z "$TOOL_USE_ID" ]; then echo '{}'; exit 0; fi
1148
1179
 
1180
+ # Extract is_error from tool_result and compute command hash for consent tracking
1181
+ IS_ERROR=$(echo "$PAYLOAD" | jq -r '.tool_result.is_error // false' 2>/dev/null)
1182
+ CMD=$(echo "$PAYLOAD" | jq -r '.tool_input.command // empty' 2>/dev/null)
1183
+ CMD_HASH=""
1184
+ if [ -n "$CMD" ]; then
1185
+ CMD_HASH=$(printf '%s' "$CMD" | shasum -a 256 | cut -c1-16)
1186
+ fi
1187
+
1149
1188
  BODY=$(jq -n --arg sid "$SESSION_ID" --arg tid "$TOOL_USE_ID" \\
1150
- '{capture_type:"bash_followup",session_id:$sid,tool_use_id:$tid}')
1189
+ --argjson err "$IS_ERROR" --arg ch "$CMD_HASH" \\
1190
+ '{capture_type:"bash_followup",session_id:$sid,tool_use_id:$tid,is_error:$err,command_hash:$ch}')
1151
1191
 
1152
1192
  curl -sS -X POST "\${GATEWAY_URL}/api/v1/hook/capture" \\
1153
1193
  -H "Content-Type: application/json" -H "Authorization: Bearer $JWT" \\
@@ -1399,10 +1439,18 @@ case "$TOOL_NAME" in Shell|Bash|terminal|run_terminal_cmd|execute_command) ;; *)
1399
1439
  SESSION_ID=$(echo "$PAYLOAD" | jq -r '.conversation_id // empty' 2>/dev/null)
1400
1440
  TOOL_USE_ID=$(echo "$PAYLOAD" | jq -r '.tool_use_id // empty' 2>/dev/null)
1401
1441
 
1442
+ IS_ERROR=$(echo "$PAYLOAD" | jq -r '.tool_result.is_error // false' 2>/dev/null)
1443
+ CMD=$(echo "$PAYLOAD" | jq -r '.tool_input.command // empty' 2>/dev/null)
1444
+ CMD_HASH=""
1445
+ if [ -n "$CMD" ]; then
1446
+ CMD_HASH=$(printf '%s' "$CMD" | shasum -a 256 | cut -c1-16)
1447
+ fi
1448
+
1402
1449
  if [ -n "$SESSION_ID" ] && [ -n "$TOOL_USE_ID" ]; then
1403
1450
  (
1404
1451
  BODY=$(jq -n --arg sid "$SESSION_ID" --arg tid "$TOOL_USE_ID" \\
1405
- '{capture_type:"bash_followup",session_id:$sid,tool_use_id:$tid}')
1452
+ --argjson err "$IS_ERROR" --arg ch "$CMD_HASH" \\
1453
+ '{capture_type:"bash_followup",session_id:$sid,tool_use_id:$tid,is_error:$err,command_hash:$ch}')
1406
1454
  curl -sS -X POST "\${GATEWAY_URL}/api/v1/hook/capture" \\
1407
1455
  -H "Content-Type: application/json" -H "Authorization: Bearer $JWT" \\
1408
1456
  -d "$BODY" --max-time 3 >/dev/null 2>&1 || true
@@ -3602,7 +3650,7 @@ function writeConfigEnv(opts) {
3602
3650
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
3603
3651
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
3604
3652
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
3605
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.18")}`
3653
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.19")}`
3606
3654
  ];
3607
3655
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
3608
3656
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);