@shepai/cli 1.148.0 → 1.149.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/dist/src/presentation/web/app/api/agent-events/route.js +1 -1
  2. package/dist/src/presentation/web/app/api/sessions/route.d.ts.map +1 -1
  3. package/dist/src/presentation/web/app/api/sessions/route.js +2 -268
  4. package/dist/src/presentation/web/app/api/sessions-batch/route.d.ts +17 -0
  5. package/dist/src/presentation/web/app/api/sessions-batch/route.d.ts.map +1 -0
  6. package/dist/src/presentation/web/app/api/sessions-batch/route.js +61 -0
  7. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.d.ts +1 -1
  8. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.d.ts.map +1 -1
  9. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.js +15 -73
  10. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.stories.d.ts.map +1 -1
  11. package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.stories.js +18 -17
  12. package/dist/src/presentation/web/components/features/control-center/control-center.d.ts.map +1 -1
  13. package/dist/src/presentation/web/components/features/control-center/control-center.js +2 -1
  14. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  15. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +4 -1
  16. package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.d.ts.map +1 -1
  17. package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.js +32 -33
  18. package/dist/src/presentation/web/hooks/sessions-provider.d.ts +12 -0
  19. package/dist/src/presentation/web/hooks/sessions-provider.d.ts.map +1 -0
  20. package/dist/src/presentation/web/hooks/sessions-provider.js +57 -0
  21. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
  22. package/dist/src/presentation/web/hooks/use-deploy-action.js +8 -54
  23. package/dist/src/presentation/web/lib/session-scanner.d.ts +27 -0
  24. package/dist/src/presentation/web/lib/session-scanner.d.ts.map +1 -0
  25. package/dist/src/presentation/web/lib/session-scanner.js +255 -0
  26. package/dist/tsconfig.build.tsbuildinfo +1 -1
  27. package/package.json +1 -1
  28. package/web/.next/BUILD_ID +1 -1
  29. package/web/.next/app-path-routes-manifest.json +1 -0
  30. package/web/.next/build-manifest.json +2 -2
  31. package/web/.next/fallback-build-manifest.json +2 -2
  32. package/web/.next/prerender-manifest.json +3 -3
  33. package/web/.next/required-server-files.js +2 -2
  34. package/web/.next/required-server-files.json +2 -2
  35. package/web/.next/routes-manifest.json +6 -0
  36. package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +28 -28
  37. package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
  38. package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
  39. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +28 -28
  40. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  41. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  42. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
  43. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  44. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  45. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +36 -36
  46. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  47. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  48. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
  49. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  50. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  51. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +28 -28
  52. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  53. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  54. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
  55. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  56. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  57. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +36 -36
  58. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  59. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  60. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +26 -26
  61. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  62. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  63. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
  64. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  65. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/_global-error.html +2 -2
  67. package/web/.next/server/app/_global-error.rsc +1 -1
  68. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  69. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  70. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  71. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  72. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  73. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +3 -3
  74. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  75. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  76. package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
  77. package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
  78. package/web/.next/server/app/api/sessions/route.js +2 -3
  79. package/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
  80. package/web/.next/server/app/api/sessions-batch/route/app-paths-manifest.json +3 -0
  81. package/web/.next/server/app/api/sessions-batch/route/build-manifest.json +11 -0
  82. package/web/.next/server/app/api/sessions-batch/route/server-reference-manifest.json +4 -0
  83. package/web/.next/server/app/api/sessions-batch/route.js +7 -0
  84. package/web/.next/server/app/api/sessions-batch/route.js.map +5 -0
  85. package/web/.next/server/app/api/sessions-batch/route.js.nft.json +1 -0
  86. package/web/.next/server/app/api/sessions-batch/route_client-reference-manifest.js +2 -0
  87. package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  88. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  89. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  90. package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
  91. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  92. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  93. package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
  94. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  95. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  96. package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
  97. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  98. package/web/.next/server/app-paths-manifest.json +1 -0
  99. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +1 -1
  100. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
  101. package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_sessions-batch_route_actions_4859f283.js +3 -0
  102. package/web/.next/server/chunks/[root-of-the-server]__0d33c29e._.js +3 -0
  103. package/web/.next/server/chunks/[root-of-the-server]__0d33c29e._.js.map +1 -0
  104. package/web/.next/server/chunks/[root-of-the-server]__2f61738a._.js +3 -0
  105. package/web/.next/server/chunks/[root-of-the-server]__2f61738a._.js.map +1 -0
  106. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  107. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  108. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  109. package/web/.next/server/chunks/ssr/[root-of-the-server]__2138fa7e._.js +2 -2
  110. package/web/.next/server/chunks/ssr/[root-of-the-server]__29580090._.js +1 -1
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__29580090._.js.map +1 -1
  112. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  113. package/web/.next/server/chunks/ssr/[root-of-the-server]__3ef34e4c._.js +1 -1
  114. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
  115. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
  116. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
  117. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
  118. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +2 -2
  119. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  120. package/web/.next/server/chunks/ssr/[root-of-the-server]__c094882b._.js +1 -1
  121. package/web/.next/server/chunks/ssr/[root-of-the-server]__c094882b._.js.map +1 -1
  122. package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js +1 -1
  123. package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js.map +1 -1
  124. package/web/.next/server/chunks/ssr/[root-of-the-server]__dac5dbf1._.js +1 -1
  125. package/web/.next/server/chunks/ssr/[root-of-the-server]__dac5dbf1._.js.map +1 -1
  126. package/web/.next/server/chunks/ssr/[root-of-the-server]__fae8b355._.js +1 -1
  127. package/web/.next/server/chunks/ssr/[root-of-the-server]__fae8b355._.js.map +1 -1
  128. package/web/.next/server/chunks/ssr/_05c23ad9._.js +1 -1
  129. package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +1 -1
  130. package/web/.next/server/chunks/ssr/_0c5f56e3._.js +2 -2
  131. package/web/.next/server/chunks/ssr/_0c5f56e3._.js.map +1 -1
  132. package/web/.next/server/chunks/ssr/_16eb4fec._.js +1 -1
  133. package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +1 -1
  134. package/web/.next/server/chunks/ssr/_1b719e7f._.js +1 -1
  135. package/web/.next/server/chunks/ssr/_1b719e7f._.js.map +1 -1
  136. package/web/.next/server/chunks/ssr/_37e8548b._.js +1 -1
  137. package/web/.next/server/chunks/ssr/_37e8548b._.js.map +1 -1
  138. package/web/.next/server/chunks/ssr/{_fe63a7f9._.js → _458e9a64._.js} +2 -2
  139. package/web/.next/server/chunks/ssr/{_fe63a7f9._.js.map → _458e9a64._.js.map} +1 -1
  140. package/web/.next/server/chunks/ssr/_5022e2b1._.js +4 -0
  141. package/web/.next/server/chunks/ssr/_5022e2b1._.js.map +1 -0
  142. package/web/.next/server/chunks/ssr/_55d763e2._.js +1 -1
  143. package/web/.next/server/chunks/ssr/_55d763e2._.js.map +1 -1
  144. package/web/.next/server/chunks/ssr/_6256a985._.js +1 -1
  145. package/web/.next/server/chunks/ssr/_6256a985._.js.map +1 -1
  146. package/web/.next/server/chunks/ssr/_64bdfc6f._.js +2 -2
  147. package/web/.next/server/chunks/ssr/_64bdfc6f._.js.map +1 -1
  148. package/web/.next/server/chunks/ssr/_8fcc39d4._.js +1 -1
  149. package/web/.next/server/chunks/ssr/_b71645b4._.js +1 -1
  150. package/web/.next/server/chunks/ssr/_b71645b4._.js.map +1 -1
  151. package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
  152. package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
  153. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  154. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  155. package/web/.next/server/chunks/ssr/{src_presentation_web_7b2fda40._.js → src_presentation_web_35159458._.js} +2 -2
  156. package/web/.next/server/chunks/ssr/{src_presentation_web_7b2fda40._.js.map → src_presentation_web_35159458._.js.map} +1 -1
  157. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
  158. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
  159. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
  160. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
  161. package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
  162. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  163. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  164. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  165. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  166. package/web/.next/server/pages/500.html +2 -2
  167. package/web/.next/server/server-reference-manifest.js +1 -1
  168. package/web/.next/server/server-reference-manifest.json +44 -44
  169. package/web/.next/static/chunks/{0137d4850cab3c45.js → 24b1c1e60fd3b7b5.js} +2 -2
  170. package/web/.next/static/chunks/{c731682077fbac4f.js → 3e7a130816229439.js} +1 -1
  171. package/web/.next/static/chunks/{7c5131e33516a325.js → 3f1b33498b472b00.js} +1 -1
  172. package/web/.next/static/chunks/{04869f1d3f5d9071.js → 4ef564fb1174e497.js} +1 -1
  173. package/web/.next/static/chunks/75834e430247b325.js +1 -0
  174. package/web/.next/static/chunks/79dc2e2f1c2ff519.js +1 -0
  175. package/web/.next/static/chunks/{063a24b49d9818a0.js → a086f8dfef2c3325.js} +1 -1
  176. package/web/.next/static/chunks/{48850e202dd814ac.js → a6363f73e05ccf47.js} +1 -1
  177. package/web/.next/static/chunks/{6f76e63ead3fac2e.js → b7126c0b3a97e77e.js} +1 -1
  178. package/web/.next/static/chunks/d3df6e6434e16519.js +1 -0
  179. package/web/.next/static/chunks/eaca60cc3ab0bf9f.js +2 -0
  180. package/web/.next/static/chunks/{9dad6769d10a32df.js → fe5d48f8ca483935.js} +1 -1
  181. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_ff60e4a5.js +0 -3
  182. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_ff60e4a5.js.map +0 -1
  183. package/web/.next/server/chunks/[externals]__448264a3._.js +0 -3
  184. package/web/.next/server/chunks/ssr/_4533d6f8._.js +0 -4
  185. package/web/.next/server/chunks/ssr/_4533d6f8._.js.map +0 -1
  186. package/web/.next/static/chunks/21e82fee1a7e1668.js +0 -1
  187. package/web/.next/static/chunks/682563e4503cbd58.js +0 -1
  188. package/web/.next/static/chunks/683b1d85e789c2eb.js +0 -2
  189. package/web/.next/static/chunks/d62ae5e449d87057.js +0 -1
  190. /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
  191. /package/web/.next/static/{zYKuE1zbe1UWwAJv5EVwg → 1CQHYZVn3VajyhdvnsCaw}/_buildManifest.js +0 -0
  192. /package/web/.next/static/{zYKuE1zbe1UWwAJv5EVwg → 1CQHYZVn3VajyhdvnsCaw}/_clientMiddlewareManifest.json +0 -0
  193. /package/web/.next/static/{zYKuE1zbe1UWwAJv5EVwg → 1CQHYZVn3VajyhdvnsCaw}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAkBjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAM7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,mBAAmB,EAAE,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,EACjB,aAAa,CAAC,EAAE,OAAO,EACvB,OAAO,CAAC,EAAE,OAAO,KACd,IAAI,CAAC;IACV,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sBAAsB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,yDAAyD;IACzD,YAAY,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,eAAe,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAQD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CA+kBpB"}
1
+ {"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAkBjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAM7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,mBAAmB,EAAE,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,EACjB,aAAa,CAAC,EAAE,OAAO,EACvB,OAAO,CAAC,EAAE,OAAO,KACd,IAAI,CAAC;IACV,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,sBAAsB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,yDAAyD;IACzD,YAAY,EAAE,OAAO,CAAC;IACtB,0CAA0C;IAC1C,eAAe,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAQD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CAilBpB"}
@@ -18,7 +18,7 @@ import { createLogger } from '../../../lib/logger.js';
18
18
  import { mapEventTypeToState, resolveSseEventUpdates, } from '../../common/feature-node/derive-feature-state.js';
19
19
  import { useGraphState } from '../../../hooks/use-graph-state.js';
20
20
  const log = createLogger('[Polling]');
21
- const POLL_INTERVAL_MS = 3_000;
21
+ const POLL_INTERVAL_MS = 15_000;
22
22
  /** Must match the message string emitted by the SSE route in agent-events/route.ts */
23
23
  const METADATA_UPDATED_MESSAGE = 'Feature metadata updated';
24
24
  let nextFeatureId = 0;
@@ -175,6 +175,9 @@ export function useControlCenterState(initialNodes, initialEdges) {
175
175
  useEffect(() => {
176
176
  log.debug(`polling enabled (${POLL_INTERVAL_MS}ms interval)`);
177
177
  const timer = setInterval(async () => {
178
+ // Skip when tab is hidden — no point polling for a user who isn't looking.
179
+ if (document.hidden)
180
+ return;
178
181
  // Skip fetch entirely while a mutation is in-flight — the response
179
182
  // would contain pre-mutation data that reconcile would discard anyway.
180
183
  if (isMutating())
@@ -1 +1 @@
1
- {"version":3,"file":"app-sidebar.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/layouts/app-sidebar/app-sidebar.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAI/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,YAAY,EAAE,iBAAiB,CAAC;IAEhC,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAED,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,YAAY,EAEZ,cAAc,GACf,EAAE,eAAe,2CA6MjB"}
1
+ {"version":3,"file":"app-sidebar.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/layouts/app-sidebar/app-sidebar.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAI/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,YAAY,EAAE,iBAAiB,CAAC;IAEhC,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAED,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,YAAY,EAEZ,cAAc,GACf,EAAE,eAAe,2CAoMjB"}
@@ -1,7 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { usePathname } from 'next/navigation';
4
- import Link from 'next/link';
5
4
  import { Home, Moon, Sun, Volume2, VolumeOff, Wrench, Puzzle, Settings } from 'lucide-react';
6
5
  import { Sidebar, SidebarHeader, SidebarContent, SidebarFooter, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarRail, useSidebar, } from '../../ui/sidebar.js';
7
6
  import { ScrollArea } from '../../ui/scroll-area.js';
@@ -39,39 +38,39 @@ export function AppSidebar({ features, featureFlags, onFeatureClick, }) {
39
38
  'flex min-w-0 flex-1 items-center gap-2 overflow-hidden px-2',
40
39
  'transition-opacity duration-200 ease-out',
41
40
  expandedVisible ? 'opacity-100' : 'opacity-0',
42
- ].join(' '), "aria-hidden": !expandedVisible, children: [_jsx(ShepLogo, { className: "shrink-0", size: 20, variant: versionData.isDev ? 'dev' : 'default' }), _jsx("span", { className: "truncate text-sm font-semibold tracking-tight", children: "Shep" }), _jsx(VersionBadge, { version: versionData.version, branch: versionData.branch || undefined, commitHash: versionData.commitHash || undefined, isDev: versionData.isDev, packageName: versionData.packageName, description: versionData.description, instancePath: versionData.instancePath || undefined })] })) : null, _jsx(SidebarCollapseToggle, { className: "shrink-0 transition-all duration-200" })] }) }), _jsx(SidebarNavItem, { icon: Home, label: "Control Center", href: "/", active: pathname === '/' }), _jsx(SidebarNavItem, { icon: Wrench, label: "Tools", href: "/tools", active: pathname === '/tools' }), featureFlags.skills ? (_jsx(SidebarNavItem, { icon: Puzzle, label: "Skills", href: "/skills", active: pathname === '/skills' })) : null] }) }), _jsx(SidebarContent, { children: showExpanded ? (_jsxs("div", { className: [
41
+ ].join(' '), "aria-hidden": !expandedVisible, children: [_jsx(ShepLogo, { className: "shrink-0", size: 20, variant: versionData.isDev ? 'dev' : 'default' }), _jsx("span", { className: "truncate text-sm font-semibold tracking-tight", children: "Shep" }), _jsx(VersionBadge, { version: versionData.version, branch: versionData.branch || undefined, commitHash: versionData.commitHash || undefined, isDev: versionData.isDev, packageName: versionData.packageName, description: versionData.description, instancePath: versionData.instancePath || undefined })] })) : null, _jsx(SidebarCollapseToggle, { className: "shrink-0 transition-all duration-200" })] }) }), _jsx(SidebarNavItem, { icon: Home, label: "Control Center", href: "/", active: pathname === '/' }), _jsx(SidebarNavItem, { icon: Wrench, label: "Tools", href: "/tools", active: pathname === '/tools' }), featureFlags.skills ? (_jsx(SidebarNavItem, { icon: Puzzle, label: "Skills", href: "/skills", active: pathname === '/skills' })) : null, _jsx(SidebarNavItem, { icon: Settings, label: "Settings", href: "/settings", active: pathname === '/settings' })] }) }), _jsx(SidebarContent, { children: showExpanded ? (_jsxs("div", { className: [
43
42
  'flex min-h-0 flex-1 flex-col overflow-hidden transition-opacity duration-200 ease-out',
44
43
  '[&_[data-sidebar=group-label]]:!mt-0 [&_[data-sidebar=group-label]]:!opacity-100 [&_[data-sidebar=group-label]]:!transition-none',
45
44
  expandedVisible ? 'opacity-100' : 'opacity-0',
46
- ].join(' '), children: [_jsx(SidebarSectionHeader, { label: "Features" }), _jsx(ScrollArea, { className: "min-h-0 flex-1", children: grouped.map(({ key, label, items }) => items.length > 0 ? (_jsx(FeatureStatusGroup, { label: label, count: items.length, children: items.map((feature) => (_jsx(FeatureListItem, { name: feature.name, status: feature.status, startedAt: feature.startedAt, duration: feature.duration, agentType: feature.agentType, modelId: feature.modelId, onClick: onFeatureClick ? () => onFeatureClick(feature.featureId) : undefined }, feature.featureId))) }, key)) : null) })] })) : null }), _jsx(SidebarFooter, { className: "border-t p-2", children: _jsx(SidebarMenu, { children: _jsx(SidebarMenuItem, { children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(SidebarMenuButton, { asChild: true, tooltip: "Settings", className: "w-auto flex-none", children: _jsx(Link, { href: '/settings', onClick: () => clickSound.play(), children: _jsx(Settings, { className: "h-4 w-4" }) }) }) }), _jsx(TooltipContent, { side: "top", hidden: collapsed, children: "Settings" })] }) }), !collapsed && _jsx("div", { className: "flex-1" }), !collapsed && (_jsxs(TooltipProvider, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(SidebarMenuButton, { className: "w-auto flex-none", onClick: () => {
47
- clickSound.play();
48
- toggleSound();
49
- }, "aria-label": soundEnabled ? 'Mute sounds' : 'Unmute sounds', children: soundEnabled ? (_jsx(Volume2, { className: "h-4 w-4" })) : (_jsx(VolumeOff, { className: "h-4 w-4" })) }) }), _jsx(TooltipContent, { side: "top", children: soundEnabled ? 'Mute sounds' : 'Unmute sounds' })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(SidebarMenuButton, { className: "w-auto flex-none", onClick: (e) => {
50
- const currentResolved = theme === 'system' ? resolvedTheme : theme;
51
- const goingToDark = currentResolved !== 'dark';
52
- const newTheme = theme === 'system'
53
- ? resolvedTheme === 'dark'
54
- ? 'light'
55
- : 'dark'
56
- : theme === 'dark'
57
- ? 'light'
58
- : 'dark';
59
- if (goingToDark) {
60
- toggleOnSound.play();
61
- }
62
- else {
63
- toggleOffSound.play();
64
- }
65
- const prefersReducedMotion = typeof window !== 'undefined' &&
66
- window.matchMedia('(prefers-reduced-motion: reduce)').matches;
67
- if (!('startViewTransition' in document) || prefersReducedMotion) {
68
- setTheme(newTheme);
69
- return;
70
- }
71
- document.documentElement.style.setProperty('--x', `${e.clientX}px`);
72
- document.documentElement.style.setProperty('--y', `${e.clientY}px`);
73
- document.startViewTransition(() => {
74
- setTheme(newTheme);
75
- });
76
- }, "aria-label": `Switch to ${resolvedTheme === 'dark' ? 'light' : 'dark'} mode`, children: [_jsx(Sun, { className: "h-4 w-4 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }), _jsx(Moon, { className: "absolute h-4 w-4 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" })] }) }), _jsx(TooltipContent, { side: "top", children: resolvedTheme === 'dark' ? 'Light mode' : 'Dark mode' })] })] }))] }) }) }) }), _jsx(SidebarRail, {})] }));
45
+ ].join(' '), children: [_jsx(SidebarSectionHeader, { label: "Features" }), _jsx(ScrollArea, { className: "min-h-0 flex-1", children: grouped.map(({ key, label, items }) => items.length > 0 ? (_jsx(FeatureStatusGroup, { label: label, count: items.length, children: items.map((feature) => (_jsx(FeatureListItem, { name: feature.name, status: feature.status, startedAt: feature.startedAt, duration: feature.duration, agentType: feature.agentType, modelId: feature.modelId, onClick: onFeatureClick ? () => onFeatureClick(feature.featureId) : undefined }, feature.featureId))) }, key)) : null) })] })) : null }), _jsx(SidebarFooter, { className: "border-t p-2", children: _jsx(SidebarMenu, { children: _jsx(SidebarMenuItem, { children: _jsx("div", { className: "flex items-center gap-1", children: _jsxs(TooltipProvider, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs(SidebarMenuButton, { className: "w-auto flex-none", onClick: (e) => {
46
+ const currentResolved = theme === 'system' ? resolvedTheme : theme;
47
+ const goingToDark = currentResolved !== 'dark';
48
+ const newTheme = theme === 'system'
49
+ ? resolvedTheme === 'dark'
50
+ ? 'light'
51
+ : 'dark'
52
+ : theme === 'dark'
53
+ ? 'light'
54
+ : 'dark';
55
+ if (goingToDark) {
56
+ toggleOnSound.play();
57
+ }
58
+ else {
59
+ toggleOffSound.play();
60
+ }
61
+ const prefersReducedMotion = typeof window !== 'undefined' &&
62
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches;
63
+ if (!('startViewTransition' in document) || prefersReducedMotion) {
64
+ setTheme(newTheme);
65
+ return;
66
+ }
67
+ document.documentElement.style.setProperty('--x', `${e.clientX}px`);
68
+ document.documentElement.style.setProperty('--y', `${e.clientY}px`);
69
+ document.startViewTransition(() => {
70
+ setTheme(newTheme);
71
+ });
72
+ }, "aria-label": `Switch to ${resolvedTheme === 'dark' ? 'light' : 'dark'} mode`, children: [_jsx(Sun, { className: "h-4 w-4 scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90" }), _jsx(Moon, { className: "absolute h-4 w-4 scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0" })] }) }), _jsx(TooltipContent, { side: "top", children: resolvedTheme === 'dark' ? 'Light mode' : 'Dark mode' })] }), !collapsed && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(SidebarMenuButton, { className: "w-auto flex-none", onClick: () => {
73
+ clickSound.play();
74
+ toggleSound();
75
+ }, "aria-label": soundEnabled ? 'Mute sounds' : 'Unmute sounds', children: soundEnabled ? (_jsx(Volume2, { className: "h-4 w-4" })) : (_jsx(VolumeOff, { className: "h-4 w-4" })) }) }), _jsx(TooltipContent, { side: "top", children: soundEnabled ? 'Mute sounds' : 'Unmute sounds' })] }))] }) }) }) }) }), _jsx(SidebarRail, {})] }));
77
76
  }
@@ -0,0 +1,12 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { SessionSummary } from '../components/common/feature-node/feature-sessions-dropdown.js';
3
+ interface SessionsContextValue {
4
+ getSessionsForPath: (path: string) => SessionSummary[];
5
+ hasActiveSessions: (path: string) => boolean;
6
+ }
7
+ export declare function SessionsProvider({ children }: {
8
+ children: ReactNode;
9
+ }): import("react/jsx-runtime").JSX.Element;
10
+ export declare function useSessionsContext(): SessionsContextValue;
11
+ export {};
12
+ //# sourceMappingURL=sessions-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessions-provider.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/sessions-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4DAA4D,CAAC;AAOjG,UAAU,oBAAoB;IAC5B,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,EAAE,CAAC;IACvD,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC9C;AAMD,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAoDrE;AAID,wBAAgB,kBAAkB,IAAI,oBAAoB,CAMzD"}
@@ -0,0 +1,57 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
4
+ const POLL_INTERVAL_MS = 30_000;
5
+ const ACTIVE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
6
+ const SessionsContext = createContext(null);
7
+ // ── Provider component ────────────────────────────────────────────────
8
+ export function SessionsProvider({ children }) {
9
+ const [sessionsByPath, setSessionsByPath] = useState(new Map());
10
+ const sessionsByPathRef = useRef(sessionsByPath);
11
+ sessionsByPathRef.current = sessionsByPath;
12
+ const fetchSessions = useCallback(async () => {
13
+ if (document.hidden)
14
+ return;
15
+ try {
16
+ const res = await fetch('/api/sessions-batch');
17
+ if (!res.ok)
18
+ return;
19
+ const data = (await res.json());
20
+ const next = new Map();
21
+ for (const [path, sessions] of Object.entries(data.sessionsByPath)) {
22
+ next.set(path, sessions);
23
+ }
24
+ setSessionsByPath(next);
25
+ }
26
+ catch {
27
+ // Silent — stale data is better than no data
28
+ }
29
+ }, []);
30
+ useEffect(() => {
31
+ void fetchSessions();
32
+ const timer = setInterval(() => void fetchSessions(), POLL_INTERVAL_MS);
33
+ return () => clearInterval(timer);
34
+ }, [fetchSessions]);
35
+ const getSessionsForPath = useCallback((path) => sessionsByPathRef.current.get(path) ?? [],
36
+ // eslint-disable-next-line react-hooks/exhaustive-deps
37
+ [sessionsByPath]);
38
+ const hasActiveSessions = useCallback((path) => {
39
+ const sessions = sessionsByPathRef.current.get(path);
40
+ if (!sessions)
41
+ return false;
42
+ const now = Date.now();
43
+ return sessions.some((s) => s.lastMessageAt && now - new Date(s.lastMessageAt).getTime() < ACTIVE_THRESHOLD_MS);
44
+ },
45
+ // eslint-disable-next-line react-hooks/exhaustive-deps
46
+ [sessionsByPath]);
47
+ const value = useMemo(() => ({ getSessionsForPath, hasActiveSessions }), [getSessionsForPath, hasActiveSessions]);
48
+ return _jsx(SessionsContext.Provider, { value: value, children: children });
49
+ }
50
+ // ── Consumer hook ─────────────────────────────────────────────────────
51
+ export function useSessionsContext() {
52
+ const ctx = useContext(SessionsContext);
53
+ if (!ctx) {
54
+ return { getSessionsForPath: () => [], hasActiveSessions: () => false };
55
+ }
56
+ return ctx;
57
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"use-deploy-action.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-deploy-action.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAM5E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,GAAG,YAAY,CAAC;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAMD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAAG,iBAAiB,CAmOlF"}
1
+ {"version":3,"file":"use-deploy-action.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/hooks/use-deploy-action.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAM5E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,GAAG,YAAY,CAAC;IACrC,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACpB;AAMD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,GAAG,iBAAiB,CAwLlF"}
@@ -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
+ }