@dtlabs/ai-toolkit 0.10.1 → 0.12.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 +108 -0
- package/bin/cli.js +1457 -143
- package/docs/installation.md +74 -8
- package/docs/reference.md +60 -12
- package/lib/asset-catalog.js +52 -0
- package/lib/execution-ledger.js +515 -0
- package/package.json +9 -7
- package/{.claude → src/claude}/agents/define-feature.md +36 -60
- package/{.claude → src/claude}/agents/install-toolkit.md +30 -103
- package/{.claude → src/claude}/scripts/wb-render.js +101 -2
- package/{.claude → src/claude}/scripts/wb-validate.js +32 -2
- package/{.claude → src/claude}/skills/implement-feature/SKILL.md +4 -2
- package/{.claude → src/claude}/workflows/am-phase1.js +9 -12
- package/{.claude → src/claude}/workflows/pm-phase1.js +25 -75
- package/{.claude → src/claude}/workflows/pm-phase2.js +57 -108
- package/{.claude → src/claude}/workflows/pm-phase3.js +162 -75
- package/.claude/scripts/.gitkeep +0 -0
- /package/{.claude → src/claude}/agents/concurrency-safety-assessment.md +0 -0
- /package/{.claude → src/claude}/agents/dependency-injection-refactoring.md +0 -0
- /package/{.claude → src/claude}/agents/dependency-supply-chain-security.md +0 -0
- /package/{.claude → src/claude}/agents/developer-backend.md +0 -0
- /package/{.claude → src/claude}/agents/developer-frontend.md +0 -0
- /package/{.claude → src/claude}/agents/developer-testing.md +0 -0
- /package/{.claude → src/claude}/agents/domain-model-refactoring.md +0 -0
- /package/{.claude → src/claude}/agents/generate-requirements.md +0 -0
- /package/{.claude → src/claude}/agents/generate-tech-spec.md +0 -0
- /package/{.claude → src/claude}/agents/generate-work-breakdown.md +0 -0
- /package/{.claude → src/claude}/agents/generic-software-assessment.md +0 -0
- /package/{.claude → src/claude}/agents/god-class-decomposition.md +0 -0
- /package/{.claude → src/claude}/agents/init-agents-md.md +0 -0
- /package/{.claude → src/claude}/agents/intervention-documentation-standard.md +0 -0
- /package/{.claude → src/claude}/agents/layered-architecture-assessment.md +0 -0
- /package/{.claude → src/claude}/agents/review-solution.md +0 -0
- /package/{.claude → src/claude}/agents/security-hardening.md +0 -0
- /package/{.claude → src/claude}/agents/validate-feature-docs.md +0 -0
- /package/{.claude → src/claude}/agents/validate-work-breakdown-semantic.md +0 -0
- /package/{.claude → src/claude}/commands/assessment-status.md +0 -0
- /package/{.claude → src/claude}/commands/check-docs.md +0 -0
- /package/{.claude → src/claude}/commands/check-interventions.md +0 -0
- /package/{.claude → src/claude}/commands/feature-status.md +0 -0
- /package/{.claude → src/claude}/commands/next-intervention.md +0 -0
- /package/{.claude → src/claude}/commands/next-task.md +0 -0
- /package/{.claude → src/claude}/commands/pr-description.md +0 -0
- /package/{.claude → src/claude}/skills/assess-codebase/SKILL.md +0 -0
- /package/{.claude → src/claude}/skills/define-feature/SKILL.md +0 -0
- /package/{.claude → src/claude}/skills/hi-gaia/SKILL.md +0 -0
- /package/{.claude → src/claude}/skills/init-agents/SKILL.md +0 -0
- /package/{.claude → src/claude}/skills/install-toolkit/SKILL.md +0 -0
- /package/{.claude → src/claude}/workflows/am-phase2.js +0 -0
|
@@ -9,38 +9,6 @@ export const meta = {
|
|
|
9
9
|
],
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
// ── Ledger helper functions ───────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
async function appendLedgerEntry(featureDir, prefix, entry) {
|
|
15
|
-
const ledgerPath = `${featureDir}/${prefix}-token-ledger.json`
|
|
16
|
-
// started_at is generated via Bash inside the agent to get a real UTC timestamp with time
|
|
17
|
-
const entryWithoutTs = JSON.stringify({ ...entry, started_at: '__TS__', completed_at: null })
|
|
18
|
-
await agent(
|
|
19
|
-
`Append a JSON object to the ledger array at: ${ledgerPath}\n\n` +
|
|
20
|
-
`1. Run: date -u +"%Y-%m-%dT%H:%M:%SZ" and capture the output as NOW.\n` +
|
|
21
|
-
`2. Read the file. If it does not exist or cannot be parsed as a JSON array, start with [].\n` +
|
|
22
|
-
`3. Push this object onto the array, replacing "__TS__" in started_at with NOW: ${entryWithoutTs}\n` +
|
|
23
|
-
`4. Write the full array back (JSON, 2-space indent). Return no output.`,
|
|
24
|
-
{ label: 'append-ledger', phase: 'Requirements', model: 'haiku' }
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async function updateLedgerEntry(featureDir, prefix, agentKey, updates) {
|
|
29
|
-
const ledgerPath = `${featureDir}/${prefix}-token-ledger.json`
|
|
30
|
-
// completed_at is generated via Bash inside the agent to get a real UTC timestamp with time
|
|
31
|
-
const updatesWithoutTs = JSON.stringify({ ...updates, completed_at: '__TS__' })
|
|
32
|
-
await agent(
|
|
33
|
-
`Update an entry in the ledger array at: ${ledgerPath}\n\n` +
|
|
34
|
-
`1. Run: date -u +"%Y-%m-%dT%H:%M:%SZ" and capture the output as NOW.\n` +
|
|
35
|
-
`2. Read the file. If it does not exist or cannot be parsed as a JSON array, do nothing.\n` +
|
|
36
|
-
`3. Search from the end for the last entry where agent === "${agentKey}".\n` +
|
|
37
|
-
`4. If found, merge these fields into that entry, replacing "__TS__" in completed_at with NOW: ${updatesWithoutTs}\n` +
|
|
38
|
-
`5. Write the full array back (JSON, 2-space indent). Return no output.\n` +
|
|
39
|
-
`6. If not found, do nothing.`,
|
|
40
|
-
{ label: 'update-ledger', phase: 'Requirements', model: 'haiku' }
|
|
41
|
-
)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
12
|
// ── Parse args ────────────────────────────────────────────────────────────────
|
|
45
13
|
// args is the raw prompt string: "<path-to-feature.md> [--force]"
|
|
46
14
|
const featurePath = args.split(/\s+/)[0]
|
|
@@ -104,7 +72,7 @@ log(`needs_requirements=${discoveryResult.needs_requirements} needs_tech_spec=${
|
|
|
104
72
|
|
|
105
73
|
// ── Ensure ledger file exists (US-02-T02) ─────────────────────────────────────
|
|
106
74
|
// If define-feature was not used, the ledger file will not exist yet.
|
|
107
|
-
// Touch it with an empty array so
|
|
75
|
+
// Touch it with an empty array so the ledger facade can always assume a valid base.
|
|
108
76
|
const ledgerFilePath = `${feature_dir}/${prefix}-token-ledger.json`
|
|
109
77
|
await agent(
|
|
110
78
|
`Check whether the file ${ledgerFilePath} exists.\n\n1. Try to read the file using the Read tool.\n2. If the file does NOT exist: write it now using the Write tool with contents: []\n3. If the file already exists and is a valid JSON array: do nothing.\n4. If the file exists but is not valid JSON: overwrite it with: []\n5. Return no output.`,
|
|
@@ -120,23 +88,17 @@ const errors = []
|
|
|
120
88
|
|
|
121
89
|
if (discoveryResult.needs_requirements) {
|
|
122
90
|
const reqKey = 'generate-requirements:phase1'
|
|
123
|
-
await
|
|
124
|
-
agent
|
|
125
|
-
phase: '
|
|
126
|
-
|
|
127
|
-
status: 'running',
|
|
128
|
-
phase_delta_tokens: 0,
|
|
129
|
-
started_at: '__TS__',
|
|
130
|
-
completed_at: null,
|
|
131
|
-
})
|
|
91
|
+
await agent(
|
|
92
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger open --dir ${feature_dir} --prefix ${prefix} --agent ${reqKey} --phase phase1 --model haiku --attempt 1\n\nReturn no output.`,
|
|
93
|
+
{ label: 'ledger-open-requirements', phase: 'Requirements', model: 'haiku' }
|
|
94
|
+
)
|
|
132
95
|
const beforeReq = budget.spent()
|
|
133
96
|
const reqResult = await agent(featurePath, { agentType: 'generate-requirements', label: 'generate-requirements', phase: 'Requirements' })
|
|
134
97
|
const reqTokens = budget.spent() - beforeReq
|
|
135
|
-
await
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
})
|
|
98
|
+
await agent(
|
|
99
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger close --dir ${feature_dir} --prefix ${prefix} --agent ${reqKey} --tokens ${reqTokens} --attempt 1\n\nReturn no output.`,
|
|
100
|
+
{ label: 'ledger-close-requirements', phase: 'Requirements', model: 'haiku' }
|
|
101
|
+
)
|
|
140
102
|
tokenLedger.push({ agent: 'generate-requirements', model: 'haiku', phase_delta_tokens: reqTokens })
|
|
141
103
|
log(`generate-requirements done — phase delta: ${reqTokens} tokens`)
|
|
142
104
|
} else {
|
|
@@ -148,23 +110,17 @@ phase('Tech-Spec')
|
|
|
148
110
|
|
|
149
111
|
if (discoveryResult.needs_tech_spec) {
|
|
150
112
|
const specKey = 'generate-tech-spec:phase1'
|
|
151
|
-
await
|
|
152
|
-
agent
|
|
153
|
-
phase: '
|
|
154
|
-
|
|
155
|
-
status: 'running',
|
|
156
|
-
phase_delta_tokens: 0,
|
|
157
|
-
started_at: '__TS__',
|
|
158
|
-
completed_at: null,
|
|
159
|
-
})
|
|
113
|
+
await agent(
|
|
114
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger open --dir ${feature_dir} --prefix ${prefix} --agent ${specKey} --phase phase1 --model haiku --attempt 1\n\nReturn no output.`,
|
|
115
|
+
{ label: 'ledger-open-tech-spec', phase: 'Tech-Spec', model: 'haiku' }
|
|
116
|
+
)
|
|
160
117
|
const beforeSpec = budget.spent()
|
|
161
118
|
const specResult = await agent(featurePath, { agentType: 'generate-tech-spec', label: 'generate-tech-spec', phase: 'Tech-Spec' })
|
|
162
119
|
const specTokens = budget.spent() - beforeSpec
|
|
163
|
-
await
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
})
|
|
120
|
+
await agent(
|
|
121
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger close --dir ${feature_dir} --prefix ${prefix} --agent ${specKey} --tokens ${specTokens} --attempt 1\n\nReturn no output.`,
|
|
122
|
+
{ label: 'ledger-close-tech-spec', phase: 'Tech-Spec', model: 'haiku' }
|
|
123
|
+
)
|
|
168
124
|
tokenLedger.push({ agent: 'generate-tech-spec', model: 'haiku', phase_delta_tokens: specTokens })
|
|
169
125
|
log(`generate-tech-spec done — phase delta: ${specTokens} tokens`)
|
|
170
126
|
} else {
|
|
@@ -181,23 +137,17 @@ const MAX_CYCLES = 3
|
|
|
181
137
|
for (let cycle = 1; cycle <= MAX_CYCLES; cycle++) {
|
|
182
138
|
log(`validate-feature-docs cycle ${cycle}`)
|
|
183
139
|
const valKey = `validate-feature-docs:phase1:cycle${cycle}`
|
|
184
|
-
await
|
|
185
|
-
agent
|
|
186
|
-
phase: '
|
|
187
|
-
|
|
188
|
-
status: 'running',
|
|
189
|
-
phase_delta_tokens: 0,
|
|
190
|
-
started_at: '__TS__',
|
|
191
|
-
completed_at: null,
|
|
192
|
-
})
|
|
140
|
+
await agent(
|
|
141
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger open --dir ${feature_dir} --prefix ${prefix} --agent ${valKey} --phase phase1 --model haiku --attempt 1\n\nReturn no output.`,
|
|
142
|
+
{ label: `ledger-open-validate-cycle-${cycle}`, phase: 'Validation', model: 'haiku' }
|
|
143
|
+
)
|
|
193
144
|
const beforeVal = budget.spent()
|
|
194
145
|
const valResult = await agent(featurePath, { agentType: 'validate-feature-docs', label: `validate-feature-docs (cycle ${cycle})`, phase: 'Validation' })
|
|
195
146
|
const valTokens = budget.spent() - beforeVal
|
|
196
|
-
await
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
})
|
|
147
|
+
await agent(
|
|
148
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger close --dir ${feature_dir} --prefix ${prefix} --agent ${valKey} --tokens ${valTokens} --attempt 1\n\nReturn no output.`,
|
|
149
|
+
{ label: `ledger-close-validate-cycle-${cycle}`, phase: 'Validation', model: 'haiku' }
|
|
150
|
+
)
|
|
201
151
|
tokenLedger.push({ agent: `validate-feature-docs (cycle ${cycle})`, model: 'haiku', phase_delta_tokens: valTokens })
|
|
202
152
|
|
|
203
153
|
// valResult is the agent's text output — check for gap indicators
|
|
@@ -7,42 +7,6 @@ export const meta = {
|
|
|
7
7
|
],
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
// ── Ledger helper functions ───────────────────────────────────────────────────
|
|
11
|
-
// Route all ledger I/O through agent() — fs is not available in the workflow runtime.
|
|
12
|
-
// Mirrors appendLedgerEntry / updateLedgerEntry from bin/cli.js (same contract).
|
|
13
|
-
|
|
14
|
-
async function appendLedgerEntry(featureDir, prefix, entry) {
|
|
15
|
-
const ledgerPath = `${featureDir}/${prefix}-token-ledger.json`
|
|
16
|
-
// Defaults come first so the caller can override started_at/completed_at.
|
|
17
|
-
// Skipped entries pass completed_at: '__TS__' to get a real timestamp; running entries
|
|
18
|
-
// pass completed_at: null to keep it null. Both are replaced/kept by the agent below.
|
|
19
|
-
const entryWithoutTs = JSON.stringify({ started_at: '__TS__', completed_at: null, ...entry })
|
|
20
|
-
await agent(
|
|
21
|
-
`Append a JSON object to the ledger array at: ${ledgerPath}\n\n` +
|
|
22
|
-
`1. Run: date -u +"%Y-%m-%dT%H:%M:%SZ" and capture the output as NOW.\n` +
|
|
23
|
-
`2. Read the file. If it does not exist or cannot be parsed as a JSON array, start with [].\n` +
|
|
24
|
-
`3. Push this object onto the array, replacing every "__TS__" string value in the object with NOW: ${entryWithoutTs}\n` +
|
|
25
|
-
`4. Write the full array back (JSON, 2-space indent). Return no output.`,
|
|
26
|
-
{ label: 'append-ledger', phase: 'Work Breakdown', model: 'haiku' }
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function updateLedgerEntry(featureDir, prefix, agentKey, updates) {
|
|
31
|
-
const ledgerPath = `${featureDir}/${prefix}-token-ledger.json`
|
|
32
|
-
// completed_at is generated via Bash inside the agent to get a real UTC timestamp with time
|
|
33
|
-
const updatesWithoutTs = JSON.stringify({ ...updates, completed_at: '__TS__' })
|
|
34
|
-
await agent(
|
|
35
|
-
`Update an entry in the ledger array at: ${ledgerPath}\n\n` +
|
|
36
|
-
`1. Run: date -u +"%Y-%m-%dT%H:%M:%SZ" and capture the output as NOW.\n` +
|
|
37
|
-
`2. Read the file. If it does not exist or cannot be parsed as a JSON array, do nothing.\n` +
|
|
38
|
-
`3. Search from the end for the last entry where agent === "${agentKey}".\n` +
|
|
39
|
-
`4. If found, merge these fields into that entry, replacing "__TS__" in completed_at with NOW: ${updatesWithoutTs}\n` +
|
|
40
|
-
`5. Write the full array back (JSON, 2-space indent). Return no output.\n` +
|
|
41
|
-
`6. If not found, do nothing.`,
|
|
42
|
-
{ label: 'update-ledger', phase: 'Work Breakdown', model: 'haiku' }
|
|
43
|
-
)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
10
|
// Output schemas for wb-validate and wb-render agent invocations (used by US-05)
|
|
47
11
|
const WB_WRAPPER_SCHEMA = {
|
|
48
12
|
type: 'object',
|
|
@@ -90,8 +54,21 @@ function normalizeError(err) {
|
|
|
90
54
|
// args: "<path-to-feature.md>"
|
|
91
55
|
const featurePath = (typeof args === 'string' ? args : '').trim().split(/\s+/)[0]
|
|
92
56
|
|
|
57
|
+
// Feature directory = parent of the feature.md path. Separator-agnostic: the workflow
|
|
58
|
+
// runtime provides no `path` module, so we cannot use path.dirname. Handle BOTH POSIX
|
|
59
|
+
// "/" and Windows "\": strip a trailing "<sep>feature.md" tail when present; if the
|
|
60
|
+
// input is already a directory (no feature.md tail), strip only a trailing separator.
|
|
61
|
+
// This replaces the previous POSIX-only regex (/\/[^/]+$/), which left "\feature.md"
|
|
62
|
+
// attached on Windows paths and produced malformed "…\feature.md/…json" paths that only
|
|
63
|
+
// "worked" because an LLM wrapper agent silently repaired them.
|
|
64
|
+
function deriveFeatureDir(featurePath) {
|
|
65
|
+
return /[/\\]feature\.md$/i.test(featurePath)
|
|
66
|
+
? featurePath.replace(/[/\\]feature\.md$/i, '')
|
|
67
|
+
: featurePath.replace(/[/\\]+$/, '')
|
|
68
|
+
}
|
|
69
|
+
|
|
93
70
|
// Derive feature directory and prefix early (needed for ledger writes before metrics agent runs)
|
|
94
|
-
const featureDir = featurePath
|
|
71
|
+
const featureDir = deriveFeatureDir(featurePath)
|
|
95
72
|
const prefixMatch = featureDir.match(/([A-Z]+-\d+)/)
|
|
96
73
|
const prefix = prefixMatch ? prefixMatch[1] : 'FTR-000'
|
|
97
74
|
|
|
@@ -101,15 +78,11 @@ phase('Work Breakdown')
|
|
|
101
78
|
const tokenLedger = []
|
|
102
79
|
|
|
103
80
|
log(`Running generate-work-breakdown for ${featurePath}`)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
phase
|
|
107
|
-
model: 'haiku'
|
|
108
|
-
|
|
109
|
-
phase_delta_tokens: 0,
|
|
110
|
-
started_at: '__TS__',
|
|
111
|
-
completed_at: null,
|
|
112
|
-
})
|
|
81
|
+
const wbKey = 'generate-work-breakdown:phase2'
|
|
82
|
+
await agent(
|
|
83
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger open --dir ${featureDir} --prefix ${prefix} --agent ${wbKey} --phase phase2 --model haiku --attempt 1\n\nReturn no output.`,
|
|
84
|
+
{ label: 'ledger-open-generate-work-breakdown', phase: 'Work Breakdown', model: 'haiku' }
|
|
85
|
+
)
|
|
113
86
|
const beforeWB = budget.spent()
|
|
114
87
|
await agent(featurePath, {
|
|
115
88
|
agentType: 'generate-work-breakdown',
|
|
@@ -117,11 +90,10 @@ await agent(featurePath, {
|
|
|
117
90
|
phase: 'Work Breakdown',
|
|
118
91
|
})
|
|
119
92
|
const wbTokens = budget.spent() - beforeWB
|
|
120
|
-
await
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
})
|
|
93
|
+
await agent(
|
|
94
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger close --dir ${featureDir} --prefix ${prefix} --agent ${wbKey} --tokens ${wbTokens} --attempt 1\n\nReturn no output.`,
|
|
95
|
+
{ label: 'ledger-close-generate-work-breakdown', phase: 'Work Breakdown', model: 'haiku' }
|
|
96
|
+
)
|
|
125
97
|
tokenLedger.push({ agent: 'generate-work-breakdown', model: 'haiku', phase_delta_tokens: wbTokens })
|
|
126
98
|
log(`generate-work-breakdown done — phase delta: ${wbTokens} tokens`)
|
|
127
99
|
|
|
@@ -129,16 +101,16 @@ log(`generate-work-breakdown done — phase delta: ${wbTokens} tokens`)
|
|
|
129
101
|
let wbValidatorReport = null
|
|
130
102
|
let validateFailed = false
|
|
131
103
|
let validateExitCode = null
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
phase
|
|
135
|
-
|
|
136
|
-
|
|
104
|
+
const wbValidateKey = 'wb-validate:phase2'
|
|
105
|
+
await agent(
|
|
106
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger open --dir ${featureDir} --prefix ${prefix} --agent ${wbValidateKey} --phase phase2 --model haiku --attempt 1\n\nReturn no output.`,
|
|
107
|
+
{ label: 'ledger-open-wb-validate', phase: 'Work Breakdown', model: 'haiku' }
|
|
108
|
+
)
|
|
137
109
|
const beforeValidate = budget.spent()
|
|
138
110
|
try {
|
|
139
111
|
const validateWrapper = await agent(
|
|
140
112
|
`Run this command and return the result as structured output:\n` +
|
|
141
|
-
`
|
|
113
|
+
`ai-toolkit run-asset scripts/wb-validate.js -- "${featureDir}/${prefix}-Work-Breakdown.json" "${featureDir}/${prefix}-Requirements.md"\n\n` +
|
|
142
114
|
`Capture exitCode (integer), stdout (string), stderr (string). Return all three.`,
|
|
143
115
|
{
|
|
144
116
|
label: 'wb-validate',
|
|
@@ -173,20 +145,14 @@ try {
|
|
|
173
145
|
if (validateWrapper.exitCode === 1 && wbValidatorReport.valid) {
|
|
174
146
|
throw new Error('Inconsistent wb-validate result: exit 1 with valid=true')
|
|
175
147
|
}
|
|
176
|
-
await updateLedgerEntry(featureDir, prefix, 'wb-validate:phase2', {
|
|
177
|
-
status: 'done', completed_at: '__TS__',
|
|
178
|
-
phase_delta_tokens: budget.spent() - beforeValidate,
|
|
179
|
-
})
|
|
180
148
|
} catch (err) {
|
|
181
149
|
validateFailed = true
|
|
182
|
-
await updateLedgerEntry(featureDir, prefix, 'wb-validate:phase2', {
|
|
183
|
-
status: 'failed', completed_at: '__TS__',
|
|
184
|
-
phase_delta_tokens: budget.spent() - beforeValidate,
|
|
185
|
-
error_summary: normalizeError(err),
|
|
186
|
-
exit_code: err._exitCode ?? validateExitCode ?? null,
|
|
187
|
-
})
|
|
188
150
|
}
|
|
189
151
|
const validateTokens = budget.spent() - beforeValidate
|
|
152
|
+
await agent(
|
|
153
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger close --dir ${featureDir} --prefix ${prefix} --agent ${wbValidateKey} --tokens ${validateTokens} --attempt 1\n\nReturn no output.`,
|
|
154
|
+
{ label: 'ledger-close-wb-validate', phase: 'Work Breakdown', model: 'haiku' }
|
|
155
|
+
)
|
|
190
156
|
const wbValidatorPassed = !validateFailed && wbValidatorReport !== null
|
|
191
157
|
&& wbValidatorReport.valid === true && wbValidatorReport.errors.length === 0
|
|
192
158
|
log(`wb-validate: ${wbValidatorPassed ? 'passed' : 'failed/errors'} — ${validateTokens} tokens`)
|
|
@@ -195,18 +161,14 @@ log(`wb-validate: ${wbValidatorPassed ? 'passed' : 'failed/errors'} — ${valida
|
|
|
195
161
|
let semanticResult = null
|
|
196
162
|
let semanticFailed = false
|
|
197
163
|
let semanticTokens = 0
|
|
164
|
+
const semanticKey = 'validate-work-breakdown-semantic:phase2'
|
|
198
165
|
if (!wbValidatorPassed) {
|
|
199
|
-
|
|
200
|
-
agent: 'validate-work-breakdown-semantic:phase2',
|
|
201
|
-
phase: 'phase2', model: 'sonnet', status: 'skipped',
|
|
202
|
-
phase_delta_tokens: 0, started_at: '__TS__', completed_at: '__TS__',
|
|
203
|
-
})
|
|
166
|
+
log('validate-work-breakdown-semantic: skipped (wb-validate did not pass)')
|
|
204
167
|
} else {
|
|
205
|
-
await
|
|
206
|
-
agent
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
})
|
|
168
|
+
await agent(
|
|
169
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger open --dir ${featureDir} --prefix ${prefix} --agent ${semanticKey} --phase phase2 --model sonnet --attempt 1\n\nReturn no output.`,
|
|
170
|
+
{ label: 'ledger-open-semantic-validator', phase: 'Work Breakdown', model: 'haiku' }
|
|
171
|
+
)
|
|
210
172
|
const beforeSemantic = budget.spent()
|
|
211
173
|
try {
|
|
212
174
|
semanticResult = await agent(
|
|
@@ -218,18 +180,14 @@ if (!wbValidatorPassed) {
|
|
|
218
180
|
schema: WB_SEMANTIC_SCHEMA,
|
|
219
181
|
}
|
|
220
182
|
)
|
|
221
|
-
semanticTokens = budget.spent() - beforeSemantic
|
|
222
|
-
await updateLedgerEntry(featureDir, prefix, 'validate-work-breakdown-semantic:phase2', {
|
|
223
|
-
status: 'done', completed_at: '__TS__', phase_delta_tokens: semanticTokens,
|
|
224
|
-
})
|
|
225
183
|
} catch (err) {
|
|
226
184
|
semanticFailed = true
|
|
227
|
-
semanticTokens = budget.spent() - beforeSemantic
|
|
228
|
-
await updateLedgerEntry(featureDir, prefix, 'validate-work-breakdown-semantic:phase2', {
|
|
229
|
-
status: 'failed', completed_at: '__TS__', phase_delta_tokens: semanticTokens,
|
|
230
|
-
error_summary: normalizeError(err), exit_code: null,
|
|
231
|
-
})
|
|
232
185
|
}
|
|
186
|
+
semanticTokens = budget.spent() - beforeSemantic
|
|
187
|
+
await agent(
|
|
188
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger close --dir ${featureDir} --prefix ${prefix} --agent ${semanticKey} --tokens ${semanticTokens} --attempt 1\n\nReturn no output.`,
|
|
189
|
+
{ label: 'ledger-close-semantic-validator', phase: 'Work Breakdown', model: 'haiku' }
|
|
190
|
+
)
|
|
233
191
|
}
|
|
234
192
|
log(`semantic validator: ${semanticFailed ? 'failed' : semanticResult ? 'done' : 'skipped'}`)
|
|
235
193
|
|
|
@@ -237,23 +195,19 @@ log(`semantic validator: ${semanticFailed ? 'failed' : semanticResult ? 'done' :
|
|
|
237
195
|
const canRender = wbValidatorPassed && !semanticFailed
|
|
238
196
|
let renderFailed = false
|
|
239
197
|
let renderResult = null
|
|
198
|
+
const wbRenderKey = 'wb-render:phase2'
|
|
240
199
|
if (!canRender) {
|
|
241
|
-
|
|
242
|
-
agent: 'wb-render:phase2',
|
|
243
|
-
phase: 'phase2', model: 'haiku', status: 'skipped',
|
|
244
|
-
phase_delta_tokens: 0, started_at: '__TS__', completed_at: '__TS__',
|
|
245
|
-
})
|
|
200
|
+
log('wb-render: skipped (wb-validate or semantic validator did not pass)')
|
|
246
201
|
} else {
|
|
247
|
-
await
|
|
248
|
-
agent
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
})
|
|
202
|
+
await agent(
|
|
203
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger open --dir ${featureDir} --prefix ${prefix} --agent ${wbRenderKey} --phase phase2 --model haiku --attempt 1\n\nReturn no output.`,
|
|
204
|
+
{ label: 'ledger-open-wb-render', phase: 'Work Breakdown', model: 'haiku' }
|
|
205
|
+
)
|
|
252
206
|
const beforeRender = budget.spent()
|
|
253
207
|
try {
|
|
254
208
|
renderResult = await agent(
|
|
255
209
|
`Run this command and return the result as structured output:\n` +
|
|
256
|
-
`
|
|
210
|
+
`ai-toolkit run-asset scripts/wb-render.js -- "${featureDir}/${prefix}-Work-Breakdown.json" "${prefix}"\n\n` +
|
|
257
211
|
`Capture exitCode (integer), stdout (string), stderr (string).\n` +
|
|
258
212
|
`Resolve the expected output paths:\n` +
|
|
259
213
|
` markdownPath = "${featureDir}/${prefix}-Work-Breakdown.md"\n` +
|
|
@@ -291,20 +245,15 @@ if (!canRender) {
|
|
|
291
245
|
{ _exitCode: renderResult.exitCode }
|
|
292
246
|
)
|
|
293
247
|
}
|
|
294
|
-
await updateLedgerEntry(featureDir, prefix, 'wb-render:phase2', {
|
|
295
|
-
status: 'done', completed_at: '__TS__',
|
|
296
|
-
phase_delta_tokens: budget.spent() - beforeRender,
|
|
297
|
-
})
|
|
298
248
|
} catch (err) {
|
|
299
249
|
renderFailed = true
|
|
300
|
-
await updateLedgerEntry(featureDir, prefix, 'wb-render:phase2', {
|
|
301
|
-
status: 'failed', completed_at: '__TS__',
|
|
302
|
-
phase_delta_tokens: budget.spent() - beforeRender,
|
|
303
|
-
error_summary: normalizeError(err),
|
|
304
|
-
exit_code: err._exitCode ?? renderResult?.exitCode ?? null,
|
|
305
|
-
})
|
|
306
250
|
}
|
|
307
|
-
|
|
251
|
+
const renderTokens = budget.spent() - beforeRender
|
|
252
|
+
await agent(
|
|
253
|
+
`Run this shell command via Bash. If the --dir path contains spaces, enclose it in double quotes.\n\nai-toolkit ledger close --dir ${featureDir} --prefix ${prefix} --agent ${wbRenderKey} --tokens ${renderTokens} --attempt 1\n\nReturn no output.`,
|
|
254
|
+
{ label: 'ledger-close-wb-render', phase: 'Work Breakdown', model: 'haiku' }
|
|
255
|
+
)
|
|
256
|
+
tokenLedger.push({ agent: 'wb-render', model: 'haiku', phase_delta_tokens: renderTokens })
|
|
308
257
|
}
|
|
309
258
|
|
|
310
259
|
tokenLedger.push({ agent: 'wb-validate', model: 'haiku', phase_delta_tokens: validateTokens })
|