hail-hydra-cc 2.2.0 → 2.3.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/files/SKILL.md +53 -0
- package/files/agents/hydra-analyst.md +48 -0
- package/files/agents/hydra-coder.md +44 -0
- package/files/agents/hydra-git.md +21 -0
- package/files/agents/hydra-guard.md +24 -0
- package/files/agents/hydra-preflight.md +13 -0
- package/files/agents/hydra-runner.md +21 -0
- package/files/agents/hydra-scout.md +30 -0
- package/files/agents/hydra-scribe.md +12 -0
- package/files/agents/hydra-sentinel-scan.md +13 -0
- package/files/agents/hydra-sentinel.md +27 -0
- package/files/commands/hydra/help.md +1 -0
- package/files/commands/hydra/stats.md +185 -0
- package/files/commands/hydra/status.md +2 -0
- package/package.json +58 -44
- package/src/files.js +1 -0
package/files/SKILL.md
CHANGED
|
@@ -57,6 +57,59 @@ When hydra-sentinel confirms real issues:
|
|
|
57
57
|
Architectural changes, migration needed, business logic decisions.
|
|
58
58
|
→ Show the report. Let user decide.
|
|
59
59
|
|
|
60
|
+
## Response Compression Protocol — Orchestrator
|
|
61
|
+
|
|
62
|
+
Apply light compression to your responses to the user. This is NOT
|
|
63
|
+
caveman-speak or fragmented language. Keep full grammar and natural prose.
|
|
64
|
+
Just remove waste.
|
|
65
|
+
|
|
66
|
+
### Drop These (Always)
|
|
67
|
+
|
|
68
|
+
- **Filler words**: just, really, basically, actually, simply, quite, very, totally
|
|
69
|
+
- **Pleasantries**: "Sure!", "Of course!", "Happy to help!", "Great question!"
|
|
70
|
+
- **Hedging**: "I think maybe", "It might be that", "Perhaps we could"
|
|
71
|
+
- **Throat-clearing**: "Let me explain...", "What I'll do is...", "Here's what I'll do..."
|
|
72
|
+
- **Signoffs**: "Let me know if you'd like me to adjust anything!", "Feel free to ask if...", "Hope this helps!"
|
|
73
|
+
- **Restating the question**: Don't repeat what the user asked back at them.
|
|
74
|
+
- **Apologetic preambles**: "Sorry for the confusion", "My apologies" (only apologize when you actually made an error, not as filler)
|
|
75
|
+
|
|
76
|
+
### Keep These (Always)
|
|
77
|
+
|
|
78
|
+
- Full grammar and articles (a, an, the)
|
|
79
|
+
- Natural sentence structure
|
|
80
|
+
- Code explanations when genuinely needed
|
|
81
|
+
- Reasoning when the user asks "why"
|
|
82
|
+
- Warnings about destructive operations
|
|
83
|
+
- Onboarding/learning explanations when the user is new to a concept
|
|
84
|
+
|
|
85
|
+
### Examples
|
|
86
|
+
|
|
87
|
+
**WRONG (verbose):**
|
|
88
|
+
> Sure! I'd be happy to help you fix that auth bug. Let me take a look at the
|
|
89
|
+
> code. Looking at this, I think the issue is that the token expiry check is
|
|
90
|
+
> using `<` instead of `<=`. I'll go ahead and fix that for you. Let me know
|
|
91
|
+
> if you'd like me to adjust anything!
|
|
92
|
+
|
|
93
|
+
**RIGHT (compressed):**
|
|
94
|
+
> The token expiry check uses `<` instead of `<=`. Fixing it now.
|
|
95
|
+
|
|
96
|
+
Same information. ~70% fewer tokens. User barely notices.
|
|
97
|
+
|
|
98
|
+
### Auto-Clarity — When to Drop Compression
|
|
99
|
+
|
|
100
|
+
Resume normal verbose prose for:
|
|
101
|
+
- **Security warnings** ("This will permanently delete...", "Cannot be undone")
|
|
102
|
+
- **Destructive operations** that need explicit user confirmation
|
|
103
|
+
- **Multi-step instructions** where compression risks misreading
|
|
104
|
+
- **User confused or asking follow-up clarification** — they need detail
|
|
105
|
+
- **Onboarding** — explaining new concepts the user is learning
|
|
106
|
+
|
|
107
|
+
Compression is for normal task completion. Anything safety-critical or educational gets full prose.
|
|
108
|
+
|
|
109
|
+
### What This Is NOT
|
|
110
|
+
|
|
111
|
+
This is not "caveman mode" or fragment-style. Don't drop articles. Don't write "Bug auth middleware. Token expiry use < not <=. Fix now." That's too aggressive — users WILL notice. Goal is invisible compression: a careful reader notices responses are tighter, but no average user complains it sounds robotic.
|
|
112
|
+
|
|
60
113
|
## Why Hydra Exists
|
|
61
114
|
|
|
62
115
|
Autoregressive LLM inference is memory-bandwidth bound — the time per token scales with model
|
|
@@ -95,3 +95,51 @@ You may be running in parallel with other Hydra agents. Your output must be:
|
|
|
95
95
|
even if you notice adjacent issues. Flag them for the orchestrator instead.
|
|
96
96
|
- **Actionable** — end with a clear summary of what you did or found, formatted so
|
|
97
97
|
the next wave's agents can use it directly as context.
|
|
98
|
+
|
|
99
|
+
## MANDATORY: Sentinel Trigger Footer
|
|
100
|
+
|
|
101
|
+
When your analysis results in code changes or code change recommendations,
|
|
102
|
+
you MUST end your response with this exact block:
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
⚠️ HYDRA_SENTINEL_REQUIRED
|
|
106
|
+
Files changed: [list every file modified]
|
|
107
|
+
Exports modified: [list any renamed/added/removed exports]
|
|
108
|
+
Signatures changed: [list any function signature changes]
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
If your task was analysis-only with no code changes, end with:
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
✅ HYDRA_NO_CODE_CHANGES
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Output Format — Compressed (MANDATORY)
|
|
118
|
+
|
|
119
|
+
You report findings to the orchestrator (Opus), NOT to the user. Opus reads your output and translates it for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
120
|
+
|
|
121
|
+
### Rules
|
|
122
|
+
|
|
123
|
+
1. NO prose preambles ("I have explored...", "After analyzing...", "Looking at...")
|
|
124
|
+
2. NO conversational closings ("Let me know if...", "Hope this helps!")
|
|
125
|
+
3. NO restating the task
|
|
126
|
+
4. Lead with findings. Format as tables, lists, or key:value pairs.
|
|
127
|
+
5. Use abbreviations: db, auth, fn, req/res, config, env, ctx, impl
|
|
128
|
+
6. Keep code symbols, function names, file paths, and error messages EXACT
|
|
129
|
+
7. Use arrows (→) for causality and relationships
|
|
130
|
+
8. One-line findings preferred. Multi-line only when structure requires it.
|
|
131
|
+
|
|
132
|
+
### Role-Specific Format
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
- severity: P0|P1|P2|P3
|
|
136
|
+
- file:line_range
|
|
137
|
+
- root_cause: technical_reason (max 15 words)
|
|
138
|
+
- fix: action (max 15 words)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
WRONG (verbose):
|
|
142
|
+
> After analyzing the codebase, I noticed the token check uses `<` which causes...
|
|
143
|
+
|
|
144
|
+
RIGHT (compressed):
|
|
145
|
+
> P1 src/services/auth.ts:12 — token expiry uses `<` not `<=`. fix: flip operator.
|
|
@@ -77,3 +77,47 @@ You may be running in parallel with other Hydra agents. Your output must be:
|
|
|
77
77
|
even if you notice adjacent issues. Flag them for the orchestrator instead.
|
|
78
78
|
- **Actionable** — end with a clear summary of what you did or found, formatted so
|
|
79
79
|
the next wave's agents can use it directly as context.
|
|
80
|
+
|
|
81
|
+
## MANDATORY: Sentinel Trigger Footer
|
|
82
|
+
|
|
83
|
+
You MUST end EVERY response that involves code changes with this exact block:
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
⚠️ HYDRA_SENTINEL_REQUIRED
|
|
87
|
+
Files changed: [list every file you modified, one per line]
|
|
88
|
+
Exports modified: [list any functions/classes/types you renamed, added, or removed]
|
|
89
|
+
Signatures changed: [list any function signature changes — parameter additions/removals/type changes]
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
This is NOT optional. The orchestrator uses this block to trigger the sentinel
|
|
93
|
+
integration scan. If you omit it, integration bugs will reach the user unchecked.
|
|
94
|
+
|
|
95
|
+
If your task did NOT involve any code changes (e.g., you only read files or
|
|
96
|
+
analyzed code), end with:
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
✅ HYDRA_NO_CODE_CHANGES
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Output Format — Compressed (MANDATORY)
|
|
103
|
+
|
|
104
|
+
You report findings to the orchestrator (Opus), NOT to the user. Opus reads your output and translates it for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
105
|
+
|
|
106
|
+
### Rules
|
|
107
|
+
|
|
108
|
+
1. NO prose preambles ("I have completed...", "After implementing...")
|
|
109
|
+
2. NO conversational closings
|
|
110
|
+
3. NO restating the task
|
|
111
|
+
4. Lead with findings. Format as tables, lists, or key:value pairs.
|
|
112
|
+
5. Use abbreviations: db, auth, fn, req/res, config, env, ctx, impl
|
|
113
|
+
6. Keep code symbols, function names, file paths, and error messages EXACT
|
|
114
|
+
7. One-line findings preferred. Multi-line only when structure requires it.
|
|
115
|
+
|
|
116
|
+
### Role-Specific Format
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
- changed: file:line_range (one per line)
|
|
120
|
+
- summary: what_changed (1 line per file, max 10 words)
|
|
121
|
+
- new_files: path (if any)
|
|
122
|
+
- removed: file:reason (if any)
|
|
123
|
+
```
|
|
@@ -107,3 +107,24 @@ You may be running in parallel with other Hydra agents. Your output must be:
|
|
|
107
107
|
- **Clearly structured** — use headers so the orchestrator can extract relevant parts
|
|
108
108
|
- **Focused on YOUR task only** — git operations only
|
|
109
109
|
- **Actionable** — end with clear next steps or confirmation of what was done
|
|
110
|
+
|
|
111
|
+
## Output Format — Compressed (MANDATORY)
|
|
112
|
+
|
|
113
|
+
You report to the orchestrator (Opus), NOT to the user. Opus translates for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
114
|
+
|
|
115
|
+
### Rules
|
|
116
|
+
|
|
117
|
+
1. NO prose preambles or conversational closings
|
|
118
|
+
2. NO restating the task
|
|
119
|
+
3. Lead with findings. Format as key:value pairs.
|
|
120
|
+
4. Keep hashes, branch names, file paths EXACT — never abbreviate
|
|
121
|
+
5. One-line findings preferred
|
|
122
|
+
|
|
123
|
+
### Role-Specific Format
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
- action: commit|branch|diff|push|merge|rebase|...
|
|
127
|
+
- result: success|failure
|
|
128
|
+
- detail: short_summary
|
|
129
|
+
- hash/branch_name (if relevant)
|
|
130
|
+
```
|
|
@@ -109,3 +109,27 @@ You may be running in parallel with other Hydra agents. Your output must be:
|
|
|
109
109
|
- **Clearly structured** — use headers so the orchestrator can extract and append findings
|
|
110
110
|
- **Focused on YOUR task only** — security scan of the specified changed files
|
|
111
111
|
- **Actionable** — every finding includes file:line and a brief fix direction
|
|
112
|
+
|
|
113
|
+
## Output Format — Compressed (MANDATORY)
|
|
114
|
+
|
|
115
|
+
You report to the orchestrator (Opus), NOT to the user. Opus translates for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
116
|
+
|
|
117
|
+
### Rules
|
|
118
|
+
|
|
119
|
+
1. NO prose preambles or conversational closings
|
|
120
|
+
2. Lead with result. One line per finding.
|
|
121
|
+
3. Keep code symbols, file paths, and error strings EXACT
|
|
122
|
+
|
|
123
|
+
### Role-Specific Format
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
- result: clean|issues_found
|
|
127
|
+
- findings: severity:file:line:short_description (one per line)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
```
|
|
132
|
+
result: issues_found
|
|
133
|
+
CRITICAL src/api/login.ts:34 hardcoded API key — move to env
|
|
134
|
+
WARNING src/utils/sql.ts:12 string concat in query — parameterize
|
|
135
|
+
```
|
|
@@ -173,3 +173,16 @@ PREFLIGHT_INVENTORY_COMPLETE
|
|
|
173
173
|
```
|
|
174
174
|
|
|
175
175
|
Do not add recommendations, compatibility judgments, or fixes. That is the analyst's job.
|
|
176
|
+
|
|
177
|
+
## Output Format — Compressed (MANDATORY)
|
|
178
|
+
|
|
179
|
+
You report to the orchestrator (Opus), NOT to the user. Opus translates for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
180
|
+
|
|
181
|
+
### Rules
|
|
182
|
+
|
|
183
|
+
1. NO prose preambles or conversational closings around the JSON
|
|
184
|
+
2. NO restating the task
|
|
185
|
+
3. The PREFLIGHT_INVENTORY JSON is already compressed — emit it directly
|
|
186
|
+
4. Keep version strings, runtime IDs, env var names EXACT
|
|
187
|
+
|
|
188
|
+
The structured `PREFLIGHT_INVENTORY` JSON above is the deliverable. Skip natural-language wrapping around it.
|
|
@@ -70,3 +70,24 @@ You may be running in parallel with other Hydra agents. Your output must be:
|
|
|
70
70
|
even if you notice adjacent issues. Flag them for the orchestrator instead.
|
|
71
71
|
- **Actionable** — end with a clear summary of what you did or found, formatted so
|
|
72
72
|
the next wave's agents can use it directly as context.
|
|
73
|
+
|
|
74
|
+
## Output Format — Compressed (MANDATORY)
|
|
75
|
+
|
|
76
|
+
You report to the orchestrator (Opus), NOT to the user. Opus translates for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
77
|
+
|
|
78
|
+
### Rules
|
|
79
|
+
|
|
80
|
+
1. NO prose preambles or conversational closings
|
|
81
|
+
2. Lead with results. Format as key:value pairs.
|
|
82
|
+
3. Keep test names, file paths, error strings EXACT
|
|
83
|
+
4. One line per failure
|
|
84
|
+
|
|
85
|
+
### Role-Specific Format
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
- result: PASS|FAIL|SKIP
|
|
89
|
+
- failures: count
|
|
90
|
+
- failed_tests: file:test_name (one per line)
|
|
91
|
+
- duration: Ns
|
|
92
|
+
- next: suggestion (1 line if relevant)
|
|
93
|
+
```
|
|
@@ -195,3 +195,33 @@ You may be running in parallel with other Hydra agents. Your output must be:
|
|
|
195
195
|
even if you notice adjacent issues. Flag them for the orchestrator instead.
|
|
196
196
|
- **Actionable** — end with a clear summary of what you did or found, formatted so
|
|
197
197
|
the next wave's agents can use it directly as context.
|
|
198
|
+
|
|
199
|
+
## Output Format — Compressed (MANDATORY)
|
|
200
|
+
|
|
201
|
+
You report to the orchestrator (Opus), NOT to the user. Opus translates for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
202
|
+
|
|
203
|
+
### Rules
|
|
204
|
+
|
|
205
|
+
1. NO prose preambles ("I explored...", "After scanning...")
|
|
206
|
+
2. NO conversational closings
|
|
207
|
+
3. Lead with findings. Format as tables, lists, or key:value pairs.
|
|
208
|
+
4. Keep file paths, function names EXACT
|
|
209
|
+
5. Use arrows (→) for relationships
|
|
210
|
+
6. One-line findings preferred
|
|
211
|
+
|
|
212
|
+
### Role-Specific Format
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
- File map: path:purpose (one per line)
|
|
216
|
+
- Relationships: file → file
|
|
217
|
+
- Risk: file (1-line reason)
|
|
218
|
+
- Conventions: pattern_name: short_description
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Example:
|
|
222
|
+
```
|
|
223
|
+
auth.ts: src/services
|
|
224
|
+
middleware.ts: src/middleware
|
|
225
|
+
auth.ts → middleware.ts → users.ts
|
|
226
|
+
auth.ts: risk=critical (12 deps)
|
|
227
|
+
```
|
|
@@ -70,3 +70,15 @@ You may be running in parallel with other Hydra agents. Your output must be:
|
|
|
70
70
|
even if you notice adjacent issues. Flag them for the orchestrator instead.
|
|
71
71
|
- **Actionable** — end with a clear summary of what you did or found, formatted so
|
|
72
72
|
the next wave's agents can use it directly as context.
|
|
73
|
+
|
|
74
|
+
## Output Format — Compressed (MANDATORY)
|
|
75
|
+
|
|
76
|
+
You report to the orchestrator (Opus), NOT to the user. The output IS the document — deliver it directly.
|
|
77
|
+
|
|
78
|
+
### Rules
|
|
79
|
+
|
|
80
|
+
1. NO prose preambles ("I have written...", "Here is the documentation...")
|
|
81
|
+
2. NO conversational closings ("Let me know if...", "Hope this helps!")
|
|
82
|
+
3. NO restating the task
|
|
83
|
+
4. The doc itself stays in normal prose — readers are humans
|
|
84
|
+
5. Skip everything around the doc
|
|
@@ -221,3 +221,16 @@ If you can't determine the session_id, run:
|
|
|
221
221
|
```bash
|
|
222
222
|
rm -f /tmp/hydra-sentinel/*-pending.json
|
|
223
223
|
```
|
|
224
|
+
|
|
225
|
+
## Output Format — Compressed (MANDATORY)
|
|
226
|
+
|
|
227
|
+
You report to the orchestrator (Opus), NOT to the user. Opus translates for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
228
|
+
|
|
229
|
+
### Rules
|
|
230
|
+
|
|
231
|
+
1. NO prose preambles or conversational closings around the JSON
|
|
232
|
+
2. NO restating the task
|
|
233
|
+
3. The structured JSON is already compressed — emit it directly
|
|
234
|
+
4. Keep file paths, import strings, function signatures EXACT
|
|
235
|
+
|
|
236
|
+
The structured JSON deliverable above is the report. Skip natural-language wrapping around it.
|
|
@@ -163,3 +163,30 @@ You may be running in parallel with other Hydra agents. Your output must be:
|
|
|
163
163
|
- **Clearly structured** — use the report format above so the orchestrator can parse it
|
|
164
164
|
- **Focused on YOUR task only** — deep integration analysis, nothing else
|
|
165
165
|
- **Actionable** — every confirmed issue includes impact scope and specific fix
|
|
166
|
+
|
|
167
|
+
## Output Format — Compressed (MANDATORY)
|
|
168
|
+
|
|
169
|
+
You report to the orchestrator (Opus), NOT to the user. Opus translates for the user. Output must be DENSE and STRUCTURED, not prose.
|
|
170
|
+
|
|
171
|
+
### Rules
|
|
172
|
+
|
|
173
|
+
1. NO prose preambles or conversational closings
|
|
174
|
+
2. Lead with counts. One line per confirmation/dismissal.
|
|
175
|
+
3. Keep code symbols, file paths, error strings EXACT
|
|
176
|
+
4. Use arrows (→) for causality
|
|
177
|
+
|
|
178
|
+
### Role-Specific Format
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
- confirmed: count, dismissed: count
|
|
182
|
+
- For each confirmed: P{level}:file:line:detail:fix
|
|
183
|
+
- For each dismissed: file:line:reason
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
```
|
|
188
|
+
confirmed: 2, dismissed: 1
|
|
189
|
+
P0 src/api/users.ts:47 null deref on req.user → add guard
|
|
190
|
+
P1 src/services/auth.ts:12 token expiry < not <= → flip operator
|
|
191
|
+
DISMISSED src/utils/x.ts:3 import unused → false positive (re-export)
|
|
192
|
+
```
|
|
@@ -20,6 +20,7 @@ COMMANDS
|
|
|
20
20
|
/hydra:verbose Enable verbose dispatch logs with timing
|
|
21
21
|
/hydra:report Report a bug, request a feature, or share feedback
|
|
22
22
|
/hydra:preflight Two-phase environment & compatibility check before new projects
|
|
23
|
+
/hydra:stats Show real token usage and estimated savings (no AI estimation)
|
|
23
24
|
|
|
24
25
|
AGENTS
|
|
25
26
|
🟢 hydra-scout (Haiku 4.5) — Explore codebase, find files, map structure
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show real token usage, delegation rate, and actual savings for the current Hydra session (parses Claude Code session JSONL — no AI estimation)
|
|
3
|
+
allowed-tools: Bash, Read
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Hydra Stats — Real Token Tracking
|
|
7
|
+
|
|
8
|
+
Read the active Claude Code session log and compute actual token usage and
|
|
9
|
+
savings. NO AI estimation — pure JSONL parsing.
|
|
10
|
+
|
|
11
|
+
## How It Works
|
|
12
|
+
|
|
13
|
+
Claude Code writes every conversation turn to a JSONL file at
|
|
14
|
+
`~/.claude/projects/{project-slug}/{session-id}.jsonl` (or
|
|
15
|
+
`$CLAUDE_CONFIG_DIR/projects/...` if overridden). The slug is the absolute
|
|
16
|
+
project path with path separators (`/`, `\`, `:`) replaced by `-` and any
|
|
17
|
+
leading `-` stripped.
|
|
18
|
+
|
|
19
|
+
Each assistant turn line includes a `message.usage` object with
|
|
20
|
+
`input_tokens`, `output_tokens`, `cache_read_input_tokens`,
|
|
21
|
+
`cache_creation_input_tokens`, and the `model` ID. We aggregate by model
|
|
22
|
+
tier and price it.
|
|
23
|
+
|
|
24
|
+
## Pricing (per 1M tokens, verified 2026-05 for Claude 4.x)
|
|
25
|
+
|
|
26
|
+
| Tier | Input | Output | Cache read |
|
|
27
|
+
|--------|-------|--------|------------|
|
|
28
|
+
| Haiku | $1 | $5 | 10% of input |
|
|
29
|
+
| Sonnet | $3 | $15 | 10% of input |
|
|
30
|
+
| Opus | $5 | $25 | 10% of input |
|
|
31
|
+
|
|
32
|
+
Edit the `pricing` map below if Anthropic publishes new prices.
|
|
33
|
+
|
|
34
|
+
## Run
|
|
35
|
+
|
|
36
|
+
Execute this single Node command (works on Windows, macOS, Linux):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
node -e "
|
|
40
|
+
const fs = require('fs');
|
|
41
|
+
const path = require('path');
|
|
42
|
+
const os = require('os');
|
|
43
|
+
|
|
44
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
|
|
45
|
+
const projectsDir = path.join(configDir, 'projects');
|
|
46
|
+
|
|
47
|
+
if (!fs.existsSync(projectsDir)) {
|
|
48
|
+
console.log('No Claude Code projects directory found at ' + projectsDir);
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Slug = absolute cwd with /, \\, : replaced by -, leading - stripped
|
|
53
|
+
const cwd = process.cwd();
|
|
54
|
+
const slug = cwd.replace(/[\\\\/:]/g, '-').replace(/^-+/, '');
|
|
55
|
+
|
|
56
|
+
// Try exact match first, then case-insensitive substring fallback
|
|
57
|
+
let sessionDir = path.join(projectsDir, slug);
|
|
58
|
+
if (!fs.existsSync(sessionDir)) {
|
|
59
|
+
const all = fs.readdirSync(projectsDir);
|
|
60
|
+
const match = all.find(d => d.toLowerCase() === slug.toLowerCase())
|
|
61
|
+
|| all.find(d => d.toLowerCase().endsWith(path.basename(cwd).toLowerCase()));
|
|
62
|
+
if (match) sessionDir = path.join(projectsDir, match);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!fs.existsSync(sessionDir)) {
|
|
66
|
+
console.log('No session data for this project yet.');
|
|
67
|
+
console.log('Looked in: ' + sessionDir);
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const files = fs.readdirSync(sessionDir)
|
|
72
|
+
.filter(f => f.endsWith('.jsonl'))
|
|
73
|
+
.map(f => ({ f, mtime: fs.statSync(path.join(sessionDir, f)).mtimeMs }))
|
|
74
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
75
|
+
|
|
76
|
+
if (files.length === 0) {
|
|
77
|
+
console.log('No session JSONL files found in ' + sessionDir);
|
|
78
|
+
process.exit(0);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const sessionFile = path.join(sessionDir, files[0].f);
|
|
82
|
+
const lines = fs.readFileSync(sessionFile, 'utf8').split('\n').filter(Boolean);
|
|
83
|
+
|
|
84
|
+
const pricing = {
|
|
85
|
+
'claude-haiku-4': { input: 1, output: 5 },
|
|
86
|
+
'claude-sonnet-4': { input: 3, output: 15 },
|
|
87
|
+
'claude-opus-4': { input: 5, output: 25 }
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const stats = {
|
|
91
|
+
haiku: { input: 0, output: 0, cache_read: 0, cache_create: 0, turns: 0 },
|
|
92
|
+
sonnet: { input: 0, output: 0, cache_read: 0, cache_create: 0, turns: 0 },
|
|
93
|
+
opus: { input: 0, output: 0, cache_read: 0, cache_create: 0, turns: 0 }
|
|
94
|
+
};
|
|
95
|
+
const unknownModels = new Set();
|
|
96
|
+
let totalAssistantTurns = 0;
|
|
97
|
+
|
|
98
|
+
for (const line of lines) {
|
|
99
|
+
try {
|
|
100
|
+
const obj = JSON.parse(line);
|
|
101
|
+
if (obj.type !== 'assistant' || !obj.message || !obj.message.usage) continue;
|
|
102
|
+
const model = obj.message.model || '';
|
|
103
|
+
const usage = obj.message.usage;
|
|
104
|
+
let tier = null;
|
|
105
|
+
if (model.startsWith('claude-haiku')) tier = 'haiku';
|
|
106
|
+
else if (model.startsWith('claude-sonnet')) tier = 'sonnet';
|
|
107
|
+
else if (model.startsWith('claude-opus')) tier = 'opus';
|
|
108
|
+
if (!tier) { if (model) unknownModels.add(model); continue; }
|
|
109
|
+
stats[tier].input += usage.input_tokens || 0;
|
|
110
|
+
stats[tier].output += usage.output_tokens || 0;
|
|
111
|
+
stats[tier].cache_read += usage.cache_read_input_tokens || 0;
|
|
112
|
+
stats[tier].cache_create += usage.cache_creation_input_tokens || 0;
|
|
113
|
+
stats[tier].turns += 1;
|
|
114
|
+
totalAssistantTurns += 1;
|
|
115
|
+
} catch (e) { /* skip malformed */ }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function cost(s, p) {
|
|
119
|
+
const inputCost = ((s.input + s.cache_create) * p.input + s.cache_read * p.input * 0.1) / 1_000_000;
|
|
120
|
+
const outputCost = (s.output * p.output) / 1_000_000;
|
|
121
|
+
return inputCost + outputCost;
|
|
122
|
+
}
|
|
123
|
+
const haikuCost = cost(stats.haiku, pricing['claude-haiku-4']);
|
|
124
|
+
const sonnetCost = cost(stats.sonnet, pricing['claude-sonnet-4']);
|
|
125
|
+
const opusCost = cost(stats.opus, pricing['claude-opus-4']);
|
|
126
|
+
const actualCost = haikuCost + sonnetCost + opusCost;
|
|
127
|
+
|
|
128
|
+
function asOpus(s) {
|
|
129
|
+
const p = pricing['claude-opus-4'];
|
|
130
|
+
return ((s.input + s.cache_create) * p.input + s.cache_read * p.input * 0.1 + s.output * p.output) / 1_000_000;
|
|
131
|
+
}
|
|
132
|
+
const hypotheticalCost = asOpus(stats.haiku) + asOpus(stats.sonnet) + asOpus(stats.opus);
|
|
133
|
+
const savedUSD = hypotheticalCost - actualCost;
|
|
134
|
+
const savedPct = hypotheticalCost > 0 ? (savedUSD / hypotheticalCost * 100) : 0;
|
|
135
|
+
|
|
136
|
+
const totalDelegations = stats.haiku.turns + stats.sonnet.turns;
|
|
137
|
+
const delegationRate = totalAssistantTurns > 0 ? (totalDelegations / totalAssistantTurns * 100) : 0;
|
|
138
|
+
|
|
139
|
+
function fmt(n) {
|
|
140
|
+
if (n >= 1_000_000) return (n / 1_000_000).toFixed(2) + 'M';
|
|
141
|
+
if (n >= 1_000) return (n / 1_000).toFixed(1) + 'k';
|
|
142
|
+
return n.toString();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const bar = '━'.repeat(40);
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log('🐉 Hydra Stats');
|
|
148
|
+
console.log(bar);
|
|
149
|
+
console.log('Session: ' + path.basename(sessionFile));
|
|
150
|
+
console.log('Turns: ' + totalAssistantTurns);
|
|
151
|
+
console.log(bar);
|
|
152
|
+
console.log('');
|
|
153
|
+
console.log('🟢 Haiku (' + stats.haiku.turns + ' turns): ' + fmt(stats.haiku.input + stats.haiku.cache_create) + ' in / ' + fmt(stats.haiku.output) + ' out → $' + haikuCost.toFixed(3));
|
|
154
|
+
console.log('🔵 Sonnet (' + stats.sonnet.turns + ' turns): ' + fmt(stats.sonnet.input + stats.sonnet.cache_create) + ' in / ' + fmt(stats.sonnet.output) + ' out → $' + sonnetCost.toFixed(3));
|
|
155
|
+
console.log('🟣 Opus (' + stats.opus.turns + ' turns): ' + fmt(stats.opus.input + stats.opus.cache_create) + ' in / ' + fmt(stats.opus.output) + ' out → $' + opusCost.toFixed(3));
|
|
156
|
+
console.log(bar);
|
|
157
|
+
console.log('');
|
|
158
|
+
console.log('Delegation rate: ' + delegationRate.toFixed(1) + '% (' + totalDelegations + '/' + totalAssistantTurns + ' turns)');
|
|
159
|
+
console.log('Actual cost: $' + actualCost.toFixed(3));
|
|
160
|
+
console.log('All-Opus baseline: $' + hypotheticalCost.toFixed(3));
|
|
161
|
+
console.log(bar);
|
|
162
|
+
console.log('💰 Saved: $' + savedUSD.toFixed(3) + ' (' + savedPct.toFixed(1) + '%)');
|
|
163
|
+
console.log(bar);
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log('Reads Claude Code session JSONL directly. No AI estimation.');
|
|
166
|
+
if (unknownModels.size > 0) {
|
|
167
|
+
console.log('');
|
|
168
|
+
console.log('⚠️ Unknown models (not counted): ' + Array.from(unknownModels).join(', '));
|
|
169
|
+
console.log(' Update pricing map in ~/.claude/commands/hydra/stats.md');
|
|
170
|
+
}
|
|
171
|
+
"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Display
|
|
175
|
+
|
|
176
|
+
Print the output exactly as the script emits. Do not summarize or reformat.
|
|
177
|
+
|
|
178
|
+
## Notes
|
|
179
|
+
|
|
180
|
+
- `All-Opus baseline` is the hypothetical cost if every turn (including
|
|
181
|
+
Haiku and Sonnet ones) had been Opus. The savings show what Hydra's model
|
|
182
|
+
routing actually saved this session.
|
|
183
|
+
- Stats are session-scoped. Future versions may add `--all` and `--since`.
|
|
184
|
+
- Cache-read pricing is 10% of input price (Anthropic prompt-caching rate
|
|
185
|
+
for Claude 4.x as of 2026-05).
|
package/package.json
CHANGED
|
@@ -1,44 +1,58 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "hail-hydra-cc",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Multi-
|
|
5
|
-
"bin": {
|
|
6
|
-
"hail-hydra-cc": "bin/cli.js"
|
|
7
|
-
},
|
|
8
|
-
"main": "./src/installer.js",
|
|
9
|
-
"engines": {
|
|
10
|
-
"node": ">=16.0.0"
|
|
11
|
-
},
|
|
12
|
-
"dependencies": {
|
|
13
|
-
"chalk": "^4.1.2",
|
|
14
|
-
"commander": "^11.1.0",
|
|
15
|
-
"inquirer": "^8.2.6"
|
|
16
|
-
},
|
|
17
|
-
"keywords": [
|
|
18
|
-
"claude-code",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
],
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "hail-hydra-cc",
|
|
3
|
+
"version": "2.3.0",
|
|
4
|
+
"description": "Multi-agent orchestration framework for Claude Code. Routes tasks to specialized Haiku/Sonnet subagents while Opus orchestrates — inspired by speculative decoding. ~50% API cost reduction.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"hail-hydra-cc": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "./src/installer.js",
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=16.0.0"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"chalk": "^4.1.2",
|
|
14
|
+
"commander": "^11.1.0",
|
|
15
|
+
"inquirer": "^8.2.6"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"claude-code",
|
|
19
|
+
"ai-agents",
|
|
20
|
+
"multi-agent",
|
|
21
|
+
"orchestration",
|
|
22
|
+
"speculative-decoding",
|
|
23
|
+
"subagents",
|
|
24
|
+
"claude",
|
|
25
|
+
"anthropic",
|
|
26
|
+
"ai-coding",
|
|
27
|
+
"developer-tools",
|
|
28
|
+
"code-review",
|
|
29
|
+
"haiku",
|
|
30
|
+
"sonnet",
|
|
31
|
+
"opus",
|
|
32
|
+
"cost-optimization",
|
|
33
|
+
"token-savings",
|
|
34
|
+
"ai-framework",
|
|
35
|
+
"claude-subagents",
|
|
36
|
+
"coding-agent",
|
|
37
|
+
"agent-orchestration",
|
|
38
|
+
"hydra"
|
|
39
|
+
],
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/AR6420/Hail_Hydra.git"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/AR6420/Hail_Hydra#readme",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/AR6420/Hail_Hydra/issues"
|
|
48
|
+
},
|
|
49
|
+
"files": [
|
|
50
|
+
"bin/",
|
|
51
|
+
"src/",
|
|
52
|
+
"files/"
|
|
53
|
+
],
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"registry": "https://registry.npmjs.org/",
|
|
56
|
+
"access": "public"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/files.js
CHANGED