zeno-cli 0.3.6__tar.gz → 0.3.7__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.
Files changed (72) hide show
  1. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/PKG-INFO +1 -1
  2. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/pyproject.toml +1 -1
  3. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/_hooks/cc_bridge.py +21 -10
  4. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/.gitignore +0 -0
  5. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/README.md +0 -0
  6. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_adapters/__init__.py +0 -0
  7. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_adapters/_common.py +0 -0
  8. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_adapters/anthropic.py +0 -0
  9. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_adapters/claude_code.py +0 -0
  10. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_adapters/crewai.py +0 -0
  11. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_adapters/langgraph.py +0 -0
  12. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_adapters/openai.py +0 -0
  13. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_core/__init__.py +0 -0
  14. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_core/analytics.py +0 -0
  15. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_core/rtlx_s.py +0 -0
  16. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_core/streak.py +0 -0
  17. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_core/tlx_s.py +0 -0
  18. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/__init__.py +0 -0
  19. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_generated/__init__.py +0 -0
  20. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_generated/client.py +0 -0
  21. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_migrations/alembic/env.py +0 -0
  22. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_migrations/alembic/script.py.mako +0 -0
  23. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_migrations/alembic/versions/0001_initial.py +0 -0
  24. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_migrations/alembic/versions/0002_cognition_samples.py +0 -0
  25. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_migrations/alembic/versions/0003_cognition_drivers.py +0 -0
  26. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_migrations/alembic/versions/0004_transcript_intelligence.py +0 -0
  27. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_migrations/alembic.ini +0 -0
  28. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/_runtime.py +0 -0
  29. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/adapters/__init__.py +0 -0
  30. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/adapters/anthropic.py +0 -0
  31. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/adapters/claude_code.py +0 -0
  32. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/adapters/crewai.py +0 -0
  33. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/adapters/langgraph.py +0 -0
  34. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/adapters/openai.py +0 -0
  35. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/auth.py +0 -0
  36. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/client.py +0 -0
  37. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/config.py +0 -0
  38. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/daemon.py +0 -0
  39. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/privacy.py +0 -0
  40. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/session.py +0 -0
  41. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/storage.py +0 -0
  42. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_sdk/types/__init__.py +0 -0
  43. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/__init__.py +0 -0
  44. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/analytics.py +0 -0
  45. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/compression.py +0 -0
  46. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/ingest.py +0 -0
  47. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/model.py +0 -0
  48. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/parsers/__init__.py +0 -0
  49. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/parsers/claude_code.py +0 -0
  50. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/parsers/codex.py +0 -0
  51. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/parsers/cursor.py +0 -0
  52. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/prices.py +0 -0
  53. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/schema.py +0 -0
  54. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/signals.py +0 -0
  55. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/_vendor_build/zeno_session_intel/taxonomy.py +0 -0
  56. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/data/outreach_suppression.txt +0 -0
  57. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/hatch_build.py +0 -0
  58. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/scripts/install-smoke.sh +0 -0
  59. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/__init__.py +0 -0
  60. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/doctor.py +0 -0
  61. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/hook_install.py +0 -0
  62. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/hud/__init__.py +0 -0
  63. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/hud/hud_install.py +0 -0
  64. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/hud/zeno_attention.py +0 -0
  65. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/hud/zeno_cognition.py +0 -0
  66. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/hud/zeno_hud.py +0 -0
  67. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/interview_invites.py +0 -0
  68. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/login.py +0 -0
  69. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/main.py +0 -0
  70. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/onboard.py +0 -0
  71. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/outreach.py +0 -0
  72. {zeno_cli-0.3.6 → zeno_cli-0.3.7}/src/zeno_cli/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zeno-cli
3
- Version: 0.3.6
3
+ Version: 0.3.7
4
4
  Summary: Zeno CLI - measure the supervision cost of AI-assisted work
5
5
  Project-URL: Homepage, https://zeno.center
6
6
  Project-URL: Repository, https://github.com/Marwan01/zeno
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zeno-cli"
3
- version = "0.3.6"
3
+ version = "0.3.7"
4
4
  description = "Zeno CLI - measure the supervision cost of AI-assisted work"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -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 (matches the SDK client's ZENO_API_TOKEN
201
- precedence), then the keyring slot `zeno login` writes (service "zeno-sdk",
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,14 @@ def _idempotency_key(body: dict) -> str:
279
279
  return f"{body['device_id']}:{body['session_id']}:{entity}"
280
280
 
281
281
 
282
- def _post_ingest(body: dict, timeout_s: float) -> bool:
282
+ def _post_ingest(body: dict, timeout_s: float, token: str | None = None) -> bool:
283
283
  """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."""
284
+ raises (all exceptions -> False). urllib + an explicit socket timeout only.
285
+
286
+ ``token`` is the pre-resolved bearer (see _maybe_push); pass it so a drain of
287
+ many spooled lines does not re-read the OS keyring per line. When omitted
288
+ (direct callers/tests) it is resolved once here.
289
+ """
285
290
  url = _api_base_url() + SYNC_PATH
286
291
  data = json.dumps(body).encode("utf-8")
287
292
  headers = {
@@ -291,7 +296,8 @@ def _post_ingest(body: dict, timeout_s: float) -> bool:
291
296
  # Attach the Clerk bearer token when one is available so the push authenticates
292
297
  # against a public API (Cloud Run). Absent it (tailnet Mini), the push relies on
293
298
  # the identity header the `tailscale serve` proxy injects - unchanged behavior.
294
- token = _api_token()
299
+ if token is None:
300
+ token = _api_token()
295
301
  if token:
296
302
  headers["Authorization"] = "Bearer " + token
297
303
  req = urllib.request.Request(
@@ -342,10 +348,11 @@ def _trim_outbox(path: Path) -> None:
342
348
  _debug(f"trim_outbox failed: {exc}")
343
349
 
344
350
 
345
- def _drain_outbox(timeout_s: float) -> None:
351
+ def _drain_outbox(timeout_s: float, token: str | None = None) -> None:
346
352
  """After a live push, best-effort + time-boxed drain of a few spooled lines.
347
353
  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."""
354
+ (so an offline window doesn't re-spin). Rewrites the outbox with the remainder.
355
+ ``token`` is threaded to _post_ingest so the keyring is read once per drain."""
349
356
  path = _outbox_path()
350
357
  try:
351
358
  if not path.exists():
@@ -367,7 +374,7 @@ def _drain_outbox(timeout_s: float) -> None:
367
374
  except Exception:
368
375
  consumed += 1 # unparseable - drop it, keep draining
369
376
  continue
370
- if not _post_ingest(body, timeout_s):
377
+ if not _post_ingest(body, timeout_s, token):
371
378
  break # stop on first failure; leave this line + the rest spooled
372
379
  consumed += 1
373
380
  if consumed == 0:
@@ -403,8 +410,12 @@ def _maybe_push(event: str, payload: dict) -> None:
403
410
  if body is None:
404
411
  return
405
412
  timeout_s = _sync_timeout_s()
406
- if _post_ingest(body, timeout_s):
407
- _drain_outbox(timeout_s)
413
+ # Resolve the bearer ONCE per hook invocation (an OS keyring read is not
414
+ # bounded by the socket timeout); thread it through the drain so a
415
+ # multi-line drain never re-reads the keyring on the hot Stop path.
416
+ token = _api_token()
417
+ if _post_ingest(body, timeout_s, token):
418
+ _drain_outbox(timeout_s, token)
408
419
  else:
409
420
  _spool(body)
410
421
  except Exception as exc: # network/build path must never break the hook
File without changes
File without changes
File without changes
File without changes
File without changes