@dtlabs/ai-toolkit 0.11.0 → 0.13.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 +65 -0
- package/bin/cli.js +757 -68
- package/lib/agent-registry.js +1018 -0
- package/lib/execution-ledger.js +609 -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} +37 -61
- 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} +1 -1
- 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/scripts/wb-render.js +101 -2
- package/src/claude/scripts/wb-validate.js +32 -2
- package/src/claude/skills/assess-codebase/SKILL.md +1 -1
- 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 +190 -10
- package/src/claude/skills/init-agents/SKILL.md +2 -2
- package/src/claude/skills/install-toolkit/SKILL.md +2 -2
- package/src/claude/workflows/pm-phase1.js +94 -73
- package/src/claude/workflows/pm-phase2.js +118 -108
- package/src/claude/workflows/pm-phase3.js +219 -75
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: define-feature
|
|
2
|
+
name: gaia-define-feature
|
|
3
3
|
description: "Define Feature — grills the user with targeted questions to define a new feature, then writes feature.md in docs/features/FTR-XXX-slug/. Output: feature.md ready for /implement-feature"
|
|
4
4
|
model: sonnet
|
|
5
5
|
---
|
|
@@ -80,56 +80,53 @@ Ask the user to **confirm or correct the draft**. Then grill ONLY on the `❓` g
|
|
|
80
80
|
|
|
81
81
|
## Phase 1 — Setup
|
|
82
82
|
|
|
83
|
-
### 1a.
|
|
83
|
+
### 1a. Resolve the features root (MANDATORY — single source of truth)
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
Before any file-system operation, run the following command **once** via Bash and capture its stdout into `featuresRoot`:
|
|
86
86
|
|
|
87
|
+
```bash
|
|
88
|
+
featuresRoot=$(ai-toolkit resolve-features-root) && echo "$featuresRoot"
|
|
87
89
|
```
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
|
|
91
|
+
If the command exits non-zero, stop immediately and report the error to the user — do not proceed.
|
|
92
|
+
|
|
93
|
+
This single captured value (`featuresRoot`) is the **sole source of truth** for the features root in every subsequent step. Do **not** hard-code `docs/features/`, `internal_docs/features/`, or any other path. Both the directory under which `feature.md` is written (step 1d) and the `--dir` argument passed to the ledger facade must use this exact value — they must always agree, with no divergent or duplicate roots.
|
|
94
|
+
|
|
95
|
+
### 1b. Discover the next FTR number
|
|
96
|
+
|
|
97
|
+
Scan `{featuresRoot}` for existing folders matching the pattern `FTR-[0-9]+*`. Extract the highest number and increment by 1. If no folders exist, start at `FTR-001`.
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
{featuresRoot}/FTR-001-user-management/ → max = 1
|
|
101
|
+
{featuresRoot}/FTR-002-product-catalog/ → max = 2
|
|
90
102
|
→ next = FTR-003
|
|
91
103
|
```
|
|
92
104
|
|
|
93
|
-
###
|
|
105
|
+
### 1c. Ask for a feature name
|
|
94
106
|
|
|
95
107
|
Ask the user: **"What is the name of this feature?"** (short, descriptive, in their language). Use it to build the folder slug in kebab-case.
|
|
96
108
|
|
|
97
109
|
Example: "Supplier Onboarding" → `FTR-003-supplier-onboarding`
|
|
98
110
|
|
|
99
|
-
###
|
|
111
|
+
### 1d. Create feature directory and open ledger entry
|
|
100
112
|
|
|
101
|
-
Once you know the PREFIX (from
|
|
113
|
+
Once you know the PREFIX (from 1b) and the feature slug (from 1c), do the following **before asking any grilling questions**:
|
|
102
114
|
|
|
103
|
-
1. Compute the
|
|
104
|
-
- `featureDir` = `
|
|
105
|
-
- `
|
|
115
|
+
1. Compute `featureDir` using the captured `featuresRoot`:
|
|
116
|
+
- `featureDir` = `{featuresRoot}/{PREFIX}-{slug}` (e.g. `{featuresRoot}/FTR-003-supplier-onboarding`)
|
|
117
|
+
- This path is also the `--dir` value for every `ai-toolkit ledger` call that follows.
|
|
106
118
|
|
|
107
119
|
2. Create the feature directory via Bash:
|
|
108
120
|
```bash
|
|
109
|
-
mkdir -p {featureDir}
|
|
121
|
+
mkdir -p "{featureDir}"
|
|
110
122
|
```
|
|
111
123
|
|
|
112
|
-
3.
|
|
124
|
+
3. Open the ledger entry via the facade. Run the following command via Bash (quote the `--dir` path to handle spaces):
|
|
113
125
|
```bash
|
|
114
|
-
|
|
126
|
+
ai-toolkit ledger open --dir "{featureDir}" --prefix {PREFIX} --agent define-feature:define --phase define --model sonnet --attempt 1
|
|
115
127
|
```
|
|
116
128
|
|
|
117
|
-
|
|
118
|
-
```json
|
|
119
|
-
[
|
|
120
|
-
{
|
|
121
|
-
"agent": "define-feature:define",
|
|
122
|
-
"phase": "define",
|
|
123
|
-
"model": "sonnet",
|
|
124
|
-
"status": "running",
|
|
125
|
-
"phase_delta_tokens": 0,
|
|
126
|
-
"started_at": "<started_at from step 3>",
|
|
127
|
-
"completed_at": null
|
|
128
|
-
}
|
|
129
|
-
]
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
The ledger records that the define-feature agent is now running. Proceed to Phase 2.
|
|
129
|
+
The ledger now records that the define-feature agent is running. Proceed to Phase 2.
|
|
133
130
|
|
|
134
131
|
---
|
|
135
132
|
|
|
@@ -254,12 +251,12 @@ Synthesize all answers into a structured `feature.md` file.
|
|
|
254
251
|
### Output path
|
|
255
252
|
|
|
256
253
|
```
|
|
257
|
-
|
|
254
|
+
{featuresRoot}/{PREFIX}-{slug}/feature.md
|
|
258
255
|
```
|
|
259
256
|
|
|
260
|
-
Example: `
|
|
257
|
+
Example: `{featuresRoot}/FTR-003-supplier-onboarding/feature.md`
|
|
261
258
|
|
|
262
|
-
The directory was created in Phase
|
|
259
|
+
The directory was created in Phase 1d using `featuresRoot`. If for any reason it doesn't exist, create it now using the same `featuresRoot` path — do not substitute a different root.
|
|
263
260
|
|
|
264
261
|
### feature.md template
|
|
265
262
|
|
|
@@ -352,34 +349,13 @@ For each entity: name, key fields (name, type, constraints), relationships.
|
|
|
352
349
|
|
|
353
350
|
### 4b. Finalize ledger entry
|
|
354
351
|
|
|
355
|
-
After writing `feature.md`,
|
|
352
|
+
After writing `feature.md`, close the ledger entry via the facade. Run the following command via Bash (quote the `--dir` path to handle spaces):
|
|
356
353
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
```
|
|
354
|
+
```bash
|
|
355
|
+
ai-toolkit ledger close --dir "{featureDir}" --prefix {PREFIX} --agent define-feature:define --attempt 1
|
|
356
|
+
```
|
|
361
357
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
3. Write the updated ledger file using the Write tool, replacing the entry's fields:
|
|
365
|
-
- `"status"`: `"done"`
|
|
366
|
-
- `"completed_at"`: the timestamp captured in step 1
|
|
367
|
-
- `"phase_delta_tokens"`: leave as `0` — token measurement is not available to the agent directly
|
|
368
|
-
|
|
369
|
-
Example final ledger content:
|
|
370
|
-
```json
|
|
371
|
-
[
|
|
372
|
-
{
|
|
373
|
-
"agent": "define-feature:define",
|
|
374
|
-
"phase": "define",
|
|
375
|
-
"model": "sonnet",
|
|
376
|
-
"status": "done",
|
|
377
|
-
"phase_delta_tokens": 0,
|
|
378
|
-
"started_at": "<original started_at>",
|
|
379
|
-
"completed_at": "<completed_at from step 1>"
|
|
380
|
-
}
|
|
381
|
-
]
|
|
382
|
-
```
|
|
358
|
+
**Important:** `--tokens` is intentionally omitted. The ledger facade records `phase_delta_tokens` as `null` when `--tokens` is not supplied. `define-feature` is an interactive/LLM activity whose token consumption cannot be observed from within the agent itself — do **not** pass `0` or any estimate.
|
|
383
359
|
|
|
384
360
|
---
|
|
385
361
|
|
|
@@ -392,7 +368,7 @@ After writing `feature.md`:
|
|
|
392
368
|
3. Tell the user the next step:
|
|
393
369
|
|
|
394
370
|
```
|
|
395
|
-
✅ feature.md written at
|
|
371
|
+
✅ feature.md written at {featuresRoot}/{PREFIX}-{slug}/feature.md
|
|
396
372
|
|
|
397
373
|
Summary:
|
|
398
374
|
Actors: N
|
|
@@ -400,7 +376,7 @@ Summary:
|
|
|
400
376
|
Acceptance criteria: N (Must: N, Should: N, Could: N)
|
|
401
377
|
Open questions: N
|
|
402
378
|
|
|
403
|
-
Next step: run /implement-feature
|
|
379
|
+
Next step: run /implement-feature {featuresRoot}/{PREFIX}-{slug}/feature.md
|
|
404
380
|
to start the full pipeline (requirements → spec → implementation → PR).
|
|
405
381
|
```
|
|
406
382
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: dependency-injection-refactoring
|
|
2
|
+
name: gaia-dependency-injection-refactoring
|
|
3
3
|
description: "Dependency Injection Refactoring — guides the incremental conversion of tightly coupled or statically accessed dependencies to constructor-injected services, preserving build integrity at every step. Language-agnostic; reads AGENTS.md for framework-specific DI patterns. Input: target classes from intervention document"
|
|
4
4
|
model: sonnet
|
|
5
5
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: dependency-supply-chain-security
|
|
2
|
+
name: gaia-dependency-supply-chain-security
|
|
3
3
|
description: "Dependency Supply Chain Security — guides the implementation of dependency integrity controls: trusted package sources, deterministic restore via lock files, unused dependency audit, and SCA integration in CI/CD pipelines. Works with npm, pip, NuGet, Maven, and other package managers; reads AGENTS.md for project stack. Output: remediated configuration files + CI/CD pipeline changes"
|
|
4
4
|
model: sonnet
|
|
5
5
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: domain-model-refactoring
|
|
2
|
+
name: gaia-domain-model-refactoring
|
|
3
3
|
description: "Domain Model Refactoring — guides the decomposition of monolithic domain model files, introduction of type hierarchies for structurally similar types, and alignment of model names with domain ubiquitous language. Language-agnostic; reads AGENTS.md for project conventions. Input: target model directory from intervention document"
|
|
4
4
|
model: sonnet
|
|
5
5
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: generate-work-breakdown
|
|
2
|
+
name: gaia-generate-work-breakdown
|
|
3
3
|
description: "Generates a structured work breakdown (User Stories + Tasks) from validated and approved Requirements and Tech-Spec. Input: path to feature.md"
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Glob, Grep, Write
|
|
@@ -24,7 +24,7 @@ The user provides the path to a `feature.md` file. From the same directory, read
|
|
|
24
24
|
```
|
|
25
25
|
Cannot generate work breakdown: `{file}` not found.
|
|
26
26
|
The work breakdown requires validated and approved Requirements + Tech-Spec.
|
|
27
|
-
Run /
|
|
27
|
+
Run /implement-feature to orchestrate the full pipeline (including validation and approval gates).
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
---
|
|
@@ -63,7 +63,7 @@ Every task must be the **smallest independently implementable, verifiable, and c
|
|
|
63
63
|
|
|
64
64
|
- **One observable outcome** — the task produces exactly one concrete artifact or behavioral change (one file, one endpoint, one migration, one test suite for one check). State it in the `outcome` field as a factual sentence describing what exists after the task is done.
|
|
65
65
|
- **One domain** — choose exactly one: `BE`, `FE`, `DB`, `DevOps`, `INFRA`, or `TEST`.
|
|
66
|
-
- **One agent type** — choose exactly one: `developer-backend`, `developer-frontend`, `developer-testing`, `developer-database
|
|
66
|
+
- **One agent type** — choose exactly one: `developer-backend`, `developer-frontend`, `developer-testing`, or `review-solution`. (`developer-database` is deprecated — use `developer-backend` for DB domain tasks.)
|
|
67
67
|
- **One commit** — supply a single `commit.subject` describing the change.
|
|
68
68
|
- **Estimated ≤ 15 minutes of agent time** — this is the target. If a task cannot be scoped to ≤ 15 minutes, split it further. Tasks up to 20 minutes are acceptable but above target. Tasks over 30 minutes are invalid and will be rejected by the validator.
|
|
69
69
|
|
|
@@ -126,7 +126,7 @@ Decomposition strategy by domain:
|
|
|
126
126
|
| `title` | string | Short descriptive title; must not contain `\|`, CR, or LF |
|
|
127
127
|
| `outcome` | string | Single observable outcome — what exists after this task is done |
|
|
128
128
|
| `domain` | string | One of: `BE`, `FE`, `DB`, `DevOps`, `INFRA`, `TEST` |
|
|
129
|
-
| `agentType` | string | One of: `developer-backend`, `developer-frontend`, `developer-testing`, `developer-database
|
|
129
|
+
| `agentType` | string | One of: `developer-backend`, `developer-frontend`, `developer-testing`, `review-solution` (deprecated: `developer-database` — maps to `developer-backend`) |
|
|
130
130
|
| `dependsOn` | array of strings | Task IDs this task depends on; may be empty `[]`; all IDs must be defined within this same JSON |
|
|
131
131
|
| `acceptanceCriteria` | array of strings | AC IDs from Requirements that this task covers; may be empty `[]` |
|
|
132
132
|
| `verification` | object | `{ "commands": ["..."] }` — one or more shell commands that verify the task output; array must be non-empty |
|
|
@@ -136,7 +136,7 @@ Decomposition strategy by domain:
|
|
|
136
136
|
| `commit` | object | `{ "type": "feat", "subject": "..." }` — subject must not contain `\|`, CR, or LF |
|
|
137
137
|
|
|
138
138
|
**Domain → agentType mapping (default):**
|
|
139
|
-
- `DB` → `developer-database`
|
|
139
|
+
- `DB` → `developer-backend` (note: `developer-database` is a deprecated alias that still resolves — do NOT use it in new Work Breakdowns)
|
|
140
140
|
- `BE`, `INFRA`, `DevOps` → `developer-backend`
|
|
141
141
|
- `FE` → `developer-frontend`
|
|
142
142
|
- `TEST` → `developer-testing`
|
package/src/claude/agents/{generic-software-assessment.md → gaia-generic-software-assessment.md}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: generic-software-assessment
|
|
2
|
+
name: gaia-generic-software-assessment
|
|
3
3
|
description: "Generic Software Assessment — performs a broad quality analysis across architecture, code quality, security, testability, observability, and DevOps. Reads AGENTS.md for project conventions. Output: {ASSESS_PREFIX}-Generic-Assessment.md"
|
|
4
4
|
tools: Read, Grep, Glob, Bash, Write
|
|
5
5
|
model: haiku
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: god-class-decomposition
|
|
2
|
+
name: gaia-god-class-decomposition
|
|
3
3
|
description: "God Class Decomposition — guides the safe, incremental decomposition of oversized classes and methods using responsibility cluster analysis, extract-method, extract-class, and parameter object refactoring. Language-agnostic; reads AGENTS.md for project conventions. Input: target class(es) from intervention document"
|
|
4
4
|
model: sonnet
|
|
5
5
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: init-agents-md
|
|
2
|
+
name: gaia-init-agents-md
|
|
3
3
|
description: "Analyzes a project codebase and generates a complete AGENTS.md file with tech stack, conventions, real code patterns, build/test commands, and hard constraints. Input: (optional) path to project root — defaults to current working directory."
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Glob, Grep, Bash, Write
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: install-toolkit
|
|
2
|
+
name: gaia-install-toolkit
|
|
3
3
|
description: "Installs the ai-toolkit into a destination project by copying agents, skills, commands, and procedures. Input: [path-to-destination] [--force] — defaults to current working directory"
|
|
4
4
|
model: sonnet
|
|
5
5
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: intervention-documentation-standard
|
|
2
|
+
name: gaia-intervention-documentation-standard
|
|
3
3
|
description: "Intervention Documentation Standard — generates structured, self-contained intervention documents from assessment findings. Each document is independently actionable by an architect or developer agent. Input: assessment findings; Output: {ASSESS_PREFIX}-INT-NNN-{slug}.md per finding + Interventions-Index.md"
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Grep, Glob, Bash, Write
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: layered-architecture-assessment
|
|
2
|
+
name: gaia-layered-architecture-assessment
|
|
3
3
|
description: "Layered Architecture Assessment — audits a codebase for layer boundary violations, missing separation of concerns, and namespace/package misalignment. Produces a violation inventory and a recommended layer model. Language-agnostic; reads AGENTS.md for project conventions. Output: {ASSESS_PREFIX}-Layer-Assessment.md"
|
|
4
4
|
tools: Read, Grep, Glob, Bash, Write
|
|
5
5
|
model: haiku
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: review-solution
|
|
2
|
+
name: gaia-review-solution
|
|
3
3
|
description: "Senior Architect — full solution review across quality, reuse, architecture, and security dimensions. Reports findings without auto-fixing. Input: scope (files, US-XX, or git diff)"
|
|
4
4
|
model: opus
|
|
5
5
|
tools: Read, Grep, Glob, Bash
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: security-hardening
|
|
2
|
+
name: gaia-security-hardening
|
|
3
3
|
description: "Security Hardening — guides the implementation of targeted security fixes: input validation at system boundaries, parameterised queries, secret management, log sanitisation, and TLS/transport configuration. Language-agnostic; reads AGENTS.md for project-specific patterns. Input: security findings from assessment"
|
|
4
4
|
model: sonnet
|
|
5
5
|
---
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: validate-feature-docs
|
|
2
|
+
name: gaia-validate-feature-docs
|
|
3
3
|
description: "Validates Requirements and Tech-Spec documents against feature.md. Triggers targeted revision of failing documents if gaps are found. Input: path to feature.md"
|
|
4
4
|
model: haiku
|
|
5
5
|
tools: Read, Glob, Grep, Write
|
|
@@ -18,7 +18,7 @@ A QA agent that cross-references `feature.md` against `{PREFIX}-Requirements.md`
|
|
|
18
18
|
- `feature.md` — source of truth
|
|
19
19
|
- `{PREFIX}-Requirements.md`
|
|
20
20
|
- `{PREFIX}-Tech-Spec.md`
|
|
21
|
-
3. If either output document is missing, abort and report: "Cannot validate: `{file}` not found. Run /
|
|
21
|
+
3. If either output document is missing, abort and report: "Cannot validate: `{file}` not found. Run /implement-feature first."
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: validate-work-breakdown-semantic
|
|
2
|
+
name: gaia-validate-work-breakdown-semantic
|
|
3
3
|
description: "Semantic validator for Work Breakdown JSON — analyzes task coherence, scope alignment, and estimate realism. Runs after wb-validate.js exits 0. Input: path to {PREFIX}-Work-Breakdown.json"
|
|
4
4
|
model: sonnet
|
|
5
5
|
tools: Read, Glob, Grep
|
|
@@ -23,14 +23,14 @@ Steps:
|
|
|
23
23
|
|
|
24
24
|
Suggested agent: <subagent_type>
|
|
25
25
|
Suggested invocation:
|
|
26
|
-
subagent_type: <developer-backend | developer-frontend | developer-testing>
|
|
26
|
+
subagent_type: <gaia-developer-backend | gaia-developer-frontend | gaia-developer-testing>
|
|
27
27
|
prompt: <feature-md-path> <task-id>
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Domain → agent mapping:
|
|
31
|
-
- `DB`, `BE`, `INFRA` → `developer-backend`
|
|
32
|
-
- `FE` → `developer-frontend`
|
|
33
|
-
- `TEST` → `developer-testing`
|
|
31
|
+
- `DB`, `BE`, `INFRA` → `gaia-developer-backend`
|
|
32
|
+
- `FE` → `gaia-developer-frontend`
|
|
33
|
+
- `TEST` → `gaia-developer-testing`
|
|
34
34
|
|
|
35
35
|
5. If no unblocked task remains, output: `✅ All tasks are either done, in progress, or blocked. Check blockers.`
|
|
36
36
|
|
|
@@ -105,6 +105,38 @@ function sanitizeField(str) {
|
|
|
105
105
|
.trim()
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
// ── Verification-command helpers (LOSSLESS — never sanitized) ─────────────────
|
|
109
|
+
//
|
|
110
|
+
// Verification commands are executable and MUST survive verbatim: operators like
|
|
111
|
+
// `||`, shell pipes `|`, and regex alternations `grep -E 'a|b|c'` are destroyed by
|
|
112
|
+
// sanitizeField (which maps `|` → space to protect table/CSV column structure).
|
|
113
|
+
// These commands are therefore rendered in a dedicated section as fenced code
|
|
114
|
+
// blocks whose content is byte-equivalent to the source JSON. The task table shows
|
|
115
|
+
// only a reference (a count + anchor link), never a sanitized copy of a command.
|
|
116
|
+
|
|
117
|
+
function getVerificationCommands(task) {
|
|
118
|
+
const v = task && (task.verificationCommands ?? task.verification?.commands)
|
|
119
|
+
return Array.isArray(v) ? v : []
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Stable, deterministic HTML anchor id for a task's authoritative detail block.
|
|
123
|
+
// The summary table links here; the "Task Details" section renders every field.
|
|
124
|
+
function taskAnchor(id) {
|
|
125
|
+
const s = typeof id === 'string' ? id : String(id ?? '')
|
|
126
|
+
return 'task-' + s.replace(/[^A-Za-z0-9_-]/g, '-')
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Render a single command inside a fenced code block, byte-equivalent to `cmd`.
|
|
130
|
+
// The fence length is chosen to exceed the longest backtick run in the content so a
|
|
131
|
+
// command that itself contains backticks can never prematurely close the fence.
|
|
132
|
+
function fencedCommandBlock(cmd) {
|
|
133
|
+
const s = typeof cmd === 'string' ? cmd : String(cmd ?? '')
|
|
134
|
+
const runs = s.match(/`+/g) || []
|
|
135
|
+
const maxRun = runs.reduce((m, r) => Math.max(m, r.length), 0)
|
|
136
|
+
const fence = '`'.repeat(Math.max(3, maxRun + 1))
|
|
137
|
+
return `${fence}\n${s}\n${fence}`
|
|
138
|
+
}
|
|
139
|
+
|
|
108
140
|
function buildCommitSubject(task) {
|
|
109
141
|
if (!task.commit || typeof task.commit !== 'object') {
|
|
110
142
|
return 'chore: implement task'
|
|
@@ -189,8 +221,15 @@ function renderMarkdown(wb, prefix, phaseDepsMap) {
|
|
|
189
221
|
const est = mins !== null ? String(mins) : '—'
|
|
190
222
|
const depArr = Array.isArray(task.dependsOn) && task.dependsOn.length > 0 ? task.dependsOn : null
|
|
191
223
|
const deps = depArr ? depArr.join(', ') : '—'
|
|
192
|
-
|
|
193
|
-
|
|
224
|
+
// The summary table is a digest only. Verification commands are NOT rendered
|
|
225
|
+
// in-table (sanitizeField would destroy their operators). The cell links to the
|
|
226
|
+
// authoritative per-task "Task Details" section, which carries every field
|
|
227
|
+
// (outcome, acceptance criteria, estimates, grouping rationale, commit, and the
|
|
228
|
+
// lossless verification commands). See renderTaskDetails / fencedCommandBlock.
|
|
229
|
+
const verifCmds = getVerificationCommands(task)
|
|
230
|
+
const verif = verifCmds.length > 0
|
|
231
|
+
? `${verifCmds.length} cmd — [details](#${taskAnchor(task.id)})`
|
|
232
|
+
: `[details](#${taskAnchor(task.id)})`
|
|
194
233
|
return `| ${id} | ${title} | ${outcome} | ${domain} | ${est} | ${deps} | ${verif} |`
|
|
195
234
|
}
|
|
196
235
|
|
|
@@ -263,6 +302,66 @@ function renderMarkdown(wb, prefix, phaseDepsMap) {
|
|
|
263
302
|
}
|
|
264
303
|
}
|
|
265
304
|
|
|
305
|
+
// ── Task Details (AUTHORITATIVE) ──
|
|
306
|
+
// The summary tables above are a digest. This section is the authoritative,
|
|
307
|
+
// self-contained representation of every task: it renders each field integrally so
|
|
308
|
+
// the Work Breakdown Markdown (plus the dispatch CSV) is a complete deliverable —
|
|
309
|
+
// the intermediate JSON is not required by any downstream consumer.
|
|
310
|
+
//
|
|
311
|
+
// Free-text fields (title, outcome, grouping rationale, commit subject) are rendered
|
|
312
|
+
// OUTSIDE any table and are therefore preserved verbatim — including pipes, which
|
|
313
|
+
// sanitizeField would otherwise map to spaces to protect table/CSV columns.
|
|
314
|
+
// Verification commands are emitted as fenced code blocks that are byte-equivalent
|
|
315
|
+
// to the source; the fence length exceeds any backtick run in the command so a
|
|
316
|
+
// command containing backticks can never break out of its block.
|
|
317
|
+
const raw = v => (typeof v === 'string' ? v : String(v ?? ''))
|
|
318
|
+
const getTokens = task => {
|
|
319
|
+
const t = task.estimate?.tokens ?? task.tokens
|
|
320
|
+
return (t !== undefined && t !== null) ? String(t) : '—'
|
|
321
|
+
}
|
|
322
|
+
const listOrDash = arr =>
|
|
323
|
+
(Array.isArray(arr) && arr.length > 0) ? arr.join(', ') : '—'
|
|
324
|
+
|
|
325
|
+
L.push('## Task Details')
|
|
326
|
+
L.push('')
|
|
327
|
+
L.push('> Authoritative per-task detail. Every field is rendered integrally so this document, together with the dispatch CSV, is a complete deliverable requiring no separate JSON. Verification commands are preserved **verbatim** in fenced code blocks — operators such as `||`, shell pipes `|`, and regex alternations (`grep -E \'a|b|c\'`) survive byte-for-byte. Each command is an independent fenced block.')
|
|
328
|
+
L.push('')
|
|
329
|
+
for (const phase of wb.phases) {
|
|
330
|
+
for (const task of (Array.isArray(phase.tasks) ? phase.tasks : [])) {
|
|
331
|
+
const cmds = getVerificationCommands(task)
|
|
332
|
+
const mins = getAgentMinutes(task)
|
|
333
|
+
L.push(`<a id="${taskAnchor(task.id)}"></a>`)
|
|
334
|
+
L.push(`### ${raw(task.id)}`)
|
|
335
|
+
L.push('')
|
|
336
|
+
L.push(`- **Task ID:** ${raw(task.id)}`)
|
|
337
|
+
L.push(`- **Title:** ${raw(task.title)}`)
|
|
338
|
+
L.push(`- **Outcome:** ${raw(task.outcome)}`)
|
|
339
|
+
L.push(`- **Domain:** ${raw(task.domain)}`)
|
|
340
|
+
L.push(`- **Agent type:** ${raw(task.agentType)}`)
|
|
341
|
+
L.push(`- **Dependencies:** ${listOrDash(task.dependsOn)}`)
|
|
342
|
+
L.push(`- **Acceptance criteria:** ${listOrDash(task.acceptanceCriteria)}`)
|
|
343
|
+
L.push(`- **Estimate — agent minutes:** ${mins !== null ? String(mins) : '—'}`)
|
|
344
|
+
L.push(`- **Estimate — tokens:** ${getTokens(task)}`)
|
|
345
|
+
L.push(`- **Output count:** ${task.outputCount != null ? String(task.outputCount) : '—'}`)
|
|
346
|
+
L.push(`- **Grouping rationale:** ${task.groupingRationale != null ? raw(task.groupingRationale) : '—'}`)
|
|
347
|
+
L.push(`- **Commit type:** ${task.commit && task.commit.type != null ? raw(task.commit.type) : '—'}`)
|
|
348
|
+
L.push(`- **Commit scope:** ${task.commit && task.commit.scope != null ? raw(task.commit.scope) : '—'}`)
|
|
349
|
+
L.push(`- **Commit subject:** ${task.commit && task.commit.subject != null ? raw(task.commit.subject) : '—'}`)
|
|
350
|
+
L.push('')
|
|
351
|
+
L.push('**Verification commands:**')
|
|
352
|
+
L.push('')
|
|
353
|
+
if (cmds.length === 0) {
|
|
354
|
+
L.push('_No verification commands._')
|
|
355
|
+
L.push('')
|
|
356
|
+
} else {
|
|
357
|
+
for (const cmd of cmds) {
|
|
358
|
+
L.push(fencedCommandBlock(cmd))
|
|
359
|
+
L.push('')
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
266
365
|
// ── Statistics ──
|
|
267
366
|
L.push('## Statistics')
|
|
268
367
|
L.push('')
|
|
@@ -59,6 +59,36 @@ const ERRORS = {
|
|
|
59
59
|
EMPTY_PHASE: 'empty_phase', // check 23
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
// ── Markdown table row splitter ─────────────────────────────────────────────
|
|
63
|
+
// Splits a Markdown table row into cells on unescaped pipe separators only.
|
|
64
|
+
// A backslash-escaped pipe (\|) is treated as a literal pipe *inside* the cell
|
|
65
|
+
// rather than a column separator and is unescaped in the returned cell, so a
|
|
66
|
+
// criterion such as `ai-toolkit ledger open\|close\|fail\|skip` stays in a
|
|
67
|
+
// single cell and does not shift the "Related UC" column.
|
|
68
|
+
// Returns the raw split including the leading/trailing empty cells produced by
|
|
69
|
+
// the row's outer pipes, matching the previous `line.split('|')` contract so
|
|
70
|
+
// callers can keep using `.slice(1, -1)`.
|
|
71
|
+
function splitTableRow(line) {
|
|
72
|
+
const cells = []
|
|
73
|
+
let current = ''
|
|
74
|
+
for (let i = 0; i < line.length; i++) {
|
|
75
|
+
const ch = line[i]
|
|
76
|
+
if (ch === '\\' && line[i + 1] === '|') {
|
|
77
|
+
current += '|' // unescape: keep the literal pipe inside this cell
|
|
78
|
+
i++ // consume the escaped '|'
|
|
79
|
+
continue
|
|
80
|
+
}
|
|
81
|
+
if (ch === '|') {
|
|
82
|
+
cells.push(current)
|
|
83
|
+
current = ''
|
|
84
|
+
continue
|
|
85
|
+
}
|
|
86
|
+
current += ch
|
|
87
|
+
}
|
|
88
|
+
cells.push(current)
|
|
89
|
+
return cells
|
|
90
|
+
}
|
|
91
|
+
|
|
62
92
|
// ── AC table parser (prerequisite for checks 19–21) ─────────────────────────
|
|
63
93
|
|
|
64
94
|
function parseAcTable(requirementsPath) {
|
|
@@ -122,7 +152,7 @@ function parseAcTable(requirementsPath) {
|
|
|
122
152
|
}
|
|
123
153
|
|
|
124
154
|
// ── Validate column headers ────────────────────────────────────────────────
|
|
125
|
-
const headerCells = lines[tableHeaderIdx]
|
|
155
|
+
const headerCells = splitTableRow(lines[tableHeaderIdx]).slice(1, -1).map(c => c.trim())
|
|
126
156
|
if (headerCells.length < 3) {
|
|
127
157
|
process.stderr.write('Error: AC table header has fewer than 3 columns\n')
|
|
128
158
|
process.exit(2)
|
|
@@ -143,7 +173,7 @@ function parseAcTable(requirementsPath) {
|
|
|
143
173
|
if (!line.trim().startsWith('|')) break
|
|
144
174
|
|
|
145
175
|
// Skip separator rows: every cell is only dashes, colons, or spaces
|
|
146
|
-
const rawCells = line
|
|
176
|
+
const rawCells = splitTableRow(line).slice(1, -1)
|
|
147
177
|
if (rawCells.every(c => /^[\s\-:]+$/.test(c))) continue
|
|
148
178
|
|
|
149
179
|
const cells = rawCells.map(c => c.trim())
|
|
@@ -157,7 +157,7 @@ Append a horizontal rule (`---`) followed by:
|
|
|
157
157
|
|-------|------------|-------|-------------|---------------|-------|---------------|-----------------|----------|
|
|
158
158
|
| {agent} | {scope} | {model} | {est} | {actual} | {±delta} | {est_cost} | {actual_cost} | {Xmin Ys} |
|
|
159
159
|
...
|
|
160
|
-
|
|
|
160
|
+
| am-phase1 (orchestrator) | — | sonnet | 80,000 | {actual} | ±{delta} | $0.4320 | ${actual_cost} | {duration} |
|
|
161
161
|
```
|
|
162
162
|
|
|
163
163
|
Column rules:
|
|
@@ -3,10 +3,10 @@ description: "Define Feature — reads existing repo context, then grills only o
|
|
|
3
3
|
disable-model-invocation: true
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Spawn the `define-feature` agent, passing through whatever the user provided as a source reference (a backlog entry, ticket path, spec path, or free-text description). If the user gave nothing, pass an empty source.
|
|
6
|
+
Spawn the `gaia-define-feature` agent, passing through whatever the user provided as a source reference (a backlog entry, ticket path, spec path, or free-text description). If the user gave nothing, pass an empty source.
|
|
7
7
|
|
|
8
8
|
```
|
|
9
|
-
subagent_type: define-feature
|
|
9
|
+
subagent_type: gaia-define-feature
|
|
10
10
|
prompt: |
|
|
11
11
|
Start the feature definition session.
|
|
12
12
|
Source reference (may be empty): {{user arguments verbatim}}
|
|
@@ -37,7 +37,7 @@ Here's what I know and what's available for you:
|
|
|
37
37
|
- `/feature-status`, `/check-docs`, `/next-task`, `/pr-description`
|
|
38
38
|
- `/assessment-status`
|
|
39
39
|
|
|
40
|
-
**Specialized agents** (spawnable):
|
|
40
|
+
**Specialized agents** (spawnable): developer-backend, developer-frontend, developer-testing, review-solution, and more.
|
|
41
41
|
|
|
42
42
|
Let me take a look at your workspace to understand the context…
|
|
43
43
|
|