@sienklogic/plan-build-run 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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,144 +1,144 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* PostToolUse hook on Task: Validates that subagent outputs exist.
|
|
5
|
-
*
|
|
6
|
-
* Maps agent types to expected output files and warns if they're missing
|
|
7
|
-
* after the agent completes. This catches silent agent failures early
|
|
8
|
-
* rather than discovering them during verification.
|
|
9
|
-
*
|
|
10
|
-
* Agent → Expected output mapping:
|
|
11
|
-
* executor → SUMMARY-{plan_id}.md (or SUMMARY.md) in the phase directory
|
|
12
|
-
* planner → PLAN-{MM}.md in the phase directory
|
|
13
|
-
* verifier → VERIFICATION.md in the phase directory
|
|
14
|
-
* researcher → RESEARCH.md (or domain-specific .md) in research/
|
|
15
|
-
*
|
|
16
|
-
* Exit codes:
|
|
17
|
-
* 0 = always (informational hook, never blocks — PostToolUse can only warn)
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
const fs = require('fs');
|
|
21
|
-
const path = require('path');
|
|
22
|
-
const { logHook } = require('./hook-logger');
|
|
23
|
-
|
|
24
|
-
// Agent type → expected output patterns
|
|
25
|
-
const AGENT_OUTPUTS = {
|
|
26
|
-
'pbr:executor': {
|
|
27
|
-
description: 'SUMMARY.md in the phase directory',
|
|
28
|
-
check: (planningDir) => findInPhaseDir(planningDir, /^SUMMARY.*\.md$/i)
|
|
29
|
-
},
|
|
30
|
-
'pbr:planner': {
|
|
31
|
-
description: 'PLAN.md in the phase directory',
|
|
32
|
-
check: (planningDir) => findInPhaseDir(planningDir, /^PLAN.*\.md$/i)
|
|
33
|
-
},
|
|
34
|
-
'pbr:verifier': {
|
|
35
|
-
description: 'VERIFICATION.md in the phase directory',
|
|
36
|
-
check: (planningDir) => findInPhaseDir(planningDir, /^VERIFICATION\.md$/i)
|
|
37
|
-
},
|
|
38
|
-
'pbr:researcher': {
|
|
39
|
-
description: 'research file in .planning/research/',
|
|
40
|
-
check: (planningDir) => {
|
|
41
|
-
const researchDir = path.join(planningDir, 'research');
|
|
42
|
-
if (!fs.existsSync(researchDir)) return [];
|
|
43
|
-
try {
|
|
44
|
-
return fs.readdirSync(researchDir)
|
|
45
|
-
.filter(f => f.endsWith('.md'))
|
|
46
|
-
.map(f => path.join('research', f));
|
|
47
|
-
} catch (_e) {
|
|
48
|
-
return [];
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
function findInPhaseDir(planningDir, pattern) {
|
|
55
|
-
const matches = [];
|
|
56
|
-
const phasesDir = path.join(planningDir, 'phases');
|
|
57
|
-
if (!fs.existsSync(phasesDir)) return matches;
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
// Find the active phase from STATE.md
|
|
61
|
-
const stateFile = path.join(planningDir, 'STATE.md');
|
|
62
|
-
if (!fs.existsSync(stateFile)) return matches;
|
|
63
|
-
|
|
64
|
-
const stateContent = fs.readFileSync(stateFile, 'utf8');
|
|
65
|
-
const phaseMatch = stateContent.match(/Phase:\s*(\d+)\s+of\s+\d+/);
|
|
66
|
-
if (!phaseMatch) return matches;
|
|
67
|
-
|
|
68
|
-
const currentPhase = phaseMatch[1].padStart(2, '0');
|
|
69
|
-
const dirs = fs.readdirSync(phasesDir).filter(d => d.startsWith(currentPhase));
|
|
70
|
-
if (dirs.length === 0) return matches;
|
|
71
|
-
|
|
72
|
-
const phaseDir = path.join(phasesDir, dirs[0]);
|
|
73
|
-
const files = fs.readdirSync(phaseDir);
|
|
74
|
-
for (const file of files) {
|
|
75
|
-
if (pattern.test(file)) {
|
|
76
|
-
// Check it's non-empty
|
|
77
|
-
const filePath = path.join(phaseDir, file);
|
|
78
|
-
const stat = fs.statSync(filePath);
|
|
79
|
-
if (stat.size > 0) {
|
|
80
|
-
matches.push(path.join('phases', dirs[0], file));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
} catch (_e) {
|
|
85
|
-
// best-effort
|
|
86
|
-
}
|
|
87
|
-
return matches;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function readStdin() {
|
|
91
|
-
try {
|
|
92
|
-
const input = fs.readFileSync(0, 'utf8').trim();
|
|
93
|
-
if (input) return JSON.parse(input);
|
|
94
|
-
} catch (_e) {
|
|
95
|
-
// empty or non-JSON stdin
|
|
96
|
-
}
|
|
97
|
-
return {};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function main() {
|
|
101
|
-
const data = readStdin();
|
|
102
|
-
const cwd = process.cwd();
|
|
103
|
-
const planningDir = path.join(cwd, '.planning');
|
|
104
|
-
|
|
105
|
-
// Only relevant for Plan-Build-Run projects
|
|
106
|
-
if (!fs.existsSync(planningDir)) {
|
|
107
|
-
process.exit(0);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Extract agent type from the Task completion data
|
|
111
|
-
const agentType = data.tool_input?.subagent_type || data.subagent_type || '';
|
|
112
|
-
|
|
113
|
-
// Only check known Plan-Build-Run agent types
|
|
114
|
-
const outputSpec = AGENT_OUTPUTS[agentType];
|
|
115
|
-
if (!outputSpec) {
|
|
116
|
-
process.exit(0);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Check for expected outputs
|
|
120
|
-
const found = outputSpec.check(planningDir);
|
|
121
|
-
|
|
122
|
-
if (found.length === 0) {
|
|
123
|
-
logHook('check-subagent-output', 'PostToolUse', 'warning', {
|
|
124
|
-
agent_type: agentType,
|
|
125
|
-
expected: outputSpec.description,
|
|
126
|
-
found: 'none'
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
const output = {
|
|
130
|
-
additionalContext: `Warning: Agent ${agentType} completed but no ${outputSpec.description} was found. The agent may have failed silently. Check agent output for errors.`
|
|
131
|
-
};
|
|
132
|
-
process.stdout.write(JSON.stringify(output));
|
|
133
|
-
} else {
|
|
134
|
-
logHook('check-subagent-output', 'PostToolUse', 'verified', {
|
|
135
|
-
agent_type: agentType,
|
|
136
|
-
found: found
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
process.exit(0);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
module.exports = { AGENT_OUTPUTS, findInPhaseDir };
|
|
144
|
-
if (require.main === module) { main(); }
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PostToolUse hook on Task: Validates that subagent outputs exist.
|
|
5
|
+
*
|
|
6
|
+
* Maps agent types to expected output files and warns if they're missing
|
|
7
|
+
* after the agent completes. This catches silent agent failures early
|
|
8
|
+
* rather than discovering them during verification.
|
|
9
|
+
*
|
|
10
|
+
* Agent → Expected output mapping:
|
|
11
|
+
* executor → SUMMARY-{plan_id}.md (or SUMMARY.md) in the phase directory
|
|
12
|
+
* planner → PLAN-{MM}.md in the phase directory
|
|
13
|
+
* verifier → VERIFICATION.md in the phase directory
|
|
14
|
+
* researcher → RESEARCH.md (or domain-specific .md) in research/
|
|
15
|
+
*
|
|
16
|
+
* Exit codes:
|
|
17
|
+
* 0 = always (informational hook, never blocks — PostToolUse can only warn)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const { logHook } = require('./hook-logger');
|
|
23
|
+
|
|
24
|
+
// Agent type → expected output patterns
|
|
25
|
+
const AGENT_OUTPUTS = {
|
|
26
|
+
'pbr:executor': {
|
|
27
|
+
description: 'SUMMARY.md in the phase directory',
|
|
28
|
+
check: (planningDir) => findInPhaseDir(planningDir, /^SUMMARY.*\.md$/i)
|
|
29
|
+
},
|
|
30
|
+
'pbr:planner': {
|
|
31
|
+
description: 'PLAN.md in the phase directory',
|
|
32
|
+
check: (planningDir) => findInPhaseDir(planningDir, /^PLAN.*\.md$/i)
|
|
33
|
+
},
|
|
34
|
+
'pbr:verifier': {
|
|
35
|
+
description: 'VERIFICATION.md in the phase directory',
|
|
36
|
+
check: (planningDir) => findInPhaseDir(planningDir, /^VERIFICATION\.md$/i)
|
|
37
|
+
},
|
|
38
|
+
'pbr:researcher': {
|
|
39
|
+
description: 'research file in .planning/research/',
|
|
40
|
+
check: (planningDir) => {
|
|
41
|
+
const researchDir = path.join(planningDir, 'research');
|
|
42
|
+
if (!fs.existsSync(researchDir)) return [];
|
|
43
|
+
try {
|
|
44
|
+
return fs.readdirSync(researchDir)
|
|
45
|
+
.filter(f => f.endsWith('.md'))
|
|
46
|
+
.map(f => path.join('research', f));
|
|
47
|
+
} catch (_e) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function findInPhaseDir(planningDir, pattern) {
|
|
55
|
+
const matches = [];
|
|
56
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
57
|
+
if (!fs.existsSync(phasesDir)) return matches;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
// Find the active phase from STATE.md
|
|
61
|
+
const stateFile = path.join(planningDir, 'STATE.md');
|
|
62
|
+
if (!fs.existsSync(stateFile)) return matches;
|
|
63
|
+
|
|
64
|
+
const stateContent = fs.readFileSync(stateFile, 'utf8');
|
|
65
|
+
const phaseMatch = stateContent.match(/Phase:\s*(\d+)\s+of\s+\d+/);
|
|
66
|
+
if (!phaseMatch) return matches;
|
|
67
|
+
|
|
68
|
+
const currentPhase = phaseMatch[1].padStart(2, '0');
|
|
69
|
+
const dirs = fs.readdirSync(phasesDir).filter(d => d.startsWith(currentPhase));
|
|
70
|
+
if (dirs.length === 0) return matches;
|
|
71
|
+
|
|
72
|
+
const phaseDir = path.join(phasesDir, dirs[0]);
|
|
73
|
+
const files = fs.readdirSync(phaseDir);
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
if (pattern.test(file)) {
|
|
76
|
+
// Check it's non-empty
|
|
77
|
+
const filePath = path.join(phaseDir, file);
|
|
78
|
+
const stat = fs.statSync(filePath);
|
|
79
|
+
if (stat.size > 0) {
|
|
80
|
+
matches.push(path.join('phases', dirs[0], file));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
} catch (_e) {
|
|
85
|
+
// best-effort
|
|
86
|
+
}
|
|
87
|
+
return matches;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function readStdin() {
|
|
91
|
+
try {
|
|
92
|
+
const input = fs.readFileSync(0, 'utf8').trim();
|
|
93
|
+
if (input) return JSON.parse(input);
|
|
94
|
+
} catch (_e) {
|
|
95
|
+
// empty or non-JSON stdin
|
|
96
|
+
}
|
|
97
|
+
return {};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function main() {
|
|
101
|
+
const data = readStdin();
|
|
102
|
+
const cwd = process.cwd();
|
|
103
|
+
const planningDir = path.join(cwd, '.planning');
|
|
104
|
+
|
|
105
|
+
// Only relevant for Plan-Build-Run projects
|
|
106
|
+
if (!fs.existsSync(planningDir)) {
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Extract agent type from the Task completion data
|
|
111
|
+
const agentType = data.tool_input?.subagent_type || data.subagent_type || '';
|
|
112
|
+
|
|
113
|
+
// Only check known Plan-Build-Run agent types
|
|
114
|
+
const outputSpec = AGENT_OUTPUTS[agentType];
|
|
115
|
+
if (!outputSpec) {
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check for expected outputs
|
|
120
|
+
const found = outputSpec.check(planningDir);
|
|
121
|
+
|
|
122
|
+
if (found.length === 0) {
|
|
123
|
+
logHook('check-subagent-output', 'PostToolUse', 'warning', {
|
|
124
|
+
agent_type: agentType,
|
|
125
|
+
expected: outputSpec.description,
|
|
126
|
+
found: 'none'
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const output = {
|
|
130
|
+
additionalContext: `Warning: Agent ${agentType} completed but no ${outputSpec.description} was found. The agent may have failed silently. Check agent output for errors.`
|
|
131
|
+
};
|
|
132
|
+
process.stdout.write(JSON.stringify(output));
|
|
133
|
+
} else {
|
|
134
|
+
logHook('check-subagent-output', 'PostToolUse', 'verified', {
|
|
135
|
+
agent_type: agentType,
|
|
136
|
+
found: found
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
process.exit(0);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = { AGENT_OUTPUTS, findInPhaseDir };
|
|
144
|
+
if (require.main === module) { main(); }
|