cc-session-tools 3.9.2__tar.gz → 3.10.1__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.2/src/cc_session_tools.egg-info → cc_session_tools-3.10.1}/PKG-INFO +1 -1
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/pyproject.toml +3 -3
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/ccst.py +21 -52
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/cutover.py +9 -1
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/init_service.py +196 -97
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/pm-pdata-do-init/SKILL.md +16 -0
- cc_session_tools-3.10.1/src/cc_session_tools/skills/pm-pdata-do-update-consuming-skills/SKILL.md +114 -0
- cc_session_tools-3.10.1/src/cc_session_tools/skills/pm-pdata-do-update-project-docs/SKILL.md +103 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1/src/cc_session_tools.egg-info}/PKG-INFO +1 -1
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools.egg-info/SOURCES.txt +3 -2
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_bundle_discovery.py +35 -62
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_pdata_init_cli.py +15 -9
- cc_session_tools-3.10.1/tests/test_pdata_post_migration_skills.py +123 -0
- cc_session_tools-3.9.2/src/cc_session_tools/prompts/pdata-migration-claude-md-update.md +0 -134
- cc_session_tools-3.9.2/src/cc_session_tools/prompts/pdata-migration-skills-update.md +0 -137
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/LICENSE +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/README.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/setup.cfg +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/__init__.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/__init__.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/ccd.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/ccmsg.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/ccr.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/ccs.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/ccsched.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/migrate_ccmsg.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/migrate_ccsched.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/migrate_sessions_db.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/cli/migrate_telemetry.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/config/hooks-bundle.json +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/config/session-tag-hook.json +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/hooks_install.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/__init__.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/bun_tools.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/claude_flags.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/claude_md_install.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/context_overrides.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/db.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/debug.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/doctor.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/doctor_mutes.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/hook_registry.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/install_sync.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/levenshtein.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/machine_identity.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/__init__.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/addressing.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/cursor.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/lock.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/message.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/move_safety.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/repository.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/retention.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/service.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/messaging/store.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/occupancy.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/paths.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/__init__.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/backup.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/classify.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/dump.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/formatting.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/importers.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/init_paths.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/manifest.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/naming.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/readiness.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/rehydrate.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/rename_group.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/reorganize.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/repository.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/resolve.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/service.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/session_output.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/store.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/sync_check.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/sync_lock.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/sync_notify.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/vector_clock.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/vector_clock_store.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/verify.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/write_log.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/picker.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/proc_lock.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/prompts.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/roots.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/rules.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/__init__.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/bundled_jobs.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/cadence.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/cursor.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/digest.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/due.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/duration.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/jobspec.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/ledger.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/lock.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/notify.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/reconcile.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/registry.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/runner.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/state.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/store.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/surface.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/throttle.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/scheduler/worker.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/session_gc.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/sessions.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/sessions_db.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/sessions_repair.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/shell_install.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/tasklist.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/telemetry_store.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/text_wrap.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/analyse-cc-usage/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/clean-hook-sessions/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/clean-hook-sessions/scripts/clean-hook-sessions.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/compact-smart/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/context-override/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/delete-sessions/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/delete-sessions/scripts/delete_sessions.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/do-executor-critic-assessor-loop/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/extract-pptx/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/extract-pptx/scripts/extract_pptx.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/extract-to-text/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/extract-to-text/scripts/extract_to_text.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/find-claude-code-session/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/generate-8digit-code/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/generate-8digit-code/scripts/generate_8digit_code.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/list-empty-sessions/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/list-empty-sessions/scripts/list_empty_sessions.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/manage-recurring-cc-jobs-using-ccsched/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/move-session/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/move-session/hooks/sessionstart-pending-rename.sh +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/move-session/scripts/cc_session_rules.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/move-session/scripts/move_session.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/pm-pdata-design-schema/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/pm-pdata-do-audit-and-prepare-to-migrate/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/pm-pdata-do-manual-migration/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/pm-pdata-resolve-conflicts/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/pm-project-layout-reference/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/pm-update-central-files/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/reduce-persistent-context/CALIBRATION.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/reduce-persistent-context/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/reduce-persistent-context/scripts/analyze_context.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/reduce-persistent-context/scripts/duplicates.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/reduce-persistent-context/scripts/measure.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/reduce-persistent-context/scripts/report.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/reduce-persistent-context/scripts/tokens.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/reduce-persistent-context/scripts/usage.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/select-agent-model/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/send-session-message/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/update-command-cache/SKILL.md +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/skills/update-command-cache/scripts/update_command_cache.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools.egg-info/dependency_links.txt +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools.egg-info/entry_points.txt +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools.egg-info/requires.txt +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools.egg-info/top_level.txt +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/__init__.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/attribution.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/cache.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/ccusage_wrapper.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/data/pricing.json +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/parent_inference.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/parser.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/pricing.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/query.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/report.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/schema.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/claude_code_usage/session_names.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/__init__.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/after_response.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/bash_hard_deny.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/bash_security_review.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/cache.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/catchup.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/confirm_8digit.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/context_window_warning.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/last_screenshot.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/marker_allow.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/markers.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/messaging_deliver.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/model_info.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/normalise.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/pdata_sync.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/pending_migration.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/pending_rename.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/script_allowlist.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/session_tag.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/stats.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/telemetry.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/telemetry_query.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/telemetry_trim.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/transcript.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/hooks/worklog_guard.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_after_response.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_attribution.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_bash_hard_deny.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_bash_security_review.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_bash_security_review_allowlist.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_bun_tools.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_cache.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_cache_sqlite.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccr_orphans.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccs_emptiness.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccs_eta.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccs_list_mode.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccs_scope_flags.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccs_sentinel_sort.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccs_session_counts.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_ccsched_jobs_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_context_override_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_doctor.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_gc_prune.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_gc_report.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_hook_dispatcher.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_hooks_allowlist.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_hooks_install_prune.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_hooks_install_zero_arg.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_hooks_uninstall.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_install_everything.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_machine_identity_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_main_gate.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_pdata_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_pdata_readiness_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_pdata_reconcile_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_pdata_rename_group_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_pdata_reorganize_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_pdata_sync_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_pdata_verify_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_repair_sessions_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_sessions_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_shell_install.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_skills_install.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_skills_uninstall.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_telemetry_query.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccst_telemetry_trim.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_ccusage_wrapper.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_claude_flags.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_claude_md_install.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_cli.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_cli_ccd.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_cli_ccd_dry_run.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_cli_ccr.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_cli_ccs.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_cli_version.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_confirm_8digit.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_context_overrides.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_context_window_warning.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_db.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_debug.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_doctor_mutes.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_empty_session.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_hook_cache.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_hooks_install.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_hooks_install_records.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_install_sync.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_last_screenshot.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_levenshtein.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_machine_identity.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_marker_allow.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_migrate_ccmsg.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_migrate_ccsched.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_migrate_sessions_db.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_migrate_telemetry.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_model_info.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_normalise.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_occupancy.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_parent_inference.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_parser.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_paths.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_pdata_audit_skill.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_pending_migration_hook.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_picker.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_pricing.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_proc_lock.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_prompts.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_query.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_report.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_roots.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_rules.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_scheduler_bundled_jobs.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_schema.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_script_allowlist.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_session_names.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_session_tag.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_sessions.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_sessions_db.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_sessions_db_migration_chain.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_sessions_repair.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_tasklist.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_telemetry.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_telemetry_store.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_text_wrap.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_transcript.py +0 -0
- {cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/tests/test_worklog_guard.py +0 -0
|
@@ -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.1"
|
|
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
|
{cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/cutover.py
RENAMED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import time
|
|
5
|
+
from collections.abc import Callable
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
from cc_session_tools.lib.pdata.init_paths import (
|
|
@@ -59,6 +60,7 @@ def _write_pointer_file(*, project_root: Path, project: str, entry: ManifestEntr
|
|
|
59
60
|
def archive_entries(
|
|
60
61
|
*, project_root: Path, entries: list[ManifestEntry], project: str,
|
|
61
62
|
write_pointer_files: bool = True,
|
|
63
|
+
on_archived: Callable[[ManifestEntry], None] | None = None,
|
|
62
64
|
) -> None:
|
|
63
65
|
"""Move every db-owned entry's source file into project_root/.pdata-migrated/,
|
|
64
66
|
preserving its relative path, and append one line per entry to MANIFEST.md.
|
|
@@ -69,7 +71,11 @@ def archive_entries(
|
|
|
69
71
|
Markdown pointer file back at each entry's original path so anything else in the
|
|
70
72
|
project that cites the old path by name finds a live signpost instead of a silent
|
|
71
73
|
404. Pass write_pointer_files=False (--leave-no-pointer-files at the CLI) to
|
|
72
|
-
suppress this.
|
|
74
|
+
suppress this.
|
|
75
|
+
|
|
76
|
+
`on_archived`, if given, is called with each entry immediately after its source has been
|
|
77
|
+
moved (before its log line and pointer file are written), so a caller that sees this
|
|
78
|
+
function raise part-way knows exactly which entries were already cut over."""
|
|
73
79
|
if not entries:
|
|
74
80
|
return
|
|
75
81
|
archive_root = project_root / MIGRATED_ARCHIVE_DIRNAME
|
|
@@ -82,6 +88,8 @@ def archive_entries(
|
|
|
82
88
|
destination = archive_root / entry.path
|
|
83
89
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
84
90
|
source.rename(destination)
|
|
91
|
+
if on_archived is not None:
|
|
92
|
+
on_archived(entry)
|
|
85
93
|
log.write(
|
|
86
94
|
f"- {now} — {entry.path} — migrated source, superseded by ccst pdata "
|
|
87
95
|
f"(record_group={entry.db_group()})\n"
|
{cc_session_tools-3.9.2 → cc_session_tools-3.10.1}/src/cc_session_tools/lib/pdata/init_service.py
RENAMED
|
@@ -213,6 +213,69 @@ def _rollback(*, project: str, created_ids: list[int]) -> list[str]:
|
|
|
213
213
|
return rollback_failures
|
|
214
214
|
|
|
215
215
|
|
|
216
|
+
def _rollback_after_error(
|
|
217
|
+
exc: BaseException, *, project: str, created_ids: list[int],
|
|
218
|
+
on_progress: Callable[[str], None] | None,
|
|
219
|
+
) -> None:
|
|
220
|
+
"""Roll back `created_ids` after an error `write()` did not anticipate, without ever
|
|
221
|
+
replacing `exc` (the caller re-raises it): a rollback that itself fails is reported through
|
|
222
|
+
`on_progress` and attached to `exc` as a note naming every record id still live, so the
|
|
223
|
+
manual cleanup the failure implies is not a hunt."""
|
|
224
|
+
if not created_ids:
|
|
225
|
+
return
|
|
226
|
+
try:
|
|
227
|
+
failures = _rollback(project=project, created_ids=created_ids)
|
|
228
|
+
except Exception as rollback_exc:
|
|
229
|
+
note = (
|
|
230
|
+
f"rollback of {len(created_ids)} inserted row(s) aborted: {rollback_exc!r} - rows "
|
|
231
|
+
f"from this run may still be live; record ids: {created_ids}"
|
|
232
|
+
)
|
|
233
|
+
exc.add_note(note)
|
|
234
|
+
_emit(on_progress, note)
|
|
235
|
+
return
|
|
236
|
+
rolled_back = len(created_ids) - len(failures)
|
|
237
|
+
_emit(
|
|
238
|
+
on_progress,
|
|
239
|
+
f"Unexpected {type(exc).__name__} - rolled back {rolled_back} of "
|
|
240
|
+
f"{len(created_ids)} inserted row(s)",
|
|
241
|
+
)
|
|
242
|
+
if failures:
|
|
243
|
+
exc.add_note("rows from this run still live:\n" + "\n".join(failures))
|
|
244
|
+
for failure in failures:
|
|
245
|
+
_emit(on_progress, f" {failure}")
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _recover_from_failed_cutover(
|
|
249
|
+
exc: BaseException, *, project: str, m: Manifest, proposal_path: Path,
|
|
250
|
+
written_entries: list[ManifestEntry], archived: list[ManifestEntry],
|
|
251
|
+
entry_rows: dict[str, list[tuple[int, ImportRow]]],
|
|
252
|
+
on_progress: Callable[[str], None] | None,
|
|
253
|
+
) -> None:
|
|
254
|
+
"""Cutover failed part-way. An entry whose source was already moved into the archive is cut
|
|
255
|
+
over: its rows are its live copy, so they stay and the entry is marked migrated (a rerun then
|
|
256
|
+
skips it). An entry still in place has its rows rolled back, so a rerun imports it once
|
|
257
|
+
rather than twice."""
|
|
258
|
+
if archived:
|
|
259
|
+
stamp = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
260
|
+
for entry in archived:
|
|
261
|
+
entry.migrated_at = stamp
|
|
262
|
+
try:
|
|
263
|
+
manifest.save(m, proposal_path)
|
|
264
|
+
except Exception as save_exc:
|
|
265
|
+
exc.add_note(
|
|
266
|
+
f"could not record {len(archived)} already cut-over entr(ies) as migrated in "
|
|
267
|
+
f"{proposal_path}: {save_exc!r}; mark these migrated by hand before re-running: "
|
|
268
|
+
f"{', '.join(e.path for e in archived)}"
|
|
269
|
+
)
|
|
270
|
+
archived_paths = {e.path for e in archived}
|
|
271
|
+
pending_ids = [
|
|
272
|
+
record_id
|
|
273
|
+
for entry in written_entries if entry.path not in archived_paths
|
|
274
|
+
for record_id, _ in entry_rows[entry.path]
|
|
275
|
+
]
|
|
276
|
+
_rollback_after_error(exc, project=project, created_ids=pending_ids, on_progress=on_progress)
|
|
277
|
+
|
|
278
|
+
|
|
216
279
|
def _check_db_not_locked(project: str) -> None:
|
|
217
280
|
"""Pre-flight concurrency guard (inter-session message 20260819T114156Z-3ec7,
|
|
218
281
|
gap #2): refuse to start --write if another connection already holds a write
|
|
@@ -432,105 +495,125 @@ def write(
|
|
|
432
495
|
db_owned = [e for e in m.entries if e.classification == "db-owned"]
|
|
433
496
|
already_migrated = [e for e in db_owned if e.migrated_at is not None]
|
|
434
497
|
to_import = [e for e in db_owned if e.migrated_at is None]
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
498
|
+
# Everything from the first insert through the backup either returns a WriteResult
|
|
499
|
+
# (rolling back by hand) or, for any exception this code did not anticipate, rolls the
|
|
500
|
+
# inserted rows back here before re-raising - never leaves them live with the manifest
|
|
501
|
+
# unmarked and cutover unrun.
|
|
502
|
+
try:
|
|
503
|
+
_emit(on_progress, f"Importing {len(to_import)} file(s)...")
|
|
504
|
+
if already_migrated:
|
|
505
|
+
_emit(
|
|
506
|
+
on_progress,
|
|
507
|
+
f" skipping {len(already_migrated)} already-migrated file(s): "
|
|
508
|
+
f"{', '.join(e.path for e in already_migrated)}",
|
|
509
|
+
)
|
|
510
|
+
for entry in to_import:
|
|
511
|
+
try:
|
|
512
|
+
source_path = project_root / entry.path
|
|
513
|
+
if not source_path.exists():
|
|
514
|
+
# entry.migrated_at is None here (to_import excludes already-migrated
|
|
515
|
+
# entries above), so this is not the ordinary "already cut over by an
|
|
516
|
+
# earlier --write" case — the source is genuinely missing for an entry
|
|
517
|
+
# this run believes still needs importing. Fail with a specific,
|
|
518
|
+
# actionable message (still caught by this loop's own except clause
|
|
519
|
+
# below, so it contributes to `reasons`/rollback exactly like any other
|
|
520
|
+
# per-entry import failure) instead of a bare FileNotFoundError only
|
|
521
|
+
# discoverable via the rollback reasons list.
|
|
522
|
+
raise ValueError(
|
|
523
|
+
f"{entry.path}: marked db-owned with no migrated_at, but its source "
|
|
524
|
+
f"file does not exist at {source_path} — if this entry was already "
|
|
525
|
+
f"migrated by another means, set its classification to folder-owned "
|
|
526
|
+
f"(or otherwise correct the manifest) before running --write again"
|
|
527
|
+
)
|
|
528
|
+
_emit(on_progress, f" importing {entry.path} -> group={entry.db_group()}...")
|
|
529
|
+
for spec in entry.fields:
|
|
530
|
+
service.schema_add_field(
|
|
531
|
+
project=project, record_group=entry.db_group(),
|
|
532
|
+
field_name=spec.name, sql_type=spec.sql_type,
|
|
533
|
+
description=spec.description, default=spec.default,
|
|
534
|
+
)
|
|
535
|
+
rows_for_entry: list[tuple[int, ImportRow]] = []
|
|
536
|
+
for row in import_entry(project_root, entry):
|
|
537
|
+
record = service.add_record(
|
|
538
|
+
project=project, record_group=entry.db_group(),
|
|
539
|
+
content=row.content, file_path=row.file_path,
|
|
540
|
+
fields=row.fields, created_at=row.created_at,
|
|
541
|
+
)
|
|
542
|
+
created_ids.append(record.id)
|
|
543
|
+
rows_for_entry.append((record.id, row))
|
|
544
|
+
entry_rows[entry.path] = rows_for_entry
|
|
545
|
+
_emit(on_progress, f" {len(rows_for_entry)} row(s) imported")
|
|
546
|
+
written_entries.append(entry)
|
|
547
|
+
except (ValueError, OSError, csv.Error) as exc:
|
|
548
|
+
reasons.append(f"{entry.path}: {exc}")
|
|
549
|
+
|
|
550
|
+
_emit(on_progress, "Verifying imported rows...")
|
|
551
|
+
reasons.extend(
|
|
552
|
+
_verify(project=project, project_root=project_root,
|
|
553
|
+
written_entries=written_entries, entry_rows=entry_rows)
|
|
441
554
|
)
|
|
442
|
-
for entry in to_import:
|
|
443
|
-
try:
|
|
444
|
-
source_path = project_root / entry.path
|
|
445
|
-
if not source_path.exists():
|
|
446
|
-
# entry.migrated_at is None here (to_import excludes already-migrated
|
|
447
|
-
# entries above), so this is not the ordinary "already cut over by an
|
|
448
|
-
# earlier --write" case — the source is genuinely missing for an entry
|
|
449
|
-
# this run believes still needs importing. Fail with a specific,
|
|
450
|
-
# actionable message (still caught by this loop's own except clause
|
|
451
|
-
# below, so it contributes to `reasons`/rollback exactly like any other
|
|
452
|
-
# per-entry import failure) instead of a bare FileNotFoundError only
|
|
453
|
-
# discoverable via the rollback reasons list.
|
|
454
|
-
raise ValueError(
|
|
455
|
-
f"{entry.path}: marked db-owned with no migrated_at, but its source "
|
|
456
|
-
f"file does not exist at {source_path} — if this entry was already "
|
|
457
|
-
f"migrated by another means, set its classification to folder-owned "
|
|
458
|
-
f"(or otherwise correct the manifest) before running --write again"
|
|
459
|
-
)
|
|
460
|
-
_emit(on_progress, f" importing {entry.path} -> group={entry.db_group()}...")
|
|
461
|
-
for spec in entry.fields:
|
|
462
|
-
service.schema_add_field(
|
|
463
|
-
project=project, record_group=entry.db_group(),
|
|
464
|
-
field_name=spec.name, sql_type=spec.sql_type,
|
|
465
|
-
description=spec.description, default=spec.default,
|
|
466
|
-
)
|
|
467
|
-
rows_for_entry: list[tuple[int, ImportRow]] = []
|
|
468
|
-
for row in import_entry(project_root, entry):
|
|
469
|
-
record = service.add_record(
|
|
470
|
-
project=project, record_group=entry.db_group(),
|
|
471
|
-
content=row.content, file_path=row.file_path,
|
|
472
|
-
fields=row.fields, created_at=row.created_at,
|
|
473
|
-
)
|
|
474
|
-
created_ids.append(record.id)
|
|
475
|
-
rows_for_entry.append((record.id, row))
|
|
476
|
-
entry_rows[entry.path] = rows_for_entry
|
|
477
|
-
_emit(on_progress, f" {len(rows_for_entry)} row(s) imported")
|
|
478
|
-
written_entries.append(entry)
|
|
479
|
-
except (ValueError, OSError, csv.Error) as exc:
|
|
480
|
-
reasons.append(f"{entry.path}: {exc}")
|
|
481
|
-
|
|
482
|
-
_emit(on_progress, "Verifying imported rows...")
|
|
483
|
-
reasons.extend(
|
|
484
|
-
_verify(project=project, project_root=project_root,
|
|
485
|
-
written_entries=written_entries, entry_rows=entry_rows)
|
|
486
|
-
)
|
|
487
555
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
556
|
+
if reasons:
|
|
557
|
+
_emit(on_progress, "Verification failed — rolling back inserted rows...")
|
|
558
|
+
return WriteResult(
|
|
559
|
+
created_record_ids=[], entries_written=[], backup_path=None,
|
|
560
|
+
failure=WriteFailure(
|
|
561
|
+
reasons=reasons + _rollback(project=project, created_ids=created_ids)
|
|
562
|
+
),
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
# Still inside both overrides: a rehearsed run's backup must land in the
|
|
566
|
+
# rehearsal sandbox (backup_dir_override), never in the real backup dir.
|
|
567
|
+
_emit(on_progress, "Backing up project and database before cutover...")
|
|
568
|
+
try:
|
|
569
|
+
backup_path = backup.create_backup(
|
|
570
|
+
project=project, project_root=project_root, on_progress=on_progress,
|
|
571
|
+
)
|
|
572
|
+
_emit(on_progress, f"Backup written: {backup_path}")
|
|
573
|
+
except backup.BackupError as exc:
|
|
574
|
+
_emit(on_progress, "Backup failed — rolling back inserted rows...")
|
|
575
|
+
return WriteResult(
|
|
576
|
+
created_record_ids=[], entries_written=[], backup_path=None,
|
|
577
|
+
failure=WriteFailure(
|
|
578
|
+
reasons=[str(exc)] + _rollback(project=project, created_ids=created_ids)
|
|
579
|
+
),
|
|
580
|
+
)
|
|
581
|
+
except BaseException as exc:
|
|
582
|
+
_rollback_after_error(
|
|
583
|
+
exc, project=project, created_ids=created_ids, on_progress=on_progress,
|
|
495
584
|
)
|
|
585
|
+
raise
|
|
496
586
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
_emit(on_progress, "Backing up project and database before cutover...")
|
|
587
|
+
_emit(on_progress, f"Cutting over {len(written_entries)} file(s)...")
|
|
588
|
+
archived: list[ManifestEntry] = []
|
|
500
589
|
try:
|
|
501
|
-
|
|
502
|
-
|
|
590
|
+
cutover.archive_entries(
|
|
591
|
+
project_root=project_root, entries=written_entries, project=project,
|
|
592
|
+
write_pointer_files=not leave_no_pointer_files, on_archived=archived.append,
|
|
503
593
|
)
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
594
|
+
# Mark every entry this run actually cut over as migrated, and persist that back to
|
|
595
|
+
# the manifest — write() only ever `manifest.load`s otherwise, so without this a
|
|
596
|
+
# later --write would re-attempt (and, pre-fix, roll back) these same now-archived
|
|
597
|
+
# entries. written_entries holds the same ManifestEntry objects m.entries does (see
|
|
598
|
+
# the `to_import`/`written_entries.append(entry)` loop above), so mutating here
|
|
599
|
+
# mutates m.
|
|
600
|
+
migrated_at = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
601
|
+
for entry in written_entries:
|
|
602
|
+
entry.migrated_at = migrated_at
|
|
603
|
+
manifest.save(m, proposal_path)
|
|
604
|
+
except BaseException as exc:
|
|
605
|
+
_recover_from_failed_cutover(
|
|
606
|
+
exc, project=project, m=m, proposal_path=proposal_path,
|
|
607
|
+
written_entries=written_entries, archived=archived, entry_rows=entry_rows,
|
|
608
|
+
on_progress=on_progress,
|
|
512
609
|
)
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
# the manifest — write() only ever `manifest.load`s otherwise, so without this a later
|
|
521
|
-
# --write would re-attempt (and, pre-fix, roll back) these same now-archived entries.
|
|
522
|
-
# written_entries holds the same ManifestEntry objects m.entries does (see the
|
|
523
|
-
# `to_import`/`written_entries.append(entry)` loop above), so mutating here mutates m.
|
|
524
|
-
migrated_at = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
525
|
-
for entry in written_entries:
|
|
526
|
-
entry.migrated_at = migrated_at
|
|
527
|
-
manifest.save(m, proposal_path)
|
|
528
|
-
return WriteResult(
|
|
529
|
-
created_record_ids=created_ids,
|
|
530
|
-
entries_written=[e.path for e in written_entries],
|
|
531
|
-
backup_path=backup_path, failure=None,
|
|
532
|
-
report=_render_diff_report(written_entries=written_entries, entry_rows=entry_rows),
|
|
533
|
-
)
|
|
610
|
+
raise
|
|
611
|
+
return WriteResult(
|
|
612
|
+
created_record_ids=created_ids,
|
|
613
|
+
entries_written=[e.path for e in written_entries],
|
|
614
|
+
backup_path=backup_path, failure=None,
|
|
615
|
+
report=_render_diff_report(written_entries=written_entries, entry_rows=entry_rows),
|
|
616
|
+
)
|
|
534
617
|
|
|
535
618
|
|
|
536
619
|
def _verify(
|
|
@@ -544,12 +627,18 @@ def _verify(
|
|
|
544
627
|
reasons: list[str] = []
|
|
545
628
|
for entry in written_entries:
|
|
546
629
|
rows = entry_rows[entry.path]
|
|
547
|
-
|
|
548
|
-
|
|
630
|
+
try:
|
|
631
|
+
expected_count = count_source_rows(project_root, entry)
|
|
632
|
+
except (ValueError, OSError, csv.Error) as exc:
|
|
549
633
|
reasons.append(
|
|
550
|
-
f"{entry.path}:
|
|
551
|
-
f"gives {expected_count} — entry-count parity check failed"
|
|
634
|
+
f"{entry.path}: could not re-count the source rows for the parity check: {exc}"
|
|
552
635
|
)
|
|
636
|
+
else:
|
|
637
|
+
if len(rows) != expected_count:
|
|
638
|
+
reasons.append(
|
|
639
|
+
f"{entry.path}: imported {len(rows)} row(s) but re-counting the source "
|
|
640
|
+
f"gives {expected_count} — entry-count parity check failed"
|
|
641
|
+
)
|
|
553
642
|
for record_id, import_row in rows:
|
|
554
643
|
record = service.get_record(project=project, record_id=record_id)
|
|
555
644
|
assert record is not None, (
|
|
@@ -562,7 +651,17 @@ def _verify(
|
|
|
562
651
|
)
|
|
563
652
|
if record.file_path:
|
|
564
653
|
target = project_root / record.file_path
|
|
565
|
-
|
|
654
|
+
try:
|
|
655
|
+
resolves = target.exists()
|
|
656
|
+
except OSError as exc:
|
|
657
|
+
# A string the OS rejects outright (e.g. "File name too long") raises
|
|
658
|
+
# instead of returning False; it is the same "does not resolve" outcome.
|
|
659
|
+
reasons.append(
|
|
660
|
+
f"{entry.path}: record {record_id} file_path "
|
|
661
|
+
f"{record.file_path!r} cannot be checked under {project_root}: {exc}"
|
|
662
|
+
)
|
|
663
|
+
continue
|
|
664
|
+
if not resolves:
|
|
566
665
|
reasons.append(
|
|
567
666
|
f"{entry.path}: record {record_id} file_path "
|
|
568
667
|
f"{record.file_path!r} does not resolve under {project_root}"
|
|
@@ -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:
|
cc_session_tools-3.10.1/src/cc_session_tools/skills/pm-pdata-do-update-consuming-skills/SKILL.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pm-pdata-do-update-consuming-skills
|
|
3
|
+
description: Use after `ccst pdata init --write` has migrated a ~/cc/<project>'s flat files into its pdata store - finds Claude Code skills under ~/.claude/skills/ that literally reference the project's old flat-file paths, rewrites direct reads/writes to the equivalent `ccst pdata` commands, and flags anything that cannot be rewritten mechanically for a human decision. Matches by literal path only. Triggers - "update the skills that read the old <project> files", "fix skills that use the old paths after the pdata migration", "/pm-pdata-do-update-consuming-skills"; also run automatically as a step of pm-pdata-do-init. Do NOT use for the project's own docs (pm-pdata-do-update-project-docs) or the migration itself (pm-pdata-do-init).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# pm-pdata-do-update-consuming-skills
|
|
7
|
+
|
|
8
|
+
Finds skills that read or write a project's old flat-file paths directly and switches them to the
|
|
9
|
+
equivalent `ccst pdata` command. Run it after `ccst pdata init --write` has cut a project's data
|
|
10
|
+
over.
|
|
11
|
+
|
|
12
|
+
## Run this in a fresh context
|
|
13
|
+
|
|
14
|
+
Run this skill in a fresh context, not inline in the session that just ran `ccst pdata init
|
|
15
|
+
--write`. The point of a fresh read is that it cannot rationalize away a stale reference it
|
|
16
|
+
half-remembers writing earlier in the same conversation. Either is acceptable:
|
|
17
|
+
|
|
18
|
+
- An orchestrating session dispatches it as an `Agent` subagent. The Agent tool cannot set a cwd,
|
|
19
|
+
so the subagent's prompt must begin by changing into the project root (`cd ~/cc/<project>`).
|
|
20
|
+
- A new Claude Code session started in `~/cc/<project>`.
|
|
21
|
+
|
|
22
|
+
Running it inline in the migrating session is not acceptable.
|
|
23
|
+
|
|
24
|
+
## Step 1 - Verify project context
|
|
25
|
+
|
|
26
|
+
Check the cwd is a `~/cc/<project>` project directory with a `CLAUDE.md`:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
pwd && basename "$(pwd)" && ls CLAUDE.md 2>/dev/null && echo "project CLAUDE.md confirmed"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If `CLAUDE.md` is present, the `basename` output is the project name to search for in Step 2. If
|
|
33
|
+
not, print the following and stop:
|
|
34
|
+
|
|
35
|
+
> ERROR: This skill must be run from a `~/cc/<project>` directory containing a `CLAUDE.md`.
|
|
36
|
+
> Aborting without touching any skills.
|
|
37
|
+
|
|
38
|
+
## Step 2 - Find every skill referencing this project's old flat-file paths
|
|
39
|
+
|
|
40
|
+
Search every skill's `SKILL.md` and any scripts under its directory for literal mentions of this
|
|
41
|
+
project's pre-migration paths:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
grep -rl "~/cc/<project>/<old-path>" ~/.claude/skills/*/ 2>/dev/null
|
|
45
|
+
grep -rl "cc/<project>/<old-path>" ~/.claude/skills/*/ 2>/dev/null # relative-path equivalents
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Substitute the project's actual name and the pre-migration path(s) from the project's
|
|
49
|
+
`ccst-pdata-init-write.log`, or from the classification report `ccst pdata init` produced. If
|
|
50
|
+
neither is available, check `<project-root>/.pdata-migrated/`: the migration archives the
|
|
51
|
+
original pre-cutover files there, unchanged, under their original relative paths. For example, a
|
|
52
|
+
project `home` that migrated its Tesco order history would search for `~/cc/home/data/tesco/*.csv`
|
|
53
|
+
or `home/data/tesco` across every skill's `SKILL.md` and scripts.
|
|
54
|
+
|
|
55
|
+
Match by literal path only. Do not widen the search to skills whose name merely sounds related to
|
|
56
|
+
the project or its domain: a skill named `do-tesco-shop` is not evidence on its own that it
|
|
57
|
+
touches this project's files. Only a literal path match is.
|
|
58
|
+
|
|
59
|
+
If Step 2 finds no matches at all, say so in the report and stop. There is nothing to do.
|
|
60
|
+
|
|
61
|
+
## Step 3 - Classify each match
|
|
62
|
+
|
|
63
|
+
For each skill with a literal path match, read the matching lines and enough surrounding
|
|
64
|
+
code or prose to be sure which category applies. Do not guess from the skill's name or its
|
|
65
|
+
one-line description.
|
|
66
|
+
|
|
67
|
+
- **Direct read/write** - the skill's script (or its documented instructions) opens, parses,
|
|
68
|
+
appends to, or otherwise operates on the file at that path as part of normal execution. This
|
|
69
|
+
needs rewriting.
|
|
70
|
+
- **Passing mention** - the path appears only in prose (an example, a comment about history, a
|
|
71
|
+
reference to "where this used to live") and no code path touches the file. This may not need
|
|
72
|
+
changing; leave it alone.
|
|
73
|
+
|
|
74
|
+
## Step 4 - Rewrite direct read/write matches
|
|
75
|
+
|
|
76
|
+
For each direct read/write, rewrite the file I/O to use the equivalent `ccst pdata` command:
|
|
77
|
+
|
|
78
|
+
- Reading to list or browse records: `ccst pdata list --project <name> --group <record_group>
|
|
79
|
+
[--format json]`.
|
|
80
|
+
- Reading one record: `ccst pdata get --project <name> --id <id>`.
|
|
81
|
+
- Filtering or searching: `ccst pdata query --project <name> --group <record_group> --where
|
|
82
|
+
'<field> <op> <value>'`.
|
|
83
|
+
- Appending a record: `ccst pdata add` (check `ccst pdata add --help` for the record shape the
|
|
84
|
+
target record_group expects).
|
|
85
|
+
- Editing a record: `ccst pdata update` (version-checked; check `ccst pdata update --help`).
|
|
86
|
+
|
|
87
|
+
Keep the rewrite mechanical and narrow: change the I/O call to go through `ccst pdata`, and do not
|
|
88
|
+
otherwise restructure the skill's logic or prose beyond what reflects the new access path. If the
|
|
89
|
+
skill's script parsed CSV columns or JSON keys directly, map them to the pdata record fields using
|
|
90
|
+
`ccst pdata schema show --project <name> --group <record_group>` (it lists the group's registered
|
|
91
|
+
extension fields) rather than guessing field names.
|
|
92
|
+
|
|
93
|
+
Do not touch skills unrelated to this project. A match that on closer reading references a
|
|
94
|
+
different project's similarly-named folder is not this skill's concern - skip it.
|
|
95
|
+
|
|
96
|
+
## Step 5 - Flag anything unsafe to rewrite mechanically
|
|
97
|
+
|
|
98
|
+
Some direct matches do more than read a file or append a row: custom locking, multi-file
|
|
99
|
+
transactions, format transformations that do not map onto one `ccst pdata` command, or logic that
|
|
100
|
+
depends on file-level properties (mtime, file size, row order) that pdata does not expose the same
|
|
101
|
+
way.
|
|
102
|
+
|
|
103
|
+
Do not attempt to rewrite these. List each in the report as needing a human decision, with enough
|
|
104
|
+
detail (skill name, file, what it does, why it does not map cleanly) for the user to decide.
|
|
105
|
+
Silently skipping a match is not acceptable: every match found in Step 2 must appear in the
|
|
106
|
+
report as "updated", "left alone (passing mention only)", or "needs a human decision".
|
|
107
|
+
|
|
108
|
+
## Step 6 - Report
|
|
109
|
+
|
|
110
|
+
Summarise for the user:
|
|
111
|
+
|
|
112
|
+
1. Which skills had a literal path match (Step 2).
|
|
113
|
+
2. For each, its category (Step 3) and outcome: updated, left alone, or needs a human decision.
|
|
114
|
+
3. If there were no matches at all, say so plainly. That is a valid and complete outcome.
|