cc-transcript 10.7.0__tar.gz → 11.0.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-11.0.0}/PKG-INFO +1 -1
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/__init__.py +144 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/activity.py +14 -2
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/activity_probe.py +2 -1
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/discovery.py +20 -1
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/facts.py +6 -2
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/filterspec.py +16 -3
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/judge/verdicts.py +12 -2
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/__init__.py +2 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/signals.py +44 -17
- cc_transcript-11.0.0/cc_transcript/models.py +965 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/notifications.py +3 -5
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/parser.py +284 -11
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/render.py +37 -2
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/tools.py +362 -1
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/pyproject.toml +1 -1
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/Cargo.toml +3 -1
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/activity.rs +8 -9
- cc_transcript-11.0.0/rust/src/event.rs +546 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/filter.rs +3 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/generated/protocol.rs +2 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/mining.rs +62 -25
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/model.rs +19 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/parse.rs +267 -17
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/protocol.rs +2 -1
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/python.rs +2 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/types.rs +214 -0
- cc_transcript-10.7.0/cc_transcript/models.py +0 -501
- cc_transcript-10.7.0/rust/src/event.rs +0 -290
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/Cargo.lock +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/Cargo.toml +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/LICENSE +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/README.md +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/__main__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/_parser_rs.pyi +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/backend.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/builders.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/cli.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/command.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/context.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/corrections.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/corrections_cli.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/cost.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/decisions.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/disktruth.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/evidence.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/extract/__init__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/extract/correct.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/ids.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/judge/__init__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/judge/llm.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/judge/similar.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/ledger.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/candidates.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/confidence.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/engine.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/filterspec.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/formats.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/sourcekind.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/spec.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/mining/store.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/py.typed +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/query.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/rust.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/sentiment/__init__.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/sentiment/buckets.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/sentiment/engine.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/sentiment/lexicon.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/sentiment/scorespec.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/cc_transcript/store.py +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/build.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/data/afinn-en-165.tsv +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/data/domain_overrides.tsv +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/command.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/generated/command.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/generated/mining.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/generated/mod.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/lexicon.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/lib.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/score.rs +0 -0
- {cc_transcript-10.7.0 → cc_transcript-11.0.0}/rust/src/value.rs +0 -0
|
@@ -30,8 +30,11 @@ EXPORTS: dict[str, str] = {
|
|
|
30
30
|
),
|
|
31
31
|
"cc_transcript.tools": (
|
|
32
32
|
"TOOL_ALIASES",
|
|
33
|
+
"AskUserQuestionResult",
|
|
33
34
|
"BashCall",
|
|
35
|
+
"BashResult",
|
|
34
36
|
"EditCall",
|
|
37
|
+
"EditResult",
|
|
35
38
|
"EditSpan",
|
|
36
39
|
"ExitPlanModeCall",
|
|
37
40
|
"GlobCall",
|
|
@@ -40,16 +43,27 @@ EXPORTS: dict[str, str] = {
|
|
|
40
43
|
"MultiEditCall",
|
|
41
44
|
"NotebookEditCall",
|
|
42
45
|
"OtherCall",
|
|
46
|
+
"OtherResult",
|
|
47
|
+
"QuestionAnnotation",
|
|
43
48
|
"ReadCall",
|
|
49
|
+
"ReadResult",
|
|
44
50
|
"SkillCall",
|
|
51
|
+
"SkillResult",
|
|
45
52
|
"TaskCall",
|
|
46
53
|
"TaskCreateCall",
|
|
54
|
+
"TaskLaunchResult",
|
|
55
|
+
"TaskResult",
|
|
47
56
|
"TaskUpdateCall",
|
|
57
|
+
"TextResult",
|
|
48
58
|
"ToolCall",
|
|
49
59
|
"ToolCallBase",
|
|
50
60
|
"ToolInputError",
|
|
61
|
+
"ToolResult",
|
|
62
|
+
"ToolResultBase",
|
|
63
|
+
"ToolResultError",
|
|
51
64
|
"WorkflowCall",
|
|
52
65
|
"WriteCall",
|
|
66
|
+
"WriteResult",
|
|
53
67
|
"expand_tool_names",
|
|
54
68
|
"file_path_of",
|
|
55
69
|
"hunks_of",
|
|
@@ -57,6 +71,7 @@ EXPORTS: dict[str, str] = {
|
|
|
57
71
|
"mcp_access",
|
|
58
72
|
"mcp_parts",
|
|
59
73
|
"parse_tool_call",
|
|
74
|
+
"parse_tool_result",
|
|
60
75
|
"tool_name_matches",
|
|
61
76
|
),
|
|
62
77
|
"cc_transcript.command": (
|
|
@@ -68,29 +83,50 @@ EXPORTS: dict[str, str] = {
|
|
|
68
83
|
"parse_command_line",
|
|
69
84
|
),
|
|
70
85
|
"cc_transcript.models": (
|
|
86
|
+
"ApiError",
|
|
71
87
|
"AssistantEvent",
|
|
88
|
+
"AsyncHookResponse",
|
|
89
|
+
"AttachmentDetail",
|
|
90
|
+
"AttachmentEvent",
|
|
91
|
+
"Attribution",
|
|
72
92
|
"CacheCreation",
|
|
73
93
|
"CcVersion",
|
|
94
|
+
"CompactBoundary",
|
|
74
95
|
"ContentBlock",
|
|
75
96
|
"EntryMeta",
|
|
76
97
|
"FallbackBlock",
|
|
98
|
+
"HookAdditionalContext",
|
|
99
|
+
"HookBlockingError",
|
|
100
|
+
"HookCancelled",
|
|
101
|
+
"HookInfo",
|
|
102
|
+
"HookNonBlockingError",
|
|
103
|
+
"HookSuccess",
|
|
77
104
|
"InitInfo",
|
|
78
105
|
"McpServer",
|
|
106
|
+
"ModelRefusalFallback",
|
|
79
107
|
"ModeEvent",
|
|
80
108
|
"ModelUsage",
|
|
109
|
+
"OtherAttachment",
|
|
81
110
|
"OtherBlock",
|
|
82
111
|
"OtherEvent",
|
|
112
|
+
"OtherSystemDetail",
|
|
83
113
|
"Plugin",
|
|
114
|
+
"PreservedMessages",
|
|
115
|
+
"PreservedSegment",
|
|
84
116
|
"PrintMessage",
|
|
85
117
|
"PrintResult",
|
|
86
118
|
"Question",
|
|
119
|
+
"QueuedCommand",
|
|
87
120
|
"ServerToolUse",
|
|
121
|
+
"StopHookSummary",
|
|
122
|
+
"SystemDetail",
|
|
88
123
|
"SystemEvent",
|
|
89
124
|
"TextBlock",
|
|
90
125
|
"ThinkingBlock",
|
|
91
126
|
"ToolResultBlock",
|
|
92
127
|
"ToolUseBlock",
|
|
93
128
|
"TranscriptEvent",
|
|
129
|
+
"TurnDuration",
|
|
94
130
|
"Usage",
|
|
95
131
|
"UserEvent",
|
|
96
132
|
"thinking_chars",
|
|
@@ -478,15 +514,33 @@ if TYPE_CHECKING:
|
|
|
478
514
|
from cc_transcript.ids import (
|
|
479
515
|
tool_digest as tool_digest,
|
|
480
516
|
)
|
|
517
|
+
from cc_transcript.models import (
|
|
518
|
+
ApiError as ApiError,
|
|
519
|
+
)
|
|
481
520
|
from cc_transcript.models import (
|
|
482
521
|
AssistantEvent as AssistantEvent,
|
|
483
522
|
)
|
|
523
|
+
from cc_transcript.models import (
|
|
524
|
+
AsyncHookResponse as AsyncHookResponse,
|
|
525
|
+
)
|
|
526
|
+
from cc_transcript.models import (
|
|
527
|
+
AttachmentDetail as AttachmentDetail,
|
|
528
|
+
)
|
|
529
|
+
from cc_transcript.models import (
|
|
530
|
+
AttachmentEvent as AttachmentEvent,
|
|
531
|
+
)
|
|
532
|
+
from cc_transcript.models import (
|
|
533
|
+
Attribution as Attribution,
|
|
534
|
+
)
|
|
484
535
|
from cc_transcript.models import (
|
|
485
536
|
CacheCreation as CacheCreation,
|
|
486
537
|
)
|
|
487
538
|
from cc_transcript.models import (
|
|
488
539
|
CcVersion as CcVersion,
|
|
489
540
|
)
|
|
541
|
+
from cc_transcript.models import (
|
|
542
|
+
CompactBoundary as CompactBoundary,
|
|
543
|
+
)
|
|
490
544
|
from cc_transcript.models import (
|
|
491
545
|
ContentBlock as ContentBlock,
|
|
492
546
|
)
|
|
@@ -496,6 +550,24 @@ if TYPE_CHECKING:
|
|
|
496
550
|
from cc_transcript.models import (
|
|
497
551
|
FallbackBlock as FallbackBlock,
|
|
498
552
|
)
|
|
553
|
+
from cc_transcript.models import (
|
|
554
|
+
HookAdditionalContext as HookAdditionalContext,
|
|
555
|
+
)
|
|
556
|
+
from cc_transcript.models import (
|
|
557
|
+
HookBlockingError as HookBlockingError,
|
|
558
|
+
)
|
|
559
|
+
from cc_transcript.models import (
|
|
560
|
+
HookCancelled as HookCancelled,
|
|
561
|
+
)
|
|
562
|
+
from cc_transcript.models import (
|
|
563
|
+
HookInfo as HookInfo,
|
|
564
|
+
)
|
|
565
|
+
from cc_transcript.models import (
|
|
566
|
+
HookNonBlockingError as HookNonBlockingError,
|
|
567
|
+
)
|
|
568
|
+
from cc_transcript.models import (
|
|
569
|
+
HookSuccess as HookSuccess,
|
|
570
|
+
)
|
|
499
571
|
from cc_transcript.models import (
|
|
500
572
|
InitInfo as InitInfo,
|
|
501
573
|
)
|
|
@@ -505,18 +577,33 @@ if TYPE_CHECKING:
|
|
|
505
577
|
from cc_transcript.models import (
|
|
506
578
|
ModeEvent as ModeEvent,
|
|
507
579
|
)
|
|
580
|
+
from cc_transcript.models import (
|
|
581
|
+
ModelRefusalFallback as ModelRefusalFallback,
|
|
582
|
+
)
|
|
508
583
|
from cc_transcript.models import (
|
|
509
584
|
ModelUsage as ModelUsage,
|
|
510
585
|
)
|
|
586
|
+
from cc_transcript.models import (
|
|
587
|
+
OtherAttachment as OtherAttachment,
|
|
588
|
+
)
|
|
511
589
|
from cc_transcript.models import (
|
|
512
590
|
OtherBlock as OtherBlock,
|
|
513
591
|
)
|
|
514
592
|
from cc_transcript.models import (
|
|
515
593
|
OtherEvent as OtherEvent,
|
|
516
594
|
)
|
|
595
|
+
from cc_transcript.models import (
|
|
596
|
+
OtherSystemDetail as OtherSystemDetail,
|
|
597
|
+
)
|
|
517
598
|
from cc_transcript.models import (
|
|
518
599
|
Plugin as Plugin,
|
|
519
600
|
)
|
|
601
|
+
from cc_transcript.models import (
|
|
602
|
+
PreservedMessages as PreservedMessages,
|
|
603
|
+
)
|
|
604
|
+
from cc_transcript.models import (
|
|
605
|
+
PreservedSegment as PreservedSegment,
|
|
606
|
+
)
|
|
520
607
|
from cc_transcript.models import (
|
|
521
608
|
PrintMessage as PrintMessage,
|
|
522
609
|
)
|
|
@@ -526,9 +613,18 @@ if TYPE_CHECKING:
|
|
|
526
613
|
from cc_transcript.models import (
|
|
527
614
|
Question as Question,
|
|
528
615
|
)
|
|
616
|
+
from cc_transcript.models import (
|
|
617
|
+
QueuedCommand as QueuedCommand,
|
|
618
|
+
)
|
|
529
619
|
from cc_transcript.models import (
|
|
530
620
|
ServerToolUse as ServerToolUse,
|
|
531
621
|
)
|
|
622
|
+
from cc_transcript.models import (
|
|
623
|
+
StopHookSummary as StopHookSummary,
|
|
624
|
+
)
|
|
625
|
+
from cc_transcript.models import (
|
|
626
|
+
SystemDetail as SystemDetail,
|
|
627
|
+
)
|
|
532
628
|
from cc_transcript.models import (
|
|
533
629
|
SystemEvent as SystemEvent,
|
|
534
630
|
)
|
|
@@ -547,6 +643,9 @@ if TYPE_CHECKING:
|
|
|
547
643
|
from cc_transcript.models import (
|
|
548
644
|
TranscriptEvent as TranscriptEvent,
|
|
549
645
|
)
|
|
646
|
+
from cc_transcript.models import (
|
|
647
|
+
TurnDuration as TurnDuration,
|
|
648
|
+
)
|
|
550
649
|
from cc_transcript.models import (
|
|
551
650
|
Usage as Usage,
|
|
552
651
|
)
|
|
@@ -606,12 +705,21 @@ if TYPE_CHECKING:
|
|
|
606
705
|
from cc_transcript.tools import (
|
|
607
706
|
TOOL_ALIASES as TOOL_ALIASES,
|
|
608
707
|
)
|
|
708
|
+
from cc_transcript.tools import (
|
|
709
|
+
AskUserQuestionResult as AskUserQuestionResult,
|
|
710
|
+
)
|
|
609
711
|
from cc_transcript.tools import (
|
|
610
712
|
BashCall as BashCall,
|
|
611
713
|
)
|
|
714
|
+
from cc_transcript.tools import (
|
|
715
|
+
BashResult as BashResult,
|
|
716
|
+
)
|
|
612
717
|
from cc_transcript.tools import (
|
|
613
718
|
EditCall as EditCall,
|
|
614
719
|
)
|
|
720
|
+
from cc_transcript.tools import (
|
|
721
|
+
EditResult as EditResult,
|
|
722
|
+
)
|
|
615
723
|
from cc_transcript.tools import (
|
|
616
724
|
EditSpan as EditSpan,
|
|
617
725
|
)
|
|
@@ -636,21 +744,42 @@ if TYPE_CHECKING:
|
|
|
636
744
|
from cc_transcript.tools import (
|
|
637
745
|
OtherCall as OtherCall,
|
|
638
746
|
)
|
|
747
|
+
from cc_transcript.tools import (
|
|
748
|
+
OtherResult as OtherResult,
|
|
749
|
+
)
|
|
750
|
+
from cc_transcript.tools import (
|
|
751
|
+
QuestionAnnotation as QuestionAnnotation,
|
|
752
|
+
)
|
|
639
753
|
from cc_transcript.tools import (
|
|
640
754
|
ReadCall as ReadCall,
|
|
641
755
|
)
|
|
756
|
+
from cc_transcript.tools import (
|
|
757
|
+
ReadResult as ReadResult,
|
|
758
|
+
)
|
|
642
759
|
from cc_transcript.tools import (
|
|
643
760
|
SkillCall as SkillCall,
|
|
644
761
|
)
|
|
762
|
+
from cc_transcript.tools import (
|
|
763
|
+
SkillResult as SkillResult,
|
|
764
|
+
)
|
|
645
765
|
from cc_transcript.tools import (
|
|
646
766
|
TaskCall as TaskCall,
|
|
647
767
|
)
|
|
648
768
|
from cc_transcript.tools import (
|
|
649
769
|
TaskCreateCall as TaskCreateCall,
|
|
650
770
|
)
|
|
771
|
+
from cc_transcript.tools import (
|
|
772
|
+
TaskLaunchResult as TaskLaunchResult,
|
|
773
|
+
)
|
|
774
|
+
from cc_transcript.tools import (
|
|
775
|
+
TaskResult as TaskResult,
|
|
776
|
+
)
|
|
651
777
|
from cc_transcript.tools import (
|
|
652
778
|
TaskUpdateCall as TaskUpdateCall,
|
|
653
779
|
)
|
|
780
|
+
from cc_transcript.tools import (
|
|
781
|
+
TextResult as TextResult,
|
|
782
|
+
)
|
|
654
783
|
from cc_transcript.tools import (
|
|
655
784
|
ToolCall as ToolCall,
|
|
656
785
|
)
|
|
@@ -660,12 +789,24 @@ if TYPE_CHECKING:
|
|
|
660
789
|
from cc_transcript.tools import (
|
|
661
790
|
ToolInputError as ToolInputError,
|
|
662
791
|
)
|
|
792
|
+
from cc_transcript.tools import (
|
|
793
|
+
ToolResult as ToolResult,
|
|
794
|
+
)
|
|
795
|
+
from cc_transcript.tools import (
|
|
796
|
+
ToolResultBase as ToolResultBase,
|
|
797
|
+
)
|
|
798
|
+
from cc_transcript.tools import (
|
|
799
|
+
ToolResultError as ToolResultError,
|
|
800
|
+
)
|
|
663
801
|
from cc_transcript.tools import (
|
|
664
802
|
WorkflowCall as WorkflowCall,
|
|
665
803
|
)
|
|
666
804
|
from cc_transcript.tools import (
|
|
667
805
|
WriteCall as WriteCall,
|
|
668
806
|
)
|
|
807
|
+
from cc_transcript.tools import (
|
|
808
|
+
WriteResult as WriteResult,
|
|
809
|
+
)
|
|
669
810
|
from cc_transcript.tools import (
|
|
670
811
|
expand_tool_names as expand_tool_names,
|
|
671
812
|
)
|
|
@@ -687,6 +828,9 @@ if TYPE_CHECKING:
|
|
|
687
828
|
from cc_transcript.tools import (
|
|
688
829
|
parse_tool_call as parse_tool_call,
|
|
689
830
|
)
|
|
831
|
+
from cc_transcript.tools import (
|
|
832
|
+
parse_tool_result as parse_tool_result,
|
|
833
|
+
)
|
|
690
834
|
from cc_transcript.tools import (
|
|
691
835
|
tool_name_matches as tool_name_matches,
|
|
692
836
|
)
|
|
@@ -21,7 +21,7 @@ from cc_transcript.filterspec import event_meta
|
|
|
21
21
|
from cc_transcript.ids import EventRef
|
|
22
22
|
from cc_transcript.models import AssistantEvent, ToolResultBlock, ToolUseBlock, UserEvent
|
|
23
23
|
from cc_transcript.parser import TranscriptParser
|
|
24
|
-
from cc_transcript.tools import file_path_of, hunks_of, parse_tool_call
|
|
24
|
+
from cc_transcript.tools import file_path_of, hunks_of, parse_tool_call, parse_tool_result
|
|
25
25
|
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
27
|
from collections.abc import Mapping, Sequence
|
|
@@ -30,7 +30,7 @@ if TYPE_CHECKING:
|
|
|
30
30
|
|
|
31
31
|
from cc_transcript.ids import SessionId, ToolUseId
|
|
32
32
|
from cc_transcript.models import TranscriptEvent
|
|
33
|
-
from cc_transcript.tools import Hunk, ToolCall
|
|
33
|
+
from cc_transcript.tools import Hunk, ToolCall, ToolResult
|
|
34
34
|
|
|
35
35
|
UserClassifier = Callable[["UserEvent"], bool]
|
|
36
36
|
"""Decides which :class:`~cc_transcript.models.UserEvent` objects open a turn."""
|
|
@@ -78,6 +78,18 @@ class ToolUse:
|
|
|
78
78
|
"""Milliseconds from the call to its result, or None without a result."""
|
|
79
79
|
return None if self.result_ts is None else round((self.result_ts - self.ts).total_seconds() * 1000)
|
|
80
80
|
|
|
81
|
+
@property
|
|
82
|
+
def typed_result(self) -> ToolResult | None:
|
|
83
|
+
"""The result parsed into the typed result hierarchy, or None without a result.
|
|
84
|
+
|
|
85
|
+
The join point for :func:`~cc_transcript.tools.parse_tool_result`: pairs
|
|
86
|
+
this use's tool name with its result block's ``tool_use_result`` payload,
|
|
87
|
+
degrading to :class:`~cc_transcript.tools.OtherResult` on any shape drift.
|
|
88
|
+
"""
|
|
89
|
+
if self.result is None:
|
|
90
|
+
return None
|
|
91
|
+
return parse_tool_result(self.call.name, self.result.tool_use_result, on_error="other")
|
|
92
|
+
|
|
81
93
|
|
|
82
94
|
@dataclass(frozen=True, slots=True)
|
|
83
95
|
class Edit:
|
|
@@ -23,6 +23,7 @@ from typing import TYPE_CHECKING, Literal
|
|
|
23
23
|
from cc_transcript.activity import native_user_classifier
|
|
24
24
|
from cc_transcript.models import (
|
|
25
25
|
AssistantEvent,
|
|
26
|
+
AttachmentEvent,
|
|
26
27
|
SystemEvent,
|
|
27
28
|
ToolResultBlock,
|
|
28
29
|
ToolUseBlock,
|
|
@@ -170,7 +171,7 @@ def probe_events(
|
|
|
170
171
|
(
|
|
171
172
|
int(event.meta.timestamp.timestamp())
|
|
172
173
|
for event in events
|
|
173
|
-
if isinstance(event, UserEvent | AssistantEvent | SystemEvent)
|
|
174
|
+
if isinstance(event, UserEvent | AssistantEvent | SystemEvent | AttachmentEvent)
|
|
174
175
|
),
|
|
175
176
|
default=None,
|
|
176
177
|
),
|
|
@@ -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:
|
|
@@ -16,7 +16,7 @@ from dataclasses import dataclass
|
|
|
16
16
|
from typing import TYPE_CHECKING, Literal
|
|
17
17
|
|
|
18
18
|
from cc_transcript.activity import SessionActivity
|
|
19
|
-
from cc_transcript.filterspec import
|
|
19
|
+
from cc_transcript.filterspec import DENIAL_KIND_USER_REJECTED, embedded_user_text, session_id_of
|
|
20
20
|
from cc_transcript.tools import BashCall, file_path_of, mcp_access, mcp_parts
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
@@ -31,7 +31,7 @@ if TYPE_CHECKING:
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def is_denial(block: ToolResultBlock) -> bool:
|
|
34
|
-
return block.
|
|
34
|
+
return block.denial_kind == DENIAL_KIND_USER_REJECTED
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def denial_fields(result: ToolResultBlock | None) -> tuple[bool, str | None]:
|
|
@@ -67,6 +67,8 @@ class ToolFact:
|
|
|
67
67
|
file_path: The file the call targets, when it targets one.
|
|
68
68
|
is_error: Whether the call's result reported a failure.
|
|
69
69
|
denied: Whether the result is a user rejection of the tool use.
|
|
70
|
+
denial_kind: The structured tool-denial kind (``user-rejected`` for a human
|
|
71
|
+
rejection, ``permission-rule`` for a hook/guard block), or None.
|
|
70
72
|
user_said: The user's verbatim instruction embedded in a denial, else None.
|
|
71
73
|
duration_ms: Milliseconds from the call to its result, or None without one.
|
|
72
74
|
"""
|
|
@@ -84,6 +86,7 @@ class ToolFact:
|
|
|
84
86
|
file_path: str | None
|
|
85
87
|
is_error: bool
|
|
86
88
|
denied: bool
|
|
89
|
+
denial_kind: str | None
|
|
87
90
|
user_said: str | None
|
|
88
91
|
duration_ms: int | None
|
|
89
92
|
|
|
@@ -106,6 +109,7 @@ def fact_of(use: ToolUse, session_id: SessionId, path: Path, prefixes: tuple[str
|
|
|
106
109
|
file_path=file_path_of(call),
|
|
107
110
|
is_error=use.result.is_error if use.result is not None else False,
|
|
108
111
|
denied=denied,
|
|
112
|
+
denial_kind=use.result.denial_kind if use.result is not None else None,
|
|
109
113
|
user_said=user_said,
|
|
110
114
|
duration_ms=use.duration_ms,
|
|
111
115
|
)
|
|
@@ -27,7 +27,15 @@ from typing import TYPE_CHECKING, Literal
|
|
|
27
27
|
|
|
28
28
|
import orjson
|
|
29
29
|
|
|
30
|
-
from cc_transcript.models import
|
|
30
|
+
from cc_transcript.models import (
|
|
31
|
+
AssistantEvent,
|
|
32
|
+
AttachmentEvent,
|
|
33
|
+
ModeEvent,
|
|
34
|
+
OtherEvent,
|
|
35
|
+
SystemEvent,
|
|
36
|
+
ToolUseBlock,
|
|
37
|
+
UserEvent,
|
|
38
|
+
)
|
|
31
39
|
|
|
32
40
|
if TYPE_CHECKING:
|
|
33
41
|
from collections.abc import Iterable, Iterator, Sequence
|
|
@@ -35,7 +43,7 @@ if TYPE_CHECKING:
|
|
|
35
43
|
|
|
36
44
|
from cc_transcript.models import EntryMeta, SessionId, ToolUseId, TranscriptEvent
|
|
37
45
|
|
|
38
|
-
EventKind = Literal["user", "assistant", "system", "mode", "other"]
|
|
46
|
+
EventKind = Literal["user", "assistant", "system", "mode", "other", "attachment"]
|
|
39
47
|
MetaFlagName = Literal["is_sidechain", "is_meta", "is_compact_summary", "is_visible_in_transcript_only"]
|
|
40
48
|
|
|
41
49
|
TRAILING_PUNCT = ".!?…,;:"
|
|
@@ -77,6 +85,9 @@ STOP_HOOK_GROUPS: tuple[tuple[str, str], ...] = (("stop_hook", r"Stop hook feedb
|
|
|
77
85
|
|
|
78
86
|
# Raw CC-injected protocol strings carried in tool-result content, not user-authored text.
|
|
79
87
|
DENIAL_PREFIX = "The user doesn't want to proceed with this tool use. The tool use was rejected"
|
|
88
|
+
# Record-level ``toolDenialKind`` values: a human rejection versus a hook/guard block.
|
|
89
|
+
DENIAL_KIND_USER_REJECTED = "user-rejected"
|
|
90
|
+
DENIAL_KIND_PERMISSION_RULE = "permission-rule"
|
|
80
91
|
USER_SAID_MARKER = "To tell you how to proceed, the user said:\n"
|
|
81
92
|
USER_SAID_TRAILER = "Note: The user's next message"
|
|
82
93
|
ANSWERED_PREFIX = "Your questions have been answered: "
|
|
@@ -371,6 +382,8 @@ def event_kind(event: TranscriptEvent) -> EventKind:
|
|
|
371
382
|
return "mode"
|
|
372
383
|
case OtherEvent():
|
|
373
384
|
return "other"
|
|
385
|
+
case AttachmentEvent():
|
|
386
|
+
return "attachment"
|
|
374
387
|
|
|
375
388
|
|
|
376
389
|
def event_text(event: TranscriptEvent) -> str:
|
|
@@ -383,7 +396,7 @@ def event_text(event: TranscriptEvent) -> str:
|
|
|
383
396
|
|
|
384
397
|
def event_meta(event: TranscriptEvent) -> EntryMeta | None:
|
|
385
398
|
match event:
|
|
386
|
-
case UserEvent(meta=meta) | AssistantEvent(meta=meta) | SystemEvent(meta=meta):
|
|
399
|
+
case UserEvent(meta=meta) | AssistantEvent(meta=meta) | SystemEvent(meta=meta) | AttachmentEvent(meta=meta):
|
|
387
400
|
return meta
|
|
388
401
|
case _:
|
|
389
402
|
return 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
|
|
@@ -20,6 +20,7 @@ and reasons instead of re-deriving them.
|
|
|
20
20
|
|
|
21
21
|
from __future__ import annotations
|
|
22
22
|
|
|
23
|
+
from collections.abc import Mapping
|
|
23
24
|
from dataclasses import dataclass, field
|
|
24
25
|
from typing import TYPE_CHECKING, NamedTuple
|
|
25
26
|
|
|
@@ -61,12 +62,19 @@ from cc_transcript.mining.spec import (
|
|
|
61
62
|
regex_review_comments,
|
|
62
63
|
score_user_message,
|
|
63
64
|
)
|
|
64
|
-
from cc_transcript.models import
|
|
65
|
-
|
|
65
|
+
from cc_transcript.models import (
|
|
66
|
+
AssistantEvent,
|
|
67
|
+
ModeEvent,
|
|
68
|
+
ToolResultBlock,
|
|
69
|
+
ToolUseBlock,
|
|
70
|
+
UserEvent,
|
|
71
|
+
parse_questions,
|
|
72
|
+
)
|
|
73
|
+
from cc_transcript.tools import AskUserQuestionResult, matches_names
|
|
66
74
|
|
|
67
75
|
if TYPE_CHECKING:
|
|
68
76
|
import re
|
|
69
|
-
from collections.abc import Iterator,
|
|
77
|
+
from collections.abc import Iterator, Sequence
|
|
70
78
|
from datetime import datetime
|
|
71
79
|
from typing import Any
|
|
72
80
|
|
|
@@ -416,16 +424,6 @@ class AnsweredPair(NamedTuple):
|
|
|
416
424
|
notes: str | None
|
|
417
425
|
|
|
418
426
|
|
|
419
|
-
def answered_question_results(event: UserEvent) -> Iterator[ToolResultBlock]:
|
|
420
|
-
return (
|
|
421
|
-
block
|
|
422
|
-
for block in event.blocks
|
|
423
|
-
if isinstance(block, ToolResultBlock)
|
|
424
|
-
if not block.is_error
|
|
425
|
-
if block.content.startswith(ANSWERED_PREFIX)
|
|
426
|
-
)
|
|
427
|
-
|
|
428
|
-
|
|
429
427
|
def split_answer_segment(segment: str) -> tuple[str, str | None, str | None]:
|
|
430
428
|
if (at := segment.find(ANSWER_PREVIEW_SEP)) != -1:
|
|
431
429
|
rest = segment[at + len(ANSWER_PREVIEW_SEP) :]
|
|
@@ -534,18 +532,47 @@ def question_answer_signal(
|
|
|
534
532
|
)
|
|
535
533
|
|
|
536
534
|
|
|
535
|
+
def structured_answered_pairs(payload: Mapping[str, Any], use: ToolUseBlock) -> Iterator[AnsweredPair]:
|
|
536
|
+
result = AskUserQuestionResult.from_raw("AskUserQuestion", payload)
|
|
537
|
+
questions = parse_questions(payload.get("questions"))
|
|
538
|
+
for question in use.questions or () if questions is None else questions:
|
|
539
|
+
annotation = result.annotations.get(question.question)
|
|
540
|
+
yield AnsweredPair(
|
|
541
|
+
question,
|
|
542
|
+
result.answers.get(question.question),
|
|
543
|
+
annotation.preview if annotation is not None else None,
|
|
544
|
+
annotation.notes if annotation is not None else None,
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
def banner_answered_pairs(block: ToolResultBlock, use: ToolUseBlock) -> Iterator[AnsweredPair]:
|
|
549
|
+
if (
|
|
550
|
+
block.is_error
|
|
551
|
+
or not block.content.startswith(ANSWERED_PREFIX)
|
|
552
|
+
or not block.content.endswith(ANSWERED_TRAILER)
|
|
553
|
+
or (questions := use.questions) is None
|
|
554
|
+
):
|
|
555
|
+
return
|
|
556
|
+
yield from answered_pairs(block.content[len(ANSWERED_PREFIX) : -len(ANSWERED_TRAILER)], questions)
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
def question_pairs(block: ToolResultBlock, use: ToolUseBlock) -> Iterator[AnsweredPair]:
|
|
560
|
+
if not block.is_error and isinstance(payload := block.tool_use_result, Mapping) and "answers" in payload:
|
|
561
|
+
return structured_answered_pairs(payload, use)
|
|
562
|
+
return banner_answered_pairs(block, use)
|
|
563
|
+
|
|
564
|
+
|
|
537
565
|
def iter_ask_user_question_signals(events: Sequence[TranscriptEvent], spec: MiningSpec) -> Iterator[MiningSignal]:
|
|
538
566
|
uses = tool_uses(events)
|
|
539
567
|
return (
|
|
540
568
|
signal
|
|
541
569
|
for index, event in enumerate(events)
|
|
542
570
|
if isinstance(event, UserEvent)
|
|
543
|
-
for block in
|
|
571
|
+
for block in event.blocks
|
|
572
|
+
if isinstance(block, ToolResultBlock)
|
|
544
573
|
if (use := uses.get(block.tool_use_id)) is not None
|
|
545
574
|
if use.name == "AskUserQuestion"
|
|
546
|
-
|
|
547
|
-
if (questions := use.questions) is not None
|
|
548
|
-
for pair in answered_pairs(block.content[len(ANSWERED_PREFIX) : -len(ANSWERED_TRAILER)], questions)
|
|
575
|
+
for pair in question_pairs(block, use)
|
|
549
576
|
if (signal := question_answer_signal(events, event, index, pair, spec)) is not None
|
|
550
577
|
)
|
|
551
578
|
|