@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
|
@@ -27,34 +27,9 @@ export function useDeployAction(input) {
|
|
|
27
27
|
mountedRef.current = false;
|
|
28
28
|
};
|
|
29
29
|
}, []);
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
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 removed — getGraphData() 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 —
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
+
}
|