cc-session-tools 3.9.0__tar.gz → 3.10.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.9.0/src/cc_session_tools.egg-info → cc_session_tools-3.10.0}/PKG-INFO +3 -3
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/README.md +2 -2
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/pyproject.toml +3 -3
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/ccst.py +61 -55
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/migrate_sessions_db.py +81 -8
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/doctor.py +56 -7
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/init_paths.py +32 -4
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/init_service.py +5 -1
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/sessions_db.py +47 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/pm-pdata-do-init/SKILL.md +16 -0
- cc_session_tools-3.10.0/src/cc_session_tools/skills/pm-pdata-do-update-consuming-skills/SKILL.md +114 -0
- cc_session_tools-3.10.0/src/cc_session_tools/skills/pm-pdata-do-update-project-docs/SKILL.md +103 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0/src/cc_session_tools.egg-info}/PKG-INFO +3 -3
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools.egg-info/SOURCES.txt +4 -2
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_bundle_discovery.py +35 -62
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_pdata_init_cli.py +70 -9
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_migrate_sessions_db.py +3 -3
- cc_session_tools-3.10.0/tests/test_pdata_post_migration_skills.py +123 -0
- cc_session_tools-3.10.0/tests/test_sessions_db_migration_chain.py +464 -0
- cc_session_tools-3.9.0/src/cc_session_tools/prompts/pdata-migration-claude-md-update.md +0 -134
- cc_session_tools-3.9.0/src/cc_session_tools/prompts/pdata-migration-skills-update.md +0 -137
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/LICENSE +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/setup.cfg +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/__init__.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/__init__.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/ccd.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/ccmsg.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/ccr.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/ccs.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/ccsched.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/config/hooks-bundle.json +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/config/session-tag-hook.json +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/hooks_install.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/__init__.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/bun_tools.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/claude_flags.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/claude_md_install.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/context_overrides.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/db.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/debug.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/doctor_mutes.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/hook_registry.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/install_sync.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/levenshtein.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/machine_identity.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/lock.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/message.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/repository.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/retention.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/service.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/messaging/store.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/occupancy.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/paths.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/backup.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/classify.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/cutover.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/dump.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/importers.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/naming.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/readiness.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/rehydrate.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/rename_group.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/reorganize.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/repository.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/resolve.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/service.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/session_output.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/store.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/sync_check.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/sync_lock.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/sync_notify.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/vector_clock.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/vector_clock_store.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/verify.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/write_log.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/picker.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/proc_lock.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/prompts.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/roots.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/rules.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/due.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/lock.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/state.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/store.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/session_gc.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/sessions.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/sessions_repair.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/shell_install.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/tasklist.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/telemetry_store.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/text_wrap.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/clean-hook-sessions/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/compact-smart/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/context-override/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/extract-pptx/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/extract-pptx/scripts/extract_pptx.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/extract-to-text/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/extract-to-text/scripts/extract_to_text.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/pm-pdata-design-schema/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/pm-pdata-do-manual-migration/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/pm-pdata-resolve-conflicts/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools.egg-info/requires.txt +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools.egg-info/top_level.txt +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/__init__.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/attribution.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/cache.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/ccusage_wrapper.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/data/pricing.json +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/parent_inference.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/parser.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/pricing.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/query.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/report.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/schema.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/claude_code_usage/session_names.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/__init__.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/after_response.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/bash_hard_deny.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/bash_security_review.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/cache.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/catchup.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/confirm_8digit.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/context_window_warning.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/last_screenshot.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/marker_allow.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/markers.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/messaging_deliver.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/model_info.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/normalise.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/pdata_sync.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/pending_migration.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/pending_rename.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/script_allowlist.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/session_tag.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/stats.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/telemetry.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/telemetry_query.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/telemetry_trim.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/transcript.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/hooks/worklog_guard.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_after_response.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_attribution.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_bash_hard_deny.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_bash_security_review.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_bash_security_review_allowlist.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_bun_tools.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_cache.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_cache_sqlite.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccr_orphans.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccs_emptiness.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccs_eta.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccs_list_mode.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccs_scope_flags.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccs_sentinel_sort.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccs_session_counts.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_context_override_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_doctor.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_gc_prune.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_gc_report.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_hook_dispatcher.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_hooks_allowlist.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_hooks_install_prune.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_hooks_uninstall.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_install_everything.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_machine_identity_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_main_gate.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_pdata_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_pdata_readiness_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_pdata_rename_group_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_pdata_reorganize_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_pdata_sync_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_pdata_verify_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_repair_sessions_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_sessions_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_shell_install.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_skills_install.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_skills_uninstall.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_telemetry_query.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccst_telemetry_trim.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_ccusage_wrapper.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_claude_flags.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_claude_md_install.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_cli.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_cli_ccd.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_cli_ccd_dry_run.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_cli_ccr.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_cli_ccs.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_cli_version.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_confirm_8digit.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_context_overrides.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_context_window_warning.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_db.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_debug.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_doctor_mutes.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_empty_session.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_hook_cache.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_hooks_install.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_hooks_install_records.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_install_sync.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_last_screenshot.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_levenshtein.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_machine_identity.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_marker_allow.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_migrate_ccmsg.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_migrate_ccsched.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_migrate_telemetry.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_model_info.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_normalise.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_occupancy.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_parent_inference.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_parser.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_paths.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_pdata_audit_skill.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_pending_migration_hook.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_picker.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_pricing.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_proc_lock.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_prompts.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_query.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_report.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_roots.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_rules.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_scheduler_bundled_jobs.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_schema.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_script_allowlist.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_session_names.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_session_tag.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_sessions.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_sessions_db.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_sessions_repair.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_tasklist.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_telemetry.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_telemetry_store.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_text_wrap.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/tests/test_transcript.py +0 -0
- {cc_session_tools-3.9.0 → cc_session_tools-3.10.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.
|
|
3
|
+
Version: 3.10.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
|
|
@@ -192,8 +192,8 @@ Messages can also be addressed to a specific session (`--to-session`) or to a fr
|
|
|
192
192
|
description for whichever session picks it up first (`--to-description`) - project-
|
|
193
193
|
addressed is by far the most common pattern in practice.
|
|
194
194
|
|
|
195
|
-
The easiest way to use
|
|
196
|
-
another session (e.g. by name tag and/or location).
|
|
195
|
+
The easiest way to use messages when you need them is just to tell your session to send
|
|
196
|
+
a message to another session (e.g. by name tag and/or location).
|
|
197
197
|
|
|
198
198
|
## Scheduled housekeeping: `ccsched`
|
|
199
199
|
|
|
@@ -135,8 +135,8 @@ Messages can also be addressed to a specific session (`--to-session`) or to a fr
|
|
|
135
135
|
description for whichever session picks it up first (`--to-description`) - project-
|
|
136
136
|
addressed is by far the most common pattern in practice.
|
|
137
137
|
|
|
138
|
-
The easiest way to use
|
|
139
|
-
another session (e.g. by name tag and/or location).
|
|
138
|
+
The easiest way to use messages when you need them is just to tell your session to send
|
|
139
|
+
a message to another session (e.g. by name tag and/or location).
|
|
140
140
|
|
|
141
141
|
## Scheduled housekeeping: `ccsched`
|
|
142
142
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cc-session-tools"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.10.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" }
|
|
@@ -62,11 +62,11 @@ where = ["src"]
|
|
|
62
62
|
# only filters within the file's *own* discovered package, and a wrongly
|
|
63
63
|
# auto-discovered "cc_session_tools.skills.<name>.tests" package was never
|
|
64
64
|
# covered by an exclude-package-data entry keyed just "cc_session_tools").
|
|
65
|
-
exclude = ["cc_session_tools.skills", "cc_session_tools.skills.*", "cc_session_tools.config", "cc_session_tools.config.*"
|
|
65
|
+
exclude = ["cc_session_tools.skills", "cc_session_tools.skills.*", "cc_session_tools.config", "cc_session_tools.config.*"]
|
|
66
66
|
|
|
67
67
|
[tool.setuptools.package-data]
|
|
68
68
|
claude_code_usage = ["data/*.json"]
|
|
69
|
-
cc_session_tools = ["skills/**/*", "config/*"
|
|
69
|
+
cc_session_tools = ["skills/**/*", "config/*"]
|
|
70
70
|
|
|
71
71
|
[tool.setuptools.exclude-package-data]
|
|
72
72
|
cc_session_tools = ["**/tests/*", "**/__pycache__/*"]
|
|
@@ -160,56 +160,25 @@ def _discover_bundle() -> Path:
|
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
|
|
163
|
-
def
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
prompts/ is packaged inside cc_session_tools the same way skills/ and config/ are (see
|
|
167
|
-
_discover_source_dir) - src/cc_session_tools/cli/ccst.py -> ../prompts. No install-location
|
|
168
|
-
fallback, same reasoning as the other two: a fallback here would just mask a broken install.
|
|
169
|
-
"""
|
|
170
|
-
candidate = Path(__file__).resolve().parent.parent / "prompts"
|
|
171
|
-
if candidate.is_dir():
|
|
172
|
-
return candidate
|
|
173
|
-
raise FileNotFoundError(
|
|
174
|
-
"Cannot locate bundled prompts/ directory. Run from the source tree or reinstall ccst."
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
def _print_migration_prompt_reminders(
|
|
179
|
-
project_root: Path, *labeled_filenames: tuple[str, str]
|
|
163
|
+
def _print_post_migration_skill_reminders(
|
|
164
|
+
project_root: Path, *labeled_skills: tuple[str, str]
|
|
180
165
|
) -> None:
|
|
181
|
-
"""Print one "<label>: <
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
session
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
earlier in the same conversation - a dispatched Agent subagent (same cwd) gets that same
|
|
191
|
-
benefit without shelling out to a literal second process, so both are offered here rather
|
|
192
|
-
than only the `claude -p` invocation. Printing the reminder without saying so reads as "open
|
|
193
|
-
this file", which invites running it inline in whatever session called `ccst pdata init` -
|
|
194
|
-
the wrong cwd entirely.
|
|
195
|
-
|
|
196
|
-
Best-effort, deliberately swallowing a missing prompts/ directory: these reminders are a
|
|
197
|
-
nicety layered on top of an otherwise-already-completed classification or migration, not
|
|
198
|
-
the operation itself — a broken/partial install must never turn a successful --write (rows
|
|
199
|
-
already written, files already cut over) or dry-run (proposal already written) into a
|
|
200
|
-
reported failure just because this follow-up reminder couldn't be printed.
|
|
166
|
+
"""Print one "<label>: <skill-name>" reminder per (label, skill) pair, each followed by a
|
|
167
|
+
line telling the user to run it in a fresh context rooted at project_root.
|
|
168
|
+
|
|
169
|
+
Each skill's Step 1 checks that cwd is the project root and aborts otherwise, so a bare skill
|
|
170
|
+
name invites running it inline in whatever session called `ccst pdata init` - the wrong cwd,
|
|
171
|
+
and the wrong context: the fresh-context requirement protects against an orchestrating
|
|
172
|
+
session rationalizing away a stale reference it half-remembers writing earlier in the same
|
|
173
|
+
conversation. A dispatched Agent subagent whose prompt starts with a `cd` into project_root
|
|
174
|
+
gets that same benefit as a new Claude Code session, so both are offered.
|
|
201
175
|
"""
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
except FileNotFoundError as exc:
|
|
205
|
-
print(f"({exc})", file=sys.stderr)
|
|
206
|
-
return
|
|
207
|
-
for label, filename in labeled_filenames:
|
|
208
|
-
print(f"{label}: {prompts_dir / filename}")
|
|
176
|
+
for label, skill in labeled_skills:
|
|
177
|
+
print(f"{label}: {skill}")
|
|
209
178
|
print(
|
|
210
|
-
f" Run in a
|
|
211
|
-
f"
|
|
212
|
-
f"
|
|
179
|
+
f" Run it in a fresh context rooted at {project_root}: dispatch an Agent subagent "
|
|
180
|
+
f"whose prompt starts with `cd {project_root}`, or start a new Claude Code session "
|
|
181
|
+
f"there - not inline in this session."
|
|
213
182
|
)
|
|
214
183
|
|
|
215
184
|
|
|
@@ -1236,9 +1205,9 @@ def _cmd_pdata_init(args: argparse.Namespace) -> int:
|
|
|
1236
1205
|
# apply here.
|
|
1237
1206
|
return 0
|
|
1238
1207
|
print(f"\nProposal: {result.proposal_path}")
|
|
1239
|
-
|
|
1208
|
+
_print_post_migration_skill_reminders(
|
|
1240
1209
|
result.proposal_path.parent,
|
|
1241
|
-
("After a successful --write, update project docs", "pdata-
|
|
1210
|
+
("After a successful --write, update project docs", "pm-pdata-do-update-project-docs"),
|
|
1242
1211
|
)
|
|
1243
1212
|
return 0
|
|
1244
1213
|
|
|
@@ -1286,10 +1255,10 @@ def _cmd_pdata_init(args: argparse.Namespace) -> int:
|
|
|
1286
1255
|
print()
|
|
1287
1256
|
print(write_result.report) # spec §7.1 step 4's diff report, for review
|
|
1288
1257
|
print(f"\nVerify: ccst pdata verify --project {args.project} --full")
|
|
1289
|
-
|
|
1258
|
+
_print_post_migration_skill_reminders(
|
|
1290
1259
|
project_root,
|
|
1291
|
-
("Update project docs", "pdata-
|
|
1292
|
-
("Update consuming skills", "pdata-
|
|
1260
|
+
("Update project docs", "pm-pdata-do-update-project-docs"),
|
|
1261
|
+
("Update consuming skills", "pm-pdata-do-update-consuming-skills"),
|
|
1293
1262
|
)
|
|
1294
1263
|
print("SUCCESS")
|
|
1295
1264
|
return 0
|
|
@@ -2340,12 +2309,44 @@ _MIGRATE_ALL_BANNER = (
|
|
|
2340
2309
|
)
|
|
2341
2310
|
|
|
2342
2311
|
|
|
2312
|
+
def _migrate_all_sessions_step(args: argparse.Namespace) -> int:
|
|
2313
|
+
"""The sessions step of `migrate all`: the legacy import writes uuid-keyed rows, so a
|
|
2314
|
+
pre-uuid `sessions.db` is rebuilt first (`sessions migrate-uuid`, with its own backup and
|
|
2315
|
+
concurrent-writer guard). A failed or refused rebuild skips the import."""
|
|
2316
|
+
import sqlite3
|
|
2317
|
+
|
|
2318
|
+
from cc_session_tools.cli.migrate_sessions_db import migrate_uuid
|
|
2319
|
+
from cc_session_tools.lib import sessions_db
|
|
2320
|
+
|
|
2321
|
+
db_path = sessions_db.default_db_path()
|
|
2322
|
+
try:
|
|
2323
|
+
pre_uuid = sessions_db.pre_uuid_sessions_table(db_path)
|
|
2324
|
+
except sqlite3.DatabaseError as exc:
|
|
2325
|
+
print(f"cannot read {db_path}: {exc} - not a valid sessions.db; nothing was changed",
|
|
2326
|
+
file=sys.stderr)
|
|
2327
|
+
return 1
|
|
2328
|
+
if pre_uuid:
|
|
2329
|
+
print(f"{db_path} is on the pre-3.0.0 schema - rebuilding it first "
|
|
2330
|
+
"(`ccst sessions migrate-uuid`) so the legacy import can write to it.")
|
|
2331
|
+
try:
|
|
2332
|
+
rc = migrate_uuid(db_path=db_path, dry_run=args.dry_run)
|
|
2333
|
+
except ValueError as exc:
|
|
2334
|
+
print(str(exc), file=sys.stderr)
|
|
2335
|
+
return 1
|
|
2336
|
+
if rc != 0:
|
|
2337
|
+
return rc
|
|
2338
|
+
if args.dry_run:
|
|
2339
|
+
print("The legacy import's own dry-run is skipped until the rebuild has run.")
|
|
2340
|
+
return 0
|
|
2341
|
+
return _cmd_sessions_migrate(argparse.Namespace(
|
|
2342
|
+
dry_run=args.dry_run, sessions_db=None, tags_dir=None, mutes_file=None))
|
|
2343
|
+
|
|
2344
|
+
|
|
2343
2345
|
def _cmd_migrate_all(args: argparse.Namespace) -> int:
|
|
2344
2346
|
print(_MIGRATE_ALL_BANNER)
|
|
2345
2347
|
|
|
2346
2348
|
steps: list[tuple[str, object]] = [
|
|
2347
|
-
("sessions", lambda:
|
|
2348
|
-
dry_run=args.dry_run, sessions_db=None, tags_dir=None, mutes_file=None))),
|
|
2349
|
+
("sessions", lambda: _migrate_all_sessions_step(args)),
|
|
2349
2350
|
("ccmsg", lambda: _cmd_migrate_ccmsg(argparse.Namespace(
|
|
2350
2351
|
old_root=None, backup_dir=None, dry_run=args.dry_run))),
|
|
2351
2352
|
("ccsched", lambda: _cmd_migrate_ccsched(argparse.Namespace(
|
|
@@ -2355,14 +2356,19 @@ def _cmd_migrate_all(args: argparse.Namespace) -> int:
|
|
|
2355
2356
|
]
|
|
2356
2357
|
|
|
2357
2358
|
overall_rc = 0
|
|
2359
|
+
failed: list[str] = []
|
|
2358
2360
|
for name, step in steps:
|
|
2359
2361
|
print(f"\n=== {name} ===")
|
|
2360
2362
|
rc = step() # type: ignore[operator]
|
|
2361
2363
|
if rc != 0:
|
|
2362
2364
|
overall_rc = rc
|
|
2365
|
+
failed.append(name)
|
|
2363
2366
|
|
|
2364
2367
|
print()
|
|
2365
|
-
if
|
|
2368
|
+
if failed:
|
|
2369
|
+
print(f"Steps that failed: {', '.join(failed)}. Review the ERROR/ABORT/refusal lines "
|
|
2370
|
+
"above; a failed step leaves its own old files untouched and is safe to re-run.")
|
|
2371
|
+
elif args.dry_run:
|
|
2366
2372
|
print("Dry run complete — re-run without --dry-run once you're satisfied.")
|
|
2367
2373
|
else:
|
|
2368
2374
|
print("All migrations attempted. Review any ERROR/ABORT lines above; a "
|
{cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/cli/migrate_sessions_db.py
RENAMED
|
@@ -114,10 +114,15 @@ def _read_legacy_sessions_rows(conn: sqlite3.Connection) -> list[sqlite3.Row]:
|
|
|
114
114
|
"""Every row from the pre-3.0.0 (project_dir, basename) `sessions` table, via raw SQL -
|
|
115
115
|
not sessions_db.list_sessions()/_row_to_session, which require the `uuid` column this
|
|
116
116
|
migration is the one adding. Safe to call against either schema shape: only the columns
|
|
117
|
-
that exist pre-3.0.0 are selected.
|
|
117
|
+
that exist pre-3.0.0 are selected; `updated_at` (absent from v1.0.0 through v2.12.x) is read
|
|
118
|
+
as NULL when the table has no such column."""
|
|
119
|
+
updated_at = (
|
|
120
|
+
"updated_at" if "updated_at" in sessions_db.sessions_column_names(conn)
|
|
121
|
+
else "NULL AS updated_at"
|
|
122
|
+
)
|
|
118
123
|
return conn.execute(
|
|
119
124
|
"SELECT project_dir, basename, start_date, last_opened, last_active, "
|
|
120
|
-
"discovered_at, updated_at FROM sessions"
|
|
125
|
+
f"discovered_at, {updated_at} FROM sessions"
|
|
121
126
|
).fetchall()
|
|
122
127
|
|
|
123
128
|
|
|
@@ -162,6 +167,26 @@ def print_uuid_migration_dry_run(plan: UuidMigrationPlan, *, db_path: Path) -> N
|
|
|
162
167
|
print("backing up: this rebuilds the sessions table and is a one-way schema change.")
|
|
163
168
|
|
|
164
169
|
|
|
170
|
+
def _record_uuid_marker_only(db_path: Path, *, dry_run: bool) -> int:
|
|
171
|
+
"""`sessions` is already uuid-keyed, or there is no `sessions` table to rebuild: there is
|
|
172
|
+
nothing to rebuild, only the completion marker to record (creating the current schema first
|
|
173
|
+
if the table is missing)."""
|
|
174
|
+
if dry_run:
|
|
175
|
+
print(f"{db_path} needs no rebuild - only its 3.0.0 completion marker would be "
|
|
176
|
+
"recorded. Re-run with --write to record it.")
|
|
177
|
+
return 0
|
|
178
|
+
conn = sessions_db.connect(path=db_path)
|
|
179
|
+
try:
|
|
180
|
+
db.record_migration(
|
|
181
|
+
conn, sessions_db.SESSIONS_UUID_MIGRATION, applied_at=sessions_db._now_iso()
|
|
182
|
+
)
|
|
183
|
+
conn.commit()
|
|
184
|
+
finally:
|
|
185
|
+
conn.close()
|
|
186
|
+
print(f"{db_path} needed no rebuild - recorded its 3.0.0 completion marker.")
|
|
187
|
+
return 0
|
|
188
|
+
|
|
189
|
+
|
|
165
190
|
def migrate_uuid(*, db_path: Path, dry_run: bool, backup_dir: Path | None = None) -> int:
|
|
166
191
|
"""The 3.0.0 schema migration: rebuild `sessions` from the pre-3.0.0
|
|
167
192
|
(project_dir, basename) primary key to (project_dir, basename, uuid), backfilling each
|
|
@@ -185,15 +210,35 @@ def migrate_uuid(*, db_path: Path, dry_run: bool, backup_dir: Path | None = None
|
|
|
185
210
|
# be held by a live hook write, defeating the point of checking before touching anything.
|
|
186
211
|
conn = db.connect(db_path)
|
|
187
212
|
try:
|
|
188
|
-
if sessions_db.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
213
|
+
if not sessions_db.sessions_table_exists(conn):
|
|
214
|
+
marker_only = True
|
|
215
|
+
legacy_rows: list[sqlite3.Row] = []
|
|
216
|
+
else:
|
|
217
|
+
keyed = sessions_db.sessions_schema_is_uuid_keyed(conn)
|
|
218
|
+
recorded = sessions_db.migration_marker_recorded(
|
|
219
|
+
conn, sessions_db.SESSIONS_UUID_MIGRATION
|
|
220
|
+
)
|
|
221
|
+
if keyed and recorded:
|
|
222
|
+
print(f"{db_path} is already migrated to the uuid-aware schema - nothing to do.")
|
|
223
|
+
return 0
|
|
224
|
+
marker_only = keyed
|
|
225
|
+
if not keyed:
|
|
226
|
+
missing = sessions_db.missing_rebuild_columns(conn)
|
|
227
|
+
if missing:
|
|
228
|
+
print(
|
|
229
|
+
f"cannot migrate {db_path}: its `sessions` table is missing "
|
|
230
|
+
f"column(s) the rebuild copies: {', '.join(missing)}. Nothing was "
|
|
231
|
+
"changed; restore the file from a backup or repair it by hand.",
|
|
232
|
+
file=sys.stderr,
|
|
233
|
+
)
|
|
234
|
+
return 1
|
|
235
|
+
legacy_rows = [] if keyed else _read_legacy_sessions_rows(conn)
|
|
194
236
|
finally:
|
|
195
237
|
conn.close()
|
|
196
238
|
|
|
239
|
+
if marker_only:
|
|
240
|
+
return _record_uuid_marker_only(db_path, dry_run=dry_run)
|
|
241
|
+
|
|
197
242
|
plan = plan_uuid_migration(legacy_rows)
|
|
198
243
|
|
|
199
244
|
if dry_run:
|
|
@@ -418,6 +463,30 @@ def _tar_backup(sources: list[Path], *, backup_dir: Path) -> Path | None:
|
|
|
418
463
|
return dest
|
|
419
464
|
|
|
420
465
|
|
|
466
|
+
def refuse_if_sessions_db_pre_uuid(db_path: Path) -> int | None:
|
|
467
|
+
"""Pre-flight for the legacy import: it writes uuid-keyed rows, which a `sessions.db` still
|
|
468
|
+
on the pre-3.0.0 schema cannot accept. Returns a non-zero exit code (after printing the
|
|
469
|
+
fix) when the import must not run, else None. Read-only; must run before anything that could
|
|
470
|
+
connect-with-DDL, write, or back up."""
|
|
471
|
+
try:
|
|
472
|
+
pre_uuid = sessions_db.pre_uuid_sessions_table(db_path)
|
|
473
|
+
except sqlite3.DatabaseError as exc:
|
|
474
|
+
print(f"cannot read {db_path}: {exc} - not a valid sessions.db; nothing was changed",
|
|
475
|
+
file=sys.stderr)
|
|
476
|
+
return 1
|
|
477
|
+
if not pre_uuid:
|
|
478
|
+
return None
|
|
479
|
+
print(
|
|
480
|
+
f"cannot run the legacy flat-file import: {db_path} is still on the pre-3.0.0 schema "
|
|
481
|
+
"(no uuid column), which the import cannot write to. Nothing was changed. First run "
|
|
482
|
+
"`ccst sessions migrate-uuid --write` from a plain terminal with no other `claude` "
|
|
483
|
+
"session running (it takes a backup first), then re-run this - or run `ccst migrate "
|
|
484
|
+
"all`, which does both in order.",
|
|
485
|
+
file=sys.stderr,
|
|
486
|
+
)
|
|
487
|
+
return 1
|
|
488
|
+
|
|
489
|
+
|
|
421
490
|
def run_migration(
|
|
422
491
|
*,
|
|
423
492
|
dry_run: bool,
|
|
@@ -427,6 +496,10 @@ def run_migration(
|
|
|
427
496
|
roots: list[Path],
|
|
428
497
|
backup_dir: Path,
|
|
429
498
|
) -> int:
|
|
499
|
+
refusal = refuse_if_sessions_db_pre_uuid(db_path)
|
|
500
|
+
if refusal is not None:
|
|
501
|
+
return refusal
|
|
502
|
+
|
|
430
503
|
print(f"Sessions DB : {db_path}")
|
|
431
504
|
print(f"Tags source : {tags_dir}")
|
|
432
505
|
print(f"Mutes source : {mutes_file}")
|
|
@@ -675,7 +675,26 @@ def _migration_recorded(db_path: Path, marker_name: str) -> bool:
|
|
|
675
675
|
conn.close()
|
|
676
676
|
|
|
677
677
|
|
|
678
|
-
def
|
|
678
|
+
def _sessions_marker() -> str:
|
|
679
|
+
from cc_session_tools.lib.sessions_db import LEGACY_FLAT_FILE_MIGRATION
|
|
680
|
+
|
|
681
|
+
return LEGACY_FLAT_FILE_MIGRATION
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
def _sessions_db_is_pre_uuid(db_path: Path) -> bool:
|
|
685
|
+
"""`sessions_db.pre_uuid_sessions_table`, with an unreadable file counting as not pre-uuid
|
|
686
|
+
(other checks already report a database that fails to open)."""
|
|
687
|
+
from cc_session_tools.lib import sessions_db
|
|
688
|
+
|
|
689
|
+
try:
|
|
690
|
+
return sessions_db.pre_uuid_sessions_table(db_path)
|
|
691
|
+
except sqlite3.DatabaseError:
|
|
692
|
+
return False
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
def check_pending_data_store_migration(
|
|
696
|
+
paths: LegacyMigrationPaths, *, sessions_db_path: Path | None = None,
|
|
697
|
+
) -> list[CheckResult]:
|
|
679
698
|
"""Detect legacy flat-file data left over from a pre-1.0.0 install.
|
|
680
699
|
|
|
681
700
|
:func:`check_data_stores` can't distinguish a fresh install (nothing to
|
|
@@ -696,6 +715,10 @@ def check_pending_data_store_migration(paths: LegacyMigrationPaths) -> list[Chec
|
|
|
696
715
|
fills from the first hook fire after install, so counting rows reported "already
|
|
697
716
|
migrated" for anyone who opened a session before migrating, and the FAIL that should
|
|
698
717
|
have prompted them never fired.
|
|
718
|
+
|
|
719
|
+
`sessions_db_path` is the sessions.db the `sessions` finding reads; pass the same path the
|
|
720
|
+
3.0.0 uuid check uses so the two findings can never describe different files (defaults to
|
|
721
|
+
`paths.data_home / "sessions.db"`).
|
|
699
722
|
"""
|
|
700
723
|
from cc_session_tools.lib.messaging.repository import (
|
|
701
724
|
LEGACY_FLAT_FILE_MIGRATION as _CCMSG_MIGRATION,
|
|
@@ -724,7 +747,7 @@ def check_pending_data_store_migration(paths: LegacyMigrationPaths) -> list[Chec
|
|
|
724
747
|
"sessions": (
|
|
725
748
|
(paths.tags_dir, paths.mutes_file),
|
|
726
749
|
_count_legacy_sessions(paths.tags_dir, paths.mutes_file),
|
|
727
|
-
paths.data_home / "sessions.db",
|
|
750
|
+
sessions_db_path if sessions_db_path is not None else paths.data_home / "sessions.db",
|
|
728
751
|
_SESSIONS_MIGRATION,
|
|
729
752
|
),
|
|
730
753
|
"telemetry": (
|
|
@@ -748,6 +771,13 @@ def check_pending_data_store_migration(paths: LegacyMigrationPaths) -> list[Chec
|
|
|
748
771
|
already_migrated = _migration_recorded(new_db_path, marker_name)
|
|
749
772
|
evidence = f"the import is recorded in {new_db_path.name}"
|
|
750
773
|
if not already_migrated:
|
|
774
|
+
rebuild_note = ""
|
|
775
|
+
if store_name == "sessions" and _sessions_db_is_pre_uuid(new_db_path):
|
|
776
|
+
rebuild_note = (
|
|
777
|
+
f" It will first rebuild {new_db_path.name} to the 3.0.0 uuid schema "
|
|
778
|
+
"(taking a backup; close any running `claude` sessions first) - the "
|
|
779
|
+
"import cannot write to the old schema."
|
|
780
|
+
)
|
|
751
781
|
results.append(
|
|
752
782
|
CheckResult(
|
|
753
783
|
name=name,
|
|
@@ -756,7 +786,7 @@ def check_pending_data_store_migration(paths: LegacyMigrationPaths) -> list[Chec
|
|
|
756
786
|
f"{legacy_count} unmigrated item(s) at {existing}; run "
|
|
757
787
|
"`ccst migrate all` from a plain terminal (NOT inside a Claude Code "
|
|
758
788
|
"session — the delete step is blocked by bash-hard-deny) to migrate "
|
|
759
|
-
f"into {new_db_path}"
|
|
789
|
+
f"into {new_db_path}.{rebuild_note}"
|
|
760
790
|
),
|
|
761
791
|
)
|
|
762
792
|
)
|
|
@@ -942,7 +972,9 @@ def check_sessions_project_dir_absolute(sessions_db_path: Path) -> list[CheckRes
|
|
|
942
972
|
)]
|
|
943
973
|
|
|
944
974
|
|
|
945
|
-
def check_sessions_uuid_migration(
|
|
975
|
+
def check_sessions_uuid_migration(
|
|
976
|
+
sessions_db_path: Path, *, legacy_sessions_pending: bool = False,
|
|
977
|
+
) -> list[CheckResult]:
|
|
946
978
|
"""FAIL if sessions.db still has the pre-3.0.0 (project_dir, basename) primary key -
|
|
947
979
|
forked sessions (Ctrl-L) silently clobber each other's activity rows until
|
|
948
980
|
`ccst sessions migrate-uuid --write` runs. Distinguishes "never migrated" from
|
|
@@ -956,7 +988,10 @@ def check_sessions_uuid_migration(sessions_db_path: Path) -> list[CheckResult]:
|
|
|
956
988
|
A sessions.db that doesn't exist yet reads OK: connect() records the migration
|
|
957
989
|
marker at creation time for any brand-new file (sessions_db.py), so a genuinely
|
|
958
990
|
fresh install is never in a pending state - there is simply nothing to check here
|
|
959
|
-
yet, and this check must not create the file itself just to inspect it.
|
|
991
|
+
yet, and this check must not create the file itself just to inspect it.
|
|
992
|
+
|
|
993
|
+
`legacy_sessions_pending` says the 1.0.0 flat-file import is also still pending; the two FAIL
|
|
994
|
+
branches then note that `ccst migrate all` performs both, in the order that works."""
|
|
960
995
|
import sqlite3
|
|
961
996
|
|
|
962
997
|
from cc_session_tools.lib import db as db_lib
|
|
@@ -1000,6 +1035,11 @@ def check_sessions_uuid_migration(sessions_db_path: Path) -> list[CheckResult]:
|
|
|
1000
1035
|
"run `ccst sessions migrate-uuid --write` from a plain terminal with no other "
|
|
1001
1036
|
"`claude` session running (it takes a backup first; see --help)"
|
|
1002
1037
|
)
|
|
1038
|
+
if legacy_sessions_pending:
|
|
1039
|
+
remediation += (
|
|
1040
|
+
"; the legacy import is also pending, and `ccst migrate all` performs both in "
|
|
1041
|
+
"the order that works"
|
|
1042
|
+
)
|
|
1003
1043
|
if not pk_is_uuid_keyed and not marker_present:
|
|
1004
1044
|
return [CheckResult(
|
|
1005
1045
|
name=name, status=Status.FAIL,
|
|
@@ -1158,7 +1198,8 @@ def run_all_checks(
|
|
|
1158
1198
|
|
|
1159
1199
|
# Pending legacy-data migration
|
|
1160
1200
|
if legacy_migration_paths is not None:
|
|
1161
|
-
results.extend(check_pending_data_store_migration(
|
|
1201
|
+
results.extend(check_pending_data_store_migration(
|
|
1202
|
+
legacy_migration_paths, sessions_db_path=sessions_db_path))
|
|
1162
1203
|
|
|
1163
1204
|
# Pending ccst pdata init cutover (spec §7.1 step 7)
|
|
1164
1205
|
if projects_root is not None:
|
|
@@ -1172,7 +1213,15 @@ def run_all_checks(
|
|
|
1172
1213
|
# since project-dir-absolute's own check degrades to a WARN pointing back at it when
|
|
1173
1214
|
# the uuid migration hasn't run yet (a pre-migration schema can't be queried the same way).
|
|
1174
1215
|
if sessions_db_path is not None:
|
|
1175
|
-
|
|
1216
|
+
legacy_sessions_pending = (
|
|
1217
|
+
legacy_migration_paths is not None
|
|
1218
|
+
and _count_legacy_sessions(
|
|
1219
|
+
legacy_migration_paths.tags_dir, legacy_migration_paths.mutes_file
|
|
1220
|
+
) > 0
|
|
1221
|
+
and not _migration_recorded(sessions_db_path, _sessions_marker())
|
|
1222
|
+
)
|
|
1223
|
+
results.extend(check_sessions_uuid_migration(
|
|
1224
|
+
sessions_db_path, legacy_sessions_pending=legacy_sessions_pending))
|
|
1176
1225
|
results.extend(check_sessions_project_dir_absolute(sessions_db_path))
|
|
1177
1226
|
|
|
1178
1227
|
# Optional dependencies for claude-code-usage's reconcile / ccusage blocks
|
{cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/init_paths.py
RENAMED
|
@@ -112,13 +112,41 @@ def project_db_dir_override(rehearse: Path | None) -> Iterator[None]:
|
|
|
112
112
|
override_dir = rehearse / REHEARSAL_DB_DIRNAME
|
|
113
113
|
previous = os.environ.get(store.PROJECT_DB_DIR_ENV)
|
|
114
114
|
os.environ[store.PROJECT_DB_DIR_ENV] = str(override_dir)
|
|
115
|
+
_live_db_dir_env_stack.append(previous)
|
|
115
116
|
try:
|
|
116
117
|
yield
|
|
117
118
|
finally:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
_live_db_dir_env_stack.pop()
|
|
120
|
+
_restore_db_dir_env(previous)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# The CCST_PROJECT_DB_DIR value in effect before each active project_db_dir_override (None =
|
|
124
|
+
# unset), outermost first - what live_project_db_dir() restores.
|
|
125
|
+
_live_db_dir_env_stack: list[str | None] = []
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _restore_db_dir_env(value: str | None) -> None:
|
|
129
|
+
if value is None:
|
|
130
|
+
os.environ.pop(store.PROJECT_DB_DIR_ENV, None)
|
|
131
|
+
else:
|
|
132
|
+
os.environ[store.PROJECT_DB_DIR_ENV] = value
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@contextmanager
|
|
136
|
+
def live_project_db_dir() -> Iterator[None]:
|
|
137
|
+
"""Inside a project_db_dir_override block, temporarily point store.db_path() back at the
|
|
138
|
+
real per-project .db dir. For questions about the machine rather than the rehearsal copy
|
|
139
|
+
(e.g. "is this project already migrated here?"): a `cp -r` rehearsal copy never contains the
|
|
140
|
+
real .db, so the sandbox always answers "no". No-op outside an override."""
|
|
141
|
+
if not _live_db_dir_env_stack:
|
|
142
|
+
yield
|
|
143
|
+
return
|
|
144
|
+
inside = os.environ.get(store.PROJECT_DB_DIR_ENV)
|
|
145
|
+
_restore_db_dir_env(_live_db_dir_env_stack[0])
|
|
146
|
+
try:
|
|
147
|
+
yield
|
|
148
|
+
finally:
|
|
149
|
+
_restore_db_dir_env(inside)
|
|
122
150
|
|
|
123
151
|
|
|
124
152
|
@contextmanager
|
{cc_session_tools-3.9.0 → cc_session_tools-3.10.0}/src/cc_session_tools/lib/pdata/init_service.py
RENAMED
|
@@ -324,7 +324,11 @@ def _pending_adoption(*, project: str, project_root: Path) -> dump.DumpInfo | No
|
|
|
324
324
|
"project. Publish a fresh dump from a known-good machine (ccst pdata dump --force) "
|
|
325
325
|
"or reconcile manually (ccst pdata resolve) once those commands exist."
|
|
326
326
|
)
|
|
327
|
-
|
|
327
|
+
# The live .db, not a --rehearse sandbox's: a rehearsal copy never contains the real .db, so
|
|
328
|
+
# the sandbox would always look unmigrated and rehearsal would never reach classification.
|
|
329
|
+
with init_paths.live_project_db_dir():
|
|
330
|
+
already_migrated = _already_locally_migrated(project)
|
|
331
|
+
if already_migrated:
|
|
328
332
|
return None
|
|
329
333
|
return info
|
|
330
334
|
|
|
@@ -153,6 +153,53 @@ def sessions_schema_is_uuid_keyed(conn: sqlite3.Connection) -> bool:
|
|
|
153
153
|
)
|
|
154
154
|
|
|
155
155
|
|
|
156
|
+
# Columns of the pre-3.0.0 `sessions` table that the uuid rebuild copies into the new table.
|
|
157
|
+
# `updated_at` is deliberately absent: databases from v1.0.0 through v2.12.x never had it.
|
|
158
|
+
REBUILD_REQUIRED_COLUMNS = (
|
|
159
|
+
"project_dir", "basename", "start_date", "last_opened", "last_active", "discovered_at",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def sessions_table_exists(conn: sqlite3.Connection) -> bool:
|
|
164
|
+
return conn.execute(
|
|
165
|
+
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='sessions'"
|
|
166
|
+
).fetchone() is not None
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def sessions_column_names(conn: sqlite3.Connection) -> set[str]:
|
|
170
|
+
return {row["name"] for row in conn.execute("PRAGMA table_info(sessions)")}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def missing_rebuild_columns(conn: sqlite3.Connection) -> list[str]:
|
|
174
|
+
"""Columns the 3.0.0 rebuild must copy that the existing `sessions` table lacks."""
|
|
175
|
+
present = sessions_column_names(conn)
|
|
176
|
+
return [c for c in REBUILD_REQUIRED_COLUMNS if c not in present]
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def migration_marker_recorded(conn: sqlite3.Connection, name: str) -> bool:
|
|
180
|
+
"""`db.migration_applied`, but False (not an error) on a database that predates the
|
|
181
|
+
`migrations` table (v1.0.0 through roughly v2.8)."""
|
|
182
|
+
try:
|
|
183
|
+
return db.migration_applied(conn, name)
|
|
184
|
+
except sqlite3.OperationalError:
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def pre_uuid_sessions_table(path: Path) -> bool:
|
|
189
|
+
"""True iff `path` exists, has a `sessions` table, and that table is not uuid-keyed - the
|
|
190
|
+
one state in which the 1.0.0 legacy import cannot write. A missing file or a missing
|
|
191
|
+
`sessions` table is False: `connect()` creates the current schema for both. Read-only, so it
|
|
192
|
+
never creates or alters anything; raises sqlite3.DatabaseError for a file that is not a
|
|
193
|
+
valid database."""
|
|
194
|
+
if not path.exists():
|
|
195
|
+
return False
|
|
196
|
+
conn = db.connect(path, readonly=True)
|
|
197
|
+
try:
|
|
198
|
+
return sessions_table_exists(conn) and not sessions_schema_is_uuid_keyed(conn)
|
|
199
|
+
finally:
|
|
200
|
+
conn.close()
|
|
201
|
+
|
|
202
|
+
|
|
156
203
|
def connect(*, path: Path | None = None, readonly: bool = False) -> sqlite3.Connection:
|
|
157
204
|
"""Open sessions.db (or an explicit override path — used by tests and by
|
|
158
205
|
ccst doctor --mutes-file). readonly=True skips schema creation; callers
|
|
@@ -210,6 +210,22 @@ Step 3's garbled-header recipe) - so anything else in the project citing the old
|
|
|
210
210
|
a live signpost instead of a silent 404. Pass `--leave-no-pointer-files` if this run shouldn't
|
|
211
211
|
leave one (e.g. a rehearsal, or a project convention against extra files at migrated paths).
|
|
212
212
|
|
|
213
|
+
### Then run both post-migration skills
|
|
214
|
+
|
|
215
|
+
After a successful `--write` (not after a dry-run or a rehearsal), update everything that still
|
|
216
|
+
describes or uses the old flat-file layout. Run these in order, each in its own fresh-context
|
|
217
|
+
`Agent` subagent whose prompt begins with `cd ~/cc/<project>` - not inline in this session, which
|
|
218
|
+
has just written the migration and would rationalize away stale references it remembers:
|
|
219
|
+
|
|
220
|
+
1. `pm-pdata-do-update-project-docs` - rewrites the project's `CLAUDE.md` and other top-level docs
|
|
221
|
+
to name the pdata record_groups and `ccst pdata` commands, and reports folder-layout drift.
|
|
222
|
+
2. `pm-pdata-do-update-consuming-skills` - finds skills that literally reference the old paths and
|
|
223
|
+
rewrites direct reads/writes to `ccst pdata` commands, flagging anything it cannot rewrite
|
|
224
|
+
mechanically.
|
|
225
|
+
|
|
226
|
+
Relay each subagent's report to the user, including anything flagged for a human decision. If a
|
|
227
|
+
later `--write` round adds more record groups, run both again; they are safe to re-run.
|
|
228
|
+
|
|
213
229
|
## 8. Rollback, if something's found wrong post-cutover
|
|
214
230
|
|
|
215
231
|
There is no `--rollback` flag. Recover by hand:
|