hail-hydra-cc 2.0.3 → 2.0.4
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 +7 -4
- package/files/SKILL.md +75 -0
- package/files/commands/hydra/help.md +1 -0
- package/files/commands/hydra/quiet.md +2 -0
- package/files/commands/hydra/report.md +112 -0
- package/files/commands/hydra/update.md +78 -35
- package/files/commands/hydra/verbose.md +2 -0
- package/files/hooks/hydra-notify.js +80 -0
- package/files/hooks/hydra-task-complete.wav +0 -0
- package/package.json +1 -1
- package/src/display.js +3 -3
- package/src/files.js +7 -1
- package/src/installer.js +31 -1
package/README.md
CHANGED
|
@@ -56,18 +56,21 @@ npx hail-hydra-cc --help # Show help
|
|
|
56
56
|
│ ├── hydra-coder.md
|
|
57
57
|
│ ├── hydra-analyst.md
|
|
58
58
|
│ └── hydra-sentinel.md
|
|
59
|
-
├── commands/hydra/ #
|
|
59
|
+
├── commands/hydra/ # 8 slash commands
|
|
60
60
|
│ ├── help.md # /hydra:help
|
|
61
61
|
│ ├── status.md # /hydra:status
|
|
62
62
|
│ ├── update.md # /hydra:update
|
|
63
63
|
│ ├── config.md # /hydra:config
|
|
64
64
|
│ ├── guard.md # /hydra:guard
|
|
65
65
|
│ ├── quiet.md # /hydra:quiet
|
|
66
|
-
│
|
|
67
|
-
|
|
66
|
+
│ ├── verbose.md # /hydra:verbose
|
|
67
|
+
│ └── report.md # /hydra:report
|
|
68
|
+
├── hooks/ # 4 lifecycle hooks
|
|
68
69
|
│ ├── hydra-check-update.js # SessionStart — version check
|
|
69
70
|
│ ├── hydra-statusline.js # StatusLine — status bar
|
|
70
|
-
│
|
|
71
|
+
│ ├── hydra-auto-guard.js # PostToolUse — file tracker
|
|
72
|
+
│ ├── hydra-notify.js # Notification — task completion sound
|
|
73
|
+
│ └── hydra-task-complete.wav # Notification sound file
|
|
71
74
|
└── skills/hydra/ # Skill (Claude Code discoverable via /skills)
|
|
72
75
|
├── SKILL.md # Orchestrator instructions
|
|
73
76
|
├── VERSION # Installed version
|
package/files/SKILL.md
CHANGED
|
@@ -14,6 +14,49 @@ description: >
|
|
|
14
14
|
> *"Cut off one head, two more shall take its place."*
|
|
15
15
|
> Except here — every head is doing your work faster and cheaper.
|
|
16
16
|
|
|
17
|
+
## ⛔ MANDATORY PROTOCOLS — NEVER SKIP
|
|
18
|
+
|
|
19
|
+
These protocols are NON-NEGOTIABLE. Skipping them is a framework violation.
|
|
20
|
+
|
|
21
|
+
### Protocol 1: Sentinel Scan After Code Changes
|
|
22
|
+
|
|
23
|
+
When ANY agent returns output containing `⚠️ HYDRA_SENTINEL_REQUIRED`, you
|
|
24
|
+
MUST — before doing ANYTHING else, before presenting results to the user,
|
|
25
|
+
before running any other agents — dispatch hydra-sentinel-scan with the
|
|
26
|
+
files and changes listed in the trigger block.
|
|
27
|
+
|
|
28
|
+
**This is blocking.** The user does NOT see the code changes until sentinel
|
|
29
|
+
completes. If you present code changes to the user without running sentinel
|
|
30
|
+
first, you have violated the framework's core safety guarantee.
|
|
31
|
+
|
|
32
|
+
Sequence:
|
|
33
|
+
1. Receive agent output containing ⚠️ HYDRA_SENTINEL_REQUIRED
|
|
34
|
+
2. IMMEDIATELY dispatch hydra-sentinel-scan AND hydra-guard in parallel
|
|
35
|
+
3. WAIT for both to complete
|
|
36
|
+
4. If sentinel-scan finds issues → dispatch hydra-sentinel (deep analysis)
|
|
37
|
+
5. WAIT for deep analysis
|
|
38
|
+
6. THEN — and ONLY then — present results to the user
|
|
39
|
+
|
|
40
|
+
If the agent output contains `✅ HYDRA_NO_CODE_CHANGES`, skip sentinel. Present
|
|
41
|
+
results immediately.
|
|
42
|
+
|
|
43
|
+
### Protocol 2: Sentinel Fix Decision Tree
|
|
44
|
+
|
|
45
|
+
When hydra-sentinel confirms real issues:
|
|
46
|
+
|
|
47
|
+
**TRIVIAL** (auto-fix without asking):
|
|
48
|
+
Import renames, file path updates, barrel file re-exports.
|
|
49
|
+
→ Dispatch hydra-coder to fix. Re-run sentinel-scan to verify.
|
|
50
|
+
→ Tell user: "Sentinel caught [issue]. Auto-fixed."
|
|
51
|
+
|
|
52
|
+
**MEDIUM** (present to user, offer to fix):
|
|
53
|
+
API contract mismatches, missing env vars, signature mismatches.
|
|
54
|
+
→ Show the sentinel report. Ask: "Want me to fix these?"
|
|
55
|
+
|
|
56
|
+
**COMPLEX** (report only):
|
|
57
|
+
Architectural changes, migration needed, business logic decisions.
|
|
58
|
+
→ Show the report. Let user decide.
|
|
59
|
+
|
|
17
60
|
## Why Hydra Exists
|
|
18
61
|
|
|
19
62
|
Autoregressive LLM inference is memory-bandwidth bound — the time per token scales with model
|
|
@@ -505,6 +548,10 @@ When manual verification is required, match depth to risk:
|
|
|
505
548
|
|
|
506
549
|
## Sentinel Protocol — Integration Integrity
|
|
507
550
|
|
|
551
|
+
> **REMINDER:** If you see `⚠️ HYDRA_SENTINEL_REQUIRED` in any agent's output
|
|
552
|
+
> and you skip sentinel, you are violating the framework's core protocol.
|
|
553
|
+
> See "⛔ MANDATORY PROTOCOLS" at the top of this document.
|
|
554
|
+
|
|
508
555
|
After EVERY code change made by hydra-coder or hydra-analyst (or yourself),
|
|
509
556
|
you MUST run the sentinel pipeline BEFORE presenting results to the user.
|
|
510
557
|
|
|
@@ -703,6 +750,19 @@ Note: Savings calculated against Opus 4.6 pricing ($5/$25 per MTok) as of Februa
|
|
|
703
750
|
"Re-executing [task] directly — [agent]'s output was insufficient because [reason]"
|
|
704
751
|
- **If accepted as-is**, no inline comment needed — the dispatch log covers it
|
|
705
752
|
|
|
753
|
+
### Sentinel Status in Dispatch Log
|
|
754
|
+
|
|
755
|
+
The dispatch log MUST show sentinel status for every task involving code changes:
|
|
756
|
+
|
|
757
|
+
| Step | Agent | Task | Verdict |
|
|
758
|
+
|------|-------|------|---------|
|
|
759
|
+
| 1 | hydra-coder (Sonnet 4.6) | Fixed auth bug | ✅ Accepted |
|
|
760
|
+
| 2 | hydra-sentinel-scan (Haiku) | Integration sweep | ✅ Clean |
|
|
761
|
+
| 3 | hydra-guard (Haiku 4.5) | Security scan | ✅ Clean |
|
|
762
|
+
|
|
763
|
+
If sentinel-scan is missing from the dispatch log after a code change,
|
|
764
|
+
something went wrong. This is your self-check.
|
|
765
|
+
|
|
706
766
|
### Controlling the Dispatch Log
|
|
707
767
|
|
|
708
768
|
- **Default**: ON — always shown when 2+ agents were used
|
|
@@ -887,6 +947,21 @@ Track these mentally to calibrate:
|
|
|
887
947
|
If rejection rate > 20%, you're too aggressive — shift borderline tasks up one tier.
|
|
888
948
|
If rejection rate < 5%, you're too conservative — delegate more.
|
|
889
949
|
|
|
950
|
+
## Task Completion Notification
|
|
951
|
+
|
|
952
|
+
After completing a user's task (the final response you present to the user),
|
|
953
|
+
run this command as the LAST action:
|
|
954
|
+
```bash
|
|
955
|
+
node ~/.claude/hooks/hydra-notify.js < /dev/null
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
This plays a short notification sound so the user knows you're done —
|
|
959
|
+
especially useful when they've tabbed away while waiting.
|
|
960
|
+
|
|
961
|
+
Do this for SUBSTANTIAL tasks only (tasks that took more than ~10 seconds).
|
|
962
|
+
Do NOT play it for quick conversational responses, acknowledgments, or
|
|
963
|
+
follow-up questions.
|
|
964
|
+
|
|
890
965
|
## Reference Material
|
|
891
966
|
|
|
892
967
|
- `references/routing-guide.md` — Mandatory delegation examples, decision flowchart
|
|
@@ -17,6 +17,7 @@ COMMANDS
|
|
|
17
17
|
/hydra:guard Run security scan on files (usage: /hydra:guard src/auth.py)
|
|
18
18
|
/hydra:quiet Suppress dispatch logs for this session
|
|
19
19
|
/hydra:verbose Enable verbose dispatch logs with timing
|
|
20
|
+
/hydra:report Report a bug, request a feature, or share feedback
|
|
20
21
|
|
|
21
22
|
AGENTS
|
|
22
23
|
🟢 hydra-scout (Haiku 4.5) — Explore codebase, find files, map structure
|
|
@@ -12,3 +12,5 @@ Respond with:
|
|
|
12
12
|
"🐉 Quiet mode enabled. Dispatch logs suppressed for this session. Use /hydra:verbose to re-enable."
|
|
13
13
|
|
|
14
14
|
Continue operating Hydra normally (delegation, verification, auto-guard) — just don't show the dispatch log table.
|
|
15
|
+
|
|
16
|
+
Also suppress the task completion notification sound for this session.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Report a bug, request a feature, or share feedback about Hydra
|
|
3
|
+
allowed-tools: Bash
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hydra Report
|
|
7
|
+
|
|
8
|
+
Walk the user through submitting a bug report, feature request, or general feedback for the Hydra framework. Follow these steps interactively:
|
|
9
|
+
|
|
10
|
+
## Step 1 — Ask report type
|
|
11
|
+
|
|
12
|
+
Ask the user:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
🐉 What would you like to report?
|
|
16
|
+
|
|
17
|
+
1. 🐛 Bug Report — something is broken or not working as expected
|
|
18
|
+
2. ✨ Feature Request — an idea for a new feature or improvement
|
|
19
|
+
3. 💬 General Feedback — anything else you'd like to share
|
|
20
|
+
|
|
21
|
+
Enter 1, 2, or 3:
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Wait for their response. Map:
|
|
25
|
+
- 1 → label: `bug`, template: Bug Report
|
|
26
|
+
- 2 → label: `enhancement`, template: Feature Request
|
|
27
|
+
- 3 → label: `feedback`, template: General Feedback
|
|
28
|
+
|
|
29
|
+
## Step 2 — Collect description
|
|
30
|
+
|
|
31
|
+
Ask the user to describe the issue or idea:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Describe the [bug/feature/feedback] in a few sentences:
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For bugs, also ask:
|
|
38
|
+
```
|
|
39
|
+
Steps to reproduce (if applicable):
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Step 3 — Collect system info (optional)
|
|
43
|
+
|
|
44
|
+
Ask: "Include system info in the report? (recommended for bugs) [Y/n]"
|
|
45
|
+
|
|
46
|
+
If yes, gather:
|
|
47
|
+
```bash
|
|
48
|
+
# Hydra version
|
|
49
|
+
cat ~/.claude/skills/hydra/VERSION 2>/dev/null || echo "not found"
|
|
50
|
+
```
|
|
51
|
+
```bash
|
|
52
|
+
# OS info
|
|
53
|
+
node -e "console.log(process.platform + ' ' + process.arch + ' ' + require('os').release())"
|
|
54
|
+
```
|
|
55
|
+
```bash
|
|
56
|
+
# Agent count
|
|
57
|
+
ls ~/.claude/agents/hydra-*.md 2>/dev/null | wc -l
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Format as a "System Info" section in the report.
|
|
61
|
+
|
|
62
|
+
## Step 4 — Submit via GitHub CLI or fallback
|
|
63
|
+
|
|
64
|
+
Check if `gh` CLI is available:
|
|
65
|
+
```bash
|
|
66
|
+
gh --version 2>/dev/null
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### If `gh` is installed, check auth:
|
|
70
|
+
```bash
|
|
71
|
+
gh auth status 2>/dev/null
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### If authenticated → create issue directly:
|
|
75
|
+
```bash
|
|
76
|
+
gh issue create \
|
|
77
|
+
--repo AR6420/Hail_Hydra \
|
|
78
|
+
--title "<concise title based on description>" \
|
|
79
|
+
--label "<bug|enhancement|feedback>" \
|
|
80
|
+
--body "<formatted report body>"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Show the resulting issue URL to the user.
|
|
84
|
+
|
|
85
|
+
### If `gh` is installed but NOT authenticated:
|
|
86
|
+
|
|
87
|
+
Tell the user:
|
|
88
|
+
```
|
|
89
|
+
GitHub CLI is installed but not authenticated.
|
|
90
|
+
Run this in your terminal to authenticate:
|
|
91
|
+
|
|
92
|
+
gh auth login
|
|
93
|
+
|
|
94
|
+
Then try /hydra:report again.
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### If `gh` is NOT installed → browser fallback:
|
|
98
|
+
|
|
99
|
+
Construct a pre-filled GitHub issue URL and show it to the user:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
GitHub CLI not found. You can submit your report via browser:
|
|
103
|
+
|
|
104
|
+
https://github.com/AR6420/Hail_Hydra/issues/new?template=<template>&title=<encoded-title>&labels=<label>&body=<encoded-body>
|
|
105
|
+
|
|
106
|
+
Or install GitHub CLI: https://cli.github.com
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Map template filenames:
|
|
110
|
+
- bug → `bug_report.md`
|
|
111
|
+
- enhancement → `feature_request.md`
|
|
112
|
+
- feedback → `feedback.md`
|
|
@@ -1,35 +1,78 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Update the Hydra framework to the latest version from npm
|
|
3
|
-
allowed-tools: Bash
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Hydra Update
|
|
7
|
-
|
|
8
|
-
Run the following steps to update Hydra to the latest version:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
---
|
|
2
|
+
description: Update the Hydra framework to the latest version from npm
|
|
3
|
+
allowed-tools: Bash, Read
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hydra Update
|
|
7
|
+
|
|
8
|
+
Run the following steps to update Hydra to the latest version:
|
|
9
|
+
|
|
10
|
+
## Step 1 — Check versions
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
cat ~/.claude/skills/hydra/VERSION 2>/dev/null || echo "VERSION file not found"
|
|
14
|
+
```
|
|
15
|
+
```bash
|
|
16
|
+
npm view hail-hydra-cc version 2>/dev/null || echo "Package not found on npm"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If the installed version matches the latest npm version, tell the user:
|
|
20
|
+
"🐉 Hydra is already at the latest version ([version])."
|
|
21
|
+
and stop here.
|
|
22
|
+
|
|
23
|
+
## Step 2 — Show changelog preview
|
|
24
|
+
|
|
25
|
+
Fetch the CHANGELOG from GitHub:
|
|
26
|
+
```bash
|
|
27
|
+
curl -sL "https://raw.githubusercontent.com/AR6420/Hail_Hydra/main/CHANGELOG.md"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Parse the changelog to extract entries between the installed version and the latest version. Display a formatted "What's New" section:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
🐉 Hydra Update Available: [installed] → [latest]
|
|
34
|
+
═══════════════════════════════════════════════════
|
|
35
|
+
|
|
36
|
+
📋 What's New:
|
|
37
|
+
[changelog entries for versions between installed and latest]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
If the changelog fetch fails, skip the preview and continue with the update.
|
|
41
|
+
|
|
42
|
+
## Step 3 — Show safety note
|
|
43
|
+
|
|
44
|
+
Display:
|
|
45
|
+
```
|
|
46
|
+
⚠️ What gets replaced:
|
|
47
|
+
• Agent definitions (agents/*.md)
|
|
48
|
+
• SKILL.md, references, commands, hooks
|
|
49
|
+
• VERSION file
|
|
50
|
+
|
|
51
|
+
✅ What's preserved:
|
|
52
|
+
• Your hydra.config.md settings
|
|
53
|
+
• Agent memory directories (memory/)
|
|
54
|
+
• CLAUDE.md orchestrator notes
|
|
55
|
+
• settings.json hook registrations (re-registered automatically)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Step 4 — Ask for confirmation
|
|
59
|
+
|
|
60
|
+
Ask the user: "Proceed with update? [Y/n]"
|
|
61
|
+
|
|
62
|
+
If they decline, respond: "🐉 Update cancelled." and stop.
|
|
63
|
+
|
|
64
|
+
## Step 5 — Run the update
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npx hail-hydra-cc@latest --global
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Step 6 — Verify
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cat ~/.claude/skills/hydra/VERSION
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Report to the user:
|
|
77
|
+
- If updated: "🐉 Hydra updated from [old] → [new]. All heads refreshed. Restart Claude Code to load the new files."
|
|
78
|
+
- If error: Show the error and suggest running `npx hail-hydra-cc@latest --global` manually in their terminal.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hydra Task Completion Notification
|
|
6
|
+
*
|
|
7
|
+
* Plays a short notification sound when Claude Code finishes a task.
|
|
8
|
+
* Cross-platform: macOS (afplay), Windows (PowerShell), Linux (paplay/aplay).
|
|
9
|
+
*
|
|
10
|
+
* Called by Claude Code's Notification hook — stdin receives JSON from
|
|
11
|
+
* the hook system, which we drain and discard to prevent EPIPE errors.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { spawn } = require('child_process');
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const os = require('os');
|
|
18
|
+
|
|
19
|
+
// Drain stdin to prevent EPIPE when Claude Code pipes hook data
|
|
20
|
+
process.stdin.resume();
|
|
21
|
+
process.stdin.on('data', () => {});
|
|
22
|
+
process.stdin.on('end', () => {});
|
|
23
|
+
|
|
24
|
+
const wavFile = path.join(os.homedir(), '.claude', 'hooks', 'hydra-task-complete.wav');
|
|
25
|
+
|
|
26
|
+
// Bail silently if the sound file is missing
|
|
27
|
+
if (!fs.existsSync(wavFile)) {
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const platform = process.platform;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
let child;
|
|
35
|
+
|
|
36
|
+
if (platform === 'darwin') {
|
|
37
|
+
// macOS
|
|
38
|
+
child = spawn('afplay', [wavFile], {
|
|
39
|
+
detached: true,
|
|
40
|
+
stdio: 'ignore',
|
|
41
|
+
});
|
|
42
|
+
} else if (platform === 'win32') {
|
|
43
|
+
// Windows — use PowerShell to play the .wav
|
|
44
|
+
child = spawn('powershell', [
|
|
45
|
+
'-NoProfile', '-NonInteractive', '-Command',
|
|
46
|
+
`(New-Object Media.SoundPlayer '${wavFile.replace(/'/g, "''")}').PlaySync()`,
|
|
47
|
+
], {
|
|
48
|
+
detached: true,
|
|
49
|
+
stdio: 'ignore',
|
|
50
|
+
windowsHide: true,
|
|
51
|
+
});
|
|
52
|
+
} else {
|
|
53
|
+
// Linux — try paplay (PulseAudio) first, fall back to aplay (ALSA)
|
|
54
|
+
const paplay = spawn('paplay', [wavFile], {
|
|
55
|
+
detached: true,
|
|
56
|
+
stdio: 'ignore',
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
paplay.on('error', () => {
|
|
60
|
+
// paplay not available, try aplay
|
|
61
|
+
const aplay = spawn('aplay', [wavFile], {
|
|
62
|
+
detached: true,
|
|
63
|
+
stdio: 'ignore',
|
|
64
|
+
});
|
|
65
|
+
aplay.unref();
|
|
66
|
+
aplay.on('error', () => {}); // silently ignore if neither works
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
paplay.unref();
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (child) {
|
|
74
|
+
child.unref();
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
// Silently ignore errors — notification sound is non-critical
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
process.exit(0);
|
|
Binary file
|
package/package.json
CHANGED
package/src/display.js
CHANGED
|
@@ -42,8 +42,8 @@ function showInstallComplete(statusLineConfigured = true) {
|
|
|
42
42
|
console.log(chalk.cyan.bold(' \uD83D\uDC09 Hail Hydra! Framework deployed and ready.'));
|
|
43
43
|
console.log(chalk.gray(' ' + '\u2500'.repeat(45)));
|
|
44
44
|
console.log(chalk.green(` \u2714 9 agents installed`));
|
|
45
|
-
console.log(chalk.green(` \u2714
|
|
46
|
-
console.log(chalk.green(` \u2714
|
|
45
|
+
console.log(chalk.green(` \u2714 8 slash commands installed`));
|
|
46
|
+
console.log(chalk.green(` \u2714 4 hooks registered`));
|
|
47
47
|
if (statusLineConfigured) {
|
|
48
48
|
console.log(chalk.green(` \u2714 StatusLine configured`));
|
|
49
49
|
} else {
|
|
@@ -141,7 +141,7 @@ function showStatusTable(globalStatus, localStatus) {
|
|
|
141
141
|
// Global hooks (always ~/.claude/hooks/)
|
|
142
142
|
console.log();
|
|
143
143
|
console.log(chalk.bold(' Global Hooks (~/.claude/hooks/)'));
|
|
144
|
-
const hookKeys = ['hydra-check-update', 'hydra-statusline', 'hydra-auto-guard'];
|
|
144
|
+
const hookKeys = ['hydra-check-update', 'hydra-statusline', 'hydra-auto-guard', 'hydra-notify'];
|
|
145
145
|
for (const key of hookKeys) {
|
|
146
146
|
const dest = path.join(os.homedir(), '.claude', 'hooks', `${key}.js`);
|
|
147
147
|
if (fileExists(dest)) {
|
package/src/files.js
CHANGED
|
@@ -80,12 +80,18 @@ const commands = {
|
|
|
80
80
|
'guard': readBundled('commands/hydra/guard.md'),
|
|
81
81
|
'quiet': readBundled('commands/hydra/quiet.md'),
|
|
82
82
|
'verbose': readBundled('commands/hydra/verbose.md'),
|
|
83
|
+
'report': readBundled('commands/hydra/report.md'),
|
|
83
84
|
};
|
|
84
85
|
|
|
85
86
|
const hooks = {
|
|
86
87
|
'hydra-check-update': readBundled('hooks/hydra-check-update.js'),
|
|
87
88
|
'hydra-statusline': readBundled('hooks/hydra-statusline.js'),
|
|
88
89
|
'hydra-auto-guard': readBundled('hooks/hydra-auto-guard.js'),
|
|
90
|
+
'hydra-notify': readBundled('hooks/hydra-notify.js'),
|
|
89
91
|
};
|
|
90
92
|
|
|
91
|
-
|
|
93
|
+
const binaryHooks = {
|
|
94
|
+
'hydra-task-complete.wav': path.join(FILES_DIR, 'hooks', 'hydra-task-complete.wav'),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
module.exports = { agents, skill, references, commands, hooks, binaryHooks };
|
package/src/installer.js
CHANGED
|
@@ -5,7 +5,7 @@ const path = require('path');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const chalk = require('chalk');
|
|
7
7
|
|
|
8
|
-
const { agents, skill, references, commands, hooks } = require('./files');
|
|
8
|
+
const { agents, skill, references, commands, hooks, binaryHooks } = require('./files');
|
|
9
9
|
const { showInstallHeader, showFileInstalled, showInstallComplete, showStatusTable, VERSION } = require('./display');
|
|
10
10
|
|
|
11
11
|
// ── Install locations ────────────────────────────────────────────────────────
|
|
@@ -100,6 +100,17 @@ function installHooks() {
|
|
|
100
100
|
showFileInstalled(`hooks/${key}.js`, false, err.message);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
+
|
|
104
|
+
// Copy binary hook files (e.g., .wav) that can't be read as UTF-8 text
|
|
105
|
+
for (const [filename, srcPath] of Object.entries(binaryHooks)) {
|
|
106
|
+
const dest = path.join(hooksDir, filename);
|
|
107
|
+
try {
|
|
108
|
+
fs.copyFileSync(srcPath, dest);
|
|
109
|
+
showFileInstalled(`hooks/${filename}`, true);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
showFileInstalled(`hooks/${filename}`, false, err.message);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
103
114
|
}
|
|
104
115
|
|
|
105
116
|
function registerHooksInSettings() {
|
|
@@ -130,6 +141,12 @@ function registerHooksInSettings() {
|
|
|
130
141
|
hooks: [{ type: 'command', command: 'node ~/.claude/hooks/hydra-auto-guard.js' }]
|
|
131
142
|
});
|
|
132
143
|
|
|
144
|
+
if (!settings.hooks.Notification) settings.hooks.Notification = [];
|
|
145
|
+
settings.hooks.Notification = settings.hooks.Notification.filter(x => !isHydraHook(x));
|
|
146
|
+
settings.hooks.Notification.push({
|
|
147
|
+
hooks: [{ type: 'command', command: 'node ~/.claude/hooks/hydra-notify.js' }]
|
|
148
|
+
});
|
|
149
|
+
|
|
133
150
|
let statusLineConfigured = false;
|
|
134
151
|
if (!settings.statusLine || (settings.statusLine.command && settings.statusLine.command.includes('hydra-'))) {
|
|
135
152
|
settings.statusLine = {
|
|
@@ -161,6 +178,10 @@ function deregisterHooks() {
|
|
|
161
178
|
settings.hooks.PostToolUse = settings.hooks.PostToolUse.filter(x => !isHydraHook(x));
|
|
162
179
|
if (!settings.hooks.PostToolUse.length) delete settings.hooks.PostToolUse;
|
|
163
180
|
}
|
|
181
|
+
if (settings.hooks?.Notification) {
|
|
182
|
+
settings.hooks.Notification = settings.hooks.Notification.filter(x => !isHydraHook(x));
|
|
183
|
+
if (!settings.hooks.Notification.length) delete settings.hooks.Notification;
|
|
184
|
+
}
|
|
164
185
|
if (settings.hooks && !Object.keys(settings.hooks).length) delete settings.hooks;
|
|
165
186
|
|
|
166
187
|
if (settings.statusLine?.command?.includes('hydra-')) delete settings.statusLine;
|
|
@@ -305,6 +326,15 @@ async function runUninstall({ interactive = true } = {}) {
|
|
|
305
326
|
}
|
|
306
327
|
}
|
|
307
328
|
|
|
329
|
+
// Remove binary hook files (e.g., .wav)
|
|
330
|
+
for (const filename of Object.keys(binaryHooks)) {
|
|
331
|
+
const dest = path.join(GLOBAL_BASE, 'hooks', filename);
|
|
332
|
+
if (fileExists(dest)) {
|
|
333
|
+
try { fs.unlinkSync(dest); console.log(chalk.green(` \u2714 Removed hooks/${filename}`)); }
|
|
334
|
+
catch (err) { console.log(chalk.red(` \u2716 Failed: hooks/${filename} \u2014 ${err.message}`)); }
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
308
338
|
// Remove cache file
|
|
309
339
|
const cacheFile = path.join(GLOBAL_BASE, 'cache', 'hydra-update-check.json');
|
|
310
340
|
if (fileExists(cacheFile)) {
|