@dtlabs/ai-toolkit 0.1.7 → 0.2.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/.claude/agents/define-feature.md +1 -0
- package/.claude/agents/dependency-injection-refactoring.md +1 -0
- package/.claude/agents/dependency-supply-chain-security.md +1 -0
- package/.claude/agents/developer-backend.md +1 -0
- package/.claude/agents/developer-frontend.md +1 -0
- package/.claude/agents/developer-testing.md +1 -0
- package/.claude/agents/domain-model-refactoring.md +1 -0
- package/.claude/agents/god-class-decomposition.md +1 -0
- package/.claude/agents/init-agents-md.md +1 -0
- package/.claude/agents/install-toolkit.md +134 -3
- package/.claude/agents/intervention-documentation-standard.md +1 -0
- package/.claude/agents/review-solution.md +1 -0
- package/.claude/agents/security-hardening.md +1 -0
- package/.claude/settings.json +5 -0
- package/.claude/skills/assess-codebase/SKILL.md +139 -60
- package/.claude/skills/implement-feature/SKILL.md +208 -26
- package/.claude/workflows/am-phase1.js +304 -0
- package/.claude/workflows/am-phase2.js +166 -0
- package/.claude/workflows/pm-phase1.js +163 -0
- package/.claude/workflows/pm-phase2.js +108 -0
- package/.claude/workflows/pm-phase3.js +309 -0
- package/CHANGELOG.md +21 -0
- package/README.md +26 -0
- package/bin/cli.js +64 -5
- package/docs/token-optimization-backlog.md +115 -0
- package/docs/token-optimization.md +274 -0
- package/package.json +1 -1
- package/.claude/agents/assessment-manager.md +0 -672
- package/.claude/agents/project-manager.md +0 -309
|
@@ -5,65 +5,247 @@ argument-hint: <path-to-feature.md> [--force]
|
|
|
5
5
|
|
|
6
6
|
# Implement Feature
|
|
7
7
|
|
|
8
|
-
Orchestrates the full feature delivery pipeline by
|
|
9
|
-
|
|
8
|
+
Orchestrates the full feature delivery pipeline by invoking three sequential workflow phases
|
|
9
|
+
(`pm-phase1`, `pm-phase2`, `pm-phase3`), handling approval gates in the main loop between
|
|
10
|
+
each phase, and recording the real token consumption at the end.
|
|
11
|
+
|
|
12
|
+
Each workflow phase runs as a real subagent boundary, ensuring worker agents are dispatched
|
|
13
|
+
with their declared `model:` frontmatter honoured and producing accurate per-agent `usage` data.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Step 1 — Invoke pm-phase1 (Documentation Phase)
|
|
18
|
+
|
|
19
|
+
Invoke the `pm-phase1` workflow with the feature path:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
subagent_type: pm-phase1
|
|
23
|
+
prompt: <path-to-feature.md>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Wait for the workflow to complete. Do NOT proceed until it returns.
|
|
27
|
+
|
|
28
|
+
Extract from the result:
|
|
29
|
+
- `prefix` — feature prefix (e.g. `FTR-009`)
|
|
30
|
+
- `requirements.summary` — requirements file summary
|
|
31
|
+
- `tech_spec.summary` — tech-spec file summary
|
|
32
|
+
- `validation.summary` — validation result (gaps or clean)
|
|
33
|
+
- `token_ledger` — array of per-agent token data from phase 1
|
|
34
|
+
- `errors` — any agent failures during phase 1
|
|
35
|
+
|
|
36
|
+
If `errors` is non-empty, report them to the user but continue to Gate 1 if the
|
|
37
|
+
required documents were produced.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Step 2 — Present Gate 1 (HARD STOP — present in main loop)
|
|
42
|
+
|
|
43
|
+
Present the following to the user:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
Documents generated for {PREFIX}:
|
|
47
|
+
|
|
48
|
+
{PREFIX}-Requirements.md — {requirements.summary}
|
|
49
|
+
{PREFIX}-Tech-Spec.md — {tech_spec.summary}
|
|
50
|
+
{PREFIX}-Validation-Report.md — {validation.summary}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Then output this hard-stop message and **wait for a text reply from the user**:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
⛔ GATE 1 — DOCS APPROVAL — HARD STOP
|
|
57
|
+
|
|
58
|
+
Please review the documents above and reply with one of:
|
|
59
|
+
|
|
60
|
+
"Approve — proceed to Work Breakdown"
|
|
61
|
+
"Request changes: <describe what to change>"
|
|
62
|
+
"Approve with notes: <your comments>"
|
|
63
|
+
|
|
64
|
+
The pipeline CANNOT continue until you reply directly.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**If the user requests changes:** note them and stop. Do not invoke pm-phase2.
|
|
68
|
+
|
|
69
|
+
**If the user approves:** immediately write `{PREFIX}-Approvals.md`:
|
|
70
|
+
|
|
71
|
+
```markdown
|
|
72
|
+
# Approval Record — {PREFIX}
|
|
73
|
+
|
|
74
|
+
## Gate 1 — Document Approvals
|
|
75
|
+
|
|
76
|
+
| Document | Status | Date | Notes |
|
|
77
|
+
|----------|--------|------|-------|
|
|
78
|
+
| {PREFIX}-Requirements.md | ✅ Approved | {today} | {notes or —} |
|
|
79
|
+
| {PREFIX}-Tech-Spec.md | ✅ Approved | {today} | {notes or —} |
|
|
80
|
+
| {PREFIX}-Validation-Report.md | ✅ Approved | {today} | {notes or —} |
|
|
81
|
+
|
|
82
|
+
## Approval History
|
|
83
|
+
|
|
84
|
+
| Cycle | Action | Date | Details |
|
|
85
|
+
|-------|--------|------|---------|
|
|
86
|
+
| 1 | Approved | {today} | {user reply text} |
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Read back `{PREFIX}-Approvals.md` and verify it exists with Gate 1 ✅ before continuing.
|
|
90
|
+
If the file is missing or incomplete, write it again before proceeding.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Step 3 — Invoke pm-phase2 (Work Breakdown Phase)
|
|
95
|
+
|
|
96
|
+
Invoke the `pm-phase2` workflow:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
subagent_type: pm-phase2
|
|
100
|
+
prompt: <path-to-feature.md>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Wait for the workflow to complete. Extract from the result:
|
|
104
|
+
- `user_stories` — number of User Stories
|
|
105
|
+
- `total_tasks` — total task count
|
|
106
|
+
- `domain_breakdown` — tasks per domain
|
|
107
|
+
- `implementation_phases` — number of phases
|
|
108
|
+
- `human_estimate` — human sequential estimate
|
|
109
|
+
- `agent_estimate` — agent parallel estimate
|
|
110
|
+
- `token_ledger` — per-agent token data from phase 2
|
|
10
111
|
|
|
11
112
|
---
|
|
12
113
|
|
|
13
|
-
## Step
|
|
114
|
+
## Step 4 — Present Gate 2 (HARD STOP — present in main loop)
|
|
115
|
+
|
|
116
|
+
Pre-condition check: read `{PREFIX}-Approvals.md` and verify Gate 1 ✅ is present.
|
|
117
|
+
If missing, return to Step 2.
|
|
118
|
+
|
|
119
|
+
Present the following to the user:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Work Breakdown for {PREFIX}:
|
|
123
|
+
|
|
124
|
+
User Stories: {user_stories} (US-01 ÷ US-{NN})
|
|
125
|
+
Total tasks: {total_tasks} ({domain_breakdown})
|
|
126
|
+
Implementation phases: {implementation_phases}
|
|
127
|
+
Human estimate: {human_estimate} | Agent estimate: {agent_estimate}
|
|
128
|
+
Reference: {PREFIX}-Effort-Estimate.md for full detail
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Then output this hard-stop message and **wait for a text reply from the user**:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
⛔ GATE 2 — WORK BREAKDOWN APPROVAL — HARD STOP
|
|
135
|
+
|
|
136
|
+
Please review the Work Breakdown above and reply with one of:
|
|
137
|
+
|
|
138
|
+
"Approve — start implementation"
|
|
139
|
+
"Request changes: <describe what to change>"
|
|
140
|
+
"Approve with notes: <your comments>"
|
|
14
141
|
|
|
15
|
-
|
|
142
|
+
Implementation CANNOT start until you reply directly.
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**If the user requests changes:** note them and stop. Do not invoke pm-phase3.
|
|
146
|
+
|
|
147
|
+
**If the user approves:** append Gate 2 to `{PREFIX}-Approvals.md`:
|
|
148
|
+
|
|
149
|
+
```markdown
|
|
150
|
+
## Gate 2 — Work Breakdown Approval
|
|
16
151
|
|
|
152
|
+
| Document | Status | Date | Notes |
|
|
153
|
+
|----------|--------|------|-------|
|
|
154
|
+
| {PREFIX}-Work-Breakdown.md | ✅ Approved | {today} | {total_tasks} tasks, {implementation_phases} phases |
|
|
17
155
|
```
|
|
18
|
-
|
|
19
|
-
|
|
156
|
+
|
|
157
|
+
Read back `{PREFIX}-Approvals.md` and verify Gate 2 ✅ is present before continuing.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Step 5 — Create feature branch
|
|
162
|
+
|
|
163
|
+
Before invoking pm-phase3, create the feature branch:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
git checkout -b feature/{PREFIX}-{short-slug}
|
|
20
167
|
```
|
|
21
168
|
|
|
22
|
-
|
|
23
|
-
|
|
169
|
+
If the branch already exists, switch to it without recreating:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
git checkout feature/{PREFIX}-{short-slug}
|
|
173
|
+
```
|
|
24
174
|
|
|
25
175
|
---
|
|
26
176
|
|
|
27
|
-
## Step
|
|
177
|
+
## Step 6 — Invoke pm-phase3 (Implementation Phase)
|
|
178
|
+
|
|
179
|
+
Pre-condition check: read `{PREFIX}-Approvals.md` and verify BOTH Gate 1 ✅ and Gate 2 ✅.
|
|
180
|
+
If either is missing, return to the missing gate.
|
|
181
|
+
|
|
182
|
+
Invoke the `pm-phase3` workflow:
|
|
28
183
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
184
|
+
```
|
|
185
|
+
subagent_type: pm-phase3
|
|
186
|
+
prompt: <path-to-feature.md> --branch feature/{PREFIX}-{short-slug}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Wait for the workflow to complete. Capture its full result, including the `<usage>` block
|
|
190
|
+
(format: `subagent_tokens: N`). Extract from the result:
|
|
191
|
+
- `pr_url` — the created pull request URL
|
|
192
|
+
- `token_ledger` — all per-agent token data from phase 3
|
|
193
|
+
- `issues_summary` — escalation and issues counts
|
|
194
|
+
|
|
195
|
+
If `issues_summary.escalations > 0`, report the escalation details to the user.
|
|
32
196
|
|
|
33
197
|
---
|
|
34
198
|
|
|
35
|
-
## Step
|
|
199
|
+
## Step 7 — Complete Token Estimate file
|
|
200
|
+
|
|
201
|
+
From the `<usage>` block of the pm-phase3 result, read:
|
|
202
|
+
- `subagent_tokens` — total tokens consumed by the pm-phase3 workflow
|
|
203
|
+
- `duration_ms` — wall-clock duration of pm-phase3
|
|
36
204
|
|
|
37
|
-
|
|
38
|
-
upfront estimate and the child agents' actuals. Read that file, then **append**
|
|
39
|
-
the orchestrator row and the grand total:
|
|
205
|
+
Read `{PREFIX}-Token-Estimate.md`. Append the orchestrator row and grand total:
|
|
40
206
|
|
|
41
207
|
```markdown
|
|
42
|
-
| project-manager (orchestrator) | — | sonnet |
|
|
208
|
+
| project-manager/pm-phase3 (orchestrator) | — | sonnet | 80,000 (estimated) | {subagent_tokens} (actual) | ±{delta} | {duration} |
|
|
43
209
|
|
|
44
210
|
---
|
|
45
211
|
|
|
46
|
-
|
|
212
|
+
## Actuals vs Estimate
|
|
213
|
+
|
|
214
|
+
| Agent | Task / Scope | Model | Est. tokens | Actual tokens | Delta | Est. cost ($) | Actual cost ($) | Duration |
|
|
215
|
+
|-------|-------------|-------|------------|---------------|-------|--------------|----------------|----------|
|
|
216
|
+
{one row per entry in token_ledger — from phase 1, 2, and 3}
|
|
217
|
+
| project-manager/pm-phase3 (orchestrator) | — | sonnet | 80,000 | {subagent_tokens} | ±{delta} | $0.4320 | ${actual_cost} | {duration} |
|
|
218
|
+
|
|
219
|
+
## Estimation accuracy by agent type
|
|
220
|
+
|
|
221
|
+
| Model | Count | Avg est. tokens | Avg actual tokens | Avg delta | Trend |
|
|
222
|
+
|-------|-------|----------------|------------------|-----------|-------|
|
|
223
|
+
{one row per model tier (haiku, sonnet) — exclude N/A rows from averages}
|
|
224
|
+
|
|
225
|
+
## Grand Total
|
|
47
226
|
|
|
48
227
|
| Metric | Estimated | Actual | Delta |
|
|
49
228
|
|--------|-----------|--------|-------|
|
|
50
|
-
| Total tokens (all agents) |
|
|
51
|
-
| Total
|
|
52
|
-
|
|
|
229
|
+
| Total tokens (all agents) | {sum_est} | {sum_actual} | ±{delta} |
|
|
230
|
+
| Total cost ($) | ${sum_est_cost} | ${sum_actual_cost} | ±${delta_cost} |
|
|
231
|
+
| Total wall-clock | — | {total_duration} | — |
|
|
53
232
|
```
|
|
54
233
|
|
|
55
|
-
|
|
56
|
-
|
|
234
|
+
> Per-agent values marked *(proportional)* are estimated distributions of the phase total.
|
|
235
|
+
> Phase totals and grand total are exact measurements from workflow subagent_tokens.
|
|
236
|
+
|
|
237
|
+
If the Token Estimate file does not exist (pm-phase3 failed before writing it), create it
|
|
238
|
+
from scratch using the data available in the token_ledger.
|
|
57
239
|
|
|
58
240
|
---
|
|
59
241
|
|
|
60
|
-
## Step
|
|
242
|
+
## Step 8 — Report to user
|
|
61
243
|
|
|
62
244
|
After writing the token file, report:
|
|
63
245
|
|
|
64
246
|
```
|
|
65
|
-
|
|
247
|
+
Feature pipeline complete.
|
|
66
248
|
Token estimate + actuals → {PREFIX}-Token-Estimate.md
|
|
67
249
|
Effort estimate + actuals → {PREFIX}-Effort-Estimate.md
|
|
68
|
-
Pull Request → {
|
|
250
|
+
Pull Request → {pr_url}
|
|
69
251
|
```
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: 'am-phase1',
|
|
3
|
+
description: 'Assessment pipeline phase 1: discover assessment agents → scope filter → parallel assessment → intervention-documentation-standard → Token-Estimate → Effort-Estimate → findings_gate_payload.',
|
|
4
|
+
phases: [
|
|
5
|
+
{ title: 'Discovery', detail: 'Scan .claude/agents/ for assessment agents, apply scope filter' },
|
|
6
|
+
{ title: 'Assessment', detail: 'Dispatch all assessment agents in parallel' },
|
|
7
|
+
{ title: 'Interventions', detail: 'Run intervention-documentation-standard on all findings' },
|
|
8
|
+
{ title: 'Estimates', detail: 'Write Token-Estimate and Effort-Estimate files' },
|
|
9
|
+
],
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// args: "<target_path> [--scope=area1,area2] --prefix ASSESS-NNN [--force]"
|
|
13
|
+
const argStr = typeof args === 'string' ? args : '.'
|
|
14
|
+
const parts = argStr.trim().split(/\s+/)
|
|
15
|
+
|
|
16
|
+
let targetPath = '.'
|
|
17
|
+
let scope = null
|
|
18
|
+
let prefix = null
|
|
19
|
+
let force = false
|
|
20
|
+
|
|
21
|
+
for (const part of parts) {
|
|
22
|
+
if (part.startsWith('--scope=')) { scope = part.slice('--scope='.length).split(',').map(s => s.trim()) }
|
|
23
|
+
else if (part === '--force') { force = true }
|
|
24
|
+
else if (part === '--prefix') { /* next part is value */ }
|
|
25
|
+
else if (prefix === null && parts[parts.indexOf(part) - 1] === '--prefix') { prefix = part }
|
|
26
|
+
else if (!part.startsWith('--')) { targetPath = part }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Re-parse prefix properly
|
|
30
|
+
const prefixMatch = argStr.match(/--prefix\s+(\S+)/)
|
|
31
|
+
if (prefixMatch) prefix = prefixMatch[1]
|
|
32
|
+
|
|
33
|
+
if (!prefix) prefix = 'ASSESS-001'
|
|
34
|
+
|
|
35
|
+
const outputDir = `docs/assessments/${prefix}`
|
|
36
|
+
|
|
37
|
+
// ── Discovery ─────────────────────────────────────────────────────────────────
|
|
38
|
+
phase('Discovery')
|
|
39
|
+
|
|
40
|
+
const DISCOVERY_SCHEMA = {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
assessment_agents: {
|
|
44
|
+
type: 'array',
|
|
45
|
+
items: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: {
|
|
48
|
+
name: { type: 'string' },
|
|
49
|
+
description: { type: 'string' },
|
|
50
|
+
},
|
|
51
|
+
required: ['name'],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
required: ['assessment_agents'],
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const SCOPE_AGENT_MAP = {
|
|
59
|
+
architecture: ['layered-architecture-assessment'],
|
|
60
|
+
security: ['security-hardening'],
|
|
61
|
+
quality: ['generic-software-assessment'],
|
|
62
|
+
concurrency: ['concurrency-safety-assessment'],
|
|
63
|
+
devops: [],
|
|
64
|
+
'domain-model': ['domain-model-refactoring'],
|
|
65
|
+
dependencies: ['dependency-supply-chain-security'],
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const discovery = await agent(
|
|
69
|
+
`Scan .claude/agents/ and list all assessment agents.
|
|
70
|
+
|
|
71
|
+
An assessment agent is a .md file whose name or description contains one of: "assessment", "audit", "analysis".
|
|
72
|
+
Exclude orchestrators (files containing "manager" in their name).
|
|
73
|
+
Exclude remediation-only agents (files containing "refactoring", "hardening", "decomposition" in their name UNLESS they also contain "assessment" or "audit").
|
|
74
|
+
|
|
75
|
+
For each matching agent, read its frontmatter and extract:
|
|
76
|
+
- name (from the name: field in frontmatter)
|
|
77
|
+
- description (from the description: field)
|
|
78
|
+
|
|
79
|
+
Return { "assessment_agents": [ { "name": "...", "description": "..." }, ... ] }`,
|
|
80
|
+
{
|
|
81
|
+
label: 'discover-assessment-agents',
|
|
82
|
+
phase: 'Discovery',
|
|
83
|
+
schema: DISCOVERY_SCHEMA,
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
let assessmentAgents = discovery.assessment_agents || []
|
|
88
|
+
|
|
89
|
+
// Apply scope filter
|
|
90
|
+
if (scope && scope.length > 0) {
|
|
91
|
+
const allowed = new Set(scope.flatMap(s => SCOPE_AGENT_MAP[s] || []))
|
|
92
|
+
assessmentAgents = assessmentAgents.filter(a => allowed.has(a.name))
|
|
93
|
+
log(`Scope filter applied (${scope.join(', ')}): ${assessmentAgents.length} agents selected`)
|
|
94
|
+
} else {
|
|
95
|
+
log(`No scope filter: ${assessmentAgents.length} assessment agents discovered`)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (assessmentAgents.length === 0) {
|
|
99
|
+
log('WARNING: No assessment agents to run — proceeding with empty assessment')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ── Assessment (parallel) ─────────────────────────────────────────────────────
|
|
103
|
+
phase('Assessment')
|
|
104
|
+
|
|
105
|
+
log(`Dispatching ${assessmentAgents.length} assessment agents in parallel`)
|
|
106
|
+
|
|
107
|
+
const tokenLedger = []
|
|
108
|
+
const beforeAssess = budget.spent()
|
|
109
|
+
|
|
110
|
+
const assessmentResults = await parallel(
|
|
111
|
+
assessmentAgents.map(a => () =>
|
|
112
|
+
agent(
|
|
113
|
+
`${targetPath} --prefix ${prefix} --output-dir ${outputDir}`,
|
|
114
|
+
{
|
|
115
|
+
agentType: a.name,
|
|
116
|
+
label: a.name,
|
|
117
|
+
phase: 'Assessment',
|
|
118
|
+
}
|
|
119
|
+
).then(result => ({ agent: a.name, success: true, result }))
|
|
120
|
+
.catch(err => ({ agent: a.name, success: false, error: String(err) }))
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
const assessTokens = budget.spent() - beforeAssess
|
|
125
|
+
log(`Assessment phase complete — ${assessmentResults.filter(r => r?.success).length}/${assessmentAgents.length} succeeded | total phase delta: ${assessTokens} tokens`)
|
|
126
|
+
|
|
127
|
+
// Proportional token distribution across agents
|
|
128
|
+
const perAgentTokens = assessmentAgents.length > 0
|
|
129
|
+
? Math.round(assessTokens / assessmentAgents.length)
|
|
130
|
+
: 0
|
|
131
|
+
|
|
132
|
+
for (const r of assessmentResults.filter(Boolean)) {
|
|
133
|
+
tokenLedger.push({
|
|
134
|
+
agent: r.agent,
|
|
135
|
+
model: 'sonnet',
|
|
136
|
+
phase_delta_tokens: perAgentTokens,
|
|
137
|
+
note: 'proportional distribution of assessment phase total',
|
|
138
|
+
success: r.success,
|
|
139
|
+
error: r.error || null,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const failedAgents = assessmentResults.filter(r => r && !r.success)
|
|
144
|
+
const completedAgents = assessmentResults.filter(r => r && r.success)
|
|
145
|
+
|
|
146
|
+
// ── Interventions ─────────────────────────────────────────────────────────────
|
|
147
|
+
phase('Interventions')
|
|
148
|
+
|
|
149
|
+
log('Running intervention-documentation-standard')
|
|
150
|
+
|
|
151
|
+
const beforeInt = budget.spent()
|
|
152
|
+
await agent(
|
|
153
|
+
`--prefix ${prefix} --output-dir ${outputDir} --target ${targetPath}`,
|
|
154
|
+
{
|
|
155
|
+
agentType: 'intervention-documentation-standard',
|
|
156
|
+
label: 'intervention-documentation-standard',
|
|
157
|
+
phase: 'Interventions',
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
const intTokens = budget.spent() - beforeInt
|
|
161
|
+
tokenLedger.push({
|
|
162
|
+
agent: 'intervention-documentation-standard',
|
|
163
|
+
model: 'sonnet',
|
|
164
|
+
phase_delta_tokens: intTokens,
|
|
165
|
+
note: 'exact phase delta',
|
|
166
|
+
})
|
|
167
|
+
log(`intervention-documentation-standard done — phase delta: ${intTokens} tokens`)
|
|
168
|
+
|
|
169
|
+
// ── Estimates ─────────────────────────────────────────────────────────────────
|
|
170
|
+
phase('Estimates')
|
|
171
|
+
|
|
172
|
+
const ESTIMATES_SCHEMA = {
|
|
173
|
+
type: 'object',
|
|
174
|
+
properties: {
|
|
175
|
+
severity_counts: {
|
|
176
|
+
type: 'object',
|
|
177
|
+
properties: {
|
|
178
|
+
CRITICAL: { type: 'number' },
|
|
179
|
+
HIGH: { type: 'number' },
|
|
180
|
+
MEDIUM: { type: 'number' },
|
|
181
|
+
LOW: { type: 'number' },
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
total_interventions: { type: 'number' },
|
|
185
|
+
interventions_index_path: { type: 'string' },
|
|
186
|
+
token_estimate_path: { type: 'string' },
|
|
187
|
+
effort_estimate_path: { type: 'string' },
|
|
188
|
+
remediation_hours_est: { type: 'number' },
|
|
189
|
+
},
|
|
190
|
+
required: ['severity_counts', 'total_interventions'],
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const totalPhaseTokens = tokenLedger.reduce((s, e) => s + (e.phase_delta_tokens || 0), 0)
|
|
194
|
+
|
|
195
|
+
const estimatesResult = await agent(
|
|
196
|
+
`You are the estimates recorder for the assessment pipeline.
|
|
197
|
+
|
|
198
|
+
Prefix: ${prefix}
|
|
199
|
+
Output directory: ${outputDir}
|
|
200
|
+
Assessment agents that ran: ${assessmentAgents.map(a => a.name).join(', ') || 'none'}
|
|
201
|
+
Failed agents: ${failedAgents.map(r => r.agent).join(', ') || 'none'}
|
|
202
|
+
|
|
203
|
+
Token ledger (phase-level measurements):
|
|
204
|
+
${JSON.stringify(tokenLedger, null, 2)}
|
|
205
|
+
|
|
206
|
+
TASK 1 — Read ${prefix}-Interventions-Index.md from ${outputDir}.
|
|
207
|
+
Count rows by Criticality column: CRITICAL, HIGH, MEDIUM, LOW.
|
|
208
|
+
Compute remediation_hours_est = CRITICAL×8 + HIGH×4 + MEDIUM×2 + LOW×1.
|
|
209
|
+
|
|
210
|
+
TASK 2 — Write Token-Estimate file at ${outputDir}/${prefix}-Token-Estimate.md.
|
|
211
|
+
|
|
212
|
+
Use this template (fill in all values):
|
|
213
|
+
|
|
214
|
+
# Token Estimate — ${prefix} — Assessment Pipeline
|
|
215
|
+
|
|
216
|
+
> Phase totals are exact measurements from budget tracking.
|
|
217
|
+
> Per-agent values within the assessment phase are proportional distributions of the phase total.
|
|
218
|
+
> Pricing model: docs/pricing.md (80% input / 20% output split).
|
|
219
|
+
> ⚠️ Per-agent values marked (proportional) are estimated distributions, not exact measurements.
|
|
220
|
+
|
|
221
|
+
## Estimation model
|
|
222
|
+
|
|
223
|
+
| Parameter | Value |
|
|
224
|
+
|-----------|-------|
|
|
225
|
+
| Avg chars per token | 4 |
|
|
226
|
+
| Sonnet system prompt | ~3,000 tokens |
|
|
227
|
+
| Base overhead per call | ~5,000 tokens |
|
|
228
|
+
| Input/output split | 80% / 20% |
|
|
229
|
+
|
|
230
|
+
## Assessment agents (Phase 1)
|
|
231
|
+
|
|
232
|
+
| Agent | Model | Phase delta tokens | Note | Status |
|
|
233
|
+
|-------|-------|--------------------|------|--------|
|
|
234
|
+
{one row per agent from token ledger — use phase_delta_tokens and note fields}
|
|
235
|
+
|
|
236
|
+
## Phase subtotals
|
|
237
|
+
|
|
238
|
+
| Phase | Tokens (exact) |
|
|
239
|
+
|-------|---------------|
|
|
240
|
+
| Assessment agents (parallel) | {sum of assessment agent phase_delta_tokens} |
|
|
241
|
+
| intervention-documentation-standard | {its phase_delta_tokens} |
|
|
242
|
+
| Total am-phase1 | ${totalPhaseTokens} |
|
|
243
|
+
|
|
244
|
+
## Grand total
|
|
245
|
+
|
|
246
|
+
> Updated at pipeline end by assess-codebase skill.
|
|
247
|
+
|
|
248
|
+
| Metric | Value |
|
|
249
|
+
|--------|-------|
|
|
250
|
+
| Total tokens (am-phase1) | ${totalPhaseTokens} (exact) |
|
|
251
|
+
|
|
252
|
+
TASK 3 — Write Effort-Estimate file at ${outputDir}/${prefix}-Effort-Estimate.md.
|
|
253
|
+
|
|
254
|
+
Use this template:
|
|
255
|
+
|
|
256
|
+
# Effort Estimate — ${prefix} — Assessment Pipeline
|
|
257
|
+
|
|
258
|
+
> Wall-clock effort tracking for the assessment pipeline.
|
|
259
|
+
> Remediation effort: CRITICAL=8h, HIGH=4h, MEDIUM=2h, LOW=1h (human hours, sequential).
|
|
260
|
+
|
|
261
|
+
## Assessment phase
|
|
262
|
+
|
|
263
|
+
| Agent | Status |
|
|
264
|
+
|-------|--------|
|
|
265
|
+
{one row per assessment agent}
|
|
266
|
+
| intervention-documentation-standard | complete |
|
|
267
|
+
|
|
268
|
+
## Remediation effort estimate
|
|
269
|
+
|
|
270
|
+
| Severity | Count | Rate | Subtotal |
|
|
271
|
+
|----------|-------|------|---------|
|
|
272
|
+
| CRITICAL | {count} | 8h | {subtotal}h |
|
|
273
|
+
| HIGH | {count} | 4h | {subtotal}h |
|
|
274
|
+
| MEDIUM | {count} | 2h | {subtotal}h |
|
|
275
|
+
| LOW | {count} | 1h | {subtotal}h |
|
|
276
|
+
| **Total** | **{total}** | — | **{total_hours}h** |
|
|
277
|
+
|
|
278
|
+
Human sequential total: {total_hours}h
|
|
279
|
+
|
|
280
|
+
Return the structured metrics.`,
|
|
281
|
+
{
|
|
282
|
+
label: 'write-estimates',
|
|
283
|
+
phase: 'Estimates',
|
|
284
|
+
schema: ESTIMATES_SCHEMA,
|
|
285
|
+
}
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
log(`Estimates written — ${estimatesResult.total_interventions} interventions: CRITICAL=${estimatesResult.severity_counts?.CRITICAL} HIGH=${estimatesResult.severity_counts?.HIGH} MEDIUM=${estimatesResult.severity_counts?.MEDIUM} LOW=${estimatesResult.severity_counts?.LOW}`)
|
|
289
|
+
log(`Remediation estimate: ${estimatesResult.remediation_hours_est}h human sequential`)
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
prefix,
|
|
293
|
+
output_dir: outputDir,
|
|
294
|
+
target_path: targetPath,
|
|
295
|
+
assessment_summaries: completedAgents.map(r => ({ agent: r.agent })),
|
|
296
|
+
interventions_index_path: estimatesResult.interventions_index_path || `${outputDir}/${prefix}-Interventions-Index.md`,
|
|
297
|
+
severity_counts: estimatesResult.severity_counts || { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0 },
|
|
298
|
+
total_interventions: estimatesResult.total_interventions || 0,
|
|
299
|
+
remediation_hours_est: estimatesResult.remediation_hours_est || 0,
|
|
300
|
+
effort_estimate_path: estimatesResult.effort_estimate_path || `${outputDir}/${prefix}-Effort-Estimate.md`,
|
|
301
|
+
token_estimate_path: estimatesResult.token_estimate_path || `${outputDir}/${prefix}-Token-Estimate.md`,
|
|
302
|
+
token_ledger: tokenLedger,
|
|
303
|
+
errors: failedAgents.map(r => ({ agent: r.agent, error: r.error })),
|
|
304
|
+
}
|