@synkro-sh/cli 1.4.10 → 1.4.12

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
@@ -132,7 +132,7 @@ function installCCHooks(settingsPath, config) {
132
132
  {
133
133
  type: "command",
134
134
  command: config.bashJudgeScriptPath,
135
- timeout: 15
135
+ timeout: 30
136
136
  }
137
137
  ],
138
138
  [SYNKRO_MARKER]: true
@@ -709,8 +709,17 @@ ensure_fresh_jwt() {
709
709
 
710
710
  ensure_fresh_jwt
711
711
 
712
- # Resolve tier + capture_depth live from /cli/me every call. Default to local_only (fail-safe).
713
- ME_RESP=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null || echo "")
712
+ # Parallel fetch: /cli/me + rules in background, wait for both.
713
+ _ME_TMP=$(mktemp -t synkro-me.XXXXXX)
714
+ _RULES_TMP=$(mktemp -t synkro-rules.XXXXXX)
715
+ trap "rm -f \\"$_ME_TMP\\" \\"$_RULES_TMP\\"" EXIT
716
+ curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null > "$_ME_TMP" &
717
+ _ME_PID=$!
718
+ curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null > "$_RULES_TMP" &
719
+ _RULES_PID=$!
720
+ wait $_ME_PID 2>/dev/null; wait $_RULES_PID 2>/dev/null
721
+
722
+ ME_RESP=$(cat "$_ME_TMP" 2>/dev/null || echo "")
714
723
  SYNKRO_INFERENCE_TIER=$(echo "$ME_RESP" | jq -r '.tier // empty' 2>/dev/null)
715
724
  SYNKRO_CAPTURE_DEPTH=$(echo "$ME_RESP" | jq -r '.capture_depth // empty' 2>/dev/null)
716
725
  SYNKRO_INFERENCE_TIER="\${SYNKRO_INFERENCE_TIER:-fast}"
@@ -721,32 +730,14 @@ if command -v claude >/dev/null 2>&1; then
721
730
  USE_LOCAL=true
722
731
  fi
723
732
 
724
- # Prefer local grading whenever it's available \u2014 the local-cc channel beats
725
- # the cloud fast tier on latency, and it's available regardless of the
726
- # server-assigned tier. Fall through to the cloud curl only when neither
727
- # the channel nor a usable \`claude\` CLI is reachable.
728
733
  if synkro_channel_up || { [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v claude >/dev/null 2>&1; }; then
729
- # \u2500\u2500\u2500 LOCAL PATH: channel-grader first, then \`claude --print\` cold fallback. \u2500\u2500\u2500
730
-
731
734
  RULES_CACHE="$HOME/.synkro/.rules-cache-bash"
732
- ORG_RULES="[]"
733
- if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then
734
- ORG_RULES=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" \\
735
- -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null \\
736
- | jq -c '[.rules[]? | select(.hook_stage == "pre" or .hook_stage == "both" or .hook_stage == null) | {rule_id, text, severity, category}]' 2>/dev/null || echo "[]")
737
- if [ -n "$ORG_RULES" ] && [ "$ORG_RULES" != "null" ] && [ "$ORG_RULES" != "[]" ]; then
738
- printf '%s' "$ORG_RULES" > "$RULES_CACHE" 2>/dev/null || true
739
- elif [ -f "$RULES_CACHE" ]; then
740
- ORG_RULES=$(cat "$RULES_CACHE" 2>/dev/null || echo "[]")
741
- fi
742
- else
743
- ORG_RULES=$(printf '%s' "$COMMAND" | head -c 4000 \\
744
- | jq -Rs '{content: .}' \\
745
- | curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules?top_k=15" \\
746
- -X POST -H "Content-Type: application/json" \\
747
- -H "Authorization: Bearer $JWT" \\
748
- -d @- --max-time 2 2>/dev/null \\
749
- | jq -c '[.rules[]? | select(.hook_stage == "pre" or .hook_stage == "both" or .hook_stage == null) | {rule_id, text, severity, category}]' 2>/dev/null || echo "[]")
735
+ RULES_JQ='[.rules[]? | select(.hook_stage == "pre" or .hook_stage == "both" or .hook_stage == null) | {rule_id, text, severity, category}]'
736
+ ORG_RULES=$(jq -c "$RULES_JQ" "$_RULES_TMP" 2>/dev/null || echo "[]")
737
+ if [ -n "$ORG_RULES" ] && [ "$ORG_RULES" != "null" ] && [ "$ORG_RULES" != "[]" ]; then
738
+ printf '%s' "$ORG_RULES" > "$RULES_CACHE" 2>/dev/null || true
739
+ elif [ -f "$RULES_CACHE" ]; then
740
+ ORG_RULES=$(cat "$RULES_CACHE" 2>/dev/null || echo "[]")
750
741
  fi
751
742
  if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
752
743
 
@@ -831,7 +822,9 @@ if [ "$VERDICT" != "__LOCAL_XML_PARSED__" ]; then
831
822
  ALTERNATIVE=$(echo "$VERDICT" | jq -r '.alternative // ""' 2>/dev/null)
832
823
  CATEGORY=$(echo "$VERDICT" | jq -r '.category // "destructive_command"' 2>/dev/null)
833
824
  RISK_LEVEL=$(echo "$VERDICT" | jq -r '.risk_level // empty' 2>/dev/null)
825
+ VIOLATED_RULES=$(echo "$VERDICT" | jq -c '.violated_rules // []' 2>/dev/null)
834
826
  fi
827
+ VIOLATED_RULES="\${VIOLATED_RULES:-[]}"
835
828
  # Defaults if any var is empty (defensive \u2014 XML primer should always emit them).
836
829
  SEVERITY="\${SEVERITY:-audit}"
837
830
  VERDICT_KIND="\${VERDICT_KIND:-warn}"
@@ -951,6 +944,7 @@ if [ "$USE_LOCAL" = "true" ] && [ -n "$VERDICT_KIND" ]; then
951
944
  --arg reasoning "$REASONING" \\
952
945
  --arg alternative "$ALTERNATIVE" \\
953
946
  --argjson rules_checked "\${ORG_RULES:-[]}" \\
947
+ --argjson violated_rules "\${VIOLATED_RULES:-[]}" \\
954
948
  --argjson recent_user_messages "\${RECENT_USER_MESSAGES:-[]}" \\
955
949
  '{
956
950
  event_id: $event_id,
@@ -963,7 +957,8 @@ if [ "$USE_LOCAL" = "true" ] && [ -n "$VERDICT_KIND" ]; then
963
957
  model: $model,
964
958
  tool_name: $tool_name,
965
959
  capture_depth: $capture_depth,
966
- rules_checked: $rules_checked
960
+ rules_checked: $rules_checked,
961
+ violated_rules: $violated_rules
967
962
  } + (if $repo != "" then {repo: $repo} else {} end)
968
963
  + (if $session_id != "" then {session_id: $session_id} else {} end)
969
964
  + (if $tool_use_id != "" then {tool_use_id: $tool_use_id} else {} end)
@@ -1217,34 +1212,30 @@ ensure_fresh_jwt() {
1217
1212
  ensure_fresh_jwt
1218
1213
 
1219
1214
 
1220
- # Resolve tier + capture_depth live from /cli/me every call. Default to local_only (fail-safe).
1221
- ME_RESP=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null || echo "")
1215
+ # Parallel fetch: /cli/me + rules in background, wait for both.
1216
+ _ME_TMP=$(mktemp -t synkro-me.XXXXXX)
1217
+ _RULES_TMP=$(mktemp -t synkro-rules.XXXXXX)
1218
+ trap "rm -f \\"$_ME_TMP\\" \\"$_RULES_TMP\\"" EXIT
1219
+ curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null > "$_ME_TMP" &
1220
+ _ME_PID=$!
1221
+ curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null > "$_RULES_TMP" &
1222
+ _RULES_PID=$!
1223
+ wait $_ME_PID 2>/dev/null; wait $_RULES_PID 2>/dev/null
1224
+
1225
+ ME_RESP=$(cat "$_ME_TMP" 2>/dev/null || echo "")
1222
1226
  SYNKRO_INFERENCE_TIER=$(echo "$ME_RESP" | jq -r '.tier // empty' 2>/dev/null)
1223
1227
  SYNKRO_CAPTURE_DEPTH=$(echo "$ME_RESP" | jq -r '.capture_depth // empty' 2>/dev/null)
1224
1228
  SYNKRO_INFERENCE_TIER="\${SYNKRO_INFERENCE_TIER:-fast}"
1225
1229
  SYNKRO_CAPTURE_DEPTH="\${SYNKRO_CAPTURE_DEPTH:-local_only}"
1226
1230
 
1227
1231
  if synkro_channel_up || { [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v claude >/dev/null 2>&1; }; then
1228
- # \u2500\u2500\u2500 LOCAL PATH: channel-grader first, then \`claude --print\` cold fallback. \u2500\u2500\u2500
1229
1232
  RULES_CACHE="$HOME/.synkro/.rules-cache-edit"
1230
- ORG_RULES="[]"
1231
- if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then
1232
- ORG_RULES=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" \\
1233
- -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null \\
1234
- | jq -c '[.rules[]? | select(.hook_stage == "pre" or .hook_stage == "both" or .hook_stage == null) | {rule_id, text, severity, category, mode}]' 2>/dev/null || echo "[]")
1235
- if [ -n "$ORG_RULES" ] && [ "$ORG_RULES" != "null" ] && [ "$ORG_RULES" != "[]" ]; then
1236
- printf '%s' "$ORG_RULES" > "$RULES_CACHE" 2>/dev/null || true
1237
- elif [ -f "$RULES_CACHE" ]; then
1238
- ORG_RULES=$(cat "$RULES_CACHE" 2>/dev/null || echo "[]")
1239
- fi
1240
- else
1241
- ORG_RULES=$(printf '%s' "$PROPOSED" | head -c 8000 \\
1242
- | jq -Rs '{content: .}' \\
1243
- | curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules?top_k=20" \\
1244
- -X POST -H "Content-Type: application/json" \\
1245
- -H "Authorization: Bearer $JWT" \\
1246
- -d @- --max-time 2 2>/dev/null \\
1247
- | jq -c '[.rules[]? | select(.hook_stage == "pre" or .hook_stage == "both" or .hook_stage == null) | {rule_id, text, severity, category, mode}]' 2>/dev/null || echo "[]")
1233
+ RULES_JQ='[.rules[]? | select(.hook_stage == "pre" or .hook_stage == "both" or .hook_stage == null) | {rule_id, text, severity, category, mode}]'
1234
+ ORG_RULES=$(jq -c "$RULES_JQ" "$_RULES_TMP" 2>/dev/null || echo "[]")
1235
+ if [ -n "$ORG_RULES" ] && [ "$ORG_RULES" != "null" ] && [ "$ORG_RULES" != "[]" ]; then
1236
+ printf '%s' "$ORG_RULES" > "$RULES_CACHE" 2>/dev/null || true
1237
+ elif [ -f "$RULES_CACHE" ]; then
1238
+ ORG_RULES=$(cat "$RULES_CACHE" 2>/dev/null || echo "[]")
1248
1239
  fi
1249
1240
  if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
1250
1241
 
@@ -1256,15 +1247,20 @@ if synkro_channel_up || { [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v cl
1256
1247
  printf 'Diff:\\n' >> "$GRADER_PROMPT_FILE"
1257
1248
  printf '%s\\n' "$PROPOSED" >> "$GRADER_PROMPT_FILE"
1258
1249
 
1250
+ ROUTE_TAG=""
1259
1251
  if synkro_channel_up && [ -n "\${SYNKRO_CLI_BIN:-}" ] && [ -f "$SYNKRO_CLI_BIN" ] && command -v node >/dev/null 2>&1; then
1252
+ ROUTE_TAG="local-cc"
1260
1253
  synkro_log "editGuard $FILE_SHORT \u2192 routing via local-cc"
1261
1254
  CC_RESP=$(node "$SYNKRO_CLI_BIN" grade edit < "$GRADER_PROMPT_FILE" 2>/dev/null || echo "")
1262
1255
  elif synkro_channel_up && command -v synkro >/dev/null 2>&1; then
1256
+ ROUTE_TAG="local-cc"
1263
1257
  synkro_log "editGuard $FILE_SHORT \u2192 routing via local-cc (PATH)"
1264
1258
  CC_RESP=$(synkro grade edit < "$GRADER_PROMPT_FILE" 2>/dev/null || echo "")
1265
1259
  else
1260
+ ROUTE_TAG="cc-print"
1266
1261
  CC_RESP=$(claude --print --model claude-sonnet-4-6 --no-session-persistence < "$GRADER_PROMPT_FILE" 2>/dev/null || echo "")
1267
1262
  fi
1263
+ SYNKRO_PREFIX="[synkro:\${ROUTE_TAG:-cloud}]"
1268
1264
 
1269
1265
  # Wrapper extraction (greedy \u2014 tolerates nested XML tags).
1270
1266
  V_INNER=$(printf '%s' "$CC_RESP" | tr '\\n' ' ' | sed -nE 's|.*<synkro-verdict>(.*)</synkro-verdict>.*|\\1|p' | tail -1)
@@ -1363,6 +1359,7 @@ if synkro_channel_up || { [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v cl
1363
1359
  fi
1364
1360
  else
1365
1361
  # \u2500\u2500\u2500 Server-side grading. \u2500\u2500\u2500
1362
+ SYNKRO_PREFIX="[synkro:cloud]"
1366
1363
  RESP=$(curl -sS -X POST "\${GATEWAY_URL}/api/v1/precheck-edit" \\
1367
1364
  -H "Content-Type: application/json" \\
1368
1365
  -H "Authorization: Bearer $JWT" \\
@@ -1382,13 +1379,13 @@ fi
1382
1379
 
1383
1380
  if [ -z "$RESP" ]; then
1384
1381
  synkro_log "editGuard $FILE_SHORT \u2192 error (timeout)"
1385
- jq -n --arg m "[synkro] editGuard $FILE_SHORT \u2192 error (timeout)" '{systemMessage: $m}'
1382
+ jq -n --arg m "$SYNKRO_PREFIX editGuard $FILE_SHORT \u2192 error (timeout)" '{systemMessage: $m}'
1386
1383
  exit 0
1387
1384
  fi
1388
1385
 
1389
1386
  if ! echo "$RESP" | jq -e 'type == "object"' >/dev/null 2>&1; then
1390
1387
  synkro_log "editGuard $FILE_SHORT \u2192 error (bad response)"
1391
- jq -n --arg m "[synkro] editGuard $FILE_SHORT \u2192 error (bad response)" '{systemMessage: $m}'
1388
+ jq -n --arg m "$SYNKRO_PREFIX editGuard $FILE_SHORT \u2192 error (bad response)" '{systemMessage: $m}'
1392
1389
  exit 0
1393
1390
  fi
1394
1391
 
@@ -1401,10 +1398,10 @@ else
1401
1398
  VERDICT_REASON=$(echo "$RESP" | jq -r '.reason // empty' 2>/dev/null)
1402
1399
  if [ -n "$VERDICT_REASON" ]; then
1403
1400
  synkro_log "editGuard $FILE_SHORT \u2192 pass: $VERDICT_REASON"
1404
- RESP_WITH_MSG=$(echo "$RESP" | jq --arg m "[synkro] editGuard $FILE_SHORT \u2192 pass: $VERDICT_REASON" '. + {systemMessage: $m}')
1401
+ RESP_WITH_MSG=$(echo "$RESP" | jq --arg m "$SYNKRO_PREFIX editGuard $FILE_SHORT \u2192 pass: $VERDICT_REASON" '. + {systemMessage: $m}')
1405
1402
  else
1406
1403
  synkro_log "editGuard $FILE_SHORT \u2192 pass"
1407
- RESP_WITH_MSG=$(echo "$RESP" | jq --arg m "[synkro] editGuard $FILE_SHORT \u2192 pass" '. + {systemMessage: $m}')
1404
+ RESP_WITH_MSG=$(echo "$RESP" | jq --arg m "$SYNKRO_PREFIX editGuard $FILE_SHORT \u2192 pass" '. + {systemMessage: $m}')
1408
1405
  fi
1409
1406
  echo "$RESP_WITH_MSG"
1410
1407
  fi
@@ -1661,30 +1658,25 @@ if [ -n "$SESSION_ID" ] && [ -n "$TOOL_USE_ID" ]; then
1661
1658
  ) &
1662
1659
  fi
1663
1660
 
1664
- # Resolve tier + capture_depth live from /cli/me every call. Default to local_only (fail-safe).
1665
- ME_RESP=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null || echo "")
1661
+ # Parallel fetch: /cli/me + rules in background, wait for both.
1662
+ _ME_TMP=$(mktemp -t synkro-me.XXXXXX)
1663
+ _RULES_TMP=$(mktemp -t synkro-rules.XXXXXX)
1664
+ trap "rm -f \\"$_ME_TMP\\" \\"$_RULES_TMP\\"" EXIT
1665
+ curl -sS "\${GATEWAY_URL}/api/v1/cli/me" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null > "$_ME_TMP" &
1666
+ _ME_PID=$!
1667
+ curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null > "$_RULES_TMP" &
1668
+ _RULES_PID=$!
1669
+ wait $_ME_PID 2>/dev/null; wait $_RULES_PID 2>/dev/null
1670
+
1671
+ ME_RESP=$(cat "$_ME_TMP" 2>/dev/null || echo "")
1666
1672
  SYNKRO_INFERENCE_TIER=$(echo "$ME_RESP" | jq -r '.tier // empty' 2>/dev/null)
1667
1673
  SYNKRO_CAPTURE_DEPTH=$(echo "$ME_RESP" | jq -r '.capture_depth // empty' 2>/dev/null)
1668
1674
  SYNKRO_INFERENCE_TIER="\${SYNKRO_INFERENCE_TIER:-fast}"
1669
1675
  SYNKRO_CAPTURE_DEPTH="\${SYNKRO_CAPTURE_DEPTH:-local_only}"
1670
1676
 
1671
1677
  if synkro_channel_up || { [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v claude >/dev/null 2>&1; }; then
1672
- # \u2500\u2500\u2500 LOCAL PATH: channel-grader first, then \`claude --print\` cold fallback. \u2500\u2500\u2500
1673
-
1674
1678
  RULES_CACHE="$HOME/.synkro/.rules-cache-edit-capture"
1675
- RULES_RESP=""
1676
- if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then
1677
- RULES_RESP=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" \\
1678
- -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null || echo "")
1679
- else
1680
- RULES_RESP=$(printf '%s' "$FILE_CONTENT" | head -c 8000 \\
1681
- | jq -Rs '{content: .}' \\
1682
- | curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules?top_k=20" \\
1683
- -X POST -H "Content-Type: application/json" \\
1684
- -H "Authorization: Bearer $JWT" \\
1685
- -d @- --max-time 2 2>/dev/null || echo "")
1686
- fi
1687
- ORG_RULES=$(echo "$RULES_RESP" | jq -c '[.rules[]? | select(.hook_stage == "post" or .hook_stage == "both" or .hook_stage == null) | {rule_id, text, severity, category}]' 2>/dev/null || echo "[]")
1679
+ ORG_RULES=$(jq -c '[.rules[]? | select(.hook_stage == "post" or .hook_stage == "both" or .hook_stage == null) | {rule_id, text, severity, category}]' "$_RULES_TMP" 2>/dev/null || echo "[]")
1688
1680
  if [ -n "$ORG_RULES" ] && [ "$ORG_RULES" != "null" ] && [ "$ORG_RULES" != "[]" ]; then
1689
1681
  printf '%s' "$ORG_RULES" > "$RULES_CACHE" 2>/dev/null || true
1690
1682
  elif [ -f "$RULES_CACHE" ]; then
@@ -1714,15 +1706,20 @@ if synkro_channel_up || { [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v cl
1714
1706
  printf 'Content:\\n' >> "$GRADER_PROMPT_FILE"
1715
1707
  printf '%s\\n' "$FILE_CONTENT" >> "$GRADER_PROMPT_FILE"
1716
1708
 
1709
+ ROUTE_TAG=""
1717
1710
  if synkro_channel_up && [ -n "\${SYNKRO_CLI_BIN:-}" ] && [ -f "$SYNKRO_CLI_BIN" ] && command -v node >/dev/null 2>&1; then
1711
+ ROUTE_TAG="local-cc"
1718
1712
  synkro_log "editGuard $BASENAME \u2192 routing via local-cc"
1719
1713
  CC_RESP=$(node "$SYNKRO_CLI_BIN" grade edit < "$GRADER_PROMPT_FILE" 2>/dev/null || echo "")
1720
1714
  elif synkro_channel_up && command -v synkro >/dev/null 2>&1; then
1715
+ ROUTE_TAG="local-cc"
1721
1716
  synkro_log "editGuard $BASENAME \u2192 routing via local-cc (PATH)"
1722
1717
  CC_RESP=$(synkro grade edit < "$GRADER_PROMPT_FILE" 2>/dev/null || echo "")
1723
1718
  else
1719
+ ROUTE_TAG="cc-print"
1724
1720
  CC_RESP=$(claude --print --model claude-sonnet-4-6 --no-session-persistence < "$GRADER_PROMPT_FILE" 2>/dev/null || echo "")
1725
1721
  fi
1722
+ SYNKRO_PREFIX="[synkro:\${ROUTE_TAG:-cloud}]"
1726
1723
 
1727
1724
  # Wait for CVE scan
1728
1725
  wait $CVE_PID 2>/dev/null
@@ -1779,6 +1776,7 @@ if synkro_channel_up || { [ "$SYNKRO_INFERENCE_TIER" = "free" ] && command -v cl
1779
1776
  fi
1780
1777
  else
1781
1778
  # \u2500\u2500\u2500 Server-side grading. \u2500\u2500\u2500
1779
+ SYNKRO_PREFIX="[synkro:cloud]"
1782
1780
  RESP=$(curl -sS -X POST "\${GATEWAY_URL}/api/v1/judge-edit" \\
1783
1781
  -H "Content-Type: application/json" \\
1784
1782
  -H "Authorization: Bearer $JWT" \\
@@ -1798,7 +1796,7 @@ fi
1798
1796
 
1799
1797
  if [ -z "$RESP" ] || ! echo "$RESP" | jq -e 'type == "object"' >/dev/null 2>&1; then
1800
1798
  synkro_log "editScan $BASENAME \u2192 error (no response)"
1801
- jq -n --arg m "[synkro] editScan $BASENAME \u2192 error (no response)" '{systemMessage: $m}'
1799
+ jq -n --arg m "$SYNKRO_PREFIX editScan $BASENAME \u2192 error (no response)" '{systemMessage: $m}'
1802
1800
  exit 0
1803
1801
  fi
1804
1802
 
@@ -1867,8 +1865,8 @@ fi
1867
1865
 
1868
1866
  if [ "$OK" = "false" ] && [ -n "$REASON" ]; then
1869
1867
  synkro_log "editScan $BASENAME \u2192 FAIL ($CATEGORY): $REASON"
1870
- SYS_MSG="[synkro] editScan $BASENAME \u2192 FAIL: \${REASON}"
1871
- ADDITIONAL_CTX="Synkro post-edit grader flagged \${BASENAME} (severity: \${SEVERITY}, category: \${CATEGORY}). Re-edit the file applying the retry guidance: \${REASON}"
1868
+ SYS_MSG="$SYNKRO_PREFIX editScan $BASENAME \u2192 FAIL: \${REASON}"
1869
+ ADDITIONAL_CTX="Synkro post-edit grader flagged \${BASENAME} (severity: \${SEVERITY}, category: \${CATEGORY}, route: \${ROUTE_TAG:-cloud}). Re-edit the file applying the retry guidance: \${REASON}"
1872
1870
  jq -n \\
1873
1871
  --arg sys_msg "$SYS_MSG" \\
1874
1872
  --arg ctx "$ADDITIONAL_CTX" \\
@@ -1884,10 +1882,10 @@ fi
1884
1882
 
1885
1883
  if [ -n "$REASON" ]; then
1886
1884
  synkro_log "editScan $BASENAME \u2192 pass ($CATEGORY): $REASON"
1887
- jq -n --arg m "[synkro] editScan $BASENAME \u2192 pass ($CATEGORY): $REASON" '{systemMessage: $m}'
1885
+ jq -n --arg m "$SYNKRO_PREFIX editScan $BASENAME \u2192 pass ($CATEGORY): $REASON" '{systemMessage: $m}'
1888
1886
  else
1889
1887
  synkro_log "editScan $BASENAME \u2192 pass"
1890
- jq -n --arg m "[synkro] editScan $BASENAME \u2192 pass" '{systemMessage: $m}'
1888
+ jq -n --arg m "$SYNKRO_PREFIX editScan $BASENAME \u2192 pass" '{systemMessage: $m}'
1891
1889
  fi
1892
1890
  exit 0
1893
1891
  `;
@@ -4839,7 +4837,7 @@ function writeConfigEnv(opts) {
4839
4837
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
4840
4838
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
4841
4839
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
4842
- `SYNKRO_VERSION=${shellQuoteSingle("1.4.10")}`
4840
+ `SYNKRO_VERSION=${shellQuoteSingle("1.4.12")}`
4843
4841
  ];
4844
4842
  if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
4845
4843
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);