@sienklogic/plan-build-run 2.33.1 → 2.37.0
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 +678 -0
- package/dashboard/public/css/command-center.css +152 -65
- package/dashboard/public/css/explorer.css +70 -41
- package/dashboard/public/css/layout.css +163 -2
- package/dashboard/public/css/settings.css +108 -110
- package/dashboard/public/css/timeline.css +2 -1
- package/dashboard/public/css/tokens.css +13 -0
- package/dashboard/public/js/sidebar-toggle.js +21 -7
- package/dashboard/src/components/Layout.tsx +51 -7
- package/dashboard/src/components/explorer/tabs/MilestonesTab.tsx +18 -2
- package/dashboard/src/components/explorer/tabs/PhasesTab.tsx +11 -1
- package/dashboard/src/components/explorer/tabs/TodosTab.tsx +25 -6
- package/dashboard/src/components/partials/AttentionPanel.tsx +7 -1
- package/dashboard/src/components/partials/CurrentPhaseCard.tsx +26 -24
- package/dashboard/src/components/partials/QuickActions.tsx +21 -11
- package/dashboard/src/components/partials/StatCardGrid.tsx +67 -0
- package/dashboard/src/components/partials/StatusHeader.tsx +2 -1
- package/dashboard/src/components/settings/LogEntryList.tsx +43 -5
- package/dashboard/src/routes/command-center.routes.tsx +8 -7
- package/dashboard/src/routes/index.routes.tsx +32 -29
- package/package.json +2 -2
- package/plugins/copilot-pbr/agents/audit.agent.md +128 -16
- package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +48 -1
- package/plugins/copilot-pbr/agents/debugger.agent.md +47 -1
- package/plugins/copilot-pbr/agents/executor.agent.md +152 -8
- package/plugins/copilot-pbr/agents/general.agent.md +46 -1
- package/plugins/copilot-pbr/agents/integration-checker.agent.md +52 -2
- package/plugins/copilot-pbr/agents/plan-checker.agent.md +50 -2
- package/plugins/copilot-pbr/agents/planner.agent.md +54 -1
- package/plugins/copilot-pbr/agents/researcher.agent.md +47 -2
- package/plugins/copilot-pbr/agents/synthesizer.agent.md +49 -1
- package/plugins/copilot-pbr/agents/verifier.agent.md +86 -2
- package/plugins/copilot-pbr/hooks/hooks.json +11 -0
- package/plugins/copilot-pbr/plugin.json +1 -1
- package/plugins/copilot-pbr/references/agent-contracts.md +27 -0
- package/plugins/copilot-pbr/references/checkpoints.md +32 -1
- package/plugins/copilot-pbr/references/context-quality-tiers.md +45 -0
- package/plugins/copilot-pbr/references/pbr-tools-cli.md +115 -0
- package/plugins/copilot-pbr/references/questioning.md +21 -1
- package/plugins/copilot-pbr/references/verification-patterns.md +52 -1
- package/plugins/copilot-pbr/skills/audit/SKILL.md +19 -3
- package/plugins/copilot-pbr/skills/begin/SKILL.md +57 -4
- package/plugins/copilot-pbr/skills/build/SKILL.md +39 -2
- package/plugins/copilot-pbr/skills/debug/SKILL.md +12 -1
- package/plugins/copilot-pbr/skills/explore/SKILL.md +13 -2
- package/plugins/copilot-pbr/skills/import/SKILL.md +26 -1
- package/plugins/copilot-pbr/skills/milestone/SKILL.md +15 -3
- package/plugins/copilot-pbr/skills/plan/SKILL.md +50 -0
- package/plugins/copilot-pbr/skills/quick/SKILL.md +21 -0
- package/plugins/copilot-pbr/skills/review/SKILL.md +45 -0
- package/plugins/copilot-pbr/skills/scan/SKILL.md +20 -0
- package/plugins/copilot-pbr/templates/SUMMARY-complex.md.tmpl +95 -0
- package/plugins/copilot-pbr/templates/SUMMARY-minimal.md.tmpl +48 -0
- package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
- package/plugins/cursor-pbr/agents/audit.md +51 -5
- package/plugins/cursor-pbr/agents/codebase-mapper.md +48 -1
- package/plugins/cursor-pbr/agents/debugger.md +47 -1
- package/plugins/cursor-pbr/agents/executor.md +152 -8
- package/plugins/cursor-pbr/agents/general.md +46 -1
- package/plugins/cursor-pbr/agents/integration-checker.md +51 -1
- package/plugins/cursor-pbr/agents/plan-checker.md +49 -1
- package/plugins/cursor-pbr/agents/planner.md +54 -1
- package/plugins/cursor-pbr/agents/researcher.md +46 -1
- package/plugins/cursor-pbr/agents/synthesizer.md +49 -1
- package/plugins/cursor-pbr/agents/verifier.md +85 -1
- package/plugins/cursor-pbr/hooks/hooks.json +9 -0
- package/plugins/cursor-pbr/references/agent-contracts.md +27 -0
- package/plugins/cursor-pbr/references/checkpoints.md +32 -1
- package/plugins/cursor-pbr/references/context-quality-tiers.md +45 -0
- package/plugins/cursor-pbr/references/pbr-tools-cli.md +115 -0
- package/plugins/cursor-pbr/references/questioning.md +21 -1
- package/plugins/cursor-pbr/references/verification-patterns.md +52 -1
- package/plugins/cursor-pbr/skills/audit/SKILL.md +19 -3
- package/plugins/cursor-pbr/skills/begin/SKILL.md +57 -4
- package/plugins/cursor-pbr/skills/build/SKILL.md +37 -2
- package/plugins/cursor-pbr/skills/debug/SKILL.md +12 -1
- package/plugins/cursor-pbr/skills/explore/SKILL.md +13 -2
- package/plugins/cursor-pbr/skills/import/SKILL.md +26 -1
- package/plugins/cursor-pbr/skills/milestone/SKILL.md +15 -3
- package/plugins/cursor-pbr/skills/plan/SKILL.md +50 -0
- package/plugins/cursor-pbr/skills/quick/SKILL.md +21 -0
- package/plugins/cursor-pbr/skills/review/SKILL.md +45 -0
- package/plugins/cursor-pbr/skills/scan/SKILL.md +20 -0
- package/plugins/cursor-pbr/templates/SUMMARY-complex.md.tmpl +95 -0
- package/plugins/cursor-pbr/templates/SUMMARY-minimal.md.tmpl +48 -0
- package/plugins/pbr/.claude-plugin/plugin.json +1 -1
- package/plugins/pbr/agents/audit.md +44 -0
- package/plugins/pbr/agents/codebase-mapper.md +47 -0
- package/plugins/pbr/agents/debugger.md +46 -0
- package/plugins/pbr/agents/executor.md +150 -6
- package/plugins/pbr/agents/general.md +45 -0
- package/plugins/pbr/agents/integration-checker.md +50 -0
- package/plugins/pbr/agents/plan-checker.md +48 -0
- package/plugins/pbr/agents/planner.md +51 -0
- package/plugins/pbr/agents/researcher.md +45 -0
- package/plugins/pbr/agents/synthesizer.md +48 -0
- package/plugins/pbr/agents/verifier.md +84 -0
- package/plugins/pbr/hooks/hooks.json +9 -0
- package/plugins/pbr/references/agent-contracts.md +27 -0
- package/plugins/pbr/references/checkpoints.md +32 -0
- package/plugins/pbr/references/context-quality-tiers.md +45 -0
- package/plugins/pbr/references/pbr-tools-cli.md +115 -0
- package/plugins/pbr/references/questioning.md +21 -0
- package/plugins/pbr/references/verification-patterns.md +52 -0
- package/plugins/pbr/scripts/check-plan-format.js +15 -3
- package/plugins/pbr/scripts/check-state-sync.js +26 -7
- package/plugins/pbr/scripts/check-subagent-output.js +30 -2
- package/plugins/pbr/scripts/config-schema.json +11 -1
- package/plugins/pbr/scripts/context-bridge.js +259 -0
- package/plugins/pbr/scripts/context-budget-check.js +2 -2
- package/plugins/pbr/scripts/lib/config.js +178 -0
- package/plugins/pbr/scripts/lib/core.js +578 -0
- package/plugins/pbr/scripts/lib/history.js +73 -0
- package/plugins/pbr/scripts/lib/init.js +166 -0
- package/plugins/pbr/scripts/lib/phase.js +364 -0
- package/plugins/pbr/scripts/lib/roadmap.js +175 -0
- package/plugins/pbr/scripts/lib/state.js +397 -0
- package/plugins/pbr/scripts/pbr-tools.js +346 -1235
- package/plugins/pbr/scripts/post-write-dispatch.js +5 -4
- package/plugins/pbr/scripts/post-write-quality.js +3 -3
- package/plugins/pbr/scripts/pre-write-dispatch.js +1 -1
- package/plugins/pbr/scripts/progress-tracker.js +1 -1
- package/plugins/pbr/scripts/suggest-compact.js +1 -1
- package/plugins/pbr/scripts/track-context-budget.js +53 -2
- package/plugins/pbr/scripts/validate-task.js +20 -28
- package/plugins/pbr/skills/audit/SKILL.md +19 -3
- package/plugins/pbr/skills/begin/SKILL.md +48 -2
- package/plugins/pbr/skills/build/SKILL.md +39 -2
- package/plugins/pbr/skills/debug/SKILL.md +12 -1
- package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +12 -1
- package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +12 -5
- package/plugins/pbr/skills/explore/SKILL.md +13 -2
- package/plugins/pbr/skills/import/SKILL.md +26 -1
- package/plugins/pbr/skills/milestone/SKILL.md +15 -3
- package/plugins/pbr/skills/plan/SKILL.md +52 -2
- package/plugins/pbr/skills/quick/SKILL.md +21 -0
- package/plugins/pbr/skills/review/SKILL.md +46 -0
- package/plugins/pbr/skills/scan/SKILL.md +20 -0
- package/plugins/pbr/templates/SUMMARY-complex.md.tmpl +95 -0
- package/plugins/pbr/templates/SUMMARY-minimal.md.tmpl +48 -0
|
@@ -19,7 +19,7 @@ interface TodoListFragmentProps {
|
|
|
19
19
|
|
|
20
20
|
export function TodosTab({ todos }: TodosTabProps) {
|
|
21
21
|
return (
|
|
22
|
-
<div x-data="{ showCreate: false, showDone: false, search: '' }">
|
|
22
|
+
<div x-data="{ showCreate: false, showDone: false, search: '', statusFilter: '', priorityFilter: '', applyFilters() {} }">
|
|
23
23
|
{/* Search + filters row */}
|
|
24
24
|
<div class="explorer-toolbar">
|
|
25
25
|
<input
|
|
@@ -29,6 +29,22 @@ export function TodosTab({ todos }: TodosTabProps) {
|
|
|
29
29
|
class="explorer-search"
|
|
30
30
|
aria-label="Filter todos by title"
|
|
31
31
|
/>
|
|
32
|
+
<select class="explorer-filter-select" aria-label="Filter by status"
|
|
33
|
+
x-model="statusFilter"
|
|
34
|
+
x-on:change="applyFilters()">
|
|
35
|
+
<option value="">All statuses</option>
|
|
36
|
+
<option value="pending">Pending</option>
|
|
37
|
+
<option value="in-progress">In Progress</option>
|
|
38
|
+
<option value="done">Done</option>
|
|
39
|
+
</select>
|
|
40
|
+
<select class="explorer-filter-select" aria-label="Filter by priority"
|
|
41
|
+
x-model="priorityFilter"
|
|
42
|
+
x-on:change="applyFilters()">
|
|
43
|
+
<option value="">All priorities</option>
|
|
44
|
+
<option value="high">High</option>
|
|
45
|
+
<option value="medium">Medium</option>
|
|
46
|
+
<option value="low">Low</option>
|
|
47
|
+
</select>
|
|
32
48
|
<button x-on:click="showCreate = !showCreate" class="btn btn--primary btn--sm">
|
|
33
49
|
+ New Todo
|
|
34
50
|
</button>
|
|
@@ -74,16 +90,15 @@ export function TodoListFragment({ todos }: TodoListFragmentProps) {
|
|
|
74
90
|
{todos.length === 0 && <li class="explorer__loading">No pending todos.</li>}
|
|
75
91
|
{todos.map((todo) => (
|
|
76
92
|
<li
|
|
77
|
-
class=
|
|
93
|
+
class={`todo-card todo-card--${todo.priority}`}
|
|
78
94
|
key={todo.id}
|
|
79
|
-
x-show={
|
|
95
|
+
x-show={`(!search || '${todo.title.toLowerCase()}'.includes(search.toLowerCase())) && (!priorityFilter || priorityFilter === '${todo.priority}') && (!statusFilter || statusFilter === '${todo.status || ''}')`}
|
|
80
96
|
>
|
|
81
|
-
<div class="
|
|
97
|
+
<div class="todo-card__main">
|
|
82
98
|
<span class={`explorer-badge explorer-badge--${todo.priority}`}>{todo.priority}</span>
|
|
83
99
|
<span class="explorer-item__title">{todo.title}</span>
|
|
84
|
-
{todo.phase && <span class="explorer-item__meta">Phase {todo.phase}</span>}
|
|
85
100
|
<button
|
|
86
|
-
class="btn btn--
|
|
101
|
+
class="btn btn--ghost btn--sm"
|
|
87
102
|
hx-post={`/api/explorer/todos/${todo.id}/complete`}
|
|
88
103
|
hx-target="closest li"
|
|
89
104
|
hx-swap="outerHTML"
|
|
@@ -92,6 +107,10 @@ export function TodoListFragment({ todos }: TodoListFragmentProps) {
|
|
|
92
107
|
Done
|
|
93
108
|
</button>
|
|
94
109
|
</div>
|
|
110
|
+
<div class="todo-card__meta">
|
|
111
|
+
{todo.phase && <span>Phase {todo.phase}</span>}
|
|
112
|
+
{todo.created && <span>{new Date(todo.created).toLocaleDateString()}</span>}
|
|
113
|
+
</div>
|
|
95
114
|
</li>
|
|
96
115
|
))}
|
|
97
116
|
</ul>
|
|
@@ -41,7 +41,13 @@ export const AttentionPanel: FC<AttentionPanelProps> = ({
|
|
|
41
41
|
))}
|
|
42
42
|
</ul>
|
|
43
43
|
) : (
|
|
44
|
-
<
|
|
44
|
+
<div class="empty-state">
|
|
45
|
+
<span class="empty-state__icon" aria-hidden="true">
|
|
46
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
|
|
47
|
+
</span>
|
|
48
|
+
<p class="empty-state__heading">All clear</p>
|
|
49
|
+
<p class="empty-state__body">No blockers or attention items right now.</p>
|
|
50
|
+
</div>
|
|
45
51
|
)}
|
|
46
52
|
</div>
|
|
47
53
|
);
|
|
@@ -21,30 +21,32 @@ export const CurrentPhaseCard: FC<CurrentPhaseCardProps> = ({
|
|
|
21
21
|
}) => {
|
|
22
22
|
return (
|
|
23
23
|
<div class="card current-phase-card">
|
|
24
|
-
<div class="card__header">
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{currentPhase.status}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
24
|
+
<div class="card__header">CURRENT PHASE</div>
|
|
25
|
+
<div class="card__body">
|
|
26
|
+
<h2 class="card__title">
|
|
27
|
+
Phase {currentPhase.id}: {currentPhase.name}
|
|
28
|
+
</h2>
|
|
29
|
+
<span class={`badge status-badge status-badge--${currentPhase.status}`} data-status={currentPhase.status}>
|
|
30
|
+
{currentPhase.status}
|
|
31
|
+
</span>
|
|
32
|
+
<p class="card__meta">Plans: {currentPhase.planStatus}</p>
|
|
33
|
+
<p class="card__meta">
|
|
34
|
+
Last activity: {lastActivity.date || 'N/A'} — {lastActivity.description}
|
|
35
|
+
</p>
|
|
36
|
+
{nextAction && (
|
|
37
|
+
<div class="next-action">
|
|
38
|
+
<span class="next-action__label">Next</span>
|
|
39
|
+
<code class="next-action__cmd">{nextAction}</code>
|
|
40
|
+
<button
|
|
41
|
+
class="btn btn--ghost btn--sm"
|
|
42
|
+
type="button"
|
|
43
|
+
onclick={`navigator.clipboard.writeText('${nextAction}')`}
|
|
44
|
+
>
|
|
45
|
+
Copy
|
|
46
|
+
</button>
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
</div>
|
|
48
50
|
</div>
|
|
49
51
|
);
|
|
50
52
|
};
|
|
@@ -14,17 +14,27 @@ export const QuickActions: FC<QuickActionsProps> = ({ actions }) => {
|
|
|
14
14
|
return (
|
|
15
15
|
<div class="quick-actions" id="quick-actions">
|
|
16
16
|
<p class="quick-actions__label">Quick Actions</p>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
17
|
+
{actions.length === 0 ? (
|
|
18
|
+
<div class="empty-state">
|
|
19
|
+
<span class="empty-state__icon" aria-hidden="true">
|
|
20
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
|
|
21
|
+
</span>
|
|
22
|
+
<p class="empty-state__heading">No quick actions</p>
|
|
23
|
+
<p class="empty-state__body">Start a new phase to see actions here.</p>
|
|
24
|
+
</div>
|
|
25
|
+
) : (
|
|
26
|
+
<div class="quick-actions__buttons">
|
|
27
|
+
{actions.map((action, i) => (
|
|
28
|
+
<a
|
|
29
|
+
key={i}
|
|
30
|
+
href={action.href}
|
|
31
|
+
class={`btn${action.primary ? ' btn--primary' : ' btn--secondary'}`}
|
|
32
|
+
>
|
|
33
|
+
{action.label}
|
|
34
|
+
</a>
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
37
|
+
)}
|
|
28
38
|
</div>
|
|
29
39
|
);
|
|
30
40
|
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { FC } from 'hono/jsx';
|
|
2
|
+
|
|
3
|
+
interface StatCardGridProps {
|
|
4
|
+
currentPhase: { id: number; name: string; status: string };
|
|
5
|
+
plansComplete: number;
|
|
6
|
+
plansTotal: number;
|
|
7
|
+
progress: number;
|
|
8
|
+
completedPhases: number;
|
|
9
|
+
totalPhases: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface StatCardProps {
|
|
13
|
+
label: string;
|
|
14
|
+
value: string | number;
|
|
15
|
+
sub?: string | any;
|
|
16
|
+
accent?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const StatCard: FC<StatCardProps> = ({ label, value, sub, accent }) => (
|
|
20
|
+
<div class={`stat-card${accent ? ' stat-card--accent' : ''}`}>
|
|
21
|
+
<span class="stat-card__label">{label}</span>
|
|
22
|
+
<span class="stat-card__value">{value}</span>
|
|
23
|
+
{sub && <span class="stat-card__sub">{sub}</span>}
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
export const StatCardGrid: FC<StatCardGridProps> = ({
|
|
28
|
+
currentPhase,
|
|
29
|
+
plansComplete,
|
|
30
|
+
plansTotal,
|
|
31
|
+
progress,
|
|
32
|
+
completedPhases,
|
|
33
|
+
totalPhases,
|
|
34
|
+
}) => {
|
|
35
|
+
const plansDisplay = plansTotal > 0 ? `${plansComplete} / ${plansTotal}` : '—';
|
|
36
|
+
const phasesDisplay = `${completedPhases} / ${totalPhases}`;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div class="stat-card-grid">
|
|
40
|
+
<StatCard
|
|
41
|
+
label="Current Phase"
|
|
42
|
+
value={`#${currentPhase.id}`}
|
|
43
|
+
sub={currentPhase.name}
|
|
44
|
+
accent
|
|
45
|
+
/>
|
|
46
|
+
<StatCard
|
|
47
|
+
label="Plans"
|
|
48
|
+
value={plansDisplay}
|
|
49
|
+
sub={plansTotal > 0 ? `${plansTotal - plansComplete} remaining` : 'none yet'}
|
|
50
|
+
/>
|
|
51
|
+
<StatCard
|
|
52
|
+
label="Phases"
|
|
53
|
+
value={phasesDisplay}
|
|
54
|
+
sub="completed"
|
|
55
|
+
/>
|
|
56
|
+
<StatCard
|
|
57
|
+
label="Progress"
|
|
58
|
+
value={`${progress}%`}
|
|
59
|
+
sub={
|
|
60
|
+
<div class="stat-card__mini-bar">
|
|
61
|
+
<div class="stat-card__mini-bar-fill" style={`width:${progress}%`} />
|
|
62
|
+
</div>
|
|
63
|
+
}
|
|
64
|
+
/>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @deprecated Replaced by StatCardGrid in Phase 44. Kept for test compatibility. */
|
|
1
2
|
import type { FC } from 'hono/jsx';
|
|
2
3
|
|
|
3
4
|
interface StatusHeaderProps {
|
|
@@ -26,7 +27,7 @@ export const StatusHeader: FC<StatusHeaderProps> = ({
|
|
|
26
27
|
<span class="status-header__phase">
|
|
27
28
|
Phase {currentPhase.id}: {currentPhase.name}
|
|
28
29
|
</span>
|
|
29
|
-
<span class={`badge status-badge status-badge--${currentPhase.status}`}>
|
|
30
|
+
<span class={`badge status-badge status-badge--${currentPhase.status}`} data-status={currentPhase.status}>
|
|
30
31
|
{currentPhase.status}
|
|
31
32
|
</span>
|
|
32
33
|
<div class="milestone-bar">
|
|
@@ -14,7 +14,7 @@ function sanitizeType(t: unknown): string {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function getTimestamp(entry: Record<string, unknown>): string {
|
|
17
|
-
const raw = entry['timestamp'] ?? entry['ts'] ?? entry['time'];
|
|
17
|
+
const raw = entry['timestamp'] ?? entry['ts'] ?? entry['time'] ?? entry['start'] ?? entry['end'];
|
|
18
18
|
if (!raw) return '—';
|
|
19
19
|
try {
|
|
20
20
|
return new Date(raw as string).toLocaleString();
|
|
@@ -23,15 +23,53 @@ function getTimestamp(entry: Record<string, unknown>): string {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function getType(entry: Record<string, unknown>): string {
|
|
27
|
+
if (typeof entry['type'] === 'string' && entry['type']) return entry['type'];
|
|
28
|
+
if (typeof entry['event'] === 'string' && entry['event']) return entry['event'];
|
|
29
|
+
if (typeof entry['hook'] === 'string' && entry['hook']) return 'hook';
|
|
30
|
+
if (typeof entry['action'] === 'string' && entry['action']) return entry['action'];
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
function getSummary(entry: Record<string, unknown>): string {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
// Session log entry: has start/end/duration_minutes
|
|
36
|
+
if (entry['duration_minutes'] != null || (entry['start'] && entry['end'])) {
|
|
37
|
+
const parts: string[] = [];
|
|
38
|
+
if (entry['duration_minutes'] != null) parts.push(`Duration: ${entry['duration_minutes']}m`);
|
|
39
|
+
if (entry['reason']) parts.push(`Reason: ${entry['reason']}`);
|
|
40
|
+
if (entry['agents'] != null) parts.push(`Agents: ${entry['agents']}`);
|
|
41
|
+
if (parts.length > 0) return parts.join(', ');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Hook log entry: has hook/script fields
|
|
45
|
+
if (entry['hook'] || entry['script']) {
|
|
46
|
+
const parts: string[] = [];
|
|
47
|
+
if (entry['hook']) parts.push(`Hook: ${entry['hook']}`);
|
|
48
|
+
if (entry['script']) parts.push(`Script: ${entry['script']}`);
|
|
49
|
+
if (entry['result']) parts.push(`Result: ${entry['result']}`);
|
|
50
|
+
if (parts.length > 0) return parts.join(', ');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Event/action entry
|
|
54
|
+
if (entry['event'] || entry['action']) {
|
|
55
|
+
const parts: string[] = [];
|
|
56
|
+
if (entry['event']) parts.push(`Event: ${entry['event']}`);
|
|
57
|
+
if (entry['action']) parts.push(`Action: ${entry['action']}`);
|
|
58
|
+
if (parts.length > 0) return parts.join(', ');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Fallback: first 3 meaningful key-value pairs
|
|
62
|
+
const skip = new Set(['type', 'timestamp', 'ts', 'time', 'start', 'end']);
|
|
63
|
+
const pairs = Object.entries(entry)
|
|
64
|
+
.filter(([k, v]) => !skip.has(k) && v != null && typeof v !== 'object')
|
|
65
|
+
.slice(0, 3)
|
|
66
|
+
.map(([k, v]) => `${k}: ${v}`);
|
|
67
|
+
return pairs.length > 0 ? pairs.join(', ') : '—';
|
|
30
68
|
}
|
|
31
69
|
|
|
32
70
|
export function LogEntryRow({ entry }: { entry: object }) {
|
|
33
71
|
const e = entry as Record<string, unknown>;
|
|
34
|
-
const type =
|
|
72
|
+
const type = getType(e);
|
|
35
73
|
const badge = sanitizeType(type);
|
|
36
74
|
const timestamp = getTimestamp(e);
|
|
37
75
|
const summary = getSummary(e);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
2
|
import { getDashboardData } from '../services/dashboard.service.js';
|
|
3
3
|
import { listPendingTodos } from '../services/todo.service.js';
|
|
4
|
-
import {
|
|
5
|
-
import { ProgressRing } from '../components/partials/ProgressRing';
|
|
4
|
+
import { StatCardGrid } from '../components/partials/StatCardGrid';
|
|
6
5
|
import { CurrentPhaseCard } from '../components/partials/CurrentPhaseCard';
|
|
7
6
|
import { AttentionPanel } from '../components/partials/AttentionPanel';
|
|
8
7
|
import { PhaseTimeline } from '../components/partials/PhaseTimeline';
|
|
@@ -29,16 +28,18 @@ async function fetchAllData(projectDir: string) {
|
|
|
29
28
|
router.get('/status', async (c) => {
|
|
30
29
|
const projectDir = c.get('projectDir');
|
|
31
30
|
const { data, completed } = await fetchAllData(projectDir);
|
|
31
|
+
const plansComplete = (data.phases as any[]).reduce((sum: number, p: any) => sum + (p.plansComplete || 0), 0);
|
|
32
|
+
const plansTotal = (data.phases as any[]).reduce((sum: number, p: any) => sum + (p.plansTotal || 0), 0);
|
|
32
33
|
return c.html(
|
|
33
34
|
<div id="cc-status">
|
|
34
|
-
<
|
|
35
|
-
projectName={data.projectName}
|
|
35
|
+
<StatCardGrid
|
|
36
36
|
currentPhase={data.currentPhase}
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
plansComplete={plansComplete}
|
|
38
|
+
plansTotal={plansTotal}
|
|
39
39
|
progress={data.progress}
|
|
40
|
+
completedPhases={completed}
|
|
41
|
+
totalPhases={(data.phases as any[]).length}
|
|
40
42
|
/>
|
|
41
|
-
<ProgressRing percent={data.progress} />
|
|
42
43
|
</div>
|
|
43
44
|
);
|
|
44
45
|
});
|
|
@@ -51,42 +51,45 @@ router.get('/', async (c) => {
|
|
|
51
51
|
<ProgressRing percent={data.progress} />
|
|
52
52
|
</div>
|
|
53
53
|
|
|
54
|
-
<div class="
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
id="attention-panel-wrapper"
|
|
63
|
-
hx-get="/api/command-center/attention"
|
|
64
|
-
hx-trigger="sse:file-change"
|
|
65
|
-
hx-swap="outerHTML"
|
|
66
|
-
hx-ext="sse"
|
|
67
|
-
>
|
|
68
|
-
<AttentionPanel
|
|
69
|
-
todos={todos}
|
|
54
|
+
<div class="cc-two-col">
|
|
55
|
+
<div class="cc-col-main">
|
|
56
|
+
<CurrentPhaseCard
|
|
57
|
+
currentPhase={data.currentPhase}
|
|
58
|
+
lastActivity={data.lastActivity}
|
|
59
|
+
nextAction={(data as any).nextAction ?? null}
|
|
60
|
+
/>
|
|
61
|
+
<PhaseTimeline
|
|
70
62
|
phases={data.phases as any[]}
|
|
71
63
|
currentPhaseId={data.currentPhase.id}
|
|
72
64
|
/>
|
|
73
65
|
</div>
|
|
74
66
|
|
|
75
|
-
<
|
|
67
|
+
<div class="cc-col-side">
|
|
68
|
+
<div
|
|
69
|
+
id="attention-panel-wrapper"
|
|
70
|
+
hx-get="/api/command-center/attention"
|
|
71
|
+
hx-trigger="sse:file-change"
|
|
72
|
+
hx-swap="outerHTML"
|
|
73
|
+
hx-ext="sse"
|
|
74
|
+
>
|
|
75
|
+
<AttentionPanel
|
|
76
|
+
todos={todos}
|
|
77
|
+
phases={data.phases as any[]}
|
|
78
|
+
currentPhaseId={data.currentPhase.id}
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
76
81
|
|
|
77
|
-
|
|
78
|
-
phases={data.phases as any[]}
|
|
79
|
-
currentPhaseId={data.currentPhase.id}
|
|
80
|
-
/>
|
|
82
|
+
<QuickActions actions={data.quickActions} />
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
<div
|
|
85
|
+
id="activity-stream-wrapper"
|
|
86
|
+
hx-get="/api/command-center/activity"
|
|
87
|
+
hx-trigger="sse:file-change"
|
|
88
|
+
hx-swap="outerHTML"
|
|
89
|
+
hx-ext="sse"
|
|
90
|
+
>
|
|
91
|
+
<ActivityStream activity={data.recentActivity} />
|
|
92
|
+
</div>
|
|
90
93
|
</div>
|
|
91
94
|
</div>
|
|
92
95
|
</main>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sienklogic/plan-build-run",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.37.0",
|
|
4
4
|
"description": "Plan it, Build it, Run it — structured development workflow for Claude Code",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"coverageThreshold": {
|
|
49
49
|
"global": {
|
|
50
50
|
"statements": 70,
|
|
51
|
-
"branches":
|
|
51
|
+
"branches": 69,
|
|
52
52
|
"functions": 70,
|
|
53
53
|
"lines": 70
|
|
54
54
|
}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: audit
|
|
3
3
|
description: "Analyzes Claude Code session logs for PBR workflow compliance, hook firing, state file hygiene, and user experience quality."
|
|
4
|
-
tools: ["
|
|
4
|
+
tools: ["*"]
|
|
5
5
|
infer: true
|
|
6
6
|
target: "github-copilot"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
<files_to_read>
|
|
10
|
+
CRITICAL: If your spawn prompt contains a files_to_read block,
|
|
11
|
+
you MUST Read every listed file BEFORE any other action.
|
|
12
|
+
Skipping this causes hallucinated context and broken output.
|
|
13
|
+
</files_to_read>
|
|
14
|
+
|
|
15
|
+
> Default files: session JSONL path provided in spawn prompt
|
|
16
|
+
|
|
9
17
|
# Plan-Build-Run Session Auditor
|
|
10
18
|
|
|
11
19
|
You are **audit**, the session analysis agent for the Plan-Build-Run development system. You analyze Claude Code session JSONL logs to evaluate PBR workflow compliance, hook firing, state management, commit discipline, and user experience quality.
|
|
@@ -49,65 +57,169 @@ For each session, check:
|
|
|
49
57
|
|
|
50
58
|
### 1. PBR Commands Used
|
|
51
59
|
- Extract all `/pbr:*` command invocations from user messages
|
|
52
|
-
- Was the command sequence logical?
|
|
60
|
+
- Was the command sequence logical? (e.g., plan before build, build before review)
|
|
53
61
|
- Were there commands that SHOULD have been used but weren't?
|
|
54
62
|
|
|
55
63
|
### 2. STATE.md Lifecycle
|
|
56
64
|
- Was STATE.md read before starting work?
|
|
57
65
|
- Was STATE.md updated at phase transitions?
|
|
66
|
+
- After context compaction/continuation, was STATE.md re-read?
|
|
58
67
|
|
|
59
68
|
### 3. ROADMAP.md Consultation
|
|
60
69
|
- Was ROADMAP.md read during build, plan, or milestone operations?
|
|
61
70
|
|
|
62
71
|
### 4. SUMMARY.md Creation
|
|
63
72
|
- After any build or quick task, was SUMMARY.md created?
|
|
73
|
+
- Does it contain required frontmatter fields (`requires`, `key_files`, `deferred`)?
|
|
64
74
|
|
|
65
75
|
### 5. Hook Evidence
|
|
66
76
|
- Are there `hook_progress` entries in the log?
|
|
67
77
|
- Which hooks fired and how many times?
|
|
78
|
+
- Were any hooks missing that should have fired?
|
|
68
79
|
- If NO hook evidence exists, flag as HIGH severity
|
|
69
80
|
|
|
70
81
|
### 6. Commit Format
|
|
82
|
+
- Extract all `git commit` commands from Bash tool calls
|
|
71
83
|
- Verify format: `{type}({scope}): {description}`
|
|
72
84
|
- Check for forbidden `Co-Authored-By` lines
|
|
73
85
|
|
|
74
|
-
### 7.
|
|
86
|
+
### 7. Agent Delegation
|
|
75
87
|
- Was implementation work delegated to executor agents?
|
|
76
88
|
- Or was it done directly in main context (anti-pattern)?
|
|
89
|
+
- Count tool calls in main context vs agents
|
|
90
|
+
|
|
91
|
+
### 8. Active Skill Management
|
|
92
|
+
- Was `.active-skill` written when skills were invoked?
|
|
93
|
+
- Was it cleaned up when skills completed?
|
|
77
94
|
|
|
78
95
|
---
|
|
79
96
|
|
|
80
97
|
## UX Audit Checklist
|
|
81
98
|
|
|
99
|
+
For each session, evaluate:
|
|
100
|
+
|
|
82
101
|
### 1. User Intent vs Assistant Behavior
|
|
102
|
+
- What did the user ask for? (Extract exact user messages)
|
|
83
103
|
- Did the assistant deliver what was asked?
|
|
84
|
-
- Did the user have to repeat instructions?
|
|
104
|
+
- Did the user have to repeat instructions? (Escalation = frustration)
|
|
105
|
+
- Count the number of course-corrections
|
|
85
106
|
|
|
86
107
|
### 2. Flow Choice Quality
|
|
87
|
-
- Was the chosen PBR command the best fit?
|
|
88
|
-
-
|
|
108
|
+
- Was the chosen PBR command the best fit for the task?
|
|
109
|
+
- Would a different command have been more efficient?
|
|
110
|
+
- Was the ceremony proportionate to the task scope?
|
|
89
111
|
|
|
90
112
|
### 3. Feedback and Progress
|
|
91
113
|
- Were there progress updates during long operations?
|
|
114
|
+
- Were CI results communicated clearly?
|
|
115
|
+
- Were there silent gaps with no user feedback?
|
|
116
|
+
|
|
117
|
+
### 4. Handoff Quality
|
|
118
|
+
- After skill completion, was the next step suggested?
|
|
119
|
+
- Did the user know what to do next?
|
|
120
|
+
|
|
121
|
+
### 5. Context Efficiency
|
|
122
|
+
- Did the session approach or hit context limits?
|
|
123
|
+
- Was work delegated to agents appropriately?
|
|
124
|
+
- Were there unnecessary file reads burning context?
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Output Format
|
|
129
|
+
|
|
130
|
+
Write findings to the specified output path using this structure:
|
|
131
|
+
|
|
132
|
+
```markdown
|
|
133
|
+
# PBR Session Audit
|
|
134
|
+
|
|
135
|
+
## Session Metadata
|
|
136
|
+
- **Session ID**: {id}
|
|
137
|
+
- **Time Range**: {start} to {end}
|
|
138
|
+
- **Duration**: {duration}
|
|
139
|
+
- **Claude Code Version**: {version}
|
|
140
|
+
- **Branch**: {branch}
|
|
141
|
+
|
|
142
|
+
## PBR Commands Invoked
|
|
143
|
+
| # | Command | Arguments | Timestamp |
|
|
144
|
+
|---|---------|-----------|-----------|
|
|
145
|
+
|
|
146
|
+
## Compliance Score
|
|
147
|
+
| Category | Status | Details |
|
|
148
|
+
|----------|--------|---------|
|
|
149
|
+
|
|
150
|
+
## UX Score (if audit mode includes UX)
|
|
151
|
+
| Dimension | Rating | Details |
|
|
152
|
+
|-----------|--------|---------|
|
|
153
|
+
|
|
154
|
+
## Hook Firing Report
|
|
155
|
+
| Hook Event | Count | Notes |
|
|
156
|
+
|------------|-------|-------|
|
|
92
157
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
158
|
+
## Commits Made
|
|
159
|
+
| Hash | Message | Format Valid? |
|
|
160
|
+
|------|---------|---------------|
|
|
161
|
+
|
|
162
|
+
## Issues Found
|
|
163
|
+
### Critical
|
|
164
|
+
### High
|
|
165
|
+
### Medium
|
|
166
|
+
### Low
|
|
167
|
+
|
|
168
|
+
## Recommendations
|
|
169
|
+
```
|
|
96
170
|
|
|
97
171
|
---
|
|
98
172
|
|
|
99
173
|
## Context Budget
|
|
100
174
|
|
|
101
|
-
- **Maximum**: 50% of context for reading logs, 50% for analysis
|
|
102
|
-
- Large JSONL files:
|
|
103
|
-
- Focus on user messages, tool calls, and hook progress entries
|
|
175
|
+
- **Maximum**: 50% of context for reading logs, 50% for analysis and output
|
|
176
|
+
- Large JSONL files (>1MB): Read in chunks using `offset` and `limit` on Read tool, or use Bash with `wc -l` to assess size first, then sample key sections
|
|
177
|
+
- Focus on user messages (`"role": "human"`), tool calls, and hook progress entries
|
|
178
|
+
- Skip verbose tool output content — focus on tool names and results
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### Context Quality Tiers
|
|
183
|
+
|
|
184
|
+
| Budget Used | Tier | Behavior |
|
|
185
|
+
|------------|------|----------|
|
|
186
|
+
| 0-30% | PEAK | Explore freely, read broadly |
|
|
187
|
+
| 30-50% | GOOD | Be selective with reads |
|
|
188
|
+
| 50-70% | DEGRADING | Write incrementally, skip non-essential |
|
|
189
|
+
| 70%+ | POOR | Finish current task and return immediately |
|
|
104
190
|
|
|
105
191
|
---
|
|
106
192
|
|
|
193
|
+
<anti_patterns>
|
|
194
|
+
|
|
107
195
|
## Anti-Patterns
|
|
108
196
|
|
|
109
|
-
1. DO NOT guess what hooks did — only report evidence
|
|
110
|
-
2. DO NOT read the entire JSONL if it exceeds 2000 lines
|
|
111
|
-
3. DO NOT judge explore
|
|
197
|
+
1. DO NOT guess what hooks did — only report what the log evidence shows
|
|
198
|
+
2. DO NOT read the entire JSONL if it exceeds 2000 lines — sample strategically
|
|
199
|
+
3. DO NOT judge workflow violations without understanding the skill type (explore is read-only, doesn't need STATE.md updates)
|
|
112
200
|
4. DO NOT fabricate timestamps or session IDs
|
|
113
|
-
5. DO NOT include raw JSONL content in output
|
|
201
|
+
5. DO NOT include raw JSONL content in the output — summarize findings
|
|
202
|
+
6. DO NOT over-report informational items as critical — use appropriate severity
|
|
203
|
+
|
|
204
|
+
</anti_patterns>
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
<success_criteria>
|
|
209
|
+
- [ ] Session JSONL files located and read
|
|
210
|
+
- [ ] Compliance checklist evaluated
|
|
211
|
+
- [ ] UX checklist evaluated (if mode includes UX)
|
|
212
|
+
- [ ] Hook firing patterns analyzed
|
|
213
|
+
- [ ] Scores calculated with evidence
|
|
214
|
+
- [ ] Report written with required sections
|
|
215
|
+
- [ ] Completion marker returned
|
|
216
|
+
</success_criteria>
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Completion Protocol
|
|
221
|
+
|
|
222
|
+
CRITICAL: Your final output MUST end with exactly one completion marker.
|
|
223
|
+
Orchestrators pattern-match on these markers to route results. Omitting causes silent failures.
|
|
224
|
+
|
|
225
|
+
- `## AUDIT COMPLETE` - audit report written to .planning/audits/
|