start-vibing 2.0.11 → 2.0.13
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/README.md +177 -177
- package/dist/cli.js +19 -2
- package/package.json +42 -42
- package/template/.claude/CLAUDE.md +174 -174
- package/template/.claude/agents/01-orchestration/agent-selector.md +130 -130
- package/template/.claude/agents/01-orchestration/checkpoint-manager.md +142 -142
- package/template/.claude/agents/01-orchestration/context-manager.md +138 -138
- package/template/.claude/agents/01-orchestration/error-recovery.md +182 -182
- package/template/.claude/agents/01-orchestration/orchestrator.md +114 -114
- package/template/.claude/agents/01-orchestration/parallel-coordinator.md +141 -141
- package/template/.claude/agents/01-orchestration/task-decomposer.md +121 -121
- package/template/.claude/agents/01-orchestration/workflow-router.md +114 -114
- package/template/.claude/agents/02-typescript/bun-runtime-expert.md +197 -197
- package/template/.claude/agents/02-typescript/esm-resolver.md +193 -193
- package/template/.claude/agents/02-typescript/import-alias-enforcer.md +158 -158
- package/template/.claude/agents/02-typescript/ts-generics-helper.md +183 -183
- package/template/.claude/agents/02-typescript/ts-migration-helper.md +238 -238
- package/template/.claude/agents/02-typescript/ts-strict-checker.md +180 -180
- package/template/.claude/agents/02-typescript/ts-types-analyzer.md +199 -199
- package/template/.claude/agents/02-typescript/type-definition-writer.md +187 -187
- package/template/.claude/agents/02-typescript/zod-schema-designer.md +212 -212
- package/template/.claude/agents/02-typescript/zod-validator.md +158 -158
- package/template/.claude/agents/03-testing/playwright-assertions.md +265 -265
- package/template/.claude/agents/03-testing/playwright-e2e.md +247 -247
- package/template/.claude/agents/03-testing/playwright-fixtures.md +234 -234
- package/template/.claude/agents/03-testing/playwright-multi-viewport.md +256 -256
- package/template/.claude/agents/03-testing/playwright-page-objects.md +247 -247
- package/template/.claude/agents/03-testing/test-cleanup-manager.md +248 -248
- package/template/.claude/agents/03-testing/test-data-generator.md +254 -254
- package/template/.claude/agents/03-testing/tester-integration.md +278 -278
- package/template/.claude/agents/03-testing/tester-unit.md +207 -207
- package/template/.claude/agents/03-testing/vitest-config.md +287 -287
- package/template/.claude/agents/04-docker/container-health.md +255 -255
- package/template/.claude/agents/04-docker/deployment-validator.md +225 -225
- package/template/.claude/agents/04-docker/docker-compose-designer.md +281 -281
- package/template/.claude/agents/04-docker/docker-env-manager.md +235 -235
- package/template/.claude/agents/04-docker/docker-multi-stage.md +241 -241
- package/template/.claude/agents/04-docker/dockerfile-optimizer.md +208 -208
- package/template/.claude/agents/05-database/database-seeder.md +273 -273
- package/template/.claude/agents/05-database/mongodb-query-optimizer.md +230 -230
- package/template/.claude/agents/05-database/mongoose-aggregation.md +306 -306
- package/template/.claude/agents/05-database/mongoose-index-optimizer.md +182 -182
- package/template/.claude/agents/05-database/mongoose-schema-designer.md +267 -267
- package/template/.claude/agents/06-security/auth-session-validator.md +68 -68
- package/template/.claude/agents/06-security/input-sanitizer.md +80 -80
- package/template/.claude/agents/06-security/owasp-checker.md +97 -97
- package/template/.claude/agents/06-security/permission-auditor.md +100 -100
- package/template/.claude/agents/06-security/security-auditor.md +84 -84
- package/template/.claude/agents/06-security/sensitive-data-scanner.md +83 -83
- package/template/.claude/agents/07-documentation/api-documenter.md +136 -136
- package/template/.claude/agents/07-documentation/changelog-manager.md +105 -105
- package/template/.claude/agents/07-documentation/documenter.md +76 -76
- package/template/.claude/agents/07-documentation/domain-updater.md +81 -81
- package/template/.claude/agents/07-documentation/jsdoc-generator.md +114 -114
- package/template/.claude/agents/07-documentation/readme-generator.md +135 -135
- package/template/.claude/agents/08-git/branch-manager.md +58 -58
- package/template/.claude/agents/08-git/commit-manager.md +63 -63
- package/template/.claude/agents/08-git/pr-creator.md +76 -76
- package/template/.claude/agents/09-quality/code-reviewer.md +71 -71
- package/template/.claude/agents/09-quality/quality-checker.md +67 -67
- package/template/.claude/agents/10-research/best-practices-finder.md +89 -89
- package/template/.claude/agents/10-research/competitor-analyzer.md +106 -106
- package/template/.claude/agents/10-research/pattern-researcher.md +93 -93
- package/template/.claude/agents/10-research/research-cache-manager.md +76 -76
- package/template/.claude/agents/10-research/research-web.md +98 -98
- package/template/.claude/agents/10-research/tech-evaluator.md +101 -101
- package/template/.claude/agents/11-ui-ux/accessibility-auditor.md +136 -136
- package/template/.claude/agents/11-ui-ux/design-system-enforcer.md +125 -125
- package/template/.claude/agents/11-ui-ux/skeleton-generator.md +118 -118
- package/template/.claude/agents/11-ui-ux/ui-desktop.md +132 -132
- package/template/.claude/agents/11-ui-ux/ui-mobile.md +98 -98
- package/template/.claude/agents/11-ui-ux/ui-tablet.md +110 -110
- package/template/.claude/agents/12-performance/api-latency-analyzer.md +156 -156
- package/template/.claude/agents/12-performance/bundle-analyzer.md +113 -113
- package/template/.claude/agents/12-performance/memory-leak-detector.md +137 -137
- package/template/.claude/agents/12-performance/performance-profiler.md +115 -115
- package/template/.claude/agents/12-performance/query-optimizer.md +124 -124
- package/template/.claude/agents/12-performance/render-optimizer.md +154 -154
- package/template/.claude/agents/13-debugging/build-error-fixer.md +207 -207
- package/template/.claude/agents/13-debugging/debugger.md +149 -149
- package/template/.claude/agents/13-debugging/error-stack-analyzer.md +141 -141
- package/template/.claude/agents/13-debugging/network-debugger.md +208 -208
- package/template/.claude/agents/13-debugging/runtime-error-fixer.md +181 -181
- package/template/.claude/agents/13-debugging/type-error-resolver.md +185 -185
- package/template/.claude/agents/14-validation/final-validator.md +93 -93
- package/template/.claude/agents/_backup/analyzer.md +134 -134
- package/template/.claude/agents/_backup/code-reviewer.md +279 -279
- package/template/.claude/agents/_backup/commit-manager.md +219 -219
- package/template/.claude/agents/_backup/debugger.md +280 -280
- package/template/.claude/agents/_backup/documenter.md +237 -237
- package/template/.claude/agents/_backup/domain-updater.md +197 -197
- package/template/.claude/agents/_backup/final-validator.md +169 -169
- package/template/.claude/agents/_backup/orchestrator.md +149 -149
- package/template/.claude/agents/_backup/performance.md +232 -232
- package/template/.claude/agents/_backup/quality-checker.md +240 -240
- package/template/.claude/agents/_backup/research.md +315 -315
- package/template/.claude/agents/_backup/security-auditor.md +192 -192
- package/template/.claude/agents/_backup/tester.md +566 -566
- package/template/.claude/agents/_backup/ui-ux-reviewer.md +247 -247
- package/template/.claude/config/README.md +30 -30
- package/template/.claude/config/mcp-config.json +344 -344
- package/template/.claude/config/project-config.json +53 -53
- package/template/.claude/config/quality-gates.json +46 -46
- package/template/.claude/config/security-rules.json +45 -45
- package/template/.claude/config/testing-config.json +164 -164
- package/template/.claude/hooks/SETUP.md +126 -126
- package/template/.claude/hooks/run-hook.ts +176 -176
- package/template/.claude/hooks/stop-validator.ts +914 -824
- package/template/.claude/hooks/user-prompt-submit.ts +886 -886
- package/template/.claude/scripts/mcp-quick-install.ts +151 -151
- package/template/.claude/scripts/setup-mcps.ts +651 -651
- package/template/.claude/settings.json +275 -275
- package/template/.claude/skills/bun-runtime/SKILL.md +430 -430
- package/template/.claude/skills/codebase-knowledge/domains/claude-system.md +431 -431
- package/template/.claude/skills/codebase-knowledge/domains/mcp-integration.md +295 -295
- package/template/.claude/skills/debugging-patterns/SKILL.md +485 -485
- package/template/.claude/skills/docker-patterns/SKILL.md +555 -555
- package/template/.claude/skills/git-workflow/SKILL.md +454 -454
- package/template/.claude/skills/mongoose-patterns/SKILL.md +499 -499
- package/template/.claude/skills/nextjs-app-router/SKILL.md +327 -327
- package/template/.claude/skills/performance-patterns/SKILL.md +547 -547
- package/template/.claude/skills/playwright-automation/SKILL.md +438 -438
- package/template/.claude/skills/react-patterns/SKILL.md +389 -389
- package/template/.claude/skills/research-cache/SKILL.md +222 -222
- package/template/.claude/skills/shadcn-ui/SKILL.md +511 -511
- package/template/.claude/skills/tailwind-patterns/SKILL.md +465 -465
- package/template/.claude/skills/test-coverage/SKILL.md +467 -467
- package/template/.claude/skills/trpc-api/SKILL.md +434 -434
- package/template/.claude/skills/typescript-strict/SKILL.md +367 -367
- package/template/.claude/skills/zod-validation/SKILL.md +403 -403
- package/template/CLAUDE.md +117 -117
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
# Workflow Enforcement Hooks - Setup Guide
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This system provides agent selection guidance by analyzing prompts and suggesting the best agent for the task. It includes a **universal hook runner** that supports multiple runtimes with automatic fallback.
|
|
6
|
-
|
|
7
|
-
## Runtime Support
|
|
8
|
-
|
|
9
|
-
The hooks use a universal runner (`run-hook.ts`) that automatically detects and uses the first available runtime:
|
|
10
|
-
|
|
11
|
-
| Priority | Runtime | Extension | Notes |
|
|
12
|
-
| -------- | ------- | --------- | -------------------------- |
|
|
13
|
-
| 1 | python3 | .py | Primary (user's preferred) |
|
|
14
|
-
| 2 | python | .py | Fallback |
|
|
15
|
-
| 3 | bun | .ts | TypeScript fallback |
|
|
16
|
-
| 4 | npx tsx | .ts | Final fallback |
|
|
17
|
-
|
|
18
|
-
**If no runtime is available**, the hooks return a safe default (approve/continue) to avoid blocking the user.
|
|
19
|
-
|
|
20
|
-
## Files
|
|
21
|
-
|
|
22
|
-
| File | Purpose |
|
|
23
|
-
| ------------------------ | --------------------------------------------- |
|
|
24
|
-
| `run-hook.ts` | Universal runner with runtime detection |
|
|
25
|
-
| `run-hook.sh` | Shell wrapper for Unix/Linux/Mac |
|
|
26
|
-
| `run-hook.cmd` | Batch wrapper for Windows |
|
|
27
|
-
| `user-prompt-submit.py` | Analyzes prompts and suggests agents (Python) |
|
|
28
|
-
| `user-prompt-submit.ts` | Same as above (TypeScript fallback) |
|
|
29
|
-
| `stop-validator.py` | Validates before task completion (Python) |
|
|
30
|
-
| `stop-validator.ts` | Same as above (TypeScript fallback) |
|
|
31
|
-
| `check-documentation.py` | Verifies file documentation (Python) |
|
|
32
|
-
|
|
33
|
-
## Claude Code Configuration
|
|
34
|
-
|
|
35
|
-
The hooks are configured in `.claude/settings.json`:
|
|
36
|
-
|
|
37
|
-
```json
|
|
38
|
-
{
|
|
39
|
-
"hooks": {
|
|
40
|
-
"UserPromptSubmit": [
|
|
41
|
-
{
|
|
42
|
-
"matcher": "",
|
|
43
|
-
"hooks": [
|
|
44
|
-
{
|
|
45
|
-
"type": "command",
|
|
46
|
-
"command": "bun .claude/hooks/run-hook.ts user-prompt-submit",
|
|
47
|
-
"timeout": 10
|
|
48
|
-
}
|
|
49
|
-
]
|
|
50
|
-
}
|
|
51
|
-
],
|
|
52
|
-
"Stop": [
|
|
53
|
-
{
|
|
54
|
-
"hooks": [
|
|
55
|
-
{
|
|
56
|
-
"type": "command",
|
|
57
|
-
"command": "bun .claude/hooks/run-hook.ts stop-validator",
|
|
58
|
-
"timeout": 30
|
|
59
|
-
}
|
|
60
|
-
]
|
|
61
|
-
}
|
|
62
|
-
]
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## How It Works
|
|
68
|
-
|
|
69
|
-
1. Claude Code calls `bun .claude/hooks/run-hook.ts <hook-name>`
|
|
70
|
-
2. `run-hook.ts` checks for available runtimes in priority order
|
|
71
|
-
3. First available runtime executes the corresponding hook file (.py or .ts)
|
|
72
|
-
4. If no runtime is available, returns safe default to avoid blocking
|
|
73
|
-
|
|
74
|
-
## Environment Variables
|
|
75
|
-
|
|
76
|
-
| Variable | Default | Description |
|
|
77
|
-
| -------------------- | ------------- | ---------------------- |
|
|
78
|
-
| `CLAUDE_PROJECT_DIR` | `os.getcwd()` | Project root directory |
|
|
79
|
-
|
|
80
|
-
## Troubleshooting
|
|
81
|
-
|
|
82
|
-
### Hooks not executing
|
|
83
|
-
|
|
84
|
-
1. Verify Bun is in PATH: `bun --version`
|
|
85
|
-
2. If Python is preferred, verify: `python3 --version` or `python --version`
|
|
86
|
-
3. Check `.claude/settings.json` hooks configuration
|
|
87
|
-
4. Ensure hook files exist in `.claude/hooks/`
|
|
88
|
-
|
|
89
|
-
### "python: not found" error
|
|
90
|
-
|
|
91
|
-
This error occurs when Python is not installed or not in PATH. The universal runner will automatically fallback to TypeScript hooks run by Bun.
|
|
92
|
-
|
|
93
|
-
**Solutions:**
|
|
94
|
-
|
|
95
|
-
1. **Install Python** (recommended for full functionality):
|
|
96
|
-
- Windows: `winget install Python.Python.3.12` or download from python.org
|
|
97
|
-
- Linux: `apt install python3` or `dnf install python3`
|
|
98
|
-
- Mac: `brew install python3`
|
|
99
|
-
|
|
100
|
-
2. **Use Bun only** (already configured):
|
|
101
|
-
- TypeScript fallback hooks are automatically used when Python is unavailable
|
|
102
|
-
- No additional setup required
|
|
103
|
-
|
|
104
|
-
### Runtime detection failed
|
|
105
|
-
|
|
106
|
-
If you see `[run-hook] No runtime available`:
|
|
107
|
-
|
|
108
|
-
1. Ensure at least one runtime is installed: python3, python, bun, or Node.js
|
|
109
|
-
2. Verify the runtime is in your system PATH
|
|
110
|
-
3. For Bun: `curl -fsSL https://bun.sh/install | bash`
|
|
111
|
-
4. For Node.js (npx tsx): Install from nodejs.org
|
|
112
|
-
|
|
113
|
-
## Testing Hooks
|
|
114
|
-
|
|
115
|
-
Test the hook runner manually:
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
# Test with Bun
|
|
119
|
-
echo '{}' | bun .claude/hooks/run-hook.ts user-prompt-submit
|
|
120
|
-
|
|
121
|
-
# Test with Python (if available)
|
|
122
|
-
echo '{}' | python3 .claude/hooks/user-prompt-submit.py
|
|
123
|
-
|
|
124
|
-
# Test stop-validator
|
|
125
|
-
echo '{}' | bun .claude/hooks/run-hook.ts stop-validator
|
|
126
|
-
```
|
|
1
|
+
# Workflow Enforcement Hooks - Setup Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This system provides agent selection guidance by analyzing prompts and suggesting the best agent for the task. It includes a **universal hook runner** that supports multiple runtimes with automatic fallback.
|
|
6
|
+
|
|
7
|
+
## Runtime Support
|
|
8
|
+
|
|
9
|
+
The hooks use a universal runner (`run-hook.ts`) that automatically detects and uses the first available runtime:
|
|
10
|
+
|
|
11
|
+
| Priority | Runtime | Extension | Notes |
|
|
12
|
+
| -------- | ------- | --------- | -------------------------- |
|
|
13
|
+
| 1 | python3 | .py | Primary (user's preferred) |
|
|
14
|
+
| 2 | python | .py | Fallback |
|
|
15
|
+
| 3 | bun | .ts | TypeScript fallback |
|
|
16
|
+
| 4 | npx tsx | .ts | Final fallback |
|
|
17
|
+
|
|
18
|
+
**If no runtime is available**, the hooks return a safe default (approve/continue) to avoid blocking the user.
|
|
19
|
+
|
|
20
|
+
## Files
|
|
21
|
+
|
|
22
|
+
| File | Purpose |
|
|
23
|
+
| ------------------------ | --------------------------------------------- |
|
|
24
|
+
| `run-hook.ts` | Universal runner with runtime detection |
|
|
25
|
+
| `run-hook.sh` | Shell wrapper for Unix/Linux/Mac |
|
|
26
|
+
| `run-hook.cmd` | Batch wrapper for Windows |
|
|
27
|
+
| `user-prompt-submit.py` | Analyzes prompts and suggests agents (Python) |
|
|
28
|
+
| `user-prompt-submit.ts` | Same as above (TypeScript fallback) |
|
|
29
|
+
| `stop-validator.py` | Validates before task completion (Python) |
|
|
30
|
+
| `stop-validator.ts` | Same as above (TypeScript fallback) |
|
|
31
|
+
| `check-documentation.py` | Verifies file documentation (Python) |
|
|
32
|
+
|
|
33
|
+
## Claude Code Configuration
|
|
34
|
+
|
|
35
|
+
The hooks are configured in `.claude/settings.json`:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"hooks": {
|
|
40
|
+
"UserPromptSubmit": [
|
|
41
|
+
{
|
|
42
|
+
"matcher": "",
|
|
43
|
+
"hooks": [
|
|
44
|
+
{
|
|
45
|
+
"type": "command",
|
|
46
|
+
"command": "bun .claude/hooks/run-hook.ts user-prompt-submit",
|
|
47
|
+
"timeout": 10
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"Stop": [
|
|
53
|
+
{
|
|
54
|
+
"hooks": [
|
|
55
|
+
{
|
|
56
|
+
"type": "command",
|
|
57
|
+
"command": "bun .claude/hooks/run-hook.ts stop-validator",
|
|
58
|
+
"timeout": 30
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## How It Works
|
|
68
|
+
|
|
69
|
+
1. Claude Code calls `bun .claude/hooks/run-hook.ts <hook-name>`
|
|
70
|
+
2. `run-hook.ts` checks for available runtimes in priority order
|
|
71
|
+
3. First available runtime executes the corresponding hook file (.py or .ts)
|
|
72
|
+
4. If no runtime is available, returns safe default to avoid blocking
|
|
73
|
+
|
|
74
|
+
## Environment Variables
|
|
75
|
+
|
|
76
|
+
| Variable | Default | Description |
|
|
77
|
+
| -------------------- | ------------- | ---------------------- |
|
|
78
|
+
| `CLAUDE_PROJECT_DIR` | `os.getcwd()` | Project root directory |
|
|
79
|
+
|
|
80
|
+
## Troubleshooting
|
|
81
|
+
|
|
82
|
+
### Hooks not executing
|
|
83
|
+
|
|
84
|
+
1. Verify Bun is in PATH: `bun --version`
|
|
85
|
+
2. If Python is preferred, verify: `python3 --version` or `python --version`
|
|
86
|
+
3. Check `.claude/settings.json` hooks configuration
|
|
87
|
+
4. Ensure hook files exist in `.claude/hooks/`
|
|
88
|
+
|
|
89
|
+
### "python: not found" error
|
|
90
|
+
|
|
91
|
+
This error occurs when Python is not installed or not in PATH. The universal runner will automatically fallback to TypeScript hooks run by Bun.
|
|
92
|
+
|
|
93
|
+
**Solutions:**
|
|
94
|
+
|
|
95
|
+
1. **Install Python** (recommended for full functionality):
|
|
96
|
+
- Windows: `winget install Python.Python.3.12` or download from python.org
|
|
97
|
+
- Linux: `apt install python3` or `dnf install python3`
|
|
98
|
+
- Mac: `brew install python3`
|
|
99
|
+
|
|
100
|
+
2. **Use Bun only** (already configured):
|
|
101
|
+
- TypeScript fallback hooks are automatically used when Python is unavailable
|
|
102
|
+
- No additional setup required
|
|
103
|
+
|
|
104
|
+
### Runtime detection failed
|
|
105
|
+
|
|
106
|
+
If you see `[run-hook] No runtime available`:
|
|
107
|
+
|
|
108
|
+
1. Ensure at least one runtime is installed: python3, python, bun, or Node.js
|
|
109
|
+
2. Verify the runtime is in your system PATH
|
|
110
|
+
3. For Bun: `curl -fsSL https://bun.sh/install | bash`
|
|
111
|
+
4. For Node.js (npx tsx): Install from nodejs.org
|
|
112
|
+
|
|
113
|
+
## Testing Hooks
|
|
114
|
+
|
|
115
|
+
Test the hook runner manually:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Test with Bun
|
|
119
|
+
echo '{}' | bun .claude/hooks/run-hook.ts user-prompt-submit
|
|
120
|
+
|
|
121
|
+
# Test with Python (if available)
|
|
122
|
+
echo '{}' | python3 .claude/hooks/user-prompt-submit.py
|
|
123
|
+
|
|
124
|
+
# Test stop-validator
|
|
125
|
+
echo '{}' | bun .claude/hooks/run-hook.ts stop-validator
|
|
126
|
+
```
|
|
@@ -1,176 +1,176 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Universal Hook Runner
|
|
4
|
-
*
|
|
5
|
-
* Runs hooks with multiple runtime fallbacks:
|
|
6
|
-
* 1. python3 (primary - user's preferred)
|
|
7
|
-
* 2. python (fallback)
|
|
8
|
-
* 3. npx tsx (TypeScript execution)
|
|
9
|
-
*
|
|
10
|
-
* Usage: npx tsx run-hook.ts <hook-name>
|
|
11
|
-
* The hook-name should be without extension (e.g., "stop-validator")
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { spawnSync } from 'child_process';
|
|
15
|
-
import { existsSync } from 'fs';
|
|
16
|
-
import { join, dirname } from 'path';
|
|
17
|
-
import { fileURLToPath } from 'url';
|
|
18
|
-
|
|
19
|
-
// Get hooks directory - handle both ESM and CJS contexts
|
|
20
|
-
const getHooksDir = (): string => {
|
|
21
|
-
try {
|
|
22
|
-
if (typeof import.meta.url !== 'undefined') {
|
|
23
|
-
return dirname(fileURLToPath(import.meta.url));
|
|
24
|
-
}
|
|
25
|
-
} catch {
|
|
26
|
-
// Fallback for environments where import.meta is not available
|
|
27
|
-
}
|
|
28
|
-
return process.cwd();
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const HOOKS_DIR = getHooksDir();
|
|
32
|
-
|
|
33
|
-
function checkRuntime(cmd: string): boolean {
|
|
34
|
-
try {
|
|
35
|
-
const result = spawnSync(cmd, ['--version'], {
|
|
36
|
-
stdio: 'pipe',
|
|
37
|
-
shell: true,
|
|
38
|
-
timeout: 5000,
|
|
39
|
-
windowsHide: true,
|
|
40
|
-
});
|
|
41
|
-
return result.status === 0;
|
|
42
|
-
} catch {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function runWithRuntime(
|
|
48
|
-
cmd: string,
|
|
49
|
-
args: string[],
|
|
50
|
-
input: string
|
|
51
|
-
): { success: boolean; output: string; error?: string } {
|
|
52
|
-
try {
|
|
53
|
-
const result = spawnSync(cmd, args, {
|
|
54
|
-
input,
|
|
55
|
-
shell: true,
|
|
56
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
57
|
-
timeout: 30000,
|
|
58
|
-
windowsHide: true,
|
|
59
|
-
encoding: 'utf8',
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
success: result.status === 0,
|
|
64
|
-
output: result.stdout?.toString() || '',
|
|
65
|
-
error: result.stderr?.toString() || undefined,
|
|
66
|
-
};
|
|
67
|
-
} catch (err) {
|
|
68
|
-
return {
|
|
69
|
-
success: false,
|
|
70
|
-
output: '',
|
|
71
|
-
error: err instanceof Error ? err.message : 'Unknown error',
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function runHook(hookName: string, stdinData: string): Promise<void> {
|
|
77
|
-
const tsPath = join(HOOKS_DIR, `${hookName}.ts`);
|
|
78
|
-
const pyPath = join(HOOKS_DIR, `${hookName}.py`);
|
|
79
|
-
|
|
80
|
-
// Runtime detection order - Python FIRST, then fallbacks
|
|
81
|
-
const runtimes: Array<{ name: string; cmd: string; ext: string }> = [
|
|
82
|
-
{ name: 'python3', cmd: 'python3', ext: '.py' },
|
|
83
|
-
{ name: 'python', cmd: 'python', ext: '.py' },
|
|
84
|
-
{ name: 'bun-ts', cmd: 'bun', ext: '.ts' },
|
|
85
|
-
{ name: 'npx-tsx', cmd: 'npx tsx', ext: '.ts' },
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
for (const runtime of runtimes) {
|
|
89
|
-
const hookPath = runtime.ext === '.ts' ? tsPath : pyPath;
|
|
90
|
-
|
|
91
|
-
if (!existsSync(hookPath)) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (!checkRuntime(runtime.cmd.split(' ')[0])) {
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const result = runWithRuntime(runtime.cmd, [hookPath], stdinData);
|
|
100
|
-
|
|
101
|
-
if (result.success || !result.error?.includes('not found')) {
|
|
102
|
-
// Runtime worked (success or runtime-specific failure)
|
|
103
|
-
process.stdout.write(result.output);
|
|
104
|
-
if (result.error && !result.success) {
|
|
105
|
-
process.stderr.write(result.error);
|
|
106
|
-
}
|
|
107
|
-
process.exit(result.success ? 0 : 1);
|
|
108
|
-
}
|
|
109
|
-
// Runtime not available, try next
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// No runtime available - return safe default
|
|
113
|
-
console.error(`[run-hook] No runtime available to run hook: ${hookName}`);
|
|
114
|
-
console.error('[run-hook] Please install one of: python3, python, bun, or Node.js');
|
|
115
|
-
const safeDefault = JSON.stringify({
|
|
116
|
-
decision: 'approve',
|
|
117
|
-
continue: true,
|
|
118
|
-
reason: 'Hook runtime not available, allowing by default',
|
|
119
|
-
});
|
|
120
|
-
process.stdout.write(safeDefault);
|
|
121
|
-
process.exit(0);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async function readStdinWithTimeout(timeoutMs: number): Promise<string> {
|
|
125
|
-
return new Promise((resolve) => {
|
|
126
|
-
const timeout = setTimeout(() => {
|
|
127
|
-
process.stdin.destroy();
|
|
128
|
-
resolve('{}');
|
|
129
|
-
}, timeoutMs);
|
|
130
|
-
|
|
131
|
-
let data = '';
|
|
132
|
-
process.stdin.setEncoding('utf8');
|
|
133
|
-
process.stdin.on('data', (chunk: string) => {
|
|
134
|
-
data += chunk;
|
|
135
|
-
});
|
|
136
|
-
process.stdin.on('end', () => {
|
|
137
|
-
clearTimeout(timeout);
|
|
138
|
-
resolve(data || '{}');
|
|
139
|
-
});
|
|
140
|
-
process.stdin.on('error', () => {
|
|
141
|
-
clearTimeout(timeout);
|
|
142
|
-
resolve('{}');
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// Handle case where stdin is empty/closed immediately
|
|
146
|
-
if (process.stdin.readableEnded) {
|
|
147
|
-
clearTimeout(timeout);
|
|
148
|
-
resolve('{}');
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Main
|
|
154
|
-
async function main(): Promise<void> {
|
|
155
|
-
const hookName = process.argv[2];
|
|
156
|
-
if (!hookName) {
|
|
157
|
-
console.error('Usage: bun run-hook.ts <hook-name>');
|
|
158
|
-
process.exit(1);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Read stdin with timeout to avoid hanging
|
|
162
|
-
const stdinData = await readStdinWithTimeout(2000);
|
|
163
|
-
await runHook(hookName, stdinData);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
main().catch((err) => {
|
|
167
|
-
console.error('[run-hook] Fatal error:', err);
|
|
168
|
-
// Return safe default on error
|
|
169
|
-
const safeDefault = JSON.stringify({
|
|
170
|
-
decision: 'approve',
|
|
171
|
-
continue: true,
|
|
172
|
-
reason: 'Hook runner error, allowing by default',
|
|
173
|
-
});
|
|
174
|
-
process.stdout.write(safeDefault);
|
|
175
|
-
process.exit(0);
|
|
176
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Universal Hook Runner
|
|
4
|
+
*
|
|
5
|
+
* Runs hooks with multiple runtime fallbacks:
|
|
6
|
+
* 1. python3 (primary - user's preferred)
|
|
7
|
+
* 2. python (fallback)
|
|
8
|
+
* 3. npx tsx (TypeScript execution)
|
|
9
|
+
*
|
|
10
|
+
* Usage: npx tsx run-hook.ts <hook-name>
|
|
11
|
+
* The hook-name should be without extension (e.g., "stop-validator")
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { spawnSync } from 'child_process';
|
|
15
|
+
import { existsSync } from 'fs';
|
|
16
|
+
import { join, dirname } from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
|
|
19
|
+
// Get hooks directory - handle both ESM and CJS contexts
|
|
20
|
+
const getHooksDir = (): string => {
|
|
21
|
+
try {
|
|
22
|
+
if (typeof import.meta.url !== 'undefined') {
|
|
23
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
// Fallback for environments where import.meta is not available
|
|
27
|
+
}
|
|
28
|
+
return process.cwd();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const HOOKS_DIR = getHooksDir();
|
|
32
|
+
|
|
33
|
+
function checkRuntime(cmd: string): boolean {
|
|
34
|
+
try {
|
|
35
|
+
const result = spawnSync(cmd, ['--version'], {
|
|
36
|
+
stdio: 'pipe',
|
|
37
|
+
shell: true,
|
|
38
|
+
timeout: 5000,
|
|
39
|
+
windowsHide: true,
|
|
40
|
+
});
|
|
41
|
+
return result.status === 0;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function runWithRuntime(
|
|
48
|
+
cmd: string,
|
|
49
|
+
args: string[],
|
|
50
|
+
input: string
|
|
51
|
+
): { success: boolean; output: string; error?: string } {
|
|
52
|
+
try {
|
|
53
|
+
const result = spawnSync(cmd, args, {
|
|
54
|
+
input,
|
|
55
|
+
shell: true,
|
|
56
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
57
|
+
timeout: 30000,
|
|
58
|
+
windowsHide: true,
|
|
59
|
+
encoding: 'utf8',
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
success: result.status === 0,
|
|
64
|
+
output: result.stdout?.toString() || '',
|
|
65
|
+
error: result.stderr?.toString() || undefined,
|
|
66
|
+
};
|
|
67
|
+
} catch (err) {
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
output: '',
|
|
71
|
+
error: err instanceof Error ? err.message : 'Unknown error',
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function runHook(hookName: string, stdinData: string): Promise<void> {
|
|
77
|
+
const tsPath = join(HOOKS_DIR, `${hookName}.ts`);
|
|
78
|
+
const pyPath = join(HOOKS_DIR, `${hookName}.py`);
|
|
79
|
+
|
|
80
|
+
// Runtime detection order - Python FIRST, then fallbacks
|
|
81
|
+
const runtimes: Array<{ name: string; cmd: string; ext: string }> = [
|
|
82
|
+
{ name: 'python3', cmd: 'python3', ext: '.py' },
|
|
83
|
+
{ name: 'python', cmd: 'python', ext: '.py' },
|
|
84
|
+
{ name: 'bun-ts', cmd: 'bun', ext: '.ts' },
|
|
85
|
+
{ name: 'npx-tsx', cmd: 'npx tsx', ext: '.ts' },
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
for (const runtime of runtimes) {
|
|
89
|
+
const hookPath = runtime.ext === '.ts' ? tsPath : pyPath;
|
|
90
|
+
|
|
91
|
+
if (!existsSync(hookPath)) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!checkRuntime(runtime.cmd.split(' ')[0])) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const result = runWithRuntime(runtime.cmd, [hookPath], stdinData);
|
|
100
|
+
|
|
101
|
+
if (result.success || !result.error?.includes('not found')) {
|
|
102
|
+
// Runtime worked (success or runtime-specific failure)
|
|
103
|
+
process.stdout.write(result.output);
|
|
104
|
+
if (result.error && !result.success) {
|
|
105
|
+
process.stderr.write(result.error);
|
|
106
|
+
}
|
|
107
|
+
process.exit(result.success ? 0 : 1);
|
|
108
|
+
}
|
|
109
|
+
// Runtime not available, try next
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// No runtime available - return safe default
|
|
113
|
+
console.error(`[run-hook] No runtime available to run hook: ${hookName}`);
|
|
114
|
+
console.error('[run-hook] Please install one of: python3, python, bun, or Node.js');
|
|
115
|
+
const safeDefault = JSON.stringify({
|
|
116
|
+
decision: 'approve',
|
|
117
|
+
continue: true,
|
|
118
|
+
reason: 'Hook runtime not available, allowing by default',
|
|
119
|
+
});
|
|
120
|
+
process.stdout.write(safeDefault);
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async function readStdinWithTimeout(timeoutMs: number): Promise<string> {
|
|
125
|
+
return new Promise((resolve) => {
|
|
126
|
+
const timeout = setTimeout(() => {
|
|
127
|
+
process.stdin.destroy();
|
|
128
|
+
resolve('{}');
|
|
129
|
+
}, timeoutMs);
|
|
130
|
+
|
|
131
|
+
let data = '';
|
|
132
|
+
process.stdin.setEncoding('utf8');
|
|
133
|
+
process.stdin.on('data', (chunk: string) => {
|
|
134
|
+
data += chunk;
|
|
135
|
+
});
|
|
136
|
+
process.stdin.on('end', () => {
|
|
137
|
+
clearTimeout(timeout);
|
|
138
|
+
resolve(data || '{}');
|
|
139
|
+
});
|
|
140
|
+
process.stdin.on('error', () => {
|
|
141
|
+
clearTimeout(timeout);
|
|
142
|
+
resolve('{}');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Handle case where stdin is empty/closed immediately
|
|
146
|
+
if (process.stdin.readableEnded) {
|
|
147
|
+
clearTimeout(timeout);
|
|
148
|
+
resolve('{}');
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Main
|
|
154
|
+
async function main(): Promise<void> {
|
|
155
|
+
const hookName = process.argv[2];
|
|
156
|
+
if (!hookName) {
|
|
157
|
+
console.error('Usage: bun run-hook.ts <hook-name>');
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Read stdin with timeout to avoid hanging
|
|
162
|
+
const stdinData = await readStdinWithTimeout(2000);
|
|
163
|
+
await runHook(hookName, stdinData);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
main().catch((err) => {
|
|
167
|
+
console.error('[run-hook] Fatal error:', err);
|
|
168
|
+
// Return safe default on error
|
|
169
|
+
const safeDefault = JSON.stringify({
|
|
170
|
+
decision: 'approve',
|
|
171
|
+
continue: true,
|
|
172
|
+
reason: 'Hook runner error, allowing by default',
|
|
173
|
+
});
|
|
174
|
+
process.stdout.write(safeDefault);
|
|
175
|
+
process.exit(0);
|
|
176
|
+
});
|