@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,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Git Info Cache - Cross-platform git information batching
|
|
6
|
+
*
|
|
7
|
+
* Problem: 5-6 git process spawns per statusline render are slow on Windows (CreateProcess overhead)
|
|
8
|
+
* Solution: Cache git query results for 3 seconds — subsequent renders read cache (zero processes)
|
|
9
|
+
*
|
|
10
|
+
* Performance: 5 spawns per render → event-driven refresh + 30s TTL fallback
|
|
11
|
+
* Cross-platform: No bash-only syntax (no 2>/dev/null), windowsHide on all exec calls
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { execSync } = require('child_process');
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const os = require('os');
|
|
18
|
+
|
|
19
|
+
// Cache TTL — long fallback for external changes (git checkout outside Claude)
|
|
20
|
+
// Active invalidation happens via PostToolUse hooks after Edit/Write/Bash
|
|
21
|
+
const CACHE_TTL = 30000;
|
|
22
|
+
const CACHE_MISS = Symbol('cache_miss');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Safe command execution wrapper with optional cwd
|
|
26
|
+
*/
|
|
27
|
+
function execIn(cmd, cwd) {
|
|
28
|
+
try {
|
|
29
|
+
return execSync(cmd, {
|
|
30
|
+
encoding: 'utf8',
|
|
31
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
32
|
+
windowsHide: true,
|
|
33
|
+
cwd: cwd || undefined
|
|
34
|
+
}).trim();
|
|
35
|
+
} catch {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get cache file path for current working directory
|
|
42
|
+
*/
|
|
43
|
+
function getCachePath(cwd) {
|
|
44
|
+
const hash = require('crypto')
|
|
45
|
+
.createHash('md5')
|
|
46
|
+
.update(cwd)
|
|
47
|
+
.digest('hex')
|
|
48
|
+
.slice(0, 8);
|
|
49
|
+
return path.join(os.tmpdir(), `ck-git-cache-${hash}.json`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Read cache if valid (not expired). Returns CACHE_MISS on miss.
|
|
54
|
+
* No existsSync check (TOCTOU race) — just try read and catch.
|
|
55
|
+
*/
|
|
56
|
+
function readCache(cachePath) {
|
|
57
|
+
try {
|
|
58
|
+
const cache = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
|
|
59
|
+
if (Date.now() - cache.timestamp < CACHE_TTL) {
|
|
60
|
+
return cache.data; // Can be null (non-git dir) or object (git info)
|
|
61
|
+
}
|
|
62
|
+
} catch {
|
|
63
|
+
// File missing, corrupted, or expired — all treated as cache miss
|
|
64
|
+
}
|
|
65
|
+
return CACHE_MISS;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Write cache atomically (temp file + rename to avoid partial reads on Windows)
|
|
70
|
+
*/
|
|
71
|
+
function writeCache(cachePath, data) {
|
|
72
|
+
const tmpPath = cachePath + '.tmp';
|
|
73
|
+
try {
|
|
74
|
+
fs.writeFileSync(tmpPath, JSON.stringify({ timestamp: Date.now(), data }));
|
|
75
|
+
fs.renameSync(tmpPath, cachePath);
|
|
76
|
+
} catch {
|
|
77
|
+
try { fs.unlinkSync(tmpPath); } catch {}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Count non-empty lines in a newline-delimited string
|
|
83
|
+
*/
|
|
84
|
+
function countLines(str) {
|
|
85
|
+
if (!str) return 0;
|
|
86
|
+
return str.split('\n').filter(l => l.trim()).length;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Fetch git info directly in-process
|
|
91
|
+
* The cache is what eliminates redundant spawns — not subprocess wrapping
|
|
92
|
+
* @param {string} cwd - Directory to run git commands in
|
|
93
|
+
* Returns: { branch, unstaged, staged, ahead, behind } or null if not git repo
|
|
94
|
+
*/
|
|
95
|
+
function fetchGitInfo(cwd) {
|
|
96
|
+
// Check if git repo (fast check) — run in target cwd, not process.cwd()
|
|
97
|
+
if (!execIn('git rev-parse --git-dir', cwd)) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const branch = execIn('git branch --show-current', cwd) || execIn('git rev-parse --short HEAD', cwd);
|
|
102
|
+
const unstaged = countLines(execIn('git diff --name-only', cwd));
|
|
103
|
+
const staged = countLines(execIn('git diff --cached --name-only', cwd));
|
|
104
|
+
|
|
105
|
+
// Ahead/behind — no 2>/dev/null (invalid on Windows cmd.exe)
|
|
106
|
+
let ahead = 0, behind = 0;
|
|
107
|
+
const aheadBehind = execIn('git rev-list --left-right --count @{u}...HEAD', cwd);
|
|
108
|
+
if (aheadBehind) {
|
|
109
|
+
const parts = aheadBehind.split(/\s+/);
|
|
110
|
+
behind = parseInt(parts[0], 10) || 0;
|
|
111
|
+
ahead = parseInt(parts[1], 10) || 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { branch, unstaged, staged, ahead, behind };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get git info with caching
|
|
119
|
+
* Main export function used by statusline
|
|
120
|
+
*/
|
|
121
|
+
function getGitInfo(cwd = process.cwd()) {
|
|
122
|
+
const cachePath = getCachePath(cwd);
|
|
123
|
+
|
|
124
|
+
// Try cache first (includes cached null for non-git dirs)
|
|
125
|
+
const cached = readCache(cachePath);
|
|
126
|
+
if (cached !== CACHE_MISS) return cached;
|
|
127
|
+
|
|
128
|
+
// Cache miss or expired, fetch fresh data in target cwd
|
|
129
|
+
const data = fetchGitInfo(cwd);
|
|
130
|
+
// Cache both positive and null results (avoids re-spawning git in non-git dirs)
|
|
131
|
+
writeCache(cachePath, data);
|
|
132
|
+
|
|
133
|
+
return data;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Invalidate cache for a directory (call after file changes to trigger fresh git query)
|
|
138
|
+
*/
|
|
139
|
+
function invalidateCache(cwd = process.cwd()) {
|
|
140
|
+
try { fs.unlinkSync(getCachePath(cwd)); } catch {}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = { getGitInfo, invalidateCache };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hook-logger.cjs - Zero-dependency structured logger for hooks
|
|
3
|
+
*
|
|
4
|
+
* Logs to .claude/hooks/.logs/hook-log.jsonl (JSON Lines format)
|
|
5
|
+
* Auto-creates .logs/ directory and handles rotation (1000 lines max → 500 last)
|
|
6
|
+
* Uses only Node builtins (fs, path) — no external dependencies
|
|
7
|
+
*
|
|
8
|
+
* Export: logHook(hookName, data), createHookTimer(hookName)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
const LOG_DIR = path.join(__dirname, '..', '.logs');
|
|
15
|
+
const LOG_FILE = path.join(LOG_DIR, 'hook-log.jsonl');
|
|
16
|
+
const MAX_LINES = 1000;
|
|
17
|
+
const TRUNCATE_TO = 500;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Ensure log directory exists
|
|
21
|
+
*/
|
|
22
|
+
function ensureLogDir() {
|
|
23
|
+
try {
|
|
24
|
+
if (!fs.existsSync(LOG_DIR)) {
|
|
25
|
+
fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
} catch (_) {
|
|
28
|
+
// Fail silently — never crash
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Rotate log file if it exceeds MAX_LINES
|
|
34
|
+
*/
|
|
35
|
+
function rotateIfNeeded() {
|
|
36
|
+
try {
|
|
37
|
+
if (!fs.existsSync(LOG_FILE)) return;
|
|
38
|
+
const lines = fs.readFileSync(LOG_FILE, 'utf-8').split('\n').filter(Boolean);
|
|
39
|
+
if (lines.length >= MAX_LINES) {
|
|
40
|
+
const truncated = lines.slice(-TRUNCATE_TO).join('\n') + '\n';
|
|
41
|
+
fs.writeFileSync(LOG_FILE, truncated, 'utf-8');
|
|
42
|
+
}
|
|
43
|
+
} catch (_) {
|
|
44
|
+
// Fail silently
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Log a hook event
|
|
50
|
+
* @param {string} hookName - Hook filename (e.g., 'scout-block')
|
|
51
|
+
* @param {object} data - Log data { tool?, dur?, status, exit?, error? }
|
|
52
|
+
*/
|
|
53
|
+
function logHook(hookName, data) {
|
|
54
|
+
try {
|
|
55
|
+
ensureLogDir();
|
|
56
|
+
rotateIfNeeded();
|
|
57
|
+
|
|
58
|
+
const entry = {
|
|
59
|
+
ts: new Date().toISOString(),
|
|
60
|
+
hook: hookName,
|
|
61
|
+
tool: data.tool || '',
|
|
62
|
+
dur: data.dur || 0,
|
|
63
|
+
status: data.status || 'ok',
|
|
64
|
+
exit: data.exit !== undefined ? data.exit : 0,
|
|
65
|
+
error: data.error || ''
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
fs.appendFileSync(LOG_FILE, JSON.stringify(entry) + '\n', 'utf-8');
|
|
69
|
+
} catch (_) {
|
|
70
|
+
// Never crash — fail silently
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Create a duration timer for a hook
|
|
76
|
+
* @param {string} hookName - Hook filename
|
|
77
|
+
* @returns {{ end: (data) => void }} Timer object with end() method
|
|
78
|
+
*/
|
|
79
|
+
function createHookTimer(hookName) {
|
|
80
|
+
const start = Date.now();
|
|
81
|
+
return {
|
|
82
|
+
end(data = {}) {
|
|
83
|
+
const dur = Date.now() - start;
|
|
84
|
+
logHook(hookName, { ...data, dur });
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
logHook,
|
|
91
|
+
createHookTimer
|
|
92
|
+
};
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* privacy-checker.cjs - Privacy pattern matching logic for sensitive file detection
|
|
4
|
+
*
|
|
5
|
+
* Extracted from privacy-block.cjs for reuse in both Claude hooks and OpenCode plugins.
|
|
6
|
+
* Pure logic module - no stdin/stdout, no exit codes.
|
|
7
|
+
*
|
|
8
|
+
* @module privacy-checker
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
|
|
14
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
|
+
// CONSTANTS
|
|
16
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
17
|
+
|
|
18
|
+
const APPROVED_PREFIX = 'APPROVED:';
|
|
19
|
+
|
|
20
|
+
// Safe file patterns - exempt from privacy checks (documentation/template files)
|
|
21
|
+
const SAFE_PATTERNS = [
|
|
22
|
+
/\.example$/i, // .env.example, config.example
|
|
23
|
+
/\.sample$/i, // .env.sample
|
|
24
|
+
/\.template$/i, // .env.template
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// Privacy-sensitive patterns
|
|
28
|
+
const PRIVACY_PATTERNS = [
|
|
29
|
+
/^\.env$/, // .env
|
|
30
|
+
/^\.env\./, // .env.local, .env.production, etc.
|
|
31
|
+
/\.env$/, // path/to/.env
|
|
32
|
+
/\/\.env\./, // path/to/.env.local
|
|
33
|
+
/credentials/i, // credentials.json, etc.
|
|
34
|
+
/secrets?\.ya?ml$/i, // secrets.yaml, secret.yml
|
|
35
|
+
/\.pem$/, // Private keys
|
|
36
|
+
/\.key$/, // Private keys
|
|
37
|
+
/id_rsa/, // SSH keys
|
|
38
|
+
/id_ed25519/, // SSH keys
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
+
// HELPER FUNCTIONS
|
|
43
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check if path is a safe file (example/sample/template)
|
|
47
|
+
* @param {string} testPath - Path to check
|
|
48
|
+
* @returns {boolean} true if file matches safe patterns
|
|
49
|
+
*/
|
|
50
|
+
function isSafeFile(testPath) {
|
|
51
|
+
if (!testPath) return false;
|
|
52
|
+
const basename = path.basename(testPath);
|
|
53
|
+
return SAFE_PATTERNS.some(p => p.test(basename));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if path has APPROVED: prefix
|
|
58
|
+
* @param {string} testPath - Path to check
|
|
59
|
+
* @returns {boolean} true if path starts with APPROVED:
|
|
60
|
+
*/
|
|
61
|
+
function hasApprovalPrefix(testPath) {
|
|
62
|
+
return testPath && testPath.startsWith(APPROVED_PREFIX);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Strip APPROVED: prefix from path
|
|
67
|
+
* @param {string} testPath - Path to process
|
|
68
|
+
* @returns {string} Path without APPROVED: prefix
|
|
69
|
+
*/
|
|
70
|
+
function stripApprovalPrefix(testPath) {
|
|
71
|
+
if (hasApprovalPrefix(testPath)) {
|
|
72
|
+
return testPath.slice(APPROVED_PREFIX.length);
|
|
73
|
+
}
|
|
74
|
+
return testPath;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check if stripped path is suspicious (path traversal or absolute)
|
|
79
|
+
* @param {string} strippedPath - Path after stripping APPROVED: prefix
|
|
80
|
+
* @returns {boolean} true if path looks suspicious
|
|
81
|
+
*/
|
|
82
|
+
function isSuspiciousPath(strippedPath) {
|
|
83
|
+
return strippedPath.includes('..') || path.isAbsolute(strippedPath);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if path matches privacy patterns
|
|
88
|
+
* @param {string} testPath - Path to check
|
|
89
|
+
* @returns {boolean} true if path matches privacy-sensitive patterns
|
|
90
|
+
*/
|
|
91
|
+
function isPrivacySensitive(testPath) {
|
|
92
|
+
if (!testPath) return false;
|
|
93
|
+
|
|
94
|
+
// Strip prefix for pattern matching
|
|
95
|
+
const cleanPath = stripApprovalPrefix(testPath);
|
|
96
|
+
let normalized = cleanPath.replace(/\\/g, '/');
|
|
97
|
+
|
|
98
|
+
// Decode URI components to catch obfuscated paths (%2e = '.')
|
|
99
|
+
try {
|
|
100
|
+
normalized = decodeURIComponent(normalized);
|
|
101
|
+
} catch (e) {
|
|
102
|
+
// Invalid encoding, use as-is
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Check safe patterns first - exempt example/sample/template files
|
|
106
|
+
if (isSafeFile(normalized)) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const basename = path.basename(normalized);
|
|
111
|
+
|
|
112
|
+
for (const pattern of PRIVACY_PATTERNS) {
|
|
113
|
+
if (pattern.test(basename) || pattern.test(normalized)) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract paths from tool input
|
|
122
|
+
* @param {Object} toolInput - Tool input object with file_path, path, pattern, or command
|
|
123
|
+
* @returns {Array<{value: string, field: string}>} Array of extracted paths with field names
|
|
124
|
+
*/
|
|
125
|
+
function extractPaths(toolInput) {
|
|
126
|
+
const paths = [];
|
|
127
|
+
if (!toolInput) return paths;
|
|
128
|
+
|
|
129
|
+
if (toolInput.file_path) paths.push({ value: toolInput.file_path, field: 'file_path' });
|
|
130
|
+
if (toolInput.path) paths.push({ value: toolInput.path, field: 'path' });
|
|
131
|
+
if (toolInput.pattern) paths.push({ value: toolInput.pattern, field: 'pattern' });
|
|
132
|
+
|
|
133
|
+
// Check bash commands for file paths
|
|
134
|
+
if (toolInput.command) {
|
|
135
|
+
// Look for APPROVED:.env or .env patterns
|
|
136
|
+
const approvedMatch = toolInput.command.match(/APPROVED:[^\s]+/g) || [];
|
|
137
|
+
approvedMatch.forEach(p => paths.push({ value: p, field: 'command' }));
|
|
138
|
+
|
|
139
|
+
// Only look for .env if no APPROVED: version found
|
|
140
|
+
if (approvedMatch.length === 0) {
|
|
141
|
+
const envMatch = toolInput.command.match(/\.env[^\s]*/g) || [];
|
|
142
|
+
envMatch.forEach(p => paths.push({ value: p, field: 'command' }));
|
|
143
|
+
|
|
144
|
+
// Also check bash variable assignments (FILE=.env, ENV_FILE=.env.local)
|
|
145
|
+
const varAssignments = toolInput.command.match(/\w+=[^\s]*\.env[^\s]*/g) || [];
|
|
146
|
+
varAssignments.forEach(a => {
|
|
147
|
+
const value = a.split('=')[1];
|
|
148
|
+
if (value) paths.push({ value, field: 'command' });
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Check command substitution containing sensitive patterns - extract .env from inside
|
|
152
|
+
const cmdSubst = toolInput.command.match(/\$\([^)]*?(\.env[^\s)]*)[^)]*\)/g) || [];
|
|
153
|
+
for (const subst of cmdSubst) {
|
|
154
|
+
const inner = subst.match(/\.env[^\s)]*/);
|
|
155
|
+
if (inner) paths.push({ value: inner[0], field: 'command' });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return paths.filter(p => p.value);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Load .ck.json config to check if privacy block is disabled
|
|
165
|
+
* @param {string} [configDir] - Directory containing .ck.json (defaults to .claude in cwd)
|
|
166
|
+
* @returns {boolean} true if privacy block should be skipped
|
|
167
|
+
*/
|
|
168
|
+
function isPrivacyBlockDisabled(configDir) {
|
|
169
|
+
try {
|
|
170
|
+
const configPath = configDir
|
|
171
|
+
? path.join(configDir, '.ck.json')
|
|
172
|
+
: path.join(process.cwd(), '.claude', '.ck.json');
|
|
173
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
174
|
+
return config.privacyBlock === false;
|
|
175
|
+
} catch {
|
|
176
|
+
return false; // Default to enabled on error (file not found or invalid JSON)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Build prompt data for AskUserQuestion tool
|
|
182
|
+
* @param {string} filePath - Blocked file path
|
|
183
|
+
* @returns {Object} Prompt data object
|
|
184
|
+
*/
|
|
185
|
+
function buildPromptData(filePath) {
|
|
186
|
+
const basename = path.basename(filePath);
|
|
187
|
+
return {
|
|
188
|
+
type: 'PRIVACY_PROMPT',
|
|
189
|
+
file: filePath,
|
|
190
|
+
basename: basename,
|
|
191
|
+
question: {
|
|
192
|
+
header: 'File Access',
|
|
193
|
+
text: `I need to read "${basename}" which may contain sensitive data (API keys, passwords, tokens). Do you approve?`,
|
|
194
|
+
options: [
|
|
195
|
+
{ label: 'Yes, approve access', description: `Allow reading ${basename} this time` },
|
|
196
|
+
{ label: 'No, skip this file', description: 'Continue without accessing this file' }
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
203
|
+
// MAIN ENTRY POINT
|
|
204
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Check if a tool call accesses privacy-sensitive files
|
|
208
|
+
*
|
|
209
|
+
* @param {Object} params
|
|
210
|
+
* @param {string} params.toolName - Name of tool (Read, Write, Bash, etc.)
|
|
211
|
+
* @param {Object} params.toolInput - Tool input with file_path, path, command, etc.
|
|
212
|
+
* @param {Object} [params.options]
|
|
213
|
+
* @param {boolean} [params.options.disabled] - Skip checks if true
|
|
214
|
+
* @param {string} [params.options.configDir] - Directory for .ck.json config
|
|
215
|
+
* @param {boolean} [params.options.allowBash] - Allow Bash tool without blocking (default: true)
|
|
216
|
+
* @returns {{
|
|
217
|
+
* blocked: boolean,
|
|
218
|
+
* filePath?: string,
|
|
219
|
+
* reason?: string,
|
|
220
|
+
* approved?: boolean,
|
|
221
|
+
* isBash?: boolean,
|
|
222
|
+
* suspicious?: boolean,
|
|
223
|
+
* promptData?: Object
|
|
224
|
+
* }}
|
|
225
|
+
*/
|
|
226
|
+
function checkPrivacy({ toolName, toolInput, options = {} }) {
|
|
227
|
+
const { disabled, configDir, allowBash = true } = options;
|
|
228
|
+
|
|
229
|
+
// Check if disabled via options or config
|
|
230
|
+
if (disabled || isPrivacyBlockDisabled(configDir)) {
|
|
231
|
+
return { blocked: false };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const isBashTool = toolName === 'Bash';
|
|
235
|
+
const paths = extractPaths(toolInput);
|
|
236
|
+
|
|
237
|
+
// Check each path
|
|
238
|
+
for (const { value: testPath } of paths) {
|
|
239
|
+
if (!isPrivacySensitive(testPath)) continue;
|
|
240
|
+
|
|
241
|
+
// Check for approval prefix
|
|
242
|
+
if (hasApprovalPrefix(testPath)) {
|
|
243
|
+
const strippedPath = stripApprovalPrefix(testPath);
|
|
244
|
+
return {
|
|
245
|
+
blocked: false,
|
|
246
|
+
approved: true,
|
|
247
|
+
filePath: strippedPath,
|
|
248
|
+
suspicious: isSuspiciousPath(strippedPath)
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// For Bash: warn but don't block (allows "Yes → bash cat" flow)
|
|
253
|
+
if (isBashTool && allowBash) {
|
|
254
|
+
return {
|
|
255
|
+
blocked: false,
|
|
256
|
+
isBash: true,
|
|
257
|
+
filePath: testPath,
|
|
258
|
+
reason: `Bash command accesses sensitive file: ${testPath}`
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Block - sensitive file without approval
|
|
263
|
+
return {
|
|
264
|
+
blocked: true,
|
|
265
|
+
filePath: testPath,
|
|
266
|
+
reason: `Sensitive file access requires user approval`,
|
|
267
|
+
promptData: buildPromptData(testPath)
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// No sensitive paths found
|
|
272
|
+
return { blocked: false };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
276
|
+
// EXPORTS
|
|
277
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
278
|
+
|
|
279
|
+
module.exports = {
|
|
280
|
+
// Main entry point
|
|
281
|
+
checkPrivacy,
|
|
282
|
+
|
|
283
|
+
// Helper functions (for testing and direct use)
|
|
284
|
+
isSafeFile,
|
|
285
|
+
isPrivacySensitive,
|
|
286
|
+
hasApprovalPrefix,
|
|
287
|
+
stripApprovalPrefix,
|
|
288
|
+
isSuspiciousPath,
|
|
289
|
+
extractPaths,
|
|
290
|
+
isPrivacyBlockDisabled,
|
|
291
|
+
buildPromptData,
|
|
292
|
+
|
|
293
|
+
// Constants
|
|
294
|
+
APPROVED_PREFIX,
|
|
295
|
+
SAFE_PATTERNS,
|
|
296
|
+
PRIVACY_PATTERNS
|
|
297
|
+
};
|