@shepai/cli 1.124.0 → 1.126.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 (227) hide show
  1. package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts +13 -2
  2. package/dist/packages/core/src/application/ports/output/services/deployment-service.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  4. package/dist/packages/core/src/infrastructure/di/container.js +2 -0
  5. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/040-create-dev-servers-table.d.ts +21 -0
  6. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/040-create-dev-servers-table.d.ts.map +1 -0
  7. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/040-create-dev-servers-table.js +32 -0
  8. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/ci-watch-fix-loop.d.ts.map +1 -1
  9. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/ci-watch-fix-loop.js +9 -0
  10. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts +24 -14
  11. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -1
  12. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +203 -31
  13. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.d.ts +0 -6
  14. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.d.ts.map +1 -1
  15. package/dist/packages/core/src/infrastructure/services/deployment/parse-port.js +6 -1
  16. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
  17. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +7 -2
  18. package/dist/src/presentation/web/app/actions/deploy-feature.js +1 -1
  19. package/dist/src/presentation/web/app/actions/deploy-repository.js +1 -1
  20. package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
  21. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +7 -4
  22. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  23. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +12 -3
  24. package/dist/src/presentation/web/components/features/settings/notification-settings-section.d.ts.map +1 -1
  25. package/dist/src/presentation/web/components/features/settings/notification-settings-section.js +4 -8
  26. package/dist/src/presentation/web/components/features/settings/notification-settings-section.stories.js +3 -3
  27. package/dist/src/presentation/web/components/features/settings/settings-page-client.d.ts.map +1 -1
  28. package/dist/src/presentation/web/components/features/settings/settings-page-client.js +12 -37
  29. package/dist/src/presentation/web/components/features/settings/settings-page-client.stories.d.ts.map +1 -1
  30. package/dist/src/presentation/web/components/features/settings/settings-page-client.stories.js +2 -3
  31. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
  32. package/dist/src/presentation/web/hooks/use-deploy-action.js +69 -10
  33. package/dist/src/presentation/web/lib/layout-with-dagre.js +3 -3
  34. package/dist/tsconfig.build.tsbuildinfo +1 -1
  35. package/package.json +1 -1
  36. package/web/.next/BUILD_ID +1 -1
  37. package/web/.next/build-manifest.json +2 -2
  38. package/web/.next/fallback-build-manifest.json +2 -2
  39. package/web/.next/prerender-manifest.json +3 -3
  40. package/web/.next/required-server-files.js +2 -2
  41. package/web/.next/required-server-files.json +2 -2
  42. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +57 -57
  43. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +2 -2
  44. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  45. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  46. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +69 -69
  47. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +2 -2
  48. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  49. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  50. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +69 -69
  51. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +2 -2
  52. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  53. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  54. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +53 -53
  55. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +2 -2
  56. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  57. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  58. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +57 -57
  59. package/web/.next/server/app/(dashboard)/create/page.js +2 -2
  60. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  61. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  62. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +69 -69
  63. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +2 -2
  64. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  65. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +69 -69
  67. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +2 -2
  68. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  69. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  70. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +53 -53
  71. package/web/.next/server/app/(dashboard)/page.js +2 -2
  72. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  73. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  74. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +53 -53
  75. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +2 -2
  76. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  77. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  78. package/web/.next/server/app/_global-error.html +2 -2
  79. package/web/.next/server/app/_global-error.rsc +1 -1
  80. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  81. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  82. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  83. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  84. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  85. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  86. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  87. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  88. package/web/.next/server/app/settings/page/server-reference-manifest.json +6 -6
  89. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  90. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  92. package/web/.next/server/app/skills/page.js +1 -2
  93. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  94. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  95. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  96. package/web/.next/server/app/tools/page.js +1 -2
  97. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  98. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  99. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  100. package/web/.next/server/app/version/page.js.nft.json +1 -1
  101. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  102. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
  103. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
  104. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  105. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  106. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  107. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_fdfbf5cc.js +3 -0
  108. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_fdfbf5cc.js.map +1 -0
  109. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_d8fa0b5f.js +3 -0
  110. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_d8fa0b5f.js.map +1 -0
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__06fef644._.js +1 -1
  112. package/web/.next/server/chunks/ssr/{[root-of-the-server]__ce6057f6._.js → [root-of-the-server]__248b9fc3._.js} +2 -2
  113. package/web/.next/server/chunks/ssr/{[root-of-the-server]__9e8b25ad._.js.map → [root-of-the-server]__248b9fc3._.js.map} +1 -1
  114. package/web/.next/server/chunks/ssr/[root-of-the-server]__357de47c._.js +4 -0
  115. package/web/.next/server/chunks/ssr/[root-of-the-server]__357de47c._.js.map +1 -0
  116. package/web/.next/server/chunks/ssr/[root-of-the-server]__56ecbe40._.js +3 -0
  117. package/web/.next/server/chunks/ssr/[root-of-the-server]__56ecbe40._.js.map +1 -0
  118. package/web/.next/server/chunks/ssr/[root-of-the-server]__67fe07fe._.js +4 -0
  119. package/web/.next/server/chunks/ssr/[root-of-the-server]__67fe07fe._.js.map +1 -0
  120. package/web/.next/server/chunks/ssr/[root-of-the-server]__68c2d48e._.js +3 -0
  121. package/web/.next/server/chunks/ssr/[root-of-the-server]__68c2d48e._.js.map +1 -0
  122. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  123. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  124. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
  125. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
  126. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  127. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  128. package/web/.next/server/chunks/ssr/[root-of-the-server]__8c553503._.js +2 -2
  129. package/web/.next/server/chunks/ssr/[root-of-the-server]__a50a7e39._.js +4 -0
  130. package/web/.next/server/chunks/ssr/[root-of-the-server]__a50a7e39._.js.map +1 -0
  131. package/web/.next/server/chunks/ssr/{[root-of-the-server]__7cbda1ea._.js → [root-of-the-server]__dfc367f2._.js} +2 -2
  132. package/web/.next/server/chunks/ssr/{[root-of-the-server]__ce6057f6._.js.map → [root-of-the-server]__dfc367f2._.js.map} +1 -1
  133. package/web/.next/server/chunks/ssr/{[root-of-the-server]__9e8b25ad._.js → [root-of-the-server]__e7f61cc6._.js} +2 -2
  134. package/web/.next/server/chunks/ssr/{[root-of-the-server]__7cbda1ea._.js.map → [root-of-the-server]__e7f61cc6._.js.map} +1 -1
  135. package/web/.next/server/chunks/ssr/{[root-of-the-server]__aed1d6f8._.js → [root-of-the-server]__fe48d2dc._.js} +2 -2
  136. package/web/.next/server/chunks/ssr/{[root-of-the-server]__aed1d6f8._.js.map → [root-of-the-server]__fe48d2dc._.js.map} +1 -1
  137. package/web/.next/server/chunks/ssr/_243e3685._.js +3 -0
  138. package/web/.next/server/chunks/ssr/_243e3685._.js.map +1 -0
  139. package/web/.next/server/chunks/ssr/_2f6f48b8._.js +1 -1
  140. package/web/.next/server/chunks/ssr/_2f6f48b8._.js.map +1 -1
  141. package/web/.next/server/chunks/ssr/_7dca1882._.js +3 -0
  142. package/web/.next/server/chunks/ssr/_7dca1882._.js.map +1 -0
  143. package/web/.next/server/chunks/ssr/{_f84c16ab._.js → _821bbcc5._.js} +2 -2
  144. package/web/.next/server/chunks/ssr/{_f84c16ab._.js.map → _821bbcc5._.js.map} +1 -1
  145. package/web/.next/server/chunks/ssr/{_0e506641._.js → _918887c5._.js} +2 -2
  146. package/web/.next/server/chunks/ssr/_918887c5._.js.map +1 -0
  147. package/web/.next/server/chunks/ssr/{_1bb131c4._.js → _d4b20e29._.js} +2 -2
  148. package/web/.next/server/chunks/ssr/_d4b20e29._.js.map +1 -0
  149. package/web/.next/server/chunks/ssr/_e9703421._.js +1 -1
  150. package/web/.next/server/chunks/ssr/_e9703421._.js.map +1 -1
  151. package/web/.next/server/chunks/ssr/_f39a1adb._.js +3 -0
  152. package/web/.next/server/chunks/ssr/{_135edb9c._.js.map → _f39a1adb._.js.map} +1 -1
  153. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  154. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  155. package/web/.next/server/chunks/ssr/src_presentation_web_9db47db7._.js +5 -0
  156. package/web/.next/server/chunks/ssr/{src_presentation_web_5f039db1._.js.map → src_presentation_web_9db47db7._.js.map} +1 -1
  157. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f66cd328.js +3 -0
  158. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_f66cd328.js.map +1 -0
  159. package/web/.next/server/chunks/ssr/src_presentation_web_aeddd007._.js +3 -0
  160. package/web/.next/server/chunks/ssr/{src_presentation_web_164fa933._.js.map → src_presentation_web_aeddd007._.js.map} +1 -1
  161. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  162. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
  163. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
  164. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -1
  165. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
  166. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js.map +1 -1
  167. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  168. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  169. package/web/.next/server/chunks/ssr/src_presentation_web_ede4a227._.js +5 -0
  170. package/web/.next/server/chunks/ssr/{src_presentation_web_c4337169._.js.map → src_presentation_web_ede4a227._.js.map} +1 -1
  171. package/web/.next/server/pages/500.html +2 -2
  172. package/web/.next/server/server-reference-manifest.js +1 -1
  173. package/web/.next/server/server-reference-manifest.json +325 -325
  174. package/web/.next/static/chunks/01ba448cf76c6014.js +1 -0
  175. package/web/.next/static/chunks/044f4665499a9656.js +1 -0
  176. package/web/.next/static/chunks/112cf5891d1ca558.js +1 -0
  177. package/web/.next/static/chunks/1be7ac7a24009333.css +1 -0
  178. package/web/.next/static/chunks/37ada233462bcaec.js +11 -0
  179. package/web/.next/static/chunks/4ac11847f73b50d6.js +1 -0
  180. package/web/.next/static/chunks/{5b7726ff31c25338.js → 4ac4a43b7eb441e1.js} +2 -2
  181. package/web/.next/static/chunks/5fb66ee5a353a6c6.js +1 -0
  182. package/web/.next/static/chunks/6cfc75060a243290.js +1 -0
  183. package/web/.next/static/chunks/b70dd4985a814b27.js +1 -0
  184. package/web/.next/static/chunks/{9db7f24ddea15a4c.js → d60f93a1a25ab09d.js} +1 -1
  185. package/web/.next/static/chunks/dcfed2c9b7cd1cb4.js +1 -0
  186. package/web/.next/static/chunks/{ad076c0b68dd9971.js → de66f8d6a67c2361.js} +1 -1
  187. package/web/.next/static/chunks/{74fa59dbd04fdfcb.js → de8b0265f780e212.js} +2 -2
  188. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js +0 -3
  189. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js.map +0 -1
  190. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js +0 -3
  191. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js.map +0 -1
  192. package/web/.next/server/chunks/ssr/[root-of-the-server]__14664e9b._.js +0 -4
  193. package/web/.next/server/chunks/ssr/[root-of-the-server]__14664e9b._.js.map +0 -1
  194. package/web/.next/server/chunks/ssr/[root-of-the-server]__4993a47c._.js +0 -3
  195. package/web/.next/server/chunks/ssr/[root-of-the-server]__4993a47c._.js.map +0 -1
  196. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js +0 -3
  197. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js.map +0 -1
  198. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +0 -4
  199. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js.map +0 -1
  200. package/web/.next/server/chunks/ssr/_0e506641._.js.map +0 -1
  201. package/web/.next/server/chunks/ssr/_135edb9c._.js +0 -3
  202. package/web/.next/server/chunks/ssr/_1bb131c4._.js.map +0 -1
  203. package/web/.next/server/chunks/ssr/_b89059c0._.js +0 -3
  204. package/web/.next/server/chunks/ssr/_b89059c0._.js.map +0 -1
  205. package/web/.next/server/chunks/ssr/_cc77a143._.js +0 -3
  206. package/web/.next/server/chunks/ssr/_cc77a143._.js.map +0 -1
  207. package/web/.next/server/chunks/ssr/src_presentation_web_164fa933._.js +0 -3
  208. package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js +0 -5
  209. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js +0 -3
  210. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js.map +0 -1
  211. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +0 -3
  212. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +0 -1
  213. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +0 -3
  214. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +0 -1
  215. package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js +0 -5
  216. package/web/.next/static/chunks/0dc102ef519487f5.js +0 -1
  217. package/web/.next/static/chunks/10fc8c2e5ff44bb2.js +0 -1
  218. package/web/.next/static/chunks/3925626b99dcd57a.css +0 -1
  219. package/web/.next/static/chunks/76c038a9d55ca717.js +0 -1
  220. package/web/.next/static/chunks/9d7e0bb6dc2f88ae.js +0 -1
  221. package/web/.next/static/chunks/ac7251026c1e2cdf.js +0 -1
  222. package/web/.next/static/chunks/d72044b2826292fe.js +0 -1
  223. package/web/.next/static/chunks/e2ef95d904c360f3.js +0 -1
  224. package/web/.next/static/chunks/eaeabda870a35a9a.js +0 -11
  225. /package/web/.next/static/{Ap_0BUaFHzD8WxrlWsbMg → 4hN7Gtw--ruMbDn0FRI2-}/_buildManifest.js +0 -0
  226. /package/web/.next/static/{Ap_0BUaFHzD8WxrlWsbMg → 4hN7Gtw--ruMbDn0FRI2-}/_clientMiddlewareManifest.json +0 -0
  227. /package/web/.next/static/{Ap_0BUaFHzD8WxrlWsbMg → 4hN7Gtw--ruMbDn0FRI2-}/_ssgManifest.js +0 -0
@@ -9,6 +9,7 @@
9
9
  * - Application layer depends on this interface
10
10
  * - Infrastructure layer provides concrete implementations
11
11
  */
12
+ import type Database from 'better-sqlite3';
12
13
  import type { DeploymentState } from '../../../../domain/generated/output.js';
13
14
  /** A single log line captured from a deployment's stdout or stderr. */
14
15
  export interface LogEntry {
@@ -39,16 +40,26 @@ export interface DeploymentStatus {
39
40
  * - Support graceful shutdown (SIGTERM → SIGKILL) for individual and bulk stops
40
41
  */
41
42
  export interface IDeploymentService {
43
+ /**
44
+ * Inject the database connection for persistence.
45
+ * Must be called before start/stop/getStatus to enable DB persistence.
46
+ */
47
+ setDatabase(db: Database.Database): void;
48
+ /**
49
+ * Recover dev servers from the database on startup.
50
+ * Validates each PID is still alive; removes dead rows.
51
+ */
52
+ recoverAll(): void;
42
53
  /**
43
54
  * Start a dev server deployment for the given target.
44
55
  * If a deployment already exists for this targetId, it is stopped first.
45
56
  *
46
57
  * @param targetId - Unique identifier for the deployment target (featureId or repositoryId)
47
58
  * @param targetPath - Absolute filesystem path to the directory to run the dev server in
48
- * @returns The initial deployment state (always Booting on success)
59
+ * @param targetType - Type of target ('feature' or 'repository')
49
60
  * @throws Error if no dev script is found in package.json or the process fails to spawn
50
61
  */
51
- start(targetId: string, targetPath: string): void;
62
+ start(targetId: string, targetPath: string, targetType?: string): void;
52
63
  /**
53
64
  * Stop a running deployment gracefully.
54
65
  * Sends SIGTERM to the process group, then SIGKILL after a timeout.
@@ -1 +1 @@
1
- {"version":3,"file":"deployment-service.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/services/deployment-service.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,uEAAuE;AACvE,MAAM,WAAW,QAAQ;IACvB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,KAAK,EAAE,eAAe,CAAC;IACvB,qEAAqE;IACrE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;OAQG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAElD;;;;;;OAMG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAErD;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;IAIhB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC;IAE7C;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAC;CAC7D"}
1
+ {"version":3,"file":"deployment-service.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/services/deployment-service.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAEpE,uEAAuE;AACvE,MAAM,WAAW,QAAQ;IACvB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,MAAM,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,KAAK,EAAE,eAAe,CAAC;IACvB,qEAAqE;IACrE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC;IAEzC;;;OAGG;IACH,UAAU,IAAI,IAAI,CAAC;IAEnB;;;;;;;;OAQG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvE;;;;;;OAMG;IACH,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAErD;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAC;IAIhB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC;IAE7C;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAC;CAC7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAoHrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAiUrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAoHrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAmUrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -169,6 +169,8 @@ export async function initializeContainer() {
169
169
  container.registerSingleton(AttachmentStorageService);
170
170
  container.register('AttachmentStorageService', { useToken: AttachmentStorageService });
171
171
  const deploymentService = new DeploymentService();
172
+ deploymentService.setDatabase(db);
173
+ deploymentService.recoverAll();
172
174
  container.registerInstance('IDeploymentService', deploymentService);
173
175
  // Register agent infrastructure
174
176
  container.register('IAgentRunRepository', {
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Migration 040: Create dev_servers table.
3
+ *
4
+ * Persists running dev server deployments so they survive page reloads
5
+ * and server restarts. The DeploymentService reconciles on startup by
6
+ * checking PID liveness and cleaning up stale rows.
7
+ *
8
+ * Columns:
9
+ * - target_id TEXT PRIMARY KEY — featureId or repositoryPath
10
+ * - target_type TEXT NOT NULL — 'feature' | 'repository'
11
+ * - pid INTEGER NOT NULL — OS process ID
12
+ * - state TEXT NOT NULL — DeploymentState enum value
13
+ * - url TEXT — detected dev server URL (null while Booting)
14
+ * - target_path TEXT NOT NULL — filesystem path where the dev server runs
15
+ * - started_at INTEGER NOT NULL — unix milliseconds
16
+ */
17
+ import type { MigrationParams } from 'umzug';
18
+ import type Database from 'better-sqlite3';
19
+ export declare function up({ context: db }: MigrationParams<Database.Database>): Promise<void>;
20
+ export declare function down({ context: db }: MigrationParams<Database.Database>): Promise<void>;
21
+ //# sourceMappingURL=040-create-dev-servers-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"040-create-dev-servers-table.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/persistence/sqlite/migrations/040-create-dev-servers-table.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,wBAAsB,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAY3F;AAED,wBAAsB,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,eAAe,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7F"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Migration 040: Create dev_servers table.
3
+ *
4
+ * Persists running dev server deployments so they survive page reloads
5
+ * and server restarts. The DeploymentService reconciles on startup by
6
+ * checking PID liveness and cleaning up stale rows.
7
+ *
8
+ * Columns:
9
+ * - target_id TEXT PRIMARY KEY — featureId or repositoryPath
10
+ * - target_type TEXT NOT NULL — 'feature' | 'repository'
11
+ * - pid INTEGER NOT NULL — OS process ID
12
+ * - state TEXT NOT NULL — DeploymentState enum value
13
+ * - url TEXT — detected dev server URL (null while Booting)
14
+ * - target_path TEXT NOT NULL — filesystem path where the dev server runs
15
+ * - started_at INTEGER NOT NULL — unix milliseconds
16
+ */
17
+ export async function up({ context: db }) {
18
+ db.exec(`
19
+ CREATE TABLE IF NOT EXISTS dev_servers (
20
+ target_id TEXT PRIMARY KEY,
21
+ target_type TEXT NOT NULL,
22
+ pid INTEGER NOT NULL,
23
+ state TEXT NOT NULL DEFAULT 'Booting',
24
+ url TEXT,
25
+ target_path TEXT NOT NULL,
26
+ started_at INTEGER NOT NULL
27
+ )
28
+ `);
29
+ }
30
+ export async function down({ context: db }) {
31
+ db.exec('DROP TABLE IF EXISTS dev_servers');
32
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"ci-watch-fix-loop.d.ts","sourceRoot":"","sources":["../../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/ci-watch-fix-loop.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yEAAyE,CAAC;AAClH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iEAAiE,CAAC;AAKrG,OAAO,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+DAA+D,CAAC;AAK3G,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,YAAY,EAAE,aAAa,CAAC;IAC5B,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;CACpE;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAEpG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,WAAW,EAAE,gBAAgB,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CA8I3B"}
1
+ {"version":3,"file":"ci-watch-fix-loop.d.ts","sourceRoot":"","sources":["../../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/ci-watch-fix-loop.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yEAAyE,CAAC;AAClH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iEAAiE,CAAC;AAKrG,OAAO,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,+DAA+D,CAAC;AAK3G,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,YAAY,EAAE,aAAa,CAAC;IAC5B,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;CACpE;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,qBAAqB,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAEpG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,WAAW,EAAE,gBAAgB,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAuJ3B"}
@@ -84,6 +84,11 @@ export async function runCiWatchFixLoop(deps, params) {
84
84
  }
85
85
  throw err;
86
86
  }
87
+ // Use the run URL from watchCi — it reflects the actual run watched,
88
+ // which may differ from the initial getCiStatus() result when multiple
89
+ // workflow runs exist for the same branch.
90
+ if (watchResult.runUrl)
91
+ runUrl = watchResult.runUrl;
87
92
  if (watchResult.status === 'success') {
88
93
  log.info('CI passed on first watch');
89
94
  return { ciStatus: CiStatus.Success, ciFixAttempts, ciFixHistory, ciFixStatus: 'success' };
@@ -128,6 +133,10 @@ export async function runCiWatchFixLoop(deps, params) {
128
133
  }
129
134
  throw err;
130
135
  }
136
+ // Update runUrl to the run that was actually watched (avoids mismatch
137
+ // when multiple workflow runs exist for the same branch).
138
+ if (fixWatchResult.runUrl)
139
+ runUrl = fixWatchResult.runUrl;
131
140
  const outcome = fixWatchResult.status === 'success' ? 'fixed' : 'failed';
132
141
  ciFixHistory.push({
133
142
  attempt: ciFixAttempts,
@@ -2,11 +2,15 @@
2
2
  * Deployment Service
3
3
  *
4
4
  * Infrastructure service that manages local dev server deployments.
5
- * Holds an in-memory Map of active deployments keyed by targetId.
6
- * Handles process spawning, stdout-based port detection, and graceful
7
- * shutdown (SIGTERM poll SIGKILL).
5
+ * Holds an in-memory Map of active deployments keyed by targetId AND
6
+ * persists deployment records to the `dev_servers` SQLite table so that
7
+ * running dev servers survive page reloads and server restarts.
8
+ *
9
+ * On startup, call `recoverAll()` to reconcile the DB with actual
10
+ * process state (clean up dead PIDs, re-adopt live ones).
8
11
  */
9
12
  import { spawn } from 'node:child_process';
13
+ import type Database from 'better-sqlite3';
10
14
  import type { IDeploymentService, DeploymentStatus, LogEntry } from '../../../application/ports/output/services/deployment-service.interface.js';
11
15
  import { detectDevScript } from './detect-dev-script.js';
12
16
  export interface DeploymentServiceDeps {
@@ -19,15 +23,26 @@ export declare class DeploymentService implements IDeploymentService {
19
23
  private readonly deployments;
20
24
  private readonly deps;
21
25
  private readonly emitter;
26
+ private db;
22
27
  constructor(deps?: Partial<DeploymentServiceDeps>);
28
+ /**
29
+ * Inject the database connection. Called from DI container after DB is ready.
30
+ */
31
+ setDatabase(db: Database.Database): void;
32
+ /**
33
+ * Recover dev servers from the database on startup.
34
+ * Validates each PID is still alive; removes dead rows.
35
+ */
36
+ recoverAll(): void;
23
37
  /**
24
38
  * Start a deployment for the given target.
25
39
  * If a deployment already exists for this target, it is stopped first.
26
40
  */
27
- start(targetId: string, targetPath: string): void;
41
+ start(targetId: string, targetPath: string, targetType?: string): void;
28
42
  /**
29
43
  * Get the current deployment status for a target.
30
- * Returns null if no deployment exists for this target.
44
+ * Checks in-memory Map first, then falls back to DB for recovered deployments.
45
+ * Validates PID liveness — cleans up if dead.
31
46
  */
32
47
  getStatus(targetId: string): DeploymentStatus | null;
33
48
  /**
@@ -50,22 +65,17 @@ export declare class DeploymentService implements IDeploymentService {
50
65
  * Unsubscribe from real-time log events.
51
66
  */
52
67
  off(event: 'log', handler: (entry: LogEntry) => void): void;
53
- /**
54
- * Send SIGKILL to a process tree.
55
- */
68
+ private dbUpsert;
69
+ private dbUpdateState;
70
+ private dbDelete;
71
+ private dbFind;
56
72
  private killProcess;
57
73
  /**
58
74
  * Attach a line-buffered listener on stdout or stderr that calls parsePort
59
75
  * and accumulates log entries.
60
76
  */
61
77
  private attachOutputListener;
62
- /**
63
- * Poll until a process is dead or timeout expires.
64
- */
65
78
  private pollUntilDead;
66
- /**
67
- * Wait for a child process to emit 'exit', with a short timeout.
68
- */
69
79
  private waitForExit;
70
80
  }
71
81
  //# sourceMappingURL=deployment.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAI9D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACT,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAoBzD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AAgBD,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;gBAElC,IAAI,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAIrD;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IA+EjD;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAYpD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAyC3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAOf;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI;IAM5C;;OAEG;IACH,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAI1D;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAI3D;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IA+D5B;;OAEG;YACW,aAAa;IAW3B;;OAEG;IACH,OAAO,CAAC,WAAW;CASpB"}
1
+ {"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAO3C,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACT,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAgCzD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AA6BD,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,EAAE,CAAkC;gBAEhC,IAAI,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAIrD;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI;IAIxC;;;OAGG;IACH,UAAU,IAAI,IAAI;IA4ClB;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,SAAe,GAAG,IAAI;IAqF5E;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IA4CpD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0D3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAef;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI;IAM5C;;OAEG;IACH,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAI1D;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAM3D,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,MAAM;IAed,OAAO,CAAC,WAAW;IAQnB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;YA4Dd,aAAa;IAW3B,OAAO,CAAC,WAAW;CASpB"}
@@ -2,13 +2,20 @@
2
2
  * Deployment Service
3
3
  *
4
4
  * Infrastructure service that manages local dev server deployments.
5
- * Holds an in-memory Map of active deployments keyed by targetId.
6
- * Handles process spawning, stdout-based port detection, and graceful
7
- * shutdown (SIGTERM poll SIGKILL).
5
+ * Holds an in-memory Map of active deployments keyed by targetId AND
6
+ * persists deployment records to the `dev_servers` SQLite table so that
7
+ * running dev servers survive page reloads and server restarts.
8
+ *
9
+ * On startup, call `recoverAll()` to reconcile the DB with actual
10
+ * process state (clean up dead PIDs, re-adopt live ones).
8
11
  */
9
12
  import { spawn } from 'node:child_process';
10
13
  import { EventEmitter } from 'node:events';
11
- import treeKill from 'tree-kill';
14
+ // NOTE: We intentionally do NOT use tree-kill here. tree-kill traverses
15
+ // /proc to find child processes which can accidentally kill parent processes
16
+ // (including the Shep web UI). Instead, we use process.kill(-pid) to send
17
+ // signals to the process GROUP (since we spawn with detached: true, the
18
+ // child gets its own process group via setsid()).
12
19
  import { DeploymentState } from '../../../domain/generated/output.js';
13
20
  import { detectDevScript } from './detect-dev-script.js';
14
21
  import { createDeploymentLogger } from './deployment-logger.js';
@@ -20,7 +27,22 @@ const MAX_WAIT_MS = 5000;
20
27
  const defaultDeps = {
21
28
  spawn,
22
29
  detectDevScript,
23
- kill: (pid, signal) => treeKill(pid, signal),
30
+ kill: (pid, signal) => {
31
+ try {
32
+ // Kill the entire process group (negative PID) — safe because
33
+ // detached: true puts the child in its own group via setsid().
34
+ process.kill(-pid, signal);
35
+ }
36
+ catch {
37
+ // Fallback: kill just the process itself
38
+ try {
39
+ process.kill(pid, signal);
40
+ }
41
+ catch {
42
+ // Process already dead
43
+ }
44
+ }
45
+ },
24
46
  isAlive: (pid) => {
25
47
  try {
26
48
  process.kill(pid, 0);
@@ -35,14 +57,65 @@ export class DeploymentService {
35
57
  deployments = new Map();
36
58
  deps;
37
59
  emitter = new EventEmitter();
60
+ db = null;
38
61
  constructor(deps = {}) {
39
62
  this.deps = { ...defaultDeps, ...deps };
40
63
  }
64
+ /**
65
+ * Inject the database connection. Called from DI container after DB is ready.
66
+ */
67
+ setDatabase(db) {
68
+ this.db = db;
69
+ }
70
+ /**
71
+ * Recover dev servers from the database on startup.
72
+ * Validates each PID is still alive; removes dead rows.
73
+ */
74
+ recoverAll() {
75
+ if (!this.db)
76
+ return;
77
+ let rows;
78
+ try {
79
+ const stmt = this.db.prepare('SELECT * FROM dev_servers');
80
+ rows = stmt.all() ?? [];
81
+ }
82
+ catch {
83
+ log.info('dev_servers table not ready — skipping recovery');
84
+ return;
85
+ }
86
+ if (!rows || rows.length === 0) {
87
+ log.info('No dev servers to recover from database');
88
+ return;
89
+ }
90
+ log.info(`Recovering ${rows.length} dev server(s) from database`);
91
+ for (const row of rows) {
92
+ if (this.deps.isAlive(row.pid)) {
93
+ log.info(`Recovered "${row.target_id}" (pid=${row.pid}, state=${row.state}, url=${row.url})`);
94
+ const entry = {
95
+ pid: row.pid,
96
+ child: null, // orphan — we don't have the ChildProcess handle
97
+ state: row.state,
98
+ url: row.url,
99
+ targetId: row.target_id,
100
+ targetPath: row.target_path,
101
+ targetType: row.target_type,
102
+ stdoutBuffer: '',
103
+ stderrBuffer: '',
104
+ logs: new LogRingBuffer(),
105
+ };
106
+ this.deployments.set(row.target_id, entry);
107
+ }
108
+ else {
109
+ log.info(`Stale dev server "${row.target_id}" (pid=${row.pid}) — removing from DB`);
110
+ this.dbDelete(row.target_id);
111
+ }
112
+ }
113
+ }
41
114
  /**
42
115
  * Start a deployment for the given target.
43
116
  * If a deployment already exists for this target, it is stopped first.
44
117
  */
45
- start(targetId, targetPath) {
118
+ start(targetId, targetPath, targetType = 'repository') {
46
119
  log.info(`start() called — targetId="${targetId}", targetPath="${targetPath}"`);
47
120
  // Stop any existing deployment for this target
48
121
  const existing = this.deployments.get(targetId);
@@ -50,6 +123,7 @@ export class DeploymentService {
50
123
  log.info(`Stopping existing deployment for "${targetId}" (pid=${existing.pid})`);
51
124
  this.killProcess(existing);
52
125
  this.deployments.delete(targetId);
126
+ this.dbDelete(targetId);
53
127
  }
54
128
  // Detect the dev script
55
129
  const detection = this.deps.detectDevScript(targetPath);
@@ -78,11 +152,14 @@ export class DeploymentService {
78
152
  state: DeploymentState.Booting,
79
153
  url: null,
80
154
  targetId,
155
+ targetPath,
156
+ targetType,
81
157
  stdoutBuffer: '',
82
158
  stderrBuffer: '',
83
159
  logs: new LogRingBuffer(),
84
160
  };
85
161
  this.deployments.set(targetId, entry);
162
+ this.dbUpsert(entry);
86
163
  // Attach stdout/stderr listeners for port detection
87
164
  this.attachOutputListener(entry, 'stdout');
88
165
  this.attachOutputListener(entry, 'stderr');
@@ -91,6 +168,7 @@ export class DeploymentService {
91
168
  log.error(`Child process error for "${targetId}" (pid=${entry.pid}): ${err.message}`);
92
169
  entry.state = DeploymentState.Stopped;
93
170
  this.deployments.delete(targetId);
171
+ this.dbDelete(targetId);
94
172
  });
95
173
  // Clean up on process exit
96
174
  child.on('exit', (code, signal) => {
@@ -100,20 +178,52 @@ export class DeploymentService {
100
178
  log.warn('Process exited while still in Booting state — dev server likely crashed on startup. Check stderr output above.');
101
179
  }
102
180
  this.deployments.delete(targetId);
181
+ this.dbDelete(targetId);
103
182
  });
104
183
  }
105
184
  /**
106
185
  * Get the current deployment status for a target.
107
- * Returns null if no deployment exists for this target.
186
+ * Checks in-memory Map first, then falls back to DB for recovered deployments.
187
+ * Validates PID liveness — cleans up if dead.
108
188
  */
109
189
  getStatus(targetId) {
110
190
  const entry = this.deployments.get(targetId);
111
- if (!entry) {
112
- log.debug(`getStatus("${targetId}") no deployment found`);
113
- return null;
191
+ if (entry) {
192
+ // Validate the process is still alive (handles orphan crashes)
193
+ if (!this.deps.isAlive(entry.pid)) {
194
+ log.info(`getStatus("${targetId}") — pid=${entry.pid} is dead, cleaning up`);
195
+ this.deployments.delete(targetId);
196
+ this.dbDelete(targetId);
197
+ return null;
198
+ }
199
+ log.debug(`getStatus("${targetId}") — state=${entry.state}, url=${entry.url}, pid=${entry.pid}`);
200
+ return { state: entry.state, url: entry.url };
114
201
  }
115
- log.debug(`getStatus("${targetId}") state=${entry.state}, url=${entry.url}, pid=${entry.pid}`);
116
- return { state: entry.state, url: entry.url };
202
+ // Check DB for entries not yet in memory (e.g., after hook re-mount)
203
+ const row = this.dbFind(targetId);
204
+ if (row) {
205
+ if (this.deps.isAlive(row.pid)) {
206
+ // Re-adopt into memory
207
+ const recovered = {
208
+ pid: row.pid,
209
+ child: null,
210
+ state: row.state,
211
+ url: row.url,
212
+ targetId: row.target_id,
213
+ targetPath: row.target_path,
214
+ targetType: row.target_type,
215
+ stdoutBuffer: '',
216
+ stderrBuffer: '',
217
+ logs: new LogRingBuffer(),
218
+ };
219
+ this.deployments.set(targetId, recovered);
220
+ return { state: recovered.state, url: recovered.url };
221
+ }
222
+ // Dead — clean up
223
+ this.dbDelete(targetId);
224
+ }
225
+ log.debug(`getStatus("${targetId}") — no deployment found`);
226
+ return null;
117
227
  }
118
228
  /**
119
229
  * Stop a deployment gracefully: SIGTERM → poll → SIGKILL.
@@ -121,7 +231,19 @@ export class DeploymentService {
121
231
  async stop(targetId) {
122
232
  const entry = this.deployments.get(targetId);
123
233
  if (!entry) {
124
- log.info(`stop("${targetId}") no deployment found, nothing to stop`);
234
+ // Check DB in case it's a recovered orphan
235
+ const row = this.dbFind(targetId);
236
+ if (row && this.deps.isAlive(row.pid)) {
237
+ log.info(`stop("${targetId}") — killing orphan process (pid=${row.pid})`);
238
+ try {
239
+ this.deps.kill(row.pid, 'SIGKILL');
240
+ }
241
+ catch {
242
+ // already dead
243
+ }
244
+ }
245
+ this.dbDelete(targetId);
246
+ log.info(`stop("${targetId}") — no in-memory deployment found, cleaned DB`);
125
247
  return;
126
248
  }
127
249
  log.info(`stop("${targetId}") — sending SIGTERM to process tree (pid=${entry.pid})`);
@@ -133,13 +255,13 @@ export class DeploymentService {
133
255
  catch {
134
256
  log.info(`stop("${targetId}") — process already dead on SIGTERM`);
135
257
  this.deployments.delete(targetId);
258
+ this.dbDelete(targetId);
136
259
  return;
137
260
  }
138
261
  // Wait for the process to exit
139
262
  const died = await this.pollUntilDead(entry.pid, MAX_WAIT_MS, POLL_INTERVAL_MS);
140
263
  if (!died) {
141
264
  log.warn(`stop("${targetId}") — process did not exit after ${MAX_WAIT_MS}ms, escalating to SIGKILL`);
142
- // Escalate to SIGKILL
143
265
  try {
144
266
  this.deps.kill(entry.pid, 'SIGKILL');
145
267
  }
@@ -150,8 +272,13 @@ export class DeploymentService {
150
272
  else {
151
273
  log.info(`stop("${targetId}") — process exited gracefully`);
152
274
  }
153
- // Wait for the exit event to clean up the map
154
- await this.waitForExit(entry.child);
275
+ // Wait for the exit event to clean up the map (only if we have a ChildProcess handle)
276
+ if (entry.child) {
277
+ await this.waitForExit(entry.child);
278
+ }
279
+ // Ensure cleanup
280
+ this.deployments.delete(targetId);
281
+ this.dbDelete(targetId);
155
282
  }
156
283
  /**
157
284
  * Force-stop all tracked deployments immediately (for daemon shutdown).
@@ -161,6 +288,15 @@ export class DeploymentService {
161
288
  entry.logs.clear();
162
289
  this.killProcess(entry);
163
290
  }
291
+ // Also clean DB
292
+ if (this.db) {
293
+ try {
294
+ this.db.prepare('DELETE FROM dev_servers').run();
295
+ }
296
+ catch {
297
+ // table might not exist yet
298
+ }
299
+ }
164
300
  }
165
301
  /**
166
302
  * Get the accumulated log buffer for a deployment.
@@ -183,9 +319,54 @@ export class DeploymentService {
183
319
  off(event, handler) {
184
320
  this.emitter.off(event, handler);
185
321
  }
186
- /**
187
- * Send SIGKILL to a process tree.
188
- */
322
+ // ─── Database helpers ───────────────────────────────────────────────
323
+ dbUpsert(entry) {
324
+ if (!this.db)
325
+ return;
326
+ try {
327
+ this.db
328
+ .prepare(`INSERT OR REPLACE INTO dev_servers
329
+ (target_id, target_type, pid, state, url, target_path, started_at)
330
+ VALUES (?, ?, ?, ?, ?, ?, ?)`)
331
+ .run(entry.targetId, entry.targetType, entry.pid, entry.state, entry.url, entry.targetPath, Date.now());
332
+ }
333
+ catch (err) {
334
+ log.warn(`dbUpsert failed for "${entry.targetId}": ${err}`);
335
+ }
336
+ }
337
+ dbUpdateState(targetId, state, url) {
338
+ if (!this.db)
339
+ return;
340
+ try {
341
+ this.db
342
+ .prepare('UPDATE dev_servers SET state = ?, url = ? WHERE target_id = ?')
343
+ .run(state, url, targetId);
344
+ }
345
+ catch (err) {
346
+ log.warn(`dbUpdateState failed for "${targetId}": ${err}`);
347
+ }
348
+ }
349
+ dbDelete(targetId) {
350
+ if (!this.db)
351
+ return;
352
+ try {
353
+ this.db.prepare('DELETE FROM dev_servers WHERE target_id = ?').run(targetId);
354
+ }
355
+ catch (err) {
356
+ log.warn(`dbDelete failed for "${targetId}": ${err}`);
357
+ }
358
+ }
359
+ dbFind(targetId) {
360
+ if (!this.db)
361
+ return null;
362
+ try {
363
+ return (this.db.prepare('SELECT * FROM dev_servers WHERE target_id = ?').get(targetId) ?? null);
364
+ }
365
+ catch {
366
+ return null;
367
+ }
368
+ }
369
+ // ─── Process helpers ────────────────────────────────────────────────
189
370
  killProcess(entry) {
190
371
  try {
191
372
  this.deps.kill(entry.pid, 'SIGKILL');
@@ -200,24 +381,20 @@ export class DeploymentService {
200
381
  */
201
382
  attachOutputListener(entry, stream) {
202
383
  const bufferKey = stream === 'stdout' ? 'stdoutBuffer' : 'stderrBuffer';
203
- const childStream = entry.child[stream];
384
+ const childStream = entry.child?.[stream];
204
385
  if (!childStream) {
205
386
  log.warn(`[${entry.targetId}] No ${stream} stream available — cannot attach listener`);
206
387
  return;
207
388
  }
208
389
  childStream.on('data', (chunk) => {
209
390
  const text = chunk.toString();
210
- // Append chunk to buffer
211
391
  entry[bufferKey] += text;
212
- // Process complete lines
213
392
  const lines = entry[bufferKey].split('\n');
214
- // Keep the last element (incomplete line) in the buffer
215
393
  entry[bufferKey] = lines.pop() ?? '';
216
394
  for (const line of lines) {
217
395
  if (!line.trim())
218
396
  continue;
219
397
  log.debug(`[${entry.targetId}] ${stream}: ${line}`);
220
- // Accumulate in log buffer and emit event
221
398
  const logEntry = {
222
399
  targetId: entry.targetId,
223
400
  stream,
@@ -233,12 +410,12 @@ export class DeploymentService {
233
410
  log.info(`[${entry.targetId}] Port detected — url="${url}" (from ${stream})`);
234
411
  entry.state = DeploymentState.Ready;
235
412
  entry.url = url;
413
+ this.dbUpdateState(entry.targetId, entry.state, entry.url);
236
414
  }
237
415
  }
238
416
  }
239
417
  });
240
418
  childStream.on('end', () => {
241
- // Flush remaining buffer content
242
419
  const remaining = entry[bufferKey].trim();
243
420
  if (remaining) {
244
421
  log.debug(`[${entry.targetId}] ${stream} (flush): ${remaining}`);
@@ -248,6 +425,7 @@ export class DeploymentService {
248
425
  log.info(`[${entry.targetId}] Port detected in flushed buffer — url="${url}"`);
249
426
  entry.state = DeploymentState.Ready;
250
427
  entry.url = url;
428
+ this.dbUpdateState(entry.targetId, entry.state, entry.url);
251
429
  }
252
430
  }
253
431
  entry[bufferKey] = '';
@@ -255,9 +433,6 @@ export class DeploymentService {
255
433
  log.debug(`[${entry.targetId}] ${stream} stream ended`);
256
434
  });
257
435
  }
258
- /**
259
- * Poll until a process is dead or timeout expires.
260
- */
261
436
  async pollUntilDead(pid, maxMs, intervalMs) {
262
437
  const deadline = Date.now() + maxMs;
263
438
  while (Date.now() < deadline) {
@@ -268,9 +443,6 @@ export class DeploymentService {
268
443
  }
269
444
  return false;
270
445
  }
271
- /**
272
- * Wait for a child process to emit 'exit', with a short timeout.
273
- */
274
446
  waitForExit(child) {
275
447
  return new Promise((resolve) => {
276
448
  const timeout = setTimeout(() => resolve(), 1000);
@@ -5,11 +5,5 @@
5
5
  * dev server stdout/stderr output. Handles common patterns from Next.js,
6
6
  * Vite, Express, and generic servers.
7
7
  */
8
- /**
9
- * Parse a line of stdout/stderr output for a localhost URL or port.
10
- *
11
- * @param line - A single line of process output
12
- * @returns The detected URL string, or null if no URL/port was found
13
- */
14
8
  export declare function parsePort(line: string): string | null;
15
9
  //# sourceMappingURL=parse-port.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-port.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/parse-port.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkCH;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAarD"}
1
+ {"version":3,"file":"parse-port.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/parse-port.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4CH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBrD"}