@dtlabs/ai-toolkit 0.12.0 → 0.14.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 +72 -0
- package/bin/cli.js +851 -9
- package/docs/task-executor-bootstrap.md +195 -0
- package/docs/task-executor-cli.md +319 -0
- package/docs/workflow-control-plane.md +95 -0
- package/lib/agent-registry.js +1018 -0
- package/lib/execution-ledger.js +283 -7
- package/lib/task-executor/claude-process.js +563 -0
- package/lib/task-executor/git.js +1362 -0
- package/lib/task-executor/index.js +3729 -0
- package/lib/task-executor/ownership.js +590 -0
- package/lib/task-executor/plan.js +725 -0
- package/lib/task-executor/store.js +1164 -0
- package/lib/workflow-artifacts.js +102 -0
- package/lib/workflow-control.js +219 -0
- package/lib/workflow-runner.js +39 -0
- package/package.json +1 -1
- package/src/claude/agents/{concurrency-safety-assessment.md → gaia-concurrency-safety-assessment.md} +1 -1
- package/src/claude/agents/{define-feature.md → gaia-define-feature.md} +1 -1
- package/src/claude/agents/{dependency-injection-refactoring.md → gaia-dependency-injection-refactoring.md} +1 -1
- package/src/claude/agents/{dependency-supply-chain-security.md → gaia-dependency-supply-chain-security.md} +1 -1
- package/src/claude/agents/{developer-backend.md → gaia-developer-backend.md} +1 -1
- package/src/claude/agents/{developer-frontend.md → gaia-developer-frontend.md} +1 -1
- package/src/claude/agents/{developer-testing.md → gaia-developer-testing.md} +1 -1
- package/src/claude/agents/{domain-model-refactoring.md → gaia-domain-model-refactoring.md} +1 -1
- package/src/claude/agents/{generate-requirements.md → gaia-generate-requirements.md} +1 -1
- package/src/claude/agents/{generate-tech-spec.md → gaia-generate-tech-spec.md} +1 -1
- package/src/claude/agents/{generate-work-breakdown.md → gaia-generate-work-breakdown.md} +5 -5
- package/src/claude/agents/{generic-software-assessment.md → gaia-generic-software-assessment.md} +1 -1
- package/src/claude/agents/{god-class-decomposition.md → gaia-god-class-decomposition.md} +1 -1
- package/src/claude/agents/{init-agents-md.md → gaia-init-agents-md.md} +1 -1
- package/src/claude/agents/{install-toolkit.md → gaia-install-toolkit.md} +1 -1
- package/src/claude/agents/{intervention-documentation-standard.md → gaia-intervention-documentation-standard.md} +10 -10
- package/src/claude/agents/{layered-architecture-assessment.md → gaia-layered-architecture-assessment.md} +1 -1
- package/src/claude/agents/{review-solution.md → gaia-review-solution.md} +1 -1
- package/src/claude/agents/{security-hardening.md → gaia-security-hardening.md} +1 -1
- package/src/claude/agents/{validate-feature-docs.md → gaia-validate-feature-docs.md} +2 -2
- package/src/claude/agents/{validate-work-breakdown-semantic.md → gaia-validate-work-breakdown-semantic.md} +1 -1
- package/src/claude/commands/next-task.md +4 -4
- package/src/claude/skills/assess-codebase/SKILL.md +9 -103
- package/src/claude/skills/define-feature/SKILL.md +2 -2
- package/src/claude/skills/hi-gaia/SKILL.md +1 -1
- package/src/claude/skills/implement-feature/SKILL.md +131 -38
- package/src/claude/skills/init-agents/SKILL.md +2 -2
- package/src/claude/skills/install-toolkit/SKILL.md +2 -2
- package/src/claude/workflows/am-phase1.js +43 -294
- package/src/claude/workflows/am-phase2.js +10 -164
- package/src/claude/workflows/pm-phase1.js +45 -287
- package/src/claude/workflows/pm-phase2.js +51 -511
- package/src/claude/workflows/pm-phase3.js +5 -767
|
@@ -1,293 +1,51 @@
|
|
|
1
1
|
export const meta = {
|
|
2
|
+
controlPlaneVersion: 1,
|
|
2
3
|
name: 'pm-phase1',
|
|
3
|
-
description: '
|
|
4
|
-
phases: [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
`You are a discovery agent for the feature delivery pipeline.
|
|
22
|
-
|
|
23
|
-
Read the feature.md file at: ${featurePath}
|
|
24
|
-
|
|
25
|
-
Extract:
|
|
26
|
-
1. The feature PREFIX from the directory name (pattern [A-Z]+-[0-9]+, e.g. FTR-009)
|
|
27
|
-
2. The feature directory path (parent of feature.md)
|
|
28
|
-
3. Whether these files exist and are NOT stale vs feature.md (stale = older mtime):
|
|
29
|
-
- {PREFIX}-Requirements.md
|
|
30
|
-
- {PREFIX}-Tech-Spec.md
|
|
31
|
-
- {PREFIX}-Validation-Report.md
|
|
32
|
-
|
|
33
|
-
Return a JSON object:
|
|
34
|
-
{
|
|
35
|
-
"prefix": "FTR-009",
|
|
36
|
-
"feature_dir": "internal_docs/features/FTR-009-workflow-orchestrators",
|
|
37
|
-
"needs_requirements": true,
|
|
38
|
-
"needs_tech_spec": true,
|
|
39
|
-
"needs_validation": true,
|
|
40
|
-
"force": ${force}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
If force=true, set all needs_* to true regardless of file state.
|
|
44
|
-
If feature.md does not exist, return { "error": "feature.md not found: ${featurePath}" }.`,
|
|
45
|
-
{
|
|
46
|
-
label: 'discovery',
|
|
47
|
-
phase: 'Discovery',
|
|
48
|
-
schema: {
|
|
49
|
-
type: 'object',
|
|
50
|
-
properties: {
|
|
51
|
-
prefix: { type: 'string' },
|
|
52
|
-
feature_dir: { type: 'string' },
|
|
53
|
-
needs_requirements: { type: 'boolean' },
|
|
54
|
-
needs_tech_spec: { type: 'boolean' },
|
|
55
|
-
needs_validation: { type: 'boolean' },
|
|
56
|
-
force: { type: 'boolean' },
|
|
57
|
-
error: { type: 'string' },
|
|
58
|
-
},
|
|
59
|
-
required: ['prefix', 'feature_dir'],
|
|
60
|
-
},
|
|
4
|
+
description: 'Deterministic documentation workflow; returns Gate 1 evidence.',
|
|
5
|
+
phases: [{ title: 'Discovery' }, { title: 'Requirements' }, { title: 'Tech-Spec' }, { title: 'Validation' }],
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const c = control
|
|
9
|
+
const { featurePath, featureDir, prefix } = c.feature(args[0])
|
|
10
|
+
const force = args.includes('--force')
|
|
11
|
+
return c.run(meta.name, featureDir, prefix, async () => {
|
|
12
|
+
const file = suffix => `${featureDir}/${prefix}-${suffix}.md`
|
|
13
|
+
const fresh = (output, inputs = [featurePath]) => c.exists(output) && c.read(output).trim().length > 0 && inputs.every(input => c.exists(input) && c.mtime(output) >= c.mtime(input))
|
|
14
|
+
const reqId = 'gaia.agent.planner.requirements'
|
|
15
|
+
const specId = 'gaia.agent.planner.tech-spec'
|
|
16
|
+
const valId = 'gaia.agent.planner.validate-feature-docs'
|
|
17
|
+
let changed = false
|
|
18
|
+
if (force || !fresh(file('Requirements'))) {
|
|
19
|
+
await c.worker(reqId, featurePath)
|
|
20
|
+
if (!c.exists(file('Requirements'))) throw new Error('Requirements output missing')
|
|
21
|
+
changed = true
|
|
61
22
|
}
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const { prefix, feature_dir } = discoveryResult
|
|
69
|
-
|
|
70
|
-
log(`Prefix: ${prefix} | Dir: ${feature_dir}`)
|
|
71
|
-
log(`needs_requirements=${discoveryResult.needs_requirements} needs_tech_spec=${discoveryResult.needs_tech_spec}`)
|
|
72
|
-
|
|
73
|
-
// ── Ensure ledger file exists (US-02-T02) ─────────────────────────────────────
|
|
74
|
-
// If define-feature was not used, the ledger file will not exist yet.
|
|
75
|
-
// Touch it with an empty array so the ledger facade can always assume a valid base.
|
|
76
|
-
const ledgerFilePath = `${feature_dir}/${prefix}-token-ledger.json`
|
|
77
|
-
await agent(
|
|
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.`,
|
|
79
|
-
{ label: 'ensure-ledger', phase: 'Discovery', model: 'haiku' }
|
|
80
|
-
)
|
|
81
|
-
log(`Ledger ensured at ${ledgerFilePath}`)
|
|
82
|
-
|
|
83
|
-
// ── generate-requirements ─────────────────────────────────────────────────────
|
|
84
|
-
phase('Requirements')
|
|
85
|
-
|
|
86
|
-
const tokenLedger = []
|
|
87
|
-
const errors = []
|
|
88
|
-
|
|
89
|
-
if (discoveryResult.needs_requirements) {
|
|
90
|
-
const reqKey = 'generate-requirements:phase1'
|
|
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
|
-
)
|
|
95
|
-
const beforeReq = budget.spent()
|
|
96
|
-
const reqResult = await agent(featurePath, { agentType: 'generate-requirements', label: 'generate-requirements', phase: 'Requirements' })
|
|
97
|
-
const reqTokens = budget.spent() - beforeReq
|
|
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
|
-
)
|
|
102
|
-
tokenLedger.push({ agent: 'generate-requirements', model: 'haiku', phase_delta_tokens: reqTokens })
|
|
103
|
-
log(`generate-requirements done — phase delta: ${reqTokens} tokens`)
|
|
104
|
-
} else {
|
|
105
|
-
log('generate-requirements: fresh — skipped')
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ── generate-tech-spec ────────────────────────────────────────────────────────
|
|
109
|
-
phase('Tech-Spec')
|
|
110
|
-
|
|
111
|
-
if (discoveryResult.needs_tech_spec) {
|
|
112
|
-
const specKey = 'generate-tech-spec:phase1'
|
|
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
|
-
)
|
|
117
|
-
const beforeSpec = budget.spent()
|
|
118
|
-
const specResult = await agent(featurePath, { agentType: 'generate-tech-spec', label: 'generate-tech-spec', phase: 'Tech-Spec' })
|
|
119
|
-
const specTokens = budget.spent() - beforeSpec
|
|
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
|
-
)
|
|
124
|
-
tokenLedger.push({ agent: 'generate-tech-spec', model: 'haiku', phase_delta_tokens: specTokens })
|
|
125
|
-
log(`generate-tech-spec done — phase delta: ${specTokens} tokens`)
|
|
126
|
-
} else {
|
|
127
|
-
log('generate-tech-spec: fresh — skipped')
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ── validate-feature-docs (revision loop, max 3 cycles) ──────────────────────
|
|
131
|
-
phase('Validation')
|
|
132
|
-
|
|
133
|
-
let validationSummary = 'skipped'
|
|
134
|
-
let lastValText = ''
|
|
135
|
-
const MAX_CYCLES = 3
|
|
136
|
-
|
|
137
|
-
for (let cycle = 1; cycle <= MAX_CYCLES; cycle++) {
|
|
138
|
-
log(`validate-feature-docs cycle ${cycle}`)
|
|
139
|
-
const valKey = `validate-feature-docs:phase1:cycle${cycle}`
|
|
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
|
-
)
|
|
144
|
-
const beforeVal = budget.spent()
|
|
145
|
-
const valResult = await agent(featurePath, { agentType: 'validate-feature-docs', label: `validate-feature-docs (cycle ${cycle})`, phase: 'Validation' })
|
|
146
|
-
const valTokens = budget.spent() - beforeVal
|
|
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
|
-
)
|
|
151
|
-
tokenLedger.push({ agent: `validate-feature-docs (cycle ${cycle})`, model: 'haiku', phase_delta_tokens: valTokens })
|
|
152
|
-
|
|
153
|
-
// valResult is the agent's text output — check for gap indicators
|
|
154
|
-
// Use only 'MISSING:' as the gap signal: 'gaps found' also matches 'ZERO GAPS FOUND'
|
|
155
|
-
const resultText = typeof valResult === 'string' ? valResult : JSON.stringify(valResult)
|
|
156
|
-
lastValText = resultText
|
|
157
|
-
const hasGaps = resultText.includes('MISSING:')
|
|
158
|
-
|
|
159
|
-
if (!hasGaps) {
|
|
160
|
-
validationSummary = `0 gaps (clean on cycle ${cycle})`
|
|
161
|
-
log(`Validation clean on cycle ${cycle}`)
|
|
162
|
-
break
|
|
23
|
+
if (force || changed || !fresh(file('Tech-Spec'), [featurePath, file('Requirements')])) {
|
|
24
|
+
await c.worker(specId, featurePath)
|
|
25
|
+
if (!c.exists(file('Tech-Spec'))) throw new Error('Tech-Spec output missing')
|
|
26
|
+
changed = true
|
|
163
27
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
28
|
+
let validationSummary = 'skipped (fresh)'
|
|
29
|
+
if (force || changed || !fresh(file('Validation-Report'), [featurePath, file('Requirements'), file('Tech-Spec')])) {
|
|
30
|
+
for (let cycle = 1; cycle <= 3; cycle++) {
|
|
31
|
+
const result = await c.worker(valId, featurePath + '\nValidate only; the host owns the revision loop. Write the validation report and return valid plus a findings array (one string per remaining gap). Do not dispatch other agents.', { label: `validation:${cycle}`, schema: { type: 'object', properties: { valid: { type: 'boolean' }, findings: { type: 'array', items: { type: 'string' } } }, required: ['valid', 'findings'] } })
|
|
32
|
+
const text = result.findings.join('\n')
|
|
33
|
+
if (result.valid && result.findings.length === 0) {
|
|
34
|
+
if (!fresh(file('Validation-Report'), [featurePath, file('Requirements'), file('Tech-Spec')])) throw new Error('Validation agent did not produce its report')
|
|
35
|
+
validationSummary = `0 gaps (clean on cycle ${cycle})`
|
|
36
|
+
break
|
|
37
|
+
}
|
|
38
|
+
if (cycle === 3) throw new Error('Validation gaps remain after 3 cycles')
|
|
39
|
+
if (!text.includes('Tech-Spec') || text.includes('Requirements')) await c.worker(reqId, featurePath)
|
|
40
|
+
if (!text.includes('Requirements') || text.includes('Tech-Spec')) await c.worker(specId, featurePath)
|
|
174
41
|
}
|
|
175
|
-
} else {
|
|
176
|
-
validationSummary = 'gaps remain after 3 cycles'
|
|
177
|
-
errors.push('validate-feature-docs: gaps remain after 3 revision cycles')
|
|
178
42
|
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
await agent(
|
|
189
|
-
`Ensure the Validation Report file exists on disk for this feature delivery run.
|
|
190
|
-
|
|
191
|
-
File path: ${validationReportPath}
|
|
192
|
-
|
|
193
|
-
Steps:
|
|
194
|
-
1. Check whether the file already exists (use Read or Glob).
|
|
195
|
-
2. If it ALREADY EXISTS: do nothing, return "exists".
|
|
196
|
-
3. If it DOES NOT EXIST: write it now using the Write tool, based on the validation outcome below.
|
|
197
|
-
Get the current date via Bash: run \`date -u +"%Y-%m-%d"\`.
|
|
198
|
-
|
|
199
|
-
Validation outcome summary: ${validationSummary}
|
|
200
|
-
|
|
201
|
-
Validation agent output (source of truth for gaps found/resolved):
|
|
202
|
-
──────────────────────────────────────────────────
|
|
203
|
-
${lastValText.slice(0, 4000)}
|
|
204
|
-
──────────────────────────────────────────────────
|
|
205
|
-
|
|
206
|
-
File format to write (fill from the outcome above; if the run was clean, mark both documents Clean with 0 gaps):
|
|
207
|
-
|
|
208
|
-
# Validation Report — ${prefix}
|
|
209
|
-
|
|
210
|
-
## Summary
|
|
211
|
-
| Document | Gaps found | Gaps resolved | Status |
|
|
212
|
-
|----------|-----------|--------------|--------|
|
|
213
|
-
| ${prefix}-Requirements.md | N | N | Clean / Gaps remain |
|
|
214
|
-
| ${prefix}-Tech-Spec.md | N | N | Clean / Gaps remain |
|
|
215
|
-
|
|
216
|
-
## Gaps found and resolved
|
|
217
|
-
(derive from the validation output above; write "(none)" if clean)
|
|
218
|
-
|
|
219
|
-
## Remaining gaps (if any)
|
|
220
|
-
(list any unresolved gaps, or "(none)")
|
|
221
|
-
|
|
222
|
-
## Validation date
|
|
223
|
-
{date from Bash}
|
|
224
|
-
|
|
225
|
-
Return "written" if you created the file, or "exists" if it was already present.`,
|
|
226
|
-
{ label: 'ensure-validation-report', phase: 'Validation' }
|
|
227
|
-
)
|
|
228
|
-
log(`Validation report ensured at ${validationReportPath}`)
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// ── Write process-log (phase 1 snapshot) ─────────────────────────────────────
|
|
232
|
-
const reqEntry = tokenLedger.find(e => e.agent === 'generate-requirements')
|
|
233
|
-
const specEntry = tokenLedger.find(e => e.agent === 'generate-tech-spec')
|
|
234
|
-
const valEntries = tokenLedger.filter(e => e.agent.startsWith('validate-feature-docs'))
|
|
235
|
-
const phase1Events = [
|
|
236
|
-
`pm-phase1 START — documentation phase`,
|
|
237
|
-
reqEntry
|
|
238
|
-
? `Agent DONE: generate-requirements — tokens: ${reqEntry.phase_delta_tokens}`
|
|
239
|
-
: `generate-requirements: skipped (fresh)`,
|
|
240
|
-
specEntry
|
|
241
|
-
? `Agent DONE: generate-tech-spec — tokens: ${specEntry.phase_delta_tokens}`
|
|
242
|
-
: `generate-tech-spec: skipped (fresh)`,
|
|
243
|
-
...valEntries.map(e => `Agent DONE: ${e.agent} — tokens: ${e.phase_delta_tokens}`),
|
|
244
|
-
`Validation result: ${validationSummary}`,
|
|
245
|
-
`APPROVAL REQUESTED — Gate 1`,
|
|
246
|
-
].join('\n')
|
|
247
|
-
|
|
248
|
-
await agent(
|
|
249
|
-
`Create the process-log file for this feature delivery run.
|
|
250
|
-
|
|
251
|
-
File path: ${feature_dir}/${prefix}-process-log.txt
|
|
252
|
-
|
|
253
|
-
Steps:
|
|
254
|
-
1. Get current UTC datetime via Bash: run \`date -u +"%Y-%m-%dT%H:%M:%S"\`
|
|
255
|
-
2. Read feature.md at: ${featurePath} — extract the feature title (first H1 heading after the frontmatter).
|
|
256
|
-
3. Write the file using the Write tool. Use the datetime from step 1 for ALL timestamps.
|
|
257
|
-
Format each event line as: [{datetime}] {event text}
|
|
258
|
-
|
|
259
|
-
File structure:
|
|
260
|
-
════════════════════════════════════════════════════════
|
|
261
|
-
RUN STARTED — {datetime}
|
|
262
|
-
Feature: ${prefix} — {title from step 2}
|
|
263
|
-
════════════════════════════════════════════════════════
|
|
264
|
-
{one line per event below, each prefixed with [{datetime}]}
|
|
265
|
-
|
|
266
|
-
Events to log:
|
|
267
|
-
${phase1Events}`,
|
|
268
|
-
{ label: 'write-process-log', phase: 'Validation' }
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
// ── Build gate1_payload ───────────────────────────────────────────────────────
|
|
272
|
-
const gate1Payload = {
|
|
273
|
-
prefix,
|
|
274
|
-
feature_dir,
|
|
275
|
-
feature_path: featurePath,
|
|
276
|
-
requirements: {
|
|
277
|
-
path: `${feature_dir}/${prefix}-Requirements.md`,
|
|
278
|
-
summary: `${prefix}-Requirements.md — generated`,
|
|
279
|
-
},
|
|
280
|
-
tech_spec: {
|
|
281
|
-
path: `${feature_dir}/${prefix}-Tech-Spec.md`,
|
|
282
|
-
summary: `${prefix}-Tech-Spec.md — generated`,
|
|
283
|
-
},
|
|
284
|
-
validation: {
|
|
285
|
-
path: `${feature_dir}/${prefix}-Validation-Report.md`,
|
|
286
|
-
summary: validationSummary,
|
|
287
|
-
},
|
|
288
|
-
token_ledger: tokenLedger,
|
|
289
|
-
errors,
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
log(`pm-phase1 complete — gate1_payload ready`)
|
|
293
|
-
return gate1Payload
|
|
43
|
+
c.append(`${featureDir}/${prefix}-process-log.txt`, `[${new Date().toISOString()}] pm-phase1: ${validationSummary}; Gate 1 approval requested\n`)
|
|
44
|
+
return {
|
|
45
|
+
prefix, feature_dir: featureDir, feature_path: featurePath,
|
|
46
|
+
requirements: { path: file('Requirements'), summary: 'Requirements ready' },
|
|
47
|
+
tech_spec: { path: file('Tech-Spec'), summary: 'Tech-Spec ready' },
|
|
48
|
+
validation: { path: file('Validation-Report'), summary: validationSummary },
|
|
49
|
+
token_ledger: c.tokenLedger, errors: [],
|
|
50
|
+
}
|
|
51
|
+
})
|