cc-transcript 14.2.0__tar.gz → 14.5.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.2.0 → cc_transcript-14.5.0}/PKG-INFO +1 -1
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/__init__.py +18 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/__init__.pyi +35 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/_native.pyi +83 -36
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/corrections.py +42 -21
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/decisions.py +24 -17
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/evidence.py +2 -2
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/extract/correct.py +2 -2
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/heartbeats.py +40 -20
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/judge/similar.py +27 -26
- cc_transcript-14.5.0/cc_transcript/ledger.py +163 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/spec.py +23 -8
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/store.py +95 -74
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/parser.py +30 -0
- cc_transcript-14.5.0/cc_transcript/synthetic.py +219 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/tools.py +27 -8
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/watch.py +23 -10
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/pyproject.toml +1 -1
- cc_transcript-14.5.0/rust/crates/core/src/actor.rs +166 -0
- cc_transcript-14.5.0/rust/crates/core/src/codex/lower.rs +1342 -0
- cc_transcript-14.5.0/rust/crates/core/src/codex/mod.rs +12 -0
- cc_transcript-14.5.0/rust/crates/core/src/codex/parse.rs +1270 -0
- cc_transcript-14.5.0/rust/crates/core/src/codex/protocol.rs +129 -0
- cc_transcript-14.5.0/rust/crates/core/src/codex/types.rs +260 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/lib.rs +3 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/toolcall.rs +227 -18
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/types.rs +4 -4
- cc_transcript-14.5.0/rust/crates/py/src/actor_bridge.rs +135 -0
- cc_transcript-14.5.0/rust/crates/py/src/corrections.rs +260 -0
- cc_transcript-14.5.0/rust/crates/py/src/feedback.rs +405 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/lib.rs +1 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/mining.rs +3 -3
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/toolcall.rs +1 -8
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/toolcall.rs +110 -11
- cc_transcript-14.2.0/cc_transcript/ledger.py +0 -94
- cc_transcript-14.2.0/rust/crates/py/src/corrections.rs +0 -200
- cc_transcript-14.2.0/rust/crates/py/src/feedback.rs +0 -321
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/Cargo.lock +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/Cargo.toml +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/LICENSE +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/README.md +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/activity.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/activity_probe.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/builders.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/command.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/context.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/cost.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/discovery.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/disktruth.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/extract/__init__.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/facts.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/filterspec.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/ids.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/judge/__init__.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/judge/llm.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/judge/verdicts.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/literals.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/__init__.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/candidates.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/confidence.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/engine.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/formats.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/sampling.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/signals.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/mining/sourcekind.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/models.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/nlp.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/notifications.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/py.typed +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/query.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/render.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/sentiment/__init__.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/sentiment/buckets.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/sentiment/data/afinn-en-165.tsv +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/sentiment/data/domain_overrides.tsv +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/sentiment/data/en-ewt.udpipe +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/sentiment/engine.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/sentiment/lexicon.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/cc_transcript/sentiment/scorespec.py +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/Cargo.toml +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/corrections.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/digest.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/facts.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/grep.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/list.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/mod.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/scratchpad.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/show.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/slice.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/stats.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/commands/watch.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/lib.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/main.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/output.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/cli/src/target.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/Cargo.toml +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/benches/parse.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/benches/render.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/benches/toolcall.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/activity.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/buckets.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/command.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/context.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/corrections.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/cost.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/discovery.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/facts.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/feedback.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/filter.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/ids.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/literals/command.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/literals/corrections.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/literals/feedback.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/literals/mining.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/literals/mod.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/literals/protocol.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/notifications.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/parse.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/protocol.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/pystr.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/query.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/render.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/sqlite.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/value.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/core/src/watch.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/Cargo.toml +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/build.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/data/command_prefix_pins.tsv +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/bin/stub_gen.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/command.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/context.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/discovery.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/lexicon.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/nlp.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/python.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/render.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/score.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/sqlite.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/attachment.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/blocks.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/command.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/convert.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/dunder.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/events.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/meta.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/mod.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/print.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/store.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/system.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/toolresult.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/views/transcript.rs +0 -0
- {cc_transcript-14.2.0 → cc_transcript-14.5.0}/rust/crates/py/src/watch.rs +0 -0
|
@@ -53,6 +53,7 @@ EXPORTS: dict[str, str] = {
|
|
|
53
53
|
"ReadResult",
|
|
54
54
|
"SkillCall",
|
|
55
55
|
"SkillResult",
|
|
56
|
+
"SpanEditCall",
|
|
56
57
|
"TaskCall",
|
|
57
58
|
"TaskCreateCall",
|
|
58
59
|
"TaskLaunchResult",
|
|
@@ -76,7 +77,9 @@ EXPORTS: dict[str, str] = {
|
|
|
76
77
|
"mcp_parts",
|
|
77
78
|
"parse_tool_call",
|
|
78
79
|
"parse_tool_result",
|
|
80
|
+
"register_mcp_tool",
|
|
79
81
|
"tool_name_matches",
|
|
82
|
+
"unregister_mcp_tool",
|
|
80
83
|
),
|
|
81
84
|
"cc_transcript.command": (
|
|
82
85
|
"Command",
|
|
@@ -142,10 +145,25 @@ EXPORTS: dict[str, str] = {
|
|
|
142
145
|
"cc_transcript.parser": (
|
|
143
146
|
"parse",
|
|
144
147
|
"parse_event",
|
|
148
|
+
"parse_events",
|
|
145
149
|
"parse_events_from_bytes",
|
|
146
150
|
"parse_print_result",
|
|
147
151
|
"stream",
|
|
148
152
|
),
|
|
153
|
+
"cc_transcript.synthetic": (
|
|
154
|
+
"assistant_line",
|
|
155
|
+
"meta_fields",
|
|
156
|
+
"mode_line",
|
|
157
|
+
"other_line",
|
|
158
|
+
"synthetic_assistant_event",
|
|
159
|
+
"synthetic_user_event",
|
|
160
|
+
"system_line",
|
|
161
|
+
"text_block",
|
|
162
|
+
"thinking_block",
|
|
163
|
+
"tool_result",
|
|
164
|
+
"tool_use",
|
|
165
|
+
"user_line",
|
|
166
|
+
),
|
|
149
167
|
"cc_transcript.cost": (
|
|
150
168
|
"PRICING",
|
|
151
169
|
"CostBreakdown",
|
|
@@ -187,6 +187,7 @@ from cc_transcript.notifications import (
|
|
|
187
187
|
from cc_transcript.parser import (
|
|
188
188
|
parse as parse,
|
|
189
189
|
parse_event as parse_event,
|
|
190
|
+
parse_events as parse_events,
|
|
190
191
|
parse_events_from_bytes as parse_events_from_bytes,
|
|
191
192
|
parse_print_result as parse_print_result,
|
|
192
193
|
stream as stream,
|
|
@@ -207,6 +208,21 @@ from cc_transcript.render import (
|
|
|
207
208
|
render_turn as render_turn,
|
|
208
209
|
)
|
|
209
210
|
|
|
211
|
+
from cc_transcript.synthetic import (
|
|
212
|
+
assistant_line as assistant_line,
|
|
213
|
+
meta_fields as meta_fields,
|
|
214
|
+
mode_line as mode_line,
|
|
215
|
+
other_line as other_line,
|
|
216
|
+
synthetic_assistant_event as synthetic_assistant_event,
|
|
217
|
+
synthetic_user_event as synthetic_user_event,
|
|
218
|
+
system_line as system_line,
|
|
219
|
+
text_block as text_block,
|
|
220
|
+
thinking_block as thinking_block,
|
|
221
|
+
tool_result as tool_result,
|
|
222
|
+
tool_use as tool_use,
|
|
223
|
+
user_line as user_line,
|
|
224
|
+
)
|
|
225
|
+
|
|
210
226
|
from cc_transcript.tools import (
|
|
211
227
|
AskUserQuestionResult as AskUserQuestionResult,
|
|
212
228
|
BashCall as BashCall,
|
|
@@ -227,6 +243,7 @@ from cc_transcript.tools import (
|
|
|
227
243
|
ReadResult as ReadResult,
|
|
228
244
|
SkillCall as SkillCall,
|
|
229
245
|
SkillResult as SkillResult,
|
|
246
|
+
SpanEditCall as SpanEditCall,
|
|
230
247
|
TOOL_ALIASES as TOOL_ALIASES,
|
|
231
248
|
TaskCall as TaskCall,
|
|
232
249
|
TaskCreateCall as TaskCreateCall,
|
|
@@ -251,7 +268,9 @@ from cc_transcript.tools import (
|
|
|
251
268
|
mcp_parts as mcp_parts,
|
|
252
269
|
parse_tool_call as parse_tool_call,
|
|
253
270
|
parse_tool_result as parse_tool_result,
|
|
271
|
+
register_mcp_tool as register_mcp_tool,
|
|
254
272
|
tool_name_matches as tool_name_matches,
|
|
273
|
+
unregister_mcp_tool as unregister_mcp_tool,
|
|
255
274
|
)
|
|
256
275
|
|
|
257
276
|
from cc_transcript.watch import (
|
|
@@ -360,6 +379,7 @@ __all__ = [
|
|
|
360
379
|
"SessionId",
|
|
361
380
|
"SkillCall",
|
|
362
381
|
"SkillResult",
|
|
382
|
+
"SpanEditCall",
|
|
363
383
|
"StopHookSummary",
|
|
364
384
|
"SubagentIndex",
|
|
365
385
|
"SubagentSession",
|
|
@@ -406,6 +426,7 @@ __all__ = [
|
|
|
406
426
|
"WriteResult",
|
|
407
427
|
"annotate_spec",
|
|
408
428
|
"apply_spec",
|
|
429
|
+
"assistant_line",
|
|
409
430
|
"build_spec",
|
|
410
431
|
"canonical_json",
|
|
411
432
|
"capture_window",
|
|
@@ -440,15 +461,20 @@ __all__ = [
|
|
|
440
461
|
"mcp_access",
|
|
441
462
|
"mcp_parts",
|
|
442
463
|
"mcp_summary",
|
|
464
|
+
"meta_fields",
|
|
465
|
+
"mode_line",
|
|
443
466
|
"native_user_classifier",
|
|
467
|
+
"other_line",
|
|
444
468
|
"parse",
|
|
445
469
|
"parse_command_line",
|
|
446
470
|
"parse_event",
|
|
471
|
+
"parse_events",
|
|
447
472
|
"parse_events_from_bytes",
|
|
448
473
|
"parse_print_result",
|
|
449
474
|
"parse_tool_call",
|
|
450
475
|
"parse_tool_result",
|
|
451
476
|
"record_harvest",
|
|
477
|
+
"register_mcp_tool",
|
|
452
478
|
"render_session",
|
|
453
479
|
"render_tool_call",
|
|
454
480
|
"render_turn",
|
|
@@ -457,9 +483,18 @@ __all__ = [
|
|
|
457
483
|
"result_index",
|
|
458
484
|
"stream",
|
|
459
485
|
"subagent_paths",
|
|
486
|
+
"synthetic_assistant_event",
|
|
487
|
+
"synthetic_user_event",
|
|
488
|
+
"system_line",
|
|
489
|
+
"text_block",
|
|
490
|
+
"thinking_block",
|
|
460
491
|
"thinking_chars",
|
|
461
492
|
"tool_digest",
|
|
462
493
|
"tool_facts",
|
|
463
494
|
"tool_name_matches",
|
|
495
|
+
"tool_result",
|
|
496
|
+
"tool_use",
|
|
464
497
|
"tool_uses",
|
|
498
|
+
"unregister_mcp_tool",
|
|
499
|
+
"user_line",
|
|
465
500
|
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# This file is automatically generated by pyo3_stub_gen
|
|
2
2
|
# ruff: noqa: E501, F401, F403, F405
|
|
3
3
|
|
|
4
|
+
import asyncio
|
|
4
5
|
import builtins
|
|
5
6
|
from cc_transcript import command
|
|
6
7
|
from cc_transcript import ids
|
|
@@ -72,6 +73,7 @@ __all__ = [
|
|
|
72
73
|
"ServerToolUse",
|
|
73
74
|
"SkillCall",
|
|
74
75
|
"SkillResult",
|
|
76
|
+
"SpanEditCall",
|
|
75
77
|
"SpecMatcher",
|
|
76
78
|
"StopHookSummary",
|
|
77
79
|
"SystemEvent",
|
|
@@ -133,6 +135,7 @@ __all__ = [
|
|
|
133
135
|
"parse_bytes",
|
|
134
136
|
"parse_print_result",
|
|
135
137
|
"query_session",
|
|
138
|
+
"register_mcp_tool",
|
|
136
139
|
"render_compact_lines",
|
|
137
140
|
"render_haystacks",
|
|
138
141
|
"render_stats",
|
|
@@ -147,6 +150,7 @@ __all__ = [
|
|
|
147
150
|
"tool_name_matches",
|
|
148
151
|
"toolcall_parse_view",
|
|
149
152
|
"toolresult_parse_view",
|
|
153
|
+
"unregister_mcp_tool",
|
|
150
154
|
]
|
|
151
155
|
|
|
152
156
|
@typing.final
|
|
@@ -1131,6 +1135,11 @@ class OtherCall(ToolCallBase):
|
|
|
1131
1135
|
__match_args__: typing.ClassVar[tuple[str, ...]]
|
|
1132
1136
|
@property
|
|
1133
1137
|
def name(self) -> builtins.str: ...
|
|
1138
|
+
@property
|
|
1139
|
+
def error(self) -> typing.Optional[builtins.str]:
|
|
1140
|
+
r"""
|
|
1141
|
+
The strict-parse failure this call degraded from; None when the payload was well-formed but the tool has no typed model.
|
|
1142
|
+
"""
|
|
1134
1143
|
|
|
1135
1144
|
@typing.final
|
|
1136
1145
|
class OtherEvent:
|
|
@@ -1439,37 +1448,40 @@ class Redirect:
|
|
|
1439
1448
|
@typing.final
|
|
1440
1449
|
class RustCorrectionLog:
|
|
1441
1450
|
def __new__(cls, path: builtins.str) -> RustCorrectionLog: ...
|
|
1442
|
-
def
|
|
1443
|
-
def
|
|
1444
|
-
def
|
|
1445
|
-
def
|
|
1446
|
-
def
|
|
1447
|
-
def
|
|
1448
|
-
def
|
|
1451
|
+
def open(self) -> asyncio.Future[None]: ...
|
|
1452
|
+
def close(self) -> asyncio.Future[None]: ...
|
|
1453
|
+
def append(self, ts_ms: builtins.int, session_id: builtins.str, source: builtins.str, anchor_uuid: builtins.str, incorrect_digest: typing.Optional[builtins.str], incorrect_file: builtins.str, incorrect_old: builtins.str, incorrect_new: builtins.str, correction_origin: typing.Optional[builtins.str], correction_file: typing.Optional[builtins.str], correction_old: typing.Optional[builtins.str], correction_new: typing.Optional[builtins.str], correction_commit: typing.Optional[builtins.str], correction_text: typing.Optional[builtins.str], overlap: builtins.float, detail: typing.Any) -> asyncio.Future[None]: ...
|
|
1454
|
+
def for_session(self, session_id: builtins.str) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1455
|
+
def for_repo(self, repo: builtins.str) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1456
|
+
def since(self, ts_ms: builtins.int, source: typing.Optional[builtins.str] = None) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1457
|
+
def for_anchor(self, session_id: builtins.str, anchor_uuid: builtins.str) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1458
|
+
def by_digest(self, session_id: builtins.str, incorrect_digest: builtins.str) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1459
|
+
def sql(self, statement: builtins.str) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1449
1460
|
|
|
1450
1461
|
@typing.final
|
|
1451
1462
|
class RustFeedbackStore:
|
|
1452
1463
|
def __new__(cls, path: builtins.str, extra_ddl: typing.Sequence[builtins.str], event_columns: typing.Sequence[builtins.str], migrations: typing.Sequence[tuple[builtins.str, builtins.str, builtins.str, typing.Optional[builtins.str]]], verdict_table: builtins.str, accepted_column: builtins.str, summary_column: builtins.str, event_filter: typing.Optional[builtins.str], readonly: builtins.bool = False, busy_timeout_ms: typing.Optional[builtins.int] = None) -> RustFeedbackStore: ...
|
|
1453
|
-
def
|
|
1454
|
-
def
|
|
1455
|
-
def
|
|
1456
|
-
def
|
|
1457
|
-
def
|
|
1458
|
-
def
|
|
1459
|
-
def
|
|
1460
|
-
def
|
|
1461
|
-
def
|
|
1462
|
-
def
|
|
1463
|
-
def
|
|
1464
|
-
def
|
|
1465
|
-
def
|
|
1466
|
-
def
|
|
1467
|
-
def
|
|
1468
|
-
def
|
|
1469
|
-
def
|
|
1470
|
-
def
|
|
1471
|
-
def
|
|
1472
|
-
def
|
|
1464
|
+
def open(self) -> asyncio.Future[None]: ...
|
|
1465
|
+
def close(self) -> asyncio.Future[None]: ...
|
|
1466
|
+
def sql(self, statement: builtins.str, params: typing.Optional[typing.Sequence[typing.Any]] = None) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1467
|
+
def execute(self, statement: builtins.str, params: typing.Optional[typing.Sequence[typing.Any]] = None) -> asyncio.Future[int]: ...
|
|
1468
|
+
def executemany(self, statement: builtins.str, seq: typing.Sequence[typing.Sequence[typing.Any]]) -> asyncio.Future[int]: ...
|
|
1469
|
+
def executescript(self, script: builtins.str) -> asyncio.Future[None]: ...
|
|
1470
|
+
def last_insert_rowid(self) -> asyncio.Future[int]: ...
|
|
1471
|
+
def load_extension(self, path: builtins.str) -> asyncio.Future[None]: ...
|
|
1472
|
+
def begin_immediate(self) -> asyncio.Future[None]: ...
|
|
1473
|
+
def commit(self) -> asyncio.Future[None]: ...
|
|
1474
|
+
def rollback(self) -> asyncio.Future[None]: ...
|
|
1475
|
+
def insert_candidates(self, rows: typing.Sequence[typing.Sequence[typing.Any]], extras: typing.Optional[typing.Sequence[typing.Sequence[typing.Any]]] = None) -> asyncio.Future[list[str]]: ...
|
|
1476
|
+
def record_file(self, path: builtins.str, mtime: builtins.float) -> asyncio.Future[None]: ...
|
|
1477
|
+
def file_mtimes(self) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1478
|
+
def stats(self) -> asyncio.Future[tuple[int, int, list[dict[str, typing.Any]]]]: ...
|
|
1479
|
+
def recent(self, source_kind: typing.Optional[builtins.str] = None, limit: builtins.int = 20) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1480
|
+
def events(self, source_kind: typing.Optional[builtins.str] = None) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1481
|
+
def dedup_keys(self) -> asyncio.Future[list[str]]: ...
|
|
1482
|
+
def record_verdict(self, dedup_key: builtins.str, role: builtins.str, prompt_version: builtins.int, model: builtins.str, category: builtins.str, accepted: builtins.bool, summary: builtins.str, confidence: builtins.float, rationale: builtins.str, canonical_key: typing.Optional[builtins.str], fidelity: builtins.str, judged_at: builtins.str) -> asyncio.Future[bool]: ...
|
|
1483
|
+
def unjudged(self, role: builtins.str, prompt_version: builtins.int, refresh_summary: builtins.bool = False, limit: typing.Optional[builtins.int] = None, offset: typing.Optional[builtins.int] = None) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1484
|
+
def judged(self, role: builtins.str, prompt_version: builtins.int) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
|
|
1473
1485
|
|
|
1474
1486
|
@typing.final
|
|
1475
1487
|
class ServerToolUse:
|
|
@@ -1514,6 +1526,27 @@ class SkillResult(ToolResultBase):
|
|
|
1514
1526
|
@property
|
|
1515
1527
|
def allowed_tools(self) -> tuple[str, ...] | None: ...
|
|
1516
1528
|
|
|
1529
|
+
@typing.final
|
|
1530
|
+
class SpanEditCall(ToolCallBase):
|
|
1531
|
+
r"""
|
|
1532
|
+
An in-place file edit addressed by an opaque locator.
|
|
1533
|
+
|
|
1534
|
+
A registered MCP tool whose spec carries a span-edit lowering. The payload
|
|
1535
|
+
carries no pre-image, so :func:`hunks_of` yields no hunk; ``new`` is ``None``
|
|
1536
|
+
when the call deletes rather than writes. Registrations are process-local.
|
|
1537
|
+
|
|
1538
|
+
Attributes:
|
|
1539
|
+
file_path: The file the edit targets.
|
|
1540
|
+
new: The written content, or ``None`` when the call is a deletion.
|
|
1541
|
+
"""
|
|
1542
|
+
__match_args__: typing.ClassVar[tuple[str, ...]]
|
|
1543
|
+
@property
|
|
1544
|
+
def name(self) -> builtins.str: ...
|
|
1545
|
+
@property
|
|
1546
|
+
def file_path(self) -> builtins.str: ...
|
|
1547
|
+
@property
|
|
1548
|
+
def new(self) -> typing.Optional[builtins.str]: ...
|
|
1549
|
+
|
|
1517
1550
|
@typing.final
|
|
1518
1551
|
class SpecMatcher:
|
|
1519
1552
|
def __new__(cls, spec_json: builtins.str) -> SpecMatcher: ...
|
|
@@ -2147,6 +2180,8 @@ def hunks_of(call: tools.ToolCall | tools.FallbackCall) -> tuple[Hunk, ...]:
|
|
|
2147
2180
|
|
|
2148
2181
|
MultiEdit yields one hunk per span in application order — never just the
|
|
2149
2182
|
first. Write and NotebookEdit are pure additions with an empty old side.
|
|
2183
|
+
:class:`~SpanEditCall` yields none: its payload carries no
|
|
2184
|
+
pre-image, so no honest hunk can be derived.
|
|
2150
2185
|
"""
|
|
2151
2186
|
|
|
2152
2187
|
def ids_canonical_json(value_json: builtins.str) -> builtins.str: ...
|
|
@@ -2166,19 +2201,16 @@ def matches_names(actual: builtins.str, names: collections.abc.Container[str]) -
|
|
|
2166
2201
|
Whether ``actual`` is one of ``names``, exactly or as an MCP tool suffix.
|
|
2167
2202
|
|
|
2168
2203
|
True when ``actual`` is in ``names``, or when it splits as
|
|
2169
|
-
``mcp__<server>__<tool>`` on the first two ``__`` and ``<tool>`` — or
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
``
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
taken verbatim; pre-expand with :func:`expand_tool_names` for those.
|
|
2204
|
+
``mcp__<server>__<tool>`` on the first two ``__`` and ``<tool>`` — or the
|
|
2205
|
+
built-in gate its registered spec ``behaves_like`` — is in ``names``. That
|
|
2206
|
+
closure lets a registered MCP tool (e.g. one that gates as ``Edit``) match an
|
|
2207
|
+
``Edit`` gate even under a name no built-in gate would catch. Display-name
|
|
2208
|
+
aliases from :data:`~tools.TOOL_ALIASES` are not closed over —
|
|
2209
|
+
``names`` is taken verbatim; pre-expand with :func:`expand_tool_names` for those.
|
|
2176
2210
|
|
|
2177
2211
|
Example:
|
|
2178
2212
|
>>> matches_names("mcp__github__Grep", {"Grep"})
|
|
2179
2213
|
True
|
|
2180
|
-
>>> matches_names("mcp__cc-context__ccx_code_edit", {"Edit"})
|
|
2181
|
-
True
|
|
2182
2214
|
>>> matches_names("Execute", {"Bash"})
|
|
2183
2215
|
False
|
|
2184
2216
|
"""
|
|
@@ -2230,6 +2262,16 @@ def parse_print_result(raw: bytes) -> PrintResult: ...
|
|
|
2230
2262
|
|
|
2231
2263
|
def query_session(path: builtins.str, max_events: builtins.int) -> dict[str, typing.Any]: ...
|
|
2232
2264
|
|
|
2265
|
+
def register_mcp_tool(tool: builtins.str, behaves_like: builtins.str, span_edit: collections.abc.Mapping[str, str] | None = None) -> None:
|
|
2266
|
+
r"""
|
|
2267
|
+
Register an MCP tool spec, keyed by its bare segment; last write wins.
|
|
2268
|
+
|
|
2269
|
+
``behaves_like`` names the built-in gate the tool matches. ``span_edit``, when
|
|
2270
|
+
given, maps the payload key names — ``path``, ``content``, and optionally
|
|
2271
|
+
``delete`` — the tool's :class:`~SpanEditCall` lowering
|
|
2272
|
+
reads. Registrations are process-local.
|
|
2273
|
+
"""
|
|
2274
|
+
|
|
2233
2275
|
def render_compact_lines(raw: bytes, width: builtins.int, thinking: builtins.bool, uuids: builtins.bool) -> builtins.list[builtins.str]: ...
|
|
2234
2276
|
|
|
2235
2277
|
def render_haystacks(raw: bytes, wheres: typing.Sequence[builtins.str]) -> builtins.list[builtins.str]: ...
|
|
@@ -2275,3 +2317,8 @@ def toolresult_parse_view(name: builtins.str, payload_json: builtins.str) -> too
|
|
|
2275
2317
|
the typed view hierarchy; the ``cc_transcript.tools`` facade owns the public
|
|
2276
2318
|
signature.
|
|
2277
2319
|
"""
|
|
2320
|
+
|
|
2321
|
+
def unregister_mcp_tool(tool: builtins.str) -> builtins.bool:
|
|
2322
|
+
r"""
|
|
2323
|
+
Unregister an MCP tool by its bare segment; returns whether it was registered.
|
|
2324
|
+
"""
|
|
@@ -26,6 +26,7 @@ from cc_transcript.literals import literal_str
|
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
28
28
|
from collections.abc import Mapping
|
|
29
|
+
from types import TracebackType
|
|
29
30
|
from typing import Any
|
|
30
31
|
|
|
31
32
|
from cc_transcript.ids import EventUuid, SessionId, ToolDigest
|
|
@@ -93,16 +94,16 @@ class CorrectionLog:
|
|
|
93
94
|
the module docstring).
|
|
94
95
|
|
|
95
96
|
Example:
|
|
96
|
-
>>>
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
>>> async with await CorrectionLog.open() as log:
|
|
98
|
+
... await log.append(correction)
|
|
99
|
+
... await log.by_digest(session_id, incorrect_digest=digest)
|
|
99
100
|
"""
|
|
100
101
|
|
|
101
102
|
def __init__(self, engine: _native.RustCorrectionLog) -> None:
|
|
102
103
|
self._engine = engine
|
|
103
104
|
|
|
104
105
|
@classmethod
|
|
105
|
-
def open(cls, path: Path | None = None) -> Self:
|
|
106
|
+
async def open(cls, path: Path | None = None) -> Self:
|
|
106
107
|
"""Opens (creating if needed) the ledger at ``path``.
|
|
107
108
|
|
|
108
109
|
Args:
|
|
@@ -113,17 +114,37 @@ class CorrectionLog:
|
|
|
113
114
|
The opened log.
|
|
114
115
|
"""
|
|
115
116
|
path = path or Path.home() / ".cc-transcript" / "corrections.db"
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
engine = _native.RustCorrectionLog(str(path))
|
|
118
|
+
try:
|
|
119
|
+
await engine.open()
|
|
120
|
+
except BaseException:
|
|
121
|
+
await engine.close()
|
|
122
|
+
raise
|
|
123
|
+
return cls(engine)
|
|
124
|
+
|
|
125
|
+
async def close(self) -> None:
|
|
126
|
+
"""Closes the underlying connection; a second close is a no-op."""
|
|
127
|
+
await self._engine.close()
|
|
128
|
+
|
|
129
|
+
async def __aenter__(self) -> Self:
|
|
130
|
+
return self
|
|
131
|
+
|
|
132
|
+
async def __aexit__(
|
|
133
|
+
self,
|
|
134
|
+
exc_type: type[BaseException] | None,
|
|
135
|
+
exc: BaseException | None,
|
|
136
|
+
tb: TracebackType | None,
|
|
137
|
+
) -> None:
|
|
138
|
+
await self.close()
|
|
139
|
+
|
|
140
|
+
async def append(self, record: Correction) -> None:
|
|
120
141
|
"""Appends ``record`` as a single ``INSERT OR IGNORE``.
|
|
121
142
|
|
|
122
143
|
Idempotent on the table's UNIQUE key, so re-running a writer writes one
|
|
123
144
|
row; SQLite treats NULL key columns as distinct, so rows whose key
|
|
124
145
|
carries a NULL rely on the writer not repeating the same values.
|
|
125
146
|
"""
|
|
126
|
-
self._engine.append(
|
|
147
|
+
await self._engine.append(
|
|
127
148
|
record.ts_ms,
|
|
128
149
|
record.session_id,
|
|
129
150
|
record.source,
|
|
@@ -142,39 +163,39 @@ class CorrectionLog:
|
|
|
142
163
|
record.detail,
|
|
143
164
|
)
|
|
144
165
|
|
|
145
|
-
def for_session(self, session_id: SessionId) -> tuple[Correction, ...]:
|
|
166
|
+
async def for_session(self, session_id: SessionId) -> tuple[Correction, ...]:
|
|
146
167
|
"""All records for ``session_id``, ordered by timestamp."""
|
|
147
|
-
return tuple(Correction(**row) for row in self._engine.for_session(session_id))
|
|
168
|
+
return tuple(Correction(**row) for row in await self._engine.for_session(session_id))
|
|
148
169
|
|
|
149
|
-
def for_repo(self, repo: str) -> tuple[Correction, ...]:
|
|
170
|
+
async def for_repo(self, repo: str) -> tuple[Correction, ...]:
|
|
150
171
|
"""All corrections whose ``detail.repo`` is ``repo``, ordered by timestamp.
|
|
151
172
|
|
|
152
173
|
The repo key producers stamp into ``detail`` so a per-repo consumer (the
|
|
153
174
|
captain-hook reviewer) can pull every correction for its repo at once.
|
|
154
175
|
"""
|
|
155
|
-
return tuple(Correction(**row) for row in self._engine.for_repo(repo))
|
|
176
|
+
return tuple(Correction(**row) for row in await self._engine.for_repo(repo))
|
|
156
177
|
|
|
157
|
-
def since(self, ts_ms: int, *, source: str | None = None) -> tuple[Correction, ...]:
|
|
178
|
+
async def since(self, ts_ms: int, *, source: str | None = None) -> tuple[Correction, ...]:
|
|
158
179
|
"""Corrections with ``ts_ms`` strictly greater than ``ts_ms``, oldest first.
|
|
159
180
|
|
|
160
181
|
A cursor read for incremental consumers; pass ``source`` to scope to one
|
|
161
182
|
producer.
|
|
162
183
|
"""
|
|
163
|
-
return tuple(Correction(**row) for row in self._engine.since(ts_ms, source))
|
|
184
|
+
return tuple(Correction(**row) for row in await self._engine.since(ts_ms, source))
|
|
164
185
|
|
|
165
|
-
def for_anchor(self, session_id: SessionId, anchor_uuid: EventUuid) -> tuple[Correction, ...]:
|
|
186
|
+
async def for_anchor(self, session_id: SessionId, anchor_uuid: EventUuid) -> tuple[Correction, ...]:
|
|
166
187
|
"""The corrections harvested around one feedback ``anchor_uuid``."""
|
|
167
|
-
return tuple(Correction(**row) for row in self._engine.for_anchor(session_id, anchor_uuid))
|
|
188
|
+
return tuple(Correction(**row) for row in await self._engine.for_anchor(session_id, anchor_uuid))
|
|
168
189
|
|
|
169
|
-
def by_digest(self, session_id: SessionId, *, incorrect_digest: ToolDigest) -> tuple[Correction, ...]:
|
|
190
|
+
async def by_digest(self, session_id: SessionId, *, incorrect_digest: ToolDigest) -> tuple[Correction, ...]:
|
|
170
191
|
"""Corrections of the tool call with ``incorrect_digest`` in ``session_id``.
|
|
171
192
|
|
|
172
193
|
The cross-consumer join: pass the ``tool_digest`` a hook recorded in
|
|
173
194
|
the ``decisions`` ledger to learn whether that exact edit was later
|
|
174
195
|
corrected.
|
|
175
196
|
"""
|
|
176
|
-
return tuple(Correction(**row) for row in self._engine.by_digest(session_id, incorrect_digest))
|
|
197
|
+
return tuple(Correction(**row) for row in await self._engine.by_digest(session_id, incorrect_digest))
|
|
177
198
|
|
|
178
|
-
def sql(self, statement: str) -> list[dict[str, Any]]:
|
|
199
|
+
async def sql(self, statement: str) -> list[dict[str, Any]]:
|
|
179
200
|
"""Runs one raw SQL ``statement`` — the escape hatch behind ``corrections sql``."""
|
|
180
|
-
return self._engine.sql(statement)
|
|
201
|
+
return await self._engine.sql(statement)
|
|
@@ -14,7 +14,7 @@ import sqlite3
|
|
|
14
14
|
from dataclasses import dataclass, field
|
|
15
15
|
from typing import TYPE_CHECKING, Literal
|
|
16
16
|
|
|
17
|
-
from cc_transcript.ledger import
|
|
17
|
+
from cc_transcript.ledger import AsyncLedger
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
20
|
from collections.abc import Mapping
|
|
@@ -87,7 +87,7 @@ class Decision:
|
|
|
87
87
|
detail: Mapping[str, Any] = field(default_factory=dict)
|
|
88
88
|
|
|
89
89
|
|
|
90
|
-
class DecisionLog(
|
|
90
|
+
class DecisionLog(AsyncLedger[Decision]):
|
|
91
91
|
"""The ``decisions`` ledger at ``~/.cc-transcript/decisions.db``.
|
|
92
92
|
|
|
93
93
|
Opened in WAL mode with a busy timeout because cc-review's Go daemon
|
|
@@ -95,9 +95,10 @@ class DecisionLog(SyncLedger[Decision]):
|
|
|
95
95
|
auto-dropped. Requires a local disk — WAL does not work over NFS.
|
|
96
96
|
|
|
97
97
|
Example:
|
|
98
|
-
>>> log = DecisionLog.open()
|
|
99
|
-
>>> log
|
|
100
|
-
|
|
98
|
+
>>> log = await DecisionLog.open()
|
|
99
|
+
>>> async with log:
|
|
100
|
+
... await log.append(decision)
|
|
101
|
+
... await log.attribute_tool(session_id, tool_digest=digest, near_ts_ms=ts)
|
|
101
102
|
"""
|
|
102
103
|
|
|
103
104
|
DDL = DECISIONS_DDL
|
|
@@ -134,7 +135,7 @@ class DecisionLog(SyncLedger[Decision]):
|
|
|
134
135
|
detail=json.loads(row["detail_json"]),
|
|
135
136
|
)
|
|
136
137
|
|
|
137
|
-
def attribute_tool(
|
|
138
|
+
async def attribute_tool(
|
|
138
139
|
self, session_id: SessionId, *, tool_digest: ToolDigest, near_ts_ms: int, window_ms: int = 300_000
|
|
139
140
|
) -> Decision | None:
|
|
140
141
|
"""The nearest decision preceding ``near_ts_ms`` with this digest.
|
|
@@ -148,14 +149,17 @@ class DecisionLog(SyncLedger[Decision]):
|
|
|
148
149
|
The matching decision, or None when no digest-equal row lies in
|
|
149
150
|
``[near_ts_ms - window_ms, near_ts_ms]``.
|
|
150
151
|
"""
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
conn = self._actor.conn
|
|
153
|
+
row = await self._actor.run(
|
|
154
|
+
lambda: conn.execute(
|
|
155
|
+
"SELECT * FROM decisions WHERE session_id = ? AND tool_digest = ? AND ts_ms BETWEEN ? AND ?"
|
|
156
|
+
" ORDER BY ts_ms DESC, id DESC LIMIT 1",
|
|
157
|
+
(session_id, tool_digest, near_ts_ms - window_ms, near_ts_ms),
|
|
158
|
+
).fetchone()
|
|
159
|
+
)
|
|
156
160
|
return self.row_to_record(row) if row else None
|
|
157
161
|
|
|
158
|
-
def attribute_nearest(
|
|
162
|
+
async def attribute_nearest(
|
|
159
163
|
self,
|
|
160
164
|
session_id: SessionId,
|
|
161
165
|
*,
|
|
@@ -175,10 +179,13 @@ class DecisionLog(SyncLedger[Decision]):
|
|
|
175
179
|
The nearest matching decision, or None when none lies in
|
|
176
180
|
``[near_ts_ms - window_ms, near_ts_ms + window_ms]``.
|
|
177
181
|
"""
|
|
182
|
+
conn = self._actor.conn
|
|
178
183
|
kind_clause, kind_params = ("AND kind = ? ", (kind,)) if kind is not None else ("", ())
|
|
179
|
-
row = self.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
+
row = await self._actor.run(
|
|
185
|
+
lambda: conn.execute(
|
|
186
|
+
f"SELECT * FROM decisions WHERE session_id = ? AND event = ? {kind_clause}AND ts_ms BETWEEN ? AND ?"
|
|
187
|
+
" ORDER BY ABS(ts_ms - ?), id DESC LIMIT 1",
|
|
188
|
+
(session_id, event, *kind_params, near_ts_ms - window_ms, near_ts_ms + window_ms, near_ts_ms),
|
|
189
|
+
).fetchone()
|
|
190
|
+
)
|
|
184
191
|
return self.row_to_record(row) if row else None
|
|
@@ -199,7 +199,7 @@ def run_git(repo: Path, *args: str) -> str | None:
|
|
|
199
199
|
return proc.stdout if proc.returncode == 0 else None
|
|
200
200
|
|
|
201
201
|
|
|
202
|
-
def record_harvest(
|
|
202
|
+
async def record_harvest(
|
|
203
203
|
log: CorrectionLog,
|
|
204
204
|
activity: SessionActivity,
|
|
205
205
|
anchor: EventRef,
|
|
@@ -219,7 +219,7 @@ def record_harvest(
|
|
|
219
219
|
"""
|
|
220
220
|
rows = [correction for pair in pairs if (correction := lower_pair(activity, anchor, pair, source=source))]
|
|
221
221
|
for row in rows:
|
|
222
|
-
log.append(row)
|
|
222
|
+
await log.append(row)
|
|
223
223
|
return len(rows)
|
|
224
224
|
|
|
225
225
|
|
|
@@ -163,7 +163,7 @@ async def extract_correction(
|
|
|
163
163
|
already has a row, so re-runs and overlapping producers never duplicate.
|
|
164
164
|
Returns the appended correction, or None when nothing is harvested or picked.
|
|
165
165
|
"""
|
|
166
|
-
if log.for_anchor(anchor.session_id, anchor.event_uuid):
|
|
166
|
+
if await log.for_anchor(anchor.session_id, anchor.event_uuid):
|
|
167
167
|
return None
|
|
168
168
|
pairs = await asyncio.to_thread(harvest_pairs, activity, anchor, repo=repo)
|
|
169
169
|
if not pairs or (turn := activity.turn_of(anchor)) is None:
|
|
@@ -173,5 +173,5 @@ async def extract_correction(
|
|
|
173
173
|
return None
|
|
174
174
|
if repo is not None:
|
|
175
175
|
row = replace(row, detail={"repo": str(repo)})
|
|
176
|
-
log.append(row)
|
|
176
|
+
await log.append(row)
|
|
177
177
|
return row
|