@sienklogic/plan-build-run 2.23.0 → 2.26.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 (90) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +62 -13
  3. package/dashboard/package.json +2 -2
  4. package/dashboard/public/css/layout.css +128 -21
  5. package/dashboard/public/css/status-colors.css +14 -2
  6. package/dashboard/public/css/tokens.css +36 -0
  7. package/dashboard/src/middleware/current-phase.js +2 -1
  8. package/dashboard/src/repositories/planning.repository.js +1 -11
  9. package/dashboard/src/routes/events.routes.js +49 -0
  10. package/dashboard/src/routes/pages.routes.js +367 -3
  11. package/dashboard/src/server.js +4 -0
  12. package/dashboard/src/services/audit.service.js +42 -0
  13. package/dashboard/src/services/config.service.js +140 -0
  14. package/dashboard/src/services/dashboard.service.js +153 -19
  15. package/dashboard/src/services/log.service.js +105 -0
  16. package/dashboard/src/services/notes.service.js +16 -0
  17. package/dashboard/src/services/phase.service.js +58 -9
  18. package/dashboard/src/services/requirements.service.js +130 -0
  19. package/dashboard/src/services/research.service.js +137 -0
  20. package/dashboard/src/services/roadmap.service.js +1 -11
  21. package/dashboard/src/services/todo.service.js +30 -0
  22. package/dashboard/src/utils/strip-bom.js +8 -0
  23. package/dashboard/src/views/audit-detail.ejs +5 -0
  24. package/dashboard/src/views/audits.ejs +5 -0
  25. package/dashboard/src/views/config.ejs +5 -0
  26. package/dashboard/src/views/logs.ejs +3 -0
  27. package/dashboard/src/views/note-detail.ejs +3 -0
  28. package/dashboard/src/views/partials/activity-feed.ejs +12 -0
  29. package/dashboard/src/views/partials/audit-detail-content.ejs +12 -0
  30. package/dashboard/src/views/partials/audits-content.ejs +34 -0
  31. package/dashboard/src/views/partials/config-content.ejs +196 -0
  32. package/dashboard/src/views/partials/dashboard-content.ejs +71 -46
  33. package/dashboard/src/views/partials/log-entries-content.ejs +17 -0
  34. package/dashboard/src/views/partials/logs-content.ejs +131 -0
  35. package/dashboard/src/views/partials/note-detail-content.ejs +22 -0
  36. package/dashboard/src/views/partials/notes-content.ejs +7 -1
  37. package/dashboard/src/views/partials/phase-content.ejs +181 -146
  38. package/dashboard/src/views/partials/phase-timeline.ejs +16 -0
  39. package/dashboard/src/views/partials/requirements-content.ejs +44 -0
  40. package/dashboard/src/views/partials/research-content.ejs +49 -0
  41. package/dashboard/src/views/partials/research-detail-content.ejs +23 -0
  42. package/dashboard/src/views/partials/sidebar.ejs +67 -22
  43. package/dashboard/src/views/partials/todos-content.ejs +13 -3
  44. package/dashboard/src/views/partials/todos-done-content.ejs +44 -0
  45. package/dashboard/src/views/requirements.ejs +3 -0
  46. package/dashboard/src/views/research-detail.ejs +3 -0
  47. package/dashboard/src/views/research.ejs +3 -0
  48. package/dashboard/src/views/todos-done.ejs +3 -0
  49. package/package.json +1 -1
  50. package/plugins/copilot-pbr/agents/dev-sync.agent.md +114 -0
  51. package/plugins/copilot-pbr/agents/integration-checker.agent.md +9 -2
  52. package/plugins/copilot-pbr/agents/planner.agent.md +19 -0
  53. package/plugins/copilot-pbr/agents/verifier.agent.md +22 -2
  54. package/plugins/copilot-pbr/hooks/hooks.json +12 -0
  55. package/plugins/copilot-pbr/plugin.json +1 -1
  56. package/plugins/copilot-pbr/references/plan-format.md +22 -0
  57. package/plugins/copilot-pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
  58. package/plugins/copilot-pbr/templates/VERIFICATION-DETAIL.md.tmpl +2 -1
  59. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
  60. package/plugins/cursor-pbr/agents/dev-sync.md +113 -0
  61. package/plugins/cursor-pbr/agents/integration-checker.md +9 -2
  62. package/plugins/cursor-pbr/agents/planner.md +19 -0
  63. package/plugins/cursor-pbr/agents/verifier.md +22 -2
  64. package/plugins/cursor-pbr/hooks/hooks.json +10 -0
  65. package/plugins/cursor-pbr/references/plan-format.md +22 -0
  66. package/plugins/cursor-pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
  67. package/plugins/cursor-pbr/templates/VERIFICATION-DETAIL.md.tmpl +2 -1
  68. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  69. package/plugins/pbr/agents/dev-sync.md +120 -0
  70. package/plugins/pbr/agents/integration-checker.md +9 -2
  71. package/plugins/pbr/agents/planner.md +19 -0
  72. package/plugins/pbr/agents/verifier.md +22 -2
  73. package/plugins/pbr/hooks/hooks.json +10 -0
  74. package/plugins/pbr/references/plan-format.md +22 -0
  75. package/plugins/pbr/scripts/check-plan-format.js +2 -2
  76. package/plugins/pbr/scripts/check-subagent-output.js +2 -2
  77. package/plugins/pbr/scripts/config-schema.json +4 -1
  78. package/plugins/pbr/scripts/local-llm/health.js +4 -1
  79. package/plugins/pbr/scripts/local-llm/operations/classify-commit.js +68 -0
  80. package/plugins/pbr/scripts/local-llm/operations/classify-file-intent.js +73 -0
  81. package/plugins/pbr/scripts/local-llm/operations/triage-test-output.js +72 -0
  82. package/plugins/pbr/scripts/post-bash-triage.js +132 -0
  83. package/plugins/pbr/scripts/post-write-dispatch.js +44 -0
  84. package/plugins/pbr/scripts/pre-bash-dispatch.js +17 -11
  85. package/plugins/pbr/scripts/status-line.js +50 -5
  86. package/plugins/pbr/scripts/validate-commit.js +66 -2
  87. package/plugins/pbr/scripts/validate-task.js +1 -1
  88. package/plugins/pbr/templates/INTEGRATION-REPORT.md.tmpl +18 -2
  89. package/plugins/pbr/templates/VERIFICATION-DETAIL.md.tmpl +2 -1
  90. package/dashboard/src/views/coming-soon.ejs +0 -11
@@ -17,10 +17,13 @@
17
17
  * 2 = invalid commit message format (blocks the tool)
18
18
  */
19
19
 
20
+ const fs = require('fs');
20
21
  const path = require('path');
21
22
  const { execSync } = require('child_process');
22
23
  const { logHook } = require('./hook-logger');
23
24
  const { logEvent } = require('./event-logger');
25
+ const { resolveConfig } = require('./local-llm/health');
26
+ const { classifyCommit } = require('./local-llm/operations/classify-commit');
24
27
 
25
28
  const VALID_TYPES = ['feat', 'fix', 'refactor', 'test', 'docs', 'chore', 'wip'];
26
29
 
@@ -149,12 +152,64 @@ function checkCommit(data) {
149
152
  return null;
150
153
  }
151
154
 
155
+ /**
156
+ * Load and resolve the local_llm config block from .planning/config.json.
157
+ * Returns a resolved config (always safe to use — disabled by default on error).
158
+ */
159
+ function loadLocalLlmConfig(cwd) {
160
+ try {
161
+ const configPath = path.join(cwd || process.cwd(), '.planning', 'config.json');
162
+ const parsed = JSON.parse(fs.readFileSync(configPath, 'utf8'));
163
+ return resolveConfig(parsed.local_llm);
164
+ } catch (_e) {
165
+ return resolveConfig(undefined);
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Async LLM enrichment for commit messages. Returns an advisory string or null.
171
+ * Called after checkCommit passes (valid format) to provide semantic classification.
172
+ *
173
+ * @param {object} data - parsed hook data
174
+ * @returns {Promise<string|null>}
175
+ */
176
+ async function enrichCommitLlm(data) {
177
+ try {
178
+ const command = data.tool_input?.command || '';
179
+ const message = extractCommitMessage(command);
180
+ if (!message) return null;
181
+
182
+ const cwd = process.cwd();
183
+ const llmConfig = loadLocalLlmConfig(cwd);
184
+ const planningDir = path.join(cwd, '.planning');
185
+
186
+ // Get staged files for scope validation
187
+ let stagedFiles = [];
188
+ try {
189
+ const output = execSync('git diff --cached --name-only', { encoding: 'utf8' });
190
+ stagedFiles = output.trim().split('\n').filter(Boolean);
191
+ } catch (_e) {
192
+ // Not in a git repo — skip staged files context
193
+ }
194
+
195
+ const llmResult = await classifyCommit(llmConfig, planningDir, message, stagedFiles, data.session_id);
196
+ if (llmResult && llmResult.classification !== 'correct') {
197
+ return 'LLM commit advisory: ' + llmResult.classification +
198
+ ' (confidence: ' + (llmResult.confidence * 100).toFixed(0) + '%)';
199
+ }
200
+ return null;
201
+ } catch (_llmErr) {
202
+ // Never propagate LLM errors
203
+ return null;
204
+ }
205
+ }
206
+
152
207
  function main() {
153
208
  let input = '';
154
209
 
155
210
  process.stdin.setEncoding('utf8');
156
211
  process.stdin.on('data', (chunk) => { input += chunk; });
157
- process.stdin.on('end', () => {
212
+ process.stdin.on('end', async () => {
158
213
  try {
159
214
  const data = JSON.parse(input);
160
215
  const result = checkCommit(data);
@@ -162,6 +217,15 @@ function main() {
162
217
  process.stdout.write(JSON.stringify(result.output));
163
218
  process.exit(result.exitCode);
164
219
  }
220
+
221
+ // LLM semantic classification — advisory only (after format validation passes)
222
+ const llmAdvisory = await enrichCommitLlm(data);
223
+ if (llmAdvisory) {
224
+ process.stdout.write(JSON.stringify({
225
+ additionalContext: '[pbr] ' + llmAdvisory
226
+ }));
227
+ }
228
+
165
229
  process.exit(0);
166
230
  } catch (_e) {
167
231
  // Parse error - don't block
@@ -197,5 +261,5 @@ function extractCommitMessage(command) {
197
261
  return null;
198
262
  }
199
263
 
200
- module.exports = { checkCommit };
264
+ module.exports = { checkCommit, enrichCommitLlm };
201
265
  if (require.main === module || process.argv[1] === __filename) { main(); }
@@ -805,7 +805,7 @@ function main() {
805
805
  try {
806
806
  const llmConfig = loadLocalLlmConfig(process.cwd());
807
807
  const planningDir = path.join(process.cwd(), '.planning');
808
- const llmResult = await llmValidateTask(llmConfig, planningDir, data.tool_input || {}, undefined);
808
+ const llmResult = await llmValidateTask(llmConfig, planningDir, data.tool_input || {}, data.session_id);
809
809
  if (llmResult && !llmResult.coherent) {
810
810
  warnings.push('LLM task coherence advisory: ' + (llmResult.issue || 'Task description may not match intended operation.') + ' (confidence: ' + (llmResult.confidence * 100).toFixed(0) + '%)');
811
811
  }
@@ -111,7 +111,22 @@ Phase 03 (Core) ──provides──→ Phase 04 (Frontend)
111
111
  ### Flow 2: {Flow Name} - {STATUS}
112
112
  ...
113
113
 
114
- ## 5. Integration Issues Summary
114
+ ## 5. Data-Flow Propagation
115
+
116
+ ### Cross-Boundary Data Flows
117
+
118
+ | Data Field | Source | Intermediate Steps | Destination | Status |
119
+ |------------|--------|-------------------|-------------|--------|
120
+ | {field name} | {origin, e.g., hook stdin `data.session_id`} | {module1:L12 → module2:L45} | {dest, e.g., metrics.jsonl `session_id`} | PROPAGATED |
121
+ | {field name} | {origin} | {module1:L12 → module2:L45} | {dest} | DATA_DROPPED |
122
+
123
+ ### Data-Flow Issues
124
+
125
+ | Field | Dropped At | Available In Scope | Passed Instead | Fix |
126
+ |-------|-----------|-------------------|----------------|-----|
127
+ | {field} | {file:line} | `data.session_id` | `undefined` | Pass `data.session_id` |
128
+
129
+ ## 6. Integration Issues Summary
115
130
 
116
131
  ### Critical Issues (system cannot function)
117
132
 
@@ -130,7 +145,7 @@ Phase 03 (Core) ──provides──→ Phase 04 (Frontend)
130
145
  1. **{Issue}**: {description}
131
146
  - Fix: {recommended action}
132
147
 
133
- ## 6. Integration Score
148
+ ## 7. Integration Score
134
149
 
135
150
  | Category | Items Checked | Passed | Failed | Score |
136
151
  |----------|--------------|--------|--------|-------|
@@ -138,6 +153,7 @@ Phase 03 (Core) ──provides──→ Phase 04 (Frontend)
138
153
  | API coverage | {n} | {n} | {n} | {%} |
139
154
  | Auth protection | {n} | {n} | {n} | {%} |
140
155
  | E2E flows | {n} | {n} | {n} | {%} |
156
+ | Data-flow propagation | {n} | {n} | {n} | {%} |
141
157
  | **Overall** | {n} | {n} | {n} | **{%}** |
142
158
 
143
159
  ## Recommendations
@@ -53,8 +53,9 @@ anti_patterns:
53
53
 
54
54
  | # | Link Description | Source | Target | Status | Evidence |
55
55
  |---|-----------------|--------|--------|--------|----------|
56
- | 1 | {what connects to what} | `{source_file}` | `{target_file}` | WIRED | Import at L12, called at L45 |
56
+ | 1 | {what connects to what} | `{source_file}` | `{target_file}` | WIRED | Import at L12, called at L45, args correct |
57
57
  | 2 | {what connects to what} | `{source_file}` | `{target_file}` | BROKEN | Imported but never called |
58
+ | 3 | {what connects to what} | `{source_file}` | `{target_file}` | ARGS_WRONG | Called at L45 but passes undefined for sessionId (data.session_id in scope) |
58
59
 
59
60
  ## Gaps Found
60
61
 
@@ -1,11 +0,0 @@
1
- <%- include('partials/layout-top', { title: title, activePage: activePage }) %>
2
-
3
- <h1><%= featureName %></h1>
4
- <p>This feature is coming soon.</p>
5
- <p>
6
- The <strong><%= featureName %></strong> view is planned but not yet implemented.
7
- Check back in a future phase.
8
- </p>
9
- <p><a href="/">Back to Dashboard</a></p>
10
-
11
- <%- include('partials/layout-bottom') %>