zeno-cli 0.3.6__tar.gz → 0.3.8__tar.gz
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.
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/PKG-INFO +1 -1
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_generated/client.py +14 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/pyproject.toml +1 -1
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/_hooks/cc_bridge.py +30 -12
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/login.py +11 -11
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/.gitignore +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/README.md +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_adapters/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_adapters/_common.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_adapters/anthropic.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_adapters/claude_code.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_adapters/crewai.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_adapters/langgraph.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_adapters/openai.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_core/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_core/analytics.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_core/rtlx_s.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_core/streak.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_core/tlx_s.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_generated/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_migrations/alembic/env.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_migrations/alembic/script.py.mako +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_migrations/alembic/versions/0001_initial.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_migrations/alembic/versions/0002_cognition_samples.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_migrations/alembic/versions/0003_cognition_drivers.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_migrations/alembic/versions/0004_transcript_intelligence.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_migrations/alembic.ini +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/_runtime.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/adapters/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/adapters/anthropic.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/adapters/claude_code.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/adapters/crewai.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/adapters/langgraph.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/adapters/openai.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/auth.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/client.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/config.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/daemon.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/privacy.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/session.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/storage.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_sdk/types/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/analytics.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/compression.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/ingest.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/model.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/parsers/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/parsers/claude_code.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/parsers/codex.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/parsers/cursor.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/prices.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/schema.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/signals.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/_vendor_build/zeno_session_intel/taxonomy.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/data/outreach_suppression.txt +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/hatch_build.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/scripts/install-smoke.sh +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/doctor.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/hook_install.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/hud/__init__.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/hud/hud_install.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/hud/zeno_attention.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/hud/zeno_cognition.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/hud/zeno_hud.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/interview_invites.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/main.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/onboard.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/outreach.py +0 -0
- {zeno_cli-0.3.6 → zeno_cli-0.3.8}/src/zeno_cli/version.py +0 -0
|
@@ -574,6 +574,20 @@ class ZenoApiClient:
|
|
|
574
574
|
headers=headers,
|
|
575
575
|
)
|
|
576
576
|
|
|
577
|
+
def capture_recent(self, *, limit: str | None = None) -> dict[str, Any]:
|
|
578
|
+
"""GET /v1/capture/recent"""
|
|
579
|
+
query: dict[str, str] | None = None
|
|
580
|
+
headers: dict[str, str] | None = None
|
|
581
|
+
query = {}
|
|
582
|
+
if limit is not None:
|
|
583
|
+
query["limit"] = str(limit)
|
|
584
|
+
return self._request(
|
|
585
|
+
"GET",
|
|
586
|
+
"/v1/capture/recent",
|
|
587
|
+
query=query,
|
|
588
|
+
headers=headers,
|
|
589
|
+
)
|
|
590
|
+
|
|
577
591
|
def capture_stream(self) -> dict[str, Any]:
|
|
578
592
|
"""GET /v1/capture/stream"""
|
|
579
593
|
query: dict[str, str] | None = None
|
|
@@ -197,8 +197,8 @@ def _api_base_url() -> str:
|
|
|
197
197
|
def _api_token() -> str | None:
|
|
198
198
|
"""Bearer token for the capture push, when one is available.
|
|
199
199
|
|
|
200
|
-
Checks the explicit env var first (
|
|
201
|
-
|
|
200
|
+
Checks the explicit env var first (same precedence as the CLI's
|
|
201
|
+
resolve_api_token), then the keyring slot `zeno login` writes (service "zeno-sdk",
|
|
202
202
|
key "clerk_jwt"). The keyring lookup is best-effort: keyring is an optional
|
|
203
203
|
dependency and may be absent under the system python the hook runs on.
|
|
204
204
|
Returns None on the tailnet Mini, where identity comes from a header the
|
|
@@ -279,9 +279,22 @@ def _idempotency_key(body: dict) -> str:
|
|
|
279
279
|
return f"{body['device_id']}:{body['session_id']}:{entity}"
|
|
280
280
|
|
|
281
281
|
|
|
282
|
-
|
|
282
|
+
# Sentinel for "token not supplied -> resolve it here", distinct from a resolved
|
|
283
|
+
# None ("no token, tailnet path"). Lets _maybe_push pass the once-resolved value
|
|
284
|
+
# (str OR None) down so neither the public nor the Mini path re-reads the keyring
|
|
285
|
+
# per drained line.
|
|
286
|
+
_UNSET = object()
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _post_ingest(body: dict, timeout_s: float, token=_UNSET) -> bool:
|
|
283
290
|
"""POST one ingest body. Returns True on a 2xx, False on any failure. Never
|
|
284
|
-
raises (all exceptions -> False). urllib + an explicit socket timeout only.
|
|
291
|
+
raises (all exceptions -> False). urllib + an explicit socket timeout only.
|
|
292
|
+
|
|
293
|
+
``token`` is the pre-resolved bearer (see _maybe_push); pass it so a drain of
|
|
294
|
+
many spooled lines does not re-read the OS keyring per line. When omitted
|
|
295
|
+
(_UNSET; direct callers/tests) it is resolved once here. An explicit None means
|
|
296
|
+
"no token" (tailnet path) and is used as-is without re-resolving.
|
|
297
|
+
"""
|
|
285
298
|
url = _api_base_url() + SYNC_PATH
|
|
286
299
|
data = json.dumps(body).encode("utf-8")
|
|
287
300
|
headers = {
|
|
@@ -291,9 +304,9 @@ def _post_ingest(body: dict, timeout_s: float) -> bool:
|
|
|
291
304
|
# Attach the Clerk bearer token when one is available so the push authenticates
|
|
292
305
|
# against a public API (Cloud Run). Absent it (tailnet Mini), the push relies on
|
|
293
306
|
# the identity header the `tailscale serve` proxy injects - unchanged behavior.
|
|
294
|
-
|
|
295
|
-
if
|
|
296
|
-
headers["Authorization"] = "Bearer " +
|
|
307
|
+
resolved = _api_token() if token is _UNSET else token
|
|
308
|
+
if resolved:
|
|
309
|
+
headers["Authorization"] = "Bearer " + resolved
|
|
297
310
|
req = urllib.request.Request(
|
|
298
311
|
url,
|
|
299
312
|
data=data,
|
|
@@ -342,10 +355,11 @@ def _trim_outbox(path: Path) -> None:
|
|
|
342
355
|
_debug(f"trim_outbox failed: {exc}")
|
|
343
356
|
|
|
344
357
|
|
|
345
|
-
def _drain_outbox(timeout_s: float) -> None:
|
|
358
|
+
def _drain_outbox(timeout_s: float, token=_UNSET) -> None:
|
|
346
359
|
"""After a live push, best-effort + time-boxed drain of a few spooled lines.
|
|
347
360
|
Pushes oldest-first; stops at the budget, the line cap, or the first failure
|
|
348
|
-
(so an offline window doesn't re-spin). Rewrites the outbox with the remainder.
|
|
361
|
+
(so an offline window doesn't re-spin). Rewrites the outbox with the remainder.
|
|
362
|
+
``token`` is threaded to _post_ingest so the keyring is read once per drain."""
|
|
349
363
|
path = _outbox_path()
|
|
350
364
|
try:
|
|
351
365
|
if not path.exists():
|
|
@@ -367,7 +381,7 @@ def _drain_outbox(timeout_s: float) -> None:
|
|
|
367
381
|
except Exception:
|
|
368
382
|
consumed += 1 # unparseable - drop it, keep draining
|
|
369
383
|
continue
|
|
370
|
-
if not _post_ingest(body, timeout_s):
|
|
384
|
+
if not _post_ingest(body, timeout_s, token):
|
|
371
385
|
break # stop on first failure; leave this line + the rest spooled
|
|
372
386
|
consumed += 1
|
|
373
387
|
if consumed == 0:
|
|
@@ -403,8 +417,12 @@ def _maybe_push(event: str, payload: dict) -> None:
|
|
|
403
417
|
if body is None:
|
|
404
418
|
return
|
|
405
419
|
timeout_s = _sync_timeout_s()
|
|
406
|
-
|
|
407
|
-
|
|
420
|
+
# Resolve the bearer ONCE per hook invocation (an OS keyring read is not
|
|
421
|
+
# bounded by the socket timeout); thread it through the drain so a
|
|
422
|
+
# multi-line drain never re-reads the keyring on the hot Stop path.
|
|
423
|
+
token = _api_token()
|
|
424
|
+
if _post_ingest(body, timeout_s, token):
|
|
425
|
+
_drain_outbox(timeout_s, token)
|
|
408
426
|
else:
|
|
409
427
|
_spool(body)
|
|
410
428
|
except Exception as exc: # network/build path must never break the hook
|
|
@@ -18,17 +18,17 @@ apps/api/src/zeno_api/auth.py).
|
|
|
18
18
|
|
|
19
19
|
The security control on the callback today is the CSRF `state` token (browser +
|
|
20
20
|
loopback, state-CSRF) - NOT PKCE. The bridge returns the token directly in the
|
|
21
|
-
redirect; there is no authorization-code-for-token
|
|
22
|
-
would be unused theater.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Clerk `zeno-api` JWT template
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
redirect to the localhost loopback; there is no authorization-code-for-token
|
|
22
|
+
exchange, so a PKCE verifier would be unused theater. FOLLOW-UP (hardening): a
|
|
23
|
+
real OAuth code-for-token exchange (PKCE S256: send a code_challenge, receive a
|
|
24
|
+
short-lived auth code on the callback, then POST code + code_verifier to the
|
|
25
|
+
bridge to redeem the JWT) instead of receiving the token in the URL.
|
|
26
|
+
|
|
27
|
+
LIVE: the dashboard `/cli/authorize` bridge page (apps/cognition-dashboard) and
|
|
28
|
+
the Clerk `zeno-api` JWT template both exist; `DEFAULT_AUTHORIZE_URL` points at
|
|
29
|
+
the deployed bridge. The module stays fully unit-testable because `authorize_url`
|
|
30
|
+
is injectable (env `ZENO_LOGIN_AUTHORIZE_URL`, flag `--authorize-url`) and the
|
|
31
|
+
loopback leg is driven by a fake "browser" in tests.
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
from __future__ import annotations
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|