@sienklogic/plan-build-run 2.31.0 → 2.32.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.
Files changed (82) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dashboard/public/css/settings.css +314 -0
  3. package/dashboard/src/components/Layout.tsx +1 -0
  4. package/dashboard/src/components/settings/LogEntryList.tsx +108 -0
  5. package/dashboard/src/components/settings/LogFileList.tsx +36 -0
  6. package/dashboard/src/components/settings/LogViewer.tsx +129 -0
  7. package/dashboard/src/components/settings/SettingsPage.tsx +1 -1
  8. package/dashboard/src/index.tsx +10 -2
  9. package/dashboard/src/routes/settings.routes.tsx +231 -0
  10. package/dashboard/src/services/config.service.d.ts +9 -0
  11. package/dashboard/src/services/log.service.d.ts +13 -0
  12. package/package.json +2 -2
  13. package/plugins/copilot-pbr/plugin.json +1 -1
  14. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
  15. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  16. package/dashboard/src/app.js +0 -91
  17. package/dashboard/src/middleware/current-phase.js +0 -25
  18. package/dashboard/src/middleware/errorHandler.js +0 -62
  19. package/dashboard/src/middleware/notFoundHandler.js +0 -9
  20. package/dashboard/src/routes/events.routes.js +0 -94
  21. package/dashboard/src/routes/index.routes.js +0 -35
  22. package/dashboard/src/routes/pages.routes.js +0 -853
  23. package/dashboard/src/views/analytics.ejs +0 -5
  24. package/dashboard/src/views/audit-detail.ejs +0 -5
  25. package/dashboard/src/views/audits.ejs +0 -5
  26. package/dashboard/src/views/config.ejs +0 -5
  27. package/dashboard/src/views/dependencies.ejs +0 -5
  28. package/dashboard/src/views/error.ejs +0 -20
  29. package/dashboard/src/views/index.ejs +0 -5
  30. package/dashboard/src/views/logs.ejs +0 -3
  31. package/dashboard/src/views/milestone-detail.ejs +0 -5
  32. package/dashboard/src/views/milestones.ejs +0 -5
  33. package/dashboard/src/views/note-detail.ejs +0 -3
  34. package/dashboard/src/views/notes.ejs +0 -5
  35. package/dashboard/src/views/partials/activity-feed.ejs +0 -27
  36. package/dashboard/src/views/partials/analytics-content.ejs +0 -241
  37. package/dashboard/src/views/partials/audit-detail-content.ejs +0 -14
  38. package/dashboard/src/views/partials/audits-content.ejs +0 -36
  39. package/dashboard/src/views/partials/breadcrumbs.ejs +0 -18
  40. package/dashboard/src/views/partials/config-content.ejs +0 -219
  41. package/dashboard/src/views/partials/dashboard-content.ejs +0 -124
  42. package/dashboard/src/views/partials/dependencies-content.ejs +0 -50
  43. package/dashboard/src/views/partials/empty-state.ejs +0 -12
  44. package/dashboard/src/views/partials/footer.ejs +0 -9
  45. package/dashboard/src/views/partials/head.ejs +0 -31
  46. package/dashboard/src/views/partials/header.ejs +0 -18
  47. package/dashboard/src/views/partials/layout-bottom.ejs +0 -8
  48. package/dashboard/src/views/partials/layout-top.ejs +0 -17
  49. package/dashboard/src/views/partials/log-entries-content.ejs +0 -17
  50. package/dashboard/src/views/partials/logs-content.ejs +0 -131
  51. package/dashboard/src/views/partials/milestone-detail-content.ejs +0 -20
  52. package/dashboard/src/views/partials/milestones-content.ejs +0 -127
  53. package/dashboard/src/views/partials/note-detail-content.ejs +0 -24
  54. package/dashboard/src/views/partials/notes-content.ejs +0 -28
  55. package/dashboard/src/views/partials/phase-content.ejs +0 -226
  56. package/dashboard/src/views/partials/phase-doc-content.ejs +0 -36
  57. package/dashboard/src/views/partials/phase-timeline.ejs +0 -27
  58. package/dashboard/src/views/partials/phases-content.ejs +0 -137
  59. package/dashboard/src/views/partials/quick-content.ejs +0 -42
  60. package/dashboard/src/views/partials/quick-detail-content.ejs +0 -30
  61. package/dashboard/src/views/partials/requirements-content.ejs +0 -44
  62. package/dashboard/src/views/partials/research-content.ejs +0 -56
  63. package/dashboard/src/views/partials/research-detail-content.ejs +0 -25
  64. package/dashboard/src/views/partials/roadmap-content.ejs +0 -197
  65. package/dashboard/src/views/partials/sidebar.ejs +0 -98
  66. package/dashboard/src/views/partials/todo-create-content.ejs +0 -59
  67. package/dashboard/src/views/partials/todo-detail-content.ejs +0 -43
  68. package/dashboard/src/views/partials/todos-content.ejs +0 -110
  69. package/dashboard/src/views/partials/todos-done-content.ejs +0 -46
  70. package/dashboard/src/views/phase-detail.ejs +0 -5
  71. package/dashboard/src/views/phase-doc.ejs +0 -5
  72. package/dashboard/src/views/phases.ejs +0 -5
  73. package/dashboard/src/views/quick-detail.ejs +0 -5
  74. package/dashboard/src/views/quick.ejs +0 -5
  75. package/dashboard/src/views/requirements.ejs +0 -3
  76. package/dashboard/src/views/research-detail.ejs +0 -3
  77. package/dashboard/src/views/research.ejs +0 -3
  78. package/dashboard/src/views/roadmap.ejs +0 -5
  79. package/dashboard/src/views/todo-create.ejs +0 -5
  80. package/dashboard/src/views/todo-detail.ejs +0 -5
  81. package/dashboard/src/views/todos-done.ejs +0 -3
  82. package/dashboard/src/views/todos.ejs +0 -5
@@ -1,226 +0,0 @@
1
- <%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
2
- <h1>Phase <%= phaseId %>: <%= phaseName %></h1>
3
-
4
- <nav class="phase-nav" aria-label="Phase navigation">
5
- <% if (typeof prevPhase !== 'undefined' && prevPhase) { %>
6
- <a href="/phases/<%= String(prevPhase.id).padStart(2, '0') %>"
7
- hx-get="/phases/<%= String(prevPhase.id).padStart(2, '0') %>"
8
- hx-target="#main-content"
9
- hx-push-url="true">
10
- &larr; Phase <%= String(prevPhase.id).padStart(2, '0') %>: <%= prevPhase.name %>
11
- </a>
12
- <% } else { %>
13
- <span></span>
14
- <% } %>
15
-
16
- <a href="/phases"
17
- hx-get="/phases"
18
- hx-target="#main-content"
19
- hx-push-url="true">All Phases</a>
20
-
21
- <% if (typeof nextPhase !== 'undefined' && nextPhase) { %>
22
- <a href="/phases/<%= String(nextPhase.id).padStart(2, '0') %>"
23
- hx-get="/phases/<%= String(nextPhase.id).padStart(2, '0') %>"
24
- hx-target="#main-content"
25
- hx-push-url="true">
26
- Phase <%= String(nextPhase.id).padStart(2, '0') %>: <%= nextPhase.name %> &rarr;
27
- </a>
28
- <% } else { %>
29
- <span></span>
30
- <% } %>
31
- </nav>
32
-
33
- <% if (verification) { %>
34
- <%
35
- var vStatus = verification.result || verification.status || verification.verdict || 'unknown';
36
- var verificationCssStatus = 'not-started';
37
- if (vStatus === 'pass' || vStatus === 'passed') verificationCssStatus = 'complete';
38
- else if (vStatus === 'fail' || vStatus === 'failed') verificationCssStatus = 'blocked';
39
- else if (vStatus === 'partial') verificationCssStatus = 'in-progress';
40
- %>
41
- <div class="card">
42
- <div class="card-header">
43
- <strong>Verification Status</strong>
44
- <span style="float:right;">
45
- <span class="status-badge" data-status="<%= verificationCssStatus %>"><%= vStatus.toUpperCase() %></span>
46
- </span>
47
- </div>
48
- <div class="card-body">
49
- <% if (verification.verified) { %>
50
- <p style="margin:0 0 var(--space-sm);">Verified: <%= new Date(verification.verified).toLocaleString() %></p>
51
- <% } %>
52
- <% if (verification.score) { %>
53
- <p style="margin:0 0 var(--space-sm);">
54
- Score: <%= verification.score.verified %>/<%= verification.score.total_must_haves %> must-haves verified
55
- <% if (verification.score.failed > 0) { %>
56
- &nbsp; <strong><%= verification.score.failed %> FAILED</strong>
57
- <% } %>
58
- </p>
59
- <% } %>
60
- <% if (verification.mustHaves && verification.mustHaves.length > 0) { %>
61
- <details>
62
- <summary>Must-Haves (<%= verification.mustHaves.length %>)</summary>
63
- <ul style="list-style:none;padding:0;margin:var(--space-sm) 0 0;">
64
- <% verification.mustHaves.forEach(function(mh) { %>
65
- <li style="display:flex;gap:var(--space-xs);align-items:flex-start;padding:var(--space-xs) 0;border-bottom:1px solid var(--color-border);">
66
- <span class="status-badge status-badge--sm" data-status="<%= mh.passed ? 'complete' : 'blocked' %>">
67
- <%= mh.passed ? 'PASS' : 'FAIL' %>
68
- </span>
69
- <span style="flex:1;font-size:0.875rem;"><%= mh.text %></span>
70
- </li>
71
- <% }); %>
72
- </ul>
73
- </details>
74
- <% } else if (verification.gaps && verification.gaps.length > 0) { %>
75
- <details>
76
- <summary>Verification Gaps (<%= verification.gaps.length %>)</summary>
77
- <ul><% verification.gaps.forEach(function(gap) { %><li><%= gap %></li><% }); %></ul>
78
- </details>
79
- <% } %>
80
- </div>
81
- </div>
82
- <% } %>
83
-
84
- <% if (plans.length === 0) { %>
85
- <!-- Empty State -->
86
- <%- include('empty-state', { title: 'No plans found for this phase.' }) %>
87
- <% } else { %>
88
-
89
- <h2>Plans (<%= plans.length %>)</h2>
90
-
91
- <!-- Plan Cards -->
92
- <% plans.forEach(function(plan) { %>
93
- <%
94
- var planStatus = (plan.summary && plan.summary.status) ? plan.summary.status : 'planned';
95
- var planCssStatus = planStatus === 'built' ? 'complete'
96
- : planStatus === 'building' ? 'in-progress'
97
- : planStatus === 'blocked' ? 'blocked'
98
- : 'not-started';
99
- var wave = (plan.summary && plan.summary.wave) ? plan.summary.wave : null;
100
- var taskCount = plan.taskCount || 0;
101
- var planTitle = plan.planTitle || ('Plan ' + plan.planId);
102
- %>
103
- <div class="card">
104
- <div class="card-header">
105
- <span><strong><%= planTitle %></strong></span>
106
- <span style="display:inline-flex;gap:var(--space-xs);align-items:center;float:right;">
107
- <% if (wave) { %>
108
- <span class="status-badge status-badge--sm" data-status="not-started" title="Wave <%= wave %>">W<%= wave %></span>
109
- <% } %>
110
- <% if (taskCount > 0) { %>
111
- <span class="status-badge status-badge--sm" data-status="not-started"><%= taskCount %> task<%= taskCount !== 1 ? 's' : '' %></span>
112
- <% } %>
113
- <span class="status-badge" data-status="<%= planCssStatus %>"><%= planStatus.replace(/-/g, ' ').toUpperCase() %></span>
114
- </span>
115
- </div>
116
- <div class="card-body">
117
- <p style="margin:0 0 var(--space-sm);">
118
- <a href="/phases/<%= phaseId %>/<%= plan.planId %>/plan"
119
- hx-get="/phases/<%= phaseId %>/<%= plan.planId %>/plan"
120
- hx-target="#main-content" hx-push-url="true">View Plan</a>
121
- <% if (plan.summary) { %>
122
- &nbsp;|&nbsp;
123
- <a href="/phases/<%= phaseId %>/<%= plan.planId %>/summary"
124
- hx-get="/phases/<%= phaseId %>/<%= plan.planId %>/summary"
125
- hx-target="#main-content" hx-push-url="true">View Summary</a>
126
- <% } %>
127
- <% if (verification) { %>
128
- &nbsp;|&nbsp;
129
- <a href="/phases/<%= phaseId %>/<%= plan.planId %>/verification"
130
- hx-get="/phases/<%= phaseId %>/<%= plan.planId %>/verification"
131
- hx-target="#main-content" hx-push-url="true">View Verification</a>
132
- <% } %>
133
- </p>
134
-
135
- <% if (plan.summary) { %>
136
- <% if (plan.summary.subsystem) { %>
137
- <p><strong>Subsystem:</strong> <%= plan.summary.subsystem %></p>
138
- <% } %>
139
- <% if (plan.summary.key_decisions && plan.summary.key_decisions.length > 0) { %>
140
- <details>
141
- <summary>Key Decisions (<%= plan.summary.key_decisions.length %>)</summary>
142
- <ul><% plan.summary.key_decisions.forEach(function(d) { %><li><%= d %></li><% }); %></ul>
143
- </details>
144
- <% } %>
145
- <% if (plan.summary.key_files && plan.summary.key_files.length > 0) { %>
146
- <details>
147
- <summary>Key Files (<%= plan.summary.key_files.length %>)</summary>
148
- <ul><% plan.summary.key_files.forEach(function(f) { %><li><code><%= f %></code></li><% }); %></ul>
149
- </details>
150
- <% } %>
151
- <% if (plan.summary.deferred && plan.summary.deferred.length > 0) { %>
152
- <details>
153
- <summary>Deferred Items (<%= plan.summary.deferred.length %>)</summary>
154
- <ul><% plan.summary.deferred.forEach(function(item) { %><li><%= item %></li><% }); %></ul>
155
- </details>
156
- <% } %>
157
- <% if (plan.summary.metrics) { %>
158
- <p style="margin-top:var(--space-sm);">
159
- <small>
160
- <% if (plan.summary.metrics.duration_minutes != null) { %>Duration: <%= plan.summary.metrics.duration_minutes %> min<% } %>
161
- <% if (plan.summary.metrics.commits != null) { %> | Commits: <%= plan.summary.metrics.commits %><% } %>
162
- <% if (plan.summary.metrics.files_created != null || plan.summary.metrics.files_modified != null) { %>
163
- | Files: <%= plan.summary.metrics.files_created || 0 %> created, <%= plan.summary.metrics.files_modified || 0 %> modified
164
- <% } %>
165
- </small>
166
- </p>
167
- <% } %>
168
- <% } else { %>
169
- <p><em>Plan file exists but has not been executed yet. No summary available.</em></p>
170
- <% } %>
171
- </div>
172
- </div>
173
- <% }); %>
174
-
175
- <% } %>
176
-
177
- <!-- Commit History Section -->
178
- <%
179
- var allCommits = [];
180
- plans.forEach(function(plan) {
181
- if (plan.commits && plan.commits.length > 0) {
182
- plan.commits.forEach(function(commit) {
183
- allCommits.push({ planId: plan.planId, commit: commit });
184
- });
185
- }
186
- });
187
-
188
- // Extract commit type from task string: "NN-NN-T1: feat(scope): msg" -> "feat"
189
- function commitType(entry) {
190
- var m = entry.commit.task && entry.commit.task.match(/\b(feat|fix|refactor|test|docs|chore|wip|perf)\b/i);
191
- return m ? m[1].toLowerCase() : 'chore';
192
- }
193
-
194
- var typeStatusMap = {
195
- feat: 'complete', fix: 'in-progress', refactor: 'not-started',
196
- test: 'not-started', docs: 'not-started', chore: 'not-started',
197
- wip: 'in-progress', perf: 'complete'
198
- };
199
- %>
200
-
201
- <h2>Commit History (<%= allCommits.length %>)</h2>
202
-
203
- <% if (allCommits.length === 0) { %>
204
- <div class="card"><div class="card-body"><p><em>No commits yet for this phase.</em></p></div></div>
205
- <% } else { %>
206
- <ol class="commit-timeline">
207
- <% allCommits.forEach(function(entry) { %>
208
- <%
209
- var ctype = commitType(entry);
210
- var cStatus = typeStatusMap[ctype] || 'not-started';
211
- var verifyStatus = entry.commit.verify === 'passed' ? 'complete'
212
- : entry.commit.verify === 'failed' ? 'blocked' : 'in-progress';
213
- %>
214
- <li class="commit-timeline__item">
215
- <span class="status-badge status-badge--sm" data-status="<%= cStatus %>" title="<%= ctype %>"><%= ctype %></span>
216
- <code class="commit-timeline__hash"><%= entry.commit.hash %></code>
217
- <span class="commit-timeline__task"><%= entry.commit.task %></span>
218
- <span class="commit-timeline__meta">
219
- plan <strong><%= entry.planId %></strong>
220
- &middot; <%= entry.commit.files %> file<%= entry.commit.files !== 1 ? 's' : '' %>
221
- &middot; <span class="status-badge status-badge--sm" data-status="<%= verifyStatus %>"><%= entry.commit.verify %></span>
222
- </span>
223
- </li>
224
- <% }); %>
225
- </ol>
226
- <% } %>
@@ -1,36 +0,0 @@
1
- <%
2
- var docLabel = docType === 'plan' ? 'Plan' : docType === 'verification' ? 'Verification' : 'Summary';
3
- %>
4
- <%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
5
- <h1><%= docLabel %> <%= planId %></h1>
6
-
7
- <p><a href="/phases/<%= phaseId %>" class="btn btn-outline-secondary">&larr; Back to Phase <%= phaseId %>: <%= phaseName %></a></p>
8
-
9
- <% if (frontmatter && Object.keys(frontmatter).length > 0) { %>
10
- <div class="card mb-3">
11
- <div class="card-header"><strong>Metadata</strong></div>
12
- <div class="table-responsive">
13
- <table class="table table-vcenter">
14
- <tbody>
15
- <% Object.entries(frontmatter).forEach(function([key, val]) { %>
16
- <% if (typeof val !== 'object' || val === null) { %>
17
- <tr>
18
- <td><strong><%= key %></strong></td>
19
- <td><%= val %></td>
20
- </tr>
21
- <% } %>
22
- <% }); %>
23
- </tbody>
24
- </table>
25
- </div>
26
- </div>
27
- <% } %>
28
-
29
- <div class="card mb-3">
30
- <div class="card-header"><strong>Content</strong></div>
31
- <div class="card-body">
32
- <div class="markdown-body">
33
- <%- html %>
34
- </div>
35
- </div>
36
- </div>
@@ -1,27 +0,0 @@
1
- <% if (!phases || phases.length === 0) { %>
2
- <%- include('empty-state', { title: 'No phases found' }) %>
3
- <% } else { %>
4
- <div class="list-group list-group-flush">
5
- <% phases.forEach(function(phase) { %>
6
- <div class="list-group-item<%= currentPhase && phase.id === currentPhase.id ? ' active' : '' %>"
7
- data-status="<%= phase.status %>"
8
- <% if (currentPhase && phase.id === currentPhase.id) { %> aria-current="step"<% } %>>
9
- <div class="row align-items-center">
10
- <div class="col">
11
- <a class="text-decoration-none"
12
- href="/phases/<%= String(phase.id).padStart(2, '0') %>"
13
- hx-get="/phases/<%= String(phase.id).padStart(2, '0') %>"
14
- hx-target="#main-content"
15
- hx-push-url="true">
16
- <strong class="me-2">Phase <%= phase.id %></strong>
17
- <span class="text-muted small"><%= phase.name %></span>
18
- </a>
19
- </div>
20
- <div class="col-auto">
21
- <span class="status-badge status-badge--sm" data-status="<%= phase.status %>"><%= phase.status %></span>
22
- </div>
23
- </div>
24
- </div>
25
- <% }); %>
26
- </div>
27
- <% } %>
@@ -1,137 +0,0 @@
1
- <%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
2
- <h1>Phases</h1>
3
-
4
- <% if (phases.length === 0) { %>
5
- <div class="card mb-3">
6
- <div class="card-body">
7
- <p>No phases found. Add a ROADMAP.md file to your .planning/ directory to see phases here.</p>
8
- </div>
9
- </div>
10
- <% } else { %>
11
-
12
- <%
13
- // Build milestone-to-phases mapping
14
- const milestoneGroups = milestones.map(m => ({
15
- ...m,
16
- phases: phases.filter(p => p.id >= m.startPhase && p.id <= m.endPhase)
17
- })).filter(g => g.phases.length > 0);
18
-
19
- // Collect any phases not covered by a milestone
20
- const coveredIds = new Set(milestoneGroups.flatMap(g => g.phases.map(p => p.id)));
21
- const ungrouped = phases.filter(p => !coveredIds.has(p.id));
22
- %>
23
-
24
- <!-- Summary -->
25
- <div class="card mb-3">
26
- <div class="card-header"><strong>Summary</strong></div>
27
- <div class="card-body">
28
- <p>
29
- <%= phases.filter(p => p.status === 'complete').length %> of <%= phases.length %> phases complete<%= milestoneGroups.length > 0 ? ' across ' + milestoneGroups.length + ' milestone' + (milestoneGroups.length !== 1 ? 's' : '') : '' %>.
30
- </p>
31
- <div class="progress" style="height:0.5rem">
32
- <div class="progress-bar" role="progressbar"
33
- style="width:<%= phases.filter(p => p.status === 'complete').length / phases.length * 100 %>%"
34
- aria-valuenow="<%= phases.filter(p => p.status === 'complete').length %>"
35
- aria-valuemin="0" aria-valuemax="<%= phases.length %>">
36
- </div>
37
- </div>
38
- </div>
39
- </div>
40
-
41
- <% milestoneGroups.forEach(function(group) { %>
42
- <div class="card mb-3">
43
- <div class="card-header">
44
- <strong><%= group.name %></strong>
45
- <small class="ms-1">(Phases <%= String(group.startPhase).padStart(2, '0') %>&ndash;<%= String(group.endPhase).padStart(2, '0') %>)</small>
46
- &nbsp;&mdash;&nbsp;
47
- <%
48
- const groupComplete = group.phases.filter(p => p.status === 'complete').length;
49
- const groupTotal = group.phases.length;
50
- %>
51
- <span class="status-badge" data-status="<%= groupComplete === groupTotal ? 'complete' : (groupComplete > 0 ? 'in-progress' : 'not-started') %>">
52
- <%= groupComplete %>/<%= groupTotal %>
53
- </span>
54
- </div>
55
- <div class="card-body">
56
- <% if (group.goal) { %>
57
- <p><small><%= group.goal %></small></p>
58
- <% } %>
59
- <div class="table-responsive">
60
- <table class="table table-vcenter table-hover">
61
- <thead>
62
- <tr>
63
- <th scope="col">Phase</th>
64
- <th scope="col">Name</th>
65
- <th scope="col">Plans</th>
66
- <th scope="col">Status</th>
67
- </tr>
68
- </thead>
69
- <tbody>
70
- <% group.phases.forEach(function(phase) { %>
71
- <tr>
72
- <td><%= String(phase.id).padStart(2, '0') %></td>
73
- <td>
74
- <a href="/phases/<%= String(phase.id).padStart(2, '0') %>"
75
- hx-get="/phases/<%= String(phase.id).padStart(2, '0') %>"
76
- hx-target="#main-content"
77
- hx-push-url="true">
78
- <%= phase.name %>
79
- </a>
80
- </td>
81
- <td><%= phase.planCount %></td>
82
- <td>
83
- <span class="status-badge" data-status="<%= phase.status %>">
84
- <%= phase.status.replace('-', ' ') %>
85
- </span>
86
- </td>
87
- </tr>
88
- <% }); %>
89
- </tbody>
90
- </table>
91
- </div>
92
- </div>
93
- </div>
94
- <% }); %>
95
-
96
- <% if (ungrouped.length > 0) { %>
97
- <div class="card mb-3">
98
- <div class="card-header"><strong>Other Phases</strong></div>
99
- <div class="card-body">
100
- <div class="table-responsive">
101
- <table class="table table-vcenter table-hover">
102
- <thead>
103
- <tr>
104
- <th scope="col">Phase</th>
105
- <th scope="col">Name</th>
106
- <th scope="col">Plans</th>
107
- <th scope="col">Status</th>
108
- </tr>
109
- </thead>
110
- <tbody>
111
- <% ungrouped.forEach(function(phase) { %>
112
- <tr>
113
- <td><%= String(phase.id).padStart(2, '0') %></td>
114
- <td>
115
- <a href="/phases/<%= String(phase.id).padStart(2, '0') %>"
116
- hx-get="/phases/<%= String(phase.id).padStart(2, '0') %>"
117
- hx-target="#main-content"
118
- hx-push-url="true">
119
- <%= phase.name %>
120
- </a>
121
- </td>
122
- <td><%= phase.planCount %></td>
123
- <td>
124
- <span class="status-badge" data-status="<%= phase.status %>">
125
- <%= phase.status.replace('-', ' ') %>
126
- </span>
127
- </td>
128
- </tr>
129
- <% }); %>
130
- </tbody>
131
- </table>
132
- </div>
133
- </div>
134
- </div>
135
- <% } %>
136
-
137
- <% } %>
@@ -1,42 +0,0 @@
1
- <%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
2
- <h1>Quick Tasks</h1>
3
-
4
- <% if (typeof tasks !== 'undefined' && tasks.length > 0) { %>
5
- <div class="card">
6
- <div class="card-body p-0">
7
- <div class="table-responsive">
8
- <table class="table table-vcenter card-table">
9
- <thead>
10
- <tr>
11
- <th scope="col">ID</th>
12
- <th scope="col">Title</th>
13
- <th scope="col">Status</th>
14
- </tr>
15
- </thead>
16
- <tbody>
17
- <% tasks.forEach(function(task) { %>
18
- <tr>
19
- <td><%= task.id %></td>
20
- <td>
21
- <a href="/quick/<%= task.id %>"
22
- hx-get="/quick/<%= task.id %>"
23
- hx-target="#main-content"
24
- hx-push-url="true">
25
- <%= task.title %>
26
- </a>
27
- </td>
28
- <td>
29
- <span class="status-badge" data-status="<%= task.status %>">
30
- <%= task.status %>
31
- </span>
32
- </td>
33
- </tr>
34
- <% }); %>
35
- </tbody>
36
- </table>
37
- </div>
38
- </div>
39
- </div>
40
- <% } else { %>
41
- <%- include('empty-state', { icon: '⚡', title: 'No quick tasks found', action: '' }) %>
42
- <% } %>
@@ -1,30 +0,0 @@
1
- <%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
2
- <h1><%= title %></h1>
3
-
4
- <p><a href="/quick" class="btn btn-outline-secondary">&larr; Back to Quick Tasks</a></p>
5
-
6
- <div class="card mb-3">
7
- <div class="card-header">
8
- <strong>Quick Task <%= id %></strong>
9
- &nbsp;
10
- <span class="status-badge" data-status="<%= status %>">
11
- <%= status %>
12
- </span>
13
- </div>
14
- <div class="card-body">
15
- <% if (planHtml) { %>
16
- <section>
17
- <h2>Plan</h2>
18
- <%- planHtml %>
19
- </section>
20
- <% } %>
21
-
22
- <% if (summaryHtml) { %>
23
- <hr>
24
- <section>
25
- <h2>Summary</h2>
26
- <%- summaryHtml %>
27
- </section>
28
- <% } %>
29
- </div>
30
- </div>
@@ -1,44 +0,0 @@
1
- <%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
2
- <h1>Requirements</h1>
3
-
4
- <% if (totalCount === 0) { %>
5
- <%- include('empty-state', { icon: 'R', title: 'No requirements found', action: 'Add a REQUIREMENTS.md file to your .planning/ directory.' }) %>
6
- <% } else { %>
7
- <p class="requirements-summary">
8
- <strong><%= coveredCount %> / <%= totalCount %></strong> requirements covered by plans.
9
- <% if (uncoveredCount > 0) { %>
10
- <span class="status-badge" data-status="warning"><%= uncoveredCount %> uncovered</span>
11
- <% } else { %>
12
- <span class="status-badge" data-status="verified">All covered</span>
13
- <% } %>
14
- </p>
15
-
16
- <% sections.forEach(function(section) { %>
17
- <section class="requirements-section">
18
- <h2><%= section.sectionTitle %></h2>
19
- <% section.requirements.forEach(function(req) { %>
20
- <div class="card mb-2 requirements-card" data-covered="<%= req.covered %>">
21
- <div class="card-header">
22
- <code class="req-id"><%= req.id %></code>
23
- <% if (req.covered) { %>
24
- <span class="status-badge" data-status="verified">covered</span>
25
- <% } else { %>
26
- <span class="status-badge" data-status="warning">uncovered</span>
27
- <% } %>
28
- </div>
29
- <div class="card-body">
30
- <p><%= req.text %></p>
31
- <% if (req.planRefs.length > 0) { %>
32
- <p class="req-plan-refs mb-0">
33
- <small>Plans: </small>
34
- <% req.planRefs.forEach(function(planId) { %>
35
- <code class="req-plan-ref"><%= planId %></code>
36
- <% }); %>
37
- </p>
38
- <% } %>
39
- </div>
40
- </div>
41
- <% }); %>
42
- </section>
43
- <% }); %>
44
- <% } %>
@@ -1,56 +0,0 @@
1
- <%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
2
- <h1>Research</h1>
3
-
4
- <h2>Research Documents</h2>
5
- <% if (researchDocs.length === 0) { %>
6
- <%- include('empty-state', { icon: 'R', title: 'No research documents', action: 'Run /pbr:explore or /pbr:scan to generate research.' }) %>
7
- <% } else { %>
8
- <% researchDocs.forEach(function(doc) { %>
9
- <div class="card mb-2">
10
- <div class="card-header">
11
- <strong>
12
- <a href="/research/<%= doc.slug %>"
13
- hx-get="/research/<%= doc.slug %>"
14
- hx-target="#main-content"
15
- hx-push-url="true"><%= doc.title %></a>
16
- </strong>
17
- <% if (doc.date) { %><small class="ms-auto text-muted"><%= doc.date %></small><% } %>
18
- </div>
19
- <div class="card-body">
20
- <% if (doc.topic) { %><p><strong>Topic:</strong> <%= doc.topic %></p><% } %>
21
- <% if (doc.confidence || doc.coverage) { %>
22
- <p>
23
- <% if (doc.confidence) { %><span class="status-badge" data-status="<%= doc.confidence %>"><%= doc.confidence %></span>&nbsp;<% } %>
24
- <% if (doc.coverage) { %><small>Coverage: <%= doc.coverage %></small><% } %>
25
- </p>
26
- <% } %>
27
- <% if (!doc.topic && !doc.confidence && !doc.coverage) { %>
28
- <p class="text-muted mb-0"><small>Click to view full document</small></p>
29
- <% } %>
30
- </div>
31
- </div>
32
- <% }); %>
33
- <% } %>
34
-
35
- <h2>Codebase Documents</h2>
36
- <% if (codebaseDocs.length === 0) { %>
37
- <%- include('empty-state', { icon: 'C', title: 'No codebase documents', action: 'Run /pbr:scan to generate codebase analysis.' }) %>
38
- <% } else { %>
39
- <% codebaseDocs.forEach(function(doc) { %>
40
- <div class="card mb-2">
41
- <div class="card-header">
42
- <strong>
43
- <a href="/research/<%= doc.slug %>"
44
- hx-get="/research/<%= doc.slug %>"
45
- hx-target="#main-content"
46
- hx-push-url="true"><%= doc.title %></a>
47
- </strong>
48
- <% if (doc.date) { %><small class="ms-auto text-muted"><%= doc.date %></small><% } %>
49
- </div>
50
- <div class="card-body">
51
- <% if (doc.focus) { %><p><strong>Focus:</strong> <%= doc.focus %></p><% } %>
52
- <% if (!doc.focus) { %><p class="text-muted mb-0"><small>Click to view full document</small></p><% } %>
53
- </div>
54
- </div>
55
- <% }); %>
56
- <% } %>
@@ -1,25 +0,0 @@
1
- <%- include('breadcrumbs', { breadcrumbs: typeof breadcrumbs !== 'undefined' ? breadcrumbs : [] }) %>
2
- <h1><%= title %></h1>
3
-
4
- <% if (topic || date || confidence || coverage || sources_checked) { %>
5
- <div class="card mb-3">
6
- <div class="card-body">
7
- <% if (topic) { %><p><strong>Topic:</strong> <%= topic %></p><% } %>
8
- <% if (date) { %><p><strong>Date:</strong> <%= date %></p><% } %>
9
- <% if (confidence) { %><p><strong>Confidence:</strong> <span class="status-badge" data-status="<%= confidence %>"><%= confidence %></span></p><% } %>
10
- <% if (coverage) { %><p><strong>Coverage:</strong> <%= coverage %></p><% } %>
11
- <% if (sources_checked) { %><p class="mb-0"><strong>Sources checked:</strong> <%= sources_checked %></p><% } %>
12
- </div>
13
- </div>
14
- <% } %>
15
-
16
- <div class="card mb-3">
17
- <div class="card-body markdown-body">
18
- <%- html %>
19
- </div>
20
- </div>
21
-
22
- <p><a href="/research" class="btn btn-outline-secondary"
23
- hx-get="/research"
24
- hx-target="#main-content"
25
- hx-push-url="true">&larr; Back to Research</a></p>