@automagik/genie 4.260411.2 → 4.260414.2
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-plugin/marketplace.json +1 -1
- package/.genie/agents/metrics-updater/AGENT.md +129 -13
- package/.genie/agents/metrics-updater/author-aliases.json +9 -0
- package/.genie/agents/metrics-updater/daily-stats.jsonl +33 -0
- package/.genie/agents/metrics-updater/runs.jsonl +6 -0
- package/.genie/agents/metrics-updater/state.json +10 -6
- package/.genie/agents/metrics-updater/tools/backfill.sh +54 -0
- package/.genie/agents/metrics-updater/tools/collect-stats.sh +132 -0
- package/.genie/agents/metrics-updater/tools/generate-charts.py +224 -0
- package/.genie/agents/metrics-updater/tools/generate-readme-hero.py +137 -0
- package/.genie/agents/metrics-updater/tools/generate-velocity.py +378 -0
- package/.genie/agents/metrics-updater/tools/run-metrics.sh +150 -232
- package/.genie/assets/commits-30d.svg +43 -0
- package/.genie/assets/loc-30d.svg +75 -0
- package/.genie/assets/releases-30d.svg +43 -0
- package/.genie/brainstorms/README.md +1 -0
- package/.genie/brainstorms/brainstorm-links-convention/DESIGN.md +69 -0
- package/.genie/brainstorms/velocity-dashboard/DESIGN.md +160 -0
- package/.genie/brainstorms/velocity-dashboard/DRAFT.md +28 -0
- package/.genie/brainstorms/workflow-engine-runtime/DESIGN.md +66 -0
- package/.genie/wishes/_archive/agent-stability-hardening/WISH.md +1 -1
- package/.genie/wishes/_archive/brain-identity-impl/WISH.md +1 -1
- package/.genie/wishes/_archive/genie-app/WISH.md +1 -1
- package/.genie/wishes/_archive/genie-layout-migration/WISH.md +1 -1
- package/.genie/wishes/_archive/genie-model-resolution/WISH.md +3 -3
- package/.genie/wishes/_archive/genie-onboarding-flow/WISH.md +3 -3
- package/.genie/wishes/_archive/omni-skill-upgrade/WISH.md +1 -1
- package/.genie/wishes/_archive/omni-version-unify/WISH.md +1 -1
- package/.genie/wishes/_archive/rlmx-v02/WISH.md +1 -1
- package/.genie/wishes/_archive/rlmx-v03-cag/WISH.md +1 -1
- package/.genie/wishes/_archive/rlmx-v04-gemini3/WISH.md +1 -1
- package/.genie/wishes/_archive/v4-database-layer/WISH.md +1 -1
- package/.genie/wishes/_archive/v4-hook-cli-safety/WISH.md +1 -1
- package/.genie/wishes/_archive/v4-message-routing/WISH.md +1 -1
- package/.genie/wishes/_archive/v4-session-executor/WISH.md +1 -1
- package/.genie/wishes/_archive/v4-spawn-resilience/WISH.md +1 -1
- package/.genie/wishes/_archive/v4-team-lifecycle/WISH.md +1 -1
- package/.genie/wishes/_archive/velocity-dashboard/WISH.md +272 -0
- package/.genie/wishes/brain-cag-v2-polish/WISH.md +1 -1
- package/.genie/wishes/brainstorm-links-convention/WISH.md +375 -0
- package/.genie/wishes/crew-simplification/WISH.md +1 -1
- package/.genie/wishes/genie-simulations/WISH.md +1 -1
- package/.genie/wishes/sac-agent/WISH.md +1 -1
- package/.genie/wishes/security-key-leak-remediation/WISH.md +198 -0
- package/.genie/wishes/x-tool/WISH.md +1 -1
- package/.github/workflows/version.yml +2 -2
- package/README.md +3 -9
- package/VELOCITY.md +44 -0
- package/dist/genie.js +145 -145
- package/package.json +3 -2
- package/plugins/genie/.claude-plugin/plugin.json +1 -1
- package/plugins/genie/package.json +1 -1
- package/scripts/wishes-lint.ts +116 -0
- package/skills/brainstorm/SKILL.md +8 -2
- package/skills/wish/SKILL.md +14 -0
- package/src/genie.ts +23 -2
- package/src/lib/db-backup.test.ts +26 -12
- package/src/lib/db-backup.ts +26 -5
- package/src/services/__tests__/omni-bridge.test.ts +34 -1
- package/src/services/omni-bridge.ts +7 -3
- package/src/tui/components/Nav.tsx +2 -2
- package/src/tui/diagnostics.ts +16 -0
- package/src/tui/session-tree.test.ts +21 -1
- package/src/tui/session-tree.ts +4 -0
- package/.genie/agents/metrics-updater/tools/batch-commit.sh +0 -38
- package/.genie/agents/metrics-updater/tools/cached-fetch.sh +0 -86
- package/.genie/agents/metrics-updater/tools/commit-formatter.sh +0 -27
- package/.genie/agents/metrics-updater/tools/fast-parse.py +0 -92
- package/.genie/agents/metrics-updater/tools/generate-tools.py +0 -419
- package/.genie/agents/metrics-updater/tools/github-api.sh +0 -100
- package/.genie/agents/metrics-updater/tools/parse-metrics.py +0 -282
- package/.genie/agents/metrics-updater/tools/perf-analyzer.py +0 -248
- package/.genie/agents/metrics-updater/tools/self-refine.sh +0 -133
- package/.genie/agents/metrics-updater/tools/update-readme.py +0 -120
- package/.genie/snapshot.sql.gz +0 -0
- /package/.genie/wishes/{brain-help-passthrough → _archive/brain-help-passthrough}/WISH.md +0 -0
- /package/.genie/wishes/{fix-ghost-approval-p0 → _archive/fix-ghost-approval-p0}/REPRO.md +0 -0
- /package/.genie/wishes/{fix-ghost-approval-p0 → _archive/fix-ghost-approval-p0}/WISH.md +0 -0
- /package/.genie/wishes/{perfect-spawn-hierarchy → _archive/perfect-spawn-hierarchy}/WISH.md +0 -0
- /package/.genie/wishes/{scaffold-auto-memory → _archive/scaffold-auto-memory}/WISH.md +0 -0
- /package/.genie/wishes/{unify-bridge-revamp-skills → _archive/unify-bridge-revamp-skills}/WISH.md +0 -0
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "genie",
|
|
13
|
-
"version": "4.
|
|
13
|
+
"version": "4.260414.2",
|
|
14
14
|
"source": "./plugins/genie",
|
|
15
15
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, wish them into plans, make with parallel agents, ship as one team. A coding genie that grows with your project."
|
|
16
16
|
}
|
|
@@ -1,29 +1,145 @@
|
|
|
1
1
|
# metrics-updater Agent
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Autonomous velocity dashboard agent. Collects git-based metrics, generates SVG charts, builds VELOCITY.md and README hero line. Runs daily on `dev` branch.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
7
|
+
```bash
|
|
8
|
+
cd "$(git rev-parse --show-toplevel)"
|
|
9
|
+
bash .genie/agents/metrics-updater/tools/run-metrics.sh # Full run: collect, chart, publish, commit
|
|
10
|
+
bash .genie/agents/metrics-updater/tools/run-metrics.sh --dry-run # Generate all outputs without commit/push
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Pipeline Steps
|
|
14
|
+
|
|
15
|
+
| Step | Tool | Input | Output | Exit 0 |
|
|
16
|
+
|------|------|-------|--------|--------|
|
|
17
|
+
| 1. Collect today | `collect-stats.sh --date YYYY-MM-DD` | git history | JSON line → `daily-stats.jsonl` | Stats appended |
|
|
18
|
+
| 2. Backfill | `backfill.sh` (if <30 entries) | git history (30d) | `daily-stats.jsonl` filled | 30+ entries |
|
|
19
|
+
| 3. Charts | `generate-charts.py --input ... --output-dir ...` | `daily-stats.jsonl` | `.genie/assets/*.svg` (3 files) | SVGs written |
|
|
20
|
+
| 4. Dashboard | `generate-velocity.py --stats-dir ... --output ...` | `daily-stats.jsonl` + cumulative | `VELOCITY.md` | File written |
|
|
21
|
+
| 5. README hero | `generate-readme-hero.py --stats-dir ... --readme ...` | `daily-stats.jsonl` | `README.md` updated | Markers replaced |
|
|
22
|
+
| 6. Commit + push | git add/commit/push | Changed files | Commit on `dev` | Pushed |
|
|
23
|
+
| 7. State update | inline python | Run results | `state.json` + `runs.jsonl` | State persisted |
|
|
24
|
+
|
|
25
|
+
## Tool Inventory
|
|
26
|
+
|
|
27
|
+
### `collect-stats.sh`
|
|
28
|
+
- **`--date YYYY-MM-DD`**: Extract single-day metrics from git history (all branches). Returns JSON with `date`, `commits`, `loc_added`, `loc_removed`, `releases`, `contributors`.
|
|
29
|
+
- **`--cumulative`**: Returns all-time totals: `total_commits`, `total_tags`, `first_commit_date`, `total_contributors`.
|
|
30
|
+
- Release detection: tags matching `v4.YYMMDD.*` pattern.
|
|
31
|
+
|
|
32
|
+
### `backfill.sh`
|
|
33
|
+
- **`--days N`** (default: 30): Runs `collect-stats.sh` for each of the last N days, writes `daily-stats.jsonl`.
|
|
34
|
+
- Clears and rebuilds the entire file. Safe to re-run.
|
|
11
35
|
|
|
12
|
-
|
|
36
|
+
### `generate-charts.py`
|
|
37
|
+
- **`--input PATH`**: Path to `daily-stats.jsonl`.
|
|
38
|
+
- **`--output-dir DIR`**: Directory for SVG output (created if missing).
|
|
39
|
+
- **`--sample`**: Use generated sample data (for testing).
|
|
40
|
+
- Produces: `commits-30d.svg`, `releases-30d.svg`, `loc-30d.svg`.
|
|
41
|
+
- Dark theme (#0d1117), 800x200px, no external fonts or deps.
|
|
13
42
|
|
|
14
|
-
|
|
43
|
+
### `generate-velocity.py`
|
|
44
|
+
- **`--stats-dir DIR`**: Directory containing `daily-stats.jsonl` and `author-aliases.json`.
|
|
45
|
+
- **`--assets-dir PATH`**: Relative path for SVG image links in markdown.
|
|
46
|
+
- **`--output PATH`**: Output path for `VELOCITY.md`.
|
|
47
|
+
- Calls `collect-stats.sh --cumulative` internally for all-time numbers.
|
|
15
48
|
|
|
16
|
-
|
|
49
|
+
### `generate-readme-hero.py`
|
|
50
|
+
- **`--stats-dir DIR`**: Directory containing `daily-stats.jsonl` and `author-aliases.json`.
|
|
51
|
+
- **`--readme PATH`**: Path to README.md.
|
|
52
|
+
- Replaces content between `<!-- METRICS:START -->` and `<!-- METRICS:END -->` markers.
|
|
53
|
+
|
|
54
|
+
### `run-metrics.sh` (orchestrator)
|
|
55
|
+
- **`--dry-run`**: Run full pipeline but skip git commit/push.
|
|
56
|
+
- Calls all tools in sequence, handles backfill decision, updates state.
|
|
57
|
+
|
|
58
|
+
## Data Files
|
|
59
|
+
|
|
60
|
+
| File | Format | Purpose |
|
|
61
|
+
|------|--------|---------|
|
|
62
|
+
| `daily-stats.jsonl` | JSONL | One JSON object per day, last 30+ days of metrics |
|
|
63
|
+
| `state.json` | JSON | Last run status, stats count, charts generated |
|
|
64
|
+
| `runs.jsonl` | JSONL | Append-only log of every run with step timings |
|
|
65
|
+
| `author-aliases.json` | JSON | Git author name normalization map |
|
|
66
|
+
|
|
67
|
+
## Author Aliases
|
|
68
|
+
|
|
69
|
+
`author-aliases.json` maps variant git author names to canonical names:
|
|
70
|
+
```json
|
|
71
|
+
{"felipe": "Felipe Rosa", "filipexyz": "Felipe Rosa", "genie": "Genie"}
|
|
72
|
+
```
|
|
73
|
+
Edit this file to add new aliases. Used by `generate-velocity.py` and `generate-readme-hero.py`.
|
|
17
74
|
|
|
18
75
|
## Commit Convention
|
|
19
76
|
|
|
20
77
|
```
|
|
21
|
-
chore: update live metrics (
|
|
78
|
+
chore: update live metrics (N commits, N releases, +N/-N LoC)
|
|
22
79
|
```
|
|
23
80
|
|
|
24
81
|
Push to `dev` branch only. Never push to `main`.
|
|
25
82
|
|
|
26
|
-
##
|
|
83
|
+
## Error Handling
|
|
27
84
|
|
|
28
|
-
|
|
29
|
-
|
|
85
|
+
| Condition | Behavior |
|
|
86
|
+
|-----------|----------|
|
|
87
|
+
| `git` unavailable | `collect-stats.sh` exits 1, pipeline aborts |
|
|
88
|
+
| `daily-stats.jsonl` missing | Backfill runs automatically |
|
|
89
|
+
| `daily-stats.jsonl` < 30 entries | Backfill runs automatically |
|
|
90
|
+
| Chart generation fails | Pipeline aborts with error in `runs.jsonl` |
|
|
91
|
+
| README missing METRICS markers | `generate-readme-hero.py` exits 1 |
|
|
92
|
+
| `author-aliases.json` missing | Aliases ignored, raw git names used |
|
|
93
|
+
| No changes to commit | Commit step skipped, run logged as success |
|
|
94
|
+
| Push fails | Logged as error, run continues |
|
|
95
|
+
|
|
96
|
+
## Backfill Decision Tree
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
daily-stats.jsonl exists?
|
|
100
|
+
NO → backfill.sh (creates file with 30 days)
|
|
101
|
+
YES → count entries
|
|
102
|
+
< 30 → backfill.sh (rebuilds with 30 days)
|
|
103
|
+
>= 30 → skip backfill, append today only
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Self-Diagnosis Checklist
|
|
107
|
+
|
|
108
|
+
If output looks wrong, check in order:
|
|
109
|
+
|
|
110
|
+
1. **No commits showing**: Run `git log --all --oneline | head -5` — is git history accessible?
|
|
111
|
+
2. **0 releases**: Run `git tag -l "v4.*" | head -5` — are v4.YYMMDD.* tags present?
|
|
112
|
+
3. **Stale data**: Check `daily-stats.jsonl` dates — is today's entry present?
|
|
113
|
+
4. **Wrong contributor names**: Check `author-aliases.json` — missing alias?
|
|
114
|
+
5. **Charts empty**: Check `daily-stats.jsonl` — are values all zero?
|
|
115
|
+
6. **README not updated**: Check for `<!-- METRICS:START -->` and `<!-- METRICS:END -->` markers.
|
|
116
|
+
7. **State not persisted**: Check `state.json` — does it have `daily_stats_count`?
|
|
117
|
+
|
|
118
|
+
## State Schema
|
|
119
|
+
|
|
120
|
+
### state.json
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"last_run": "2026-04-12T00:00:00Z",
|
|
124
|
+
"last_run_status": "success",
|
|
125
|
+
"daily_stats_count": 31,
|
|
126
|
+
"charts_generated": 3,
|
|
127
|
+
"velocity_md_updated": true,
|
|
128
|
+
"duration_ms": 12345
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### runs.jsonl (each line)
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"timestamp": "2026-04-12T00:00:00Z",
|
|
136
|
+
"duration_ms": 12345,
|
|
137
|
+
"status": "success",
|
|
138
|
+
"dry_run": false,
|
|
139
|
+
"daily_stats_count": 31,
|
|
140
|
+
"charts_generated": 3,
|
|
141
|
+
"velocity_md_updated": true,
|
|
142
|
+
"errors": [],
|
|
143
|
+
"steps": [{"name": "collect_stats", "duration_ms": 500}, ...]
|
|
144
|
+
}
|
|
145
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{"date":"2026-03-13","commits":13,"loc_added":6920,"loc_removed":2948,"releases":0,"contributors":["Genie","Test","Test User"]}
|
|
2
|
+
{"date":"2026-03-14","commits":45,"loc_added":2761,"loc_removed":5243,"releases":0,"contributors":["Felipe Rosa","Test User","github-actions[bot]"]}
|
|
3
|
+
{"date":"2026-03-15","commits":14,"loc_added":3552,"loc_removed":3096,"releases":0,"contributors":["Automagik Genie 🧞","Felipe Rosa","Test User","github-actions[bot]"]}
|
|
4
|
+
{"date":"2026-03-16","commits":82,"loc_added":11464,"loc_removed":10990,"releases":0,"contributors":["Felipe Rosa","Test User","clawtom","github-actions[bot]"]}
|
|
5
|
+
{"date":"2026-03-17","commits":86,"loc_added":6482,"loc_removed":1928,"releases":0,"contributors":["Felipe Rosa","Genie","Test","Test User","github-actions[bot]"]}
|
|
6
|
+
{"date":"2026-03-18","commits":41,"loc_added":789,"loc_removed":4077,"releases":0,"contributors":["Felipe Rosa","Genie","github-actions[bot]"]}
|
|
7
|
+
{"date":"2026-03-19","commits":5,"loc_added":1183,"loc_removed":202,"releases":0,"contributors":["Felipe Rosa","Genie","Luís","github-actions[bot]"]}
|
|
8
|
+
{"date":"2026-03-20","commits":15,"loc_added":10671,"loc_removed":234,"releases":0,"contributors":["Felipe Rosa","Genie","Luís Sousa"]}
|
|
9
|
+
{"date":"2026-03-21","commits":8,"loc_added":609,"loc_removed":436,"releases":0,"contributors":["Felipe Rosa","Genie","Luís Sousa"]}
|
|
10
|
+
{"date":"2026-03-22","commits":46,"loc_added":4065,"loc_removed":1256,"releases":0,"contributors":["Felipe Rosa","Genie","Luís Sousa"]}
|
|
11
|
+
{"date":"2026-03-23","commits":33,"loc_added":7093,"loc_removed":2792,"releases":5,"contributors":["Felipe Rosa","Genie","github-actions[bot]"]}
|
|
12
|
+
{"date":"2026-03-24","commits":66,"loc_added":6248,"loc_removed":888,"releases":20,"contributors":["Automagik Genie 🧞","Felipe Rosa","Genie","github-actions[bot]"]}
|
|
13
|
+
{"date":"2026-03-25","commits":133,"loc_added":16626,"loc_removed":3927,"releases":34,"contributors":["Automagik Genie 🧞","Claude","Felipe Rosa","Genie","github-actions[bot]"]}
|
|
14
|
+
{"date":"2026-03-26","commits":17,"loc_added":627,"loc_removed":177,"releases":3,"contributors":["Felipe Rosa","Genie","github-actions[bot]"]}
|
|
15
|
+
{"date":"2026-03-27","commits":32,"loc_added":6836,"loc_removed":5629,"releases":7,"contributors":["Felipe Rosa","Genie","Luís","github-actions[bot]"]}
|
|
16
|
+
{"date":"2026-03-28","commits":42,"loc_added":23738,"loc_removed":2763,"releases":15,"contributors":["Claude","Felipe Rosa","Genie","Luís","github-actions[bot]"]}
|
|
17
|
+
{"date":"2026-03-29","commits":84,"loc_added":12534,"loc_removed":2379,"releases":33,"contributors":["Claude","Felipe Rosa","Genie","github-actions[bot]"]}
|
|
18
|
+
{"date":"2026-03-30","commits":100,"loc_added":5574,"loc_removed":2602,"releases":26,"contributors":["Claude","Felipe Rosa","Genie","github-actions[bot]"]}
|
|
19
|
+
{"date":"2026-03-31","commits":76,"loc_added":4503,"loc_removed":5663,"releases":20,"contributors":["Cezar Vasconcelos","Claude","Felipe Rosa","Genie","Luís","Luís Sousa","github-actions[bot]"]}
|
|
20
|
+
{"date":"2026-04-01","commits":58,"loc_added":3754,"loc_removed":842,"releases":6,"contributors":["Claude","Felipe Rosa","Genie","Test","github-actions[bot]"]}
|
|
21
|
+
{"date":"2026-04-02","commits":84,"loc_added":3484,"loc_removed":1136,"releases":20,"contributors":["Claude","Felipe Rosa","Genie","Luís Sousa","Test","github-actions[bot]"]}
|
|
22
|
+
{"date":"2026-04-03","commits":42,"loc_added":2187,"loc_removed":338,"releases":4,"contributors":["Automagik Genie 🧞","Claude","Felipe Rosa","Genie","Test","Zakir Jiwani","github-actions[bot]"]}
|
|
23
|
+
{"date":"2026-04-04","commits":58,"loc_added":10390,"loc_removed":649,"releases":2,"contributors":["Claude","Felipe Rosa","Genie","Test","filipexyz","github-actions[bot]"]}
|
|
24
|
+
{"date":"2026-04-05","commits":109,"loc_added":22624,"loc_removed":2611,"releases":16,"contributors":["Claude","Felipe Rosa","Test","github-actions[bot]"]}
|
|
25
|
+
{"date":"2026-04-06","commits":28,"loc_added":1745,"loc_removed":225,"releases":5,"contributors":["Claude","Felipe Rosa","Test","github-actions[bot]"]}
|
|
26
|
+
{"date":"2026-04-07","commits":35,"loc_added":3865,"loc_removed":208,"releases":7,"contributors":["Cezar Vasconcelos","Claude","Felipe Rosa","Genie","Test","github-actions[bot]"]}
|
|
27
|
+
{"date":"2026-04-08","commits":35,"loc_added":3780,"loc_removed":2109,"releases":5,"contributors":["Claude","Felipe Rosa","Genie","filipexyz","genie","github-actions[bot]"]}
|
|
28
|
+
{"date":"2026-04-09","commits":73,"loc_added":9761,"loc_removed":1253,"releases":14,"contributors":["Felipe Rosa","Genie","Luís","Test","filipexyz","genie","github-actions[bot]"]}
|
|
29
|
+
{"date":"2026-04-10","commits":37,"loc_added":34969,"loc_removed":205,"releases":5,"contributors":["Felipe Rosa","Genie","Test","felipe","github-actions[bot]"]}
|
|
30
|
+
{"date":"2026-04-11","commits":12,"loc_added":81,"loc_removed":38,"releases":3,"contributors":["Claude","Felipe Rosa","genie","github-actions[bot]"]}
|
|
31
|
+
{"date":"2026-04-12","commits":14,"loc_added":2754,"loc_removed":3653,"releases":1,"contributors":["Claude","Felipe Rosa","Test","genie","github-actions[bot]"]}
|
|
32
|
+
{"date":"2026-04-13","commits":14,"loc_added":668,"loc_removed":70,"releases":0,"contributors":["Claude","Felipe Rosa","genie","github-actions[bot]"]}
|
|
33
|
+
{"date":"2026-04-14","commits":0,"loc_added":0,"loc_removed":0,"releases":0,"contributors":[]}
|
|
@@ -22,3 +22,9 @@
|
|
|
22
22
|
{"timestamp":"2026-04-07T12:04:30Z","duration_ms":27000,"api_calls":0,"tools_generated":0,"errors":["gh CLI not available","no GitHub token or MCP GitHub tools present in session"],"status":"failed","fallback":false,"metrics":null}
|
|
23
23
|
{"timestamp":"2026-04-08T00:00:00.000Z","duration_ms":18000,"api_calls":0,"tools_generated":0,"errors":["gh CLI not available","GitHub MCP tools not present in session","fallback data older than current README — README update skipped"],"status":"failed","fallback":false,"metrics":null}
|
|
24
24
|
{"timestamp":"2026-04-11T12:35:40Z","duration_ms":72153,"api_calls":0,"tools_generated":0,"errors":["gh CLI not available","GitHub MCP tools not present in session"],"status":"success","fallback":true,"metrics":{"releases_24h":2,"merged_prs_7d":35,"avg_merge_time_h":0.3,"ship_rate_pct":85}}
|
|
25
|
+
{"timestamp":"2026-04-12T00:00:00.000Z","duration_ms":30000,"api_calls":2,"tools_generated":0,"errors":[],"status":"success","fallback":false,"metrics":{"releases_24h":0,"merged_prs_7d":5,"avg_merge_time_h":2.5,"ship_rate_pct":100}}
|
|
26
|
+
{"timestamp": "2026-04-12T18:38:51Z", "duration_ms": 732, "status": "success", "dry_run": true, "daily_stats_count": 31, "charts_generated": 3, "velocity_md_updated": true, "errors": [], "steps": [{"name": "collect_stats", "duration_ms": 93}, {"name": "backfill_check", "duration_ms": 22}, {"name": "generate_charts", "duration_ms": 62}, {"name": "generate_velocity", "duration_ms": 336}, {"name": "generate_readme", "duration_ms": 66}, {"name": "commit_push", "duration_ms": 19}]}
|
|
27
|
+
{"timestamp": "2026-04-12T19:41:00Z", "duration_ms": 817, "status": "success", "dry_run": true, "daily_stats_count": 31, "charts_generated": 3, "velocity_md_updated": true, "errors": [], "steps": [{"name": "collect_stats", "duration_ms": 110}, {"name": "backfill_check", "duration_ms": 22}, {"name": "generate_charts", "duration_ms": 68}, {"name": "generate_velocity", "duration_ms": 372}, {"name": "generate_readme", "duration_ms": 73}, {"name": "commit_push", "duration_ms": 20}]}
|
|
28
|
+
{"timestamp":"2026-04-13T00:00:00.000Z","duration_ms":45000,"api_calls":2,"tools_generated":0,"errors":[],"status":"success","fallback":false,"metrics":{"releases_24h":0,"merged_prs_7d":9,"avg_merge_time_h":1.4,"ship_rate_pct":100}}
|
|
29
|
+
{"timestamp": "2026-04-14T12:09:00Z", "duration_ms": 1264, "status": "success", "dry_run": true, "daily_stats_count": 33, "charts_generated": 3, "velocity_md_updated": true, "errors": [], "steps": [{"name": "collect_stats", "duration_ms": 216}, {"name": "backfill_check", "duration_ms": 47}, {"name": "generate_charts", "duration_ms": 158}, {"name": "generate_velocity", "duration_ms": 359}, {"name": "generate_readme", "duration_ms": 159}, {"name": "commit_push", "duration_ms": 33}]}
|
|
30
|
+
{"timestamp": "2026-04-14T12:09:00Z", "duration_ms": 1576, "api_calls": 2, "tools_generated": 3, "errors": [], "metrics": {"releases_24h": 1, "merged_prs_7d": 12, "avg_merge_time_h": 10.4, "ship_rate_pct": 100, "git_commits_7d": 185, "git_releases_7d": 28, "git_loc_net_7d": 44700, "git_contributors_7d": 6, "daily_stats_count": 33, "charts_generated": 3}}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"last_run": "2026-04-
|
|
2
|
+
"last_run": "2026-04-14T12:09:00Z",
|
|
3
3
|
"last_run_status": "success",
|
|
4
4
|
"last_metrics": {
|
|
5
|
-
"releases_24h":
|
|
6
|
-
"merged_prs_7d":
|
|
7
|
-
"avg_merge_time_h":
|
|
8
|
-
"ship_rate_pct":
|
|
9
|
-
}
|
|
5
|
+
"releases_24h": 1,
|
|
6
|
+
"merged_prs_7d": 12,
|
|
7
|
+
"avg_merge_time_h": 10.4,
|
|
8
|
+
"ship_rate_pct": 100
|
|
9
|
+
},
|
|
10
|
+
"daily_stats_count": 33,
|
|
11
|
+
"charts_generated": 3,
|
|
12
|
+
"velocity_md_updated": true,
|
|
13
|
+
"duration_ms": 1576
|
|
10
14
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# backfill.sh — Run collect-stats.sh for the last 30 days, write daily-stats.jsonl.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# backfill.sh [--days N] Backfill N days (default: 30)
|
|
6
|
+
#
|
|
7
|
+
# Output: daily-stats.jsonl in the metrics-updater agent directory.
|
|
8
|
+
#
|
|
9
|
+
# daily-stats.jsonl schema (one JSON object per line):
|
|
10
|
+
# {
|
|
11
|
+
# "date": "YYYY-MM-DD", // Calendar date
|
|
12
|
+
# "commits": <int>, // Commit count across all branches
|
|
13
|
+
# "loc_added": <int>, // Lines of code added
|
|
14
|
+
# "loc_removed": <int>, // Lines of code removed
|
|
15
|
+
# "releases": <int>, // Release tags (v4.YYMMDD.*) for this date
|
|
16
|
+
# "contributors": [<string>] // Unique author names for this date
|
|
17
|
+
# }
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
cd "$(git rev-parse --show-toplevel)"
|
|
22
|
+
|
|
23
|
+
DAYS=30
|
|
24
|
+
while [[ $# -gt 0 ]]; do
|
|
25
|
+
case "$1" in
|
|
26
|
+
--days)
|
|
27
|
+
DAYS="$2"
|
|
28
|
+
shift 2
|
|
29
|
+
;;
|
|
30
|
+
*)
|
|
31
|
+
echo "Usage: $0 [--days N]" >&2
|
|
32
|
+
exit 1
|
|
33
|
+
;;
|
|
34
|
+
esac
|
|
35
|
+
done
|
|
36
|
+
|
|
37
|
+
AGENT_DIR=".genie/agents/metrics-updater"
|
|
38
|
+
TOOLS_DIR="$AGENT_DIR/tools"
|
|
39
|
+
OUTPUT="$AGENT_DIR/daily-stats.jsonl"
|
|
40
|
+
|
|
41
|
+
# Clear existing file
|
|
42
|
+
> "$OUTPUT"
|
|
43
|
+
|
|
44
|
+
echo "Backfilling $DAYS days of stats..." >&2
|
|
45
|
+
|
|
46
|
+
for i in $(seq "$DAYS" -1 0); do
|
|
47
|
+
target_date=$(date -d "today - ${i} days" +%Y-%m-%d 2>/dev/null || date -v-${i}d +%Y-%m-%d 2>/dev/null)
|
|
48
|
+
result=$(bash "$TOOLS_DIR/collect-stats.sh" --date "$target_date")
|
|
49
|
+
echo "$result" >> "$OUTPUT"
|
|
50
|
+
echo " $target_date: done" >&2
|
|
51
|
+
done
|
|
52
|
+
|
|
53
|
+
lines=$(wc -l < "$OUTPUT")
|
|
54
|
+
echo "Backfill complete: $lines entries in $OUTPUT" >&2
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# collect-stats.sh — Extract daily metrics from git history across all branches.
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# collect-stats.sh --date YYYY-MM-DD Output JSON for a single day
|
|
6
|
+
# collect-stats.sh --cumulative Output all-time cumulative JSON
|
|
7
|
+
#
|
|
8
|
+
# Output schema (daily):
|
|
9
|
+
# {
|
|
10
|
+
# "date": "YYYY-MM-DD",
|
|
11
|
+
# "commits": <int>,
|
|
12
|
+
# "loc_added": <int>,
|
|
13
|
+
# "loc_removed": <int>,
|
|
14
|
+
# "releases": <int>,
|
|
15
|
+
# "contributors": ["name1", "name2", ...]
|
|
16
|
+
# }
|
|
17
|
+
#
|
|
18
|
+
# Output schema (cumulative):
|
|
19
|
+
# {
|
|
20
|
+
# "total_commits": <int>,
|
|
21
|
+
# "total_tags": <int>,
|
|
22
|
+
# "first_commit_date": "YYYY-MM-DD",
|
|
23
|
+
# "total_contributors": <int>
|
|
24
|
+
# }
|
|
25
|
+
|
|
26
|
+
set -euo pipefail
|
|
27
|
+
|
|
28
|
+
# Navigate to repo root
|
|
29
|
+
cd "$(git rev-parse --show-toplevel)"
|
|
30
|
+
|
|
31
|
+
MODE=""
|
|
32
|
+
TARGET_DATE=""
|
|
33
|
+
|
|
34
|
+
while [[ $# -gt 0 ]]; do
|
|
35
|
+
case "$1" in
|
|
36
|
+
--date)
|
|
37
|
+
MODE="daily"
|
|
38
|
+
TARGET_DATE="$2"
|
|
39
|
+
shift 2
|
|
40
|
+
;;
|
|
41
|
+
--cumulative)
|
|
42
|
+
MODE="cumulative"
|
|
43
|
+
shift
|
|
44
|
+
;;
|
|
45
|
+
*)
|
|
46
|
+
echo "Usage: $0 --date YYYY-MM-DD | --cumulative" >&2
|
|
47
|
+
exit 1
|
|
48
|
+
;;
|
|
49
|
+
esac
|
|
50
|
+
done
|
|
51
|
+
|
|
52
|
+
if [[ -z "$MODE" ]]; then
|
|
53
|
+
echo "Usage: $0 --date YYYY-MM-DD | --cumulative" >&2
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if [[ "$MODE" == "cumulative" ]]; then
|
|
58
|
+
total_commits=$(git log --all --oneline | wc -l)
|
|
59
|
+
total_tags=$(git tag -l "v4.*" | wc -l)
|
|
60
|
+
first_commit_date=$(git log --all --reverse --format='%aI' -- | head -1 | cut -d'T' -f1 || true)
|
|
61
|
+
total_contributors=$(git log --all --format='%aN' | sort -u | wc -l)
|
|
62
|
+
|
|
63
|
+
printf '{"total_commits":%d,"total_tags":%d,"first_commit_date":"%s","total_contributors":%d}\n' \
|
|
64
|
+
"$total_commits" "$total_tags" "$first_commit_date" "$total_contributors"
|
|
65
|
+
exit 0
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Daily mode
|
|
69
|
+
AFTER="${TARGET_DATE} 00:00:00"
|
|
70
|
+
BEFORE="${TARGET_DATE} 23:59:59"
|
|
71
|
+
|
|
72
|
+
# Pathspec exclusions — keep LoC focused on real source code.
|
|
73
|
+
# Drops vendored deps, build outputs, lockfiles, minified bundles,
|
|
74
|
+
# orphaned worktree artifacts, and the agent's own generated assets.
|
|
75
|
+
# Without these, a single cleanup commit (e.g. 9bf66347 on 2026-03-14
|
|
76
|
+
# which deleted 524k lines of claude worktree artifacts) can dominate
|
|
77
|
+
# an entire 30d window and destroy the signal.
|
|
78
|
+
EXCLUDE_PATHS=(
|
|
79
|
+
':(exclude,glob)node_modules/**'
|
|
80
|
+
':(exclude,glob)**/node_modules/**'
|
|
81
|
+
':(exclude,glob).claude/worktrees/**'
|
|
82
|
+
':(exclude,glob).genie/worktrees/**'
|
|
83
|
+
':(exclude,glob).worktrees/**'
|
|
84
|
+
':(exclude,glob)dist/**'
|
|
85
|
+
':(exclude,glob)**/dist/**'
|
|
86
|
+
':(exclude,glob)build/**'
|
|
87
|
+
':(exclude,glob)**/build/**'
|
|
88
|
+
':(exclude,glob).cache/**'
|
|
89
|
+
':(exclude,glob)**/*.lock'
|
|
90
|
+
':(exclude,glob)**/*.lockb'
|
|
91
|
+
':(exclude,glob)**/package-lock.json'
|
|
92
|
+
':(exclude,glob)**/*.min.js'
|
|
93
|
+
':(exclude,glob)**/*.min.css'
|
|
94
|
+
':(exclude,glob).genie/assets/**'
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Commits count (all branches, deduplicated)
|
|
98
|
+
commits=$(git log --all --after="$AFTER" --before="$BEFORE" --oneline | wc -l)
|
|
99
|
+
|
|
100
|
+
# LoC added/removed via shortstat (source files only — see EXCLUDE_PATHS)
|
|
101
|
+
loc_stats=$(git log --all --after="$AFTER" --before="$BEFORE" --shortstat --format="" -- . "${EXCLUDE_PATHS[@]}" | \
|
|
102
|
+
awk '
|
|
103
|
+
/insertion/ {
|
|
104
|
+
for (i=1; i<=NF; i++) {
|
|
105
|
+
if ($(i+1) ~ /insertion/) added += $i
|
|
106
|
+
if ($(i+1) ~ /deletion/) removed += $i
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
END { printf "%d %d", added+0, removed+0 }
|
|
110
|
+
')
|
|
111
|
+
loc_added=$(echo "$loc_stats" | awk '{print $1}')
|
|
112
|
+
loc_removed=$(echo "$loc_stats" | awk '{print $2}')
|
|
113
|
+
|
|
114
|
+
# Release count: tags matching v4.YYMMDD.* for this date
|
|
115
|
+
# Convert YYYY-MM-DD to YYMMDD for tag pattern
|
|
116
|
+
tag_date=$(date -d "$TARGET_DATE" +%y%m%d 2>/dev/null || date -j -f "%Y-%m-%d" "$TARGET_DATE" +%y%m%d 2>/dev/null)
|
|
117
|
+
releases=$(git tag -l "v4.${tag_date}.*" | wc -l)
|
|
118
|
+
|
|
119
|
+
# Contributors (unique author names)
|
|
120
|
+
contributors_json=$(git log --all --after="$AFTER" --before="$BEFORE" --format='%aN' | sort -u | \
|
|
121
|
+
awk 'BEGIN { printf "[" }
|
|
122
|
+
NR>1 { printf "," }
|
|
123
|
+
{ gsub(/"/, "\\\""); printf "\"%s\"", $0 }
|
|
124
|
+
END { printf "]" }')
|
|
125
|
+
|
|
126
|
+
# Handle empty contributors
|
|
127
|
+
if [[ "$contributors_json" == "[]" ]] || [[ -z "$contributors_json" ]]; then
|
|
128
|
+
contributors_json="[]"
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
printf '{"date":"%s","commits":%d,"loc_added":%d,"loc_removed":%d,"releases":%d,"contributors":%s}\n' \
|
|
132
|
+
"$TARGET_DATE" "$commits" "$loc_added" "$loc_removed" "$releases" "$contributors_json"
|