cc-session-tools 3.16.2__tar.gz → 4.0.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.
- {cc_session_tools-3.16.2/src/cc_session_tools.egg-info → cc_session_tools-4.0.0}/PKG-INFO +5 -1
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/README.md +4 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/pyproject.toml +1 -1
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/ccst.py +315 -85
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/doctor.py +93 -1
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/hook_registry.py +1 -1
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/dump.py +165 -31
- cc_session_tools-4.0.0/src/cc_session_tools/lib/pdata/formats.py +186 -0
- cc_session_tools-4.0.0/src/cc_session_tools/lib/pdata/ids.py +38 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/init_service.py +45 -19
- cc_session_tools-4.0.0/src/cc_session_tools/lib/pdata/migrate_uuid.py +907 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/rehydrate.py +91 -5
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/repository.py +53 -26
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/resolve.py +69 -89
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/service.py +10 -6
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/session_output.py +53 -5
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/sync_check.py +61 -1
- cc_session_tools-4.0.0/src/cc_session_tools/lib/pdata/vector_clock_store.py +113 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/verify.py +19 -7
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-pdata-do-init/SKILL.md +3 -2
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-pdata-do-manual-migration/SKILL.md +2 -1
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-pdata-do-update-consuming-skills/SKILL.md +2 -1
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-pdata-do-update-project-docs/SKILL.md +2 -1
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-pdata-resolve-conflicts/SKILL.md +26 -36
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0/src/cc_session_tools.egg-info}/PKG-INFO +5 -1
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools.egg-info/SOURCES.txt +6 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/pdata_sync.py +13 -3
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/pending_migration.py +27 -6
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_doctor.py +172 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_pdata_cli.py +15 -11
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_pdata_init_cli.py +54 -0
- cc_session_tools-4.0.0/tests/test_ccst_pdata_migrate_uuid_cli.py +175 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_pdata_sync_cli.py +47 -13
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_date_format_conformance.py +2 -0
- cc_session_tools-4.0.0/tests/test_install_everything_migration_banner.py +151 -0
- cc_session_tools-4.0.0/tests/test_pdata_uuid_migration_runbook.py +92 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_pending_migration_hook.py +106 -0
- cc_session_tools-3.16.2/src/cc_session_tools/lib/pdata/vector_clock_store.py +0 -34
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/LICENSE +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/setup.cfg +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/__init__.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/__init__.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/ccd.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/ccmsg.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/ccr.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/ccs.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/ccsched.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/migrate_sessions_db.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/config/api-keys.example +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/config/hooks-bundle.json +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/config/session-tag-hook.json +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/hooks_install.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/__init__.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/api_keys.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/bun_tools.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/claude_flags.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/claude_md_install.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/claude_md_store.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/context_overrides.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/db.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/debug.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/doctor_mutes.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/install_sync.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/levenshtein.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/machine_identity.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/lock.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/message.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/repository.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/retention.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/service.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/session_ref.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/messaging/store.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/occupancy.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/paths.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/backup.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/classify.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/cutover.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/importers.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/init_paths.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/naming.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/project_claude_md.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/readiness.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/rename_group.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/reorganize.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/store.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/sync_lock.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/sync_notify.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/vector_clock.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/pdata/write_log.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/picker.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/proc_lock.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/prompts.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/roots.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/rules.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/due.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/lock.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/state.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/store.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/session_gc.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/sessions.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/sessions_db.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/sessions_repair.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/shell_install.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/tasklist.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/telemetry_store.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/text_wrap.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/lib/timefmt.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/clean-hook-sessions/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/compact-smart/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/context-override/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/extract-pptx/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/extract-pptx/scripts/extract_pptx.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/extract-to-text/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/extract-to-text/scripts/extract_to_text.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-pdata-design-schema/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools.egg-info/requires.txt +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/cc_session_tools.egg-info/top_level.txt +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/__init__.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/attribution.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/cache.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/ccusage_wrapper.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/data/pricing.json +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/parent_inference.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/parser.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/pricing.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/query.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/report.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/schema.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/claude_code_usage/session_names.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/__init__.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/after_response.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/bash_hard_deny.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/bash_security_review.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/cache.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/catchup.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/confirm_8digit.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/context_window_warning.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/last_screenshot.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/marker_allow.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/markers.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/messaging_deliver.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/model_info.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/normalise.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/pending_rename.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/script_allowlist.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/session_tag.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/stats.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/telemetry.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/telemetry_query.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/telemetry_trim.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/transcript.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/src/hooks/worklog_guard.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_after_response.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_api_keys.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_attribution.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_bash_hard_deny.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_bash_security_review.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_bash_security_review_allowlist.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_bun_tools.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cache.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cache_sqlite.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccr_orphans.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccs_emptiness.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccs_eta.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccs_list_mode.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccs_scope_flags.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccs_sentinel_sort.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccs_session_counts.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_bundle_discovery.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_context_override_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_gc_prune.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_gc_report.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_hook_dispatcher.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_hooks_allowlist.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_hooks_install_prune.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_hooks_uninstall.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_install_everything.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_machine_identity_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_main_gate.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_pdata_readiness_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_pdata_rename_group_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_pdata_reorganize_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_pdata_verify_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_repair_sessions_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_sessions_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_shell_install.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_skills_install.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_skills_uninstall.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_telemetry_query.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccst_telemetry_trim.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_ccusage_wrapper.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_claude_flags.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_claude_md_drift.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_claude_md_install.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_clean_hook_sessions_format.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cli.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cli_api_launchers.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cli_ccd.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cli_ccd_dry_run.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cli_ccr.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cli_ccs.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_cli_version.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_confirm_8digit.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_context_overrides.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_context_window_warning.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_db.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_debug.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_doctor_mutes.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_empty_session.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_hook_cache.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_hooks_install.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_hooks_install_records.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_install_sync.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_last_screenshot.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_levenshtein.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_machine_identity.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_marker_allow.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_migrate_ccmsg.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_migrate_ccsched.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_migrate_sessions_db.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_migrate_telemetry.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_model_info.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_normalise.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_occupancy.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_parent_inference.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_parser.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_paths.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_pdata_audit_skill.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_pdata_post_migration_skills.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_picker.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_pricing.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_proc_lock.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_prompts.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_query.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_report.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_roots.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_rules.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_scheduler_bundled_jobs.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_schema.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_script_allowlist.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_session_names.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_session_tag.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_sessions.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_sessions_db.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_sessions_db_migration_chain.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_sessions_repair.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_tasklist.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_telemetry.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_telemetry_store.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_text_wrap.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_timefmt.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_transcript.py +0 -0
- {cc_session_tools-3.16.2 → cc_session_tools-4.0.0}/tests/test_worklog_guard.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cc-session-tools
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: Claude Code session management CLI tools (ccd, ccr, ccs, claude-code-usage, ccst) and hook library (hooks package)
|
|
5
5
|
Author: raffishquartan
|
|
6
6
|
License: MIT License
|
|
@@ -455,6 +455,10 @@ ccst pdata schema list --project myproject
|
|
|
455
455
|
vector clock per project means a genuine fork (two machines both edited) is flagged for
|
|
456
456
|
your choice with `ccst pdata resolve`, never silently merged. Each machine has a confirmed
|
|
457
457
|
identity (`ccst machine-identity show|confirm`).
|
|
458
|
+
- **UUID record ids** - record ids are UUIDs, so two machines can never hand out the same id
|
|
459
|
+
for different records. Upgrading from 3.x needs a one-time `ccst pdata migrate-uuid` on every
|
|
460
|
+
machine, from a plain terminal: follow
|
|
461
|
+
[docs/pdata-uuid-migration-runbook.md](docs/pdata-uuid-migration-runbook.md).
|
|
458
462
|
- **New projects start well** - the first `pdata init` for a new project seeds starter
|
|
459
463
|
folders and a `CLAUDE.md` with date-format and line-ending conventions. An existing
|
|
460
464
|
`CLAUDE.md` is never touched.
|
|
@@ -396,6 +396,10 @@ ccst pdata schema list --project myproject
|
|
|
396
396
|
vector clock per project means a genuine fork (two machines both edited) is flagged for
|
|
397
397
|
your choice with `ccst pdata resolve`, never silently merged. Each machine has a confirmed
|
|
398
398
|
identity (`ccst machine-identity show|confirm`).
|
|
399
|
+
- **UUID record ids** - record ids are UUIDs, so two machines can never hand out the same id
|
|
400
|
+
for different records. Upgrading from 3.x needs a one-time `ccst pdata migrate-uuid` on every
|
|
401
|
+
machine, from a plain terminal: follow
|
|
402
|
+
[docs/pdata-uuid-migration-runbook.md](docs/pdata-uuid-migration-runbook.md).
|
|
399
403
|
- **New projects start well** - the first `pdata init` for a new project seeds starter
|
|
400
404
|
folders and a `CLAUDE.md` with date-format and line-ending conventions. An existing
|
|
401
405
|
`CLAUDE.md` is never touched.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cc-session-tools"
|
|
7
|
-
version = "
|
|
7
|
+
version = "4.0.0"
|
|
8
8
|
description = "Claude Code session management CLI tools (ccd, ccr, ccs, claude-code-usage, ccst) and hook library (hooks package)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -48,18 +48,24 @@ Current subcommands:
|
|
|
48
48
|
resolution, suspicious double-updates) for --project NAME or
|
|
49
49
|
--all-projects and persist the result for ccst doctor.
|
|
50
50
|
pdata dump Publish the current local DB state to
|
|
51
|
-
.pdata-db-dump/latest.sql for --project NAME or
|
|
51
|
+
.pdata-db-dump/v4/latest.sql for --project NAME or
|
|
52
52
|
--all-projects. Refuses (unless --force) to overwrite an
|
|
53
53
|
unresolved cross-machine fork.
|
|
54
54
|
pdata rehydrate Fast-forward the local DB from the published dump for
|
|
55
55
|
--project NAME or --all-projects, if it's ahead. --force
|
|
56
56
|
fast-forwards even over a diverged local revision.
|
|
57
57
|
pdata resolve Diagnose (default, prints the diff) or apply per-record
|
|
58
|
-
--choice
|
|
58
|
+
--choice UUID=local|dump resolutions for a cross-machine fork.
|
|
59
59
|
pdata sync-check Do whichever of rehydrate/dump each project needs, in that
|
|
60
60
|
order, for --project NAME or --all-projects. The unattended
|
|
61
61
|
trigger behind the hourly pdata-sync-hourly ccsched job:
|
|
62
62
|
skips an unchanged republish and never overrides a fork.
|
|
63
|
+
pdata migrate-uuid Convert format 3 (integer id) databases to format 4 (UUID
|
|
64
|
+
ids) for --project NAME or --all-projects. Dry run unless
|
|
65
|
+
--write; run from a plain terminal with no `claude` session.
|
|
66
|
+
pdata migration-notice Print the migrate-uuid dry run and a framed banner when any
|
|
67
|
+
project is still format 3; nothing otherwise. Used by
|
|
68
|
+
install-everything.sh; always exits 0.
|
|
63
69
|
machine-identity show Print this laptop's resolved machine id and whether it's
|
|
64
70
|
confirmed.
|
|
65
71
|
machine-identity confirm Store this laptop's confirmed machine id (--name NAME), used
|
|
@@ -1029,6 +1035,165 @@ def _cmd_gc_prune(args: argparse.Namespace) -> int:
|
|
|
1029
1035
|
# ---------- pdata ----------
|
|
1030
1036
|
|
|
1031
1037
|
|
|
1038
|
+
def _record_id_arg(raw: str) -> str:
|
|
1039
|
+
"""argparse type for a record id: a canonical UUID string, else a usage error naming it."""
|
|
1040
|
+
from cc_session_tools.lib.pdata import ids
|
|
1041
|
+
|
|
1042
|
+
if not ids.is_record_id(raw):
|
|
1043
|
+
raise argparse.ArgumentTypeError(
|
|
1044
|
+
f"{raw!r} is not a UUID (record ids look like 3f2b8c1e-6d4a-4e9b-9a7c-2d5e8f1b0c64)"
|
|
1045
|
+
)
|
|
1046
|
+
return raw
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
def _pdata_gate_targets(args: argparse.Namespace) -> list[str]:
|
|
1050
|
+
"""The projects a gated verb would open: the named one, or every project its --all-projects
|
|
1051
|
+
run would visit. `reconcile-session-output --all-projects` visits projects that have a
|
|
1052
|
+
cc-sessions/ directory, with or without a database, so it is the one verb whose sweep can
|
|
1053
|
+
create a database."""
|
|
1054
|
+
from cc_session_tools.lib import roots
|
|
1055
|
+
from cc_session_tools.lib.pdata import session_output, verify
|
|
1056
|
+
|
|
1057
|
+
if not getattr(args, "all_projects", False):
|
|
1058
|
+
return [args.project]
|
|
1059
|
+
if args.verb == "reconcile-session-output":
|
|
1060
|
+
try:
|
|
1061
|
+
return [name for name, _root in session_output.discover_projects_with_sessions()]
|
|
1062
|
+
except roots.RootsConfigError:
|
|
1063
|
+
return [] # the verb's own handler reports the missing configuration
|
|
1064
|
+
return verify.discover_projects()
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
@dataclass(frozen=True, slots=True)
|
|
1068
|
+
class _PdataFormatGate:
|
|
1069
|
+
targets: tuple[str, ...] # every project the verb would open
|
|
1070
|
+
refused: tuple[str, ...] # those it must not open, each already named on stderr
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
def _pdata_gate_reason(verb: str, project: str) -> str | None:
|
|
1074
|
+
"""Why the format gate keeps `verb` off `project`, or None when it may run there."""
|
|
1075
|
+
import sqlite3
|
|
1076
|
+
|
|
1077
|
+
from cc_session_tools.lib.pdata import dump, formats, store, vector_clock_store
|
|
1078
|
+
|
|
1079
|
+
try:
|
|
1080
|
+
path = store.db_path(project)
|
|
1081
|
+
project_root = store.project_root(project)
|
|
1082
|
+
except ValueError:
|
|
1083
|
+
return None # the verb's own handler rejects an invalid project name
|
|
1084
|
+
if not path.exists():
|
|
1085
|
+
# `init` refuses this case itself, with its adoption-mismatch message.
|
|
1086
|
+
if verb != "init" and dump.only_format3_published(project_root):
|
|
1087
|
+
return formats.format3_only_message(project)
|
|
1088
|
+
return None
|
|
1089
|
+
try:
|
|
1090
|
+
fmt = formats.database_format(path)
|
|
1091
|
+
except formats.UnknownPdataFormatError as exc:
|
|
1092
|
+
return f"{project}: {exc}"
|
|
1093
|
+
except sqlite3.DatabaseError:
|
|
1094
|
+
return None # not a readable database: the verb's own handler reports it per project
|
|
1095
|
+
if fmt == formats.PDATA_FORMAT_INTEGER_IDS:
|
|
1096
|
+
return formats.legacy_format_message(project)
|
|
1097
|
+
if vector_clock_store.migration_unfinished(path):
|
|
1098
|
+
return formats.unfinished_migration_message(project)
|
|
1099
|
+
return None
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
def _pdata_format_gate(args: argparse.Namespace) -> _PdataFormatGate:
|
|
1103
|
+
"""The format gate (`formats` module docstring), for a verb that is not exempt: every target
|
|
1104
|
+
project whose database is still format 3, or was converted by a migration run that did not
|
|
1105
|
+
finish, or that has no database while its only published dump is format 3, is refused, with
|
|
1106
|
+
the reason printed to stderr. Read-only, and runs before the verb's handler opens anything."""
|
|
1107
|
+
from cc_session_tools.lib.pdata import formats
|
|
1108
|
+
|
|
1109
|
+
if args.verb in formats.FORMAT_GATE_EXEMPT_VERBS:
|
|
1110
|
+
return _PdataFormatGate(targets=(), refused=())
|
|
1111
|
+
targets = tuple(_pdata_gate_targets(args))
|
|
1112
|
+
skipping = "skipped " if getattr(args, "all_projects", False) else ""
|
|
1113
|
+
refused: list[str] = []
|
|
1114
|
+
for project in targets:
|
|
1115
|
+
reason = _pdata_gate_reason(args.verb, project)
|
|
1116
|
+
if reason is not None:
|
|
1117
|
+
print(f"ccst pdata {args.verb}: {skipping}{reason}", file=sys.stderr)
|
|
1118
|
+
refused.append(project)
|
|
1119
|
+
return _PdataFormatGate(targets=targets, refused=tuple(refused))
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
def _pdata_projects(args: argparse.Namespace) -> list[str]:
|
|
1123
|
+
"""The projects a verb handler runs on: the named one, or for --all-projects every project
|
|
1124
|
+
with a database except those the format gate refused."""
|
|
1125
|
+
from cc_session_tools.lib.pdata import verify
|
|
1126
|
+
|
|
1127
|
+
if not args.all_projects:
|
|
1128
|
+
return [args.project]
|
|
1129
|
+
gated: frozenset[str] = getattr(args, "format_gated_projects", frozenset())
|
|
1130
|
+
return [project for project in verify.discover_projects() if project not in gated]
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
def _cmd_pdata(args: argparse.Namespace) -> int:
|
|
1134
|
+
"""Run one `ccst pdata` verb behind the format gate. A single-project run on a gated project
|
|
1135
|
+
refuses with exit 1. An --all-projects run skips the gated projects (naming each), runs the
|
|
1136
|
+
verb on the rest, and exits 1 at the end when it skipped any and the verb itself succeeded."""
|
|
1137
|
+
gate = _pdata_format_gate(args)
|
|
1138
|
+
if gate.refused:
|
|
1139
|
+
if not getattr(args, "all_projects", False):
|
|
1140
|
+
return 1
|
|
1141
|
+
args.format_gated_projects = frozenset(gate.refused)
|
|
1142
|
+
if set(gate.targets) <= set(gate.refused):
|
|
1143
|
+
return 1
|
|
1144
|
+
status = _run_pdata_verb(args)
|
|
1145
|
+
return 1 if gate.refused and status == 0 else status
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
def _run_pdata_verb(args: argparse.Namespace) -> int:
|
|
1149
|
+
if args.verb == "add":
|
|
1150
|
+
return _cmd_pdata_add(args)
|
|
1151
|
+
if args.verb == "schema":
|
|
1152
|
+
if args.subverb == "add-field":
|
|
1153
|
+
return _cmd_pdata_schema_add_field(args)
|
|
1154
|
+
if args.subverb == "list":
|
|
1155
|
+
return _cmd_pdata_schema_list(args)
|
|
1156
|
+
if args.subverb == "show":
|
|
1157
|
+
return _cmd_pdata_schema_show(args)
|
|
1158
|
+
if args.verb == "get":
|
|
1159
|
+
return _cmd_pdata_get(args)
|
|
1160
|
+
if args.verb == "list":
|
|
1161
|
+
return _cmd_pdata_list(args)
|
|
1162
|
+
if args.verb == "query":
|
|
1163
|
+
return _cmd_pdata_query(args)
|
|
1164
|
+
if args.verb == "update":
|
|
1165
|
+
return _cmd_pdata_update(args)
|
|
1166
|
+
if args.verb == "delete":
|
|
1167
|
+
return _cmd_pdata_delete(args)
|
|
1168
|
+
if args.verb == "restore":
|
|
1169
|
+
return _cmd_pdata_restore(args)
|
|
1170
|
+
if args.verb == "init":
|
|
1171
|
+
return _cmd_pdata_init(args)
|
|
1172
|
+
if args.verb == "reorganize":
|
|
1173
|
+
return _cmd_pdata_reorganize(args)
|
|
1174
|
+
if args.verb == "rename-group":
|
|
1175
|
+
return _cmd_pdata_rename_group(args)
|
|
1176
|
+
if args.verb == "reconcile-session-output":
|
|
1177
|
+
return _cmd_pdata_reconcile_session_output(args)
|
|
1178
|
+
if args.verb == "verify":
|
|
1179
|
+
return _cmd_pdata_verify(args)
|
|
1180
|
+
if args.verb == "readiness-scan":
|
|
1181
|
+
return _cmd_pdata_readiness_scan(args)
|
|
1182
|
+
if args.verb == "dump":
|
|
1183
|
+
return _cmd_pdata_dump(args)
|
|
1184
|
+
if args.verb == "rehydrate":
|
|
1185
|
+
return _cmd_pdata_rehydrate(args)
|
|
1186
|
+
if args.verb == "resolve":
|
|
1187
|
+
return _cmd_pdata_resolve(args)
|
|
1188
|
+
if args.verb == "sync-check":
|
|
1189
|
+
return _cmd_pdata_sync_check(args)
|
|
1190
|
+
if args.verb == "migrate-uuid":
|
|
1191
|
+
return _cmd_pdata_migrate_uuid(args)
|
|
1192
|
+
if args.verb == "migration-notice":
|
|
1193
|
+
return _cmd_pdata_migration_notice(args)
|
|
1194
|
+
raise AssertionError(f"unhandled ccst pdata verb {args.verb!r}")
|
|
1195
|
+
|
|
1196
|
+
|
|
1032
1197
|
def _parse_field_assignment(raw: str) -> tuple[str, str | None]:
|
|
1033
1198
|
"""Parse "k=v" into (k, v). The literal token `null` (unquoted, lowercase) is interpreted
|
|
1034
1199
|
as SQL NULL rather than the four-character string "null" - this is the documented way to
|
|
@@ -1453,7 +1618,11 @@ def _cmd_pdata_reconcile_session_output(args: argparse.Namespace) -> int:
|
|
|
1453
1618
|
|
|
1454
1619
|
try:
|
|
1455
1620
|
if args.all_projects:
|
|
1456
|
-
|
|
1621
|
+
gated: frozenset[str] = getattr(args, "format_gated_projects", frozenset())
|
|
1622
|
+
targets = [
|
|
1623
|
+
(name, root) for name, root in session_output.discover_projects_with_sessions()
|
|
1624
|
+
if name not in gated
|
|
1625
|
+
]
|
|
1457
1626
|
else:
|
|
1458
1627
|
root = session_output.find_project_root(args.project)
|
|
1459
1628
|
if root is None:
|
|
@@ -1491,7 +1660,7 @@ def _cmd_pdata_reconcile_session_output(args: argparse.Namespace) -> int:
|
|
|
1491
1660
|
def _cmd_pdata_verify(args: argparse.Namespace) -> int:
|
|
1492
1661
|
from cc_session_tools.lib.pdata import verify
|
|
1493
1662
|
|
|
1494
|
-
projects =
|
|
1663
|
+
projects = _pdata_projects(args)
|
|
1495
1664
|
if not projects:
|
|
1496
1665
|
print("ccst pdata verify: no project databases found", file=sys.stderr)
|
|
1497
1666
|
return 2
|
|
@@ -1566,10 +1735,10 @@ def _cmd_pdata_verify(args: argparse.Namespace) -> int:
|
|
|
1566
1735
|
def _cmd_pdata_dump(args: argparse.Namespace) -> int:
|
|
1567
1736
|
from cc_session_tools.lib import machine_identity
|
|
1568
1737
|
from cc_session_tools.lib.pdata import (
|
|
1569
|
-
dump, repository, store, sync_notify, vector_clock_store,
|
|
1738
|
+
dump, repository, store, sync_notify, vector_clock_store,
|
|
1570
1739
|
)
|
|
1571
1740
|
|
|
1572
|
-
projects =
|
|
1741
|
+
projects = _pdata_projects(args)
|
|
1573
1742
|
if not projects:
|
|
1574
1743
|
print("ccst pdata dump: no project databases found", file=sys.stderr)
|
|
1575
1744
|
return 2
|
|
@@ -1630,9 +1799,9 @@ def _cmd_pdata_dump(args: argparse.Namespace) -> int:
|
|
|
1630
1799
|
|
|
1631
1800
|
|
|
1632
1801
|
def _cmd_pdata_rehydrate(args: argparse.Namespace) -> int:
|
|
1633
|
-
from cc_session_tools.lib.pdata import rehydrate, sync_notify
|
|
1802
|
+
from cc_session_tools.lib.pdata import rehydrate, sync_notify
|
|
1634
1803
|
|
|
1635
|
-
projects =
|
|
1804
|
+
projects = _pdata_projects(args)
|
|
1636
1805
|
if not projects:
|
|
1637
1806
|
print("ccst pdata rehydrate: no project databases found", file=sys.stderr)
|
|
1638
1807
|
return 2
|
|
@@ -1669,6 +1838,12 @@ def _cmd_pdata_rehydrate(args: argparse.Namespace) -> int:
|
|
|
1669
1838
|
sync_notify.notify_conflict(project, outcome=result.outcome.value, detail=detail)
|
|
1670
1839
|
if not compact:
|
|
1671
1840
|
print(f"ccst pdata rehydrate: {project}: {detail}", file=sys.stderr)
|
|
1841
|
+
elif result.outcome is rehydrate.RehydrateOutcome.MIGRATION_PENDING:
|
|
1842
|
+
# Nothing loaded, and not a conflict: the published dump and this database are
|
|
1843
|
+
# different formats until `ccst pdata migrate-uuid` runs on the format 3 side.
|
|
1844
|
+
if not compact:
|
|
1845
|
+
detail = rehydrate.migration_pending_detail(result, project=project)
|
|
1846
|
+
print(f"ccst pdata rehydrate: {project}: migration pending - {detail}")
|
|
1672
1847
|
else:
|
|
1673
1848
|
# DEFERRED - another writer holds sync_lock right now. Expected and transient, not
|
|
1674
1849
|
# an error (rehydrate.py's own RehydrateOutcome docstring: "retry later" rather than
|
|
@@ -1687,24 +1862,28 @@ def _cmd_pdata_rehydrate(args: argparse.Namespace) -> int:
|
|
|
1687
1862
|
f"no-op {counts[rehydrate.RehydrateOutcome.NO_OP.value]}, "
|
|
1688
1863
|
f"fork {counts[rehydrate.RehydrateOutcome.FORK.value]}, "
|
|
1689
1864
|
f"checksum-invalid {counts[rehydrate.RehydrateOutcome.CHECKSUM_INVALID.value]}, "
|
|
1690
|
-
f"deferred {counts[rehydrate.RehydrateOutcome.DEFERRED.value]}
|
|
1865
|
+
f"deferred {counts[rehydrate.RehydrateOutcome.DEFERRED.value]}, "
|
|
1866
|
+
f"migration-pending {counts[rehydrate.RehydrateOutcome.MIGRATION_PENDING.value]} of "
|
|
1691
1867
|
f"{len(projects)} project(s)"
|
|
1692
1868
|
)
|
|
1693
1869
|
|
|
1694
1870
|
return worst
|
|
1695
1871
|
|
|
1696
1872
|
|
|
1697
|
-
def _parse_resolve_choice(raw: str) -> tuple[
|
|
1698
|
-
"""Parse "
|
|
1699
|
-
actually 'local'/'dump' is apply_resolution's own job
|
|
1700
|
-
not re-derived here). Raises ValueError on malformed
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1873
|
+
def _parse_resolve_choice(raw: str) -> tuple[str, str]:
|
|
1874
|
+
"""Parse "UUID=local|dump" into (record_id, choice). Only checks the shape and that the id is
|
|
1875
|
+
a canonical UUID - whether choice is actually 'local'/'dump' is apply_resolution's own job
|
|
1876
|
+
(its error message is printed verbatim, not re-derived here). Raises ValueError on malformed
|
|
1877
|
+
input."""
|
|
1878
|
+
from cc_session_tools.lib.pdata import ids
|
|
1879
|
+
|
|
1880
|
+
record_id, sep, choice = raw.partition("=")
|
|
1881
|
+
if not sep or not record_id or not choice:
|
|
1882
|
+
raise ValueError(f"malformed --choice (want UUID=local|dump): {raw!r}")
|
|
1883
|
+
if not ids.is_record_id(record_id):
|
|
1884
|
+
raise ValueError(
|
|
1885
|
+
f"malformed --choice (want UUID=local|dump): {raw!r} - {record_id!r} is not a UUID"
|
|
1886
|
+
)
|
|
1708
1887
|
return record_id, choice
|
|
1709
1888
|
|
|
1710
1889
|
|
|
@@ -1749,7 +1928,7 @@ def _close_empty_fork_if_any(project: str) -> bool:
|
|
|
1749
1928
|
|
|
1750
1929
|
|
|
1751
1930
|
def _cmd_pdata_resolve(args: argparse.Namespace) -> int:
|
|
1752
|
-
from cc_session_tools.lib.pdata import resolve
|
|
1931
|
+
from cc_session_tools.lib.pdata import resolve
|
|
1753
1932
|
|
|
1754
1933
|
if args.choice:
|
|
1755
1934
|
if args.all_projects:
|
|
@@ -1783,7 +1962,7 @@ def _cmd_pdata_resolve(args: argparse.Namespace) -> int:
|
|
|
1783
1962
|
print(f"ccst pdata resolve: {args.project}: resolved {len(choices)} record(s)")
|
|
1784
1963
|
return 0
|
|
1785
1964
|
|
|
1786
|
-
projects =
|
|
1965
|
+
projects = _pdata_projects(args)
|
|
1787
1966
|
if not projects:
|
|
1788
1967
|
print("ccst pdata resolve: no project databases found", file=sys.stderr)
|
|
1789
1968
|
return 2
|
|
@@ -1828,15 +2007,6 @@ def _cmd_pdata_resolve(args: argparse.Namespace) -> int:
|
|
|
1828
2007
|
f"field(s) to resolve"
|
|
1829
2008
|
)
|
|
1830
2009
|
for rd in diff.records:
|
|
1831
|
-
if rd.id_collision:
|
|
1832
|
-
print(
|
|
1833
|
-
f" record {rd.record_id} (group={rd.record_group}): id collision - "
|
|
1834
|
-
f"this id was independently assigned to two unrelated records on "
|
|
1835
|
-
f"different machines, not a genuine edit conflict; `ccst pdata resolve` "
|
|
1836
|
-
f"cannot apply a local/dump choice to this one, it needs manual, "
|
|
1837
|
-
f"out-of-band reconciliation"
|
|
1838
|
-
)
|
|
1839
|
-
continue
|
|
1840
2010
|
if rd.group_mismatch:
|
|
1841
2011
|
# Both sides' own group names, not rd.record_group: that field carries whichever
|
|
1842
2012
|
# side happened to be available, and RecordDiff's docstring says so - printing it
|
|
@@ -1844,11 +2014,10 @@ def _cmd_pdata_resolve(args: argparse.Namespace) -> int:
|
|
|
1844
2014
|
# the reader neither which side they are seeing nor what the other side's is.
|
|
1845
2015
|
print(
|
|
1846
2016
|
f" record {rd.record_id} (local group={rd.local_record_group}, "
|
|
1847
|
-
f"dump group={rd.dump_record_group}): group mismatch - same
|
|
1848
|
-
f"
|
|
1849
|
-
f"
|
|
1850
|
-
f"
|
|
1851
|
-
f"`ccst pdata resolve` cannot apply a local/dump choice to this one"
|
|
2017
|
+
f"dump group={rd.dump_record_group}): group mismatch - the same record, "
|
|
2018
|
+
f"but local and dump disagree on record_group; run `ccst pdata "
|
|
2019
|
+
f"rename-group` on one side so both agree - `ccst pdata resolve` cannot "
|
|
2020
|
+
f"apply a local/dump choice to this one"
|
|
1852
2021
|
)
|
|
1853
2022
|
continue
|
|
1854
2023
|
if rd.is_delete_vs_update:
|
|
@@ -1916,9 +2085,9 @@ def _cmd_pdata_sync_check(args: argparse.Namespace) -> int:
|
|
|
1916
2085
|
rules). This handler is the loop, the printing, and the exit-code mapping."""
|
|
1917
2086
|
import sqlite3
|
|
1918
2087
|
|
|
1919
|
-
from cc_session_tools.lib.pdata import sync_check
|
|
2088
|
+
from cc_session_tools.lib.pdata import sync_check
|
|
1920
2089
|
|
|
1921
|
-
projects =
|
|
2090
|
+
projects = _pdata_projects(args)
|
|
1922
2091
|
if not projects:
|
|
1923
2092
|
print("ccst pdata sync-check: no project databases found", file=sys.stderr)
|
|
1924
2093
|
return 2
|
|
@@ -1953,6 +2122,18 @@ def _cmd_pdata_sync_check(args: argparse.Namespace) -> int:
|
|
|
1953
2122
|
worst = max(worst, 1)
|
|
1954
2123
|
if not compact:
|
|
1955
2124
|
print(f"ccst pdata sync-check: {project}: {result.detail}", file=sys.stderr)
|
|
2125
|
+
elif result.outcome is sync_check.SyncOutcome.MIGRATION_PENDING:
|
|
2126
|
+
# Status, not an error and not a conflict: the project waits for `ccst pdata
|
|
2127
|
+
# migrate-uuid`, and the doctor check and pending-migration hook report that.
|
|
2128
|
+
if not compact:
|
|
2129
|
+
status = (
|
|
2130
|
+
f" (format 3 dump: {result.format3_status.value})"
|
|
2131
|
+
if result.format3_status is not None else ""
|
|
2132
|
+
)
|
|
2133
|
+
print(
|
|
2134
|
+
f"ccst pdata sync-check: {project}: migration pending{status} - "
|
|
2135
|
+
f"{result.detail}"
|
|
2136
|
+
)
|
|
1956
2137
|
elif not compact:
|
|
1957
2138
|
print(f"ccst pdata sync-check: {project}: {_sync_check_line(result)}")
|
|
1958
2139
|
|
|
@@ -1965,6 +2146,7 @@ def _cmd_pdata_sync_check(args: argparse.Namespace) -> int:
|
|
|
1965
2146
|
f"conflict {counts[sync_check.SyncOutcome.CONFLICT.value]}, "
|
|
1966
2147
|
f"deferred {counts[sync_check.SyncOutcome.DEFERRED.value]}, "
|
|
1967
2148
|
f"occupied {counts[sync_check.SyncOutcome.OCCUPIED.value]}, "
|
|
2149
|
+
f"migration-pending {counts[sync_check.SyncOutcome.MIGRATION_PENDING.value]}, "
|
|
1968
2150
|
f"errors {errors} of {len(projects)} project(s)"
|
|
1969
2151
|
)
|
|
1970
2152
|
|
|
@@ -1974,6 +2156,67 @@ def _cmd_pdata_sync_check(args: argparse.Namespace) -> int:
|
|
|
1974
2156
|
return worst
|
|
1975
2157
|
|
|
1976
2158
|
|
|
2159
|
+
def _cmd_pdata_migrate_uuid(args: argparse.Namespace) -> int:
|
|
2160
|
+
"""`ccst pdata migrate-uuid`: every rule lives in `pdata.migrate_uuid`; this handler is the
|
|
2161
|
+
project loop, the printing and the exit status (the worst over all projects)."""
|
|
2162
|
+
projects = _pdata_projects(args)
|
|
2163
|
+
if not projects:
|
|
2164
|
+
print("ccst pdata migrate-uuid: no project databases found - nothing to migrate")
|
|
2165
|
+
return 0
|
|
2166
|
+
return _run_pdata_migrate_uuid(projects, write=args.write)
|
|
2167
|
+
|
|
2168
|
+
|
|
2169
|
+
def _run_pdata_migrate_uuid(projects: list[str], *, write: bool) -> int:
|
|
2170
|
+
"""Run `migrate_uuid.migrate_project` over `projects`, printing each report; returns the
|
|
2171
|
+
worst exit status."""
|
|
2172
|
+
import sqlite3
|
|
2173
|
+
|
|
2174
|
+
from cc_session_tools.lib.pdata import migrate_uuid
|
|
2175
|
+
|
|
2176
|
+
worst = 0
|
|
2177
|
+
for project in projects:
|
|
2178
|
+
try:
|
|
2179
|
+
result = migrate_uuid.migrate_project(project, write=write)
|
|
2180
|
+
except (OSError, ValueError, sqlite3.Error) as exc:
|
|
2181
|
+
print(f"ccst pdata migrate-uuid: {project}: {exc}", file=sys.stderr)
|
|
2182
|
+
worst = max(worst, 2)
|
|
2183
|
+
continue
|
|
2184
|
+
status = migrate_uuid.exit_status(result.outcome)
|
|
2185
|
+
stream = sys.stderr if status else sys.stdout
|
|
2186
|
+
for line in migrate_uuid.render(result):
|
|
2187
|
+
print(line, file=stream)
|
|
2188
|
+
worst = max(worst, status)
|
|
2189
|
+
return worst
|
|
2190
|
+
|
|
2191
|
+
|
|
2192
|
+
def _cmd_pdata_migration_notice(args: argparse.Namespace) -> int:
|
|
2193
|
+
"""`ccst pdata migration-notice`: for `install-everything.sh`. Prints nothing when no project
|
|
2194
|
+
database is format 3; otherwise the migrate-uuid dry run for those projects, then the framed
|
|
2195
|
+
banner. Always exits 0 - it is advice, and must not change the installer's exit status."""
|
|
2196
|
+
import sqlite3
|
|
2197
|
+
|
|
2198
|
+
from cc_session_tools.lib.pdata import formats, migrate_uuid, store, verify
|
|
2199
|
+
|
|
2200
|
+
unmigrated: list[str] = []
|
|
2201
|
+
for project in verify.discover_projects():
|
|
2202
|
+
try:
|
|
2203
|
+
fmt = formats.database_format(store.db_path(project))
|
|
2204
|
+
except (formats.UnknownPdataFormatError, sqlite3.DatabaseError) as exc:
|
|
2205
|
+
print(f"ccst pdata migration-notice: {project}: could not read the database "
|
|
2206
|
+
f"format ({exc}); see `ccst doctor`", file=sys.stderr)
|
|
2207
|
+
continue
|
|
2208
|
+
if fmt == formats.PDATA_FORMAT_INTEGER_IDS:
|
|
2209
|
+
unmigrated.append(project)
|
|
2210
|
+
if not unmigrated:
|
|
2211
|
+
return 0
|
|
2212
|
+
print(f"{formats.MIGRATE_COMMAND} --all-projects (dry run) for the format 3 projects:")
|
|
2213
|
+
_run_pdata_migrate_uuid(unmigrated, write=False)
|
|
2214
|
+
print()
|
|
2215
|
+
for line in migrate_uuid.install_banner(unmigrated):
|
|
2216
|
+
print(line)
|
|
2217
|
+
return 0
|
|
2218
|
+
|
|
2219
|
+
|
|
1977
2220
|
def _sync_check_line(result: SyncCheckResult) -> str:
|
|
1978
2221
|
"""The one-line, --project-mode wording for each non-conflict sync-check outcome."""
|
|
1979
2222
|
from cc_session_tools.lib.pdata import sync_check
|
|
@@ -3191,7 +3434,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
3191
3434
|
|
|
3192
3435
|
pdata_get_parser = pdata_sub.add_parser("get", help="Fetch a single record by id")
|
|
3193
3436
|
pdata_get_parser.add_argument("--project", required=True, metavar="NAME")
|
|
3194
|
-
pdata_get_parser.add_argument("--id", required=True, type=
|
|
3437
|
+
pdata_get_parser.add_argument("--id", required=True, type=_record_id_arg, metavar="UUID")
|
|
3195
3438
|
pdata_get_parser.add_argument("--include-deleted", action="store_true")
|
|
3196
3439
|
|
|
3197
3440
|
pdata_list_parser = pdata_sub.add_parser("list", help="List records in one record_group")
|
|
@@ -3222,7 +3465,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
3222
3465
|
|
|
3223
3466
|
pdata_update_parser = pdata_sub.add_parser("update", help="Update a record (version-checked)")
|
|
3224
3467
|
pdata_update_parser.add_argument("--project", required=True, metavar="NAME")
|
|
3225
|
-
pdata_update_parser.add_argument("--id", required=True, type=
|
|
3468
|
+
pdata_update_parser.add_argument("--id", required=True, type=_record_id_arg, metavar="UUID")
|
|
3226
3469
|
pdata_update_parser.add_argument("--version", required=True, type=int, dest="version",
|
|
3227
3470
|
metavar="EXPECTED_VERSION")
|
|
3228
3471
|
pdata_update_parser.add_argument(
|
|
@@ -3248,13 +3491,13 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
3248
3491
|
|
|
3249
3492
|
pdata_delete_parser = pdata_sub.add_parser("delete", help="Soft-delete a record (version-checked)")
|
|
3250
3493
|
pdata_delete_parser.add_argument("--project", required=True, metavar="NAME")
|
|
3251
|
-
pdata_delete_parser.add_argument("--id", required=True, type=
|
|
3494
|
+
pdata_delete_parser.add_argument("--id", required=True, type=_record_id_arg, metavar="UUID")
|
|
3252
3495
|
pdata_delete_parser.add_argument("--version", required=True, type=int,
|
|
3253
3496
|
metavar="EXPECTED_VERSION")
|
|
3254
3497
|
|
|
3255
3498
|
pdata_restore_parser = pdata_sub.add_parser("restore", help="Clear a soft-delete")
|
|
3256
3499
|
pdata_restore_parser.add_argument("--project", required=True, metavar="NAME")
|
|
3257
|
-
pdata_restore_parser.add_argument("--id", required=True, type=
|
|
3500
|
+
pdata_restore_parser.add_argument("--id", required=True, type=_record_id_arg, metavar="UUID")
|
|
3258
3501
|
|
|
3259
3502
|
pdata_init_parser = pdata_sub.add_parser(
|
|
3260
3503
|
"init", help="Initialize/migrate a project's data store (spec §7)"
|
|
@@ -3324,6 +3567,33 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
3324
3567
|
"(no file scan or registration)",
|
|
3325
3568
|
)
|
|
3326
3569
|
|
|
3570
|
+
pdata_migrate_uuid_parser = pdata_sub.add_parser(
|
|
3571
|
+
"migrate-uuid",
|
|
3572
|
+
help="Convert format 3 (integer id) databases to format 4 (UUID ids). Dry run by "
|
|
3573
|
+
"default; run from a plain terminal with no `claude` session running",
|
|
3574
|
+
)
|
|
3575
|
+
migrate_uuid_target = pdata_migrate_uuid_parser.add_mutually_exclusive_group(required=True)
|
|
3576
|
+
migrate_uuid_target.add_argument("--project", metavar="NAME")
|
|
3577
|
+
migrate_uuid_target.add_argument(
|
|
3578
|
+
"--all-projects", action="store_true",
|
|
3579
|
+
help="Migrate every project with a .db under project-db/",
|
|
3580
|
+
)
|
|
3581
|
+
migrate_uuid_mode = pdata_migrate_uuid_parser.add_mutually_exclusive_group()
|
|
3582
|
+
migrate_uuid_mode.add_argument(
|
|
3583
|
+
"--dry-run", action="store_true",
|
|
3584
|
+
help="Print the plan and every precondition without changing anything (the default)",
|
|
3585
|
+
)
|
|
3586
|
+
migrate_uuid_mode.add_argument(
|
|
3587
|
+
"--write", action="store_true",
|
|
3588
|
+
help="Back up, migrate, verify, record the marker and publish the format 4 dump",
|
|
3589
|
+
)
|
|
3590
|
+
|
|
3591
|
+
pdata_sub.add_parser(
|
|
3592
|
+
"migration-notice",
|
|
3593
|
+
help="Print the migrate-uuid dry run and a framed banner when any project is still "
|
|
3594
|
+
"format 3; nothing otherwise (used by install-everything.sh; always exits 0)",
|
|
3595
|
+
)
|
|
3596
|
+
|
|
3327
3597
|
pdata_verify_parser = pdata_sub.add_parser(
|
|
3328
3598
|
"verify", help="Run the integrity-check backstop (spec §6.3/§8.2)"
|
|
3329
3599
|
)
|
|
@@ -3362,7 +3632,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
3362
3632
|
)
|
|
3363
3633
|
|
|
3364
3634
|
pdata_dump_parser = pdata_sub.add_parser(
|
|
3365
|
-
"dump", help="Publish the current local DB state to .pdata-db-dump/latest.sql"
|
|
3635
|
+
"dump", help="Publish the current local DB state to .pdata-db-dump/v4/latest.sql"
|
|
3366
3636
|
)
|
|
3367
3637
|
dump_target = pdata_dump_parser.add_mutually_exclusive_group(required=True)
|
|
3368
3638
|
dump_target.add_argument("--project", metavar="NAME")
|
|
@@ -3403,7 +3673,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
3403
3673
|
"--choice requires --project)",
|
|
3404
3674
|
)
|
|
3405
3675
|
pdata_resolve_parser.add_argument(
|
|
3406
|
-
"--choice", action="append", default=[], metavar="
|
|
3676
|
+
"--choice", action="append", default=[], metavar="UUID=local|dump",
|
|
3407
3677
|
help="Apply a per-record resolution; may repeat. Requires --project. Without any "
|
|
3408
3678
|
"--choice, resolve runs in diagnostic (dry-run) mode and prints the diff.",
|
|
3409
3679
|
)
|
|
@@ -3749,47 +4019,7 @@ def main() -> None:
|
|
|
3749
4019
|
sys.exit(_cmd_gc_prune(args))
|
|
3750
4020
|
|
|
3751
4021
|
if args.noun == "pdata":
|
|
3752
|
-
|
|
3753
|
-
sys.exit(_cmd_pdata_add(args))
|
|
3754
|
-
if args.verb == "schema":
|
|
3755
|
-
if args.subverb == "add-field":
|
|
3756
|
-
sys.exit(_cmd_pdata_schema_add_field(args))
|
|
3757
|
-
if args.subverb == "list":
|
|
3758
|
-
sys.exit(_cmd_pdata_schema_list(args))
|
|
3759
|
-
if args.subverb == "show":
|
|
3760
|
-
sys.exit(_cmd_pdata_schema_show(args))
|
|
3761
|
-
if args.verb == "get":
|
|
3762
|
-
sys.exit(_cmd_pdata_get(args))
|
|
3763
|
-
if args.verb == "list":
|
|
3764
|
-
sys.exit(_cmd_pdata_list(args))
|
|
3765
|
-
if args.verb == "query":
|
|
3766
|
-
sys.exit(_cmd_pdata_query(args))
|
|
3767
|
-
if args.verb == "update":
|
|
3768
|
-
sys.exit(_cmd_pdata_update(args))
|
|
3769
|
-
if args.verb == "delete":
|
|
3770
|
-
sys.exit(_cmd_pdata_delete(args))
|
|
3771
|
-
if args.verb == "restore":
|
|
3772
|
-
sys.exit(_cmd_pdata_restore(args))
|
|
3773
|
-
if args.verb == "init":
|
|
3774
|
-
sys.exit(_cmd_pdata_init(args))
|
|
3775
|
-
if args.verb == "reorganize":
|
|
3776
|
-
sys.exit(_cmd_pdata_reorganize(args))
|
|
3777
|
-
if args.verb == "rename-group":
|
|
3778
|
-
sys.exit(_cmd_pdata_rename_group(args))
|
|
3779
|
-
if args.verb == "reconcile-session-output":
|
|
3780
|
-
sys.exit(_cmd_pdata_reconcile_session_output(args))
|
|
3781
|
-
if args.verb == "verify":
|
|
3782
|
-
sys.exit(_cmd_pdata_verify(args))
|
|
3783
|
-
if args.verb == "readiness-scan":
|
|
3784
|
-
sys.exit(_cmd_pdata_readiness_scan(args))
|
|
3785
|
-
if args.verb == "dump":
|
|
3786
|
-
sys.exit(_cmd_pdata_dump(args))
|
|
3787
|
-
if args.verb == "rehydrate":
|
|
3788
|
-
sys.exit(_cmd_pdata_rehydrate(args))
|
|
3789
|
-
if args.verb == "resolve":
|
|
3790
|
-
sys.exit(_cmd_pdata_resolve(args))
|
|
3791
|
-
if args.verb == "sync-check":
|
|
3792
|
-
sys.exit(_cmd_pdata_sync_check(args))
|
|
4022
|
+
sys.exit(_cmd_pdata(args))
|
|
3793
4023
|
|
|
3794
4024
|
if args.noun == "machine-identity":
|
|
3795
4025
|
if args.verb == "show":
|