@sienklogic/plan-build-run 2.26.1 → 2.26.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/CHANGELOG.md +7 -0
- package/dashboard/public/css/layout.css +110 -3
- package/dashboard/src/services/roadmap.service.js +28 -0
- package/dashboard/src/views/partials/activity-feed.ejs +9 -2
- package/dashboard/src/views/partials/analytics-content.ejs +4 -4
- package/dashboard/src/views/partials/config-content.ejs +28 -8
- package/dashboard/src/views/partials/dashboard-content.ejs +7 -1
- package/dashboard/src/views/partials/logs-content.ejs +4 -1
- package/dashboard/src/views/partials/milestones-content.ejs +34 -4
- package/dashboard/src/views/partials/notes-content.ejs +10 -11
- package/dashboard/src/views/partials/phase-timeline.ejs +5 -1
- package/dashboard/src/views/partials/phases-content.ejs +1 -2
- package/dashboard/src/views/partials/research-content.ejs +7 -0
- package/dashboard/src/views/partials/sidebar.ejs +2 -2
- package/dashboard/src/views/partials/todos-content.ejs +2 -2
- package/package.json +1 -1
- package/plugins/copilot-pbr/plugin.json +1 -1
- package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
- package/plugins/pbr/.claude-plugin/plugin.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to Plan-Build-Run will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.26.2](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.26.1...plan-build-run-v2.26.2) (2026-02-24)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **36-08:** improve dashboard UX across 12 pages with 16 visual fixes ([3e0d715](https://github.com/SienkLogic/plan-build-run/commit/3e0d715bb93c7fa18d93960e7ca322c14a1c9deb))
|
|
14
|
+
|
|
8
15
|
## [2.26.1](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.26.0...plan-build-run-v2.26.1) (2026-02-24)
|
|
9
16
|
|
|
10
17
|
|
|
@@ -164,6 +164,30 @@ aside.sidebar nav a[aria-current="page"] {
|
|
|
164
164
|
margin-top: 2px;
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
/* --- Sidebar: Next Action --- */
|
|
168
|
+
.sidebar-next-action {
|
|
169
|
+
padding: var(--space-sm) var(--space-lg);
|
|
170
|
+
border-bottom: 1px solid var(--color-border);
|
|
171
|
+
overflow: hidden;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.sidebar-next-action small {
|
|
175
|
+
text-transform: uppercase;
|
|
176
|
+
letter-spacing: 0.04em;
|
|
177
|
+
font-size: 0.6875rem;
|
|
178
|
+
color: var(--color-text-dim);
|
|
179
|
+
display: block;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.sidebar-next-action__cmd {
|
|
183
|
+
display: block;
|
|
184
|
+
font-size: 0.75rem;
|
|
185
|
+
margin-top: 2px;
|
|
186
|
+
overflow: hidden;
|
|
187
|
+
text-overflow: ellipsis;
|
|
188
|
+
white-space: nowrap;
|
|
189
|
+
}
|
|
190
|
+
|
|
167
191
|
/* --- Sidebar: Section Details --- */
|
|
168
192
|
aside.sidebar details {
|
|
169
193
|
border: none;
|
|
@@ -171,22 +195,29 @@ aside.sidebar details {
|
|
|
171
195
|
padding: 0;
|
|
172
196
|
}
|
|
173
197
|
|
|
198
|
+
aside.sidebar details + details {
|
|
199
|
+
margin-top: var(--space-xs);
|
|
200
|
+
}
|
|
201
|
+
|
|
174
202
|
aside.sidebar details summary {
|
|
175
203
|
text-transform: uppercase;
|
|
176
|
-
font-size: 0.
|
|
204
|
+
font-size: 0.6875rem;
|
|
177
205
|
font-weight: 600;
|
|
178
|
-
letter-spacing: 0.
|
|
206
|
+
letter-spacing: 0.06em;
|
|
179
207
|
color: var(--color-text-dim);
|
|
180
|
-
padding: var(--space-
|
|
208
|
+
padding: var(--space-xs) var(--space-lg);
|
|
181
209
|
cursor: pointer;
|
|
210
|
+
border-left: 3px solid transparent;
|
|
182
211
|
}
|
|
183
212
|
|
|
184
213
|
aside.sidebar details[open] summary {
|
|
185
214
|
color: var(--color-accent);
|
|
215
|
+
border-left-color: var(--color-accent);
|
|
186
216
|
}
|
|
187
217
|
|
|
188
218
|
aside.sidebar details ul {
|
|
189
219
|
margin: 0;
|
|
220
|
+
padding-bottom: var(--space-xs);
|
|
190
221
|
}
|
|
191
222
|
|
|
192
223
|
/* --- Main Content --- */
|
|
@@ -422,6 +453,82 @@ details li {
|
|
|
422
453
|
font-weight: 500;
|
|
423
454
|
}
|
|
424
455
|
|
|
456
|
+
/* --- Phase Timeline (homepage) --- */
|
|
457
|
+
.phase-timeline {
|
|
458
|
+
list-style: none;
|
|
459
|
+
padding: 0;
|
|
460
|
+
margin: 0;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.phase-step {
|
|
464
|
+
display: flex;
|
|
465
|
+
align-items: center;
|
|
466
|
+
gap: var(--space-sm);
|
|
467
|
+
padding: var(--space-xs) 0;
|
|
468
|
+
border-bottom: 1px solid var(--color-border);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.phase-step:last-child {
|
|
472
|
+
border-bottom: none;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.step-label {
|
|
476
|
+
text-decoration: none;
|
|
477
|
+
display: flex;
|
|
478
|
+
gap: var(--space-sm);
|
|
479
|
+
align-items: baseline;
|
|
480
|
+
flex: 1;
|
|
481
|
+
min-width: 0;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.step-label strong {
|
|
485
|
+
font-size: 0.85rem;
|
|
486
|
+
white-space: nowrap;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.step-name {
|
|
490
|
+
font-size: 0.85rem;
|
|
491
|
+
color: var(--color-text-dim);
|
|
492
|
+
overflow: hidden;
|
|
493
|
+
text-overflow: ellipsis;
|
|
494
|
+
white-space: nowrap;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/* --- Activity Feed (homepage) --- */
|
|
498
|
+
.activity-feed {
|
|
499
|
+
list-style: none;
|
|
500
|
+
padding: 0;
|
|
501
|
+
margin: 0;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
.activity-item {
|
|
505
|
+
display: flex;
|
|
506
|
+
justify-content: space-between;
|
|
507
|
+
align-items: baseline;
|
|
508
|
+
gap: var(--space-md);
|
|
509
|
+
padding: var(--space-xs) 0;
|
|
510
|
+
border-bottom: 1px solid var(--color-border);
|
|
511
|
+
font-size: 0.85rem;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.activity-item:last-child {
|
|
515
|
+
border-bottom: none;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.activity-path {
|
|
519
|
+
overflow: hidden;
|
|
520
|
+
text-overflow: ellipsis;
|
|
521
|
+
white-space: nowrap;
|
|
522
|
+
min-width: 0;
|
|
523
|
+
flex: 1;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
.activity-time {
|
|
527
|
+
white-space: nowrap;
|
|
528
|
+
color: var(--color-text-dim);
|
|
529
|
+
font-size: 0.8rem;
|
|
530
|
+
}
|
|
531
|
+
|
|
425
532
|
/* Phase Navigation */
|
|
426
533
|
.phase-nav {
|
|
427
534
|
display: grid;
|
|
@@ -111,6 +111,34 @@ function extractMilestones(roadmapContent) {
|
|
|
111
111
|
});
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
// Parse milestones that use ### Phase NN: format instead of **Phases:** N - M
|
|
115
|
+
// Format: "## Milestone: Name\n\nDescription\n\n### Phase NN: ..."
|
|
116
|
+
const sectionRegex = /## Milestone:\s*([^\n]+?)(?:\s*\{[^}]*\})?\s*\n([\s\S]*?)(?=\n## |\n---|\n$)/g;
|
|
117
|
+
for (const match of roadmapContent.matchAll(sectionRegex)) {
|
|
118
|
+
const rawName = match[1].trim();
|
|
119
|
+
// Skip already-seen (explicit or completed formats)
|
|
120
|
+
if (seenNames.has(rawName)) continue;
|
|
121
|
+
// Skip collapsed "-- COMPLETED" entries (already handled above)
|
|
122
|
+
if (/--\s*COMPLETED/i.test(rawName)) continue;
|
|
123
|
+
const body = match[2];
|
|
124
|
+
// Find ### Phase NN: lines within this milestone section
|
|
125
|
+
const phaseLines = [...body.matchAll(/### Phase\s+(\d+):/g)];
|
|
126
|
+
if (phaseLines.length > 0) {
|
|
127
|
+
const phaseIds = phaseLines.map(m => parseInt(m[1], 10));
|
|
128
|
+
const startPhase = Math.min(...phaseIds);
|
|
129
|
+
const endPhase = Math.max(...phaseIds);
|
|
130
|
+
// Extract goal from first paragraph (before first ### heading)
|
|
131
|
+
const goalText = body.split(/### /)[0].trim();
|
|
132
|
+
seenNames.add(rawName);
|
|
133
|
+
explicit.push({
|
|
134
|
+
name: rawName,
|
|
135
|
+
goal: goalText || '',
|
|
136
|
+
startPhase,
|
|
137
|
+
endPhase
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
114
142
|
// Sort explicit milestones by start phase
|
|
115
143
|
explicit.sort((a, b) => a.startPhase - b.startPhase);
|
|
116
144
|
|
|
@@ -3,9 +3,16 @@
|
|
|
3
3
|
<% } else { %>
|
|
4
4
|
<ul class="activity-feed">
|
|
5
5
|
<% recentActivity.forEach(function(item) { %>
|
|
6
|
+
<%
|
|
7
|
+
// Format path: strip .planning/ prefix for brevity
|
|
8
|
+
var displayPath = item.path.replace(/^\.planning\//, '');
|
|
9
|
+
// Format timestamp: show just date+time, no timezone
|
|
10
|
+
var ts = item.timestamp || '';
|
|
11
|
+
var dateOnly = ts.replace(/\s+[-+]\d{4}$/, '').replace(/:\d{2}$/, '');
|
|
12
|
+
%>
|
|
6
13
|
<li class="activity-item">
|
|
7
|
-
<span class="activity-path"><%=
|
|
8
|
-
<time class="activity-time" datetime="<%=
|
|
14
|
+
<span class="activity-path"><%= displayPath %></span>
|
|
15
|
+
<time class="activity-time" datetime="<%= ts %>"><%= dateOnly %></time>
|
|
9
16
|
</li>
|
|
10
17
|
<% }); %>
|
|
11
18
|
</ul>
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
<% if (typeof llmMetrics !== 'undefined' && llmMetrics) { %>
|
|
93
93
|
<article>
|
|
94
94
|
<header>Local LLM Offload</header>
|
|
95
|
-
<div class="grid">
|
|
95
|
+
<div class="grid" style="grid-template-columns:repeat(auto-fit,minmax(140px,1fr))">
|
|
96
96
|
<article>
|
|
97
97
|
<header>Total Calls</header>
|
|
98
98
|
<strong class="stat-value"><%= llmMetrics.summary.total_calls %></strong>
|
|
@@ -104,17 +104,17 @@
|
|
|
104
104
|
<span class="stat-unit">frontier tokens</span>
|
|
105
105
|
</article>
|
|
106
106
|
<article>
|
|
107
|
-
<header>
|
|
107
|
+
<header>Cost Saved</header>
|
|
108
108
|
<strong class="stat-value">$<%= llmMetrics.summary.cost_saved_usd.toFixed(4) %></strong>
|
|
109
109
|
<span class="stat-unit">at $3/M tokens</span>
|
|
110
110
|
</article>
|
|
111
111
|
<article>
|
|
112
|
-
<header>
|
|
112
|
+
<header>Fallbacks</header>
|
|
113
113
|
<strong class="stat-value"><%= llmMetrics.summary.fallback_rate_pct %>%</strong>
|
|
114
114
|
<span class="stat-unit"><%= llmMetrics.summary.fallback_count %> fallbacks</span>
|
|
115
115
|
</article>
|
|
116
116
|
<article>
|
|
117
|
-
<header>
|
|
117
|
+
<header>Latency</header>
|
|
118
118
|
<strong class="stat-value"><%= llmMetrics.summary.avg_latency_ms %></strong>
|
|
119
119
|
<span class="stat-unit">ms/call</span>
|
|
120
120
|
</article>
|
|
@@ -132,37 +132,57 @@
|
|
|
132
132
|
</fieldset>
|
|
133
133
|
<% } %>
|
|
134
134
|
|
|
135
|
-
<%# Parallelization number
|
|
135
|
+
<%# Parallelization inputs (toggles for booleans, number for numbers) %>
|
|
136
136
|
<% if (config.parallelization && typeof config.parallelization === 'object') { %>
|
|
137
137
|
<fieldset class="config-fieldset">
|
|
138
138
|
<legend>Parallelization</legend>
|
|
139
139
|
<% for (const [key, val] of Object.entries(config.parallelization)) { %>
|
|
140
|
+
<% if (typeof val === 'boolean') { %>
|
|
141
|
+
<div class="config-toggle-row">
|
|
142
|
+
<label>
|
|
143
|
+
<input type="checkbox" role="switch" name="parallelization.<%= key %>" value="on" <%= val ? 'checked' : '' %> />
|
|
144
|
+
<%= key %>
|
|
145
|
+
</label>
|
|
146
|
+
</div>
|
|
147
|
+
<% } else if (typeof val === 'number') { %>
|
|
140
148
|
<div class="config-row">
|
|
141
149
|
<label for="cfg-par-<%= key %>"><%= key %></label>
|
|
142
|
-
<% if (typeof val === 'number') { %>
|
|
143
150
|
<input id="cfg-par-<%= key %>" type="number" name="parallelization.<%= key %>" value="<%= val %>" min="1" />
|
|
144
|
-
|
|
151
|
+
</div>
|
|
152
|
+
<% } else { %>
|
|
153
|
+
<div class="config-row">
|
|
154
|
+
<label for="cfg-par-<%= key %>"><%= key %></label>
|
|
145
155
|
<input id="cfg-par-<%= key %>" type="text" name="parallelization.<%= key %>" value="<%= val %>" />
|
|
146
|
-
<% } %>
|
|
147
156
|
</div>
|
|
148
157
|
<% } %>
|
|
158
|
+
<% } %>
|
|
149
159
|
</fieldset>
|
|
150
160
|
<% } %>
|
|
151
161
|
|
|
152
|
-
<%# Planning number
|
|
162
|
+
<%# Planning inputs (toggles for booleans, number for numbers) %>
|
|
153
163
|
<% if (config.planning && typeof config.planning === 'object') { %>
|
|
154
164
|
<fieldset class="config-fieldset">
|
|
155
165
|
<legend>Planning</legend>
|
|
156
166
|
<% for (const [key, val] of Object.entries(config.planning)) { %>
|
|
167
|
+
<% if (typeof val === 'boolean') { %>
|
|
168
|
+
<div class="config-toggle-row">
|
|
169
|
+
<label>
|
|
170
|
+
<input type="checkbox" role="switch" name="planning.<%= key %>" value="on" <%= val ? 'checked' : '' %> />
|
|
171
|
+
<%= key %>
|
|
172
|
+
</label>
|
|
173
|
+
</div>
|
|
174
|
+
<% } else if (typeof val === 'number') { %>
|
|
157
175
|
<div class="config-row">
|
|
158
176
|
<label for="cfg-plan-<%= key %>"><%= key %></label>
|
|
159
|
-
<% if (typeof val === 'number') { %>
|
|
160
177
|
<input id="cfg-plan-<%= key %>" type="number" name="planning.<%= key %>" value="<%= val %>" />
|
|
161
|
-
|
|
178
|
+
</div>
|
|
179
|
+
<% } else { %>
|
|
180
|
+
<div class="config-row">
|
|
181
|
+
<label for="cfg-plan-<%= key %>"><%= key %></label>
|
|
162
182
|
<input id="cfg-plan-<%= key %>" type="text" name="planning.<%= key %>" value="<%= val %>" />
|
|
163
|
-
<% } %>
|
|
164
183
|
</div>
|
|
165
184
|
<% } %>
|
|
185
|
+
<% } %>
|
|
166
186
|
</fieldset>
|
|
167
187
|
<% } %>
|
|
168
188
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
<%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
|
|
2
|
-
|
|
2
|
+
<%
|
|
3
|
+
// Show just the phase name as h1, not the full focus description
|
|
4
|
+
var dashboardTitle = (typeof currentPhase !== 'undefined' && currentPhase && currentPhase.name)
|
|
5
|
+
? currentPhase.name
|
|
6
|
+
: (typeof projectName !== 'undefined' ? projectName.split(/\s*[—–-]\s*/)[0] : 'Dashboard');
|
|
7
|
+
%>
|
|
8
|
+
<h1><%= dashboardTitle %></h1>
|
|
3
9
|
|
|
4
10
|
<!-- Status Cards -->
|
|
5
11
|
<div class="status-cards">
|
|
@@ -98,7 +98,10 @@
|
|
|
98
98
|
<% } %>
|
|
99
99
|
|
|
100
100
|
<% } else { %>
|
|
101
|
-
<
|
|
101
|
+
<div style="text-align:center;padding:var(--space-xl) var(--space-md);color:var(--color-text-dim)">
|
|
102
|
+
<p style="font-size:1.5rem;margin-bottom:var(--space-sm)">←</p>
|
|
103
|
+
<p>Select a log file from the list to view entries.</p>
|
|
104
|
+
</div>
|
|
102
105
|
<% } %>
|
|
103
106
|
</div>
|
|
104
107
|
</div>
|
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
<%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
|
|
2
2
|
<h1>Milestones</h1>
|
|
3
3
|
|
|
4
|
-
<%
|
|
4
|
+
<%
|
|
5
|
+
// Filter out milestones that the parser already flagged as completed (collapsed in ROADMAP.md)
|
|
6
|
+
var nonCollapsed = active.filter(function(m) { return !m.completed; });
|
|
7
|
+
|
|
8
|
+
// From non-collapsed, separate truly active from ones whose phases are all complete
|
|
9
|
+
var trulyActive = nonCollapsed.filter(function(m) {
|
|
10
|
+
var msPhases = (typeof phases !== 'undefined' && phases) ? phases.filter(function(p) { return p.id >= m.startPhase && p.id <= m.endPhase; }) : [];
|
|
11
|
+
var completedPhases = msPhases.filter(function(p) { return p.status === 'complete'; }).length;
|
|
12
|
+
return msPhases.length === 0 || completedPhases < msPhases.length;
|
|
13
|
+
});
|
|
14
|
+
var completedNotArchived = nonCollapsed.filter(function(m) {
|
|
15
|
+
var msPhases = (typeof phases !== 'undefined' && phases) ? phases.filter(function(p) { return p.id >= m.startPhase && p.id <= m.endPhase; }) : [];
|
|
16
|
+
var completedPhases = msPhases.filter(function(p) { return p.status === 'complete'; }).length;
|
|
17
|
+
return msPhases.length > 0 && completedPhases >= msPhases.length;
|
|
18
|
+
});
|
|
19
|
+
%>
|
|
20
|
+
|
|
21
|
+
<% if (trulyActive.length > 0) { %>
|
|
5
22
|
<h2>Active</h2>
|
|
6
|
-
<%
|
|
23
|
+
<% trulyActive.forEach(function(m) {
|
|
7
24
|
var msPhases = (typeof phases !== 'undefined' && phases) ? phases.filter(function(p) { return p.id >= m.startPhase && p.id <= m.endPhase; }) : [];
|
|
8
25
|
var totalPhases = msPhases.length;
|
|
9
26
|
var completedPhases = msPhases.filter(function(p) { return p.status === 'complete'; }).length;
|
|
@@ -24,6 +41,19 @@
|
|
|
24
41
|
<% }); %>
|
|
25
42
|
<% } %>
|
|
26
43
|
|
|
44
|
+
<% if (completedNotArchived.length > 0) { %>
|
|
45
|
+
<h2>Completed (Pending Archive)</h2>
|
|
46
|
+
<% completedNotArchived.forEach(function(m) { %>
|
|
47
|
+
<article>
|
|
48
|
+
<header>
|
|
49
|
+
<strong><%= m.name %></strong>
|
|
50
|
+
<span class="status-badge status-badge--sm" data-status="complete" style="float:right">completed</span>
|
|
51
|
+
</header>
|
|
52
|
+
<p>Phases <%= m.startPhase %> – <%= m.endPhase %></p>
|
|
53
|
+
</article>
|
|
54
|
+
<% }); %>
|
|
55
|
+
<% } %>
|
|
56
|
+
|
|
27
57
|
<% if (archived.length > 0) { %>
|
|
28
58
|
<h2>Archived</h2>
|
|
29
59
|
<article>
|
|
@@ -45,12 +75,12 @@
|
|
|
45
75
|
<td colspan="6" style="padding:0">
|
|
46
76
|
<details>
|
|
47
77
|
<summary style="padding:0.5rem 1rem;cursor:pointer">
|
|
48
|
-
<span class="grid" style="display:inline-grid;grid-template-columns:
|
|
78
|
+
<span class="grid" style="display:inline-grid;grid-template-columns:60px 2fr 1fr 1fr 60px 60px;width:100%;text-align:left;gap:var(--space-sm)">
|
|
49
79
|
<span><a href="/milestones/<%= m.version %>"
|
|
50
80
|
hx-get="/milestones/<%= m.version %>"
|
|
51
81
|
hx-target="#main-content"
|
|
52
82
|
hx-push-url="true">v<%= m.version %></a></span>
|
|
53
|
-
<span><%= m.name %></span>
|
|
83
|
+
<span style="white-space:nowrap;overflow:hidden;text-overflow:ellipsis"><%= m.name %></span>
|
|
54
84
|
<span><%= m.date || '—' %></span>
|
|
55
85
|
<span><%= m.duration || '—' %></span>
|
|
56
86
|
<span><%= m.stats && m.stats.phaseCount ? m.stats.phaseCount : '—' %></span>
|
|
@@ -6,24 +6,23 @@
|
|
|
6
6
|
<% } else { %>
|
|
7
7
|
<% notes.forEach(function(note) { %>
|
|
8
8
|
<% const noteSlug = note.filename.replace(/^\d{4}-\d{2}-\d{2}-/, '').replace(/\.md$/, ''); %>
|
|
9
|
-
<article>
|
|
10
|
-
<header>
|
|
9
|
+
<article class="card">
|
|
10
|
+
<header class="card__header">
|
|
11
11
|
<strong>
|
|
12
12
|
<a href="/notes/<%= noteSlug %>"
|
|
13
13
|
hx-get="/notes/<%= noteSlug %>"
|
|
14
14
|
hx-target="#main-content"
|
|
15
15
|
hx-push-url="true"><%= note.title %></a>
|
|
16
16
|
</strong>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
<span style="display:flex;gap:var(--space-sm);align-items:center;margin-left:auto">
|
|
18
|
+
<% if (note.promoted) { %>
|
|
19
|
+
<span class="status-badge status-badge--sm" data-status="complete">promoted</span>
|
|
20
|
+
<% } %>
|
|
21
|
+
<% if (note.date) { %>
|
|
22
|
+
<small style="color:var(--color-text-dim)"><%= typeof note.date === 'object' ? note.date.toISOString().slice(0, 10) : String(note.date).slice(0, 10) %></small>
|
|
23
|
+
<% } %>
|
|
24
|
+
</span>
|
|
23
25
|
</header>
|
|
24
|
-
<div class="markdown-body">
|
|
25
|
-
<%- note.html %>
|
|
26
|
-
</div>
|
|
27
26
|
</article>
|
|
28
27
|
<% }); %>
|
|
29
28
|
<% } %>
|
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
href="/phases/<%= String(phase.id).padStart(2, '0') %>"
|
|
10
10
|
hx-get="/phases/<%= String(phase.id).padStart(2, '0') %>"
|
|
11
11
|
hx-target="#main-content"
|
|
12
|
-
hx-push-url="true">
|
|
12
|
+
hx-push-url="true">
|
|
13
|
+
<strong>Phase <%= phase.id %></strong>
|
|
14
|
+
<span class="step-name"><%= phase.name %></span>
|
|
15
|
+
</a>
|
|
16
|
+
<span class="status-badge status-badge--sm" data-status="<%= phase.status %>"><%= phase.status %></span>
|
|
13
17
|
</li>
|
|
14
18
|
<% }); %>
|
|
15
19
|
</ol>
|
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
<article>
|
|
24
24
|
<header><strong>Summary</strong></header>
|
|
25
25
|
<p>
|
|
26
|
-
<%= phases.filter(p => p.status === 'complete').length %> of <%= phases.length %> phases complete
|
|
27
|
-
across <%= milestoneGroups.length %> milestone<%= milestoneGroups.length !== 1 ? 's' : '' %>.
|
|
26
|
+
<%= phases.filter(p => p.status === 'complete').length %> of <%= phases.length %> phases complete<%= milestoneGroups.length > 0 ? ' across ' + milestoneGroups.length + ' milestone' + (milestoneGroups.length !== 1 ? 's' : '') : '' %>.
|
|
28
27
|
</p>
|
|
29
28
|
<progress value="<%= phases.filter(p => p.status === 'complete').length %>" max="<%= phases.length %>"></progress>
|
|
30
29
|
</article>
|
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
<% if (doc.coverage) { %><small>Coverage: <%= doc.coverage %></small><% } %>
|
|
25
25
|
</p>
|
|
26
26
|
<% } %>
|
|
27
|
+
<% if (!doc.topic && !doc.confidence && !doc.coverage) { %>
|
|
28
|
+
<p class="muted"><small>Click to view full document</small></p>
|
|
29
|
+
<% } %>
|
|
27
30
|
</div>
|
|
28
31
|
</article>
|
|
29
32
|
<% }); %>
|
|
@@ -44,6 +47,10 @@
|
|
|
44
47
|
</strong>
|
|
45
48
|
<% if (doc.date) { %><small style="float:right"><%= doc.date %></small><% } %>
|
|
46
49
|
</header>
|
|
50
|
+
<div class="card__body">
|
|
51
|
+
<% if (doc.focus) { %><p><strong>Focus:</strong> <%= doc.focus %></p><% } %>
|
|
52
|
+
<% if (!doc.focus) { %><p class="muted"><small>Click to view full document</small></p><% } %>
|
|
53
|
+
</div>
|
|
47
54
|
</article>
|
|
48
55
|
<% }); %>
|
|
49
56
|
<% } %>
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
<% if (typeof currentPhase !== 'undefined' && currentPhase && currentPhase.nextAction) { %>
|
|
17
17
|
<div class="sidebar-next-action">
|
|
18
|
-
<small>Suggested next
|
|
19
|
-
<code><%= currentPhase.nextAction %></code>
|
|
18
|
+
<small>Suggested next</small>
|
|
19
|
+
<code class="sidebar-next-action__cmd"><%= currentPhase.nextAction %></code>
|
|
20
20
|
</div>
|
|
21
21
|
<% } %>
|
|
22
22
|
|
|
@@ -89,13 +89,13 @@
|
|
|
89
89
|
<%= todo.priority %>
|
|
90
90
|
</span>
|
|
91
91
|
</td>
|
|
92
|
-
<td><%= todo.phase %></td>
|
|
92
|
+
<td><%= todo.phase || '—' %></td>
|
|
93
93
|
<td>
|
|
94
94
|
<span class="status-badge" data-status="<%= todo.status %>">
|
|
95
95
|
<%= todo.status %>
|
|
96
96
|
</span>
|
|
97
97
|
</td>
|
|
98
|
-
<td><%= todo.created %></td>
|
|
98
|
+
<td><%= todo.created ? new Date(todo.created).toISOString().slice(0, 10) : '—' %></td>
|
|
99
99
|
</tr>
|
|
100
100
|
<% }); %>
|
|
101
101
|
</tbody>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
3
|
"displayName": "Plan-Build-Run",
|
|
4
|
-
"version": "2.26.
|
|
4
|
+
"version": "2.26.2",
|
|
5
5
|
"description": "Plan-Build-Run — Structured development workflow for GitHub Copilot CLI. Solves context rot through disciplined agent delegation, structured planning, atomic execution, and goal-backward verification.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "SienkLogic",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
3
|
"displayName": "Plan-Build-Run",
|
|
4
|
-
"version": "2.26.
|
|
4
|
+
"version": "2.26.2",
|
|
5
5
|
"description": "Plan-Build-Run — Structured development workflow for Cursor. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "SienkLogic",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
|
-
"version": "2.26.
|
|
3
|
+
"version": "2.26.2",
|
|
4
4
|
"description": "Plan-Build-Run — Structured development workflow for Claude Code. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SienkLogic",
|