@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.
Files changed (140) hide show
  1. package/CHANGELOG.md +678 -0
  2. package/dashboard/public/css/command-center.css +152 -65
  3. package/dashboard/public/css/explorer.css +70 -41
  4. package/dashboard/public/css/layout.css +163 -2
  5. package/dashboard/public/css/settings.css +108 -110
  6. package/dashboard/public/css/timeline.css +2 -1
  7. package/dashboard/public/css/tokens.css +13 -0
  8. package/dashboard/public/js/sidebar-toggle.js +21 -7
  9. package/dashboard/src/components/Layout.tsx +51 -7
  10. package/dashboard/src/components/explorer/tabs/MilestonesTab.tsx +18 -2
  11. package/dashboard/src/components/explorer/tabs/PhasesTab.tsx +11 -1
  12. package/dashboard/src/components/explorer/tabs/TodosTab.tsx +25 -6
  13. package/dashboard/src/components/partials/AttentionPanel.tsx +7 -1
  14. package/dashboard/src/components/partials/CurrentPhaseCard.tsx +26 -24
  15. package/dashboard/src/components/partials/QuickActions.tsx +21 -11
  16. package/dashboard/src/components/partials/StatCardGrid.tsx +67 -0
  17. package/dashboard/src/components/partials/StatusHeader.tsx +2 -1
  18. package/dashboard/src/components/settings/LogEntryList.tsx +43 -5
  19. package/dashboard/src/routes/command-center.routes.tsx +8 -7
  20. package/dashboard/src/routes/index.routes.tsx +32 -29
  21. package/package.json +2 -2
  22. package/plugins/copilot-pbr/agents/audit.agent.md +128 -16
  23. package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +48 -1
  24. package/plugins/copilot-pbr/agents/debugger.agent.md +47 -1
  25. package/plugins/copilot-pbr/agents/executor.agent.md +152 -8
  26. package/plugins/copilot-pbr/agents/general.agent.md +46 -1
  27. package/plugins/copilot-pbr/agents/integration-checker.agent.md +52 -2
  28. package/plugins/copilot-pbr/agents/plan-checker.agent.md +50 -2
  29. package/plugins/copilot-pbr/agents/planner.agent.md +54 -1
  30. package/plugins/copilot-pbr/agents/researcher.agent.md +47 -2
  31. package/plugins/copilot-pbr/agents/synthesizer.agent.md +49 -1
  32. package/plugins/copilot-pbr/agents/verifier.agent.md +86 -2
  33. package/plugins/copilot-pbr/hooks/hooks.json +11 -0
  34. package/plugins/copilot-pbr/plugin.json +1 -1
  35. package/plugins/copilot-pbr/references/agent-contracts.md +27 -0
  36. package/plugins/copilot-pbr/references/checkpoints.md +32 -1
  37. package/plugins/copilot-pbr/references/context-quality-tiers.md +45 -0
  38. package/plugins/copilot-pbr/references/pbr-tools-cli.md +115 -0
  39. package/plugins/copilot-pbr/references/questioning.md +21 -1
  40. package/plugins/copilot-pbr/references/verification-patterns.md +52 -1
  41. package/plugins/copilot-pbr/skills/audit/SKILL.md +19 -3
  42. package/plugins/copilot-pbr/skills/begin/SKILL.md +57 -4
  43. package/plugins/copilot-pbr/skills/build/SKILL.md +39 -2
  44. package/plugins/copilot-pbr/skills/debug/SKILL.md +12 -1
  45. package/plugins/copilot-pbr/skills/explore/SKILL.md +13 -2
  46. package/plugins/copilot-pbr/skills/import/SKILL.md +26 -1
  47. package/plugins/copilot-pbr/skills/milestone/SKILL.md +15 -3
  48. package/plugins/copilot-pbr/skills/plan/SKILL.md +50 -0
  49. package/plugins/copilot-pbr/skills/quick/SKILL.md +21 -0
  50. package/plugins/copilot-pbr/skills/review/SKILL.md +45 -0
  51. package/plugins/copilot-pbr/skills/scan/SKILL.md +20 -0
  52. package/plugins/copilot-pbr/templates/SUMMARY-complex.md.tmpl +95 -0
  53. package/plugins/copilot-pbr/templates/SUMMARY-minimal.md.tmpl +48 -0
  54. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
  55. package/plugins/cursor-pbr/agents/audit.md +51 -5
  56. package/plugins/cursor-pbr/agents/codebase-mapper.md +48 -1
  57. package/plugins/cursor-pbr/agents/debugger.md +47 -1
  58. package/plugins/cursor-pbr/agents/executor.md +152 -8
  59. package/plugins/cursor-pbr/agents/general.md +46 -1
  60. package/plugins/cursor-pbr/agents/integration-checker.md +51 -1
  61. package/plugins/cursor-pbr/agents/plan-checker.md +49 -1
  62. package/plugins/cursor-pbr/agents/planner.md +54 -1
  63. package/plugins/cursor-pbr/agents/researcher.md +46 -1
  64. package/plugins/cursor-pbr/agents/synthesizer.md +49 -1
  65. package/plugins/cursor-pbr/agents/verifier.md +85 -1
  66. package/plugins/cursor-pbr/hooks/hooks.json +9 -0
  67. package/plugins/cursor-pbr/references/agent-contracts.md +27 -0
  68. package/plugins/cursor-pbr/references/checkpoints.md +32 -1
  69. package/plugins/cursor-pbr/references/context-quality-tiers.md +45 -0
  70. package/plugins/cursor-pbr/references/pbr-tools-cli.md +115 -0
  71. package/plugins/cursor-pbr/references/questioning.md +21 -1
  72. package/plugins/cursor-pbr/references/verification-patterns.md +52 -1
  73. package/plugins/cursor-pbr/skills/audit/SKILL.md +19 -3
  74. package/plugins/cursor-pbr/skills/begin/SKILL.md +57 -4
  75. package/plugins/cursor-pbr/skills/build/SKILL.md +37 -2
  76. package/plugins/cursor-pbr/skills/debug/SKILL.md +12 -1
  77. package/plugins/cursor-pbr/skills/explore/SKILL.md +13 -2
  78. package/plugins/cursor-pbr/skills/import/SKILL.md +26 -1
  79. package/plugins/cursor-pbr/skills/milestone/SKILL.md +15 -3
  80. package/plugins/cursor-pbr/skills/plan/SKILL.md +50 -0
  81. package/plugins/cursor-pbr/skills/quick/SKILL.md +21 -0
  82. package/plugins/cursor-pbr/skills/review/SKILL.md +45 -0
  83. package/plugins/cursor-pbr/skills/scan/SKILL.md +20 -0
  84. package/plugins/cursor-pbr/templates/SUMMARY-complex.md.tmpl +95 -0
  85. package/plugins/cursor-pbr/templates/SUMMARY-minimal.md.tmpl +48 -0
  86. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  87. package/plugins/pbr/agents/audit.md +44 -0
  88. package/plugins/pbr/agents/codebase-mapper.md +47 -0
  89. package/plugins/pbr/agents/debugger.md +46 -0
  90. package/plugins/pbr/agents/executor.md +150 -6
  91. package/plugins/pbr/agents/general.md +45 -0
  92. package/plugins/pbr/agents/integration-checker.md +50 -0
  93. package/plugins/pbr/agents/plan-checker.md +48 -0
  94. package/plugins/pbr/agents/planner.md +51 -0
  95. package/plugins/pbr/agents/researcher.md +45 -0
  96. package/plugins/pbr/agents/synthesizer.md +48 -0
  97. package/plugins/pbr/agents/verifier.md +84 -0
  98. package/plugins/pbr/hooks/hooks.json +9 -0
  99. package/plugins/pbr/references/agent-contracts.md +27 -0
  100. package/plugins/pbr/references/checkpoints.md +32 -0
  101. package/plugins/pbr/references/context-quality-tiers.md +45 -0
  102. package/plugins/pbr/references/pbr-tools-cli.md +115 -0
  103. package/plugins/pbr/references/questioning.md +21 -0
  104. package/plugins/pbr/references/verification-patterns.md +52 -0
  105. package/plugins/pbr/scripts/check-plan-format.js +15 -3
  106. package/plugins/pbr/scripts/check-state-sync.js +26 -7
  107. package/plugins/pbr/scripts/check-subagent-output.js +30 -2
  108. package/plugins/pbr/scripts/config-schema.json +11 -1
  109. package/plugins/pbr/scripts/context-bridge.js +259 -0
  110. package/plugins/pbr/scripts/context-budget-check.js +2 -2
  111. package/plugins/pbr/scripts/lib/config.js +178 -0
  112. package/plugins/pbr/scripts/lib/core.js +578 -0
  113. package/plugins/pbr/scripts/lib/history.js +73 -0
  114. package/plugins/pbr/scripts/lib/init.js +166 -0
  115. package/plugins/pbr/scripts/lib/phase.js +364 -0
  116. package/plugins/pbr/scripts/lib/roadmap.js +175 -0
  117. package/plugins/pbr/scripts/lib/state.js +397 -0
  118. package/plugins/pbr/scripts/pbr-tools.js +346 -1235
  119. package/plugins/pbr/scripts/post-write-dispatch.js +5 -4
  120. package/plugins/pbr/scripts/post-write-quality.js +3 -3
  121. package/plugins/pbr/scripts/pre-write-dispatch.js +1 -1
  122. package/plugins/pbr/scripts/progress-tracker.js +1 -1
  123. package/plugins/pbr/scripts/suggest-compact.js +1 -1
  124. package/plugins/pbr/scripts/track-context-budget.js +53 -2
  125. package/plugins/pbr/scripts/validate-task.js +20 -28
  126. package/plugins/pbr/skills/audit/SKILL.md +19 -3
  127. package/plugins/pbr/skills/begin/SKILL.md +48 -2
  128. package/plugins/pbr/skills/build/SKILL.md +39 -2
  129. package/plugins/pbr/skills/debug/SKILL.md +12 -1
  130. package/plugins/pbr/skills/debug/templates/continuation-prompt.md.tmpl +12 -1
  131. package/plugins/pbr/skills/debug/templates/initial-investigation-prompt.md.tmpl +12 -5
  132. package/plugins/pbr/skills/explore/SKILL.md +13 -2
  133. package/plugins/pbr/skills/import/SKILL.md +26 -1
  134. package/plugins/pbr/skills/milestone/SKILL.md +15 -3
  135. package/plugins/pbr/skills/plan/SKILL.md +52 -2
  136. package/plugins/pbr/skills/quick/SKILL.md +21 -0
  137. package/plugins/pbr/skills/review/SKILL.md +46 -0
  138. package/plugins/pbr/skills/scan/SKILL.md +20 -0
  139. package/plugins/pbr/templates/SUMMARY-complex.md.tmpl +95 -0
  140. 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="explorer-item"
93
+ class={`todo-card todo-card--${todo.priority}`}
78
94
  key={todo.id}
79
- x-show={`!search || '${todo.title.toLowerCase()}'.includes(search.toLowerCase())`}
95
+ x-show={`(!search || '${todo.title.toLowerCase()}'.includes(search.toLowerCase())) && (!priorityFilter || priorityFilter === '${todo.priority}') && (!statusFilter || statusFilter === '${todo.status || ''}')`}
80
96
  >
81
- <div class="explorer-item__header">
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--danger btn--sm"
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
- <p class="attention-panel__clear">All clear — nothing needs attention.</p>
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">Current Phase</div>
25
- <h2 class="card__title">
26
- Phase {currentPhase.id}: {currentPhase.name}
27
- </h2>
28
- <span class={`badge status-badge status-badge--${currentPhase.status}`}>
29
- {currentPhase.status}
30
- </span>
31
- <p class="card__meta">Plans: {currentPhase.planStatus}</p>
32
- <p class="card__meta">
33
- Last activity: {lastActivity.date || 'N/A'} — {lastActivity.description}
34
- </p>
35
- {nextAction && (
36
- <div class="next-action">
37
- <span class="next-action__label">Next</span>
38
- <code class="next-action__cmd">{nextAction}</code>
39
- <button
40
- class="btn btn--ghost btn--sm"
41
- type="button"
42
- onclick={`navigator.clipboard.writeText('${nextAction}')`}
43
- >
44
- Copy
45
- </button>
46
- </div>
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
- <div class="quick-actions__buttons">
18
- {actions.map((action, i) => (
19
- <a
20
- key={i}
21
- href={action.href}
22
- class={`btn${action.primary ? ' btn--primary' : ' btn--secondary'}`}
23
- >
24
- {action.label}
25
- </a>
26
- ))}
27
- </div>
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
- const { type: _type, timestamp: _ts, ts: _ts2, time: _time, ...rest } = entry;
28
- const str = JSON.stringify(rest);
29
- return str.length > 120 ? str.slice(0, 117) + '...' : str;
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 = typeof e['type'] === 'string' ? e['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 { StatusHeader } from '../components/partials/StatusHeader';
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
- <StatusHeader
35
- projectName={data.projectName}
35
+ <StatCardGrid
36
36
  currentPhase={data.currentPhase}
37
- completedCount={completed}
38
- totalCount={(data.phases as any[]).length}
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="command-center__grid">
55
- <CurrentPhaseCard
56
- currentPhase={data.currentPhase}
57
- lastActivity={data.lastActivity}
58
- nextAction={(data as any).nextAction ?? null}
59
- />
60
-
61
- <div
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
- <QuickActions actions={data.quickActions} />
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
- <PhaseTimeline
78
- phases={data.phases as any[]}
79
- currentPhaseId={data.currentPhase.id}
80
- />
82
+ <QuickActions actions={data.quickActions} />
81
83
 
82
- <div
83
- id="activity-stream-wrapper"
84
- hx-get="/api/command-center/activity"
85
- hx-trigger="sse:file-change"
86
- hx-swap="outerHTML"
87
- hx-ext="sse"
88
- >
89
- <ActivityStream activity={data.recentActivity} />
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.33.1",
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": 70,
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: ["read", "search"]
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. Subagent Delegation
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
- - Was ceremony proportionate to task scope?
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
- ### 4. Context Efficiency
94
- - Did the session hit context limits?
95
- - Was work delegated appropriately?
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: sample strategically, don't read entirely
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 sessions for missing STATE.md updates
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/