cc-transcript 10.7.0__tar.gz → 10.8.0__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.
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/PKG-INFO +1 -1
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/discovery.py +20 -1
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/judge/verdicts.py +12 -2
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/pyproject.toml +1 -1
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/Cargo.lock +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/Cargo.toml +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/LICENSE +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/README.md +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/__init__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/__main__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/_parser_rs.pyi +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/activity.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/activity_probe.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/backend.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/builders.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/cli.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/command.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/context.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/corrections.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/corrections_cli.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/cost.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/decisions.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/disktruth.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/evidence.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/extract/__init__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/extract/correct.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/facts.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/filterspec.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/ids.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/judge/__init__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/judge/llm.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/judge/similar.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/ledger.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/__init__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/candidates.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/confidence.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/engine.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/filterspec.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/formats.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/signals.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/sourcekind.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/spec.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/mining/store.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/models.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/notifications.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/parser.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/py.typed +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/query.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/render.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/rust.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/sentiment/__init__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/sentiment/buckets.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/sentiment/engine.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/sentiment/lexicon.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/sentiment/scorespec.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/store.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/cc_transcript/tools.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/Cargo.toml +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/build.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/data/afinn-en-165.tsv +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/data/domain_overrides.tsv +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/activity.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/command.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/event.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/filter.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/generated/command.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/generated/mining.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/generated/mod.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/generated/protocol.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/lexicon.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/lib.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/mining.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/model.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/parse.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/protocol.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/python.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/score.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/types.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-10.8.0}/rust/src/value.rs +0 -0
|
@@ -14,6 +14,15 @@ if TYPE_CHECKING:
|
|
|
14
14
|
|
|
15
15
|
CLAUDE_PROJECTS_DIR = Path.home() / ".claude" / "projects"
|
|
16
16
|
|
|
17
|
+
TRANSCRIPT_MEMO: dict[tuple[SessionId, Path], Path] = {}
|
|
18
|
+
"""Positive-hit memo for :func:`find_transcript_sync`, keyed by ``(session_id, resolved root)``.
|
|
19
|
+
|
|
20
|
+
Only successful lookups are cached: a miss may become a hit once Claude Code
|
|
21
|
+
writes the file, so ``None`` is never stored. A cached hit is revalidated with
|
|
22
|
+
``Path.exists`` before it is reused — a transcript file can be pruned from disk —
|
|
23
|
+
and a stale entry falls through to a fresh scan.
|
|
24
|
+
"""
|
|
25
|
+
|
|
17
26
|
|
|
18
27
|
class TranscriptExpiredError(RuntimeError):
|
|
19
28
|
"""A session's transcript file is gone from disk.
|
|
@@ -106,10 +115,18 @@ def find_transcript_sync(session_id: SessionId, *, root: Path | None = None) ->
|
|
|
106
115
|
:data:`CLAUDE_PROJECTS_DIR`), resolving symlinks — cc-pool gives one
|
|
107
116
|
transcript several path spellings — and deduping by resolved real path.
|
|
108
117
|
|
|
118
|
+
A successful lookup is memoized in ``TRANSCRIPT_MEMO`` under
|
|
119
|
+
``(session_id, resolved root)`` and revalidated on the next hit, so a
|
|
120
|
+
repeated probe skips the recursive glob while a pruned transcript still
|
|
121
|
+
forces a fresh scan.
|
|
122
|
+
|
|
109
123
|
Returns:
|
|
110
124
|
The newest-mtime real path, or None when no transcript exists.
|
|
111
125
|
"""
|
|
112
126
|
base = root or CLAUDE_PROJECTS_DIR
|
|
127
|
+
key = (session_id, base.resolve())
|
|
128
|
+
if (cached := TRANSCRIPT_MEMO.get(key)) is not None and cached.exists():
|
|
129
|
+
return cached
|
|
113
130
|
if not base.exists():
|
|
114
131
|
return None
|
|
115
132
|
candidates: dict[Path, float] = {}
|
|
@@ -120,7 +137,9 @@ def find_transcript_sync(session_id: SessionId, *, root: Path | None = None) ->
|
|
|
120
137
|
candidates[real] = real.stat().st_mtime
|
|
121
138
|
except OSError:
|
|
122
139
|
continue
|
|
123
|
-
|
|
140
|
+
if (hit := max(candidates, key=candidates.__getitem__, default=None)) is not None:
|
|
141
|
+
TRANSCRIPT_MEMO[key] = hit
|
|
142
|
+
return hit
|
|
124
143
|
|
|
125
144
|
|
|
126
145
|
async def find_transcript(session_id: SessionId, *, root: Path | None = None) -> Path | None:
|
|
@@ -282,6 +282,7 @@ class VerdictStoreMixin:
|
|
|
282
282
|
prompt_version: int,
|
|
283
283
|
limit: int | None = None,
|
|
284
284
|
refresh_summary: bool = False,
|
|
285
|
+
probe_hydration: bool = True,
|
|
285
286
|
) -> list[dict[str, object]]:
|
|
286
287
|
"""Returns events lacking a verdict for ``(role, prompt_version)``, unjudged first.
|
|
287
288
|
|
|
@@ -298,7 +299,15 @@ class VerdictStoreMixin:
|
|
|
298
299
|
full fidelity once their windows hydrate again. A summary row
|
|
299
300
|
whose context window no longer hydrates — its transcript expired
|
|
300
301
|
or a ref was compacted away — is dropped, so a dead transcript
|
|
301
|
-
stops burning the cap.
|
|
302
|
+
stops burning the cap (unless ``probe_hydration`` is False).
|
|
303
|
+
probe_hydration: When True (default), each summary-refresh row is
|
|
304
|
+
probed with a transcript-discovery hydration check and dropped
|
|
305
|
+
when its window no longer hydrates. When False, that per-row
|
|
306
|
+
probe — and the recursive transcript scan behind it — is skipped
|
|
307
|
+
entirely: every summary-refresh row is returned unprobed, so some
|
|
308
|
+
may name a transcript that is no longer discoverable. Only the
|
|
309
|
+
``refresh_summary`` path probes, so this flag is a no-op
|
|
310
|
+
otherwise. The default preserves the probing behavior exactly.
|
|
302
311
|
|
|
303
312
|
Returns:
|
|
304
313
|
One dict per event with the columns needed to build its prompt.
|
|
@@ -327,7 +336,8 @@ class VerdictStoreMixin:
|
|
|
327
336
|
) as cur:
|
|
328
337
|
async for raw in cur:
|
|
329
338
|
row = dict(raw)
|
|
330
|
-
|
|
339
|
+
fresh = row.pop("verdict_id") is None
|
|
340
|
+
if not probe_hydration or fresh or await hydratable(str(row["context_json"])):
|
|
331
341
|
kept.append(row)
|
|
332
342
|
if limit is not None and len(kept) >= limit:
|
|
333
343
|
break
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|