@shepai/cli 1.116.0 → 1.116.1-pr369.ea52340
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/eslint.config.mjs +3 -0
- package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts +14 -0
- package/dist/packages/core/src/application/ports/output/services/git-pr-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts +2 -1
- package/dist/packages/core/src/application/ports/output/services/worktree-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/cleanup-feature-worktree.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/cleanup-feature-worktree.use-case.js +6 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts +3 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +30 -2
- package/dist/packages/core/src/application/use-cases/features/delete-feature.use-case.js +1 -1
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +4 -6
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-executor.service.js +6 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts +12 -1
- 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 +98 -26
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/gemini-cli-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/gemini-cli-executor.service.js +13 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +1 -0
- 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 +18 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence.node.js +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.js +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/ci-watch-fix-loop.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/ci-watch-fix-loop.js +13 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts +4 -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 +9 -17
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +8 -4
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/implement.prompt.js +7 -4
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/repair.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/repair.node.js +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.js +1 -0
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +71 -1
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts +1 -1
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +5 -3
- package/dist/packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js +3 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/json-driven-ide-launcher.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/json-driven-ide-launcher.service.js +5 -1
- package/dist/packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.d.ts +5 -0
- package/dist/packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.js +56 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/github-webhook-runtime.service.d.ts +43 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/github-webhook-runtime.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/github-webhook-runtime.service.js +208 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/github-webhook.service.d.ts +25 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/github-webhook.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/github-webhook.service.js +99 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/webhook-secret.service.d.ts +3 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/webhook-secret.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/webhooks/webhook-secret.service.js +19 -0
- package/dist/src/presentation/cli/commands/_serve.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/_serve.command.js +23 -0
- package/dist/src/presentation/cli/commands/ui.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/ui.command.js +16 -0
- package/dist/src/presentation/web/app/api/webhooks/github/route.d.ts +3 -0
- package/dist/src/presentation/web/app/api/webhooks/github/route.d.ts.map +1 -0
- package/dist/src/presentation/web/app/api/webhooks/github/route.js +38 -0
- package/dist/src/presentation/web/dev-server.js +23 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +1 -0
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/routes-manifest.json +6 -0
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +20 -20
- 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/server-reference-manifest.json +26 -26
- 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/server-reference-manifest.json +26 -26
- 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/server-reference-manifest.json +18 -18
- 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/server-reference-manifest.json +20 -20
- 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/server-reference-manifest.json +26 -26
- 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/server-reference-manifest.json +26 -26
- 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/server-reference-manifest.json +18 -18
- 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/server-reference-manifest.json +18 -18
- 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.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/agent-events/route.js +1 -1
- package/web/.next/server/app/api/agent-events/route.js.nft.json +1 -1
- package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
- package/web/.next/server/app/api/graph-data/route.js +1 -1
- package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
- package/web/.next/server/app/api/webhooks/github/route/app-paths-manifest.json +3 -0
- package/web/.next/server/app/api/webhooks/github/route/build-manifest.json +11 -0
- package/web/.next/server/app/api/webhooks/github/route/server-reference-manifest.json +4 -0
- package/web/.next/server/app/api/webhooks/github/route.js +7 -0
- package/web/.next/server/app/api/webhooks/github/route.js.map +5 -0
- package/web/.next/server/app/api/webhooks/github/route.js.nft.json +1 -0
- package/web/.next/server/app/api/webhooks/github/route_client-reference-manifest.js +2 -0
- package/web/.next/server/app/settings/page/server-reference-manifest.json +5 -5
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +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/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/server-reference-manifest.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_0ab2579c.js +4 -0
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_0ab2579c.js.map +1 -0
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_webhooks_github_route_actions_1b0d0c38.js +3 -0
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_webhooks_github_route_actions_1b0d0c38.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__1fd12120._.js +3 -0
- package/web/.next/server/chunks/{[root-of-the-server]__7d5492a0._.js.map → [root-of-the-server]__1fd12120._.js.map} +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__67fab82a._.js +3 -0
- package/web/.next/server/chunks/{[root-of-the-server]__cd67a84c._.js.map → [root-of-the-server]__67fab82a._.js.map} +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__ea37e7e1._.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__ea37e7e1._.js.map +1 -0
- 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_a1104008.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_a1104008.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_92642200.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_92642200.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__039967e3._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__039967e3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__07a39ff2._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__11033878._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2773312c._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2773312c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__5836d236._.js +4 -0
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__24dd0927._.js.map → [root-of-the-server]__5836d236._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__5d87af2e._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6367aea0._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6367aea0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8cb3333c._.js +4 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8cb3333c._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cbd8062c._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__cbd8062c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e70c5627._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e70c5627._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fdc75809._.js.map +1 -1
- 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/{_9f9a0a13._.js → _5fceca1d._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_9f9a0a13._.js.map → _5fceca1d._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{_28c112df._.js → _74b6a797._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_28c112df._.js.map → _74b6a797._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_8dacd1e7._.js +1 -1
- package/web/.next/server/chunks/ssr/_8dacd1e7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_07566303._.js → _bbb7316f._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_07566303._.js.map → _bbb7316f._.js.map} +1 -1
- 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/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_888633e1.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_888633e1.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_ce7cbc3c._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_ce7cbc3c._.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_de814675._.js +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/chunks/ssr/src_presentation_web_e2604413._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_e2604413._.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 +31 -31
- package/web/.next/static/chunks/{685adf3a56420f0b.js → 0aebffb399bbb9ed.js} +1 -1
- package/web/.next/static/chunks/2e8262cd524e9f0c.js +2 -0
- package/web/.next/static/chunks/{6168a928704dfc29.js → 2fbf145a6771f83d.js} +1 -1
- package/web/.next/static/chunks/{526482abdde534e5.js → 55f4d0cdbd44c85c.js} +1 -1
- package/web/.next/static/chunks/{43102414475749cf.js → 64fff64abb23a98a.js} +1 -1
- package/web/.next/static/chunks/{8131c822c4d545e5.js → 692809ab808fb5b0.js} +1 -1
- package/web/.next/static/chunks/{28524a4debc4ab27.js → 739ad28b1bd6139f.js} +1 -1
- package/web/.next/static/chunks/{9c68af62b0ac608c.js → 79cb8d40234e2dae.js} +1 -1
- package/web/.next/static/chunks/80027601774ec110.js +1 -0
- package/web/.next/static/chunks/{4b2abcc77ae796bd.js → e8c2d1bb5972372a.js} +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__7d5492a0._.js +0 -3
- package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__24dd0927._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__89e8a5cc._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__89e8a5cc._.js.map +0 -1
- package/web/.next/static/chunks/281ebd968bf7607f.js +0 -1
- package/web/.next/static/chunks/c51298d5a17232b2.js +0 -2
- /package/web/.next/static/{0KO3WOdJ7F-5vNEe_BKUA → uDyTlPWSuePQAmkQTwP4z}/_buildManifest.js +0 -0
- /package/web/.next/static/{0KO3WOdJ7F-5vNEe_BKUA → uDyTlPWSuePQAmkQTwP4z}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{0KO3WOdJ7F-5vNEe_BKUA → uDyTlPWSuePQAmkQTwP4z}/_ssgManifest.js +0 -0
package/dist/packages/core/src/infrastructure/services/webhooks/github-webhook-runtime.service.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { SdlcLifecycle } from '../../../domain/generated/output.js';
|
|
4
|
+
import { findAvailablePort } from '../port.service.js';
|
|
5
|
+
import { getOrCreateGitHubWebhookSecret } from './webhook-secret.service.js';
|
|
6
|
+
const DEFAULT_GATEWAY_PORT = 4590;
|
|
7
|
+
const DEFAULT_RECONCILE_INTERVAL_MS = 60_000;
|
|
8
|
+
const TUNNEL_READY_TIMEOUT_MS = 15_000;
|
|
9
|
+
const GITHUB_WEBHOOK_CALLBACK_PATH = '/api/webhooks/github?source=shep';
|
|
10
|
+
const ENABLE_ENV = 'SHEP_ENABLE_GITHUB_WEBHOOKS';
|
|
11
|
+
const defaultDeps = {
|
|
12
|
+
createServer: http.createServer,
|
|
13
|
+
spawnProcess: spawn,
|
|
14
|
+
findAvailablePort,
|
|
15
|
+
fetchImpl: fetch,
|
|
16
|
+
getSecret: getOrCreateGitHubWebhookSecret,
|
|
17
|
+
logInfo: (message) => process.stdout.write(`${message}\n`),
|
|
18
|
+
logWarn: (message) => process.stderr.write(`${message}\n`),
|
|
19
|
+
};
|
|
20
|
+
export function isGitHubWebhookRuntimeEnabled() {
|
|
21
|
+
return process.env[ENABLE_ENV] === '1' || process.env[ENABLE_ENV] === 'true';
|
|
22
|
+
}
|
|
23
|
+
export class GitHubWebhookRuntimeService {
|
|
24
|
+
featureRepo;
|
|
25
|
+
webhookService;
|
|
26
|
+
appPort;
|
|
27
|
+
reconcileIntervalMs;
|
|
28
|
+
deps;
|
|
29
|
+
gatewayServer = null;
|
|
30
|
+
tunnelProcess = null;
|
|
31
|
+
reconcileTimer = null;
|
|
32
|
+
publicBaseUrl = null;
|
|
33
|
+
gatewayPort = null;
|
|
34
|
+
secret = null;
|
|
35
|
+
constructor(featureRepo, webhookService, appPort, reconcileIntervalMs = DEFAULT_RECONCILE_INTERVAL_MS, deps = {}) {
|
|
36
|
+
this.featureRepo = featureRepo;
|
|
37
|
+
this.webhookService = webhookService;
|
|
38
|
+
this.appPort = appPort;
|
|
39
|
+
this.reconcileIntervalMs = reconcileIntervalMs;
|
|
40
|
+
this.deps = { ...defaultDeps, ...deps };
|
|
41
|
+
}
|
|
42
|
+
getPublicBaseUrl() {
|
|
43
|
+
return this.publicBaseUrl;
|
|
44
|
+
}
|
|
45
|
+
getGatewayPort() {
|
|
46
|
+
return this.gatewayPort;
|
|
47
|
+
}
|
|
48
|
+
async start() {
|
|
49
|
+
if (!isGitHubWebhookRuntimeEnabled()) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (this.publicBaseUrl) {
|
|
53
|
+
return this.publicBaseUrl;
|
|
54
|
+
}
|
|
55
|
+
this.secret = this.deps.getSecret();
|
|
56
|
+
try {
|
|
57
|
+
this.gatewayPort = await this.deps.findAvailablePort(DEFAULT_GATEWAY_PORT);
|
|
58
|
+
await this.startGateway();
|
|
59
|
+
this.publicBaseUrl = await this.startTunnel();
|
|
60
|
+
await this.reconcileHooks();
|
|
61
|
+
this.reconcileTimer = setInterval(() => {
|
|
62
|
+
void this.reconcileHooks();
|
|
63
|
+
}, this.reconcileIntervalMs);
|
|
64
|
+
this.reconcileTimer.unref?.();
|
|
65
|
+
return this.publicBaseUrl;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
await this.stop();
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async stop() {
|
|
73
|
+
if (this.reconcileTimer) {
|
|
74
|
+
clearInterval(this.reconcileTimer);
|
|
75
|
+
this.reconcileTimer = null;
|
|
76
|
+
}
|
|
77
|
+
if (this.tunnelProcess) {
|
|
78
|
+
this.tunnelProcess.kill('SIGTERM');
|
|
79
|
+
this.tunnelProcess = null;
|
|
80
|
+
}
|
|
81
|
+
if (this.gatewayServer) {
|
|
82
|
+
await new Promise((resolve) => {
|
|
83
|
+
this.gatewayServer.close(() => resolve());
|
|
84
|
+
});
|
|
85
|
+
this.gatewayServer = null;
|
|
86
|
+
}
|
|
87
|
+
this.publicBaseUrl = null;
|
|
88
|
+
this.gatewayPort = null;
|
|
89
|
+
}
|
|
90
|
+
async startGateway() {
|
|
91
|
+
const port = this.gatewayPort;
|
|
92
|
+
if (!port) {
|
|
93
|
+
throw new Error('Gateway port not allocated');
|
|
94
|
+
}
|
|
95
|
+
const server = this.deps.createServer((req, res) => {
|
|
96
|
+
void this.handleGatewayRequest(req, res);
|
|
97
|
+
});
|
|
98
|
+
await new Promise((resolve, reject) => {
|
|
99
|
+
server.once('error', reject);
|
|
100
|
+
server.listen(port, '127.0.0.1', () => resolve());
|
|
101
|
+
});
|
|
102
|
+
this.gatewayServer = server;
|
|
103
|
+
}
|
|
104
|
+
async handleGatewayRequest(req, res) {
|
|
105
|
+
if (!req.url?.startsWith('/api/webhooks/')) {
|
|
106
|
+
res.statusCode = 404;
|
|
107
|
+
res.end('Not found');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const body = await this.readRequestBody(req);
|
|
111
|
+
const headers = new Headers();
|
|
112
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
113
|
+
if (!value)
|
|
114
|
+
continue;
|
|
115
|
+
if (key === 'host' || key === 'connection' || key === 'content-length')
|
|
116
|
+
continue;
|
|
117
|
+
if (Array.isArray(value)) {
|
|
118
|
+
for (const item of value)
|
|
119
|
+
headers.append(key, item);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
headers.set(key, value);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const requestBody = this.requestCanHaveBody(req.method) ? new Uint8Array(body) : undefined;
|
|
126
|
+
const response = await this.deps.fetchImpl(`http://127.0.0.1:${this.appPort}${req.url}`, {
|
|
127
|
+
method: req.method,
|
|
128
|
+
headers,
|
|
129
|
+
body: requestBody,
|
|
130
|
+
});
|
|
131
|
+
res.statusCode = response.status;
|
|
132
|
+
response.headers.forEach((value, key) => {
|
|
133
|
+
res.setHeader(key, value);
|
|
134
|
+
});
|
|
135
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
136
|
+
res.end(buffer);
|
|
137
|
+
}
|
|
138
|
+
requestCanHaveBody(method) {
|
|
139
|
+
return method !== undefined && method !== 'GET' && method !== 'HEAD';
|
|
140
|
+
}
|
|
141
|
+
async readRequestBody(req) {
|
|
142
|
+
const chunks = [];
|
|
143
|
+
for await (const chunk of req) {
|
|
144
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
145
|
+
}
|
|
146
|
+
return Buffer.concat(chunks);
|
|
147
|
+
}
|
|
148
|
+
async startTunnel() {
|
|
149
|
+
const port = this.gatewayPort;
|
|
150
|
+
if (!port) {
|
|
151
|
+
throw new Error('Gateway port not allocated');
|
|
152
|
+
}
|
|
153
|
+
const child = this.deps.spawnProcess(process.env.SHEP_CLOUDFLARED_BIN ?? 'cloudflared', ['tunnel', '--url', `http://127.0.0.1:${port}`], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
154
|
+
this.tunnelProcess = child;
|
|
155
|
+
const publicUrl = await new Promise((resolve, reject) => {
|
|
156
|
+
const timeout = setTimeout(() => {
|
|
157
|
+
cleanup();
|
|
158
|
+
reject(new Error('Timed out waiting for cloudflared public URL'));
|
|
159
|
+
}, TUNNEL_READY_TIMEOUT_MS);
|
|
160
|
+
const onData = (chunk) => {
|
|
161
|
+
const match = String(chunk).match(/https:\/\/[a-zA-Z0-9.-]+\.trycloudflare\.com/);
|
|
162
|
+
if (!match)
|
|
163
|
+
return;
|
|
164
|
+
cleanup();
|
|
165
|
+
resolve(match[0]);
|
|
166
|
+
};
|
|
167
|
+
const onExit = (code) => {
|
|
168
|
+
cleanup();
|
|
169
|
+
reject(new Error(`cloudflared exited before URL was ready (code ${code ?? 'unknown'})`));
|
|
170
|
+
};
|
|
171
|
+
const cleanup = () => {
|
|
172
|
+
clearTimeout(timeout);
|
|
173
|
+
child.stdout?.off('data', onData);
|
|
174
|
+
child.stderr?.off('data', onData);
|
|
175
|
+
child.off('exit', onExit);
|
|
176
|
+
};
|
|
177
|
+
child.stdout?.on('data', onData);
|
|
178
|
+
child.stderr?.on('data', onData);
|
|
179
|
+
child.on('exit', onExit);
|
|
180
|
+
});
|
|
181
|
+
this.deps.logInfo(`[GitHubWebhookRuntime] Tunnel ready at ${publicUrl}`);
|
|
182
|
+
return publicUrl;
|
|
183
|
+
}
|
|
184
|
+
async reconcileHooks() {
|
|
185
|
+
if (!this.publicBaseUrl || !this.secret)
|
|
186
|
+
return;
|
|
187
|
+
const features = await this.featureRepo.list({ lifecycle: SdlcLifecycle.Review });
|
|
188
|
+
const repoPaths = [
|
|
189
|
+
...new Set(features.map((feature) => feature.repositoryPath).filter(Boolean)),
|
|
190
|
+
];
|
|
191
|
+
for (const repoPath of repoPaths) {
|
|
192
|
+
try {
|
|
193
|
+
const result = await this.webhookService.ensureRepositoryWebhook(repoPath, {
|
|
194
|
+
callbackUrl: `${this.publicBaseUrl}${GITHUB_WEBHOOK_CALLBACK_PATH}`,
|
|
195
|
+
secret: this.secret,
|
|
196
|
+
events: ['pull_request', 'check_suite'],
|
|
197
|
+
});
|
|
198
|
+
if (result.action !== 'unchanged' && result.action !== 'skipped') {
|
|
199
|
+
this.deps.logInfo(`[GitHubWebhookRuntime] ${result.action} webhook for ${repoPath} -> ${result.callbackUrl ?? 'n/a'}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
204
|
+
this.deps.logWarn(`[GitHubWebhookRuntime] Failed to reconcile ${repoPath}: ${msg}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ExecFunction } from '../git/worktree.service.js';
|
|
2
|
+
import type { IGitPrService } from '../../../application/ports/output/services/git-pr-service.interface.js';
|
|
3
|
+
export interface GitHubWebhookConfig {
|
|
4
|
+
callbackUrl: string;
|
|
5
|
+
secret: string;
|
|
6
|
+
events: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface GitHubWebhookSyncResult {
|
|
9
|
+
action: 'created' | 'updated' | 'unchanged' | 'skipped';
|
|
10
|
+
hookId?: number;
|
|
11
|
+
callbackUrl?: string;
|
|
12
|
+
}
|
|
13
|
+
declare const SHEP_WEBHOOK_MARKER = "source=shep";
|
|
14
|
+
export declare class GitHubWebhookService {
|
|
15
|
+
private readonly execFile;
|
|
16
|
+
private readonly gitPrService;
|
|
17
|
+
constructor(execFile: ExecFunction, gitPrService: Pick<IGitPrService, 'getRemoteUrl'>);
|
|
18
|
+
ensureRepositoryWebhook(cwd: string, config: GitHubWebhookConfig): Promise<GitHubWebhookSyncResult>;
|
|
19
|
+
private listHooks;
|
|
20
|
+
private buildMutationArgs;
|
|
21
|
+
private isHookUpToDate;
|
|
22
|
+
private parseHookPayload;
|
|
23
|
+
}
|
|
24
|
+
export { SHEP_WEBHOOK_MARKER };
|
|
25
|
+
//# sourceMappingURL=github-webhook.service.d.ts.map
|
package/dist/packages/core/src/infrastructure/services/webhooks/github-webhook.service.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-webhook.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/webhooks/github-webhook.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qEAAqE,CAAC;AAEzG,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAYD,QAAA,MAAM,mBAAmB,gBAAgB,CAAC;AAkB1C,qBAAa,oBAAoB;IAE7B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,QAAQ,EAAE,YAAY,EACtB,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC;IAG9D,uBAAuB,CAC3B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,uBAAuB,CAAC;YAmDrB,SAAS;IAKvB,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,gBAAgB;CAIzB;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const SHEP_WEBHOOK_MARKER = 'source=shep';
|
|
2
|
+
function parseGitHubOwnerRepo(remoteUrl) {
|
|
3
|
+
if (!remoteUrl)
|
|
4
|
+
return null;
|
|
5
|
+
const httpsMatch = remoteUrl.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
6
|
+
if (httpsMatch) {
|
|
7
|
+
return { owner: httpsMatch[1], repo: httpsMatch[2] };
|
|
8
|
+
}
|
|
9
|
+
const sshMatch = remoteUrl.match(/^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
10
|
+
if (sshMatch) {
|
|
11
|
+
return { owner: sshMatch[1], repo: sshMatch[2] };
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
export class GitHubWebhookService {
|
|
16
|
+
execFile;
|
|
17
|
+
gitPrService;
|
|
18
|
+
constructor(execFile, gitPrService) {
|
|
19
|
+
this.execFile = execFile;
|
|
20
|
+
this.gitPrService = gitPrService;
|
|
21
|
+
}
|
|
22
|
+
async ensureRepositoryWebhook(cwd, config) {
|
|
23
|
+
const remoteUrl = await this.gitPrService.getRemoteUrl(cwd);
|
|
24
|
+
const repo = parseGitHubOwnerRepo(remoteUrl);
|
|
25
|
+
if (!repo) {
|
|
26
|
+
return { action: 'skipped' };
|
|
27
|
+
}
|
|
28
|
+
const hooksPath = `repos/${repo.owner}/${repo.repo}/hooks`;
|
|
29
|
+
const hooks = await this.listHooks(cwd, hooksPath);
|
|
30
|
+
const existing = hooks.find((hook) => hook.config?.url?.includes(SHEP_WEBHOOK_MARKER));
|
|
31
|
+
if (!existing) {
|
|
32
|
+
const created = await this.execFile('gh', ['api', hooksPath, '--method', 'POST', ...this.buildMutationArgs(config)], { cwd });
|
|
33
|
+
const payload = this.parseHookPayload(created.stdout);
|
|
34
|
+
return {
|
|
35
|
+
action: 'created',
|
|
36
|
+
hookId: payload?.id,
|
|
37
|
+
callbackUrl: config.callbackUrl,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (this.isHookUpToDate(existing, config)) {
|
|
41
|
+
return {
|
|
42
|
+
action: 'unchanged',
|
|
43
|
+
hookId: existing.id,
|
|
44
|
+
callbackUrl: config.callbackUrl,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
await this.execFile('gh', [
|
|
48
|
+
'api',
|
|
49
|
+
`${hooksPath}/${existing.id}`,
|
|
50
|
+
'--method',
|
|
51
|
+
'PATCH',
|
|
52
|
+
...this.buildMutationArgs(config),
|
|
53
|
+
], { cwd });
|
|
54
|
+
return {
|
|
55
|
+
action: 'updated',
|
|
56
|
+
hookId: existing.id,
|
|
57
|
+
callbackUrl: config.callbackUrl,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
async listHooks(cwd, hooksPath) {
|
|
61
|
+
const result = await this.execFile('gh', ['api', hooksPath], { cwd });
|
|
62
|
+
return JSON.parse(result.stdout) ?? [];
|
|
63
|
+
}
|
|
64
|
+
buildMutationArgs(config) {
|
|
65
|
+
const args = [
|
|
66
|
+
'-f',
|
|
67
|
+
'name=web',
|
|
68
|
+
'-f',
|
|
69
|
+
'active=true',
|
|
70
|
+
'-f',
|
|
71
|
+
`config[url]=${config.callbackUrl}`,
|
|
72
|
+
'-f',
|
|
73
|
+
'config[content_type]=json',
|
|
74
|
+
'-f',
|
|
75
|
+
`config[secret]=${config.secret}`,
|
|
76
|
+
'-f',
|
|
77
|
+
'config[insecure_ssl]=0',
|
|
78
|
+
];
|
|
79
|
+
for (const event of config.events) {
|
|
80
|
+
args.push('-f', `events[]=${event}`);
|
|
81
|
+
}
|
|
82
|
+
return args;
|
|
83
|
+
}
|
|
84
|
+
isHookUpToDate(hook, config) {
|
|
85
|
+
const actualEvents = [...(hook.events ?? [])].sort();
|
|
86
|
+
const desiredEvents = [...config.events].sort();
|
|
87
|
+
return (hook.active === true &&
|
|
88
|
+
hook.config?.url === config.callbackUrl &&
|
|
89
|
+
hook.config?.content_type === 'json' &&
|
|
90
|
+
actualEvents.length === desiredEvents.length &&
|
|
91
|
+
actualEvents.every((event, index) => event === desiredEvents[index]));
|
|
92
|
+
}
|
|
93
|
+
parseHookPayload(stdout) {
|
|
94
|
+
if (!stdout.trim())
|
|
95
|
+
return null;
|
|
96
|
+
return JSON.parse(stdout);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export { SHEP_WEBHOOK_MARKER };
|
package/dist/packages/core/src/infrastructure/services/webhooks/webhook-secret.service.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-secret.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/webhooks/webhook-secret.service.ts"],"names":[],"mappings":"AAQA,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD;AAED,wBAAgB,8BAA8B,IAAI,MAAM,CAUvD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { randomBytes } from 'node:crypto';
|
|
4
|
+
import { getShepHomeDir } from '../filesystem/shep-directory.service.js';
|
|
5
|
+
const WEBHOOK_SECRET_DIR = 'webhooks';
|
|
6
|
+
const GITHUB_SECRET_FILE = 'github.secret';
|
|
7
|
+
export function getGitHubWebhookSecretPath() {
|
|
8
|
+
return join(getShepHomeDir(), WEBHOOK_SECRET_DIR, GITHUB_SECRET_FILE);
|
|
9
|
+
}
|
|
10
|
+
export function getOrCreateGitHubWebhookSecret() {
|
|
11
|
+
const secretPath = getGitHubWebhookSecretPath();
|
|
12
|
+
if (existsSync(secretPath)) {
|
|
13
|
+
return readFileSync(secretPath, 'utf8').trim();
|
|
14
|
+
}
|
|
15
|
+
mkdirSync(join(getShepHomeDir(), WEBHOOK_SECRET_DIR), { recursive: true });
|
|
16
|
+
const secret = randomBytes(32).toString('hex');
|
|
17
|
+
writeFileSync(secretPath, `${secret}\n`, { mode: 0o600 });
|
|
18
|
+
return secret;
|
|
19
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_serve.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/_serve.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"_serve.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/_serve.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,OAAO,EAAwB,MAAM,WAAW,CAAC;AAoC1D;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAqF5C"}
|
|
@@ -29,6 +29,10 @@ import { container } from '../../../../packages/core/src/infrastructure/di/conta
|
|
|
29
29
|
import { setVersionEnvVars } from '../../../../packages/core/src/infrastructure/services/version.service.js';
|
|
30
30
|
import { resolveWebDir } from '../../../../packages/core/src/infrastructure/services/web-server.service.js';
|
|
31
31
|
import { initializeNotificationWatcher, getNotificationWatcher, } from '../../../../packages/core/src/infrastructure/services/notifications/notification-watcher.service.js';
|
|
32
|
+
import { initializePrSyncWatcher, getPrSyncWatcher, } from '../../../../packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.js';
|
|
33
|
+
import { getExistingConnection } from '../../../../packages/core/src/infrastructure/persistence/sqlite/connection.js';
|
|
34
|
+
import { GitHubWebhookRuntimeService, isGitHubWebhookRuntimeEnabled, } from '../../../../packages/core/src/infrastructure/services/webhooks/github-webhook-runtime.service.js';
|
|
35
|
+
import { GitHubWebhookService } from '../../../../packages/core/src/infrastructure/services/webhooks/github-webhook.service.js';
|
|
32
36
|
function parsePort(value) {
|
|
33
37
|
const port = parseInt(value, 10);
|
|
34
38
|
if (isNaN(port) || port < 1024 || port > 65535) {
|
|
@@ -62,6 +66,23 @@ export function createServeCommand() {
|
|
|
62
66
|
const notificationService = container.resolve('INotificationService');
|
|
63
67
|
initializeNotificationWatcher(runRepo, phaseTimingRepo, featureRepo, notificationService);
|
|
64
68
|
getNotificationWatcher().start();
|
|
69
|
+
const gitPrService = container.resolve('IGitPrService');
|
|
70
|
+
const db = getExistingConnection();
|
|
71
|
+
initializePrSyncWatcher(featureRepo, runRepo, gitPrService, notificationService, undefined, db);
|
|
72
|
+
getPrSyncWatcher().start();
|
|
73
|
+
let webhookRuntime = null;
|
|
74
|
+
if (isGitHubWebhookRuntimeEnabled()) {
|
|
75
|
+
try {
|
|
76
|
+
const execFile = container.resolve('ExecFunction');
|
|
77
|
+
const webhookService = new GitHubWebhookService(execFile, gitPrService);
|
|
78
|
+
webhookRuntime = new GitHubWebhookRuntimeService(featureRepo, webhookService, port);
|
|
79
|
+
await webhookRuntime.start();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
83
|
+
process.stderr.write(`[_serve] GitHub webhook runtime disabled: ${err.message}\n`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
65
86
|
// Graceful shutdown handler — identical pattern to ui.command.ts
|
|
66
87
|
let isShuttingDown = false;
|
|
67
88
|
const shutdown = async () => {
|
|
@@ -71,6 +92,8 @@ export function createServeCommand() {
|
|
|
71
92
|
// Force exit after 5s if graceful shutdown stalls
|
|
72
93
|
const forceExit = setTimeout(() => process.exit(0), 5000);
|
|
73
94
|
forceExit.unref();
|
|
95
|
+
await webhookRuntime?.stop();
|
|
96
|
+
getPrSyncWatcher().stop();
|
|
74
97
|
getNotificationWatcher().stop();
|
|
75
98
|
const deploymentService = container.resolve('IDeploymentService');
|
|
76
99
|
deploymentService.stopAll();
|
|
@@ -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;AAsC1D;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAwGzC"}
|
|
@@ -23,6 +23,8 @@ import { initializeNotificationWatcher, getNotificationWatcher, } from '../../..
|
|
|
23
23
|
import { initializePrSyncWatcher, getPrSyncWatcher, } from '../../../../packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.js';
|
|
24
24
|
import { getExistingConnection } from '../../../../packages/core/src/infrastructure/persistence/sqlite/connection.js';
|
|
25
25
|
import { BrowserOpenerService } from '../../../../packages/core/src/infrastructure/services/browser-opener.service.js';
|
|
26
|
+
import { GitHubWebhookRuntimeService, isGitHubWebhookRuntimeEnabled, } from '../../../../packages/core/src/infrastructure/services/webhooks/github-webhook-runtime.service.js';
|
|
27
|
+
import { GitHubWebhookService } from '../../../../packages/core/src/infrastructure/services/webhooks/github-webhook.service.js';
|
|
26
28
|
import { colors, fmt, messages } from '../ui/index.js';
|
|
27
29
|
function parsePort(value) {
|
|
28
30
|
const port = parseInt(value, 10);
|
|
@@ -70,6 +72,19 @@ Examples:
|
|
|
70
72
|
const db = getExistingConnection();
|
|
71
73
|
initializePrSyncWatcher(featureRepo, runRepo, gitPrService, notificationService, undefined, db);
|
|
72
74
|
getPrSyncWatcher().start();
|
|
75
|
+
let webhookRuntime = null;
|
|
76
|
+
if (isGitHubWebhookRuntimeEnabled()) {
|
|
77
|
+
try {
|
|
78
|
+
const execFile = container.resolve('ExecFunction');
|
|
79
|
+
const webhookService = new GitHubWebhookService(execFile, gitPrService);
|
|
80
|
+
webhookRuntime = new GitHubWebhookRuntimeService(featureRepo, webhookService, port);
|
|
81
|
+
await webhookRuntime.start();
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
85
|
+
messages.warning(`GitHub webhook runtime disabled: ${err.message}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
73
88
|
const url = `http://localhost:${port}`;
|
|
74
89
|
messages.success(`Server ready at ${fmt.code(url)}`);
|
|
75
90
|
messages.info('Press Ctrl+C to stop');
|
|
@@ -91,6 +106,7 @@ Examples:
|
|
|
91
106
|
// Force exit after 5s if graceful shutdown stalls
|
|
92
107
|
const forceExit = setTimeout(() => process.exit(0), 5000);
|
|
93
108
|
forceExit.unref();
|
|
109
|
+
await webhookRuntime?.stop();
|
|
94
110
|
getPrSyncWatcher().stop();
|
|
95
111
|
getNotificationWatcher().stop();
|
|
96
112
|
await service.stop();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/webhooks/github/route.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAiBvC,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2B9D"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { getPrSyncWatcher, hasPrSyncWatcher, } from '../../../../../../../packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.js';
|
|
3
|
+
import { getOrCreateGitHubWebhookSecret } from '../../../../../../../packages/core/src/infrastructure/services/webhooks/webhook-secret.service.js';
|
|
4
|
+
export const dynamic = 'force-dynamic';
|
|
5
|
+
function isValidSignature(rawBody, signatureHeader, secret) {
|
|
6
|
+
if (!signatureHeader?.startsWith('sha256='))
|
|
7
|
+
return false;
|
|
8
|
+
const digest = createHmac('sha256', secret).update(rawBody).digest('hex');
|
|
9
|
+
const expected = Buffer.from(`sha256=${digest}`);
|
|
10
|
+
const received = Buffer.from(signatureHeader);
|
|
11
|
+
if (expected.length !== received.length)
|
|
12
|
+
return false;
|
|
13
|
+
return timingSafeEqual(expected, received);
|
|
14
|
+
}
|
|
15
|
+
export async function POST(request) {
|
|
16
|
+
const rawBody = await request.text();
|
|
17
|
+
const secret = getOrCreateGitHubWebhookSecret();
|
|
18
|
+
const signature = request.headers.get('x-hub-signature-256');
|
|
19
|
+
if (!isValidSignature(rawBody, signature, secret)) {
|
|
20
|
+
return Response.json({ error: 'Invalid GitHub webhook signature' }, { status: 401 });
|
|
21
|
+
}
|
|
22
|
+
let payload;
|
|
23
|
+
try {
|
|
24
|
+
payload = JSON.parse(rawBody);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return Response.json({ error: 'Invalid JSON payload' }, { status: 400 });
|
|
28
|
+
}
|
|
29
|
+
const fullName = payload.repository?.full_name;
|
|
30
|
+
if (!fullName) {
|
|
31
|
+
return Response.json({ error: 'Missing repository.full_name' }, { status: 400 });
|
|
32
|
+
}
|
|
33
|
+
if (!hasPrSyncWatcher()) {
|
|
34
|
+
return Response.json({ accepted: true, refreshed: false }, { status: 202 });
|
|
35
|
+
}
|
|
36
|
+
const refreshed = await getPrSyncWatcher().syncRepositoryByGitHubFullName(fullName);
|
|
37
|
+
return Response.json({ accepted: true, refreshed }, { status: 202 });
|
|
38
|
+
}
|
|
@@ -20,6 +20,8 @@ import { initializeSettings } from '../../../packages/core/src/infrastructure/se
|
|
|
20
20
|
import { initializeNotificationWatcher, getNotificationWatcher, } from '../../../packages/core/src/infrastructure/services/notifications/notification-watcher.service.js';
|
|
21
21
|
import { initializePrSyncWatcher, getPrSyncWatcher, } from '../../../packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.js';
|
|
22
22
|
import { getExistingConnection } from '../../../packages/core/src/infrastructure/persistence/sqlite/connection.js';
|
|
23
|
+
import { GitHubWebhookRuntimeService, isGitHubWebhookRuntimeEnabled, } from '../../../packages/core/src/infrastructure/services/webhooks/github-webhook-runtime.service.js';
|
|
24
|
+
import { GitHubWebhookService } from '../../../packages/core/src/infrastructure/services/webhooks/github-webhook.service.js';
|
|
23
25
|
const DEFAULT_PORT = 3000;
|
|
24
26
|
async function isPortAvailable(port) {
|
|
25
27
|
return new Promise((resolve) => {
|
|
@@ -68,6 +70,19 @@ async function main() {
|
|
|
68
70
|
const db = getExistingConnection();
|
|
69
71
|
initializePrSyncWatcher(featureRepo, runRepo, gitPrService, notificationService, undefined, db);
|
|
70
72
|
getPrSyncWatcher().start();
|
|
73
|
+
let webhookRuntime = null;
|
|
74
|
+
if (isGitHubWebhookRuntimeEnabled()) {
|
|
75
|
+
try {
|
|
76
|
+
const execFile = container.resolve('ExecFunction');
|
|
77
|
+
const webhookService = new GitHubWebhookService(execFile, gitPrService);
|
|
78
|
+
webhookRuntime = new GitHubWebhookRuntimeService(featureRepo, webhookService, port);
|
|
79
|
+
await webhookRuntime.start();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.warn('[dev-server] GitHub webhook runtime disabled:', error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
globalThis.__shepGithubWebhookRuntime = webhookRuntime;
|
|
71
86
|
}
|
|
72
87
|
catch (error) {
|
|
73
88
|
console.warn('[dev-server] DI initialization failed — features will be empty:', error);
|
|
@@ -107,6 +122,14 @@ async function main() {
|
|
|
107
122
|
console.log('\n[dev-server] Shutting down...');
|
|
108
123
|
const forceExit = setTimeout(() => process.exit(0), 2000);
|
|
109
124
|
try {
|
|
125
|
+
try {
|
|
126
|
+
const webhookRuntime = globalThis
|
|
127
|
+
.__shepGithubWebhookRuntime;
|
|
128
|
+
await webhookRuntime?.stop();
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
/* runtime not initialized */
|
|
132
|
+
}
|
|
110
133
|
try {
|
|
111
134
|
getNotificationWatcher().stop();
|
|
112
135
|
}
|