@trieungoctam/vibekit 1.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/LICENSE +21 -0
- package/README.md +85 -0
- package/agents/debugger.md +158 -0
- package/agents/docs-manager.md +220 -0
- package/agents/planner.md +129 -0
- package/agents/researcher.md +58 -0
- package/agents/reviewer.md +152 -0
- package/agents/tester.md +126 -0
- package/bin/vibekit.js +18 -0
- package/hooks/lib/ck-config-utils.cjs +831 -0
- package/hooks/lib/colors.cjs +95 -0
- package/hooks/lib/config-counter.cjs +103 -0
- package/hooks/lib/context-builder.cjs +616 -0
- package/hooks/lib/git-info-cache.cjs +143 -0
- package/hooks/lib/hook-logger.cjs +92 -0
- package/hooks/lib/privacy-checker.cjs +297 -0
- package/hooks/lib/project-detector.cjs +474 -0
- package/hooks/lib/scout-checker.cjs +263 -0
- package/hooks/lib/transcript-parser.cjs +181 -0
- package/hooks/post-edit-simplify-reminder.cjs +156 -0
- package/hooks/privacy-block.cjs +166 -0
- package/hooks/scout-block.cjs +147 -0
- package/hooks/session-init.cjs +360 -0
- package/package.json +41 -0
- package/rules/development-rules.md +52 -0
- package/rules/documentation-management.md +121 -0
- package/rules/orchestration-protocol.md +43 -0
- package/rules/primary-workflow.md +57 -0
- package/rules/team-coordination-rules.md +90 -0
- package/skills/ai/agent-browser/SKILL.md +294 -0
- package/skills/ai/agent-browser/references/.gitkeep +0 -0
- package/skills/ai/agent-browser/references/agent-browser-vs-chrome-devtools.md +112 -0
- package/skills/ai/agent-browser/references/browserbase-cloud-setup.md +161 -0
- package/skills/ai/ai-artist/SKILL.md +122 -0
- package/skills/ai/ai-artist/data/awesome-prompts.csv +3592 -0
- package/skills/ai/ai-artist/data/lighting.csv +19 -0
- package/skills/ai/ai-artist/data/nano-banana-templates.csv +17 -0
- package/skills/ai/ai-artist/data/platforms.csv +11 -0
- package/skills/ai/ai-artist/data/styles.csv +26 -0
- package/skills/ai/ai-artist/data/techniques.csv +19 -0
- package/skills/ai/ai-artist/data/use-cases.csv +16 -0
- package/skills/ai/ai-artist/references/advanced-techniques.md +184 -0
- package/skills/ai/ai-artist/references/awesome-nano-banana-pro-prompts.md +8575 -0
- package/skills/ai/ai-artist/references/domain-code.md +66 -0
- package/skills/ai/ai-artist/references/domain-data.md +72 -0
- package/skills/ai/ai-artist/references/domain-marketing.md +66 -0
- package/skills/ai/ai-artist/references/domain-patterns.md +33 -0
- package/skills/ai/ai-artist/references/domain-writing.md +68 -0
- package/skills/ai/ai-artist/references/image-prompting.md +141 -0
- package/skills/ai/ai-artist/references/llm-prompting.md +165 -0
- package/skills/ai/ai-artist/references/nano-banana.md +136 -0
- package/skills/ai/ai-artist/references/reasoning-techniques.md +201 -0
- package/skills/ai/ai-artist/references/validation-workflow.md +117 -0
- package/skills/ai/ai-artist/scripts/core.py +197 -0
- package/skills/ai/ai-artist/scripts/extract_prompts.py +102 -0
- package/skills/ai/ai-artist/scripts/generate.py +370 -0
- package/skills/ai/ai-artist/scripts/search.py +147 -0
- package/skills/ai/ai-multimodal/.env.example +204 -0
- package/skills/ai/ai-multimodal/SKILL.md +110 -0
- package/skills/ai/ai-multimodal/references/audio-processing.md +387 -0
- package/skills/ai/ai-multimodal/references/image-generation.md +939 -0
- package/skills/ai/ai-multimodal/references/music-generation.md +311 -0
- package/skills/ai/ai-multimodal/references/video-analysis.md +515 -0
- package/skills/ai/ai-multimodal/references/video-generation.md +457 -0
- package/skills/ai/ai-multimodal/references/vision-understanding.md +492 -0
- package/skills/ai/ai-multimodal/scripts/.coverage +0 -0
- package/skills/ai/ai-multimodal/scripts/check_setup.py +315 -0
- package/skills/ai/ai-multimodal/scripts/document_converter.py +395 -0
- package/skills/ai/ai-multimodal/scripts/gemini_batch_process.py +1185 -0
- package/skills/ai/ai-multimodal/scripts/media_optimizer.py +506 -0
- package/skills/ai/ai-multimodal/scripts/requirements.txt +26 -0
- package/skills/ai/ai-multimodal/scripts/tests/.coverage +0 -0
- package/skills/ai/ai-multimodal/scripts/tests/requirements.txt +20 -0
- package/skills/ai/ai-multimodal/scripts/tests/test_document_converter.py +74 -0
- package/skills/ai/ai-multimodal/scripts/tests/test_gemini_batch_process.py +362 -0
- package/skills/ai/ai-multimodal/scripts/tests/test_media_optimizer.py +373 -0
- package/skills/ai/mcp-management/README.md +219 -0
- package/skills/ai/mcp-management/SKILL.md +210 -0
- package/skills/ai/mcp-management/assets/tools.json +3146 -0
- package/skills/ai/mcp-management/references/configuration.md +114 -0
- package/skills/ai/mcp-management/references/gemini-cli-integration.md +221 -0
- package/skills/ai/mcp-management/references/mcp-protocol.md +116 -0
- package/skills/ai/mcp-management/scripts/.env.example +10 -0
- package/skills/ai/mcp-management/scripts/cli.ts +195 -0
- package/skills/ai/mcp-management/scripts/dist/analyze-tools.js +70 -0
- package/skills/ai/mcp-management/scripts/dist/cli.js +160 -0
- package/skills/ai/mcp-management/scripts/dist/mcp-client.js +183 -0
- package/skills/ai/mcp-management/scripts/mcp-client.ts +230 -0
- package/skills/ai/mcp-management/scripts/package.json +20 -0
- package/skills/ai/mcp-management/scripts/tsconfig.json +15 -0
- package/skills/core/brainstorm/SKILL.md +164 -0
- package/skills/core/brainstorm/scripts/frame-template.html +214 -0
- package/skills/core/brainstorm/scripts/helper.js +88 -0
- package/skills/core/brainstorm/scripts/server.cjs +338 -0
- package/skills/core/brainstorm/scripts/start-server.sh +153 -0
- package/skills/core/brainstorm/scripts/stop-server.sh +55 -0
- package/skills/core/brainstorm/spec-document-reviewer-prompt.md +49 -0
- package/skills/core/brainstorm/visual-companion.md +286 -0
- package/skills/core/code-review/SKILL.md +147 -0
- package/skills/core/code-review/references/code-review-reception.md +113 -0
- package/skills/core/code-review/references/codebase-scan-workflow.md +29 -0
- package/skills/core/code-review/references/edge-case-scouting.md +119 -0
- package/skills/core/code-review/references/parallel-review-workflow.md +69 -0
- package/skills/core/code-review/references/requesting-code-review.md +116 -0
- package/skills/core/code-review/references/task-management-reviews.md +140 -0
- package/skills/core/code-review/references/verification-before-completion.md +139 -0
- package/skills/core/cook/README.md +86 -0
- package/skills/core/cook/SKILL.md +113 -0
- package/skills/core/cook/references/intent-detection.md +101 -0
- package/skills/core/cook/references/review-cycle.md +75 -0
- package/skills/core/cook/references/subagent-patterns.md +75 -0
- package/skills/core/cook/references/workflow-steps.md +172 -0
- package/skills/core/debug/SKILL.md +121 -0
- package/skills/core/debug/references/defense-in-depth.md +124 -0
- package/skills/core/debug/references/frontend-verification.md +103 -0
- package/skills/core/debug/references/investigation-methodology.md +101 -0
- package/skills/core/debug/references/log-and-ci-analysis.md +97 -0
- package/skills/core/debug/references/performance-diagnostics.md +113 -0
- package/skills/core/debug/references/reporting-standards.md +122 -0
- package/skills/core/debug/references/root-cause-tracing.md +122 -0
- package/skills/core/debug/references/systematic-debugging.md +102 -0
- package/skills/core/debug/references/task-management-debugging.md +155 -0
- package/skills/core/debug/references/verification.md +123 -0
- package/skills/core/debug/scripts/find-polluter.sh +63 -0
- package/skills/core/debug/scripts/find-polluter.test.md +102 -0
- package/skills/core/execute/SKILL.md +70 -0
- package/skills/core/fix/SKILL.md +111 -0
- package/skills/core/fix/references/complexity-assessment.md +72 -0
- package/skills/core/fix/references/mode-selection.md +46 -0
- package/skills/core/fix/references/parallel-exploration.md +100 -0
- package/skills/core/fix/references/review-cycle.md +77 -0
- package/skills/core/fix/references/skill-activation-matrix.md +78 -0
- package/skills/core/fix/references/task-orchestration.md +103 -0
- package/skills/core/fix/references/workflow-ci.md +28 -0
- package/skills/core/fix/references/workflow-deep.md +122 -0
- package/skills/core/fix/references/workflow-logs.md +72 -0
- package/skills/core/fix/references/workflow-quick.md +59 -0
- package/skills/core/fix/references/workflow-standard.md +111 -0
- package/skills/core/fix/references/workflow-test.md +75 -0
- package/skills/core/fix/references/workflow-types.md +33 -0
- package/skills/core/fix/references/workflow-ui.md +75 -0
- package/skills/core/plan/SKILL.md +145 -0
- package/skills/core/plan/plan-document-reviewer-prompt.md +49 -0
- package/skills/core/subagent-dev/SKILL.md +277 -0
- package/skills/core/subagent-dev/code-quality-reviewer-prompt.md +26 -0
- package/skills/core/subagent-dev/implementer-prompt.md +113 -0
- package/skills/core/subagent-dev/spec-reviewer-prompt.md +61 -0
- package/skills/core/tdd/SKILL.md +371 -0
- package/skills/core/tdd/testing-anti-patterns.md +299 -0
- package/skills/core/test/SKILL.md +109 -0
- package/skills/core/test/references/report-format.md +58 -0
- package/skills/core/test/references/test-execution-workflow.md +103 -0
- package/skills/core/test/references/ui-testing-workflow.md +65 -0
- package/skills/core/verify/SKILL.md +139 -0
- package/skills/dev/backend-dev/SKILL.md +96 -0
- package/skills/dev/backend-dev/references/backend-api-design.md +495 -0
- package/skills/dev/backend-dev/references/backend-architecture.md +454 -0
- package/skills/dev/backend-dev/references/backend-authentication.md +338 -0
- package/skills/dev/backend-dev/references/backend-code-quality.md +659 -0
- package/skills/dev/backend-dev/references/backend-debugging.md +904 -0
- package/skills/dev/backend-dev/references/backend-devops.md +494 -0
- package/skills/dev/backend-dev/references/backend-mindset.md +387 -0
- package/skills/dev/backend-dev/references/backend-performance.md +397 -0
- package/skills/dev/backend-dev/references/backend-security.md +290 -0
- package/skills/dev/backend-dev/references/backend-technologies.md +256 -0
- package/skills/dev/backend-dev/references/backend-testing.md +429 -0
- package/skills/dev/context-engineering/SKILL.md +108 -0
- package/skills/dev/context-engineering/references/context-compression.md +84 -0
- package/skills/dev/context-engineering/references/context-degradation.md +93 -0
- package/skills/dev/context-engineering/references/context-fundamentals.md +75 -0
- package/skills/dev/context-engineering/references/context-optimization.md +82 -0
- package/skills/dev/context-engineering/references/evaluation.md +89 -0
- package/skills/dev/context-engineering/references/memory-systems.md +88 -0
- package/skills/dev/context-engineering/references/multi-agent-patterns.md +90 -0
- package/skills/dev/context-engineering/references/project-development.md +97 -0
- package/skills/dev/context-engineering/references/runtime-awareness.md +202 -0
- package/skills/dev/context-engineering/references/tool-design.md +86 -0
- package/skills/dev/context-engineering/scripts/compression_evaluator.py +349 -0
- package/skills/dev/context-engineering/scripts/context_analyzer.py +317 -0
- package/skills/dev/context-engineering/scripts/tests/test_edge_cases.py +246 -0
- package/skills/dev/databases/SKILL.md +84 -0
- package/skills/dev/databases/analytics.md +198 -0
- package/skills/dev/databases/db-design.md +188 -0
- package/skills/dev/databases/incremental-etl.md +213 -0
- package/skills/dev/databases/references/mongodb-aggregation.md +447 -0
- package/skills/dev/databases/references/mongodb-atlas.md +465 -0
- package/skills/dev/databases/references/mongodb-crud.md +408 -0
- package/skills/dev/databases/references/mongodb-indexing.md +442 -0
- package/skills/dev/databases/references/postgresql-administration.md +594 -0
- package/skills/dev/databases/references/postgresql-performance.md +527 -0
- package/skills/dev/databases/references/postgresql-psql-cli.md +467 -0
- package/skills/dev/databases/references/postgresql-queries.md +475 -0
- package/skills/dev/databases/scripts/.coverage +0 -0
- package/skills/dev/databases/scripts/db_backup.py +502 -0
- package/skills/dev/databases/scripts/db_migrate.py +426 -0
- package/skills/dev/databases/scripts/db_performance_check.py +457 -0
- package/skills/dev/databases/scripts/requirements.txt +20 -0
- package/skills/dev/databases/scripts/tests/coverage-db.json +1 -0
- package/skills/dev/databases/scripts/tests/requirements.txt +4 -0
- package/skills/dev/databases/scripts/tests/test_db_backup.py +340 -0
- package/skills/dev/databases/scripts/tests/test_db_migrate.py +277 -0
- package/skills/dev/databases/scripts/tests/test_db_performance_check.py +370 -0
- package/skills/dev/databases/stacks/bigquery.md +231 -0
- package/skills/dev/databases/stacks/d1_cloudflare.md +137 -0
- package/skills/dev/databases/stacks/mysql.md +216 -0
- package/skills/dev/databases/stacks/postgres.md +235 -0
- package/skills/dev/databases/stacks/sqlite.md +244 -0
- package/skills/dev/databases/transactional.md +176 -0
- package/skills/dev/devops/.env.example +76 -0
- package/skills/dev/devops/SKILL.md +97 -0
- package/skills/dev/devops/references/browser-rendering.md +305 -0
- package/skills/dev/devops/references/cloudflare-d1-kv.md +123 -0
- package/skills/dev/devops/references/cloudflare-platform.md +271 -0
- package/skills/dev/devops/references/cloudflare-r2-storage.md +280 -0
- package/skills/dev/devops/references/cloudflare-workers-advanced.md +312 -0
- package/skills/dev/devops/references/cloudflare-workers-apis.md +309 -0
- package/skills/dev/devops/references/cloudflare-workers-basics.md +418 -0
- package/skills/dev/devops/references/docker-basics.md +297 -0
- package/skills/dev/devops/references/docker-compose.md +292 -0
- package/skills/dev/devops/references/gcloud-platform.md +297 -0
- package/skills/dev/devops/references/gcloud-services.md +304 -0
- package/skills/dev/devops/references/kubernetes-basics.md +99 -0
- package/skills/dev/devops/references/kubernetes-helm-advanced.md +75 -0
- package/skills/dev/devops/references/kubernetes-helm.md +81 -0
- package/skills/dev/devops/references/kubernetes-kubectl.md +74 -0
- package/skills/dev/devops/references/kubernetes-security-advanced.md +98 -0
- package/skills/dev/devops/references/kubernetes-security.md +95 -0
- package/skills/dev/devops/references/kubernetes-troubleshooting-advanced.md +74 -0
- package/skills/dev/devops/references/kubernetes-troubleshooting.md +49 -0
- package/skills/dev/devops/references/kubernetes-workflows-advanced.md +75 -0
- package/skills/dev/devops/references/kubernetes-workflows.md +78 -0
- package/skills/dev/devops/scripts/cloudflare_deploy.py +269 -0
- package/skills/dev/devops/scripts/docker_optimize.py +332 -0
- package/skills/dev/devops/scripts/requirements.txt +20 -0
- package/skills/dev/devops/scripts/tests/requirements.txt +3 -0
- package/skills/dev/devops/scripts/tests/test_cloudflare_deploy.py +285 -0
- package/skills/dev/devops/scripts/tests/test_docker_optimize.py +436 -0
- package/skills/dev/frontend-design/SKILL.md +78 -0
- package/skills/dev/frontend-design/references/ai-multimodal-overview.md +165 -0
- package/skills/dev/frontend-design/references/analysis-best-practices.md +80 -0
- package/skills/dev/frontend-design/references/analysis-prompts.md +141 -0
- package/skills/dev/frontend-design/references/analysis-techniques.md +118 -0
- package/skills/dev/frontend-design/references/animejs.md +396 -0
- package/skills/dev/frontend-design/references/asset-generation.md +337 -0
- package/skills/dev/frontend-design/references/design-extraction-overview.md +71 -0
- package/skills/dev/frontend-design/references/extraction-best-practices.md +141 -0
- package/skills/dev/frontend-design/references/extraction-output-templates.md +162 -0
- package/skills/dev/frontend-design/references/extraction-prompts.md +127 -0
- package/skills/dev/frontend-design/references/technical-accessibility.md +119 -0
- package/skills/dev/frontend-design/references/technical-best-practices.md +97 -0
- package/skills/dev/frontend-design/references/technical-optimization.md +44 -0
- package/skills/dev/frontend-design/references/technical-overview.md +90 -0
- package/skills/dev/frontend-design/references/technical-workflows.md +150 -0
- package/skills/dev/frontend-design/references/visual-analysis-overview.md +95 -0
- package/skills/dev/frontend-design/references/workflow-3d.md +102 -0
- package/skills/dev/frontend-design/references/workflow-describe.md +87 -0
- package/skills/dev/frontend-design/references/workflow-immersive.md +87 -0
- package/skills/dev/frontend-design/references/workflow-quick.md +57 -0
- package/skills/dev/frontend-design/references/workflow-screenshot.md +63 -0
- package/skills/dev/frontend-design/references/workflow-video.md +74 -0
- package/skills/dev/frontend-dev/SKILL.md +400 -0
- package/skills/dev/frontend-dev/resources/common-patterns.md +331 -0
- package/skills/dev/frontend-dev/resources/complete-examples.md +872 -0
- package/skills/dev/frontend-dev/resources/component-patterns.md +502 -0
- package/skills/dev/frontend-dev/resources/data-fetching.md +767 -0
- package/skills/dev/frontend-dev/resources/file-organization.md +502 -0
- package/skills/dev/frontend-dev/resources/loading-and-error-states.md +501 -0
- package/skills/dev/frontend-dev/resources/performance.md +406 -0
- package/skills/dev/frontend-dev/resources/routing-guide.md +364 -0
- package/skills/dev/frontend-dev/resources/styling-guide.md +428 -0
- package/skills/dev/frontend-dev/resources/typescript-standards.md +418 -0
- package/skills/dev/git/SKILL.md +114 -0
- package/skills/dev/git/references/branch-management.md +88 -0
- package/skills/dev/git/references/commit-standards.md +46 -0
- package/skills/dev/git/references/gh-cli-guide.md +109 -0
- package/skills/dev/git/references/safety-protocols.md +69 -0
- package/skills/dev/git/references/workflow-commit.md +58 -0
- package/skills/dev/git/references/workflow-merge.md +48 -0
- package/skills/dev/git/references/workflow-pr.md +58 -0
- package/skills/dev/git/references/workflow-push.md +52 -0
- package/skills/dev/git-worktree/SKILL.md +218 -0
- package/skills/utils/ask/SKILL.md +58 -0
- package/skills/utils/bootstrap/SKILL.md +101 -0
- package/skills/utils/bootstrap/references/shared-phases.md +59 -0
- package/skills/utils/bootstrap/references/workflow-auto.md +52 -0
- package/skills/utils/bootstrap/references/workflow-fast.md +50 -0
- package/skills/utils/bootstrap/references/workflow-full.md +60 -0
- package/skills/utils/bootstrap/references/workflow-parallel.md +59 -0
- package/skills/utils/ck-help/SKILL.md +102 -0
- package/skills/utils/ck-help/scripts/ck-help.py +1321 -0
- package/skills/utils/ck-help/scripts/commands_data.yaml +3 -0
- package/skills/utils/ck-help/scripts/skills_data.yaml +593 -0
- package/skills/utils/copywriting/SKILL.md +94 -0
- package/skills/utils/copywriting/references/copy-formulas.md +150 -0
- package/skills/utils/copywriting/references/cta-patterns.md +168 -0
- package/skills/utils/copywriting/references/email-copy.md +193 -0
- package/skills/utils/copywriting/references/headline-templates.md +140 -0
- package/skills/utils/copywriting/references/landing-page-copy.md +175 -0
- package/skills/utils/copywriting/references/power-words.md +189 -0
- package/skills/utils/copywriting/references/social-media-copy.md +222 -0
- package/skills/utils/copywriting/references/workflow-cro.md +83 -0
- package/skills/utils/copywriting/references/workflow-enhance.md +32 -0
- package/skills/utils/copywriting/references/workflow-fast.md +29 -0
- package/skills/utils/copywriting/references/workflow-good.md +39 -0
- package/skills/utils/copywriting/references/writing-styles.md +247 -0
- package/skills/utils/copywriting/scripts/extract-writing-styles.py +308 -0
- package/skills/utils/copywriting/templates/copy-brief.md +49 -0
- package/skills/utils/docs/SKILL.md +55 -0
- package/skills/utils/docs/references/init-workflow.md +32 -0
- package/skills/utils/docs/references/summarize-workflow.md +18 -0
- package/skills/utils/docs/references/update-workflow.md +59 -0
- package/skills/utils/journal/SKILL.md +11 -0
- package/skills/utils/kanban/SKILL.md +99 -0
- package/skills/utils/preview/SKILL.md +75 -0
- package/skills/utils/preview/references/generation-modes.md +95 -0
- package/skills/utils/preview/references/view-mode.md +42 -0
- package/skills/utils/repomix/SKILL.md +248 -0
- package/skills/utils/repomix/references/configuration.md +211 -0
- package/skills/utils/repomix/references/usage-patterns.md +232 -0
- package/skills/utils/repomix/scripts/.coverage +0 -0
- package/skills/utils/repomix/scripts/README.md +179 -0
- package/skills/utils/repomix/scripts/repomix_batch.py +455 -0
- package/skills/utils/repomix/scripts/repos.example.json +15 -0
- package/skills/utils/repomix/scripts/requirements.txt +15 -0
- package/skills/utils/repomix/scripts/tests/test_repomix_batch.py +531 -0
- package/skills/utils/research/SKILL.md +171 -0
- package/skills/utils/scout/SKILL.md +89 -0
- package/skills/utils/scout/references/external-scouting.md +140 -0
- package/skills/utils/scout/references/internal-scouting.md +119 -0
- package/skills/utils/scout/references/task-management-scouting.md +125 -0
- package/skills/utils/sequential-thinking/.env.example +8 -0
- package/skills/utils/sequential-thinking/README.md +183 -0
- package/skills/utils/sequential-thinking/SKILL.md +95 -0
- package/skills/utils/sequential-thinking/package.json +31 -0
- package/skills/utils/sequential-thinking/references/advanced-strategies.md +79 -0
- package/skills/utils/sequential-thinking/references/advanced-techniques.md +76 -0
- package/skills/utils/sequential-thinking/references/core-patterns.md +95 -0
- package/skills/utils/sequential-thinking/references/examples-api.md +88 -0
- package/skills/utils/sequential-thinking/references/examples-architecture.md +94 -0
- package/skills/utils/sequential-thinking/references/examples-debug.md +90 -0
- package/skills/utils/sequential-thinking/scripts/format-thought.js +159 -0
- package/skills/utils/sequential-thinking/scripts/process-thought.js +236 -0
- package/skills/utils/sequential-thinking/tests/format-thought.test.js +133 -0
- package/skills/utils/sequential-thinking/tests/process-thought.test.js +215 -0
- package/skills/utils/write-skill/SKILL.md +655 -0
- package/skills/utils/write-skill/anthropic-best-practices.md +1150 -0
- package/skills/utils/write-skill/examples/CLAUDE_MD_TESTING.md +189 -0
- package/skills/utils/write-skill/graphviz-conventions.dot +172 -0
- package/skills/utils/write-skill/persuasion-principles.md +187 -0
- package/skills/utils/write-skill/render-graphs.js +168 -0
- package/skills/utils/write-skill/testing-skills-with-subagents.md +384 -0
- package/src/commands/init.js +238 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* privacy-block.cjs - Block access to sensitive files unless user-approved
|
|
4
|
+
*
|
|
5
|
+
* PRIVACY-based blocking (separate from SIZE-based scout-block)
|
|
6
|
+
* Blocks sensitive files. LLM must get user approval and use APPROVED: prefix.
|
|
7
|
+
*
|
|
8
|
+
* Flow:
|
|
9
|
+
* 1. LLM tries: Read ".env" ā BLOCKED
|
|
10
|
+
* 2. LLM asks user for permission
|
|
11
|
+
* 3. User approves
|
|
12
|
+
* 4. LLM retries: Read "APPROVED:.env" ā ALLOWED
|
|
13
|
+
*
|
|
14
|
+
* Core logic extracted to lib/privacy-checker.cjs for OpenCode plugin reuse.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
(async () => {
|
|
18
|
+
try {
|
|
19
|
+
const path = require('path');
|
|
20
|
+
|
|
21
|
+
// Import shared privacy checking logic
|
|
22
|
+
const {
|
|
23
|
+
checkPrivacy,
|
|
24
|
+
isSafeFile,
|
|
25
|
+
isPrivacyBlockDisabled,
|
|
26
|
+
isPrivacySensitive,
|
|
27
|
+
hasApprovalPrefix,
|
|
28
|
+
stripApprovalPrefix,
|
|
29
|
+
extractPaths,
|
|
30
|
+
isSuspiciousPath
|
|
31
|
+
} = require('./lib/privacy-checker.cjs');
|
|
32
|
+
const { isHookEnabled } = require('./lib/ck-config-utils.cjs');
|
|
33
|
+
|
|
34
|
+
// Early exit if hook disabled in config
|
|
35
|
+
if (!isHookEnabled('privacy-block')) {
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Format block message with approval instructions and JSON marker for AskUserQuestion
|
|
41
|
+
* @param {string} filePath - Blocked file path
|
|
42
|
+
* @returns {string} Formatted block message with JSON marker
|
|
43
|
+
*/
|
|
44
|
+
function formatBlockMessage(filePath) {
|
|
45
|
+
const basename = path.basename(filePath);
|
|
46
|
+
|
|
47
|
+
// JSON marker for LLM to parse and use AskUserQuestion tool
|
|
48
|
+
const promptData = {
|
|
49
|
+
type: 'PRIVACY_PROMPT',
|
|
50
|
+
file: filePath,
|
|
51
|
+
basename: basename,
|
|
52
|
+
question: {
|
|
53
|
+
header: 'File Access',
|
|
54
|
+
text: `I need to read "${basename}" which may contain sensitive data (API keys, passwords, tokens). Do you approve?`,
|
|
55
|
+
options: [
|
|
56
|
+
{ label: 'Yes, approve access', description: `Allow reading ${basename} this time` },
|
|
57
|
+
{ label: 'No, skip this file', description: 'Continue without accessing this file' }
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return `
|
|
63
|
+
\x1b[36mNOTE:\x1b[0m This is not an error - this block protects sensitive data.
|
|
64
|
+
|
|
65
|
+
\x1b[33mPRIVACY BLOCK\x1b[0m: Sensitive file access requires user approval
|
|
66
|
+
|
|
67
|
+
\x1b[33mFile:\x1b[0m ${filePath}
|
|
68
|
+
|
|
69
|
+
This file may contain secrets (API keys, passwords, tokens).
|
|
70
|
+
|
|
71
|
+
\x1b[90m@@PRIVACY_PROMPT_START@@\x1b[0m
|
|
72
|
+
${JSON.stringify(promptData, null, 2)}
|
|
73
|
+
\x1b[90m@@PRIVACY_PROMPT_END@@\x1b[0m
|
|
74
|
+
|
|
75
|
+
\x1b[34mClaude:\x1b[0m Use AskUserQuestion tool with the JSON above, then:
|
|
76
|
+
\x1b[32mIf "Yes":\x1b[0m Use bash to read: cat "${filePath}"
|
|
77
|
+
\x1b[31mIf "No":\x1b[0m Continue without this file.
|
|
78
|
+
`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Format approval notice
|
|
83
|
+
* @param {string} filePath - Approved file path
|
|
84
|
+
* @returns {string} Formatted approval notice
|
|
85
|
+
*/
|
|
86
|
+
function formatApprovalNotice(filePath) {
|
|
87
|
+
return `\x1b[32mā\x1b[0m Privacy: User-approved access to ${path.basename(filePath)}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Main
|
|
91
|
+
async function main() {
|
|
92
|
+
let input = '';
|
|
93
|
+
for await (const chunk of process.stdin) {
|
|
94
|
+
input += chunk;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let hookData;
|
|
98
|
+
try {
|
|
99
|
+
hookData = JSON.parse(input);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
process.exit(0); // Invalid JSON, allow
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const { tool_input: toolInput, tool_name: toolName } = hookData;
|
|
105
|
+
|
|
106
|
+
// Use shared privacy checker
|
|
107
|
+
const result = checkPrivacy({
|
|
108
|
+
toolName,
|
|
109
|
+
toolInput,
|
|
110
|
+
options: { allowBash: true }
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Handle results
|
|
114
|
+
if (result.approved) {
|
|
115
|
+
// User approved - allow with notice
|
|
116
|
+
if (result.suspicious) {
|
|
117
|
+
console.error('\x1b[33mWARN:\x1b[0m Approved path is outside project:', result.filePath);
|
|
118
|
+
}
|
|
119
|
+
console.error(formatApprovalNotice(result.filePath));
|
|
120
|
+
process.exit(0);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (result.isBash) {
|
|
124
|
+
// Bash: warn but don't block - allows "Yes ā bash cat" flow
|
|
125
|
+
console.error(`\x1b[33mWARN:\x1b[0m ${result.reason}`);
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (result.blocked) {
|
|
130
|
+
// No approval - block
|
|
131
|
+
console.error(formatBlockMessage(result.filePath));
|
|
132
|
+
process.exit(2);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
process.exit(0); // Allow
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Run main only when executed directly (not when required for testing)
|
|
139
|
+
if (require.main === module) {
|
|
140
|
+
main().catch(() => process.exit(0));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Export functions for unit testing
|
|
144
|
+
if (typeof module !== 'undefined') {
|
|
145
|
+
module.exports = {
|
|
146
|
+
isSafeFile,
|
|
147
|
+
isPrivacyBlockDisabled,
|
|
148
|
+
isPrivacySensitive,
|
|
149
|
+
hasApprovalPrefix,
|
|
150
|
+
stripApprovalPrefix,
|
|
151
|
+
extractPaths,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
} catch (e) {
|
|
155
|
+
// Minimal crash logging (zero deps ā only Node builtins)
|
|
156
|
+
try {
|
|
157
|
+
const fs = require('fs');
|
|
158
|
+
const p = require('path');
|
|
159
|
+
const logDir = p.join(__dirname, '.logs');
|
|
160
|
+
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
|
|
161
|
+
fs.appendFileSync(p.join(logDir, 'hook-log.jsonl'),
|
|
162
|
+
JSON.stringify({ ts: new Date().toISOString(), hook: p.basename(__filename, '.cjs'), status: 'crash', error: e.message }) + '\n');
|
|
163
|
+
} catch (_) {}
|
|
164
|
+
process.exit(0); // fail-open
|
|
165
|
+
}
|
|
166
|
+
})();
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scout-block.cjs - Cross-platform hook for blocking directory access
|
|
4
|
+
*
|
|
5
|
+
* Blocks access to directories listed in .claude/.ckignore
|
|
6
|
+
* Uses gitignore-spec compliant pattern matching via 'ignore' package
|
|
7
|
+
*
|
|
8
|
+
* Blocking Rules:
|
|
9
|
+
* - File paths: Blocks any file_path/path/pattern containing blocked directories
|
|
10
|
+
* - Bash commands: Blocks directory access (cd, ls, cat, etc.) but ALLOWS build commands
|
|
11
|
+
* - Blocked: cd node_modules, ls packages/web/node_modules, cat dist/file.js
|
|
12
|
+
* - Allowed: npm build, go build, cargo build, make, mvn, gradle, docker build, kubectl, terraform
|
|
13
|
+
*
|
|
14
|
+
* Configuration:
|
|
15
|
+
* - Edit .claude/.ckignore to customize blocked patterns (one per line, # for comments)
|
|
16
|
+
* - Supports negation patterns (!) to allow specific paths
|
|
17
|
+
*
|
|
18
|
+
* Exit Codes:
|
|
19
|
+
* - 0: Command allowed
|
|
20
|
+
* - 2: Command blocked
|
|
21
|
+
*
|
|
22
|
+
* Core logic extracted to lib/scout-checker.cjs for OpenCode plugin reuse.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Crash wrapper ā catches require() failures and logs them
|
|
26
|
+
try {
|
|
27
|
+
const fs = require('fs');
|
|
28
|
+
const path = require('path');
|
|
29
|
+
|
|
30
|
+
// Import shared scout checking logic
|
|
31
|
+
const {
|
|
32
|
+
checkScoutBlock,
|
|
33
|
+
isBuildCommand,
|
|
34
|
+
isVenvExecutable,
|
|
35
|
+
isAllowedCommand
|
|
36
|
+
} = require('./lib/scout-checker.cjs');
|
|
37
|
+
const { isHookEnabled } = require('./lib/ck-config-utils.cjs');
|
|
38
|
+
|
|
39
|
+
// Early exit if hook disabled in config
|
|
40
|
+
if (!isHookEnabled('scout-block')) {
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Import formatters (kept local as they're Claude-specific output)
|
|
45
|
+
const { formatBlockedError } = require('./scout-block/error-formatter.cjs');
|
|
46
|
+
const { formatBroadPatternError } = require('./scout-block/broad-pattern-detector.cjs');
|
|
47
|
+
|
|
48
|
+
const { createHookTimer } = require('./lib/hook-logger.cjs');
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const timer = createHookTimer('scout-block');
|
|
52
|
+
// Read stdin synchronously
|
|
53
|
+
const hookInput = fs.readFileSync(0, 'utf-8');
|
|
54
|
+
|
|
55
|
+
// Validate input not empty
|
|
56
|
+
if (!hookInput || hookInput.trim().length === 0) {
|
|
57
|
+
console.error('ERROR: Empty input');
|
|
58
|
+
timer.end({ status: 'error', exit: 2 });
|
|
59
|
+
process.exit(2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Parse JSON
|
|
63
|
+
let data;
|
|
64
|
+
try {
|
|
65
|
+
data = JSON.parse(hookInput);
|
|
66
|
+
} catch (parseError) {
|
|
67
|
+
// Fail-open for unparseable input
|
|
68
|
+
console.error('WARN: JSON parse failed, allowing operation');
|
|
69
|
+
timer.end({ status: 'ok', exit: 0 });
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Validate structure
|
|
74
|
+
if (!data.tool_input || typeof data.tool_input !== 'object') {
|
|
75
|
+
// Fail-open for invalid structure
|
|
76
|
+
console.error('WARN: Invalid JSON structure, allowing operation');
|
|
77
|
+
timer.end({ status: 'ok', exit: 0 });
|
|
78
|
+
process.exit(0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const toolInput = data.tool_input;
|
|
82
|
+
const toolName = data.tool_name || 'unknown';
|
|
83
|
+
const claudeDir = path.dirname(__dirname); // Go up from hooks/ to .claude/
|
|
84
|
+
|
|
85
|
+
// Use shared scout checker
|
|
86
|
+
const result = checkScoutBlock({
|
|
87
|
+
toolName,
|
|
88
|
+
toolInput,
|
|
89
|
+
options: {
|
|
90
|
+
claudeDir,
|
|
91
|
+
ckignorePath: path.join(claudeDir, '.ckignore'),
|
|
92
|
+
checkBroadPatterns: true
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// Handle allowed commands
|
|
97
|
+
if (result.isAllowedCommand) {
|
|
98
|
+
timer.end({ tool: toolName, status: 'ok', exit: 0 });
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Handle broad pattern blocks
|
|
103
|
+
if (result.blocked && result.isBroadPattern) {
|
|
104
|
+
const errorMsg = formatBroadPatternError({
|
|
105
|
+
blocked: true,
|
|
106
|
+
reason: result.reason,
|
|
107
|
+
suggestions: result.suggestions
|
|
108
|
+
}, claudeDir);
|
|
109
|
+
console.error(errorMsg);
|
|
110
|
+
timer.end({ tool: toolName, status: 'block', exit: 2 });
|
|
111
|
+
process.exit(2);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Handle pattern blocks
|
|
115
|
+
if (result.blocked) {
|
|
116
|
+
const errorMsg = formatBlockedError({
|
|
117
|
+
path: result.path,
|
|
118
|
+
pattern: result.pattern,
|
|
119
|
+
tool: toolName,
|
|
120
|
+
claudeDir: claudeDir
|
|
121
|
+
});
|
|
122
|
+
console.error(errorMsg);
|
|
123
|
+
timer.end({ tool: toolName, status: 'block', exit: 2 });
|
|
124
|
+
process.exit(2);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// All paths allowed
|
|
128
|
+
timer.end({ tool: toolName, status: 'ok', exit: 0 });
|
|
129
|
+
process.exit(0);
|
|
130
|
+
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// Fail-open for unexpected errors
|
|
133
|
+
console.error('WARN: Hook error, allowing operation -', error.message);
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
} catch (e) {
|
|
137
|
+
// Minimal crash logging (zero deps ā only Node builtins)
|
|
138
|
+
try {
|
|
139
|
+
const fs = require('fs');
|
|
140
|
+
const p = require('path');
|
|
141
|
+
const logDir = p.join(__dirname, '.logs');
|
|
142
|
+
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
|
|
143
|
+
fs.appendFileSync(p.join(logDir, 'hook-log.jsonl'),
|
|
144
|
+
JSON.stringify({ ts: new Date().toISOString(), hook: p.basename(__filename, '.cjs'), status: 'crash', error: e.message }) + '\n');
|
|
145
|
+
} catch (_) {}
|
|
146
|
+
process.exit(0); // fail-open
|
|
147
|
+
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* SessionStart Hook - Initializes session environment with project detection
|
|
4
|
+
*
|
|
5
|
+
* Fires: Once per session (startup, resume, clear, compact)
|
|
6
|
+
* Purpose: Load config, detect project info, persist to env vars, output context
|
|
7
|
+
*
|
|
8
|
+
* Exit Codes:
|
|
9
|
+
* 0 - Success (non-blocking, allows continuation)
|
|
10
|
+
*
|
|
11
|
+
* Core detection logic extracted to lib/project-detector.cjs for OpenCode plugin reuse.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Crash wrapper
|
|
15
|
+
try {
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const os = require('os');
|
|
19
|
+
const {
|
|
20
|
+
loadConfig,
|
|
21
|
+
writeEnv,
|
|
22
|
+
writeSessionState,
|
|
23
|
+
resolvePlanPath,
|
|
24
|
+
getReportsPath,
|
|
25
|
+
resolveNamingPattern,
|
|
26
|
+
extractTaskListId,
|
|
27
|
+
isHookEnabled
|
|
28
|
+
} = require('./lib/ck-config-utils.cjs');
|
|
29
|
+
|
|
30
|
+
// Early exit if hook disabled in config
|
|
31
|
+
if (!isHookEnabled('session-init')) {
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Import shared project detection logic
|
|
36
|
+
const {
|
|
37
|
+
detectProjectType,
|
|
38
|
+
detectPackageManager,
|
|
39
|
+
detectFramework,
|
|
40
|
+
getPythonVersion,
|
|
41
|
+
getGitRemoteUrl,
|
|
42
|
+
getGitBranch,
|
|
43
|
+
getGitRoot,
|
|
44
|
+
getCodingLevelStyleName,
|
|
45
|
+
getCodingLevelGuidelines,
|
|
46
|
+
buildContextOutput,
|
|
47
|
+
execSafe
|
|
48
|
+
} = require('./lib/project-detector.cjs');
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* One-time cleanup for orphaned .shadowed/ directories from skill-dedup hook (Issue #422)
|
|
52
|
+
* The hook was disabled due to race conditions; this restores any orphaned skills.
|
|
53
|
+
*/
|
|
54
|
+
function cleanupOrphanedShadowedSkills() {
|
|
55
|
+
const shadowedDir = path.join(process.cwd(), '.claude', 'skills', '.shadowed');
|
|
56
|
+
if (!fs.existsSync(shadowedDir)) return { restored: [], skipped: [], kept: [] };
|
|
57
|
+
|
|
58
|
+
const skillsDir = path.join(process.cwd(), '.claude', 'skills');
|
|
59
|
+
const restored = [];
|
|
60
|
+
const skipped = [];
|
|
61
|
+
const kept = []; // Skills kept for manual review (content differs)
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const entries = fs.readdirSync(shadowedDir, { withFileTypes: true });
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
if (!entry.isDirectory()) continue;
|
|
67
|
+
const src = path.join(shadowedDir, entry.name);
|
|
68
|
+
const dest = path.join(skillsDir, entry.name);
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
if (!fs.existsSync(dest)) {
|
|
72
|
+
fs.renameSync(src, dest);
|
|
73
|
+
restored.push(entry.name);
|
|
74
|
+
} else {
|
|
75
|
+
// Skill exists in local - verify content match before deleting orphaned copy
|
|
76
|
+
const orphanedSkill = path.join(src, 'SKILL.md');
|
|
77
|
+
const localSkill = path.join(dest, 'SKILL.md');
|
|
78
|
+
if (fs.existsSync(orphanedSkill) && fs.existsSync(localSkill)) {
|
|
79
|
+
const orphanedContent = fs.readFileSync(orphanedSkill, 'utf8');
|
|
80
|
+
const localContent = fs.readFileSync(localSkill, 'utf8');
|
|
81
|
+
if (orphanedContent === localContent) {
|
|
82
|
+
// Content identical - safe to remove orphaned duplicate
|
|
83
|
+
fs.rmSync(src, { recursive: true, force: true });
|
|
84
|
+
skipped.push(entry.name);
|
|
85
|
+
} else {
|
|
86
|
+
// Content differs - user may have edited orphaned version, keep for review
|
|
87
|
+
kept.push(entry.name);
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
// Missing SKILL.md - safe to remove orphaned copy
|
|
91
|
+
fs.rmSync(src, { recursive: true, force: true });
|
|
92
|
+
skipped.push(entry.name);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
process.stderr.write(`[session-init] Failed to process "${entry.name}": ${err.message}\n`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Clean up manifest and shadowed dir if empty
|
|
100
|
+
const manifestFile = path.join(shadowedDir, '.dedup-manifest.json');
|
|
101
|
+
if (fs.existsSync(manifestFile)) fs.unlinkSync(manifestFile);
|
|
102
|
+
// Only remove shadowed dir if empty (kept skills may remain)
|
|
103
|
+
const remaining = fs.readdirSync(shadowedDir);
|
|
104
|
+
if (remaining.length === 0) fs.rmdirSync(shadowedDir);
|
|
105
|
+
return { restored, skipped, kept };
|
|
106
|
+
} catch (err) {
|
|
107
|
+
process.stderr.write(`[session-init] Shadowed cleanup error: ${err.message}\n`);
|
|
108
|
+
return { restored, skipped, kept };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Detect if this session is running inside an Agent Team.
|
|
114
|
+
* Scans ~/.claude/teams/ for active team configs and checks membership.
|
|
115
|
+
* Note: Returns first team found ā Claude Code supports one team per session.
|
|
116
|
+
* Note: Team lifecycle (creation/cleanup) is managed by Claude Code, not this hook.
|
|
117
|
+
* @returns {{ teamName: string, memberCount: number } | null}
|
|
118
|
+
*/
|
|
119
|
+
function detectAgentTeam() {
|
|
120
|
+
try {
|
|
121
|
+
const teamsDir = path.join(os.homedir(), '.claude', 'teams');
|
|
122
|
+
if (!fs.existsSync(teamsDir)) return null;
|
|
123
|
+
|
|
124
|
+
const teams = fs.readdirSync(teamsDir, { withFileTypes: true });
|
|
125
|
+
for (const entry of teams) {
|
|
126
|
+
if (!entry.isDirectory()) continue;
|
|
127
|
+
const configPath = path.join(teamsDir, entry.name, 'config.json');
|
|
128
|
+
if (!fs.existsSync(configPath)) continue;
|
|
129
|
+
try {
|
|
130
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
131
|
+
if (config.members && config.members.length > 0) {
|
|
132
|
+
return { teamName: entry.name, memberCount: config.members.length };
|
|
133
|
+
}
|
|
134
|
+
} catch { /* skip malformed configs */ }
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
} catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Main hook execution
|
|
144
|
+
*/
|
|
145
|
+
async function main() {
|
|
146
|
+
try {
|
|
147
|
+
// Issue #422: One-time cleanup of orphaned .shadowed/ from disabled skill-dedup hook
|
|
148
|
+
const shadowedCleanup = cleanupOrphanedShadowedSkills();
|
|
149
|
+
|
|
150
|
+
const stdin = fs.readFileSync(0, 'utf-8').trim();
|
|
151
|
+
const data = stdin ? JSON.parse(stdin) : {};
|
|
152
|
+
const envFile = process.env.CLAUDE_ENV_FILE;
|
|
153
|
+
const source = data.source || 'unknown';
|
|
154
|
+
const sessionId = data.session_id || null;
|
|
155
|
+
|
|
156
|
+
const config = loadConfig();
|
|
157
|
+
|
|
158
|
+
const detections = {
|
|
159
|
+
type: detectProjectType(config.project?.type),
|
|
160
|
+
pm: detectPackageManager(config.project?.packageManager),
|
|
161
|
+
framework: detectFramework(config.project?.framework)
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Resolve plan - now returns { path, resolvedBy }
|
|
165
|
+
const resolved = resolvePlanPath(null, config);
|
|
166
|
+
|
|
167
|
+
// CRITICAL FIX: Only persist explicitly-set plans to session state
|
|
168
|
+
// Branch-matched plans are "suggested" - stored separately, not as activePlan
|
|
169
|
+
// This prevents stale plan pollution on fresh sessions
|
|
170
|
+
if (sessionId) {
|
|
171
|
+
writeSessionState(sessionId, {
|
|
172
|
+
sessionOrigin: process.cwd(),
|
|
173
|
+
// Only session-resolved plans are truly "active"
|
|
174
|
+
activePlan: resolved.resolvedBy === 'session' ? resolved.path : null,
|
|
175
|
+
// Track suggested plan separately (for UI hints, not for report paths)
|
|
176
|
+
suggestedPlan: resolved.resolvedBy === 'branch' ? resolved.path : null,
|
|
177
|
+
timestamp: Date.now(),
|
|
178
|
+
source
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Reports path only uses active plans, not suggested ones
|
|
183
|
+
const reportsPath = getReportsPath(resolved.path, resolved.resolvedBy, config.plan, config.paths);
|
|
184
|
+
|
|
185
|
+
// Extract task list ID for Claude Code Tasks coordination (shared helper)
|
|
186
|
+
const taskListId = extractTaskListId(resolved);
|
|
187
|
+
|
|
188
|
+
// Collect static environment info (computed once per session)
|
|
189
|
+
const staticEnv = {
|
|
190
|
+
nodeVersion: process.version,
|
|
191
|
+
pythonVersion: getPythonVersion(),
|
|
192
|
+
osPlatform: process.platform,
|
|
193
|
+
gitUrl: getGitRemoteUrl(),
|
|
194
|
+
gitBranch: getGitBranch(),
|
|
195
|
+
gitRoot: getGitRoot(),
|
|
196
|
+
user: process.env.USERNAME || process.env.USER || process.env.LOGNAME || os.userInfo().username,
|
|
197
|
+
locale: process.env.LANG || '',
|
|
198
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
199
|
+
claudeSettingsDir: path.resolve(__dirname, '..')
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Compute base directory for absolute paths (Issue #327: use CWD for subdirectory support)
|
|
203
|
+
// Git root is kept in staticEnv for reference, but CWD determines where files are created
|
|
204
|
+
const baseDir = process.cwd();
|
|
205
|
+
|
|
206
|
+
// Compute resolved naming pattern (date + issue resolved, {slug} kept as placeholder)
|
|
207
|
+
const namePattern = resolveNamingPattern(config.plan, staticEnv.gitBranch);
|
|
208
|
+
|
|
209
|
+
if (envFile) {
|
|
210
|
+
// Session & plan config
|
|
211
|
+
writeEnv(envFile, 'CK_SESSION_ID', sessionId || '');
|
|
212
|
+
writeEnv(envFile, 'CK_PLAN_NAMING_FORMAT', config.plan.namingFormat);
|
|
213
|
+
writeEnv(envFile, 'CK_PLAN_DATE_FORMAT', config.plan.dateFormat);
|
|
214
|
+
writeEnv(envFile, 'CK_PLAN_ISSUE_PREFIX', config.plan.issuePrefix || '');
|
|
215
|
+
writeEnv(envFile, 'CK_PLAN_REPORTS_DIR', config.plan.reportsDir);
|
|
216
|
+
|
|
217
|
+
// NEW: Resolved naming pattern for DRY file naming in agents
|
|
218
|
+
// Example: "251212-1830-GH-88-{slug}" or "251212-1830-{slug}"
|
|
219
|
+
// Agents use: `{agent-type}-$CK_NAME_PATTERN.md` and substitute {slug}
|
|
220
|
+
writeEnv(envFile, 'CK_NAME_PATTERN', namePattern);
|
|
221
|
+
|
|
222
|
+
// Plan resolution
|
|
223
|
+
writeEnv(envFile, 'CK_ACTIVE_PLAN', resolved.resolvedBy === 'session' ? resolved.path : '');
|
|
224
|
+
writeEnv(envFile, 'CK_SUGGESTED_PLAN', resolved.resolvedBy === 'branch' ? resolved.path : '');
|
|
225
|
+
|
|
226
|
+
// Claude Code Tasks integration - enables multi-session/subagent coordination
|
|
227
|
+
// Task list ID = plan directory name (shared across all sessions working on same plan)
|
|
228
|
+
if (taskListId) {
|
|
229
|
+
writeEnv(envFile, 'CLAUDE_CODE_TASK_LIST_ID', taskListId);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Paths - use absolute paths based on CWD for subdirectory workflow support (Issue #327)
|
|
233
|
+
writeEnv(envFile, 'CK_GIT_ROOT', staticEnv.gitRoot || '');
|
|
234
|
+
writeEnv(envFile, 'CK_REPORTS_PATH', path.join(baseDir, reportsPath));
|
|
235
|
+
writeEnv(envFile, 'CK_DOCS_PATH', path.join(baseDir, config.paths.docs));
|
|
236
|
+
writeEnv(envFile, 'CK_PLANS_PATH', path.join(baseDir, config.paths.plans));
|
|
237
|
+
writeEnv(envFile, 'CK_PROJECT_ROOT', process.cwd());
|
|
238
|
+
|
|
239
|
+
// Project detection
|
|
240
|
+
writeEnv(envFile, 'CK_PROJECT_TYPE', detections.type || '');
|
|
241
|
+
writeEnv(envFile, 'CK_PACKAGE_MANAGER', detections.pm || '');
|
|
242
|
+
writeEnv(envFile, 'CK_FRAMEWORK', detections.framework || '');
|
|
243
|
+
|
|
244
|
+
// NEW: Static environment info (so other hooks don't need to recompute)
|
|
245
|
+
writeEnv(envFile, 'CK_NODE_VERSION', staticEnv.nodeVersion);
|
|
246
|
+
writeEnv(envFile, 'CK_PYTHON_VERSION', staticEnv.pythonVersion || '');
|
|
247
|
+
writeEnv(envFile, 'CK_OS_PLATFORM', staticEnv.osPlatform);
|
|
248
|
+
writeEnv(envFile, 'CK_GIT_URL', staticEnv.gitUrl || '');
|
|
249
|
+
writeEnv(envFile, 'CK_GIT_BRANCH', staticEnv.gitBranch || '');
|
|
250
|
+
writeEnv(envFile, 'CK_USER', staticEnv.user);
|
|
251
|
+
writeEnv(envFile, 'CK_LOCALE', staticEnv.locale);
|
|
252
|
+
writeEnv(envFile, 'CK_TIMEZONE', staticEnv.timezone);
|
|
253
|
+
writeEnv(envFile, 'CK_CLAUDE_SETTINGS_DIR', staticEnv.claudeSettingsDir);
|
|
254
|
+
|
|
255
|
+
// Locale config
|
|
256
|
+
if (config.locale?.thinkingLanguage) {
|
|
257
|
+
writeEnv(envFile, 'CK_THINKING_LANGUAGE', config.locale.thinkingLanguage);
|
|
258
|
+
}
|
|
259
|
+
if (config.locale?.responseLanguage) {
|
|
260
|
+
writeEnv(envFile, 'CK_RESPONSE_LANGUAGE', config.locale.responseLanguage);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Plan validation config (for /plan validate, /plan --hard, /plan --parallel)
|
|
264
|
+
const validation = config.plan?.validation || {};
|
|
265
|
+
writeEnv(envFile, 'CK_VALIDATION_MODE', validation.mode || 'prompt');
|
|
266
|
+
writeEnv(envFile, 'CK_VALIDATION_MIN_QUESTIONS', validation.minQuestions || 3);
|
|
267
|
+
writeEnv(envFile, 'CK_VALIDATION_MAX_QUESTIONS', validation.maxQuestions || 8);
|
|
268
|
+
writeEnv(envFile, 'CK_VALIDATION_FOCUS_AREAS', (validation.focusAreas || ['assumptions', 'risks', 'tradeoffs', 'architecture']).join(','));
|
|
269
|
+
|
|
270
|
+
// Coding level config (for output style selection)
|
|
271
|
+
const codingLevel = config.codingLevel ?? 5;
|
|
272
|
+
writeEnv(envFile, 'CK_CODING_LEVEL', codingLevel);
|
|
273
|
+
writeEnv(envFile, 'CK_CODING_LEVEL_STYLE', getCodingLevelStyleName(codingLevel));
|
|
274
|
+
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Agent Teams detection ā detect once, used for env vars and console output
|
|
278
|
+
const teamInfo = detectAgentTeam();
|
|
279
|
+
if (envFile && teamInfo) {
|
|
280
|
+
writeEnv(envFile, 'CK_AGENT_TEAM', teamInfo.teamName);
|
|
281
|
+
writeEnv(envFile, 'CK_AGENT_TEAM_MEMBERS', teamInfo.memberCount);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
console.log(`Session ${source}. ${buildContextOutput(config, detections, resolved, staticEnv.gitRoot)}`);
|
|
285
|
+
|
|
286
|
+
// Issue #422: Notify user if orphaned skills were recovered from .shadowed/
|
|
287
|
+
const hasCleanup = shadowedCleanup.restored.length > 0 || shadowedCleanup.skipped.length > 0 || shadowedCleanup.kept.length > 0;
|
|
288
|
+
if (hasCleanup) {
|
|
289
|
+
console.log(`\n[!] SKILL-DEDUP CLEANUP (Issue #422):`);
|
|
290
|
+
console.log(`Recovered orphaned .shadowed/ directory from disabled skill-dedup hook.`);
|
|
291
|
+
if (shadowedCleanup.restored.length > 0) {
|
|
292
|
+
console.log(`Restored ${shadowedCleanup.restored.length} skill(s): ${shadowedCleanup.restored.join(', ')}`);
|
|
293
|
+
}
|
|
294
|
+
if (shadowedCleanup.skipped.length > 0) {
|
|
295
|
+
console.log(`Removed ${shadowedCleanup.skipped.length} duplicate(s): ${shadowedCleanup.skipped.join(', ')}`);
|
|
296
|
+
}
|
|
297
|
+
if (shadowedCleanup.kept.length > 0) {
|
|
298
|
+
console.log(`[!] Kept ${shadowedCleanup.kept.length} skill(s) for manual review (content differs): ${shadowedCleanup.kept.join(', ')}`);
|
|
299
|
+
console.log(` Review .claude/skills/.shadowed/ and merge changes manually.`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Agent Teams: Show team context if running inside a team (uses cached result)
|
|
304
|
+
if (teamInfo) {
|
|
305
|
+
console.log(`[i] Agent Team detected: "${teamInfo.teamName}" (${teamInfo.memberCount} members)`);
|
|
306
|
+
console.log(` Team config: ~/.claude/teams/${teamInfo.teamName}/config.json`);
|
|
307
|
+
console.log(` Use /team skill for orchestration templates.`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Info: Show git root when running from subdirectory (Issue #327: now supported)
|
|
311
|
+
if (staticEnv.gitRoot && staticEnv.gitRoot !== process.cwd()) {
|
|
312
|
+
console.log(`š Subdirectory mode: Plans/docs will be created in current directory`);
|
|
313
|
+
console.log(` Git root: ${staticEnv.gitRoot}`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// MITIGATION: Issue #277 - Auto-compact can bypass AskUserQuestion approval gates
|
|
317
|
+
// When context is compacted mid-workflow, the summarization may lose "pending approval" state.
|
|
318
|
+
// This warning reminds Claude to verify if user approval was pending before proceeding.
|
|
319
|
+
// Upstream bug: Claude Code CLI should preserve pending interactive state during compaction.
|
|
320
|
+
if (source === 'compact') {
|
|
321
|
+
console.log(`\nā ļø CONTEXT COMPACTED - APPROVAL STATE CHECK:`);
|
|
322
|
+
console.log(`If you were waiting for user approval via AskUserQuestion (e.g., Step 4 review gate),`);
|
|
323
|
+
console.log(`you MUST re-confirm with the user before proceeding. Do NOT assume approval was given.`);
|
|
324
|
+
console.log(`Use AskUserQuestion to verify: "Context was compacted. Please confirm approval to continue."`);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Auto-inject coding level guidelines (if not disabled)
|
|
328
|
+
const codingLevel = config.codingLevel ?? -1;
|
|
329
|
+
const guidelines = getCodingLevelGuidelines(codingLevel);
|
|
330
|
+
if (guidelines) {
|
|
331
|
+
console.log(`\n${guidelines}`);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (config.assertions?.length > 0) {
|
|
335
|
+
console.log(`\nUser Assertions:`);
|
|
336
|
+
config.assertions.forEach((assertion, i) => {
|
|
337
|
+
console.log(` ${i + 1}. ${assertion}`);
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
process.exit(0);
|
|
342
|
+
} catch (error) {
|
|
343
|
+
console.error(`SessionStart hook error: ${error.message}`);
|
|
344
|
+
process.exit(0);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
main();
|
|
349
|
+
} catch (e) {
|
|
350
|
+
// Minimal crash logging (zero deps ā only Node builtins)
|
|
351
|
+
try {
|
|
352
|
+
const fs = require('fs');
|
|
353
|
+
const p = require('path');
|
|
354
|
+
const logDir = p.join(__dirname, '.logs');
|
|
355
|
+
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
|
|
356
|
+
fs.appendFileSync(p.join(logDir, 'hook-log.jsonl'),
|
|
357
|
+
JSON.stringify({ ts: new Date().toISOString(), hook: p.basename(__filename, '.cjs'), status: 'crash', error: e.message }) + '\n');
|
|
358
|
+
} catch (_) {}
|
|
359
|
+
process.exit(0); // fail-open
|
|
360
|
+
}
|