bigpowers 2.1.0 → 2.1.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 +7 -0
- package/dashboard/src/tui/epic-queue.js +14 -14
- package/dashboard/src/tui/filesystem.js +3 -3
- package/dashboard/src/tui/index.js +1 -1
- package/dashboard/src/tui/ledger.js +5 -5
- package/dashboard/src/tui/metrics-bar.js +16 -16
- package/dashboard/src/tui/pipeline.js +5 -5
- package/dashboard/src/tui/state-yaml.js +6 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [2.1.1](https://github.com/danielvm-git/bigpowers/compare/v2.1.0...v2.1.1) (2026-06-11)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **dashboard/tui:** replace invalid {dim} tags with {gray-fg} across all render modules ([f029360](https://github.com/danielvm-git/bigpowers/commit/f02936068b024107e7685accb62fe2bb1b0917b7))
|
|
7
|
+
|
|
1
8
|
# [2.1.0](https://github.com/danielvm-git/bigpowers/compare/v2.0.1...v2.1.0) (2026-06-11)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -4,7 +4,7 @@ function renderEpicQueue(box, epics, executionStatus) {
|
|
|
4
4
|
}
|
|
5
5
|
|
|
6
6
|
if (!epics || epics.length === 0) {
|
|
7
|
-
box.setContent('{
|
|
7
|
+
box.setContent('{gray-fg}no epic shards found{/gray-fg}');
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -16,7 +16,7 @@ function renderEpicQueue(box, epics, executionStatus) {
|
|
|
16
16
|
const s = statusMap.get(id) || '';
|
|
17
17
|
if (doneStatuses.has(s)) return '{green-fg}●{/green-fg}';
|
|
18
18
|
if (activeStatuses.has(s)) return '{yellow-fg}●{/yellow-fg}';
|
|
19
|
-
return '{
|
|
19
|
+
return '{gray-fg}·{/gray-fg}';
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function epicDot(epic) {
|
|
@@ -27,7 +27,7 @@ function renderEpicQueue(box, epics, executionStatus) {
|
|
|
27
27
|
if (stories.length > 0 && stories.every(st => doneStatuses.has(statusMap.get(st.id) || ''))) {
|
|
28
28
|
return '{green-fg}●{/green-fg}';
|
|
29
29
|
}
|
|
30
|
-
return '{
|
|
30
|
+
return '{gray-fg}·{/gray-fg}';
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const lines = [];
|
|
@@ -35,7 +35,7 @@ function renderEpicQueue(box, epics, executionStatus) {
|
|
|
35
35
|
const perEpicBcp = [];
|
|
36
36
|
|
|
37
37
|
epics.forEach(epic => {
|
|
38
|
-
lines.push(`${epicDot(epic)} {bold}${epic.id}{/bold} {
|
|
38
|
+
lines.push(`${epicDot(epic)} {bold}${epic.id}{/bold} {gray-fg}·{/gray-fg} ${epic.title || '—'}`);
|
|
39
39
|
|
|
40
40
|
const stories = epic.stories || [];
|
|
41
41
|
let epicBcpDone = 0;
|
|
@@ -51,25 +51,25 @@ function renderEpicQueue(box, epics, executionStatus) {
|
|
|
51
51
|
|
|
52
52
|
const bcpStr = isDone
|
|
53
53
|
? `{green-fg}${bcp} BCP{/green-fg}`
|
|
54
|
-
: `{
|
|
55
|
-
lines.push(` ${dot(story.id)} {
|
|
54
|
+
: `{gray-fg}${bcp} BCP{/gray-fg}`;
|
|
55
|
+
lines.push(` ${dot(story.id)} {gray-fg}${story.id}{/gray-fg} ${story.title || '—'} ${bcpStr}`);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
perEpicBcp.push({ id: epic.id, bcps: epicBcpTotal });
|
|
59
59
|
|
|
60
60
|
const bcpProgressStr = epicBcpDone > 0
|
|
61
|
-
? `{green-fg}${epicBcpDone}{/green-fg}{
|
|
62
|
-
: `{
|
|
63
|
-
lines.push(` {
|
|
61
|
+
? `{green-fg}${epicBcpDone}{/green-fg}{gray-fg}/${epicBcpTotal} BCP{/gray-fg}`
|
|
62
|
+
: `{gray-fg}0/${epicBcpTotal} BCP{/gray-fg}`;
|
|
63
|
+
lines.push(` {gray-fg}${epicStoriesDone}/${stories.length} done · ${bcpProgressStr}`);
|
|
64
64
|
lines.push('');
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
// Release baseline footer
|
|
68
|
-
lines.push('{
|
|
69
|
-
lines.push(`{
|
|
70
|
-
lines.push(`{
|
|
71
|
-
lines.push(perEpicBcp.map(e => `{
|
|
72
|
-
lines.push(`{
|
|
68
|
+
lines.push('{gray-fg}─────────────────────────{/gray-fg}');
|
|
69
|
+
lines.push(`{gray-fg}release baseline{/gray-fg}`);
|
|
70
|
+
lines.push(`{gray-fg}total: {/gray-fg}{yellow-fg}${grandTotalBcps} BCPs{/yellow-fg}`);
|
|
71
|
+
lines.push(perEpicBcp.map(e => `{gray-fg}${e.id}: ${e.bcps} BCP{/gray-fg}`).join(' '));
|
|
72
|
+
lines.push(`{gray-fg}target: {/gray-fg}{bold}v2.0.0{/bold}`);
|
|
73
73
|
|
|
74
74
|
box.setContent(lines.join('\n'));
|
|
75
75
|
}
|
|
@@ -9,7 +9,7 @@ function renderFilesystem(box, projectRoot) {
|
|
|
9
9
|
const specsPath = path.join(projectRoot, 'specs');
|
|
10
10
|
|
|
11
11
|
if (!fs.existsSync(specsPath)) {
|
|
12
|
-
box.setContent('{center}{
|
|
12
|
+
box.setContent('{center}{gray-fg}specs/ not found{/gray-fg}{/center}');
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -39,7 +39,7 @@ function renderFilesystem(box, projectRoot) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
fileCount = countFiles(specsPath);
|
|
42
|
-
lines.push(`{
|
|
42
|
+
lines.push(`{gray-fg}[${fileCount} files]{/gray-fg}`);
|
|
43
43
|
lines.push('');
|
|
44
44
|
|
|
45
45
|
// Build tree
|
|
@@ -83,7 +83,7 @@ function renderFilesystem(box, projectRoot) {
|
|
|
83
83
|
|
|
84
84
|
buildTree(specsPath);
|
|
85
85
|
} catch (err) {
|
|
86
|
-
lines.push('{
|
|
86
|
+
lines.push('{gray-fg}Error reading specs/{/gray-fg}');
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
box.setContent(lines.join('\n'));
|
|
@@ -154,7 +154,7 @@ function start(projectRoot) {
|
|
|
154
154
|
const metrics = computeProjectMetrics(cycleTimes);
|
|
155
155
|
|
|
156
156
|
// Title bar: fixed project identity
|
|
157
|
-
titleBar.setContent(' {bold}{cyan-fg}⚙ bigpowers factory{/cyan-fg}{/bold} {
|
|
157
|
+
titleBar.setContent(' {bold}{cyan-fg}⚙ bigpowers factory{/cyan-fg}{/bold} {gray-fg}v2 — seed {cyan-fg}→{/cyan-fg} epics {cyan-fg}→{/cyan-fg} mvp{/gray-fg}');
|
|
158
158
|
|
|
159
159
|
renderMetricsBar(metricsBar, metrics, stateData, epics, cycleTimes);
|
|
160
160
|
renderPipeline(pipeline, stateData);
|
|
@@ -9,7 +9,7 @@ function renderLedger(box, cycleTimes) {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
if (!cycleTimes || cycleTimes.length === 0) {
|
|
12
|
-
box.setContent('{
|
|
12
|
+
box.setContent('{gray-fg}stories complete here as they land{/gray-fg}');
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -22,7 +22,7 @@ function renderLedger(box, cycleTimes) {
|
|
|
22
22
|
lines.push(
|
|
23
23
|
`{cyan-fg}{bold}${pad('Story ID', W.sid)}${pad('Epic', W.epic)}${pad('BCPs', W.bcps)}${pad('Minutes', W.min)}${pad('BCP/hr', W.bhr)}{/bold}{/cyan-fg}`
|
|
24
24
|
);
|
|
25
|
-
lines.push('{
|
|
25
|
+
lines.push('{gray-fg}' + '─'.repeat(W.sid + W.epic + W.bcps + W.min + W.bhr) + '{/gray-fg}');
|
|
26
26
|
|
|
27
27
|
let totalBCPs = 0;
|
|
28
28
|
let totalMinutes = 0;
|
|
@@ -39,14 +39,14 @@ function renderLedger(box, cycleTimes) {
|
|
|
39
39
|
|
|
40
40
|
lines.push(
|
|
41
41
|
`{white-fg}${pad(storyId, W.sid)}{/white-fg}` +
|
|
42
|
-
`{
|
|
42
|
+
`{gray-fg}${pad(epicId, W.epic)}{/gray-fg}` +
|
|
43
43
|
`{yellow-fg}${pad(bcps, W.bcps)}{/yellow-fg}` +
|
|
44
|
-
`{
|
|
44
|
+
`{gray-fg}${pad(minutes, W.min)}{/gray-fg}` +
|
|
45
45
|
`{green-fg}${pad(bph, W.bhr)}{/green-fg}`
|
|
46
46
|
);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
lines.push('{
|
|
49
|
+
lines.push('{gray-fg}' + '─'.repeat(W.sid + W.epic + W.bcps + W.min + W.bhr) + '{/gray-fg}');
|
|
50
50
|
|
|
51
51
|
const avgBph = totalMinutes > 0 ? ((totalBCPs * 60) / totalMinutes).toFixed(1) : '—';
|
|
52
52
|
lines.push(
|
|
@@ -41,11 +41,11 @@ function renderMetricsBar(box, projectMetrics, stateData, epics, cycleTimes) {
|
|
|
41
41
|
|
|
42
42
|
// ── Line 1: status bar ──
|
|
43
43
|
const statusLine =
|
|
44
|
-
`{
|
|
45
|
-
` {
|
|
46
|
-
` {
|
|
47
|
-
` {
|
|
48
|
-
`
|
|
44
|
+
`{gray-fg}BCPs:{/gray-fg} {yellow-fg}${deliveredBcps}{/yellow-fg}{gray-fg}/${targetBcps}{/gray-fg}` +
|
|
45
|
+
` {gray-fg}│{/gray-fg} {gray-fg}Cycle:{/gray-fg} ${cycleDisplay}` +
|
|
46
|
+
` {gray-fg}│{/gray-fg} {gray-fg}BCP/hr:{/gray-fg} {${bphColor}-fg}${bphDisplay}{/${bphColor}-fg}` +
|
|
47
|
+
` {gray-fg}│{/gray-fg} {gray-fg}v{/gray-fg}{green-fg}${version}{/green-fg}` +
|
|
48
|
+
` {gray-fg}branch:{/gray-fg} {green-fg}${branch}{/green-fg}`;
|
|
49
49
|
|
|
50
50
|
// ── Line 2: step info ──
|
|
51
51
|
const currentStep = stateData?.epicCycle?.current_step;
|
|
@@ -60,21 +60,21 @@ function renderMetricsBar(box, projectMetrics, stateData, epics, cycleTimes) {
|
|
|
60
60
|
? `{yellow-fg}running{/yellow-fg}`
|
|
61
61
|
: `{green-fg}ready{/green-fg}`;
|
|
62
62
|
const storyDesc = isActive
|
|
63
|
-
? `{
|
|
64
|
-
: `{
|
|
63
|
+
? `{gray-fg}${activeEpic}{/gray-fg} {gray-fg}›{/gray-fg} {cyan-fg}${activeStory}{/cyan-fg} {gray-fg}—{/gray-fg} ${stepName}`
|
|
64
|
+
: `{gray-fg}flow:{/gray-fg} ${activeFlow} {gray-fg}next:{/gray-fg} {cyan-fg}${stateData?.epicCycle?.next_skill ?? 'survey-context'}{/cyan-fg}`;
|
|
65
65
|
const stepLine =
|
|
66
|
-
`{
|
|
67
|
-
` {
|
|
68
|
-
` {
|
|
66
|
+
`{gray-fg}step {/gray-fg}{cyan-fg}${doneStories}{/cyan-fg}{gray-fg}/${totalStories}{/gray-fg}` +
|
|
67
|
+
` {gray-fg}—{/gray-fg} ${statusWord}` +
|
|
68
|
+
` {gray-fg}—{/gray-fg} ${storyDesc}`;
|
|
69
69
|
|
|
70
70
|
// ── Line 3: stats row ──
|
|
71
71
|
const statsLine =
|
|
72
|
-
`{
|
|
73
|
-
` {
|
|
74
|
-
` {
|
|
75
|
-
` {
|
|
76
|
-
` {
|
|
77
|
-
` {
|
|
72
|
+
`{gray-fg}[{/gray-fg} epics {green-fg}${doneEpics}${doneEpics > 0 ? '' : ''}{/green-fg}{gray-fg}/${totalEpics} ]{/gray-fg}` +
|
|
73
|
+
` {gray-fg}[{/gray-fg} stories {cyan-fg}${doneStories}{/cyan-fg}{gray-fg}/${totalStories} ]{/gray-fg}` +
|
|
74
|
+
` {gray-fg}[{/gray-fg} BCPs {yellow-fg}${deliveredBcps}{/yellow-fg}{gray-fg}/${targetBcps} ]{/gray-fg}` +
|
|
75
|
+
` {gray-fg}[{/gray-fg} cycle ${cycleDisplay}{gray-fg} ]{/gray-fg}` +
|
|
76
|
+
` {gray-fg}[{/gray-fg} BCP/hr {${bphColor}-fg}${bphDisplay}{/${bphColor}-fg}{gray-fg} ]{/gray-fg}` +
|
|
77
|
+
` {gray-fg}[{/gray-fg} v{green-fg}${version}{/green-fg}{gray-fg} ]{/gray-fg}`;
|
|
78
78
|
|
|
79
79
|
box.setContent([statusLine, stepLine, statsLine].join('\n'));
|
|
80
80
|
}
|
|
@@ -8,7 +8,7 @@ function renderPipeline(box, stateData) {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
if (!stateData) {
|
|
11
|
-
box.setContent('{
|
|
11
|
+
box.setContent('{gray-fg}state.yaml not loaded{/gray-fg}');
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -24,13 +24,13 @@ function renderPipeline(box, stateData) {
|
|
|
24
24
|
} else if (i === currentIdx) {
|
|
25
25
|
return `{reverse}{cyan-fg}${i + 1} ${step}{/cyan-fg}{/reverse}`;
|
|
26
26
|
} else {
|
|
27
|
-
return `{
|
|
27
|
+
return `{gray-fg}${i + 1} ${step}{/gray-fg}`;
|
|
28
28
|
}
|
|
29
|
-
}).join(' {
|
|
29
|
+
}).join(' {gray-fg}›{/gray-fg} ');
|
|
30
30
|
|
|
31
31
|
const stepLabel = currentIdx >= 0 && currentIdx < STEPS.length
|
|
32
|
-
? `{
|
|
33
|
-
: '{
|
|
32
|
+
? `{gray-fg}step{/gray-fg} {cyan-fg}${currentIdx + 1}{/cyan-fg}{gray-fg}/${STEPS.length}{/gray-fg} {gray-fg}—{/gray-fg} ${STEPS[currentIdx]}`
|
|
33
|
+
: '{gray-fg}no active step{/gray-fg}';
|
|
34
34
|
|
|
35
35
|
box.setContent(stepLabel + '\n\n' + strip);
|
|
36
36
|
}
|
|
@@ -10,7 +10,7 @@ function renderStateYaml(box, stateData) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
if (!stateData) {
|
|
13
|
-
box.setContent('{center}{
|
|
13
|
+
box.setContent('{center}{gray-fg}state.yaml not found{/gray-fg}{/center}');
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -34,7 +34,7 @@ function renderStateYaml(box, stateData) {
|
|
|
34
34
|
const isDash = v === '—';
|
|
35
35
|
let colored;
|
|
36
36
|
if (isDash) {
|
|
37
|
-
colored = `{
|
|
37
|
+
colored = `{gray-fg}${v}{/gray-fg}`;
|
|
38
38
|
} else if (fields.find(f => f.key === key)?.color === 'cyan') {
|
|
39
39
|
colored = `{cyan-fg}${v}{/cyan-fg}`;
|
|
40
40
|
} else if (fields.find(f => f.key === key)?.color === 'green') {
|
|
@@ -42,19 +42,19 @@ function renderStateYaml(box, stateData) {
|
|
|
42
42
|
} else if (fields.find(f => f.key === key)?.color === 'yellow') {
|
|
43
43
|
colored = `{yellow-fg}${v}{/yellow-fg}`;
|
|
44
44
|
} else if (fields.find(f => f.key === key)?.color === 'dim') {
|
|
45
|
-
colored = `{
|
|
45
|
+
colored = `{gray-fg}${v}{/gray-fg}`;
|
|
46
46
|
} else {
|
|
47
47
|
colored = v;
|
|
48
48
|
}
|
|
49
|
-
return `{
|
|
49
|
+
return `{gray-fg}${key}:{/gray-fg} ${colored}`;
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
// Stage tracker strip
|
|
53
53
|
const tracker = STEP_ABBR.map((abbr, i) => {
|
|
54
54
|
if (i < currentIdx) return `{green-fg}${abbr}{/green-fg}`;
|
|
55
55
|
if (i === currentIdx) return `{cyan-fg}{bold}${abbr}{/bold}{/cyan-fg}`;
|
|
56
|
-
return `{
|
|
57
|
-
}).join(' {
|
|
56
|
+
return `{gray-fg}${abbr}{/gray-fg}`;
|
|
57
|
+
}).join(' {gray-fg}·{/gray-fg} ');
|
|
58
58
|
|
|
59
59
|
lines.push('');
|
|
60
60
|
lines.push(tracker);
|