@shepai/cli 1.147.0 → 1.148.0-pr462.42531fe

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 (228) hide show
  1. package/apis/json-schema/Attachment.yaml +3 -0
  2. package/dist/packages/core/src/domain/generated/output.d.ts +4 -0
  3. package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
  4. package/dist/src/presentation/web/app/actions/compose-user-input.d.ts +1 -0
  5. package/dist/src/presentation/web/app/actions/compose-user-input.d.ts.map +1 -1
  6. package/dist/src/presentation/web/app/actions/compose-user-input.js +3 -1
  7. package/dist/src/presentation/web/app/actions/create-feature.d.ts +1 -0
  8. package/dist/src/presentation/web/app/actions/create-feature.d.ts.map +1 -1
  9. package/dist/src/presentation/web/app/api/agent-events/route.js +1 -1
  10. package/dist/src/presentation/web/app/api/sessions/route.d.ts.map +1 -1
  11. package/dist/src/presentation/web/app/api/sessions/route.js +2 -268
  12. package/dist/src/presentation/web/app/api/sessions-batch/route.d.ts +17 -0
  13. package/dist/src/presentation/web/app/api/sessions-batch/route.d.ts.map +1 -0
  14. package/dist/src/presentation/web/app/api/sessions-batch/route.js +61 -0
  15. package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.d.ts +5 -1
  16. package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.d.ts.map +1 -1
  17. package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.js +6 -3
  18. package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.stories.d.ts +2 -0
  19. package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.stories.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.stories.js +20 -0
  21. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
  22. package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +5 -1
  23. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.d.ts +2 -0
  24. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.d.ts.map +1 -1
  25. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts.map +1 -1
  26. package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.js +4 -1
  27. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts +2 -0
  28. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
  29. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +4 -1
  30. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.d.ts +1 -1
  31. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.d.ts.map +1 -1
  32. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.js +15 -73
  33. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.stories.d.ts.map +1 -1
  34. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.stories.js +18 -17
  35. package/dist/src/presentation/web/components/features/control-center/control-center.d.ts.map +1 -1
  36. package/dist/src/presentation/web/components/features/control-center/control-center.js +2 -1
  37. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  38. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +4 -1
  39. package/dist/src/presentation/web/hooks/sessions-provider.d.ts +12 -0
  40. package/dist/src/presentation/web/hooks/sessions-provider.d.ts.map +1 -0
  41. package/dist/src/presentation/web/hooks/sessions-provider.js +57 -0
  42. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
  43. package/dist/src/presentation/web/hooks/use-deploy-action.js +8 -54
  44. package/dist/src/presentation/web/lib/session-scanner.d.ts +27 -0
  45. package/dist/src/presentation/web/lib/session-scanner.d.ts.map +1 -0
  46. package/dist/src/presentation/web/lib/session-scanner.js +255 -0
  47. package/dist/tsconfig.build.tsbuildinfo +1 -1
  48. package/package.json +1 -1
  49. package/web/.next/BUILD_ID +1 -1
  50. package/web/.next/app-path-routes-manifest.json +1 -0
  51. package/web/.next/build-manifest.json +2 -2
  52. package/web/.next/fallback-build-manifest.json +2 -2
  53. package/web/.next/prerender-manifest.json +3 -3
  54. package/web/.next/required-server-files.js +3 -3
  55. package/web/.next/required-server-files.json +3 -3
  56. package/web/.next/routes-manifest.json +6 -0
  57. package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +28 -28
  58. package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
  59. package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
  60. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +28 -28
  61. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  62. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  63. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
  64. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  65. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +36 -36
  67. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  68. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  69. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
  70. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  71. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  72. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +28 -28
  73. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  74. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  75. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
  76. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  77. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  78. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +36 -36
  79. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  80. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  81. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +26 -26
  82. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  83. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  84. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
  85. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  86. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  87. package/web/.next/server/app/_global-error.html +2 -2
  88. package/web/.next/server/app/_global-error.rsc +1 -1
  89. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  90. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  91. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  92. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  93. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  94. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +3 -3
  95. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  96. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  97. package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
  98. package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
  99. package/web/.next/server/app/api/sessions/route.js +2 -3
  100. package/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
  101. package/web/.next/server/app/api/sessions-batch/route/app-paths-manifest.json +3 -0
  102. package/web/.next/server/app/api/sessions-batch/route/build-manifest.json +11 -0
  103. package/web/.next/server/app/api/sessions-batch/route/server-reference-manifest.json +4 -0
  104. package/web/.next/server/app/api/sessions-batch/route.js +7 -0
  105. package/web/.next/server/app/api/sessions-batch/route.js.map +5 -0
  106. package/web/.next/server/app/api/sessions-batch/route.js.nft.json +1 -0
  107. package/web/.next/server/app/api/sessions-batch/route_client-reference-manifest.js +2 -0
  108. package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  109. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  110. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  111. package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
  112. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  113. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  114. package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
  115. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  116. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  117. package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
  118. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  119. package/web/.next/server/app-paths-manifest.json +1 -0
  120. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +1 -1
  121. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
  122. package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_sessions-batch_route_actions_4859f283.js +3 -0
  123. package/web/.next/server/chunks/[root-of-the-server]__0d33c29e._.js +3 -0
  124. package/web/.next/server/chunks/[root-of-the-server]__0d33c29e._.js.map +1 -0
  125. package/web/.next/server/chunks/[root-of-the-server]__2f61738a._.js +3 -0
  126. package/web/.next/server/chunks/[root-of-the-server]__2f61738a._.js.map +1 -0
  127. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  128. package/web/.next/server/chunks/[root-of-the-server]__c6e32a23._.js.map +1 -1
  129. package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js.map +1 -1
  130. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  131. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  132. package/web/.next/server/chunks/ssr/[root-of-the-server]__0b150ddf._.js.map +1 -1
  133. package/web/.next/server/chunks/ssr/[root-of-the-server]__2138fa7e._.js +2 -2
  134. package/web/.next/server/chunks/ssr/[root-of-the-server]__2138fa7e._.js.map +1 -1
  135. package/web/.next/server/chunks/ssr/[root-of-the-server]__29580090._.js +1 -1
  136. package/web/.next/server/chunks/ssr/[root-of-the-server]__29580090._.js.map +1 -1
  137. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  138. package/web/.next/server/chunks/ssr/[root-of-the-server]__3ef34e4c._.js +1 -1
  139. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
  140. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
  141. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
  142. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
  143. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +5 -2
  144. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  145. package/web/.next/server/chunks/ssr/[root-of-the-server]__c094882b._.js +1 -1
  146. package/web/.next/server/chunks/ssr/[root-of-the-server]__c094882b._.js.map +1 -1
  147. package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js +1 -1
  148. package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js.map +1 -1
  149. package/web/.next/server/chunks/ssr/[root-of-the-server]__dac5dbf1._.js +1 -1
  150. package/web/.next/server/chunks/ssr/[root-of-the-server]__dac5dbf1._.js.map +1 -1
  151. package/web/.next/server/chunks/ssr/[root-of-the-server]__df7c1cd3._.js +1 -1
  152. package/web/.next/server/chunks/ssr/[root-of-the-server]__df7c1cd3._.js.map +1 -1
  153. package/web/.next/server/chunks/ssr/[root-of-the-server]__fae8b355._.js +1 -1
  154. package/web/.next/server/chunks/ssr/[root-of-the-server]__fae8b355._.js.map +1 -1
  155. package/web/.next/server/chunks/ssr/_05c23ad9._.js +1 -1
  156. package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +1 -1
  157. package/web/.next/server/chunks/ssr/_0c5f56e3._.js +2 -2
  158. package/web/.next/server/chunks/ssr/_0c5f56e3._.js.map +1 -1
  159. package/web/.next/server/chunks/ssr/_16eb4fec._.js +1 -1
  160. package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +1 -1
  161. package/web/.next/server/chunks/ssr/_1b719e7f._.js +1 -1
  162. package/web/.next/server/chunks/ssr/_1b719e7f._.js.map +1 -1
  163. package/web/.next/server/chunks/ssr/_24c98f2c._.js +3 -0
  164. package/web/.next/server/chunks/ssr/{_b839d4f1._.js.map → _24c98f2c._.js.map} +1 -1
  165. package/web/.next/server/chunks/ssr/_37e8548b._.js +1 -1
  166. package/web/.next/server/chunks/ssr/_37e8548b._.js.map +1 -1
  167. package/web/.next/server/chunks/ssr/_41d9cd95._.js +4 -0
  168. package/web/.next/server/chunks/ssr/_41d9cd95._.js.map +1 -0
  169. package/web/.next/server/chunks/ssr/_55d763e2._.js +1 -1
  170. package/web/.next/server/chunks/ssr/_55d763e2._.js.map +1 -1
  171. package/web/.next/server/chunks/ssr/_6256a985._.js +1 -1
  172. package/web/.next/server/chunks/ssr/_6256a985._.js.map +1 -1
  173. package/web/.next/server/chunks/ssr/_64bdfc6f._.js +2 -2
  174. package/web/.next/server/chunks/ssr/_64bdfc6f._.js.map +1 -1
  175. package/web/.next/server/chunks/ssr/_8fcc39d4._.js +1 -1
  176. package/web/.next/server/chunks/ssr/_8fcc39d4._.js.map +1 -1
  177. package/web/.next/server/chunks/ssr/_b71645b4._.js +1 -1
  178. package/web/.next/server/chunks/ssr/_b71645b4._.js.map +1 -1
  179. package/web/.next/server/chunks/ssr/_d4b20e29._.js.map +1 -1
  180. package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
  181. package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
  182. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  183. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  184. package/web/.next/server/chunks/ssr/{src_presentation_web_523768ca._.js → src_presentation_web_4128a266._.js} +2 -2
  185. package/web/.next/server/chunks/ssr/{src_presentation_web_523768ca._.js.map → src_presentation_web_4128a266._.js.map} +1 -1
  186. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
  187. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
  188. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
  189. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
  190. package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
  191. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  192. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  193. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  194. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  195. package/web/.next/server/pages/500.html +2 -2
  196. package/web/.next/server/server-reference-manifest.js +1 -1
  197. package/web/.next/server/server-reference-manifest.json +44 -44
  198. package/web/.next/static/chunks/{63f412a89bde2484.js → 08a345de60f7a916.js} +1 -1
  199. package/web/.next/static/chunks/155eeac110efde49.js +5 -0
  200. package/web/.next/static/chunks/{8923825cdb21cf1c.js → 2a89bc5c539a887c.js} +1 -1
  201. package/web/.next/static/chunks/49057cf8cd37e262.js +1 -0
  202. package/web/.next/static/chunks/57489f571eaef682.js +1 -0
  203. package/web/.next/static/chunks/{a63c16171b149d2d.js → 76ae0ee5b19cb24d.js} +1 -1
  204. package/web/.next/static/chunks/{9fd5c3ecc8c5eb07.js → 79050ec2da3b1545.js} +1 -1
  205. package/web/.next/static/chunks/{79984461b85f1e4e.js → 82b4ce7dd487497c.js} +1 -1
  206. package/web/.next/static/chunks/9b8678597fa1db84.css +1 -0
  207. package/web/.next/static/chunks/a48d1fbd73f27a65.js +1 -0
  208. package/web/.next/static/chunks/{0ddea46ed4ba1621.js → b650639ad2c0225a.js} +1 -1
  209. package/web/.next/static/chunks/da1da0780b5c0772.js +2 -0
  210. package/web/.next/static/chunks/f5c613066998f4d3.js +1 -0
  211. package/web/.next/static/chunks/{28f5e2d65510526a.js → fbaff86b010c0bff.js} +1 -1
  212. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_ff60e4a5.js +0 -3
  213. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_ff60e4a5.js.map +0 -1
  214. package/web/.next/server/chunks/[externals]__448264a3._.js +0 -3
  215. package/web/.next/server/chunks/ssr/_5a50254c._.js +0 -4
  216. package/web/.next/server/chunks/ssr/_5a50254c._.js.map +0 -1
  217. package/web/.next/server/chunks/ssr/_b839d4f1._.js +0 -3
  218. package/web/.next/static/chunks/0539e93ac218f442.js +0 -2
  219. package/web/.next/static/chunks/7ab5c32984198a7e.js +0 -2
  220. package/web/.next/static/chunks/869ae48ca73fa328.js +0 -1
  221. package/web/.next/static/chunks/a0ab3aee9a5e3d02.js +0 -1
  222. package/web/.next/static/chunks/d61c239df26c61fd.css +0 -1
  223. package/web/.next/static/chunks/ebbc5dd20e227e3d.js +0 -1
  224. package/web/.next/static/chunks/fa556c575c788679.js +0 -1
  225. /package/web/.next/server/chunks/{[externals]__448264a3._.js.map → 744ca_web__next-internal_server_app_api_sessions-batch_route_actions_4859f283.js.map} +0 -0
  226. /package/web/.next/static/{41QsWn4e2sGnQCNBIar6W → kW82VHngwCjHeZ0IeW0ZK}/_buildManifest.js +0 -0
  227. /package/web/.next/static/{41QsWn4e2sGnQCNBIar6W → kW82VHngwCjHeZ0IeW0ZK}/_clientMiddlewareManifest.json +0 -0
  228. /package/web/.next/static/{41QsWn4e2sGnQCNBIar6W → kW82VHngwCjHeZ0IeW0ZK}/_ssgManifest.js +0 -0
@@ -27,34 +27,9 @@ export function useDeployAction(input) {
27
27
  mountedRef.current = false;
28
28
  };
29
29
  }, []);
30
- // Fetch status on mount recover running dev servers after page reload
31
- useEffect(() => {
32
- if (!input)
33
- return;
34
- let cancelled = false;
35
- (async () => {
36
- try {
37
- const result = await getDeploymentStatus(input.targetId);
38
- if (cancelled || !mountedRef.current)
39
- return;
40
- if (result && result.state !== 'Stopped') {
41
- log.info(`mount recovery: "${input.targetId}" state=${result.state}, url=${result.url}`);
42
- setStatus(result.state);
43
- setUrl(result.url);
44
- startPolling(input.targetId);
45
- }
46
- }
47
- catch {
48
- // Server container may not be available (e.g., in tests)
49
- log.debug(`mount recovery failed for "${input.targetId}" — ignoring`);
50
- }
51
- })();
52
- return () => {
53
- cancelled = true;
54
- };
55
- // Only run on mount (input identity is stable from the caller)
56
- // eslint-disable-next-line react-hooks/exhaustive-deps
57
- }, [input?.targetId]);
30
+ // Mount recovery removedgetGraphData() already enriches nodes with
31
+ // deployment status (get-graph-data.ts lines 180-200). No need to call
32
+ // a server action per node on every mount.
58
33
  // Cleanup on unmount
59
34
  useEffect(() => {
60
35
  return () => {
@@ -108,32 +83,11 @@ export function useDeployAction(input) {
108
83
  }
109
84
  }, POLL_INTERVAL);
110
85
  }, [stopPolling]);
111
- // Idle poll — when no deployment is known, periodically check if one was
112
- // started externally (e.g., from the drawer while the repo node is mounted).
113
- const IDLE_POLL_INTERVAL = 5000;
114
- useEffect(() => {
115
- if (!input || status !== null)
116
- return;
117
- const timer = setInterval(async () => {
118
- if (!mountedRef.current)
119
- return;
120
- try {
121
- const result = await getDeploymentStatus(input.targetId);
122
- if (!mountedRef.current)
123
- return;
124
- if (result && result.state !== 'Stopped') {
125
- log.info(`idle poll: "${input.targetId}" state=${result.state}, url=${result.url}`);
126
- setStatus(result.state);
127
- setUrl(result.url);
128
- startPolling(input.targetId);
129
- }
130
- }
131
- catch {
132
- // ignore
133
- }
134
- }, IDLE_POLL_INTERVAL);
135
- return () => clearInterval(timer);
136
- }, [input, status, startPolling]);
86
+ // Idle poll removed it was calling getDeploymentStatus every 5s for EVERY
87
+ // node on the canvas (~25 nodes = ~5 server action calls/sec). The mount
88
+ // recovery effect above (line 57) already checks on mount. Deployments
89
+ // started externally (e.g., from the drawer) should update the node via
90
+ // reconcile from the graph-data poll instead.
137
91
  const handleDeploy = useCallback(async () => {
138
92
  if (!input) {
139
93
  log.warn('deploy() called but input is null — no-op');
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Shared session scanning logic used by both /api/sessions and /api/sessions-batch.
3
+ *
4
+ * Scans Claude Code and Cursor session directories for JSONL session files,
5
+ * parsing headers to extract preview, message count, and timestamps.
6
+ */
7
+ export interface SessionResult {
8
+ id: string;
9
+ agentType: string;
10
+ preview: string | null;
11
+ messageCount: number;
12
+ firstMessageAt: string | null;
13
+ lastMessageAt: string | null;
14
+ createdAt: string | null;
15
+ projectPath: string;
16
+ filePath: string;
17
+ /** mtime for sorting — not sent to client */
18
+ _mtime: number;
19
+ }
20
+ export declare function scanClaudeSessions(repositoryPath: string, limit: number, includeWorktrees?: boolean): Promise<SessionResult[]>;
21
+ export declare function scanCursorSessions(repositoryPath: string, limit: number): Promise<SessionResult[]>;
22
+ /**
23
+ * Scan sessions for a single repository path from all providers.
24
+ * Merges and sorts by recency.
25
+ */
26
+ export declare function scanSessionsForPath(repositoryPath: string, limit: number, includeWorktrees?: boolean): Promise<SessionResult[]>;
27
+ //# sourceMappingURL=session-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-scanner.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/lib/session-scanner.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;CAChB;AAsID,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,gBAAgB,UAAQ,GACvB,OAAO,CAAC,aAAa,EAAE,CAAC,CA2C1B;AAiED,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,aAAa,EAAE,CAAC,CA6D1B;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,gBAAgB,UAAQ,GACvB,OAAO,CAAC,aAAa,EAAE,CAAC,CAS1B"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Shared session scanning logic used by both /api/sessions and /api/sessions-batch.
3
+ *
4
+ * Scans Claude Code and Cursor session directories for JSONL session files,
5
+ * parsing headers to extract preview, message count, and timestamps.
6
+ */
7
+ import { createHash } from 'node:crypto';
8
+ import { homedir } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { readdir, stat } from 'node:fs/promises';
11
+ // ── Path encoding helpers ─────────────────────────────────────────────
12
+ /**
13
+ * Claude Code encodes paths by replacing '/', '\', '.' with '-'.
14
+ * e.g. /home/user/.shep/repos/abc → -home-user--shep-repos-abc
15
+ */
16
+ function claudeEncodePath(p) {
17
+ return p.replace(/[/\\.]/g, '-');
18
+ }
19
+ /**
20
+ * Cursor encodes paths by stripping the leading '/', removing dots,
21
+ * and replacing '/' and '\' with '-'.
22
+ * e.g. /home/user/.shep/repos/abc → home-user-shep-repos-abc
23
+ */
24
+ function cursorEncodePath(p) {
25
+ return p.replace(/^\//, '').replace(/\./g, '').replace(/[/\\]/g, '-');
26
+ }
27
+ // ── Shared helpers ────────────────────────────────────────────────────
28
+ function extractText(content) {
29
+ if (typeof content === 'string')
30
+ return content;
31
+ if (Array.isArray(content)) {
32
+ for (const block of content) {
33
+ if (typeof block === 'object' && block !== null) {
34
+ const b = block;
35
+ if (b.type === 'text' && typeof b.text === 'string')
36
+ return b.text;
37
+ }
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ const PREVIEW_READ_BYTES = 8_192; // 8KB is enough for first few messages
43
+ // ── Claude Code session scanner ───────────────────────────────────────
44
+ async function collectJsonlFiles(projectDir) {
45
+ let entries;
46
+ try {
47
+ entries = await readdir(projectDir);
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ const jsonlFiles = entries.filter((e) => e.endsWith('.jsonl'));
53
+ const fileInfos = await Promise.allSettled(jsonlFiles.map(async (name) => {
54
+ const filePath = join(projectDir, name);
55
+ const s = await stat(filePath);
56
+ return { name, filePath, mtime: s.mtime.getTime() };
57
+ }));
58
+ return fileInfos
59
+ .filter((r) => r.status === 'fulfilled')
60
+ .map((r) => r.value);
61
+ }
62
+ async function parseClaudeSession(filePath, fileName, mtime, repositoryPath) {
63
+ const { createReadStream } = await import('node:fs');
64
+ const id = fileName.replace('.jsonl', '');
65
+ let preview = null;
66
+ let firstTimestamp = null;
67
+ let messageCount = 0;
68
+ const head = await new Promise((resolve) => {
69
+ const chunks = [];
70
+ let size = 0;
71
+ const stream = createReadStream(filePath, { end: PREVIEW_READ_BYTES - 1 });
72
+ stream.on('data', (chunk) => {
73
+ chunks.push(chunk);
74
+ size += chunk.length;
75
+ });
76
+ stream.on('end', () => resolve(Buffer.concat(chunks, size).toString('utf-8')));
77
+ stream.on('error', () => resolve(''));
78
+ });
79
+ if (!head)
80
+ return null;
81
+ const lines = head.split('\n').filter((l) => l.trim());
82
+ for (const line of lines) {
83
+ try {
84
+ const entry = JSON.parse(line);
85
+ if (entry.type === 'user' || entry.type === 'assistant') {
86
+ const role = entry.message?.role;
87
+ if (role === 'user' || role === 'assistant') {
88
+ messageCount++;
89
+ if (entry.timestamp) {
90
+ firstTimestamp ??= entry.timestamp;
91
+ }
92
+ if (role === 'user' && preview === null) {
93
+ preview = extractText(entry.message?.content);
94
+ }
95
+ }
96
+ }
97
+ }
98
+ catch {
99
+ break;
100
+ }
101
+ }
102
+ if (messageCount === 0)
103
+ return null;
104
+ const mtimeIso = new Date(mtime).toISOString();
105
+ return {
106
+ id,
107
+ agentType: 'claude-code',
108
+ preview,
109
+ messageCount,
110
+ firstMessageAt: firstTimestamp,
111
+ lastMessageAt: mtimeIso,
112
+ createdAt: firstTimestamp ?? mtimeIso,
113
+ projectPath: repositoryPath,
114
+ filePath,
115
+ _mtime: mtime,
116
+ };
117
+ }
118
+ export async function scanClaudeSessions(repositoryPath, limit, includeWorktrees = false) {
119
+ const dirName = claudeEncodePath(repositoryPath);
120
+ const projectsRoot = join(homedir(), '.claude', 'projects');
121
+ const primaryDir = join(projectsRoot, dirName);
122
+ let allFiles = await collectJsonlFiles(primaryDir);
123
+ if (includeWorktrees) {
124
+ try {
125
+ const allDirs = await readdir(projectsRoot);
126
+ const prefixMatches = allDirs.filter((d) => d !== dirName && d.startsWith(dirName));
127
+ const normalizedRepoPath = repositoryPath.replace(/\\/g, '/');
128
+ const repoHash = createHash('sha256').update(normalizedRepoPath).digest('hex').slice(0, 16);
129
+ const shepHome = join(homedir(), '.shep').replace(/\\/g, '/');
130
+ const shepWorktreePrefix = claudeEncodePath(join(shepHome, 'repos', repoHash));
131
+ const shepMatches = allDirs.filter((d) => d.startsWith(shepWorktreePrefix) && !prefixMatches.includes(d) && d !== dirName);
132
+ const worktreeDirs = [...prefixMatches, ...shepMatches];
133
+ const worktreeResults = await Promise.all(worktreeDirs.map((d) => collectJsonlFiles(join(projectsRoot, d))));
134
+ for (const files of worktreeResults) {
135
+ allFiles = allFiles.concat(files);
136
+ }
137
+ }
138
+ catch {
139
+ // projectsRoot doesn't exist — no sessions at all
140
+ }
141
+ }
142
+ const valid = allFiles.sort((a, b) => b.mtime - a.mtime).slice(0, limit);
143
+ const results = await Promise.allSettled(valid.map(async (fi) => parseClaudeSession(fi.filePath, fi.name, fi.mtime, repositoryPath)));
144
+ return results
145
+ .filter((r) => r.status === 'fulfilled')
146
+ .map((r) => r.value)
147
+ .filter((s) => s !== null);
148
+ }
149
+ // ── Cursor session scanner ────────────────────────────────────────────
150
+ async function parseCursorSession(filePath, fileName, mtime, repositoryPath) {
151
+ const { createReadStream } = await import('node:fs');
152
+ const id = fileName.replace('.jsonl', '');
153
+ const head = await new Promise((resolve) => {
154
+ const chunks = [];
155
+ let size = 0;
156
+ const stream = createReadStream(filePath, { end: PREVIEW_READ_BYTES - 1 });
157
+ stream.on('data', (chunk) => {
158
+ chunks.push(chunk);
159
+ size += chunk.length;
160
+ });
161
+ stream.on('end', () => resolve(Buffer.concat(chunks, size).toString('utf-8')));
162
+ stream.on('error', () => resolve(''));
163
+ });
164
+ if (!head)
165
+ return null;
166
+ let preview = null;
167
+ let messageCount = 0;
168
+ const lines = head.split('\n').filter((l) => l.trim());
169
+ for (const line of lines) {
170
+ try {
171
+ const entry = JSON.parse(line);
172
+ if (entry.role === 'user' || entry.role === 'assistant') {
173
+ messageCount++;
174
+ if (entry.role === 'user' && preview === null) {
175
+ preview = extractText(entry.message?.content);
176
+ }
177
+ }
178
+ }
179
+ catch {
180
+ break;
181
+ }
182
+ }
183
+ if (messageCount === 0)
184
+ return null;
185
+ const mtimeIso = new Date(mtime).toISOString();
186
+ return {
187
+ id,
188
+ agentType: 'cursor',
189
+ preview,
190
+ messageCount,
191
+ firstMessageAt: mtimeIso,
192
+ lastMessageAt: mtimeIso,
193
+ createdAt: mtimeIso,
194
+ projectPath: repositoryPath,
195
+ filePath,
196
+ _mtime: mtime,
197
+ };
198
+ }
199
+ export async function scanCursorSessions(repositoryPath, limit) {
200
+ const dirName = cursorEncodePath(repositoryPath);
201
+ const transcriptsDir = join(homedir(), '.cursor', 'projects', dirName, 'agent-transcripts');
202
+ let entries;
203
+ try {
204
+ entries = await readdir(transcriptsDir);
205
+ }
206
+ catch {
207
+ return [];
208
+ }
209
+ const fileInfos = await Promise.allSettled(entries.map(async (entry) => {
210
+ const entryPath = join(transcriptsDir, entry);
211
+ const s = await stat(entryPath);
212
+ if (s.isFile() && entry.endsWith('.jsonl')) {
213
+ return { name: entry, filePath: entryPath, mtime: s.mtime.getTime() };
214
+ }
215
+ if (s.isDirectory()) {
216
+ const jsonlPath = join(entryPath, `${entry}.jsonl`);
217
+ try {
218
+ const jsonlStat = await stat(jsonlPath);
219
+ return {
220
+ name: `${entry}.jsonl`,
221
+ filePath: jsonlPath,
222
+ mtime: jsonlStat.mtime.getTime(),
223
+ };
224
+ }
225
+ catch {
226
+ return null;
227
+ }
228
+ }
229
+ return null;
230
+ }));
231
+ const valid = fileInfos
232
+ .filter((r) => r.status === 'fulfilled')
233
+ .map((r) => r.value)
234
+ .filter((v) => v !== null)
235
+ .sort((a, b) => b.mtime - a.mtime)
236
+ .slice(0, limit);
237
+ const results = await Promise.allSettled(valid.map(async (fi) => parseCursorSession(fi.filePath, fi.name, fi.mtime, repositoryPath)));
238
+ return results
239
+ .filter((r) => r.status === 'fulfilled')
240
+ .map((r) => r.value)
241
+ .filter((s) => s !== null);
242
+ }
243
+ /**
244
+ * Scan sessions for a single repository path from all providers.
245
+ * Merges and sorts by recency.
246
+ */
247
+ export async function scanSessionsForPath(repositoryPath, limit, includeWorktrees = false) {
248
+ const [claudeSessions, cursorSessions] = await Promise.all([
249
+ scanClaudeSessions(repositoryPath, limit, includeWorktrees),
250
+ scanCursorSessions(repositoryPath, limit),
251
+ ]);
252
+ return [...claudeSessions, ...cursorSessions]
253
+ .sort((a, b) => b._mtime - a._mtime)
254
+ .slice(0, Math.min(limit, 50));
255
+ }