cc-transcript 14.6.0__tar.gz → 14.7.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.
Files changed (161) hide show
  1. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/PKG-INFO +3 -2
  2. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/README.md +2 -1
  3. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/__init__.py +14 -0
  4. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/__init__.pyi +27 -0
  5. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/_native.pyi +142 -7
  6. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/activity.py +10 -4
  7. cc_transcript-14.7.0/cc_transcript/codex.py +235 -0
  8. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/discovery.py +7 -3
  9. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/evidence.py +12 -15
  10. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/judge/similar.py +8 -35
  11. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/judge/verdicts.py +26 -57
  12. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/__init__.py +1 -5
  13. cc_transcript-14.7.0/cc_transcript/mining/formats.py +56 -0
  14. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/sampling.py +19 -31
  15. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/query.py +18 -12
  16. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/tools.py +26 -18
  17. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/pyproject.toml +1 -1
  18. cc_transcript-14.7.0/rust/crates/cli/src/commands/list.rs +225 -0
  19. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/slice.rs +63 -8
  20. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/lib.rs +19 -1
  21. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/activity.rs +145 -25
  22. cc_transcript-14.7.0/rust/crates/core/src/codex/discovery.rs +336 -0
  23. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/codex/mod.rs +1 -1
  24. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/codex/probe.rs +21 -0
  25. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/command.rs +232 -8
  26. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/facts.rs +1 -1
  27. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/feedback.rs +146 -1
  28. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/gateway.rs +9 -0
  29. cc_transcript-14.7.0/rust/crates/core/src/judge.rs +296 -0
  30. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/lib.rs +2 -0
  31. cc_transcript-14.7.0/rust/crates/core/src/literals/command.rs +97 -0
  32. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/query.rs +54 -11
  33. cc_transcript-14.7.0/rust/crates/core/src/rng.rs +141 -0
  34. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/toolcall.rs +709 -35
  35. cc_transcript-14.7.0/rust/crates/py/src/codex.rs +155 -0
  36. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/feedback.rs +35 -0
  37. cc_transcript-14.7.0/rust/crates/py/src/judge.rs +48 -0
  38. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/lib.rs +2 -0
  39. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/mining.rs +37 -3
  40. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/python.rs +54 -8
  41. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/command.rs +15 -0
  42. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/toolcall.rs +300 -3
  43. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/transcript.rs +11 -5
  44. cc_transcript-14.6.0/cc_transcript/mining/formats.py +0 -142
  45. cc_transcript-14.6.0/rust/crates/cli/src/commands/list.rs +0 -75
  46. cc_transcript-14.6.0/rust/crates/core/src/codex/discovery.rs +0 -192
  47. cc_transcript-14.6.0/rust/crates/core/src/literals/command.rs +0 -33
  48. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/Cargo.lock +0 -0
  49. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/Cargo.toml +0 -0
  50. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/LICENSE +0 -0
  51. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/activity_probe.py +0 -0
  52. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/builders.py +0 -0
  53. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/command.py +0 -0
  54. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/context.py +0 -0
  55. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/corrections.py +0 -0
  56. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/cost.py +0 -0
  57. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/decisions.py +0 -0
  58. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/disktruth.py +0 -0
  59. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/extract/__init__.py +0 -0
  60. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/extract/correct.py +0 -0
  61. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/facts.py +0 -0
  62. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/filterspec.py +0 -0
  63. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/heartbeats.py +0 -0
  64. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/ids.py +0 -0
  65. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/judge/__init__.py +0 -0
  66. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/judge/llm.py +0 -0
  67. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/ledger.py +0 -0
  68. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/literals.py +0 -0
  69. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/candidates.py +0 -0
  70. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/confidence.py +0 -0
  71. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/engine.py +0 -0
  72. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/signals.py +0 -0
  73. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/sourcekind.py +0 -0
  74. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/spec.py +0 -0
  75. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/mining/store.py +0 -0
  76. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/models.py +0 -0
  77. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/nlp.py +0 -0
  78. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/notifications.py +0 -0
  79. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/parser.py +0 -0
  80. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/py.typed +0 -0
  81. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/render.py +0 -0
  82. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/sentiment/__init__.py +0 -0
  83. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/sentiment/buckets.py +0 -0
  84. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/sentiment/data/afinn-en-165.tsv +0 -0
  85. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/sentiment/data/domain_overrides.tsv +0 -0
  86. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/sentiment/data/en-ewt.udpipe +0 -0
  87. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/sentiment/engine.py +0 -0
  88. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/sentiment/lexicon.py +0 -0
  89. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/sentiment/scorespec.py +0 -0
  90. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/synthetic.py +0 -0
  91. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/cc_transcript/watch.py +0 -0
  92. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/Cargo.toml +0 -0
  93. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/corrections.rs +0 -0
  94. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/digest.rs +0 -0
  95. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/facts.rs +0 -0
  96. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/grep.rs +0 -0
  97. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/mod.rs +0 -0
  98. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/scratchpad.rs +0 -0
  99. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/show.rs +0 -0
  100. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/stats.rs +0 -0
  101. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/commands/watch.rs +0 -0
  102. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/main.rs +0 -0
  103. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/output.rs +0 -0
  104. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/cli/src/target.rs +0 -0
  105. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/Cargo.toml +0 -0
  106. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/benches/parse.rs +0 -0
  107. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/benches/render.rs +0 -0
  108. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/benches/toolcall.rs +0 -0
  109. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/actor.rs +0 -0
  110. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/buckets.rs +0 -0
  111. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/codex/lower.rs +0 -0
  112. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/codex/parse.rs +0 -0
  113. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/codex/protocol.rs +0 -0
  114. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/codex/types.rs +0 -0
  115. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/context.rs +0 -0
  116. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/corrections.rs +0 -0
  117. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/cost.rs +0 -0
  118. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/discovery.rs +0 -0
  119. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/filter.rs +0 -0
  120. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/ids.rs +0 -0
  121. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/literals/corrections.rs +0 -0
  122. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/literals/feedback.rs +0 -0
  123. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/literals/mining.rs +0 -0
  124. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/literals/mod.rs +0 -0
  125. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/literals/protocol.rs +0 -0
  126. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/notifications.rs +0 -0
  127. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/parse.rs +0 -0
  128. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/protocol.rs +0 -0
  129. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/pystr.rs +0 -0
  130. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/render.rs +0 -0
  131. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/sqlite.rs +0 -0
  132. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/types.rs +0 -0
  133. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/value.rs +0 -0
  134. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/core/src/watch.rs +0 -0
  135. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/Cargo.toml +0 -0
  136. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/build.rs +0 -0
  137. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/data/command_prefix_pins.tsv +0 -0
  138. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/actor_bridge.rs +0 -0
  139. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/bin/stub_gen.rs +0 -0
  140. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/command.rs +0 -0
  141. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/context.rs +0 -0
  142. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/corrections.rs +0 -0
  143. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/discovery.rs +0 -0
  144. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/lexicon.rs +0 -0
  145. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/nlp.rs +0 -0
  146. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/render.rs +0 -0
  147. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/score.rs +0 -0
  148. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/sqlite.rs +0 -0
  149. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/toolcall.rs +0 -0
  150. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/attachment.rs +0 -0
  151. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/blocks.rs +0 -0
  152. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/convert.rs +0 -0
  153. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/dunder.rs +0 -0
  154. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/events.rs +0 -0
  155. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/meta.rs +0 -0
  156. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/mod.rs +0 -0
  157. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/print.rs +0 -0
  158. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/store.rs +0 -0
  159. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/system.rs +0 -0
  160. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/views/toolresult.rs +0 -0
  161. {cc_transcript-14.6.0 → cc_transcript-14.7.0}/rust/crates/py/src/watch.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cc-transcript
3
- Version: 14.6.0
3
+ Version: 14.7.0
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -118,7 +118,7 @@ transcript = parse(discover()[0], drop=NOISE_SPEC)
118
118
  print(len(transcript.events), "events after the noise drop")
119
119
  ```
120
120
 
121
- `discover()` lists every transcript on disk newest first, `stream` fans a whole corpus across the parse pool, and `resolve` finds one session by UUID. The [getting-started guide](https://yasyf.github.io/cc-transcript/docs/getting-started/index.html) builds this out to a composed filter and a sentiment score.
121
+ `discover()` lists every transcript on disk newest first, `stream` fans a whole corpus across the parse pool, and `resolve` finds one session by UUID. `parse` also reads OpenAI Codex CLI rollouts — hand it a path from `~/.codex/sessions` and the same typed events come back. The [getting-started guide](https://yasyf.github.io/cc-transcript/docs/getting-started/index.html) builds this out to a composed filter and a sentiment score.
122
122
 
123
123
  ## More in the docs
124
124
 
@@ -127,6 +127,7 @@ print(len(transcript.events), "events after the noise drop")
127
127
  - [Sentiment scoring](https://yasyf.github.io/cc-transcript/docs/guide/scoring-sentiment.html) buckets conversations and scores them around any inference engine.
128
128
  - [Feedback mining](https://yasyf.github.io/cc-transcript/docs/guide/mining-feedback.html) runs detectors, confidence calibration, and LLM verdict passes over your corpus.
129
129
  - [The Rust engine](https://yasyf.github.io/cc-transcript/docs/guide/rust-engine.html) is the implementation — parsing, filtering, scoring, and mining — its correctness pinned by hand-owned literals and golden fixtures.
130
+ - [Codex rollouts](https://yasyf.github.io/cc-transcript/docs/guide/codex-rollouts.html) make the parser two-provider: OpenAI Codex CLI sessions lower into the same typed events, with rollout discovery, subagent joins, and per-session lifecycle and token totals. `list --provider codex` finds them from the shell.
130
131
  - [API reference](https://yasyf.github.io/cc-transcript/reference/index.html) documents the complete typed surface, from `TranscriptEvent` to `SessionActivity`.
131
132
 
132
133
  Read the [docs](https://yasyf.github.io/cc-transcript/) for the full guide. Licensed under [PolyForm Noncommercial 1.0.0](https://github.com/yasyf/cc-transcript/blob/main/LICENSE).
@@ -82,7 +82,7 @@ transcript = parse(discover()[0], drop=NOISE_SPEC)
82
82
  print(len(transcript.events), "events after the noise drop")
83
83
  ```
84
84
 
85
- `discover()` lists every transcript on disk newest first, `stream` fans a whole corpus across the parse pool, and `resolve` finds one session by UUID. The [getting-started guide](https://yasyf.github.io/cc-transcript/docs/getting-started/index.html) builds this out to a composed filter and a sentiment score.
85
+ `discover()` lists every transcript on disk newest first, `stream` fans a whole corpus across the parse pool, and `resolve` finds one session by UUID. `parse` also reads OpenAI Codex CLI rollouts — hand it a path from `~/.codex/sessions` and the same typed events come back. The [getting-started guide](https://yasyf.github.io/cc-transcript/docs/getting-started/index.html) builds this out to a composed filter and a sentiment score.
86
86
 
87
87
  ## More in the docs
88
88
 
@@ -91,6 +91,7 @@ print(len(transcript.events), "events after the noise drop")
91
91
  - [Sentiment scoring](https://yasyf.github.io/cc-transcript/docs/guide/scoring-sentiment.html) buckets conversations and scores them around any inference engine.
92
92
  - [Feedback mining](https://yasyf.github.io/cc-transcript/docs/guide/mining-feedback.html) runs detectors, confidence calibration, and LLM verdict passes over your corpus.
93
93
  - [The Rust engine](https://yasyf.github.io/cc-transcript/docs/guide/rust-engine.html) is the implementation — parsing, filtering, scoring, and mining — its correctness pinned by hand-owned literals and golden fixtures.
94
+ - [Codex rollouts](https://yasyf.github.io/cc-transcript/docs/guide/codex-rollouts.html) make the parser two-provider: OpenAI Codex CLI sessions lower into the same typed events, with rollout discovery, subagent joins, and per-session lifecycle and token totals. `list --provider codex` finds them from the shell.
94
95
  - [API reference](https://yasyf.github.io/cc-transcript/reference/index.html) documents the complete typed surface, from `TranscriptEvent` to `SessionActivity`.
95
96
 
96
97
  Read the [docs](https://yasyf.github.io/cc-transcript/) for the full guide. Licensed under [PolyForm Noncommercial 1.0.0](https://github.com/yasyf/cc-transcript/blob/main/LICENSE).
@@ -34,9 +34,11 @@ EXPORTS: dict[str, str] = {
34
34
  ),
35
35
  "cc_transcript.tools": (
36
36
  "TOOL_ALIASES",
37
+ "ApplyPatchCall",
37
38
  "AskUserQuestionResult",
38
39
  "BashCall",
39
40
  "BashResult",
41
+ "CodeModeCall",
40
42
  "EditCall",
41
43
  "EditResult",
42
44
  "EditSpan",
@@ -48,6 +50,7 @@ EXPORTS: dict[str, str] = {
48
50
  "NotebookEditCall",
49
51
  "OtherCall",
50
52
  "OtherResult",
53
+ "PatchEdit",
51
54
  "QuestionAnnotation",
52
55
  "ReadCall",
53
56
  "ReadResult",
@@ -66,11 +69,15 @@ EXPORTS: dict[str, str] = {
66
69
  "ToolResult",
67
70
  "ToolResultBase",
68
71
  "ToolResultError",
72
+ "UpdatePlanCall",
69
73
  "WorkflowCall",
70
74
  "WriteCall",
71
75
  "WriteResult",
76
+ "WriteStdinCall",
77
+ "edits_of",
72
78
  "expand_tool_names",
73
79
  "file_path_of",
80
+ "file_paths_of",
74
81
  "hunks_of",
75
82
  "matches_names",
76
83
  "mcp_access",
@@ -181,6 +188,13 @@ EXPORTS: dict[str, str] = {
181
188
  "resolve",
182
189
  "subagent_paths",
183
190
  ),
191
+ "cc_transcript.codex": (
192
+ "CodexPendingItem",
193
+ "CodexRollout",
194
+ "CodexSessionInfo",
195
+ "CodexUsage",
196
+ "Lifecycle",
197
+ ),
184
198
  "cc_transcript.activity": (
185
199
  "Edit",
186
200
  "SessionActivity",
@@ -27,6 +27,14 @@ from cc_transcript.builders import (
27
27
  keep_only as keep_only,
28
28
  )
29
29
 
30
+ from cc_transcript.codex import (
31
+ CodexPendingItem as CodexPendingItem,
32
+ CodexRollout as CodexRollout,
33
+ CodexSessionInfo as CodexSessionInfo,
34
+ CodexUsage as CodexUsage,
35
+ Lifecycle as Lifecycle,
36
+ )
37
+
30
38
  from cc_transcript.command import (
31
39
  Command as Command,
32
40
  CommandLine as CommandLine,
@@ -225,9 +233,11 @@ from cc_transcript.synthetic import (
225
233
  )
226
234
 
227
235
  from cc_transcript.tools import (
236
+ ApplyPatchCall as ApplyPatchCall,
228
237
  AskUserQuestionResult as AskUserQuestionResult,
229
238
  BashCall as BashCall,
230
239
  BashResult as BashResult,
240
+ CodeModeCall as CodeModeCall,
231
241
  EditCall as EditCall,
232
242
  EditResult as EditResult,
233
243
  EditSpan as EditSpan,
@@ -239,6 +249,7 @@ from cc_transcript.tools import (
239
249
  NotebookEditCall as NotebookEditCall,
240
250
  OtherCall as OtherCall,
241
251
  OtherResult as OtherResult,
252
+ PatchEdit as PatchEdit,
242
253
  QuestionAnnotation as QuestionAnnotation,
243
254
  ReadCall as ReadCall,
244
255
  ReadResult as ReadResult,
@@ -258,11 +269,15 @@ from cc_transcript.tools import (
258
269
  ToolResult as ToolResult,
259
270
  ToolResultBase as ToolResultBase,
260
271
  ToolResultError as ToolResultError,
272
+ UpdatePlanCall as UpdatePlanCall,
261
273
  WorkflowCall as WorkflowCall,
262
274
  WriteCall as WriteCall,
263
275
  WriteResult as WriteResult,
276
+ WriteStdinCall as WriteStdinCall,
277
+ edits_of as edits_of,
264
278
  expand_tool_names as expand_tool_names,
265
279
  file_path_of as file_path_of,
280
+ file_paths_of as file_paths_of,
266
281
  hunks_of as hunks_of,
267
282
  matches_names as matches_names,
268
283
  mcp_access as mcp_access,
@@ -287,6 +302,7 @@ __all__ = [
287
302
  "ASSISTANTS",
288
303
  "Action",
289
304
  "ApiError",
305
+ "ApplyPatchCall",
290
306
  "AskUserQuestionResult",
291
307
  "AssistantEvent",
292
308
  "AsyncHookResponse",
@@ -302,6 +318,11 @@ __all__ = [
302
318
  "CacheCreation",
303
319
  "CandidatePair",
304
320
  "CcVersion",
321
+ "CodeModeCall",
322
+ "CodexPendingItem",
323
+ "CodexRollout",
324
+ "CodexSessionInfo",
325
+ "CodexUsage",
305
326
  "Command",
306
327
  "CommandLine",
307
328
  "CommandLineQuery",
@@ -342,6 +363,7 @@ __all__ = [
342
363
  "HydratedWindow",
343
364
  "InitInfo",
344
365
  "JUNK_USER_MESSAGE_RE",
366
+ "Lifecycle",
345
367
  "McpServer",
346
368
  "ModeEvent",
347
369
  "ModelPricing",
@@ -360,6 +382,7 @@ __all__ = [
360
382
  "OtherResult",
361
383
  "OtherSystemDetail",
362
384
  "PRICING",
385
+ "PatchEdit",
363
386
  "Plugin",
364
387
  "PreservedMessages",
365
388
  "PreservedSegment",
@@ -417,6 +440,7 @@ __all__ = [
417
440
  "TurnDuration",
418
441
  "TurnRef",
419
442
  "USERS",
443
+ "UpdatePlanCall",
420
444
  "Usage",
421
445
  "UserClassifier",
422
446
  "UserEvent",
@@ -426,6 +450,7 @@ __all__ = [
426
450
  "WorkflowCall",
427
451
  "WriteCall",
428
452
  "WriteResult",
453
+ "WriteStdinCall",
429
454
  "annotate_spec",
430
455
  "apply_spec",
431
456
  "assistant_line",
@@ -446,9 +471,11 @@ __all__ = [
446
471
  "drop_short",
447
472
  "drop_sidechain",
448
473
  "drop_synthetic",
474
+ "edits_of",
449
475
  "expand_tool_names",
450
476
  "export_activity",
451
477
  "file_path_of",
478
+ "file_paths_of",
452
479
  "find_in",
453
480
  "git_corrections",
454
481
  "harvest_pairs",
@@ -14,6 +14,7 @@ import pathlib
14
14
  import typing
15
15
  __all__ = [
16
16
  "ApiError",
17
+ "ApplyPatchCall",
17
18
  "AskUserQuestionResult",
18
19
  "AssistantEvent",
19
20
  "AsyncHookResponse",
@@ -22,6 +23,7 @@ __all__ = [
22
23
  "BashCall",
23
24
  "BashResult",
24
25
  "CacheCreation",
26
+ "CodeModeCall",
25
27
  "Command",
26
28
  "CommandLine",
27
29
  "CommandLineQuery",
@@ -57,6 +59,7 @@ __all__ = [
57
59
  "OtherResult",
58
60
  "OtherSystemDetail",
59
61
  "ParseStream",
62
+ "PatchEdit",
60
63
  "Plugin",
61
64
  "PreservedMessages",
62
65
  "PreservedSegment",
@@ -92,6 +95,7 @@ __all__ = [
92
95
  "ToolUseBlock",
93
96
  "Transcript",
94
97
  "TurnDuration",
98
+ "UpdatePlanCall",
95
99
  "Usage",
96
100
  "UserEvent",
97
101
  "WatchTailer",
@@ -99,11 +103,18 @@ __all__ = [
99
103
  "WorkflowCall",
100
104
  "WriteCall",
101
105
  "WriteResult",
106
+ "WriteStdinCall",
102
107
  "activity_hunk_overlap",
103
108
  "activity_lift",
104
109
  "activity_lift_from_events",
110
+ "activity_overlap_between",
111
+ "activity_parse_show_hunks",
105
112
  "bucket_events_from_events",
106
113
  "cli_main",
114
+ "codex_children_of",
115
+ "codex_discover",
116
+ "codex_resolve",
117
+ "codex_session_info",
107
118
  "command_parse",
108
119
  "command_prefixes",
109
120
  "context_capture_window",
@@ -116,12 +127,16 @@ __all__ = [
116
127
  "discovery_is_subagent_path",
117
128
  "discovery_subagent_paths",
118
129
  "discovery_subagent_transcripts",
130
+ "edits_of",
119
131
  "embedded_literals",
120
132
  "expand_tool_names",
121
133
  "file_path_of",
134
+ "file_paths_of",
122
135
  "hunks_of",
123
136
  "ids_canonical_json",
124
137
  "ids_tool_digest",
138
+ "judge_exact_upper_bound",
139
+ "judge_sample_audit",
125
140
  "lexicon_has_hit",
126
141
  "lexicon_overrides",
127
142
  "lexicon_polarity",
@@ -130,6 +145,7 @@ __all__ = [
130
145
  "mcp_access",
131
146
  "mcp_parts",
132
147
  "mine_events",
148
+ "mining_sample_refs",
133
149
  "nlp_analyze",
134
150
  "noise_spec_json",
135
151
  "notifications_from_events",
@@ -175,6 +191,17 @@ class ApiError:
175
191
  @property
176
192
  def details(self) -> typing.Optional[builtins.str]: ...
177
193
 
194
+ @typing.final
195
+ class ApplyPatchCall(ToolCallBase):
196
+ r"""
197
+ A codex apply_patch call: one :class:`PatchEdit` per file in the envelope.
198
+ """
199
+ __match_args__: typing.ClassVar[tuple[str, ...]]
200
+ @property
201
+ def name(self) -> builtins.str: ...
202
+ @property
203
+ def edits(self) -> tuple[PatchEdit, ...]: ...
204
+
178
205
  @typing.final
179
206
  class AskUserQuestionResult(ToolResultBase):
180
207
  r"""
@@ -382,6 +409,18 @@ class CacheCreation:
382
409
  @property
383
410
  def ephemeral_1h_input_tokens(self) -> builtins.int: ...
384
411
 
412
+ @typing.final
413
+ class CodeModeCall(ToolCallBase):
414
+ r"""
415
+ A codex code-mode ``exec`` call whose ``source`` is a free-form program, kept
416
+ verbatim — never JSON-decoded.
417
+ """
418
+ __match_args__: typing.ClassVar[tuple[str, ...]]
419
+ @property
420
+ def name(self) -> builtins.str: ...
421
+ @property
422
+ def source(self) -> builtins.str: ...
423
+
385
424
  @typing.final
386
425
  class Command:
387
426
  r"""
@@ -430,6 +469,7 @@ class Command:
430
469
  @classmethod
431
470
  def parse(cls, raw: builtins.str) -> typing.Optional[Command]: ...
432
471
  def runs(self, *argv: typing.Any) -> builtins.bool: ...
472
+ def split_options(self, value_flags: typing.Sequence[builtins.str]) -> tuple[tuple[Word, ...], tuple[Word, ...]]: ...
433
473
  def matches(self, pattern: builtins.str) -> builtins.bool: ...
434
474
  def has_arg(self, *patterns: typing.Any) -> builtins.bool: ...
435
475
  def __str__(self) -> builtins.str: ...
@@ -1228,6 +1268,23 @@ class ParseStream:
1228
1268
  def recv(self) -> Transcript | None: ...
1229
1269
  def recv_many(self, max: builtins.int) -> list[Transcript]: ...
1230
1270
 
1271
+ @typing.final
1272
+ class PatchEdit:
1273
+ r"""
1274
+ One file's edit within a codex apply_patch envelope: its ``file_path``, ``kind``
1275
+ (``"add"``/``"update"``/``"delete"``), rename ``move_path``, and before/after
1276
+ ``hunks`` (empty for a deletion, one addition hunk for an add).
1277
+ """
1278
+ __match_args__: typing.ClassVar[tuple[str, ...]]
1279
+ @property
1280
+ def file_path(self) -> builtins.str: ...
1281
+ @property
1282
+ def kind(self) -> typing.Literal["add", "update", "delete"]: ...
1283
+ @property
1284
+ def move_path(self) -> typing.Optional[builtins.str]: ...
1285
+ @property
1286
+ def hunks(self) -> tuple[Hunk, ...]: ...
1287
+
1231
1288
  @typing.final
1232
1289
  class Plugin:
1233
1290
  r"""
@@ -1516,6 +1573,8 @@ class RustFeedbackStore:
1516
1573
  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]: ...
1517
1574
  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]]]: ...
1518
1575
  def judged(self, role: builtins.str, prompt_version: builtins.int) -> asyncio.Future[list[dict[str, typing.Any]]]: ...
1576
+ def suggest_canonical_keys(self, query: typing.Sequence[builtins.int], prompt_version: builtins.int, k: builtins.int) -> asyncio.Future[list[tuple[str, float, list[str]]]]: ...
1577
+ def near_duplicate_keys(self, prompt_version: builtins.int, threshold: builtins.float) -> asyncio.Future[list[tuple[str, str, float]]]: ...
1519
1578
 
1520
1579
  @typing.final
1521
1580
  class ServerToolUse:
@@ -1810,13 +1869,14 @@ class ToolCallBase:
1810
1869
  Attributes:
1811
1870
  name: The tool name exactly as invoked (aliases are not normalized —
1812
1871
  the digest must match what the hook saw).
1813
- raw: The verbatim input mapping; the only digest substrate.
1872
+ raw: The verbatim input value — a mapping for structured calls, a plain
1873
+ string for Codex calls, or None when absent. The only digest substrate.
1814
1874
  """
1815
1875
  __match_args__: typing.ClassVar[tuple[str, ...]]
1816
1876
  @property
1817
1877
  def name(self) -> builtins.str: ...
1818
1878
  @property
1819
- def raw(self) -> collections.abc.Mapping[str, typing.Any]: ...
1879
+ def raw(self) -> collections.abc.Mapping[str, typing.Any] | str | None: ...
1820
1880
  @property
1821
1881
  def digest(self) -> ids.ToolDigest:
1822
1882
  r"""
@@ -1941,15 +2001,14 @@ class Transcript:
1941
2001
  The parsed events of a single transcript file, backed by the native parse
1942
2002
  output; ``events`` materializes lazy views on access.
1943
2003
 
1944
- One parse owns one ``Arc<Vec<Entry>>`` that every event and nested view shares,
1945
- so retaining any single view keeps that whole parse's entries alive; keeping one
1946
- event from each of several parses retains all of their entries. The live
1947
- :class:`~watch.WatchEvent` stream is exempt — its tailer builds a
1948
- one-entry Arc per yielded event, so a held watch event pins only itself.
2004
+ One parse owns one ``Arc<Vec<Entry>>`` shared by every view, so retaining any
2005
+ view keeps the whole parse's entries alive; the live
2006
+ :class:`~watch.WatchEvent` stream is exempt (one-entry Arc each).
1949
2007
 
1950
2008
  Attributes:
1951
2009
  path: The transcript's path on disk; None for a bytes parse.
1952
2010
  mtime: The transcript's modification time when parsed.
2011
+ provider: The transcript's source provider: "claude" or "codex".
1953
2012
  events: The parsed events, in file order.
1954
2013
  """
1955
2014
  @property
@@ -1957,6 +2016,8 @@ class Transcript:
1957
2016
  @property
1958
2017
  def mtime(self) -> builtins.float: ...
1959
2018
  @property
2019
+ def provider(self) -> typing.Literal["claude", "codex"]: ...
2020
+ @property
1960
2021
  def events(self) -> EventList: ...
1961
2022
 
1962
2023
  @typing.final
@@ -1981,6 +2042,19 @@ class TurnDuration:
1981
2042
  @property
1982
2043
  def pending_background_agent_count(self) -> typing.Optional[builtins.int]: ...
1983
2044
 
2045
+ @typing.final
2046
+ class UpdatePlanCall(ToolCallBase):
2047
+ r"""
2048
+ A codex update_plan call: the plan-step array and its optional narration.
2049
+ """
2050
+ __match_args__: typing.ClassVar[tuple[str, ...]]
2051
+ @property
2052
+ def name(self) -> builtins.str: ...
2053
+ @property
2054
+ def plan(self) -> list[typing.Any] | None: ...
2055
+ @property
2056
+ def explanation(self) -> typing.Optional[builtins.str]: ...
2057
+
1984
2058
  @typing.final
1985
2059
  class Usage:
1986
2060
  r"""
@@ -2178,12 +2252,33 @@ class WriteResult(ToolResultBase):
2178
2252
  @property
2179
2253
  def user_modified(self) -> bool: ...
2180
2254
 
2255
+ @typing.final
2256
+ class WriteStdinCall(ToolCallBase):
2257
+ r"""
2258
+ A codex write_stdin call: the text written to a session's stdin and its target.
2259
+ """
2260
+ __match_args__: typing.ClassVar[tuple[str, ...]]
2261
+ @property
2262
+ def name(self) -> builtins.str: ...
2263
+ @property
2264
+ def chars(self) -> typing.Any | None: ...
2265
+ @property
2266
+ def session_id(self) -> builtins.int: ...
2267
+ @property
2268
+ def yield_time_ms(self) -> typing.Optional[builtins.int]: ...
2269
+ @property
2270
+ def max_output_tokens(self) -> typing.Optional[builtins.int]: ...
2271
+
2181
2272
  def activity_hunk_overlap(a_old: builtins.str, a_new: builtins.str, b_old: builtins.str, b_new: builtins.str) -> builtins.float: ...
2182
2273
 
2183
2274
  def activity_lift(path: builtins.str, max_events: builtins.int) -> dict[str, typing.Any]: ...
2184
2275
 
2185
2276
  def activity_lift_from_events(events: list[models.TranscriptEvent], opener_flags: typing.Optional[typing.Sequence[builtins.bool]] = None) -> list[dict[str, typing.Any]]: ...
2186
2277
 
2278
+ def activity_overlap_between(incorrect: typing.Sequence[tuple[builtins.str, builtins.str]], correction: typing.Sequence[tuple[builtins.str, builtins.str]]) -> builtins.float: ...
2279
+
2280
+ def activity_parse_show_hunks(diff: builtins.str) -> builtins.list[tuple[builtins.str, builtins.str]]: ...
2281
+
2187
2282
  def bucket_events_from_events(events: list[models.TranscriptEvent]) -> list[dict[str, typing.Any]]: ...
2188
2283
 
2189
2284
  def cli_main() -> builtins.int:
@@ -2193,6 +2288,14 @@ def cli_main() -> builtins.int:
2193
2288
  run, and the exit code returned verbatim for the wrapper's `sys.exit`.
2194
2289
  """
2195
2290
 
2291
+ def codex_children_of(session_id: builtins.str, root: typing.Optional[builtins.str] = None) -> builtins.list[tuple[pathlib.Path, builtins.str, builtins.bool]]: ...
2292
+
2293
+ def codex_discover(root: typing.Optional[builtins.str | os.PathLike | pathlib.Path] = None) -> builtins.list[tuple[pathlib.Path, builtins.str, builtins.bool]]: ...
2294
+
2295
+ def codex_resolve(session_id: builtins.str, root: typing.Optional[builtins.str | os.PathLike | pathlib.Path] = None) -> typing.Optional[pathlib.Path]: ...
2296
+
2297
+ def codex_session_info(path: builtins.str) -> dict[str, typing.Any]: ...
2298
+
2196
2299
  def command_parse(command: builtins.str) -> dict[str, typing.Any]: ...
2197
2300
 
2198
2301
  def command_prefixes(commands: typing.Sequence[builtins.str]) -> builtins.list[builtins.list[builtins.str]]: ...
@@ -2217,6 +2320,12 @@ def discovery_subagent_paths(path: builtins.str | os.PathLike | pathlib.Path) ->
2217
2320
 
2218
2321
  def discovery_subagent_transcripts(path: builtins.str | os.PathLike | pathlib.Path) -> dict[str, pathlib.Path]: ...
2219
2322
 
2323
+ def edits_of(call: tools.ToolCall | tools.FallbackCall) -> tuple[tuple[str, tuple[Hunk, ...]], ...]:
2324
+ r"""
2325
+ Every ``(file_path, hunks)`` a call lowers to: one entry per patched file for
2326
+ apply_patch (empty hunks for a deletion), else the singular 0/1-element projection.
2327
+ """
2328
+
2220
2329
  def embedded_literals() -> dict[str, str | float | int | list[str]]: ...
2221
2330
 
2222
2331
  def expand_tool_names(spec: builtins.str) -> frozenset[str]:
@@ -2229,6 +2338,12 @@ def file_path_of(call: tools.ToolCall | tools.FallbackCall) -> typing.Optional[b
2229
2338
  The file a call targets, when it targets one.
2230
2339
  """
2231
2340
 
2341
+ def file_paths_of(call: tools.ToolCall | tools.FallbackCall) -> tuple[str, ...]:
2342
+ r"""
2343
+ Every file a call targets: one entry per patched file for apply_patch, else the
2344
+ singular projection as a 0/1-element tuple.
2345
+ """
2346
+
2232
2347
  def hunks_of(call: tools.ToolCall | tools.FallbackCall) -> tuple[Hunk, ...]:
2233
2348
  r"""
2234
2349
  Lower an edit-shaped call to before/after hunks; ``()`` for the rest.
@@ -2243,6 +2358,19 @@ def ids_canonical_json(value_json: builtins.str) -> builtins.str: ...
2243
2358
 
2244
2359
  def ids_tool_digest(name: builtins.str, input_json: builtins.str) -> builtins.str: ...
2245
2360
 
2361
+ def judge_exact_upper_bound(hits: builtins.int, n: builtins.int, alpha: builtins.float) -> builtins.float:
2362
+ r"""
2363
+ The exact (Clopper-Pearson) one-sided upper confidence bound
2364
+ (judge/verdicts.py exact_upper_bound).
2365
+ """
2366
+
2367
+ def judge_sample_audit(rows: typing.Sequence[tuple[builtins.str, builtins.str, builtins.float, builtins.bool]], accepts: builtins.int, rejects: builtins.int, seed: builtins.str, quotas: typing.Sequence[tuple[builtins.str, typing.Optional[builtins.int]]], remainder_kind: builtins.str, oversample_share: builtins.float) -> tuple[builtins.list[builtins.int], builtins.list[builtins.int]]:
2368
+ r"""
2369
+ The seeded stratified audit draw over pre-coerced judged rows
2370
+ (judge/verdicts.py sample_audit): returns `(core, oversample)` as row indexes
2371
+ into `rows`.
2372
+ """
2373
+
2246
2374
  def lexicon_has_hit(text: builtins.str, want_negative: builtins.bool) -> builtins.bool: ...
2247
2375
 
2248
2376
  def lexicon_overrides() -> builtins.list[tuple[builtins.str, builtins.int]]: ...
@@ -2300,6 +2428,13 @@ def mcp_parts(name: builtins.str) -> tuple[str, str] | None:
2300
2428
 
2301
2429
  def mine_events(events: list[models.TranscriptEvent], spec_json: builtins.str, callable_formats: typing.Sequence[tuple[builtins.str, typing.Any, typing.Any]]) -> list[dict[str, typing.Any]]: ...
2302
2430
 
2431
+ def mining_sample_refs(data: bytes, n: builtins.int, exclude: typing.Sequence[tuple[builtins.str, builtins.str]], exclusion_radius: builtins.int, seed: builtins.str) -> builtins.list[tuple[builtins.int, builtins.str, builtins.str]]:
2432
+ r"""
2433
+ The seeded negative-window draw over a transcript's completed turns
2434
+ (mining/sampling.py sample_windows candidate build + draw): returns each drawn
2435
+ anchor as `(turn_index, session_id, event_uuid)`, sorted by turn index.
2436
+ """
2437
+
2303
2438
  def nlp_analyze(text: builtins.str) -> builtins.list[tuple[builtins.str, builtins.str, builtins.str, builtins.str, builtins.int, builtins.int, builtins.int, builtins.bool]]:
2304
2439
  r"""
2305
2440
  Analyze `text` with the embedded UDPipe model. Returns, per token,
@@ -22,7 +22,7 @@ from cc_transcript.filterspec import event_meta
22
22
  from cc_transcript.ids import EventRef
23
23
  from cc_transcript.models import AssistantEvent, ToolResultBlock, ToolUseBlock, UserEvent
24
24
  from cc_transcript.parser import parse
25
- from cc_transcript.tools import file_path_of, hunks_of, parse_tool_call, parse_tool_result
25
+ from cc_transcript.tools import edits_of, parse_tool_call, parse_tool_result
26
26
 
27
27
  if TYPE_CHECKING:
28
28
  from collections.abc import Sequence
@@ -63,6 +63,8 @@ class ToolUse:
63
63
  result: The matching result block, or None when none ever arrived.
64
64
  result_ts: The timestamp of the user entry carrying the result, or
65
65
  None when no result ever arrived.
66
+ edits: The call's lowered ``(file_path, hunks)`` entries, one per
67
+ edited file.
66
68
  turn_index: The index of the turn the call fired in.
67
69
  ts: The timestamp of the assistant entry carrying the call.
68
70
  """
@@ -71,6 +73,7 @@ class ToolUse:
71
73
  call: ToolCall | FallbackCall
72
74
  result: ToolResultBlock | None
73
75
  result_ts: datetime | None
76
+ edits: tuple[tuple[str, tuple[Hunk, ...]], ...]
74
77
  turn_index: int
75
78
  ts: datetime
76
79
 
@@ -139,11 +142,12 @@ class Turn:
139
142
 
140
143
  @property
141
144
  def edits(self) -> tuple[Edit, ...]:
142
- """The turn's file modifications: tool uses with hunks and a file path."""
145
+ """The turn's file modifications: one entry per edited file (every file of an
146
+ apply_patch), in order."""
143
147
  return tuple(
144
148
  Edit(file_path=path, hunks=hunks, tool=use.call.name, ref=use.ref, turn_index=use.turn_index, ts=use.ts)
145
149
  for use in self.tool_uses
146
- if (hunks := hunks_of(use.call)) and (path := file_path_of(use.call)) is not None
150
+ for path, hunks in use.edits
147
151
  )
148
152
 
149
153
 
@@ -210,12 +214,14 @@ class SessionActivity:
210
214
  if isinstance(candidate, ToolResultBlock) and candidate.tool_use_id == use["tool_use_id"]
211
215
  )
212
216
  result_ts = result_event.meta.timestamp
217
+ call = parse_tool_call(block.name, block.input, on_error="other")
213
218
  tool_uses.append(
214
219
  ToolUse(
215
220
  ref=EventRef(session_id, event.meta.uuid, block.id),
216
- call=parse_tool_call(block.name, block.input, on_error="other"),
221
+ call=call,
217
222
  result=result,
218
223
  result_ts=result_ts,
224
+ edits=edits_of(call),
219
225
  turn_index=index,
220
226
  ts=event.meta.timestamp,
221
227
  )