@sienklogic/plan-build-run 2.19.0 → 2.20.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 +7 -0
- package/package.json +1 -1
- package/plugins/copilot-pbr/hooks/hooks.json +13 -0
- package/plugins/copilot-pbr/plugin.json +1 -1
- package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
- package/plugins/cursor-pbr/hooks/hooks.json +11 -0
- package/plugins/pbr/.claude-plugin/plugin.json +1 -1
- package/plugins/pbr/agents/plan-checker.md +1 -0
- package/plugins/pbr/agents/verifier.md +1 -0
- package/plugins/pbr/hooks/hooks.json +11 -0
- package/plugins/pbr/scripts/check-config-change.js +130 -0
- package/plugins/pbr/scripts/hooks-schema.json +1 -0
- package/plugins/pbr/skills/help/SKILL.md +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@ All notable changes to Plan-Build-Run will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.20.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.19.0...plan-build-run-v2.20.0) (2026-02-23)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **tools:** add worktree isolation, ConfigChange hook, and claude agents docs ([d704f34](https://github.com/SienkLogic/plan-build-run/commit/d704f340c636fa41f988d27a661a1e1918b04c87))
|
|
14
|
+
|
|
8
15
|
## [2.19.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.18.1...plan-build-run-v2.19.0) (2026-02-22)
|
|
9
16
|
|
|
10
17
|
|
package/package.json
CHANGED
|
@@ -139,6 +139,19 @@
|
|
|
139
139
|
]
|
|
140
140
|
}
|
|
141
141
|
],
|
|
142
|
+
"configChange": [
|
|
143
|
+
{
|
|
144
|
+
"hooks": [
|
|
145
|
+
{
|
|
146
|
+
"type": "command",
|
|
147
|
+
"bash": "node \"$(cd \"$(dirname \"$0\")\" && pwd)/../../pbr/scripts/run-hook.js\" check-config-change.js",
|
|
148
|
+
"powershell": "node (Join-Path (Split-Path -Parent $PSScriptRoot) 'pbr\\scripts\\run-hook.js') check-config-change.js",
|
|
149
|
+
"cwd": ".",
|
|
150
|
+
"timeoutSec": 15
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
],
|
|
142
155
|
"sessionEnd": [
|
|
143
156
|
{
|
|
144
157
|
"hooks": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
3
|
"displayName": "Plan-Build-Run",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.20.0",
|
|
5
5
|
"description": "Plan-Build-Run — Structured development workflow for GitHub Copilot CLI. Solves context rot through disciplined agent delegation, structured planning, atomic execution, and goal-backward verification.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "SienkLogic",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
3
|
"displayName": "Plan-Build-Run",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.20.0",
|
|
5
5
|
"description": "Plan-Build-Run — Structured development workflow for Cursor. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "SienkLogic",
|
|
@@ -196,6 +196,17 @@
|
|
|
196
196
|
]
|
|
197
197
|
}
|
|
198
198
|
],
|
|
199
|
+
"ConfigChange": [
|
|
200
|
+
{
|
|
201
|
+
"hooks": [
|
|
202
|
+
{
|
|
203
|
+
"type": "command",
|
|
204
|
+
"command": "node -e \"var r=process.env.CLAUDE_PLUGIN_ROOT||'',m=r.match(/^\\/([a-zA-Z])\\/(.*)/);if(m)r=m[1]+String.fromCharCode(58)+String.fromCharCode(92)+m[2];require(require('path').resolve(r,'..','pbr','scripts','run-hook.js'))\" check-config-change.js",
|
|
205
|
+
"statusMessage": "Validating configuration..."
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
],
|
|
199
210
|
"SessionEnd": [
|
|
200
211
|
{
|
|
201
212
|
"hooks": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.0",
|
|
4
4
|
"description": "Plan-Build-Run — Structured development workflow for Claude Code. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "SienkLogic",
|
|
@@ -192,6 +192,17 @@
|
|
|
192
192
|
]
|
|
193
193
|
}
|
|
194
194
|
],
|
|
195
|
+
"ConfigChange": [
|
|
196
|
+
{
|
|
197
|
+
"hooks": [
|
|
198
|
+
{
|
|
199
|
+
"type": "command",
|
|
200
|
+
"command": "node -e \"var r=process.env.CLAUDE_PLUGIN_ROOT||'',m=r.match(/^\\/([a-zA-Z])\\/(.*)/);if(m)r=m[1]+String.fromCharCode(58)+String.fromCharCode(92)+m[2];require(require('path').resolve(r,'scripts','run-hook.js'))\" check-config-change.js",
|
|
201
|
+
"statusMessage": "Validating configuration..."
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
],
|
|
195
206
|
"SessionEnd": [
|
|
196
207
|
{
|
|
197
208
|
"hooks": [
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ConfigChange hook: Validates config.json changes and warns about inconsistencies.
|
|
5
|
+
*
|
|
6
|
+
* Fires when Claude Code detects configuration file changes (v2.1.49+).
|
|
7
|
+
* Checks .planning/config.json for:
|
|
8
|
+
* - Required top-level keys
|
|
9
|
+
* - Semantic conflicts (e.g., parallel agents enabled with max=1)
|
|
10
|
+
* - Version field presence
|
|
11
|
+
*
|
|
12
|
+
* Exit codes:
|
|
13
|
+
* 0 = always (advisory hook, never blocks)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const { logHook } = require('./hook-logger');
|
|
19
|
+
const { logEvent } = require('./event-logger');
|
|
20
|
+
|
|
21
|
+
function readStdin() {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
let input = '';
|
|
24
|
+
process.stdin.setEncoding('utf8');
|
|
25
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
26
|
+
process.stdin.on('end', () => {
|
|
27
|
+
try {
|
|
28
|
+
resolve(JSON.parse(input));
|
|
29
|
+
} catch (_e) {
|
|
30
|
+
resolve({});
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function findPlanningDir() {
|
|
37
|
+
let dir = process.cwd();
|
|
38
|
+
const root = path.parse(dir).root;
|
|
39
|
+
while (dir !== root) {
|
|
40
|
+
const candidate = path.join(dir, '.planning');
|
|
41
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
42
|
+
dir = path.dirname(dir);
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function validateConfig(configPath) {
|
|
48
|
+
const warnings = [];
|
|
49
|
+
|
|
50
|
+
let config;
|
|
51
|
+
try {
|
|
52
|
+
const raw = fs.readFileSync(configPath, 'utf8');
|
|
53
|
+
config = JSON.parse(raw);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
warnings.push(`config.json parse error: ${e.message}`);
|
|
56
|
+
return warnings;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check required top-level keys
|
|
60
|
+
const requiredKeys = ['version', 'features', 'models', 'gates'];
|
|
61
|
+
for (const key of requiredKeys) {
|
|
62
|
+
if (!(key in config)) {
|
|
63
|
+
warnings.push(`Missing required key: ${key}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check version
|
|
68
|
+
if (config.version && config.version < 2) {
|
|
69
|
+
warnings.push(`Config version ${config.version} is outdated — expected version 2+`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Check semantic conflicts
|
|
73
|
+
if (config.parallelization) {
|
|
74
|
+
const p = config.parallelization;
|
|
75
|
+
if (p.enabled && p.max_concurrent_agents === 1) {
|
|
76
|
+
warnings.push('Semantic conflict: parallelization.enabled=true but max_concurrent_agents=1');
|
|
77
|
+
}
|
|
78
|
+
if (!p.enabled && (p.plan_level || p.task_level)) {
|
|
79
|
+
warnings.push('Semantic conflict: parallelization.enabled=false but plan_level/task_level are true');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Check model values
|
|
84
|
+
if (config.models) {
|
|
85
|
+
const validModels = ['sonnet', 'opus', 'haiku', 'inherit'];
|
|
86
|
+
for (const [role, model] of Object.entries(config.models)) {
|
|
87
|
+
if (!validModels.includes(model)) {
|
|
88
|
+
warnings.push(`Invalid model "${model}" for ${role} — expected: ${validModels.join(', ')}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return warnings;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function main() {
|
|
97
|
+
await readStdin();
|
|
98
|
+
const startTime = Date.now();
|
|
99
|
+
|
|
100
|
+
const planningDir = findPlanningDir();
|
|
101
|
+
if (!planningDir) {
|
|
102
|
+
logHook('check-config-change', 'ConfigChange', 'skip', { reason: 'no .planning dir' }, startTime);
|
|
103
|
+
process.exit(0);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const configPath = path.join(planningDir, 'config.json');
|
|
107
|
+
if (!fs.existsSync(configPath)) {
|
|
108
|
+
logHook('check-config-change', 'ConfigChange', 'skip', { reason: 'no config.json' }, startTime);
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const warnings = validateConfig(configPath);
|
|
113
|
+
|
|
114
|
+
if (warnings.length > 0) {
|
|
115
|
+
const msg = `⚠️ Config validation (${warnings.length} issue${warnings.length > 1 ? 's' : ''}):\n${warnings.map(w => ` - ${w}`).join('\n')}`;
|
|
116
|
+
|
|
117
|
+
logHook('check-config-change', 'ConfigChange', 'warn', { warnings }, startTime);
|
|
118
|
+
logEvent('workflow', 'config-change', { warnings });
|
|
119
|
+
|
|
120
|
+
process.stdout.write(JSON.stringify({ additionalContext: msg }));
|
|
121
|
+
} else {
|
|
122
|
+
logHook('check-config-change', 'ConfigChange', 'ok', {}, startTime);
|
|
123
|
+
logEvent('workflow', 'config-change', { status: 'valid' });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (require.main === module || process.argv[1] === __filename) main();
|
|
130
|
+
module.exports = { validateConfig, findPlanningDir };
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"SubagentStart": { "$ref": "#/definitions/hookEntryList" },
|
|
19
19
|
"SubagentStop": { "$ref": "#/definitions/hookEntryList" },
|
|
20
20
|
"TaskCompleted": { "$ref": "#/definitions/hookEntryList" },
|
|
21
|
+
"ConfigChange": { "$ref": "#/definitions/hookEntryList" },
|
|
21
22
|
"SessionEnd": { "$ref": "#/definitions/hookEntryList" }
|
|
22
23
|
},
|
|
23
24
|
"additionalProperties": false
|
|
@@ -138,6 +138,7 @@ Display the following reference to the user:
|
|
|
138
138
|
- **Depth**: `quick` (skip research, ~50% cheaper) | `standard` | `comprehensive` (~2x cost)
|
|
139
139
|
- **State files**: `.planning/STATE.md` (position), `.planning/ROADMAP.md` (phases), `.planning/config.json` (settings)
|
|
140
140
|
- **Configure**: `/pbr:config` to change depth, models, gates, parallelization
|
|
141
|
+
- **List agents**: Run `claude agents` in your terminal to see all registered PBR agents and verify loading
|
|
141
142
|
- **Tip**: Use `/pbr:quick` for creative/visual work where structured planning adds overhead without benefit.
|
|
142
143
|
- **PR hygiene**: When creating PRs from a Plan-Build-Run project, `.planning/` commits can be filtered using phase branching (`git.branching: phase`) which squash-merges code-only changes to main.
|
|
143
144
|
- **Seeds**: `/pbr:explore` can create seed files (`.planning/seeds/`) with trigger conditions. Seeds auto-inject into planning when their trigger phase is reached.
|