cc-transcript 14.5.0__tar.gz → 14.6.1__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 (154) hide show
  1. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/PKG-INFO +1 -1
  2. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/__init__.py +8 -0
  3. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/__init__.pyi +15 -0
  4. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/_native.pyi +71 -6
  5. cc_transcript-14.6.1/cc_transcript/codex.py +212 -0
  6. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/command.py +4 -0
  7. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/discovery.py +7 -3
  8. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/judge/verdicts.py +6 -1
  9. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/literals.py +7 -1
  10. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/pyproject.toml +1 -1
  11. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/target.rs +2 -2
  12. cc_transcript-14.6.1/rust/crates/core/src/codex/discovery.rs +210 -0
  13. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/codex/mod.rs +4 -0
  14. cc_transcript-14.6.1/rust/crates/core/src/codex/probe.rs +567 -0
  15. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/command.rs +772 -39
  16. cc_transcript-14.6.1/rust/crates/core/src/gateway.rs +216 -0
  17. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/lib.rs +1 -0
  18. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/literals/command.rs +5 -0
  19. cc_transcript-14.6.1/rust/crates/py/src/codex.rs +144 -0
  20. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/context.rs +2 -2
  21. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/lib.rs +1 -0
  22. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/python.rs +40 -16
  23. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/render.rs +4 -4
  24. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/command.rs +126 -2
  25. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/mod.rs +1 -0
  26. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/transcript.rs +11 -5
  27. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/Cargo.lock +0 -0
  28. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/Cargo.toml +0 -0
  29. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/LICENSE +0 -0
  30. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/README.md +0 -0
  31. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/activity.py +0 -0
  32. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/activity_probe.py +0 -0
  33. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/builders.py +0 -0
  34. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/context.py +0 -0
  35. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/corrections.py +0 -0
  36. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/cost.py +0 -0
  37. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/decisions.py +0 -0
  38. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/disktruth.py +0 -0
  39. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/evidence.py +0 -0
  40. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/extract/__init__.py +0 -0
  41. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/extract/correct.py +0 -0
  42. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/facts.py +0 -0
  43. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/filterspec.py +0 -0
  44. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/heartbeats.py +0 -0
  45. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/ids.py +0 -0
  46. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/judge/__init__.py +0 -0
  47. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/judge/llm.py +0 -0
  48. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/judge/similar.py +0 -0
  49. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/ledger.py +0 -0
  50. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/__init__.py +0 -0
  51. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/candidates.py +0 -0
  52. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/confidence.py +0 -0
  53. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/engine.py +0 -0
  54. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/formats.py +0 -0
  55. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/sampling.py +0 -0
  56. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/signals.py +0 -0
  57. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/sourcekind.py +0 -0
  58. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/spec.py +0 -0
  59. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/mining/store.py +0 -0
  60. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/models.py +0 -0
  61. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/nlp.py +0 -0
  62. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/notifications.py +0 -0
  63. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/parser.py +0 -0
  64. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/py.typed +0 -0
  65. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/query.py +0 -0
  66. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/render.py +0 -0
  67. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/sentiment/__init__.py +0 -0
  68. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/sentiment/buckets.py +0 -0
  69. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/sentiment/data/afinn-en-165.tsv +0 -0
  70. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/sentiment/data/domain_overrides.tsv +0 -0
  71. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/sentiment/data/en-ewt.udpipe +0 -0
  72. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/sentiment/engine.py +0 -0
  73. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/sentiment/lexicon.py +0 -0
  74. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/sentiment/scorespec.py +0 -0
  75. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/synthetic.py +0 -0
  76. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/tools.py +0 -0
  77. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/cc_transcript/watch.py +0 -0
  78. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/Cargo.toml +0 -0
  79. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/corrections.rs +0 -0
  80. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/digest.rs +0 -0
  81. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/facts.rs +0 -0
  82. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/grep.rs +0 -0
  83. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/list.rs +0 -0
  84. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/mod.rs +0 -0
  85. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/scratchpad.rs +0 -0
  86. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/show.rs +0 -0
  87. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/slice.rs +0 -0
  88. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/stats.rs +0 -0
  89. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/commands/watch.rs +0 -0
  90. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/lib.rs +0 -0
  91. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/main.rs +0 -0
  92. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/cli/src/output.rs +0 -0
  93. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/Cargo.toml +0 -0
  94. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/benches/parse.rs +0 -0
  95. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/benches/render.rs +0 -0
  96. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/benches/toolcall.rs +0 -0
  97. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/activity.rs +0 -0
  98. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/actor.rs +0 -0
  99. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/buckets.rs +0 -0
  100. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/codex/lower.rs +0 -0
  101. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/codex/parse.rs +0 -0
  102. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/codex/protocol.rs +0 -0
  103. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/codex/types.rs +0 -0
  104. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/context.rs +0 -0
  105. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/corrections.rs +0 -0
  106. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/cost.rs +0 -0
  107. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/discovery.rs +0 -0
  108. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/facts.rs +0 -0
  109. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/feedback.rs +0 -0
  110. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/filter.rs +0 -0
  111. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/ids.rs +0 -0
  112. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/literals/corrections.rs +0 -0
  113. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/literals/feedback.rs +0 -0
  114. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/literals/mining.rs +0 -0
  115. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/literals/mod.rs +0 -0
  116. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/literals/protocol.rs +0 -0
  117. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/notifications.rs +0 -0
  118. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/parse.rs +0 -0
  119. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/protocol.rs +0 -0
  120. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/pystr.rs +0 -0
  121. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/query.rs +0 -0
  122. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/render.rs +0 -0
  123. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/sqlite.rs +0 -0
  124. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/toolcall.rs +0 -0
  125. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/types.rs +0 -0
  126. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/value.rs +0 -0
  127. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/core/src/watch.rs +0 -0
  128. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/Cargo.toml +0 -0
  129. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/build.rs +0 -0
  130. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/data/command_prefix_pins.tsv +0 -0
  131. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/actor_bridge.rs +0 -0
  132. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/bin/stub_gen.rs +0 -0
  133. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/command.rs +0 -0
  134. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/corrections.rs +0 -0
  135. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/discovery.rs +0 -0
  136. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/feedback.rs +0 -0
  137. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/lexicon.rs +0 -0
  138. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/mining.rs +0 -0
  139. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/nlp.rs +0 -0
  140. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/score.rs +0 -0
  141. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/sqlite.rs +0 -0
  142. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/toolcall.rs +0 -0
  143. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/attachment.rs +0 -0
  144. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/blocks.rs +0 -0
  145. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/convert.rs +0 -0
  146. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/dunder.rs +0 -0
  147. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/events.rs +0 -0
  148. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/meta.rs +0 -0
  149. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/print.rs +0 -0
  150. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/store.rs +0 -0
  151. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/system.rs +0 -0
  152. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/toolcall.rs +0 -0
  153. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/rust/crates/py/src/views/toolresult.rs +0 -0
  154. {cc_transcript-14.5.0 → cc_transcript-14.6.1}/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.5.0
3
+ Version: 14.6.1
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -87,6 +87,7 @@ EXPORTS: dict[str, str] = {
87
87
  "CommandLineQuery",
88
88
  "Occurrence",
89
89
  "Redirect",
90
+ "Word",
90
91
  "command_prefixes",
91
92
  "parse_command_line",
92
93
  ),
@@ -180,6 +181,13 @@ EXPORTS: dict[str, str] = {
180
181
  "resolve",
181
182
  "subagent_paths",
182
183
  ),
184
+ "cc_transcript.codex": (
185
+ "CodexPendingItem",
186
+ "CodexRollout",
187
+ "CodexSessionInfo",
188
+ "CodexUsage",
189
+ "Lifecycle",
190
+ ),
183
191
  "cc_transcript.activity": (
184
192
  "Edit",
185
193
  "SessionActivity",
@@ -27,12 +27,21 @@ 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,
33
41
  CommandLineQuery as CommandLineQuery,
34
42
  Occurrence as Occurrence,
35
43
  Redirect as Redirect,
44
+ Word as Word,
36
45
  command_prefixes as command_prefixes,
37
46
  parse_command_line as parse_command_line,
38
47
  )
@@ -301,6 +310,10 @@ __all__ = [
301
310
  "CacheCreation",
302
311
  "CandidatePair",
303
312
  "CcVersion",
313
+ "CodexPendingItem",
314
+ "CodexRollout",
315
+ "CodexSessionInfo",
316
+ "CodexUsage",
304
317
  "Command",
305
318
  "CommandLine",
306
319
  "CommandLineQuery",
@@ -341,6 +354,7 @@ __all__ = [
341
354
  "HydratedWindow",
342
355
  "InitInfo",
343
356
  "JUNK_USER_MESSAGE_RE",
357
+ "Lifecycle",
344
358
  "McpServer",
345
359
  "ModeEvent",
346
360
  "ModelPricing",
@@ -421,6 +435,7 @@ __all__ = [
421
435
  "UserEvent",
422
436
  "WatchEvent",
423
437
  "Watcher",
438
+ "Word",
424
439
  "WorkflowCall",
425
440
  "WriteCall",
426
441
  "WriteResult",
@@ -95,6 +95,7 @@ __all__ = [
95
95
  "Usage",
96
96
  "UserEvent",
97
97
  "WatchTailer",
98
+ "Word",
98
99
  "WorkflowCall",
99
100
  "WriteCall",
100
101
  "WriteResult",
@@ -103,6 +104,9 @@ __all__ = [
103
104
  "activity_lift_from_events",
104
105
  "bucket_events_from_events",
105
106
  "cli_main",
107
+ "codex_discover",
108
+ "codex_resolve",
109
+ "codex_session_info",
106
110
  "command_parse",
107
111
  "command_prefixes",
108
112
  "context_capture_window",
@@ -411,6 +415,11 @@ class Command:
411
415
  @property
412
416
  def span(self) -> typing.Optional[tuple[builtins.int, builtins.int]]: ...
413
417
  @property
418
+ def words(self) -> tuple[Word, ...]:
419
+ r"""
420
+ The structural words: ``words[0]`` is the executable, ``words[1:]`` parallel ``args``.
421
+ """
422
+ @property
414
423
  def argv(self) -> tuple[str, ...]: ...
415
424
  @property
416
425
  def program(self) -> builtins.str: ...
@@ -470,6 +479,11 @@ class CommandLine:
470
479
  def parse(cls, raw: builtins.str) -> CommandLine: ...
471
480
  @staticmethod
472
481
  def dequote(text: builtins.str) -> builtins.str: ...
482
+ @staticmethod
483
+ def quote(text: builtins.str) -> builtins.str:
484
+ r"""
485
+ Quote ``text`` as one POSIX-sh word, with Python ``shlex.quote`` semantics.
486
+ """
473
487
  def splice(self, replacements: typing.Mapping[builtins.int, builtins.str]) -> builtins.str: ...
474
488
  def rewrite_occurrences(self, to: collections.abc.Callable[[Occurrence], str | None]) -> typing.Optional[builtins.str]: ...
475
489
  def __iter__(self) -> collections.abc.Iterator[Command]: ...
@@ -1087,7 +1101,30 @@ class Occurrence:
1087
1101
  def next_op(self) -> typing.Optional[builtins.str]: ...
1088
1102
  @property
1089
1103
  def piped(self) -> builtins.bool: ...
1104
+ @property
1105
+ def nesting(self) -> builtins.int:
1106
+ r"""
1107
+ Substitution/payload hops below top level; 0 for a top-level command.
1108
+ """
1109
+ @property
1110
+ def host(self) -> Occurrence | None:
1111
+ r"""
1112
+ The occurrence hosting this nested part, or None at top level.
1113
+ """
1114
+ @property
1115
+ def quote_contexts(self) -> tuple[str, ...]:
1116
+ r"""
1117
+ Enclosing payload quote layers outermost-first: ``"'"``, ``'"'``, or ``""`` (bare).
1118
+ """
1090
1119
  def __new__(cls, line: CommandLine, index: builtins.int) -> Occurrence: ...
1120
+ def embeddable(self, text: builtins.str) -> builtins.bool:
1121
+ r"""
1122
+ Whether splicing ``text`` at this occurrence survives every enclosing quote layer.
1123
+ """
1124
+ def quote_for(self, text: builtins.str) -> typing.Optional[builtins.str]:
1125
+ r"""
1126
+ One shell-word spelling of ``text`` that survives every enclosing layer, or None.
1127
+ """
1091
1128
 
1092
1129
  @typing.final
1093
1130
  class OtherAttachment:
@@ -1907,15 +1944,14 @@ class Transcript:
1907
1944
  The parsed events of a single transcript file, backed by the native parse
1908
1945
  output; ``events`` materializes lazy views on access.
1909
1946
 
1910
- One parse owns one ``Arc<Vec<Entry>>`` that every event and nested view shares,
1911
- so retaining any single view keeps that whole parse's entries alive; keeping one
1912
- event from each of several parses retains all of their entries. The live
1913
- :class:`~watch.WatchEvent` stream is exempt — its tailer builds a
1914
- one-entry Arc per yielded event, so a held watch event pins only itself.
1947
+ One parse owns one ``Arc<Vec<Entry>>`` shared by every view, so retaining any
1948
+ view keeps the whole parse's entries alive; the live
1949
+ :class:`~watch.WatchEvent` stream is exempt (one-entry Arc each).
1915
1950
 
1916
1951
  Attributes:
1917
1952
  path: The transcript's path on disk; None for a bytes parse.
1918
1953
  mtime: The transcript's modification time when parsed.
1954
+ provider: The transcript's source provider: "claude" or "codex".
1919
1955
  events: The parsed events, in file order.
1920
1956
  """
1921
1957
  @property
@@ -1923,6 +1959,8 @@ class Transcript:
1923
1959
  @property
1924
1960
  def mtime(self) -> builtins.float: ...
1925
1961
  @property
1962
+ def provider(self) -> typing.Literal["claude", "codex"]: ...
1963
+ @property
1926
1964
  def events(self) -> EventList: ...
1927
1965
 
1928
1966
  @typing.final
@@ -2063,6 +2101,27 @@ class WatchTailer:
2063
2101
  size, mtime, session_id, seen}}}`, the Python `TailState` projection.
2064
2102
  """
2065
2103
 
2104
+ @typing.final
2105
+ class Word:
2106
+ r"""
2107
+ One structural word of a parsed command (``Command.words``).
2108
+ Attributes:
2109
+ raw: verbatim source text.
2110
+ value: literal with quotes/escapes removed; None when an expansion taints it.
2111
+ span: byte span in the owning ``CommandLine.raw``; None without verbatim source.
2112
+ expandable: bash would glob/brace/tilde-expand despite the literal value.
2113
+ """
2114
+ __match_args__: typing.ClassVar[tuple[str, ...]]
2115
+ @property
2116
+ def raw(self) -> builtins.str: ...
2117
+ @property
2118
+ def value(self) -> typing.Optional[builtins.str]: ...
2119
+ @property
2120
+ def span(self) -> typing.Optional[tuple[builtins.int, builtins.int]]: ...
2121
+ @property
2122
+ def expandable(self) -> builtins.bool: ...
2123
+ def __new__(cls, raw: builtins.str, value: typing.Optional[builtins.str] = None, span: typing.Optional[tuple[builtins.int, builtins.int]] = None, expandable: builtins.bool = False) -> Word: ...
2124
+
2066
2125
  @typing.final
2067
2126
  class WorkflowCall(ToolCallBase):
2068
2127
  r"""
@@ -2138,6 +2197,12 @@ def cli_main() -> builtins.int:
2138
2197
  run, and the exit code returned verbatim for the wrapper's `sys.exit`.
2139
2198
  """
2140
2199
 
2200
+ def codex_discover(root: typing.Optional[builtins.str | os.PathLike | pathlib.Path] = None) -> builtins.list[tuple[pathlib.Path, builtins.str, builtins.bool]]: ...
2201
+
2202
+ def codex_resolve(session_id: builtins.str, root: typing.Optional[builtins.str | os.PathLike | pathlib.Path] = None) -> typing.Optional[pathlib.Path]: ...
2203
+
2204
+ def codex_session_info(path: builtins.str) -> dict[str, typing.Any]: ...
2205
+
2141
2206
  def command_parse(command: builtins.str) -> dict[str, typing.Any]: ...
2142
2207
 
2143
2208
  def command_prefixes(commands: typing.Sequence[builtins.str]) -> builtins.list[builtins.list[builtins.str]]: ...
@@ -2162,7 +2227,7 @@ def discovery_subagent_paths(path: builtins.str | os.PathLike | pathlib.Path) ->
2162
2227
 
2163
2228
  def discovery_subagent_transcripts(path: builtins.str | os.PathLike | pathlib.Path) -> dict[str, pathlib.Path]: ...
2164
2229
 
2165
- def embedded_literals() -> dict[str, str | float | list[str]]: ...
2230
+ def embedded_literals() -> dict[str, str | float | int | list[str]]: ...
2166
2231
 
2167
2232
  def expand_tool_names(spec: builtins.str) -> frozenset[str]:
2168
2233
  r"""
@@ -0,0 +1,212 @@
1
+ """The codex session surface: discovery, resolution, and per-rollout session info.
2
+
3
+ A sync facade over the native codex functions, mirroring
4
+ :mod:`cc_transcript.discovery` for the ``~/.codex/sessions`` tree. The sessions-root
5
+ default is a facade concern; the native side scans exactly the root it is handed.
6
+
7
+ There is no parse function here: :func:`cc_transcript.parse` is already
8
+ provider-transparent — it sniffs a codex rollout, lowers it into the native event
9
+ model, and yields the same :class:`~cc_transcript.models.Transcript` view a Claude
10
+ transcript produces, with ``provider == "codex"``. This module adds only the codex
11
+ identity, lifecycle, and token-usage surface that the lowered event stream drops.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass
17
+ from pathlib import Path
18
+ from typing import TYPE_CHECKING, Literal
19
+
20
+ if TYPE_CHECKING:
21
+ from cc_transcript.ids import SessionId
22
+
23
+ SESSIONS_ROOT = Path.home() / ".codex" / "sessions"
24
+
25
+ Lifecycle = Literal["uninitialized", "no_instrumentation", "open", "completed", "aborted"]
26
+ """A codex rollout's turn-lifecycle state.
27
+
28
+ ``uninitialized`` — no content at all; ``no_instrumentation`` — content but no
29
+ ``task_started``/``task_complete`` brackets; ``open`` — the latest turn is still
30
+ running; ``completed`` — the latest turn finished; ``aborted`` — the latest turn was
31
+ interrupted.
32
+ """
33
+
34
+
35
+ @dataclass(frozen=True, slots=True)
36
+ class CodexRollout:
37
+ """A rollout found in the codex sessions tree.
38
+
39
+ Attributes:
40
+ path: The rollout's path.
41
+ session_id: The session id encoded in the rollout filename.
42
+ compressed: Whether the rollout is a ``.jsonl.zst`` file.
43
+ """
44
+
45
+ path: Path
46
+ session_id: str
47
+ compressed: bool
48
+
49
+
50
+ @dataclass(frozen=True, slots=True)
51
+ class CodexUsage:
52
+ """Session-level token totals lowered from a codex rollout.
53
+
54
+ The totals are the last observed cumulative ``total_token_usage`` fields — codex
55
+ ``token_count`` events carry running totals, not per-turn deltas — so this is the
56
+ session's final accounting, not a sum.
57
+
58
+ Attributes:
59
+ input_tokens: Total input tokens, or None when never reported.
60
+ cached_input_tokens: Cached input tokens, or None when never reported.
61
+ output_tokens: Output tokens, or None when never reported.
62
+ reasoning_output_tokens: Reasoning output tokens, or None when never reported.
63
+ total_tokens: Total tokens, or None when never reported.
64
+ model_context_window: The model's context window, or None when never reported.
65
+ token_count_events: The number of ``token_count`` events observed.
66
+ """
67
+
68
+ input_tokens: int | None
69
+ cached_input_tokens: int | None
70
+ output_tokens: int | None
71
+ reasoning_output_tokens: int | None
72
+ total_tokens: int | None
73
+ model_context_window: int | None
74
+ token_count_events: int
75
+
76
+
77
+ @dataclass(frozen=True, slots=True)
78
+ class CodexPendingItem:
79
+ """A dangling tool call in the rollout's open turn.
80
+
81
+ Attributes:
82
+ tool_use_id: The call's ``call_id``.
83
+ name: The tool's name, such as ``exec``.
84
+ kind: How the call contributes to the verdict; always ``mid_tool`` for codex.
85
+ """
86
+
87
+ tool_use_id: str | None
88
+ name: str
89
+ kind: str
90
+
91
+
92
+ @dataclass(frozen=True, slots=True)
93
+ class CodexSessionInfo:
94
+ """The identity, lifecycle, and usage of one codex rollout.
95
+
96
+ Attributes:
97
+ rollout_thread_id: This rollout's own thread id (the session-meta ``id``).
98
+ session_id: The logical session id; a forked rollout inherits its origin's.
99
+ parent_thread_id: The spawning thread's id for a subagent rollout, else None.
100
+ forked_from_id: The origin thread's id when this rollout is a fork, else None.
101
+ cwd: The working directory recorded in the session meta.
102
+ originator: What launched the session, such as ``codex_exec``.
103
+ cli_version: The codex CLI version that wrote the rollout.
104
+ model_provider: The model provider, such as ``openai``.
105
+ lifecycle: The latest turn's lifecycle state.
106
+ turn_id: The latest turn's id, or None before any turn brackets.
107
+ pending: The dangling tool calls in an open turn, in document order.
108
+ last_event_epoch: The latest envelope timestamp as epoch seconds, or None.
109
+ usage: The session token totals, or None when no ``token_count`` event occurred.
110
+ """
111
+
112
+ rollout_thread_id: str | None
113
+ session_id: str | None
114
+ parent_thread_id: str | None
115
+ forked_from_id: str | None
116
+ cwd: str | None
117
+ originator: str | None
118
+ cli_version: str | None
119
+ model_provider: str | None
120
+ lifecycle: Lifecycle
121
+ turn_id: str | None
122
+ pending: tuple[CodexPendingItem, ...]
123
+ last_event_epoch: int | None
124
+ usage: CodexUsage | None
125
+
126
+
127
+ def sessions_root(root: Path | None = None) -> Path:
128
+ """The codex sessions root, defaulting to ``~/.codex/sessions``.
129
+
130
+ Args:
131
+ root: An explicit root; when None, :data:`SESSIONS_ROOT`.
132
+
133
+ Returns:
134
+ The root that :func:`discover` and :func:`find_transcript` scan.
135
+ """
136
+ return root or SESSIONS_ROOT
137
+
138
+
139
+ def discover(root: Path | None = None) -> tuple[CodexRollout, ...]:
140
+ """Every codex rollout under ``root``, newest first.
141
+
142
+ Rollouts live as ``rollout-<timestamp>-<session_id>.jsonl`` (or ``.jsonl.zst``)
143
+ files under the date-sharded sessions tree. Each result preserves its path,
144
+ session id, and compression state.
145
+
146
+ Args:
147
+ root: The sessions root; when None, :func:`sessions_root`.
148
+
149
+ Returns:
150
+ The rollouts, newest first; ``()`` when the root does not exist.
151
+
152
+ Example:
153
+ >>> for rollout in discover():
154
+ ... print(rollout.session_id, rollout.path)
155
+ """
156
+ from cc_transcript import _native
157
+
158
+ return tuple(CodexRollout(*rollout) for rollout in _native.codex_discover(sessions_root(root)))
159
+
160
+
161
+ def find_transcript(session_id: SessionId, root: Path | None = None) -> Path | None:
162
+ """Locates ``session_id``'s rollout under the codex sessions tree.
163
+
164
+ Only uncompressed ``.jsonl`` rollouts resolve. Compressed rollouts appear in
165
+ ``discover()`` but do not resolve until zstd support lands. The newest wins among
166
+ same-id uncompressed rollouts.
167
+
168
+ Args:
169
+ session_id: The codex session id, as it appears in the rollout filename.
170
+ root: The sessions root; when None, :func:`sessions_root`.
171
+
172
+ Returns:
173
+ The rollout path, or None when no rollout carries that session id.
174
+ """
175
+ from cc_transcript import _native
176
+
177
+ return _native.codex_resolve(session_id, sessions_root(root))
178
+
179
+
180
+ def session_info(path: Path) -> CodexSessionInfo:
181
+ """The identity, lifecycle, and token usage of the rollout at ``path``.
182
+
183
+ The native extension reads and folds the rollout in one pass, returning the
184
+ session identity, the turn lifecycle, any dangling calls, and the token totals.
185
+
186
+ Args:
187
+ path: The ``.jsonl`` rollout to inspect.
188
+
189
+ Returns:
190
+ The rollout's session info.
191
+ """
192
+ from cc_transcript import _native
193
+
194
+ payload = _native.codex_session_info(str(path))
195
+ identity = payload["identity"]
196
+ lifecycle = payload["lifecycle"]
197
+ usage = payload["usage"]
198
+ return CodexSessionInfo(
199
+ rollout_thread_id=identity["rollout_thread_id"],
200
+ session_id=identity["session_id"],
201
+ parent_thread_id=identity["parent_thread_id"],
202
+ forked_from_id=identity["forked_from_id"],
203
+ cwd=identity["cwd"],
204
+ originator=identity["originator"],
205
+ cli_version=identity["cli_version"],
206
+ model_provider=identity["model_provider"],
207
+ lifecycle=lifecycle["state"],
208
+ turn_id=lifecycle["turn_id"],
209
+ pending=tuple(CodexPendingItem(**item) for item in payload["pending"]),
210
+ last_event_epoch=payload["last_event_epoch"],
211
+ usage=CodexUsage(**usage) if usage is not None else None,
212
+ )
@@ -18,6 +18,10 @@ from cc_transcript._native import CommandLine as CommandLine
18
18
  from cc_transcript._native import CommandLineQuery as CommandLineQuery
19
19
  from cc_transcript._native import Occurrence as Occurrence
20
20
  from cc_transcript._native import Redirect as Redirect
21
+ from cc_transcript._native import Word as Word
22
+ from cc_transcript.literals import literal_int
23
+
24
+ PAYLOAD_DEPTH_LIMIT: int = literal_int("command.PAYLOAD_DEPTH_LIMIT")
21
25
 
22
26
  parse_command_line = lru_cache(maxsize=4096)(CommandLine.parse)
23
27
 
@@ -96,7 +96,8 @@ def resolve(session_id: SessionId, *, root: Path | None = None) -> Path | None:
96
96
  A successful lookup is memoized in ``TRANSCRIPT_MEMO`` under
97
97
  ``(session_id, resolved root)`` and revalidated on the next hit, so a
98
98
  repeated probe skips the recursive scan while a pruned transcript still
99
- forces a fresh one.
99
+ forces a fresh one. When the projects tree yields nothing, the codex
100
+ sessions tree is tried as a fallback, so a codex session id resolves too.
100
101
 
101
102
  Returns:
102
103
  The newest-mtime real path, or None when no transcript exists.
@@ -105,8 +106,11 @@ def resolve(session_id: SessionId, *, root: Path | None = None) -> Path | None:
105
106
  key = (session_id, base.resolve())
106
107
  if (cached := TRANSCRIPT_MEMO.get(key)) is not None and cached.exists():
107
108
  return cached
108
- if (hit := _native.discovery_find_transcript(base, session_id)) is None:
109
- return None
109
+ hit = _native.discovery_find_transcript(base, session_id)
110
+ if hit is None:
111
+ from cc_transcript import codex
112
+
113
+ return codex.find_transcript(session_id)
110
114
  TRANSCRIPT_MEMO[key] = hit
111
115
  return hit
112
116
 
@@ -334,6 +334,7 @@ async def run_verdicts[V](
334
334
  """
335
335
  counts = {"judged": 0, "failed": 0}
336
336
  limiter = asyncio.Semaphore(concurrency)
337
+ persister = asyncio.Lock()
337
338
 
338
339
  async def worker(row: Mapping[str, object]) -> None:
339
340
  async with limiter:
@@ -342,7 +343,11 @@ async def run_verdicts[V](
342
343
  except JudgeError:
343
344
  counts["failed"] += 1
344
345
  return
345
- await persist(row, verdict)
346
+ # The store's transaction is exclusive by contract; persists serialize on
347
+ # this lock so concurrent workers never race record_verdict into a
348
+ # TransactionConflictError. Judge concurrency is untouched.
349
+ async with persister:
350
+ await persist(row, verdict)
346
351
  counts["judged"] += 1
347
352
 
348
353
  async with asyncio.TaskGroup() as tg:
@@ -12,7 +12,7 @@ from __future__ import annotations
12
12
 
13
13
  from cc_transcript import _native
14
14
 
15
- LITERALS: dict[str, str | float | list[str]] = _native.embedded_literals()
15
+ LITERALS: dict[str, str | float | int | list[str]] = _native.embedded_literals()
16
16
 
17
17
 
18
18
  def literal_str(key: str) -> str:
@@ -25,3 +25,9 @@ def literal_float(key: str) -> float:
25
25
  value = LITERALS[key]
26
26
  assert isinstance(value, float), key
27
27
  return value
28
+
29
+
30
+ def literal_int(key: str) -> int:
31
+ value = LITERALS[key]
32
+ assert isinstance(value, int), key
33
+ return value
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cc-transcript"
3
- version = "14.5.0" # informational — releases stamp the version from the git tag
3
+ version = "14.6.1" # informational — releases stamp the version from the git tag
4
4
  description = "Grep every Claude Code session you've ever run."
5
5
  readme = "README.md"
6
6
  license = "PolyForm-Noncommercial-1.0.0"
@@ -4,7 +4,7 @@
4
4
  use std::path::{Path, PathBuf};
5
5
 
6
6
  use cc_transcript_core::discovery::{find_in, mtime_secs};
7
- use cc_transcript_core::parse::parse_bytes;
7
+ use cc_transcript_core::gateway::parse_transcript_bytes;
8
8
  use cc_transcript_core::render::display_path;
9
9
  use cc_transcript_core::types::Entry;
10
10
  use rayon::prelude::*;
@@ -108,7 +108,7 @@ pub fn parse_transcripts(targets: &[(PathBuf, f64)]) -> Vec<Parsed> {
108
108
  .par_iter()
109
109
  .map(|(path, _)| {
110
110
  let bytes = std::fs::read(path).ok()?;
111
- let entries = parse_bytes(&bytes, |_| true).ok()?;
111
+ let entries = parse_transcript_bytes(&bytes).ok()?.entries;
112
112
  Some(Parsed {
113
113
  path: path.clone(),
114
114
  session_id: session_id_of(&entries),