@shepai/cli 1.122.2-pr367.fdba557 → 1.122.2-pr381.7d9e407
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/dist/packages/core/src/application/ports/output/services/index.d.ts +0 -2
- package/dist/packages/core/src/application/ports/output/services/index.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 +0 -14
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.js +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts +28 -8
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.js +187 -29
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +9 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts +5 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +82 -54
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +2 -2
- package/dist/src/presentation/cli/commands/ui.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/ui.command.js +0 -15
- package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.d.ts.map +1 -1
- package/dist/src/presentation/web/components/layouts/app-sidebar/app-sidebar.js +2 -2
- package/dist/src/presentation/web/dev-server.js +0 -20
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -3
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +1 -5
- package/web/.next/build-manifest.json +6 -6
- 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 +0 -24
- package/web/.next/server/app/(dashboard)/@drawer/create/page/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/create/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/(dashboard)/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +1 -1
- 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/page/build-manifest.json +4 -4
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/_not-found/page.js +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/attachments/preview/route.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 +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 +1 -1
- package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
- package/web/.next/server/app/settings/page/build-manifest.json +4 -4
- package/web/.next/server/app/settings/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/settings/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/skills/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/tools/page.js +1 -1
- 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/build-manifest.json +4 -4
- package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/version/page.js +2 -2
- 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 -5
- package/web/.next/server/chunks/{[root-of-the-server]__3baec744._.js → [root-of-the-server]__42b7ab55._.js} +2 -2
- package/web/.next/server/chunks/{[root-of-the-server]__3baec744._.js.map → [root-of-the-server]__42b7ab55._.js.map} +1 -1
- package/web/.next/server/chunks/{[root-of-the-server]__7d63f9a4._.js → [root-of-the-server]__53013576._.js} +2 -2
- package/web/.next/server/chunks/{[root-of-the-server]__a1c7c02a._.js → [root-of-the-server]__92078db6._.js} +2 -2
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +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/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js.map +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__12c2ab7d._.js → [root-of-the-server]__06fef644._.js} +2 -2
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__12c2ab7d._.js.map → [root-of-the-server]__06fef644._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2698e9f4._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2698e9f4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +4 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__11033878._.js.map → [root-of-the-server]__6b17a22d._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +4 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__fdc75809._.js.map → [root-of-the-server]__804c006d._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8c553503._.js +4 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__76915230._.js.map → [root-of-the-server]__8c553503._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8e3bf5d7._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8e3bf5d7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9f155c0e._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9f155c0e._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a022445f._.js +4 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__7a939e4e._.js.map → [root-of-the-server]__a022445f._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +4 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__c4dc1b5a._.js.map → [root-of-the-server]__a7de2711._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0dc2cfd3._.js +3 -0
- package/web/.next/server/chunks/ssr/_0dc2cfd3._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
- package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{node_modules__pnpm_747b43ac._.js → _1bb131c4._.js} +2 -2
- package/web/.next/server/chunks/ssr/_1bb131c4._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_1bb79fe8._.js +3 -0
- package/web/.next/server/chunks/ssr/_1bb79fe8._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_204ecb5a._.js +3 -0
- package/web/.next/server/chunks/ssr/_204ecb5a._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_2f6f48b8._.js +1 -1
- package/web/.next/server/chunks/ssr/_2f6f48b8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_3d1ed2a7._.js → _434878d3._.js} +2 -2
- package/web/.next/server/chunks/ssr/_434878d3._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_510be09a._.js +3 -0
- package/web/.next/server/chunks/ssr/{_3eca2297._.js.map → _510be09a._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_6d26a08f._.js +3 -0
- package/web/.next/server/chunks/ssr/_6d26a08f._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_75f4ccb3._.js +3 -0
- package/web/.next/server/chunks/ssr/_75f4ccb3._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_b5fc318a._.js +3 -0
- package/web/.next/server/chunks/ssr/_b5fc318a._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
- package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_f1a649e3._.js +9 -0
- package/web/.next/server/chunks/ssr/_f1a649e3._.js.map +1 -0
- 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/node_modules__pnpm_b59e4b16._.js +3 -0
- package/web/.next/server/chunks/ssr/node_modules__pnpm_b59e4b16._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.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_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/middleware-build-manifest.js +4 -4
- 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 +35 -57
- package/web/.next/static/chunks/0d2af96e64960ef5.css +1 -0
- package/web/.next/static/chunks/19401b65e1298cb0.js +1 -0
- package/web/.next/static/chunks/{3f0773d9b56e04a2.js → 2c0191c062d5f7ae.js} +2 -2
- package/web/.next/static/chunks/303a1217006489b9.js +1 -0
- package/web/.next/static/chunks/4562ee849ea13c3a.js +1 -0
- package/web/.next/static/chunks/4da275e6ef808c4d.js +11 -0
- package/web/.next/static/chunks/{c3c68de2392a9071.js → 50bf223ed146d4ed.js} +1 -1
- package/web/.next/static/chunks/5a9e671eb04de758.js +1 -0
- package/web/.next/static/chunks/{98e3a7cf58fc912a.js → 672e3da3ad26005b.js} +1 -1
- package/web/.next/static/chunks/6a8fb1992b738cc9.js +1 -0
- package/web/.next/static/chunks/845d8e58a91014e6.js +1 -0
- package/web/.next/static/chunks/84a181ff3270fd9f.js +1 -0
- package/web/.next/static/chunks/{e087f3e5c46c0756.js → 89ffd07cdb158389.js} +1 -1
- package/web/.next/static/chunks/96eeeb28e06de78c.js +1 -0
- package/web/.next/static/chunks/{293ccfbe777d995a.js → a637e16d364af323.js} +1 -1
- package/web/.next/static/chunks/bc1ce100834f414a.js +1 -0
- package/web/.next/static/chunks/cca0f5112a9260d8.js +1 -0
- package/web/.next/static/chunks/{1b9d34af4064dafe.js → df88f3e08b196bbf.js} +2 -2
- package/web/.next/static/chunks/e2ef95d904c360f3.js +1 -0
- package/web/.next/static/chunks/ed3a602003bcb31b.js +1 -0
- package/web/.next/static/chunks/{turbopack-b1685b5f87ad1d60.js → turbopack-426d9bc2450816ba.js} +1 -1
- package/dist/packages/core/src/application/ports/output/services/tunnel-service.interface.d.ts +0 -41
- package/dist/packages/core/src/application/ports/output/services/tunnel-service.interface.d.ts.map +0 -1
- package/dist/packages/core/src/application/ports/output/services/tunnel-service.interface.js +0 -14
- package/dist/packages/core/src/application/ports/output/services/webhook-service.interface.d.ts +0 -65
- package/dist/packages/core/src/application/ports/output/services/webhook-service.interface.d.ts.map +0 -1
- package/dist/packages/core/src/application/ports/output/services/webhook-service.interface.js +0 -10
- package/dist/packages/core/src/infrastructure/services/tunnel/cloudflare-tunnel.service.d.ts +0 -55
- package/dist/packages/core/src/infrastructure/services/tunnel/cloudflare-tunnel.service.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/tunnel/cloudflare-tunnel.service.js +0 -203
- package/dist/packages/core/src/infrastructure/services/webhook/github-webhook.service.d.ts +0 -75
- package/dist/packages/core/src/infrastructure/services/webhook/github-webhook.service.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/webhook/github-webhook.service.js +0 -372
- package/dist/packages/core/src/infrastructure/services/webhook/webhook-manager.service.d.ts +0 -82
- package/dist/packages/core/src/infrastructure/services/webhook/webhook-manager.service.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/webhook/webhook-manager.service.js +0 -206
- package/dist/src/presentation/web/app/actions/load-webhook-status.d.ts +0 -3
- package/dist/src/presentation/web/app/actions/load-webhook-status.d.ts.map +0 -1
- package/dist/src/presentation/web/app/actions/load-webhook-status.js +0 -19
- package/dist/src/presentation/web/app/api/webhooks/deliveries/route.d.ts +0 -9
- package/dist/src/presentation/web/app/api/webhooks/deliveries/route.d.ts.map +0 -1
- package/dist/src/presentation/web/app/api/webhooks/deliveries/route.js +0 -27
- package/dist/src/presentation/web/app/api/webhooks/github/route.d.ts +0 -17
- package/dist/src/presentation/web/app/api/webhooks/github/route.d.ts.map +0 -1
- package/dist/src/presentation/web/app/api/webhooks/github/route.js +0 -70
- package/dist/src/presentation/web/app/api/webhooks/status/route.d.ts +0 -9
- package/dist/src/presentation/web/app/api/webhooks/status/route.d.ts.map +0 -1
- package/dist/src/presentation/web/app/api/webhooks/status/route.js +0 -26
- package/dist/src/presentation/web/app/webhooks/page.d.ts +0 -4
- package/dist/src/presentation/web/app/webhooks/page.d.ts.map +0 -1
- package/dist/src/presentation/web/app/webhooks/page.js +0 -9
- package/dist/src/presentation/web/components/features/webhooks/types.d.ts +0 -32
- package/dist/src/presentation/web/components/features/webhooks/types.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/types.js +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhook-delivery-table.d.ts +0 -6
- package/dist/src/presentation/web/components/features/webhooks/webhook-delivery-table.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhook-delivery-table.js +0 -38
- package/dist/src/presentation/web/components/features/webhooks/webhook-delivery-table.stories.d.ts +0 -9
- package/dist/src/presentation/web/components/features/webhooks/webhook-delivery-table.stories.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhook-delivery-table.stories.js +0 -69
- package/dist/src/presentation/web/components/features/webhooks/webhook-repo-list.d.ts +0 -7
- package/dist/src/presentation/web/components/features/webhooks/webhook-repo-list.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhook-repo-list.js +0 -11
- package/dist/src/presentation/web/components/features/webhooks/webhook-repo-list.stories.d.ts +0 -9
- package/dist/src/presentation/web/components/features/webhooks/webhook-repo-list.stories.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhook-repo-list.stories.js +0 -31
- package/dist/src/presentation/web/components/features/webhooks/webhook-status-cards.d.ts +0 -6
- package/dist/src/presentation/web/components/features/webhooks/webhook-status-cards.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhook-status-cards.js +0 -21
- package/dist/src/presentation/web/components/features/webhooks/webhook-status-cards.stories.d.ts +0 -9
- package/dist/src/presentation/web/components/features/webhooks/webhook-status-cards.stories.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhook-status-cards.stories.js +0 -56
- package/dist/src/presentation/web/components/features/webhooks/webhooks-page-client.d.ts +0 -6
- package/dist/src/presentation/web/components/features/webhooks/webhooks-page-client.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhooks-page-client.js +0 -39
- package/dist/src/presentation/web/components/features/webhooks/webhooks-page-client.stories.d.ts +0 -8
- package/dist/src/presentation/web/components/features/webhooks/webhooks-page-client.stories.d.ts.map +0 -1
- package/dist/src/presentation/web/components/features/webhooks/webhooks-page-client.stories.js +0 -59
- package/web/.next/server/app/api/webhooks/deliveries/route/app-paths-manifest.json +0 -3
- package/web/.next/server/app/api/webhooks/deliveries/route/build-manifest.json +0 -11
- package/web/.next/server/app/api/webhooks/deliveries/route/server-reference-manifest.json +0 -4
- package/web/.next/server/app/api/webhooks/deliveries/route.js +0 -6
- package/web/.next/server/app/api/webhooks/deliveries/route.js.map +0 -5
- package/web/.next/server/app/api/webhooks/deliveries/route.js.nft.json +0 -1
- package/web/.next/server/app/api/webhooks/deliveries/route_client-reference-manifest.js +0 -2
- package/web/.next/server/app/api/webhooks/github/route/app-paths-manifest.json +0 -3
- package/web/.next/server/app/api/webhooks/github/route/build-manifest.json +0 -11
- package/web/.next/server/app/api/webhooks/github/route/server-reference-manifest.json +0 -4
- package/web/.next/server/app/api/webhooks/github/route.js +0 -6
- package/web/.next/server/app/api/webhooks/github/route.js.map +0 -5
- package/web/.next/server/app/api/webhooks/github/route.js.nft.json +0 -1
- package/web/.next/server/app/api/webhooks/github/route_client-reference-manifest.js +0 -2
- package/web/.next/server/app/api/webhooks/status/route/app-paths-manifest.json +0 -3
- package/web/.next/server/app/api/webhooks/status/route/build-manifest.json +0 -11
- package/web/.next/server/app/api/webhooks/status/route/server-reference-manifest.json +0 -4
- package/web/.next/server/app/api/webhooks/status/route.js +0 -6
- package/web/.next/server/app/api/webhooks/status/route.js.map +0 -5
- package/web/.next/server/app/api/webhooks/status/route.js.nft.json +0 -1
- package/web/.next/server/app/api/webhooks/status/route_client-reference-manifest.js +0 -2
- package/web/.next/server/app/webhooks/page/app-paths-manifest.json +0 -3
- package/web/.next/server/app/webhooks/page/build-manifest.json +0 -18
- package/web/.next/server/app/webhooks/page/next-font-manifest.json +0 -6
- package/web/.next/server/app/webhooks/page/react-loadable-manifest.json +0 -1
- package/web/.next/server/app/webhooks/page/server-reference-manifest.json +0 -35
- package/web/.next/server/app/webhooks/page.js +0 -16
- package/web/.next/server/app/webhooks/page.js.map +0 -5
- package/web/.next/server/app/webhooks/page.js.nft.json +0 -1
- package/web/.next/server/app/webhooks/page_client-reference-manifest.js +0 -2
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_webhooks_deliveries_route_actions_d9e34c8d.js +0 -3
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_webhooks_deliveries_route_actions_d9e34c8d.js.map +0 -1
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_webhooks_github_route_actions_1b0d0c38.js +0 -3
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_webhooks_github_route_actions_1b0d0c38.js.map +0 -1
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_webhooks_status_route_actions_1a0d86a1.js +0 -3
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_webhooks_status_route_actions_1a0d86a1.js.map +0 -1
- package/web/.next/server/chunks/[root-of-the-server]__15e5d45c._.js +0 -3
- package/web/.next/server/chunks/[root-of-the-server]__15e5d45c._.js.map +0 -1
- package/web/.next/server/chunks/[root-of-the-server]__23be381e._.js +0 -3
- package/web/.next/server/chunks/[root-of-the-server]__23be381e._.js.map +0 -1
- package/web/.next/server/chunks/[root-of-the-server]__9fc760c0._.js +0 -3
- package/web/.next/server/chunks/[root-of-the-server]__9fc760c0._.js.map +0 -1
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_activity_22f9667f.js +0 -3
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_activity_22f9667f.js.map +0 -1
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_rocket_1575cd4d.js +0 -3
- package/web/.next/server/chunks/ssr/7f428_lucide-react_dist_esm_icons_rocket_1575cd4d.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__3c16bf85._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__3c16bf85._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__610f06df._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__610f06df._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__76915230._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7a939e4e._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__87a7ae30._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__87a7ae30._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__920dccd5._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__920dccd5._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c4dc1b5a._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js +0 -4
- package/web/.next/server/chunks/ssr/_07f57bd0._.js +0 -3
- package/web/.next/server/chunks/ssr/_07f57bd0._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_15a756dd._.js +0 -3
- package/web/.next/server/chunks/ssr/_15a756dd._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_26b2c311._.js +0 -3
- package/web/.next/server/chunks/ssr/_26b2c311._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_3d1ed2a7._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_3eca2297._.js +0 -3
- package/web/.next/server/chunks/ssr/_4470c218._.js +0 -3
- package/web/.next/server/chunks/ssr/_4470c218._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_462cc3a6._.js +0 -3
- package/web/.next/server/chunks/ssr/_462cc3a6._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_961cb4b2._.js +0 -3
- package/web/.next/server/chunks/ssr/_961cb4b2._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_a4899a76._.js +0 -3
- package/web/.next/server/chunks/ssr/_a4899a76._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_b5babdfc._.js +0 -9
- package/web/.next/server/chunks/ssr/_b5babdfc._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_b7eb93fc._.js +0 -4
- package/web/.next/server/chunks/ssr/_b7eb93fc._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_f8b36e2c._.js +0 -3
- package/web/.next/server/chunks/ssr/_f8b36e2c._.js.map +0 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_webhooks_webhooks-page-client_tsx_b2662ea3._.js +0 -3
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_webhooks_webhooks-page-client_tsx_b2662ea3._.js.map +0 -1
- package/web/.next/server/chunks/ssr/node_modules__pnpm_747b43ac._.js.map +0 -1
- package/web/.next/static/chunks/0c76de69325ef923.js +0 -1
- package/web/.next/static/chunks/3835a408dbf8d0bb.js +0 -1
- package/web/.next/static/chunks/40b6bcf1a2de4a0f.js +0 -1
- package/web/.next/static/chunks/4c5b31a2c65d4aa5.js +0 -11
- package/web/.next/static/chunks/59a0709f1b080353.js +0 -1
- package/web/.next/static/chunks/5f6161ceb4263319.js +0 -1
- package/web/.next/static/chunks/77ff1b7b725b7780.js +0 -1
- package/web/.next/static/chunks/9af45e885bd4ccef.js +0 -1
- package/web/.next/static/chunks/a57dc2afcf67304a.js +0 -1
- package/web/.next/static/chunks/b4f502a76ba10e4b.js +0 -1
- package/web/.next/static/chunks/b5d8e8100e310d9f.css +0 -1
- package/web/.next/static/chunks/b747e59ebdcbd917.js +0 -1
- package/web/.next/static/chunks/c04ce6760f349f3e.js +0 -1
- package/web/.next/static/chunks/c7e793951b20a67f.js +0 -1
- package/web/.next/static/chunks/cf30e300568abf0f.js +0 -1
- package/web/.next/static/chunks/d43dff89384fb60a.js +0 -1
- /package/web/.next/server/chunks/{[root-of-the-server]__7d63f9a4._.js.map → [root-of-the-server]__53013576._.js.map} +0 -0
- /package/web/.next/server/chunks/{[root-of-the-server]__a1c7c02a._.js.map → [root-of-the-server]__92078db6._.js.map} +0 -0
- /package/web/.next/static/{svtG6xX1MdaGWkml8eX53 → NKkt3_PEmNxKD_ihRAzNE}/_buildManifest.js +0 -0
- /package/web/.next/static/{svtG6xX1MdaGWkml8eX53 → NKkt3_PEmNxKD_ihRAzNE}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{svtG6xX1MdaGWkml8eX53 → NKkt3_PEmNxKD_ihRAzNE}/_ssgManifest.js +0 -0
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cloudflare Tunnel Service
|
|
3
|
-
*
|
|
4
|
-
* Manages a `cloudflared` quick-tunnel that exposes ONLY the webhook
|
|
5
|
-
* API routes to the public internet via a random *.trycloudflare.com
|
|
6
|
-
* subdomain.
|
|
7
|
-
*
|
|
8
|
-
* Uses the `cloudflared` npm package which handles binary installation
|
|
9
|
-
* and provides a typed Tunnel API — no need for the user to install
|
|
10
|
-
* cloudflared separately.
|
|
11
|
-
*
|
|
12
|
-
* Security: A lightweight proxy HTTP server is started on a random port
|
|
13
|
-
* that only forwards requests matching the allowed path prefix
|
|
14
|
-
* (/api/webhooks) to the main app. The tunnel connects to this proxy,
|
|
15
|
-
* not the main app server. All other paths return 404.
|
|
16
|
-
*/
|
|
17
|
-
import { createServer, request as httpRequest } from 'node:http';
|
|
18
|
-
const TAG = '[CloudflareTunnel]';
|
|
19
|
-
const STARTUP_TIMEOUT_MS = 30_000;
|
|
20
|
-
const ALLOWED_PATH_PREFIX = '/api/webhooks';
|
|
21
|
-
async function defaultCreateTunnel(origin) {
|
|
22
|
-
const { Tunnel } = await import('cloudflared');
|
|
23
|
-
return Tunnel.quick(origin);
|
|
24
|
-
}
|
|
25
|
-
const defaultDeps = {
|
|
26
|
-
createTunnel: defaultCreateTunnel,
|
|
27
|
-
};
|
|
28
|
-
export class CloudflareTunnelService {
|
|
29
|
-
tunnel = null;
|
|
30
|
-
proxyServer = null;
|
|
31
|
-
publicUrl = null;
|
|
32
|
-
urlChangeHandlers = [];
|
|
33
|
-
deps;
|
|
34
|
-
constructor(deps = {}) {
|
|
35
|
-
this.deps = { ...defaultDeps, ...deps };
|
|
36
|
-
}
|
|
37
|
-
async start(localPort) {
|
|
38
|
-
if (this.tunnel) {
|
|
39
|
-
throw new Error(`${TAG} Tunnel already running at ${this.publicUrl}`);
|
|
40
|
-
}
|
|
41
|
-
// Start a proxy server that only forwards webhook routes
|
|
42
|
-
const proxyPort = await this.startProxyServer(localPort);
|
|
43
|
-
let tunnel;
|
|
44
|
-
try {
|
|
45
|
-
tunnel = await Promise.resolve(this.deps.createTunnel(`http://localhost:${proxyPort}`));
|
|
46
|
-
}
|
|
47
|
-
catch (err) {
|
|
48
|
-
this.stopProxyServer();
|
|
49
|
-
throw new Error(`${TAG} Failed to create tunnel: ${err.message}`);
|
|
50
|
-
}
|
|
51
|
-
this.tunnel = tunnel;
|
|
52
|
-
return new Promise((resolve, reject) => {
|
|
53
|
-
const timeout = setTimeout(() => {
|
|
54
|
-
this.stopTunnel();
|
|
55
|
-
reject(new Error(`${TAG} Timed out waiting for tunnel URL (${STARTUP_TIMEOUT_MS}ms)`));
|
|
56
|
-
}, STARTUP_TIMEOUT_MS);
|
|
57
|
-
tunnel.on('url', (url) => {
|
|
58
|
-
if (!this.publicUrl) {
|
|
59
|
-
// First URL — startup complete
|
|
60
|
-
this.publicUrl = url;
|
|
61
|
-
clearTimeout(timeout);
|
|
62
|
-
// eslint-disable-next-line no-console
|
|
63
|
-
console.log(`${TAG} Tunnel ready: ${url} (proxying ${ALLOWED_PATH_PREFIX}/* to port ${localPort})`);
|
|
64
|
-
resolve(url);
|
|
65
|
-
}
|
|
66
|
-
else if (url !== this.publicUrl) {
|
|
67
|
-
// URL changed — reconnection with new subdomain
|
|
68
|
-
const oldUrl = this.publicUrl;
|
|
69
|
-
this.publicUrl = url;
|
|
70
|
-
// eslint-disable-next-line no-console
|
|
71
|
-
console.log(`${TAG} Tunnel URL changed: ${oldUrl} -> ${url}`);
|
|
72
|
-
this.notifyUrlChange(url);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
tunnel.on('error', (err) => {
|
|
76
|
-
clearTimeout(timeout);
|
|
77
|
-
this.tunnel = null;
|
|
78
|
-
this.publicUrl = null;
|
|
79
|
-
this.stopProxyServer();
|
|
80
|
-
reject(new Error(`${TAG} Failed to start tunnel: ${err.message}`));
|
|
81
|
-
});
|
|
82
|
-
tunnel.on('exit', (code) => {
|
|
83
|
-
clearTimeout(timeout);
|
|
84
|
-
if (this.tunnel === tunnel) {
|
|
85
|
-
this.tunnel = null;
|
|
86
|
-
const wasRunning = this.publicUrl !== null;
|
|
87
|
-
this.publicUrl = null;
|
|
88
|
-
this.stopProxyServer();
|
|
89
|
-
if (wasRunning) {
|
|
90
|
-
// eslint-disable-next-line no-console
|
|
91
|
-
console.log(`${TAG} Tunnel process exited (code ${code})`);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
reject(new Error(`${TAG} cloudflared exited with code ${code} before producing a URL`));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
async stop() {
|
|
101
|
-
this.stopTunnel();
|
|
102
|
-
this.publicUrl = null;
|
|
103
|
-
}
|
|
104
|
-
getPublicUrl() {
|
|
105
|
-
return this.publicUrl;
|
|
106
|
-
}
|
|
107
|
-
onUrlChange(handler) {
|
|
108
|
-
this.urlChangeHandlers.push(handler);
|
|
109
|
-
}
|
|
110
|
-
isRunning() {
|
|
111
|
-
return this.tunnel !== null && this.publicUrl !== null;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Start a lightweight HTTP proxy on a random port that only forwards
|
|
115
|
-
* requests with paths starting with ALLOWED_PATH_PREFIX to the main app.
|
|
116
|
-
* Everything else gets a 404.
|
|
117
|
-
*/
|
|
118
|
-
startProxyServer(targetPort) {
|
|
119
|
-
return new Promise((resolve, reject) => {
|
|
120
|
-
const server = createServer((req, res) => {
|
|
121
|
-
const url = req.url ?? '';
|
|
122
|
-
if (!url.startsWith(ALLOWED_PATH_PREFIX)) {
|
|
123
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
124
|
-
res.end(JSON.stringify({ error: 'Not found' }));
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
// Proxy the request to the main app
|
|
128
|
-
const proxyReq = httpRequest({
|
|
129
|
-
hostname: 'localhost',
|
|
130
|
-
port: targetPort,
|
|
131
|
-
path: url,
|
|
132
|
-
method: req.method,
|
|
133
|
-
headers: req.headers,
|
|
134
|
-
}, (proxyRes) => {
|
|
135
|
-
res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
|
|
136
|
-
proxyRes.pipe(res);
|
|
137
|
-
});
|
|
138
|
-
proxyReq.on('error', (err) => {
|
|
139
|
-
// eslint-disable-next-line no-console
|
|
140
|
-
console.warn(`${TAG} Proxy error: ${err.message}`);
|
|
141
|
-
if (!res.headersSent) {
|
|
142
|
-
res.writeHead(502, { 'Content-Type': 'application/json' });
|
|
143
|
-
}
|
|
144
|
-
res.end(JSON.stringify({ error: 'Bad gateway' }));
|
|
145
|
-
});
|
|
146
|
-
req.pipe(proxyReq);
|
|
147
|
-
});
|
|
148
|
-
// Listen on port 0 = OS assigns a random available port
|
|
149
|
-
server.listen(0, '127.0.0.1', () => {
|
|
150
|
-
const addr = server.address();
|
|
151
|
-
if (addr && typeof addr === 'object') {
|
|
152
|
-
this.proxyServer = server;
|
|
153
|
-
// eslint-disable-next-line no-console
|
|
154
|
-
console.log(`${TAG} Webhook proxy listening on port ${addr.port}`);
|
|
155
|
-
resolve(addr.port);
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
server.close();
|
|
159
|
-
reject(new Error(`${TAG} Failed to start proxy server`));
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
server.on('error', (err) => {
|
|
163
|
-
reject(new Error(`${TAG} Proxy server error: ${err.message}`));
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
stopProxyServer() {
|
|
168
|
-
if (this.proxyServer) {
|
|
169
|
-
this.proxyServer.close();
|
|
170
|
-
this.proxyServer = null;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
stopTunnel() {
|
|
174
|
-
if (this.tunnel) {
|
|
175
|
-
const tunnel = this.tunnel;
|
|
176
|
-
this.tunnel = null;
|
|
177
|
-
try {
|
|
178
|
-
tunnel.stop();
|
|
179
|
-
}
|
|
180
|
-
catch {
|
|
181
|
-
// Tunnel already stopped
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
this.stopProxyServer();
|
|
185
|
-
}
|
|
186
|
-
notifyUrlChange(newUrl) {
|
|
187
|
-
for (const handler of this.urlChangeHandlers) {
|
|
188
|
-
try {
|
|
189
|
-
const result = handler(newUrl);
|
|
190
|
-
if (result instanceof Promise) {
|
|
191
|
-
result.catch((err) => {
|
|
192
|
-
// eslint-disable-next-line no-console
|
|
193
|
-
console.warn(`${TAG} URL change handler failed:`, err);
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
catch (err) {
|
|
198
|
-
// eslint-disable-next-line no-console
|
|
199
|
-
console.warn(`${TAG} URL change handler threw:`, err);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub Webhook Service
|
|
3
|
-
*
|
|
4
|
-
* Manages GitHub webhook registration and incoming event processing.
|
|
5
|
-
* Uses the GitHub CLI (`gh api`) for webhook CRUD operations.
|
|
6
|
-
*
|
|
7
|
-
* Webhook events supplement the existing PR sync polling:
|
|
8
|
-
* - Webhooks provide near-instant event delivery
|
|
9
|
-
* - Polling remains as a fallback for missed events
|
|
10
|
-
*
|
|
11
|
-
* Registered events: pull_request, check_suite, check_run
|
|
12
|
-
*/
|
|
13
|
-
import type { IWebhookService, WebhookEvent, WebhookValidationResult } from '../../../application/ports/output/services/webhook-service.interface.js';
|
|
14
|
-
import type { IFeatureRepository } from '../../../application/ports/output/repositories/feature-repository.interface.js';
|
|
15
|
-
import type { IGitPrService } from '../../../application/ports/output/services/git-pr-service.interface.js';
|
|
16
|
-
import type { INotificationService } from '../../../application/ports/output/services/notification-service.interface.js';
|
|
17
|
-
export type ExecFunction = (file: string, args: string[], options?: object) => Promise<{
|
|
18
|
-
stdout: string;
|
|
19
|
-
stderr: string;
|
|
20
|
-
}>;
|
|
21
|
-
export interface RegisteredWebhook {
|
|
22
|
-
repoFullName: string;
|
|
23
|
-
webhookId: number;
|
|
24
|
-
repositoryPath: string;
|
|
25
|
-
}
|
|
26
|
-
export type WebhookDeliveryStatus = 'success' | 'ignored' | 'error';
|
|
27
|
-
export interface WebhookDeliveryRecord {
|
|
28
|
-
deliveryId: string;
|
|
29
|
-
eventType: string;
|
|
30
|
-
source: string;
|
|
31
|
-
receivedAt: string;
|
|
32
|
-
status: WebhookDeliveryStatus;
|
|
33
|
-
statusMessage: string;
|
|
34
|
-
durationMs: number;
|
|
35
|
-
payload: Record<string, unknown>;
|
|
36
|
-
}
|
|
37
|
-
export declare class GitHubWebhookService implements IWebhookService {
|
|
38
|
-
private readonly featureRepo;
|
|
39
|
-
private readonly gitPrService;
|
|
40
|
-
private readonly notificationService;
|
|
41
|
-
private readonly execFn;
|
|
42
|
-
private readonly registeredWebhooks;
|
|
43
|
-
private readonly deliveryHistory;
|
|
44
|
-
private webhookSecret;
|
|
45
|
-
constructor(featureRepo: IFeatureRepository, gitPrService: IGitPrService, notificationService: INotificationService, execFn: ExecFunction);
|
|
46
|
-
/**
|
|
47
|
-
* Get the webhook secret for signature validation.
|
|
48
|
-
* Exposed so the API route can validate incoming requests.
|
|
49
|
-
*/
|
|
50
|
-
getSecret(): string;
|
|
51
|
-
/**
|
|
52
|
-
* Get the list of registered webhooks (for dashboard display).
|
|
53
|
-
*/
|
|
54
|
-
getRegisteredWebhooks(): readonly RegisteredWebhook[];
|
|
55
|
-
/**
|
|
56
|
-
* Get recent delivery history (newest first).
|
|
57
|
-
*/
|
|
58
|
-
getDeliveryHistory(): readonly WebhookDeliveryRecord[];
|
|
59
|
-
registerWebhooks(publicUrl: string): Promise<void>;
|
|
60
|
-
updateWebhookUrl(newUrl: string): Promise<void>;
|
|
61
|
-
removeWebhooks(): Promise<void>;
|
|
62
|
-
validateSignature(payload: string, signature: string, secret: string): WebhookValidationResult;
|
|
63
|
-
handleEvent(event: WebhookEvent): Promise<void>;
|
|
64
|
-
private recordDelivery;
|
|
65
|
-
private handlePullRequestEvent;
|
|
66
|
-
private handleCheckSuiteEvent;
|
|
67
|
-
private handleCheckRunEvent;
|
|
68
|
-
private findFeatureByPrOrBranch;
|
|
69
|
-
private findFeatureByBranch;
|
|
70
|
-
private updateFeaturePrStatus;
|
|
71
|
-
private updateFeatureCiStatus;
|
|
72
|
-
private registerWebhookForRepo;
|
|
73
|
-
private getRepoFullName;
|
|
74
|
-
}
|
|
75
|
-
//# sourceMappingURL=github-webhook.service.d.ts.map
|
package/dist/packages/core/src/infrastructure/services/webhook/github-webhook.service.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"github-webhook.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/webhook/github-webhook.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,uBAAuB,EACxB,MAAM,yEAAyE,CAAC;AACjF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gFAAgF,CAAC;AACzH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wEAAwE,CAAC;AAC5G,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8EAA8E,CAAC;AASzH,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,MAAM,KACb,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpE,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,qBAAqB,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,qBAAa,oBAAqB,YAAW,eAAe;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAuB;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2B;IAC9D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA+B;IAC/D,OAAO,CAAC,aAAa,CAAS;gBAG5B,WAAW,EAAE,kBAAkB,EAC/B,YAAY,EAAE,aAAa,EAC3B,mBAAmB,EAAE,oBAAoB,EACzC,MAAM,EAAE,YAAY;IAStB;;;OAGG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,qBAAqB,IAAI,SAAS,iBAAiB,EAAE;IAIrD;;OAEG;IACH,kBAAkB,IAAI,SAAS,qBAAqB,EAAE;IAIhD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBlD,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkC/C,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BrC,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,uBAAuB;IAgCxF,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA4CrD,OAAO,CAAC,cAAc;YAOR,sBAAsB;YAsBtB,qBAAqB;YAiBrB,mBAAmB;YAoBnB,uBAAuB;YAWvB,mBAAmB;YAKnB,qBAAqB;YA6CrB,qBAAqB;YA4BrB,sBAAsB;YAqDtB,eAAe;CAe9B"}
|
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub Webhook Service
|
|
3
|
-
*
|
|
4
|
-
* Manages GitHub webhook registration and incoming event processing.
|
|
5
|
-
* Uses the GitHub CLI (`gh api`) for webhook CRUD operations.
|
|
6
|
-
*
|
|
7
|
-
* Webhook events supplement the existing PR sync polling:
|
|
8
|
-
* - Webhooks provide near-instant event delivery
|
|
9
|
-
* - Polling remains as a fallback for missed events
|
|
10
|
-
*
|
|
11
|
-
* Registered events: pull_request, check_suite, check_run
|
|
12
|
-
*/
|
|
13
|
-
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
14
|
-
import { SdlcLifecycle, PrStatus, CiStatus } from '../../../domain/generated/output.js';
|
|
15
|
-
import { NotificationEventType, NotificationSeverity } from '../../../domain/generated/output.js';
|
|
16
|
-
const TAG = '[GitHubWebhook]';
|
|
17
|
-
const WEBHOOK_EVENTS = ['pull_request', 'check_suite', 'check_run'];
|
|
18
|
-
const MAX_EVENT_HISTORY = 200;
|
|
19
|
-
export class GitHubWebhookService {
|
|
20
|
-
featureRepo;
|
|
21
|
-
gitPrService;
|
|
22
|
-
notificationService;
|
|
23
|
-
execFn;
|
|
24
|
-
registeredWebhooks = [];
|
|
25
|
-
deliveryHistory = [];
|
|
26
|
-
webhookSecret;
|
|
27
|
-
constructor(featureRepo, gitPrService, notificationService, execFn) {
|
|
28
|
-
this.featureRepo = featureRepo;
|
|
29
|
-
this.gitPrService = gitPrService;
|
|
30
|
-
this.notificationService = notificationService;
|
|
31
|
-
this.execFn = execFn;
|
|
32
|
-
this.webhookSecret = randomBytes(32).toString('hex');
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Get the webhook secret for signature validation.
|
|
36
|
-
* Exposed so the API route can validate incoming requests.
|
|
37
|
-
*/
|
|
38
|
-
getSecret() {
|
|
39
|
-
return this.webhookSecret;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Get the list of registered webhooks (for dashboard display).
|
|
43
|
-
*/
|
|
44
|
-
getRegisteredWebhooks() {
|
|
45
|
-
return this.registeredWebhooks;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Get recent delivery history (newest first).
|
|
49
|
-
*/
|
|
50
|
-
getDeliveryHistory() {
|
|
51
|
-
return this.deliveryHistory;
|
|
52
|
-
}
|
|
53
|
-
async registerWebhooks(publicUrl) {
|
|
54
|
-
const webhookUrl = `${publicUrl}/api/webhooks/github`;
|
|
55
|
-
// Find all repos with features in Review lifecycle
|
|
56
|
-
const features = await this.featureRepo.list({ lifecycle: SdlcLifecycle.Review });
|
|
57
|
-
const repoPaths = new Set();
|
|
58
|
-
for (const feature of features) {
|
|
59
|
-
if (feature.repositoryPath) {
|
|
60
|
-
repoPaths.add(feature.repositoryPath);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
for (const repoPath of repoPaths) {
|
|
64
|
-
await this.registerWebhookForRepo(repoPath, webhookUrl);
|
|
65
|
-
}
|
|
66
|
-
// eslint-disable-next-line no-console
|
|
67
|
-
console.log(`${TAG} Registered webhooks for ${this.registeredWebhooks.length} repositories`);
|
|
68
|
-
}
|
|
69
|
-
async updateWebhookUrl(newUrl) {
|
|
70
|
-
const webhookUrl = `${newUrl}/api/webhooks/github`;
|
|
71
|
-
for (const webhook of this.registeredWebhooks) {
|
|
72
|
-
try {
|
|
73
|
-
await this.execFn('gh', [
|
|
74
|
-
'api',
|
|
75
|
-
'--method',
|
|
76
|
-
'PATCH',
|
|
77
|
-
`-H`,
|
|
78
|
-
'Accept: application/vnd.github+json',
|
|
79
|
-
`/repos/${webhook.repoFullName}/hooks/${webhook.webhookId}`,
|
|
80
|
-
'-f',
|
|
81
|
-
`config[url]=${webhookUrl}`,
|
|
82
|
-
'-f',
|
|
83
|
-
`config[content_type]=json`,
|
|
84
|
-
'-f',
|
|
85
|
-
`config[secret]=${this.webhookSecret}`,
|
|
86
|
-
], { cwd: webhook.repositoryPath });
|
|
87
|
-
// eslint-disable-next-line no-console
|
|
88
|
-
console.log(`${TAG} Updated webhook URL for ${webhook.repoFullName}`);
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
92
|
-
// eslint-disable-next-line no-console
|
|
93
|
-
console.warn(`${TAG} Failed to update webhook for ${webhook.repoFullName}: ${msg}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
async removeWebhooks() {
|
|
98
|
-
for (const webhook of this.registeredWebhooks) {
|
|
99
|
-
try {
|
|
100
|
-
await this.execFn('gh', [
|
|
101
|
-
'api',
|
|
102
|
-
'--method',
|
|
103
|
-
'DELETE',
|
|
104
|
-
`-H`,
|
|
105
|
-
'Accept: application/vnd.github+json',
|
|
106
|
-
`/repos/${webhook.repoFullName}/hooks/${webhook.webhookId}`,
|
|
107
|
-
], { cwd: webhook.repositoryPath });
|
|
108
|
-
// eslint-disable-next-line no-console
|
|
109
|
-
console.log(`${TAG} Removed webhook for ${webhook.repoFullName}`);
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
113
|
-
// eslint-disable-next-line no-console
|
|
114
|
-
console.warn(`${TAG} Failed to remove webhook for ${webhook.repoFullName}: ${msg}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
this.registeredWebhooks.length = 0;
|
|
118
|
-
}
|
|
119
|
-
validateSignature(payload, signature, secret) {
|
|
120
|
-
if (!signature) {
|
|
121
|
-
return { valid: false, error: 'Missing signature header' };
|
|
122
|
-
}
|
|
123
|
-
const parts = signature.split('=');
|
|
124
|
-
if (parts.length !== 2 || parts[0] !== 'sha256') {
|
|
125
|
-
return { valid: false, error: 'Invalid signature format (expected sha256=...)' };
|
|
126
|
-
}
|
|
127
|
-
const expected = createHmac('sha256', secret).update(payload).digest('hex');
|
|
128
|
-
const actual = parts[1];
|
|
129
|
-
// Use timing-safe comparison to prevent timing attacks
|
|
130
|
-
try {
|
|
131
|
-
const expectedBuf = Buffer.from(expected, 'hex');
|
|
132
|
-
const actualBuf = Buffer.from(actual, 'hex');
|
|
133
|
-
if (expectedBuf.length !== actualBuf.length) {
|
|
134
|
-
return { valid: false, error: 'Signature length mismatch' };
|
|
135
|
-
}
|
|
136
|
-
if (!timingSafeEqual(expectedBuf, actualBuf)) {
|
|
137
|
-
return { valid: false, error: 'Signature mismatch' };
|
|
138
|
-
}
|
|
139
|
-
return { valid: true };
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
return { valid: false, error: 'Invalid signature encoding' };
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
async handleEvent(event) {
|
|
146
|
-
const startTime = Date.now();
|
|
147
|
-
// eslint-disable-next-line no-console
|
|
148
|
-
console.log(`${TAG} Received ${event.source}/${event.eventType} (delivery: ${event.deliveryId})`);
|
|
149
|
-
let status = 'success';
|
|
150
|
-
let statusMessage = 'Processed successfully';
|
|
151
|
-
try {
|
|
152
|
-
switch (event.eventType) {
|
|
153
|
-
case 'pull_request':
|
|
154
|
-
await this.handlePullRequestEvent(event.payload);
|
|
155
|
-
break;
|
|
156
|
-
case 'check_suite':
|
|
157
|
-
await this.handleCheckSuiteEvent(event.payload);
|
|
158
|
-
break;
|
|
159
|
-
case 'check_run':
|
|
160
|
-
await this.handleCheckRunEvent(event.payload);
|
|
161
|
-
break;
|
|
162
|
-
default:
|
|
163
|
-
status = 'ignored';
|
|
164
|
-
statusMessage = `Unhandled event type: ${event.eventType}`;
|
|
165
|
-
// eslint-disable-next-line no-console
|
|
166
|
-
console.log(`${TAG} Ignoring unhandled event type: ${event.eventType}`);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
catch (error) {
|
|
170
|
-
status = 'error';
|
|
171
|
-
statusMessage = error instanceof Error ? error.message : String(error);
|
|
172
|
-
}
|
|
173
|
-
this.recordDelivery({
|
|
174
|
-
deliveryId: event.deliveryId,
|
|
175
|
-
eventType: event.eventType,
|
|
176
|
-
source: event.source,
|
|
177
|
-
receivedAt: new Date().toISOString(),
|
|
178
|
-
status,
|
|
179
|
-
statusMessage,
|
|
180
|
-
durationMs: Date.now() - startTime,
|
|
181
|
-
payload: event.payload,
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
recordDelivery(record) {
|
|
185
|
-
this.deliveryHistory.unshift(record);
|
|
186
|
-
if (this.deliveryHistory.length > MAX_EVENT_HISTORY) {
|
|
187
|
-
this.deliveryHistory.length = MAX_EVENT_HISTORY;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
async handlePullRequestEvent(payload) {
|
|
191
|
-
const action = payload.action;
|
|
192
|
-
const pr = payload.pull_request;
|
|
193
|
-
if (!pr)
|
|
194
|
-
return;
|
|
195
|
-
const prNumber = pr.number;
|
|
196
|
-
const prUrl = pr.html_url ?? '';
|
|
197
|
-
const headBranch = pr.head?.ref;
|
|
198
|
-
// Find feature by PR number or branch
|
|
199
|
-
const feature = await this.findFeatureByPrOrBranch(prNumber, headBranch);
|
|
200
|
-
if (!feature)
|
|
201
|
-
return;
|
|
202
|
-
if (action === 'closed' && pr.merged === true) {
|
|
203
|
-
await this.updateFeaturePrStatus(feature, PrStatus.Merged, prNumber, prUrl);
|
|
204
|
-
}
|
|
205
|
-
else if (action === 'closed') {
|
|
206
|
-
await this.updateFeaturePrStatus(feature, PrStatus.Closed, prNumber, prUrl);
|
|
207
|
-
}
|
|
208
|
-
else if (action === 'reopened') {
|
|
209
|
-
await this.updateFeaturePrStatus(feature, PrStatus.Open, prNumber, prUrl);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
async handleCheckSuiteEvent(payload) {
|
|
213
|
-
const action = payload.action;
|
|
214
|
-
if (action !== 'completed')
|
|
215
|
-
return;
|
|
216
|
-
const checkSuite = payload.check_suite;
|
|
217
|
-
if (!checkSuite)
|
|
218
|
-
return;
|
|
219
|
-
const conclusion = checkSuite.conclusion;
|
|
220
|
-
const headBranch = checkSuite.head_branch;
|
|
221
|
-
const feature = await this.findFeatureByBranch(headBranch);
|
|
222
|
-
if (!feature)
|
|
223
|
-
return;
|
|
224
|
-
const ciStatus = conclusion === 'success' ? CiStatus.Success : CiStatus.Failure;
|
|
225
|
-
await this.updateFeatureCiStatus(feature, ciStatus);
|
|
226
|
-
}
|
|
227
|
-
async handleCheckRunEvent(payload) {
|
|
228
|
-
const action = payload.action;
|
|
229
|
-
if (action !== 'completed')
|
|
230
|
-
return;
|
|
231
|
-
const checkRun = payload.check_run;
|
|
232
|
-
if (!checkRun)
|
|
233
|
-
return;
|
|
234
|
-
const conclusion = checkRun.conclusion;
|
|
235
|
-
const checkSuite = checkRun.check_suite;
|
|
236
|
-
const headBranch = checkSuite?.head_branch;
|
|
237
|
-
if (!headBranch)
|
|
238
|
-
return;
|
|
239
|
-
const feature = await this.findFeatureByBranch(headBranch);
|
|
240
|
-
if (!feature)
|
|
241
|
-
return;
|
|
242
|
-
const ciStatus = conclusion === 'success' ? CiStatus.Success : CiStatus.Failure;
|
|
243
|
-
await this.updateFeatureCiStatus(feature, ciStatus);
|
|
244
|
-
}
|
|
245
|
-
async findFeatureByPrOrBranch(prNumber, branch) {
|
|
246
|
-
const features = await this.featureRepo.list({ lifecycle: SdlcLifecycle.Review });
|
|
247
|
-
// Try matching by PR number first
|
|
248
|
-
const byPr = features.find((f) => f.pr?.number === prNumber);
|
|
249
|
-
if (byPr)
|
|
250
|
-
return byPr;
|
|
251
|
-
// Fall back to branch matching
|
|
252
|
-
return features.find((f) => f.branch === branch) ?? null;
|
|
253
|
-
}
|
|
254
|
-
async findFeatureByBranch(branch) {
|
|
255
|
-
const features = await this.featureRepo.list({ lifecycle: SdlcLifecycle.Review });
|
|
256
|
-
return features.find((f) => f.branch === branch) ?? null;
|
|
257
|
-
}
|
|
258
|
-
async updateFeaturePrStatus(feature, status, prNumber, prUrl) {
|
|
259
|
-
const oldStatus = feature.pr?.status;
|
|
260
|
-
if (oldStatus === status)
|
|
261
|
-
return;
|
|
262
|
-
feature.pr = { ...feature.pr, status, url: prUrl, number: prNumber };
|
|
263
|
-
if (status === PrStatus.Merged) {
|
|
264
|
-
feature.lifecycle = SdlcLifecycle.Maintain;
|
|
265
|
-
}
|
|
266
|
-
await this.featureRepo.update(feature);
|
|
267
|
-
// Emit notification
|
|
268
|
-
const eventType = status === PrStatus.Merged
|
|
269
|
-
? NotificationEventType.PrMerged
|
|
270
|
-
: status === PrStatus.Closed
|
|
271
|
-
? NotificationEventType.PrClosed
|
|
272
|
-
: NotificationEventType.PrChecksPassed; // reopened
|
|
273
|
-
const severity = status === PrStatus.Merged
|
|
274
|
-
? NotificationSeverity.Success
|
|
275
|
-
: status === PrStatus.Closed
|
|
276
|
-
? NotificationSeverity.Warning
|
|
277
|
-
: NotificationSeverity.Info;
|
|
278
|
-
const event = {
|
|
279
|
-
eventType,
|
|
280
|
-
featureId: feature.id,
|
|
281
|
-
agentRunId: feature.agentRunId ?? '',
|
|
282
|
-
featureName: feature.name,
|
|
283
|
-
message: `PR #${prNumber} ${status.toLowerCase()} for ${feature.name} (via webhook)`,
|
|
284
|
-
severity,
|
|
285
|
-
timestamp: new Date().toISOString(),
|
|
286
|
-
};
|
|
287
|
-
this.notificationService.notify(event);
|
|
288
|
-
}
|
|
289
|
-
async updateFeatureCiStatus(feature, ciStatus) {
|
|
290
|
-
if (!feature.pr)
|
|
291
|
-
return;
|
|
292
|
-
if (feature.pr.ciStatus === ciStatus)
|
|
293
|
-
return;
|
|
294
|
-
feature.pr = { ...feature.pr, ciStatus };
|
|
295
|
-
await this.featureRepo.update(feature);
|
|
296
|
-
const eventType = ciStatus === CiStatus.Success
|
|
297
|
-
? NotificationEventType.PrChecksPassed
|
|
298
|
-
: NotificationEventType.PrChecksFailed;
|
|
299
|
-
const severity = ciStatus === CiStatus.Success ? NotificationSeverity.Success : NotificationSeverity.Error;
|
|
300
|
-
const event = {
|
|
301
|
-
eventType,
|
|
302
|
-
featureId: feature.id,
|
|
303
|
-
agentRunId: feature.agentRunId ?? '',
|
|
304
|
-
featureName: feature.name,
|
|
305
|
-
message: `CI ${ciStatus === CiStatus.Success ? 'passed' : 'failed'} for ${feature.name} (via webhook)`,
|
|
306
|
-
severity,
|
|
307
|
-
timestamp: new Date().toISOString(),
|
|
308
|
-
};
|
|
309
|
-
this.notificationService.notify(event);
|
|
310
|
-
}
|
|
311
|
-
async registerWebhookForRepo(repoPath, webhookUrl) {
|
|
312
|
-
try {
|
|
313
|
-
// Get the repo full name (owner/repo) from the remote URL
|
|
314
|
-
const repoFullName = await this.getRepoFullName(repoPath);
|
|
315
|
-
if (!repoFullName) {
|
|
316
|
-
// eslint-disable-next-line no-console
|
|
317
|
-
console.warn(`${TAG} Could not determine repo name for ${repoPath}`);
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
// Create webhook via GitHub API
|
|
321
|
-
const { stdout } = await this.execFn('gh', [
|
|
322
|
-
'api',
|
|
323
|
-
'--method',
|
|
324
|
-
'POST',
|
|
325
|
-
`-H`,
|
|
326
|
-
'Accept: application/vnd.github+json',
|
|
327
|
-
`/repos/${repoFullName}/hooks`,
|
|
328
|
-
'-f',
|
|
329
|
-
'name=web',
|
|
330
|
-
'-f',
|
|
331
|
-
`config[url]=${webhookUrl}`,
|
|
332
|
-
'-f',
|
|
333
|
-
'config[content_type]=json',
|
|
334
|
-
'-f',
|
|
335
|
-
`config[secret]=${this.webhookSecret}`,
|
|
336
|
-
...WEBHOOK_EVENTS.flatMap((e) => ['-f', `events[]=${e}`]),
|
|
337
|
-
'-F',
|
|
338
|
-
'active=true',
|
|
339
|
-
], { cwd: repoPath });
|
|
340
|
-
const response = JSON.parse(stdout);
|
|
341
|
-
const webhookId = response.id;
|
|
342
|
-
this.registeredWebhooks.push({
|
|
343
|
-
repoFullName,
|
|
344
|
-
webhookId,
|
|
345
|
-
repositoryPath: repoPath,
|
|
346
|
-
});
|
|
347
|
-
// eslint-disable-next-line no-console
|
|
348
|
-
console.log(`${TAG} Registered webhook #${webhookId} for ${repoFullName}`);
|
|
349
|
-
}
|
|
350
|
-
catch (error) {
|
|
351
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
352
|
-
// eslint-disable-next-line no-console
|
|
353
|
-
console.warn(`${TAG} Failed to register webhook for ${repoPath}: ${msg}`);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
async getRepoFullName(repoPath) {
|
|
357
|
-
try {
|
|
358
|
-
const remoteUrl = await this.gitPrService.getRemoteUrl(repoPath);
|
|
359
|
-
if (!remoteUrl)
|
|
360
|
-
return null;
|
|
361
|
-
// Parse owner/repo from URL
|
|
362
|
-
// Handles both https://github.com/owner/repo and git@github.com:owner/repo.git
|
|
363
|
-
const match = remoteUrl.match(/github\.com[/:]([\w.-]+)\/([\w.-]+?)(?:\.git)?$/);
|
|
364
|
-
if (!match)
|
|
365
|
-
return null;
|
|
366
|
-
return `${match[1]}/${match[2]}`;
|
|
367
|
-
}
|
|
368
|
-
catch {
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|