@synkro-sh/cli 1.3.35 → 1.3.36
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 +72 -8
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -1986,25 +1986,73 @@ def _read_jwt():
|
|
|
1986
1986
|
except Exception:
|
|
1987
1987
|
return ""
|
|
1988
1988
|
|
|
1989
|
+
def _refresh_jwt():
|
|
1990
|
+
"""Refresh the access token using the saved refresh_token. Writes new
|
|
1991
|
+
tokens back to credentials.json. Returns the new access_token or ''."""
|
|
1992
|
+
try:
|
|
1993
|
+
with open(CREDS_PATH) as f:
|
|
1994
|
+
creds = json.load(f)
|
|
1995
|
+
rt = creds.get("refresh_token", "")
|
|
1996
|
+
if not rt:
|
|
1997
|
+
return ""
|
|
1998
|
+
req = urllib.request.Request(
|
|
1999
|
+
f"{GATEWAY_URL}/api/auth/refresh",
|
|
2000
|
+
data=json.dumps({"refresh_token": rt}).encode("utf-8"),
|
|
2001
|
+
headers={
|
|
2002
|
+
"Content-Type": "application/json",
|
|
2003
|
+
"User-Agent": "synkro-cli-grader-daemon/1",
|
|
2004
|
+
},
|
|
2005
|
+
)
|
|
2006
|
+
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
2007
|
+
data = json.loads(resp.read().decode("utf-8"))
|
|
2008
|
+
new_at = data.get("access_token", "")
|
|
2009
|
+
new_rt = data.get("refresh_token", "") or rt
|
|
2010
|
+
if not new_at:
|
|
2011
|
+
return ""
|
|
2012
|
+
creds["access_token"] = new_at
|
|
2013
|
+
creds["refresh_token"] = new_rt
|
|
2014
|
+
tmp = str(CREDS_PATH) + ".synkro.tmp"
|
|
2015
|
+
with open(tmp, "w") as f:
|
|
2016
|
+
json.dump(creds, f)
|
|
2017
|
+
os.replace(tmp, str(CREDS_PATH))
|
|
2018
|
+
return new_at
|
|
2019
|
+
except Exception:
|
|
2020
|
+
return ""
|
|
2021
|
+
|
|
1989
2022
|
def fetch_primer(mode):
|
|
1990
|
-
"""Fetch primer text for {bash,edit} from /cli/judge-prompts. In-memory only.
|
|
2023
|
+
"""Fetch primer text for {bash,edit} from /cli/judge-prompts. In-memory only.
|
|
2024
|
+
Auto-refreshes JWT on 401 and retries once."""
|
|
1991
2025
|
_load_gateway_url()
|
|
1992
|
-
jwt = _read_jwt()
|
|
1993
|
-
if not jwt:
|
|
1994
|
-
return ""
|
|
1995
2026
|
field = "grader_primer_bash" if mode == "bash" else "grader_primer_edit"
|
|
1996
|
-
|
|
2027
|
+
|
|
2028
|
+
def _do_fetch(jwt):
|
|
1997
2029
|
req = urllib.request.Request(
|
|
1998
2030
|
f"{GATEWAY_URL}/api/v1/cli/judge-prompts",
|
|
1999
2031
|
headers={
|
|
2000
2032
|
"Authorization": f"Bearer {jwt}",
|
|
2001
|
-
# CF rejects requests without UA \u2014 without this we get 403.
|
|
2002
2033
|
"User-Agent": "synkro-cli-grader-daemon/1",
|
|
2003
2034
|
},
|
|
2004
2035
|
)
|
|
2005
2036
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
2006
2037
|
data = json.loads(resp.read().decode("utf-8"))
|
|
2007
2038
|
return data.get(field, "") or ""
|
|
2039
|
+
|
|
2040
|
+
jwt = _read_jwt()
|
|
2041
|
+
if not jwt:
|
|
2042
|
+
return ""
|
|
2043
|
+
try:
|
|
2044
|
+
return _do_fetch(jwt)
|
|
2045
|
+
except urllib.error.HTTPError as e:
|
|
2046
|
+
if e.code != 401:
|
|
2047
|
+
return ""
|
|
2048
|
+
# Token expired \u2014 refresh and retry once.
|
|
2049
|
+
new_jwt = _refresh_jwt()
|
|
2050
|
+
if not new_jwt:
|
|
2051
|
+
return ""
|
|
2052
|
+
try:
|
|
2053
|
+
return _do_fetch(new_jwt)
|
|
2054
|
+
except Exception:
|
|
2055
|
+
return ""
|
|
2008
2056
|
except Exception:
|
|
2009
2057
|
return ""
|
|
2010
2058
|
|
|
@@ -2111,6 +2159,7 @@ class WarmGrader:
|
|
|
2111
2159
|
def __init__(self, primer):
|
|
2112
2160
|
self.primer = primer or ""
|
|
2113
2161
|
self._warm_proc = None
|
|
2162
|
+
self._warm_ready_at = 0.0
|
|
2114
2163
|
self._warm_thread = None
|
|
2115
2164
|
self._lock = threading.Lock()
|
|
2116
2165
|
self._total_grades = 0
|
|
@@ -2149,6 +2198,7 @@ class WarmGrader:
|
|
|
2149
2198
|
with self._lock:
|
|
2150
2199
|
old = self._warm_proc
|
|
2151
2200
|
self._warm_proc = proc
|
|
2201
|
+
self._warm_ready_at = time.time()
|
|
2152
2202
|
self._prewarm_ok = True
|
|
2153
2203
|
if old:
|
|
2154
2204
|
self._kill_proc(old)
|
|
@@ -2173,8 +2223,16 @@ class WarmGrader:
|
|
|
2173
2223
|
|
|
2174
2224
|
with self._lock:
|
|
2175
2225
|
proc = self._warm_proc
|
|
2226
|
+
ready_at = self._warm_ready_at
|
|
2176
2227
|
self._warm_proc = None
|
|
2177
|
-
|
|
2228
|
+
self._warm_ready_at = 0.0
|
|
2229
|
+
|
|
2230
|
+
# Warm-process TTL: claude --print holds an HTTP/2 conn to Anthropic
|
|
2231
|
+
# that goes stale after ~20s idle. The subprocess doesn't notice the
|
|
2232
|
+
# broken pipe and just hangs forever when given a prompt. Force cold
|
|
2233
|
+
# if the warm has been sitting idle too long \u2014 still faster than
|
|
2234
|
+
# eating a 10s stall timeout + cold fallback.
|
|
2235
|
+
WARM_TTL_SEC = int(os.environ.get("SYNKRO_DAEMON_WARM_TTL", "15"))
|
|
2178
2236
|
warm = True
|
|
2179
2237
|
if not proc or proc.poll() is not None:
|
|
2180
2238
|
log("no warm process, cold fallback")
|
|
@@ -2185,6 +2243,12 @@ class WarmGrader:
|
|
|
2185
2243
|
self._kill_proc(proc)
|
|
2186
2244
|
proc = self._make_proc()
|
|
2187
2245
|
warm = False
|
|
2246
|
+
elif ready_at and (time.time() - ready_at) > WARM_TTL_SEC:
|
|
2247
|
+
age = time.time() - ready_at
|
|
2248
|
+
log(f"warm process stale ({age:.0f}s > {WARM_TTL_SEC}s), cold fallback")
|
|
2249
|
+
self._kill_proc(proc)
|
|
2250
|
+
proc = self._make_proc()
|
|
2251
|
+
warm = False
|
|
2188
2252
|
|
|
2189
2253
|
wall_limit = int(os.environ.get("SYNKRO_DAEMON_WALL_TIMEOUT", "12"))
|
|
2190
2254
|
t0 = time.time()
|
|
@@ -3651,7 +3715,7 @@ function writeConfigEnv(opts) {
|
|
|
3651
3715
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3652
3716
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3653
3717
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3654
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.3.
|
|
3718
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.3.36")}`
|
|
3655
3719
|
];
|
|
3656
3720
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
3657
3721
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|