@shepai/cli 1.15.1 → 1.16.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/README.md +168 -22
- package/dist/src/application/ports/output/agents/agent-executor.interface.d.ts +2 -0
- package/dist/src/application/ports/output/agents/agent-executor.interface.d.ts.map +1 -1
- package/dist/src/application/use-cases/features/create-feature.use-case.d.ts.map +1 -1
- package/dist/src/application/use-cases/features/create-feature.use-case.js +1 -0
- package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts +2 -0
- package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.js +5 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts +8 -7
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +140 -16
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.d.ts +44 -4
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.js +86 -14
- package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/new.command.js +3 -3
- package/dist/src/presentation/cli/ui/index.d.ts +1 -0
- package/dist/src/presentation/cli/ui/index.d.ts.map +1 -1
- package/dist/src/presentation/cli/ui/index.js +1 -0
- package/dist/src/presentation/cli/ui/spinner.d.ts +21 -0
- package/dist/src/presentation/cli/ui/spinner.d.ts.map +1 -0
- package/dist/src/presentation/cli/ui/spinner.js +45 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.html +2 -2
- package/web/.next/server/app/_not-found.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/index.html +2 -2
- package/web/.next/server/app/index.rsc +1 -1
- package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.html +2 -2
- package/web/.next/server/app/version.rsc +1 -1
- package/web/.next/server/app/version.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
- package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
- package/web/.next/server/pages/404.html +2 -2
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- /package/web/.next/static/{iYaq62xFNOChDTbH3WMrr → KqMr5DLdrvbaA-agLuHP1}/_buildManifest.js +0 -0
- /package/web/.next/static/{iYaq62xFNOChDTbH3WMrr → KqMr5DLdrvbaA-agLuHP1}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{iYaq62xFNOChDTbH3WMrr → KqMr5DLdrvbaA-agLuHP1}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -23,27 +23,183 @@ _Manage Claude Code, Cursor CLI, or any coding agent across the full development
|
|
|
23
23
|
|
|
24
24
|
<img src="docs/poc/imgs/00-control-center-hero.png" alt="Shep AI Control Center — manage all features across repos from a single canvas" width="100%" />
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
[](https://shep-ai.github.io/cli/poc/)
|
|
27
27
|
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Running AI agents is easy. **Managing many of them through a full SDLC is the hard part.** Shep gives you a control center that handles the entire lifecycle — requirements gathering, planning, implementation, QA, and deployment — across multiple agent sessions running in parallel. See what each agent is doing, jump into any session's web preview, code editor, or terminal, approve plans when agents need your input, and let them keep working while you move on. Plug in Claude Code, Cursor CLI, Gemini CLI, or any coding agent. Each feature gets its own isolated worktree and dev environment. You manage the lifecycle, agents do the work.
|
|
30
|
+
### Install
|
|
33
31
|
|
|
34
32
|
```bash
|
|
35
33
|
npm i -g @shepai/cli
|
|
36
|
-
cd your-repo/
|
|
37
|
-
shep feat new "Implement SSO with SAML 2.0"
|
|
38
|
-
# Agent starts working in a dedicated worktree.
|
|
39
|
-
# Open the control center to watch progress, intervene, or switch context.
|
|
40
|
-
shep ui
|
|
41
34
|
```
|
|
42
35
|
|
|
36
|
+
### Try it
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd your-project/
|
|
40
|
+
shep feat new "Add unit tests for all source files"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
<details>
|
|
44
|
+
<summary><b>List features</b> — <code>shep feat ls</code></summary>
|
|
45
|
+
<br />
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Features for /home/user/projects/my-app
|
|
49
|
+
|
|
50
|
+
ID Name Status Branch Created
|
|
51
|
+
1b0a7969 Add Unit Tests ✓ Completed feat/add-unit-tests 2/13/2026
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
</details>
|
|
55
|
+
|
|
56
|
+
<details>
|
|
57
|
+
<summary><b>Show feature detail</b> — <code>shep feat show 1b0a7969</code></summary>
|
|
58
|
+
<br />
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
Feature: Add Unit Tests
|
|
62
|
+
|
|
63
|
+
ID 1b0a7969-b420-4754-832f-5c38801b4852
|
|
64
|
+
Slug add-unit-tests
|
|
65
|
+
Description Add comprehensive unit tests for all existing source files
|
|
66
|
+
in the project to ensure code correctness and improve test coverage.
|
|
67
|
+
Repository /home/user/projects/my-app
|
|
68
|
+
Branch feat/add-unit-tests
|
|
69
|
+
Status ✓ Completed
|
|
70
|
+
Worktree ~/.shep/repos/9bbd30de/wt/feat-add-unit-tests
|
|
71
|
+
Spec Dir ~/.shep/repos/9bbd30de/wt/feat-add-unit-tests/specs/001-add-unit-tests
|
|
72
|
+
Agent Run 732a1fc2-a346-4052-a028-dcb1a46b6f2c
|
|
73
|
+
|
|
74
|
+
Timestamps
|
|
75
|
+
Created 2/13/2026, 12:15:08 AM
|
|
76
|
+
Updated 2/13/2026, 12:15:08 AM
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
</details>
|
|
80
|
+
|
|
81
|
+
<details>
|
|
82
|
+
<summary><b>Isolated worktree per feature</b> — no stashing, no branch switching</summary>
|
|
83
|
+
<br />
|
|
84
|
+
|
|
85
|
+
Each feature gets its own git worktree — fully isolated from your main branch.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
~/.shep/repos/9bbd30de/wt/feat-add-unit-tests/
|
|
89
|
+
├── .git # linked worktree (not a clone)
|
|
90
|
+
├── src/
|
|
91
|
+
├── tests/
|
|
92
|
+
├── specs/
|
|
93
|
+
│ └── 001-add-unit-tests/
|
|
94
|
+
│ ├── feature.yaml # status tracking
|
|
95
|
+
│ ├── spec.yaml # requirements & scope
|
|
96
|
+
│ ├── research.yaml # technical decisions
|
|
97
|
+
│ ├── plan.yaml # implementation strategy
|
|
98
|
+
│ └── tasks.yaml # task breakdown
|
|
99
|
+
├── pyproject.toml
|
|
100
|
+
└── README.md
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
</details>
|
|
104
|
+
|
|
105
|
+
<details>
|
|
106
|
+
<summary><b>Auto-generated spec files</b> — real output from a single <code>shep feat new</code></summary>
|
|
107
|
+
<br />
|
|
108
|
+
|
|
109
|
+
> **`spec.yaml`** — requirements & scope
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
name: add-unit-tests
|
|
113
|
+
oneLiner: Add comprehensive unit tests for all source modules
|
|
114
|
+
summary: >
|
|
115
|
+
Add unit tests for every module in the package. The project currently has
|
|
116
|
+
minimal test coverage (only 7 tests total). This feature adds tests for
|
|
117
|
+
config, agents, flows, tools, observability, and CLI — using pytest with
|
|
118
|
+
mocking to avoid external dependencies.
|
|
119
|
+
sizeEstimate: M
|
|
120
|
+
openQuestions:
|
|
121
|
+
- question: 'Should we set a minimum coverage threshold and enforce it in CI?'
|
|
122
|
+
resolved: true
|
|
123
|
+
answer: >
|
|
124
|
+
Set 70% minimum via --cov-fail-under=70. Achievable and prevents regression.
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
> **`research.yaml`** — technical decisions with rationale
|
|
128
|
+
|
|
129
|
+
```yaml
|
|
130
|
+
decisions:
|
|
131
|
+
- title: 'Test Framework'
|
|
132
|
+
chosen: 'pytest (already configured)'
|
|
133
|
+
rejected:
|
|
134
|
+
- 'unittest — More verbose, no fixture system'
|
|
135
|
+
- 'nose2 — Unmaintained, no advantage'
|
|
136
|
+
rationale: >
|
|
137
|
+
Already a dev dependency with asyncio and coverage plugins configured.
|
|
138
|
+
|
|
139
|
+
- title: 'Mocking Library'
|
|
140
|
+
chosen: 'unittest.mock (stdlib)'
|
|
141
|
+
rejected:
|
|
142
|
+
- 'pytest-mock — Adds a dependency for marginal convenience'
|
|
143
|
+
rationale: >
|
|
144
|
+
patch() for module-level replacement, MagicMock for spec objects,
|
|
145
|
+
assert_called_with for verification. No new dependency needed.
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
> **`tasks.yaml`** — TDD task breakdown
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
tasks:
|
|
152
|
+
- id: task-1
|
|
153
|
+
title: 'Create conftest.py with shared fixtures'
|
|
154
|
+
dependencies: []
|
|
155
|
+
acceptanceCriteria:
|
|
156
|
+
- 'mock_settings returns a Settings instance with known values'
|
|
157
|
+
- 'mock_llm returns MagicMock(spec=LLM) for agent tests'
|
|
158
|
+
- 'tmp_repo creates a temp dir with git init and one commit'
|
|
159
|
+
tdd:
|
|
160
|
+
red: ['Write test_smoke.py that imports fixtures and asserts properties']
|
|
161
|
+
green: ['Implement conftest.py with all three fixtures']
|
|
162
|
+
refactor: ['Remove smoke test — subsumed by real test files']
|
|
163
|
+
|
|
164
|
+
- id: task-3
|
|
165
|
+
title: 'Test config/llm.py'
|
|
166
|
+
dependencies: [task-1]
|
|
167
|
+
acceptanceCriteria:
|
|
168
|
+
- 'test_create_llm_with_openai_provider: verifies model, temperature, api_key'
|
|
169
|
+
- 'test_create_llm_with_cursor_provider: verifies base_url included'
|
|
170
|
+
- 'test_get_fast_llm: calls create_llm with settings.fast_model'
|
|
171
|
+
tdd:
|
|
172
|
+
red: ['Patch LLM and get_settings, assert constructor kwargs']
|
|
173
|
+
green: ['Tests pass — they verify existing code with mocks']
|
|
174
|
+
refactor: ['Extract common patch decorators if repetitive']
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
> **`feature.yaml`** — machine-readable progress (updated continuously)
|
|
178
|
+
|
|
179
|
+
```yaml
|
|
180
|
+
feature:
|
|
181
|
+
id: '001-add-unit-tests'
|
|
182
|
+
branch: 'feat/001-add-unit-tests'
|
|
183
|
+
lifecycle: 'research'
|
|
184
|
+
|
|
185
|
+
status:
|
|
186
|
+
phase: 'research'
|
|
187
|
+
progress: { completed: 0, total: 12, percentage: 0 }
|
|
188
|
+
lastUpdatedBy: 'feature-agent'
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
</details>
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
Running AI agents is easy. **Managing many of them through a full SDLC is the hard part.** Shep gives you a control center that handles the entire lifecycle — requirements gathering, planning, implementation, QA, and deployment — across multiple agent sessions running in parallel. See what each agent is doing, jump into any session's web preview, code editor, or terminal, approve plans when agents need your input, and let them keep working while you move on. Plug in Claude Code, Cursor CLI, Gemini CLI, or any coding agent. Each feature gets its own isolated worktree and dev environment. You manage the lifecycle, agents do the work.
|
|
196
|
+
|
|
43
197
|
---
|
|
44
198
|
|
|
45
199
|
## Features
|
|
46
200
|
|
|
201
|
+
> 🚧 **Under active development** — Web UI screenshots are from the design spec. Core CLI (`feat new`, `feat ls`, `feat show`, `settings`, `ui`) works today. Some commands (`mem`, `start`) are still WIP.
|
|
202
|
+
|
|
47
203
|
<table>
|
|
48
204
|
<tr>
|
|
49
205
|
<td width="55%"><img src="docs/poc/imgs/01-features-control-center-overview.png" alt="Feature properties with attachments and metadata" /></td>
|
|
@@ -182,21 +338,11 @@ shep ui
|
|
|
182
338
|
## Quick Start
|
|
183
339
|
|
|
184
340
|
```bash
|
|
185
|
-
#
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
# Start the background service
|
|
189
|
-
shep start
|
|
190
|
-
# ➜ Local: http://localhost:5173/
|
|
191
|
-
# Shep service is running in background, have fun!
|
|
192
|
-
|
|
193
|
-
# Navigate to any repo
|
|
194
|
-
cd ~/repos/your-project
|
|
195
|
-
|
|
196
|
-
# Create your first feature
|
|
341
|
+
# Navigate to any repo and create a feature
|
|
342
|
+
cd ~/projects/your-app
|
|
197
343
|
shep feat new "Add user authentication with OAuth 2.0"
|
|
198
344
|
|
|
199
|
-
# Open the control center
|
|
345
|
+
# Open the control center to watch progress
|
|
200
346
|
shep ui
|
|
201
347
|
```
|
|
202
348
|
|
|
@@ -68,6 +68,8 @@ export interface AgentExecutionOptions {
|
|
|
68
68
|
outputSchema?: object;
|
|
69
69
|
/** Execution timeout in milliseconds */
|
|
70
70
|
timeout?: number;
|
|
71
|
+
/** Suppress executor debug logging (e.g. for quick foreground calls) */
|
|
72
|
+
silent?: boolean;
|
|
71
73
|
}
|
|
72
74
|
/**
|
|
73
75
|
* Port interface for executing prompts against an AI agent.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-executor.interface.d.ts","sourceRoot":"","sources":["../../../../../../src/application/ports/output/agents/agent-executor.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAC;AAEtF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,KAAK,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,2DAA2D;IAC3D,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAE9B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAExF;;;;;;OAMG;IACH,aAAa,CACX,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,qBAAqB,GAC9B,aAAa,CAAC,yBAAyB,CAAC,CAAC;IAE5C;;;;;OAKG;IACH,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;CACjD"}
|
|
1
|
+
{"version":3,"file":"agent-executor.interface.d.ts","sourceRoot":"","sources":["../../../../../../src/application/ports/output/agents/agent-executor.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAC;AAEtF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,KAAK,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,2DAA2D;IAC3D,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;IACtC,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAc;IAC7B,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAE9B;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAExF;;;;;;OAMG;IACH,aAAa,CACX,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,qBAAqB,GAC9B,aAAa,CAAC,yBAAyB,CAAC,CAAC;IAE5C;;;;;OAKG;IACH,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;CACjD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-feature.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/application/use-cases/features/create-feature.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAClG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2DAA2D,CAAC;AACzG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+DAA+D,CAAC;AAO3G,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAQD,qBACa,oBAAoB;IAG7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAVf,WAAW,EAAE,kBAAkB,EAE/B,eAAe,EAAE,gBAAgB,EAEjC,YAAY,EAAE,2BAA2B,EAEzC,aAAa,EAAE,mBAAmB,EAElC,eAAe,EAAE,uBAAuB,EAExC,eAAe,EAAE,qBAAqB;IAGnD,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;YA8E5C,gBAAgB;
|
|
1
|
+
{"version":3,"file":"create-feature.use-case.d.ts","sourceRoot":"","sources":["../../../../../src/application/use-cases/features/create-feature.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAClG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2DAA2D,CAAC;AACzG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+DAA+D,CAAC;AAO3G,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAQD,qBACa,oBAAoB;IAG7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAE5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAE9B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAVf,WAAW,EAAE,kBAAkB,EAE/B,eAAe,EAAE,gBAAgB,EAEjC,YAAY,EAAE,2BAA2B,EAEzC,aAAa,EAAE,mBAAmB,EAElC,eAAe,EAAE,uBAAuB,EAExC,eAAe,EAAE,qBAAqB;IAGnD,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;YA8E5C,gBAAgB;IA8C9B,OAAO,CAAC,MAAM;CAQf"}
|
|
@@ -124,6 +124,7 @@ JSON only, no markdown fences.`;
|
|
|
124
124
|
const result = await executor.execute(prompt, {
|
|
125
125
|
maxTurns: 1,
|
|
126
126
|
allowedTools: [],
|
|
127
|
+
silent: true,
|
|
127
128
|
});
|
|
128
129
|
const parsed = JSON.parse(result.result);
|
|
129
130
|
if (!parsed.slug || !parsed.name || !parsed.description) {
|
package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export type SpawnFunction = (command: string, args: string[], options?: object)
|
|
|
24
24
|
export declare class ClaudeCodeExecutorService implements IAgentExecutor {
|
|
25
25
|
private readonly spawn;
|
|
26
26
|
readonly agentType: AgentType;
|
|
27
|
+
/** When true, suppresses debug logging (set per-call via options.silent) */
|
|
28
|
+
private silent;
|
|
27
29
|
constructor(spawn: SpawnFunction);
|
|
28
30
|
/** Debug logging — writes to stdout so it appears in the worker log file */
|
|
29
31
|
private log;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code-executor.service.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/common/executors/claude-code-executor.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzF,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,4EAA4E,CAAC;AAEpF;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,YAAY,CAAC;AAUhG;;;GAGG;AACH,qBAAa,yBAA0B,YAAW,cAAc;
|
|
1
|
+
{"version":3,"file":"claude-code-executor.service.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/common/executors/claude-code-executor.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AACzF,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,4EAA4E,CAAC;AAEpF;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,YAAY,CAAC;AAUhG;;;GAGG;AACH,qBAAa,yBAA0B,YAAW,cAAc;IAMlD,OAAO,CAAC,QAAQ,CAAC,KAAK;IALlC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAA8B;IAE3D,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAS;gBAEM,KAAK,EAAE,aAAa;IAEjD,4EAA4E;IAC5E,OAAO,CAAC,GAAG;IAML,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAmHtF,aAAa,CAClB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,qBAAqB,GAC9B,aAAa,CAAC,yBAAyB,CAAC;IA+F3C;;;OAGG;IACH,OAAO,CAAC,cAAc;IAmCtB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAI/C,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,eAAe;IAiCvB,OAAO,CAAC,eAAe;CAkExB"}
|
package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.js
CHANGED
|
@@ -22,15 +22,20 @@ const SUPPORTED_FEATURES = new Set([
|
|
|
22
22
|
export class ClaudeCodeExecutorService {
|
|
23
23
|
spawn;
|
|
24
24
|
agentType = 'claude-code';
|
|
25
|
+
/** When true, suppresses debug logging (set per-call via options.silent) */
|
|
26
|
+
silent = false;
|
|
25
27
|
constructor(spawn) {
|
|
26
28
|
this.spawn = spawn;
|
|
27
29
|
}
|
|
28
30
|
/** Debug logging — writes to stdout so it appears in the worker log file */
|
|
29
31
|
log(message) {
|
|
32
|
+
if (this.silent)
|
|
33
|
+
return;
|
|
30
34
|
const ts = new Date().toISOString();
|
|
31
35
|
process.stdout.write(`[${ts}] [claude-executor] ${message}\n`);
|
|
32
36
|
}
|
|
33
37
|
async execute(prompt, options) {
|
|
38
|
+
this.silent = options?.silent ?? false;
|
|
34
39
|
// Use stream-json so we get real-time events in the worker log
|
|
35
40
|
// instead of zero output for minutes with --output-format json
|
|
36
41
|
const args = this.buildStreamArgs(prompt, options);
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type { IAgentExecutor } from '../../../../../application/ports/output/agents/agent-executor.interface.js';
|
|
2
|
-
import type { FeatureAgentState } from '../state.js';
|
|
3
1
|
/**
|
|
4
|
-
*
|
|
2
|
+
* Implement Node — Phase-Level Orchestrator
|
|
5
3
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Reads plan.yaml and tasks.yaml, then executes each phase by building
|
|
5
|
+
* a focused implementation prompt and calling the executor. Parallel
|
|
6
|
+
* phases spawn concurrent executor calls. Progress is tracked in
|
|
7
|
+
* feature.yaml between phases.
|
|
9
8
|
*/
|
|
10
|
-
|
|
9
|
+
import type { IAgentExecutor } from '../../../../../application/ports/output/agents/agent-executor.interface.js';
|
|
10
|
+
import type { FeatureAgentState } from '../state.js';
|
|
11
|
+
export declare function createImplementNode(executor: IAgentExecutor): (state: FeatureAgentState) => Promise<Partial<FeatureAgentState>>;
|
|
11
12
|
//# sourceMappingURL=implement.node.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implement.node.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/implement.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"implement.node.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/implement.node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA2DrD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,IAG5C,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAqJ7E"}
|
|
@@ -1,23 +1,147 @@
|
|
|
1
|
-
import { createNodeLogger } from './node-helpers.js';
|
|
2
|
-
import { reportNodeStart } from '../heartbeat.js';
|
|
3
|
-
import { getImplementPlaceholderJoke } from './prompts/implement.prompt.js';
|
|
4
1
|
/**
|
|
5
|
-
*
|
|
2
|
+
* Implement Node — Phase-Level Orchestrator
|
|
6
3
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* Reads plan.yaml and tasks.yaml, then executes each phase by building
|
|
5
|
+
* a focused implementation prompt and calling the executor. Parallel
|
|
6
|
+
* phases spawn concurrent executor calls. Progress is tracked in
|
|
7
|
+
* feature.yaml between phases.
|
|
8
|
+
*/
|
|
9
|
+
import yaml from 'js-yaml';
|
|
10
|
+
import { writeFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { interrupt, isGraphBubbleUp } from '@langchain/langgraph';
|
|
13
|
+
import { createNodeLogger, readSpecFile, buildExecutorOptions, shouldInterrupt, } from './node-helpers.js';
|
|
14
|
+
import { reportNodeStart } from '../heartbeat.js';
|
|
15
|
+
import { buildImplementPhasePrompt, } from './prompts/implement.prompt.js';
|
|
16
|
+
/**
|
|
17
|
+
* Update feature.yaml with current implementation progress.
|
|
18
|
+
* Silently no-ops if the file is missing or unparseable.
|
|
10
19
|
*/
|
|
11
|
-
|
|
20
|
+
function updateFeatureProgress(specDir, completedCount, totalCount, currentPhase, currentTaskId, log) {
|
|
21
|
+
try {
|
|
22
|
+
const content = readSpecFile(specDir, 'feature.yaml');
|
|
23
|
+
if (!content)
|
|
24
|
+
return;
|
|
25
|
+
const data = yaml.load(content);
|
|
26
|
+
if (!data || typeof data !== 'object')
|
|
27
|
+
return;
|
|
28
|
+
const status = (data.status ?? {});
|
|
29
|
+
data.status = {
|
|
30
|
+
...status,
|
|
31
|
+
phase: currentPhase,
|
|
32
|
+
progress: {
|
|
33
|
+
completed: completedCount,
|
|
34
|
+
total: totalCount,
|
|
35
|
+
percentage: totalCount > 0 ? Math.round((completedCount / totalCount) * 100) : 0,
|
|
36
|
+
},
|
|
37
|
+
currentTask: currentTaskId,
|
|
38
|
+
lastUpdated: new Date().toISOString(),
|
|
39
|
+
lastUpdatedBy: 'feature-agent:implement',
|
|
40
|
+
};
|
|
41
|
+
writeFileSync(join(specDir, 'feature.yaml'), yaml.dump(data, { indent: 2, lineWidth: -1 }), 'utf-8');
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
log.error(`Failed to update feature.yaml: ${err instanceof Error ? err.message : String(err)}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function createImplementNode(executor) {
|
|
12
48
|
const log = createNodeLogger('implement');
|
|
13
|
-
return async (
|
|
14
|
-
log.info('Starting
|
|
49
|
+
return async (state) => {
|
|
50
|
+
log.info('Starting implementation phase orchestration');
|
|
15
51
|
reportNodeStart('implement');
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
52
|
+
const startTime = Date.now();
|
|
53
|
+
const messages = [];
|
|
54
|
+
try {
|
|
55
|
+
// --- Parse plan & tasks ---
|
|
56
|
+
const planContent = readSpecFile(state.specDir, 'plan.yaml');
|
|
57
|
+
const tasksContent = readSpecFile(state.specDir, 'tasks.yaml');
|
|
58
|
+
if (!planContent || !tasksContent) {
|
|
59
|
+
const msg = 'Missing plan.yaml or tasks.yaml — cannot implement';
|
|
60
|
+
log.error(msg);
|
|
61
|
+
return { currentNode: 'implement', error: msg, messages: [`[implement] Error: ${msg}`] };
|
|
62
|
+
}
|
|
63
|
+
const planData = yaml.load(planContent);
|
|
64
|
+
const tasksData = yaml.load(tasksContent);
|
|
65
|
+
if (!planData?.phases?.length || !tasksData?.tasks?.length) {
|
|
66
|
+
const msg = 'Empty phases or tasks — nothing to implement';
|
|
67
|
+
log.error(msg);
|
|
68
|
+
return { currentNode: 'implement', error: msg, messages: [`[implement] Error: ${msg}`] };
|
|
69
|
+
}
|
|
70
|
+
const taskMap = new Map(tasksData.tasks.map((t) => [t.id, t]));
|
|
71
|
+
const totalTasks = tasksData.tasks.length;
|
|
72
|
+
let completedTasks = 0;
|
|
73
|
+
const totalPhases = planData.phases.length;
|
|
74
|
+
// --- Execute phases in order ---
|
|
75
|
+
for (let i = 0; i < totalPhases; i++) {
|
|
76
|
+
const phase = planData.phases[i];
|
|
77
|
+
const isLastPhase = i === totalPhases - 1;
|
|
78
|
+
// Resolve tasks: use explicit taskIds if present, otherwise match by phaseId
|
|
79
|
+
const phaseTasks = phase.taskIds?.length
|
|
80
|
+
? phase.taskIds
|
|
81
|
+
.map((id) => taskMap.get(id))
|
|
82
|
+
.filter((t) => t !== undefined)
|
|
83
|
+
: tasksData.tasks.filter((t) => t.phaseId === phase.id);
|
|
84
|
+
if (phaseTasks.length === 0) {
|
|
85
|
+
log.info(`Phase ${phase.id} "${phase.name}" — no tasks, skipping`);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
log.info(`Phase ${phase.id} "${phase.name}" — ${phaseTasks.length} task(s), parallel: ${phase.parallel}`);
|
|
89
|
+
updateFeatureProgress(state.specDir, completedTasks, totalTasks, `implementing-${phase.id}`, phaseTasks[0].id, log);
|
|
90
|
+
const options = buildExecutorOptions(state);
|
|
91
|
+
const promptContext = { isLastPhase, phaseIndex: i, totalPhases };
|
|
92
|
+
if (phase.parallel && phaseTasks.length > 1) {
|
|
93
|
+
// Parallel: one executor call per task
|
|
94
|
+
log.info(`Spawning ${phaseTasks.length} parallel executor calls`);
|
|
95
|
+
const results = await Promise.all(phaseTasks.map((task) => {
|
|
96
|
+
const singleTaskPhase = {
|
|
97
|
+
...phase,
|
|
98
|
+
taskIds: [task.id],
|
|
99
|
+
};
|
|
100
|
+
const prompt = buildImplementPhasePrompt(state, singleTaskPhase, [task], promptContext);
|
|
101
|
+
log.info(` [parallel] Task ${task.id}: "${task.title}" — ${prompt.length} chars`);
|
|
102
|
+
return executor.execute(prompt, options);
|
|
103
|
+
}));
|
|
104
|
+
for (let j = 0; j < results.length; j++) {
|
|
105
|
+
log.info(` [parallel] Task ${phaseTasks[j].id} complete (${results[j].result.length} chars)`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Sequential: single executor call with all phase tasks
|
|
110
|
+
const prompt = buildImplementPhasePrompt(state, phase, phaseTasks, promptContext);
|
|
111
|
+
log.info(`Executing phase prompt — ${prompt.length} chars`);
|
|
112
|
+
const result = await executor.execute(prompt, options);
|
|
113
|
+
log.info(`Phase complete (${result.result.length} chars)`);
|
|
114
|
+
}
|
|
115
|
+
completedTasks += phaseTasks.length;
|
|
116
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
117
|
+
messages.push(`[implement] Phase ${phase.id} "${phase.name}" — ${phaseTasks.length} task(s) done (${elapsed}s)`);
|
|
118
|
+
updateFeatureProgress(state.specDir, completedTasks, totalTasks, `implementing-${phase.id}`, null, log);
|
|
119
|
+
}
|
|
120
|
+
// --- Final ---
|
|
121
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
122
|
+
log.info(`All phases complete — ${completedTasks}/${totalTasks} tasks (${elapsed}s)`);
|
|
123
|
+
updateFeatureProgress(state.specDir, totalTasks, totalTasks, 'implementation-complete', null, log);
|
|
124
|
+
messages.push(`[implement] Complete: ${totalTasks} tasks across ${totalPhases} phases (${elapsed}s)`);
|
|
125
|
+
if (shouldInterrupt('implement', state.approvalMode)) {
|
|
126
|
+
log.info('Interrupting for human approval');
|
|
127
|
+
interrupt({
|
|
128
|
+
node: 'implement',
|
|
129
|
+
message: `Implementation complete: ${totalTasks} tasks across ${totalPhases} phases. Approve to finish.`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return { currentNode: 'implement', messages };
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
if (isGraphBubbleUp(err))
|
|
136
|
+
throw err;
|
|
137
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
138
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
139
|
+
log.error(`${message} (after ${elapsed}s)`);
|
|
140
|
+
return {
|
|
141
|
+
currentNode: 'implement',
|
|
142
|
+
error: message,
|
|
143
|
+
messages: [...messages, `[implement] Error: ${message}`],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
22
146
|
};
|
|
23
147
|
}
|
package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.d.ts
CHANGED
|
@@ -1,8 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Implement Phase Prompt
|
|
2
|
+
* Implement Phase Prompt
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Builds per-phase implementation prompts that include full spec/research/plan
|
|
5
|
+
* context plus the specific tasks for the current phase, with TDD guidance
|
|
6
|
+
* and verification instructions.
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
+
import type { FeatureAgentState } from '../../state.js';
|
|
9
|
+
export interface PhaseTask {
|
|
10
|
+
id: string;
|
|
11
|
+
phaseId?: string;
|
|
12
|
+
title: string;
|
|
13
|
+
description: string;
|
|
14
|
+
state: string;
|
|
15
|
+
dependencies: string[];
|
|
16
|
+
acceptanceCriteria: string[];
|
|
17
|
+
tdd: {
|
|
18
|
+
red: string[];
|
|
19
|
+
green: string[];
|
|
20
|
+
refactor: string[];
|
|
21
|
+
} | null;
|
|
22
|
+
estimatedEffort: string;
|
|
23
|
+
}
|
|
24
|
+
export interface PlanPhase {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
parallel: boolean;
|
|
29
|
+
/** Optional — if absent, tasks are matched via their phaseId field */
|
|
30
|
+
taskIds?: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface PlanYaml {
|
|
33
|
+
phases: PlanPhase[];
|
|
34
|
+
}
|
|
35
|
+
export interface TasksYaml {
|
|
36
|
+
tasks: PhaseTask[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build the implementation prompt for a single phase (or a single task
|
|
40
|
+
* within a parallel phase). Includes full project context so each
|
|
41
|
+
* executor session is self-contained.
|
|
42
|
+
*/
|
|
43
|
+
export declare function buildImplementPhasePrompt(state: FeatureAgentState, phase: PlanPhase, tasks: PhaseTask[], context: {
|
|
44
|
+
isLastPhase: boolean;
|
|
45
|
+
phaseIndex: number;
|
|
46
|
+
totalPhases: number;
|
|
47
|
+
}): string;
|
|
8
48
|
//# sourceMappingURL=implement.prompt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implement.prompt.d.ts","sourceRoot":"","sources":["../../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"implement.prompt.d.ts","sourceRoot":"","sources":["../../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,GAAG,EAAE;QAAE,GAAG,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IACnE,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAwBD;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,iBAAiB,EACxB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,SAAS,EAAE,EAClB,OAAO,EAAE;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACzE,MAAM,CA8DR"}
|
package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.js
CHANGED
|
@@ -1,18 +1,90 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Implement Phase Prompt
|
|
2
|
+
* Implement Phase Prompt
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Builds per-phase implementation prompts that include full spec/research/plan
|
|
5
|
+
* context plus the specific tasks for the current phase, with TDD guidance
|
|
6
|
+
* and verification instructions.
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
import { readSpecFile } from '../node-helpers.js';
|
|
9
|
+
function formatTaskSection(task) {
|
|
10
|
+
let section = `### Task ${task.id}: ${task.title}\n${task.description}\n`;
|
|
11
|
+
section += `\n**Acceptance Criteria:**\n`;
|
|
12
|
+
for (const criterion of task.acceptanceCriteria) {
|
|
13
|
+
section += `- ${criterion}\n`;
|
|
14
|
+
}
|
|
15
|
+
if (task.tdd) {
|
|
16
|
+
section += `\n**TDD Guidance:**\n`;
|
|
17
|
+
section += `- Write tests for: ${task.tdd.red.join('; ')}\n`;
|
|
18
|
+
section += `- Implement: ${task.tdd.green.join('; ')}\n`;
|
|
19
|
+
section += `- Then consider: ${task.tdd.refactor.join('; ')}\n`;
|
|
20
|
+
}
|
|
21
|
+
if (task.dependencies.length > 0) {
|
|
22
|
+
section += `\nDepends on: ${task.dependencies.join(', ')}\n`;
|
|
23
|
+
}
|
|
24
|
+
return section;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the implementation prompt for a single phase (or a single task
|
|
28
|
+
* within a parallel phase). Includes full project context so each
|
|
29
|
+
* executor session is self-contained.
|
|
30
|
+
*/
|
|
31
|
+
export function buildImplementPhasePrompt(state, phase, tasks, context) {
|
|
32
|
+
const specContent = readSpecFile(state.specDir, 'spec.yaml');
|
|
33
|
+
const researchContent = readSpecFile(state.specDir, 'research.yaml');
|
|
34
|
+
const planContent = readSpecFile(state.specDir, 'plan.yaml');
|
|
35
|
+
const cwd = state.worktreePath || state.repositoryPath;
|
|
36
|
+
const taskSections = tasks.map(formatTaskSection).join('\n');
|
|
37
|
+
const verificationBlock = context.isLastPhase
|
|
38
|
+
? `4. Run full project validation:
|
|
39
|
+
- \`pnpm test\` (all tests must pass)
|
|
40
|
+
- \`pnpm lint\` (no lint errors)
|
|
41
|
+
- \`pnpm typecheck\` (no type errors)
|
|
42
|
+
- Fix any issues before finishing`
|
|
43
|
+
: `4. Run tests relevant to what you changed:
|
|
44
|
+
- Run targeted tests for modified files (e.g. \`pnpm test:single <test-file>\`)
|
|
45
|
+
- Fix any test failures before moving on`;
|
|
46
|
+
return `You are a senior software engineer performing autonomous implementation.
|
|
47
|
+
You are executing phase ${context.phaseIndex + 1} of ${context.totalPhases}: "${phase.name}".
|
|
48
|
+
|
|
49
|
+
## Feature Specification
|
|
50
|
+
|
|
51
|
+
\`\`\`yaml
|
|
52
|
+
${specContent}
|
|
53
|
+
\`\`\`
|
|
54
|
+
|
|
55
|
+
## Research Decisions
|
|
56
|
+
|
|
57
|
+
\`\`\`yaml
|
|
58
|
+
${researchContent}
|
|
59
|
+
\`\`\`
|
|
60
|
+
|
|
61
|
+
## Implementation Plan
|
|
62
|
+
|
|
63
|
+
\`\`\`yaml
|
|
64
|
+
${planContent}
|
|
65
|
+
\`\`\`
|
|
66
|
+
|
|
67
|
+
## Your Tasks for This Phase: "${phase.name}"
|
|
68
|
+
|
|
69
|
+
${taskSections}
|
|
70
|
+
|
|
71
|
+
## Implementation Instructions
|
|
72
|
+
|
|
73
|
+
1. Work through each task in dependency order
|
|
74
|
+
2. For tasks with TDD guidance: write tests alongside implementation following the hints provided — use them as guidance, not rigid steps
|
|
75
|
+
3. Follow existing codebase conventions for file placement, naming patterns, and architecture layers
|
|
76
|
+
${verificationBlock}
|
|
77
|
+
5. Commit your work with descriptive conventional commit messages (e.g. \`feat(scope): description\`)
|
|
78
|
+
|
|
79
|
+
## Working Directory
|
|
80
|
+
|
|
81
|
+
${cwd}
|
|
82
|
+
|
|
83
|
+
## Constraints
|
|
84
|
+
|
|
85
|
+
- Implement ONLY the tasks listed above — do not work ahead to future phases
|
|
86
|
+
- Follow existing codebase conventions and architecture patterns
|
|
87
|
+
- Do NOT modify any spec YAML files (spec.yaml, research.yaml, plan.yaml, tasks.yaml, feature.yaml)
|
|
88
|
+
- Do NOT skip writing tests for tasks that have TDD guidance
|
|
89
|
+
- Keep changes focused and minimal — avoid unnecessary refactoring beyond what the tasks specify`;
|
|
18
90
|
}
|