claude-code-pilot 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/install.js +267 -250
- package/manifest.json +5 -18
- package/package.json +5 -7
- package/src/agents/build-error-resolver.md +114 -0
- package/src/agents/ccp-advisor-researcher.md +104 -0
- package/src/agents/ccp-assumptions-analyzer.md +105 -0
- package/{gsd/agents/gsd-codebase-mapper.md → src/agents/ccp-codebase-mapper.md} +7 -7
- package/{gsd/agents/gsd-debugger.md → src/agents/ccp-debugger.md} +125 -8
- package/{gsd/agents/gsd-executor.md → src/agents/ccp-executor.md} +31 -20
- package/{gsd/agents/gsd-integration-checker.md → src/agents/ccp-integration-checker.md} +2 -2
- package/{gsd/agents/gsd-nyquist-auditor.md → src/agents/ccp-nyquist-auditor.md} +3 -3
- package/{gsd/agents/gsd-phase-researcher.md → src/agents/ccp-phase-researcher.md} +127 -13
- package/{gsd/agents/gsd-plan-checker.md → src/agents/ccp-plan-checker.md} +57 -21
- package/{gsd/agents/gsd-planner.md → src/agents/ccp-planner.md} +61 -23
- package/{gsd/agents/gsd-project-researcher.md → src/agents/ccp-project-researcher.md} +33 -6
- package/{gsd/agents/gsd-research-synthesizer.md → src/agents/ccp-research-synthesizer.md} +11 -11
- package/{gsd/agents/gsd-roadmapper.md → src/agents/ccp-roadmapper.md} +39 -10
- package/src/agents/ccp-ui-auditor.md +439 -0
- package/src/agents/ccp-ui-checker.md +300 -0
- package/src/agents/ccp-ui-researcher.md +357 -0
- package/{gsd/agents/gsd-verifier.md → src/agents/ccp-verifier.md} +81 -15
- package/src/agents/cpp-build-resolver.md +90 -0
- package/src/agents/cpp-reviewer.md +72 -0
- package/src/agents/database-reviewer.md +91 -0
- package/src/agents/docs-lookup.md +68 -0
- package/src/agents/flutter-reviewer.md +243 -0
- package/src/agents/go-build-resolver.md +94 -0
- package/src/agents/go-reviewer.md +76 -0
- package/src/agents/java-build-resolver.md +153 -0
- package/src/agents/java-reviewer.md +92 -0
- package/src/agents/kotlin-build-resolver.md +118 -0
- package/src/agents/kotlin-reviewer.md +159 -0
- package/src/agents/planner.md +212 -0
- package/src/agents/python-reviewer.md +98 -0
- package/src/agents/pytorch-build-resolver.md +120 -0
- package/src/agents/refactor-cleaner.md +85 -0
- package/src/agents/rust-build-resolver.md +148 -0
- package/src/agents/rust-reviewer.md +94 -0
- package/src/agents/typescript-reviewer.md +112 -0
- package/src/available-rules/README.md +80 -0
- package/src/available-rules/cpp/coding-style.md +44 -0
- package/src/available-rules/cpp/hooks.md +39 -0
- package/src/available-rules/cpp/patterns.md +51 -0
- package/src/available-rules/cpp/security.md +51 -0
- package/src/available-rules/cpp/testing.md +44 -0
- package/src/available-rules/csharp/coding-style.md +72 -0
- package/src/available-rules/csharp/hooks.md +25 -0
- package/src/available-rules/csharp/patterns.md +50 -0
- package/src/available-rules/csharp/security.md +58 -0
- package/src/available-rules/csharp/testing.md +46 -0
- package/src/available-rules/java/coding-style.md +114 -0
- package/src/available-rules/java/hooks.md +18 -0
- package/src/available-rules/java/patterns.md +146 -0
- package/src/available-rules/java/security.md +100 -0
- package/src/available-rules/java/testing.md +131 -0
- package/src/available-rules/kotlin/hooks.md +17 -0
- package/src/available-rules/rust/coding-style.md +151 -0
- package/src/available-rules/rust/hooks.md +16 -0
- package/src/available-rules/rust/patterns.md +168 -0
- package/src/available-rules/rust/security.md +141 -0
- package/src/available-rules/rust/testing.md +154 -0
- package/src/commands/aside.md +164 -0
- package/src/commands/build-fix.md +62 -0
- package/src/commands/ccp/add-backlog.md +76 -0
- package/{gsd/commands-gsd → src/commands/ccp}/add-phase.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/add-tests.md +5 -5
- package/{gsd/commands-gsd → src/commands/ccp}/add-todo.md +4 -4
- package/{gsd/commands-gsd → src/commands/ccp}/audit-milestone.md +3 -3
- package/src/commands/ccp/audit-uat.md +24 -0
- package/src/commands/ccp/autonomous.md +41 -0
- package/{gsd/commands-gsd → src/commands/ccp}/check-todos.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/cleanup.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/complete-milestone.md +9 -9
- package/{gsd/commands-gsd → src/commands/ccp}/debug.md +14 -9
- package/src/commands/ccp/discuss-phase.md +64 -0
- package/src/commands/ccp/do.md +30 -0
- package/src/commands/ccp/execute-phase.md +59 -0
- package/src/commands/ccp/fast.md +30 -0
- package/src/commands/ccp/forensics.md +56 -0
- package/{gsd/commands-gsd → src/commands/ccp}/health.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/help.md +5 -5
- package/{gsd/commands-gsd → src/commands/ccp}/insert-phase.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/list-phase-assumptions.md +2 -2
- package/src/commands/ccp/manager.md +39 -0
- package/{gsd/commands-gsd → src/commands/ccp}/map-codebase.md +7 -7
- package/src/commands/ccp/milestone-summary.md +51 -0
- package/{gsd/commands-gsd → src/commands/ccp}/new-milestone.md +8 -8
- package/{gsd/commands-gsd → src/commands/ccp}/new-project.md +8 -8
- package/src/commands/ccp/next.md +24 -0
- package/src/commands/ccp/note.md +34 -0
- package/{gsd/commands-gsd → src/commands/ccp}/pause-work.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/plan-milestone-gaps.md +5 -5
- package/{gsd/commands-gsd → src/commands/ccp}/plan-phase.md +9 -7
- package/src/commands/ccp/plant-seed.md +28 -0
- package/src/commands/ccp/pr-branch.md +25 -0
- package/{gsd/commands-gsd → src/commands/ccp}/progress.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/quick.md +10 -8
- package/{gsd/commands-gsd → src/commands/ccp}/remove-phase.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/research-phase.md +17 -12
- package/{gsd/commands-gsd → src/commands/ccp}/resume-work.md +3 -3
- package/src/commands/ccp/review-backlog.md +61 -0
- package/src/commands/ccp/session-report.md +19 -0
- package/src/commands/ccp/set-profile.md +12 -0
- package/{gsd/commands-gsd → src/commands/ccp}/settings.md +5 -5
- package/src/commands/ccp/ship.md +23 -0
- package/src/commands/ccp/stats.md +18 -0
- package/src/commands/ccp/thread.md +127 -0
- package/src/commands/ccp/ui-phase.md +34 -0
- package/src/commands/ccp/ui-review.md +32 -0
- package/{gsd/commands-gsd → src/commands/ccp}/update.md +5 -5
- package/{gsd/commands-gsd → src/commands/ccp}/validate-phase.md +3 -3
- package/{gsd/commands-gsd → src/commands/ccp}/verify-work.md +5 -5
- package/src/commands/code-review.md +40 -0
- package/src/commands/context-budget.md +29 -0
- package/src/commands/cpp-build.md +173 -0
- package/src/commands/cpp-review.md +132 -0
- package/src/commands/cpp-test.md +251 -0
- package/src/commands/docs.md +31 -0
- package/src/commands/e2e.md +364 -0
- package/src/commands/eval.md +120 -0
- package/{ecc → src}/commands/evolve.md +2 -2
- package/src/commands/go-build.md +183 -0
- package/src/commands/go-review.md +148 -0
- package/src/commands/go-test.md +268 -0
- package/src/commands/gradle-build.md +70 -0
- package/src/commands/harness-audit.md +71 -0
- package/src/commands/kotlin-build.md +174 -0
- package/src/commands/kotlin-review.md +140 -0
- package/src/commands/kotlin-test.md +312 -0
- package/src/commands/orchestrate.md +231 -0
- package/src/commands/plan.md +114 -0
- package/src/commands/prompt-optimize.md +38 -0
- package/src/commands/prune.md +25 -0
- package/src/commands/python-review.md +297 -0
- package/{ecc → src}/commands/quality-gate.md +1 -1
- package/src/commands/refactor-clean.md +80 -0
- package/src/commands/rules-distill.md +11 -0
- package/src/commands/rust-build.md +187 -0
- package/src/commands/rust-review.md +142 -0
- package/src/commands/rust-test.md +308 -0
- package/{ecc → src}/commands/sessions.md +10 -10
- package/src/commands/setup-pm.md +80 -0
- package/{kit → src}/commands/setup.md +45 -19
- package/src/commands/skill-create.md +172 -0
- package/src/commands/skill-health.md +51 -0
- package/src/commands/tdd.md +328 -0
- package/src/commands/test-coverage.md +69 -0
- package/src/commands/update-codemaps.md +72 -0
- package/src/commands/update-docs.md +84 -0
- package/{gsd/hooks/gsd-context-monitor.js → src/hooks/ccp-context-monitor.js} +3 -3
- package/src/hooks/ccp-prompt-guard.js +96 -0
- package/{gsd/hooks/gsd-statusline.js → src/hooks/ccp-statusline.js} +7 -7
- package/src/hooks/ccp-workflow-guard.js +94 -0
- package/src/hooks/config-protection.js +141 -0
- package/{kit → src}/hooks/kit-check-update.js +7 -4
- package/src/hooks/mcp-health-check.js +620 -0
- package/{ecc/scripts → src}/hooks/run-with-flags-shell.sh +1 -1
- package/{ecc/scripts → src}/hooks/run-with-flags.js +74 -13
- package/src/hooks/session-end-marker.js +29 -0
- package/{ecc/scripts → src}/hooks/session-end.js +83 -40
- package/{ecc/scripts → src}/hooks/session-start.js +75 -9
- package/{ecc/scripts → src}/lib/hook-flags.js +8 -4
- package/{ecc/scripts → src}/lib/project-detect.js +2 -1
- package/{ecc/scripts → src}/lib/session-manager.d.ts +5 -1
- package/{ecc/scripts → src}/lib/session-manager.js +202 -92
- package/{ecc/scripts → src}/lib/utils.d.ts +23 -1
- package/{ecc/scripts → src}/lib/utils.js +91 -3
- package/{gsd/get-shit-done/bin/gsd-tools.cjs → src/pilot/bin/ccp-tools.cjs} +257 -86
- package/{gsd/get-shit-done → src/pilot}/bin/lib/commands.cjs +1 -1
- package/src/pilot/bin/lib/config.cjs +444 -0
- package/src/pilot/bin/lib/core.cjs +1190 -0
- package/src/pilot/bin/lib/init.cjs +1281 -0
- package/src/pilot/bin/lib/model-profiles.cjs +67 -0
- package/{gsd/get-shit-done → src/pilot}/bin/lib/phase.cjs +2 -2
- package/src/pilot/bin/lib/security.cjs +382 -0
- package/{gsd/get-shit-done → src/pilot}/bin/lib/state.cjs +1 -1
- package/src/pilot/bin/lib/uat.cjs +282 -0
- package/{gsd/get-shit-done → src/pilot}/bin/lib/verify.cjs +10 -10
- package/{gsd/get-shit-done → src/pilot}/references/continuation-format.md +16 -16
- package/{gsd/get-shit-done → src/pilot}/references/decimal-phase-calculation.md +5 -5
- package/{gsd/get-shit-done → src/pilot}/references/git-integration.md +5 -5
- package/{gsd/get-shit-done → src/pilot}/references/git-planning-commit.md +4 -4
- package/src/pilot/references/mcp-servers.json +153 -0
- package/{gsd/get-shit-done → src/pilot}/references/model-profile-resolution.md +2 -2
- package/{gsd/get-shit-done → src/pilot}/references/model-profiles.md +20 -20
- package/{gsd/get-shit-done → src/pilot}/references/phase-argument-parsing.md +4 -4
- package/{gsd/get-shit-done → src/pilot}/references/planning-config.md +15 -15
- package/{gsd/get-shit-done → src/pilot}/references/ui-brand.md +5 -5
- package/{gsd/get-shit-done → src/pilot}/references/verification-patterns.md +1 -1
- package/{gsd/get-shit-done → src/pilot}/templates/DEBUG.md +1 -1
- package/{gsd/get-shit-done → src/pilot}/templates/UAT.md +3 -3
- package/src/pilot/templates/UI-SPEC.md +100 -0
- package/{gsd/get-shit-done → src/pilot}/templates/VALIDATION.md +1 -1
- package/src/pilot/templates/claude-md.md +122 -0
- package/{gsd/get-shit-done → src/pilot}/templates/codebase/architecture.md +2 -2
- package/{gsd/get-shit-done → src/pilot}/templates/codebase/structure.md +13 -13
- package/{gsd/get-shit-done → src/pilot}/templates/context.md +4 -4
- package/src/pilot/templates/copilot-instructions.md +7 -0
- package/{gsd/get-shit-done → src/pilot}/templates/debug-subagent-prompt.md +4 -4
- package/src/pilot/templates/dev-preferences.md +21 -0
- package/{gsd/get-shit-done → src/pilot}/templates/discovery.md +2 -2
- package/src/pilot/templates/discussion-log.md +63 -0
- package/{gsd/get-shit-done → src/pilot}/templates/phase-prompt.md +12 -12
- package/{gsd/get-shit-done → src/pilot}/templates/planner-subagent-prompt.md +7 -7
- package/{gsd/get-shit-done → src/pilot}/templates/project.md +1 -1
- package/{gsd/get-shit-done → src/pilot}/templates/research.md +2 -2
- package/{gsd/get-shit-done → src/pilot}/templates/state.md +2 -2
- package/{gsd/get-shit-done → src/pilot}/templates/summary-complex.md +1 -1
- package/{gsd/get-shit-done → src/pilot}/workflows/add-phase.md +11 -11
- package/{gsd/get-shit-done → src/pilot}/workflows/add-tests.md +15 -15
- package/{gsd/get-shit-done → src/pilot}/workflows/add-todo.md +7 -7
- package/{gsd/get-shit-done → src/pilot}/workflows/audit-milestone.md +24 -16
- package/src/pilot/workflows/audit-uat.md +109 -0
- package/src/pilot/workflows/autonomous.md +891 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/check-todos.md +10 -10
- package/{gsd/get-shit-done → src/pilot}/workflows/cleanup.md +3 -3
- package/{gsd/get-shit-done → src/pilot}/workflows/complete-milestone.md +19 -16
- package/{gsd/get-shit-done → src/pilot}/workflows/diagnose-issues.md +9 -4
- package/{gsd/get-shit-done → src/pilot}/workflows/discovery-phase.md +8 -8
- package/src/pilot/workflows/discuss-phase-assumptions.md +653 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/discuss-phase.md +407 -49
- package/src/pilot/workflows/do.md +104 -0
- package/src/pilot/workflows/execute-phase.md +821 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/execute-plan.md +79 -28
- package/src/pilot/workflows/fast.md +105 -0
- package/src/pilot/workflows/forensics.md +265 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/health.md +34 -11
- package/src/pilot/workflows/help.md +775 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/insert-phase.md +10 -10
- package/{gsd/get-shit-done → src/pilot}/workflows/list-phase-assumptions.md +4 -4
- package/src/pilot/workflows/manager.md +362 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/map-codebase.md +27 -17
- package/src/pilot/workflows/milestone-summary.md +223 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/new-milestone.md +135 -33
- package/{gsd/get-shit-done → src/pilot}/workflows/new-project.md +152 -79
- package/src/pilot/workflows/next.md +97 -0
- package/src/pilot/workflows/node-repair.md +92 -0
- package/src/pilot/workflows/note.md +156 -0
- package/src/pilot/workflows/pause-work.md +177 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/plan-milestone-gaps.md +10 -11
- package/src/pilot/workflows/plan-phase.md +859 -0
- package/src/pilot/workflows/plant-seed.md +169 -0
- package/src/pilot/workflows/pr-branch.md +129 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/progress.md +95 -34
- package/{gsd/get-shit-done → src/pilot}/workflows/quick.md +33 -21
- package/{gsd/get-shit-done → src/pilot}/workflows/remove-phase.md +14 -14
- package/{gsd/get-shit-done → src/pilot}/workflows/research-phase.md +18 -10
- package/{gsd/get-shit-done → src/pilot}/workflows/resume-project.md +37 -18
- package/src/pilot/workflows/session-report.md +146 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/set-profile.md +7 -7
- package/{gsd/get-shit-done → src/pilot}/workflows/settings.md +75 -22
- package/src/pilot/workflows/ship.md +228 -0
- package/src/pilot/workflows/stats.md +60 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/transition.md +57 -17
- package/src/pilot/workflows/ui-phase.md +302 -0
- package/src/pilot/workflows/ui-review.md +165 -0
- package/{gsd/get-shit-done → src/pilot}/workflows/update.md +88 -58
- package/{gsd/get-shit-done → src/pilot}/workflows/validate-phase.md +24 -17
- package/{gsd/get-shit-done → src/pilot}/workflows/verify-phase.md +26 -15
- package/{gsd/get-shit-done → src/pilot}/workflows/verify-work.md +89 -37
- package/{ecc → src}/rules/common/agents.md +1 -0
- package/{ecc → src}/rules/common/coding-style.md +21 -0
- package/src/skills/agentic-engineering/SKILL.md +63 -0
- package/src/skills/ai-first-engineering/SKILL.md +51 -0
- package/src/skills/ai-regression-testing/SKILL.md +385 -0
- package/src/skills/api-design/SKILL.md +523 -0
- package/src/skills/architecture-decision-records/SKILL.md +179 -0
- package/src/skills/backend-patterns/SKILL.md +598 -0
- package/src/skills/benchmark/SKILL.md +87 -0
- package/src/skills/blueprint/SKILL.md +90 -0
- package/src/skills/browser-qa/SKILL.md +81 -0
- package/src/skills/claude-api/SKILL.md +337 -0
- package/src/skills/codebase-onboarding/SKILL.md +233 -0
- package/src/skills/coding-standards/SKILL.md +530 -0
- package/src/skills/context-budget/SKILL.md +135 -0
- package/{ecc → src}/skills/continuous-learning-v2/SKILL.md +2 -2
- package/{ecc → src}/skills/continuous-learning-v2/agents/observer-loop.sh +1 -1
- package/src/skills/cpp-coding-standards/SKILL.md +723 -0
- package/src/skills/cpp-testing/SKILL.md +324 -0
- package/src/skills/database-migrations/SKILL.md +429 -0
- package/src/skills/deep-research/SKILL.md +155 -0
- package/src/skills/deployment-patterns/SKILL.md +427 -0
- package/src/skills/django-patterns/SKILL.md +734 -0
- package/src/skills/django-security/SKILL.md +593 -0
- package/src/skills/django-tdd/SKILL.md +729 -0
- package/src/skills/django-verification/SKILL.md +469 -0
- package/src/skills/docker-patterns/SKILL.md +364 -0
- package/src/skills/documentation-lookup/SKILL.md +90 -0
- package/src/skills/e2e-testing/SKILL.md +326 -0
- package/src/skills/exa-search/SKILL.md +103 -0
- package/src/skills/frontend-patterns/SKILL.md +642 -0
- package/src/skills/golang-patterns/SKILL.md +674 -0
- package/src/skills/golang-testing/SKILL.md +720 -0
- package/src/skills/java-coding-standards/SKILL.md +147 -0
- package/src/skills/jpa-patterns/SKILL.md +151 -0
- package/src/skills/kotlin-coroutines-flows/SKILL.md +284 -0
- package/src/skills/kotlin-exposed-patterns/SKILL.md +719 -0
- package/src/skills/kotlin-ktor-patterns/SKILL.md +689 -0
- package/src/skills/kotlin-patterns/SKILL.md +711 -0
- package/src/skills/kotlin-testing/SKILL.md +824 -0
- package/src/skills/laravel-patterns/SKILL.md +415 -0
- package/src/skills/laravel-security/SKILL.md +285 -0
- package/src/skills/laravel-tdd/SKILL.md +283 -0
- package/src/skills/laravel-verification/SKILL.md +179 -0
- package/src/skills/mcp-server-patterns/SKILL.md +67 -0
- package/src/skills/perl-patterns/SKILL.md +504 -0
- package/src/skills/perl-testing/SKILL.md +475 -0
- package/src/skills/postgres-patterns/SKILL.md +147 -0
- package/src/skills/prompt-optimizer/SKILL.md +397 -0
- package/src/skills/python-patterns/SKILL.md +750 -0
- package/src/skills/python-testing/SKILL.md +816 -0
- package/src/skills/rust-patterns/SKILL.md +499 -0
- package/src/skills/rust-testing/SKILL.md +500 -0
- package/src/skills/safety-guard/SKILL.md +69 -0
- package/src/skills/search-first/SKILL.md +161 -0
- package/src/skills/security-review/SKILL.md +495 -0
- package/src/skills/security-review/cloud-infrastructure-security.md +361 -0
- package/src/skills/security-scan/SKILL.md +165 -0
- package/src/skills/springboot-patterns/SKILL.md +314 -0
- package/src/skills/springboot-security/SKILL.md +272 -0
- package/src/skills/springboot-tdd/SKILL.md +158 -0
- package/src/skills/springboot-verification/SKILL.md +231 -0
- package/src/skills/tdd-workflow/SKILL.md +410 -0
- package/ecc/scripts/hooks/session-end-marker.js +0 -15
- package/gsd/LICENSE +0 -21
- package/gsd/commands-gsd/discuss-phase.md +0 -90
- package/gsd/commands-gsd/execute-phase.md +0 -41
- package/gsd/commands-gsd/join-discord.md +0 -18
- package/gsd/commands-gsd/reapply-patches.md +0 -123
- package/gsd/commands-gsd/set-profile.md +0 -34
- package/gsd/get-shit-done/bin/lib/config.cjs +0 -169
- package/gsd/get-shit-done/bin/lib/core.cjs +0 -492
- package/gsd/get-shit-done/bin/lib/init.cjs +0 -710
- package/gsd/get-shit-done/workflows/execute-phase.md +0 -459
- package/gsd/get-shit-done/workflows/help.md +0 -489
- package/gsd/get-shit-done/workflows/pause-work.md +0 -122
- package/gsd/get-shit-done/workflows/plan-phase.md +0 -560
- package/gsd/hooks/gsd-check-update.js +0 -81
- package/kit/CLAUDE.md +0 -43
- package/kit/commands/kit/update.md +0 -46
- package/kit/mcp.json +0 -10
- package/kit/rules/code-style.md +0 -24
- /package/{ecc → src}/agents/architect.md +0 -0
- /package/{ecc → src}/agents/code-reviewer.md +0 -0
- /package/{ecc → src}/agents/doc-updater.md +0 -0
- /package/{ecc → src}/agents/e2e-runner.md +0 -0
- /package/{ecc → src}/agents/security-reviewer.md +0 -0
- /package/{ecc → src}/agents/tdd-guide.md +0 -0
- /package/{ecc/rules → src/available-rules}/golang/coding-style.md +0 -0
- /package/{ecc/rules → src/available-rules}/golang/hooks.md +0 -0
- /package/{ecc/rules → src/available-rules}/golang/patterns.md +0 -0
- /package/{ecc/rules → src/available-rules}/golang/security.md +0 -0
- /package/{ecc/rules → src/available-rules}/golang/testing.md +0 -0
- /package/{ecc/rules → src/available-rules}/kotlin/coding-style.md +0 -0
- /package/{ecc/rules → src/available-rules}/kotlin/patterns.md +0 -0
- /package/{ecc/rules → src/available-rules}/kotlin/security.md +0 -0
- /package/{ecc/rules → src/available-rules}/kotlin/testing.md +0 -0
- /package/{ecc/rules → src/available-rules}/perl/coding-style.md +0 -0
- /package/{ecc/rules → src/available-rules}/perl/hooks.md +0 -0
- /package/{ecc/rules → src/available-rules}/perl/patterns.md +0 -0
- /package/{ecc/rules → src/available-rules}/perl/security.md +0 -0
- /package/{ecc/rules → src/available-rules}/perl/testing.md +0 -0
- /package/{ecc/rules → src/available-rules}/php/coding-style.md +0 -0
- /package/{ecc/rules → src/available-rules}/php/hooks.md +0 -0
- /package/{ecc/rules → src/available-rules}/php/patterns.md +0 -0
- /package/{ecc/rules → src/available-rules}/php/security.md +0 -0
- /package/{ecc/rules → src/available-rules}/php/testing.md +0 -0
- /package/{ecc/rules → src/available-rules}/python/coding-style.md +0 -0
- /package/{ecc/rules → src/available-rules}/python/hooks.md +0 -0
- /package/{ecc/rules → src/available-rules}/python/patterns.md +0 -0
- /package/{ecc/rules → src/available-rules}/python/security.md +0 -0
- /package/{ecc/rules → src/available-rules}/python/testing.md +0 -0
- /package/{ecc/rules → src/available-rules}/swift/coding-style.md +0 -0
- /package/{ecc/rules → src/available-rules}/swift/hooks.md +0 -0
- /package/{ecc/rules → src/available-rules}/swift/patterns.md +0 -0
- /package/{ecc/rules → src/available-rules}/swift/security.md +0 -0
- /package/{ecc/rules → src/available-rules}/swift/testing.md +0 -0
- /package/{ecc/rules → src/available-rules}/typescript/coding-style.md +0 -0
- /package/{ecc/rules → src/available-rules}/typescript/hooks.md +0 -0
- /package/{ecc/rules → src/available-rules}/typescript/patterns.md +0 -0
- /package/{ecc/rules → src/available-rules}/typescript/security.md +0 -0
- /package/{ecc/rules → src/available-rules}/typescript/testing.md +0 -0
- /package/{ecc → src}/commands/checkpoint.md +0 -0
- /package/{ecc → src}/commands/learn.md +0 -0
- /package/{ecc → src}/commands/model-route.md +0 -0
- /package/{ecc → src}/commands/resume-session.md +0 -0
- /package/{ecc → src}/commands/save-session.md +0 -0
- /package/{kit → src}/commands/setup-refresh.md +0 -0
- /package/{kit → src}/commands/tool-guide.md +0 -0
- /package/{ecc → src}/commands/verify.md +0 -0
- /package/{ecc → src}/contexts/dev.md +0 -0
- /package/{ecc → src}/contexts/research.md +0 -0
- /package/{ecc → src}/contexts/review.md +0 -0
- /package/{ecc → src}/examples/CLAUDE.md +0 -0
- /package/{ecc → src}/examples/django-api-CLAUDE.md +0 -0
- /package/{ecc → src}/examples/go-microservice-CLAUDE.md +0 -0
- /package/{ecc → src}/examples/rust-api-CLAUDE.md +0 -0
- /package/{ecc → src}/examples/saas-nextjs-CLAUDE.md +0 -0
- /package/{ecc → src}/examples/user-CLAUDE.md +0 -0
- /package/{ecc/scripts → src}/hooks/check-hook-enabled.js +0 -0
- /package/{ecc/scripts → src}/hooks/evaluate-session.js +0 -0
- /package/{ecc/scripts → src}/hooks/pre-compact.js +0 -0
- /package/{ecc/scripts → src}/hooks/suggest-compact.js +0 -0
- /package/{ecc/scripts → src}/lib/package-manager.d.ts +0 -0
- /package/{ecc/scripts → src}/lib/package-manager.js +0 -0
- /package/{ecc/scripts → src}/lib/resolve-formatter.js +0 -0
- /package/{ecc/scripts → src}/lib/session-aliases.d.ts +0 -0
- /package/{ecc/scripts → src}/lib/session-aliases.js +0 -0
- /package/{ecc/scripts → src}/lib/shell-split.js +0 -0
- /package/{gsd/get-shit-done → src/pilot}/bin/lib/frontmatter.cjs +0 -0
- /package/{gsd/get-shit-done → src/pilot}/bin/lib/milestone.cjs +0 -0
- /package/{gsd/get-shit-done → src/pilot}/bin/lib/roadmap.cjs +0 -0
- /package/{gsd/get-shit-done → src/pilot}/bin/lib/template.cjs +0 -0
- /package/{gsd/get-shit-done → src/pilot}/references/checkpoints.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/references/questioning.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/references/tdd.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/codebase/concerns.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/codebase/conventions.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/codebase/integrations.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/codebase/stack.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/codebase/testing.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/config.json +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/continue-here.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/milestone-archive.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/milestone.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/requirements.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/research-project/ARCHITECTURE.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/research-project/FEATURES.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/research-project/PITFALLS.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/research-project/STACK.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/research-project/SUMMARY.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/retrospective.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/roadmap.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/summary-minimal.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/summary-standard.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/summary.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/user-setup.md +0 -0
- /package/{gsd/get-shit-done → src/pilot}/templates/verification-report.md +0 -0
- /package/{ecc → src}/rules/common/development-workflow.md +0 -0
- /package/{ecc → src}/rules/common/git-workflow.md +0 -0
- /package/{ecc → src}/rules/common/hooks.md +0 -0
- /package/{ecc → src}/rules/common/patterns.md +0 -0
- /package/{ecc → src}/rules/common/performance.md +0 -0
- /package/{ecc → src}/rules/common/security.md +0 -0
- /package/{ecc → src}/rules/common/testing.md +0 -0
- /package/{ecc → src}/skills/continuous-learning-v2/agents/observer.md +0 -0
- /package/{ecc → src}/skills/continuous-learning-v2/agents/start-observer.sh +0 -0
- /package/{ecc → src}/skills/continuous-learning-v2/config.json +0 -0
- /package/{ecc → src}/skills/continuous-learning-v2/hooks/observe.sh +0 -0
- /package/{ecc → src}/skills/continuous-learning-v2/scripts/detect-project.sh +0 -0
- /package/{ecc → src}/skills/continuous-learning-v2/scripts/instinct-cli.py +0 -0
- /package/{ecc → src}/skills/continuous-learning-v2/scripts/test_parse_instinct.py +0 -0
- /package/{ecc → src}/skills/strategic-compact/SKILL.md +0 -0
- /package/{ecc → src}/skills/strategic-compact/suggest-compact.sh +0 -0
- /package/{ecc/skills/verification-loop-SKILL.md → src/skills/verification-loop/SKILL.md} +0 -0
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Session Manager Library for Claude Code
|
|
3
3
|
* Provides core session CRUD operations for listing, loading, and managing sessions
|
|
4
4
|
*
|
|
5
|
-
* Sessions are stored as markdown files in ~/.claude/
|
|
5
|
+
* Sessions are stored as markdown files in ~/.claude/session-data/ with
|
|
6
|
+
* legacy read compatibility for ~/.claude/sessions/:
|
|
6
7
|
* - YYYY-MM-DD-session.tmp (old format)
|
|
7
8
|
* - YYYY-MM-DD-<short-id>-session.tmp (new format)
|
|
8
9
|
*/
|
|
@@ -12,16 +13,18 @@ const path = require('path');
|
|
|
12
13
|
|
|
13
14
|
const {
|
|
14
15
|
getSessionsDir,
|
|
16
|
+
getSessionSearchDirs,
|
|
15
17
|
readFile,
|
|
16
18
|
log
|
|
17
19
|
} = require('./utils');
|
|
18
20
|
|
|
19
21
|
// Session filename pattern: YYYY-MM-DD-[session-id]-session.tmp
|
|
20
|
-
// The session-id is optional (old format) and can include
|
|
21
|
-
//
|
|
22
|
+
// The session-id is optional (old format) and can include letters, digits,
|
|
23
|
+
// underscores, and hyphens, but must not start with a hyphen.
|
|
22
24
|
// Matches: "2026-02-01-session.tmp", "2026-02-01-a1b2c3d4-session.tmp",
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
+
// "2026-02-01-frontend-worktree-1-session.tmp", and
|
|
26
|
+
// "2026-02-01-ChezMoi_2-session.tmp"
|
|
27
|
+
const SESSION_FILENAME_REGEX = /^(\d{4}-\d{2}-\d{2})(?:-([a-zA-Z0-9_][a-zA-Z0-9_-]*))?-session\.tmp$/;
|
|
25
28
|
|
|
26
29
|
/**
|
|
27
30
|
* Parse session filename to extract metadata
|
|
@@ -29,6 +32,7 @@ const SESSION_FILENAME_REGEX = /^(\d{4}-\d{2}-\d{2})(?:-([a-z0-9-]{8,}))?-sessio
|
|
|
29
32
|
* @returns {object|null} Parsed metadata or null if invalid
|
|
30
33
|
*/
|
|
31
34
|
function parseSessionFilename(filename) {
|
|
35
|
+
if (!filename || typeof filename !== 'string') return null;
|
|
32
36
|
const match = filename.match(SESSION_FILENAME_REGEX);
|
|
33
37
|
if (!match) return null;
|
|
34
38
|
|
|
@@ -74,6 +78,166 @@ function getSessionContent(sessionPath) {
|
|
|
74
78
|
return readFile(sessionPath);
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Gather session candidates from all search directories, deduplicated by filename.
|
|
83
|
+
* session-data/ entries take priority over sessions/ entries.
|
|
84
|
+
* @param {object} options - Filter options { date, search }
|
|
85
|
+
* @returns {object[]} Deduplicated, sorted session candidates
|
|
86
|
+
*/
|
|
87
|
+
function getSessionCandidates(options = {}) {
|
|
88
|
+
const {
|
|
89
|
+
date = null,
|
|
90
|
+
search = null
|
|
91
|
+
} = options;
|
|
92
|
+
|
|
93
|
+
const candidates = [];
|
|
94
|
+
|
|
95
|
+
for (const sessionsDir of getSessionSearchDirs()) {
|
|
96
|
+
if (!fs.existsSync(sessionsDir)) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let entries;
|
|
101
|
+
try {
|
|
102
|
+
entries = fs.readdirSync(sessionsDir, { withFileTypes: true });
|
|
103
|
+
} catch (error) {
|
|
104
|
+
log(`[SessionManager] Error reading sessions directory ${sessionsDir}: ${error.message}`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
if (!entry.isFile() || !entry.name.endsWith('.tmp')) continue;
|
|
110
|
+
|
|
111
|
+
const filename = entry.name;
|
|
112
|
+
const metadata = parseSessionFilename(filename);
|
|
113
|
+
|
|
114
|
+
if (!metadata) continue;
|
|
115
|
+
if (date && metadata.date !== date) continue;
|
|
116
|
+
if (search && !metadata.shortId.includes(search)) continue;
|
|
117
|
+
|
|
118
|
+
const sessionPath = path.join(sessionsDir, filename);
|
|
119
|
+
|
|
120
|
+
let stats;
|
|
121
|
+
try {
|
|
122
|
+
stats = fs.statSync(sessionPath);
|
|
123
|
+
} catch {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
candidates.push({
|
|
128
|
+
...metadata,
|
|
129
|
+
sessionPath,
|
|
130
|
+
hasContent: stats.size > 0,
|
|
131
|
+
size: stats.size,
|
|
132
|
+
modifiedTime: stats.mtime,
|
|
133
|
+
createdTime: stats.birthtime || stats.ctime
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const deduped = [];
|
|
139
|
+
const seenFilenames = new Set();
|
|
140
|
+
|
|
141
|
+
for (const session of candidates) {
|
|
142
|
+
if (seenFilenames.has(session.filename)) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
seenFilenames.add(session.filename);
|
|
146
|
+
deduped.push(session);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
deduped.sort((a, b) => b.modifiedTime - a.modifiedTime);
|
|
150
|
+
return deduped;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Build a session record from a path and metadata
|
|
155
|
+
* @param {string} sessionPath - Full path to session file
|
|
156
|
+
* @param {object} metadata - Parsed filename metadata
|
|
157
|
+
* @returns {object|null} Session record or null if stat fails
|
|
158
|
+
*/
|
|
159
|
+
function buildSessionRecord(sessionPath, metadata) {
|
|
160
|
+
let stats;
|
|
161
|
+
try {
|
|
162
|
+
stats = fs.statSync(sessionPath);
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
...metadata,
|
|
169
|
+
sessionPath,
|
|
170
|
+
hasContent: stats.size > 0,
|
|
171
|
+
size: stats.size,
|
|
172
|
+
modifiedTime: stats.mtime,
|
|
173
|
+
createdTime: stats.birthtime || stats.ctime
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Check if a session's metadata matches a given session ID
|
|
179
|
+
* @param {object} metadata - Parsed filename metadata
|
|
180
|
+
* @param {string} normalizedSessionId - Trimmed session ID to match against
|
|
181
|
+
* @returns {boolean} True if the session matches
|
|
182
|
+
*/
|
|
183
|
+
function sessionMatchesId(metadata, normalizedSessionId) {
|
|
184
|
+
const filename = metadata.filename;
|
|
185
|
+
const shortIdMatch = metadata.shortId !== 'no-id' && metadata.shortId.startsWith(normalizedSessionId);
|
|
186
|
+
const filenameMatch = filename === normalizedSessionId || filename === `${normalizedSessionId}.tmp`;
|
|
187
|
+
const noIdMatch = metadata.shortId === 'no-id' && filename === `${normalizedSessionId}-session.tmp`;
|
|
188
|
+
|
|
189
|
+
return shortIdMatch || filenameMatch || noIdMatch;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Find matching session candidates across all search directories
|
|
194
|
+
* @param {string} normalizedSessionId - Trimmed session ID to match
|
|
195
|
+
* @returns {object[]} Matching session records, sorted by modification time
|
|
196
|
+
*/
|
|
197
|
+
function getMatchingSessionCandidates(normalizedSessionId) {
|
|
198
|
+
const matches = [];
|
|
199
|
+
const seenFilenames = new Set();
|
|
200
|
+
|
|
201
|
+
for (const sessionsDir of getSessionSearchDirs()) {
|
|
202
|
+
if (!fs.existsSync(sessionsDir)) {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
let entries;
|
|
207
|
+
try {
|
|
208
|
+
entries = fs.readdirSync(sessionsDir, { withFileTypes: true });
|
|
209
|
+
} catch (error) {
|
|
210
|
+
log(`[SessionManager] Error reading sessions directory ${sessionsDir}: ${error.message}`);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
for (const entry of entries) {
|
|
215
|
+
if (!entry.isFile() || !entry.name.endsWith('.tmp')) continue;
|
|
216
|
+
|
|
217
|
+
const metadata = parseSessionFilename(entry.name);
|
|
218
|
+
if (!metadata || !sessionMatchesId(metadata, normalizedSessionId)) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (seenFilenames.has(metadata.filename)) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const sessionPath = path.join(sessionsDir, metadata.filename);
|
|
227
|
+
const sessionRecord = buildSessionRecord(sessionPath, metadata);
|
|
228
|
+
if (!sessionRecord) {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
seenFilenames.add(metadata.filename);
|
|
233
|
+
matches.push(sessionRecord);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
matches.sort((a, b) => b.modifiedTime - a.modifiedTime);
|
|
238
|
+
return matches;
|
|
239
|
+
}
|
|
240
|
+
|
|
77
241
|
/**
|
|
78
242
|
* Parse session metadata from markdown content
|
|
79
243
|
* @param {string} content - Session markdown content
|
|
@@ -85,6 +249,9 @@ function parseSessionMetadata(content) {
|
|
|
85
249
|
date: null,
|
|
86
250
|
started: null,
|
|
87
251
|
lastUpdated: null,
|
|
252
|
+
project: null,
|
|
253
|
+
branch: null,
|
|
254
|
+
worktree: null,
|
|
88
255
|
completed: [],
|
|
89
256
|
inProgress: [],
|
|
90
257
|
notes: '',
|
|
@@ -117,6 +284,22 @@ function parseSessionMetadata(content) {
|
|
|
117
284
|
metadata.lastUpdated = updatedMatch[1];
|
|
118
285
|
}
|
|
119
286
|
|
|
287
|
+
// Extract control-plane metadata
|
|
288
|
+
const projectMatch = content.match(/\*\*Project:\*\*\s*(.+)$/m);
|
|
289
|
+
if (projectMatch) {
|
|
290
|
+
metadata.project = projectMatch[1].trim();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const branchMatch = content.match(/\*\*Branch:\*\*\s*(.+)$/m);
|
|
294
|
+
if (branchMatch) {
|
|
295
|
+
metadata.branch = branchMatch[1].trim();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const worktreeMatch = content.match(/\*\*Worktree:\*\*\s*(.+)$/m);
|
|
299
|
+
if (worktreeMatch) {
|
|
300
|
+
metadata.worktree = worktreeMatch[1].trim();
|
|
301
|
+
}
|
|
302
|
+
|
|
120
303
|
// Extract completed items
|
|
121
304
|
const completedSection = content.match(/### Completed\s*\n([\s\S]*?)(?=###|\n\n|$)/);
|
|
122
305
|
if (completedSection) {
|
|
@@ -208,58 +391,12 @@ function getAllSessions(options = {}) {
|
|
|
208
391
|
const limitNum = Number(rawLimit);
|
|
209
392
|
const limit = Number.isNaN(limitNum) ? 50 : Math.max(1, Math.floor(limitNum));
|
|
210
393
|
|
|
211
|
-
const
|
|
394
|
+
const sessions = getSessionCandidates({ date, search });
|
|
212
395
|
|
|
213
|
-
if (
|
|
396
|
+
if (sessions.length === 0) {
|
|
214
397
|
return { sessions: [], total: 0, offset, limit, hasMore: false };
|
|
215
398
|
}
|
|
216
399
|
|
|
217
|
-
const entries = fs.readdirSync(sessionsDir, { withFileTypes: true });
|
|
218
|
-
const sessions = [];
|
|
219
|
-
|
|
220
|
-
for (const entry of entries) {
|
|
221
|
-
// Skip non-files (only process .tmp files)
|
|
222
|
-
if (!entry.isFile() || !entry.name.endsWith('.tmp')) continue;
|
|
223
|
-
|
|
224
|
-
const filename = entry.name;
|
|
225
|
-
const metadata = parseSessionFilename(filename);
|
|
226
|
-
|
|
227
|
-
if (!metadata) continue;
|
|
228
|
-
|
|
229
|
-
// Apply date filter
|
|
230
|
-
if (date && metadata.date !== date) {
|
|
231
|
-
continue;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Apply search filter (search in short ID)
|
|
235
|
-
if (search && !metadata.shortId.includes(search)) {
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const sessionPath = path.join(sessionsDir, filename);
|
|
240
|
-
|
|
241
|
-
// Get file stats (wrapped in try-catch to handle TOCTOU race where
|
|
242
|
-
// file is deleted between readdirSync and statSync)
|
|
243
|
-
let stats;
|
|
244
|
-
try {
|
|
245
|
-
stats = fs.statSync(sessionPath);
|
|
246
|
-
} catch {
|
|
247
|
-
continue; // File was deleted between readdir and stat
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
sessions.push({
|
|
251
|
-
...metadata,
|
|
252
|
-
sessionPath,
|
|
253
|
-
hasContent: stats.size > 0,
|
|
254
|
-
size: stats.size,
|
|
255
|
-
modifiedTime: stats.mtime,
|
|
256
|
-
createdTime: stats.birthtime || stats.ctime
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Sort by modified time (newest first)
|
|
261
|
-
sessions.sort((a, b) => b.modifiedTime - a.modifiedTime);
|
|
262
|
-
|
|
263
400
|
// Apply pagination
|
|
264
401
|
const paginatedSessions = sessions.slice(offset, offset + limit);
|
|
265
402
|
|
|
@@ -279,55 +416,28 @@ function getAllSessions(options = {}) {
|
|
|
279
416
|
* @returns {object|null} Session object or null if not found
|
|
280
417
|
*/
|
|
281
418
|
function getSessionById(sessionId, includeContent = false) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
if (!fs.existsSync(sessionsDir)) {
|
|
419
|
+
if (typeof sessionId !== 'string') {
|
|
285
420
|
return null;
|
|
286
421
|
}
|
|
287
422
|
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
const filename = entry.name;
|
|
294
|
-
const metadata = parseSessionFilename(filename);
|
|
295
|
-
|
|
296
|
-
if (!metadata) continue;
|
|
297
|
-
|
|
298
|
-
// Check if session ID matches (short ID or full filename without .tmp)
|
|
299
|
-
const shortIdMatch = sessionId.length > 0 && metadata.shortId !== 'no-id' && metadata.shortId.startsWith(sessionId);
|
|
300
|
-
const filenameMatch = filename === sessionId || filename === `${sessionId}.tmp`;
|
|
301
|
-
const noIdMatch = metadata.shortId === 'no-id' && filename === `${sessionId}-session.tmp`;
|
|
302
|
-
|
|
303
|
-
if (!shortIdMatch && !filenameMatch && !noIdMatch) {
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
423
|
+
const normalizedSessionId = sessionId.trim();
|
|
424
|
+
if (!normalizedSessionId) {
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
306
427
|
|
|
307
|
-
|
|
308
|
-
let stats;
|
|
309
|
-
try {
|
|
310
|
-
stats = fs.statSync(sessionPath);
|
|
311
|
-
} catch {
|
|
312
|
-
return null; // File was deleted between readdir and stat
|
|
313
|
-
}
|
|
428
|
+
const sessions = getMatchingSessionCandidates(normalizedSessionId);
|
|
314
429
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
sessionPath,
|
|
318
|
-
size: stats.size,
|
|
319
|
-
modifiedTime: stats.mtime,
|
|
320
|
-
createdTime: stats.birthtime || stats.ctime
|
|
321
|
-
};
|
|
430
|
+
for (const session of sessions) {
|
|
431
|
+
const sessionRecord = { ...session };
|
|
322
432
|
|
|
323
433
|
if (includeContent) {
|
|
324
|
-
|
|
325
|
-
|
|
434
|
+
sessionRecord.content = getSessionContent(sessionRecord.sessionPath);
|
|
435
|
+
sessionRecord.metadata = parseSessionMetadata(sessionRecord.content);
|
|
326
436
|
// Pass pre-read content to avoid a redundant disk read
|
|
327
|
-
|
|
437
|
+
sessionRecord.stats = getSessionStats(sessionRecord.content || '');
|
|
328
438
|
}
|
|
329
439
|
|
|
330
|
-
return
|
|
440
|
+
return sessionRecord;
|
|
331
441
|
}
|
|
332
442
|
|
|
333
443
|
return null;
|
|
@@ -18,9 +18,15 @@ export function getHomeDir(): string;
|
|
|
18
18
|
/** Get the Claude config directory (~/.claude) */
|
|
19
19
|
export function getClaudeDir(): string;
|
|
20
20
|
|
|
21
|
-
/** Get the sessions directory (~/.claude/
|
|
21
|
+
/** Get the sessions directory (~/.claude/session-data) */
|
|
22
22
|
export function getSessionsDir(): string;
|
|
23
23
|
|
|
24
|
+
/** Get the legacy sessions directory (~/.claude/sessions) used by older installs */
|
|
25
|
+
export function getLegacySessionsDir(): string;
|
|
26
|
+
|
|
27
|
+
/** Get all session directories to search, in canonical-first order */
|
|
28
|
+
export function getSessionSearchDirs(): string[];
|
|
29
|
+
|
|
24
30
|
/** Get the learned skills directory (~/.claude/skills/learned) */
|
|
25
31
|
export function getLearnedSkillsDir(): string;
|
|
26
32
|
|
|
@@ -47,6 +53,14 @@ export function getDateTimeString(): string;
|
|
|
47
53
|
|
|
48
54
|
// --- Session/Project ---
|
|
49
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Sanitize a string for use as a session filename segment.
|
|
58
|
+
* Replaces invalid characters, handles non-ASCII via hashing,
|
|
59
|
+
* and guards against Windows reserved names.
|
|
60
|
+
* @returns Sanitized string, or null if input is empty/meaningless
|
|
61
|
+
*/
|
|
62
|
+
export function sanitizeSessionId(raw: string): string | null;
|
|
63
|
+
|
|
50
64
|
/**
|
|
51
65
|
* Get short session ID from CLAUDE_SESSION_ID environment variable.
|
|
52
66
|
* Returns last 8 characters, falls back to project name then the provided fallback.
|
|
@@ -123,6 +137,14 @@ export interface GrepMatch {
|
|
|
123
137
|
/** Search for a pattern in a file and return matching lines with line numbers */
|
|
124
138
|
export function grepFile(filePath: string, pattern: string | RegExp): GrepMatch[];
|
|
125
139
|
|
|
140
|
+
// --- String sanitisation ---
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Strip all ANSI escape sequences from a string.
|
|
144
|
+
* Handles CSI, OSC, charset selection, and bare ESC sequences.
|
|
145
|
+
*/
|
|
146
|
+
export function stripAnsi(str: string): string;
|
|
147
|
+
|
|
126
148
|
// --- Hook I/O ---
|
|
127
149
|
|
|
128
150
|
export interface ReadStdinJsonOptions {
|
|
@@ -6,12 +6,20 @@
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const os = require('os');
|
|
9
|
+
const crypto = require('crypto');
|
|
9
10
|
const { execSync, spawnSync } = require('child_process');
|
|
10
11
|
|
|
11
12
|
// Platform detection
|
|
12
13
|
const isWindows = process.platform === 'win32';
|
|
13
14
|
const isMacOS = process.platform === 'darwin';
|
|
14
15
|
const isLinux = process.platform === 'linux';
|
|
16
|
+
const SESSION_DATA_DIR_NAME = 'session-data';
|
|
17
|
+
const LEGACY_SESSIONS_DIR_NAME = 'sessions';
|
|
18
|
+
const WINDOWS_RESERVED_SESSION_IDS = new Set([
|
|
19
|
+
'CON', 'PRN', 'AUX', 'NUL',
|
|
20
|
+
'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', 'COM8', 'COM9',
|
|
21
|
+
'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'
|
|
22
|
+
]);
|
|
15
23
|
|
|
16
24
|
/**
|
|
17
25
|
* Get the user's home directory (cross-platform)
|
|
@@ -21,17 +29,38 @@ function getHomeDir() {
|
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
/**
|
|
24
|
-
* Get the Claude config directory
|
|
32
|
+
* Get the Claude config directory.
|
|
33
|
+
* Self-detects local CCP installs by checking for .claude/pilot/VERSION
|
|
34
|
+
* in the current working directory. Falls back to CLAUDE_CONFIG_DIR env
|
|
35
|
+
* var or the global ~/.claude/ directory.
|
|
25
36
|
*/
|
|
26
37
|
function getClaudeDir() {
|
|
27
|
-
|
|
38
|
+
const localDir = path.join(process.cwd(), '.claude');
|
|
39
|
+
if (fs.existsSync(path.join(localDir, 'pilot', 'VERSION'))) {
|
|
40
|
+
return localDir;
|
|
41
|
+
}
|
|
42
|
+
return process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
|
|
28
43
|
}
|
|
29
44
|
|
|
30
45
|
/**
|
|
31
46
|
* Get the sessions directory
|
|
32
47
|
*/
|
|
33
48
|
function getSessionsDir() {
|
|
34
|
-
return path.join(getClaudeDir(),
|
|
49
|
+
return path.join(getClaudeDir(), SESSION_DATA_DIR_NAME);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get the legacy sessions directory used by older ECC installs
|
|
54
|
+
*/
|
|
55
|
+
function getLegacySessionsDir() {
|
|
56
|
+
return path.join(getClaudeDir(), LEGACY_SESSIONS_DIR_NAME);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get all session directories to search, in canonical-first order
|
|
61
|
+
*/
|
|
62
|
+
function getSessionSearchDirs() {
|
|
63
|
+
return Array.from(new Set([getSessionsDir(), getLegacySessionsDir()]));
|
|
35
64
|
}
|
|
36
65
|
|
|
37
66
|
/**
|
|
@@ -107,6 +136,41 @@ function getProjectName() {
|
|
|
107
136
|
return path.basename(process.cwd()) || null;
|
|
108
137
|
}
|
|
109
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Sanitize a string for use as a session filename segment.
|
|
141
|
+
* Replaces invalid characters with hyphens, collapses runs, strips
|
|
142
|
+
* leading/trailing hyphens, and removes leading dots so hidden-dir names
|
|
143
|
+
* like ".claude" map cleanly to "claude".
|
|
144
|
+
*
|
|
145
|
+
* Pure non-ASCII inputs get a stable 8-char hash so distinct names do not
|
|
146
|
+
* collapse to the same fallback session id. Mixed-script inputs retain their
|
|
147
|
+
* ASCII part and gain a short hash suffix for disambiguation.
|
|
148
|
+
*/
|
|
149
|
+
function sanitizeSessionId(raw) {
|
|
150
|
+
if (!raw || typeof raw !== 'string') return null;
|
|
151
|
+
|
|
152
|
+
const hasNonAscii = Array.from(raw).some(char => char.codePointAt(0) > 0x7f);
|
|
153
|
+
const normalized = raw.replace(/^\.+/, '');
|
|
154
|
+
const sanitized = normalized
|
|
155
|
+
.replace(/[^a-zA-Z0-9_-]/g, '-')
|
|
156
|
+
.replace(/-{2,}/g, '-')
|
|
157
|
+
.replace(/^-+|-+$/g, '');
|
|
158
|
+
|
|
159
|
+
if (sanitized.length > 0) {
|
|
160
|
+
const suffix = crypto.createHash('sha256').update(normalized).digest('hex').slice(0, 6);
|
|
161
|
+
if (WINDOWS_RESERVED_SESSION_IDS.has(sanitized.toUpperCase())) {
|
|
162
|
+
return `${sanitized}-${suffix}`;
|
|
163
|
+
}
|
|
164
|
+
if (!hasNonAscii) return sanitized;
|
|
165
|
+
return `${sanitized}-${suffix}`;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const meaningful = normalized.replace(/[\s\p{P}]/gu, '');
|
|
169
|
+
if (meaningful.length === 0) return null;
|
|
170
|
+
|
|
171
|
+
return crypto.createHash('sha256').update(normalized).digest('hex').slice(0, 8);
|
|
172
|
+
}
|
|
173
|
+
|
|
110
174
|
/**
|
|
111
175
|
* Get short session ID from CLAUDE_SESSION_ID environment variable
|
|
112
176
|
* Returns last 8 characters, falls back to project name then 'default'
|
|
@@ -464,6 +528,24 @@ function countInFile(filePath, pattern) {
|
|
|
464
528
|
return matches ? matches.length : 0;
|
|
465
529
|
}
|
|
466
530
|
|
|
531
|
+
/**
|
|
532
|
+
* Strip all ANSI escape sequences from a string.
|
|
533
|
+
*
|
|
534
|
+
* Handles:
|
|
535
|
+
* - CSI sequences: \x1b[ ... <letter> (colors, cursor movement, erase, etc.)
|
|
536
|
+
* - OSC sequences: \x1b] ... BEL/ST (window titles, hyperlinks)
|
|
537
|
+
* - Charset selection: \x1b(B
|
|
538
|
+
* - Bare ESC + single letter: \x1b <letter> (e.g. \x1bM for reverse index)
|
|
539
|
+
*
|
|
540
|
+
* @param {string} str - Input string possibly containing ANSI codes
|
|
541
|
+
* @returns {string} Cleaned string with all escape sequences removed
|
|
542
|
+
*/
|
|
543
|
+
function stripAnsi(str) {
|
|
544
|
+
if (typeof str !== 'string') return '';
|
|
545
|
+
// eslint-disable-next-line no-control-regex
|
|
546
|
+
return str.replace(/\x1b(?:\[[0-9;?]*[A-Za-z]|\][^\x07\x1b]*(?:\x07|\x1b\\)|\([A-Z]|[A-Z])/g, '');
|
|
547
|
+
}
|
|
548
|
+
|
|
467
549
|
/**
|
|
468
550
|
* Search for pattern in file and return matching lines with line numbers
|
|
469
551
|
*/
|
|
@@ -507,6 +589,8 @@ module.exports = {
|
|
|
507
589
|
getHomeDir,
|
|
508
590
|
getClaudeDir,
|
|
509
591
|
getSessionsDir,
|
|
592
|
+
getLegacySessionsDir,
|
|
593
|
+
getSessionSearchDirs,
|
|
510
594
|
getLearnedSkillsDir,
|
|
511
595
|
getTempDir,
|
|
512
596
|
ensureDir,
|
|
@@ -517,6 +601,7 @@ module.exports = {
|
|
|
517
601
|
getDateTimeString,
|
|
518
602
|
|
|
519
603
|
// Session/Project
|
|
604
|
+
sanitizeSessionId,
|
|
520
605
|
getSessionIdShort,
|
|
521
606
|
getGitRepoName,
|
|
522
607
|
getProjectName,
|
|
@@ -530,6 +615,9 @@ module.exports = {
|
|
|
530
615
|
countInFile,
|
|
531
616
|
grepFile,
|
|
532
617
|
|
|
618
|
+
// String sanitisation
|
|
619
|
+
stripAnsi,
|
|
620
|
+
|
|
533
621
|
// Hook I/O
|
|
534
622
|
readStdinJson,
|
|
535
623
|
log,
|