@pjmendonca/devflow 1.13.2 → 1.19.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/.claude/commands/agent.md +1 -1
- package/.claude/commands/brainstorm.md +28 -0
- package/.claude/commands/bugfix.md +21 -0
- package/.claude/commands/checkpoint.md +0 -1
- package/.claude/commands/collab.md +0 -1
- package/.claude/commands/costs.md +88 -18
- package/.claude/commands/devflow.md +26 -0
- package/.claude/commands/handoff.md +0 -1
- package/.claude/commands/init.md +383 -0
- package/.claude/commands/memory.md +0 -1
- package/.claude/commands/pair.md +0 -1
- package/.claude/commands/review.md +27 -0
- package/.claude/commands/route.md +0 -1
- package/.claude/commands/swarm.md +0 -1
- package/.claude/commands/validate.md +55 -0
- package/.claude/hooks/session-notification.sh +44 -0
- package/.claude/hooks/session-startup.sh +427 -0
- package/.claude/hooks/session-stop.sh +38 -0
- package/.claude/hooks/session_tracker.py +272 -0
- package/.claude/settings.json +38 -0
- package/.claude/skills/brainstorm/SKILL.md +531 -0
- package/.claude/skills/costs/SKILL.md +156 -0
- package/.claude/skills/validate/SKILL.md +101 -0
- package/CHANGELOG.md +284 -0
- package/README.md +207 -10
- package/bin/devflow-install.js +2 -1
- package/bin/devflow.js +4 -0
- package/lib/constants.js +0 -1
- package/lib/exec-python.js +1 -1
- package/package.json +1 -1
- package/tooling/.automation/.checkpoint_lock +1 -0
- package/tooling/.automation/agents/architect.md +19 -0
- package/tooling/.automation/agents/ba.md +19 -0
- package/tooling/.automation/agents/maintainer.md +19 -0
- package/tooling/.automation/agents/pm.md +19 -0
- package/tooling/.automation/agents/reviewer.md +1 -1
- package/tooling/.automation/agents/writer.md +19 -0
- package/tooling/.automation/benchmarks/benchmark_20251230_100119.json +314 -0
- package/tooling/.automation/benchmarks/benchmark_20251230_100216.json +314 -0
- package/tooling/.automation/costs/config.json +31 -0
- package/tooling/.automation/costs/sessions/2025-12-29_20251229_164128.json +22 -0
- package/tooling/.automation/memory/knowledge/kg_integration-test.json +738 -1
- package/tooling/.automation/memory/knowledge/kg_test-story.json +3381 -2
- package/tooling/.automation/memory/shared/shared_integration-test.json +193 -1
- package/tooling/.automation/memory/shared/shared_test-story.json +757 -1
- package/tooling/.automation/memory/shared/shared_test.json +1332 -0
- package/tooling/.automation/memory/shared/shared_validation-check.json +240 -0
- package/tooling/.automation/overrides/templates/architect/cloud-native.yaml +5 -5
- package/tooling/.automation/overrides/templates/architect/enterprise-architect.yaml +23 -5
- package/tooling/.automation/overrides/templates/architect/pragmatic-minimalist.yaml +24 -6
- package/tooling/.automation/overrides/templates/ba/agile-storyteller.yaml +4 -4
- package/tooling/.automation/overrides/templates/ba/domain-expert.yaml +4 -4
- package/tooling/.automation/overrides/templates/ba/requirements-engineer.yaml +4 -4
- package/tooling/.automation/overrides/templates/dev/performance-engineer.yaml +18 -0
- package/tooling/.automation/overrides/templates/dev/rapid-prototyper.yaml +19 -1
- package/tooling/.automation/overrides/templates/dev/security-focused.yaml +18 -0
- package/tooling/.automation/overrides/templates/dev/user-advocate.yaml +54 -0
- package/tooling/.automation/overrides/templates/maintainer/devops-maintainer.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/legacy-steward.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/oss-maintainer.yaml +4 -4
- package/tooling/.automation/overrides/templates/maintainer/reliability-engineer.yaml +55 -0
- package/tooling/.automation/overrides/templates/pm/agile-pm.yaml +4 -4
- package/tooling/.automation/overrides/templates/pm/hybrid-delivery.yaml +3 -3
- package/tooling/.automation/overrides/templates/pm/traditional-pm.yaml +4 -4
- package/tooling/.automation/overrides/templates/reviewer/quick-sanity.yaml +18 -0
- package/tooling/.automation/overrides/templates/reviewer/thorough-critic.yaml +18 -0
- package/tooling/.automation/overrides/templates/sm/agile-coach.yaml +2 -2
- package/tooling/.automation/overrides/templates/sm/startup-pm.yaml +3 -3
- package/tooling/.automation/overrides/templates/writer/api-documentarian.yaml +5 -5
- package/tooling/.automation/overrides/templates/writer/docs-as-code.yaml +4 -4
- package/tooling/.automation/overrides/templates/writer/user-guide-author.yaml +5 -5
- package/tooling/.automation/validation/history/2025-12-29_val_002a28c1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_01273bb1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_03369914.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_07a449ba.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_0df1f0a2.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_10ff3d34.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_110771d7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_13f3a7f9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_17ba9d21.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_22247089.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_227ea6a4.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2335d5ae.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_246824bb.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_28b4b9cd.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2abd12cc.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2c801b2f.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2c8cfa8e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_2ce76eb0.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_30351948.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_30eb7229.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_34df0e77.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_376e4d6a.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3a4e8a1a.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3b77a628.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_3ea4e1cf.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_44aacdb4.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_457ddfa8.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_45af6238.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_4735dba1.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_486b203c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_49dc56cd.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_4d863d6d.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_5149a808.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_52e0bb43.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_585d6319.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_5b2d859a.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_635a7081.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_64df4905.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_70634cee.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_714553f9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_7f7bfdbf.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_7faad91d.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_81821f8f.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8249f3c9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8422b50f.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8446c134.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_879f4e26.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8b6d5bd7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_8c5cd787.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_91d20bc7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_958a12b7.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_95d91108.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_980dbb74.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9e40c79b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9f499b7c.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_9f7c3b57.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a30d5bd4.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a6eb09c7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_a86f7b83.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ad5347e1.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_b0a5a993.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_bcb0192e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_bf3c9aaa.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c461ff88.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c4f4e258.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c7f0fa6d.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_c911b0e6.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cc581964.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cdd5a33b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_cfd42495.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d1c7a4ee.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d2280d0e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d2a6ff69.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d8c53ab2.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d9c1247a.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_d9d58569.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_dabb4fd9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_dd8fe359.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_decdffc9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_e3a95476.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_e776dfca.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ea70969f.json +59 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ef41ea95.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_f384f9b1.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_f8adc38c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fa40b69e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fc538d54.json +41 -0
- package/tooling/.automation/validation/history/2025-12-29_val_fe814665.json +32 -0
- package/tooling/.automation/validation/history/2025-12-29_val_ffea4b12.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_02d001e5.json +59 -0
- package/tooling/.automation/validation/history/2025-12-30_val_0b8966dc.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_15455fbf.json +59 -0
- package/tooling/.automation/validation/history/2025-12-30_val_157e34b9.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_28d1d933.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_3442a52c.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_37f1ce1e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_4f1d8a93.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_56ff1de3.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_664fd4e2.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_66afb0a7.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_7634663c.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_8ea830c3.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_998957c2.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_a52177db.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_a5b65a63.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ae391d0e.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_c7895339.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ca416593.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_cee19422.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ddd4f4e6.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_f2e1394b.json +32 -0
- package/tooling/.automation/validation/history/2025-12-30_val_f4a7fa06.json +41 -0
- package/tooling/.automation/validation/history/2025-12-30_val_ffea3369.json +32 -0
- package/tooling/.automation/validation/history/2026-01-03_val_1287a74c.json +41 -0
- package/tooling/.automation/validation/history/2026-01-03_val_3b24071f.json +32 -0
- package/tooling/.automation/validation/history/2026-01-03_val_44d77573.json +32 -0
- package/tooling/.automation/validation/history/2026-01-03_val_5b31dc51.json +32 -0
- package/tooling/.automation/validation/history/2026-01-03_val_74267244.json +32 -0
- package/tooling/.automation/validation/history/2026-01-03_val_8b2d95c7.json +59 -0
- package/tooling/.automation/validation/history/2026-01-03_val_d875b297.json +41 -0
- package/tooling/.automation/validation-config.yaml +103 -0
- package/tooling/completions/DevflowCompletion.ps1 +21 -21
- package/tooling/completions/_run-story +3 -3
- package/tooling/completions/run-story-completion.bash +8 -8
- package/tooling/docs/DOC-STANDARD.md +14 -14
- package/tooling/docs/stories/.gitkeep +0 -0
- package/tooling/docs/templates/brainstorm-guide.md +314 -0
- package/tooling/docs/templates/migration-spec.md +4 -4
- package/tooling/docs/templates/story.md +66 -0
- package/tooling/scripts/context_checkpoint.py +5 -15
- package/tooling/scripts/cost_dashboard.py +610 -13
- package/tooling/scripts/create-persona.py +1 -12
- package/tooling/scripts/create-persona.sh +44 -44
- package/tooling/scripts/lib/__init__.py +12 -1
- package/tooling/scripts/lib/agent_handoff.py +11 -2
- package/tooling/scripts/lib/agent_router.py +31 -10
- package/tooling/scripts/lib/colors.py +106 -0
- package/tooling/scripts/lib/context_monitor.py +766 -0
- package/tooling/scripts/lib/cost_config.py +229 -10
- package/tooling/scripts/lib/cost_display.py +20 -45
- package/tooling/scripts/lib/cost_tracker.py +462 -15
- package/tooling/scripts/lib/currency_converter.py +28 -5
- package/tooling/scripts/lib/pair_programming.py +102 -3
- package/tooling/scripts/lib/personality_system.py +949 -0
- package/tooling/scripts/lib/platform.py +55 -0
- package/tooling/scripts/lib/shared_memory.py +9 -3
- package/tooling/scripts/lib/swarm_orchestrator.py +514 -75
- package/tooling/scripts/lib/validation_loop.py +1014 -0
- package/tooling/scripts/memory_summarize.py +9 -2
- package/tooling/scripts/new-doc.py +2 -9
- package/tooling/scripts/personalize_agent.py +1 -12
- package/tooling/scripts/rollback-migration.sh +60 -60
- package/tooling/scripts/run-collab.ps1 +16 -16
- package/tooling/scripts/run-collab.py +88 -53
- package/tooling/scripts/run-collab.sh +4 -4
- package/tooling/scripts/run-story.py +278 -20
- package/tooling/scripts/run-story.sh +3 -3
- package/tooling/scripts/setup-checkpoint-service.py +2 -9
- package/tooling/scripts/tech-debt-tracker.py +1 -12
- package/tooling/scripts/test_adversarial_swarm.py +452 -0
- package/tooling/scripts/validate-overrides.py +1 -10
- package/tooling/scripts/validate-overrides.sh +40 -40
- package/tooling/scripts/validate_loop.py +162 -0
- package/tooling/scripts/validate_setup.py +2 -30
- package/.claude/skills/init/SKILL.md +0 -496
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Validate
|
|
2
|
+
|
|
3
|
+
Run validation checks on the current story or codebase.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
/validate [story-key] [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Options
|
|
12
|
+
|
|
13
|
+
- `--tier 1|2|3|all` - Which validation tier to run
|
|
14
|
+
- 1: Pre-flight (story exists, budget, dependencies)
|
|
15
|
+
- 2: Inter-phase (code compiles, lint, transitions)
|
|
16
|
+
- 3: Post-completion (tests, types, version sync)
|
|
17
|
+
- all: Run all tiers
|
|
18
|
+
- `--auto-fix` - Attempt automatic fixes for failures
|
|
19
|
+
- `--json` - Output as JSON
|
|
20
|
+
- `--quiet` - Minimal output
|
|
21
|
+
|
|
22
|
+
## Examples
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Run all validation tiers
|
|
26
|
+
/validate 3-5 --tier all
|
|
27
|
+
|
|
28
|
+
# Run pre-flight checks only
|
|
29
|
+
/validate 3-5 --tier 1
|
|
30
|
+
|
|
31
|
+
# Run post-completion with auto-fix
|
|
32
|
+
/validate 3-5 --tier 3 --auto-fix
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Prompt
|
|
36
|
+
|
|
37
|
+
Run the validation loop for story: $ARGUMENTS
|
|
38
|
+
|
|
39
|
+
Execute the following:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
python3 tooling/scripts/lib/validation_loop.py --story "$ARGUMENTS" --all
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
If no story key is provided, run validation on the current codebase state:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
python3 tooling/scripts/lib/validation_loop.py --tier 3
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Report the validation results clearly, including:
|
|
52
|
+
- Which gates passed
|
|
53
|
+
- Which gates failed with reasons
|
|
54
|
+
- Any warnings
|
|
55
|
+
- Suggested fixes if available
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Session Notification Hook - Captures token usage from Claude Code notifications
|
|
3
|
+
|
|
4
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
5
|
+
TRACKER="$PROJECT_DIR/.claude/hooks/session_tracker.py"
|
|
6
|
+
|
|
7
|
+
# Read notification data from Claude Code
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
|
|
10
|
+
# Try to extract token usage from notification
|
|
11
|
+
# Claude Code may send usage data in various formats
|
|
12
|
+
INPUT_TOKENS=$(echo "$INPUT" | jq -r '
|
|
13
|
+
.usage.input_tokens //
|
|
14
|
+
.data.usage.input_tokens //
|
|
15
|
+
.message.usage.input_tokens //
|
|
16
|
+
.input_tokens //
|
|
17
|
+
0
|
|
18
|
+
' 2>/dev/null)
|
|
19
|
+
|
|
20
|
+
OUTPUT_TOKENS=$(echo "$INPUT" | jq -r '
|
|
21
|
+
.usage.output_tokens //
|
|
22
|
+
.data.usage.output_tokens //
|
|
23
|
+
.message.usage.output_tokens //
|
|
24
|
+
.output_tokens //
|
|
25
|
+
0
|
|
26
|
+
' 2>/dev/null)
|
|
27
|
+
|
|
28
|
+
MODEL=$(echo "$INPUT" | jq -r '
|
|
29
|
+
.model //
|
|
30
|
+
.data.model //
|
|
31
|
+
.message.model //
|
|
32
|
+
""
|
|
33
|
+
' 2>/dev/null)
|
|
34
|
+
|
|
35
|
+
# Only log if we have actual token data
|
|
36
|
+
if [ "$INPUT_TOKENS" -gt 0 ] 2>/dev/null || [ "$OUTPUT_TOKENS" -gt 0 ] 2>/dev/null; then
|
|
37
|
+
if [ -n "$MODEL" ] && [ "$MODEL" != "null" ]; then
|
|
38
|
+
python3 "$TRACKER" log --input "$INPUT_TOKENS" --output "$OUTPUT_TOKENS" --model "$MODEL" 2>/dev/null
|
|
39
|
+
else
|
|
40
|
+
python3 "$TRACKER" log --input "$INPUT_TOKENS" --output "$OUTPUT_TOKENS" 2>/dev/null
|
|
41
|
+
fi
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
exit 0
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Devflow Session Startup Hook
|
|
3
|
+
# Automatically loads plans and context when Claude Code starts
|
|
4
|
+
|
|
5
|
+
# Read input from Claude Code (contains model info)
|
|
6
|
+
INPUT=$(cat)
|
|
7
|
+
|
|
8
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
9
|
+
TRACKER="$PROJECT_DIR/.claude/hooks/session_tracker.py"
|
|
10
|
+
PLANS_DIR="$PROJECT_DIR/.claude/plans"
|
|
11
|
+
SESSIONS_DIR="$PROJECT_DIR/tooling/.automation/costs/sessions"
|
|
12
|
+
MEMORY_DIR="$PROJECT_DIR/tooling/.automation/memory"
|
|
13
|
+
CONTEXT_DIR="$PROJECT_DIR/tooling/.automation/context"
|
|
14
|
+
COST_CONFIG="$PROJECT_DIR/tooling/.automation/costs/config.json"
|
|
15
|
+
|
|
16
|
+
# Ensure plans directory exists
|
|
17
|
+
mkdir -p "$PLANS_DIR" 2>/dev/null
|
|
18
|
+
|
|
19
|
+
# Start session tracking
|
|
20
|
+
MODEL_NAME=$(echo "$INPUT" | jq -r '.model.name // .model // ""' 2>/dev/null)
|
|
21
|
+
if [ -n "$MODEL_NAME" ] && [ "$MODEL_NAME" != "null" ]; then
|
|
22
|
+
python3 "$TRACKER" start --model "$MODEL_NAME" 2>/dev/null
|
|
23
|
+
else
|
|
24
|
+
python3 "$TRACKER" start 2>/dev/null
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
echo "[DEVFLOW SESSION START]"
|
|
28
|
+
echo ""
|
|
29
|
+
|
|
30
|
+
# ============================================================================
|
|
31
|
+
# CUMULATIVE USAGE DISPLAY
|
|
32
|
+
# ============================================================================
|
|
33
|
+
|
|
34
|
+
calc_cumulative_usage() {
|
|
35
|
+
local billing_period=${1:-30}
|
|
36
|
+
local total_tokens=0
|
|
37
|
+
local total_cost=0
|
|
38
|
+
local session_count=0
|
|
39
|
+
|
|
40
|
+
if [ -d "$SESSIONS_DIR" ]; then
|
|
41
|
+
CUTOFF_DATE=$(date -v-${billing_period}d +%Y-%m-%d 2>/dev/null || date -d "-${billing_period} days" +%Y-%m-%d 2>/dev/null)
|
|
42
|
+
|
|
43
|
+
for session_file in "$SESSIONS_DIR"/*.json; do
|
|
44
|
+
[ -f "$session_file" ] || continue
|
|
45
|
+
FILE_DATE=$(basename "$session_file" | cut -d'_' -f1)
|
|
46
|
+
|
|
47
|
+
if [[ "$FILE_DATE" > "$CUTOFF_DATE" ]] || [[ "$FILE_DATE" == "$CUTOFF_DATE" ]]; then
|
|
48
|
+
SESSION_TOKENS=$(jq -r '.totals.total_tokens // 0' "$session_file" 2>/dev/null)
|
|
49
|
+
SESSION_COST=$(jq -r '.totals.cost_usd // 0' "$session_file" 2>/dev/null)
|
|
50
|
+
|
|
51
|
+
total_tokens=$((total_tokens + SESSION_TOKENS))
|
|
52
|
+
total_cost=$(echo "$total_cost + $SESSION_COST" | bc 2>/dev/null || echo "$total_cost")
|
|
53
|
+
session_count=$((session_count + 1))
|
|
54
|
+
fi
|
|
55
|
+
done
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
echo "$total_tokens|$total_cost|$session_count"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Get cumulative usage
|
|
62
|
+
CUMULATIVE=$(calc_cumulative_usage 30)
|
|
63
|
+
CUM_TOKENS=$(echo "$CUMULATIVE" | cut -d'|' -f1)
|
|
64
|
+
CUM_COST=$(echo "$CUMULATIVE" | cut -d'|' -f2)
|
|
65
|
+
CUM_SESSIONS=$(echo "$CUMULATIVE" | cut -d'|' -f3)
|
|
66
|
+
|
|
67
|
+
# Add baseline to cumulative
|
|
68
|
+
BASELINE_TOKENS=$(jq -r '.baseline_tokens // 0' "$COST_CONFIG" 2>/dev/null)
|
|
69
|
+
BASELINE_COST=$(jq -r '.baseline_cost // 0' "$COST_CONFIG" 2>/dev/null)
|
|
70
|
+
CUM_TOKENS=$((CUM_TOKENS + BASELINE_TOKENS))
|
|
71
|
+
CUM_COST=$(echo "$CUM_COST + $BASELINE_COST" | bc 2>/dev/null || echo "$CUM_COST")
|
|
72
|
+
|
|
73
|
+
# Format tokens for display
|
|
74
|
+
format_tokens() {
|
|
75
|
+
local tokens=$1
|
|
76
|
+
if [ "$tokens" -ge 1000000 ] 2>/dev/null; then
|
|
77
|
+
echo "$(echo "scale=1; $tokens / 1000000" | bc 2>/dev/null || echo "$tokens")M"
|
|
78
|
+
elif [ "$tokens" -ge 1000 ] 2>/dev/null; then
|
|
79
|
+
echo "$(echo "scale=1; $tokens / 1000" | bc 2>/dev/null || echo "$tokens")K"
|
|
80
|
+
else
|
|
81
|
+
echo "$tokens"
|
|
82
|
+
fi
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
CUM_TOKENS_FMT=$(format_tokens "$CUM_TOKENS")
|
|
86
|
+
CUM_COST_FMT=$(printf "%.2f" "$CUM_COST" 2>/dev/null || echo "$CUM_COST")
|
|
87
|
+
|
|
88
|
+
if [ "$CUM_SESSIONS" -gt 0 ] 2>/dev/null; then
|
|
89
|
+
echo "[CUMULATIVE USAGE] Last 30 days: ${CUM_TOKENS_FMT} tokens | \$${CUM_COST_FMT} | ${CUM_SESSIONS} sessions"
|
|
90
|
+
echo ""
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# ============================================================================
|
|
94
|
+
# SUBSCRIPTION PLAN DETECTION
|
|
95
|
+
# ============================================================================
|
|
96
|
+
|
|
97
|
+
# Extract model from input
|
|
98
|
+
MODEL=$(echo "$INPUT" | jq -r '.model.display_name // .model.name // .model // ""' 2>/dev/null)
|
|
99
|
+
|
|
100
|
+
# Token limits by plan
|
|
101
|
+
get_token_limit() {
|
|
102
|
+
case "$1" in
|
|
103
|
+
free) echo 100000 ;;
|
|
104
|
+
developer) echo 1000000 ;;
|
|
105
|
+
pro) echo 5000000 ;;
|
|
106
|
+
scale) echo 20000000 ;;
|
|
107
|
+
enterprise) echo 100000000 ;;
|
|
108
|
+
*) echo 1000000 ;;
|
|
109
|
+
esac
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# Detect plan from model
|
|
113
|
+
detect_plan_from_model() {
|
|
114
|
+
local model_lower=$(echo "$1" | tr '[:upper:]' '[:lower:]')
|
|
115
|
+
case "$model_lower" in
|
|
116
|
+
*opus*) echo "pro" ;;
|
|
117
|
+
*sonnet*) echo "developer" ;;
|
|
118
|
+
*haiku*) echo "free" ;;
|
|
119
|
+
*) echo "developer" ;;
|
|
120
|
+
esac
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Ensure config directory exists
|
|
124
|
+
mkdir -p "$(dirname "$COST_CONFIG")" 2>/dev/null
|
|
125
|
+
|
|
126
|
+
# Check if config exists, create if not
|
|
127
|
+
if [ ! -f "$COST_CONFIG" ]; then
|
|
128
|
+
echo '{"display_currency": "USD", "currency_rates": {"USD": 1.0}}' > "$COST_CONFIG"
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Read current plan from config
|
|
132
|
+
CURRENT_PLAN=$(jq -r '.subscription_plan // ""' "$COST_CONFIG" 2>/dev/null)
|
|
133
|
+
|
|
134
|
+
# Detect plan based on model if not already configured
|
|
135
|
+
if [ -z "$CURRENT_PLAN" ] && [ -n "$MODEL" ]; then
|
|
136
|
+
DETECTED_PLAN=$(detect_plan_from_model "$MODEL")
|
|
137
|
+
TOKEN_LIMIT=$(get_token_limit "$DETECTED_PLAN")
|
|
138
|
+
|
|
139
|
+
# Save to config
|
|
140
|
+
TMP_CONFIG=$(mktemp)
|
|
141
|
+
jq --arg plan "$DETECTED_PLAN" --argjson limit "$TOKEN_LIMIT" \
|
|
142
|
+
'.subscription_plan = $plan | .subscription_token_limit = $limit' \
|
|
143
|
+
"$COST_CONFIG" > "$TMP_CONFIG" 2>/dev/null && \
|
|
144
|
+
mv "$TMP_CONFIG" "$COST_CONFIG" 2>/dev/null || rm -f "$TMP_CONFIG"
|
|
145
|
+
|
|
146
|
+
CURRENT_PLAN="$DETECTED_PLAN"
|
|
147
|
+
echo "[SUBSCRIPTION] Auto-detected plan: $DETECTED_PLAN ($(get_token_limit "$DETECTED_PLAN" | numfmt --to=si 2>/dev/null || echo "$(get_token_limit "$DETECTED_PLAN")") tokens/month)"
|
|
148
|
+
echo ""
|
|
149
|
+
elif [ -n "$CURRENT_PLAN" ]; then
|
|
150
|
+
TOKEN_LIMIT=$(jq -r '.subscription_token_limit // 0' "$COST_CONFIG" 2>/dev/null)
|
|
151
|
+
if [ "$TOKEN_LIMIT" -gt 0 ] 2>/dev/null; then
|
|
152
|
+
# Calculate current usage
|
|
153
|
+
BILLING_PERIOD=$(jq -r '.subscription_billing_period_days // 30' "$COST_CONFIG" 2>/dev/null)
|
|
154
|
+
CUTOFF_DATE=$(date -v-${BILLING_PERIOD}d +%Y-%m-%d 2>/dev/null || date -d "-${BILLING_PERIOD} days" +%Y-%m-%d 2>/dev/null)
|
|
155
|
+
|
|
156
|
+
TOTAL_TOKENS=0
|
|
157
|
+
if [ -d "$SESSIONS_DIR" ]; then
|
|
158
|
+
for session_file in "$SESSIONS_DIR"/*.json; do
|
|
159
|
+
[ -f "$session_file" ] || continue
|
|
160
|
+
FILE_DATE=$(basename "$session_file" | cut -d'_' -f1)
|
|
161
|
+
if [[ "$FILE_DATE" > "$CUTOFF_DATE" ]] || [[ "$FILE_DATE" == "$CUTOFF_DATE" ]]; then
|
|
162
|
+
SESSION_TOKENS=$(jq -r '.totals.total_tokens // 0' "$session_file" 2>/dev/null)
|
|
163
|
+
TOTAL_TOKENS=$((TOTAL_TOKENS + SESSION_TOKENS))
|
|
164
|
+
fi
|
|
165
|
+
done
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
USAGE_PERCENT=$(echo "scale=1; ($TOTAL_TOKENS * 100) / $TOKEN_LIMIT" | bc 2>/dev/null || echo "0")
|
|
169
|
+
echo "[SUBSCRIPTION] Plan: $CURRENT_PLAN | Usage: ${USAGE_PERCENT}% of $(echo "$TOKEN_LIMIT" | numfmt --to=si 2>/dev/null || echo "$TOKEN_LIMIT") tokens"
|
|
170
|
+
echo ""
|
|
171
|
+
fi
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
# ============================================================================
|
|
175
|
+
# BASELINE USAGE SETUP (First-time only)
|
|
176
|
+
# ============================================================================
|
|
177
|
+
|
|
178
|
+
setup_baseline() {
|
|
179
|
+
# Check if baseline has been configured
|
|
180
|
+
BASELINE_CONFIGURED=$(jq -r '.baseline_configured // false' "$COST_CONFIG" 2>/dev/null)
|
|
181
|
+
|
|
182
|
+
if [ "$BASELINE_CONFIGURED" = "true" ]; then
|
|
183
|
+
return 0
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Check if we have a real interactive terminal
|
|
187
|
+
# Hooks run non-interactively, so we auto-configure with defaults
|
|
188
|
+
if [ ! -t 0 ] || [ -z "$(tty 2>/dev/null)" ] || [ "$(tty 2>/dev/null)" = "not a tty" ]; then
|
|
189
|
+
# Non-interactive: auto-configure with defaults
|
|
190
|
+
BASELINE_TOKENS=0
|
|
191
|
+
BASELINE_COST=0
|
|
192
|
+
|
|
193
|
+
# Save to config
|
|
194
|
+
TMP_CONFIG=$(mktemp)
|
|
195
|
+
jq --argjson tokens "$BASELINE_TOKENS" \
|
|
196
|
+
--argjson cost "$BASELINE_COST" \
|
|
197
|
+
--argjson configured true \
|
|
198
|
+
'.baseline_tokens = $tokens | .baseline_cost = $cost | .baseline_configured = $configured' \
|
|
199
|
+
"$COST_CONFIG" > "$TMP_CONFIG" 2>/dev/null && \
|
|
200
|
+
mv "$TMP_CONFIG" "$COST_CONFIG" 2>/dev/null || rm -f "$TMP_CONFIG"
|
|
201
|
+
|
|
202
|
+
echo "[OK] Baseline auto-configured (starting fresh). Run 'devflow baseline' to adjust."
|
|
203
|
+
return 0
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
echo ""
|
|
207
|
+
echo "============================================================"
|
|
208
|
+
echo " USAGE TRACKING SETUP"
|
|
209
|
+
echo "============================================================"
|
|
210
|
+
echo ""
|
|
211
|
+
echo "Devflow tracks your Claude Code usage across sessions."
|
|
212
|
+
echo "Since this is your first time, we need to set a baseline."
|
|
213
|
+
echo ""
|
|
214
|
+
echo "Options:"
|
|
215
|
+
echo " 1) Start fresh - Begin tracking from 0 (recommended for new billing periods)"
|
|
216
|
+
echo " 2) Set baseline - Enter your current usage from Claude Console"
|
|
217
|
+
echo ""
|
|
218
|
+
|
|
219
|
+
# Read user choice with timeout to prevent hanging
|
|
220
|
+
if read -r -t 5 -p "Choose an option [1/2]: " choice </dev/tty 2>/dev/null; then
|
|
221
|
+
case "$choice" in
|
|
222
|
+
2)
|
|
223
|
+
echo ""
|
|
224
|
+
echo "Enter your current token usage (e.g., 500000 or 500K or 1.5M):"
|
|
225
|
+
read -r -t 30 -p "Tokens: " token_input </dev/tty
|
|
226
|
+
|
|
227
|
+
# Parse token input (handle K/M suffixes)
|
|
228
|
+
BASELINE_TOKENS=$(echo "$token_input" | awk '{
|
|
229
|
+
gsub(/,/, "");
|
|
230
|
+
if (tolower($0) ~ /m$/) { gsub(/[mM]/, ""); print int($0 * 1000000) }
|
|
231
|
+
else if (tolower($0) ~ /k$/) { gsub(/[kK]/, ""); print int($0 * 1000) }
|
|
232
|
+
else { print int($0) }
|
|
233
|
+
}')
|
|
234
|
+
|
|
235
|
+
echo "Enter your current cost (e.g., 5.50):"
|
|
236
|
+
read -r -t 30 -p "Cost $: " cost_input </dev/tty
|
|
237
|
+
BASELINE_COST=$(echo "$cost_input" | sed 's/[$,]//g')
|
|
238
|
+
|
|
239
|
+
echo ""
|
|
240
|
+
echo "Setting baseline: ${BASELINE_TOKENS} tokens, \$${BASELINE_COST}"
|
|
241
|
+
;;
|
|
242
|
+
*)
|
|
243
|
+
BASELINE_TOKENS=0
|
|
244
|
+
BASELINE_COST=0
|
|
245
|
+
echo ""
|
|
246
|
+
echo "Starting fresh with 0 baseline."
|
|
247
|
+
;;
|
|
248
|
+
esac
|
|
249
|
+
else
|
|
250
|
+
# Timeout or no input - use defaults
|
|
251
|
+
BASELINE_TOKENS=0
|
|
252
|
+
BASELINE_COST=0
|
|
253
|
+
echo ""
|
|
254
|
+
echo "Starting fresh with 0 baseline (timeout)."
|
|
255
|
+
fi
|
|
256
|
+
|
|
257
|
+
# Save to config
|
|
258
|
+
TMP_CONFIG=$(mktemp)
|
|
259
|
+
jq --argjson tokens "$BASELINE_TOKENS" \
|
|
260
|
+
--argjson cost "$BASELINE_COST" \
|
|
261
|
+
--argjson configured true \
|
|
262
|
+
'.baseline_tokens = $tokens | .baseline_cost = $cost | .baseline_configured = $configured' \
|
|
263
|
+
"$COST_CONFIG" > "$TMP_CONFIG" 2>/dev/null && \
|
|
264
|
+
mv "$TMP_CONFIG" "$COST_CONFIG" 2>/dev/null || rm -f "$TMP_CONFIG"
|
|
265
|
+
|
|
266
|
+
echo ""
|
|
267
|
+
echo "[OK] Baseline configured. Your cumulative usage will now include this baseline."
|
|
268
|
+
echo "============================================================"
|
|
269
|
+
echo ""
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# Always run setup_baseline - it handles non-interactive mode internally
|
|
273
|
+
setup_baseline
|
|
274
|
+
|
|
275
|
+
# Check for active plans (multiple locations)
|
|
276
|
+
detect_plans() {
|
|
277
|
+
local found_plans=()
|
|
278
|
+
local plan_details=()
|
|
279
|
+
|
|
280
|
+
# Location 1: Devflow plans directory
|
|
281
|
+
if [ -d "$PLANS_DIR" ]; then
|
|
282
|
+
while IFS= read -r -d '' plan; do
|
|
283
|
+
found_plans+=("$plan")
|
|
284
|
+
name=$(basename "$plan" .md)
|
|
285
|
+
# Get first line as description
|
|
286
|
+
desc=$(head -1 "$plan" 2>/dev/null | sed 's/^#* *//' | cut -c1-50)
|
|
287
|
+
plan_details+=("$name: $desc")
|
|
288
|
+
done < <(find "$PLANS_DIR" -name "*.md" -type f -print0 2>/dev/null)
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
# Location 2: Claude Code plan files (look for plan.md or PLAN.md in project)
|
|
292
|
+
for plan_file in "$PROJECT_DIR/plan.md" "$PROJECT_DIR/PLAN.md" "$PROJECT_DIR/.claude/plan.md"; do
|
|
293
|
+
if [ -f "$plan_file" ]; then
|
|
294
|
+
found_plans+=("$plan_file")
|
|
295
|
+
name=$(basename "$plan_file" .md)
|
|
296
|
+
desc=$(head -1 "$plan_file" 2>/dev/null | sed 's/^#* *//' | cut -c1-50)
|
|
297
|
+
plan_details+=("$name: $desc")
|
|
298
|
+
fi
|
|
299
|
+
done
|
|
300
|
+
|
|
301
|
+
# Location 3: Check for recent plan mode files (Claude Code creates these)
|
|
302
|
+
if [ -d "$PROJECT_DIR/.claude" ]; then
|
|
303
|
+
while IFS= read -r -d '' plan; do
|
|
304
|
+
# Avoid duplicates
|
|
305
|
+
if [[ ! " ${found_plans[*]} " =~ " ${plan} " ]]; then
|
|
306
|
+
found_plans+=("$plan")
|
|
307
|
+
name=$(basename "$plan" .md)
|
|
308
|
+
modified=$(stat -f "%Sm" -t "%Y-%m-%d" "$plan" 2>/dev/null || stat -c "%y" "$plan" 2>/dev/null | cut -d' ' -f1)
|
|
309
|
+
plan_details+=("$name ($modified)")
|
|
310
|
+
fi
|
|
311
|
+
done < <(find "$PROJECT_DIR/.claude" -maxdepth 2 -name "*plan*.md" -type f -print0 2>/dev/null)
|
|
312
|
+
fi
|
|
313
|
+
|
|
314
|
+
# Output results
|
|
315
|
+
local count=${#found_plans[@]}
|
|
316
|
+
if [ "$count" -gt 0 ]; then
|
|
317
|
+
echo "[PLANS] Found $count plan(s):"
|
|
318
|
+
for detail in "${plan_details[@]}"; do
|
|
319
|
+
echo " - $detail"
|
|
320
|
+
done
|
|
321
|
+
echo ""
|
|
322
|
+
else
|
|
323
|
+
echo "[PLANS] No saved plans found"
|
|
324
|
+
echo ""
|
|
325
|
+
fi
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
detect_plans
|
|
329
|
+
|
|
330
|
+
# Check for recent sessions
|
|
331
|
+
if [ -d "$SESSIONS_DIR" ]; then
|
|
332
|
+
recent=$(ls -t "$SESSIONS_DIR" 2>/dev/null | head -1)
|
|
333
|
+
if [ -n "$recent" ]; then
|
|
334
|
+
echo "[SESSIONS] Most recent session: $recent"
|
|
335
|
+
# Try to extract story key from session file
|
|
336
|
+
if command -v jq >/dev/null 2>&1; then
|
|
337
|
+
if [ -f "$SESSIONS_DIR/$recent" ]; then
|
|
338
|
+
story_key=$(jq -r '.story_key // empty' "$SESSIONS_DIR/$recent" 2>/dev/null)
|
|
339
|
+
if [ -n "$story_key" ]; then
|
|
340
|
+
echo " Story: $story_key"
|
|
341
|
+
fi
|
|
342
|
+
fi
|
|
343
|
+
fi
|
|
344
|
+
echo ""
|
|
345
|
+
fi
|
|
346
|
+
fi
|
|
347
|
+
|
|
348
|
+
# Check for shared memory/knowledge
|
|
349
|
+
if [ -d "$MEMORY_DIR/shared" ]; then
|
|
350
|
+
count=$(find "$MEMORY_DIR/shared" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
351
|
+
if [ "$count" -gt 0 ]; then
|
|
352
|
+
echo "[MEMORY] $count shared memory file(s) available"
|
|
353
|
+
echo " Use /memory to view knowledge graph"
|
|
354
|
+
echo ""
|
|
355
|
+
fi
|
|
356
|
+
fi
|
|
357
|
+
|
|
358
|
+
# Check for context state
|
|
359
|
+
if [ -d "$CONTEXT_DIR" ]; then
|
|
360
|
+
ctx_count=$(find "$CONTEXT_DIR" -name "context_*.json" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
361
|
+
if [ "$ctx_count" -gt 0 ]; then
|
|
362
|
+
echo "[CONTEXT] Previous context state available"
|
|
363
|
+
find "$CONTEXT_DIR" -name "context_*.json" -type f 2>/dev/null | while read -r ctx; do
|
|
364
|
+
name=$(basename "$ctx" .json | sed 's/context_//')
|
|
365
|
+
if command -v jq >/dev/null 2>&1; then
|
|
366
|
+
usage=$(jq -r '.estimated_context_tokens // 0' "$ctx" 2>/dev/null)
|
|
367
|
+
if [ "$usage" != "0" ] && [ -n "$usage" ]; then
|
|
368
|
+
echo " - $name: ~$usage tokens"
|
|
369
|
+
fi
|
|
370
|
+
else
|
|
371
|
+
echo " - $name"
|
|
372
|
+
fi
|
|
373
|
+
done
|
|
374
|
+
echo ""
|
|
375
|
+
fi
|
|
376
|
+
fi
|
|
377
|
+
|
|
378
|
+
# ============================================================================
|
|
379
|
+
# STATUS BAR PREVIEW
|
|
380
|
+
# ============================================================================
|
|
381
|
+
|
|
382
|
+
# Build status bar preview
|
|
383
|
+
STATUS_BAR=""
|
|
384
|
+
|
|
385
|
+
# Extract model from input
|
|
386
|
+
MODEL=$(echo "$INPUT" | jq -r '.model.display_name // .model.name // .model // "Unknown"' 2>/dev/null)
|
|
387
|
+
|
|
388
|
+
# Get subscription info
|
|
389
|
+
if [ -f "$COST_CONFIG" ]; then
|
|
390
|
+
SUB_PLAN=$(jq -r '.subscription_plan // ""' "$COST_CONFIG" 2>/dev/null)
|
|
391
|
+
TOKEN_LIMIT=$(jq -r '.subscription_token_limit // 0' "$COST_CONFIG" 2>/dev/null)
|
|
392
|
+
|
|
393
|
+
if [ -n "$SUB_PLAN" ] && [ "$TOKEN_LIMIT" -gt 0 ] 2>/dev/null; then
|
|
394
|
+
USAGE_PCT=$(echo "scale=1; ($CUM_TOKENS * 100) / $TOKEN_LIMIT" | bc 2>/dev/null || echo "0")
|
|
395
|
+
|
|
396
|
+
# Color based on usage
|
|
397
|
+
if (( $(echo "$USAGE_PCT >= 90" | bc -l 2>/dev/null || echo 0) )); then
|
|
398
|
+
COLOR="\033[31m" # Red
|
|
399
|
+
elif (( $(echo "$USAGE_PCT >= 75" | bc -l 2>/dev/null || echo 0) )); then
|
|
400
|
+
COLOR="\033[33m" # Yellow
|
|
401
|
+
else
|
|
402
|
+
COLOR="\033[32m" # Green
|
|
403
|
+
fi
|
|
404
|
+
RESET="\033[0m"
|
|
405
|
+
|
|
406
|
+
TOKEN_LIMIT_FMT=$(format_tokens "$TOKEN_LIMIT")
|
|
407
|
+
STATUS_BAR="[Devflow] $MODEL | ${COLOR}Usage: ${USAGE_PCT}% (${CUM_TOKENS_FMT}/${TOKEN_LIMIT_FMT})${RESET} | Cost: \$${CUM_COST_FMT}"
|
|
408
|
+
else
|
|
409
|
+
STATUS_BAR="[Devflow] $MODEL | Tokens: ${CUM_TOKENS_FMT} | Cost: \$${CUM_COST_FMT}"
|
|
410
|
+
fi
|
|
411
|
+
else
|
|
412
|
+
STATUS_BAR="[Devflow] $MODEL | Tokens: ${CUM_TOKENS_FMT} | Cost: \$${CUM_COST_FMT}"
|
|
413
|
+
fi
|
|
414
|
+
|
|
415
|
+
echo "---"
|
|
416
|
+
echo -e "$STATUS_BAR"
|
|
417
|
+
echo "---"
|
|
418
|
+
echo ""
|
|
419
|
+
|
|
420
|
+
# Quick tips
|
|
421
|
+
echo "[QUICK START]"
|
|
422
|
+
echo " /story <key> - Run full story pipeline"
|
|
423
|
+
echo " /develop - Development phase only"
|
|
424
|
+
echo " /review - Code review only"
|
|
425
|
+
echo " /costs - View cost dashboard"
|
|
426
|
+
|
|
427
|
+
exit 0
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Session Stop Hook - Saves session cost data when Claude Code stops
|
|
3
|
+
|
|
4
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
5
|
+
TRACKER="$PROJECT_DIR/.claude/hooks/session_tracker.py"
|
|
6
|
+
|
|
7
|
+
# Read input from Claude Code (contains stop reason, transcript summary)
|
|
8
|
+
INPUT=$(cat)
|
|
9
|
+
|
|
10
|
+
# Extract token info if available from the stop event
|
|
11
|
+
# The stop event may contain usage statistics
|
|
12
|
+
INPUT_TOKENS=$(echo "$INPUT" | jq -r '.usage.input_tokens // .transcript_summary.input_tokens // 0' 2>/dev/null)
|
|
13
|
+
OUTPUT_TOKENS=$(echo "$INPUT" | jq -r '.usage.output_tokens // .transcript_summary.output_tokens // 0' 2>/dev/null)
|
|
14
|
+
MODEL=$(echo "$INPUT" | jq -r '.model // ""' 2>/dev/null)
|
|
15
|
+
|
|
16
|
+
# Log final usage if we have token data
|
|
17
|
+
if [ "$INPUT_TOKENS" -gt 0 ] 2>/dev/null || [ "$OUTPUT_TOKENS" -gt 0 ] 2>/dev/null; then
|
|
18
|
+
if [ -n "$MODEL" ]; then
|
|
19
|
+
python3 "$TRACKER" log --input "$INPUT_TOKENS" --output "$OUTPUT_TOKENS" --model "$MODEL" 2>/dev/null
|
|
20
|
+
else
|
|
21
|
+
python3 "$TRACKER" log --input "$INPUT_TOKENS" --output "$OUTPUT_TOKENS" 2>/dev/null
|
|
22
|
+
fi
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# End the session and save
|
|
26
|
+
RESULT=$(python3 "$TRACKER" end 2>/dev/null)
|
|
27
|
+
|
|
28
|
+
# Output summary if session had activity
|
|
29
|
+
SAVED=$(echo "$RESULT" | jq -r '.saved // false' 2>/dev/null)
|
|
30
|
+
TOKENS=$(echo "$RESULT" | jq -r '.total_tokens // 0' 2>/dev/null)
|
|
31
|
+
COST=$(echo "$RESULT" | jq -r '.cost_usd // 0' 2>/dev/null)
|
|
32
|
+
|
|
33
|
+
if [ "$SAVED" = "true" ] 2>/dev/null; then
|
|
34
|
+
echo ""
|
|
35
|
+
echo "[SESSION SAVED] Tokens: $TOKENS | Cost: \$$COST"
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
exit 0
|