@synkro-sh/cli 1.3.34 → 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 +76 -8
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -1986,21 +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
|
-
headers={
|
|
2031
|
+
headers={
|
|
2032
|
+
"Authorization": f"Bearer {jwt}",
|
|
2033
|
+
"User-Agent": "synkro-cli-grader-daemon/1",
|
|
2034
|
+
},
|
|
2000
2035
|
)
|
|
2001
2036
|
with urllib.request.urlopen(req, timeout=5) as resp:
|
|
2002
2037
|
data = json.loads(resp.read().decode("utf-8"))
|
|
2003
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 ""
|
|
2004
2056
|
except Exception:
|
|
2005
2057
|
return ""
|
|
2006
2058
|
|
|
@@ -2107,6 +2159,7 @@ class WarmGrader:
|
|
|
2107
2159
|
def __init__(self, primer):
|
|
2108
2160
|
self.primer = primer or ""
|
|
2109
2161
|
self._warm_proc = None
|
|
2162
|
+
self._warm_ready_at = 0.0
|
|
2110
2163
|
self._warm_thread = None
|
|
2111
2164
|
self._lock = threading.Lock()
|
|
2112
2165
|
self._total_grades = 0
|
|
@@ -2145,6 +2198,7 @@ class WarmGrader:
|
|
|
2145
2198
|
with self._lock:
|
|
2146
2199
|
old = self._warm_proc
|
|
2147
2200
|
self._warm_proc = proc
|
|
2201
|
+
self._warm_ready_at = time.time()
|
|
2148
2202
|
self._prewarm_ok = True
|
|
2149
2203
|
if old:
|
|
2150
2204
|
self._kill_proc(old)
|
|
@@ -2169,8 +2223,16 @@ class WarmGrader:
|
|
|
2169
2223
|
|
|
2170
2224
|
with self._lock:
|
|
2171
2225
|
proc = self._warm_proc
|
|
2226
|
+
ready_at = self._warm_ready_at
|
|
2172
2227
|
self._warm_proc = None
|
|
2173
|
-
|
|
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"))
|
|
2174
2236
|
warm = True
|
|
2175
2237
|
if not proc or proc.poll() is not None:
|
|
2176
2238
|
log("no warm process, cold fallback")
|
|
@@ -2181,6 +2243,12 @@ class WarmGrader:
|
|
|
2181
2243
|
self._kill_proc(proc)
|
|
2182
2244
|
proc = self._make_proc()
|
|
2183
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
|
|
2184
2252
|
|
|
2185
2253
|
wall_limit = int(os.environ.get("SYNKRO_DAEMON_WALL_TIMEOUT", "12"))
|
|
2186
2254
|
t0 = time.time()
|
|
@@ -3647,7 +3715,7 @@ function writeConfigEnv(opts) {
|
|
|
3647
3715
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3648
3716
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3649
3717
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3650
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.3.
|
|
3718
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.3.36")}`
|
|
3651
3719
|
];
|
|
3652
3720
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
3653
3721
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|