cc-transcript 10.1.0__tar.gz → 10.2.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 (74) hide show
  1. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/PKG-INFO +1 -1
  2. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/activity.py +5 -3
  3. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/activity_probe.py +1 -3
  4. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/pyproject.toml +1 -1
  5. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/mining.rs +2 -8
  6. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/parse.rs +16 -3
  7. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/Cargo.lock +0 -0
  8. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/Cargo.toml +0 -0
  9. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/LICENSE +0 -0
  10. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/README.md +0 -0
  11. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/__init__.py +0 -0
  12. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/__main__.py +0 -0
  13. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/_parser_rs.pyi +0 -0
  14. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/backend.py +0 -0
  15. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/builders.py +0 -0
  16. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/cli.py +0 -0
  17. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/command.py +0 -0
  18. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/context.py +0 -0
  19. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/corrections.py +0 -0
  20. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/corrections_cli.py +0 -0
  21. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/cost.py +0 -0
  22. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/decisions.py +0 -0
  23. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/discovery.py +0 -0
  24. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/disktruth.py +0 -0
  25. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/evidence.py +0 -0
  26. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/extract/__init__.py +0 -0
  27. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/extract/correct.py +0 -0
  28. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/facts.py +0 -0
  29. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/filterspec.py +0 -0
  30. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/ids.py +0 -0
  31. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/judge/__init__.py +0 -0
  32. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/judge/llm.py +0 -0
  33. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/judge/similar.py +0 -0
  34. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/judge/verdicts.py +0 -0
  35. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/__init__.py +0 -0
  36. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/candidates.py +0 -0
  37. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/confidence.py +0 -0
  38. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/engine.py +0 -0
  39. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/filterspec.py +0 -0
  40. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/formats.py +0 -0
  41. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/signals.py +0 -0
  42. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/sourcekind.py +0 -0
  43. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/spec.py +0 -0
  44. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/mining/store.py +0 -0
  45. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/models.py +0 -0
  46. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/notifications.py +0 -0
  47. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/parser.py +0 -0
  48. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/py.typed +0 -0
  49. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/query.py +0 -0
  50. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/render.py +0 -0
  51. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/rust.py +0 -0
  52. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/sentiment/__init__.py +0 -0
  53. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/sentiment/buckets.py +0 -0
  54. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/sentiment/engine.py +0 -0
  55. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/sentiment/lexicon.py +0 -0
  56. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/sentiment/scorespec.py +0 -0
  57. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/store.py +0 -0
  58. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/cc_transcript/tools.py +0 -0
  59. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/Cargo.toml +0 -0
  60. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/build.rs +0 -0
  61. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/data/afinn-en-165.tsv +0 -0
  62. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/data/domain_overrides.tsv +0 -0
  63. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/activity.rs +0 -0
  64. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/command.rs +0 -0
  65. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/event.rs +0 -0
  66. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/filter.rs +0 -0
  67. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/lexicon.rs +0 -0
  68. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/lib.rs +0 -0
  69. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/model.rs +0 -0
  70. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/protocol.rs +0 -0
  71. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/python.rs +0 -0
  72. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/score.rs +0 -0
  73. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/types.rs +0 -0
  74. {cc_transcript-10.1.0 → cc_transcript-10.2.0}/rust/src/value.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cc-transcript
3
- Version: 10.1.0
3
+ Version: 10.2.0
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -39,10 +39,12 @@ UserClassifier = Callable[["UserEvent"], bool]
39
39
  def native_user_classifier(event: UserEvent) -> bool:
40
40
  """Whether a user event is a real prompt under native Claude Code semantics.
41
41
 
42
- A prompt is non-meta, non-sidechain, not an interruption marker, and not
43
- tool-result-only — it must carry real text.
42
+ A prompt is non-meta, non-sidechain, not a compact summary, not an
43
+ interruption marker, and not tool-result-only — it must carry real text.
44
44
  """
45
- return not (event.meta.is_meta or event.meta.is_sidechain or event.interrupted) and bool(event.text.strip())
45
+ return not (
46
+ event.meta.is_meta or event.meta.is_sidechain or event.meta.is_compact_summary or event.interrupted
47
+ ) and bool(event.text.strip())
46
48
 
47
49
 
48
50
  @dataclass(frozen=True, slots=True)
@@ -129,9 +129,7 @@ def probe_events(
129
129
  (
130
130
  index
131
131
  for index in reversed(range(len(events)))
132
- if isinstance(event := events[index], UserEvent)
133
- and native_user_classifier(event)
134
- and not event.meta.is_compact_summary
132
+ if isinstance(event := events[index], UserEvent) and native_user_classifier(event)
135
133
  ),
136
134
  0,
137
135
  )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cc-transcript"
3
- version = "10.1.0"
3
+ version = "10.2.0"
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"
@@ -8,7 +8,7 @@ use regex::Regex;
8
8
  use sonic_rs::{Index, JsonContainerTrait, JsonValueTrait, Value};
9
9
 
10
10
  use crate::filter::compile_group_array;
11
- use crate::parse::{parse_entry, ParseError};
11
+ use crate::parse::{parse_bytes, ParseError};
12
12
  use crate::protocol::{
13
13
  embedded_user_text, interrupt_marker, is_bare_interrupt_marker, ANSWERED_PREFIX, ANSWERED_TRAILER,
14
14
  DENIAL_PREFIX, INTERRUPT_MARKER_RE,
@@ -434,13 +434,7 @@ impl Events {
434
434
  /// non-object values (parser.py decode_line) so event indices agree with the
435
435
  /// Python reference; a malformed entry fails the mine, as in the reference.
436
436
  fn parse(raw: &[u8]) -> Result<Self, ParseError> {
437
- let entries = raw
438
- .split(|&b| b == b'\n')
439
- .filter(|line| !line.iter().all(u8::is_ascii_whitespace))
440
- .filter_map(|line| sonic_rs::from_slice::<Value>(line).ok())
441
- .filter(|value| value.is_object())
442
- .map(parse_entry)
443
- .collect::<Result<Vec<_>, _>>()?;
437
+ let entries = parse_bytes(raw, |_| true)?;
444
438
  let texts = entries
445
439
  .iter()
446
440
  .map(|entry| match entry {
@@ -265,9 +265,10 @@ pub fn parse_entry(data: Value) -> Result<Entry, ParseError> {
265
265
  Ok(Entry::Other(OtherEntry { ty, raw: data }))
266
266
  }
267
267
 
268
- // Lines that are not valid JSON are skipped; a JSON line that fails the typed
269
- // parse (e.g. a missing required field) fails the whole file whole-file
270
- // parity with PythonBackend, which parses every line before filtering.
268
+ // Non-JSON lines and valid-JSON lines that are not objects (bare scalars or
269
+ // arrays) are skipped; a JSON object that fails the typed parse (e.g. a missing
270
+ // required field) fails the whole file whole-file parity with PythonBackend,
271
+ // which decodes every line, skips non-objects, then parses the rest.
271
272
  fn parse_line<F: Fn(&Entry) -> bool>(
272
273
  line: &[u8],
273
274
  lines: &mut Vec<Entry>,
@@ -277,6 +278,9 @@ fn parse_line<F: Fn(&Entry) -> bool>(
277
278
  return Ok(());
278
279
  }
279
280
  if let Ok(value) = sonic_rs::from_slice::<Value>(line) {
281
+ if !value.is_object() {
282
+ return Ok(());
283
+ }
280
284
  let entry = parse_entry(value)?;
281
285
  if keep(&entry) {
282
286
  lines.push(entry);
@@ -614,6 +618,15 @@ mod tests {
614
618
  assert_eq!(other.raw, parse(raw));
615
619
  }
616
620
 
621
+ #[test]
622
+ fn parse_bytes_skips_valid_json_non_object_lines() {
623
+ let real = format!(r#"{{"type":"user",{META},"message":{{"content":"hi"}}}}"#);
624
+ let bytes = format!("{real}\n42\n\"bare\"\n[1,2,3]\n{real}");
625
+ let entries = parse_bytes(bytes.as_bytes(), |_| true).unwrap();
626
+ assert_eq!(entries.len(), 2, "bare scalar and array lines are skipped");
627
+ assert!(entries.iter().all(|e| matches!(e, Entry::User(_))));
628
+ }
629
+
617
630
  #[test]
618
631
  fn print_envelope_requires_result_element() {
619
632
  assert!(matches!(
File without changes
File without changes