@sienklogic/plan-build-run 2.56.3 → 2.58.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 +20 -0
- package/package.json +1 -1
- package/plugins/codex-pbr/references/model-profiles.md +18 -0
- package/plugins/codex-pbr/references/model-selection.md +1 -1
- package/plugins/codex-pbr/skills/begin/SKILL.md +3 -0
- package/plugins/codex-pbr/skills/setup/SKILL.md +2 -0
- package/plugins/copilot-pbr/hooks/hooks.json +13 -0
- package/plugins/copilot-pbr/plugin.json +1 -1
- package/plugins/copilot-pbr/references/model-profiles.md +18 -0
- package/plugins/copilot-pbr/references/model-selection.md +1 -1
- package/plugins/copilot-pbr/skills/begin/SKILL.md +3 -0
- package/plugins/copilot-pbr/skills/setup/SKILL.md +2 -0
- package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
- package/plugins/cursor-pbr/hooks/hooks.json +11 -0
- package/plugins/cursor-pbr/references/model-profiles.md +18 -0
- package/plugins/cursor-pbr/references/model-selection.md +1 -1
- package/plugins/cursor-pbr/skills/begin/SKILL.md +3 -0
- package/plugins/cursor-pbr/skills/setup/SKILL.md +2 -0
- package/plugins/pbr/.claude-plugin/plugin.json +1 -1
- package/plugins/pbr/hooks/hooks.json +11 -0
- package/plugins/pbr/references/model-profiles.md +18 -0
- package/plugins/pbr/references/model-selection.md +1 -1
- package/plugins/pbr/scripts/check-subagent-output.js +1 -1
- package/plugins/pbr/scripts/hooks-schema.json +1 -0
- package/plugins/pbr/scripts/instructions-loaded.js +69 -0
- package/plugins/pbr/scripts/lib/gates/helpers.js +7 -0
- package/plugins/pbr/scripts/local-llm/operations/classify-commit.js +70 -1
- package/plugins/pbr/scripts/local-llm/operations/classify-file-intent.js +99 -1
- package/plugins/pbr/scripts/task-completed.js +89 -1
- package/plugins/pbr/skills/begin/SKILL.md +3 -0
- package/plugins/pbr/skills/setup/SKILL.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ 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.58.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.57.0...plan-build-run-v2.58.0) (2026-03-05)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* **hook-events:** add native agent_type support, continue:false halt signals, and InstructionsLoaded hook ([8f09dcb](https://github.com/SienkLogic/plan-build-run/commit/8f09dcbad39c4f0e19d7f26f4f5fa694bc2b5f2e))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **hook-events:** add InstructionsLoaded to hooks schema and valid events list ([cd6601c](https://github.com/SienkLogic/plan-build-run/commit/cd6601c66ac806e1c884e86b829596001fc81c3f))
|
|
19
|
+
* **hook-events:** fix sessionLoad bug in halt conditions, add missing agent_type and halt tests ([aab8ec6](https://github.com/SienkLogic/plan-build-run/commit/aab8ec6b9346a66fcb6e9a1f038ec5bef4c8cf6f))
|
|
20
|
+
|
|
21
|
+
## [2.57.0](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.56.3...plan-build-run-v2.57.0) (2026-03-05)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* **quick-021:** add heuristic-first classification for file intent and commits ([a70167e](https://github.com/SienkLogic/plan-build-run/commit/a70167e0d9c7449339c056ccd44d7be819ae6ce3))
|
|
27
|
+
|
|
8
28
|
## [2.56.3](https://github.com/SienkLogic/plan-build-run/compare/plan-build-run-v2.56.2...plan-build-run-v2.56.3) (2026-03-03)
|
|
9
29
|
|
|
10
30
|
|
package/package.json
CHANGED
|
@@ -4,6 +4,24 @@ How Plan-Build-Run maps agents to models and how to configure model selection.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## Session Model (Orchestrator)
|
|
8
|
+
|
|
9
|
+
The orchestrator is your main Claude Code session -- it reads skills, manages state, and routes work to agents. Its model is whatever you selected in Claude Code (not controlled by PBR's `config.json`).
|
|
10
|
+
|
|
11
|
+
**Cost impact:** The orchestrator accounts for roughly 40% of total session cost. Agents set to `inherit` (planner, executor, debugger, general in the `balanced` profile) also use this model. Switching your session from Opus to Sonnet reduces cost for both the orchestrator and all `inherit` agents.
|
|
12
|
+
|
|
13
|
+
**Recommendations:**
|
|
14
|
+
|
|
15
|
+
| Goal | Session Model | Config Adjustment |
|
|
16
|
+
|------|---------------|-------------------|
|
|
17
|
+
| Maximum quality | Opus | None needed -- `inherit` agents get Opus |
|
|
18
|
+
| Balanced cost/quality | Sonnet | None needed -- `inherit` agents get Sonnet, which handles most tasks well |
|
|
19
|
+
| Cheap orchestration, Opus agents | Sonnet | Set `planner: "opus"`, `executor: "opus"`, `debugger: "opus"` to override inherit |
|
|
20
|
+
|
|
21
|
+
Sonnet 4.6 handles orchestration tasks (state reading, routing decisions, context assembly) effectively. Reserve Opus for agents doing complex reasoning, architecture, or novel code generation.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
7
25
|
## Agent-to-Model Mapping
|
|
8
26
|
|
|
9
27
|
Each Plan-Build-Run agent has a default model specified in its agent definition frontmatter (`model:` field). These defaults are overridden by the `models` section of `config.json`.
|
|
@@ -14,7 +14,7 @@ Plan-Build-Run uses adaptive model selection to balance cost and capability.
|
|
|
14
14
|
|-----------|-------|-----------|
|
|
15
15
|
| simple | haiku | Fast, cheap — sufficient for mechanical changes |
|
|
16
16
|
| medium | sonnet | Good balance for standard feature work |
|
|
17
|
-
| complex | inherit | Uses session model —
|
|
17
|
+
| complex | inherit | Uses session model — see `model-profiles.md` Session Model section for cost implications |
|
|
18
18
|
|
|
19
19
|
## Override Mechanisms
|
|
20
20
|
|
|
@@ -132,6 +132,7 @@ Use AskUserQuestion:
|
|
|
132
132
|
description: "Walk through model selection, features, and preferences step by step."
|
|
133
133
|
|
|
134
134
|
**If user selects "Quick start":**
|
|
135
|
+
- Tell the user: "Tip: Agents set to `inherit` use your Claude Code session model. For cost savings, run on Sonnet -- orchestration and inherit agents work well at that tier. See `references/model-profiles.md` for details."
|
|
135
136
|
- Write `.planning/config.json` immediately using the default config below (no further questions):
|
|
136
137
|
```json
|
|
137
138
|
{
|
|
@@ -213,6 +214,8 @@ Use AskUserQuestion:
|
|
|
213
214
|
After understanding the project, configure the Plan-Build-Run workflow. Use AskUserQuestion for each preference below. Present them sequentially with conversational bridging (e.g., "Great. Next...") to keep the flow natural.
|
|
214
215
|
|
|
215
216
|
**3-model. Model Profile:**
|
|
217
|
+
Note: These profiles control agent models. The orchestrator uses your Claude Code session model. For cost optimization, consider running on Sonnet -- agents with `inherit` will follow. See `references/model-profiles.md`.
|
|
218
|
+
|
|
216
219
|
Use AskUserQuestion:
|
|
217
220
|
question: "Which model profile should agents use?"
|
|
218
221
|
header: "Models"
|
|
@@ -57,6 +57,8 @@ Stop. Do not proceed further.
|
|
|
57
57
|
|
|
58
58
|
## Step 2: Model Selection
|
|
59
59
|
|
|
60
|
+
Note: These profiles control agent models, not the orchestrator. The orchestrator uses your Claude Code session model. For cost optimization, consider running your session on Sonnet -- agents with `inherit` will follow. See `references/model-profiles.md` for details.
|
|
61
|
+
|
|
60
62
|
Use AskUserQuestion:
|
|
61
63
|
question: "Which model profile should agents use?"
|
|
62
64
|
header: "Models"
|
|
@@ -15,6 +15,19 @@
|
|
|
15
15
|
]
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
|
+
"instructionsLoaded": [
|
|
19
|
+
{
|
|
20
|
+
"hooks": [
|
|
21
|
+
{
|
|
22
|
+
"type": "command",
|
|
23
|
+
"bash": "node \"$(cd \"$(dirname \"$0\")\" && pwd)/../../pbr/scripts/run-hook.js\" instructions-loaded.js",
|
|
24
|
+
"powershell": "node (Join-Path (Split-Path -Parent $PSScriptRoot) 'pbr\\scripts\\run-hook.js') instructions-loaded.js",
|
|
25
|
+
"cwd": ".",
|
|
26
|
+
"timeoutSec": 15
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
],
|
|
18
31
|
"postToolUse": [
|
|
19
32
|
{
|
|
20
33
|
"matcher": "Write|Edit",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
3
|
"displayName": "Plan-Build-Run",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.58.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",
|
|
@@ -4,6 +4,24 @@ How Plan-Build-Run maps agents to models and how to configure model selection.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## Session Model (Orchestrator)
|
|
8
|
+
|
|
9
|
+
The orchestrator is your main Claude Code session -- it reads skills, manages state, and routes work to agents. Its model is whatever you selected in Claude Code (not controlled by PBR's `config.json`).
|
|
10
|
+
|
|
11
|
+
**Cost impact:** The orchestrator accounts for roughly 40% of total session cost. Agents set to `inherit` (planner, executor, debugger, general in the `balanced` profile) also use this model. Switching your session from Opus to Sonnet reduces cost for both the orchestrator and all `inherit` agents.
|
|
12
|
+
|
|
13
|
+
**Recommendations:**
|
|
14
|
+
|
|
15
|
+
| Goal | Session Model | Config Adjustment |
|
|
16
|
+
|------|---------------|-------------------|
|
|
17
|
+
| Maximum quality | Opus | None needed -- `inherit` agents get Opus |
|
|
18
|
+
| Balanced cost/quality | Sonnet | None needed -- `inherit` agents get Sonnet, which handles most tasks well |
|
|
19
|
+
| Cheap orchestration, Opus agents | Sonnet | Set `planner: "opus"`, `executor: "opus"`, `debugger: "opus"` to override inherit |
|
|
20
|
+
|
|
21
|
+
Sonnet 4.6 handles orchestration tasks (state reading, routing decisions, context assembly) effectively. Reserve Opus for agents doing complex reasoning, architecture, or novel code generation.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
7
25
|
## Agent-to-Model Mapping
|
|
8
26
|
|
|
9
27
|
Each Plan-Build-Run agent has a default model specified in its agent definition frontmatter (`model:` field). These defaults are overridden by the `models` section of `config.json`.
|
|
@@ -14,7 +14,7 @@ Plan-Build-Run uses adaptive model selection to balance cost and capability.
|
|
|
14
14
|
|-----------|-------|-----------|
|
|
15
15
|
| simple | haiku | Fast, cheap — sufficient for mechanical changes |
|
|
16
16
|
| medium | sonnet | Good balance for standard feature work |
|
|
17
|
-
| complex | inherit | Uses session model —
|
|
17
|
+
| complex | inherit | Uses session model — see `model-profiles.md` Session Model section for cost implications |
|
|
18
18
|
|
|
19
19
|
## Override Mechanisms
|
|
20
20
|
|
|
@@ -132,6 +132,7 @@ Use AskUserQuestion:
|
|
|
132
132
|
description: "Walk through model selection, features, and preferences step by step."
|
|
133
133
|
|
|
134
134
|
**If user selects "Quick start":**
|
|
135
|
+
- Tell the user: "Tip: Agents set to `inherit` use your Claude Code session model. For cost savings, run on Sonnet -- orchestration and inherit agents work well at that tier. See `references/model-profiles.md` for details."
|
|
135
136
|
- Write `.planning/config.json` immediately using the default config below (no further questions):
|
|
136
137
|
```json
|
|
137
138
|
{
|
|
@@ -213,6 +214,8 @@ Use AskUserQuestion:
|
|
|
213
214
|
After understanding the project, configure the Plan-Build-Run workflow. Use AskUserQuestion for each preference below. Present them sequentially with conversational bridging (e.g., "Great. Next...") to keep the flow natural.
|
|
214
215
|
|
|
215
216
|
**3-model. Model Profile:**
|
|
217
|
+
Note: These profiles control agent models. The orchestrator uses your Claude Code session model. For cost optimization, consider running on Sonnet -- agents with `inherit` will follow. See `references/model-profiles.md`.
|
|
218
|
+
|
|
216
219
|
Use AskUserQuestion:
|
|
217
220
|
question: "Which model profile should agents use?"
|
|
218
221
|
header: "Models"
|
|
@@ -57,6 +57,8 @@ Stop. Do not proceed further.
|
|
|
57
57
|
|
|
58
58
|
## Step 2: Model Selection
|
|
59
59
|
|
|
60
|
+
Note: These profiles control agent models, not the orchestrator. The orchestrator uses your Claude Code session model. For cost optimization, consider running your session on Sonnet -- agents with `inherit` will follow. See `references/model-profiles.md` for details.
|
|
61
|
+
|
|
60
62
|
Use AskUserQuestion:
|
|
61
63
|
question: "Which model profile should agents use?"
|
|
62
64
|
header: "Models"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
3
|
"displayName": "Plan-Build-Run",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.58.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",
|
|
@@ -13,6 +13,17 @@
|
|
|
13
13
|
]
|
|
14
14
|
}
|
|
15
15
|
],
|
|
16
|
+
"InstructionsLoaded": [
|
|
17
|
+
{
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"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'))\" instructions-loaded.js",
|
|
22
|
+
"statusMessage": "Detecting instruction reload..."
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
16
27
|
"PostToolUse": [
|
|
17
28
|
{
|
|
18
29
|
"matcher": "Write|Edit",
|
|
@@ -4,6 +4,24 @@ How Plan-Build-Run maps agents to models and how to configure model selection.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## Session Model (Orchestrator)
|
|
8
|
+
|
|
9
|
+
The orchestrator is your main Claude Code session -- it reads skills, manages state, and routes work to agents. Its model is whatever you selected in Claude Code (not controlled by PBR's `config.json`).
|
|
10
|
+
|
|
11
|
+
**Cost impact:** The orchestrator accounts for roughly 40% of total session cost. Agents set to `inherit` (planner, executor, debugger, general in the `balanced` profile) also use this model. Switching your session from Opus to Sonnet reduces cost for both the orchestrator and all `inherit` agents.
|
|
12
|
+
|
|
13
|
+
**Recommendations:**
|
|
14
|
+
|
|
15
|
+
| Goal | Session Model | Config Adjustment |
|
|
16
|
+
|------|---------------|-------------------|
|
|
17
|
+
| Maximum quality | Opus | None needed -- `inherit` agents get Opus |
|
|
18
|
+
| Balanced cost/quality | Sonnet | None needed -- `inherit` agents get Sonnet, which handles most tasks well |
|
|
19
|
+
| Cheap orchestration, Opus agents | Sonnet | Set `planner: "opus"`, `executor: "opus"`, `debugger: "opus"` to override inherit |
|
|
20
|
+
|
|
21
|
+
Sonnet 4.6 handles orchestration tasks (state reading, routing decisions, context assembly) effectively. Reserve Opus for agents doing complex reasoning, architecture, or novel code generation.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
7
25
|
## Agent-to-Model Mapping
|
|
8
26
|
|
|
9
27
|
Each Plan-Build-Run agent has a default model specified in its agent definition frontmatter (`model:` field). These defaults are overridden by the `models` section of `config.json`.
|
|
@@ -14,7 +14,7 @@ Plan-Build-Run uses adaptive model selection to balance cost and capability.
|
|
|
14
14
|
|-----------|-------|-----------|
|
|
15
15
|
| simple | haiku | Fast, cheap — sufficient for mechanical changes |
|
|
16
16
|
| medium | sonnet | Good balance for standard feature work |
|
|
17
|
-
| complex | inherit | Uses session model —
|
|
17
|
+
| complex | inherit | Uses session model — see `model-profiles.md` Session Model section for cost implications |
|
|
18
18
|
|
|
19
19
|
## Override Mechanisms
|
|
20
20
|
|
|
@@ -132,6 +132,7 @@ Use AskUserQuestion:
|
|
|
132
132
|
description: "Walk through model selection, features, and preferences step by step."
|
|
133
133
|
|
|
134
134
|
**If user selects "Quick start":**
|
|
135
|
+
- Tell the user: "Tip: Agents set to `inherit` use your Claude Code session model. For cost savings, run on Sonnet -- orchestration and inherit agents work well at that tier. See `references/model-profiles.md` for details."
|
|
135
136
|
- Write `.planning/config.json` immediately using the default config below (no further questions):
|
|
136
137
|
```json
|
|
137
138
|
{
|
|
@@ -213,6 +214,8 @@ Use AskUserQuestion:
|
|
|
213
214
|
After understanding the project, configure the Plan-Build-Run workflow. Use AskUserQuestion for each preference below. Present them sequentially with conversational bridging (e.g., "Great. Next...") to keep the flow natural.
|
|
214
215
|
|
|
215
216
|
**3-model. Model Profile:**
|
|
217
|
+
Note: These profiles control agent models. The orchestrator uses your Claude Code session model. For cost optimization, consider running on Sonnet -- agents with `inherit` will follow. See `references/model-profiles.md`.
|
|
218
|
+
|
|
216
219
|
Use AskUserQuestion:
|
|
217
220
|
question: "Which model profile should agents use?"
|
|
218
221
|
header: "Models"
|
|
@@ -57,6 +57,8 @@ Stop. Do not proceed further.
|
|
|
57
57
|
|
|
58
58
|
## Step 2: Model Selection
|
|
59
59
|
|
|
60
|
+
Note: These profiles control agent models, not the orchestrator. The orchestrator uses your Claude Code session model. For cost optimization, consider running your session on Sonnet -- agents with `inherit` will follow. See `references/model-profiles.md` for details.
|
|
61
|
+
|
|
60
62
|
Use AskUserQuestion:
|
|
61
63
|
question: "Which model profile should agents use?"
|
|
62
64
|
header: "Models"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pbr",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.58.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",
|
|
@@ -18,6 +18,17 @@
|
|
|
18
18
|
]
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
|
+
"InstructionsLoaded": [
|
|
22
|
+
{
|
|
23
|
+
"hooks": [
|
|
24
|
+
{
|
|
25
|
+
"type": "command",
|
|
26
|
+
"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'))\" instructions-loaded.js",
|
|
27
|
+
"statusMessage": "Detecting instruction reload..."
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
],
|
|
21
32
|
"PostToolUse": [
|
|
22
33
|
{
|
|
23
34
|
"matcher": "Write|Edit",
|
|
@@ -4,6 +4,24 @@ How Plan-Build-Run maps agents to models and how to configure model selection.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## Session Model (Orchestrator)
|
|
8
|
+
|
|
9
|
+
The orchestrator is your main Claude Code session -- it reads skills, manages state, and routes work to agents. Its model is whatever you selected in Claude Code (not controlled by PBR's `config.json`).
|
|
10
|
+
|
|
11
|
+
**Cost impact:** The orchestrator accounts for roughly 40% of total session cost. Agents set to `inherit` (planner, executor, debugger, general in the `balanced` profile) also use this model. Switching your session from Opus to Sonnet reduces cost for both the orchestrator and all `inherit` agents.
|
|
12
|
+
|
|
13
|
+
**Recommendations:**
|
|
14
|
+
|
|
15
|
+
| Goal | Session Model | Config Adjustment |
|
|
16
|
+
|------|---------------|-------------------|
|
|
17
|
+
| Maximum quality | Opus | None needed -- `inherit` agents get Opus |
|
|
18
|
+
| Balanced cost/quality | Sonnet | None needed -- `inherit` agents get Sonnet, which handles most tasks well |
|
|
19
|
+
| Cheap orchestration, Opus agents | Sonnet | Set `planner: "opus"`, `executor: "opus"`, `debugger: "opus"` to override inherit |
|
|
20
|
+
|
|
21
|
+
Sonnet 4.6 handles orchestration tasks (state reading, routing decisions, context assembly) effectively. Reserve Opus for agents doing complex reasoning, architecture, or novel code generation.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
7
25
|
## Agent-to-Model Mapping
|
|
8
26
|
|
|
9
27
|
Each Plan-Build-Run agent has a default model specified in its agent definition frontmatter (`model:` field). These defaults are overridden by the `models` section of `config.json`.
|
|
@@ -14,7 +14,7 @@ Plan-Build-Run uses adaptive model selection to balance cost and capability.
|
|
|
14
14
|
|-----------|-------|-----------|
|
|
15
15
|
| simple | haiku | Fast, cheap — sufficient for mechanical changes |
|
|
16
16
|
| medium | sonnet | Good balance for standard feature work |
|
|
17
|
-
| complex | inherit | Uses session model —
|
|
17
|
+
| complex | inherit | Uses session model — see `model-profiles.md` Session Model section for cost implications |
|
|
18
18
|
|
|
19
19
|
## Override Mechanisms
|
|
20
20
|
|
|
@@ -421,7 +421,7 @@ async function main() {
|
|
|
421
421
|
}
|
|
422
422
|
|
|
423
423
|
// Extract agent type from the Task completion data
|
|
424
|
-
const agentType = data.tool_input?.subagent_type || data.subagent_type || '';
|
|
424
|
+
const agentType = data.agent_type || data.tool_input?.subagent_type || data.subagent_type || '';
|
|
425
425
|
|
|
426
426
|
// Only check known Plan-Build-Run agent types
|
|
427
427
|
const outputSpec = AGENT_OUTPUTS[agentType];
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"type": "object",
|
|
11
11
|
"properties": {
|
|
12
12
|
"SessionStart": { "$ref": "#/definitions/hookEntryList" },
|
|
13
|
+
"InstructionsLoaded": { "$ref": "#/definitions/hookEntryList" },
|
|
13
14
|
"PreToolUse": { "$ref": "#/definitions/hookEntryList" },
|
|
14
15
|
"PostToolUse": { "$ref": "#/definitions/hookEntryList" },
|
|
15
16
|
"PostToolUseFailure": { "$ref": "#/definitions/hookEntryList" },
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* InstructionsLoaded hook: Lightweight PBR state reminder after CLAUDE.md loads.
|
|
5
|
+
*
|
|
6
|
+
* Fires each time Claude Code loads CLAUDE.md or .claude/rules/*.md files.
|
|
7
|
+
* For PBR projects: injects a brief reminder that PBR workflow is active.
|
|
8
|
+
* Debounces mid-session re-fires using .session.json load timestamp.
|
|
9
|
+
*
|
|
10
|
+
* Non-blocking — always exits 0.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const { logHook } = require('./hook-logger');
|
|
18
|
+
|
|
19
|
+
function readStdin() {
|
|
20
|
+
try {
|
|
21
|
+
const input = fs.readFileSync(0, 'utf8').trim();
|
|
22
|
+
if (input) return JSON.parse(input);
|
|
23
|
+
} catch (_e) { /* empty or non-JSON stdin */ }
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function main() {
|
|
28
|
+
const data = readStdin();
|
|
29
|
+
const cwd = process.env.PBR_PROJECT_ROOT || process.cwd();
|
|
30
|
+
const planningDir = path.join(cwd, '.planning');
|
|
31
|
+
|
|
32
|
+
// Only relevant for PBR projects
|
|
33
|
+
if (!fs.existsSync(planningDir)) {
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Debounce: only emit additionalContext on first fire per session.
|
|
38
|
+
// .session.json is written by progress-tracker.js at SessionStart.
|
|
39
|
+
// If it exists with a sessionStart timestamp, this is a mid-session reload.
|
|
40
|
+
let isMidSession = false;
|
|
41
|
+
try {
|
|
42
|
+
const sessionFile = path.join(planningDir, '.session.json');
|
|
43
|
+
if (fs.existsSync(sessionFile)) {
|
|
44
|
+
const session = JSON.parse(fs.readFileSync(sessionFile, 'utf8'));
|
|
45
|
+
if (session.sessionStart) {
|
|
46
|
+
isMidSession = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
} catch (_e) { /* non-fatal */ }
|
|
50
|
+
|
|
51
|
+
logHook('instructions-loaded', 'InstructionsLoaded', isMidSession ? 'mid-session-reload' : 'initial-load', {
|
|
52
|
+
instructions_file: data.instructions_file || null
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Mid-session: note that instructions reloaded (CLAUDE.md may have changed)
|
|
56
|
+
if (isMidSession) {
|
|
57
|
+
process.stdout.write(JSON.stringify({
|
|
58
|
+
additionalContext: '[Plan-Build-Run] Project CLAUDE.md was reloaded mid-session. If PBR workflow rules changed, current skill invocation may be affected. Check .planning/STATE.md for current position.'
|
|
59
|
+
}));
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Initial load: no additionalContext needed — progress-tracker.js already
|
|
64
|
+
// injected full state at SessionStart. Avoid double-injection.
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (require.main === module || process.argv[1] === __filename) { main(); }
|
|
69
|
+
module.exports = { main };
|
|
@@ -15,6 +15,13 @@ const path = require('path');
|
|
|
15
15
|
* @returns {string|null}
|
|
16
16
|
*/
|
|
17
17
|
function readActiveSkill(planningDir) {
|
|
18
|
+
// Check .session.json first (consistent with check-subagent-output.js and log-subagent.js)
|
|
19
|
+
try {
|
|
20
|
+
const { sessionLoad } = require('../../pbr-tools');
|
|
21
|
+
const session = sessionLoad(planningDir);
|
|
22
|
+
if (session && session.activeSkill) return session.activeSkill;
|
|
23
|
+
} catch (_e) { /* pbr-tools unavailable */ }
|
|
24
|
+
// Fall back to legacy .active-skill file
|
|
18
25
|
try {
|
|
19
26
|
return fs.readFileSync(path.join(planningDir, '.active-skill'), 'utf8').trim();
|
|
20
27
|
} catch (_e) {
|
|
@@ -6,6 +6,52 @@ const { route } = require('../router');
|
|
|
6
6
|
|
|
7
7
|
const VALID_CLASSIFICATIONS = ['correct', 'type_mismatch', 'vague'];
|
|
8
8
|
|
|
9
|
+
const CONVENTIONAL_COMMIT_RE = /^(feat|fix|refactor|test|docs|chore|wip|perf|ci|build|revert)(\(.*?\))?!?:/;
|
|
10
|
+
|
|
11
|
+
const TEST_FILE_RE = /(?:^|[/\\])tests[/\\]|\.test\.[jt]sx?$|\.spec\.[jt]sx?$/;
|
|
12
|
+
const MARKDOWN_RE = /\.mdx?$/i;
|
|
13
|
+
const CONFIG_TOOLING_RE = /\.(?:json|ya?ml|toml|ini|env|lock)$|(?:^|[/\\])(?:\.github|\.husky|scripts)[/\\]|(?:Makefile|Dockerfile|\.eslintrc|\.prettierrc|babel\.config|jest\.config|tsconfig|webpack\.config|rollup\.config)/i;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Heuristic-first classifier for git commit messages.
|
|
17
|
+
* Runs before the LLM path and returns early for unambiguous cases.
|
|
18
|
+
*
|
|
19
|
+
* @param {string} commitMessage - the commit message to classify
|
|
20
|
+
* @param {string[]} [stagedFiles] - optional list of staged file paths
|
|
21
|
+
* @returns {{ classification: string, confidence: number }|null} result or null (fall through to LLM)
|
|
22
|
+
*/
|
|
23
|
+
function classifyCommitHeuristic(commitMessage, stagedFiles) {
|
|
24
|
+
const match = CONVENTIONAL_COMMIT_RE.exec(commitMessage);
|
|
25
|
+
if (!match) return null;
|
|
26
|
+
|
|
27
|
+
const type = match[1];
|
|
28
|
+
const files = stagedFiles && stagedFiles.length > 0 ? stagedFiles : [];
|
|
29
|
+
|
|
30
|
+
// Check for "fix" type but description implies addition
|
|
31
|
+
const descriptionPart = commitMessage.slice(match[0].length).trim();
|
|
32
|
+
if (type === 'fix' && /^(?:add|adds|adding|new\b)/i.test(descriptionPart)) {
|
|
33
|
+
return { classification: 'type_mismatch', confidence: 0.9 };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Type-to-file alignment checks (only when staged files are known)
|
|
37
|
+
if (files.length > 0) {
|
|
38
|
+
if (type === 'test' && files.every(f => TEST_FILE_RE.test(f))) {
|
|
39
|
+
return { classification: 'correct', confidence: 1.0 };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (type === 'docs' && files.every(f => MARKDOWN_RE.test(f))) {
|
|
43
|
+
return { classification: 'correct', confidence: 1.0 };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if ((type === 'chore' || type === 'ci' || type === 'build') && files.every(f => CONFIG_TOOLING_RE.test(f))) {
|
|
47
|
+
return { classification: 'correct', confidence: 1.0 };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Type parsed cleanly — most conventional commits are typed correctly
|
|
52
|
+
return { classification: 'correct', confidence: 0.8 };
|
|
53
|
+
}
|
|
54
|
+
|
|
9
55
|
/**
|
|
10
56
|
* Classifies a git commit message for semantic correctness using the local LLM.
|
|
11
57
|
* Goes beyond regex validation — checks whether the commit type matches the
|
|
@@ -22,6 +68,29 @@ async function classifyCommit(config, planningDir, commitMessage, stagedFiles, s
|
|
|
22
68
|
if (!config.enabled || !config.features.commit_classification) return null;
|
|
23
69
|
if (isDisabled('commit-classification', config.advanced.disable_after_failures)) return null;
|
|
24
70
|
|
|
71
|
+
// Heuristic-first: skip LLM for unambiguous cases
|
|
72
|
+
const heuristic = classifyCommitHeuristic(commitMessage, stagedFiles);
|
|
73
|
+
if (heuristic !== null) {
|
|
74
|
+
logMetric(planningDir, {
|
|
75
|
+
session_id: sessionId || 'unknown',
|
|
76
|
+
timestamp: new Date().toISOString(),
|
|
77
|
+
operation: 'commit-classification',
|
|
78
|
+
model: 'heuristic',
|
|
79
|
+
latency_ms: 0,
|
|
80
|
+
tokens_used_local: 0,
|
|
81
|
+
tokens_saved_frontier: 150,
|
|
82
|
+
result: heuristic.classification,
|
|
83
|
+
fallback_used: false,
|
|
84
|
+
confidence: heuristic.confidence
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
classification: heuristic.classification,
|
|
88
|
+
confidence: heuristic.confidence,
|
|
89
|
+
latency_ms: 0,
|
|
90
|
+
fallback_used: false
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
25
94
|
const filesContext = stagedFiles && stagedFiles.length > 0
|
|
26
95
|
? '\nStaged files: ' + stagedFiles.slice(0, 20).join(', ')
|
|
27
96
|
: '';
|
|
@@ -65,4 +134,4 @@ async function classifyCommit(config, planningDir, commitMessage, stagedFiles, s
|
|
|
65
134
|
}
|
|
66
135
|
}
|
|
67
136
|
|
|
68
|
-
module.exports = { classifyCommit, VALID_CLASSIFICATIONS };
|
|
137
|
+
module.exports = { classifyCommit, classifyCommitHeuristic, VALID_CLASSIFICATIONS };
|
|
@@ -3,10 +3,83 @@
|
|
|
3
3
|
const { complete, tryParseJSON, isDisabled } = require('../client');
|
|
4
4
|
const { logMetric } = require('../metrics');
|
|
5
5
|
const { route } = require('../router');
|
|
6
|
+
const path = require('path');
|
|
6
7
|
|
|
7
8
|
const VALID_FILE_TYPES = ['plan', 'state', 'code', 'test', 'config', 'docs', 'template', 'other'];
|
|
8
9
|
const VALID_INTENTS = ['create', 'update', 'fix', 'refactor', 'delete'];
|
|
9
10
|
|
|
11
|
+
// Normalize path separators to forward slashes for consistent pattern matching.
|
|
12
|
+
function normalizePath(filePath) {
|
|
13
|
+
return filePath.replace(/\\/g, '/');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Heuristic-based file classification. Runs before the LLM path and returns a
|
|
18
|
+
* result object for clear-cut cases, or null for ambiguous inputs that should
|
|
19
|
+
* fall through to the LLM.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} filePath - the target file path
|
|
22
|
+
* @param {string} contentSnippet - first ~200 chars of the content being written
|
|
23
|
+
* @returns {{ file_type: string, intent: string, confidence: number }|null}
|
|
24
|
+
*/
|
|
25
|
+
function classifyFileIntentHeuristic(filePath, contentSnippet) {
|
|
26
|
+
const normalized = normalizePath(filePath);
|
|
27
|
+
const basename = path.basename(normalized);
|
|
28
|
+
const snippet = contentSnippet || '';
|
|
29
|
+
|
|
30
|
+
// --- Extension map (test extensions checked before generic ones) ---
|
|
31
|
+
if (/\.(test|spec)\.(js|ts|mjs|cjs)$/.test(basename)) {
|
|
32
|
+
return { file_type: 'test', intent: 'update', confidence: 1.0 };
|
|
33
|
+
}
|
|
34
|
+
if (/\.(tmpl|ejs)$/.test(basename)) {
|
|
35
|
+
return { file_type: 'template', intent: 'update', confidence: 1.0 };
|
|
36
|
+
}
|
|
37
|
+
if (/\.(json|yaml|yml)$/.test(basename)) {
|
|
38
|
+
return { file_type: 'config', intent: 'update', confidence: 1.0 };
|
|
39
|
+
}
|
|
40
|
+
if (/\.(js|ts|mjs|cjs)$/.test(basename)) {
|
|
41
|
+
// Even if in tests/ directory the double-extension rule above already caught it,
|
|
42
|
+
// but check path pattern here too as an extra safety net.
|
|
43
|
+
if (/(?:^|\/)(?:tests?|__tests__)\//.test(normalized)) {
|
|
44
|
+
return { file_type: 'test', intent: 'update', confidence: 1.0 };
|
|
45
|
+
}
|
|
46
|
+
return { file_type: 'code', intent: 'update', confidence: 1.0 };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- Path patterns (checked before .md extension so directory wins) ---
|
|
50
|
+
if (/(?:^|\/)(?:tests?|__tests__)\//.test(normalized)) {
|
|
51
|
+
return { file_type: 'test', intent: 'update', confidence: 1.0 };
|
|
52
|
+
}
|
|
53
|
+
if (/(?:^|\/)docs\//.test(normalized)) {
|
|
54
|
+
return { file_type: 'docs', intent: 'update', confidence: 1.0 };
|
|
55
|
+
}
|
|
56
|
+
if (/(?:^|\/)scripts\//.test(normalized)) {
|
|
57
|
+
return { file_type: 'code', intent: 'update', confidence: 1.0 };
|
|
58
|
+
}
|
|
59
|
+
// .planning/ special cases — STATE.md first, then general plan
|
|
60
|
+
if (/(?:^|\/)\.planning\//.test(normalized)) {
|
|
61
|
+
if (basename === 'STATE.md') {
|
|
62
|
+
return { file_type: 'state', intent: 'update', confidence: 1.0 };
|
|
63
|
+
}
|
|
64
|
+
return { file_type: 'plan', intent: 'update', confidence: 1.0 };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// --- Content signals (apply to any extension) ---
|
|
68
|
+
const trimmed = snippet.trimStart();
|
|
69
|
+
if (/^(?:describe|test|it)\s*\(/.test(trimmed)) {
|
|
70
|
+
return { file_type: 'test', intent: 'update', confidence: 1.0 };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// --- .md extension: only classify when in a recognized path, else null ---
|
|
74
|
+
if (/\.md$/.test(basename)) {
|
|
75
|
+
// docs/ and .planning/ were already handled above; all other .md is ambiguous.
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Anything else is ambiguous — let the LLM decide.
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
10
83
|
/**
|
|
11
84
|
* Classifies the type and intent of a Write/Edit operation using the local LLM.
|
|
12
85
|
* Uses the file path and a short content snippet to determine what kind of file
|
|
@@ -25,6 +98,31 @@ async function classifyFileIntent(config, planningDir, filePath, contentSnippet,
|
|
|
25
98
|
|
|
26
99
|
const snippet = contentSnippet.length > 800 ? contentSnippet.slice(0, 800) : contentSnippet;
|
|
27
100
|
|
|
101
|
+
// --- Heuristic fast-path: skip the LLM for deterministic cases ---
|
|
102
|
+
const heuristic = classifyFileIntentHeuristic(filePath, snippet);
|
|
103
|
+
if (heuristic !== null) {
|
|
104
|
+
logMetric(planningDir, {
|
|
105
|
+
session_id: sessionId || 'unknown',
|
|
106
|
+
timestamp: new Date().toISOString(),
|
|
107
|
+
operation: 'file-intent',
|
|
108
|
+
model: 'heuristic',
|
|
109
|
+
latency_ms: 0,
|
|
110
|
+
tokens_used_local: 0,
|
|
111
|
+
tokens_saved_frontier: 150,
|
|
112
|
+
result: heuristic.file_type + '/' + heuristic.intent,
|
|
113
|
+
fallback_used: false,
|
|
114
|
+
confidence: heuristic.confidence
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
file_type: heuristic.file_type,
|
|
118
|
+
intent: heuristic.intent,
|
|
119
|
+
confidence: heuristic.confidence,
|
|
120
|
+
latency_ms: 0,
|
|
121
|
+
fallback_used: false
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// --- End heuristic fast-path ---
|
|
125
|
+
|
|
28
126
|
const prompt =
|
|
29
127
|
'Classify this file write operation. Based on the file path and content snippet, determine: (1) file_type: plan (PLAN.md, ROADMAP.md, planning docs), state (STATE.md, status tracking), code (source code, scripts), test (test files), config (JSON/YAML config, package.json), docs (README, documentation), template (templates, EJS), other. (2) intent: create (new file), update (modify existing), fix (bug fix), refactor (restructure), delete (removing content). Respond with JSON: {"file_type": "<one of 8>", "intent": "<one of 5>", "confidence": 0.0-1.0}\n\nPath: ' +
|
|
30
128
|
filePath + '\nContent snippet:\n' + snippet;
|
|
@@ -70,4 +168,4 @@ async function classifyFileIntent(config, planningDir, filePath, contentSnippet,
|
|
|
70
168
|
}
|
|
71
169
|
}
|
|
72
170
|
|
|
73
|
-
module.exports = { classifyFileIntent, VALID_FILE_TYPES, VALID_INTENTS };
|
|
171
|
+
module.exports = { classifyFileIntent, classifyFileIntentHeuristic, VALID_FILE_TYPES, VALID_INTENTS };
|
|
@@ -5,14 +5,33 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Fires when a Task() sub-agent finishes (distinct from SubagentStop).
|
|
7
7
|
* Logs the completion event and agent type for workflow tracking.
|
|
8
|
+
* Returns continue:false if a verifier finds critical gaps or an executor
|
|
9
|
+
* produces no SUMMARY.md — preventing the orchestrator from silently moving on.
|
|
8
10
|
*
|
|
9
11
|
* Non-blocking — exits 0 always.
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
14
|
const fs = require('fs');
|
|
15
|
+
const path = require('path');
|
|
13
16
|
const { logHook } = require('./hook-logger');
|
|
14
17
|
const { logEvent } = require('./event-logger');
|
|
15
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Read current_phase from STATE.md frontmatter.
|
|
21
|
+
* Lightweight — avoids heavy stateLoad() which parses roadmap/config too.
|
|
22
|
+
*/
|
|
23
|
+
function readCurrentPhase(planningDir) {
|
|
24
|
+
try {
|
|
25
|
+
const statePath = path.join(planningDir, 'STATE.md');
|
|
26
|
+
if (!fs.existsSync(statePath)) return null;
|
|
27
|
+
const content = fs.readFileSync(statePath, 'utf8');
|
|
28
|
+
const match = content.match(/^current_phase:\s*(\d+)/m);
|
|
29
|
+
return match ? match[1] : null;
|
|
30
|
+
} catch (_e) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
16
35
|
function readStdin() {
|
|
17
36
|
try {
|
|
18
37
|
const input = fs.readFileSync(0, 'utf8').trim();
|
|
@@ -23,8 +42,68 @@ function readStdin() {
|
|
|
23
42
|
return {};
|
|
24
43
|
}
|
|
25
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Check whether a halt signal should be emitted after a PBR agent completes.
|
|
47
|
+
* Returns null (no halt) or { continue: false, stopReason: "..." }.
|
|
48
|
+
*
|
|
49
|
+
* @param {object} data - parsed stdin JSON from the TaskCompleted event
|
|
50
|
+
* @param {string} planningDir - absolute path to the .planning directory
|
|
51
|
+
* @returns {{ continue: false, stopReason: string }|null}
|
|
52
|
+
*/
|
|
53
|
+
function checkHaltConditions(data, planningDir) {
|
|
54
|
+
const agentType = data.agent_type || data.subagent_type || null;
|
|
55
|
+
if (!agentType) return null;
|
|
56
|
+
|
|
57
|
+
// --- Verifier: halt if VERIFICATION.md reports gaps_found or failed ---
|
|
58
|
+
if (agentType === 'pbr:verifier') {
|
|
59
|
+
try {
|
|
60
|
+
const rawPhase = readCurrentPhase(planningDir);
|
|
61
|
+
const phaseNum = rawPhase ? String(rawPhase).padStart(2, '0') : null;
|
|
62
|
+
if (phaseNum) {
|
|
63
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
64
|
+
const candidates = fs.readdirSync(phasesDir).filter(d => d.startsWith(phaseNum + '-'));
|
|
65
|
+
const target = candidates.length > 0 ? path.join(phasesDir, candidates[0], 'VERIFICATION.md') : null;
|
|
66
|
+
if (target && fs.existsSync(target)) {
|
|
67
|
+
const content = fs.readFileSync(target, 'utf8');
|
|
68
|
+
const statusMatch = content.match(/^status:\s*(.+)$/m);
|
|
69
|
+
const status = statusMatch ? statusMatch[1].trim() : null;
|
|
70
|
+
if (status === 'gaps_found' || status === 'failed') {
|
|
71
|
+
return {
|
|
72
|
+
continue: false,
|
|
73
|
+
stopReason: `Verifier found critical gaps in Phase ${phaseNum} (status: ${status}). Run /pbr:review to address gaps before continuing.`
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
} catch (_e) { /* non-fatal — fall through to normal exit */ }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// --- Executor: halt if SUMMARY.md is missing from current phase dir ---
|
|
82
|
+
if (agentType === 'pbr:executor') {
|
|
83
|
+
try {
|
|
84
|
+
const rawPhase = readCurrentPhase(planningDir);
|
|
85
|
+
const phaseNum = rawPhase ? String(rawPhase).padStart(2, '0') : null;
|
|
86
|
+
if (phaseNum) {
|
|
87
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
88
|
+
const candidates = fs.readdirSync(phasesDir).filter(d => d.startsWith(phaseNum + '-'));
|
|
89
|
+
const target = candidates.length > 0 ? path.join(phasesDir, candidates[0], 'SUMMARY.md') : null;
|
|
90
|
+
if (target && !fs.existsSync(target)) {
|
|
91
|
+
return {
|
|
92
|
+
continue: false,
|
|
93
|
+
stopReason: `Executor completed Phase ${phaseNum} but produced no SUMMARY.md. Review executor output and re-run /pbr:build.`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} catch (_e) { /* non-fatal */ }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
26
103
|
function main() {
|
|
27
104
|
const data = readStdin();
|
|
105
|
+
const cwd = process.env.PBR_PROJECT_ROOT || process.cwd();
|
|
106
|
+
const planningDir = path.join(cwd, '.planning');
|
|
28
107
|
|
|
29
108
|
logHook('task-completed', 'TaskCompleted', 'completed', {
|
|
30
109
|
agent_type: data.agent_type || data.subagent_type || null,
|
|
@@ -38,8 +117,17 @@ function main() {
|
|
|
38
117
|
duration_ms: data.duration_ms || null
|
|
39
118
|
});
|
|
40
119
|
|
|
120
|
+
if (fs.existsSync(planningDir)) {
|
|
121
|
+
const halt = checkHaltConditions(data, planningDir);
|
|
122
|
+
if (halt) {
|
|
123
|
+
logHook('task-completed', 'TaskCompleted', 'halting', halt);
|
|
124
|
+
process.stdout.write(JSON.stringify(halt));
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
41
129
|
process.exit(0);
|
|
42
130
|
}
|
|
43
131
|
|
|
44
132
|
if (require.main === module || process.argv[1] === __filename) { main(); }
|
|
45
|
-
module.exports = { main };
|
|
133
|
+
module.exports = { main, checkHaltConditions, readCurrentPhase };
|
|
@@ -133,6 +133,7 @@ Use AskUserQuestion:
|
|
|
133
133
|
description: "Walk through model selection, features, and preferences step by step."
|
|
134
134
|
|
|
135
135
|
**If user selects "Quick start":**
|
|
136
|
+
- Tell the user: "Tip: Agents set to `inherit` use your Claude Code session model. For cost savings, run on Sonnet -- orchestration and inherit agents work well at that tier. See `references/model-profiles.md` for details."
|
|
136
137
|
- Write `.planning/config.json` immediately using the default config below (no further questions):
|
|
137
138
|
```json
|
|
138
139
|
{
|
|
@@ -214,6 +215,8 @@ Use AskUserQuestion:
|
|
|
214
215
|
After understanding the project, configure the Plan-Build-Run workflow. Use AskUserQuestion for each preference below. Present them sequentially with conversational bridging (e.g., "Great. Next...") to keep the flow natural.
|
|
215
216
|
|
|
216
217
|
**3-model. Model Profile:**
|
|
218
|
+
Note: These profiles control agent models. The orchestrator uses your Claude Code session model. For cost optimization, consider running on Sonnet -- agents with `inherit` will follow. See `references/model-profiles.md`.
|
|
219
|
+
|
|
217
220
|
Use AskUserQuestion:
|
|
218
221
|
question: "Which model profile should agents use?"
|
|
219
222
|
header: "Models"
|
|
@@ -58,6 +58,8 @@ Stop. Do not proceed further.
|
|
|
58
58
|
|
|
59
59
|
## Step 2: Model Selection
|
|
60
60
|
|
|
61
|
+
Note: These profiles control agent models, not the orchestrator. The orchestrator uses your Claude Code session model. For cost optimization, consider running your session on Sonnet -- agents with `inherit` will follow. See `references/model-profiles.md` for details.
|
|
62
|
+
|
|
61
63
|
Use AskUserQuestion:
|
|
62
64
|
question: "Which model profile should agents use?"
|
|
63
65
|
header: "Models"
|