cc-transcript 14.16.0__tar.gz → 14.17.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-14.16.0 → cc_transcript-14.17.0}/PKG-INFO +1 -1
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/__init__.py +1 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/__init__.pyi +2 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/query.py +276 -53
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/pyproject.toml +1 -1
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/Cargo.lock +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/Cargo.toml +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/LICENSE +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/README.md +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/_native.pyi +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/activity.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/activity_probe.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/builders.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/codex.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/command.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/context.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/corrections.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/cost.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/decision_store.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/decisions.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/discovery.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/disktruth.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/evidence.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/extract/__init__.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/extract/correct.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/facts.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/filterspec.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/heartbeats.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/ids.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/judge/__init__.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/judge/llm.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/judge/similar.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/judge/verdicts.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/ledger.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/literals.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/__init__.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/candidates.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/confidence.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/engine.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/formats.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/sampling.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/signals.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/sourcekind.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/spec.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/mining/store.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/models.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/nlp.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/notifications.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/parser.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/py.typed +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/render.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/__init__.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/buckets.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/data/afinn-en-165.tsv +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/data/domain_overrides.tsv +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/data/en-ewt.udpipe +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/engine.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/lexicon.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/scorespec.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/synthetic.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/tools.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/watch.py +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/Cargo.toml +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/blame.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/corrections.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/digest.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/facts.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/grep.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/list.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/mod.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/scratchpad.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/show.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/slice.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/stats.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/commands/watch.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/lib.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/main.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/output.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/target.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/cli/src/timearg.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/Cargo.toml +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/benches/parse.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/benches/render.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/benches/toolcall.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/activity.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/actor.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/blame.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/buckets.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/codex/discovery.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/codex/lower.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/codex/mod.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/codex/parse.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/codex/probe.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/codex/protocol.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/codex/types.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/command.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/context.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/corrections.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/cost.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/discovery.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/facts.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/feedback.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/filter.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/gateway.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/ids.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/judge.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/lib.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/literals/command.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/literals/corrections.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/literals/feedback.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/literals/mining.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/literals/mod.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/literals/protocol.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/notifications.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/parse.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/protocol.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/pystr.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/query.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/render.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/rng.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/schema.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/sqlite.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/toolcall.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/types.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/value.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/watch.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/Cargo.toml +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/build.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/data/command_prefix_pins.tsv +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/actor_bridge.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/bin/stub_gen.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/codex.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/command.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/context.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/corrections.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/discovery.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/feedback.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/judge.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/lexicon.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/lib.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/mining.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/nlp.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/python.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/render.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/score.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/sqlite.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/toolcall.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/attachment.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/blocks.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/command.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/convert.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/dunder.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/events.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/meta.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/mod.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/print.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/store.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/system.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/toolcall.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/toolresult.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/views/transcript.rs +0 -0
- {cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/py/src/watch.rs +0 -0
|
@@ -207,6 +207,7 @@ from cc_transcript.query import (
|
|
|
207
207
|
DeepSession as DeepSession,
|
|
208
208
|
DeepView as DeepView,
|
|
209
209
|
FileRef as FileRef,
|
|
210
|
+
PredicateInputs as PredicateInputs,
|
|
210
211
|
Session as Session,
|
|
211
212
|
SubagentIndex as SubagentIndex,
|
|
212
213
|
SubagentSession as SubagentSession,
|
|
@@ -390,6 +391,7 @@ __all__ = [
|
|
|
390
391
|
"PRICING",
|
|
391
392
|
"PatchEdit",
|
|
392
393
|
"Plugin",
|
|
394
|
+
"PredicateInputs",
|
|
393
395
|
"PreservedMessages",
|
|
394
396
|
"PreservedSegment",
|
|
395
397
|
"PrintMessage",
|
|
@@ -12,8 +12,9 @@ from __future__ import annotations
|
|
|
12
12
|
|
|
13
13
|
import re
|
|
14
14
|
import threading
|
|
15
|
+
from collections import OrderedDict
|
|
15
16
|
from collections.abc import Mapping
|
|
16
|
-
from dataclasses import dataclass
|
|
17
|
+
from dataclasses import dataclass, field
|
|
17
18
|
from fnmatch import fnmatch
|
|
18
19
|
from functools import cached_property
|
|
19
20
|
from pathlib import PurePath
|
|
@@ -47,29 +48,117 @@ if TYPE_CHECKING:
|
|
|
47
48
|
from cc_transcript.models import TranscriptEvent
|
|
48
49
|
|
|
49
50
|
|
|
50
|
-
DEEP_LIFT_BUDGET =
|
|
51
|
+
DEEP_LIFT_BUDGET = 1024 * 1024 * 1024
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
type LiftStamp = tuple[int, int, int]
|
|
54
|
+
type LiftKey = tuple[Path, int, ToolUseId | None]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(slots=True)
|
|
58
|
+
class LiftCache:
|
|
59
|
+
held: OrderedDict[LiftKey, tuple[LiftStamp, DeepSession]] = field(default_factory=OrderedDict)
|
|
60
|
+
size: int = 0
|
|
61
|
+
guard: threading.Lock = field(default_factory=threading.Lock)
|
|
62
|
+
|
|
63
|
+
def get(self, key: LiftKey, stamp: LiftStamp) -> DeepSession | None:
|
|
64
|
+
with self.guard:
|
|
65
|
+
match self.held.get(key):
|
|
66
|
+
case None:
|
|
67
|
+
return None
|
|
68
|
+
case (held_stamp, deep) if held_stamp == stamp:
|
|
69
|
+
self.held.move_to_end(key)
|
|
70
|
+
return deep
|
|
71
|
+
case _:
|
|
72
|
+
self.drop(key)
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
def put(self, key: LiftKey, stamp: LiftStamp, deep: DeepSession) -> DeepSession:
|
|
76
|
+
with self.guard:
|
|
77
|
+
self.drop(key)
|
|
78
|
+
self.held[key] = (stamp, deep)
|
|
79
|
+
self.size += stamp[0]
|
|
80
|
+
while self.size > DEEP_LIFT_BUDGET:
|
|
81
|
+
self.drop(next(iter(self.held)))
|
|
82
|
+
return deep
|
|
83
|
+
|
|
84
|
+
def drop(self, key: LiftKey) -> None:
|
|
85
|
+
if (held := self.held.pop(key, None)) is not None:
|
|
86
|
+
self.size -= held[0][0]
|
|
87
|
+
|
|
88
|
+
def clear(self) -> None:
|
|
89
|
+
with self.guard:
|
|
90
|
+
self.held.clear()
|
|
91
|
+
self.size = 0
|
|
92
|
+
|
|
93
|
+
def __len__(self) -> int:
|
|
94
|
+
return len(self.held)
|
|
54
95
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
96
|
+
|
|
97
|
+
DEEP_LIFTS = LiftCache()
|
|
98
|
+
"""Lifted sidechain transcripts, keyed by tree position and stamped with the file's ``(size, mtime_ns, inode)``.
|
|
99
|
+
|
|
100
|
+
A least-recently-used hold bounded at :data:`DEEP_LIFT_BUDGET` source bytes. One resident
|
|
101
|
+
process serves many lead sessions, so the tree walked most recently stays held while an
|
|
102
|
+
idle lead's sidechains age out; a changed stamp drops the stale lift and releases its
|
|
103
|
+
bytes. A lifted session costs about 2.3 times its source bytes in resident memory, so the
|
|
104
|
+
default holds roughly 2.3 GiB. A single tree larger than the budget reparses the part that
|
|
105
|
+
no longer fits on every walk.
|
|
60
106
|
"""
|
|
61
107
|
|
|
62
|
-
DEEP_LIFT_GUARD = threading.Lock()
|
|
63
108
|
|
|
64
|
-
|
|
65
|
-
|
|
109
|
+
SIDECHAIN_INPUTS_LIMIT = 16384
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass(slots=True)
|
|
113
|
+
class PredicateInputsCache:
|
|
114
|
+
held: OrderedDict[Path, tuple[LiftStamp, PredicateInputs]] = field(default_factory=OrderedDict)
|
|
115
|
+
guard: threading.Lock = field(default_factory=threading.Lock)
|
|
116
|
+
|
|
117
|
+
def get(self, path: Path, stamp: LiftStamp) -> PredicateInputs | None:
|
|
118
|
+
with self.guard:
|
|
119
|
+
match self.held.get(path):
|
|
120
|
+
case (held_stamp, inputs) if held_stamp == stamp:
|
|
121
|
+
self.held.move_to_end(path)
|
|
122
|
+
return inputs
|
|
123
|
+
case _:
|
|
124
|
+
return None
|
|
125
|
+
|
|
126
|
+
def put(self, path: Path, stamp: LiftStamp, inputs: PredicateInputs) -> PredicateInputs:
|
|
127
|
+
with self.guard:
|
|
128
|
+
self.held[path] = (stamp, inputs)
|
|
129
|
+
self.held.move_to_end(path)
|
|
130
|
+
while len(self.held) > SIDECHAIN_INPUTS_LIMIT:
|
|
131
|
+
self.held.popitem(last=False)
|
|
132
|
+
return inputs
|
|
133
|
+
|
|
134
|
+
def clear(self) -> None:
|
|
135
|
+
with self.guard:
|
|
136
|
+
self.held.clear()
|
|
137
|
+
|
|
138
|
+
def __len__(self) -> int:
|
|
139
|
+
return len(self.held)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
SIDECHAIN_INPUTS = PredicateInputsCache()
|
|
143
|
+
"""Each sidechain's :class:`PredicateInputs`, keyed by path and stamped like :data:`DEEP_LIFTS`.
|
|
144
|
+
|
|
145
|
+
A lifted session costs about 2.3 times its source bytes, so a tree of a thousand sidechains
|
|
146
|
+
cannot stay lifted; its :class:`PredicateInputs` are a few kilobytes each. A predicate lifts a
|
|
147
|
+
sidechain only when its stamp moved, keeps those inputs, and lets the lift go, so a resident
|
|
148
|
+
process re-answering the same predicates per event neither reparses nor holds the tree.
|
|
149
|
+
"""
|
|
66
150
|
|
|
67
151
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
152
|
+
SIDECHAIN_LISTINGS: OrderedDict[Path, tuple[tuple[int, int], tuple[tuple[Path, bool], ...]]] = OrderedDict()
|
|
153
|
+
"""Each non-empty ``subagents`` listing and whether each file is a symlink, stamped ``(inode, mtime_ns)``.
|
|
154
|
+
|
|
155
|
+
Adding, removing, renaming, or replacing a sidechain moves the directory's mtime, so an unchanged
|
|
156
|
+
stamp proves the listing current. A walk then skips the directory read and resolves the directory
|
|
157
|
+
once rather than every file; only a symlinked sidechain is resolved on every walk. An empty listing
|
|
158
|
+
is never held, since the native lister reports an unreadable directory as empty.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
SIDECHAIN_LISTINGS_GUARD = threading.Lock()
|
|
73
162
|
|
|
74
163
|
|
|
75
164
|
def is_failure(use: ToolUse) -> bool:
|
|
@@ -222,8 +311,12 @@ class ToolCallQuery:
|
|
|
222
311
|
callable predicate, or a value compared for equality.
|
|
223
312
|
"""
|
|
224
313
|
return self.where(
|
|
225
|
-
lambda use:
|
|
226
|
-
|
|
314
|
+
lambda use: (
|
|
315
|
+
isinstance(use.call.raw, Mapping)
|
|
316
|
+
and all(
|
|
317
|
+
key in use.call.raw and input_rule_matches(rule, use.call.raw[key]) for key, rule in rules.items()
|
|
318
|
+
)
|
|
319
|
+
)
|
|
227
320
|
)
|
|
228
321
|
|
|
229
322
|
def count(self) -> int:
|
|
@@ -454,9 +547,7 @@ class Session:
|
|
|
454
547
|
|
|
455
548
|
def has_tool(self, name: str, *, subagents: bool = True) -> bool:
|
|
456
549
|
"""Whether any call in the window matches the pipe spec ``name``."""
|
|
457
|
-
return self.
|
|
458
|
-
subagents and any(deep.session.has_tool(name, subagents=False) for deep in self.walk())
|
|
459
|
-
)
|
|
550
|
+
return any_inputs(self, lambda inputs: inputs.has_tool(name), subagents=subagents)
|
|
460
551
|
|
|
461
552
|
def has_command(self, *argv: str, subagents: bool = True) -> bool:
|
|
462
553
|
"""Whether any Bash command in the window runs ``argv``.
|
|
@@ -465,28 +556,36 @@ class Session:
|
|
|
465
556
|
unwrapped argv, so ``has_command("git", "push")`` matches
|
|
466
557
|
``sudo git push -f`` and ``cd x && git push`` but not ``echo "git push"``.
|
|
467
558
|
"""
|
|
468
|
-
return
|
|
469
|
-
subagents and any(deep.session.has_command(*argv, subagents=False) for deep in self.walk())
|
|
470
|
-
)
|
|
559
|
+
return any_inputs(self, lambda inputs: inputs.has_command(argv), subagents=subagents)
|
|
471
560
|
|
|
472
561
|
def has_edit_to(self, *globs: str, subagents: bool = True) -> bool:
|
|
473
562
|
"""Whether any edit-shaped call in the window targets a file matching any glob."""
|
|
474
|
-
return
|
|
475
|
-
subagents and any(deep.session.has_edit_to(*globs, subagents=False) for deep in self.walk())
|
|
476
|
-
)
|
|
563
|
+
return any_inputs(self, lambda inputs: inputs.has_edit_to(globs), subagents=subagents)
|
|
477
564
|
|
|
478
565
|
def has_read(self, pattern: str, *, subagents: bool = True) -> bool:
|
|
479
566
|
"""Whether any Read in the window targets a path containing ``pattern``."""
|
|
480
|
-
return
|
|
481
|
-
subagents and any(deep.session.has_read(pattern, subagents=False) for deep in self.walk())
|
|
482
|
-
)
|
|
567
|
+
return any_inputs(self, lambda inputs: inputs.has_read(pattern), subagents=subagents)
|
|
483
568
|
|
|
484
569
|
def has_skill(self, *names: str, subagents: bool = True) -> bool:
|
|
485
570
|
"""Whether any Skill invocation in the window names one of ``names``."""
|
|
486
|
-
return
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
571
|
+
return any_inputs(self, lambda inputs: inputs.has_skill(names), subagents=subagents)
|
|
572
|
+
|
|
573
|
+
@cached_property
|
|
574
|
+
def predicate_inputs(self) -> PredicateInputs:
|
|
575
|
+
"""What the ``has_*`` predicates read from this window."""
|
|
576
|
+
return PredicateInputs.of(self)
|
|
577
|
+
|
|
578
|
+
def deep_inputs(self) -> Iterator[PredicateInputs]:
|
|
579
|
+
"""This window's :class:`PredicateInputs`, then those of every transcript :meth:`walk` reaches.
|
|
580
|
+
|
|
581
|
+
The walk order and dedupe match :meth:`walk`, but no reached transcript stays lifted: each
|
|
582
|
+
one's inputs are held per ``(size, mtime, inode)`` stamp, and a transcript is reparsed only
|
|
583
|
+
once its stamp moves. Prefer it to :meth:`walk` for any predicate these inputs can answer.
|
|
584
|
+
"""
|
|
585
|
+
yield self.predicate_inputs
|
|
586
|
+
for path, depth, spawned_by in reachable_transcripts(self):
|
|
587
|
+
if (inputs := load_predicate_inputs(path, depth, spawned_by)) is not None:
|
|
588
|
+
yield inputs
|
|
490
589
|
|
|
491
590
|
def has_override(self, token: str, *, invalidated_by: Sequence[str] = ("Edit", "Write")) -> bool:
|
|
492
591
|
"""Whether ``token`` appears in the window without a later invalidating call.
|
|
@@ -536,9 +635,7 @@ class Session:
|
|
|
536
635
|
|
|
537
636
|
@cached_property
|
|
538
637
|
def _command_lines(self) -> tuple[CommandLine, ...]:
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
return tuple(parse_command_line(command) for command in self._commands)
|
|
638
|
+
return self.predicate_inputs.command_lines
|
|
542
639
|
|
|
543
640
|
def __len__(self) -> int:
|
|
544
641
|
return sum(len(turn.events) for turn in self.turns)
|
|
@@ -619,6 +716,83 @@ class DeepSession:
|
|
|
619
716
|
spawned_by: ToolUseId | None
|
|
620
717
|
|
|
621
718
|
|
|
719
|
+
@dataclass(frozen=True) # non-slots: the cached_property below needs __dict__
|
|
720
|
+
class PredicateInputs:
|
|
721
|
+
"""The slice of one transcript window that the ``has_*`` predicates read.
|
|
722
|
+
|
|
723
|
+
Small enough to hold for every transcript in a tree of thousands, where a lifted
|
|
724
|
+
:class:`Session` is not. Calls whose result errored are left out, as
|
|
725
|
+
:class:`ToolCallQuery` hides them by default. Answers that do not depend on the MCP
|
|
726
|
+
tool registry are memoized, up to :attr:`MAX_ANSWERS` per instance.
|
|
727
|
+
|
|
728
|
+
Attributes:
|
|
729
|
+
calls: Each call's tool name and the file paths it targets, in order.
|
|
730
|
+
commands: The command string of every Bash call.
|
|
731
|
+
edited_files: The files modified by edit-shaped calls, one entry per edited file.
|
|
732
|
+
skills: The skill named by every Skill call.
|
|
733
|
+
"""
|
|
734
|
+
|
|
735
|
+
calls: tuple[tuple[str, tuple[str, ...]], ...]
|
|
736
|
+
commands: tuple[str, ...]
|
|
737
|
+
edited_files: tuple[FileRef, ...]
|
|
738
|
+
skills: tuple[str, ...]
|
|
739
|
+
answers: dict[tuple[str, object], bool] = field(default_factory=dict, compare=False, repr=False)
|
|
740
|
+
|
|
741
|
+
MAX_ANSWERS: ClassVar[int] = 256
|
|
742
|
+
|
|
743
|
+
@classmethod
|
|
744
|
+
def of(cls, session: Session) -> PredicateInputs:
|
|
745
|
+
"""Extracts the predicate inputs from ``session``'s window."""
|
|
746
|
+
calls = session.tool_calls
|
|
747
|
+
return cls(
|
|
748
|
+
calls=tuple((use.call.name, tuple(file_paths_of(use.call))) for use in calls.items),
|
|
749
|
+
commands=session.commands(),
|
|
750
|
+
edited_files=session.edited_files,
|
|
751
|
+
skills=tuple(call.skill for use in calls.named("Skill") if isinstance(call := use.call, SkillCall)),
|
|
752
|
+
)
|
|
753
|
+
|
|
754
|
+
@cached_property
|
|
755
|
+
def command_lines(self) -> tuple[CommandLine, ...]:
|
|
756
|
+
""":attr:`commands` parsed into :class:`~cc_transcript.command.CommandLine` objects."""
|
|
757
|
+
from cc_transcript.command import parse_command_line
|
|
758
|
+
|
|
759
|
+
return tuple(parse_command_line(command) for command in self.commands)
|
|
760
|
+
|
|
761
|
+
@cached_property
|
|
762
|
+
def tool_names(self) -> frozenset[str]:
|
|
763
|
+
"""The distinct names in :attr:`calls`."""
|
|
764
|
+
return frozenset(name for name, _ in self.calls)
|
|
765
|
+
|
|
766
|
+
def files(self, spec: str) -> tuple[FileRef, ...]:
|
|
767
|
+
"""The files targeted by calls matching the pipe spec ``spec``, one entry per path."""
|
|
768
|
+
matching = {name for name in self.tool_names if tool_name_matches(name, spec)}
|
|
769
|
+
return tuple(FileRef(path) for name, paths in self.calls if name in matching for path in paths)
|
|
770
|
+
|
|
771
|
+
def answer(self, query: tuple[str, object], compute: Callable[[], bool]) -> bool:
|
|
772
|
+
if (known := self.answers.get(query)) is None:
|
|
773
|
+
if len(self.answers) >= self.MAX_ANSWERS:
|
|
774
|
+
self.answers.clear()
|
|
775
|
+
known = self.answers[query] = compute()
|
|
776
|
+
return known
|
|
777
|
+
|
|
778
|
+
def has_tool(self, name: str) -> bool:
|
|
779
|
+
return any(tool_name_matches(tool, name) for tool in self.tool_names)
|
|
780
|
+
|
|
781
|
+
def has_command(self, argv: tuple[str, ...]) -> bool:
|
|
782
|
+
return self.answer(
|
|
783
|
+
("command", argv), lambda: any(cmd.runs(*argv) for line in self.command_lines for cmd in line)
|
|
784
|
+
)
|
|
785
|
+
|
|
786
|
+
def has_edit_to(self, globs: tuple[str, ...]) -> bool:
|
|
787
|
+
return self.answer(("edit", globs), lambda: any(file.matches(*globs) for file in self.edited_files))
|
|
788
|
+
|
|
789
|
+
def has_read(self, pattern: str) -> bool:
|
|
790
|
+
return any(pattern in str(file) for file in self.files("Read"))
|
|
791
|
+
|
|
792
|
+
def has_skill(self, names: tuple[str, ...]) -> bool:
|
|
793
|
+
return self.answer(("skill", names), lambda: any(skill in names for skill in self.skills))
|
|
794
|
+
|
|
795
|
+
|
|
622
796
|
@dataclass(frozen=True) # non-slots: the cached_property below needs __dict__
|
|
623
797
|
class DeepView:
|
|
624
798
|
"""The recursive union of a session and every transcript reachable from it.
|
|
@@ -680,26 +854,75 @@ def sidechain_sessions(path: Path | None) -> tuple[Session, ...]:
|
|
|
680
854
|
return tuple(Session.from_path(entry) for entry in subagent_paths(path))
|
|
681
855
|
|
|
682
856
|
|
|
683
|
-
def
|
|
857
|
+
def any_inputs(session: Session, predicate: Callable[[PredicateInputs], bool], *, subagents: bool) -> bool:
|
|
858
|
+
return any(map(predicate, session.deep_inputs() if subagents else (session.predicate_inputs,)))
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
def reachable_transcripts(root: Session) -> Iterator[tuple[Path, int, ToolUseId | None]]:
|
|
684
862
|
seen: set[Path] = {root.path.resolve()} if root.path is not None else set()
|
|
685
863
|
if root.path is not None:
|
|
686
|
-
yield from
|
|
864
|
+
yield from reachable_sidechains(root.path, 1, seen)
|
|
687
865
|
for attachment in root.attachments:
|
|
688
|
-
yield from
|
|
866
|
+
yield from reachable_from(attachment, attachment.resolve(), 1, None, seen)
|
|
689
867
|
|
|
690
868
|
|
|
691
|
-
def
|
|
692
|
-
for child in
|
|
693
|
-
yield from
|
|
869
|
+
def reachable_sidechains(parent: Path, depth: int, seen: set[Path]) -> Iterator[tuple[Path, int, ToolUseId | None]]:
|
|
870
|
+
for child, resolved in sidechain_listing(parent):
|
|
871
|
+
yield from reachable_from(child, resolved, depth, ToolUseId(child.stem.removeprefix("agent-")), seen)
|
|
694
872
|
|
|
695
873
|
|
|
696
|
-
def
|
|
697
|
-
|
|
874
|
+
def reachable_from(
|
|
875
|
+
path: Path, resolved: Path, depth: int, spawned_by: ToolUseId | None, seen: set[Path]
|
|
876
|
+
) -> Iterator[tuple[Path, int, ToolUseId | None]]:
|
|
877
|
+
if resolved in seen:
|
|
698
878
|
return
|
|
699
879
|
seen.add(resolved)
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
880
|
+
yield path, depth, spawned_by
|
|
881
|
+
yield from reachable_sidechains(path, depth + 1, seen)
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
def sidechain_listing(parent: Path) -> tuple[tuple[Path, Path], ...]:
|
|
885
|
+
directory = parent.parent / parent.stem / "subagents"
|
|
886
|
+
try:
|
|
887
|
+
stat = directory.stat()
|
|
888
|
+
except OSError:
|
|
889
|
+
return ()
|
|
890
|
+
stamp = (stat.st_ino, stat.st_mtime_ns)
|
|
891
|
+
with SIDECHAIN_LISTINGS_GUARD:
|
|
892
|
+
held = SIDECHAIN_LISTINGS.get(directory)
|
|
893
|
+
if held is not None and held[0] == stamp:
|
|
894
|
+
children = held[1]
|
|
895
|
+
else:
|
|
896
|
+
children = tuple((child, child.is_symlink()) for child in subagent_paths(parent))
|
|
897
|
+
if children:
|
|
898
|
+
with SIDECHAIN_LISTINGS_GUARD:
|
|
899
|
+
SIDECHAIN_LISTINGS[directory] = (stamp, children)
|
|
900
|
+
SIDECHAIN_LISTINGS.move_to_end(directory)
|
|
901
|
+
while len(SIDECHAIN_LISTINGS) > SIDECHAIN_INPUTS_LIMIT:
|
|
902
|
+
SIDECHAIN_LISTINGS.popitem(last=False)
|
|
903
|
+
real = directory.resolve()
|
|
904
|
+
return tuple((child, child.resolve() if link else real / child.name) for child, link in children)
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
def load_predicate_inputs(path: Path, depth: int, spawned_by: ToolUseId | None) -> PredicateInputs | None:
|
|
908
|
+
try:
|
|
909
|
+
stat = path.stat()
|
|
910
|
+
except OSError:
|
|
911
|
+
return None
|
|
912
|
+
stamp = (stat.st_size, stat.st_mtime_ns, stat.st_ino)
|
|
913
|
+
if (held := SIDECHAIN_INPUTS.get(path, stamp)) is not None:
|
|
914
|
+
return held
|
|
915
|
+
try:
|
|
916
|
+
deep = DEEP_LIFTS.get((path, depth, spawned_by), stamp) or lift_deep_session(path, depth, spawned_by)
|
|
917
|
+
except OSError:
|
|
918
|
+
return None
|
|
919
|
+
return SIDECHAIN_INPUTS.put(path, stamp, PredicateInputs.of(deep.session))
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
def deep_sessions(root: Session) -> Iterator[DeepSession]:
|
|
923
|
+
for path, depth, spawned_by in reachable_transcripts(root):
|
|
924
|
+
if (deep := load_deep_session(path, depth, spawned_by)) is not None:
|
|
925
|
+
yield deep
|
|
703
926
|
|
|
704
927
|
|
|
705
928
|
def lift_deep_session(path: Path, depth: int, spawned_by: ToolUseId | None) -> DeepSession:
|
|
@@ -719,11 +942,11 @@ def load_deep_session(path: Path, depth: int, spawned_by: ToolUseId | None) -> D
|
|
|
719
942
|
stat = path.stat()
|
|
720
943
|
except OSError:
|
|
721
944
|
return None
|
|
722
|
-
stamp = (stat.st_size, stat.st_mtime_ns)
|
|
945
|
+
stamp = (stat.st_size, stat.st_mtime_ns, stat.st_ino)
|
|
723
946
|
key = (path, depth, spawned_by)
|
|
724
|
-
if (held := DEEP_LIFTS.get(key)) is not None
|
|
725
|
-
return held
|
|
947
|
+
if (held := DEEP_LIFTS.get(key, stamp)) is not None:
|
|
948
|
+
return held
|
|
726
949
|
try:
|
|
727
|
-
return
|
|
950
|
+
return DEEP_LIFTS.put(key, stamp, lift_deep_session(path, depth, spawned_by))
|
|
728
951
|
except OSError:
|
|
729
952
|
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cc-transcript"
|
|
3
|
-
version = "14.
|
|
3
|
+
version = "14.17.0" # informational — releases stamp the version from the git tag
|
|
4
4
|
description = "Grep every Claude Code session you've ever run."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "PolyForm-Noncommercial-1.0.0"
|
|
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
|
{cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/data/afinn-en-165.tsv
RENAMED
|
File without changes
|
{cc_transcript-14.16.0 → cc_transcript-14.17.0}/cc_transcript/sentiment/data/domain_overrides.tsv
RENAMED
|
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
|
{cc_transcript-14.16.0 → cc_transcript-14.17.0}/rust/crates/core/src/literals/corrections.rs
RENAMED
|
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
|