bigpowers 1.5.1 → 2.0.1
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/CHANGELOG.md +35 -0
- package/CONVENTIONS.md +18 -2
- package/README.md +39 -13
- package/RELEASE.md +16 -1
- package/SKILL-INDEX.md +3 -3
- package/assess-impact/SKILL.md +2 -2
- package/build-epic/SKILL.md +5 -5
- package/change-request/SKILL.md +4 -4
- package/dashboard/src/loaders/reader.js +2 -1
- package/dashboard/src/tui/epic-queue.js +2 -0
- package/dashboard/src/tui/filesystem.js +5 -6
- package/dashboard/src/tui/index.js +39 -13
- package/dashboard/src/tui/ledger.js +3 -5
- package/dashboard/src/tui/metrics-bar.js +20 -3
- package/dashboard/src/tui/pipeline.js +9 -13
- package/dashboard/src/tui/state-yaml.js +6 -8
- package/deepen-architecture/SKILL.md +6 -6
- package/define-success/SKILL.md +1 -1
- package/develop-tdd/SKILL.md +3 -3
- package/elaborate-spec/SKILL.md +7 -7
- package/execute-plan/SKILL.md +4 -4
- package/investigate-bug/SKILL.md +1 -1
- package/kickoff-branch/SKILL.md +1 -1
- package/map-codebase/SKILL.md +4 -4
- package/migrate-spec/SKILL.md +8 -8
- package/model-domain/SKILL.md +8 -8
- package/orchestrate-project/REFERENCE.md +8 -4
- package/orchestrate-project/SKILL.md +2 -2
- package/package.json +1 -1
- package/plan-release/SKILL.md +73 -27
- package/plan-work/SKILL.md +23 -7
- package/release-branch/SKILL.md +15 -0
- package/research-first/SKILL.md +2 -2
- package/run-evals/SKILL.md +2 -2
- package/run-planning/SKILL.md +1 -1
- package/scope-work/SKILL.md +4 -4
- package/scripts/land-branch.sh +28 -0
- package/seed-conventions/SKILL.md +37 -6
- package/session-state/SKILL.md +34 -3
- package/slice-tasks/SKILL.md +4 -4
- package/survey-context/SKILL.md +2 -2
- package/trace-requirement/SKILL.md +6 -6
- package/verify-work/SKILL.md +35 -2
- package/write-document/SKILL.md +1 -1
- package/dashboard/src/data/gate-status.js +0 -32
- package/dashboard/src/data/metrics.js +0 -89
- package/dashboard/src/data/pipeline-map.js +0 -32
- package/dashboard/src/data/reader.js +0 -122
- package/dashboard/src/data/watcher.js +0 -108
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
## [2.0.1](https://github.com/danielvm-git/bigpowers/compare/v2.0.0...v2.0.1) (2026-06-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **dashboard/tui:** render blessed tags and improve layout ([ca3a161](https://github.com/danielvm-git/bigpowers/commit/ca3a1617a341d05dacf3b571abf58cb6c0cfceeb))
|
|
7
|
+
|
|
8
|
+
# [2.0.0](https://github.com/danielvm-git/bigpowers/compare/v1.5.1...v2.0.0) (2026-06-11)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
* feat(skills)!: evolve to capsule-dir structure (50/50 SDD adequacy) ([77a4e88](https://github.com/danielvm-git/bigpowers/commit/77a4e88ceeb3d454079a5a499362e53c0f904379))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### BREAKING CHANGES
|
|
15
|
+
|
|
16
|
+
* Renames specs/requirements/ → specs/product/,
|
|
17
|
+
specs/plans/ → specs/tech-architecture/. Epics use capsule
|
|
18
|
+
directories (epic.yaml + story .md + -tasks.yaml). Adds
|
|
19
|
+
specs/verifications/, state.yaml.lock, epic archive, bug registry.
|
|
20
|
+
|
|
21
|
+
- 30 SKILL.md files updated across 8 change themes
|
|
22
|
+
- Path renames (A+B): 10 skills for product/, 10 for tech-architecture/
|
|
23
|
+
- Capsule dirs (C): 17 skills — epic.yaml manifests, countable-story
|
|
24
|
+
.md specs, decoupled -tasks.yaml
|
|
25
|
+
- Verification ledger (D): verify-work + run-evals → specs/verifications/
|
|
26
|
+
- State lock (E): session-state + 6 skills acquire/release state.yaml.lock
|
|
27
|
+
- Bug registry (F): BUG-NNN-slug.md naming, registry.yaml
|
|
28
|
+
- ADR split (G): epic-local adr/ vs global specs/adr/
|
|
29
|
+
- Scripts: land-branch.sh epic archive, sync-skills.sh regeneration
|
|
30
|
+
- HARD GATES: 73 callouts across 61 skills (100% coverage confirmed)
|
|
31
|
+
|
|
32
|
+
Source: projected-structure-bigpowers-evolved.md (50.0/50.0 in SDD
|
|
33
|
+
adequacy), sdd-adequacy-ranking.md (22-method comparison).
|
|
34
|
+
Plan: specs/plans/PLAN-evolve-harmonized.md
|
|
35
|
+
|
|
1
36
|
## [1.5.1](https://github.com/danielvm-git/bigpowers/compare/v1.5.0...v1.5.1) (2026-06-11)
|
|
2
37
|
|
|
3
38
|
|
package/CONVENTIONS.md
CHANGED
|
@@ -49,13 +49,29 @@ Every skill that produces written output writes to `specs/` at the project root.
|
|
|
49
49
|
|
|
50
50
|
| Layer | File | Answers |
|
|
51
51
|
|-------|------|---------|
|
|
52
|
-
| Session | `specs/state.yaml` | Active flow, epic/bug, ship-epic step, git |
|
|
53
|
-
| Release index | `specs/release-plan.yaml` | Target semver, WSJF epic list,
|
|
52
|
+
| Session | `specs/state.yaml` | Active flow, epic/bug, ship-epic step, git, `handoff.next_skill`, `metrics.story_start` |
|
|
53
|
+
| Release index | `specs/release-plan.yaml` | Target semver, WSJF epic list, BCP baseline per story |
|
|
54
54
|
| Progress | `specs/execution-status.yaml` | Flat status keys (`e01`, `e01s01`) — sole SoT for story state |
|
|
55
|
+
| Cycle-time ledger | `specs/metrics/cycle-times.yaml` | Per-story: BCPs, start, end, cycle minutes, BCP/hr **(v2.0.0)** |
|
|
55
56
|
| Planning UI | `specs/planning-status.yaml` | Discover-phase workflow checklist (optional) |
|
|
56
57
|
|
|
57
58
|
**Do not** put story status in `release-plan.yaml`. **Do not** duplicate the release plan inside `state.yaml`.
|
|
58
59
|
|
|
60
|
+
### BCP accounting mandate (v2.0.0)
|
|
61
|
+
|
|
62
|
+
Every task written by `plan-work` MUST be labeled `[BCP N]` where N is the estimated Build Commit Points for that task. The story total is summed and written to `state.yaml` as `epic_cycle.story_bcps`. The BCP baseline for each story MUST appear in `specs/release-plan.yaml` before implementation begins. `release-branch` automatically appends a row to `specs/metrics/cycle-times.yaml` with the final BCP/hr after the story lands.
|
|
63
|
+
|
|
64
|
+
### Timestamp mandate (v2.0.0)
|
|
65
|
+
|
|
66
|
+
- `survey-context` MUST write `metrics.story_start` (ISO 8601) to `specs/state.yaml` at the start of every story.
|
|
67
|
+
- `release-branch` MUST write `metrics.story_end`, `metrics.cycle_minutes`, and `metrics.bcp_per_hour` to `specs/state.yaml` and append a row to `specs/metrics/cycle-times.yaml` when the story lands.
|
|
68
|
+
|
|
69
|
+
Missing timestamps are a gate violation — do not advance past `release-branch` without them.
|
|
70
|
+
|
|
71
|
+
### next_skill signaling mandate (v2.0.0)
|
|
72
|
+
|
|
73
|
+
Every critical-path skill (survey-context, plan-work, kickoff-branch, develop-tdd, verify-work, audit-code, commit-message, release-branch) MUST write `handoff.next_skill` to `specs/state.yaml` as its last action. Agents MUST read `state.yaml` and follow `handoff.next_skill` before asking "what comes next?".
|
|
74
|
+
|
|
59
75
|
### Intent vs delivery vs execution
|
|
60
76
|
|
|
61
77
|
| Question | File | Format |
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
`bigpowers` provides a prescriptive, vertical-slice methodology for building software with AI agents (Claude Code, Gemini CLI, Cursor). It bridges the gap between raw LLM capabilities and professional engineering standards.
|
|
10
10
|
|
|
11
|
-
Published on npm: [bigpowers@
|
|
11
|
+
Published on npm: [bigpowers@2.0.0](https://www.npmjs.com/package/bigpowers)
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -96,16 +96,39 @@ bigpowers
|
|
|
96
96
|
|
|
97
97
|
---
|
|
98
98
|
|
|
99
|
-
## 🏗 The
|
|
99
|
+
## 🏗 The v2.0.0 Lifecycle
|
|
100
100
|
|
|
101
|
-
Every
|
|
101
|
+
Every project follows the **orchestrate-project 6-phase model** (full SOP: [`docs/WORKFLOW-SOP-v2.md`](docs/WORKFLOW-SOP-v2.md)):
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
```
|
|
104
|
+
ONE TIME seed-conventions (CLAUDE.md, .claude/, .gemini/, agents/, skill sync)
|
|
105
|
+
↓
|
|
106
|
+
ONCE/PROJECT orchestrate-project
|
|
107
|
+
│
|
|
108
|
+
├─ Ph1 DISCOVER survey-context, research-first, elaborate-spec
|
|
109
|
+
├─ Ph2 ELABORATE model-domain, grill-me, define-language, deepen-architecture
|
|
110
|
+
├─ Ph3 PLAN scope-work, slice-tasks, plan-work → release-plan.yaml (BCP baseline)
|
|
111
|
+
├─ Ph4 BUILD build-epic × N stories
|
|
112
|
+
│
|
|
113
|
+
│ Per story — 8-step build-epic cycle:
|
|
114
|
+
│ 1. survey-context ← stamps story_start in state.yaml
|
|
115
|
+
│ 2. plan-work ← [BCP N] tasks + verify: commands
|
|
116
|
+
│ 3. kickoff-branch ← worktree + feature branch
|
|
117
|
+
│ 4. develop-tdd ← RED → GREEN → REFACTOR
|
|
118
|
+
│ 5. verify-work ← UAT gate
|
|
119
|
+
│ 6. audit-code ← quality gate ≥ 94%
|
|
120
|
+
│ 7. commit-message ← Conventional Commits + semver
|
|
121
|
+
│ 8. release-branch ← land to main; writes story_end + cycle-times.yaml
|
|
122
|
+
│
|
|
123
|
+
├─ Ph5 VERIFY run-evals, verify-work (project-level)
|
|
124
|
+
└─ Ph6 RELEASE semantic-release → v1.0.0 MVP tag
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Semver:** projects start at `0.0.0-β`; each `feat:` story → minor bump; developer declares MVP → `1.0.0`.
|
|
128
|
+
|
|
129
|
+
**BCP accounting:** every task labeled `[BCP N]`; story total in `state.yaml`; BCP/hr logged to `specs/metrics/cycle-times.yaml`.
|
|
130
|
+
|
|
131
|
+
**next_skill signaling:** each critical-path skill writes `handoff.next_skill` to `state.yaml`. Call `survey-context` after any interruption to resume exactly where you left off.
|
|
109
132
|
|
|
110
133
|
---
|
|
111
134
|
|
|
@@ -118,8 +141,9 @@ Every task in `bigpowers` follows a prescriptive lifecycle (see `SKILL-INDEX.md`
|
|
|
118
141
|
| **Scope** | `specs/requirements/SCOPE_LATEST.yaml` | In-scope / out-of-scope and success criteria. |
|
|
119
142
|
| **Vision** | `specs/requirements/VISION_LATEST.yaml` | North star and initiative success criteria. |
|
|
120
143
|
| **Decisions** | `specs/adr/` | Architectural Decision Records (irreversible choices). |
|
|
121
|
-
| **Roadmap** | `specs/release-plan.yaml` + `specs/epics/` | WSJF-prioritized epics and stories. |
|
|
122
|
-
| **Current** | `specs/state.yaml` | Session flow, active epic, handoff. |
|
|
144
|
+
| **Roadmap** | `specs/release-plan.yaml` + `specs/epics/` | WSJF-prioritized epics and stories with BCP baseline. |
|
|
145
|
+
| **Current** | `specs/state.yaml` | Session flow, active epic, `handoff.next_skill`, timestamps. |
|
|
146
|
+
| **Metrics** | `specs/metrics/cycle-times.yaml` | Per-story BCPs, cycle minutes, BCP/hr (v2.0.0). |
|
|
123
147
|
| **Index** | `SKILL-INDEX.md` | Canonical list of all active skills. |
|
|
124
148
|
| **Style** | `CONVENTIONS.md` | Coding, testing, and naming standards. |
|
|
125
149
|
|
|
@@ -128,8 +152,10 @@ Every task in `bigpowers` follows a prescriptive lifecycle (see `SKILL-INDEX.md`
|
|
|
128
152
|
## 📁 Project Structure
|
|
129
153
|
|
|
130
154
|
- `scripts/`: Installation, syncing, and compliance tools.
|
|
131
|
-
- `specs/`:
|
|
132
|
-
- `specs/
|
|
155
|
+
- `specs/`: YAML cockpit — `state.yaml`, `release-plan.yaml`, `epics/`, `execution-status.yaml`, `requirements/`.
|
|
156
|
+
- `specs/metrics/`: Cycle-time ledger (`cycle-times.yaml`) — per-story BCPs, timestamps, BCP/hr (v2.0.0).
|
|
157
|
+
- `dashboard/`: Live monitoring tool — TUI (`npm run dashboard`) and web (`npm run dashboard:web`, port 7742).
|
|
158
|
+
- `docs/`: Guides including `WORKFLOW-SOP-v2.md` (full SDLC SOP) and `using-bigpowers.md`.
|
|
133
159
|
- `docs/references/`: Theoretical foundations (Uncle Bob, Ousterhout, Karpathy, etc.).
|
|
134
160
|
- `[skill-name]/`: Source files for each of the 61 skills.
|
|
135
161
|
|
package/RELEASE.md
CHANGED
|
@@ -48,12 +48,27 @@ npm view bigpowers
|
|
|
48
48
|
# GitHub → Releases
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
## Per-Project Semver Convention (v2.0.0)
|
|
52
|
+
|
|
53
|
+
When using bigpowers to build a *project* (not the bigpowers package itself), the recommended semver lifecycle is:
|
|
54
|
+
|
|
55
|
+
| Stage | Version | How |
|
|
56
|
+
|-------|---------|-----|
|
|
57
|
+
| Pre-delivery | `0.0.0-β` | Initial state after `seed-conventions` |
|
|
58
|
+
| Each `feat:` story lands | `0.1.0`, `0.2.0`, … | `semantic-release` minor bump |
|
|
59
|
+
| Developer declares MVP | `1.0.0` | Allow the `1.0.0` tag in release config |
|
|
60
|
+
| Post-MVP features | `1.1.0`, `1.2.0`, … | Normal semver from Conventional Commits |
|
|
61
|
+
|
|
62
|
+
> This keeps all pre-MVP work in the `0.x.x` range, making the `1.0.0` tag a meaningful project milestone rather than an arbitrary number.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
51
66
|
## Commit Message Format
|
|
52
67
|
|
|
53
68
|
**Required for automatic releases:**
|
|
54
69
|
|
|
55
70
|
```
|
|
56
|
-
feat(scope): description # Minor version bump (1.0.0 → 1.1.0)
|
|
71
|
+
feat(scope): description # Minor version bump (0.1.0 → 0.2.0 or 1.0.0 → 1.1.0)
|
|
57
72
|
fix(scope): description # Patch version bump (1.0.0 → 1.0.1)
|
|
58
73
|
docs: description # No version bump
|
|
59
74
|
```
|
package/SKILL-INDEX.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Purpose:** One canonical reference for all bigpowers skills. Referenced by README.md, RELEASE-PLAN.md, and CONVENTIONS.md. Updated per-release.
|
|
4
4
|
|
|
5
|
-
**Last updated:** 2026-06-
|
|
5
|
+
**Last updated:** 2026-06-11 (v2.0.0 — verified 61 active skills; 18 sub-op concepts absorbed as sub-sections into parent SKILL.md files; count confirmed accurate)
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
| 49 | Utility | `edit-document` | Edit documents in specs/ | specs/<name>.md | ✅ Active |
|
|
85
85
|
| 50 | Utility | `session-state` | Track decisions in state.yaml; absorbs show-state, reset-state, compact-state, list-epics, check-gates | state.yaml | ✅ Active |
|
|
86
86
|
| 51 | Utility | `migrate-spec` | Migrate foreign spec formats | specs/ | ✅ Active |
|
|
87
|
-
| 52 | Utility | `visual-dashboard` | Browser dashboard |
|
|
87
|
+
| 52 | Utility | `visual-dashboard` | Browser dashboard (HTTP cockpit) | `npm run visual-dashboard` → GET /cockpit.html | ✅ Active |
|
|
88
88
|
| 53 | Utility | `write-document` | BMAD technical documents | specs/<name>.md | ✅ Active |
|
|
89
89
|
| 54 | Utility | `setup-environment` | Pre-install deps before work | (.env, packages) | ✅ Active |
|
|
90
90
|
| 55 | Utility | `reset-baseline` | Restore clean known state | (clean tree) | ✅ Active |
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
| 60 | Build | `run-planning` | Discover-phase workflow tracker | planning-status.yaml | ✅ Active |
|
|
96
96
|
| 61 | Bug | `fix-bug` | Bug fix orchestrator | bugs/BUG-*.md | ✅ Active |
|
|
97
97
|
|
|
98
|
-
**Total: 61
|
|
98
|
+
**Total: 61 active skills.** 18 sub-op concepts (zoom-out, slopcheck, red-phase, green-phase, refactor-phase, cold-start-smoke, gaps-loop, plan-work-fast, commit-message-fix, release-branch-hotfix, audit-code-quick, verify-work-smoke, show-state, reset-state, compact-state, list-epics, check-gates) are documented as sub-sections within parent SKILL.md files; none were standalone SKILL.md directories, so the count remains 61.
|
|
99
99
|
|
|
100
100
|
---
|
|
101
101
|
|
package/assess-impact/SKILL.md
CHANGED
|
@@ -27,9 +27,9 @@ git log --oneline -10 -- [file-path]
|
|
|
27
27
|
|
|
28
28
|
### 3. Map to release plan stories
|
|
29
29
|
|
|
30
|
-
Read `specs/release-plan.yaml + epic
|
|
30
|
+
Read `specs/release-plan.yaml + epic capsule directories` (if it exists). For each dependent found in Step 2, identify which story owns that module. List stories that will be affected by the change.
|
|
31
31
|
|
|
32
|
-
→ verify: `grep -c "Story" specs/release-plan.yaml + epic
|
|
32
|
+
→ verify: `grep -c "Story" specs/release-plan.yaml + epic capsule directories 2>/dev/null || echo "no release plan"`
|
|
33
33
|
|
|
34
34
|
### 4. List test coverage
|
|
35
35
|
|
package/build-epic/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build-epic
|
|
3
3
|
model: sonnet
|
|
4
|
-
description: Eight-step epic build cycle — reads state.yaml, execution-status.yaml, and one epic
|
|
4
|
+
description: Eight-step epic build cycle — reads state.yaml, execution-status.yaml, and one epic capsule; updates status via bp-yaml-set or direct edit. Resume mode runs one step per invocation. Use instead of ad-hoc execute-plan for release work.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Build Epic
|
|
@@ -19,7 +19,7 @@ Orchestrates the **build** flow for a single epic: survey → plan tasks → kic
|
|
|
19
19
|
| Step | Skill / action |
|
|
20
20
|
|------|----------------|
|
|
21
21
|
| 1 | `survey-context` — confirm epic + story |
|
|
22
|
-
| 2 | `plan-work` — flesh out story `tasks[]` in `specs/epics/eNN
|
|
22
|
+
| 2 | `plan-work` — flesh out story `tasks[]` in `specs/epics/eNN-slug/epic.yaml` |
|
|
23
23
|
| 3 | `kickoff-branch` — feature branch + clean baseline |
|
|
24
24
|
| 4 | `develop-tdd` — red-green per task |
|
|
25
25
|
| 5 | `verify-work` — UAT + mechanical gates |
|
|
@@ -29,8 +29,8 @@ Orchestrates the **build** flow for a single epic: survey → plan tasks → kic
|
|
|
29
29
|
|
|
30
30
|
## Process
|
|
31
31
|
|
|
32
|
-
1. Read `specs/state.yaml`, `specs/execution-status.yaml`, `specs/release-plan.yaml`, active `specs/epics/eNN
|
|
33
|
-
2. **BCP Tracking (Step 2):** After `plan-work` completes, read the `bcps:` count from the epic
|
|
32
|
+
1. Read `specs/state.yaml`, `specs/execution-status.yaml`, `specs/release-plan.yaml`, active `specs/epics/eNN-slug/epic.yaml`.
|
|
33
|
+
2. **BCP Tracking (Step 2):** After `plan-work` completes, read the `bcps:` count from the epic capsule and carry it into `state.yaml` as `epic_cycle.story_bcps = N`.
|
|
34
34
|
3. If `epic_cycle.step` missing, set to `1`.
|
|
35
35
|
4. Run **only the current step** (resume mode) unless user asked for full auto-run.
|
|
36
36
|
5. After step verify passes, increment `epic_cycle.step` in `state.yaml` (or `bash scripts/bp-yaml-set.sh` if available).
|
|
@@ -42,4 +42,4 @@ Write `handoff.next_skill` and `handoff.context` in `state.yaml` when pausing mi
|
|
|
42
42
|
|
|
43
43
|
## Verify
|
|
44
44
|
|
|
45
|
-
→ verify: `grep -q 'active_flow: build_epic' specs/state.yaml && test -f specs/epics
|
|
45
|
+
→ verify: `grep -q 'active_flow: build_epic' specs/state.yaml && test -f specs/epics/*/epic.yaml`
|
package/change-request/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: change-request
|
|
3
3
|
model: sonnet
|
|
4
|
-
description: Add a new requirement or reorder epics by WSJF against specs/release-plan.yaml and epic
|
|
4
|
+
description: Add a new requirement or reorder epics by WSJF against specs/release-plan.yaml and epic capsule directories. Modes Add and Reorder. Use when a new requirement arrives mid-release or the plan needs prioritization.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Change Request
|
|
@@ -19,10 +19,10 @@ Intake a new requirement mid-flight without disrupting work in progress.
|
|
|
19
19
|
1. **Capture**: What is the change? What problem does it solve?
|
|
20
20
|
2. **Locate**: Which existing stories in `specs/epics/` does it affect or replace?
|
|
21
21
|
3. **Draft**: Add story + `tasks[]` with Gherkin-style AC in epic YAML (each task has `verify`).
|
|
22
|
-
4. **Place**: Append story under existing epic
|
|
22
|
+
4. **Place**: Append story under existing epic capsule, or create `specs/epics/eNN-slug.yaml` and register in `release-plan.yaml` `epics[]`.
|
|
23
23
|
5. **Score**: Compute WSJF; note if it outranks in-progress work.
|
|
24
24
|
|
|
25
|
-
→ verify: `grep -c 'stories:' specs/epics
|
|
25
|
+
→ verify: `grep -c 'stories:' specs/epics/*/epic.yaml`
|
|
26
26
|
|
|
27
27
|
## Mode B — Reorder
|
|
28
28
|
|
|
@@ -36,7 +36,7 @@ See [REFERENCE.md](REFERENCE.md) for the full WSJF scoring rubric.
|
|
|
36
36
|
4. **Update** `specs/release-plan.yaml` and epic `wsjf` keys with rationale.
|
|
37
37
|
5. **Report** the delta.
|
|
38
38
|
|
|
39
|
-
→ verify: `grep -c 'wsjf' specs/release-plan.yaml specs/epics
|
|
39
|
+
→ verify: `grep -c 'wsjf' specs/release-plan.yaml specs/epics/*/epic.yaml`
|
|
40
40
|
|
|
41
41
|
## After either mode
|
|
42
42
|
|
|
@@ -103,10 +103,11 @@ function readCycleTimes(projectRoot) {
|
|
|
103
103
|
const stories = data.stories || [];
|
|
104
104
|
return stories.map(s => ({
|
|
105
105
|
id: s.id || null,
|
|
106
|
+
epic: s.epic || null,
|
|
106
107
|
bcps: s.bcps || 0,
|
|
107
108
|
start: s.start || null,
|
|
108
109
|
end: s.end || null,
|
|
109
|
-
cycleMin: s.
|
|
110
|
+
cycleMin: s.cycle_minutes || 0,
|
|
110
111
|
bcpPerHour: s.bcp_per_hour || 0
|
|
111
112
|
}));
|
|
112
113
|
} catch (err) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const chalk = require('chalk');
|
|
4
3
|
|
|
5
4
|
function renderFilesystem(box, projectRoot) {
|
|
6
5
|
if (!box || typeof box.setContent !== 'function') {
|
|
@@ -10,13 +9,13 @@ function renderFilesystem(box, projectRoot) {
|
|
|
10
9
|
const specsPath = path.join(projectRoot, 'specs');
|
|
11
10
|
|
|
12
11
|
if (!fs.existsSync(specsPath)) {
|
|
13
|
-
box.setContent(
|
|
12
|
+
box.setContent('{center}{dim}specs/ not found{/dim}{/center}');
|
|
14
13
|
return;
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
const now = Date.now();
|
|
18
17
|
const lines = [];
|
|
19
|
-
lines.push('{bold}{
|
|
18
|
+
lines.push('{bold}FILE SYSTEM{/bold}');
|
|
20
19
|
|
|
21
20
|
let fileCount = 0;
|
|
22
21
|
|
|
@@ -58,7 +57,7 @@ function renderFilesystem(box, projectRoot) {
|
|
|
58
57
|
let displayName = entry.name;
|
|
59
58
|
|
|
60
59
|
if (entry.isDirectory()) {
|
|
61
|
-
displayName =
|
|
60
|
+
displayName = `{blue-fg}${displayName}{/blue-fg}`;
|
|
62
61
|
lines.push(prefix + connector + displayName);
|
|
63
62
|
|
|
64
63
|
if (depth < 1) {
|
|
@@ -73,7 +72,7 @@ function renderFilesystem(box, projectRoot) {
|
|
|
73
72
|
const age = now - mtime;
|
|
74
73
|
|
|
75
74
|
if (age < 60000) {
|
|
76
|
-
displayName =
|
|
75
|
+
displayName = `{yellow-fg}${displayName} ★{/yellow-fg}`;
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
lines.push(prefix + connector + displayName);
|
|
@@ -86,7 +85,7 @@ function renderFilesystem(box, projectRoot) {
|
|
|
86
85
|
|
|
87
86
|
buildTree(specsPath);
|
|
88
87
|
} catch (err) {
|
|
89
|
-
lines.push(
|
|
88
|
+
lines.push('{dim}Error reading specs/{/dim}');
|
|
90
89
|
}
|
|
91
90
|
|
|
92
91
|
box.setContent(lines.join('\n'));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
2
|
const { watch } = require('../loaders/watcher');
|
|
3
3
|
const { readStateYaml, readExecutionStatus, readEpicShards, readCycleTimes } = require('../loaders/reader');
|
|
4
|
-
const {
|
|
4
|
+
const { computeProjectMetrics } = require('../loaders/metrics');
|
|
5
5
|
const { renderPipeline } = require('./pipeline');
|
|
6
6
|
const { renderEpicQueue } = require('./epic-queue');
|
|
7
7
|
const { renderMetricsBar } = require('./metrics-bar');
|
|
@@ -9,6 +9,9 @@ const { renderStateYaml } = require('./state-yaml');
|
|
|
9
9
|
const { renderFilesystem } = require('./filesystem');
|
|
10
10
|
const { renderLedger } = require('./ledger');
|
|
11
11
|
|
|
12
|
+
// Blessed box defaults — tags must be enabled for markup to render
|
|
13
|
+
const BOX_DEFAULTS = { tags: true };
|
|
14
|
+
|
|
12
15
|
let blessed;
|
|
13
16
|
try {
|
|
14
17
|
blessed = require('blessed');
|
|
@@ -41,6 +44,7 @@ function start(projectRoot) {
|
|
|
41
44
|
height: 10,
|
|
42
45
|
content: '{center}Terminal must be at least 120x30{/center}\n{center}Please resize and try again{/center}',
|
|
43
46
|
border: 'line',
|
|
47
|
+
tags: true,
|
|
44
48
|
style: { border: { fg: 'yellow' } }
|
|
45
49
|
});
|
|
46
50
|
screen.render();
|
|
@@ -48,75 +52,92 @@ function start(projectRoot) {
|
|
|
48
52
|
}
|
|
49
53
|
|
|
50
54
|
// Create layout zones
|
|
51
|
-
const
|
|
55
|
+
const titleBar = blessed.box({
|
|
52
56
|
parent: screen,
|
|
53
57
|
top: 0,
|
|
54
58
|
left: 0,
|
|
55
59
|
width: '100%',
|
|
60
|
+
height: 1,
|
|
61
|
+
border: 'line',
|
|
62
|
+
tags: true,
|
|
63
|
+
style: { border: { fg: 'magenta' } }
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const metricsBar = blessed.box({
|
|
67
|
+
parent: screen,
|
|
68
|
+
top: 1,
|
|
69
|
+
left: 0,
|
|
70
|
+
width: '100%',
|
|
56
71
|
height: 3,
|
|
57
72
|
border: 'line',
|
|
73
|
+
tags: true,
|
|
58
74
|
style: { border: { fg: 'blue' } }
|
|
59
75
|
});
|
|
60
76
|
|
|
61
77
|
const pipeline = blessed.box({
|
|
62
78
|
parent: screen,
|
|
63
|
-
top:
|
|
79
|
+
top: 4,
|
|
64
80
|
left: 0,
|
|
65
81
|
width: '100%',
|
|
66
82
|
height: 5,
|
|
67
83
|
border: 'line',
|
|
84
|
+
tags: true,
|
|
68
85
|
style: { border: { fg: 'cyan' } }
|
|
69
86
|
});
|
|
70
87
|
|
|
71
88
|
const epicQueue = blessed.box({
|
|
72
89
|
parent: screen,
|
|
73
|
-
top:
|
|
90
|
+
top: 9,
|
|
74
91
|
left: 0,
|
|
75
92
|
width: '33%',
|
|
76
|
-
height: screen.height -
|
|
93
|
+
height: screen.height - 21,
|
|
77
94
|
border: 'line',
|
|
78
95
|
scrollable: true,
|
|
79
96
|
mouse: true,
|
|
80
97
|
keys: true,
|
|
98
|
+
tags: true,
|
|
81
99
|
style: { border: { fg: 'green' } }
|
|
82
100
|
});
|
|
83
101
|
|
|
84
102
|
const actionLog = blessed.box({
|
|
85
103
|
parent: screen,
|
|
86
|
-
top:
|
|
104
|
+
top: 9,
|
|
87
105
|
left: '33%',
|
|
88
106
|
width: '33%',
|
|
89
|
-
height: screen.height -
|
|
107
|
+
height: screen.height - 21,
|
|
90
108
|
border: 'line',
|
|
91
109
|
scrollable: true,
|
|
92
110
|
mouse: true,
|
|
93
111
|
keys: true,
|
|
112
|
+
tags: true,
|
|
94
113
|
style: { border: { fg: 'yellow' } }
|
|
95
114
|
});
|
|
96
115
|
|
|
97
116
|
const fsPanel = blessed.box({
|
|
98
117
|
parent: screen,
|
|
99
|
-
top:
|
|
118
|
+
top: 9,
|
|
100
119
|
left: '66%',
|
|
101
120
|
width: '34%',
|
|
102
|
-
height: screen.height -
|
|
121
|
+
height: screen.height - 21,
|
|
103
122
|
border: 'line',
|
|
104
123
|
scrollable: true,
|
|
105
124
|
mouse: true,
|
|
106
125
|
keys: true,
|
|
126
|
+
tags: true,
|
|
107
127
|
style: { border: { fg: 'magenta' } }
|
|
108
128
|
});
|
|
109
129
|
|
|
110
130
|
const ledger = blessed.box({
|
|
111
131
|
parent: screen,
|
|
112
|
-
top: screen.height -
|
|
132
|
+
top: screen.height - 11,
|
|
113
133
|
left: 0,
|
|
114
134
|
width: '100%',
|
|
115
|
-
height:
|
|
135
|
+
height: 11,
|
|
116
136
|
border: 'line',
|
|
117
137
|
scrollable: true,
|
|
118
138
|
mouse: true,
|
|
119
139
|
keys: true,
|
|
140
|
+
tags: true,
|
|
120
141
|
style: { border: { fg: 'white' } }
|
|
121
142
|
});
|
|
122
143
|
|
|
@@ -126,9 +147,14 @@ function start(projectRoot) {
|
|
|
126
147
|
const executionStatus = readExecutionStatus(projectRoot);
|
|
127
148
|
const epics = readEpicShards(projectRoot);
|
|
128
149
|
const cycleTimes = readCycleTimes(projectRoot);
|
|
129
|
-
const metrics =
|
|
150
|
+
const metrics = computeProjectMetrics(cycleTimes);
|
|
151
|
+
|
|
152
|
+
// Render title bar
|
|
153
|
+
const epicTitle = stateData?.active_epic || '—';
|
|
154
|
+
const stepNum = stateData?.epicCycle?.current_step ? (stateData.epicCycle.completed_steps?.length || 0) + 1 : 0;
|
|
155
|
+
titleBar.setContent(`{bold}{magenta}bigpowers factory{/magenta}{/bold} — ${epicTitle} — step ${stepNum} / 8`);
|
|
130
156
|
|
|
131
|
-
renderMetricsBar(metricsBar, metrics, stateData);
|
|
157
|
+
renderMetricsBar(metricsBar, metrics, stateData, epics);
|
|
132
158
|
renderPipeline(pipeline, stateData);
|
|
133
159
|
renderEpicQueue(epicQueue, epics, executionStatus);
|
|
134
160
|
renderStateYaml(actionLog, stateData);
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
|
-
|
|
3
1
|
function renderLedger(box, cycleTimes) {
|
|
4
2
|
if (!box || typeof box.setContent !== 'function') {
|
|
5
3
|
return;
|
|
6
4
|
}
|
|
7
5
|
|
|
8
6
|
if (!cycleTimes || cycleTimes.length === 0) {
|
|
9
|
-
box.setContent(
|
|
7
|
+
box.setContent('{center}{dim}no completed stories yet{/dim}{/center}');
|
|
10
8
|
return;
|
|
11
9
|
}
|
|
12
10
|
|
|
@@ -30,10 +28,10 @@ function renderLedger(box, cycleTimes) {
|
|
|
30
28
|
|
|
31
29
|
// Data rows
|
|
32
30
|
cycleTimes.forEach((cycle) => {
|
|
33
|
-
const storyId = cycle.
|
|
31
|
+
const storyId = cycle.id || '—';
|
|
34
32
|
const epicPrefix = cycle.epic || '—';
|
|
35
33
|
const bcps = cycle.bcps || 0;
|
|
36
|
-
const minutes = cycle.
|
|
34
|
+
const minutes = cycle.cycleMin || 0;
|
|
37
35
|
const bcpPerHour = minutes > 0 ? ((bcps * 60) / minutes).toFixed(1) : '—';
|
|
38
36
|
|
|
39
37
|
totalBCPs += bcps;
|
|
@@ -1,9 +1,26 @@
|
|
|
1
|
-
function renderMetricsBar(box, projectMetrics, stateData) {
|
|
1
|
+
function renderMetricsBar(box, projectMetrics, stateData, epics) {
|
|
2
2
|
if (!box || typeof box.setContent !== 'function') {
|
|
3
3
|
return;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
// Count epics and stories
|
|
7
|
+
let epicCount = 0;
|
|
8
|
+
let storyCount = 0;
|
|
9
|
+
let targetBcps = 0;
|
|
10
|
+
|
|
11
|
+
if (epics && Array.isArray(epics)) {
|
|
12
|
+
epicCount = epics.length;
|
|
13
|
+
epics.forEach(epic => {
|
|
14
|
+
if (epic.stories && Array.isArray(epic.stories)) {
|
|
15
|
+
storyCount += epic.stories.length;
|
|
16
|
+
epic.stories.forEach(story => {
|
|
17
|
+
targetBcps += story.bcps || 0;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const deliveredBcps = projectMetrics?.totalBcps ?? '-';
|
|
7
24
|
const totalMin = projectMetrics?.totalMin ?? '-';
|
|
8
25
|
const avgBcpPerHour = projectMetrics?.avgBcpPerHour ?? '-';
|
|
9
26
|
const version = stateData?.release?.target_version ?? '-';
|
|
@@ -22,7 +39,7 @@ function renderMetricsBar(box, projectMetrics, stateData) {
|
|
|
22
39
|
const avgCycleTime = totalMin === '-' ? '-' : `${totalMin}m`;
|
|
23
40
|
const bcpHrDisplay = typeof avgBcpPerHour === 'number' ? avgBcpPerHour.toFixed(2) : avgBcpPerHour;
|
|
24
41
|
|
|
25
|
-
const line = `BCPs: ${
|
|
42
|
+
const line = `epics: ${epicCount} | stories: ${storyCount} | BCPs: ${deliveredBcps}/${targetBcps} | cycle: ${avgCycleTime} | {${bcpHrColor}}BCP/hr: ${bcpHrDisplay}{/${bcpHrColor}} | v${version}`;
|
|
26
43
|
|
|
27
44
|
box.setContent(line);
|
|
28
45
|
}
|
|
@@ -13,32 +13,28 @@ function renderPipeline(box, stateData) {
|
|
|
13
13
|
const currentStep = stateData.epicCycle?.current_step || null;
|
|
14
14
|
const completedSteps = stateData.epicCycle?.completed_steps || [];
|
|
15
15
|
|
|
16
|
-
// Build pipeline
|
|
17
|
-
const
|
|
18
|
-
lines.push('{bold}{cyan}Pipeline{/cyan}{/bold}');
|
|
19
|
-
lines.push('');
|
|
20
|
-
|
|
21
|
-
// Create step display
|
|
22
|
-
const stepDisplay = STEPS.map((step, index) => {
|
|
16
|
+
// Build horizontal pipeline strip
|
|
17
|
+
const steps = STEPS.map((step, index) => {
|
|
23
18
|
const isCompleted = completedSteps.includes(step);
|
|
24
19
|
const isCurrent = step === currentStep;
|
|
25
20
|
|
|
26
|
-
let display =
|
|
21
|
+
let display = `${index + 1} ${step}`;
|
|
27
22
|
|
|
28
23
|
if (isCurrent) {
|
|
29
|
-
display = `{reverse}
|
|
24
|
+
display = `{reverse}${display}{/reverse}`;
|
|
30
25
|
} else if (isCompleted) {
|
|
31
26
|
display = `{green-fg}${display}{/green-fg}`;
|
|
32
27
|
} else {
|
|
33
|
-
display = `{
|
|
28
|
+
display = `{dim}${display}{/dim}`;
|
|
34
29
|
}
|
|
35
30
|
|
|
36
31
|
return display;
|
|
37
|
-
}).join('
|
|
32
|
+
}).join(' {bold}›{/bold} ');
|
|
38
33
|
|
|
39
|
-
lines
|
|
34
|
+
const lines = [];
|
|
35
|
+
lines.push(`{bold}{cyan}Pipeline{/cyan}{/bold} step ${STEPS.indexOf(currentStep) + 1} / ${STEPS.length}`);
|
|
40
36
|
lines.push('');
|
|
41
|
-
lines.push(
|
|
37
|
+
lines.push(steps);
|
|
42
38
|
|
|
43
39
|
box.setContent(lines.join('\n'));
|
|
44
40
|
}
|