@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.
- package/apis/json-schema/Attachment.yaml +3 -0
- package/dist/packages/core/src/domain/generated/output.d.ts +4 -0
- package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/compose-user-input.d.ts +1 -0
- package/dist/src/presentation/web/app/actions/compose-user-input.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/compose-user-input.js +3 -1
- package/dist/src/presentation/web/app/actions/create-feature.d.ts +1 -0
- package/dist/src/presentation/web/app/actions/create-feature.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/agent-events/route.js +1 -1
- package/dist/src/presentation/web/app/api/sessions/route.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/sessions/route.js +2 -268
- package/dist/src/presentation/web/app/api/sessions-batch/route.d.ts +17 -0
- package/dist/src/presentation/web/app/api/sessions-batch/route.d.ts.map +1 -0
- package/dist/src/presentation/web/app/api/sessions-batch/route.js +61 -0
- package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.d.ts +5 -1
- package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.js +6 -3
- package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.stories.d.ts +2 -0
- package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.stories.js +20 -0
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +5 -1
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.d.ts +2 -0
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.js +4 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts +2 -0
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +4 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.d.ts +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.js +15 -73
- package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.stories.js +18 -17
- package/dist/src/presentation/web/components/features/control-center/control-center.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center.js +2 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +4 -1
- package/dist/src/presentation/web/hooks/sessions-provider.d.ts +12 -0
- package/dist/src/presentation/web/hooks/sessions-provider.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/sessions-provider.js +57 -0
- package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-deploy-action.js +8 -54
- package/dist/src/presentation/web/lib/session-scanner.d.ts +27 -0
- package/dist/src/presentation/web/lib/session-scanner.d.ts.map +1 -0
- package/dist/src/presentation/web/lib/session-scanner.js +255 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +1 -0
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/routes-manifest.json +6 -0
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +3 -3
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
- package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
- package/web/.next/server/app/api/sessions/route.js +2 -3
- package/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/web/.next/server/app/api/sessions-batch/route/app-paths-manifest.json +3 -0
- package/web/.next/server/app/api/sessions-batch/route/build-manifest.json +11 -0
- package/web/.next/server/app/api/sessions-batch/route/server-reference-manifest.json +4 -0
- package/web/.next/server/app/api/sessions-batch/route.js +7 -0
- package/web/.next/server/app/api/sessions-batch/route.js.map +5 -0
- package/web/.next/server/app/api/sessions-batch/route.js.nft.json +1 -0
- package/web/.next/server/app/api/sessions-batch/route_client-reference-manifest.js +2 -0
- package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app-paths-manifest.json +1 -0
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_sessions-batch_route_actions_4859f283.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__0d33c29e._.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__0d33c29e._.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__2f61738a._.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__2f61738a._.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__c6e32a23._.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0b150ddf._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2138fa7e._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2138fa7e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__29580090._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__29580090._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__3ef34e4c._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +5 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c094882b._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c094882b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__dac5dbf1._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__dac5dbf1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__df7c1cd3._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__df7c1cd3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fae8b355._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fae8b355._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0c5f56e3._.js +2 -2
- package/web/.next/server/chunks/ssr/_0c5f56e3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_1b719e7f._.js +1 -1
- package/web/.next/server/chunks/ssr/_1b719e7f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_24c98f2c._.js +3 -0
- package/web/.next/server/chunks/ssr/{_b839d4f1._.js.map → _24c98f2c._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_37e8548b._.js +1 -1
- package/web/.next/server/chunks/ssr/_37e8548b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_41d9cd95._.js +4 -0
- package/web/.next/server/chunks/ssr/_41d9cd95._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_55d763e2._.js +1 -1
- package/web/.next/server/chunks/ssr/_55d763e2._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_6256a985._.js +1 -1
- package/web/.next/server/chunks/ssr/_6256a985._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_64bdfc6f._.js +2 -2
- package/web/.next/server/chunks/ssr/_64bdfc6f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_8fcc39d4._.js +1 -1
- package/web/.next/server/chunks/ssr/_8fcc39d4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_b71645b4._.js +1 -1
- package/web/.next/server/chunks/ssr/_b71645b4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_d4b20e29._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
- package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{src_presentation_web_523768ca._.js → src_presentation_web_4128a266._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_523768ca._.js.map → src_presentation_web_4128a266._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +44 -44
- package/web/.next/static/chunks/{63f412a89bde2484.js → 08a345de60f7a916.js} +1 -1
- package/web/.next/static/chunks/155eeac110efde49.js +5 -0
- package/web/.next/static/chunks/{8923825cdb21cf1c.js → 2a89bc5c539a887c.js} +1 -1
- package/web/.next/static/chunks/49057cf8cd37e262.js +1 -0
- package/web/.next/static/chunks/57489f571eaef682.js +1 -0
- package/web/.next/static/chunks/{a63c16171b149d2d.js → 76ae0ee5b19cb24d.js} +1 -1
- package/web/.next/static/chunks/{9fd5c3ecc8c5eb07.js → 79050ec2da3b1545.js} +1 -1
- package/web/.next/static/chunks/{79984461b85f1e4e.js → 82b4ce7dd487497c.js} +1 -1
- package/web/.next/static/chunks/9b8678597fa1db84.css +1 -0
- package/web/.next/static/chunks/a48d1fbd73f27a65.js +1 -0
- package/web/.next/static/chunks/{0ddea46ed4ba1621.js → b650639ad2c0225a.js} +1 -1
- package/web/.next/static/chunks/da1da0780b5c0772.js +2 -0
- package/web/.next/static/chunks/f5c613066998f4d3.js +1 -0
- package/web/.next/static/chunks/{28f5e2d65510526a.js → fbaff86b010c0bff.js} +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_ff60e4a5.js +0 -3
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_ff60e4a5.js.map +0 -1
- package/web/.next/server/chunks/[externals]__448264a3._.js +0 -3
- package/web/.next/server/chunks/ssr/_5a50254c._.js +0 -4
- package/web/.next/server/chunks/ssr/_5a50254c._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_b839d4f1._.js +0 -3
- package/web/.next/static/chunks/0539e93ac218f442.js +0 -2
- package/web/.next/static/chunks/7ab5c32984198a7e.js +0 -2
- package/web/.next/static/chunks/869ae48ca73fa328.js +0 -1
- package/web/.next/static/chunks/a0ab3aee9a5e3d02.js +0 -1
- package/web/.next/static/chunks/d61c239df26c61fd.css +0 -1
- package/web/.next/static/chunks/ebbc5dd20e227e3d.js +0 -1
- package/web/.next/static/chunks/fa556c575c788679.js +0 -1
- /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
- /package/web/.next/static/{41QsWn4e2sGnQCNBIar6W → kW82VHngwCjHeZ0IeW0ZK}/_buildManifest.js +0 -0
- /package/web/.next/static/{41QsWn4e2sGnQCNBIar6W → kW82VHngwCjHeZ0IeW0ZK}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{41QsWn4e2sGnQCNBIar6W → kW82VHngwCjHeZ0IeW0ZK}/_ssgManifest.js +0 -0
package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.stories.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachment-chip.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/attachment-chip/attachment-chip.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,
|
|
1
|
+
{"version":3,"file":"attachment-chip.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/attachment-chip/attachment-chip.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAQrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,cAAc,CAAC,CAAC;AAE7C,eAAO,MAAM,SAAS,EAAE,KAOvB,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAQhC,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,KASxC,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAOrB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAOtB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAQrB,CAAC"}
|
package/dist/src/presentation/web/components/common/attachment-chip/attachment-chip.stories.js
CHANGED
|
@@ -6,6 +6,7 @@ const meta = {
|
|
|
6
6
|
tags: ['autodocs'],
|
|
7
7
|
args: {
|
|
8
8
|
onRemove: fn(),
|
|
9
|
+
onNotesChange: fn(),
|
|
9
10
|
},
|
|
10
11
|
};
|
|
11
12
|
export default meta;
|
|
@@ -17,6 +18,25 @@ export const ImageFile = {
|
|
|
17
18
|
path: '/tmp/test/screenshot.png',
|
|
18
19
|
},
|
|
19
20
|
};
|
|
21
|
+
export const ImageFileWithNotes = {
|
|
22
|
+
args: {
|
|
23
|
+
name: 'dashboard.png',
|
|
24
|
+
size: 250000,
|
|
25
|
+
mimeType: 'image/png',
|
|
26
|
+
path: '/tmp/test/dashboard.png',
|
|
27
|
+
notes: 'This shows the main dashboard layout with the sidebar collapsed.',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
export const ImageFileWithNotesReadOnly = {
|
|
31
|
+
args: {
|
|
32
|
+
name: 'wireframe.png',
|
|
33
|
+
size: 180000,
|
|
34
|
+
mimeType: 'image/png',
|
|
35
|
+
path: '/tmp/test/wireframe.png',
|
|
36
|
+
notes: 'Navigation should match this exact layout pattern.',
|
|
37
|
+
onNotesChange: undefined,
|
|
38
|
+
},
|
|
39
|
+
};
|
|
20
40
|
export const PdfFile = {
|
|
21
41
|
args: {
|
|
22
42
|
name: 'requirements.pdf',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAK/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAK/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,wBAAwB,2CAyoB1F"}
|
package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js
CHANGED
|
@@ -201,7 +201,11 @@ export function FeatureDrawerClient({ view: initialView, urlTab }) {
|
|
|
201
201
|
setIsRejecting(true);
|
|
202
202
|
try {
|
|
203
203
|
const attachmentPaths = attachments.map((a) => a.path).filter(Boolean);
|
|
204
|
-
const
|
|
204
|
+
const notedAttachments = attachments.filter((a) => a.notes?.trim());
|
|
205
|
+
const feedbackWithNotes = notedAttachments.length > 0
|
|
206
|
+
? `${feedback}\n\nImage notes:\n${notedAttachments.map((a) => `- @${a.path}: ${a.notes.trim()}`).join('\n')}`
|
|
207
|
+
: feedback;
|
|
208
|
+
const result = await rejectFeature(featureNode.featureId, feedbackWithNotes, attachmentPaths);
|
|
205
209
|
if (!result.rejected) {
|
|
206
210
|
toast.error(result.error ?? `Failed to reject ${label.toLowerCase()}`);
|
|
207
211
|
return;
|
package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface RejectAttachment {
|
|
|
7
7
|
mimeType: string;
|
|
8
8
|
path: string;
|
|
9
9
|
loading?: boolean;
|
|
10
|
+
/** Optional user notes or annotations for this image */
|
|
11
|
+
notes?: string;
|
|
10
12
|
}
|
|
11
13
|
export interface DrawerActionBarProps {
|
|
12
14
|
/** Callback when user rejects with feedback (inline input or dialog) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer-action-bar-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,iGAAiG;AACjG,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"drawer-action-bar-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,iGAAiG;AACjG,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACvE,kCAAkC;IAClC,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,cAAc,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IACvC,mDAAmD;IACnD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,4DAA4D;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C"}
|
package/dist/src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawer-action-bar.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,oBAAoB,EAAoB,MAAM,4BAA4B,CAAC;AAmEzF,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,cAA0B,EAC1B,mBAAmB,EACnB,YAAoB,EACpB,WAAmB,EACnB,QAAQ,EACR,SAAS,EAAE,mBAAmB,EAC9B,iBAAiB,GAClB,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"drawer-action-bar.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/drawer-action-bar/drawer-action-bar.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,oBAAoB,EAAoB,MAAM,4BAA4B,CAAC;AAmEzF,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,cAA0B,EAC1B,mBAAmB,EACnB,YAAoB,EACpB,WAAmB,EACnB,QAAQ,EACR,SAAS,EAAE,mBAAmB,EAC9B,iBAAiB,GAClB,EAAE,oBAAoB,2CA0YtB"}
|
|
@@ -244,6 +244,9 @@ export function DrawerActionBar({ onReject, onApprove, approveLabel, approveVari
|
|
|
244
244
|
const handleRemoveFile = useCallback((id) => {
|
|
245
245
|
setAttachments((prev) => prev.filter((f) => f.id !== id));
|
|
246
246
|
}, []);
|
|
247
|
+
const handleNotesChange = useCallback((id, notes) => {
|
|
248
|
+
setAttachments((prev) => prev.map((f) => (f.id === id ? { ...f, notes } : f)));
|
|
249
|
+
}, []);
|
|
247
250
|
const clearForm = useCallback(() => {
|
|
248
251
|
setChatInput('');
|
|
249
252
|
setAttachments([]);
|
|
@@ -274,7 +277,7 @@ export function DrawerActionBar({ onReject, onApprove, approveLabel, approveVari
|
|
|
274
277
|
}
|
|
275
278
|
}, []);
|
|
276
279
|
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: 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
|
|
280
|
+
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, notes: file.notes, onNotesChange: (notes) => handleNotesChange(file.id, notes) }, 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
281
|
? `${accentBorder} text-white`
|
|
279
282
|
: rejectHighlighted
|
|
280
283
|
? 'border-primary bg-muted ring-primary/30 shadow-sm ring-1'
|
package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export interface FormAttachment {
|
|
|
8
8
|
mimeType: string;
|
|
9
9
|
path: string;
|
|
10
10
|
loading?: boolean;
|
|
11
|
+
/** Optional user notes or annotations for this image */
|
|
12
|
+
notes?: string;
|
|
11
13
|
}
|
|
12
14
|
/** Minimal feature descriptor for the parent selector. */
|
|
13
15
|
export interface ParentFeatureOption {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-create-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAS5E,YAAY,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAE/F,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-create-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAS5E,YAAY,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAE/F,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE;QACb,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAC;IACd,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,SAAS,EAAE,OAAO,CAAC;IACnB,uFAAuF;IACvF,WAAW,EAAE,OAAO,CAAC;IACrB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+ED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,+EAA+E;IAC/E,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAClC,kGAAkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAoB,EACpB,gBAAgB,EAChB,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,GACnB,EAAE,wBAAwB,2CAw4B1B;AAmJD,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,eAAe,EACf,QAAQ,GACT,EAAE,uBAAuB,2CAiNzB"}
|
package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js
CHANGED
|
@@ -412,6 +412,9 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
|
|
|
412
412
|
const handleRemoveFile = useCallback((id) => {
|
|
413
413
|
setAttachments((prev) => prev.filter((f) => f.id !== id));
|
|
414
414
|
}, []);
|
|
415
|
+
const handleNotesChange = useCallback((id, notes) => {
|
|
416
|
+
setAttachments((prev) => prev.map((f) => (f.id === id ? { ...f, notes } : f)));
|
|
417
|
+
}, []);
|
|
415
418
|
const formRef = useRef(null);
|
|
416
419
|
const handleKeyDown = useCallback((e) => {
|
|
417
420
|
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
|
|
@@ -441,7 +444,7 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
|
|
|
441
444
|
setLocalRepos((prev) => [...prev, repo]);
|
|
442
445
|
setSelectedRepoPath(repo.path);
|
|
443
446
|
}, disabled: isSubmitting })] })) : validRepoPath ? (_jsxs("div", { className: "flex flex-col gap-1.5", "data-testid": "repo-readonly-section", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "REPOSITORY" }), _jsx("p", { className: "text-sm", "data-testid": "repo-readonly-label", children: repositories?.find((r) => r.path === validRepoPath)?.name ??
|
|
444
|
-
validRepoPath.split('/').pop() })] })) : null, _jsxs("div", { role: "region", "aria-label": "File drop zone", "data-drag-over": isDragOver ? 'true' : 'false', onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: cn('flex flex-col gap-1.5 rounded-md border-2 border-transparent p-1 transition-colors', isDragOver && 'border-primary/50 bg-primary/5'), children: [_jsx(Label, { htmlFor: "feature-description", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "DESCRIBE YOUR FEATURE" }), _jsxs("div", { ref: promptContainerRef, onFocus: handlePromptFocus, onBlur: handlePromptBlur, className: cn('border-input flex h-56 flex-col overflow-hidden rounded-md border shadow-xs transition-[color,box-shadow]', isPromptFocused && 'ring-ring/50 border-ring ring-[3px]'), children: [_jsx(Textarea, { id: "feature-description", placeholder: "e.g. Add GitHub OAuth login with callback handling and token refresh...", value: description, onChange: (e) => setDescription(e.target.value), onPaste: handlePaste, required: true, disabled: isSubmitting, className: "min-h-0 flex-1 resize-none rounded-none border-0 shadow-none focus-visible:ring-0" }), 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: isSubmitting, 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-3 border-t px-3 py-1.5", children: [_jsx(AgentModelPicker, { initialAgentType: overrideAgent ?? currentAgentType ?? 'claude-code', initialModel: overrideModel ?? currentModel ?? 'claude-sonnet-4-6', mode: "override", onAgentModelChange: (agent, model) => {
|
|
447
|
+
validRepoPath.split('/').pop() })] })) : null, _jsxs("div", { role: "region", "aria-label": "File drop zone", "data-drag-over": isDragOver ? 'true' : 'false', onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, className: cn('flex flex-col gap-1.5 rounded-md border-2 border-transparent p-1 transition-colors', isDragOver && 'border-primary/50 bg-primary/5'), children: [_jsx(Label, { htmlFor: "feature-description", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "DESCRIBE YOUR FEATURE" }), _jsxs("div", { ref: promptContainerRef, onFocus: handlePromptFocus, onBlur: handlePromptBlur, className: cn('border-input flex h-56 flex-col overflow-hidden rounded-md border shadow-xs transition-[color,box-shadow]', isPromptFocused && 'ring-ring/50 border-ring ring-[3px]'), children: [_jsx(Textarea, { id: "feature-description", placeholder: "e.g. Add GitHub OAuth login with callback handling and token refresh...", value: description, onChange: (e) => setDescription(e.target.value), onPaste: handlePaste, required: true, disabled: isSubmitting, className: "min-h-0 flex-1 resize-none rounded-none border-0 shadow-none focus-visible:ring-0" }), 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: isSubmitting, loading: file.loading, notes: file.notes, onNotesChange: (notes) => handleNotesChange(file.id, notes) }, 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-3 border-t px-3 py-1.5", children: [_jsx(AgentModelPicker, { initialAgentType: overrideAgent ?? currentAgentType ?? 'claude-code', initialModel: overrideModel ?? currentModel ?? 'claude-sonnet-4-6', mode: "override", onAgentModelChange: (agent, model) => {
|
|
445
448
|
setOverrideAgent(agent);
|
|
446
449
|
setOverrideModel(model);
|
|
447
450
|
}, disabled: isSubmitting, className: "w-55" }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "ml-auto flex cursor-pointer items-center gap-2", children: [_jsx(Switch, { id: "pending-mode", checked: pending, onCheckedChange: setPending, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "pending-mode", className: "flex cursor-pointer items-center gap-1 text-sm font-medium", children: [_jsx(Clock, { className: "h-3.5 w-3.5" }), "Pending"] })] }) }), _jsx(TooltipContent, { side: "bottom", children: "Create without starting \u2014 start manually later." })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-2", children: [_jsx(Switch, { id: "fast-mode", checked: fast, onCheckedChange: setFast, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "fast-mode", className: "flex cursor-pointer items-center gap-1 text-sm font-medium", children: [_jsx(Zap, { className: "h-3.5 w-3.5" }), "Fast Mode"] })] }) }), _jsx(TooltipContent, { side: "bottom", children: "Skip SDLC phases and implement directly from your prompt." })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: handleAddFiles, disabled: isSubmitting, "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: "bottom", children: "Attach files" })] })] })] })] }), hasFeatures && initialParentId !== undefined ? (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "parent-feature", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "PARENT FEATURE" }), _jsx(ParentFeatureCombobox, { features: features, value: parentId, onChange: setParentId, disabled: isSubmitting })] })) : null, _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "border-input flex items-center gap-4 rounded-md border px-3 py-2.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "text-muted-foreground w-16 shrink-0 cursor-default text-xs font-semibold tracking-wider", children: "APPROVE" }) }), _jsx(TooltipContent, { side: "bottom", children: "Auto-approve phase transitions without manual review." })] }), _jsx("div", { className: "flex flex-1 items-center gap-4", children: AUTO_APPROVE_OPTIONS.map((opt) => (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: `approve-${opt.id}`, size: "sm", checked: approvalGates[opt.id] ?? false, onCheckedChange: (v) => setApprovalGates((prev) => ({ ...prev, [opt.id]: v })), disabled: isSubmitting ||
|
package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.d.ts
CHANGED
|
@@ -18,6 +18,6 @@ interface FeatureSessionsDropdownProps {
|
|
|
18
18
|
/** Callback to create a feature from a session. Only shown on repo nodes. */
|
|
19
19
|
onCreateFromSession?: (session: SessionSummary, sessionFilePath: string) => void;
|
|
20
20
|
}
|
|
21
|
-
export declare function FeatureSessionsDropdown({ repositoryPath, className,
|
|
21
|
+
export declare function FeatureSessionsDropdown({ repositoryPath, className, onCreateFromSession, }: FeatureSessionsDropdownProps): import("react/jsx-runtime").JSX.Element;
|
|
22
22
|
export {};
|
|
23
23
|
//# sourceMappingURL=feature-sessions-dropdown.d.ts.map
|
package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-sessions-dropdown.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-sessions-dropdown.tsx"],"names":[],"mappings":"AA8BA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,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,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,4BAA4B;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6EAA6E;IAC7E,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;CAClF;AAmDD,wBAAgB,uBAAuB,CAAC,EACtC,cAAc,EACd,SAAS,EACT,
|
|
1
|
+
{"version":3,"file":"feature-sessions-dropdown.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-sessions-dropdown.tsx"],"names":[],"mappings":"AA8BA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,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,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,4BAA4B;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6EAA6E;IAC7E,mBAAmB,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;CAClF;AAmDD,wBAAgB,uBAAuB,CAAC,EACtC,cAAc,EACd,SAAS,EACT,mBAAmB,GACpB,EAAE,4BAA4B,2CA6F9B"}
|
package/dist/src/presentation/web/components/common/feature-node/feature-sessions-dropdown.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useCallback
|
|
4
|
-
import { History, Copy, ExternalLink, Terminal, MessageSquare, Clock,
|
|
3
|
+
import { useState, useCallback } from 'react';
|
|
4
|
+
import { History, Copy, ExternalLink, Terminal, MessageSquare, Clock, ChevronDown, Sparkles, } from 'lucide-react';
|
|
5
5
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuPortal, } from '../../ui/dropdown-menu.js';
|
|
6
6
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip.js';
|
|
7
7
|
import { cn } from '../../../lib/utils.js';
|
|
8
8
|
import { getAgentTypeIcon } from '../../common/feature-node/agent-type-icons.js';
|
|
9
|
+
import { useSessionsContext } from '../../../hooks/sessions-provider.js';
|
|
9
10
|
const ACTIVE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
|
|
10
11
|
const PREVIEW_COUNT = 3;
|
|
11
12
|
function isSessionActive(session) {
|
|
@@ -56,88 +57,29 @@ async function copyToClipboard(text) {
|
|
|
56
57
|
function stopNodeEvent(e) {
|
|
57
58
|
e.stopPropagation();
|
|
58
59
|
}
|
|
59
|
-
export function FeatureSessionsDropdown({ repositoryPath, className,
|
|
60
|
-
const [sessions, setSessions] = useState([]);
|
|
61
|
-
const [loading, setLoading] = useState(false);
|
|
62
|
-
const [fetched, setFetched] = useState(false);
|
|
63
|
-
const [hasActiveSessions, setHasActiveSessions] = useState(false);
|
|
60
|
+
export function FeatureSessionsDropdown({ repositoryPath, className, onCreateFromSession, }) {
|
|
64
61
|
const [expanded, setExpanded] = useState(false);
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
setSessions([]);
|
|
71
|
-
setFetched(false);
|
|
72
|
-
setHasActiveSessions(false);
|
|
73
|
-
setExpanded(false);
|
|
74
|
-
}
|
|
75
|
-
}, [repositoryPath]);
|
|
76
|
-
// Fetch sessions on mount. Fast because we only scan the matching project directory.
|
|
77
|
-
// Populates count badge + active indicator, and pre-loads the dropdown.
|
|
78
|
-
useEffect(() => {
|
|
79
|
-
let cancelled = false;
|
|
80
|
-
const params = new URLSearchParams({
|
|
81
|
-
repositoryPath,
|
|
82
|
-
limit: '10',
|
|
83
|
-
...(includeWorktrees && { includeWorktrees: 'true' }),
|
|
84
|
-
});
|
|
85
|
-
fetch(`/api/sessions?${params.toString()}`)
|
|
86
|
-
.then((res) => (res.ok ? res.json() : null))
|
|
87
|
-
.then((data) => {
|
|
88
|
-
if (!cancelled && data?.sessions) {
|
|
89
|
-
setSessions(data.sessions);
|
|
90
|
-
setHasActiveSessions(data.sessions.some(isSessionActive));
|
|
91
|
-
setFetched(true);
|
|
92
|
-
}
|
|
93
|
-
})
|
|
94
|
-
.catch(() => undefined);
|
|
95
|
-
return () => {
|
|
96
|
-
cancelled = true;
|
|
97
|
-
};
|
|
98
|
-
}, [repositoryPath, includeWorktrees]);
|
|
99
|
-
// Re-fetch on dropdown open if not already loaded (e.g. path changed)
|
|
100
|
-
const doFetch = useCallback(async () => {
|
|
101
|
-
if (fetched)
|
|
102
|
-
return;
|
|
103
|
-
setLoading(true);
|
|
104
|
-
try {
|
|
105
|
-
const params = new URLSearchParams({
|
|
106
|
-
repositoryPath,
|
|
107
|
-
limit: '10',
|
|
108
|
-
...(includeWorktrees && { includeWorktrees: 'true' }),
|
|
109
|
-
});
|
|
110
|
-
const res = await fetch(`/api/sessions?${params.toString()}`);
|
|
111
|
-
if (res.ok) {
|
|
112
|
-
const data = (await res.json());
|
|
113
|
-
setSessions(data.sessions);
|
|
114
|
-
setHasActiveSessions(data.sessions.some(isSessionActive));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
// Silently fail
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
setLoading(false);
|
|
122
|
-
setFetched(true);
|
|
123
|
-
}
|
|
124
|
-
}, [repositoryPath, fetched, includeWorktrees]);
|
|
62
|
+
// Read sessions from the centralized SessionsProvider context.
|
|
63
|
+
// Sessions are batch-fetched every 30s — no per-instance HTTP calls.
|
|
64
|
+
const { getSessionsForPath, hasActiveSessions: hasActiveForPath } = useSessionsContext();
|
|
65
|
+
const sessions = getSessionsForPath(repositoryPath);
|
|
66
|
+
const active = hasActiveForPath(repositoryPath);
|
|
125
67
|
const handleOpenChange = useCallback((open) => {
|
|
126
|
-
if (open)
|
|
127
|
-
|
|
128
|
-
}, [
|
|
68
|
+
if (!open)
|
|
69
|
+
setExpanded(false);
|
|
70
|
+
}, []);
|
|
129
71
|
const visibleSessions = expanded ? sessions : sessions.slice(0, PREVIEW_COUNT);
|
|
130
72
|
const hasMore = sessions.length > PREVIEW_COUNT;
|
|
131
|
-
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', '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,
|
|
73
|
+
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', '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, active ? (_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: active ? '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, {}), 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) => {
|
|
132
74
|
e.preventDefault();
|
|
133
75
|
setExpanded((v) => !v);
|
|
134
76
|
}, children: [_jsx(ChevronDown, { className: cn('h-3 w-3 transition-transform', expanded && 'rotate-180') }), expanded ? 'Show less' : `Show ${sessions.length - PREVIEW_COUNT} more`] })) : null] }))] })] }));
|
|
135
77
|
}
|
|
136
78
|
// ── Session row component ─────────────────────────────────────────────
|
|
137
79
|
function SessionRow({ session, repositoryPath, onCreateFromSession, }) {
|
|
138
|
-
const
|
|
80
|
+
const sessionActive = isSessionActive(session);
|
|
139
81
|
const AgentIcon = getAgentTypeIcon(session.agentType);
|
|
140
|
-
return (_jsxs(DropdownMenuSub, { children: [_jsxs(DropdownMenuSubTrigger, { className: "flex items-start gap-2 py-2 pr-2", children: [_jsxs("div", { className: "relative mt-0.5 shrink-0", children: [_jsx(AgentIcon, { className: "h-4 w-4" }),
|
|
82
|
+
return (_jsxs(DropdownMenuSub, { children: [_jsxs(DropdownMenuSubTrigger, { className: "flex items-start gap-2 py-2 pr-2", children: [_jsxs("div", { className: "relative mt-0.5 shrink-0", children: [_jsx(AgentIcon, { className: "h-4 w-4" }), sessionActive ? (_jsx("span", { className: "border-background absolute -right-0.5 -bottom-0.5 h-2 w-2 rounded-full border bg-emerald-500" })) : null] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [_jsx("span", { className: "truncate text-xs leading-tight", children: truncatePreview(session.preview) }), _jsxs("div", { className: "text-muted-foreground flex items-center gap-2 text-[10px] leading-tight", children: [_jsxs("span", { className: "flex items-center gap-0.5", children: [_jsx(MessageSquare, { className: "h-2.5 w-2.5" }), session.messageCount] }), session.firstMessageAt ? (_jsxs("span", { className: "flex items-center gap-0.5", children: [_jsx(Clock, { className: "h-2.5 w-2.5" }), new Date(session.firstMessageAt).toLocaleDateString()] })) : null, session.lastMessageAt ? (_jsx("span", { className: cn('ml-auto shrink-0', sessionActive ? 'font-medium text-emerald-600' : ''), children: formatRelativeTime(session.lastMessageAt) })) : null] })] })] }), _jsx(DropdownMenuPortal, { children: _jsxs(DropdownMenuSubContent, { onClick: stopNodeEvent, onPointerDown: stopNodeEvent, children: [_jsxs(DropdownMenuItem, { className: "gap-2 text-xs", onClick: () => void copyToClipboard(`claude --resume ${session.id} --project ${repositoryPath}`), children: [_jsx(Terminal, { className: "h-3.5 w-3.5" }), "Copy resume command"] }), _jsxs(DropdownMenuItem, { className: "gap-2 text-xs", onClick: () => void copyToClipboard(session.id), children: [_jsx(Copy, { className: "h-3.5 w-3.5" }), "Copy session ID"] }), _jsxs(DropdownMenuItem, { className: "gap-2 text-xs", onClick: () => {
|
|
141
83
|
const vscodeUri = `vscode://file${repositoryPath}`;
|
|
142
84
|
window.open(vscodeUri, '_blank');
|
|
143
85
|
}, children: [_jsx(ExternalLink, { className: "h-3.5 w-3.5" }), "Open in IDE"] }), onCreateFromSession && session.filePath ? (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { className: "gap-2 text-xs font-medium text-violet-700 focus:bg-violet-50 focus:text-violet-800", onClick: () => onCreateFromSession(session, session.filePath), children: [_jsx(Sparkles, { className: "h-3.5 w-3.5 text-violet-500" }), "Create feature from session"] })] })) : null] }) })] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-sessions-dropdown.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-sessions-dropdown.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-sessions-dropdown.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-sessions-dropdown.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAsEtE,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,uBAAuB,CAM9C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAEtD,eAAO,MAAM,YAAY,EAAE,KAE1B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,KAEhC,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { FeatureSessionsDropdown } from './feature-sessions-dropdown.js';
|
|
3
|
+
import { SessionsProvider } from '../../../hooks/sessions-provider.js';
|
|
4
|
+
const REPO_PATH = '/home/user/workspaces/my-project';
|
|
3
5
|
const mockSessions = [
|
|
4
6
|
{
|
|
5
7
|
id: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
|
|
@@ -8,7 +10,7 @@ const mockSessions = [
|
|
|
8
10
|
firstMessageAt: new Date(Date.now() - 3_600_000).toISOString(),
|
|
9
11
|
lastMessageAt: new Date(Date.now() - 1_800_000).toISOString(),
|
|
10
12
|
createdAt: new Date(Date.now() - 3_600_000).toISOString(),
|
|
11
|
-
projectPath:
|
|
13
|
+
projectPath: REPO_PATH,
|
|
12
14
|
},
|
|
13
15
|
{
|
|
14
16
|
id: 'b2c3d4e5-f6a7-8901-bcde-f12345678901',
|
|
@@ -17,7 +19,7 @@ const mockSessions = [
|
|
|
17
19
|
firstMessageAt: new Date(Date.now() - 86_400_000).toISOString(),
|
|
18
20
|
lastMessageAt: new Date(Date.now() - 82_800_000).toISOString(),
|
|
19
21
|
createdAt: new Date(Date.now() - 86_400_000).toISOString(),
|
|
20
|
-
projectPath:
|
|
22
|
+
projectPath: REPO_PATH,
|
|
21
23
|
},
|
|
22
24
|
{
|
|
23
25
|
id: 'c3d4e5f6-a7b8-9012-cdef-123456789012',
|
|
@@ -26,7 +28,7 @@ const mockSessions = [
|
|
|
26
28
|
firstMessageAt: new Date(Date.now() - 172_800_000).toISOString(),
|
|
27
29
|
lastMessageAt: new Date(Date.now() - 169_200_000).toISOString(),
|
|
28
30
|
createdAt: new Date(Date.now() - 172_800_000).toISOString(),
|
|
29
|
-
projectPath:
|
|
31
|
+
projectPath: REPO_PATH,
|
|
30
32
|
},
|
|
31
33
|
];
|
|
32
34
|
const mockActiveSession = {
|
|
@@ -36,42 +38,41 @@ const mockActiveSession = {
|
|
|
36
38
|
firstMessageAt: new Date(Date.now() - 180_000).toISOString(),
|
|
37
39
|
lastMessageAt: new Date(Date.now() - 60_000).toISOString(), // 1 min ago — active
|
|
38
40
|
createdAt: new Date(Date.now() - 180_000).toISOString(),
|
|
39
|
-
projectPath:
|
|
41
|
+
projectPath: REPO_PATH,
|
|
40
42
|
};
|
|
41
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Mock fetch for /api/sessions-batch, then wrap with SessionsProvider.
|
|
45
|
+
*/
|
|
46
|
+
function createSessionsMock(sessions) {
|
|
42
47
|
return (Story) => {
|
|
43
48
|
const originalFetch = window.fetch;
|
|
44
49
|
window.fetch = (async (input, init) => {
|
|
45
50
|
const url = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
|
|
46
|
-
if (url.includes('/api/sessions')) {
|
|
47
|
-
return new Response(JSON.stringify({ sessions }), {
|
|
51
|
+
if (url.includes('/api/sessions-batch')) {
|
|
52
|
+
return new Response(JSON.stringify({ sessionsByPath: sessions }), {
|
|
48
53
|
status: 200,
|
|
49
54
|
headers: { 'Content-Type': 'application/json' },
|
|
50
55
|
});
|
|
51
56
|
}
|
|
52
57
|
return originalFetch(input, init);
|
|
53
58
|
});
|
|
54
|
-
return _jsx(Story, {});
|
|
59
|
+
return (_jsx(SessionsProvider, { children: _jsx(Story, {}) }));
|
|
55
60
|
};
|
|
56
61
|
}
|
|
57
62
|
const meta = {
|
|
58
63
|
title: 'Composed/FeatureSessionsDropdown',
|
|
59
64
|
component: FeatureSessionsDropdown,
|
|
60
65
|
tags: ['autodocs'],
|
|
61
|
-
parameters: {
|
|
62
|
-
|
|
63
|
-
},
|
|
64
|
-
args: {
|
|
65
|
-
repositoryPath: '/home/user/workspaces/my-project',
|
|
66
|
-
},
|
|
66
|
+
parameters: { layout: 'centered' },
|
|
67
|
+
args: { repositoryPath: REPO_PATH },
|
|
67
68
|
};
|
|
68
69
|
export default meta;
|
|
69
70
|
export const WithSessions = {
|
|
70
|
-
decorators: [
|
|
71
|
+
decorators: [createSessionsMock({ [REPO_PATH]: mockSessions })],
|
|
71
72
|
};
|
|
72
73
|
export const WithActiveSessions = {
|
|
73
|
-
decorators: [
|
|
74
|
+
decorators: [createSessionsMock({ [REPO_PATH]: [mockActiveSession, ...mockSessions] })],
|
|
74
75
|
};
|
|
75
76
|
export const Empty = {
|
|
76
|
-
decorators: [
|
|
77
|
+
decorators: [createSessionsMock({ [REPO_PATH]: [] })],
|
|
77
78
|
};
|
package/dist/src/presentation/web/components/features/control-center/control-center.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-center.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;
|
|
1
|
+
{"version":3,"file":"control-center.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAI5E,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;IACrB,kEAAkE;IAClE,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,kBAAkB,2CAWvF"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { ReactFlowProvider } from '@xyflow/react';
|
|
4
|
+
import { SessionsProvider } from '../../../hooks/sessions-provider.js';
|
|
4
5
|
import { ControlCenterInner } from './control-center-inner.js';
|
|
5
6
|
export function ControlCenter({ initialNodes, initialEdges, drawer }) {
|
|
6
|
-
return (_jsxs("div", { "data-testid": "control-center", className: "h-full w-full", children: [_jsx(ReactFlowProvider, { children: _jsx(ControlCenterInner, { initialNodes: initialNodes, initialEdges: initialEdges }) }), _jsx("div", { children: drawer }, "drawer")] }));
|
|
7
|
+
return (_jsxs("div", { "data-testid": "control-center", className: "h-full w-full", children: [_jsx(SessionsProvider, { children: _jsx(ReactFlowProvider, { children: _jsx(ControlCenterInner, { initialNodes: initialNodes, initialEdges: initialEdges }) }) }), _jsx("div", { children: drawer }, "drawer")] }));
|
|
7
8
|
}
|
|
@@ -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,
|
|
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"}
|
package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js
CHANGED
|
@@ -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 =
|
|
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())
|
|
@@ -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,
|
|
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"}
|