@sienklogic/plan-build-run 2.0.0 → 2.0.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 +56 -56
- package/CLAUDE.md +149 -149
- package/LICENSE +21 -21
- package/README.md +247 -247
- package/dashboard/bin/cli.js +25 -25
- package/dashboard/package.json +34 -34
- package/dashboard/public/css/layout.css +406 -406
- package/dashboard/public/css/status-colors.css +98 -98
- package/dashboard/public/js/htmx-title.js +5 -5
- package/dashboard/public/js/sidebar-toggle.js +20 -20
- package/dashboard/src/app.js +78 -78
- package/dashboard/src/middleware/errorHandler.js +52 -52
- package/dashboard/src/middleware/notFoundHandler.js +9 -9
- package/dashboard/src/repositories/planning.repository.js +128 -128
- package/dashboard/src/routes/events.routes.js +40 -40
- package/dashboard/src/routes/index.routes.js +31 -31
- package/dashboard/src/routes/pages.routes.js +245 -195
- package/dashboard/src/server.js +42 -42
- package/dashboard/src/services/dashboard.service.js +222 -222
- package/dashboard/src/services/phase.service.js +220 -167
- package/dashboard/src/services/project.service.js +57 -57
- package/dashboard/src/services/roadmap.service.js +171 -171
- package/dashboard/src/services/sse.service.js +58 -58
- package/dashboard/src/services/todo.service.js +254 -254
- package/dashboard/src/services/watcher.service.js +48 -48
- package/dashboard/src/views/coming-soon.ejs +11 -11
- package/dashboard/src/views/error.ejs +13 -13
- package/dashboard/src/views/index.ejs +5 -5
- package/dashboard/src/views/layout.ejs +1 -1
- package/dashboard/src/views/partials/dashboard-content.ejs +77 -77
- package/dashboard/src/views/partials/footer.ejs +3 -3
- package/dashboard/src/views/partials/head.ejs +21 -21
- package/dashboard/src/views/partials/header.ejs +12 -12
- package/dashboard/src/views/partials/layout-bottom.ejs +15 -15
- package/dashboard/src/views/partials/layout-top.ejs +8 -8
- package/dashboard/src/views/partials/phase-content.ejs +188 -181
- package/dashboard/src/views/partials/phase-doc-content.ejs +38 -0
- package/dashboard/src/views/partials/phases-content.ejs +117 -117
- package/dashboard/src/views/partials/roadmap-content.ejs +142 -142
- package/dashboard/src/views/partials/sidebar.ejs +38 -38
- package/dashboard/src/views/partials/todo-create-content.ejs +53 -53
- package/dashboard/src/views/partials/todo-detail-content.ejs +38 -38
- package/dashboard/src/views/partials/todos-content.ejs +53 -53
- package/dashboard/src/views/phase-detail.ejs +5 -5
- package/dashboard/src/views/phase-doc.ejs +5 -0
- package/dashboard/src/views/phases.ejs +5 -5
- package/dashboard/src/views/roadmap.ejs +5 -5
- package/dashboard/src/views/todo-create.ejs +5 -5
- package/dashboard/src/views/todo-detail.ejs +5 -5
- package/dashboard/src/views/todos.ejs +5 -5
- package/package.json +57 -57
- package/plugins/cursor-pbr/.cursor-plugin/plugin.json +22 -0
- package/plugins/cursor-pbr/agents/.gitkeep +0 -0
- package/plugins/cursor-pbr/assets/.gitkeep +0 -0
- package/plugins/cursor-pbr/hooks/hooks.json +11 -0
- package/plugins/cursor-pbr/references/.gitkeep +0 -0
- package/plugins/cursor-pbr/rules/.gitkeep +0 -0
- package/plugins/cursor-pbr/skills/.gitkeep +0 -0
- package/plugins/cursor-pbr/templates/.gitkeep +0 -0
- package/plugins/pbr/.claude-plugin/plugin.json +13 -13
- package/plugins/pbr/UI-CONSISTENCY-GAPS.md +61 -61
- package/plugins/pbr/agents/codebase-mapper.md +279 -271
- package/plugins/pbr/agents/debugger.md +281 -281
- package/plugins/pbr/agents/executor.md +428 -407
- package/plugins/pbr/agents/general.md +164 -164
- package/plugins/pbr/agents/integration-checker.md +169 -141
- package/plugins/pbr/agents/plan-checker.md +296 -280
- package/plugins/pbr/agents/planner.md +358 -358
- package/plugins/pbr/agents/researcher.md +363 -363
- package/plugins/pbr/agents/synthesizer.md +230 -230
- package/plugins/pbr/agents/verifier.md +489 -454
- package/plugins/pbr/commands/begin.md +5 -5
- package/plugins/pbr/commands/build.md +5 -5
- package/plugins/pbr/commands/config.md +5 -5
- package/plugins/pbr/commands/continue.md +5 -5
- package/plugins/pbr/commands/debug.md +5 -5
- package/plugins/pbr/commands/discuss.md +5 -5
- package/plugins/pbr/commands/explore.md +5 -5
- package/plugins/pbr/commands/health.md +5 -5
- package/plugins/pbr/commands/help.md +5 -5
- package/plugins/pbr/commands/import.md +5 -5
- package/plugins/pbr/commands/milestone.md +5 -5
- package/plugins/pbr/commands/note.md +5 -5
- package/plugins/pbr/commands/pause.md +5 -5
- package/plugins/pbr/commands/plan.md +5 -5
- package/plugins/pbr/commands/quick.md +5 -5
- package/plugins/pbr/commands/resume.md +5 -5
- package/plugins/pbr/commands/review.md +5 -5
- package/plugins/pbr/commands/scan.md +5 -5
- package/plugins/pbr/commands/setup.md +5 -5
- package/plugins/pbr/commands/status.md +5 -5
- package/plugins/pbr/commands/todo.md +5 -5
- package/plugins/pbr/contexts/dev.md +27 -27
- package/plugins/pbr/contexts/research.md +28 -28
- package/plugins/pbr/contexts/review.md +36 -36
- package/plugins/pbr/hooks/hooks.json +183 -183
- package/plugins/pbr/references/agent-anti-patterns.md +24 -24
- package/plugins/pbr/references/agent-interactions.md +134 -134
- package/plugins/pbr/references/agent-teams.md +54 -54
- package/plugins/pbr/references/checkpoints.md +157 -157
- package/plugins/pbr/references/common-bug-patterns.md +13 -13
- package/plugins/pbr/references/config-reference.md +441 -0
- package/plugins/pbr/references/continuation-format.md +212 -212
- package/plugins/pbr/references/deviation-rules.md +112 -112
- package/plugins/pbr/references/git-integration.md +226 -226
- package/plugins/pbr/references/integration-patterns.md +117 -117
- package/plugins/pbr/references/model-profiles.md +99 -99
- package/plugins/pbr/references/model-selection.md +31 -31
- package/plugins/pbr/references/pbr-rules.md +193 -193
- package/plugins/pbr/references/plan-authoring.md +181 -181
- package/plugins/pbr/references/plan-format.md +287 -283
- package/plugins/pbr/references/planning-config.md +213 -213
- package/plugins/pbr/references/questioning.md +214 -214
- package/plugins/pbr/references/reading-verification.md +127 -127
- package/plugins/pbr/references/stub-patterns.md +160 -160
- package/plugins/pbr/references/subagent-coordination.md +119 -119
- package/plugins/pbr/references/ui-formatting.md +461 -399
- package/plugins/pbr/references/verification-patterns.md +198 -198
- package/plugins/pbr/references/wave-execution.md +95 -95
- package/plugins/pbr/scripts/auto-continue.js +80 -80
- package/plugins/pbr/scripts/check-dangerous-commands.js +136 -136
- package/plugins/pbr/scripts/check-doc-sprawl.js +102 -102
- package/plugins/pbr/scripts/check-phase-boundary.js +196 -196
- package/plugins/pbr/scripts/check-plan-format.js +270 -270
- package/plugins/pbr/scripts/check-roadmap-sync.js +322 -252
- package/plugins/pbr/scripts/check-skill-workflow.js +262 -262
- package/plugins/pbr/scripts/check-state-sync.js +476 -476
- package/plugins/pbr/scripts/check-subagent-output.js +144 -144
- package/plugins/pbr/scripts/config-schema.json +251 -251
- package/plugins/pbr/scripts/context-budget-check.js +287 -287
- package/plugins/pbr/scripts/event-handler.js +151 -151
- package/plugins/pbr/scripts/event-logger.js +92 -92
- package/plugins/pbr/scripts/hook-logger.js +80 -76
- package/plugins/pbr/scripts/hooks-schema.json +79 -79
- package/plugins/pbr/scripts/log-subagent.js +164 -152
- package/plugins/pbr/scripts/log-tool-failure.js +88 -88
- package/plugins/pbr/scripts/pbr-tools.js +1378 -1301
- package/plugins/pbr/scripts/post-write-dispatch.js +66 -66
- package/plugins/pbr/scripts/post-write-quality.js +207 -207
- package/plugins/pbr/scripts/pre-bash-dispatch.js +86 -56
- package/plugins/pbr/scripts/pre-write-dispatch.js +97 -62
- package/plugins/pbr/scripts/progress-tracker.js +281 -228
- package/plugins/pbr/scripts/run-hook.js +92 -0
- package/plugins/pbr/scripts/session-cleanup.js +254 -254
- package/plugins/pbr/scripts/status-line.js +288 -285
- package/plugins/pbr/scripts/suggest-compact.js +119 -119
- package/plugins/pbr/scripts/task-completed.js +45 -45
- package/plugins/pbr/scripts/track-context-budget.js +149 -119
- package/plugins/pbr/scripts/validate-commit.js +200 -200
- package/plugins/pbr/scripts/validate-plugin-structure.js +183 -172
- package/plugins/pbr/scripts/validate-task.js +106 -0
- package/plugins/pbr/skills/begin/SKILL.md +594 -545
- package/plugins/pbr/skills/begin/templates/PROJECT.md.tmpl +33 -33
- package/plugins/pbr/skills/begin/templates/REQUIREMENTS.md.tmpl +18 -18
- package/plugins/pbr/skills/begin/templates/STATE.md.tmpl +49 -49
- package/plugins/pbr/skills/begin/templates/config.json.tmpl +64 -63
- package/plugins/pbr/skills/begin/templates/researcher-prompt.md.tmpl +19 -19
- package/plugins/pbr/skills/begin/templates/roadmap-prompt.md.tmpl +30 -30
- package/plugins/pbr/skills/begin/templates/synthesis-prompt.md.tmpl +16 -16
- package/plugins/pbr/skills/build/SKILL.md +943 -962
- package/plugins/pbr/skills/config/SKILL.md +256 -241
- package/plugins/pbr/skills/continue/SKILL.md +164 -127
- package/plugins/pbr/skills/debug/SKILL.md +515 -489
- package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +16 -16
- package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +27 -27
- package/plugins/pbr/skills/discuss/SKILL.md +347 -338
- package/plugins/pbr/skills/discuss/templates/CONTEXT.md.tmpl +61 -61
- package/plugins/pbr/skills/discuss/templates/decision-categories.md +9 -9
- package/plugins/pbr/skills/explore/SKILL.md +378 -362
- package/plugins/pbr/skills/health/SKILL.md +221 -186
- package/plugins/pbr/skills/health/templates/check-pattern.md.tmpl +30 -30
- package/plugins/pbr/skills/health/templates/output-format.md.tmpl +63 -63
- package/plugins/pbr/skills/help/SKILL.md +155 -140
- package/plugins/pbr/skills/import/SKILL.md +504 -490
- package/plugins/pbr/skills/milestone/SKILL.md +704 -673
- package/plugins/pbr/skills/milestone/templates/audit-report.md.tmpl +48 -48
- package/plugins/pbr/skills/milestone/templates/stats-file.md.tmpl +30 -30
- package/plugins/pbr/skills/note/SKILL.md +231 -212
- package/plugins/pbr/skills/pause/SKILL.md +249 -235
- package/plugins/pbr/skills/pause/templates/continue-here.md.tmpl +71 -71
- package/plugins/pbr/skills/plan/SKILL.md +685 -628
- package/plugins/pbr/skills/plan/decimal-phase-calc.md +98 -98
- package/plugins/pbr/skills/plan/templates/checker-prompt.md.tmpl +21 -21
- package/plugins/pbr/skills/plan/templates/gap-closure-prompt.md.tmpl +32 -32
- package/plugins/pbr/skills/plan/templates/planner-prompt.md.tmpl +38 -38
- package/plugins/pbr/skills/plan/templates/researcher-prompt.md.tmpl +19 -19
- package/plugins/pbr/skills/plan/templates/revision-prompt.md.tmpl +23 -23
- package/plugins/pbr/skills/quick/SKILL.md +354 -335
- package/plugins/pbr/skills/resume/SKILL.md +402 -388
- package/plugins/pbr/skills/review/SKILL.md +686 -652
- package/plugins/pbr/skills/review/templates/debugger-prompt.md.tmpl +60 -60
- package/plugins/pbr/skills/review/templates/gap-planner-prompt.md.tmpl +40 -40
- package/plugins/pbr/skills/review/templates/verifier-prompt.md.tmpl +115 -115
- package/plugins/pbr/skills/scan/SKILL.md +304 -269
- package/plugins/pbr/skills/scan/templates/mapper-prompt.md.tmpl +201 -201
- package/plugins/pbr/skills/setup/SKILL.md +253 -227
- package/plugins/pbr/skills/shared/commit-planning-docs.md +35 -35
- package/plugins/pbr/skills/shared/config-loading.md +102 -102
- package/plugins/pbr/skills/shared/context-budget.md +40 -40
- package/plugins/pbr/skills/shared/context-loader-task.md +86 -86
- package/plugins/pbr/skills/shared/digest-select.md +79 -79
- package/plugins/pbr/skills/shared/domain-probes.md +125 -125
- package/plugins/pbr/skills/shared/error-reporting.md +79 -79
- package/plugins/pbr/skills/shared/gate-prompts.md +388 -388
- package/plugins/pbr/skills/shared/phase-argument-parsing.md +45 -45
- package/plugins/pbr/skills/shared/progress-display.md +53 -53
- package/plugins/pbr/skills/shared/revision-loop.md +81 -81
- package/plugins/pbr/skills/shared/state-loading.md +62 -62
- package/plugins/pbr/skills/shared/state-update.md +161 -161
- package/plugins/pbr/skills/shared/universal-anti-patterns.md +33 -33
- package/plugins/pbr/skills/status/SKILL.md +367 -353
- package/plugins/pbr/skills/todo/SKILL.md +198 -181
- package/plugins/pbr/templates/CONTEXT.md.tmpl +52 -52
- package/plugins/pbr/templates/INTEGRATION-REPORT.md.tmpl +151 -151
- package/plugins/pbr/templates/RESEARCH-SUMMARY.md.tmpl +97 -97
- package/plugins/pbr/templates/ROADMAP.md.tmpl +40 -40
- package/plugins/pbr/templates/SUMMARY.md.tmpl +81 -81
- package/plugins/pbr/templates/VERIFICATION-DETAIL.md.tmpl +116 -116
- package/plugins/pbr/templates/codebase/ARCHITECTURE.md.tmpl +98 -98
- package/plugins/pbr/templates/codebase/CONCERNS.md.tmpl +93 -93
- package/plugins/pbr/templates/codebase/CONVENTIONS.md.tmpl +104 -104
- package/plugins/pbr/templates/codebase/INTEGRATIONS.md.tmpl +78 -78
- package/plugins/pbr/templates/codebase/STACK.md.tmpl +78 -78
- package/plugins/pbr/templates/codebase/STRUCTURE.md.tmpl +80 -80
- package/plugins/pbr/templates/codebase/TESTING.md.tmpl +107 -107
- package/plugins/pbr/templates/continue-here.md.tmpl +73 -73
- package/plugins/pbr/templates/prompt-partials/phase-project-context.md.tmpl +37 -37
- package/plugins/pbr/templates/research/ARCHITECTURE.md.tmpl +124 -124
- package/plugins/pbr/templates/research/STACK.md.tmpl +71 -71
- package/plugins/pbr/templates/research/SUMMARY.md.tmpl +112 -112
- package/plugins/pbr/templates/research-outputs/phase-research.md.tmpl +81 -81
- package/plugins/pbr/templates/research-outputs/project-research.md.tmpl +99 -99
- package/plugins/pbr/templates/research-outputs/synthesis.md.tmpl +36 -36
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
/* ============================================
|
|
2
|
-
Status Colors & Badges
|
|
3
|
-
============================================ */
|
|
4
|
-
|
|
5
|
-
:root {
|
|
6
|
-
--status-complete: #34d399;
|
|
7
|
-
--status-in-progress: #fbbf24;
|
|
8
|
-
--status-blocked: #f87171;
|
|
9
|
-
--status-not-started: #6b7280;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/* Text color by status */
|
|
13
|
-
[data-status="complete"] { color: var(--status-complete); }
|
|
14
|
-
[data-status="in-progress"] { color: var(--status-in-progress); }
|
|
15
|
-
[data-status="blocked"],
|
|
16
|
-
[data-status="failed"] { color: var(--status-blocked); }
|
|
17
|
-
[data-status="not-started"],
|
|
18
|
-
[data-status="pending"] { color: var(--status-not-started); }
|
|
19
|
-
[data-status="passed"] { color: var(--status-complete); }
|
|
20
|
-
[data-status="partial"] { color: var(--status-in-progress); }
|
|
21
|
-
|
|
22
|
-
/* Status badge */
|
|
23
|
-
.status-badge {
|
|
24
|
-
display: inline-flex;
|
|
25
|
-
align-items: center;
|
|
26
|
-
padding: 0.15rem 0.55rem;
|
|
27
|
-
border-radius: 999px;
|
|
28
|
-
font-size: 0.75rem;
|
|
29
|
-
font-weight: 600;
|
|
30
|
-
letter-spacing: 0.02em;
|
|
31
|
-
line-height: 1.5;
|
|
32
|
-
white-space: nowrap;
|
|
33
|
-
border: 1px solid transparent;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/* Dark-friendly badge colors — softer backgrounds with good contrast */
|
|
37
|
-
.status-badge[data-status="complete"] {
|
|
38
|
-
background: rgba(52, 211, 153, 0.12);
|
|
39
|
-
color: #6ee7b7;
|
|
40
|
-
border-color: rgba(52, 211, 153, 0.2);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.status-badge[data-status="in-progress"] {
|
|
44
|
-
background: rgba(251, 191, 36, 0.12);
|
|
45
|
-
color: #fcd34d;
|
|
46
|
-
border-color: rgba(251, 191, 36, 0.2);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.status-badge[data-status="blocked"],
|
|
50
|
-
.status-badge[data-status="failed"] {
|
|
51
|
-
background: rgba(248, 113, 113, 0.12);
|
|
52
|
-
color: #fca5a5;
|
|
53
|
-
border-color: rgba(248, 113, 113, 0.2);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.status-badge[data-status="not-started"],
|
|
57
|
-
.status-badge[data-status="pending"] {
|
|
58
|
-
background: rgba(107, 114, 128, 0.12);
|
|
59
|
-
color: #9ca3af;
|
|
60
|
-
border-color: rgba(107, 114, 128, 0.2);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.status-badge[data-status="passed"] {
|
|
64
|
-
background: rgba(52, 211, 153, 0.12);
|
|
65
|
-
color: #6ee7b7;
|
|
66
|
-
border-color: rgba(52, 211, 153, 0.2);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.status-badge[data-status="partial"] {
|
|
70
|
-
background: rgba(251, 191, 36, 0.12);
|
|
71
|
-
color: #fcd34d;
|
|
72
|
-
border-color: rgba(251, 191, 36, 0.2);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/* Priority badge variants */
|
|
76
|
-
.status-badge[data-priority="P0"] {
|
|
77
|
-
background: rgba(248, 113, 113, 0.12);
|
|
78
|
-
color: #fca5a5;
|
|
79
|
-
border-color: rgba(248, 113, 113, 0.2);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.status-badge[data-priority="P1"] {
|
|
83
|
-
background: rgba(251, 146, 60, 0.12);
|
|
84
|
-
color: #fdba74;
|
|
85
|
-
border-color: rgba(251, 146, 60, 0.2);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.status-badge[data-priority="P2"] {
|
|
89
|
-
background: rgba(251, 191, 36, 0.12);
|
|
90
|
-
color: #fcd34d;
|
|
91
|
-
border-color: rgba(251, 191, 36, 0.2);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.status-badge[data-priority="PX"] {
|
|
95
|
-
background: rgba(129, 140, 248, 0.12);
|
|
96
|
-
color: #a5b4fc;
|
|
97
|
-
border-color: rgba(129, 140, 248, 0.2);
|
|
98
|
-
}
|
|
1
|
+
/* ============================================
|
|
2
|
+
Status Colors & Badges
|
|
3
|
+
============================================ */
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--status-complete: #34d399;
|
|
7
|
+
--status-in-progress: #fbbf24;
|
|
8
|
+
--status-blocked: #f87171;
|
|
9
|
+
--status-not-started: #6b7280;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/* Text color by status */
|
|
13
|
+
[data-status="complete"] { color: var(--status-complete); }
|
|
14
|
+
[data-status="in-progress"] { color: var(--status-in-progress); }
|
|
15
|
+
[data-status="blocked"],
|
|
16
|
+
[data-status="failed"] { color: var(--status-blocked); }
|
|
17
|
+
[data-status="not-started"],
|
|
18
|
+
[data-status="pending"] { color: var(--status-not-started); }
|
|
19
|
+
[data-status="passed"] { color: var(--status-complete); }
|
|
20
|
+
[data-status="partial"] { color: var(--status-in-progress); }
|
|
21
|
+
|
|
22
|
+
/* Status badge */
|
|
23
|
+
.status-badge {
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
padding: 0.15rem 0.55rem;
|
|
27
|
+
border-radius: 999px;
|
|
28
|
+
font-size: 0.75rem;
|
|
29
|
+
font-weight: 600;
|
|
30
|
+
letter-spacing: 0.02em;
|
|
31
|
+
line-height: 1.5;
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
border: 1px solid transparent;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Dark-friendly badge colors — softer backgrounds with good contrast */
|
|
37
|
+
.status-badge[data-status="complete"] {
|
|
38
|
+
background: rgba(52, 211, 153, 0.12);
|
|
39
|
+
color: #6ee7b7;
|
|
40
|
+
border-color: rgba(52, 211, 153, 0.2);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.status-badge[data-status="in-progress"] {
|
|
44
|
+
background: rgba(251, 191, 36, 0.12);
|
|
45
|
+
color: #fcd34d;
|
|
46
|
+
border-color: rgba(251, 191, 36, 0.2);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.status-badge[data-status="blocked"],
|
|
50
|
+
.status-badge[data-status="failed"] {
|
|
51
|
+
background: rgba(248, 113, 113, 0.12);
|
|
52
|
+
color: #fca5a5;
|
|
53
|
+
border-color: rgba(248, 113, 113, 0.2);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.status-badge[data-status="not-started"],
|
|
57
|
+
.status-badge[data-status="pending"] {
|
|
58
|
+
background: rgba(107, 114, 128, 0.12);
|
|
59
|
+
color: #9ca3af;
|
|
60
|
+
border-color: rgba(107, 114, 128, 0.2);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.status-badge[data-status="passed"] {
|
|
64
|
+
background: rgba(52, 211, 153, 0.12);
|
|
65
|
+
color: #6ee7b7;
|
|
66
|
+
border-color: rgba(52, 211, 153, 0.2);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.status-badge[data-status="partial"] {
|
|
70
|
+
background: rgba(251, 191, 36, 0.12);
|
|
71
|
+
color: #fcd34d;
|
|
72
|
+
border-color: rgba(251, 191, 36, 0.2);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Priority badge variants */
|
|
76
|
+
.status-badge[data-priority="P0"] {
|
|
77
|
+
background: rgba(248, 113, 113, 0.12);
|
|
78
|
+
color: #fca5a5;
|
|
79
|
+
border-color: rgba(248, 113, 113, 0.2);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.status-badge[data-priority="P1"] {
|
|
83
|
+
background: rgba(251, 146, 60, 0.12);
|
|
84
|
+
color: #fdba74;
|
|
85
|
+
border-color: rgba(251, 146, 60, 0.2);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.status-badge[data-priority="P2"] {
|
|
89
|
+
background: rgba(251, 191, 36, 0.12);
|
|
90
|
+
color: #fcd34d;
|
|
91
|
+
border-color: rgba(251, 191, 36, 0.2);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.status-badge[data-priority="PX"] {
|
|
95
|
+
background: rgba(129, 140, 248, 0.12);
|
|
96
|
+
color: #a5b4fc;
|
|
97
|
+
border-color: rgba(129, 140, 248, 0.2);
|
|
98
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Update document.title from HX-Title response header on HTMX navigation
|
|
2
|
-
document.addEventListener('htmx:afterSettle', function(event) {
|
|
3
|
-
var title = event.detail.xhr && event.detail.xhr.getResponseHeader('HX-Title');
|
|
4
|
-
if (title) document.title = title;
|
|
5
|
-
});
|
|
1
|
+
// Update document.title from HX-Title response header on HTMX navigation
|
|
2
|
+
document.addEventListener('htmx:afterSettle', function(event) {
|
|
3
|
+
var title = event.detail.xhr && event.detail.xhr.getResponseHeader('HX-Title');
|
|
4
|
+
if (title) document.title = title;
|
|
5
|
+
});
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
// Mobile sidebar toggle
|
|
2
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
3
|
-
var toggle = document.querySelector('.sidebar-toggle');
|
|
4
|
-
var sidebar = document.querySelector('.sidebar');
|
|
5
|
-
if (toggle && sidebar) {
|
|
6
|
-
toggle.addEventListener('click', function() {
|
|
7
|
-
sidebar.classList.toggle('open');
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
// Close sidebar when a nav link is clicked (mobile)
|
|
12
|
-
var navLinks = sidebar ? sidebar.querySelectorAll('a') : [];
|
|
13
|
-
navLinks.forEach(function(link) {
|
|
14
|
-
link.addEventListener('click', function() {
|
|
15
|
-
if (window.innerWidth <= 768) {
|
|
16
|
-
sidebar.classList.remove('open');
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
});
|
|
1
|
+
// Mobile sidebar toggle
|
|
2
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
3
|
+
var toggle = document.querySelector('.sidebar-toggle');
|
|
4
|
+
var sidebar = document.querySelector('.sidebar');
|
|
5
|
+
if (toggle && sidebar) {
|
|
6
|
+
toggle.addEventListener('click', function() {
|
|
7
|
+
sidebar.classList.toggle('open');
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Close sidebar when a nav link is clicked (mobile)
|
|
12
|
+
var navLinks = sidebar ? sidebar.querySelectorAll('a') : [];
|
|
13
|
+
navLinks.forEach(function(link) {
|
|
14
|
+
link.addEventListener('click', function() {
|
|
15
|
+
if (window.innerWidth <= 768) {
|
|
16
|
+
sidebar.classList.remove('open');
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
package/dashboard/src/app.js
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
import helmet from 'helmet';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
import { dirname } from 'path';
|
|
6
|
-
import indexRouter from './routes/index.routes.js';
|
|
7
|
-
import pagesRouter from './routes/pages.routes.js';
|
|
8
|
-
import eventsRouter from './routes/events.routes.js';
|
|
9
|
-
import notFoundHandler from './middleware/notFoundHandler.js';
|
|
10
|
-
import errorHandler from './middleware/errorHandler.js';
|
|
11
|
-
|
|
12
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
-
const __dirname = dirname(__filename);
|
|
14
|
-
|
|
15
|
-
export function createApp(config) {
|
|
16
|
-
const app = express();
|
|
17
|
-
|
|
18
|
-
// Security headers via Helmet
|
|
19
|
-
// CSP allows CDN scripts (HTMX, Pico.css, htmx-ext-sse) and inline styles
|
|
20
|
-
app.use(helmet({
|
|
21
|
-
contentSecurityPolicy: {
|
|
22
|
-
directives: {
|
|
23
|
-
defaultSrc: ["'self'"],
|
|
24
|
-
scriptSrc: ["'self'", "https://cdn.jsdelivr.net"],
|
|
25
|
-
styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"],
|
|
26
|
-
imgSrc: ["'self'", "data:"],
|
|
27
|
-
connectSrc: ["'self'"],
|
|
28
|
-
fontSrc: ["'self'", "https://cdn.jsdelivr.net"]
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}));
|
|
32
|
-
app.disable('x-powered-by');
|
|
33
|
-
|
|
34
|
-
// Store config for access in routes/services
|
|
35
|
-
app.locals.projectDir = config.projectDir;
|
|
36
|
-
|
|
37
|
-
// View engine setup -- all paths use path.join (cross-platform)
|
|
38
|
-
app.set('views', join(__dirname, 'views'));
|
|
39
|
-
app.set('view engine', 'ejs');
|
|
40
|
-
|
|
41
|
-
// Built-in middleware
|
|
42
|
-
app.use(express.json());
|
|
43
|
-
app.use(express.urlencoded({ extended: false }));
|
|
44
|
-
|
|
45
|
-
// Handle common browser auto-requests cleanly (no stack traces in logs)
|
|
46
|
-
app.get('/favicon.ico', (req, res) => res.status(204).end());
|
|
47
|
-
app.get('/sw.js', (req, res) => res.status(404).end());
|
|
48
|
-
|
|
49
|
-
// Static files
|
|
50
|
-
app.use(express.static(join(__dirname, '..', 'public')));
|
|
51
|
-
|
|
52
|
-
// Auto-set HX-Title on HTMX partial responses so document.title stays current
|
|
53
|
-
app.use((req, res, next) => {
|
|
54
|
-
if (req.get('HX-Request') === 'true') {
|
|
55
|
-
const originalRender = res.render.bind(res);
|
|
56
|
-
res.render = function(view, options, callback) {
|
|
57
|
-
if (options && options.title && !res.getHeader('HX-Title')) {
|
|
58
|
-
res.setHeader('HX-Title', `${options.title} - Plan-Build-Run`);
|
|
59
|
-
}
|
|
60
|
-
return originalRender(view, options, callback);
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
next();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Routes
|
|
67
|
-
app.use('/', indexRouter);
|
|
68
|
-
app.use('/', pagesRouter);
|
|
69
|
-
app.use('/api/events', eventsRouter);
|
|
70
|
-
|
|
71
|
-
// 404 catch-all (after routes, before error handler)
|
|
72
|
-
app.use(notFoundHandler);
|
|
73
|
-
|
|
74
|
-
// Error handler MUST be registered last
|
|
75
|
-
app.use(errorHandler);
|
|
76
|
-
|
|
77
|
-
return app;
|
|
78
|
-
}
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import helmet from 'helmet';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { dirname } from 'path';
|
|
6
|
+
import indexRouter from './routes/index.routes.js';
|
|
7
|
+
import pagesRouter from './routes/pages.routes.js';
|
|
8
|
+
import eventsRouter from './routes/events.routes.js';
|
|
9
|
+
import notFoundHandler from './middleware/notFoundHandler.js';
|
|
10
|
+
import errorHandler from './middleware/errorHandler.js';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
|
|
15
|
+
export function createApp(config) {
|
|
16
|
+
const app = express();
|
|
17
|
+
|
|
18
|
+
// Security headers via Helmet
|
|
19
|
+
// CSP allows CDN scripts (HTMX, Pico.css, htmx-ext-sse) and inline styles
|
|
20
|
+
app.use(helmet({
|
|
21
|
+
contentSecurityPolicy: {
|
|
22
|
+
directives: {
|
|
23
|
+
defaultSrc: ["'self'"],
|
|
24
|
+
scriptSrc: ["'self'", "https://cdn.jsdelivr.net"],
|
|
25
|
+
styleSrc: ["'self'", "'unsafe-inline'", "https://cdn.jsdelivr.net"],
|
|
26
|
+
imgSrc: ["'self'", "data:"],
|
|
27
|
+
connectSrc: ["'self'"],
|
|
28
|
+
fontSrc: ["'self'", "https://cdn.jsdelivr.net"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}));
|
|
32
|
+
app.disable('x-powered-by');
|
|
33
|
+
|
|
34
|
+
// Store config for access in routes/services
|
|
35
|
+
app.locals.projectDir = config.projectDir;
|
|
36
|
+
|
|
37
|
+
// View engine setup -- all paths use path.join (cross-platform)
|
|
38
|
+
app.set('views', join(__dirname, 'views'));
|
|
39
|
+
app.set('view engine', 'ejs');
|
|
40
|
+
|
|
41
|
+
// Built-in middleware
|
|
42
|
+
app.use(express.json());
|
|
43
|
+
app.use(express.urlencoded({ extended: false }));
|
|
44
|
+
|
|
45
|
+
// Handle common browser auto-requests cleanly (no stack traces in logs)
|
|
46
|
+
app.get('/favicon.ico', (req, res) => res.status(204).end());
|
|
47
|
+
app.get('/sw.js', (req, res) => res.status(404).end());
|
|
48
|
+
|
|
49
|
+
// Static files
|
|
50
|
+
app.use(express.static(join(__dirname, '..', 'public')));
|
|
51
|
+
|
|
52
|
+
// Auto-set HX-Title on HTMX partial responses so document.title stays current
|
|
53
|
+
app.use((req, res, next) => {
|
|
54
|
+
if (req.get('HX-Request') === 'true') {
|
|
55
|
+
const originalRender = res.render.bind(res);
|
|
56
|
+
res.render = function(view, options, callback) {
|
|
57
|
+
if (options && options.title && !res.getHeader('HX-Title')) {
|
|
58
|
+
res.setHeader('HX-Title', `${options.title} - Plan-Build-Run`);
|
|
59
|
+
}
|
|
60
|
+
return originalRender(view, options, callback);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
next();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Routes
|
|
67
|
+
app.use('/', indexRouter);
|
|
68
|
+
app.use('/', pagesRouter);
|
|
69
|
+
app.use('/api/events', eventsRouter);
|
|
70
|
+
|
|
71
|
+
// 404 catch-all (after routes, before error handler)
|
|
72
|
+
app.use(notFoundHandler);
|
|
73
|
+
|
|
74
|
+
// Error handler MUST be registered last
|
|
75
|
+
app.use(errorHandler);
|
|
76
|
+
|
|
77
|
+
return app;
|
|
78
|
+
}
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Express error-handling middleware.
|
|
3
|
-
* MUST have exactly 4 parameters for Express to recognize it as an error handler.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// eslint-disable-next-line no-unused-vars
|
|
7
|
-
export default function errorHandler(err, req, res, next) {
|
|
8
|
-
// If headers already sent, delegate to Express default handler
|
|
9
|
-
if (res.headersSent) {
|
|
10
|
-
return next(err);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const isDev = process.env.NODE_ENV !== 'production';
|
|
14
|
-
const status = err.status || err.statusCode || 500;
|
|
15
|
-
|
|
16
|
-
// Logging -- skip stack traces for 404s (they're expected, not bugs)
|
|
17
|
-
if (status === 404) {
|
|
18
|
-
console.warn(`404: ${req.originalUrl}`);
|
|
19
|
-
} else {
|
|
20
|
-
console.error('Unhandled error:', err.message);
|
|
21
|
-
if (isDev) {
|
|
22
|
-
console.error(err.stack);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Detect HTMX requests
|
|
27
|
-
const isHtmx = req.get('HX-Request') === 'true';
|
|
28
|
-
|
|
29
|
-
// Set Vary header for proper caching
|
|
30
|
-
res.setHeader('Vary', 'HX-Request');
|
|
31
|
-
|
|
32
|
-
// Build template data
|
|
33
|
-
const templateData = {
|
|
34
|
-
title: `Error ${status}`,
|
|
35
|
-
status,
|
|
36
|
-
message: err.message || 'Internal Server Error',
|
|
37
|
-
stack: isDev ? err.stack : null,
|
|
38
|
-
activePage: ''
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
// Render response
|
|
42
|
-
if (isHtmx) {
|
|
43
|
-
let html = `<h1>Error ${status}</h1><p>${templateData.message}</p>`;
|
|
44
|
-
if (templateData.stack) {
|
|
45
|
-
html += `<pre><code>${templateData.stack}</code></pre>`;
|
|
46
|
-
}
|
|
47
|
-
html += '<p><a href="/">Return to Dashboard</a></p>';
|
|
48
|
-
return res.status(status).send(html);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
res.status(status).render('error', templateData);
|
|
52
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Express error-handling middleware.
|
|
3
|
+
* MUST have exactly 4 parameters for Express to recognize it as an error handler.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// eslint-disable-next-line no-unused-vars
|
|
7
|
+
export default function errorHandler(err, req, res, next) {
|
|
8
|
+
// If headers already sent, delegate to Express default handler
|
|
9
|
+
if (res.headersSent) {
|
|
10
|
+
return next(err);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
14
|
+
const status = err.status || err.statusCode || 500;
|
|
15
|
+
|
|
16
|
+
// Logging -- skip stack traces for 404s (they're expected, not bugs)
|
|
17
|
+
if (status === 404) {
|
|
18
|
+
console.warn(`404: ${req.originalUrl}`);
|
|
19
|
+
} else {
|
|
20
|
+
console.error('Unhandled error:', err.message);
|
|
21
|
+
if (isDev) {
|
|
22
|
+
console.error(err.stack);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Detect HTMX requests
|
|
27
|
+
const isHtmx = req.get('HX-Request') === 'true';
|
|
28
|
+
|
|
29
|
+
// Set Vary header for proper caching
|
|
30
|
+
res.setHeader('Vary', 'HX-Request');
|
|
31
|
+
|
|
32
|
+
// Build template data
|
|
33
|
+
const templateData = {
|
|
34
|
+
title: `Error ${status}`,
|
|
35
|
+
status,
|
|
36
|
+
message: err.message || 'Internal Server Error',
|
|
37
|
+
stack: isDev ? err.stack : null,
|
|
38
|
+
activePage: ''
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Render response
|
|
42
|
+
if (isHtmx) {
|
|
43
|
+
let html = `<h1>Error ${status}</h1><p>${templateData.message}</p>`;
|
|
44
|
+
if (templateData.stack) {
|
|
45
|
+
html += `<pre><code>${templateData.stack}</code></pre>`;
|
|
46
|
+
}
|
|
47
|
+
html += '<p><a href="/">Return to Dashboard</a></p>';
|
|
48
|
+
return res.status(status).send(html);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
res.status(status).render('error', templateData);
|
|
52
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 404 catch-all handler for routes that don't match any defined route.
|
|
3
|
-
* Must be registered AFTER all route handlers but BEFORE the error handler.
|
|
4
|
-
*/
|
|
5
|
-
export default function notFoundHandler(req, res, next) {
|
|
6
|
-
const err = new Error(`Page not found: ${req.originalUrl}`);
|
|
7
|
-
err.status = 404;
|
|
8
|
-
next(err);
|
|
9
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 404 catch-all handler for routes that don't match any defined route.
|
|
3
|
+
* Must be registered AFTER all route handlers but BEFORE the error handler.
|
|
4
|
+
*/
|
|
5
|
+
export default function notFoundHandler(req, res, next) {
|
|
6
|
+
const err = new Error(`Page not found: ${req.originalUrl}`);
|
|
7
|
+
err.status = 404;
|
|
8
|
+
next(err);
|
|
9
|
+
}
|