@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.
Files changed (73) hide show
  1. package/README.md +168 -22
  2. package/dist/src/application/ports/output/agents/agent-executor.interface.d.ts +2 -0
  3. package/dist/src/application/ports/output/agents/agent-executor.interface.d.ts.map +1 -1
  4. package/dist/src/application/use-cases/features/create-feature.use-case.d.ts.map +1 -1
  5. package/dist/src/application/use-cases/features/create-feature.use-case.js +1 -0
  6. package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts +2 -0
  7. package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts.map +1 -1
  8. package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.js +5 -0
  9. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts +8 -7
  10. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts.map +1 -1
  11. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +140 -16
  12. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.d.ts +44 -4
  13. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.d.ts.map +1 -1
  14. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.js +86 -14
  15. package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
  16. package/dist/src/presentation/cli/commands/feat/new.command.js +3 -3
  17. package/dist/src/presentation/cli/ui/index.d.ts +1 -0
  18. package/dist/src/presentation/cli/ui/index.d.ts.map +1 -1
  19. package/dist/src/presentation/cli/ui/index.js +1 -0
  20. package/dist/src/presentation/cli/ui/spinner.d.ts +21 -0
  21. package/dist/src/presentation/cli/ui/spinner.d.ts.map +1 -0
  22. package/dist/src/presentation/cli/ui/spinner.js +45 -0
  23. package/dist/tsconfig.build.tsbuildinfo +1 -1
  24. package/package.json +1 -1
  25. package/web/.next/BUILD_ID +1 -1
  26. package/web/.next/build-manifest.json +2 -2
  27. package/web/.next/cache/.previewinfo +1 -1
  28. package/web/.next/cache/.rscinfo +1 -1
  29. package/web/.next/cache/config.json +3 -3
  30. package/web/.next/fallback-build-manifest.json +2 -2
  31. package/web/.next/prerender-manifest.json +3 -3
  32. package/web/.next/required-server-files.js +1 -1
  33. package/web/.next/required-server-files.json +1 -1
  34. package/web/.next/server/app/_global-error.html +2 -2
  35. package/web/.next/server/app/_global-error.rsc +1 -1
  36. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  37. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  38. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  39. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  40. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  41. package/web/.next/server/app/_not-found.html +2 -2
  42. package/web/.next/server/app/_not-found.rsc +1 -1
  43. package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  44. package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  45. package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  46. package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  47. package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  48. package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  49. package/web/.next/server/app/index.html +2 -2
  50. package/web/.next/server/app/index.rsc +1 -1
  51. package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  52. package/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  53. package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  54. package/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  55. package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  56. package/web/.next/server/app/version.html +2 -2
  57. package/web/.next/server/app/version.rsc +1 -1
  58. package/web/.next/server/app/version.segments/_full.segment.rsc +1 -1
  59. package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
  60. package/web/.next/server/app/version.segments/_index.segment.rsc +1 -1
  61. package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
  62. package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
  63. package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
  64. package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
  65. package/web/.next/server/pages/404.html +2 -2
  66. package/web/.next/server/pages/500.html +2 -2
  67. package/web/.next/server/server-reference-manifest.js +1 -1
  68. package/web/.next/server/server-reference-manifest.json +1 -1
  69. package/web/.next/trace +1 -1
  70. package/web/.next/trace-build +1 -1
  71. /package/web/.next/static/{iYaq62xFNOChDTbH3WMrr → KqMr5DLdrvbaA-agLuHP1}/_buildManifest.js +0 -0
  72. /package/web/.next/static/{iYaq62xFNOChDTbH3WMrr → KqMr5DLdrvbaA-agLuHP1}/_clientMiddlewareManifest.json +0 -0
  73. /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
- <br />
26
+ [![Live Demo](https://img.shields.io/badge/Live_Demo-shep--ai.github.io-blue?style=for-the-badge)](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> &mdash; <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> &mdash; <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> &mdash; 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> &mdash; 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
- # Install
186
- npm i -g @shepai/cli
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;IA6C9B,OAAO,CAAC,MAAM;CAQf"}
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) {
@@ -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;IAGlD,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFlC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAA8B;gBAE9B,KAAK,EAAE,aAAa;IAEjD,4EAA4E;IAC5E,OAAO,CAAC,GAAG;IAKL,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAkHtF,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"}
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"}
@@ -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
- * Creates the implement node — PLACEHOLDER.
2
+ * Implement Node Phase-Level Orchestrator
5
3
  *
6
- * Implementation execution is not yet wired up.
7
- * Returns a programming joke to clearly signal this is a placeholder
8
- * while keeping the graph pipeline intact.
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
- export declare function createImplementNode(_executor: IAgentExecutor): (_state: FeatureAgentState) => Promise<Partial<FeatureAgentState>>;
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;AAKrD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,cAAc,IAG7C,QAAQ,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAY9E"}
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
- * Creates the implement node — PLACEHOLDER.
2
+ * Implement Node Phase-Level Orchestrator
6
3
  *
7
- * Implementation execution is not yet wired up.
8
- * Returns a programming joke to clearly signal this is a placeholder
9
- * while keeping the graph pipeline intact.
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
- export function createImplementNode(_executor) {
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 (_state) => {
14
- log.info('Starting... (placeholder — implementation not yet wired)');
49
+ return async (state) => {
50
+ log.info('Starting implementation phase orchestration');
15
51
  reportNodeStart('implement');
16
- const joke = getImplementPlaceholderJoke();
17
- log.info(`Placeholder complete. ${joke}`);
18
- return {
19
- currentNode: 'implement',
20
- messages: [`[implement] Placeholder ${joke}`],
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
  }
@@ -1,8 +1,48 @@
1
1
  /**
2
- * Implement Phase Prompt — PLACEHOLDER
2
+ * Implement Phase Prompt
3
3
  *
4
- * The implement phase is not yet wired up. This returns a programming joke
5
- * to clearly signal it's a placeholder while keeping the graph pipeline intact.
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
- export declare function getImplementPlaceholderJoke(): string;
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;;;;;GAKG;AAYH,wBAAgB,2BAA2B,IAAI,MAAM,CAEpD"}
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"}
@@ -1,18 +1,90 @@
1
1
  /**
2
- * Implement Phase Prompt — PLACEHOLDER
2
+ * Implement Phase Prompt
3
3
  *
4
- * The implement phase is not yet wired up. This returns a programming joke
5
- * to clearly signal it's a placeholder while keeping the graph pipeline intact.
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
- const JOKES = [
8
- 'Why do programmers prefer dark mode? Because light attracts bugs.',
9
- 'A SQL query walks into a bar, walks up to two tables and asks... "Can I JOIN you?"',
10
- "There are only 10 types of people: those who understand binary, and those who don't.",
11
- "Why was the JavaScript developer sad? Because he didn't Node how to Express himself.",
12
- "What's a programmer's favorite hangout place? Foo Bar.",
13
- 'To understand recursion, you must first understand recursion.',
14
- "!false it's funny because it's true.",
15
- ];
16
- export function getImplementPlaceholderJoke() {
17
- return JOKES[Math.floor(Math.random() * JOKES.length)];
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
  }