axel-setup 0.2.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.
Files changed (117) hide show
  1. package/CHANGELOG.md +218 -0
  2. package/CONTRIBUTING.md +58 -0
  3. package/LICENSE +21 -0
  4. package/README.md +518 -0
  5. package/agents/api-design.md +51 -0
  6. package/agents/bughunter.md +136 -0
  7. package/agents/changelog.md +89 -0
  8. package/agents/cleanup.md +126 -0
  9. package/agents/compare-branch.md +35 -0
  10. package/agents/cross-repo.md +97 -0
  11. package/agents/db-check.md +14 -0
  12. package/agents/debug.md +47 -0
  13. package/agents/deploy-check.md +100 -0
  14. package/agents/draft-message.md +19 -0
  15. package/agents/excelsior-coordinator.md +75 -0
  16. package/agents/excelsior-verifier.md +94 -0
  17. package/agents/feature.md +48 -0
  18. package/agents/harness-optimizer.md +40 -0
  19. package/agents/incident.md +48 -0
  20. package/agents/linear-task.md +18 -0
  21. package/agents/onboard.md +24 -0
  22. package/agents/perf.md +44 -0
  23. package/agents/production-validator.md +96 -0
  24. package/agents/review.md +113 -0
  25. package/agents/security-check.md +29 -0
  26. package/agents/sprint-summary.md +15 -0
  27. package/agents/tdd-mainder.md +178 -0
  28. package/agents/test-gen.md +39 -0
  29. package/axel-manifest.json +129 -0
  30. package/bin/axel-setup.js +597 -0
  31. package/bootstrap.sh +1087 -0
  32. package/commands/create-pr.md +13 -0
  33. package/commands/daily.md +182 -0
  34. package/commands/deslop.md +13 -0
  35. package/commands/draft-message.md +23 -0
  36. package/commands/eod-review.md +154 -0
  37. package/commands/execute-prp.md +37 -0
  38. package/commands/generate-prp.md +75 -0
  39. package/commands/multi-repo-feature.md +60 -0
  40. package/commands/roadmap.md +31 -0
  41. package/commands/sprint-status.md +486 -0
  42. package/commands/style.md +68 -0
  43. package/commands/visualize.md +17 -0
  44. package/docs/roadmap/multi-runtime.md +73 -0
  45. package/docs/superpowers/plans/2026-06-12-setup-hardening-roadmap.md +61 -0
  46. package/hooks/desktop-notify.sh +26 -0
  47. package/hooks/enforce-agent-model.jq +14 -0
  48. package/hooks/gsd-context-monitor.js +156 -0
  49. package/hooks/linear-lifecycle-sync.sh +112 -0
  50. package/hooks/memory-dedup.sh +122 -0
  51. package/hooks/memory-extractor.sh +218 -0
  52. package/hooks/post-commit-memory-trigger.sh +16 -0
  53. package/hooks/post-commit-verify.sh +41 -0
  54. package/hooks/post-edit-lint.sh +43 -0
  55. package/hooks/precompact-save-context.sh +124 -0
  56. package/hooks/priority-map-staleness.sh +29 -0
  57. package/hooks/proactive-resolver.sh +104 -0
  58. package/hooks/session-auto-title.sh +165 -0
  59. package/hooks/session-checkpoint.sh +97 -0
  60. package/hooks/session-cost-log.sh +77 -0
  61. package/hooks/session-log-action.sh +36 -0
  62. package/hooks/session-log-prompt.sh +25 -0
  63. package/hooks/session-restore.sh +45 -0
  64. package/hooks/session-save.sh +81 -0
  65. package/hooks/session-summarize.sh +154 -0
  66. package/hooks/validate-commit-format.sh +38 -0
  67. package/hooks/weekly-priority-map-review.sh +143 -0
  68. package/install.sh +46 -0
  69. package/package.json +67 -0
  70. package/scripts/ci/bootstrap-dry-run.sh +40 -0
  71. package/scripts/ci/check.sh +65 -0
  72. package/scripts/posthog-snapshot-loader.sh +112 -0
  73. package/skills/context-budget/SKILL.md +86 -0
  74. package/skills/memory-review/SKILL.md +100 -0
  75. package/skills/model-routing/SKILL.md +70 -0
  76. package/skills/posthog-weekly/SKILL.md +271 -0
  77. package/skills/ui-ux-pro-max/SKILL.md +377 -0
  78. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  79. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  80. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  81. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  82. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  83. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  84. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  85. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  86. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  87. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  88. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  89. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  90. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  91. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  92. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  93. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  94. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  95. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  96. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  97. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  98. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  99. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  100. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  101. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  102. package/skills/ui-ux-pro-max/scripts/core.py +253 -0
  103. package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  104. package/skills/ui-ux-pro-max/scripts/search.py +114 -0
  105. package/templates/AGENTS.runtime.md +17 -0
  106. package/templates/CLAUDE.md +252 -0
  107. package/templates/claude-monitor.plist +35 -0
  108. package/templates/keybindings.json +13 -0
  109. package/templates/merge-settings.jq +53 -0
  110. package/templates/review-upgrades.md +44 -0
  111. package/templates/settings.json +255 -0
  112. package/templates/statusline-command.sh +182 -0
  113. package/tests/fixtures/hooks/events.json +32 -0
  114. package/tools/session-costs-view.sh +128 -0
  115. package/tools/session-dashboard-gen.sh +369 -0
  116. package/tools/session-live.sh +173 -0
  117. package/tools/session-server.js +441 -0
@@ -0,0 +1,255 @@
1
+ {
2
+ "env": {
3
+ "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
4
+ "CLAUDE_AUTO_BACKGROUND_TASKS": "1",
5
+ "CLAUDE_CODE_IDLE_THRESHOLD_MINUTES": "30",
6
+ "CLAUDE_CODE_IDLE_TOKEN_THRESHOLD": "50000"
7
+ },
8
+ "permissions": {
9
+ "allow": [
10
+ "Bash(*)",
11
+ "Read(*)",
12
+ "Edit(*)",
13
+ "Write(*)",
14
+ "Glob(*)",
15
+ "Grep(*)",
16
+ "Agent(*)",
17
+ "mcp__*"
18
+ ],
19
+ "deny": [
20
+ "Bash(rm -rf *)",
21
+ "Bash(dd *)"
22
+ ],
23
+ "defaultMode": "bypassPermissions"
24
+ },
25
+ "hooks": {
26
+ "PreToolUse": [
27
+ {
28
+ "matcher": "Bash",
29
+ "hooks": [
30
+ {
31
+ "type": "command",
32
+ "command": "echo \"$TOOL_INPUT\" | grep -qE '\\-\\-no-verify' && echo 'BLOCKED: --no-verify is prohibited' >&2 && exit 2 || exit 0"
33
+ }
34
+ ]
35
+ },
36
+ {
37
+ "matcher": "Bash",
38
+ "hooks": [
39
+ {
40
+ "type": "command",
41
+ "command": "bash $HOME/.claude/hooks/validate-commit-format.sh"
42
+ }
43
+ ]
44
+ },
45
+ {
46
+ "matcher": "Bash",
47
+ "hooks": [
48
+ {
49
+ "type": "command",
50
+ "command": "echo \"$TOOL_INPUT\" | grep -qE 'RAILS_ENV=staging' && echo 'WARNING: staging = PRODUCTION. Confirm with the user.' >&2 && exit 1 || exit 0"
51
+ }
52
+ ]
53
+ },
54
+ {
55
+ "matcher": "Agent",
56
+ "hooks": [
57
+ {
58
+ "type": "command",
59
+ "command": "jq -c -f $HOME/.claude/hooks/enforce-agent-model.jq",
60
+ "timeout": 5,
61
+ "statusMessage": "Checking Agent model routing..."
62
+ }
63
+ ]
64
+ }
65
+ ],
66
+ "PostToolUse": [
67
+ {
68
+ "matcher": "Bash",
69
+ "hooks": [
70
+ {
71
+ "type": "command",
72
+ "command": "bash $HOME/.claude/hooks/proactive-resolver.sh",
73
+ "timeout": 30
74
+ }
75
+ ]
76
+ },
77
+ {
78
+ "matcher": "Edit",
79
+ "hooks": [
80
+ {
81
+ "type": "command",
82
+ "command": "bash $HOME/.claude/hooks/post-edit-lint.sh",
83
+ "async": true
84
+ }
85
+ ]
86
+ },
87
+ {
88
+ "matcher": "Write",
89
+ "hooks": [
90
+ {
91
+ "type": "command",
92
+ "command": "bash $HOME/.claude/hooks/post-edit-lint.sh",
93
+ "async": true
94
+ }
95
+ ]
96
+ },
97
+ {
98
+ "matcher": "Bash|Edit|Write|MultiEdit|Agent|Task",
99
+ "hooks": [
100
+ {
101
+ "type": "command",
102
+ "command": "node \"$HOME/.claude/hooks/gsd-context-monitor.js\"",
103
+ "timeout": 3
104
+ }
105
+ ]
106
+ },
107
+ {
108
+ "matcher": "Bash|Edit|Write|Agent",
109
+ "hooks": [
110
+ {
111
+ "type": "command",
112
+ "command": "bash $HOME/.claude/hooks/session-log-action.sh",
113
+ "async": true
114
+ }
115
+ ]
116
+ },
117
+ {
118
+ "matcher": "Bash|Edit|Write|Agent",
119
+ "hooks": [
120
+ {
121
+ "type": "command",
122
+ "command": "bash $HOME/.claude/hooks/session-checkpoint.sh",
123
+ "async": true
124
+ }
125
+ ]
126
+ },
127
+ {
128
+ "matcher": "Bash",
129
+ "hooks": [
130
+ {
131
+ "type": "command",
132
+ "command": "bash $HOME/.claude/hooks/post-commit-verify.sh",
133
+ "async": true
134
+ }
135
+ ]
136
+ },
137
+ {
138
+ "matcher": "Bash",
139
+ "hooks": [
140
+ {
141
+ "type": "command",
142
+ "command": "bash $HOME/.claude/hooks/post-commit-memory-trigger.sh",
143
+ "async": true
144
+ }
145
+ ]
146
+ },
147
+ {
148
+ "matcher": "Bash",
149
+ "hooks": [
150
+ {
151
+ "type": "command",
152
+ "command": "bash $HOME/.claude/hooks/linear-lifecycle-sync.sh",
153
+ "async": true
154
+ }
155
+ ]
156
+ }
157
+ ],
158
+ "UserPromptSubmit": [
159
+ {
160
+ "hooks": [
161
+ {
162
+ "type": "command",
163
+ "command": "bash $HOME/.claude/hooks/session-auto-title.sh"
164
+ }
165
+ ]
166
+ }
167
+ ],
168
+ "Stop": [
169
+ {
170
+ "hooks": [
171
+ {
172
+ "type": "command",
173
+ "command": "bash $HOME/.claude/hooks/session-cost-log.sh",
174
+ "async": true
175
+ }
176
+ ]
177
+ },
178
+ {
179
+ "hooks": [
180
+ {
181
+ "type": "command",
182
+ "command": "bash $HOME/.claude/hooks/session-summarize.sh",
183
+ "async": true
184
+ }
185
+ ]
186
+ },
187
+ {
188
+ "hooks": [
189
+ {
190
+ "type": "command",
191
+ "command": "bash $HOME/.claude/hooks/memory-extractor.sh",
192
+ "async": true
193
+ }
194
+ ]
195
+ },
196
+ {
197
+ "hooks": [
198
+ {
199
+ "type": "command",
200
+ "command": "bash $HOME/.claude/hooks/desktop-notify.sh",
201
+ "async": true
202
+ }
203
+ ]
204
+ }
205
+ ],
206
+ "PreCompact": [
207
+ {
208
+ "hooks": [
209
+ {
210
+ "type": "command",
211
+ "command": "bash $HOME/.claude/hooks/precompact-save-context.sh"
212
+ }
213
+ ]
214
+ }
215
+ ],
216
+ "SessionStart": [
217
+ {
218
+ "hooks": [
219
+ {
220
+ "type": "command",
221
+ "command": "bash $HOME/.claude/hooks/session-restore.sh"
222
+ }
223
+ ]
224
+ }
225
+ ]
226
+ },
227
+ "statusLine": {
228
+ "type": "command",
229
+ "command": "bash $HOME/.claude/statusline-command.sh"
230
+ },
231
+ "enabledPlugins": {
232
+ "frontend-design@claude-plugins-official": true,
233
+ "context7@claude-plugins-official": true,
234
+ "ruby-lsp@claude-plugins-official": true,
235
+ "typescript-lsp@claude-plugins-official": true,
236
+ "pyright-lsp@claude-plugins-official": true,
237
+ "code-simplifier@claude-plugins-official": true,
238
+ "hookify@claude-plugins-official": true,
239
+ "claude-md-management@claude-plugins-official": true,
240
+ "commit-commands@claude-plugins-official": true,
241
+ "pr-review-toolkit@claude-plugins-official": true
242
+ },
243
+ "language": "spanish",
244
+ "alwaysThinkingEnabled": true,
245
+ "effortLevel": "high",
246
+ "autoCompactWindow": 500000,
247
+ "promptSuggestionEnabled": true,
248
+ "voiceEnabled": true,
249
+ "channelsEnabled": true,
250
+ "autoMemoryEnabled": true,
251
+ "autoMemoryDirectory": "~/.claude/memory",
252
+ "autoDreamEnabled": true,
253
+ "showThinkingSummaries": true,
254
+ "skipDangerousModePermissionPrompt": true
255
+ }
@@ -0,0 +1,182 @@
1
+ #!/usr/bin/env bash
2
+ # Claude Code status line script
3
+ # Reads JSON from stdin and prints a compact status line
4
+ # Also persists last-known stats for session cost logging
5
+
6
+ input=$(cat)
7
+
8
+ # --- Session ID (for per-session stat files) ---
9
+ session_id=$(echo "$input" | jq -r '.session_id // empty')
10
+
11
+ # --- Directory ---
12
+ cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty')
13
+ if [ -n "$cwd" ]; then
14
+ dir=$(basename "$cwd")
15
+ else
16
+ dir=$(basename "$(pwd)")
17
+ fi
18
+
19
+ # --- Git branch (skip optional locks) ---
20
+ branch=$(GIT_OPTIONAL_LOCKS=0 git -C "$cwd" symbolic-ref --short HEAD 2>/dev/null \
21
+ || GIT_OPTIONAL_LOCKS=0 git -C "$cwd" rev-parse --short HEAD 2>/dev/null)
22
+
23
+ # --- Detect project type from cwd ---
24
+ node_ver=""
25
+ ruby_ver=""
26
+
27
+ # Node version — try .nvmrc in the cwd, then `node` on PATH
28
+ if [ -f "$cwd/.nvmrc" ]; then
29
+ node_ver="node:$(cat "$cwd/.nvmrc" | tr -d '[:space:]')"
30
+ elif command -v node &>/dev/null; then
31
+ node_ver="node:$(node --version 2>/dev/null | sed 's/v//')"
32
+ fi
33
+
34
+ # Ruby version — prefer .ruby-version in the cwd, then `ruby` on PATH
35
+ if [ -f "$cwd/.ruby-version" ]; then
36
+ ruby_ver="ruby:$(cat "$cwd/.ruby-version" | tr -d '[:space:]')"
37
+ elif command -v ruby &>/dev/null; then
38
+ ruby_ver="ruby:$(ruby --version 2>/dev/null | awk '{print $2}')"
39
+ fi
40
+
41
+ # --- Context window ---
42
+ remaining=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty')
43
+ ctx_used=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
44
+ total_input=$(echo "$input" | jq -r '.context_window.total_input_tokens // empty')
45
+ total_output=$(echo "$input" | jq -r '.context_window.total_output_tokens // empty')
46
+
47
+ # --- Cost ---
48
+ cost_usd=$(echo "$input" | jq -r '.cost.total_cost_usd // empty')
49
+
50
+ # --- Rate limits ---
51
+ five_h_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
52
+ five_h_resets=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
53
+
54
+ # --- Model short name ---
55
+ model=$(echo "$input" | jq -r '.model.display_name // empty' | sed 's/Claude //' | sed 's/ (.*)//')
56
+
57
+ # --- Persist last-known stats for Stop hook ---
58
+ if [ -n "$session_id" ]; then
59
+ stats_file="$HOME/.claude/session-stats-${session_id}.json"
60
+ echo "$input" | jq -c '{
61
+ session_id: .session_id,
62
+ cwd: (.workspace.current_dir // .cwd),
63
+ cost_usd: (.cost.total_cost_usd // 0),
64
+ total_input_tokens: (.context_window.total_input_tokens // 0),
65
+ total_output_tokens: (.context_window.total_output_tokens // 0),
66
+ ctx_used_pct: (.context_window.used_percentage // 0),
67
+ five_h_pct: (.rate_limits.five_hour.used_percentage // 0),
68
+ five_h_resets: (.rate_limits.five_hour.resets_at // 0),
69
+ model: (.model.display_name // ""),
70
+ timestamp: now | todate
71
+ }' > "$stats_file" 2>/dev/null
72
+
73
+ # Save starting 5h% once (first non-zero value = baseline before this session)
74
+ start_file="$HOME/.claude/session-stats-${session_id}-start.json"
75
+ if [ ! -f "$start_file" ] && [ -n "$five_h_pct" ] && [ "$five_h_pct" != "0" ]; then
76
+ echo "{\"five_h_pct_start\": $five_h_pct}" > "$start_file"
77
+ fi
78
+ fi
79
+
80
+ # --- Colors (ANSI) ---
81
+ CYAN='\033[0;36m'
82
+ GREEN='\033[0;32m'
83
+ YELLOW='\033[0;33m'
84
+ MAGENTA='\033[0;35m'
85
+ BLUE='\033[0;34m'
86
+ RED='\033[0;31m'
87
+ DIM='\033[2m'
88
+ RESET='\033[0m'
89
+
90
+ parts=()
91
+
92
+ # Directory
93
+ parts+=("$(printf "${CYAN}%s${RESET}" "$dir")")
94
+
95
+ # Git branch
96
+ if [ -n "$branch" ]; then
97
+ parts+=("$(printf "${GREEN}(%s)${RESET}" "$branch")")
98
+ fi
99
+
100
+ # Project runtime versions (only show what's relevant to the project)
101
+ is_node=false
102
+ is_ruby=false
103
+ [ -f "$cwd/package.json" ] || [ -f "$cwd/pnpm-lock.yaml" ] || [ -f "$cwd/.nvmrc" ] && is_node=true
104
+ [ -f "$cwd/Gemfile" ] || [ -f "$cwd/.ruby-version" ] && is_ruby=true
105
+
106
+ if $is_node && [ -n "$node_ver" ]; then
107
+ parts+=("$(printf "${YELLOW}%s${RESET}" "$node_ver")")
108
+ fi
109
+ if $is_ruby && [ -n "$ruby_ver" ]; then
110
+ parts+=("$(printf "${MAGENTA}%s${RESET}" "$ruby_ver")")
111
+ fi
112
+
113
+ # Model
114
+ if [ -n "$model" ]; then
115
+ parts+=("$(printf "${BLUE}%s${RESET}" "$model")")
116
+ fi
117
+
118
+ # Context remaining
119
+ if [ -n "$remaining" ]; then
120
+ ctx_int=$(printf "%.0f" "$remaining")
121
+ if [ "$ctx_int" -le 20 ]; then
122
+ ctx_color="$RED"
123
+ else
124
+ ctx_color="$GREEN"
125
+ fi
126
+ parts+=("$(printf "${ctx_color}ctx:%s%%${RESET}" "$ctx_int")")
127
+ fi
128
+
129
+ # Cost — format: $1.26 (2 decimals if >= $0.10, 3 if smaller)
130
+ if [ -n "$cost_usd" ] && [ "$cost_usd" != "0" ]; then
131
+ cost_big=$(awk "BEGIN {exit !($cost_usd >= 0.10)}" 2>/dev/null && echo 1 || echo 0)
132
+ if [ "$cost_big" = "1" ]; then
133
+ cost_fmt=$(printf "%.2f" "$cost_usd" 2>/dev/null)
134
+ else
135
+ cost_fmt=$(printf "%.3f" "$cost_usd" 2>/dev/null)
136
+ fi
137
+ parts+=("$(printf "${YELLOW}\$%s${RESET}" "$cost_fmt")")
138
+ fi
139
+
140
+ # Rate limit 5h — shows acum% and +delta% for this session
141
+ if [ -n "$five_h_pct" ] && [ "$five_h_pct" != "0" ]; then
142
+ five_int=$(printf "%.0f" "$five_h_pct" 2>/dev/null)
143
+ if [ "$five_int" -ge 80 ]; then
144
+ rl_color="$RED"
145
+ elif [ "$five_int" -ge 50 ]; then
146
+ rl_color="$YELLOW"
147
+ else
148
+ rl_color="$DIM"
149
+ fi
150
+
151
+ # Per-session delta
152
+ delta_str=""
153
+ if [ -n "$session_id" ]; then
154
+ start_file_check="$HOME/.claude/session-stats-${session_id}-start.json"
155
+ if [ -f "$start_file_check" ]; then
156
+ five_h_start_val=$(jq -r '.five_h_pct_start // 0' "$start_file_check" 2>/dev/null)
157
+ five_h_delta_val=$(awk "BEGIN {d=$five_h_pct-$five_h_start_val; printf \"%.1f\", (d<0?0:d)}")
158
+ delta_str=" (+${five_h_delta_val}%)"
159
+ fi
160
+ fi
161
+
162
+ # Show reset time if close to limit
163
+ reset_str=""
164
+ if [ "$five_int" -ge 70 ] && [ -n "$five_h_resets" ] && [ "$five_h_resets" != "0" ]; then
165
+ reset_time=$(date -r "$five_h_resets" '+%H:%M' 2>/dev/null || date -d "@$five_h_resets" '+%H:%M' 2>/dev/null)
166
+ [ -n "$reset_time" ] && reset_str=" reset@${reset_time}"
167
+ fi
168
+ parts+=("$(printf "${rl_color}5h:%s%%%s%s${RESET}" "$five_int" "$delta_str" "$reset_str")")
169
+ fi
170
+
171
+ # Join with separator
172
+ sep=" | "
173
+ result=""
174
+ for part in "${parts[@]}"; do
175
+ if [ -z "$result" ]; then
176
+ result="$part"
177
+ else
178
+ result="$result$sep$part"
179
+ fi
180
+ done
181
+
182
+ printf "%b\n" "$result"
@@ -0,0 +1,32 @@
1
+ {
2
+ "preToolUseAgentMissingModel": {
3
+ "hook_event_name": "PreToolUse",
4
+ "tool_name": "Agent",
5
+ "tool_input": {
6
+ "description": "Audit installer behavior",
7
+ "prompt": "Review bootstrap profile side effects."
8
+ }
9
+ },
10
+ "preToolUseAgentWithModel": {
11
+ "hook_event_name": "PreToolUse",
12
+ "tool_name": "Agent",
13
+ "tool_input": {
14
+ "description": "Audit installer behavior",
15
+ "prompt": "Review bootstrap profile side effects.",
16
+ "model": "sonnet"
17
+ }
18
+ },
19
+ "postToolUseEdit": {
20
+ "hook_event_name": "PostToolUse",
21
+ "tool_name": "Edit",
22
+ "tool_input": {
23
+ "file_path": "src/example.js",
24
+ "old_string": "const enabled = false;",
25
+ "new_string": "const enabled = true;"
26
+ }
27
+ },
28
+ "sessionStop": {
29
+ "hook_event_name": "Stop",
30
+ "session_id": "fixture-session"
31
+ }
32
+ }
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env bash
2
+ # session-costs-view.sh
3
+ # Pretty-print the session costs log
4
+ # Usage:
5
+ # ~/.claude/tools/session-costs-view.sh → all sessions (last 30)
6
+ # ~/.claude/tools/session-costs-view.sh today → today only
7
+ # ~/.claude/tools/session-costs-view.sh week → last 7 days
8
+ # ~/.claude/tools/session-costs-view.sh summary → totals by day
9
+
10
+ LOG_FILE="$HOME/.claude/session-costs.log"
11
+ MODE="${1:-all}"
12
+ TODAY=$(date +%Y-%m-%d)
13
+ WEEK_AGO=$(date -v-7d +%Y-%m-%d 2>/dev/null || date -d "7 days ago" +%Y-%m-%d 2>/dev/null)
14
+
15
+ if [ ! -f "$LOG_FILE" ]; then
16
+ echo "No hay datos todavía. El log se crea al cerrar la primera sesión con actividad."
17
+ exit 0
18
+ fi
19
+
20
+ # ANSI colors
21
+ BOLD='\033[1m'
22
+ CYAN='\033[0;36m'
23
+ GREEN='\033[0;32m'
24
+ YELLOW='\033[0;33m'
25
+ RED='\033[0;31m'
26
+ DIM='\033[2m'
27
+ RESET='\033[0m'
28
+
29
+ # Filter rows based on mode (skip header)
30
+ case "$MODE" in
31
+ today)
32
+ DATA=$(tail -n +2 "$LOG_FILE" | grep "^${TODAY}")
33
+ TITLE="Sesiones de hoy (${TODAY})"
34
+ ;;
35
+ week)
36
+ DATA=$(tail -n +2 "$LOG_FILE" | awk -F',' -v cutoff="$WEEK_AGO" '$1 >= cutoff')
37
+ TITLE="Últimos 7 días"
38
+ ;;
39
+ summary)
40
+ echo -e "${BOLD}=== Resumen por día ===${RESET}"
41
+ echo ""
42
+ tail -n +2 "$LOG_FILE" | awk -F',' '
43
+ {
44
+ day[$1] += $5
45
+ sessions[$1]++
46
+ tokens[$1] += ($6 + $7)
47
+ five_h_delta[$1] += $10
48
+ }
49
+ END {
50
+ for (d in day) {
51
+ printf "%s sesiones: %2d costo: $%.2f tokens: %5dk limite-5h usado: %.1f%%\n",
52
+ d, sessions[d], day[d], tokens[d]/1000, five_h_delta[d]
53
+ }
54
+ }' | sort -r
55
+ echo ""
56
+ TOTAL=$(tail -n +2 "$LOG_FILE" | awk -F',' '{sum+=$5} END {printf "%.2f", sum}')
57
+ SESSIONS=$(tail -n +2 "$LOG_FILE" | wc -l | tr -d ' ')
58
+ TOTAL_5H=$(tail -n +2 "$LOG_FILE" | awk -F',' '{sum+=$10} END {printf "%.1f", sum}')
59
+ echo -e "${BOLD}Total acumulado: \$${TOTAL} en ${SESSIONS} sesión(es) — ${TOTAL_5H}% del límite de 5h consumido en total${RESET}"
60
+ exit 0
61
+ ;;
62
+ *)
63
+ DATA=$(tail -n +2 "$LOG_FILE" | tail -30)
64
+ TITLE="Últimas 30 sesiones"
65
+ ;;
66
+ esac
67
+
68
+ if [ -z "$DATA" ]; then
69
+ echo "Sin datos para el período seleccionado."
70
+ exit 0
71
+ fi
72
+
73
+ echo -e "${BOLD}=== ${TITLE} ===${RESET}"
74
+ echo ""
75
+ # Header: date time session project cost in out ctx% 5h-acum% 5h-sesion%
76
+ printf "${BOLD}%-12s %-6s %-10s %-18s %7s %7s %7s %6s %8s %9s${RESET}\n" \
77
+ "Fecha" "Hora" "Session" "Proyecto" "Costo" "In-tok" "Out-tok" "Ctx%" "5h-acum" "5h-sesion"
78
+ echo "────────────────────────────────────────────────────────────────────────────────────────────"
79
+
80
+ TOTAL_COST=0
81
+ TOTAL_5H_DELTA=0
82
+ while IFS=',' read -r date time sess proj cost in_tok out_tok ctx_pct five_h_end five_h_delta model; do
83
+ # Color cost
84
+ cost_cents=$(awk "BEGIN {printf \"%.0f\", ${cost:-0} * 100}" 2>/dev/null)
85
+ if [ "${cost_cents:-0}" -gt 100 ]; then
86
+ cost_color="$RED"
87
+ elif [ "${cost_cents:-0}" -gt 30 ]; then
88
+ cost_color="$YELLOW"
89
+ else
90
+ cost_color="$GREEN"
91
+ fi
92
+
93
+ # Color 5h acumulado
94
+ five_end_int=$(printf "%.0f" "${five_h_end:-0}" 2>/dev/null)
95
+ if [ "${five_end_int:-0}" -ge 80 ]; then
96
+ five_end_color="$RED"
97
+ elif [ "${five_end_int:-0}" -ge 50 ]; then
98
+ five_end_color="$YELLOW"
99
+ else
100
+ five_end_color="$DIM"
101
+ fi
102
+
103
+ # Color 5h delta de esta sesión
104
+ five_delta_int=$(printf "%.0f" "${five_h_delta:-0}" 2>/dev/null)
105
+ if [ "${five_delta_int:-0}" -ge 20 ]; then
106
+ five_delta_color="$RED"
107
+ elif [ "${five_delta_int:-0}" -ge 10 ]; then
108
+ five_delta_color="$YELLOW"
109
+ else
110
+ five_delta_color="$CYAN"
111
+ fi
112
+
113
+ in_k=$(awk "BEGIN {printf \"%.0f\", ${in_tok:-0}/1000}" 2>/dev/null)k
114
+ out_k=$(awk "BEGIN {printf \"%.0f\", ${out_tok:-0}/1000}" 2>/dev/null)k
115
+
116
+ printf "${DIM}%-12s %-6s${RESET} ${CYAN}%-10s${RESET} %-18s ${cost_color}%7s${RESET} %7s %7s %5s%% ${five_end_color}%7s%%${RESET} ${five_delta_color}%8s%%${RESET}\n" \
117
+ "$date" "$time" "$sess" "${proj:0:18}" "\$$cost" "$in_k" "$out_k" "$ctx_pct" "$five_h_end" "$five_h_delta"
118
+
119
+ TOTAL_COST=$(awk "BEGIN {printf \"%.2f\", $TOTAL_COST + ${cost:-0}}" 2>/dev/null)
120
+ TOTAL_5H_DELTA=$(awk "BEGIN {printf \"%.1f\", $TOTAL_5H_DELTA + ${five_h_delta:-0}}" 2>/dev/null)
121
+ done <<< "$DATA"
122
+
123
+ echo "────────────────────────────────────────────────────────────────────────────────────────────"
124
+ COUNT=$(echo "$DATA" | wc -l | tr -d ' ')
125
+ echo -e "${BOLD}Total: \$${TOTAL_COST} en ${COUNT} sesión(es) — ${TOTAL_5H_DELTA}% del límite de 5h consumido${RESET}"
126
+ echo ""
127
+ echo -e "${DIM}Columna '5h-sesion' = cuánto del límite de 5h consumió esta sesión específica${RESET}"
128
+ echo -e "${DIM}Modos: $(basename "$0") [today|week|summary|all]${RESET}"