cctally 1.93.0 → 1.94.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/CHANGELOG.md +48 -0
- package/bin/_cctally_cache.py +55 -6
- package/bin/_cctally_codex.py +35 -3
- package/bin/_cctally_config.py +108 -2
- package/bin/_cctally_core.py +37 -8
- package/bin/_cctally_dashboard.py +6 -0
- package/bin/_cctally_dashboard_share.py +744 -137
- package/bin/_cctally_dashboard_sources.py +9 -0
- package/bin/_cctally_db.py +315 -40
- package/bin/_cctally_doctor.py +188 -3
- package/bin/_cctally_five_hour.py +39 -12
- package/bin/_cctally_forecast.py +29 -47
- package/bin/_cctally_journal.py +79 -7
- package/bin/_cctally_parser.py +71 -1
- package/bin/_cctally_project.py +0 -2
- package/bin/_cctally_record.py +18 -0
- package/bin/_cctally_reporting.py +0 -9
- package/bin/_cctally_retention.py +2890 -0
- package/bin/_cctally_share.py +97 -92
- package/bin/_cctally_source_analytics.py +44 -16
- package/bin/_cctally_store.py +194 -14
- package/bin/_lib_artifact_retention.py +1645 -0
- package/bin/_lib_display_tz.py +18 -0
- package/bin/_lib_doctor.py +378 -24
- package/bin/_lib_share.py +1359 -183
- package/bin/_lib_share_templates.py +181 -69
- package/bin/_lib_view_models.py +12 -0
- package/bin/cctally +36 -4
- package/dashboard/static/assets/{index-HlIK7k8Q.js → index-CaUQziq_.js} +48 -48
- package/dashboard/static/assets/index-DUQjFSX7.css +1 -0
- package/dashboard/static/dashboard.html +2 -2
- package/package.json +3 -1
- package/dashboard/static/assets/index-DwWJOYxd.css +0 -1
package/bin/_cctally_parser.py
CHANGED
|
@@ -2938,7 +2938,12 @@ def _build_db_parser(subparsers, name, *, help_text, xref=None):
|
|
|
2938
2938
|
db_recover.add_argument(
|
|
2939
2939
|
"--yes",
|
|
2940
2940
|
action="store_true",
|
|
2941
|
-
help=
|
|
2941
|
+
help=(
|
|
2942
|
+
"No longer required: --db stats is retired because stats.db is a "
|
|
2943
|
+
"disposable index rebuilt from the journal (use `db rebuild --db "
|
|
2944
|
+
"stats`); a pre-cutover install whose stats.db may be the only "
|
|
2945
|
+
"copy of its history is repaired with `db repair --db stats --yes`"
|
|
2946
|
+
),
|
|
2942
2947
|
)
|
|
2943
2948
|
db_recover.set_defaults(func=c.cmd_db_recover)
|
|
2944
2949
|
db_rebuild = db_sub.add_parser(
|
|
@@ -3046,6 +3051,50 @@ def _build_db_parser(subparsers, name, *, help_text, xref=None):
|
|
|
3046
3051
|
help=argparse.SUPPRESS,
|
|
3047
3052
|
)
|
|
3048
3053
|
db_backup.set_defaults(func=c.cmd_db_backup)
|
|
3054
|
+
db_prune = db_sub.add_parser(
|
|
3055
|
+
"prune",
|
|
3056
|
+
help="Reclaim retained corruption evidence the policy no longer keeps",
|
|
3057
|
+
formatter_class=CLIHelpFormatter,
|
|
3058
|
+
description=textwrap.dedent(
|
|
3059
|
+
"""\
|
|
3060
|
+
Reclaim the quarantine incidents, forensics bundles,
|
|
3061
|
+
rebuild records and machine-written backups that the
|
|
3062
|
+
configured retention policy no longer keeps.
|
|
3063
|
+
|
|
3064
|
+
Preview by default: nothing is deleted until you pass
|
|
3065
|
+
--yes. Evidence cctally cannot classify is NEVER deleted,
|
|
3066
|
+
in either mode, and the last surviving example of each
|
|
3067
|
+
distinct damage shape is always kept, for as many shapes
|
|
3068
|
+
as max_shape_examples allows.
|
|
3069
|
+
|
|
3070
|
+
The policy lives at storage.artifact_retention in
|
|
3071
|
+
config.json. If it is present but malformed, this command
|
|
3072
|
+
exits 2 without deleting anything.
|
|
3073
|
+
|
|
3074
|
+
Examples:
|
|
3075
|
+
cctally db prune
|
|
3076
|
+
cctally db prune --yes
|
|
3077
|
+
cctally db prune --json
|
|
3078
|
+
cctally db prune --yes --include-backups
|
|
3079
|
+
"""
|
|
3080
|
+
),
|
|
3081
|
+
)
|
|
3082
|
+
db_prune.add_argument(
|
|
3083
|
+
"--yes",
|
|
3084
|
+
action="store_true",
|
|
3085
|
+
help="Apply the plan (default: preview only)",
|
|
3086
|
+
)
|
|
3087
|
+
db_prune.add_argument(
|
|
3088
|
+
"--include-backups",
|
|
3089
|
+
action="store_true",
|
|
3090
|
+
help="Also reclaim user-requested `cctally db backup` families",
|
|
3091
|
+
)
|
|
3092
|
+
db_prune.add_argument(
|
|
3093
|
+
"--json",
|
|
3094
|
+
action="store_true",
|
|
3095
|
+
help="Emit JSON to stdout",
|
|
3096
|
+
)
|
|
3097
|
+
db_prune.set_defaults(func=c.cmd_db_prune)
|
|
3049
3098
|
db_checkpoint = db_sub.add_parser(
|
|
3050
3099
|
"checkpoint",
|
|
3051
3100
|
help="Drain the WAL (TRUNCATE checkpoint) — fast, non-destructive",
|
|
@@ -3401,6 +3450,26 @@ def _build_stats_corruption_heal_parser(subparsers, name, *, help_text, xref=Non
|
|
|
3401
3450
|
)
|
|
3402
3451
|
worker.set_defaults(func=c.cmd_stats_corruption_heal_internal)
|
|
3403
3452
|
|
|
3453
|
+
def _build_artifact_retention_parser(subparsers, name, *, help_text, xref=None):
|
|
3454
|
+
"""Build the #496 S6 detached retained-artifact reclamation worker parser."""
|
|
3455
|
+
c = _cctally()
|
|
3456
|
+
worker = subparsers.add_parser(
|
|
3457
|
+
name,
|
|
3458
|
+
help=help_text,
|
|
3459
|
+
formatter_class=CLIHelpFormatter,
|
|
3460
|
+
description=textwrap.dedent(
|
|
3461
|
+
"""\
|
|
3462
|
+
Internal subcommand: reclaim retained corruption evidence
|
|
3463
|
+
that the configured retention policy no longer keeps.
|
|
3464
|
+
Scheduled at most once a day by an ordinary successful
|
|
3465
|
+
command, and immediately whenever an interrupted sweep left
|
|
3466
|
+
a plan to finish. Always returns 0; failures are logged and
|
|
3467
|
+
remain retryable.
|
|
3468
|
+
"""
|
|
3469
|
+
),
|
|
3470
|
+
)
|
|
3471
|
+
worker.set_defaults(func=c.cmd_artifact_retention_internal)
|
|
3472
|
+
|
|
3404
3473
|
def _build_codex_replay_drain_parser(subparsers, name, *, help_text, xref=None):
|
|
3405
3474
|
"""Build the `_codex-replay-drain` parser (public #5 §4)."""
|
|
3406
3475
|
c = _cctally()
|
|
@@ -3504,6 +3573,7 @@ _REGISTRATION = (
|
|
|
3504
3573
|
_Reg('_codex-quota-verify', _build_codex_quota_verify_parser, argparse.SUPPRESS, None, None),
|
|
3505
3574
|
_Reg('_stats-epoch-rebuild', _build_stats_epoch_rebuild_parser, argparse.SUPPRESS, None, None),
|
|
3506
3575
|
_Reg('_stats-corruption-heal', _build_stats_corruption_heal_parser, argparse.SUPPRESS, None, None),
|
|
3576
|
+
_Reg('_artifact-retention', _build_artifact_retention_parser, argparse.SUPPRESS, None, None),
|
|
3507
3577
|
_Reg('_codex-replay-drain', _build_codex_replay_drain_parser, argparse.SUPPRESS, None, None),
|
|
3508
3578
|
_Reg('repair-symlinks', _build_repair_symlinks_parser, argparse.SUPPRESS, None, None),
|
|
3509
3579
|
)
|
package/bin/_cctally_project.py
CHANGED
|
@@ -788,8 +788,6 @@ def cmd_project(args: argparse.Namespace) -> int:
|
|
|
788
788
|
period_end=until_dt,
|
|
789
789
|
display_tz=display_tz_str,
|
|
790
790
|
version=c._share_resolve_version(),
|
|
791
|
-
theme=args.theme,
|
|
792
|
-
reveal_projects=args.reveal_projects,
|
|
793
791
|
)
|
|
794
792
|
c._share_render_and_emit(snap, args)
|
|
795
793
|
return 0
|
package/bin/_cctally_record.py
CHANGED
|
@@ -5185,6 +5185,24 @@ def cmd_hook_tick(args: argparse.Namespace) -> int:
|
|
|
5185
5185
|
_hook_tick_log_line(line)
|
|
5186
5186
|
_hook_tick_log_rotate_if_needed()
|
|
5187
5187
|
|
|
5188
|
+
# #496 S6 §5.2, the hook-tick branch. It is admitted HERE rather than from
|
|
5189
|
+
# `main`'s post-command hook because the parent returns at the fork and
|
|
5190
|
+
# never reaches that hook, and because the INLINE FALLBACK — `os.fork()`
|
|
5191
|
+
# failed, so this body is running on Claude Code's blocking path — must not
|
|
5192
|
+
# gain a spawn. `forked` is exactly that discriminator.
|
|
5193
|
+
try:
|
|
5194
|
+
_cctally()._load_sibling(
|
|
5195
|
+
"_cctally_retention"
|
|
5196
|
+
).maybe_defer_artifact_retention(
|
|
5197
|
+
command="hook-tick",
|
|
5198
|
+
exit_code=0,
|
|
5199
|
+
hook_forked=forked,
|
|
5200
|
+
hook_explain=explain,
|
|
5201
|
+
hook_foreground=foreground,
|
|
5202
|
+
)
|
|
5203
|
+
except Exception:
|
|
5204
|
+
pass
|
|
5205
|
+
|
|
5188
5206
|
# --- Step 9: exit code ---
|
|
5189
5207
|
if not explain:
|
|
5190
5208
|
# Forked child: skip Python's atexit / argparse / cleanup paths
|
|
@@ -139,7 +139,6 @@ def cmd_daily(args: argparse.Namespace) -> int:
|
|
|
139
139
|
snap = c._build_daily_snapshot(
|
|
140
140
|
view, period_start=range_start, period_end=range_end,
|
|
141
141
|
display_tz=display_tz_str, version=c._share_resolve_version(),
|
|
142
|
-
theme=args.theme, reveal_projects=args.reveal_projects,
|
|
143
142
|
)
|
|
144
143
|
if args.order == "desc":
|
|
145
144
|
snap = dataclasses.replace(snap, rows=tuple(reversed(snap.rows)))
|
|
@@ -249,8 +248,6 @@ def cmd_daily(args: argparse.Namespace) -> int:
|
|
|
249
248
|
period_end=range_end,
|
|
250
249
|
display_tz=display_tz_str,
|
|
251
250
|
version=c._share_resolve_version(),
|
|
252
|
-
theme=args.theme,
|
|
253
|
-
reveal_projects=args.reveal_projects,
|
|
254
251
|
)
|
|
255
252
|
if args.order == "desc":
|
|
256
253
|
snap = dataclasses.replace(snap, rows=tuple(reversed(snap.rows)))
|
|
@@ -325,8 +322,6 @@ def cmd_monthly(args: argparse.Namespace) -> int:
|
|
|
325
322
|
period_end=range_end,
|
|
326
323
|
display_tz=display_tz_str,
|
|
327
324
|
version=c._share_resolve_version(),
|
|
328
|
-
theme=args.theme,
|
|
329
|
-
reveal_projects=args.reveal_projects,
|
|
330
325
|
)
|
|
331
326
|
if args.order == "desc":
|
|
332
327
|
snap = dataclasses.replace(snap, rows=tuple(reversed(snap.rows)))
|
|
@@ -460,8 +455,6 @@ def cmd_weekly(args: argparse.Namespace) -> int:
|
|
|
460
455
|
period_end=range_end,
|
|
461
456
|
display_tz=display_tz_str,
|
|
462
457
|
version=c._share_resolve_version(),
|
|
463
|
-
theme=args.theme,
|
|
464
|
-
reveal_projects=args.reveal_projects,
|
|
465
458
|
breakdown_model=bool(getattr(args, "breakdown", False)),
|
|
466
459
|
)
|
|
467
460
|
if args.order == "desc":
|
|
@@ -618,8 +611,6 @@ def cmd_session(args: argparse.Namespace) -> int:
|
|
|
618
611
|
period_end=range_end,
|
|
619
612
|
display_tz=display_tz_str,
|
|
620
613
|
version=c._share_resolve_version(),
|
|
621
|
-
theme=args.theme,
|
|
622
|
-
reveal_projects=args.reveal_projects,
|
|
623
614
|
top_n=top_n,
|
|
624
615
|
tz=tz,
|
|
625
616
|
)
|