codeforge-dev 1.4.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/.devcontainer/.env +22 -0
- package/.devcontainer/CHANGELOG.md +197 -0
- package/.devcontainer/CLAUDE.md +117 -0
- package/.devcontainer/README.md +222 -0
- package/.devcontainer/config/main-system-prompt.md +502 -0
- package/.devcontainer/config/settings.json +47 -0
- package/.devcontainer/devcontainer.json +94 -0
- package/.devcontainer/features/README.md +113 -0
- package/.devcontainer/features/agent-browser/README.md +65 -0
- package/.devcontainer/features/agent-browser/devcontainer-feature.json +23 -0
- package/.devcontainer/features/agent-browser/install.sh +79 -0
- package/.devcontainer/features/ast-grep/README.md +24 -0
- package/.devcontainer/features/ast-grep/devcontainer-feature.json +24 -0
- package/.devcontainer/features/ast-grep/install.sh +51 -0
- package/.devcontainer/features/ccstatusline/README.md +296 -0
- package/.devcontainer/features/ccstatusline/devcontainer-feature.json +19 -0
- package/.devcontainer/features/ccstatusline/install.sh +290 -0
- package/.devcontainer/features/ccusage/README.md +205 -0
- package/.devcontainer/features/ccusage/devcontainer-feature.json +38 -0
- package/.devcontainer/features/ccusage/install.sh +132 -0
- package/.devcontainer/features/claude-code/README.md +498 -0
- package/.devcontainer/features/claude-code/config/settings.json +36 -0
- package/.devcontainer/features/claude-code/config/system-prompt.md +118 -0
- package/.devcontainer/features/claude-code/config/world-building-sp.md +1432 -0
- package/.devcontainer/features/claude-code/devcontainer-feature.json +42 -0
- package/.devcontainer/features/claude-code/install.sh +466 -0
- package/.devcontainer/features/claude-monitor/README.md +74 -0
- package/.devcontainer/features/claude-monitor/devcontainer-feature.json +38 -0
- package/.devcontainer/features/claude-monitor/install.sh +99 -0
- package/.devcontainer/features/lsp-servers/README.md +85 -0
- package/.devcontainer/features/lsp-servers/devcontainer-feature.json +40 -0
- package/.devcontainer/features/lsp-servers/install.sh +116 -0
- package/.devcontainer/features/mcp-qdrant/CHANGES.md +399 -0
- package/.devcontainer/features/mcp-qdrant/README.md +474 -0
- package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +57 -0
- package/.devcontainer/features/mcp-qdrant/install.sh +295 -0
- package/.devcontainer/features/mcp-qdrant/poststart-hook.sh +129 -0
- package/.devcontainer/features/mcp-reasoner/README.md +177 -0
- package/.devcontainer/features/mcp-reasoner/devcontainer-feature.json +20 -0
- package/.devcontainer/features/mcp-reasoner/install.sh +177 -0
- package/.devcontainer/features/mcp-reasoner/poststart-hook.sh +67 -0
- package/.devcontainer/features/notify-hook/README.md +86 -0
- package/.devcontainer/features/notify-hook/devcontainer-feature.json +23 -0
- package/.devcontainer/features/notify-hook/install.sh +38 -0
- package/.devcontainer/features/splitrail/README.md +140 -0
- package/.devcontainer/features/splitrail/devcontainer-feature.json +34 -0
- package/.devcontainer/features/splitrail/install.sh +129 -0
- package/.devcontainer/features/tree-sitter/README.md +138 -0
- package/.devcontainer/features/tree-sitter/devcontainer-feature.json +52 -0
- package/.devcontainer/features/tree-sitter/install.sh +173 -0
- package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +106 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-file.py +101 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +137 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/.claude-plugin/plugin.json +8 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/SKILL.md +387 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/references/cli-flags-and-output.md +312 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/references/sdk-and-mcp.md +569 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/SKILL.md +309 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/references/compose-services.md +438 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/references/dockerfile-patterns.md +340 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/SKILL.md +412 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/references/container-lifecycle.md +388 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/references/resources-and-security.md +444 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/SKILL.md +344 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/middleware-and-lifespan.md +254 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/pydantic-models.md +245 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/routing-and-dependencies.md +255 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/sse-and-streaming.md +318 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/SKILL.md +345 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/references/agents-and-tools.md +271 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/references/models-and-streaming.md +422 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/SKILL.md +220 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/cross-vendor-principles.md +139 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/patterns-and-antipatterns.md +376 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/skill-authoring-patterns.md +356 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/SKILL.md +329 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/advanced-queries.md +314 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/javascript-patterns.md +323 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/python-patterns.md +354 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/schema-and-pragmas.md +326 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/SKILL.md +356 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/ai-sdk-svelte.md +128 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/component-patterns.md +332 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/layercake.md +203 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/migration-guide.md +350 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/runes-and-reactivity.md +328 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/spa-and-routing.md +262 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/svelte-dnd-action.md +181 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/SKILL.md +414 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/references/fastapi-testing.md +411 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/references/svelte-testing.md +538 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +110 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +108 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272create-pr.md +337 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272new.md +166 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272review-commit.md +290 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272work.md +257 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json +8 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md +184 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/.claude-plugin/plugin.json +6 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/config/planning-instructions.md +14 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/functional-conjuring-map.md +989 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/hooks/hooks.json +33 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/__pycache__/post-enhance-task.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhance-planning.py +71 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-plan.sh +68 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-task.sh +120 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-plan.py +133 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-task.py +253 -0
- package/.devcontainer/scripts/setup-aliases.sh +80 -0
- package/.devcontainer/scripts/setup-config.sh +28 -0
- package/.devcontainer/scripts/setup-irie-claude.sh +32 -0
- package/.devcontainer/scripts/setup-plugins.sh +80 -0
- package/.devcontainer/scripts/setup.sh +58 -0
- package/LICENSE.txt +674 -0
- package/README.md +267 -0
- package/package.json +44 -0
- package/setup.js +83 -0
package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/functional-conjuring-map.md
ADDED
|
@@ -0,0 +1,989 @@
|
|
|
1
|
+
# Plan: Advanced Plan & Task Validation System
|
|
2
|
+
|
|
3
|
+
## Problem Statement
|
|
4
|
+
|
|
5
|
+
The workflow-enhancer plugin currently provides basic plan and task enhancement hooks, but lacks intelligent validation. Plans can be approved without verifying they address user requirements, contain unmarked assumptions, or have adequate risk mitigation. Tasks can be created without verifying coverage against the approved plan.
|
|
6
|
+
|
|
7
|
+
This creates risk of:
|
|
8
|
+
- Requirements silently dropped or misunderstood
|
|
9
|
+
- Assumptions made without explicit approval
|
|
10
|
+
- High-risk changes without mitigation strategies
|
|
11
|
+
- Tasks that don't cover the full plan scope
|
|
12
|
+
|
|
13
|
+
## Scope Definition
|
|
14
|
+
|
|
15
|
+
### In Scope
|
|
16
|
+
- Marker enforcement system (`[ASSUMPTION]`, `[DEFERRED]`, `[APPROVED]`)
|
|
17
|
+
- Bash-based syntactic validation (fast gate)
|
|
18
|
+
- Opus-based semantic analysis (reasoning over plan + transcript + tasks)
|
|
19
|
+
- Sonnet-based verification (file access for grounding claims)
|
|
20
|
+
- Task coverage matrix generation
|
|
21
|
+
- Risk escalation detection and mitigation verification
|
|
22
|
+
|
|
23
|
+
### Out of Scope
|
|
24
|
+
- Historical pattern matching [DEFERRED] [APPROVED]
|
|
25
|
+
- Dependency graph visualization [DEFERRED] [APPROVED]
|
|
26
|
+
- Context window monitoring [DEFERRED] [APPROVED]
|
|
27
|
+
- Real-time collaboration hooks [DEFERRED] [APPROVED]
|
|
28
|
+
- External CI/CD integration [DEFERRED] [APPROVED]
|
|
29
|
+
|
|
30
|
+
### Assumptions
|
|
31
|
+
- Claude CLI supports headless mode with model selection [ASSUMPTION]
|
|
32
|
+
- Transcript JSONL format is stable and parseable [ASSUMPTION]
|
|
33
|
+
- Token costs for Opus/Sonnet calls are acceptable (~$0.05-0.08 per plan) [ASSUMPTION]
|
|
34
|
+
|
|
35
|
+
## Current State
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
PreToolUse (EnterPlanMode)
|
|
39
|
+
└── enhance-planning.py
|
|
40
|
+
└── Injects planning-instructions.md content (basic template)
|
|
41
|
+
|
|
42
|
+
PostToolUse (Write to /plans/)
|
|
43
|
+
└── post-enhance-plan.py
|
|
44
|
+
└── Detects plan files
|
|
45
|
+
└── Runs enhance-plan.sh (placeholder, no real validation)
|
|
46
|
+
└── Returns additionalContext
|
|
47
|
+
|
|
48
|
+
PostToolUse (TaskCreate|TaskUpdate)
|
|
49
|
+
└── post-enhance-task.py
|
|
50
|
+
└── Finds task file
|
|
51
|
+
└── Finds session plan (correlation implemented)
|
|
52
|
+
└── Runs enhance-task.sh (placeholder)
|
|
53
|
+
└── Returns additionalContext
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Desired State
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
PreToolUse (EnterPlanMode)
|
|
60
|
+
└── enhance-planning.py
|
|
61
|
+
└── Injects comprehensive planning-instructions.md:
|
|
62
|
+
├── Required section template
|
|
63
|
+
├── Marker syntax requirements
|
|
64
|
+
├── Assumption/deferral rules
|
|
65
|
+
└── Risk documentation requirements
|
|
66
|
+
|
|
67
|
+
PostToolUse (Write to /plans/)
|
|
68
|
+
└── post-enhance-plan.py (orchestrator)
|
|
69
|
+
│
|
|
70
|
+
├── LAYER 1: Bash Validators (fast gate)
|
|
71
|
+
│ ├── section_validator.sh → Required sections present
|
|
72
|
+
│ ├── marker_validator.sh → [ASSUMPTION], [DEFERRED], [APPROVED] syntax
|
|
73
|
+
│ ├── assumption_detector.sh → Unmarked assumption language
|
|
74
|
+
│ └── risk_detector.sh → High-risk keywords, mitigation check
|
|
75
|
+
│
|
|
76
|
+
├── LAYER 2: Opus Analyzer (reasoning, 1-2 turns)
|
|
77
|
+
│ └── opus_analyzer.py
|
|
78
|
+
│ ├── Input: plan + transcript + tasks
|
|
79
|
+
│ ├── Requirement traceability analysis
|
|
80
|
+
│ ├── Assumption audit
|
|
81
|
+
│ ├── Gap/ambiguity detection
|
|
82
|
+
│ ├── Task coverage matrix
|
|
83
|
+
│ └── Risk assessment
|
|
84
|
+
│
|
|
85
|
+
└── LAYER 3: Sonnet Verifier (conditional, file access)
|
|
86
|
+
└── sonnet_verifier.py
|
|
87
|
+
├── Triggered by: Opus concerns OR high-risk flags
|
|
88
|
+
├── File path verification
|
|
89
|
+
├── Pattern alignment check
|
|
90
|
+
├── Conflict detection
|
|
91
|
+
└── Security spot-check
|
|
92
|
+
|
|
93
|
+
PostToolUse (TaskCreate|TaskUpdate)
|
|
94
|
+
└── post-enhance-task.py
|
|
95
|
+
└── [Existing functionality]
|
|
96
|
+
└── Coverage data passed to Opus in plan validation
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Technical Approach
|
|
100
|
+
|
|
101
|
+
### Phase 1: Planning Instructions Enhancement
|
|
102
|
+
|
|
103
|
+
**Files:**
|
|
104
|
+
- `config/planning-instructions.md` - complete rewrite
|
|
105
|
+
|
|
106
|
+
**Content to inject:**
|
|
107
|
+
|
|
108
|
+
```markdown
|
|
109
|
+
## Required Plan Sections
|
|
110
|
+
|
|
111
|
+
Your plan MUST include these sections:
|
|
112
|
+
|
|
113
|
+
1. **Problem Statement** - What problem and why it matters
|
|
114
|
+
2. **Scope Definition** - In scope, out of scope, assumptions
|
|
115
|
+
3. **Current vs Desired State** - Before and after
|
|
116
|
+
4. **Technical Approach** - Phases with files and steps
|
|
117
|
+
5. **Verification Checklist** - How to confirm completion
|
|
118
|
+
6. **Risks and Mitigations** - What could go wrong
|
|
119
|
+
|
|
120
|
+
## Required Markers
|
|
121
|
+
|
|
122
|
+
### Assumptions
|
|
123
|
+
Any assumption MUST be marked: `[ASSUMPTION]`
|
|
124
|
+
Approved assumptions: `[ASSUMPTION] [APPROVED]`
|
|
125
|
+
|
|
126
|
+
Example:
|
|
127
|
+
- Database supports JSON columns [ASSUMPTION] [APPROVED]
|
|
128
|
+
|
|
129
|
+
### Deferrals
|
|
130
|
+
Anything deferred MUST be marked: `[DEFERRED]`
|
|
131
|
+
Approved deferrals: `[DEFERRED] [APPROVED]`
|
|
132
|
+
|
|
133
|
+
Example:
|
|
134
|
+
- Admin panel [DEFERRED] [APPROVED] - Phase 2 work
|
|
135
|
+
|
|
136
|
+
### Unapproved markers will be flagged
|
|
137
|
+
The plan validator will reject plans with:
|
|
138
|
+
- `[ASSUMPTION]` without `[APPROVED]`
|
|
139
|
+
- `[DEFERRED]` without `[APPROVED]`
|
|
140
|
+
- Assumption-like language without `[ASSUMPTION]` marker
|
|
141
|
+
|
|
142
|
+
## Risk Documentation
|
|
143
|
+
|
|
144
|
+
High-risk patterns MUST have explicit mitigation:
|
|
145
|
+
- Data deletion/modification → Backup strategy
|
|
146
|
+
- Production changes → Rollback plan
|
|
147
|
+
- Auth/security changes → Security review notes
|
|
148
|
+
- Schema migrations → Migration rollback steps
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Verification:**
|
|
152
|
+
- Enter plan mode, verify instructions appear in context
|
|
153
|
+
- Create plan without markers, verify they're requested
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Phase 2: Bash Validators
|
|
158
|
+
|
|
159
|
+
**Files to create:**
|
|
160
|
+
- `scripts/lib/section_validator.sh`
|
|
161
|
+
- `scripts/lib/marker_validator.sh`
|
|
162
|
+
- `scripts/lib/assumption_detector.sh`
|
|
163
|
+
- `scripts/lib/risk_detector.sh`
|
|
164
|
+
|
|
165
|
+
#### section_validator.sh
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
#!/bin/bash
|
|
169
|
+
# Validates required sections exist in plan
|
|
170
|
+
# Exit 0 = pass, Exit 1 = fail with errors on stderr
|
|
171
|
+
|
|
172
|
+
PLAN_FILE="$1"
|
|
173
|
+
errors=0
|
|
174
|
+
|
|
175
|
+
required_sections=(
|
|
176
|
+
"## Problem Statement"
|
|
177
|
+
"## Scope Definition"
|
|
178
|
+
"## Current.*State|## Current State"
|
|
179
|
+
"## Desired.*State|## Desired State"
|
|
180
|
+
"## Verification"
|
|
181
|
+
"## Risks"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
for pattern in "${required_sections[@]}"; do
|
|
185
|
+
if ! grep -qE "$pattern" "$PLAN_FILE"; then
|
|
186
|
+
echo "MISSING SECTION: $pattern" >&2
|
|
187
|
+
((errors++))
|
|
188
|
+
fi
|
|
189
|
+
done
|
|
190
|
+
|
|
191
|
+
exit $((errors > 0 ? 1 : 0))
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### marker_validator.sh
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
#!/bin/bash
|
|
198
|
+
# Validates marker syntax and approval status
|
|
199
|
+
# Exit 0 = pass, Exit 1 = warnings, Exit 2 = errors
|
|
200
|
+
|
|
201
|
+
PLAN_FILE="$1"
|
|
202
|
+
errors=0
|
|
203
|
+
warnings=0
|
|
204
|
+
|
|
205
|
+
# Find deferrals without approval
|
|
206
|
+
unapproved_deferrals=$(grep -n '\[DEFERRED\]' "$PLAN_FILE" | grep -v '\[APPROVED\]')
|
|
207
|
+
if [[ -n "$unapproved_deferrals" ]]; then
|
|
208
|
+
echo "UNAPPROVED DEFERRAL:" >&2
|
|
209
|
+
echo "$unapproved_deferrals" >&2
|
|
210
|
+
((errors++))
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
# Find assumptions without approval
|
|
214
|
+
unapproved_assumptions=$(grep -n '\[ASSUMPTION\]' "$PLAN_FILE" | grep -v '\[APPROVED\]')
|
|
215
|
+
if [[ -n "$unapproved_assumptions" ]]; then
|
|
216
|
+
echo "UNAPPROVED ASSUMPTION:" >&2
|
|
217
|
+
echo "$unapproved_assumptions" >&2
|
|
218
|
+
((errors++))
|
|
219
|
+
fi
|
|
220
|
+
|
|
221
|
+
# Check for TBD/placeholder items
|
|
222
|
+
tbd_items=$(grep -n -iE '\bTBD\b|\bTODO\b|\bPLACEHOLDER\b' "$PLAN_FILE")
|
|
223
|
+
if [[ -n "$tbd_items" ]]; then
|
|
224
|
+
echo "UNRESOLVED ITEMS:" >&2
|
|
225
|
+
echo "$tbd_items" >&2
|
|
226
|
+
((errors++))
|
|
227
|
+
fi
|
|
228
|
+
|
|
229
|
+
if [[ $errors -gt 0 ]]; then
|
|
230
|
+
exit 2
|
|
231
|
+
elif [[ $warnings -gt 0 ]]; then
|
|
232
|
+
exit 1
|
|
233
|
+
else
|
|
234
|
+
exit 0
|
|
235
|
+
fi
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### assumption_detector.sh
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
#!/bin/bash
|
|
242
|
+
# Detects assumption-like language without [ASSUMPTION] marker
|
|
243
|
+
|
|
244
|
+
PLAN_FILE="$1"
|
|
245
|
+
warnings=0
|
|
246
|
+
|
|
247
|
+
assumption_patterns=(
|
|
248
|
+
"assum[ei]"
|
|
249
|
+
"expect that"
|
|
250
|
+
"should be able"
|
|
251
|
+
"probably"
|
|
252
|
+
"likely"
|
|
253
|
+
"I believe"
|
|
254
|
+
"presumably"
|
|
255
|
+
"should work"
|
|
256
|
+
"will likely"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
for pattern in "${assumption_patterns[@]}"; do
|
|
260
|
+
matches=$(grep -in "$pattern" "$PLAN_FILE" | grep -v '\[ASSUMPTION\]')
|
|
261
|
+
if [[ -n "$matches" ]]; then
|
|
262
|
+
echo "UNMARKED ASSUMPTION LANGUAGE:" >&2
|
|
263
|
+
echo "$matches" >&2
|
|
264
|
+
((warnings++))
|
|
265
|
+
fi
|
|
266
|
+
done
|
|
267
|
+
|
|
268
|
+
exit $((warnings > 0 ? 1 : 0))
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
#### risk_detector.sh
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
#!/bin/bash
|
|
275
|
+
# Detects high-risk patterns and checks for mitigation
|
|
276
|
+
|
|
277
|
+
PLAN_FILE="$1"
|
|
278
|
+
warnings=0
|
|
279
|
+
|
|
280
|
+
declare -A risk_patterns=(
|
|
281
|
+
["DELETE|DROP|TRUNCATE|rm -rf|remove.*all"]="CRITICAL:destructive-operation"
|
|
282
|
+
["production|prod environment|live server"]="HIGH:production-impact"
|
|
283
|
+
["migration|schema change|ALTER TABLE|database change"]="HIGH:data-migration"
|
|
284
|
+
["auth|password|token|secret|credential|API.key"]="HIGH:security-sensitive"
|
|
285
|
+
["\.env|environment variable|config secret"]="HIGH:secrets-handling"
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
for pattern in "${!risk_patterns[@]}"; do
|
|
289
|
+
severity="${risk_patterns[$pattern]%:*}"
|
|
290
|
+
category="${risk_patterns[$pattern]#*:}"
|
|
291
|
+
|
|
292
|
+
if grep -qiE "$pattern" "$PLAN_FILE"; then
|
|
293
|
+
echo "RISK DETECTED [$severity]: $category" >&2
|
|
294
|
+
|
|
295
|
+
# Check for mitigation
|
|
296
|
+
if ! grep -qiE "mitigat|rollback|backup|revert|recover" "$PLAN_FILE"; then
|
|
297
|
+
echo " WARNING: No mitigation strategy found for $category" >&2
|
|
298
|
+
((warnings++))
|
|
299
|
+
fi
|
|
300
|
+
fi
|
|
301
|
+
done
|
|
302
|
+
|
|
303
|
+
exit $((warnings > 0 ? 1 : 0))
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Verification:**
|
|
307
|
+
- Run each validator against sample plans
|
|
308
|
+
- Verify correct exit codes and error messages
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
### Phase 3: Transcript Parser
|
|
313
|
+
|
|
314
|
+
**File to create:**
|
|
315
|
+
- `scripts/lib/transcript_parser.py`
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
#!/usr/bin/env python3
|
|
319
|
+
"""Extract user messages from session transcript for analysis."""
|
|
320
|
+
|
|
321
|
+
import json
|
|
322
|
+
import sys
|
|
323
|
+
from pathlib import Path
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def extract_user_messages(transcript_path: str, max_chars: int = 4000) -> str:
|
|
327
|
+
"""
|
|
328
|
+
Extract user messages from JSONL transcript.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
transcript_path: Path to session JSONL file
|
|
332
|
+
max_chars: Maximum characters to return (truncate from end)
|
|
333
|
+
|
|
334
|
+
Returns:
|
|
335
|
+
Concatenated user messages, most recent last
|
|
336
|
+
"""
|
|
337
|
+
messages = []
|
|
338
|
+
|
|
339
|
+
try:
|
|
340
|
+
with open(transcript_path) as f:
|
|
341
|
+
for line in f:
|
|
342
|
+
try:
|
|
343
|
+
entry = json.loads(line)
|
|
344
|
+
if entry.get("type") == "user":
|
|
345
|
+
msg = entry.get("message", "")
|
|
346
|
+
if msg:
|
|
347
|
+
messages.append(msg)
|
|
348
|
+
except json.JSONDecodeError:
|
|
349
|
+
continue
|
|
350
|
+
except (OSError, IOError) as e:
|
|
351
|
+
print(f"Error reading transcript: {e}", file=sys.stderr)
|
|
352
|
+
return ""
|
|
353
|
+
|
|
354
|
+
combined = "\n---\n".join(messages)
|
|
355
|
+
|
|
356
|
+
# Truncate from beginning if too long (keep recent messages)
|
|
357
|
+
if len(combined) > max_chars:
|
|
358
|
+
combined = "...[truncated]...\n" + combined[-max_chars:]
|
|
359
|
+
|
|
360
|
+
return combined
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def extract_requirements(transcript_path: str) -> list[str]:
|
|
364
|
+
"""
|
|
365
|
+
Extract likely requirements from user messages.
|
|
366
|
+
|
|
367
|
+
Heuristic: Lines that look like requirements (imperative, bullet points, etc.)
|
|
368
|
+
"""
|
|
369
|
+
messages = extract_user_messages(transcript_path, max_chars=10000)
|
|
370
|
+
requirements = []
|
|
371
|
+
|
|
372
|
+
for line in messages.split("\n"):
|
|
373
|
+
line = line.strip()
|
|
374
|
+
# Heuristic patterns for requirements
|
|
375
|
+
if any([
|
|
376
|
+
line.startswith("- "),
|
|
377
|
+
line.startswith("* "),
|
|
378
|
+
line.startswith("1.") or line.startswith("2."),
|
|
379
|
+
"should" in line.lower(),
|
|
380
|
+
"must" in line.lower(),
|
|
381
|
+
"need" in line.lower(),
|
|
382
|
+
"want" in line.lower(),
|
|
383
|
+
]):
|
|
384
|
+
requirements.append(line)
|
|
385
|
+
|
|
386
|
+
return requirements
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
if __name__ == "__main__":
|
|
390
|
+
if len(sys.argv) < 2:
|
|
391
|
+
print("Usage: transcript_parser.py <transcript_path>", file=sys.stderr)
|
|
392
|
+
sys.exit(1)
|
|
393
|
+
|
|
394
|
+
print(extract_user_messages(sys.argv[1]))
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
**Verification:**
|
|
398
|
+
- Run against actual session transcript
|
|
399
|
+
- Verify user messages extracted correctly
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### Phase 4: Opus Analyzer
|
|
404
|
+
|
|
405
|
+
**File to create:**
|
|
406
|
+
- `scripts/lib/opus_analyzer.py`
|
|
407
|
+
|
|
408
|
+
```python
|
|
409
|
+
#!/usr/bin/env python3
|
|
410
|
+
"""
|
|
411
|
+
Opus-based semantic analysis of implementation plans.
|
|
412
|
+
|
|
413
|
+
Analyzes plan against transcript and tasks for:
|
|
414
|
+
- Requirement coverage
|
|
415
|
+
- Assumption audit
|
|
416
|
+
- Gap detection
|
|
417
|
+
- Task coverage matrix
|
|
418
|
+
- Risk assessment
|
|
419
|
+
"""
|
|
420
|
+
|
|
421
|
+
import json
|
|
422
|
+
import subprocess
|
|
423
|
+
import sys
|
|
424
|
+
from pathlib import Path
|
|
425
|
+
from dataclasses import dataclass
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
@dataclass
|
|
429
|
+
class AnalysisResult:
|
|
430
|
+
requirements: list[dict] # {req, status, location}
|
|
431
|
+
assumptions: list[dict] # {text, marked, approved}
|
|
432
|
+
gaps: list[str]
|
|
433
|
+
ambiguities: list[str]
|
|
434
|
+
task_coverage: dict # {plan_item: task_or_uncovered}
|
|
435
|
+
risks: list[dict] # {risk, severity, mitigation}
|
|
436
|
+
raw_response: str
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
OPUS_PROMPT = '''You are an implementation plan auditor. Analyze the provided data and report findings.
|
|
440
|
+
|
|
441
|
+
## INPUT DATA
|
|
442
|
+
|
|
443
|
+
### User's Original Messages (from session transcript):
|
|
444
|
+
"""
|
|
445
|
+
{user_messages}
|
|
446
|
+
"""
|
|
447
|
+
|
|
448
|
+
### The Implementation Plan:
|
|
449
|
+
"""
|
|
450
|
+
{plan_content}
|
|
451
|
+
"""
|
|
452
|
+
|
|
453
|
+
### Current Task List (if any):
|
|
454
|
+
"""
|
|
455
|
+
{task_json}
|
|
456
|
+
"""
|
|
457
|
+
|
|
458
|
+
## ANALYSIS REQUIRED
|
|
459
|
+
|
|
460
|
+
Respond in this exact format:
|
|
461
|
+
|
|
462
|
+
### REQUIREMENTS
|
|
463
|
+
For each user requirement identified:
|
|
464
|
+
REQ: [requirement text]
|
|
465
|
+
STATUS: ADDRESSED | PARTIAL | MISSING
|
|
466
|
+
LOCATION: [section in plan, or "not found"]
|
|
467
|
+
|
|
468
|
+
### ASSUMPTIONS
|
|
469
|
+
For each assumption (explicit or implicit):
|
|
470
|
+
ASSUMPTION: [text]
|
|
471
|
+
MARKED: YES | NO
|
|
472
|
+
APPROVED: YES | NO
|
|
473
|
+
|
|
474
|
+
### GAPS
|
|
475
|
+
GAP: [what's missing or could fail]
|
|
476
|
+
|
|
477
|
+
### AMBIGUITIES
|
|
478
|
+
AMBIGUITY: [what's unclear or has multiple interpretations]
|
|
479
|
+
|
|
480
|
+
### TASK_COVERAGE
|
|
481
|
+
PLAN_ITEM: [phase/step from plan]
|
|
482
|
+
COVERED_BY: [task subject] | UNCOVERED
|
|
483
|
+
|
|
484
|
+
COVERAGE_SCORE: X/Y
|
|
485
|
+
|
|
486
|
+
### RISKS
|
|
487
|
+
RISK: [pattern or concern]
|
|
488
|
+
SEVERITY: CRITICAL | HIGH | MEDIUM
|
|
489
|
+
MITIGATION: PRESENT | MISSING
|
|
490
|
+
|
|
491
|
+
## RULES
|
|
492
|
+
- Be terse. No explanations unless critical.
|
|
493
|
+
- Flag only issues, not successes (except for REQUIREMENTS status).
|
|
494
|
+
- If task list is empty, skip TASK_COVERAGE section.
|
|
495
|
+
'''
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def run_opus_analysis(
|
|
499
|
+
plan_content: str,
|
|
500
|
+
user_messages: str,
|
|
501
|
+
task_json: str = "[]",
|
|
502
|
+
timeout: int = 60
|
|
503
|
+
) -> AnalysisResult:
|
|
504
|
+
"""
|
|
505
|
+
Run Opus analysis on plan.
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
plan_content: The implementation plan markdown
|
|
509
|
+
user_messages: Extracted user messages from transcript
|
|
510
|
+
task_json: JSON string of current tasks
|
|
511
|
+
timeout: Max seconds to wait for response
|
|
512
|
+
|
|
513
|
+
Returns:
|
|
514
|
+
AnalysisResult with parsed findings
|
|
515
|
+
"""
|
|
516
|
+
prompt = OPUS_PROMPT.format(
|
|
517
|
+
user_messages=user_messages,
|
|
518
|
+
plan_content=plan_content,
|
|
519
|
+
task_json=task_json
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
try:
|
|
523
|
+
# Call Claude CLI in headless mode
|
|
524
|
+
result = subprocess.run(
|
|
525
|
+
["claude", "--print", "--model", "opus", "-p", prompt],
|
|
526
|
+
capture_output=True,
|
|
527
|
+
text=True,
|
|
528
|
+
timeout=timeout
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
if result.returncode != 0:
|
|
532
|
+
raise RuntimeError(f"Claude CLI error: {result.stderr}")
|
|
533
|
+
|
|
534
|
+
response = result.stdout.strip()
|
|
535
|
+
return parse_opus_response(response)
|
|
536
|
+
|
|
537
|
+
except subprocess.TimeoutExpired:
|
|
538
|
+
raise RuntimeError("Opus analysis timed out")
|
|
539
|
+
except FileNotFoundError:
|
|
540
|
+
raise RuntimeError("Claude CLI not found")
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
def parse_opus_response(response: str) -> AnalysisResult:
|
|
544
|
+
"""Parse structured Opus response into AnalysisResult."""
|
|
545
|
+
|
|
546
|
+
# Initialize result containers
|
|
547
|
+
requirements = []
|
|
548
|
+
assumptions = []
|
|
549
|
+
gaps = []
|
|
550
|
+
ambiguities = []
|
|
551
|
+
task_coverage = {}
|
|
552
|
+
risks = []
|
|
553
|
+
|
|
554
|
+
current_section = None
|
|
555
|
+
current_item = {}
|
|
556
|
+
|
|
557
|
+
for line in response.split("\n"):
|
|
558
|
+
line = line.strip()
|
|
559
|
+
|
|
560
|
+
# Section headers
|
|
561
|
+
if line.startswith("### "):
|
|
562
|
+
current_section = line[4:].upper()
|
|
563
|
+
continue
|
|
564
|
+
|
|
565
|
+
# Parse based on current section
|
|
566
|
+
if current_section == "REQUIREMENTS":
|
|
567
|
+
if line.startswith("REQ:"):
|
|
568
|
+
if current_item:
|
|
569
|
+
requirements.append(current_item)
|
|
570
|
+
current_item = {"req": line[4:].strip()}
|
|
571
|
+
elif line.startswith("STATUS:"):
|
|
572
|
+
current_item["status"] = line[7:].strip()
|
|
573
|
+
elif line.startswith("LOCATION:"):
|
|
574
|
+
current_item["location"] = line[9:].strip()
|
|
575
|
+
requirements.append(current_item)
|
|
576
|
+
current_item = {}
|
|
577
|
+
|
|
578
|
+
elif current_section == "ASSUMPTIONS":
|
|
579
|
+
if line.startswith("ASSUMPTION:"):
|
|
580
|
+
if current_item:
|
|
581
|
+
assumptions.append(current_item)
|
|
582
|
+
current_item = {"text": line[11:].strip()}
|
|
583
|
+
elif line.startswith("MARKED:"):
|
|
584
|
+
current_item["marked"] = line[7:].strip() == "YES"
|
|
585
|
+
elif line.startswith("APPROVED:"):
|
|
586
|
+
current_item["approved"] = line[9:].strip() == "YES"
|
|
587
|
+
assumptions.append(current_item)
|
|
588
|
+
current_item = {}
|
|
589
|
+
|
|
590
|
+
elif current_section == "GAPS":
|
|
591
|
+
if line.startswith("GAP:"):
|
|
592
|
+
gaps.append(line[4:].strip())
|
|
593
|
+
|
|
594
|
+
elif current_section == "AMBIGUITIES":
|
|
595
|
+
if line.startswith("AMBIGUITY:"):
|
|
596
|
+
ambiguities.append(line[10:].strip())
|
|
597
|
+
|
|
598
|
+
elif current_section == "TASK_COVERAGE":
|
|
599
|
+
if line.startswith("PLAN_ITEM:"):
|
|
600
|
+
current_item = {"plan_item": line[10:].strip()}
|
|
601
|
+
elif line.startswith("COVERED_BY:"):
|
|
602
|
+
current_item["covered_by"] = line[11:].strip()
|
|
603
|
+
task_coverage[current_item["plan_item"]] = current_item["covered_by"]
|
|
604
|
+
current_item = {}
|
|
605
|
+
|
|
606
|
+
elif current_section == "RISKS":
|
|
607
|
+
if line.startswith("RISK:"):
|
|
608
|
+
if current_item:
|
|
609
|
+
risks.append(current_item)
|
|
610
|
+
current_item = {"risk": line[5:].strip()}
|
|
611
|
+
elif line.startswith("SEVERITY:"):
|
|
612
|
+
current_item["severity"] = line[9:].strip()
|
|
613
|
+
elif line.startswith("MITIGATION:"):
|
|
614
|
+
current_item["mitigation"] = line[11:].strip()
|
|
615
|
+
risks.append(current_item)
|
|
616
|
+
current_item = {}
|
|
617
|
+
|
|
618
|
+
return AnalysisResult(
|
|
619
|
+
requirements=requirements,
|
|
620
|
+
assumptions=assumptions,
|
|
621
|
+
gaps=gaps,
|
|
622
|
+
ambiguities=ambiguities,
|
|
623
|
+
task_coverage=task_coverage,
|
|
624
|
+
risks=risks,
|
|
625
|
+
raw_response=response
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
def format_findings(result: AnalysisResult) -> str:
|
|
630
|
+
"""Format analysis results for additionalContext."""
|
|
631
|
+
|
|
632
|
+
lines = ["--- Opus Plan Analysis ---"]
|
|
633
|
+
|
|
634
|
+
# Requirements
|
|
635
|
+
missing = [r for r in result.requirements if r.get("status") == "MISSING"]
|
|
636
|
+
partial = [r for r in result.requirements if r.get("status") == "PARTIAL"]
|
|
637
|
+
if missing:
|
|
638
|
+
lines.append(f"\nMISSING REQUIREMENTS ({len(missing)}):")
|
|
639
|
+
for r in missing:
|
|
640
|
+
lines.append(f" - {r['req']}")
|
|
641
|
+
if partial:
|
|
642
|
+
lines.append(f"\nPARTIAL REQUIREMENTS ({len(partial)}):")
|
|
643
|
+
for r in partial:
|
|
644
|
+
lines.append(f" - {r['req']} (at: {r.get('location', '?')})")
|
|
645
|
+
|
|
646
|
+
# Assumptions
|
|
647
|
+
unmarked = [a for a in result.assumptions if not a.get("marked")]
|
|
648
|
+
unapproved = [a for a in result.assumptions if a.get("marked") and not a.get("approved")]
|
|
649
|
+
if unmarked:
|
|
650
|
+
lines.append(f"\nUNMARKED ASSUMPTIONS ({len(unmarked)}):")
|
|
651
|
+
for a in unmarked:
|
|
652
|
+
lines.append(f" - {a['text']}")
|
|
653
|
+
if unapproved:
|
|
654
|
+
lines.append(f"\nUNAPPROVED ASSUMPTIONS ({len(unapproved)}):")
|
|
655
|
+
for a in unapproved:
|
|
656
|
+
lines.append(f" - {a['text']}")
|
|
657
|
+
|
|
658
|
+
# Gaps
|
|
659
|
+
if result.gaps:
|
|
660
|
+
lines.append(f"\nGAPS ({len(result.gaps)}):")
|
|
661
|
+
for g in result.gaps:
|
|
662
|
+
lines.append(f" - {g}")
|
|
663
|
+
|
|
664
|
+
# Ambiguities
|
|
665
|
+
if result.ambiguities:
|
|
666
|
+
lines.append(f"\nAMBIGUITIES ({len(result.ambiguities)}):")
|
|
667
|
+
for a in result.ambiguities:
|
|
668
|
+
lines.append(f" - {a}")
|
|
669
|
+
|
|
670
|
+
# Task coverage
|
|
671
|
+
uncovered = [k for k, v in result.task_coverage.items() if v == "UNCOVERED"]
|
|
672
|
+
if uncovered:
|
|
673
|
+
lines.append(f"\nUNCOVERED PLAN ITEMS ({len(uncovered)}):")
|
|
674
|
+
for item in uncovered:
|
|
675
|
+
lines.append(f" - {item}")
|
|
676
|
+
|
|
677
|
+
# Risks
|
|
678
|
+
critical = [r for r in result.risks if r.get("severity") == "CRITICAL"]
|
|
679
|
+
high_no_mitigation = [r for r in result.risks
|
|
680
|
+
if r.get("severity") == "HIGH" and r.get("mitigation") == "MISSING"]
|
|
681
|
+
if critical:
|
|
682
|
+
lines.append(f"\nCRITICAL RISKS ({len(critical)}):")
|
|
683
|
+
for r in critical:
|
|
684
|
+
lines.append(f" - {r['risk']} (mitigation: {r.get('mitigation', '?')})")
|
|
685
|
+
if high_no_mitigation:
|
|
686
|
+
lines.append(f"\nHIGH RISKS WITHOUT MITIGATION ({len(high_no_mitigation)}):")
|
|
687
|
+
for r in high_no_mitigation:
|
|
688
|
+
lines.append(f" - {r['risk']}")
|
|
689
|
+
|
|
690
|
+
lines.append("\n--- End Opus Analysis ---")
|
|
691
|
+
|
|
692
|
+
return "\n".join(lines)
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
if __name__ == "__main__":
|
|
696
|
+
# Test with sample data
|
|
697
|
+
print("Opus analyzer module loaded. Use run_opus_analysis() to analyze plans.")
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
**Verification:**
|
|
701
|
+
- Test with sample plan, transcript, and tasks
|
|
702
|
+
- Verify Claude CLI invocation works
|
|
703
|
+
- Verify response parsing handles edge cases
|
|
704
|
+
|
|
705
|
+
---
|
|
706
|
+
|
|
707
|
+
### Phase 5: Sonnet Verifier
|
|
708
|
+
|
|
709
|
+
**File to create:**
|
|
710
|
+
- `scripts/lib/sonnet_verifier.py`
|
|
711
|
+
|
|
712
|
+
```python
|
|
713
|
+
#!/usr/bin/env python3
|
|
714
|
+
"""
|
|
715
|
+
Sonnet-based verification of implementation plans.
|
|
716
|
+
|
|
717
|
+
Verifies claims in the plan against actual codebase:
|
|
718
|
+
- File paths exist/don't exist as expected
|
|
719
|
+
- Proposed changes align with existing patterns
|
|
720
|
+
- No conflicts with existing code
|
|
721
|
+
- Security concerns addressed
|
|
722
|
+
"""
|
|
723
|
+
|
|
724
|
+
import subprocess
|
|
725
|
+
import sys
|
|
726
|
+
from dataclasses import dataclass
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
@dataclass
|
|
730
|
+
class VerificationResult:
|
|
731
|
+
verified: list[str]
|
|
732
|
+
conflicts: list[str]
|
|
733
|
+
missing: list[str]
|
|
734
|
+
security: list[str]
|
|
735
|
+
raw_response: str
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
SONNET_PROMPT = '''You are verifying an implementation plan against the actual codebase.
|
|
739
|
+
|
|
740
|
+
## Context from Opus Analysis
|
|
741
|
+
{opus_summary}
|
|
742
|
+
|
|
743
|
+
## Plan Being Verified
|
|
744
|
+
"""
|
|
745
|
+
{plan_content}
|
|
746
|
+
"""
|
|
747
|
+
|
|
748
|
+
## Your Tasks
|
|
749
|
+
|
|
750
|
+
1. **File Verification**: For each file path mentioned in the plan:
|
|
751
|
+
- Use Read tool to check if it exists
|
|
752
|
+
- Verify described current state matches reality
|
|
753
|
+
|
|
754
|
+
2. **Pattern Alignment**: For proposed changes:
|
|
755
|
+
- Read similar existing code (max 3 files)
|
|
756
|
+
- Confirm approach matches codebase conventions
|
|
757
|
+
|
|
758
|
+
3. **Conflict Detection**: Check if changes would conflict with:
|
|
759
|
+
- Existing functionality in mentioned files
|
|
760
|
+
|
|
761
|
+
4. **Security Spot-Check**: For any auth/data/API changes:
|
|
762
|
+
- Note any security concerns
|
|
763
|
+
|
|
764
|
+
## Rules
|
|
765
|
+
- Maximum 5 file reads total
|
|
766
|
+
- Focus on CRITICAL and HIGH items from Opus analysis first
|
|
767
|
+
- Skip verification for low-risk items
|
|
768
|
+
|
|
769
|
+
## Output Format (use exactly these tags)
|
|
770
|
+
[VERIFIED] item - checks out
|
|
771
|
+
[CONFLICT] item - issue description
|
|
772
|
+
[MISSING] item - file or pattern not found
|
|
773
|
+
[SECURITY] item - concern description
|
|
774
|
+
'''
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
def run_sonnet_verification(
|
|
778
|
+
plan_content: str,
|
|
779
|
+
opus_summary: str,
|
|
780
|
+
max_turns: int = 5,
|
|
781
|
+
timeout: int = 120
|
|
782
|
+
) -> VerificationResult:
|
|
783
|
+
"""
|
|
784
|
+
Run Sonnet verification on plan.
|
|
785
|
+
|
|
786
|
+
Args:
|
|
787
|
+
plan_content: The implementation plan markdown
|
|
788
|
+
opus_summary: Summary of Opus findings to focus verification
|
|
789
|
+
max_turns: Maximum conversation turns (file reads)
|
|
790
|
+
timeout: Max seconds to wait
|
|
791
|
+
|
|
792
|
+
Returns:
|
|
793
|
+
VerificationResult with parsed findings
|
|
794
|
+
"""
|
|
795
|
+
prompt = SONNET_PROMPT.format(
|
|
796
|
+
opus_summary=opus_summary,
|
|
797
|
+
plan_content=plan_content
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
try:
|
|
801
|
+
# Call Claude CLI with Sonnet, allowing some turns for file reads
|
|
802
|
+
result = subprocess.run(
|
|
803
|
+
["claude", "--print", "--model", "sonnet",
|
|
804
|
+
"--max-turns", str(max_turns), "-p", prompt],
|
|
805
|
+
capture_output=True,
|
|
806
|
+
text=True,
|
|
807
|
+
timeout=timeout
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
if result.returncode != 0:
|
|
811
|
+
raise RuntimeError(f"Claude CLI error: {result.stderr}")
|
|
812
|
+
|
|
813
|
+
response = result.stdout.strip()
|
|
814
|
+
return parse_sonnet_response(response)
|
|
815
|
+
|
|
816
|
+
except subprocess.TimeoutExpired:
|
|
817
|
+
raise RuntimeError("Sonnet verification timed out")
|
|
818
|
+
except FileNotFoundError:
|
|
819
|
+
raise RuntimeError("Claude CLI not found")
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def parse_sonnet_response(response: str) -> VerificationResult:
|
|
823
|
+
"""Parse Sonnet response into VerificationResult."""
|
|
824
|
+
|
|
825
|
+
verified = []
|
|
826
|
+
conflicts = []
|
|
827
|
+
missing = []
|
|
828
|
+
security = []
|
|
829
|
+
|
|
830
|
+
for line in response.split("\n"):
|
|
831
|
+
line = line.strip()
|
|
832
|
+
if line.startswith("[VERIFIED]"):
|
|
833
|
+
verified.append(line[10:].strip())
|
|
834
|
+
elif line.startswith("[CONFLICT]"):
|
|
835
|
+
conflicts.append(line[10:].strip())
|
|
836
|
+
elif line.startswith("[MISSING]"):
|
|
837
|
+
missing.append(line[9:].strip())
|
|
838
|
+
elif line.startswith("[SECURITY]"):
|
|
839
|
+
security.append(line[10:].strip())
|
|
840
|
+
|
|
841
|
+
return VerificationResult(
|
|
842
|
+
verified=verified,
|
|
843
|
+
conflicts=conflicts,
|
|
844
|
+
missing=missing,
|
|
845
|
+
security=security,
|
|
846
|
+
raw_response=response
|
|
847
|
+
)
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
def format_verification(result: VerificationResult) -> str:
|
|
851
|
+
"""Format verification results for additionalContext."""
|
|
852
|
+
|
|
853
|
+
lines = ["--- Sonnet Verification ---"]
|
|
854
|
+
|
|
855
|
+
if result.conflicts:
|
|
856
|
+
lines.append(f"\nCONFLICTS ({len(result.conflicts)}):")
|
|
857
|
+
for c in result.conflicts:
|
|
858
|
+
lines.append(f" - {c}")
|
|
859
|
+
|
|
860
|
+
if result.missing:
|
|
861
|
+
lines.append(f"\nMISSING ({len(result.missing)}):")
|
|
862
|
+
for m in result.missing:
|
|
863
|
+
lines.append(f" - {m}")
|
|
864
|
+
|
|
865
|
+
if result.security:
|
|
866
|
+
lines.append(f"\nSECURITY CONCERNS ({len(result.security)}):")
|
|
867
|
+
for s in result.security:
|
|
868
|
+
lines.append(f" - {s}")
|
|
869
|
+
|
|
870
|
+
if result.verified and not (result.conflicts or result.missing or result.security):
|
|
871
|
+
lines.append(f"\nAll {len(result.verified)} items verified successfully.")
|
|
872
|
+
|
|
873
|
+
lines.append("\n--- End Verification ---")
|
|
874
|
+
|
|
875
|
+
return "\n".join(lines)
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
if __name__ == "__main__":
|
|
879
|
+
print("Sonnet verifier module loaded. Use run_sonnet_verification() to verify plans.")
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
**Verification:**
|
|
883
|
+
- Test with plan containing file references
|
|
884
|
+
- Verify file reads work within turn limit
|
|
885
|
+
- Verify response parsing
|
|
886
|
+
|
|
887
|
+
---
|
|
888
|
+
|
|
889
|
+
### Phase 6: Orchestrator Update
|
|
890
|
+
|
|
891
|
+
**File to modify:**
|
|
892
|
+
- `scripts/post-enhance-plan.py`
|
|
893
|
+
|
|
894
|
+
**Changes:**
|
|
895
|
+
1. Import new modules
|
|
896
|
+
2. Add orchestration logic for three-layer validation
|
|
897
|
+
3. Aggregate results into additionalContext
|
|
898
|
+
|
|
899
|
+
```python
|
|
900
|
+
# New orchestration flow (pseudocode)
|
|
901
|
+
|
|
902
|
+
def handle_plan_write(plan_path, transcript_path, cwd, session_id):
|
|
903
|
+
plan_content = read_file(plan_path)
|
|
904
|
+
results = []
|
|
905
|
+
|
|
906
|
+
# Layer 1: Bash validators
|
|
907
|
+
bash_results = run_bash_validators(plan_path)
|
|
908
|
+
if bash_results.has_errors:
|
|
909
|
+
return format_bash_errors(bash_results)
|
|
910
|
+
results.append(bash_results)
|
|
911
|
+
|
|
912
|
+
# Layer 2: Opus analysis
|
|
913
|
+
user_messages = extract_user_messages(transcript_path)
|
|
914
|
+
task_json = get_task_json(session_id)
|
|
915
|
+
|
|
916
|
+
opus_result = run_opus_analysis(plan_content, user_messages, task_json)
|
|
917
|
+
results.append(opus_result)
|
|
918
|
+
|
|
919
|
+
# Layer 3: Sonnet verification (conditional)
|
|
920
|
+
needs_verification = (
|
|
921
|
+
opus_result.has_critical_risks or
|
|
922
|
+
opus_result.has_missing_requirements or
|
|
923
|
+
bash_results.risk_keywords_found
|
|
924
|
+
)
|
|
925
|
+
|
|
926
|
+
if needs_verification:
|
|
927
|
+
sonnet_result = run_sonnet_verification(
|
|
928
|
+
plan_content,
|
|
929
|
+
summarize_opus_findings(opus_result)
|
|
930
|
+
)
|
|
931
|
+
results.append(sonnet_result)
|
|
932
|
+
|
|
933
|
+
return format_all_results(results)
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
**Verification:**
|
|
937
|
+
- End-to-end test with plan creation
|
|
938
|
+
- Verify all layers execute in correct order
|
|
939
|
+
- Verify conditional Sonnet invocation
|
|
940
|
+
|
|
941
|
+
---
|
|
942
|
+
|
|
943
|
+
## Files to Create/Modify
|
|
944
|
+
|
|
945
|
+
| File | Action | Description |
|
|
946
|
+
|------|--------|-------------|
|
|
947
|
+
| `config/planning-instructions.md` | Modify | Add marker requirements, section template |
|
|
948
|
+
| `scripts/lib/section_validator.sh` | Create | Validate required sections |
|
|
949
|
+
| `scripts/lib/marker_validator.sh` | Create | Validate marker syntax |
|
|
950
|
+
| `scripts/lib/assumption_detector.sh` | Create | Detect unmarked assumptions |
|
|
951
|
+
| `scripts/lib/risk_detector.sh` | Create | Detect risks, check mitigation |
|
|
952
|
+
| `scripts/lib/transcript_parser.py` | Create | Extract user messages from JSONL |
|
|
953
|
+
| `scripts/lib/opus_analyzer.py` | Create | Opus semantic analysis |
|
|
954
|
+
| `scripts/lib/sonnet_verifier.py` | Create | Sonnet file verification |
|
|
955
|
+
| `scripts/post-enhance-plan.py` | Modify | Orchestrate three-layer validation |
|
|
956
|
+
|
|
957
|
+
## Risks and Mitigations
|
|
958
|
+
|
|
959
|
+
| Risk | Severity | Mitigation |
|
|
960
|
+
|------|----------|------------|
|
|
961
|
+
| Claude CLI syntax differs from assumed | HIGH | Verify CLI flags before implementation |
|
|
962
|
+
| Token costs exceed budget | MEDIUM | Add cost caps, skip Sonnet for low-risk |
|
|
963
|
+
| Opus/Sonnet timeout on complex plans | MEDIUM | Set reasonable timeouts, fallback to bash-only |
|
|
964
|
+
| Response parsing fails on edge cases | MEDIUM | Add robust error handling, log raw responses |
|
|
965
|
+
| False positives annoy users | MEDIUM | Tune prompts, add severity thresholds |
|
|
966
|
+
|
|
967
|
+
## Verification Checklist
|
|
968
|
+
|
|
969
|
+
- [ ] Planning instructions injection works
|
|
970
|
+
- [ ] Each bash validator runs independently
|
|
971
|
+
- [ ] Transcript parser extracts messages correctly
|
|
972
|
+
- [ ] Opus analyzer produces structured output
|
|
973
|
+
- [ ] Sonnet verifier respects turn limits
|
|
974
|
+
- [ ] Orchestrator chains all layers correctly
|
|
975
|
+
- [ ] additionalContext returned to Claude
|
|
976
|
+
- [ ] End-to-end: Create plan, see validation results
|
|
977
|
+
|
|
978
|
+
## Dependencies
|
|
979
|
+
|
|
980
|
+
- Claude CLI with headless mode support
|
|
981
|
+
- `jq` for JSON parsing in bash scripts
|
|
982
|
+
- Python 3.10+ for type hints
|
|
983
|
+
- Session transcript accessible via `transcript_path`
|
|
984
|
+
|
|
985
|
+
## Open Questions
|
|
986
|
+
|
|
987
|
+
1. **Claude CLI flags**: Need to verify exact syntax for `--model`, `--print`, `--max-turns`
|
|
988
|
+
2. **Cost thresholds**: At what risk level should Sonnet verification trigger?
|
|
989
|
+
3. **Blocking vs warning**: Should critical issues block plan approval or just warn?
|