cctally 1.101.0 → 1.103.0

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.
package/README.md CHANGED
@@ -30,9 +30,15 @@ Your Claude Code plan meters you with a percentage that creeps up all week. ccta
30
30
  </p>
31
31
 
32
32
  <!-- cctally:latest-stable:begin -->
33
- **Latest stable: v1.95.5** (2026-08-09)
33
+ **Latest stable: v1.101.0** (2026-08-19)
34
34
 
35
- - Dashboard share-digest validation now pins the template artifact clock as well as the dashboard data clock, so two equivalent renders cannot fail Linux CI merely because their frontmatter and footer crossed a one-second wall-clock boundary.
35
+ Highlights from the `v1.95.5` to `v1.101.0` stable upgrade:
36
+
37
+ - Dashboard refreshes release their read lock on `cache.db` sooner, cutting the measured median hold from 3.40 seconds to 1.04. The published data is unchanged.
38
+ - Every dashboard warning carries a button that opens the surface explaining it, the week, the five-hour block, the month, the project, or the forecast. A warning whose window has closed says so and opens nothing.
39
+ - The dashboard's Projects table writes out what its two percentages mean under the week selector, where a phone can read it. `Used pp` is relabelled `Used pp (sum)`, and the caption names the denominator of `Cost share`.
40
+
41
+ [See every change in this stable upgrade](https://github.com/omrikais/cctally/releases/tag/v1.101.0)
36
42
  <!-- cctally:latest-stable:end -->
37
43
 
38
44
  ## Quick start
@@ -7327,6 +7327,20 @@ def sync_codex_cache(
7327
7327
  model=initial_model,
7328
7328
  total_tokens=initial_total_tokens,
7329
7329
  )
7330
+ if start_offset > 0 and not truncated and not requalified:
7331
+ prior_accounting = conn.execute(
7332
+ "SELECT MAX(timestamp_utc),MAX(line_offset) "
7333
+ "FROM codex_session_entries "
7334
+ "WHERE source_path=? AND line_offset<? ",
7335
+ (path_str, start_offset),
7336
+ ).fetchone()
7337
+ if prior_accounting is not None and prior_accounting[0] is not None:
7338
+ iter_state.last_accounting_timestamp = _parse_anchor_iso(
7339
+ prior_accounting[0])
7340
+ if prior_accounting is not None and prior_accounting[1] is not None:
7341
+ iter_state.generation_transition_pending = (
7342
+ _lib_jsonl._codex_generation_transition_between(
7343
+ path_str, int(prior_accounting[1]), start_offset))
7330
7344
  if (
7331
7345
  prev is not None and not truncated and not requalified
7332
7346
  and prev_native_thread_id is not None
@@ -11223,6 +11237,23 @@ def sync_codex_conversations(
11223
11237
  model=initial_model,
11224
11238
  total_tokens=initial_total_tokens,
11225
11239
  )
11240
+ if start_offset > 0 and not reset_file:
11241
+ try:
11242
+ prior_accounting = conn.execute(
11243
+ "SELECT MAX(timestamp_utc),MAX(line_offset) FROM "
11244
+ "cache_db.codex_session_entries "
11245
+ "WHERE source_path=? AND line_offset<? ",
11246
+ (path_str, start_offset),
11247
+ ).fetchone()
11248
+ except sqlite3.OperationalError:
11249
+ prior_accounting = None
11250
+ if prior_accounting is not None and prior_accounting[0] is not None:
11251
+ state.last_accounting_timestamp = _parse_anchor_iso(
11252
+ prior_accounting[0])
11253
+ if prior_accounting is not None and prior_accounting[1] is not None:
11254
+ state.generation_transition_pending = (
11255
+ _lib_jsonl._codex_generation_transition_between(
11256
+ path_str, int(prior_accounting[1]), start_offset))
11226
11257
  if initial_native and initial_root:
11227
11258
  state.thread = _lib_jsonl.CodexThreadMetadata(
11228
11259
  source_root_key=discovered.source_root_key,