start-vibing 2.0.2 → 2.0.3
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/package.json +1 -1
- package/template/.claude/agents/01-orchestration/checkpoint-manager.md +1 -1
- package/template/.claude/agents/01-orchestration/context-manager.md +1 -1
- package/template/.claude/agents/01-orchestration/error-recovery.md +1 -1
- package/template/.claude/agents/01-orchestration/orchestrator.md +1 -1
- package/template/.claude/agents/01-orchestration/parallel-coordinator.md +1 -1
- package/template/.claude/agents/01-orchestration/task-decomposer.md +1 -1
- package/template/.claude/agents/01-orchestration/workflow-router.md +1 -1
- package/template/.claude/agents/02-typescript/bun-runtime-expert.md +1 -1
- package/template/.claude/agents/02-typescript/esm-resolver.md +1 -1
- package/template/.claude/agents/02-typescript/import-alias-enforcer.md +1 -1
- package/template/.claude/agents/02-typescript/ts-migration-helper.md +1 -1
- package/template/.claude/agents/02-typescript/ts-strict-checker.md +1 -1
- package/template/.claude/agents/02-typescript/ts-types-analyzer.md +1 -1
- package/template/.claude/agents/02-typescript/type-definition-writer.md +1 -1
- package/template/.claude/agents/02-typescript/zod-schema-designer.md +1 -1
- package/template/.claude/agents/02-typescript/zod-validator.md +1 -1
- package/template/.claude/hooks/SETUP.md +85 -11
- package/template/.claude/hooks/run-hook.cmd +46 -0
- package/template/.claude/hooks/run-hook.sh +43 -0
- package/template/.claude/hooks/run-hook.ts +158 -0
- package/template/.claude/hooks/stop-validator.ts +339 -0
- package/template/.claude/hooks/user-prompt-submit.ts +298 -0
- package/template/.claude/settings.json +4 -3
- package/template/.claude/skills/bun-runtime/SKILL.md +430 -0
- package/template/.claude/skills/codebase-knowledge/domains/claude-system.md +46 -4
- package/template/.claude/skills/mongoose-patterns/SKILL.md +512 -0
- package/template/.claude/skills/nextjs-app-router/SKILL.md +337 -0
- package/template/.claude/skills/playwright-automation/SKILL.md +438 -0
- package/template/.claude/skills/react-patterns/SKILL.md +376 -0
- package/template/.claude/skills/shadcn-ui/SKILL.md +520 -0
- package/template/.claude/skills/tailwind-patterns/SKILL.md +467 -0
- package/template/.claude/skills/trpc-api/SKILL.md +435 -0
- package/template/.claude/skills/typescript-strict/SKILL.md +368 -0
- package/template/.claude/skills/zod-validation/SKILL.md +405 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: checkpoint-manager
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke BEFORE risky operations. Triggers: before git operations, before file deletions, before major refactors. Saves and restores workflow checkpoints. PROACTIVELY saves state before destructive operations."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Write, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: context-manager
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke when context grows large or between major phases. Triggers: agent handoff, long conversation, context bloat. Compresses state, saves checkpoints, prunes irrelevant data. PROACTIVELY manages token budget."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Write, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: error-recovery
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke when an agent fails or returns unexpected results. Triggers: tool failure, agent timeout, validation failure, unexpected error. Implements retry logic and fallbacks. PROACTIVELY handles failures in the pipeline."
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Bash, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: orchestrator
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke for ANY multi-step task. Triggers: 'implement feature', 'build X', 'create Y', 'fix and test', 'full workflow'. Coordinates ALL other agents in sequence. Use when task requires >2 agents or touches >3 files. PROACTIVELY takes control of complex development flows."
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch
|
|
6
6
|
skills: codebase-knowledge
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: parallel-coordinator
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke when multiple independent agents should run simultaneously. Triggers: parallel execution needed, fan-out/gather pattern, independent tasks identified. Coordinates parallel agent execution. PROACTIVELY optimizes multi-agent workflows."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: task-decomposer
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke when task has >3 steps or touches >3 files. Triggers: complex task, multi-domain task, unclear scope, feature implementation. Breaks complex tasks into atomic subtasks for parallel execution. PROACTIVELY decomposes before implementation."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Grep, Glob
|
|
6
6
|
skills: codebase-knowledge
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: workflow-router
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke at task start to route to correct agent. Triggers: new request, unclear which agent, multiple valid routes. Routes tasks based on keywords, file types, and context. PROACTIVELY analyzes requests for optimal routing."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bun-runtime-expert
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke when using Bun runtime. Triggers: 'bun', runtime issues, package management, node compatibility. Expert in Bun-specific APIs and configurations. PROACTIVELY suggests Bun alternatives to Node.js."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Bash, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: esm-resolver
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke on module errors. Triggers: 'module error', 'import error', 'cannot find module', 'require is not defined'. Fixes ESM/CJS compatibility issues. PROACTIVELY resolves import problems."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: import-alias-enforcer
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke AFTER editing .ts files. Triggers: new .ts file, imports added, code review. Enforces $types/*, @common, @db aliases. PROACTIVELY checks all imports use correct aliases."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ts-migration-helper
|
|
3
|
-
description: "Helps migrate JavaScript to TypeScript. Triggers: 'migrate to ts', 'convert to typescript'. Adds types progressively with strict mode."
|
|
3
|
+
description: "Helps migrate JavaScript to TypeScript. Triggers: 'migrate to ts', 'convert to typescript', .js files in project. Adds types progressively with strict mode."
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Write, Edit, Grep, Glob, Bash
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ts-strict-checker
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke AFTER editing any .ts file. Triggers: editing .ts files, new .ts file, process.env access. Validates index access, literal types, null checks. PROACTIVELY enforces TypeScript strict mode rules."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Grep, Glob, Bash
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ts-types-analyzer
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke on type errors. Triggers: 'type error', 'inference issue', 'generic problem', typecheck fails. Analyzes complex TypeScript types and debugs inference. PROACTIVELY fixes type issues."
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Grep, Glob, Bash
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: type-definition-writer
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke BEFORE implementing new entities. Triggers: new model, new API, new entity, interface needed. Writes type definitions for types/ folder. PROACTIVELY creates interfaces following project conventions."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Write, Edit, Grep, Glob
|
|
6
6
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: zod-schema-designer
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke BEFORE implementing any API endpoint. Triggers: new API endpoint, new route, form input, user input. Designs Zod validation schemas. PROACTIVELY creates comprehensive input validation."
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Write, Edit, Grep, Glob
|
|
6
6
|
skills: codebase-knowledge
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: zod-validator
|
|
3
|
-
description: "
|
|
3
|
+
description: "AUTOMATICALLY invoke BEFORE commit when API routes exist. Triggers: API route modified, security audit, validation audit. Validates all routes have proper Zod validation. PROACTIVELY checks schema completeness."
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Grep, Glob
|
|
6
6
|
---
|
|
@@ -2,21 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
This system provides agent selection guidance by analyzing prompts and suggesting the best agent for the task.
|
|
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
6
|
|
|
7
|
-
##
|
|
7
|
+
## Runtime Support
|
|
8
8
|
|
|
9
|
-
-
|
|
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.
|
|
10
19
|
|
|
11
20
|
## Files
|
|
12
21
|
|
|
13
|
-
| File
|
|
14
|
-
|
|
|
15
|
-
| `
|
|
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) |
|
|
16
32
|
|
|
17
33
|
## Claude Code Configuration
|
|
18
34
|
|
|
19
|
-
The hooks are configured in `.claude/settings.
|
|
35
|
+
The hooks are configured in `.claude/settings.json`:
|
|
20
36
|
|
|
21
37
|
```json
|
|
22
38
|
{
|
|
@@ -27,16 +43,34 @@ The hooks are configured in `.claude/settings.local.json`:
|
|
|
27
43
|
"hooks": [
|
|
28
44
|
{
|
|
29
45
|
"type": "command",
|
|
30
|
-
"command": "
|
|
46
|
+
"command": "bun .claude/hooks/run-hook.ts user-prompt-submit",
|
|
31
47
|
"timeout": 10
|
|
32
48
|
}
|
|
33
49
|
]
|
|
34
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
|
+
}
|
|
35
62
|
]
|
|
36
63
|
}
|
|
37
64
|
}
|
|
38
65
|
```
|
|
39
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
|
+
|
|
40
74
|
## Environment Variables
|
|
41
75
|
|
|
42
76
|
| Variable | Default | Description |
|
|
@@ -47,6 +81,46 @@ The hooks are configured in `.claude/settings.local.json`:
|
|
|
47
81
|
|
|
48
82
|
### Hooks not executing
|
|
49
83
|
|
|
50
|
-
1. Verify
|
|
51
|
-
2.
|
|
52
|
-
3.
|
|
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
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
@echo off
|
|
2
|
+
REM Universal Hook Runner for Windows
|
|
3
|
+
REM Tries: python -> python3 -> bun -> npx tsx
|
|
4
|
+
|
|
5
|
+
set HOOK_NAME=%1
|
|
6
|
+
set HOOKS_DIR=%~dp0
|
|
7
|
+
|
|
8
|
+
REM Try Python first
|
|
9
|
+
where python >nul 2>&1
|
|
10
|
+
if %ERRORLEVEL% EQU 0 (
|
|
11
|
+
if exist "%HOOKS_DIR%%HOOK_NAME%.py" (
|
|
12
|
+
python "%HOOKS_DIR%%HOOK_NAME%.py"
|
|
13
|
+
exit /b %ERRORLEVEL%
|
|
14
|
+
)
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
REM Try Python3
|
|
18
|
+
where python3 >nul 2>&1
|
|
19
|
+
if %ERRORLEVEL% EQU 0 (
|
|
20
|
+
if exist "%HOOKS_DIR%%HOOK_NAME%.py" (
|
|
21
|
+
python3 "%HOOKS_DIR%%HOOK_NAME%.py"
|
|
22
|
+
exit /b %ERRORLEVEL%
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
REM Try Bun with TypeScript
|
|
27
|
+
where bun >nul 2>&1
|
|
28
|
+
if %ERRORLEVEL% EQU 0 (
|
|
29
|
+
if exist "%HOOKS_DIR%%HOOK_NAME%.ts" (
|
|
30
|
+
bun "%HOOKS_DIR%%HOOK_NAME%.ts"
|
|
31
|
+
exit /b %ERRORLEVEL%
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
REM Try npx tsx as final fallback
|
|
36
|
+
where npx >nul 2>&1
|
|
37
|
+
if %ERRORLEVEL% EQU 0 (
|
|
38
|
+
if exist "%HOOKS_DIR%%HOOK_NAME%.ts" (
|
|
39
|
+
npx tsx "%HOOKS_DIR%%HOOK_NAME%.ts"
|
|
40
|
+
exit /b %ERRORLEVEL%
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
REM No runtime available - return safe default
|
|
45
|
+
echo {"decision":"approve","reason":"No runtime available for hook, allowing by default"}
|
|
46
|
+
exit /b 0
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Universal Hook Runner for Unix/Linux/Mac
|
|
3
|
+
# Tries: python3 -> python -> bun -> npx tsx
|
|
4
|
+
|
|
5
|
+
HOOK_NAME="$1"
|
|
6
|
+
HOOKS_DIR="$(dirname "$0")"
|
|
7
|
+
|
|
8
|
+
# Check if a command exists
|
|
9
|
+
command_exists() {
|
|
10
|
+
command -v "$1" >/dev/null 2>&1
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
# Try Python3 first
|
|
14
|
+
if command_exists python3; then
|
|
15
|
+
if [ -f "$HOOKS_DIR/$HOOK_NAME.py" ]; then
|
|
16
|
+
exec python3 "$HOOKS_DIR/$HOOK_NAME.py"
|
|
17
|
+
fi
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Try Python
|
|
21
|
+
if command_exists python; then
|
|
22
|
+
if [ -f "$HOOKS_DIR/$HOOK_NAME.py" ]; then
|
|
23
|
+
exec python "$HOOKS_DIR/$HOOK_NAME.py"
|
|
24
|
+
fi
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
# Try Bun with TypeScript
|
|
28
|
+
if command_exists bun; then
|
|
29
|
+
if [ -f "$HOOKS_DIR/$HOOK_NAME.ts" ]; then
|
|
30
|
+
exec bun "$HOOKS_DIR/$HOOK_NAME.ts"
|
|
31
|
+
fi
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Try npx tsx as final fallback
|
|
35
|
+
if command_exists npx; then
|
|
36
|
+
if [ -f "$HOOKS_DIR/$HOOK_NAME.ts" ]; then
|
|
37
|
+
exec npx tsx "$HOOKS_DIR/$HOOK_NAME.ts"
|
|
38
|
+
fi
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# No runtime available - return safe default
|
|
42
|
+
echo '{"decision":"approve","reason":"No runtime available for hook, allowing by default"}'
|
|
43
|
+
exit 0
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
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. Bun TypeScript (fallback if Python not available)
|
|
9
|
+
* 4. npx tsx (final fallback)
|
|
10
|
+
*
|
|
11
|
+
* Usage: bun run-hook.ts <hook-name>
|
|
12
|
+
* The hook-name should be without extension (e.g., "stop-validator")
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { spawnSync } from 'child_process';
|
|
16
|
+
import { existsSync } from 'fs';
|
|
17
|
+
import { join, dirname } from 'path';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
19
|
+
|
|
20
|
+
// Get hooks directory - handle both ESM and CJS contexts
|
|
21
|
+
const getHooksDir = (): string => {
|
|
22
|
+
try {
|
|
23
|
+
if (typeof import.meta.url !== 'undefined') {
|
|
24
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
}
|
|
26
|
+
} catch {
|
|
27
|
+
// Fallback for environments where import.meta is not available
|
|
28
|
+
}
|
|
29
|
+
return process.cwd();
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const HOOKS_DIR = getHooksDir();
|
|
33
|
+
|
|
34
|
+
function checkRuntime(cmd: string): boolean {
|
|
35
|
+
try {
|
|
36
|
+
const result = spawnSync(cmd, ['--version'], {
|
|
37
|
+
stdio: 'pipe',
|
|
38
|
+
shell: true,
|
|
39
|
+
timeout: 5000,
|
|
40
|
+
windowsHide: true
|
|
41
|
+
});
|
|
42
|
+
return result.status === 0;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function runWithRuntime(cmd: string, args: string[], input: string): { success: boolean; output: string; error?: string } {
|
|
49
|
+
try {
|
|
50
|
+
const result = spawnSync(cmd, args, {
|
|
51
|
+
input,
|
|
52
|
+
shell: true,
|
|
53
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
54
|
+
timeout: 30000,
|
|
55
|
+
windowsHide: true,
|
|
56
|
+
encoding: 'utf8'
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
success: result.status === 0,
|
|
61
|
+
output: result.stdout?.toString() || '',
|
|
62
|
+
error: result.stderr?.toString() || undefined
|
|
63
|
+
};
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
output: '',
|
|
68
|
+
error: err instanceof Error ? err.message : 'Unknown error'
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function runHook(hookName: string, stdinData: string): Promise<void> {
|
|
74
|
+
const tsPath = join(HOOKS_DIR, `${hookName}.ts`);
|
|
75
|
+
const pyPath = join(HOOKS_DIR, `${hookName}.py`);
|
|
76
|
+
|
|
77
|
+
// Runtime detection order - Python FIRST, then fallbacks
|
|
78
|
+
const runtimes: Array<{ name: string; cmd: string; ext: string }> = [
|
|
79
|
+
{ name: 'python3', cmd: 'python3', ext: '.py' },
|
|
80
|
+
{ name: 'python', cmd: 'python', ext: '.py' },
|
|
81
|
+
{ name: 'bun-ts', cmd: 'bun', ext: '.ts' },
|
|
82
|
+
{ name: 'npx-tsx', cmd: 'npx tsx', ext: '.ts' }
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
for (const runtime of runtimes) {
|
|
86
|
+
const hookPath = runtime.ext === '.ts' ? tsPath : pyPath;
|
|
87
|
+
|
|
88
|
+
if (!existsSync(hookPath)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!checkRuntime(runtime.cmd.split(' ')[0])) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const result = runWithRuntime(runtime.cmd, [hookPath], stdinData);
|
|
97
|
+
|
|
98
|
+
if (result.success || !result.error?.includes('not found')) {
|
|
99
|
+
// Runtime worked (success or runtime-specific failure)
|
|
100
|
+
process.stdout.write(result.output);
|
|
101
|
+
if (result.error && !result.success) {
|
|
102
|
+
process.stderr.write(result.error);
|
|
103
|
+
}
|
|
104
|
+
process.exit(result.success ? 0 : 1);
|
|
105
|
+
}
|
|
106
|
+
// Runtime not available, try next
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// No runtime available - return safe default
|
|
110
|
+
console.error(`[run-hook] No runtime available to run hook: ${hookName}`);
|
|
111
|
+
console.error('[run-hook] Please install one of: python3, python, bun, or Node.js');
|
|
112
|
+
const safeDefault = JSON.stringify({
|
|
113
|
+
decision: 'approve',
|
|
114
|
+
continue: true,
|
|
115
|
+
reason: 'Hook runtime not available, allowing by default'
|
|
116
|
+
});
|
|
117
|
+
process.stdout.write(safeDefault);
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function readStdinWithTimeout(timeoutMs: number): Promise<string> {
|
|
122
|
+
return new Promise((resolve) => {
|
|
123
|
+
const timeout = setTimeout(() => resolve('{}'), timeoutMs);
|
|
124
|
+
|
|
125
|
+
Bun.stdin.text().then((text) => {
|
|
126
|
+
clearTimeout(timeout);
|
|
127
|
+
resolve(text || '{}');
|
|
128
|
+
}).catch(() => {
|
|
129
|
+
clearTimeout(timeout);
|
|
130
|
+
resolve('{}');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Main
|
|
136
|
+
async function main(): Promise<void> {
|
|
137
|
+
const hookName = process.argv[2];
|
|
138
|
+
if (!hookName) {
|
|
139
|
+
console.error('Usage: bun run-hook.ts <hook-name>');
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Read stdin with timeout to avoid hanging
|
|
144
|
+
const stdinData = await readStdinWithTimeout(2000);
|
|
145
|
+
await runHook(hookName, stdinData);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
main().catch((err) => {
|
|
149
|
+
console.error('[run-hook] Fatal error:', err);
|
|
150
|
+
// Return safe default on error
|
|
151
|
+
const safeDefault = JSON.stringify({
|
|
152
|
+
decision: 'approve',
|
|
153
|
+
continue: true,
|
|
154
|
+
reason: 'Hook runner error, allowing by default'
|
|
155
|
+
});
|
|
156
|
+
process.stdout.write(safeDefault);
|
|
157
|
+
process.exit(0);
|
|
158
|
+
});
|