@synkro-sh/cli 1.3.30 → 1.3.31

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
@@ -602,9 +602,34 @@ fi
602
602
  if [ "$USE_LOCAL" = "true" ]; then
603
603
  # \u2500\u2500\u2500 FREE TIER: grade via the persistent claude daemon (mode=bash). \u2500\u2500\u2500
604
604
 
605
- # Fetch org guardrail rules relevant to this command (skip in local_only \u2014 no content leaves device).
605
+ # Refresh primer if older than 24h (server-side IP, fetched on demand).
606
+ PRIMER_FILE="$HOME/.synkro/grader-primer-bash.txt"
607
+ if [ ! -f "$PRIMER_FILE" ] || ! find "$PRIMER_FILE" -mmin -1440 2>/dev/null | grep -q .; then
608
+ NEW_PRIMER=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/judge-prompts" \\
609
+ -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null \\
610
+ | jq -r '.grader_primer_bash // empty' 2>/dev/null || echo "")
611
+ if [ -n "$NEW_PRIMER" ]; then
612
+ printf '%s' "$NEW_PRIMER" > "$PRIMER_FILE" 2>/dev/null || true
613
+ # Kill the daemon so it restarts with the fresh primer.
614
+ DAEMON_PID_FILE="$HOME/.synkro/daemon/bash/daemon.pid"
615
+ [ -f "$DAEMON_PID_FILE" ] && kill -TERM "$(cat "$DAEMON_PID_FILE" 2>/dev/null)" 2>/dev/null || true
616
+ fi
617
+ fi
618
+
619
+ # Fetch org guardrail rules. In local_only mode use GET (no command leaks);
620
+ # in other modes use POST with content for embedding-based top_k matching.
621
+ RULES_CACHE="$HOME/.synkro/.rules-cache-bash"
606
622
  ORG_RULES="[]"
607
- if [ "$SYNKRO_CAPTURE_DEPTH" != "local_only" ]; then
623
+ if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then
624
+ if find "$RULES_CACHE" -mmin -60 2>/dev/null | grep -q .; then
625
+ ORG_RULES=$(cat "$RULES_CACHE" 2>/dev/null || echo "[]")
626
+ else
627
+ ORG_RULES=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" \\
628
+ -H "Authorization: Bearer $JWT" --max-time 2 2>/dev/null \\
629
+ | jq -c '[.rules[]? | {rule_id, text, severity, category}]' 2>/dev/null || echo "[]")
630
+ [ -n "$ORG_RULES" ] && [ "$ORG_RULES" != "null" ] && printf '%s' "$ORG_RULES" > "$RULES_CACHE" 2>/dev/null || true
631
+ fi
632
+ else
608
633
  ORG_RULES=$(printf '%s' "$COMMAND" | head -c 4000 \\
609
634
  | jq -Rs '{content: .}' \\
610
635
  | curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules?top_k=15" \\
@@ -612,8 +637,8 @@ if [ "$USE_LOCAL" = "true" ]; then
612
637
  -H "Authorization: Bearer $JWT" \\
613
638
  -d @- --max-time 2 2>/dev/null \\
614
639
  | 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
640
  fi
641
+ if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
617
642
 
618
643
  GRADER_PROMPT_FILE=$(mktemp -t synkro-bash-prompt.XXXXXX)
619
644
  trap "rm -f \\"$GRADER_PROMPT_FILE\\"" EXIT
@@ -1029,8 +1054,31 @@ fi
1029
1054
 
1030
1055
  if [ "$USE_LOCAL" = "true" ]; then
1031
1056
  # \u2500\u2500\u2500 LOCAL GRADING: grade via the persistent claude daemon (Python helper).
1057
+
1058
+ # Refresh primer if older than 24h (server-side IP, fetched on demand).
1059
+ PRIMER_FILE="$HOME/.synkro/grader-primer-edit.txt"
1060
+ if [ ! -f "$PRIMER_FILE" ] || ! find "$PRIMER_FILE" -mmin -1440 2>/dev/null | grep -q .; then
1061
+ NEW_PRIMER=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/judge-prompts" \\
1062
+ -H "Authorization: Bearer $JWT" --max-time 3 2>/dev/null \\
1063
+ | jq -r '.grader_primer_edit // empty' 2>/dev/null || echo "")
1064
+ if [ -n "$NEW_PRIMER" ]; then
1065
+ printf '%s' "$NEW_PRIMER" > "$PRIMER_FILE" 2>/dev/null || true
1066
+ DAEMON_PID_FILE="$HOME/.synkro/daemon/edit/daemon.pid"
1067
+ [ -f "$DAEMON_PID_FILE" ] && kill -TERM "$(cat "$DAEMON_PID_FILE" 2>/dev/null)" 2>/dev/null || true
1068
+ fi
1069
+ fi
1070
+ RULES_CACHE="$HOME/.synkro/.rules-cache-edit"
1032
1071
  ORG_RULES="[]"
1033
- if [ "$SYNKRO_CAPTURE_DEPTH" != "local_only" ]; then
1072
+ if [ "$SYNKRO_CAPTURE_DEPTH" = "local_only" ]; then
1073
+ if find "$RULES_CACHE" -mmin -60 2>/dev/null | grep -q .; then
1074
+ ORG_RULES=$(cat "$RULES_CACHE" 2>/dev/null || echo "[]")
1075
+ else
1076
+ ORG_RULES=$(curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules" \\
1077
+ -H "Authorization: Bearer $JWT" --max-time 2 2>/dev/null \\
1078
+ | jq -c '[.rules[]? | {rule_id, text, severity, category, mode}]' 2>/dev/null || echo "[]")
1079
+ [ -n "$ORG_RULES" ] && [ "$ORG_RULES" != "null" ] && printf '%s' "$ORG_RULES" > "$RULES_CACHE" 2>/dev/null || true
1080
+ fi
1081
+ else
1034
1082
  ORG_RULES=$(printf '%s' "$PROPOSED" | head -c 8000 \\
1035
1083
  | jq -Rs '{content: .}' \\
1036
1084
  | curl -sS "\${GATEWAY_URL}/api/v1/cli/pr-rules?top_k=20" \\
@@ -1038,8 +1086,8 @@ if [ "$USE_LOCAL" = "true" ]; then
1038
1086
  -H "Authorization: Bearer $JWT" \\
1039
1087
  -d @- --max-time 2 2>/dev/null \\
1040
1088
  | jq -c '[.rules[]? | {rule_id, text, severity, category, mode}]' 2>/dev/null || echo "[]")
1041
- if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
1042
1089
  fi
1090
+ if [ -z "$ORG_RULES" ] || [ "$ORG_RULES" = "null" ]; then ORG_RULES="[]"; fi
1043
1091
 
1044
1092
  GRADER_PROMPT_FILE=$(mktemp -t synkro-grade.XXXXXX)
1045
1093
  trap "rm -f \\"$GRADER_PROMPT_FILE\\"" EXIT
@@ -3428,12 +3476,27 @@ function ensureSynkroDir() {
3428
3476
  mkdirSync5(BIN_DIR, { recursive: true });
3429
3477
  mkdirSync5(OFFSETS_DIR, { recursive: true });
3430
3478
  }
3431
- function writeGraderDaemon() {
3479
+ async function fetchGraderPrimers(gatewayUrl, token) {
3480
+ try {
3481
+ const resp = await fetch(`${gatewayUrl}/api/v1/cli/judge-prompts`, {
3482
+ headers: { "Authorization": `Bearer ${token}` }
3483
+ });
3484
+ if (!resp.ok) throw new Error(`status ${resp.status}`);
3485
+ const data = await resp.json();
3486
+ if (!data.grader_primer_bash || !data.grader_primer_edit) throw new Error("missing primer fields");
3487
+ return { bash: data.grader_primer_bash, edit: data.grader_primer_edit };
3488
+ } catch (err) {
3489
+ console.warn(`[synkro] primer fetch failed (${err.message}); using bundled fallback`);
3490
+ return { bash: GRADER_PRIMER_BASH, edit: GRADER_PRIMER_EDIT };
3491
+ }
3492
+ }
3493
+ async function writeGraderDaemon(gatewayUrl, token) {
3432
3494
  writeFileSync5(GRADER_DAEMON_PATH, GRADER_DAEMON_PY, "utf-8");
3433
3495
  chmodSync(GRADER_DAEMON_PATH, 493);
3434
- writeFileSync5(GRADER_PRIMER_EDIT_PATH, GRADER_PRIMER_EDIT, "utf-8");
3496
+ const primers = await fetchGraderPrimers(gatewayUrl, token);
3497
+ writeFileSync5(GRADER_PRIMER_EDIT_PATH, primers.edit, "utf-8");
3435
3498
  chmodSync(GRADER_PRIMER_EDIT_PATH, 420);
3436
- writeFileSync5(GRADER_PRIMER_BASH_PATH, GRADER_PRIMER_BASH, "utf-8");
3499
+ writeFileSync5(GRADER_PRIMER_BASH_PATH, primers.bash, "utf-8");
3437
3500
  chmodSync(GRADER_PRIMER_BASH_PATH, 420);
3438
3501
  }
3439
3502
  function writeHookScripts() {
@@ -3491,7 +3554,7 @@ function writeConfigEnv(opts) {
3491
3554
  `SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
3492
3555
  `SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
3493
3556
  `SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
3494
- `SYNKRO_VERSION=${shellQuoteSingle("1.3.30")}`
3557
+ `SYNKRO_VERSION=${shellQuoteSingle("1.3.31")}`
3495
3558
  ];
3496
3559
  if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
3497
3560
  if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
@@ -3719,7 +3782,7 @@ async function installCommand(opts = {}) {
3719
3782
  console.log(` ${scripts.sessionStartScript}`);
3720
3783
  console.log(` ${scripts.transcriptSyncScript}
3721
3784
  `);
3722
- writeGraderDaemon();
3785
+ await writeGraderDaemon(gatewayUrl, token);
3723
3786
  for (const mode of ["edit", "bash"]) {
3724
3787
  const pidFile = join6(SYNKRO_DIR2, "daemon", mode, "daemon.pid");
3725
3788
  try {