@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,263 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scout-checker.cjs - Facade for scout-block modules
|
|
4
|
+
*
|
|
5
|
+
* Provides unified interface to scout-block/* modules for reuse in both
|
|
6
|
+
* Claude hooks and OpenCode plugins.
|
|
7
|
+
*
|
|
8
|
+
* @module scout-checker
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
// Import scout-block modules
|
|
14
|
+
const { loadPatterns, createMatcher, matchPath } = require('../scout-block/pattern-matcher.cjs');
|
|
15
|
+
const { extractFromToolInput } = require('../scout-block/path-extractor.cjs');
|
|
16
|
+
const { detectBroadPatternIssue } = require('../scout-block/broad-pattern-detector.cjs');
|
|
17
|
+
|
|
18
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
19
|
+
// COMMAND PATTERNS
|
|
20
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
21
|
+
|
|
22
|
+
// Build command allowlist - these are allowed even if they contain blocked paths
|
|
23
|
+
// Handles flags and filters: npm build, pnpm --filter web run build, yarn workspace app build
|
|
24
|
+
const BUILD_COMMAND_PATTERN = /^(npm|pnpm|yarn|bun)\s+([^\s]+\s+)*(run\s+)?(build|test|lint|dev|start|install|ci|add|remove|update|publish|pack|init|create|exec)/;
|
|
25
|
+
|
|
26
|
+
// Tool commands - JS/TS, Go, Rust, Java, .NET, containers, IaC, Python, Ruby, PHP, Deno, Elixir
|
|
27
|
+
const TOOL_COMMAND_PATTERN = /^(\.\/)?(npx|pnpx|bunx|tsc|esbuild|vite|webpack|rollup|turbo|nx|jest|vitest|mocha|eslint|prettier|go|cargo|make|mvn|mvnw|gradle|gradlew|dotnet|docker|podman|kubectl|helm|terraform|ansible|bazel|cmake|sbt|flutter|swift|ant|ninja|meson|python3?|pip|uv|deno|bundle|rake|gem|php|composer|ruby|mix|elixir)/;
|
|
28
|
+
|
|
29
|
+
// Allow execution from .venv/bin/ or venv/bin/ (Unix) and .venv/Scripts/ or venv/Scripts/ (Windows)
|
|
30
|
+
const VENV_EXECUTABLE_PATTERN = /(^|[\/\\])\.?venv[\/\\](bin|Scripts)[\/\\]/;
|
|
31
|
+
|
|
32
|
+
// Allow Python venv creation commands (cross-platform):
|
|
33
|
+
// - python/python3 -m venv (Unix/macOS/Windows)
|
|
34
|
+
// - py -m venv (Windows py launcher, supports -3, -3.11, etc.)
|
|
35
|
+
// - uv venv (fast Rust-based Python package manager)
|
|
36
|
+
// - virtualenv (legacy but still widely used)
|
|
37
|
+
const VENV_CREATION_PATTERN = /^(python3?|py)\s+(-[\w.]+\s+)*-m\s+venv\s+|^uv\s+venv(\s|$)|^virtualenv\s+/;
|
|
38
|
+
|
|
39
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
40
|
+
// HELPER FUNCTIONS
|
|
41
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Strip leading ENV variable assignments and command wrappers (sudo, env, etc.)
|
|
45
|
+
* e.g., "NODE_ENV=production npm run build" → "npm run build"
|
|
46
|
+
* @param {string} command - The command to strip
|
|
47
|
+
* @returns {string}
|
|
48
|
+
*/
|
|
49
|
+
function stripCommandPrefix(command) {
|
|
50
|
+
if (!command || typeof command !== 'string') return command;
|
|
51
|
+
let stripped = command.trim();
|
|
52
|
+
// Strip env var assignments (KEY=VALUE KEY2=VALUE2 ...)
|
|
53
|
+
stripped = stripped.replace(/^(\w+=\S+\s+)+/, '');
|
|
54
|
+
// Strip common command wrappers (one level)
|
|
55
|
+
stripped = stripped.replace(/^(sudo|env|nice|nohup|time|timeout)\s+/, '');
|
|
56
|
+
// Strip env vars again (sudo env VAR=x cmd)
|
|
57
|
+
stripped = stripped.replace(/^(\w+=\S+\s+)+/, '');
|
|
58
|
+
return stripped.trim();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Check if a command is a build/tooling command (should be allowed)
|
|
63
|
+
* @param {string} command - The command to check
|
|
64
|
+
* @returns {boolean}
|
|
65
|
+
*/
|
|
66
|
+
function isBuildCommand(command) {
|
|
67
|
+
if (!command || typeof command !== 'string') return false;
|
|
68
|
+
const trimmed = command.trim();
|
|
69
|
+
return BUILD_COMMAND_PATTERN.test(trimmed) || TOOL_COMMAND_PATTERN.test(trimmed);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Split a compound command into sub-commands on &&, ||, and ;.
|
|
74
|
+
* Does NOT split on newlines — newlines in command strings are typically
|
|
75
|
+
* heredoc bodies or multiline strings, not compound operators.
|
|
76
|
+
* Does not handle operators inside quoted strings (extremely rare in practice).
|
|
77
|
+
*
|
|
78
|
+
* @param {string} command - The compound command string
|
|
79
|
+
* @returns {string[]} Array of sub-commands (trimmed, non-empty)
|
|
80
|
+
*/
|
|
81
|
+
function splitCompoundCommand(command) {
|
|
82
|
+
if (!command || typeof command !== 'string') return [];
|
|
83
|
+
return command.split(/\s*(?:&&|\|\||;)\s*/).filter(cmd => cmd && cmd.trim().length > 0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Unwrap shell executor wrappers (bash -c "...", sh -c '...', eval "...").
|
|
88
|
+
* Returns the inner command string for re-processing.
|
|
89
|
+
* @param {string} command - The command to unwrap
|
|
90
|
+
* @returns {string} Inner command, or original if not a shell executor
|
|
91
|
+
*/
|
|
92
|
+
function unwrapShellExecutor(command) {
|
|
93
|
+
if (!command || typeof command !== 'string') return command;
|
|
94
|
+
const match = command.trim().match(
|
|
95
|
+
/^(?:(?:bash|sh|zsh)\s+-c|eval)\s+["'](.+)["']\s*$/
|
|
96
|
+
);
|
|
97
|
+
return match ? match[1] : command;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check if command executes from a .venv bin directory
|
|
102
|
+
* @param {string} command - The command to check
|
|
103
|
+
* @returns {boolean}
|
|
104
|
+
*/
|
|
105
|
+
function isVenvExecutable(command) {
|
|
106
|
+
if (!command || typeof command !== 'string') return false;
|
|
107
|
+
return VENV_EXECUTABLE_PATTERN.test(command);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Check if command creates a Python virtual environment
|
|
112
|
+
* @param {string} command - The command to check
|
|
113
|
+
* @returns {boolean}
|
|
114
|
+
*/
|
|
115
|
+
function isVenvCreationCommand(command) {
|
|
116
|
+
if (!command || typeof command !== 'string') return false;
|
|
117
|
+
return VENV_CREATION_PATTERN.test(command.trim());
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check if command should be allowed (build, venv executable, or venv creation)
|
|
122
|
+
* Strips ENV prefixes and command wrappers before checking.
|
|
123
|
+
* @param {string} command - The command to check
|
|
124
|
+
* @returns {boolean}
|
|
125
|
+
*/
|
|
126
|
+
function isAllowedCommand(command) {
|
|
127
|
+
const stripped = stripCommandPrefix(command);
|
|
128
|
+
return isBuildCommand(stripped) || isVenvExecutable(stripped) || isVenvCreationCommand(stripped);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
132
|
+
// MAIN ENTRY POINT
|
|
133
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Check if a tool call accesses blocked directories or uses overly broad patterns
|
|
137
|
+
*
|
|
138
|
+
* @param {Object} params
|
|
139
|
+
* @param {string} params.toolName - Name of tool (Bash, Glob, Read, etc.)
|
|
140
|
+
* @param {Object} params.toolInput - Tool input with file_path, path, pattern, command
|
|
141
|
+
* @param {Object} [params.options]
|
|
142
|
+
* @param {string} [params.options.ckignorePath] - Path to .ckignore file
|
|
143
|
+
* @param {string} [params.options.claudeDir] - Path to .claude or .opencode directory
|
|
144
|
+
* @param {boolean} [params.options.checkBroadPatterns] - Check for overly broad glob patterns (default: true)
|
|
145
|
+
* @returns {{
|
|
146
|
+
* blocked: boolean,
|
|
147
|
+
* path?: string,
|
|
148
|
+
* pattern?: string,
|
|
149
|
+
* reason?: string,
|
|
150
|
+
* isBroadPattern?: boolean,
|
|
151
|
+
* suggestions?: string[],
|
|
152
|
+
* isAllowedCommand?: boolean
|
|
153
|
+
* }}
|
|
154
|
+
*/
|
|
155
|
+
function checkScoutBlock({ toolName, toolInput, options = {} }) {
|
|
156
|
+
const {
|
|
157
|
+
ckignorePath,
|
|
158
|
+
claudeDir = path.join(process.cwd(), '.claude'),
|
|
159
|
+
checkBroadPatterns = true
|
|
160
|
+
} = options;
|
|
161
|
+
|
|
162
|
+
// Unwrap shell executor wrappers (bash -c "...", eval "...")
|
|
163
|
+
// so the inner command gets properly analyzed
|
|
164
|
+
if (toolInput.command) {
|
|
165
|
+
const unwrapped = unwrapShellExecutor(toolInput.command);
|
|
166
|
+
if (unwrapped !== toolInput.command) {
|
|
167
|
+
toolInput = { ...toolInput, command: unwrapped };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// For Bash commands, split compound commands (&&, ||, ;) and check
|
|
172
|
+
// each sub-command independently. This prevents "echo msg && npm run build"
|
|
173
|
+
// from being blocked due to "build" token in the allowed build sub-command.
|
|
174
|
+
// Must split BEFORE isAllowedCommand because BUILD_COMMAND_PATTERN has no end
|
|
175
|
+
// anchor and would match the prefix of "npm run build && cat dist/file.js".
|
|
176
|
+
if (toolInput.command) {
|
|
177
|
+
const subCommands = splitCompoundCommand(toolInput.command);
|
|
178
|
+
const nonAllowed = subCommands.filter(cmd => !isAllowedCommand(cmd.trim()));
|
|
179
|
+
if (nonAllowed.length === 0) {
|
|
180
|
+
return { blocked: false, isAllowedCommand: true };
|
|
181
|
+
}
|
|
182
|
+
// Only extract paths from non-allowed sub-commands
|
|
183
|
+
if (nonAllowed.length < subCommands.length) {
|
|
184
|
+
toolInput = { ...toolInput, command: nonAllowed.join(' ; ') };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Check for overly broad glob patterns (Glob tool)
|
|
189
|
+
if (checkBroadPatterns && (toolName === 'Glob' || toolInput.pattern)) {
|
|
190
|
+
const broadResult = detectBroadPatternIssue(toolInput);
|
|
191
|
+
if (broadResult.blocked) {
|
|
192
|
+
return {
|
|
193
|
+
blocked: true,
|
|
194
|
+
isBroadPattern: true,
|
|
195
|
+
pattern: toolInput.pattern,
|
|
196
|
+
reason: broadResult.reason || 'Pattern too broad - may fill context with too many files',
|
|
197
|
+
suggestions: broadResult.suggestions || []
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Resolve .ckignore path
|
|
203
|
+
const resolvedCkignorePath = ckignorePath || path.join(claudeDir, '.ckignore');
|
|
204
|
+
|
|
205
|
+
// Load patterns and create matcher
|
|
206
|
+
const patterns = loadPatterns(resolvedCkignorePath);
|
|
207
|
+
const matcher = createMatcher(patterns);
|
|
208
|
+
|
|
209
|
+
// Extract paths from tool input
|
|
210
|
+
const extractedPaths = extractFromToolInput(toolInput);
|
|
211
|
+
|
|
212
|
+
// If no paths extracted, allow operation
|
|
213
|
+
if (extractedPaths.length === 0) {
|
|
214
|
+
return { blocked: false };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Check each path against patterns
|
|
218
|
+
for (const extractedPath of extractedPaths) {
|
|
219
|
+
const result = matchPath(matcher, extractedPath);
|
|
220
|
+
if (result.blocked) {
|
|
221
|
+
return {
|
|
222
|
+
blocked: true,
|
|
223
|
+
path: extractedPath,
|
|
224
|
+
pattern: result.pattern,
|
|
225
|
+
reason: `Path matches blocked pattern: ${result.pattern}`
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// All paths allowed
|
|
231
|
+
return { blocked: false };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
235
|
+
// EXPORTS
|
|
236
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
237
|
+
|
|
238
|
+
module.exports = {
|
|
239
|
+
// Main entry point
|
|
240
|
+
checkScoutBlock,
|
|
241
|
+
|
|
242
|
+
// Command checkers
|
|
243
|
+
isBuildCommand,
|
|
244
|
+
isVenvExecutable,
|
|
245
|
+
isVenvCreationCommand,
|
|
246
|
+
isAllowedCommand,
|
|
247
|
+
splitCompoundCommand,
|
|
248
|
+
stripCommandPrefix,
|
|
249
|
+
unwrapShellExecutor,
|
|
250
|
+
|
|
251
|
+
// Re-export scout-block modules for direct access
|
|
252
|
+
loadPatterns,
|
|
253
|
+
createMatcher,
|
|
254
|
+
matchPath,
|
|
255
|
+
extractFromToolInput,
|
|
256
|
+
detectBroadPatternIssue,
|
|
257
|
+
|
|
258
|
+
// Patterns (for testing)
|
|
259
|
+
BUILD_COMMAND_PATTERN,
|
|
260
|
+
TOOL_COMMAND_PATTERN,
|
|
261
|
+
VENV_EXECUTABLE_PATTERN,
|
|
262
|
+
VENV_CREATION_PATTERN
|
|
263
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Transcript Parser - Extract tool/agent/todo state from session JSONL
|
|
6
|
+
* @module transcript-parser
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parse transcript JSONL file
|
|
14
|
+
* @param {string} transcriptPath - Path to transcript file
|
|
15
|
+
* @returns {Promise<TranscriptData>}
|
|
16
|
+
*/
|
|
17
|
+
async function parseTranscript(transcriptPath) {
|
|
18
|
+
const result = {
|
|
19
|
+
tools: [],
|
|
20
|
+
agents: [],
|
|
21
|
+
todos: [],
|
|
22
|
+
sessionStart: null
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
if (!transcriptPath || !fs.existsSync(transcriptPath)) {
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const toolMap = new Map();
|
|
30
|
+
const agentMap = new Map();
|
|
31
|
+
let latestTodos = [];
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const fileStream = fs.createReadStream(transcriptPath);
|
|
35
|
+
const rl = readline.createInterface({
|
|
36
|
+
input: fileStream,
|
|
37
|
+
crlfDelay: Infinity
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
for await (const line of rl) {
|
|
41
|
+
if (!line.trim()) continue;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const entry = JSON.parse(line);
|
|
45
|
+
processEntry(entry, toolMap, agentMap, latestTodos, result);
|
|
46
|
+
} catch {
|
|
47
|
+
// Skip malformed lines
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} catch {
|
|
51
|
+
// Return partial results on error
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
result.tools = Array.from(toolMap.values()).slice(-20);
|
|
55
|
+
result.agents = Array.from(agentMap.values()).slice(-10);
|
|
56
|
+
result.todos = latestTodos;
|
|
57
|
+
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Process single JSONL entry
|
|
63
|
+
* @param {Object} entry - Parsed JSON line
|
|
64
|
+
* @param {Map} toolMap - Tool tracking map
|
|
65
|
+
* @param {Map} agentMap - Agent tracking map
|
|
66
|
+
* @param {Array} latestTodos - Latest todo array reference
|
|
67
|
+
* @param {Object} result - Result object
|
|
68
|
+
*/
|
|
69
|
+
function processEntry(entry, toolMap, agentMap, latestTodos, result) {
|
|
70
|
+
const timestamp = entry.timestamp ? new Date(entry.timestamp) : new Date();
|
|
71
|
+
|
|
72
|
+
// Track session start
|
|
73
|
+
if (!result.sessionStart && entry.timestamp) {
|
|
74
|
+
result.sessionStart = timestamp;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const content = entry.message?.content;
|
|
78
|
+
if (!content || !Array.isArray(content)) return;
|
|
79
|
+
|
|
80
|
+
for (const block of content) {
|
|
81
|
+
// Handle tool_use blocks
|
|
82
|
+
if (block.type === 'tool_use' && block.id && block.name) {
|
|
83
|
+
if (block.name === 'Task') {
|
|
84
|
+
// Agent spawn
|
|
85
|
+
agentMap.set(block.id, {
|
|
86
|
+
id: block.id,
|
|
87
|
+
type: block.input?.subagent_type ?? 'unknown',
|
|
88
|
+
model: block.input?.model ?? null,
|
|
89
|
+
description: block.input?.description ?? null,
|
|
90
|
+
status: 'running',
|
|
91
|
+
startTime: timestamp,
|
|
92
|
+
endTime: null
|
|
93
|
+
});
|
|
94
|
+
} else if (block.name === 'TodoWrite') {
|
|
95
|
+
// Legacy: Replace todo array (deprecated, kept for backwards compatibility)
|
|
96
|
+
if (block.input?.todos && Array.isArray(block.input.todos)) {
|
|
97
|
+
latestTodos.length = 0;
|
|
98
|
+
latestTodos.push(...block.input.todos);
|
|
99
|
+
}
|
|
100
|
+
} else if (block.name === 'TaskCreate') {
|
|
101
|
+
// Native Task API: Add new task
|
|
102
|
+
if (block.input?.subject) {
|
|
103
|
+
latestTodos.push({
|
|
104
|
+
content: block.input.subject,
|
|
105
|
+
status: 'pending',
|
|
106
|
+
activeForm: block.input.activeForm || null
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
} else if (block.name === 'TaskUpdate') {
|
|
110
|
+
// Native Task API: Update existing task status
|
|
111
|
+
if (block.input?.taskId && block.input?.status) {
|
|
112
|
+
const task = latestTodos.find(t => t.id === block.input.taskId);
|
|
113
|
+
if (task) {
|
|
114
|
+
task.status = block.input.status;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
// Regular tool
|
|
119
|
+
toolMap.set(block.id, {
|
|
120
|
+
id: block.id,
|
|
121
|
+
name: block.name,
|
|
122
|
+
target: extractTarget(block.name, block.input),
|
|
123
|
+
status: 'running',
|
|
124
|
+
startTime: timestamp,
|
|
125
|
+
endTime: null
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Handle tool_result blocks
|
|
131
|
+
if (block.type === 'tool_result' && block.tool_use_id) {
|
|
132
|
+
const tool = toolMap.get(block.tool_use_id);
|
|
133
|
+
if (tool) {
|
|
134
|
+
tool.status = block.is_error ? 'error' : 'completed';
|
|
135
|
+
tool.endTime = timestamp;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const agent = agentMap.get(block.tool_use_id);
|
|
139
|
+
if (agent) {
|
|
140
|
+
agent.status = 'completed';
|
|
141
|
+
agent.endTime = timestamp;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Extract target from tool input
|
|
149
|
+
* @param {string} toolName - Tool name
|
|
150
|
+
* @param {Object} input - Tool input object
|
|
151
|
+
* @returns {string|null} - Extracted target
|
|
152
|
+
*/
|
|
153
|
+
function extractTarget(toolName, input) {
|
|
154
|
+
if (!input) return null;
|
|
155
|
+
|
|
156
|
+
switch (toolName) {
|
|
157
|
+
case 'Read':
|
|
158
|
+
case 'Write':
|
|
159
|
+
case 'Edit':
|
|
160
|
+
return input.file_path ?? input.path ?? null;
|
|
161
|
+
|
|
162
|
+
case 'Glob':
|
|
163
|
+
case 'Grep':
|
|
164
|
+
return input.pattern ?? null;
|
|
165
|
+
|
|
166
|
+
case 'Bash':
|
|
167
|
+
const cmd = input.command;
|
|
168
|
+
if (!cmd) return null;
|
|
169
|
+
return cmd.length > 30 ? cmd.slice(0, 30) + '...' : cmd;
|
|
170
|
+
|
|
171
|
+
default:
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
module.exports = {
|
|
177
|
+
parseTranscript,
|
|
178
|
+
// Export for testing
|
|
179
|
+
processEntry,
|
|
180
|
+
extractTarget
|
|
181
|
+
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* PostToolUse hook: Tracks file modifications and reminds to run code-simplifier
|
|
4
|
+
*
|
|
5
|
+
* This hook fires after Edit/Write/MultiEdit operations and:
|
|
6
|
+
* 1. Tracks modified files in the session
|
|
7
|
+
* 2. After significant edits, injects a reminder to run code-simplifier
|
|
8
|
+
*
|
|
9
|
+
* Auto-trigger behavior:
|
|
10
|
+
* - Tracks edit count per session
|
|
11
|
+
* - After 5+ file edits, reminds about code-simplifier
|
|
12
|
+
* - Resets counter when simplifier is mentioned in conversation
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Crash wrapper
|
|
16
|
+
try {
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const os = require('os');
|
|
20
|
+
const { isHookEnabled } = require('./lib/ck-config-utils.cjs');
|
|
21
|
+
const { invalidateCache } = require('./lib/git-info-cache.cjs');
|
|
22
|
+
|
|
23
|
+
// Early exit if hook disabled in config
|
|
24
|
+
if (!isHookEnabled('post-edit-simplify-reminder')) {
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Session tracking file
|
|
29
|
+
const SESSION_TRACK_FILE = path.join(os.tmpdir(), 'ck-simplify-session.json');
|
|
30
|
+
const EDIT_THRESHOLD = 5; // Remind after this many edits
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Load or initialize session tracking data
|
|
34
|
+
*/
|
|
35
|
+
function loadSessionData() {
|
|
36
|
+
try {
|
|
37
|
+
if (fs.existsSync(SESSION_TRACK_FILE)) {
|
|
38
|
+
const data = JSON.parse(fs.readFileSync(SESSION_TRACK_FILE, 'utf8'));
|
|
39
|
+
// Reset if session is older than 2 hours
|
|
40
|
+
if (Date.now() - data.startTime > 2 * 60 * 60 * 1000) {
|
|
41
|
+
return initSessionData();
|
|
42
|
+
}
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// Ignore errors, reinitialize
|
|
47
|
+
}
|
|
48
|
+
return initSessionData();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Initialize fresh session data
|
|
53
|
+
*/
|
|
54
|
+
function initSessionData() {
|
|
55
|
+
return {
|
|
56
|
+
startTime: Date.now(),
|
|
57
|
+
editCount: 0,
|
|
58
|
+
modifiedFiles: [],
|
|
59
|
+
lastReminder: 0,
|
|
60
|
+
simplifierRun: false
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Save session tracking data
|
|
66
|
+
*/
|
|
67
|
+
function saveSessionData(data) {
|
|
68
|
+
try {
|
|
69
|
+
fs.writeFileSync(SESSION_TRACK_FILE, JSON.stringify(data, null, 2));
|
|
70
|
+
} catch (e) {
|
|
71
|
+
// Ignore write errors
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Main hook logic
|
|
77
|
+
*/
|
|
78
|
+
function main() {
|
|
79
|
+
try {
|
|
80
|
+
// Read hook input from stdin
|
|
81
|
+
let input = '';
|
|
82
|
+
const stdin = fs.readFileSync(0, 'utf8');
|
|
83
|
+
if (stdin) {
|
|
84
|
+
input = stdin;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const hookData = JSON.parse(input || '{}');
|
|
88
|
+
const toolName = hookData.tool_name || '';
|
|
89
|
+
const toolInput = hookData.tool_input || {};
|
|
90
|
+
|
|
91
|
+
// Only track edit operations
|
|
92
|
+
const editTools = ['Edit', 'Write', 'MultiEdit'];
|
|
93
|
+
if (!editTools.includes(toolName)) {
|
|
94
|
+
console.log(JSON.stringify({ continue: true }));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Invalidate git cache so statusline shows fresh state after file changes
|
|
99
|
+
// Use hookData.cwd (not process.cwd()) to handle subagent CWD mismatch
|
|
100
|
+
invalidateCache(hookData.cwd || process.cwd());
|
|
101
|
+
|
|
102
|
+
// Load session data
|
|
103
|
+
const session = loadSessionData();
|
|
104
|
+
|
|
105
|
+
// Track the edit
|
|
106
|
+
session.editCount++;
|
|
107
|
+
const filePath = toolInput.file_path || toolInput.path || '';
|
|
108
|
+
if (filePath && !session.modifiedFiles.includes(filePath)) {
|
|
109
|
+
session.modifiedFiles.push(filePath);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Check if we should remind about code-simplifier
|
|
113
|
+
const shouldRemind =
|
|
114
|
+
session.editCount >= EDIT_THRESHOLD &&
|
|
115
|
+
!session.simplifierRun &&
|
|
116
|
+
(Date.now() - session.lastReminder > 10 * 60 * 1000); // Don't remind more than every 10 min
|
|
117
|
+
|
|
118
|
+
let additionalContext = '';
|
|
119
|
+
if (shouldRemind) {
|
|
120
|
+
session.lastReminder = Date.now();
|
|
121
|
+
additionalContext = `\n\n[Code Simplification Reminder] You have modified ${session.modifiedFiles.length} files in this session. Consider using the \`code-simplifier\` agent to refine recent changes before proceeding to code review. This is a MANDATORY step in the workflow.`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Save updated session data
|
|
125
|
+
saveSessionData(session);
|
|
126
|
+
|
|
127
|
+
// Output hook result
|
|
128
|
+
const result = {
|
|
129
|
+
continue: true
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
if (additionalContext) {
|
|
133
|
+
result.additionalContext = additionalContext;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log(JSON.stringify(result));
|
|
137
|
+
|
|
138
|
+
} catch (e) {
|
|
139
|
+
// On error, allow the operation to continue
|
|
140
|
+
console.log(JSON.stringify({ continue: true }));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
main();
|
|
145
|
+
} catch (e) {
|
|
146
|
+
// Minimal crash logging (zero deps — only Node builtins)
|
|
147
|
+
try {
|
|
148
|
+
const fs = require('fs');
|
|
149
|
+
const p = require('path');
|
|
150
|
+
const logDir = p.join(__dirname, '.logs');
|
|
151
|
+
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
|
|
152
|
+
fs.appendFileSync(p.join(logDir, 'hook-log.jsonl'),
|
|
153
|
+
JSON.stringify({ ts: new Date().toISOString(), hook: p.basename(__filename, '.cjs'), status: 'crash', error: e.message }) + '\n');
|
|
154
|
+
} catch (_) {}
|
|
155
|
+
process.exit(0); // fail-open
|
|
156
|
+
}
|