@shepai/cli 1.14.1 → 1.15.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 (283) hide show
  1. package/README.md +191 -101
  2. package/dist/eslint.config.mjs +2 -0
  3. package/dist/src/application/ports/output/external-issue-fetcher.interface.d.ts +69 -0
  4. package/dist/src/application/ports/output/external-issue-fetcher.interface.d.ts.map +1 -0
  5. package/dist/src/application/ports/output/external-issue-fetcher.interface.js +46 -0
  6. package/dist/src/application/ports/output/feature-agent-process.interface.d.ts +44 -0
  7. package/dist/src/application/ports/output/feature-agent-process.interface.d.ts.map +1 -0
  8. package/dist/src/application/ports/output/feature-agent-process.interface.js +12 -0
  9. package/dist/src/application/ports/output/feature-repository.interface.d.ts +76 -0
  10. package/dist/src/application/ports/output/feature-repository.interface.d.ts.map +1 -0
  11. package/dist/src/application/ports/output/feature-repository.interface.js +11 -0
  12. package/dist/src/application/ports/output/index.d.ts +3 -0
  13. package/dist/src/application/ports/output/index.d.ts.map +1 -1
  14. package/dist/src/application/ports/output/index.js +1 -1
  15. package/dist/src/application/ports/output/spec-initializer.interface.d.ts +33 -0
  16. package/dist/src/application/ports/output/spec-initializer.interface.d.ts.map +1 -0
  17. package/dist/src/application/ports/output/spec-initializer.interface.js +8 -0
  18. package/dist/src/application/ports/output/worktree-service.interface.d.ts +83 -0
  19. package/dist/src/application/ports/output/worktree-service.interface.d.ts.map +1 -0
  20. package/dist/src/application/ports/output/worktree-service.interface.js +30 -0
  21. package/dist/src/application/use-cases/agents/approve-agent-run.use-case.d.ts +22 -0
  22. package/dist/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -0
  23. package/dist/src/application/use-cases/agents/approve-agent-run.use-case.js +67 -0
  24. package/dist/src/application/use-cases/agents/delete-agent-run.use-case.d.ts +16 -0
  25. package/dist/src/application/use-cases/agents/delete-agent-run.use-case.d.ts.map +1 -0
  26. package/dist/src/application/use-cases/agents/delete-agent-run.use-case.js +46 -0
  27. package/dist/src/application/use-cases/agents/get-agent-run.use-case.d.ts +22 -0
  28. package/dist/src/application/use-cases/agents/get-agent-run.use-case.d.ts.map +1 -0
  29. package/dist/src/application/use-cases/agents/get-agent-run.use-case.js +42 -0
  30. package/dist/src/application/use-cases/agents/list-agent-runs.use-case.d.ts +21 -0
  31. package/dist/src/application/use-cases/agents/list-agent-runs.use-case.d.ts.map +1 -0
  32. package/dist/src/application/use-cases/agents/list-agent-runs.use-case.js +54 -0
  33. package/dist/src/application/use-cases/agents/reject-agent-run.use-case.d.ts +16 -0
  34. package/dist/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map +1 -0
  35. package/dist/src/application/use-cases/agents/reject-agent-run.use-case.js +52 -0
  36. package/dist/src/application/use-cases/agents/show-agent-run.use-case.d.ts +24 -0
  37. package/dist/src/application/use-cases/agents/show-agent-run.use-case.d.ts.map +1 -0
  38. package/dist/src/application/use-cases/agents/show-agent-run.use-case.js +52 -0
  39. package/dist/src/application/use-cases/agents/stop-agent-run.use-case.d.ts +15 -0
  40. package/dist/src/application/use-cases/agents/stop-agent-run.use-case.d.ts.map +1 -0
  41. package/dist/src/application/use-cases/agents/stop-agent-run.use-case.js +86 -0
  42. package/dist/src/application/use-cases/features/create-feature.use-case.d.ts +43 -0
  43. package/dist/src/application/use-cases/features/create-feature.use-case.d.ts.map +1 -0
  44. package/dist/src/application/use-cases/features/create-feature.use-case.js +166 -0
  45. package/dist/src/application/use-cases/features/delete-feature.use-case.d.ts +27 -0
  46. package/dist/src/application/use-cases/features/delete-feature.use-case.d.ts.map +1 -0
  47. package/dist/src/application/use-cases/features/delete-feature.use-case.js +83 -0
  48. package/dist/src/application/use-cases/features/list-features.use-case.d.ts +17 -0
  49. package/dist/src/application/use-cases/features/list-features.use-case.d.ts.map +1 -0
  50. package/dist/src/application/use-cases/features/list-features.use-case.js +37 -0
  51. package/dist/src/application/use-cases/features/resume-feature.use-case.d.ts +24 -0
  52. package/dist/src/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -0
  53. package/dist/src/application/use-cases/features/resume-feature.use-case.js +100 -0
  54. package/dist/src/application/use-cases/features/show-feature.use-case.d.ts +17 -0
  55. package/dist/src/application/use-cases/features/show-feature.use-case.d.ts.map +1 -0
  56. package/dist/src/application/use-cases/features/show-feature.use-case.js +43 -0
  57. package/dist/src/domain/generated/output.d.ts +26 -1
  58. package/dist/src/domain/generated/output.d.ts.map +1 -1
  59. package/dist/src/domain/generated/output.js +1 -0
  60. package/dist/src/infrastructure/di/container.d.ts.map +1 -1
  61. package/dist/src/infrastructure/di/container.js +64 -14
  62. package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.d.ts +4 -0
  63. package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.d.ts.map +1 -1
  64. package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.js +8 -0
  65. package/dist/src/infrastructure/persistence/sqlite/mappers/feature.mapper.d.ts +50 -0
  66. package/dist/src/infrastructure/persistence/sqlite/mappers/feature.mapper.d.ts.map +1 -0
  67. package/dist/src/infrastructure/persistence/sqlite/mappers/feature.mapper.js +62 -0
  68. package/dist/src/infrastructure/persistence/sqlite/migrations.d.ts.map +1 -1
  69. package/dist/src/infrastructure/persistence/sqlite/migrations.js +49 -0
  70. package/dist/src/infrastructure/repositories/agent-run.repository.d.ts.map +1 -1
  71. package/dist/src/infrastructure/repositories/agent-run.repository.js +30 -8
  72. package/dist/src/infrastructure/repositories/sqlite-feature.repository.d.ts +25 -0
  73. package/dist/src/infrastructure/repositories/sqlite-feature.repository.d.ts.map +1 -0
  74. package/dist/src/infrastructure/repositories/sqlite-feature.repository.js +113 -0
  75. package/dist/src/infrastructure/services/agents/{langgraph → analyze-repo}/analyze-repository-graph.d.ts +0 -22
  76. package/dist/src/infrastructure/services/agents/analyze-repo/analyze-repository-graph.d.ts.map +1 -0
  77. package/dist/src/infrastructure/services/agents/{langgraph → analyze-repo}/analyze-repository-graph.js +4 -11
  78. package/dist/src/infrastructure/services/agents/analyze-repo/prompts/analyze-repository.prompt.d.ts.map +1 -0
  79. package/dist/src/infrastructure/services/agents/{agent-executor-factory.service.d.ts → common/agent-executor-factory.service.d.ts} +3 -3
  80. package/dist/src/infrastructure/services/agents/common/agent-executor-factory.service.d.ts.map +1 -0
  81. package/dist/src/infrastructure/services/agents/{agent-registry.service.d.ts → common/agent-registry.service.d.ts} +1 -1
  82. package/dist/src/infrastructure/services/agents/common/agent-registry.service.d.ts.map +1 -0
  83. package/dist/src/infrastructure/services/agents/{agent-registry.service.js → common/agent-registry.service.js} +7 -1
  84. package/dist/src/infrastructure/services/agents/{agent-runner.service.d.ts → common/agent-runner.service.d.ts} +5 -5
  85. package/dist/src/infrastructure/services/agents/common/agent-runner.service.d.ts.map +1 -0
  86. package/dist/src/infrastructure/services/agents/{agent-runner.service.js → common/agent-runner.service.js} +4 -4
  87. package/dist/src/infrastructure/services/agents/{agent-validator.service.d.ts → common/agent-validator.service.d.ts} +2 -2
  88. package/dist/src/infrastructure/services/agents/common/agent-validator.service.d.ts.map +1 -0
  89. package/dist/src/infrastructure/services/agents/{langgraph → common}/checkpointer.d.ts +1 -0
  90. package/dist/src/infrastructure/services/agents/common/checkpointer.d.ts.map +1 -0
  91. package/dist/src/infrastructure/services/agents/{langgraph → common}/checkpointer.js +6 -0
  92. package/dist/src/infrastructure/services/agents/{executors → common/executors}/claude-code-executor.service.d.ts +9 -2
  93. package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts.map +1 -0
  94. package/dist/src/infrastructure/services/agents/{executors → common/executors}/claude-code-executor.service.js +103 -6
  95. package/dist/src/infrastructure/services/agents/common/executors/mock-executor-factory.service.d.ts +15 -0
  96. package/dist/src/infrastructure/services/agents/common/executors/mock-executor-factory.service.d.ts.map +1 -0
  97. package/dist/src/infrastructure/services/agents/common/executors/mock-executor-factory.service.js +16 -0
  98. package/dist/src/infrastructure/services/agents/common/executors/mock-executor.service.d.ts +17 -0
  99. package/dist/src/infrastructure/services/agents/common/executors/mock-executor.service.d.ts.map +1 -0
  100. package/dist/src/infrastructure/services/agents/common/executors/mock-executor.service.js +49 -0
  101. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +244 -0
  102. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -0
  103. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +36 -0
  104. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +20 -0
  105. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -0
  106. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +90 -0
  107. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +31 -0
  108. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -0
  109. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +236 -0
  110. package/dist/src/infrastructure/services/agents/feature-agent/heartbeat.d.ts +19 -0
  111. package/dist/src/infrastructure/services/agents/feature-agent/heartbeat.d.ts.map +1 -0
  112. package/dist/src/infrastructure/services/agents/feature-agent/heartbeat.js +38 -0
  113. package/dist/src/infrastructure/services/agents/feature-agent/nodes/analyze.node.d.ts +7 -0
  114. package/dist/src/infrastructure/services/agents/feature-agent/nodes/analyze.node.d.ts.map +1 -0
  115. package/dist/src/infrastructure/services/agents/feature-agent/nodes/analyze.node.js +9 -0
  116. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts +11 -0
  117. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts.map +1 -0
  118. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +23 -0
  119. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +40 -0
  120. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -0
  121. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +114 -0
  122. package/dist/src/infrastructure/services/agents/feature-agent/nodes/plan.node.d.ts +7 -0
  123. package/dist/src/infrastructure/services/agents/feature-agent/nodes/plan.node.d.ts.map +1 -0
  124. package/dist/src/infrastructure/services/agents/feature-agent/nodes/plan.node.js +9 -0
  125. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/analyze.prompt.d.ts +9 -0
  126. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/analyze.prompt.d.ts.map +1 -0
  127. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/analyze.prompt.js +94 -0
  128. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.d.ts +8 -0
  129. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.d.ts.map +1 -0
  130. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.js +18 -0
  131. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/plan.prompt.d.ts +11 -0
  132. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/plan.prompt.d.ts.map +1 -0
  133. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/plan.prompt.js +170 -0
  134. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.d.ts +10 -0
  135. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.d.ts.map +1 -0
  136. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.js +116 -0
  137. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/research.prompt.d.ts +10 -0
  138. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/research.prompt.d.ts.map +1 -0
  139. package/dist/src/infrastructure/services/agents/feature-agent/nodes/prompts/research.prompt.js +121 -0
  140. package/dist/src/infrastructure/services/agents/feature-agent/nodes/requirements.node.d.ts +7 -0
  141. package/dist/src/infrastructure/services/agents/feature-agent/nodes/requirements.node.d.ts.map +1 -0
  142. package/dist/src/infrastructure/services/agents/feature-agent/nodes/requirements.node.js +9 -0
  143. package/dist/src/infrastructure/services/agents/feature-agent/nodes/research.node.d.ts +7 -0
  144. package/dist/src/infrastructure/services/agents/feature-agent/nodes/research.node.d.ts.map +1 -0
  145. package/dist/src/infrastructure/services/agents/feature-agent/nodes/research.node.js +9 -0
  146. package/dist/src/infrastructure/services/agents/feature-agent/state.d.ts +39 -0
  147. package/dist/src/infrastructure/services/agents/feature-agent/state.d.ts.map +1 -0
  148. package/dist/src/infrastructure/services/agents/feature-agent/state.js +27 -0
  149. package/dist/src/infrastructure/services/external/github-issue.service.d.ts +19 -0
  150. package/dist/src/infrastructure/services/external/github-issue.service.d.ts.map +1 -0
  151. package/dist/src/infrastructure/services/external/github-issue.service.js +59 -0
  152. package/dist/src/infrastructure/services/external/jira-ticket.service.d.ts +23 -0
  153. package/dist/src/infrastructure/services/external/jira-ticket.service.d.ts.map +1 -0
  154. package/dist/src/infrastructure/services/external/jira-ticket.service.js +57 -0
  155. package/dist/src/infrastructure/services/git/worktree.service.d.ts +28 -0
  156. package/dist/src/infrastructure/services/git/worktree.service.d.ts.map +1 -0
  157. package/dist/src/infrastructure/services/git/worktree.service.js +112 -0
  158. package/dist/src/infrastructure/services/spec/spec-initializer.service.d.ts +17 -0
  159. package/dist/src/infrastructure/services/spec/spec-initializer.service.d.ts.map +1 -0
  160. package/dist/src/infrastructure/services/spec/spec-initializer.service.js +281 -0
  161. package/dist/src/presentation/cli/commands/agent/approve.command.d.ts +11 -0
  162. package/dist/src/presentation/cli/commands/agent/approve.command.d.ts.map +1 -0
  163. package/dist/src/presentation/cli/commands/agent/approve.command.js +42 -0
  164. package/dist/src/presentation/cli/commands/agent/delete.command.d.ts +11 -0
  165. package/dist/src/presentation/cli/commands/agent/delete.command.d.ts.map +1 -0
  166. package/dist/src/presentation/cli/commands/agent/delete.command.js +49 -0
  167. package/dist/src/presentation/cli/commands/agent/index.d.ts +21 -0
  168. package/dist/src/presentation/cli/commands/agent/index.d.ts.map +1 -0
  169. package/dist/src/presentation/cli/commands/agent/index.js +38 -0
  170. package/dist/src/presentation/cli/commands/agent/logs.command.d.ts +13 -0
  171. package/dist/src/presentation/cli/commands/agent/logs.command.d.ts.map +1 -0
  172. package/dist/src/presentation/cli/commands/agent/logs.command.js +163 -0
  173. package/dist/src/presentation/cli/commands/agent/ls.command.d.ts +12 -0
  174. package/dist/src/presentation/cli/commands/agent/ls.command.d.ts.map +1 -0
  175. package/dist/src/presentation/cli/commands/agent/ls.command.js +111 -0
  176. package/dist/src/presentation/cli/commands/agent/reject.command.d.ts +11 -0
  177. package/dist/src/presentation/cli/commands/agent/reject.command.d.ts.map +1 -0
  178. package/dist/src/presentation/cli/commands/agent/reject.command.js +43 -0
  179. package/dist/src/presentation/cli/commands/agent/resolve-run.d.ts +10 -0
  180. package/dist/src/presentation/cli/commands/agent/resolve-run.d.ts.map +1 -0
  181. package/dist/src/presentation/cli/commands/agent/resolve-run.js +27 -0
  182. package/dist/src/presentation/cli/commands/agent/show.command.d.ts +12 -0
  183. package/dist/src/presentation/cli/commands/agent/show.command.d.ts.map +1 -0
  184. package/dist/src/presentation/cli/commands/agent/show.command.js +202 -0
  185. package/dist/src/presentation/cli/commands/agent/stop.command.d.ts +11 -0
  186. package/dist/src/presentation/cli/commands/agent/stop.command.d.ts.map +1 -0
  187. package/dist/src/presentation/cli/commands/agent/stop.command.js +42 -0
  188. package/dist/src/presentation/cli/commands/feat/del.command.d.ts +17 -0
  189. package/dist/src/presentation/cli/commands/feat/del.command.d.ts.map +1 -0
  190. package/dist/src/presentation/cli/commands/feat/del.command.js +55 -0
  191. package/dist/src/presentation/cli/commands/feat/index.d.ts +17 -0
  192. package/dist/src/presentation/cli/commands/feat/index.d.ts.map +1 -0
  193. package/dist/src/presentation/cli/commands/feat/index.js +29 -0
  194. package/dist/src/presentation/cli/commands/feat/ls.command.d.ts +15 -0
  195. package/dist/src/presentation/cli/commands/feat/ls.command.d.ts.map +1 -0
  196. package/dist/src/presentation/cli/commands/feat/ls.command.js +112 -0
  197. package/dist/src/presentation/cli/commands/feat/new.command.d.ts +17 -0
  198. package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -0
  199. package/dist/src/presentation/cli/commands/feat/new.command.js +64 -0
  200. package/dist/src/presentation/cli/commands/feat/resume.command.d.ts +11 -0
  201. package/dist/src/presentation/cli/commands/feat/resume.command.d.ts.map +1 -0
  202. package/dist/src/presentation/cli/commands/feat/resume.command.js +33 -0
  203. package/dist/src/presentation/cli/commands/feat/show.command.d.ts +11 -0
  204. package/dist/src/presentation/cli/commands/feat/show.command.d.ts.map +1 -0
  205. package/dist/src/presentation/cli/commands/feat/show.command.js +128 -0
  206. package/dist/src/presentation/cli/index.d.ts +8 -4
  207. package/dist/src/presentation/cli/index.d.ts.map +1 -1
  208. package/dist/src/presentation/cli/index.js +12 -4
  209. package/dist/src/presentation/cli/ui/detail-view.d.ts +43 -0
  210. package/dist/src/presentation/cli/ui/detail-view.d.ts.map +1 -0
  211. package/dist/src/presentation/cli/ui/detail-view.js +57 -0
  212. package/dist/src/presentation/cli/ui/index.d.ts +2 -0
  213. package/dist/src/presentation/cli/ui/index.d.ts.map +1 -1
  214. package/dist/src/presentation/cli/ui/index.js +2 -0
  215. package/dist/src/presentation/cli/ui/list-view.d.ts +34 -0
  216. package/dist/src/presentation/cli/ui/list-view.d.ts.map +1 -0
  217. package/dist/src/presentation/cli/ui/list-view.js +65 -0
  218. package/dist/src/presentation/cli/ui/symbols.d.ts +5 -1
  219. package/dist/src/presentation/cli/ui/symbols.d.ts.map +1 -1
  220. package/dist/src/presentation/cli/ui/symbols.js +4 -0
  221. package/dist/tsconfig.build.tsbuildinfo +1 -1
  222. package/package.json +2 -1
  223. package/web/.next/BUILD_ID +1 -1
  224. package/web/.next/build-manifest.json +2 -2
  225. package/web/.next/cache/.previewinfo +1 -1
  226. package/web/.next/cache/.rscinfo +1 -1
  227. package/web/.next/cache/config.json +3 -3
  228. package/web/.next/fallback-build-manifest.json +2 -2
  229. package/web/.next/prerender-manifest.json +3 -3
  230. package/web/.next/required-server-files.js +1 -1
  231. package/web/.next/required-server-files.json +1 -1
  232. package/web/.next/server/app/_global-error.html +2 -2
  233. package/web/.next/server/app/_global-error.rsc +1 -1
  234. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  235. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  236. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  237. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  238. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  239. package/web/.next/server/app/_not-found.html +2 -2
  240. package/web/.next/server/app/_not-found.rsc +1 -1
  241. package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  242. package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  243. package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  244. package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  245. package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  246. package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  247. package/web/.next/server/app/index.html +2 -2
  248. package/web/.next/server/app/index.rsc +1 -1
  249. package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  250. package/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  251. package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  252. package/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  253. package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  254. package/web/.next/server/app/version.html +2 -2
  255. package/web/.next/server/app/version.rsc +1 -1
  256. package/web/.next/server/app/version.segments/_full.segment.rsc +1 -1
  257. package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
  258. package/web/.next/server/app/version.segments/_index.segment.rsc +1 -1
  259. package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
  260. package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
  261. package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
  262. package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
  263. package/web/.next/server/pages/404.html +2 -2
  264. package/web/.next/server/pages/500.html +2 -2
  265. package/web/.next/server/server-reference-manifest.js +1 -1
  266. package/web/.next/server/server-reference-manifest.json +1 -1
  267. package/web/.next/trace +1 -1
  268. package/web/.next/trace-build +1 -1
  269. package/dist/src/infrastructure/services/agents/agent-executor-factory.service.d.ts.map +0 -1
  270. package/dist/src/infrastructure/services/agents/agent-registry.service.d.ts.map +0 -1
  271. package/dist/src/infrastructure/services/agents/agent-runner.service.d.ts.map +0 -1
  272. package/dist/src/infrastructure/services/agents/agent-validator.service.d.ts.map +0 -1
  273. package/dist/src/infrastructure/services/agents/executors/claude-code-executor.service.d.ts.map +0 -1
  274. package/dist/src/infrastructure/services/agents/langgraph/analyze-repository-graph.d.ts.map +0 -1
  275. package/dist/src/infrastructure/services/agents/langgraph/checkpointer.d.ts.map +0 -1
  276. package/dist/src/infrastructure/services/agents/langgraph/prompts/analyze-repository.prompt.d.ts.map +0 -1
  277. /package/dist/src/infrastructure/services/agents/{langgraph → analyze-repo}/prompts/analyze-repository.prompt.d.ts +0 -0
  278. /package/dist/src/infrastructure/services/agents/{langgraph → analyze-repo}/prompts/analyze-repository.prompt.js +0 -0
  279. /package/dist/src/infrastructure/services/agents/{agent-executor-factory.service.js → common/agent-executor-factory.service.js} +0 -0
  280. /package/dist/src/infrastructure/services/agents/{agent-validator.service.js → common/agent-validator.service.js} +0 -0
  281. /package/web/.next/static/{ozzHAkZyxX7nXyxpqufBs → XV-wYY85Xk9ANCuQDQ6_H}/_buildManifest.js +0 -0
  282. /package/web/.next/static/{ozzHAkZyxX7nXyxpqufBs → XV-wYY85Xk9ANCuQDQ6_H}/_clientMiddlewareManifest.json +0 -0
  283. /package/web/.next/static/{ozzHAkZyxX7nXyxpqufBs → XV-wYY85Xk9ANCuQDQ6_H}/_ssgManifest.js +0 -0
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Feature Agent Worker
4
+ *
5
+ * Background worker entry point that runs as a child process via fork().
6
+ * Initializes DI, creates the feature agent graph, and executes it.
7
+ * Sends periodic heartbeats so the CLI can detect stuck/crashed workers.
8
+ *
9
+ * CLI Args: --feature-id <id> --run-id <id> --repo <path> --spec-dir <path>
10
+ */
11
+ import 'reflect-metadata';
12
+ import { join } from 'node:path';
13
+ import { homedir } from 'node:os';
14
+ import { Command } from '@langchain/langgraph';
15
+ import { initializeContainer, container } from '../../../../infrastructure/di/container.js';
16
+ import { createFeatureAgentGraph } from './feature-agent-graph.js';
17
+ import { createCheckpointer } from '../common/checkpointer.js';
18
+ import { AgentRunStatus } from '../../../../domain/generated/output.js';
19
+ import { getSettings, initializeSettings } from '../../../../infrastructure/services/settings.service.js';
20
+ import { InitializeSettingsUseCase } from '../../../../application/use-cases/settings/initialize-settings.use-case.js';
21
+ import { setHeartbeatContext } from './heartbeat.js';
22
+ /**
23
+ * Parse CLI arguments into a WorkerArgs object.
24
+ * Throws if any required argument is missing.
25
+ */
26
+ export function parseWorkerArgs(args) {
27
+ const getArg = (name) => {
28
+ const index = args.indexOf(`--${name}`);
29
+ if (index === -1 || index + 1 >= args.length) {
30
+ throw new Error(`Missing required argument: --${name}`);
31
+ }
32
+ return args[index + 1];
33
+ };
34
+ const worktreeIdx = args.indexOf('--worktree-path');
35
+ const worktreePath = worktreeIdx !== -1 && worktreeIdx + 1 < args.length ? args[worktreeIdx + 1] : undefined;
36
+ const approvalIdx = args.indexOf('--approval-mode');
37
+ const approvalMode = approvalIdx !== -1 && approvalIdx + 1 < args.length ? args[approvalIdx + 1] : undefined;
38
+ const resume = args.includes('--resume');
39
+ return {
40
+ featureId: getArg('feature-id'),
41
+ runId: getArg('run-id'),
42
+ repo: getArg('repo'),
43
+ specDir: getArg('spec-dir'),
44
+ worktreePath,
45
+ approvalMode,
46
+ resume,
47
+ };
48
+ }
49
+ /** Simple worker logger — writes to stdout which is redirected to log file by the parent. */
50
+ function log(message) {
51
+ const ts = new Date().toISOString();
52
+ process.stdout.write(`[${ts}] [WORKER] ${message}\n`);
53
+ }
54
+ /** Heartbeat interval (30 seconds) */
55
+ const HEARTBEAT_INTERVAL_MS = 30_000;
56
+ /**
57
+ * Start periodic heartbeat that updates last_heartbeat in the DB.
58
+ * Returns a cleanup function to stop the interval.
59
+ */
60
+ function startHeartbeat(runId, runRepository) {
61
+ const interval = setInterval(async () => {
62
+ try {
63
+ const now = new Date();
64
+ await runRepository.updateStatus(runId, AgentRunStatus.running, {
65
+ lastHeartbeat: now,
66
+ updatedAt: now,
67
+ });
68
+ }
69
+ catch {
70
+ // Heartbeat failure is non-fatal — just log it
71
+ log('Heartbeat update failed (non-fatal)');
72
+ }
73
+ }, HEARTBEAT_INTERVAL_MS);
74
+ return () => clearInterval(interval);
75
+ }
76
+ /**
77
+ * Run the feature agent worker with the given arguments.
78
+ * Initializes DI, creates the graph, and executes it.
79
+ */
80
+ export async function runWorker(args) {
81
+ log(`Starting with featureId=${args.featureId} runId=${args.runId}`);
82
+ log(` repo=${args.repo}`);
83
+ log(` specDir=${args.specDir}`);
84
+ log(` worktreePath=${args.worktreePath ?? '(none)'}`);
85
+ log(` approvalMode=${args.approvalMode ?? '(none)'}`);
86
+ log(` resume=${args.resume}`);
87
+ log('Initializing container...');
88
+ await initializeContainer();
89
+ // Initialize settings in the worker process
90
+ log('Loading settings...');
91
+ const initSettingsUseCase = container.resolve(InitializeSettingsUseCase);
92
+ const settings = await initSettingsUseCase.execute();
93
+ initializeSettings(settings);
94
+ const runRepository = container.resolve('IAgentRunRepository');
95
+ const executorFactory = container.resolve('IAgentExecutorFactory');
96
+ // Create executor from configured agent settings (now settings are initialized)
97
+ const configuredSettings = getSettings();
98
+ log(`Creating executor for agent type: ${configuredSettings.agent.type}`);
99
+ const executor = executorFactory.createExecutor(configuredSettings.agent.type, configuredSettings.agent);
100
+ // Use a file-based checkpointer for persistence across restarts
101
+ const checkpointPath = join(homedir(), '.shep', 'checkpoints', `${args.runId}.db`);
102
+ log(`Creating checkpointer at ${checkpointPath}`);
103
+ const checkpointer = createCheckpointer(checkpointPath);
104
+ const graph = createFeatureAgentGraph(executor, checkpointer);
105
+ // Mark the run as running with our PID
106
+ const now = new Date();
107
+ log(`Updating status to running (PID ${process.pid})...`);
108
+ await runRepository.updateStatus(args.runId, AgentRunStatus.running, {
109
+ pid: process.pid,
110
+ startedAt: now,
111
+ lastHeartbeat: now,
112
+ updatedAt: now,
113
+ });
114
+ // Start heartbeat so the CLI can detect if we're still alive
115
+ const stopHeartbeat = startHeartbeat(args.runId, runRepository);
116
+ // Set heartbeat context so node-helpers can update current node
117
+ setHeartbeatContext(args.runId, runRepository);
118
+ try {
119
+ const graphConfig = { configurable: { thread_id: args.runId } };
120
+ let result;
121
+ if (args.resume) {
122
+ log('Resuming graph from checkpoint...');
123
+ result = await graph.invoke(new Command({ resume: { approved: true } }), graphConfig);
124
+ }
125
+ else {
126
+ log('Starting graph invocation...');
127
+ result = await graph.invoke({
128
+ featureId: args.featureId,
129
+ repositoryPath: args.repo,
130
+ worktreePath: args.worktreePath ?? args.repo,
131
+ specDir: args.specDir,
132
+ ...(args.approvalMode ? { approvalMode: args.approvalMode } : {}),
133
+ }, graphConfig);
134
+ }
135
+ log(`Graph invocation completed. Error: ${result.error ?? 'none'}`);
136
+ stopHeartbeat();
137
+ // Check if graph was interrupted (human-in-the-loop approval needed)
138
+ const interruptPayload = result.__interrupt__;
139
+ if (interruptPayload && interruptPayload.length > 0) {
140
+ const now = new Date();
141
+ await runRepository.updateStatus(args.runId, AgentRunStatus.waitingApproval, {
142
+ approvalStatus: 'waiting',
143
+ updatedAt: now,
144
+ });
145
+ log('Run paused — waiting for human approval');
146
+ return;
147
+ }
148
+ // Check if the graph itself reported an error in state
149
+ if (result.error) {
150
+ const failedAt = new Date();
151
+ await runRepository.updateStatus(args.runId, AgentRunStatus.failed, {
152
+ error: result.error,
153
+ completedAt: failedAt,
154
+ updatedAt: failedAt,
155
+ });
156
+ log(`Run marked as failed: ${result.error}`);
157
+ return;
158
+ }
159
+ const completedAt = new Date();
160
+ await runRepository.updateStatus(args.runId, AgentRunStatus.completed, {
161
+ result: result.messages?.join('\n') ?? '',
162
+ completedAt,
163
+ updatedAt: completedAt,
164
+ });
165
+ log('Run marked as completed');
166
+ }
167
+ catch (error) {
168
+ stopHeartbeat();
169
+ const failedAt = new Date();
170
+ const message = error instanceof Error ? error.message : String(error);
171
+ log(`Graph invocation error: ${message}`);
172
+ await runRepository.updateStatus(args.runId, AgentRunStatus.failed, {
173
+ error: message,
174
+ completedAt: failedAt,
175
+ updatedAt: failedAt,
176
+ });
177
+ log('Run marked as failed');
178
+ }
179
+ }
180
+ // Catch unhandled errors globally so they always appear in the log file
181
+ process.on('uncaughtException', (err) => {
182
+ log(`UNCAUGHT EXCEPTION: ${err.message}\n${err.stack}`);
183
+ process.exit(1);
184
+ });
185
+ process.on('unhandledRejection', (reason) => {
186
+ const msg = reason instanceof Error ? `${reason.message}\n${reason.stack}` : String(reason);
187
+ log(`UNHANDLED REJECTION: ${msg}`);
188
+ process.exit(1);
189
+ });
190
+ // Handle IPC disconnect (parent exited) gracefully — this is expected for detached workers
191
+ process.on('disconnect', () => {
192
+ log('Parent disconnected (IPC channel closed) — continuing as detached worker');
193
+ });
194
+ // Handle SIGTERM for graceful shutdown
195
+ let runIdForSignal;
196
+ let runRepoForSignal;
197
+ process.on('SIGTERM', async () => {
198
+ log('Received SIGTERM, shutting down...');
199
+ if (runIdForSignal && runRepoForSignal) {
200
+ const now = new Date();
201
+ await runRepoForSignal.updateStatus(runIdForSignal, AgentRunStatus.interrupted, {
202
+ error: 'Process received SIGTERM',
203
+ completedAt: now,
204
+ updatedAt: now,
205
+ });
206
+ }
207
+ process.exit(0);
208
+ });
209
+ // Main execution when run as a script
210
+ // When using fork(), the forked process runs the entire module, but we want to detect if we're the entrypoint
211
+ const isMainModule = typeof require !== 'undefined'
212
+ ? require.main === module
213
+ : process.argv[1]?.includes('feature-agent-worker');
214
+ if (isMainModule) {
215
+ log('Worker process starting...');
216
+ try {
217
+ const args = parseWorkerArgs(process.argv.slice(2));
218
+ runIdForSignal = args.runId;
219
+ runWorker(args)
220
+ .then(() => {
221
+ runRepoForSignal = container.resolve('IAgentRunRepository');
222
+ log('Worker completed successfully, exiting.');
223
+ process.exit(0);
224
+ })
225
+ .catch((err) => {
226
+ const msg = err instanceof Error ? err.message : String(err);
227
+ log(`Worker fatal error: ${msg}`);
228
+ process.exit(1);
229
+ });
230
+ }
231
+ catch (err) {
232
+ const msg = err instanceof Error ? err.message : String(err);
233
+ log(`Worker setup error: ${msg}`);
234
+ process.exit(1);
235
+ }
236
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Heartbeat context for current-node tracking.
3
+ *
4
+ * The worker sets the context (runId + repository), and node-helpers
5
+ * call reportNodeStart() to update the DB with the current node name.
6
+ * This is a module-level singleton since only one worker runs per process.
7
+ */
8
+ import type { IAgentRunRepository } from '../../../../application/ports/output/agent-run-repository.interface.js';
9
+ /**
10
+ * Set the heartbeat context. Called once by the worker after DI init.
11
+ */
12
+ export declare function setHeartbeatContext(runId: string, repository: IAgentRunRepository): void;
13
+ /**
14
+ * Report that a graph node has started executing.
15
+ * Updates the run record with the current node name and a fresh heartbeat.
16
+ * Non-blocking: errors are swallowed so graph execution is not affected.
17
+ */
18
+ export declare function reportNodeStart(nodeName: string): void;
19
+ //# sourceMappingURL=heartbeat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../../../../../src/infrastructure/services/agents/feature-agent/heartbeat.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8DAA8D,CAAC;AAMxG;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,GAAG,IAAI,CAGxF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAgBtD"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Heartbeat context for current-node tracking.
3
+ *
4
+ * The worker sets the context (runId + repository), and node-helpers
5
+ * call reportNodeStart() to update the DB with the current node name.
6
+ * This is a module-level singleton since only one worker runs per process.
7
+ */
8
+ import { AgentRunStatus } from '../../../../domain/generated/output.js';
9
+ let contextRunId;
10
+ let contextRepository;
11
+ /**
12
+ * Set the heartbeat context. Called once by the worker after DI init.
13
+ */
14
+ export function setHeartbeatContext(runId, repository) {
15
+ contextRunId = runId;
16
+ contextRepository = repository;
17
+ }
18
+ /**
19
+ * Report that a graph node has started executing.
20
+ * Updates the run record with the current node name and a fresh heartbeat.
21
+ * Non-blocking: errors are swallowed so graph execution is not affected.
22
+ */
23
+ export function reportNodeStart(nodeName) {
24
+ if (!contextRunId || !contextRepository)
25
+ return;
26
+ const runId = contextRunId;
27
+ const repo = contextRepository;
28
+ // Fire-and-forget — don't await in the graph's hot path
29
+ repo
30
+ .updateStatus(runId, AgentRunStatus.running, {
31
+ result: `node:${nodeName}`,
32
+ lastHeartbeat: new Date(),
33
+ updatedAt: new Date(),
34
+ })
35
+ .catch(() => {
36
+ // Swallow — DB write failure is non-fatal
37
+ });
38
+ }
@@ -0,0 +1,7 @@
1
+ import type { IAgentExecutor } from '../../../../../application/ports/output/agent-executor.interface.js';
2
+ /**
3
+ * Creates the analyze node that explores the repository and writes
4
+ * codebase analysis, complexity estimate, and affected areas to spec.yaml.
5
+ */
6
+ export declare function createAnalyzeNode(executor: IAgentExecutor): (state: import("../state.js").FeatureAgentState) => Promise<Partial<import("../state.js").FeatureAgentState>>;
7
+ //# sourceMappingURL=analyze.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.node.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/analyze.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wDAAwD,CAAC;AAI7F;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,iHAEzD"}
@@ -0,0 +1,9 @@
1
+ import { executeNode } from './node-helpers.js';
2
+ import { buildAnalyzePrompt } from './prompts/analyze.prompt.js';
3
+ /**
4
+ * Creates the analyze node that explores the repository and writes
5
+ * codebase analysis, complexity estimate, and affected areas to spec.yaml.
6
+ */
7
+ export function createAnalyzeNode(executor) {
8
+ return executeNode('analyze', executor, buildAnalyzePrompt);
9
+ }
@@ -0,0 +1,11 @@
1
+ import type { IAgentExecutor } from '../../../../../application/ports/output/agent-executor.interface.js';
2
+ import type { FeatureAgentState } from '../state.js';
3
+ /**
4
+ * Creates the implement node — PLACEHOLDER.
5
+ *
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.
9
+ */
10
+ export declare function createImplementNode(_executor: IAgentExecutor): (_state: FeatureAgentState) => Promise<Partial<FeatureAgentState>>;
11
+ //# sourceMappingURL=implement.node.d.ts.map
@@ -0,0 +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,wDAAwD,CAAC;AAC7F,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"}
@@ -0,0 +1,23 @@
1
+ import { createNodeLogger } from './node-helpers.js';
2
+ import { reportNodeStart } from '../heartbeat.js';
3
+ import { getImplementPlaceholderJoke } from './prompts/implement.prompt.js';
4
+ /**
5
+ * Creates the implement node — PLACEHOLDER.
6
+ *
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.
10
+ */
11
+ export function createImplementNode(_executor) {
12
+ const log = createNodeLogger('implement');
13
+ return async (_state) => {
14
+ log.info('Starting... (placeholder — implementation not yet wired)');
15
+ reportNodeStart('implement');
16
+ const joke = getImplementPlaceholderJoke();
17
+ log.info(`Placeholder complete. ${joke}`);
18
+ return {
19
+ currentNode: 'implement',
20
+ messages: [`[implement] Placeholder — ${joke}`],
21
+ };
22
+ };
23
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Shared foundation for feature-agent graph nodes.
3
+ *
4
+ * Provides consistent logging, spec file reading, executor invocation,
5
+ * and error handling so every node follows the same patterns.
6
+ */
7
+ import type { IAgentExecutor, AgentExecutionOptions } from '../../../../../application/ports/output/agent-executor.interface.js';
8
+ import type { FeatureAgentState } from '../state.js';
9
+ /**
10
+ * Create a scoped logger that prefixes messages with the node name.
11
+ * Output goes to stdout which the worker redirects to the log file.
12
+ */
13
+ export declare function createNodeLogger(nodeName: string): {
14
+ info(message: string): void;
15
+ error(message: string): void;
16
+ };
17
+ export type NodeLogger = ReturnType<typeof createNodeLogger>;
18
+ /**
19
+ * Safely read a file from the spec directory. Returns empty string if file doesn't exist.
20
+ */
21
+ export declare function readSpecFile(specDir: string, filename: string): string;
22
+ /**
23
+ * Build executor options with cwd. Each node gets a clean agent context.
24
+ */
25
+ export declare function buildExecutorOptions(state: FeatureAgentState): AgentExecutionOptions;
26
+ /**
27
+ * Determine whether the current node should trigger an interrupt
28
+ * for human approval given the configured approval mode.
29
+ */
30
+ export declare function shouldInterrupt(nodeName: string, approvalMode: string | undefined): boolean;
31
+ /**
32
+ * Execute a node with consistent logging and error handling.
33
+ *
34
+ * Wraps the node's core logic with:
35
+ * - Entry/exit logging with timing
36
+ * - Error catching that returns error state instead of throwing
37
+ * - Consistent state shape for success and failure
38
+ */
39
+ export declare function executeNode(nodeName: string, executor: IAgentExecutor, buildPrompt: (state: FeatureAgentState, log: NodeLogger) => string): (state: FeatureAgentState) => Promise<Partial<FeatureAgentState>>;
40
+ //# sourceMappingURL=node-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-helpers.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/node-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACtB,MAAM,wDAAwD,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGrD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM;kBAE/B,MAAM,GAAG,IAAI;mBAIZ,MAAM,GAAG,IAAI;EAK/B;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE7D;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,qBAAqB,CAIpF;AAUD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAI3F;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,UAAU,KAAK,MAAM,GACjE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAiDnE"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Shared foundation for feature-agent graph nodes.
3
+ *
4
+ * Provides consistent logging, spec file reading, executor invocation,
5
+ * and error handling so every node follows the same patterns.
6
+ */
7
+ import { readFileSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { interrupt, isGraphBubbleUp } from '@langchain/langgraph';
10
+ import { reportNodeStart } from '../heartbeat.js';
11
+ /**
12
+ * Create a scoped logger that prefixes messages with the node name.
13
+ * Output goes to stdout which the worker redirects to the log file.
14
+ */
15
+ export function createNodeLogger(nodeName) {
16
+ return {
17
+ info(message) {
18
+ const ts = new Date().toISOString();
19
+ process.stdout.write(`[${ts}] [${nodeName}] ${message}\n`);
20
+ },
21
+ error(message) {
22
+ const ts = new Date().toISOString();
23
+ process.stderr.write(`[${ts}] [${nodeName}] ERROR: ${message}\n`);
24
+ },
25
+ };
26
+ }
27
+ /**
28
+ * Safely read a file from the spec directory. Returns empty string if file doesn't exist.
29
+ */
30
+ export function readSpecFile(specDir, filename) {
31
+ try {
32
+ return readFileSync(join(specDir, filename), 'utf-8');
33
+ }
34
+ catch {
35
+ return '';
36
+ }
37
+ }
38
+ /**
39
+ * Build executor options with cwd. Each node gets a clean agent context.
40
+ */
41
+ export function buildExecutorOptions(state) {
42
+ return {
43
+ cwd: state.worktreePath || state.repositoryPath,
44
+ };
45
+ }
46
+ /** Nodes that are auto-approved (no interrupt) for each approval mode. */
47
+ const AUTO_APPROVED_NODES = {
48
+ interactive: [],
49
+ 'allow-prd': ['analyze', 'requirements'],
50
+ 'allow-plan': ['analyze', 'requirements', 'research', 'plan'],
51
+ 'allow-all': ['analyze', 'requirements', 'research', 'plan', 'implement'],
52
+ };
53
+ /**
54
+ * Determine whether the current node should trigger an interrupt
55
+ * for human approval given the configured approval mode.
56
+ */
57
+ export function shouldInterrupt(nodeName, approvalMode) {
58
+ if (!approvalMode || approvalMode === 'allow-all')
59
+ return false;
60
+ const autoApproved = AUTO_APPROVED_NODES[approvalMode] ?? [];
61
+ return !autoApproved.includes(nodeName);
62
+ }
63
+ /**
64
+ * Execute a node with consistent logging and error handling.
65
+ *
66
+ * Wraps the node's core logic with:
67
+ * - Entry/exit logging with timing
68
+ * - Error catching that returns error state instead of throwing
69
+ * - Consistent state shape for success and failure
70
+ */
71
+ export function executeNode(nodeName, executor, buildPrompt) {
72
+ const log = createNodeLogger(nodeName);
73
+ return async (state) => {
74
+ log.info('Starting...');
75
+ reportNodeStart(nodeName);
76
+ const startTime = Date.now();
77
+ try {
78
+ const prompt = buildPrompt(state, log);
79
+ const options = buildExecutorOptions(state);
80
+ log.info(`Executing agent at cwd=${options.cwd}`);
81
+ log.info(`Prompt length: ${prompt.length} chars`);
82
+ const result = await executor.execute(prompt, options);
83
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
84
+ log.info(`Complete (${result.result.length} chars, ${elapsed}s)`);
85
+ const nodeResult = {
86
+ currentNode: nodeName,
87
+ messages: [`[${nodeName}] Complete (${result.result.length} chars, ${elapsed}s)`],
88
+ };
89
+ // Human-in-the-loop: interrupt after node execution for review
90
+ if (shouldInterrupt(nodeName, state.approvalMode)) {
91
+ log.info('Interrupting for human approval');
92
+ interrupt({
93
+ node: nodeName,
94
+ result: result.result.slice(0, 500),
95
+ message: `Node "${nodeName}" completed. Approve to continue.`,
96
+ });
97
+ }
98
+ return nodeResult;
99
+ }
100
+ catch (err) {
101
+ // Re-throw LangGraph control-flow exceptions (interrupt, Command, etc.)
102
+ if (isGraphBubbleUp(err))
103
+ throw err;
104
+ const message = err instanceof Error ? err.message : String(err);
105
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
106
+ log.error(`${message} (after ${elapsed}s)`);
107
+ return {
108
+ currentNode: nodeName,
109
+ error: message,
110
+ messages: [`[${nodeName}] Error: ${message}`],
111
+ };
112
+ }
113
+ };
114
+ }
@@ -0,0 +1,7 @@
1
+ import type { IAgentExecutor } from '../../../../../application/ports/output/agent-executor.interface.js';
2
+ /**
3
+ * Creates the plan node that generates an implementation plan (plan.yaml)
4
+ * and task breakdown with TDD cycles (tasks.yaml) from spec and research.
5
+ */
6
+ export declare function createPlanNode(executor: IAgentExecutor): (state: import("../state.js").FeatureAgentState) => Promise<Partial<import("../state.js").FeatureAgentState>>;
7
+ //# sourceMappingURL=plan.node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.node.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/plan.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wDAAwD,CAAC;AAI7F;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,cAAc,iHAEtD"}
@@ -0,0 +1,9 @@
1
+ import { executeNode } from './node-helpers.js';
2
+ import { buildPlanPrompt } from './prompts/plan.prompt.js';
3
+ /**
4
+ * Creates the plan node that generates an implementation plan (plan.yaml)
5
+ * and task breakdown with TDD cycles (tasks.yaml) from spec and research.
6
+ */
7
+ export function createPlanNode(executor) {
8
+ return executeNode('plan', executor, buildPlanPrompt);
9
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Analyze Phase Prompt
3
+ *
4
+ * Instructs the agent to analyze the repository and user query,
5
+ * then write findings to spec.yaml with complexity estimate and affected areas.
6
+ */
7
+ import type { FeatureAgentState } from '../../state.js';
8
+ export declare function buildAnalyzePrompt(state: FeatureAgentState): string;
9
+ //# sourceMappingURL=analyze.prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.prompt.d.ts","sourceRoot":"","sources":["../../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/prompts/analyze.prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAuFnE"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Analyze Phase Prompt
3
+ *
4
+ * Instructs the agent to analyze the repository and user query,
5
+ * then write findings to spec.yaml with complexity estimate and affected areas.
6
+ */
7
+ import { readSpecFile } from '../node-helpers.js';
8
+ export function buildAnalyzePrompt(state) {
9
+ const existingSpec = readSpecFile(state.specDir, 'spec.yaml');
10
+ return `You are a senior software architect performing the ANALYSIS phase of feature development.
11
+
12
+ ## Your Task
13
+
14
+ 1. Read and understand the feature request from the spec below
15
+ 2. Explore this repository thoroughly — understand the project structure, architecture, key technologies, patterns, and conventions
16
+ 3. Assess complexity and identify which areas of the codebase are affected
17
+ 4. Write your complete analysis to the spec YAML file
18
+
19
+ ## Feature Request (from spec.yaml)
20
+
21
+ ${existingSpec || `Feature ID: ${state.featureId}`}
22
+
23
+ ## What to Analyze
24
+
25
+ - **Project structure**: directories, modules, layers, organization patterns
26
+ - **Architecture**: design patterns, dependency flow, separation of concerns
27
+ - **Technologies**: languages, frameworks, libraries, build tools
28
+ - **Conventions**: naming, file organization, testing patterns, code style
29
+ - **Affected areas**: which parts of the codebase this feature will touch and why
30
+ - **Dependencies**: existing code/libraries this feature depends on
31
+ - **Complexity**: estimate effort as S (hours), M (days), L (week+), XL (multi-week)
32
+
33
+ ## Output Instructions
34
+
35
+ Write your analysis to: ${state.specDir}/spec.yaml
36
+
37
+ You MUST write the COMPLETE file (not a partial update). Preserve the existing name/number/branch fields and update everything else. Use this YAML structure:
38
+
39
+ name: (keep existing)
40
+ number: (keep existing)
41
+ branch: (keep existing)
42
+ oneLiner: (concise one-line description of the feature)
43
+ summary: >
44
+ (2-3 sentence summary of what this feature involves based on your analysis)
45
+ phase: Analysis
46
+ sizeEstimate: (S | M | L | XL)
47
+
48
+ relatedFeatures: []
49
+
50
+ technologies:
51
+ - (list each technology relevant to implementing this feature)
52
+
53
+ relatedLinks: []
54
+
55
+ openQuestions: []
56
+
57
+ content: |
58
+ ## Problem Statement
59
+
60
+ (What problem does this feature solve? Reference specific current limitations.)
61
+
62
+ ## Codebase Analysis
63
+
64
+ ### Project Structure
65
+ (Key directories, their purposes, and how they relate)
66
+
67
+ ### Architecture Patterns
68
+ (Design patterns, dependency rules, layering)
69
+
70
+ ### Relevant Technologies
71
+ (Frameworks and libraries in use that are relevant to this feature)
72
+
73
+ ## Affected Areas
74
+
75
+ | Area | Impact | Reasoning |
76
+ | ---- | ------ | --------- |
77
+ | (path/module) | (High/Medium/Low) | (why this area is affected) |
78
+
79
+ ## Dependencies
80
+
81
+ (What existing code, libraries, or infrastructure does this feature depend on?)
82
+
83
+ ## Size Estimate
84
+
85
+ **(S/M/L/XL)** — (justify your estimate with specific reasoning)
86
+
87
+ ## Constraints
88
+
89
+ - Write ONLY to ${state.specDir}/spec.yaml
90
+ - Do NOT create any other files
91
+ - Do NOT modify any source code
92
+ - Do NOT start implementing the feature
93
+ - Keep your analysis thorough but concise`;
94
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Implement Phase Prompt — PLACEHOLDER
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.
6
+ */
7
+ export declare function getImplementPlaceholderJoke(): string;
8
+ //# sourceMappingURL=implement.prompt.d.ts.map