@shepai/cli 1.139.0 → 1.139.1-pr448.0f0de40

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 (173) hide show
  1. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -1
  2. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +41 -20
  3. package/dist/src/presentation/web/app/actions/deploy-feature.d.ts.map +1 -1
  4. package/dist/src/presentation/web/app/actions/deploy-feature.js +8 -0
  5. package/dist/src/presentation/web/app/actions/deploy-repository.d.ts.map +1 -1
  6. package/dist/src/presentation/web/app/actions/deploy-repository.js +8 -0
  7. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.d.ts.map +1 -1
  8. package/dist/src/presentation/web/components/common/base-drawer/base-drawer.js +1 -1
  9. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.js +1 -1
  10. package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
  11. package/dist/src/presentation/web/components/common/feature-node/feature-node.js +29 -24
  12. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.js +1 -1
  13. package/dist/src/presentation/web/lib/is-same-shep-instance.d.ts +7 -0
  14. package/dist/src/presentation/web/lib/is-same-shep-instance.d.ts.map +1 -0
  15. package/dist/src/presentation/web/lib/is-same-shep-instance.js +18 -0
  16. package/dist/tsconfig.build.tsbuildinfo +1 -1
  17. package/package.json +1 -1
  18. package/web/.next/BUILD_ID +1 -1
  19. package/web/.next/build-manifest.json +2 -2
  20. package/web/.next/fallback-build-manifest.json +2 -2
  21. package/web/.next/prerender-manifest.json +3 -3
  22. package/web/.next/required-server-files.js +3 -3
  23. package/web/.next/required-server-files.json +3 -3
  24. package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +28 -28
  25. package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
  26. package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
  27. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +28 -28
  28. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  29. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  30. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
  31. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +1 -1
  32. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  33. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  34. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +36 -36
  35. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
  36. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  37. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  38. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
  39. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  40. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  41. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +28 -28
  42. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  43. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  44. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
  45. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +1 -1
  46. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  47. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  48. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +36 -36
  49. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
  50. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  51. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  52. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +26 -26
  53. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  54. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  55. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
  56. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  57. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  58. package/web/.next/server/app/_global-error.html +2 -2
  59. package/web/.next/server/app/_global-error.rsc +1 -1
  60. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  61. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  62. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +3 -3
  66. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  67. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  68. package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
  69. package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
  70. package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  71. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  72. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  73. package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
  74. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  75. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  76. package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
  77. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  78. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  79. package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
  80. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  81. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  82. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  83. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  84. package/web/.next/server/chunks/ssr/[root-of-the-server]__2bdf88a0._.js +4 -0
  85. package/web/.next/server/chunks/ssr/[root-of-the-server]__2bdf88a0._.js.map +1 -0
  86. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  87. package/web/.next/server/chunks/ssr/[root-of-the-server]__3ef34e4c._.js +1 -1
  88. package/web/.next/server/chunks/ssr/[root-of-the-server]__42faf5ae._.js +4 -0
  89. package/web/.next/server/chunks/ssr/[root-of-the-server]__42faf5ae._.js.map +1 -0
  90. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__685ee565._.js +4 -0
  93. package/web/.next/server/chunks/ssr/[root-of-the-server]__685ee565._.js.map +1 -0
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__74756aae._.js +4 -0
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__74756aae._.js.map +1 -0
  96. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
  97. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
  98. package/web/.next/server/chunks/ssr/[root-of-the-server]__a5f9c6e5._.js +2 -2
  99. package/web/.next/server/chunks/ssr/[root-of-the-server]__a5f9c6e5._.js.map +1 -1
  100. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +2 -2
  101. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  102. package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js +1 -1
  103. package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js.map +1 -1
  104. package/web/.next/server/chunks/ssr/_02ec1aea._.js +1 -1
  105. package/web/.next/server/chunks/ssr/_02ec1aea._.js.map +1 -1
  106. package/web/.next/server/chunks/ssr/_0c5f56e3._.js +2 -2
  107. package/web/.next/server/chunks/ssr/_0c5f56e3._.js.map +1 -1
  108. package/web/.next/server/chunks/ssr/{_ebd0ef7f._.js → _0d80c944._.js} +2 -2
  109. package/web/.next/server/chunks/ssr/{_ebd0ef7f._.js.map → _0d80c944._.js.map} +1 -1
  110. package/web/.next/server/chunks/ssr/_1b719e7f._.js +1 -1
  111. package/web/.next/server/chunks/ssr/_1b719e7f._.js.map +1 -1
  112. package/web/.next/server/chunks/ssr/_37e8548b._.js +1 -1
  113. package/web/.next/server/chunks/ssr/_37e8548b._.js.map +1 -1
  114. package/web/.next/server/chunks/ssr/{_a3a344a8._.js → _4a899335._.js} +2 -2
  115. package/web/.next/server/chunks/ssr/{_a3a344a8._.js.map → _4a899335._.js.map} +1 -1
  116. package/web/.next/server/chunks/ssr/_55d763e2._.js +1 -1
  117. package/web/.next/server/chunks/ssr/_55d763e2._.js.map +1 -1
  118. package/web/.next/server/chunks/ssr/_64bdfc6f._.js +2 -2
  119. package/web/.next/server/chunks/ssr/_64bdfc6f._.js.map +1 -1
  120. package/web/.next/server/chunks/ssr/_7dca1882._.js +1 -1
  121. package/web/.next/server/chunks/ssr/_7dca1882._.js.map +1 -1
  122. package/web/.next/server/chunks/ssr/_a9f57758._.js +1 -1
  123. package/web/.next/server/chunks/ssr/_b71645b4._.js +1 -1
  124. package/web/.next/server/chunks/ssr/_b71645b4._.js.map +1 -1
  125. package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
  126. package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
  127. package/web/.next/server/chunks/ssr/_f39a1adb._.js +1 -1
  128. package/web/.next/server/chunks/ssr/_f39a1adb._.js.map +1 -1
  129. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  130. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  131. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
  132. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
  133. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
  134. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
  135. package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
  136. package/web/.next/server/chunks/ssr/{src_presentation_web_582e5037._.js → src_presentation_web_c893d037._.js} +2 -2
  137. package/web/.next/server/chunks/ssr/{src_presentation_web_582e5037._.js.map → src_presentation_web_c893d037._.js.map} +1 -1
  138. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  139. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  140. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  141. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  142. package/web/.next/server/pages/500.html +2 -2
  143. package/web/.next/server/server-reference-manifest.js +1 -1
  144. package/web/.next/server/server-reference-manifest.json +44 -44
  145. package/web/.next/static/chunks/{add583b93a6e62ef.js → 0e61e67ff8069062.js} +1 -1
  146. package/web/.next/static/chunks/{284bdcf374b23190.js → 1c803b4fe5ef5559.js} +1 -1
  147. package/web/.next/static/chunks/1df0c0594135d736.css +1 -0
  148. package/web/.next/static/chunks/{1a46d832fb5dbb4d.js → 2344998a2fb45a58.js} +1 -1
  149. package/web/.next/static/chunks/{9d59552a1eb58b20.js → 4400aef24cffa0b7.js} +1 -1
  150. package/web/.next/static/chunks/4ffe13422d62391f.js +1 -0
  151. package/web/.next/static/chunks/5318e17dd75388b7.js +2 -0
  152. package/web/.next/static/chunks/72c4dc236b576e6c.js +1 -0
  153. package/web/.next/static/chunks/{5aac1b0e10edc3d4.js → a425a1e3120acf10.js} +1 -1
  154. package/web/.next/static/chunks/{26f8c1dc8e8d3a85.js → a5e8bc856846d1c9.js} +1 -1
  155. package/web/.next/static/chunks/{13451dd1c5eb854a.js → b7a58ebf671be5a3.js} +1 -1
  156. package/web/.next/static/chunks/{d14b401b9ac6b439.js → e2c000d047f64875.js} +1 -1
  157. package/web/.next/static/chunks/fcbd68d30803ba31.js +1 -0
  158. package/web/.next/server/chunks/ssr/[root-of-the-server]__2c703b78._.js +0 -4
  159. package/web/.next/server/chunks/ssr/[root-of-the-server]__2c703b78._.js.map +0 -1
  160. package/web/.next/server/chunks/ssr/[root-of-the-server]__59a3897b._.js +0 -4
  161. package/web/.next/server/chunks/ssr/[root-of-the-server]__59a3897b._.js.map +0 -1
  162. package/web/.next/server/chunks/ssr/[root-of-the-server]__78aecdd5._.js +0 -4
  163. package/web/.next/server/chunks/ssr/[root-of-the-server]__78aecdd5._.js.map +0 -1
  164. package/web/.next/server/chunks/ssr/[root-of-the-server]__f222995d._.js +0 -4
  165. package/web/.next/server/chunks/ssr/[root-of-the-server]__f222995d._.js.map +0 -1
  166. package/web/.next/static/chunks/2a318598dee02204.js +0 -1
  167. package/web/.next/static/chunks/4d521e80c86070db.js +0 -1
  168. package/web/.next/static/chunks/7d4461c2f06d2cb9.js +0 -1
  169. package/web/.next/static/chunks/ba967f7de77cd5ee.css +0 -1
  170. package/web/.next/static/chunks/c4c3d56eac00b6a3.js +0 -2
  171. /package/web/.next/static/{dDoTmkPtcr9knH6GiOhGo → lfpHVz_lQ1eVteSA7vHE5}/_buildManifest.js +0 -0
  172. /package/web/.next/static/{dDoTmkPtcr9knH6GiOhGo → lfpHVz_lQ1eVteSA7vHE5}/_clientMiddlewareManifest.json +0 -0
  173. /package/web/.next/static/{dDoTmkPtcr9knH6GiOhGo → lfpHVz_lQ1eVteSA7vHE5}/_ssgManifest.js +0 -0
@@ -1 +1 @@
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,EAAmC,MAAM,oBAAoB,CAAC;AAK5E,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAK3C,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACT,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAiCzD,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;AA0CD,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;;;;;;;;;;;;OAYG;IACH,UAAU,IAAI,IAAI;IAgFlB;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,SAAe,GAAG,IAAI;IA0G5E;;;;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;IAUnB;;;;OAIG;YACW,kBAAkB;IAsChC;;;OAGG;IACH,OAAO,CAAC,SAAS;CAwBlB"}
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,EAAmC,MAAM,oBAAoB,CAAC;AAK5E,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAK3C,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACT,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAiCzD,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;AA0CD,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;;;;;;;;;;;;OAYG;IACH,UAAU,IAAI,IAAI;IAqFlB;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,SAAe,GAAG,IAAI;IA6H5E;;;;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;IAUnB;;;;OAIG;YACW,kBAAkB;IAsChC;;;OAGG;IACH,OAAO,CAAC,SAAS;CAwBlB"}
@@ -99,6 +99,12 @@ export class DeploymentService {
99
99
  recoverAll() {
100
100
  if (!this.db)
101
101
  return;
102
+ // Child dev servers spawned by DeploymentService share the same global DB.
103
+ // Skip recovery to avoid killing processes owned by the parent instance.
104
+ if (process.env.SHEP_SKIP_RECOVERY) {
105
+ log.info('SHEP_SKIP_RECOVERY set — skipping dev server recovery');
106
+ return;
107
+ }
102
108
  let rows;
103
109
  try {
104
110
  const stmt = this.db.prepare('SELECT * FROM dev_servers');
@@ -137,20 +143,16 @@ export class DeploymentService {
137
143
  continue;
138
144
  }
139
145
  if (alive) {
140
- // Strategy 2: Process alive but stuck in Booting — can't re-attach stdout
141
- // Kill the orphan so we can re-spawn with proper listeners
142
- log.info(`Orphan "${row.target_id}" (pid=${row.pid}) stuck in ${row.state} killing to re-spawn`);
143
- try {
144
- this.deps.kill(row.pid, 'SIGKILL');
145
- }
146
- catch {
147
- // already dead
148
- }
149
- }
150
- else {
151
- log.info(`Dev server "${row.target_id}" (pid=${row.pid}) is dead — will re-spawn`);
146
+ // Strategy 2: Process alive but stuck in Booting — leave it running.
147
+ // We can't re-attach stdout so we can't detect when it becomes Ready,
148
+ // but killing it would be destructive (another process on the same
149
+ // shared DB may have just spawned it). The user can restart manually.
150
+ log.info(`Orphan "${row.target_id}" (pid=${row.pid}) stuck in ${row.state} — leaving alive (cannot re-attach)`);
151
+ this.dbDelete(row.target_id);
152
+ continue;
152
153
  }
153
- // Strategy 2 & 3: Re-spawn if target directory still has a package.json
154
+ // Strategy 3: Dead process — re-spawn if target directory still exists
155
+ log.info(`Dev server "${row.target_id}" (pid=${row.pid}) is dead — will re-spawn`);
154
156
  this.dbDelete(row.target_id);
155
157
  if (!existsSync(join(row.target_path, 'package.json'))) {
156
158
  log.warn(`Skipping re-spawn for "${row.target_id}" — no package.json at "${row.target_path}"`);
@@ -215,6 +217,9 @@ export class DeploymentService {
215
217
  // stdout/stderr — we don't need it because taskkill /F /T handles tree kill.
216
218
  ...(IS_WINDOWS ? { windowsHide: true } : { detached: true }),
217
219
  stdio: ['ignore', 'pipe', 'pipe'],
220
+ // Prevent child shep instances (e.g. worktree dev servers) from running
221
+ // recoverAll() on the shared ~/.shep/data DB and killing our processes.
222
+ env: { ...process.env, SHEP_SKIP_RECOVERY: '1' },
218
223
  });
219
224
  if (!child.pid) {
220
225
  log.error('spawn() returned no PID — process failed to start');
@@ -234,7 +239,10 @@ export class DeploymentService {
234
239
  logs: new LogRingBuffer(),
235
240
  };
236
241
  this.deployments.set(targetId, entry);
237
- this.dbUpsert(entry);
242
+ // NOTE: Do NOT write to DB during Booting. The spawned process may be
243
+ // another shep instance sharing ~/.shep/data — its recoverAll() would
244
+ // find this Booting entry, see its own PID as alive, and SIGKILL itself.
245
+ // We persist to DB only when the state transitions to Ready (URL detected).
238
246
  // Attach stdout/stderr listeners for port detection
239
247
  this.attachOutputListener(entry, 'stdout');
240
248
  this.attachOutputListener(entry, 'stderr');
@@ -245,12 +253,25 @@ export class DeploymentService {
245
253
  this.deployments.delete(targetId);
246
254
  this.dbDelete(targetId);
247
255
  });
248
- // Clean up on process exit
249
- child.on('exit', (code, signal) => {
256
+ // Use 'close' instead of 'exit' — 'close' fires after stdio streams are
257
+ // fully consumed, so entry.logs will contain all captured output.
258
+ child.on('close', (code, signal) => {
250
259
  const wasBooting = entry.state === DeploymentState.Booting;
251
- log.info(`Process exited for "${targetId}" (pid=${entry.pid}) — code=${code}, signal=${signal}, wasBooting=${wasBooting}`);
260
+ log.info(`Process closed for "${targetId}" (pid=${entry.pid}) — code=${code}, signal=${signal}, wasBooting=${wasBooting}`);
252
261
  if (wasBooting) {
253
- log.warn('Process exited while still in Booting state — dev server likely crashed on startup. Check stderr output above.');
262
+ log.warn(`Process exited while still in Booting state — dev server likely crashed on startup (code=${code}, signal=${signal}).`);
263
+ const allLogs = entry.logs.getAll();
264
+ const stdoutLines = allLogs.filter((l) => l.stream === 'stdout');
265
+ const stderrLines = allLogs.filter((l) => l.stream === 'stderr');
266
+ if (stdoutLines.length > 0) {
267
+ log.warn(`[${targetId}] stdout:\n${stdoutLines.map((l) => l.line).join('\n')}`);
268
+ }
269
+ if (stderrLines.length > 0) {
270
+ log.warn(`[${targetId}] stderr:\n${stderrLines.map((l) => l.line).join('\n')}`);
271
+ }
272
+ if (allLogs.length === 0) {
273
+ log.warn(`[${targetId}] No output captured from the process.`);
274
+ }
254
275
  }
255
276
  this.deployments.delete(targetId);
256
277
  this.dbDelete(targetId);
@@ -485,7 +506,7 @@ export class DeploymentService {
485
506
  log.info(`[${entry.targetId}] Port detected — url="${url}" (from ${stream})`);
486
507
  entry.state = DeploymentState.Ready;
487
508
  entry.url = url;
488
- this.dbUpdateState(entry.targetId, entry.state, entry.url);
509
+ this.dbUpsert(entry);
489
510
  }
490
511
  }
491
512
  }
@@ -500,7 +521,7 @@ export class DeploymentService {
500
521
  log.info(`[${entry.targetId}] Port detected in flushed buffer — url="${url}"`);
501
522
  entry.state = DeploymentState.Ready;
502
523
  entry.url = url;
503
- this.dbUpdateState(entry.targetId, entry.state, entry.url);
524
+ this.dbUpsert(entry);
504
525
  }
505
526
  }
506
527
  entry[bufferKey] = '';
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-feature.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAIvE,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAwCxE"}
1
+ {"version":3,"file":"deploy-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-feature.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAKvE,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAgDxE"}
@@ -4,6 +4,7 @@ import { resolve } from '../../lib/server-container.js';
4
4
  import { createDeploymentLogger } from '../../../../../packages/core/src/infrastructure/services/deployment/deployment-logger.js';
5
5
  import { computeWorktreePath } from '../../../../../packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js';
6
6
  import { DeploymentState } from '../../../../../packages/core/src/domain/generated/output.js';
7
+ import { isSameShepInstance } from '../../lib/is-same-shep-instance.js';
7
8
  const log = createDeploymentLogger('[deployFeature]');
8
9
  export async function deployFeature(featureId) {
9
10
  log.info(`called — featureId="${featureId}"`);
@@ -25,6 +26,13 @@ export async function deployFeature(featureId) {
25
26
  log.warn(`worktree path does not exist on disk: "${worktreePath}"`);
26
27
  return { success: false, error: `Worktree path does not exist: ${worktreePath}` };
27
28
  }
29
+ if (isSameShepInstance(feature.repositoryPath)) {
30
+ log.warn('rejected — feature belongs to the running shep instance');
31
+ return {
32
+ success: false,
33
+ error: 'Cannot start a dev server for features of the repository Shep is running from',
34
+ };
35
+ }
28
36
  log.info('worktree path exists, calling deploymentService.start()');
29
37
  const deploymentService = resolve('IDeploymentService');
30
38
  deploymentService.start(featureId, worktreePath, 'feature');
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-repository.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-repository.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAIvE,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAyBxE"}
1
+ {"version":3,"file":"deploy-repository.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-repository.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAKvE,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAiCxE"}
@@ -4,6 +4,7 @@ import { isAbsolute } from 'node:path';
4
4
  import { resolve } from '../../lib/server-container.js';
5
5
  import { createDeploymentLogger } from '../../../../../packages/core/src/infrastructure/services/deployment/deployment-logger.js';
6
6
  import { DeploymentState } from '../../../../../packages/core/src/domain/generated/output.js';
7
+ import { isSameShepInstance } from '../../lib/is-same-shep-instance.js';
7
8
  const log = createDeploymentLogger('[deployRepository]');
8
9
  export async function deployRepository(repositoryPath) {
9
10
  log.info(`called — repositoryPath="${repositoryPath}"`);
@@ -16,6 +17,13 @@ export async function deployRepository(repositoryPath) {
16
17
  log.warn(`directory does not exist: "${repositoryPath}"`);
17
18
  return { success: false, error: `Directory does not exist: ${repositoryPath}` };
18
19
  }
20
+ if (isSameShepInstance(repositoryPath)) {
21
+ log.warn('rejected — target is the running shep instance');
22
+ return {
23
+ success: false,
24
+ error: 'Cannot start a dev server for the repository Shep is running from',
25
+ };
26
+ }
19
27
  log.info('directory exists, calling deploymentService.start()');
20
28
  const deploymentService = resolve('IDeploymentService');
21
29
  deploymentService.start(repositoryPath, repositoryPath, 'repository');
@@ -1 +1 @@
1
- {"version":3,"file":"base-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/base-drawer/base-drawer.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAelE,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAGpF,QAAA,MAAM,cAAc;;8EAUlB,CAAC;AAEH,MAAM,WAAW,eAAgB,SAAQ,YAAY,CAAC,OAAO,cAAc,CAAC;IAC1E,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yGAAyG;IACzG,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,OAAO,EACP,KAAa,EACb,qBAA6B,EAC7B,KAAgB,EAChB,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,MAAM,EACN,SAAS,EACT,aAAa,EAAE,MAAM,EACrB,YAAY,GACb,EAAE,eAAe,2CAsFjB"}
1
+ {"version":3,"file":"base-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/base-drawer/base-drawer.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAelE,OAAO,EAAmB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAGpF,QAAA,MAAM,cAAc;;8EAUlB,CAAC;AAEH,MAAM,WAAW,eAAgB,SAAQ,YAAY,CAAC,OAAO,cAAc,CAAC;IAC1E,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,yGAAyG;IACzG,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,OAAO,EACP,KAAa,EACb,qBAA6B,EAC7B,KAAgB,EAChB,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,MAAM,EACN,SAAS,EACT,aAAa,EAAE,MAAM,EACrB,YAAY,GACb,EAAE,eAAe,2CA0FjB"}
@@ -54,7 +54,7 @@ export function BaseDrawer({ open, onClose, modal = false, dismissOnOutsideClick
54
54
  return (_jsxs(Drawer, { direction: "right", modal: modal, handleOnly: true, open: open, onOpenChange: (isOpen) => {
55
55
  if (!isOpen)
56
56
  onClose();
57
- }, children: [modal ? _jsx(DrawerOverlay, {}) : null, _jsxs(DrawerContent, { ref: contentRef, direction: "right", showCloseButton: false, className: cn(drawerVariants({ size }), className), "data-testid": testId, onInteractOutside: modal ? undefined : (e) => e.preventDefault(), children: [_jsx(DrawerTitle, { asChild: true, children: _jsx("span", { className: "sr-only", children: title }) }), _jsx(DrawerDescription, { asChild: true, children: _jsx("span", { className: "sr-only", children: title }) }), _jsxs("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", "data-testid": testId ? `${testId}-close-button` : undefined, children: [_jsx(XIcon, { className: "size-4" }), _jsx("span", { className: "sr-only", children: "Close" })] }), header ? _jsx(DrawerHeader, { className: "shrink-0", children: header }) : null, header ? _jsx(Separator, {}) : null, featureFlags.envDeploy && deployTarget ? _jsx(DeployBar, { deployTarget: deployTarget }) : null, _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: children }), footer ? _jsx(DrawerFooter, { className: "shrink-0", children: footer }) : null] })] }));
57
+ }, children: [modal ? _jsx(DrawerOverlay, {}) : null, _jsxs(DrawerContent, { ref: contentRef, direction: "right", showCloseButton: false, className: cn(drawerVariants({ size }), 'bg-white/85 backdrop-blur-xl dark:bg-neutral-800/85', className), "data-testid": testId, onInteractOutside: modal ? undefined : (e) => e.preventDefault(), children: [_jsx(DrawerTitle, { asChild: true, children: _jsx("span", { className: "sr-only", children: title }) }), _jsx(DrawerDescription, { asChild: true, children: _jsx("span", { className: "sr-only", children: title }) }), _jsxs("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", "data-testid": testId ? `${testId}-close-button` : undefined, children: [_jsx(XIcon, { className: "size-4" }), _jsx("span", { className: "sr-only", children: "Close" })] }), header ? _jsx(DrawerHeader, { className: "shrink-0", children: header }) : null, header ? _jsx(Separator, {}) : null, featureFlags.envDeploy && deployTarget ? _jsx(DeployBar, { deployTarget: deployTarget }) : null, _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: children }), footer ? _jsx(DrawerFooter, { className: "shrink-0", children: footer }) : null] })] }));
58
58
  }
59
59
  function DeployBar({ deployTarget }) {
60
60
  const deployAction = useDeployAction(deployTarget);
@@ -274,7 +274,7 @@ export function DrawerActionBar({ onReject, onApprove, approveLabel, approveVari
274
274
  }
275
275
  }, []);
276
276
  const modKey = typeof navigator !== 'undefined' && /Mac/i.test(navigator.userAgent) ? '⌘' : 'Ctrl';
277
- return (_jsxs("div", { className: "border-border shrink-0 border-t", children: [children, onReject ? (_jsx(TooltipProvider, { delayDuration: 400, children: _jsx("form", { ref: formRef, onSubmit: handleFormSubmit, className: "p-3", children: _jsx("div", { role: "region", "aria-label": "File drop zone", "data-drag-over": isDragOver ? 'true' : 'false', onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: cn('rounded-md border-2 border-transparent transition-colors', isDragOver && 'border-primary/50 bg-primary/5'), children: _jsxs("div", { className: "border-input focus-within:ring-ring/50 focus-within:border-ring flex flex-col overflow-hidden rounded-md border shadow-xs transition-[color,box-shadow] focus-within:ring-[3px]", children: [_jsx(Textarea, { placeholder: revisionPlaceholder ?? 'Ask AI to revise...', "aria-label": revisionPlaceholder ?? 'Ask AI to revise...', disabled: disabled, value: chatInput, onChange: (e) => setChatInput(e.target.value), onKeyDown: handleKeyDown, onPaste: handlePaste, rows: 3, className: "max-h-[35dvh] min-h-0 flex-1 resize-none overflow-y-auto rounded-none border-0 shadow-none focus-visible:ring-0", "data-testid": "drawer-chat-input" }), attachments.length > 0 && (_jsx("div", { className: "flex flex-wrap items-center gap-1.5 px-3 py-2", children: attachments.map((file) => (_jsx(AttachmentChip, { name: file.name, size: file.size, mimeType: file.mimeType, path: file.path, onRemove: () => handleRemoveFile(file.id), disabled: disabled, loading: file.loading }, file.id))) })), uploadError ? (_jsx("p", { className: "text-destructive px-3 pb-2 text-xs", children: uploadError })) : null, _jsxs("div", { className: "border-input flex items-center gap-2 border-t px-3 py-1.5", children: [_jsxs("span", { className: "text-muted-foreground flex-1 truncate text-[11px]", children: [_jsxs("kbd", { className: "bg-muted rounded px-1 py-0.5 font-mono text-[10px]", children: [modKey, "+Enter"] }), ' ', hasText ? 'reject' : 'approve'] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: handleAddFiles, disabled: disabled, "aria-label": "Attach files", className: "text-muted-foreground hover:text-foreground cursor-pointer rounded p-1 transition-colors", children: _jsx(PaperclipIcon, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { side: "top", children: "Attach files" })] }), _jsx("div", { onMouseLeave: () => setHoverExpanded(false), children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "submit", disabled: disabled, "data-testid": "drawer-action-submit", className: cn('relative flex h-9 min-w-[12rem] cursor-pointer items-center overflow-hidden rounded-md border pr-10 pl-4 text-sm font-medium whitespace-nowrap transition-colors', 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50', approveExpanded
277
+ return (_jsxs("div", { className: "border-border shrink-0 border-t", children: [children, onReject ? (_jsx(TooltipProvider, { delayDuration: 400, children: _jsx("form", { ref: formRef, onSubmit: handleFormSubmit, className: "p-3", children: _jsx("div", { role: "region", "aria-label": "File drop zone", "data-drag-over": isDragOver ? 'true' : 'false', onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: cn('rounded-md border-2 border-transparent transition-colors', isDragOver && 'border-primary/50 bg-primary/5'), children: _jsxs("div", { className: "border-input focus-within:ring-ring/50 focus-within:border-ring flex flex-col overflow-hidden rounded-md border shadow-xs transition-[color,box-shadow] focus-within:ring-[3px]", children: [_jsx(Textarea, { placeholder: revisionPlaceholder ?? 'Ask AI to revise...', "aria-label": revisionPlaceholder ?? 'Ask AI to revise...', disabled: disabled, value: chatInput, onChange: (e) => setChatInput(e.target.value), onKeyDown: handleKeyDown, onPaste: handlePaste, rows: 1, className: "max-h-[35dvh] min-h-9 flex-1 resize-none overflow-y-auto rounded-none border-0 py-2 shadow-none focus-visible:ring-0", "data-testid": "drawer-chat-input" }), attachments.length > 0 && (_jsx("div", { className: "flex flex-wrap items-center gap-1.5 px-3 py-2", children: attachments.map((file) => (_jsx(AttachmentChip, { name: file.name, size: file.size, mimeType: file.mimeType, path: file.path, onRemove: () => handleRemoveFile(file.id), disabled: disabled, loading: file.loading }, file.id))) })), uploadError ? (_jsx("p", { className: "text-destructive px-3 pb-2 text-xs", children: uploadError })) : null, _jsxs("div", { className: "border-input flex items-center gap-2 border-t px-3 py-1.5", children: [_jsxs("span", { className: "text-muted-foreground flex-1 truncate text-[11px]", children: [_jsxs("kbd", { className: "bg-muted rounded px-1 py-0.5 font-mono text-[10px]", children: [modKey, "+Enter"] }), ' ', hasText ? 'reject' : 'approve'] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: handleAddFiles, disabled: disabled, "aria-label": "Attach files", className: "text-muted-foreground hover:text-foreground cursor-pointer rounded p-1 transition-colors", children: _jsx(PaperclipIcon, { className: "h-4 w-4" }) }) }), _jsx(TooltipContent, { side: "top", children: "Attach files" })] }), _jsx("div", { onMouseLeave: () => setHoverExpanded(false), children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "submit", disabled: disabled, "data-testid": "drawer-action-submit", className: cn('relative flex h-9 min-w-[12rem] cursor-pointer items-center overflow-hidden rounded-md border pr-10 pl-4 text-sm font-medium whitespace-nowrap transition-colors', 'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50', approveExpanded
278
278
  ? `${accentBorder} text-white`
279
279
  : rejectHighlighted
280
280
  ? 'border-primary bg-muted ring-primary/30 shadow-sm ring-1'
@@ -1 +1 @@
1
- {"version":3,"file":"feature-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA4CnE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,2CAgcA"}
1
+ {"version":3,"file":"feature-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA4CnE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,2CAqdA"}
@@ -54,20 +54,21 @@ export function FeatureNode({ data, selected, }) {
54
54
  const config = featureNodeStateConfig[data.state];
55
55
  const Icon = config.icon;
56
56
  const [confirmOpen, setConfirmOpen] = useState(false);
57
+ const [idCopied, setIdCopied] = useState(false);
57
58
  const [archiveConfirmOpen, setArchiveConfirmOpen] = useState(false);
58
- return (_jsxs("div", { className: "animate-in fade-in group relative duration-300", children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null, _jsxs("div", { className: "absolute top-1/2 -left-10 flex -translate-y-1/2 flex-col items-center gap-2 opacity-0 transition-opacity group-hover:opacity-100", onPointerDown: (e) => e.stopPropagation(), children: [data.onArchive &&
59
- data.featureId &&
60
- data.state !== 'deleting' &&
61
- data.state !== 'archived' ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Archive feature", "data-testid": "feature-node-archive-button", onClick: (e) => {
62
- e.stopPropagation();
63
- setArchiveConfirmOpen(true);
64
- }, className: "bg-card text-muted-foreground flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors hover:border-gray-500 hover:text-gray-600", children: _jsx(Archive, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Archive feature" })] }) })) : null, data.onDelete && data.featureId && data.state !== 'deleting' ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Delete feature", "data-testid": "feature-node-delete-button", onClick: (e) => {
65
- e.stopPropagation();
66
- setConfirmOpen(true);
67
- }, className: "bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Delete feature" })] }) })) : null, data.onUnarchive && data.featureId && data.state === 'archived' ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Unarchive feature", "data-testid": "feature-node-unarchive-button", onClick: (e) => {
68
- e.stopPropagation();
69
- data.onUnarchive?.(data.featureId);
70
- }, className: "bg-card text-muted-foreground hover:border-primary hover:text-primary flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors", children: _jsx(ArchiveRestore, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Unarchive feature" })] }) })) : null] }), data.onDelete && data.featureId && data.state !== 'deleting' ? (_jsx(DeleteFeatureDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, onConfirm: (cleanup, cascadeDelete, closePr) => {
59
+ return (_jsxs("div", { className: "animate-in fade-in group relative duration-300", children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null, _jsx("div", { className: "absolute top-0 bottom-0 -left-14 flex items-center justify-center pr-3 pl-4 opacity-0 transition-opacity group-hover:opacity-100", onPointerDown: (e) => e.stopPropagation(), children: _jsxs("div", { className: "flex flex-col items-center gap-2", children: [data.onArchive &&
60
+ data.featureId &&
61
+ data.state !== 'deleting' &&
62
+ data.state !== 'archived' ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Archive feature", "data-testid": "feature-node-archive-button", onClick: (e) => {
63
+ e.stopPropagation();
64
+ setArchiveConfirmOpen(true);
65
+ }, className: "bg-card text-muted-foreground flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors hover:border-gray-500 hover:text-gray-600", children: _jsx(Archive, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { side: "left", children: "Archive feature" })] }) })) : null, data.onDelete && data.featureId && data.state !== 'deleting' ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Delete feature", "data-testid": "feature-node-delete-button", onClick: (e) => {
66
+ e.stopPropagation();
67
+ setConfirmOpen(true);
68
+ }, className: "bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { side: "left", children: "Delete feature" })] }) })) : null, data.onUnarchive && data.featureId && data.state === 'archived' ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Unarchive feature", "data-testid": "feature-node-unarchive-button", onClick: (e) => {
69
+ e.stopPropagation();
70
+ data.onUnarchive?.(data.featureId);
71
+ }, className: "bg-card text-muted-foreground hover:border-primary hover:text-primary flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors", children: _jsx(ArchiveRestore, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { side: "left", children: "Unarchive feature" })] }) })) : null] }) }), data.onDelete && data.featureId && data.state !== 'deleting' ? (_jsx(DeleteFeatureDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, onConfirm: (cleanup, cascadeDelete, closePr) => {
71
72
  setConfirmOpen(false);
72
73
  data.onDelete?.(data.featureId, cleanup, cascadeDelete, closePr);
73
74
  }, isDeleting: false, featureName: data.name ?? 'this feature', featureId: data.featureId, hasChildren: data.hasChildren, hasOpenPr: !!data.pr && data.pr.status === 'Open' })) : null, data.onArchive &&
@@ -77,7 +78,9 @@ export function FeatureNode({ data, selected, }) {
77
78
  setArchiveConfirmOpen(false);
78
79
  data.onArchive?.(data.featureId);
79
80
  }, children: "Archive" })] })] }) })) : null, _jsxs("div", { "data-testid": "feature-node-card", "aria-busy": data.state === 'creating' || data.state === 'deleting' ? 'true' : undefined, className: cn('bg-card flex min-h-35 w-97 cursor-pointer flex-col rounded-lg border p-3 shadow-sm dark:bg-neutral-800/80', data.state === 'action-required' &&
80
- 'border-l-[3px] border-l-rose-400 dark:border-l-amber-500', selected && 'ring-primary ring-2', data.state === 'deleting' && 'opacity-60', data.state === 'archived' && 'opacity-50'), children: [data.state !== 'creating' ? (_jsx("div", { className: "absolute top-3 right-4", children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("span", { "data-testid": "feature-node-phase-badge", className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-muted-foreground text-[10px]", children: lifecyclePhaseBadge[data.lifecycle].tooltip }), _jsx("span", { className: cn('h-1.5 w-1.5 -translate-y-px rounded-full', lifecyclePhaseBadge[data.lifecycle].dot) })] }) }), _jsxs(TooltipContent, { side: "bottom", className: "max-w-56 bg-white text-neutral-900 shadow-lg dark:bg-neutral-100 dark:text-neutral-900 [&_svg]:!bg-white [&_svg]:!fill-white dark:[&_svg]:!bg-neutral-100 dark:[&_svg]:!fill-neutral-100", children: [_jsx("p", { className: "font-semibold", children: lifecyclePhaseBadge[data.lifecycle].tooltip }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-neutral-500", children: lifecyclePhaseBadge[data.lifecycle].description })] })] }) }) })) : null, _jsxs("div", { className: "flex items-center gap-1.5 pr-24", children: [data.agentType ? (_jsx(AgentIcon, { agentType: data.agentType, className: "h-4 w-4 shrink-0" })) : null, _jsx("h3", { className: "min-w-0 truncate text-sm font-bold", children: data.name })] }), data.description ? (_jsx("p", { "data-testid": "feature-node-description", className: "text-muted-foreground mt-1 line-clamp-2 text-xs", children: data.description })) : null, _jsxs("div", { className: "mt-auto pt-2", children: [config.showProgressBar ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "text-muted-foreground flex items-center justify-end text-[10px]", children: _jsxs("span", { children: [data.progress, "%"] }) }), _jsx("div", { "data-testid": "feature-node-progress-bar", className: "bg-muted mt-1.5 h-1 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', config.progressClass), style: { width: `${data.progress}%` } }) })] })) : null, !config.showProgressBar &&
81
+ 'border-l-[3px] border-l-rose-400 dark:border-l-amber-500', data.state === 'action-required' &&
82
+ selected &&
83
+ 'border-t-rose-400 border-r-rose-400 border-b-rose-400 dark:border-t-amber-500 dark:border-r-amber-500 dark:border-b-amber-500', selected && data.state !== 'action-required' && 'ring-primary ring-1', data.state === 'deleting' && 'opacity-60', data.state === 'archived' && 'opacity-50'), children: [data.state !== 'creating' ? (_jsx("div", { className: "absolute top-3 right-4", children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("span", { "data-testid": "feature-node-phase-badge", className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-muted-foreground text-[10px]", children: lifecyclePhaseBadge[data.lifecycle].tooltip }), _jsx("span", { className: cn('h-1.5 w-1.5 -translate-y-px rounded-full', lifecyclePhaseBadge[data.lifecycle].dot) })] }) }), _jsxs(TooltipContent, { side: "right", className: "max-w-56", children: [_jsx("p", { className: "font-semibold", children: lifecyclePhaseBadge[data.lifecycle].tooltip }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-neutral-500", children: lifecyclePhaseBadge[data.lifecycle].description })] })] }) }) })) : null, _jsxs("div", { className: "flex items-center gap-1.5 pr-24", children: [data.agentType ? (_jsx(AgentIcon, { agentType: data.agentType, className: "h-4 w-4 shrink-0" })) : null, _jsx("h3", { className: "min-w-0 truncate text-sm font-bold", children: data.name })] }), data.description ? (_jsx("p", { "data-testid": "feature-node-description", className: "text-muted-foreground mt-1 line-clamp-2 text-xs", children: data.description })) : null, _jsxs("div", { className: "mt-auto pt-2", children: [config.showProgressBar ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "text-muted-foreground flex items-center justify-end text-[10px]", children: _jsxs("span", { children: [data.progress, "%"] }) }), _jsx("div", { "data-testid": "feature-node-progress-bar", className: "bg-muted mt-1.5 h-1 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', config.progressClass), style: { width: `${data.progress}%` } }) })] })) : null, !config.showProgressBar &&
81
84
  ![
82
85
  'deleting',
83
86
  'creating',
@@ -89,10 +92,12 @@ export function FeatureNode({ data, selected, }) {
89
92
  ].includes(data.state) ? (_jsxs("div", { "data-testid": "feature-node-badge", className: "relative flex min-w-0 items-center gap-1.5 text-xs", children: [(() => {
90
93
  const BadgeIcon = getBadgeIcon(data);
91
94
  return _jsx(BadgeIcon, { className: cn('h-3.5 w-3.5 shrink-0', config.badgeClass) });
92
- })(), _jsx("span", { className: cn('translate-y-px truncate text-[11px] font-medium', config.badgeClass), children: getBadgeText(data) })] })) : null, _jsxs("div", { className: "mt-1.5 flex min-h-[26px] items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-1.5", style: { transform: 'translateY(1px)' }, children: [data.featureId ? (_jsxs("div", { className: "flex items-baseline gap-1", children: [_jsx("span", { className: "text-muted-foreground/50 text-[10px]", children: "ID" }), _jsx("button", { type: "button", "data-testid": "feature-node-id", className: "nodrag text-muted-foreground/60 hover:text-muted-foreground cursor-pointer font-mono text-[10px] transition-colors", onClick: (e) => {
93
- e.stopPropagation();
94
- navigator.clipboard.writeText(data.featureId);
95
- }, title: `Click to copy: ${data.featureId}`, children: data.featureId.slice(0, 6) })] })) : null, data.deployment ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": data.deployment.status === DeploymentState.Booting
95
+ })(), _jsx("span", { className: cn('translate-y-px truncate text-[11px] font-medium', config.badgeClass), children: getBadgeText(data) })] })) : null, _jsxs("div", { className: "mt-1.5 flex min-h-[26px] items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-1.5", style: { transform: 'translateY(1px)' }, children: [data.featureId ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", "data-testid": "feature-node-id", className: "nodrag text-muted-foreground/60 hover:text-muted-foreground flex cursor-pointer items-baseline gap-1 font-mono text-[10px] transition-colors active:scale-95", onClick: (e) => {
96
+ e.stopPropagation();
97
+ navigator.clipboard.writeText(data.featureId);
98
+ setIdCopied(true);
99
+ setTimeout(() => setIdCopied(false), 1500);
100
+ }, children: [_jsx("span", { className: "text-muted-foreground/50 font-sans text-[10px]", children: "ID" }), idCopied ? (_jsx("span", { className: "text-emerald-500", children: "Copied!" })) : (data.featureId.slice(0, 6))] }) }), _jsxs(TooltipContent, { side: "bottom", children: ["Click to copy: ", data.featureId] })] }) })) : null, data.deployment ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": data.deployment.status === DeploymentState.Booting
96
101
  ? 'Deploying'
97
102
  : 'Open dev server', "data-testid": "feature-node-deployment-indicator", onClick: (e) => {
98
103
  e.stopPropagation();
@@ -102,9 +107,9 @@ export function FeatureNode({ data, selected, }) {
102
107
  }
103
108
  }, className: cn('nodrag', data.deployment.status === DeploymentState.Ready && data.deployment.url
104
109
  ? 'cursor-pointer opacity-80 transition-opacity hover:opacity-100'
105
- : 'cursor-default'), children: data.deployment.status === DeploymentState.Booting ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin text-blue-500" })) : (_jsx(Globe, { className: "h-3 w-3 text-green-600" })) }) }), _jsx(TooltipContent, { side: "top", children: data.deployment.status === DeploymentState.Booting
110
+ : 'cursor-default'), children: data.deployment.status === DeploymentState.Booting ? (_jsx(Loader2, { className: "h-3 w-3 animate-spin text-blue-500" })) : (_jsx(Globe, { className: "h-3 w-3 text-green-600" })) }) }), _jsx(TooltipContent, { side: "bottom", children: data.deployment.status === DeploymentState.Booting
106
111
  ? 'Deploying...'
107
- : (data.deployment.url ?? 'Live') })] }) })) : null, data.fastMode ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { "data-testid": "feature-node-fast-mode-badge", children: _jsx(Zap, { className: "h-3 w-3 text-amber-500" }) }) }), _jsx(TooltipContent, { side: "top", children: "Fast Mode" })] }) })) : null] }), data.state === 'deleting' ? (_jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [_jsx(Loader2, { className: "h-3.5 w-3.5 shrink-0 animate-spin text-gray-400" }), _jsx("span", { className: "text-muted-foreground", children: "Deleting\u2026" })] })) : data.state === 'creating' ? (_jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [_jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 animate-spin" }), _jsx("span", { className: "text-muted-foreground", children: getBadgeText(data) })] })) : data.state === 'running' ? (_jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [_jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 animate-spin" }), _jsx("span", { className: "text-muted-foreground", children: getBadgeText(data) })] })) : data.state === 'action-required' ? (_jsxs(Button, { variant: "default", size: "xs", "aria-label": getActionRequiredLabel(data), "data-testid": "feature-node-approve-button",
112
+ : (data.deployment.url ?? 'Live') })] }) })) : null, data.fastMode ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { "data-testid": "feature-node-fast-mode-badge", children: _jsx(Zap, { className: "h-3 w-3 text-amber-500" }) }) }), _jsx(TooltipContent, { side: "bottom", children: "Fast Mode" })] }) })) : null] }), data.state === 'deleting' ? (_jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [_jsx(Loader2, { className: "h-3.5 w-3.5 shrink-0 animate-spin text-gray-400" }), _jsx("span", { className: "text-muted-foreground", children: "Deleting\u2026" })] })) : data.state === 'creating' ? (_jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [_jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 animate-spin" }), _jsx("span", { className: "text-muted-foreground", children: getBadgeText(data) })] })) : data.state === 'running' ? (_jsxs("div", { className: "flex items-center gap-1.5 text-xs", children: [_jsx(Icon, { className: "h-3.5 w-3.5 shrink-0 animate-spin" }), _jsx("span", { className: "text-muted-foreground", children: getBadgeText(data) })] })) : data.state === 'action-required' ? (_jsxs(Button, { variant: "default", size: "xs", "aria-label": getActionRequiredLabel(data), "data-testid": "feature-node-approve-button",
108
113
  // eslint-disable-next-line @typescript-eslint/no-empty-function -- click bubbles to card's onNodeClick
109
114
  onClick: () => { }, className: "nodrag dark:bg-primary dark:text-primary-foreground dark:hover:bg-primary/90 cursor-pointer bg-neutral-900 text-[11px] text-white hover:bg-neutral-800", children: [_jsx(Eye, { className: "h-3 w-3" }), getActionRequiredLabel(data)] })) : data.state === 'error' && data.onRetry ? (_jsxs(Button, { variant: "outline", size: "xs", "aria-label": "Retry", "data-testid": "feature-node-retry-button", onClick: (e) => {
110
115
  e.stopPropagation();
@@ -118,8 +123,8 @@ export function FeatureNode({ data, selected, }) {
118
123
  })(), _jsx("span", { className: cn('text-[11px] font-medium', config.badgeClass), children: getBadgeText(data) })] })) : data.state === 'pending' && data.onStart ? (_jsxs(Button, { variant: "outline", size: "xs", "aria-label": "Start", "data-testid": "feature-node-start-button", onClick: (e) => {
119
124
  e.stopPropagation();
120
125
  data.onStart(data.featureId);
121
- }, className: "nodrag cursor-pointer text-[11px] font-medium", children: [_jsx(Play, { className: "h-3 w-3" }), "Start"] })) : null] })] })] }), data.onAction && data.state !== 'deleting' ? (_jsx(Handle, { type: "source", position: Position.Right, className: "h-0! w-0! border-0! bg-transparent!", style: { top: 70 }, children: _jsx("button", { type: "button", "aria-label": "Add", "data-testid": "feature-node-action-button", onClick: (e) => {
122
- e.stopPropagation();
123
- data.onAction?.();
124
- }, className: "nodrag absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-blue-500 text-white opacity-0 shadow-md transition-opacity group-hover:opacity-100 hover:bg-blue-600", children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) })) : data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null] }));
126
+ }, className: "nodrag cursor-pointer text-[11px] font-medium", children: [_jsx(Play, { className: "h-3 w-3" }), "Start"] })) : null] })] })] }), data.onAction && data.state !== 'deleting' ? (_jsx(Handle, { type: "source", position: Position.Right, className: "h-0! w-0! border-0! bg-transparent!", style: { top: 70 }, children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": "Add feature", "data-testid": "feature-node-action-button", onClick: (e) => {
127
+ e.stopPropagation();
128
+ data.onAction?.();
129
+ }, className: "nodrag absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-blue-500 text-white opacity-0 shadow-md transition-opacity group-hover:opacity-100 hover:bg-blue-600", children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { side: "right", children: "Add feature" })] }) }) })) : data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null] }));
125
130
  }
@@ -122,7 +122,7 @@ export function FeatureSessionsDropdown({ repositoryPath, className, onCreateFro
122
122
  const hasMore = sessions.length > PREVIEW_COUNT;
123
123
  return (_jsxs(DropdownMenu, { modal: false, onOpenChange: handleOpenChange, children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": "View sessions", "data-testid": "feature-node-sessions-button", className: cn('nodrag relative flex h-5 cursor-pointer items-center gap-0.5 rounded px-0.5 text-[10px] transition-colors', hasActiveSessions
124
124
  ? 'text-emerald-600 hover:bg-emerald-50 hover:text-emerald-700'
125
- : 'text-muted-foreground hover:text-foreground hover:bg-muted', className), onClick: stopNodeEvent, onPointerDown: stopNodeEvent, children: [_jsx(History, { className: "h-3 w-3 shrink-0" }), sessions.length > 0 ? (_jsx("span", { "data-testid": "feature-node-sessions-count", children: sessions.length })) : null, hasActiveSessions ? (_jsx("span", { className: "absolute -top-0.5 -right-0.5 h-1.5 w-1.5 rounded-full bg-emerald-500" })) : null] }) }) }), _jsx(TooltipContent, { side: "bottom", children: hasActiveSessions ? 'Sessions (active)' : 'Sessions' })] }) }), _jsxs(DropdownMenuContent, { align: "start", side: "bottom", className: "w-80", onClick: stopNodeEvent, onPointerDown: stopNodeEvent, children: [_jsxs(DropdownMenuLabel, { className: "flex items-center gap-1.5 text-xs", children: [_jsx(History, { className: "h-3 w-3" }), "Agent Sessions"] }), _jsx(DropdownMenuSeparator, {}), loading ? (_jsxs("div", { className: "text-muted-foreground flex items-center justify-center gap-2 py-4 text-xs", children: [_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }), "Loading..."] })) : sessions.length === 0 ? (_jsx("div", { className: "text-muted-foreground py-4 text-center text-xs", children: "No sessions found" })) : (_jsxs(_Fragment, { children: [visibleSessions.map((session) => (_jsx(SessionRow, { session: session, repositoryPath: repositoryPath, onCreateFromSession: onCreateFromSession }, session.id))), hasMore ? (_jsxs(DropdownMenuItem, { className: "text-muted-foreground justify-center gap-1 py-1.5 text-[10px]", onClick: (e) => {
125
+ : 'text-muted-foreground hover:text-foreground hover:bg-muted', className), onClick: stopNodeEvent, onPointerDown: stopNodeEvent, children: [_jsx(History, { className: "h-3 w-3 shrink-0" }), sessions.length > 0 ? (_jsx("span", { "data-testid": "feature-node-sessions-count", children: sessions.length })) : null, hasActiveSessions ? (_jsx("span", { className: "absolute -top-0.5 -right-0.5 h-1.5 w-1.5 rounded-full bg-emerald-500" })) : null] }) }) }), _jsx(TooltipContent, { side: "top", children: hasActiveSessions ? 'Sessions (active)' : 'Sessions' })] }) }), _jsxs(DropdownMenuContent, { align: "start", side: "bottom", className: "w-80", onClick: stopNodeEvent, onPointerDown: stopNodeEvent, children: [_jsxs(DropdownMenuLabel, { className: "flex items-center gap-1.5 text-xs", children: [_jsx(History, { className: "h-3 w-3" }), "Agent Sessions"] }), _jsx(DropdownMenuSeparator, {}), loading ? (_jsxs("div", { className: "text-muted-foreground flex items-center justify-center gap-2 py-4 text-xs", children: [_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }), "Loading..."] })) : sessions.length === 0 ? (_jsx("div", { className: "text-muted-foreground py-4 text-center text-xs", children: "No sessions found" })) : (_jsxs(_Fragment, { children: [visibleSessions.map((session) => (_jsx(SessionRow, { session: session, repositoryPath: repositoryPath, onCreateFromSession: onCreateFromSession }, session.id))), hasMore ? (_jsxs(DropdownMenuItem, { className: "text-muted-foreground justify-center gap-1 py-1.5 text-[10px]", onClick: (e) => {
126
126
  e.preventDefault();
127
127
  setExpanded((v) => !v);
128
128
  }, children: [_jsx(ChevronDown, { className: cn('h-3 w-3 transition-transform', expanded && 'rotate-180') }), expanded ? 'Show less' : `Show ${sessions.length - PREVIEW_COUNT} more`] })) : null] }))] })] }));
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Check if a target path is the same directory (or a worktree of) the
3
+ * currently running shep instance. Starting a dev server there would spawn
4
+ * another shep instance that conflicts with the shared ~/.shep/data DB.
5
+ */
6
+ export declare function isSameShepInstance(targetPath: string): boolean;
7
+ //# sourceMappingURL=is-same-shep-instance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-same-shep-instance.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/lib/is-same-shep-instance.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAU9D"}
@@ -0,0 +1,18 @@
1
+ import { realpathSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ /**
4
+ * Check if a target path is the same directory (or a worktree of) the
5
+ * currently running shep instance. Starting a dev server there would spawn
6
+ * another shep instance that conflicts with the shared ~/.shep/data DB.
7
+ */
8
+ export function isSameShepInstance(targetPath) {
9
+ const instancePath = process.env.NEXT_PUBLIC_SHEP_INSTANCE_PATH ?? process.cwd();
10
+ try {
11
+ const normalizedTarget = realpathSync(resolve(targetPath)).replace(/\\/g, '/');
12
+ const normalizedInstance = realpathSync(resolve(instancePath)).replace(/\\/g, '/');
13
+ return normalizedTarget === normalizedInstance;
14
+ }
15
+ catch {
16
+ return false;
17
+ }
18
+ }