@shepai/cli 1.53.2 → 1.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -8
- package/apis/json-schema/NotificationEvent.yaml +4 -0
- package/dist/packages/core/src/application/ports/output/services/daemon-service.interface.d.ts +49 -0
- package/dist/packages/core/src/application/ports/output/services/daemon-service.interface.d.ts.map +1 -0
- package/dist/packages/core/src/application/ports/output/services/daemon-service.interface.js +7 -0
- package/dist/packages/core/src/application/ports/output/services/index.d.ts +1 -0
- package/dist/packages/core/src/application/ports/output/services/index.d.ts.map +1 -1
- 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/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +2 -0
- package/dist/packages/core/src/infrastructure/services/browser-opener.service.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/services/browser-opener.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/browser-opener.service.js +4 -0
- package/dist/packages/core/src/infrastructure/services/daemon/daemon-pid.service.d.ts +16 -0
- package/dist/packages/core/src/infrastructure/services/daemon/daemon-pid.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/daemon/daemon-pid.service.js +72 -0
- package/dist/packages/core/src/infrastructure/services/filesystem/shep-directory.service.d.ts +7 -0
- package/dist/packages/core/src/infrastructure/services/filesystem/shep-directory.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/filesystem/shep-directory.service.js +9 -0
- package/dist/packages/core/src/infrastructure/services/notifications/notification-bus.d.ts +4 -0
- package/dist/packages/core/src/infrastructure/services/notifications/notification-bus.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/notifications/notification-bus.js +19 -6
- package/dist/packages/core/src/infrastructure/services/notifications/notification-watcher.service.d.ts +5 -3
- package/dist/packages/core/src/infrastructure/services/notifications/notification-watcher.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/notifications/notification-watcher.service.js +21 -13
- package/dist/src/presentation/cli/commands/_serve.command.d.ts +32 -0
- package/dist/src/presentation/cli/commands/_serve.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/_serve.command.js +91 -0
- package/dist/src/presentation/cli/commands/daemon/start-daemon.d.ts +27 -0
- package/dist/src/presentation/cli/commands/daemon/start-daemon.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/daemon/start-daemon.js +135 -0
- package/dist/src/presentation/cli/commands/start.command.d.ts +15 -0
- package/dist/src/presentation/cli/commands/start.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/start.command.js +33 -0
- package/dist/src/presentation/cli/commands/status.command.d.ts +20 -0
- package/dist/src/presentation/cli/commands/status.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/status.command.js +119 -0
- package/dist/src/presentation/cli/commands/stop.command.d.ts +22 -0
- package/dist/src/presentation/cli/commands/stop.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/stop.command.js +79 -0
- package/dist/src/presentation/cli/commands/ui.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/ui.command.js +2 -1
- package/dist/src/presentation/cli/index.d.ts +5 -2
- package/dist/src/presentation/cli/index.d.ts.map +1 -1
- package/dist/src/presentation/cli/index.js +23 -4
- package/dist/src/presentation/web/app/api/agent-events/health/route.d.ts +13 -0
- package/dist/src/presentation/web/app/api/agent-events/health/route.d.ts.map +1 -0
- package/dist/src/presentation/web/app/api/agent-events/health/route.js +60 -0
- package/dist/src/presentation/web/app/api/agent-events/route.d.ts +8 -4
- package/dist/src/presentation/web/app/api/agent-events/route.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/agent-events/route.js +227 -55
- package/dist/src/presentation/web/app/layout.d.ts.map +1 -1
- package/dist/src/presentation/web/app/layout.js +14 -0
- package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts +5 -1
- package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.js +29 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node.js +1 -1
- package/dist/src/presentation/web/components/common/sound-toggle/index.d.ts +2 -0
- package/dist/src/presentation/web/components/common/sound-toggle/index.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/sound-toggle/index.js +1 -0
- package/dist/src/presentation/web/components/common/sound-toggle/sound-toggle.d.ts +2 -0
- package/dist/src/presentation/web/components/common/sound-toggle/sound-toggle.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/sound-toggle/sound-toggle.js +9 -0
- package/dist/src/presentation/web/components/common/sound-toggle/sound-toggle.stories.d.ts +8 -0
- package/dist/src/presentation/web/components/common/sound-toggle/sound-toggle.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/sound-toggle/sound-toggle.stories.js +17 -0
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +14 -2
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +1 -0
- 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 +151 -19
- package/dist/src/presentation/web/components/layouts/app-shell/app-shell.d.ts.map +1 -1
- package/dist/src/presentation/web/components/layouts/app-shell/app-shell.js +2 -1
- package/dist/src/presentation/web/dev-server.js +14 -0
- package/dist/src/presentation/web/hooks/use-agent-events.d.ts +7 -0
- package/dist/src/presentation/web/hooks/use-agent-events.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-agent-events.js +135 -47
- package/dist/src/presentation/web/hooks/use-notifications.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-notifications.js +56 -16
- package/dist/src/presentation/web/hooks/use-notifications.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-notifications.stories.js +28 -9
- package/dist/src/presentation/web/hooks/use-sound-enabled.d.ts +6 -0
- package/dist/src/presentation/web/hooks/use-sound-enabled.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/use-sound-enabled.js +27 -0
- package/dist/src/presentation/web/hooks/use-sound.d.ts +15 -0
- package/dist/src/presentation/web/hooks/use-sound.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/use-sound.js +83 -0
- package/dist/src/presentation/web/hooks/use-sound.stories.d.ts +8 -0
- package/dist/src/presentation/web/hooks/use-sound.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/hooks/use-sound.stories.js +67 -0
- package/dist/src/presentation/web/public/agent-events-sw.d.ts +35 -0
- package/dist/src/presentation/web/public/agent-events-sw.d.ts.map +1 -0
- package/dist/src/presentation/web/public/agent-events-sw.js +140 -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/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/.tsbuildinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/routes-manifest.json +6 -0
- 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.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/agent-events/health/route/app-paths-manifest.json +3 -0
- package/web/.next/server/app/api/agent-events/health/route/build-manifest.json +11 -0
- package/web/.next/server/app/api/agent-events/health/route/server-reference-manifest.json +4 -0
- package/web/.next/server/app/api/agent-events/health/route.js +6 -0
- package/web/.next/server/app/api/agent-events/health/route.js.map +5 -0
- package/web/.next/server/app/api/agent-events/health/route.js.nft.json +1 -0
- package/web/.next/server/app/api/agent-events/health/route_client-reference-manifest.js +2 -0
- package/web/.next/server/app/api/agent-events/route.js +2 -1
- package/web/.next/server/app/api/agent-events/route.js.nft.json +1 -1
- package/web/.next/server/app/page/server-reference-manifest.json +14 -14
- package/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page.js +1 -1
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- 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 +6 -0
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -0
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_agent-events_health_route_actions_4d471160.js +3 -0
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_agent-events_health_route_actions_4d471160.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__3b22a1eb._.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__3b22a1eb._.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__d9d410a8._.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__d9d410a8._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js.map +1 -1
- package/web/.next/{standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js → server/chunks/ssr/[root-of-the-server]__6e8b5181._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_1fafa9db._.js → _1632a21f._.js} +2 -2
- package/web/.next/server/chunks/ssr/_1632a21f._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js.map +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_ed0934e5._.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 +15 -15
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/src/presentation/web/.next/app-path-routes-manifest.json +1 -0
- package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/routes-manifest.json +6 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/health/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/health/route/build-manifest.json +11 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/health/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/health/route.js +6 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/health/route.js.map +5 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/health/route.js.nft.json +1 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/health/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/route.js +2 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/agent-events/route.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +14 -14
- package/web/.next/standalone/src/presentation/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app-paths-manifest.json +1 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +6 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/744ca_web__next-internal_server_app_api_agent-events_health_route_actions_4d471160.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__3b22a1eb._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__d9d410a8._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__2d1a8e37._.js +2 -2
- package/web/.next/{server/chunks/ssr/[root-of-the-server]__249c74f6._.js → standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6e8b5181._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_1fafa9db._.js → _1632a21f._.js} +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +15 -15
- package/web/.next/standalone/src/presentation/web/app/api/agent-events/health/route.ts +69 -0
- package/web/.next/standalone/src/presentation/web/app/api/agent-events/route.ts +258 -54
- package/web/.next/standalone/src/presentation/web/app/layout.tsx +14 -0
- package/web/.next/standalone/src/presentation/web/components/common/feature-node/derive-feature-state.ts +39 -2
- package/web/.next/standalone/src/presentation/web/components/common/repository-node/repository-node.tsx +1 -0
- package/web/.next/standalone/src/presentation/web/components/common/sound-toggle/index.ts +1 -0
- package/web/.next/standalone/src/presentation/web/components/common/sound-toggle/sound-toggle.stories.tsx +27 -0
- package/web/.next/standalone/src/presentation/web/components/common/sound-toggle/sound-toggle.tsx +21 -0
- package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +15 -1
- package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +194 -31
- package/web/.next/standalone/src/presentation/web/components/layouts/app-shell/app-shell.tsx +3 -1
- package/web/.next/standalone/src/presentation/web/dev-server.ts +21 -0
- package/web/.next/standalone/src/presentation/web/hooks/use-agent-events.ts +161 -52
- package/web/.next/standalone/src/presentation/web/hooks/use-notifications.stories.tsx +39 -10
- package/web/.next/standalone/src/presentation/web/hooks/use-notifications.ts +68 -15
- package/web/.next/standalone/src/presentation/web/hooks/use-sound-enabled.ts +38 -0
- package/web/.next/standalone/src/presentation/web/hooks/use-sound.stories.tsx +109 -0
- package/web/.next/standalone/src/presentation/web/hooks/use-sound.ts +101 -0
- package/web/.next/standalone/src/presentation/web/public/agent-events-sw.js +164 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/button.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/caution.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/celebration.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/disabled.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/notification.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/progress_loop.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/ringtone_loop.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/select.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/swipe.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/swipe_01.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/swipe_02.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/swipe_03.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/swipe_04.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/swipe_05.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/tap_01.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/tap_02.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/tap_03.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/tap_04.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/tap_05.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/toggle_off.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/toggle_on.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/transition_down.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/transition_up.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/type_01.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/type_02.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/type_03.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/type_04.wav +0 -0
- package/web/.next/standalone/src/presentation/web/public/sounds/type_05.wav +0 -0
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/1f13bc20e938335c.css +2 -0
- package/web/.next/static/chunks/3eaa6f2966e27b8f.js +10 -0
- package/web/.next/static/chunks/{68fb91b6eca14536.js → 8f4461aee9a05741.js} +2 -2
- package/web/.next/static/chunks/9a82d8c76f175235.js +1 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/web/.next/types/link.d.ts +1 -0
- package/web/.next/types/routes.d.ts +2 -1
- package/web/.next/types/validator.ts +9 -0
- package/web/public/agent-events-sw.js +164 -0
- package/web/public/sounds/button.wav +0 -0
- package/web/public/sounds/caution.wav +0 -0
- package/web/public/sounds/celebration.wav +0 -0
- package/web/public/sounds/disabled.wav +0 -0
- package/web/public/sounds/notification.wav +0 -0
- package/web/public/sounds/progress_loop.wav +0 -0
- package/web/public/sounds/ringtone_loop.wav +0 -0
- package/web/public/sounds/select.wav +0 -0
- package/web/public/sounds/swipe.wav +0 -0
- package/web/public/sounds/swipe_01.wav +0 -0
- package/web/public/sounds/swipe_02.wav +0 -0
- package/web/public/sounds/swipe_03.wav +0 -0
- package/web/public/sounds/swipe_04.wav +0 -0
- package/web/public/sounds/swipe_05.wav +0 -0
- package/web/public/sounds/tap_01.wav +0 -0
- package/web/public/sounds/tap_02.wav +0 -0
- package/web/public/sounds/tap_03.wav +0 -0
- package/web/public/sounds/tap_04.wav +0 -0
- package/web/public/sounds/tap_05.wav +0 -0
- package/web/public/sounds/toggle_off.wav +0 -0
- package/web/public/sounds/toggle_on.wav +0 -0
- package/web/public/sounds/transition_down.wav +0 -0
- package/web/public/sounds/transition_up.wav +0 -0
- package/web/public/sounds/type_01.wav +0 -0
- package/web/public/sounds/type_02.wav +0 -0
- package/web/public/sounds/type_03.wav +0 -0
- package/web/public/sounds/type_04.wav +0 -0
- package/web/public/sounds/type_05.wav +0 -0
- package/web/.next/server/chunks/[root-of-the-server]__7d5c8b74._.js +0 -6
- package/web/.next/server/chunks/[root-of-the-server]__7d5c8b74._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_1fafa9db._.js.map +0 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__7d5c8b74._.js +0 -6
- package/web/.next/static/chunks/13d5334b17480a16.js +0 -10
- package/web/.next/static/chunks/16dec8021e251230.css +0 -2
- package/web/.next/static/chunks/22f30ce91a3c79c1.js +0 -1
- /package/web/.next/server/chunks/ssr/{[root-of-the-server]__249c74f6._.js.map → [root-of-the-server]__6e8b5181._.js.map} +0 -0
- /package/web/.next/static/{nFvWyY2BF3AIS3FpZBKEb → JmDtIt3S6EfLuRKwlzJrW}/_buildManifest.js +0 -0
- /package/web/.next/static/{nFvWyY2BF3AIS3FpZBKEb → JmDtIt3S6EfLuRKwlzJrW}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{nFvWyY2BF3AIS3FpZBKEb → JmDtIt3S6EfLuRKwlzJrW}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stop Command
|
|
3
|
+
*
|
|
4
|
+
* Stops the running Shep web UI daemon.
|
|
5
|
+
*
|
|
6
|
+
* Stop sequence:
|
|
7
|
+
* 1. Read daemon.json via IDaemonService
|
|
8
|
+
* 2. If no daemon / PID not alive: print clear message and exit 0
|
|
9
|
+
* 3. Validate PID is a positive finite integer
|
|
10
|
+
* 4. Send SIGTERM
|
|
11
|
+
* 5. Poll process liveness every 200ms for up to 5000ms
|
|
12
|
+
* 6. If still alive after 5s, send SIGKILL
|
|
13
|
+
* 7. Always delete daemon.json (in finally block)
|
|
14
|
+
*
|
|
15
|
+
* Usage: shep stop
|
|
16
|
+
*/
|
|
17
|
+
import { Command } from 'commander';
|
|
18
|
+
import { container } from '../../../../packages/core/src/infrastructure/di/container.js';
|
|
19
|
+
import { messages } from '../ui/index.js';
|
|
20
|
+
const POLL_INTERVAL_MS = 200;
|
|
21
|
+
const MAX_WAIT_MS = 5000;
|
|
22
|
+
/**
|
|
23
|
+
* Poll until the given PID is dead or the timeout expires.
|
|
24
|
+
* Returns true if the process is dead, false if it survived the timeout.
|
|
25
|
+
*/
|
|
26
|
+
async function pollUntilDead(daemonService, pid, maxMs, intervalMs) {
|
|
27
|
+
const deadline = Date.now() + maxMs;
|
|
28
|
+
while (Date.now() < deadline) {
|
|
29
|
+
await new Promise((resolve) => setTimeout(resolve, intervalMs));
|
|
30
|
+
if (!daemonService.isAlive(pid)) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create the stop command.
|
|
38
|
+
*/
|
|
39
|
+
export function createStopCommand() {
|
|
40
|
+
return new Command('stop').description('Stop the running Shep web UI daemon').action(async () => {
|
|
41
|
+
const daemonService = container.resolve('IDaemonService');
|
|
42
|
+
const state = await daemonService.read();
|
|
43
|
+
// No daemon running or PID not alive
|
|
44
|
+
if (!state || !daemonService.isAlive(state.pid)) {
|
|
45
|
+
messages.info('No Shep daemon is running.');
|
|
46
|
+
await daemonService.delete();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const { pid } = state;
|
|
50
|
+
// Validate PID is a positive finite integer before kill
|
|
51
|
+
if (!Number.isFinite(pid) || !Number.isInteger(pid) || pid <= 0) {
|
|
52
|
+
messages.info('No Shep daemon is running (invalid PID in state file).');
|
|
53
|
+
await daemonService.delete();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
messages.info(`Stopping Shep daemon (PID ${pid})...`);
|
|
58
|
+
// Send SIGTERM — request graceful shutdown
|
|
59
|
+
process.kill(pid, 'SIGTERM');
|
|
60
|
+
// Poll for up to 5s waiting for the process to exit
|
|
61
|
+
const died = await pollUntilDead(daemonService, pid, MAX_WAIT_MS, POLL_INTERVAL_MS);
|
|
62
|
+
if (!died) {
|
|
63
|
+
// Graceful shutdown timed out — force kill
|
|
64
|
+
messages.info('Daemon did not stop gracefully, sending SIGKILL...');
|
|
65
|
+
try {
|
|
66
|
+
process.kill(pid, 'SIGKILL');
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Process may have exited between the check and the kill — ignore
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
messages.success('Shep daemon stopped.');
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
// Always clean up daemon.json regardless of termination path
|
|
76
|
+
await daemonService.delete();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/ui.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ui.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/ui.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;AA0B1D;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CA4EzC"}
|
|
@@ -59,8 +59,9 @@ Examples:
|
|
|
59
59
|
// Start notification watcher to detect agent status transitions
|
|
60
60
|
const runRepo = container.resolve('IAgentRunRepository');
|
|
61
61
|
const phaseTimingRepo = container.resolve('IPhaseTimingRepository');
|
|
62
|
+
const featureRepo = container.resolve('IFeatureRepository');
|
|
62
63
|
const notificationService = container.resolve('INotificationService');
|
|
63
|
-
initializeNotificationWatcher(runRepo, phaseTimingRepo, notificationService);
|
|
64
|
+
initializeNotificationWatcher(runRepo, phaseTimingRepo, featureRepo, notificationService);
|
|
64
65
|
getNotificationWatcher().start();
|
|
65
66
|
const url = `http://localhost:${port}`;
|
|
66
67
|
messages.success(`Server ready at ${fmt.code(url)}`);
|
|
@@ -8,9 +8,12 @@
|
|
|
8
8
|
* shep [command] [options]
|
|
9
9
|
*
|
|
10
10
|
* Commands:
|
|
11
|
-
* shep
|
|
11
|
+
* shep Start the web UI daemon (or run onboarding on first run)
|
|
12
|
+
* shep start Start the web UI as a background daemon
|
|
13
|
+
* shep stop Stop the running web UI daemon
|
|
14
|
+
* shep status Show status and metrics of the running daemon
|
|
12
15
|
* shep version Display version information
|
|
13
|
-
* shep ui Start the web UI
|
|
16
|
+
* shep ui Start the web UI (foreground, interactive)
|
|
14
17
|
* shep run Run an AI agent workflow
|
|
15
18
|
* shep agent Manage and view agent runs
|
|
16
19
|
* shep feat Manage features through the SDLC lifecycle
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/cli/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/cli/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,kBAAkB,CAAC"}
|
|
@@ -8,9 +8,12 @@
|
|
|
8
8
|
* shep [command] [options]
|
|
9
9
|
*
|
|
10
10
|
* Commands:
|
|
11
|
-
* shep
|
|
11
|
+
* shep Start the web UI daemon (or run onboarding on first run)
|
|
12
|
+
* shep start Start the web UI as a background daemon
|
|
13
|
+
* shep stop Stop the running web UI daemon
|
|
14
|
+
* shep status Show status and metrics of the running daemon
|
|
12
15
|
* shep version Display version information
|
|
13
|
-
* shep ui Start the web UI
|
|
16
|
+
* shep ui Start the web UI (foreground, interactive)
|
|
14
17
|
* shep run Run an AI agent workflow
|
|
15
18
|
* shep agent Manage and view agent runs
|
|
16
19
|
* shep feat Manage features through the SDLC lifecycle
|
|
@@ -38,6 +41,12 @@ import { createIdeOpenCommand } from './commands/ide-open.command.js';
|
|
|
38
41
|
import { createInstallCommand } from './commands/install.command.js';
|
|
39
42
|
import { createUpgradeCommand } from './commands/upgrade.command.js';
|
|
40
43
|
import { messages } from './ui/index.js';
|
|
44
|
+
// Daemon lifecycle commands
|
|
45
|
+
import { createStartCommand } from './commands/start.command.js';
|
|
46
|
+
import { createStopCommand } from './commands/stop.command.js';
|
|
47
|
+
import { createStatusCommand } from './commands/status.command.js';
|
|
48
|
+
import { createServeCommand } from './commands/_serve.command.js';
|
|
49
|
+
import { startDaemon } from './commands/daemon/start-daemon.js';
|
|
41
50
|
// DI container and settings
|
|
42
51
|
import { initializeContainer, container } from '../../../packages/core/src/infrastructure/di/container.js';
|
|
43
52
|
import { InitializeSettingsUseCase } from '../../../packages/core/src/application/use-cases/settings/initialize-settings.use-case.js';
|
|
@@ -88,8 +97,13 @@ async function bootstrap() {
|
|
|
88
97
|
.name('shep')
|
|
89
98
|
.description(description)
|
|
90
99
|
.version(version, '-v, --version', 'Display version number')
|
|
91
|
-
|
|
92
|
-
|
|
100
|
+
// task-10: Default action starts the daemon (or shows already-running URL).
|
|
101
|
+
// The onboarding gate above (lines 82-89) ensures the wizard runs on first launch;
|
|
102
|
+
// after the gate, startDaemon() is the correct next step in both cases.
|
|
103
|
+
// Commander only fires this action when no subcommand matches, so `shep start` etc.
|
|
104
|
+
// are unaffected.
|
|
105
|
+
.action(async () => {
|
|
106
|
+
await startDaemon();
|
|
93
107
|
});
|
|
94
108
|
// Register commands
|
|
95
109
|
program.addCommand(createVersionCommand());
|
|
@@ -103,6 +117,11 @@ async function bootstrap() {
|
|
|
103
117
|
program.addCommand(createIdeOpenCommand());
|
|
104
118
|
program.addCommand(createInstallCommand());
|
|
105
119
|
program.addCommand(createUpgradeCommand());
|
|
120
|
+
// Daemon lifecycle commands (task-9)
|
|
121
|
+
program.addCommand(createStartCommand());
|
|
122
|
+
program.addCommand(createStopCommand());
|
|
123
|
+
program.addCommand(createStatusCommand());
|
|
124
|
+
program.addCommand(createServeCommand()); // hidden from --help
|
|
106
125
|
// Parse arguments (parseAsync needed for async command actions like init)
|
|
107
126
|
await program.parseAsync();
|
|
108
127
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE Health Check: GET /api/agent-events/health
|
|
3
|
+
*
|
|
4
|
+
* Diagnostic endpoint that verifies the SSE pipeline prerequisites:
|
|
5
|
+
* - DI container is accessible from API routes
|
|
6
|
+
* - Feature listing works
|
|
7
|
+
* - Agent run repository works
|
|
8
|
+
*
|
|
9
|
+
* Use this in the browser to verify the SSE system is functional.
|
|
10
|
+
*/
|
|
11
|
+
export declare const dynamic = "force-dynamic";
|
|
12
|
+
export declare function GET(): Promise<Response>;
|
|
13
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/agent-events/health/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAEvC,wBAAsB,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAmD7C"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSE Health Check: GET /api/agent-events/health
|
|
3
|
+
*
|
|
4
|
+
* Diagnostic endpoint that verifies the SSE pipeline prerequisites:
|
|
5
|
+
* - DI container is accessible from API routes
|
|
6
|
+
* - Feature listing works
|
|
7
|
+
* - Agent run repository works
|
|
8
|
+
*
|
|
9
|
+
* Use this in the browser to verify the SSE system is functional.
|
|
10
|
+
*/
|
|
11
|
+
import { resolve } from '../../../../lib/server-container.js';
|
|
12
|
+
export const dynamic = 'force-dynamic';
|
|
13
|
+
export async function GET() {
|
|
14
|
+
const checks = {};
|
|
15
|
+
// Check 1: DI container accessible
|
|
16
|
+
try {
|
|
17
|
+
resolve('ListFeaturesUseCase');
|
|
18
|
+
checks.container = { ok: true };
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
checks.container = {
|
|
22
|
+
ok: false,
|
|
23
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Check 2: Feature listing works
|
|
27
|
+
try {
|
|
28
|
+
const listFeatures = resolve('ListFeaturesUseCase');
|
|
29
|
+
const features = await listFeatures.execute();
|
|
30
|
+
const withRuns = features.filter((f) => f.agentRunId).length;
|
|
31
|
+
checks.features = {
|
|
32
|
+
ok: true,
|
|
33
|
+
detail: `${features.length} features (${withRuns} with agent runs)`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
checks.features = {
|
|
38
|
+
ok: false,
|
|
39
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Check 3: Agent run repository works
|
|
43
|
+
try {
|
|
44
|
+
const agentRunRepo = resolve('IAgentRunRepository');
|
|
45
|
+
const runs = await agentRunRepo.list();
|
|
46
|
+
const active = runs.filter((r) => r.status === 'running' || r.status === 'pending' || r.status === 'waiting_approval').length;
|
|
47
|
+
checks.agentRuns = {
|
|
48
|
+
ok: true,
|
|
49
|
+
detail: `${runs.length} runs (${active} active)`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
checks.agentRuns = {
|
|
54
|
+
ok: false,
|
|
55
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const allOk = Object.values(checks).every((c) => c.ok);
|
|
59
|
+
return Response.json({ ok: allOk, checks }, { status: allOk ? 200 : 503 });
|
|
60
|
+
}
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
* SSE API Route: GET /api/agent-events
|
|
3
3
|
*
|
|
4
4
|
* Streams agent lifecycle notification events to connected web UI clients
|
|
5
|
-
* via Server-Sent Events (SSE).
|
|
5
|
+
* via Server-Sent Events (SSE).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* -
|
|
7
|
+
* Uses DB polling with a per-connection cache so only deltas are sent.
|
|
8
|
+
* This avoids cross-module singleton issues with an in-process event bus.
|
|
9
|
+
*
|
|
10
|
+
* - Polls features + agent runs every 500ms
|
|
11
|
+
* - Compares against cached state and emits only changes
|
|
9
12
|
* - Sends heartbeat comments every 30 seconds to keep connection alive
|
|
10
13
|
* - Supports optional ?runId query parameter to filter events
|
|
11
|
-
* - Cleans up
|
|
14
|
+
* - Cleans up intervals on client disconnect
|
|
12
15
|
*/
|
|
16
|
+
export declare const dynamic = "force-dynamic";
|
|
13
17
|
export declare function GET(request: Request): Response;
|
|
14
18
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/agent-events/route.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/agent-events/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,eAAO,MAAM,OAAO,kBAAkB,CAAC;AA4DvC,wBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAkM9C"}
|
|
@@ -2,69 +2,241 @@
|
|
|
2
2
|
* SSE API Route: GET /api/agent-events
|
|
3
3
|
*
|
|
4
4
|
* Streams agent lifecycle notification events to connected web UI clients
|
|
5
|
-
* via Server-Sent Events (SSE).
|
|
5
|
+
* via Server-Sent Events (SSE).
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* -
|
|
7
|
+
* Uses DB polling with a per-connection cache so only deltas are sent.
|
|
8
|
+
* This avoids cross-module singleton issues with an in-process event bus.
|
|
9
|
+
*
|
|
10
|
+
* - Polls features + agent runs every 500ms
|
|
11
|
+
* - Compares against cached state and emits only changes
|
|
9
12
|
* - Sends heartbeat comments every 30 seconds to keep connection alive
|
|
10
13
|
* - Supports optional ?runId query parameter to filter events
|
|
11
|
-
* - Cleans up
|
|
14
|
+
* - Cleans up intervals on client disconnect
|
|
12
15
|
*/
|
|
13
|
-
import {
|
|
16
|
+
import { resolve } from '../../../lib/server-container.js';
|
|
17
|
+
import { AgentRunStatus, SdlcLifecycle, NotificationEventType, NotificationSeverity, } from '../../../../../../packages/core/src/domain/generated/output.js';
|
|
18
|
+
// Force dynamic — SSE streams must never be statically optimized or cached
|
|
19
|
+
export const dynamic = 'force-dynamic';
|
|
20
|
+
const POLL_INTERVAL_MS = 500;
|
|
14
21
|
const HEARTBEAT_INTERVAL_MS = 30_000;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Maps SdlcLifecycle values to agent graph node names so the client
|
|
24
|
+
* can derive the correct FeatureLifecyclePhase via mapPhaseNameToLifecycle().
|
|
25
|
+
*/
|
|
26
|
+
const LIFECYCLE_TO_NODE = {
|
|
27
|
+
[SdlcLifecycle.Analyze]: 'analyze',
|
|
28
|
+
[SdlcLifecycle.Requirements]: 'requirements',
|
|
29
|
+
[SdlcLifecycle.Research]: 'research',
|
|
30
|
+
[SdlcLifecycle.Planning]: 'plan',
|
|
31
|
+
[SdlcLifecycle.Implementation]: 'implement',
|
|
32
|
+
[SdlcLifecycle.Review]: 'merge',
|
|
33
|
+
};
|
|
34
|
+
const STATUS_TO_EVENT = {
|
|
35
|
+
[AgentRunStatus.running]: {
|
|
36
|
+
eventType: NotificationEventType.AgentStarted,
|
|
37
|
+
severity: NotificationSeverity.Info,
|
|
38
|
+
},
|
|
39
|
+
[AgentRunStatus.waitingApproval]: {
|
|
40
|
+
eventType: NotificationEventType.WaitingApproval,
|
|
41
|
+
severity: NotificationSeverity.Warning,
|
|
42
|
+
},
|
|
43
|
+
[AgentRunStatus.completed]: {
|
|
44
|
+
eventType: NotificationEventType.AgentCompleted,
|
|
45
|
+
severity: NotificationSeverity.Success,
|
|
46
|
+
},
|
|
47
|
+
[AgentRunStatus.failed]: {
|
|
48
|
+
eventType: NotificationEventType.AgentFailed,
|
|
49
|
+
severity: NotificationSeverity.Error,
|
|
50
|
+
},
|
|
51
|
+
[AgentRunStatus.interrupted]: {
|
|
52
|
+
eventType: NotificationEventType.AgentFailed,
|
|
53
|
+
severity: NotificationSeverity.Warning,
|
|
54
|
+
},
|
|
55
|
+
[AgentRunStatus.cancelled]: {
|
|
56
|
+
eventType: NotificationEventType.AgentFailed,
|
|
57
|
+
severity: NotificationSeverity.Warning,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
/** Map agent graph node name from AgentRun.result to a phase name. */
|
|
61
|
+
function resultToPhase(result) {
|
|
62
|
+
if (!result?.startsWith('node:'))
|
|
63
|
+
return undefined;
|
|
64
|
+
return result.slice(5); // "node:analyze" → "analyze"
|
|
20
65
|
}
|
|
21
66
|
export function GET(request) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// Heartbeat to keep connection alive
|
|
41
|
-
const heartbeatInterval = setInterval(() => {
|
|
42
|
-
try {
|
|
43
|
-
controller.enqueue(encoder.encode(formatHeartbeat()));
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
// Stream may be closed — ignore enqueue errors
|
|
67
|
+
try {
|
|
68
|
+
const url = new URL(request.url);
|
|
69
|
+
const runIdFilter = url.searchParams.get('runId');
|
|
70
|
+
const stream = new ReadableStream({
|
|
71
|
+
start(controller) {
|
|
72
|
+
const encoder = new TextEncoder();
|
|
73
|
+
// Per-connection cache: featureId → last-seen state
|
|
74
|
+
const cache = new Map();
|
|
75
|
+
let stopped = false;
|
|
76
|
+
function enqueue(text) {
|
|
77
|
+
if (stopped)
|
|
78
|
+
return;
|
|
79
|
+
try {
|
|
80
|
+
controller.enqueue(encoder.encode(text));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Stream may be closed
|
|
84
|
+
}
|
|
47
85
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
clearInterval(heartbeatInterval);
|
|
53
|
-
try {
|
|
54
|
-
controller.close();
|
|
86
|
+
function emitEvent(event) {
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.log(`[SSE] emit: ${event.eventType} for "${event.featureName}"${event.phaseName ? ` (${event.phaseName})` : ''}`);
|
|
89
|
+
enqueue(`event: notification\ndata: ${JSON.stringify(event)}\n\n`);
|
|
55
90
|
}
|
|
56
|
-
|
|
57
|
-
|
|
91
|
+
let pollErrorCount = 0;
|
|
92
|
+
async function poll() {
|
|
93
|
+
if (stopped)
|
|
94
|
+
return;
|
|
95
|
+
try {
|
|
96
|
+
const listFeatures = resolve('ListFeaturesUseCase');
|
|
97
|
+
const agentRunRepo = resolve('IAgentRunRepository');
|
|
98
|
+
const phaseTimingRepo = resolve('IPhaseTimingRepository');
|
|
99
|
+
const features = await listFeatures.execute();
|
|
100
|
+
// Build current state for features with agent runs
|
|
101
|
+
const entries = await Promise.all(features.map(async (feature) => {
|
|
102
|
+
const run = feature.agentRunId
|
|
103
|
+
? await agentRunRepo.findById(feature.agentRunId)
|
|
104
|
+
: null;
|
|
105
|
+
return { feature, run };
|
|
106
|
+
}));
|
|
107
|
+
for (const { feature, run } of entries) {
|
|
108
|
+
if (!run)
|
|
109
|
+
continue;
|
|
110
|
+
// Apply runId filter if present
|
|
111
|
+
if (runIdFilter && run.id !== runIdFilter)
|
|
112
|
+
continue;
|
|
113
|
+
const prev = cache.get(feature.id);
|
|
114
|
+
if (!prev) {
|
|
115
|
+
// First time seeing this feature — seed cache, don't emit
|
|
116
|
+
const completedPhases = new Set();
|
|
117
|
+
try {
|
|
118
|
+
const timings = await phaseTimingRepo.findByRunId(run.id);
|
|
119
|
+
for (const t of timings) {
|
|
120
|
+
if (t.completedAt)
|
|
121
|
+
completedPhases.add(t.phase);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Ignore timing errors
|
|
126
|
+
}
|
|
127
|
+
cache.set(feature.id, {
|
|
128
|
+
status: run.status,
|
|
129
|
+
lifecycle: feature.lifecycle,
|
|
130
|
+
completedPhases,
|
|
131
|
+
featureName: feature.name,
|
|
132
|
+
});
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
// Check for status change
|
|
136
|
+
if (prev.status !== run.status) {
|
|
137
|
+
prev.status = run.status;
|
|
138
|
+
const mapping = STATUS_TO_EVENT[run.status];
|
|
139
|
+
if (mapping) {
|
|
140
|
+
const phase = resultToPhase(run.result);
|
|
141
|
+
emitEvent({
|
|
142
|
+
eventType: mapping.eventType,
|
|
143
|
+
agentRunId: run.id,
|
|
144
|
+
featureId: feature.id,
|
|
145
|
+
featureName: feature.name,
|
|
146
|
+
...(phase && { phaseName: phase }),
|
|
147
|
+
message: `Agent status: ${run.status}`,
|
|
148
|
+
severity: mapping.severity,
|
|
149
|
+
timestamp: new Date().toISOString(),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Check for lifecycle change (agent stays "running" but moves through phases)
|
|
154
|
+
if (prev.lifecycle !== feature.lifecycle) {
|
|
155
|
+
prev.lifecycle = feature.lifecycle;
|
|
156
|
+
const nodeName = LIFECYCLE_TO_NODE[feature.lifecycle];
|
|
157
|
+
if (nodeName) {
|
|
158
|
+
emitEvent({
|
|
159
|
+
eventType: NotificationEventType.PhaseCompleted,
|
|
160
|
+
agentRunId: run.id,
|
|
161
|
+
featureId: feature.id,
|
|
162
|
+
featureName: feature.name,
|
|
163
|
+
phaseName: nodeName,
|
|
164
|
+
message: `Entered ${nodeName} phase`,
|
|
165
|
+
severity: NotificationSeverity.Info,
|
|
166
|
+
timestamp: new Date().toISOString(),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Check for new phase completions
|
|
171
|
+
try {
|
|
172
|
+
const timings = await phaseTimingRepo.findByRunId(run.id);
|
|
173
|
+
for (const t of timings) {
|
|
174
|
+
if (t.completedAt && !prev.completedPhases.has(t.phase)) {
|
|
175
|
+
prev.completedPhases.add(t.phase);
|
|
176
|
+
emitEvent({
|
|
177
|
+
eventType: NotificationEventType.PhaseCompleted,
|
|
178
|
+
agentRunId: run.id,
|
|
179
|
+
featureId: feature.id,
|
|
180
|
+
featureName: feature.name,
|
|
181
|
+
phaseName: t.phase,
|
|
182
|
+
message: `Completed ${t.phase} phase`,
|
|
183
|
+
severity: NotificationSeverity.Info,
|
|
184
|
+
timestamp: new Date().toISOString(),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Ignore timing errors
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
pollErrorCount = 0; // Reset on success
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
pollErrorCount++;
|
|
197
|
+
// Log first few errors, then throttle to avoid spamming
|
|
198
|
+
if (pollErrorCount <= 3 || pollErrorCount % 60 === 0) {
|
|
199
|
+
// eslint-disable-next-line no-console
|
|
200
|
+
console.error(`[SSE /api/agent-events] poll error #${pollErrorCount}:`, error instanceof Error ? error.message : error);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
58
203
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
204
|
+
// First poll immediately, then every POLL_INTERVAL_MS
|
|
205
|
+
void poll();
|
|
206
|
+
const pollInterval = setInterval(() => void poll(), POLL_INTERVAL_MS);
|
|
207
|
+
// Heartbeat to keep connection alive
|
|
208
|
+
const heartbeatInterval = setInterval(() => {
|
|
209
|
+
enqueue(': heartbeat\n\n');
|
|
210
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
211
|
+
// Cleanup on client disconnect
|
|
212
|
+
const cleanup = () => {
|
|
213
|
+
stopped = true;
|
|
214
|
+
clearInterval(pollInterval);
|
|
215
|
+
clearInterval(heartbeatInterval);
|
|
216
|
+
try {
|
|
217
|
+
controller.close();
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
// Stream may already be closed
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
request.signal.addEventListener('abort', cleanup, { once: true });
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
return new Response(stream, {
|
|
227
|
+
headers: {
|
|
228
|
+
'Content-Type': 'text/event-stream',
|
|
229
|
+
'Cache-Control': 'no-cache',
|
|
230
|
+
Connection: 'keep-alive',
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
// eslint-disable-next-line no-console
|
|
236
|
+
console.error('[SSE route] GET handler error:', error);
|
|
237
|
+
return new Response(JSON.stringify({ error: String(error) }), {
|
|
238
|
+
status: 500,
|
|
239
|
+
headers: { 'Content-Type': 'application/json' },
|
|
240
|
+
});
|
|
241
|
+
}
|
|
70
242
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/layout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,6BAA6B,CAAC;AACrC,OAAO,eAAe,CAAC;AAIvB,sFAAsF;AACtF,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAEvC,eAAO,MAAM,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/layout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,6BAA6B,CAAC;AACrC,OAAO,eAAe,CAAC;AAIvB,sFAAsF;AACtF,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAEvC,eAAO,MAAM,QAAQ,EAAE,QAkBtB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,QAAQ,GACT,EAAE,QAAQ,CAAC;IACV,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC,2CA0BD"}
|
|
@@ -8,6 +8,20 @@ export const dynamic = 'force-dynamic';
|
|
|
8
8
|
export const metadata = {
|
|
9
9
|
title: 'Shep AI',
|
|
10
10
|
description: 'Autonomous AI Native SDLC Platform - Automate the development cycle from idea to deploy',
|
|
11
|
+
icons: [
|
|
12
|
+
{
|
|
13
|
+
rel: 'icon',
|
|
14
|
+
url: '/favicon-light.svg',
|
|
15
|
+
type: 'image/svg+xml',
|
|
16
|
+
media: '(prefers-color-scheme: light)',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
rel: 'icon',
|
|
20
|
+
url: '/favicon-dark.svg',
|
|
21
|
+
type: 'image/svg+xml',
|
|
22
|
+
media: '(prefers-color-scheme: dark)',
|
|
23
|
+
},
|
|
24
|
+
],
|
|
11
25
|
};
|
|
12
26
|
export default function RootLayout({ children, }) {
|
|
13
27
|
return (_jsxs("html", { lang: "en", suppressHydrationWarning: true, children: [_jsx("head", { children: _jsx("script", { dangerouslySetInnerHTML: {
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Derives UI node state and progress from the Feature domain model
|
|
5
5
|
* and its associated AgentRun status (mirrors CLI feat ls logic).
|
|
6
6
|
*/
|
|
7
|
+
import { NotificationEventType } from '../../../../../../packages/core/src/domain/generated/index.js';
|
|
7
8
|
import type { Feature, AgentRun } from '../../../../../../packages/core/src/domain/generated/index.js';
|
|
8
|
-
import type { FeatureNodeState } from './feature-node-state-config.js';
|
|
9
|
+
import type { FeatureNodeState, FeatureLifecyclePhase } from './feature-node-state-config.js';
|
|
9
10
|
/**
|
|
10
11
|
* Derives the visual node state from a Feature and its optional AgentRun.
|
|
11
12
|
*
|
|
@@ -25,4 +26,7 @@ export declare function deriveNodeState(feature: Feature, agentRun?: AgentRun |
|
|
|
25
26
|
* Returns 100 for Maintain lifecycle, 0 if no plan.
|
|
26
27
|
*/
|
|
27
28
|
export declare function deriveProgress(feature: Feature): number;
|
|
29
|
+
/** Maps a NotificationEventType to the corresponding FeatureNodeState for optimistic UI updates. */
|
|
30
|
+
export declare function mapEventTypeToState(eventType: NotificationEventType): FeatureNodeState;
|
|
31
|
+
export declare function mapPhaseNameToLifecycle(phaseName: string | undefined): FeatureLifecyclePhase | undefined;
|
|
28
32
|
//# sourceMappingURL=derive-feature-state.d.ts.map
|
package/dist/src/presentation/web/components/common/feature-node/derive-feature-state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-feature-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/derive-feature-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"derive-feature-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/derive-feature-state.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAIL,qBAAqB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAE3F;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,gBAAgB,CA4C9F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAYvD;AAED,oGAAoG;AACpG,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,qBAAqB,GAAG,gBAAgB,CAYtF;AAYD,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,qBAAqB,GAAG,SAAS,CAGnC"}
|