hookstack-cli 0.1.5 → 0.1.7
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 +95 -0
- package/bin/cli.mjs +4 -9
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# hookstack-cli
|
|
2
|
+
|
|
3
|
+
**Install Claude Code hooks in one command.**
|
|
4
|
+
|
|
5
|
+
[hookstack.vercel.app](https://hookstack.vercel.app) — browse 66+ community-vetted lifecycle hooks for Claude Code & GitHub Copilot, then run this CLI to wire them into your project.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx hookstack-cli@latest install --hooks=secret-detection,destructive-command-guard
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
That's it. The CLI fetches the hooks, shows you what will be installed, and patches your `.claude/settings.json`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
npx hookstack-cli@latest install --hooks=<slug1>,<slug2>,...
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--hooks <slugs> Comma-separated hook slugs (required)
|
|
26
|
+
--global, -g Install into ~/.claude instead of ./.claude
|
|
27
|
+
--scope <s> "project" (default) or "global"
|
|
28
|
+
--yes, -y Skip prompts (non-interactive / CI)
|
|
29
|
+
--version, -v Print version
|
|
30
|
+
--help, -h Show help
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Interactive mode (default in a terminal)
|
|
34
|
+
|
|
35
|
+
When run in a terminal the CLI opens an interactive prompt:
|
|
36
|
+
|
|
37
|
+
1. Fetches the requested hooks from the registry
|
|
38
|
+
2. Shows an **installation summary** (path, category, events, blocking flag)
|
|
39
|
+
3. Shows a **security panel** (shell access · network · filesystem writes · Snyk score)
|
|
40
|
+
4. Asks for confirmation before writing anything
|
|
41
|
+
|
|
42
|
+
### Non-interactive mode (`--yes` or piped)
|
|
43
|
+
|
|
44
|
+
Skips all prompts — useful in CI or dotfile bootstrap scripts.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# CI bootstrap
|
|
48
|
+
npx hookstack-cli@latest install --hooks=secret-detection,git-push-guard --yes --scope=project
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## What gets installed
|
|
54
|
+
|
|
55
|
+
For each hook the CLI:
|
|
56
|
+
|
|
57
|
+
- Writes the `.mjs` script to `.claude/hooks/` (or `~/.claude/hooks/` for global scope)
|
|
58
|
+
- Patches `.claude/settings.json` to register the hook on the right lifecycle event
|
|
59
|
+
|
|
60
|
+
No new dependencies are added to your project. Hooks are plain Node.js scripts — no SDK, no agent modification.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Finding hooks
|
|
65
|
+
|
|
66
|
+
Browse and filter the full catalogue at **[hookstack.vercel.app](https://hookstack.vercel.app)**:
|
|
67
|
+
|
|
68
|
+
- Filter by category (`security`, `workflow`, `context`, `validation`…)
|
|
69
|
+
- Select the hooks you want — your basket persists in the browser
|
|
70
|
+
- Copy the generated `npx hookstack-cli@latest install` command and run it
|
|
71
|
+
|
|
72
|
+
### Popular hooks
|
|
73
|
+
|
|
74
|
+
| Slug | Event | What it does |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| `secret-detection` | `PreToolUse / Bash` | Blocks commands that would leak API keys |
|
|
77
|
+
| `destructive-command-guard` | `PreToolUse / Bash` | Stops `rm -rf /`, `DROP TABLE`, and similar |
|
|
78
|
+
| `sensitive-file-protection` | `PreToolUse / Write` | Keeps `.env` and key files untouched |
|
|
79
|
+
| `git-push-guard` | `PreToolUse / Bash` | No accidental push straight to `main` |
|
|
80
|
+
| `git-context-on-startup` | `SessionStart` | Every session opens with branch + status |
|
|
81
|
+
| `auto-format-on-save` | `PostToolUse / Write` | ESLint + Prettier run after every file write |
|
|
82
|
+
| `slack-notify-on-stop` | `Stop` | Pings you when the long task finishes |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Requirements
|
|
87
|
+
|
|
88
|
+
- Node.js ≥ 18
|
|
89
|
+
- Claude Code installed (hooks are wired into its lifecycle)
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT — [github.com/steve-magne/hookstack](https://github.com/steve-magne/hookstack)
|
package/bin/cli.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'
|
|
3
3
|
import { homedir } from 'os'
|
|
4
|
-
import { join } from 'path'
|
|
4
|
+
import { join, dirname } from 'path'
|
|
5
5
|
import { fileURLToPath } from 'url'
|
|
6
6
|
import * as p from '@clack/prompts'
|
|
7
7
|
import pc from 'picocolors'
|
|
@@ -17,7 +17,8 @@ import {
|
|
|
17
17
|
|
|
18
18
|
const API_BASE = process.env.HOOKSTACK_API_BASE || 'https://hookstack.vercel.app'
|
|
19
19
|
const REPO_URL = 'github.com/steve-magne/hookstack'
|
|
20
|
-
const
|
|
20
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
21
|
+
const VERSION = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8')).version
|
|
21
22
|
|
|
22
23
|
async function fetchHooks(slugs) {
|
|
23
24
|
const url = `${API_BASE}/api/hooks?slugs=${slugs.map(encodeURIComponent).join(',')}`
|
|
@@ -222,7 +223,7 @@ async function main() {
|
|
|
222
223
|
const args = parseArgs(process.argv)
|
|
223
224
|
|
|
224
225
|
if (args.version) { console.log(VERSION); return }
|
|
225
|
-
if (args.help ||
|
|
226
|
+
if (args.help || args.hooks.length === 0) { console.log(HELP); return }
|
|
226
227
|
|
|
227
228
|
const command = args.command ?? 'install'
|
|
228
229
|
if (command !== 'install') {
|
|
@@ -231,12 +232,6 @@ async function main() {
|
|
|
231
232
|
process.exit(1)
|
|
232
233
|
}
|
|
233
234
|
|
|
234
|
-
if (args.hooks.length === 0) {
|
|
235
|
-
console.error('✗ No hooks specified. Use --hooks=<slug1>,<slug2>')
|
|
236
|
-
console.error(' Browse hooks at https://hookstack.vercel.app')
|
|
237
|
-
process.exit(1)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
235
|
const interactive = Boolean(process.stdout.isTTY) && !args.yes
|
|
241
236
|
if (interactive) await interactiveInstall(args.hooks, args)
|
|
242
237
|
else await directInstall(args.hooks, args)
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hookstack-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "CLI installer for the Hookstack catalogue of Claude Code hooks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"hookstack-cli": "./bin/cli.mjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
|
-
"bin/"
|
|
10
|
+
"bin/",
|
|
11
|
+
"README.md"
|
|
11
12
|
],
|
|
12
13
|
"engines": {
|
|
13
14
|
"node": ">=18"
|