cc-session-tools 3.0.0__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cc_session_tools-3.0.0/src/cc_session_tools.egg-info → cc_session_tools-3.2.0}/PKG-INFO +5 -1
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/README.md +4 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/pyproject.toml +1 -1
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/ccmsg.py +3 -1
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/ccst.py +10 -1
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/doctor.py +50 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/service.py +7 -4
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/repository.py +28 -4
- cc_session_tools-3.2.0/src/cc_session_tools/skills/compact-smart/SKILL.md +87 -0
- {cc_session_tools-3.0.0/src/cc_session_tools/skills/pm-pdata-audit → cc_session_tools-3.2.0/src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate}/SKILL.md +7 -7
- {cc_session_tools-3.0.0/src/cc_session_tools/skills/pm-pdata-migrate → cc_session_tools-3.2.0/src/cc_session_tools/skills/pm-pdata-do-migrate}/SKILL.md +10 -10
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0/src/cc_session_tools.egg-info}/PKG-INFO +5 -1
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools.egg-info/SOURCES.txt +3 -2
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/confirm_8digit.py +23 -21
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_bundle_discovery.py +21 -8
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_doctor.py +71 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_pdata_cli.py +23 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_confirm_8digit.py +114 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/LICENSE +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/setup.cfg +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/__init__.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/__init__.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/ccd.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/ccr.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/ccs.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/ccsched.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/migrate_sessions_db.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/config/hooks-bundle.json +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/config/session-tag-hook.json +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/hooks_install.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/__init__.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/claude_flags.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/claude_md_install.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/context_overrides.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/db.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/debug.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/doctor_mutes.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/hook_registry.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/install_sync.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/levenshtein.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/machine_identity.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/lock.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/message.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/repository.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/retention.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/store.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/occupancy.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/paths.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/backup.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/classify.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/cutover.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/dump.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/importers.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/init_paths.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/init_service.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/naming.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/rehydrate.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/rename_group.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/reorganize.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/resolve.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/service.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/session_output.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/store.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/sync_check.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/sync_lock.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/sync_notify.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/vector_clock.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/vector_clock_store.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/verify.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/write_log.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/picker.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/proc_lock.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/prompts.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/roots.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/rules.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/due.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/lock.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/state.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/store.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/session_gc.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/sessions.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/sessions_db.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/sessions_repair.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/shell_install.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/tasklist.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/telemetry_store.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/prompts/pdata-migration-claude-md-update.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/prompts/pdata-migration-skills-update.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/clean-hook-sessions/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/context-override/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/pm-pdata-conflict-resolution/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/pm-pdata-schema-design/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/pm-project-init/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools.egg-info/requires.txt +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools.egg-info/top_level.txt +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/__init__.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/attribution.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/cache.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/ccusage_wrapper.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/data/pricing.json +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/parent_inference.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/parser.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/pricing.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/query.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/report.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/schema.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/claude_code_usage/session_names.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/__init__.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/after_response.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/bash_hard_deny.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/bash_security_review.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/cache.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/catchup.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/context_window_warning.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/last_screenshot.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/marker_allow.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/markers.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/messaging_deliver.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/model_info.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/normalise.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/pdata_sync.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/pending_migration.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/pending_rename.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/session_tag.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/stats.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/telemetry.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/telemetry_query.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/telemetry_trim.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/transcript.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/hooks/worklog_guard.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_after_response.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_attribution.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_bash_hard_deny.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_bash_security_review.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_cache.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_cache_sqlite.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccr_orphans.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccs_emptiness.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccs_eta.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccs_list_mode.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccs_scope_flags.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccs_sentinel_sort.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccs_session_counts.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_context_override_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_gc_prune.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_gc_report.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_hook_dispatcher.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_hooks_install_prune.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_hooks_uninstall.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_install_everything.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_machine_identity_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_main_gate.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_pdata_init_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_pdata_rename_group_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_pdata_reorganize_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_pdata_sync_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_pdata_verify_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_repair_sessions_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_sessions_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_shell_install.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_skills_install.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_skills_uninstall.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_telemetry_query.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccst_telemetry_trim.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_ccusage_wrapper.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_claude_flags.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_claude_md_install.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_cli.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_cli_ccd.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_cli_ccd_dry_run.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_cli_ccr.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_cli_ccs.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_cli_version.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_context_overrides.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_context_window_warning.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_db.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_debug.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_doctor_mutes.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_empty_session.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_hook_cache.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_hooks_install.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_install_sync.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_last_screenshot.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_levenshtein.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_machine_identity.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_marker_allow.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_migrate_ccmsg.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_migrate_ccsched.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_migrate_sessions_db.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_migrate_telemetry.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_model_info.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_normalise.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_occupancy.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_parent_inference.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_parser.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_paths.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_pending_migration_hook.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_picker.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_pricing.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_proc_lock.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_prompts.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_query.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_report.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_roots.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_rules.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_scheduler_bundled_jobs.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_schema.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_session_names.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_session_tag.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_sessions.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_sessions_db.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_sessions_repair.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_tasklist.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_telemetry.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_telemetry_store.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/tests/test_transcript.py +0 -0
- {cc_session_tools-3.0.0 → cc_session_tools-3.2.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.2.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
|
|
@@ -575,6 +575,10 @@ Curates the SHA-256 command cache the `bash-security-review` hook reads (`CCCS_U
|
|
|
575
575
|
|
|
576
576
|
Archives (tar.gz, verified) then deletes `bash-security-review`'s own hook-security-check session transcripts — those whose first user message begins "Review this shell command for security risks" — which otherwise pile up by the thousands and pollute `claude --resume`/`--continue`. Triggers on "clean up hook sessions", "archive old hook security sessions", or `--resume` being cluttered with security-check conversations. Dry-run by default; 8-digit gated for `--execute` (via `generate-8digit-code`). Also runs unattended weekly via the bundled `clean-hook-sessions-weekly` job (see [Scheduled-task catch-up](#scheduled-task-catch-up)).
|
|
577
577
|
|
|
578
|
+
### `compact-smart`
|
|
579
|
+
|
|
580
|
+
Drafts the compaction-preservation paragraph you'd otherwise ask Claude for by hand before `/compact`, then hands back the exact `/compact <paragraph>` command to run — it never invokes `/compact` itself (Claude Code excludes that command from what a skill can invoke). Triggers on `/compact-smart`, "give me a paragraph to pass to compact", "draft a compact instruction", "help me compact this session". Covers decisions and their rationale (especially mid-session corrections), file/PR/branch pointers, standing constraints, and outstanding tasks split into "Claude's next steps" vs. "the user's own to-dos" — then shows you the draft to confirm or edit (including dropping an unrelated thread) before finalizing. Refreshes the session's `working/WORKLOG.md` if one already exists (never creates one), which also clears the `worklog-guard` PreCompact hook's staleness gate for the command it hands back.
|
|
581
|
+
|
|
578
582
|
See `docs/design.md` for the full design and CLI contract.
|
|
579
583
|
|
|
580
584
|
## Inter-session messaging
|
|
@@ -518,6 +518,10 @@ Curates the SHA-256 command cache the `bash-security-review` hook reads (`CCCS_U
|
|
|
518
518
|
|
|
519
519
|
Archives (tar.gz, verified) then deletes `bash-security-review`'s own hook-security-check session transcripts — those whose first user message begins "Review this shell command for security risks" — which otherwise pile up by the thousands and pollute `claude --resume`/`--continue`. Triggers on "clean up hook sessions", "archive old hook security sessions", or `--resume` being cluttered with security-check conversations. Dry-run by default; 8-digit gated for `--execute` (via `generate-8digit-code`). Also runs unattended weekly via the bundled `clean-hook-sessions-weekly` job (see [Scheduled-task catch-up](#scheduled-task-catch-up)).
|
|
520
520
|
|
|
521
|
+
### `compact-smart`
|
|
522
|
+
|
|
523
|
+
Drafts the compaction-preservation paragraph you'd otherwise ask Claude for by hand before `/compact`, then hands back the exact `/compact <paragraph>` command to run — it never invokes `/compact` itself (Claude Code excludes that command from what a skill can invoke). Triggers on `/compact-smart`, "give me a paragraph to pass to compact", "draft a compact instruction", "help me compact this session". Covers decisions and their rationale (especially mid-session corrections), file/PR/branch pointers, standing constraints, and outstanding tasks split into "Claude's next steps" vs. "the user's own to-dos" — then shows you the draft to confirm or edit (including dropping an unrelated thread) before finalizing. Refreshes the session's `working/WORKLOG.md` if one already exists (never creates one), which also clears the `worklog-guard` PreCompact hook's staleness gate for the command it hands back.
|
|
524
|
+
|
|
521
525
|
See `docs/design.md` for the full design and CLI contract.
|
|
522
526
|
|
|
523
527
|
## Inter-session messaging
|
|
@@ -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.2.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" }
|
|
@@ -206,8 +206,10 @@ def _cmd_list(args: argparse.Namespace) -> int:
|
|
|
206
206
|
partition=args.partition,
|
|
207
207
|
from_uuid=args.from_uuid,
|
|
208
208
|
)
|
|
209
|
+
now = datetime.now(timezone.utc)
|
|
209
210
|
for r in rows:
|
|
210
|
-
|
|
211
|
+
age = service.relative_age(r.sent_at, now)
|
|
212
|
+
print(f"[{r.id}] {r.status:8} {r.to_kind}={r.to_value} · {r.subject} · {age}")
|
|
211
213
|
return 0
|
|
212
214
|
|
|
213
215
|
|
|
@@ -2921,7 +2921,16 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
2921
2921
|
pdata_schema_sub.required = True
|
|
2922
2922
|
|
|
2923
2923
|
pdata_schema_add_field_parser = pdata_schema_sub.add_parser(
|
|
2924
|
-
"add-field",
|
|
2924
|
+
"add-field",
|
|
2925
|
+
help="Add/describe an extension-table field (idempotent; re-run to edit its description)",
|
|
2926
|
+
description=(
|
|
2927
|
+
"Add an extension-table field, or edit an existing field's description. "
|
|
2928
|
+
"Idempotent: re-running this command against a field name that already exists "
|
|
2929
|
+
"updates its --description in place rather than erroring or duplicating the "
|
|
2930
|
+
"column - there is no separate 'edit-description' command, this is it. "
|
|
2931
|
+
"Re-running with a DIFFERENT --field TYPE than the field already has is "
|
|
2932
|
+
"rejected with an error; add-field never changes an existing column's type."
|
|
2933
|
+
),
|
|
2925
2934
|
)
|
|
2926
2935
|
pdata_schema_add_field_parser.add_argument("--project", required=True, metavar="NAME")
|
|
2927
2936
|
pdata_schema_add_field_parser.add_argument("--group", required=True, metavar="RECORD_GROUP")
|
|
@@ -205,6 +205,51 @@ def check_no_stale_hooks(settings: dict[str, Any]) -> list[CheckResult]:
|
|
|
205
205
|
]
|
|
206
206
|
|
|
207
207
|
|
|
208
|
+
def check_no_stale_skill_symlinks(skills_target_dir: Path) -> list[CheckResult]:
|
|
209
|
+
"""WARN for every symlink under the installed skills directory whose target no longer
|
|
210
|
+
exists - the case a bundled skill's rename or removal leaves behind
|
|
211
|
+
(``ccst skills install`` only ever creates symlinks for skills currently in the bundled
|
|
212
|
+
source; it never removes one for a name that stopped being bundled, and
|
|
213
|
+
:func:`check_skill_symlink` only checks skills that ARE still bundled, so nothing else
|
|
214
|
+
catches this). Mirrors :func:`check_no_stale_hooks`'s shape for the same underlying
|
|
215
|
+
problem (a rename/removal leaving a stale registration behind), but WARN rather than
|
|
216
|
+
FAIL: a broken skill symlink degrades a feature, it does not break every matching event
|
|
217
|
+
of a running session the way a stale hook registration does.
|
|
218
|
+
|
|
219
|
+
OK (no findings) if the directory doesn't exist yet - nothing to check, not an error."""
|
|
220
|
+
if not skills_target_dir.is_dir():
|
|
221
|
+
return [CheckResult(
|
|
222
|
+
name="skills:no-stale",
|
|
223
|
+
status=Status.OK,
|
|
224
|
+
reason="skills directory does not exist yet",
|
|
225
|
+
)]
|
|
226
|
+
|
|
227
|
+
stale = [
|
|
228
|
+
entry for entry in sorted(skills_target_dir.iterdir())
|
|
229
|
+
if entry.is_symlink() and not entry.exists()
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
if not stale:
|
|
233
|
+
return [CheckResult(
|
|
234
|
+
name="skills:no-stale",
|
|
235
|
+
status=Status.OK,
|
|
236
|
+
reason="no symlinks for removed/renamed skills",
|
|
237
|
+
)]
|
|
238
|
+
|
|
239
|
+
return [
|
|
240
|
+
CheckResult(
|
|
241
|
+
name=f"skills:stale:{entry.name}",
|
|
242
|
+
status=Status.WARN,
|
|
243
|
+
reason=(
|
|
244
|
+
f"{entry} points to {os.readlink(entry)}, which no longer exists - the "
|
|
245
|
+
f"bundled skill it named was likely renamed or removed. Safe to remove: "
|
|
246
|
+
f"rm {entry}"
|
|
247
|
+
),
|
|
248
|
+
)
|
|
249
|
+
for entry in stale
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
|
|
208
253
|
def check_skill_symlink(skill_name: str, skill_src: Path, skills_dir: Path) -> CheckResult:
|
|
209
254
|
"""Check that skills_dir/<skill_name> is a valid CCST skill symlink.
|
|
210
255
|
|
|
@@ -1031,6 +1076,11 @@ def run_all_checks(
|
|
|
1031
1076
|
)
|
|
1032
1077
|
)
|
|
1033
1078
|
|
|
1079
|
+
# ...and the reverse direction: symlinks for skills that no longer exist (renamed/removed).
|
|
1080
|
+
# Runs regardless of whether skills_source_dir resolved above - an orphaned symlink can be
|
|
1081
|
+
# reported even if source discovery failed for an unrelated reason.
|
|
1082
|
+
results.extend(check_no_stale_skill_symlinks(skills_target_dir))
|
|
1083
|
+
|
|
1034
1084
|
# Bundled ccsched jobs
|
|
1035
1085
|
from cc_session_tools.lib.scheduler import bundled_jobs
|
|
1036
1086
|
|
{cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/messaging/service.py
RENAMED
|
@@ -116,6 +116,7 @@ class MessageRow:
|
|
|
116
116
|
to_value: str
|
|
117
117
|
from_session: str
|
|
118
118
|
subject: str
|
|
119
|
+
sent_at: str
|
|
119
120
|
|
|
120
121
|
|
|
121
122
|
def list_messages(
|
|
@@ -128,13 +129,15 @@ def list_messages(
|
|
|
128
129
|
return [
|
|
129
130
|
MessageRow(
|
|
130
131
|
id=m.id, status=m.status, to_kind=m.to_kind, to_value=m.to_value,
|
|
131
|
-
from_session=m.from_session, subject=m.subject,
|
|
132
|
+
from_session=m.from_session, subject=m.subject, sent_at=m.sent_at,
|
|
132
133
|
)
|
|
133
134
|
for m in repository.list_rows(status=status, partition=partition, from_uuid=from_uuid)
|
|
134
135
|
]
|
|
135
136
|
|
|
136
137
|
|
|
137
|
-
def
|
|
138
|
+
def relative_age(sent_at: str, now: datetime) -> str:
|
|
139
|
+
"""Public: used by both this module's own digest formatting and ccmsg.py's `list`
|
|
140
|
+
output - a genuine cross-module utility, not internal-only."""
|
|
138
141
|
sent = datetime.strptime(sent_at, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=timezone.utc)
|
|
139
142
|
minutes = int((now - sent).total_seconds() // 60)
|
|
140
143
|
if minutes < 1:
|
|
@@ -150,7 +153,7 @@ def _relative_age(sent_at: str, now: datetime) -> str:
|
|
|
150
153
|
def _digest_line(message: Message, now: datetime) -> str:
|
|
151
154
|
return (
|
|
152
155
|
f"[{message.id}] from {message.from_session} ({message.from_project}) · "
|
|
153
|
-
f"{message.subject} · {
|
|
156
|
+
f"{message.subject} · {relative_age(message.sent_at, now)}"
|
|
154
157
|
)
|
|
155
158
|
|
|
156
159
|
|
|
@@ -213,7 +216,7 @@ def _collect_receipts(ctx: SessionContext, now: datetime) -> list[str]:
|
|
|
213
216
|
who = message.read_by_session or "a session"
|
|
214
217
|
lines.append(
|
|
215
218
|
f'✓ read: "{message.subject}" by {who} '
|
|
216
|
-
f"({
|
|
219
|
+
f"({relative_age(message.sent_at, now)}) [{message.id}]"
|
|
217
220
|
)
|
|
218
221
|
shown.append(message.id)
|
|
219
222
|
repository.mark_receipts_shown(shown)
|
{cc_session_tools-3.0.0 → cc_session_tools-3.2.0}/src/cc_session_tools/lib/pdata/repository.py
RENAMED
|
@@ -169,6 +169,14 @@ def list_extension_columns(conn: sqlite3.Connection, record_group: str) -> list[
|
|
|
169
169
|
]
|
|
170
170
|
|
|
171
171
|
|
|
172
|
+
def _extension_column_type(conn: sqlite3.Connection, table: str, field_name: str) -> str | None:
|
|
173
|
+
"""The stored SQL type of an existing extension column, or None if it doesn't exist."""
|
|
174
|
+
for r in conn.execute(f'PRAGMA table_info("{table}")'):
|
|
175
|
+
if r["name"] == field_name:
|
|
176
|
+
return str(r["type"])
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
|
|
172
180
|
def add_extension_column(
|
|
173
181
|
conn: sqlite3.Connection,
|
|
174
182
|
record_group: str,
|
|
@@ -179,16 +187,32 @@ def add_extension_column(
|
|
|
179
187
|
) -> bool:
|
|
180
188
|
"""Idempotent: creates ext_<group> if missing (backfilling existing rows — see
|
|
181
189
|
ensure_extension_table), then ADD COLUMN if field_name isn't already a column (no-op if it
|
|
182
|
-
already exists — spec §5's schema add-field idempotency). Returns True
|
|
183
|
-
actually added, False on the no-op path — a caller gating a side effect
|
|
184
|
-
vector-clock bump) on whether this call changed anything needs that distinction,
|
|
185
|
-
"did it run without erroring". Caller owns the transaction.
|
|
190
|
+
already exists with the SAME type — spec §5's schema add-field idempotency). Returns True
|
|
191
|
+
iff a column was actually added, False on the no-op path — a caller gating a side effect
|
|
192
|
+
(e.g. a vector-clock bump) on whether this call changed anything needs that distinction,
|
|
193
|
+
not just "did it run without erroring". Caller owns the transaction.
|
|
194
|
+
|
|
195
|
+
Raises ValueError if field_name already exists with a DIFFERENT sql_type than requested -
|
|
196
|
+
rather than silently keeping the original type with no error, which is what this function
|
|
197
|
+
used to do (a rerun could look successful while dropping the type change entirely). An
|
|
198
|
+
actual column-type change is a real ALTER-TABLE-cannot-do-this rebuild, the same complexity
|
|
199
|
+
class as a primary-key change - disproportionate for this metadata-editing command; the
|
|
200
|
+
remediation text below is the deliberate manual escape hatch instead of building one."""
|
|
186
201
|
naming.validate_field_name(field_name)
|
|
187
202
|
normalized_type = _normalize_column_type(sql_type)
|
|
188
203
|
ensure_extension_table(conn, record_group)
|
|
189
204
|
table = naming.extension_table_name(record_group)
|
|
190
205
|
existing = set(list_extension_columns(conn, record_group))
|
|
191
206
|
if field_name in existing:
|
|
207
|
+
current_type = _extension_column_type(conn, table, field_name)
|
|
208
|
+
if current_type is not None and current_type != normalized_type:
|
|
209
|
+
raise ValueError(
|
|
210
|
+
f"field {field_name!r} in record_group {record_group!r} already has type "
|
|
211
|
+
f"{current_type!r}; you requested {normalized_type!r}. add-field never changes "
|
|
212
|
+
f"an existing column's type in place. To actually change it, drop and recreate "
|
|
213
|
+
f"the extension column by hand (this loses existing data in that column), or "
|
|
214
|
+
f"open an issue if this needs first-class support."
|
|
215
|
+
)
|
|
192
216
|
return False
|
|
193
217
|
if default is None:
|
|
194
218
|
conn.execute(f'ALTER TABLE "{table}" ADD COLUMN "{field_name}" {normalized_type}')
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: compact-smart
|
|
3
|
+
description: Draft a compaction-preservation paragraph from the current session and hand back the exact /compact command to run - automates what the user otherwise asks for by hand ("give me a paragraph to pass to /compact"). Use when the user runs /compact-smart, or says "give me a paragraph to pass to compact", "draft a compact instruction", "help me compact this session", "what should I tell compact to keep", or is about to /compact and wants to be sure nothing important gets lost.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# compact-smart
|
|
7
|
+
|
|
8
|
+
Drafts the instructions `/compact [instructions]` should carry, then hands back the exact
|
|
9
|
+
command to run. Does **not** invoke `/compact` itself - Claude Code's own docs explicitly
|
|
10
|
+
exclude `/compact` from the set of built-in commands a skill can invoke, so the deliverable
|
|
11
|
+
here is a ready-to-run command, not a compaction event.
|
|
12
|
+
|
|
13
|
+
## Why this exists
|
|
14
|
+
|
|
15
|
+
Real usage (a week of transcripts across every project) shows the user asking, by hand, for
|
|
16
|
+
"a paragraph to pass to /compact" roughly 3 times for every bare `/compact` call - and
|
|
17
|
+
re-explaining what counts as "relevant" nearly every time. What already survives compaction
|
|
18
|
+
automatically (project-root `CLAUDE.md`, memory files, system/environment info) is re-loaded
|
|
19
|
+
fresh from disk; what does **not** reliably survive is anything that only ever existed in
|
|
20
|
+
the conversation itself - decisions, corrections, standing agreements, outstanding to-dos.
|
|
21
|
+
A `/compact` instruction protects those for the *next* compaction only; the resulting
|
|
22
|
+
summary is itself just conversation text again and can be trimmed by a *later* one - so this
|
|
23
|
+
skill also refreshes the session's `WORKLOG.md`, if it has one, as a second, more durable
|
|
24
|
+
safeguard.
|
|
25
|
+
|
|
26
|
+
## What to draft
|
|
27
|
+
|
|
28
|
+
Review the conversation so far (you already have it loaded - no need to re-read the
|
|
29
|
+
transcript file from disk) and produce a paragraph covering, in this order:
|
|
30
|
+
|
|
31
|
+
1. **Decisions and their rationale** - especially any point where the initial plan or
|
|
32
|
+
approach was found wrong and corrected mid-session. State the corrected approach and WHY
|
|
33
|
+
it changed, not just what the original plan was.
|
|
34
|
+
2. **Concrete artifact pointers** - file paths, PR numbers, branch names, commit hashes,
|
|
35
|
+
OpenSpec change names, or anything else someone would need to go find the actual work.
|
|
36
|
+
3. **Standing constraints or policies** established or confirmed during this session that
|
|
37
|
+
must carry forward (e.g. "no attribution lines in commits", "confirm before opening a
|
|
38
|
+
PR", a data-handling rule agreed mid-session). These are easy for a generic summary to
|
|
39
|
+
drop silently because they're usually stated once, early, and never repeated.
|
|
40
|
+
4. **Outstanding tasks, split into two distinct groups**: what you (Claude) will do next,
|
|
41
|
+
and - separately and explicitly labeled - anything that is the *user's own* action to
|
|
42
|
+
take (e.g. "you still need to delete branch X yourself", "review the PR before merging").
|
|
43
|
+
Do not fold these two categories together.
|
|
44
|
+
5. **An explicit "what happens next" statement.** Never leave this implicit.
|
|
45
|
+
|
|
46
|
+
Keep it dense and concrete - file paths and specific facts, not vague summary language.
|
|
47
|
+
|
|
48
|
+
## Handling `working/WORKLOG.md`
|
|
49
|
+
|
|
50
|
+
Check whether the current session has one: `$CLD_SESSION_DIR/working/WORKLOG.md`.
|
|
51
|
+
|
|
52
|
+
- **If it exists**: update it with the same substance as the draft above (append or rewrite
|
|
53
|
+
its "current state" section - match whatever structure the file already uses). This
|
|
54
|
+
repo's own `worklog-guard` PreCompact hook blocks a manual `/compact` if this file is more
|
|
55
|
+
than an hour stale, so refreshing it here also clears that gate for the command you're
|
|
56
|
+
about to hand back.
|
|
57
|
+
- **If it does not exist**: do not create one. `ccd`/`ccr` never create a WORKLOG.md
|
|
58
|
+
automatically - it is opt-in scratch content the user or Claude may choose to keep during
|
|
59
|
+
a session, not mandatory state. Creating one here for the first time would be the skill
|
|
60
|
+
inventing a convention that has never applied to this session.
|
|
61
|
+
|
|
62
|
+
## Confirmation step
|
|
63
|
+
|
|
64
|
+
Show the drafted paragraph to the user before finalizing anything. Do not skip this even if
|
|
65
|
+
the draft feels obviously complete - the point is to catch a miss before compaction discards
|
|
66
|
+
the detail, not after. Accept:
|
|
67
|
+
|
|
68
|
+
- Approval as-is, or
|
|
69
|
+
- Free-form edits, or
|
|
70
|
+
- An explicit exclusion ("drop the X thread, keep everything else") - a stale, unrelated
|
|
71
|
+
tangent that happened to occur in the same session is a real, recurring case; when asked,
|
|
72
|
+
remove that content from the paragraph rather than trying to talk the user out of it.
|
|
73
|
+
|
|
74
|
+
This is a single review-and-edit round, not a multi-question interview - draft first, then
|
|
75
|
+
let the user correct it in one pass. Asking a series of clarifying questions before drafting
|
|
76
|
+
anything reintroduces exactly the friction this skill exists to remove.
|
|
77
|
+
|
|
78
|
+
## Final output
|
|
79
|
+
|
|
80
|
+
Once confirmed, present the exact command on its own line, ready to copy or type verbatim:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
/compact <finalized paragraph>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Do not summarize what you're about to do instead of showing the literal command - the
|
|
87
|
+
command itself is the deliverable.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: pm-pdata-audit
|
|
3
|
-
description: Full consistency/completeness audit of a project's central and recordkeeping files - OneDrive sync-conflict cleanup, cross-checking every index/register/log against what it claims to describe, and a pdata-migration readiness pass. Ends by writing a readiness manifest file that the companion `pm-pdata-migrate` skill consumes to actually run the migration. Triggers on "review all my central files", "audit the project files", "check everything is up to date and consistent", "get this project ready for pdata", "/pm-pdata-audit", or any request for a thorough review/health-check of a project's index/log/register files (as opposed to a single-session wrap-up, which is pm-update-central-files). Especially relevant when a project is scheduled to migrate to pdata - this audit is the recommended prerequisite pass, since a schema design should not be built against files that still have unresolved sync-conflict duplicates or known dangling rows.
|
|
2
|
+
name: pm-pdata-do-audit-and-prepare-to-migrate
|
|
3
|
+
description: Full consistency/completeness audit of a project's central and recordkeeping files - OneDrive sync-conflict cleanup, cross-checking every index/register/log against what it claims to describe, and a pdata-migration readiness pass. Ends by writing a readiness manifest file that the companion `pm-pdata-do-migrate` skill consumes to actually run the migration. Triggers on "review all my central files", "audit the project files", "check everything is up to date and consistent", "get this project ready for pdata", "/pm-pdata-do-audit-and-prepare-to-migrate", or any request for a thorough review/health-check of a project's index/log/register files (as opposed to a single-session wrap-up, which is pm-update-central-files). Especially relevant when a project is scheduled to migrate to pdata - this audit is the recommended prerequisite pass, since a schema design should not be built against files that still have unresolved sync-conflict duplicates or known dangling rows.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Audit central files
|
|
@@ -11,7 +11,7 @@ description: Full consistency/completeness audit of a project's central and reco
|
|
|
11
11
|
memory rules, register new `out/` files, and surface a handful of session-specific checkpoint
|
|
12
12
|
items before the user exits.
|
|
13
13
|
|
|
14
|
-
`pm-pdata-audit` is a much bigger, standalone task: a project-wide sweep of every
|
|
14
|
+
`pm-pdata-do-audit-and-prepare-to-migrate` is a much bigger, standalone task: a project-wide sweep of every
|
|
15
15
|
central file (indexes, logs, registers, CSVs) that could span an entire session or more, run on
|
|
16
16
|
demand rather than at every session's end. Use it when the user wants the whole project's
|
|
17
17
|
recordkeeping health-checked, not just today's session tidied up. It is squarely a
|
|
@@ -134,7 +134,7 @@ This file is deliberately NOT a migration plan - it's a findings list for whoeve
|
|
|
134
134
|
`pm-pdata-schema-design` session next, so that work isn't designed against a still-messy
|
|
135
135
|
substrate.
|
|
136
136
|
|
|
137
|
-
## Phase 5: write the readiness manifest (for `pm-pdata-migrate` to consume)
|
|
137
|
+
## Phase 5: write the readiness manifest (for `pm-pdata-do-migrate` to consume)
|
|
138
138
|
|
|
139
139
|
Once the audit reaches a settled state (per your own stopping rule - typically two consecutive
|
|
140
140
|
clean verification rounds, or a documented pragmatic stop), write one machine-and-human-readable
|
|
@@ -145,7 +145,7 @@ otherwise the project's own top-level docs location. Its existence and location
|
|
|
145
145
|
recorded in the project's own instructions file (`CLAUDE.md`/`AGENTS.md`/equivalent) so a future
|
|
146
146
|
session doesn't have to search for it.
|
|
147
147
|
|
|
148
|
-
The manifest must have, in this order, so `pm-pdata-migrate` can parse it deterministically:
|
|
148
|
+
The manifest must have, in this order, so `pm-pdata-do-migrate` can parse it deterministically:
|
|
149
149
|
|
|
150
150
|
1. **Header**: audit date, session/agent identifier, and an explicit "STALE IF" note - state the
|
|
151
151
|
condition that would invalidate this manifest (e.g. "stale if any of the files below have
|
|
@@ -154,7 +154,7 @@ The manifest must have, in this order, so `pm-pdata-migrate` can parse it determ
|
|
|
154
154
|
row/entry count, last-verified-clean date, and its role (`index`, `register`, `log`,
|
|
155
155
|
`narrative`, `derived-artefact`).
|
|
156
156
|
3. **Per-file migration blockers**, in the exact shape `pm-pdata-schema-design` and
|
|
157
|
-
`pm-pdata-migrate` expect to consume - this is the same content this skill's own Phase 4
|
|
157
|
+
`pm-pdata-do-migrate` expect to consume - this is the same content this skill's own Phase 4
|
|
158
158
|
already produces, just formalised into the manifest rather than a standalone prose report:
|
|
159
159
|
inconsistent separators, unstable/non-existent natural keys, mixed date formats, multi-schema
|
|
160
160
|
single files, machine-specific paths, null-value conventions that aren't real nulls.
|
|
@@ -165,7 +165,7 @@ The manifest must have, in this order, so `pm-pdata-migrate` can parse it determ
|
|
|
165
165
|
a migration pass doesn't waste time re-flagging it or, worse, silently drops one copy.
|
|
166
166
|
6. **Open decisions** - anything the audit found but explicitly did NOT resolve because it needed
|
|
167
167
|
the project owner's judgement (scope calls, curation completeness, which of two forks is
|
|
168
|
-
canonical). List these plainly; `pm-pdata-migrate` must not treat an unresolved item as settled.
|
|
168
|
+
canonical). List these plainly; `pm-pdata-do-migrate` must not treat an unresolved item as settled.
|
|
169
169
|
|
|
170
170
|
## Common mistakes
|
|
171
171
|
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: pm-pdata-migrate
|
|
3
|
-
description: Execute a project's actual migration from flat central/index files to a ccst pdata record store - build a migration plan, adversarially verify the plan itself, present it for the user's confirmation, then execute it and write a results file. Consumes the readiness manifest pm-pdata-audit produces if one exists, but always explores the project independently too, so it works even without that manifest. Triggers on "migrate this project to pdata", "run the pdata migration", "/pm-pdata-migrate", or any request to actually move a project's CSV/index/log files into pdata (as opposed to just auditing readiness, which is pm-pdata-audit, or designing the target schema in the abstract, which is pm-pdata-schema-design).
|
|
2
|
+
name: pm-pdata-do-migrate
|
|
3
|
+
description: Execute a project's actual migration from flat central/index files to a ccst pdata record store - build a migration plan, adversarially verify the plan itself, present it for the user's confirmation, then execute it and write a results file. Consumes the readiness manifest pm-pdata-do-audit-and-prepare-to-migrate produces if one exists, but always explores the project independently too, so it works even without that manifest. Triggers on "migrate this project to pdata", "run the pdata migration", "/pm-pdata-do-migrate", or any request to actually move a project's CSV/index/log files into pdata (as opposed to just auditing readiness, which is pm-pdata-do-audit-and-prepare-to-migrate, or designing the target schema in the abstract, which is pm-pdata-schema-design).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Migrate a project to pdata
|
|
7
7
|
|
|
8
8
|
## When to use this vs. the other pm-pdata-* skills
|
|
9
9
|
|
|
10
|
-
- `pm-pdata-audit` - readiness audit. Finds and fixes problems in the CURRENT flat files.
|
|
10
|
+
- `pm-pdata-do-audit-and-prepare-to-migrate` - readiness audit. Finds and fixes problems in the CURRENT flat files.
|
|
11
11
|
Produces a readiness manifest. Does not touch pdata at all.
|
|
12
12
|
- `pm-pdata-schema-design` - designs the TARGET record-group schema in the abstract (field names,
|
|
13
13
|
types, groupings) before any data moves.
|
|
14
|
-
- `pm-pdata-migrate` (this skill) - takes whatever schema exists (designed via the skill above,
|
|
14
|
+
- `pm-pdata-do-migrate` (this skill) - takes whatever schema exists (designed via the skill above,
|
|
15
15
|
or designed inline as part of this skill's own plan if no separate design session happened) and
|
|
16
16
|
actually moves the data: `ccst pdata add`/`batch` calls, verification, and a results record.
|
|
17
17
|
|
|
18
|
-
Run `pm-pdata-audit` first if the project hasn't been through it recently - a migration
|
|
18
|
+
Run `pm-pdata-do-audit-and-prepare-to-migrate` first if the project hasn't been through it recently - a migration
|
|
19
19
|
plan built against files with known unresolved duplicates or dangling rows just bakes the mess
|
|
20
20
|
into pdata. This skill doesn't refuse to run without that prerequisite (see below), but it will
|
|
21
21
|
re-derive the same checks itself if skipped, which costs more and finds less than a dedicated
|
|
@@ -23,7 +23,7 @@ audit pass would.
|
|
|
23
23
|
|
|
24
24
|
## Step 1: gather readiness information (works with or without a manifest)
|
|
25
25
|
|
|
26
|
-
1. Look for a readiness manifest from `pm-pdata-audit` (check the project's own
|
|
26
|
+
1. Look for a readiness manifest from `pm-pdata-do-audit-and-prepare-to-migrate` (check the project's own
|
|
27
27
|
instructions file for where it said one was written, typically `analysis/pdata-readiness.md`
|
|
28
28
|
or similar). If found: read it, and check its own "STALE IF" condition - if any listed file
|
|
29
29
|
has been edited more recently than the manifest's audit date, treat the manifest as a starting
|
|
@@ -32,7 +32,7 @@ audit pass would.
|
|
|
32
32
|
project's central/index/recordkeeping files: read the project's own instructions file in full,
|
|
33
33
|
list every central file it documents, and for each one note its row/entry count, its apparent
|
|
34
34
|
natural key (if any), and any obvious structural issue (multi-schema single files, inconsistent
|
|
35
|
-
separators, machine-specific paths) - the same categories `pm-pdata-audit` Phase 4
|
|
35
|
+
separators, machine-specific paths) - the same categories `pm-pdata-do-audit-and-prepare-to-migrate` Phase 4
|
|
36
36
|
checks for. If a manifest exists, use this pass to spot-check a sample of its claims rather
|
|
37
37
|
than skipping it entirely - a stale or partially-wrong manifest is worse than no manifest if
|
|
38
38
|
trusted blindly.
|
|
@@ -50,7 +50,7 @@ ran):
|
|
|
50
50
|
`filings-index`), not its filename.
|
|
51
51
|
- **Natural key** - prefer a field that's already unique, stable, and won't be reassigned by a
|
|
52
52
|
future session (a project-prefixed sequential id like `FIL-001` is a good sign; a per-session
|
|
53
|
-
independently-renumbered `row_id` is not - see `pm-pdata-audit`'s own warnings about
|
|
53
|
+
independently-renumbered `row_id` is not - see `pm-pdata-do-audit-and-prepare-to-migrate`'s own warnings about
|
|
54
54
|
this exact failure mode, which shows up often). If nothing qualifies, mint a synthetic id
|
|
55
55
|
at migration time and record the mapping.
|
|
56
56
|
- **Field types and normalisation** - fix the specific blockers the manifest/your own audit
|
|
@@ -127,13 +127,13 @@ have N records instead of the source file's row count" without re-deriving the r
|
|
|
127
127
|
|
|
128
128
|
## Common mistakes
|
|
129
129
|
|
|
130
|
-
- Refusing to run without a `pm-pdata-audit` manifest present - always fall back to your
|
|
130
|
+
- Refusing to run without a `pm-pdata-do-audit-and-prepare-to-migrate` manifest present - always fall back to your
|
|
131
131
|
own exploration instead; the manifest is an optimisation, not a hard dependency.
|
|
132
132
|
- Trusting a present manifest without checking its staleness condition against current file
|
|
133
133
|
states - a manifest from a project that's had further edits since is actively dangerous if
|
|
134
134
|
taken at face value.
|
|
135
135
|
- Migrating a session-relative or otherwise unstable field as if it were a durable natural key -
|
|
136
|
-
this is the single most common blocker `pm-pdata-audit` finds in practice; take its
|
|
136
|
+
this is the single most common blocker `pm-pdata-do-audit-and-prepare-to-migrate` finds in practice; take its
|
|
137
137
|
warnings about this seriously rather than assuming "it looks like an id column" is enough.
|
|
138
138
|
- Executing before the user has explicitly confirmed the plan summary in step 5 - a bulk pdata
|
|
139
139
|
write is exactly the kind of hard-to-reverse, outward-facing action that needs confirmation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cc-session-tools
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.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
|
|
@@ -575,6 +575,10 @@ Curates the SHA-256 command cache the `bash-security-review` hook reads (`CCCS_U
|
|
|
575
575
|
|
|
576
576
|
Archives (tar.gz, verified) then deletes `bash-security-review`'s own hook-security-check session transcripts — those whose first user message begins "Review this shell command for security risks" — which otherwise pile up by the thousands and pollute `claude --resume`/`--continue`. Triggers on "clean up hook sessions", "archive old hook security sessions", or `--resume` being cluttered with security-check conversations. Dry-run by default; 8-digit gated for `--execute` (via `generate-8digit-code`). Also runs unattended weekly via the bundled `clean-hook-sessions-weekly` job (see [Scheduled-task catch-up](#scheduled-task-catch-up)).
|
|
577
577
|
|
|
578
|
+
### `compact-smart`
|
|
579
|
+
|
|
580
|
+
Drafts the compaction-preservation paragraph you'd otherwise ask Claude for by hand before `/compact`, then hands back the exact `/compact <paragraph>` command to run — it never invokes `/compact` itself (Claude Code excludes that command from what a skill can invoke). Triggers on `/compact-smart`, "give me a paragraph to pass to compact", "draft a compact instruction", "help me compact this session". Covers decisions and their rationale (especially mid-session corrections), file/PR/branch pointers, standing constraints, and outstanding tasks split into "Claude's next steps" vs. "the user's own to-dos" — then shows you the draft to confirm or edit (including dropping an unrelated thread) before finalizing. Refreshes the session's `working/WORKLOG.md` if one already exists (never creates one), which also clears the `worklog-guard` PreCompact hook's staleness gate for the command it hands back.
|
|
581
|
+
|
|
578
582
|
See `docs/design.md` for the full design and CLI contract.
|
|
579
583
|
|
|
580
584
|
## Inter-session messaging
|
|
@@ -108,6 +108,7 @@ src/cc_session_tools/prompts/pdata-migration-skills-update.md
|
|
|
108
108
|
src/cc_session_tools/skills/analyse-cc-usage/SKILL.md
|
|
109
109
|
src/cc_session_tools/skills/clean-hook-sessions/SKILL.md
|
|
110
110
|
src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py
|
|
111
|
+
src/cc_session_tools/skills/compact-smart/SKILL.md
|
|
111
112
|
src/cc_session_tools/skills/context-override/SKILL.md
|
|
112
113
|
src/cc_session_tools/skills/delete-sessions/SKILL.md
|
|
113
114
|
src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py
|
|
@@ -122,9 +123,9 @@ src/cc_session_tools/skills/move-session/SKILL.md
|
|
|
122
123
|
src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh
|
|
123
124
|
src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py
|
|
124
125
|
src/cc_session_tools/skills/move-session/scripts/move_session.py
|
|
125
|
-
src/cc_session_tools/skills/pm-pdata-audit/SKILL.md
|
|
126
126
|
src/cc_session_tools/skills/pm-pdata-conflict-resolution/SKILL.md
|
|
127
|
-
src/cc_session_tools/skills/pm-pdata-migrate/SKILL.md
|
|
127
|
+
src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate/SKILL.md
|
|
128
|
+
src/cc_session_tools/skills/pm-pdata-do-migrate/SKILL.md
|
|
128
129
|
src/cc_session_tools/skills/pm-pdata-schema-design/SKILL.md
|
|
129
130
|
src/cc_session_tools/skills/pm-project-init/SKILL.md
|
|
130
131
|
src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md
|
|
@@ -11,7 +11,11 @@ checks (skill-marker exceptions short-circuit them):
|
|
|
11
11
|
|
|
12
12
|
If all three hold and the assistant-to-user reply gap is under 30 minutes,
|
|
13
13
|
the call is allowed. Otherwise the hook either prints a warning (default,
|
|
14
|
-
``CCCS_ENFORCE_8DIGIT=warn``) or blocks with exit 2 (``=block``)
|
|
14
|
+
``CCCS_ENFORCE_8DIGIT=warn``) or blocks with exit 2 (``=block``) - and, either
|
|
15
|
+
way, pushes the same message as a Telegram notification via
|
|
16
|
+
``lib.scheduler.notify.send_telegram`` (best-effort; never changes the exit
|
|
17
|
+
code or stderr message on its own failure), so the block/warn reaches the
|
|
18
|
+
user even when they are away from the terminal.
|
|
15
19
|
|
|
16
20
|
Skill-marker exceptions live under ``~/.cache/claude/markers/`` (override with
|
|
17
21
|
the ``CCCS_MARKERS_DIR`` env var) and have a 1-hour TTL based on file mtime.
|
|
@@ -31,6 +35,7 @@ import sys
|
|
|
31
35
|
import time
|
|
32
36
|
from typing import Literal
|
|
33
37
|
|
|
38
|
+
from cc_session_tools.lib.scheduler.notify import send_telegram
|
|
34
39
|
from hooks.markers import markers_dir
|
|
35
40
|
from hooks.transcript import (
|
|
36
41
|
TranscriptNotFound,
|
|
@@ -209,14 +214,13 @@ def verify(
|
|
|
209
214
|
try:
|
|
210
215
|
turns = load_transcript(session_id=session_id, cwd=cwd)
|
|
211
216
|
except TranscriptNotFound as e:
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
f"{tool_name}: transcript not found ({e}). Re-run from a real "
|
|
217
|
-
f"Claude Code session, or set the appropriate skill marker."
|
|
218
|
-
),
|
|
217
|
+
message = (
|
|
218
|
+
f"[8digit-block] cannot verify 8-digit confirmation for "
|
|
219
|
+
f"{tool_name}: transcript not found ({e}). Re-run from a real "
|
|
220
|
+
f"Claude Code session, or set the appropriate skill marker."
|
|
219
221
|
)
|
|
222
|
+
send_telegram(message)
|
|
223
|
+
return VerificationResult(exit_code=2, message=message)
|
|
220
224
|
|
|
221
225
|
# 3. Three-part verification.
|
|
222
226
|
failures: list[str] = []
|
|
@@ -251,21 +255,19 @@ def verify(
|
|
|
251
255
|
|
|
252
256
|
detail = "; ".join(failures) if failures else "verification failed"
|
|
253
257
|
if enforce == "block":
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
f"8-digit code, share it as 'Respond with NNNNNNNN ...', and "
|
|
259
|
-
f"only proceed if the user replies with exactly that string."
|
|
260
|
-
),
|
|
258
|
+
message = (
|
|
259
|
+
f"[8digit-block] {tool_name}: {detail}. Generate a fresh "
|
|
260
|
+
f"8-digit code, share it as 'Respond with NNNNNNNN ...', and "
|
|
261
|
+
f"only proceed if the user replies with exactly that string."
|
|
261
262
|
)
|
|
262
|
-
|
|
263
|
-
exit_code=
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
),
|
|
263
|
+
send_telegram(message)
|
|
264
|
+
return VerificationResult(exit_code=2, message=message)
|
|
265
|
+
message = (
|
|
266
|
+
f"[8digit-warn] {tool_name}: {detail}. "
|
|
267
|
+
f"(Set CCCS_ENFORCE_8DIGIT=block to enforce.)"
|
|
268
268
|
)
|
|
269
|
+
send_telegram(message)
|
|
270
|
+
return VerificationResult(exit_code=0, message=message)
|
|
269
271
|
|
|
270
272
|
|
|
271
273
|
def main(argv: list[str] | None = None) -> int:
|
|
@@ -141,12 +141,25 @@ def test_bundled_prompts_are_no_longer_placeholders():
|
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
def test_pm_pdata_audit_and_migrate_are_bundled_skills():
|
|
144
|
-
"""pm-pdata-audit and pm-pdata-migrate
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
144
|
+
"""pm-pdata-do-audit-and-prepare-to-migrate and pm-pdata-do-migrate (renamed from
|
|
145
|
+
pm-pdata-audit/pm-pdata-migrate in 3.1.0 for clarity) were built directly under
|
|
146
|
+
~/.claude/skills/ in an earlier session - moved into this repo's bundled skills/ so
|
|
147
|
+
ccst skills install / install-everything provision them on every machine, not just the
|
|
148
|
+
one they were authored on. No registry to update - _discover_skills is a directory scan
|
|
149
|
+
(any subdir with a SKILL.md), so this test is really asserting the directories/files
|
|
150
|
+
exist and are named correctly."""
|
|
150
151
|
discovered = {p.name for p in ccst._discover_skills(ccst._discover_source_dir())}
|
|
151
|
-
assert "pm-pdata-audit" in discovered
|
|
152
|
-
assert "pm-pdata-migrate" in discovered
|
|
152
|
+
assert "pm-pdata-do-audit-and-prepare-to-migrate" in discovered
|
|
153
|
+
assert "pm-pdata-do-migrate" in discovered
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_compact_smart_is_a_bundled_skill():
|
|
157
|
+
"""compact-smart drafts a /compact preservation paragraph and hands back the exact
|
|
158
|
+
command to run - see openspec/changes/add-compact-smart-skill (archived) for the design.
|
|
159
|
+
Pure instruction skill, no backing script - this discovery assertion plus a frontmatter
|
|
160
|
+
sanity check is the extent of what's mechanically testable (design.md Decision 1)."""
|
|
161
|
+
skills = {p.name: p for p in ccst._discover_skills(ccst._discover_source_dir())}
|
|
162
|
+
assert "compact-smart" in skills
|
|
163
|
+
text = (skills["compact-smart"] / "SKILL.md").read_text()
|
|
164
|
+
assert text.startswith("---\nname: compact-smart\n")
|
|
165
|
+
assert "/compact-smart" in text
|