@shepai/cli 1.140.0 → 1.141.0-pr452.1d8e904

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.
Files changed (228) hide show
  1. package/apis/json-schema/Feature.yaml +10 -0
  2. package/apis/json-schema/PullRequest.yaml +11 -0
  3. package/apis/json-schema/SdlcLifecycle.yaml +1 -0
  4. package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts +2 -0
  5. package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
  6. package/dist/packages/core/src/application/ports/output/services/git-fork-service.interface.d.ts +79 -0
  7. package/dist/packages/core/src/application/ports/output/services/git-fork-service.interface.d.ts.map +1 -0
  8. package/dist/packages/core/src/application/ports/output/services/git-fork-service.interface.js +31 -0
  9. package/dist/packages/core/src/application/use-cases/features/adopt-branch.use-case.d.ts.map +1 -1
  10. package/dist/packages/core/src/application/use-cases/features/adopt-branch.use-case.js +2 -0
  11. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  12. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +4 -0
  13. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts +4 -0
  14. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts.map +1 -1
  15. package/dist/packages/core/src/application/use-cases/features/poll-upstream-pr.use-case.d.ts +23 -0
  16. package/dist/packages/core/src/application/use-cases/features/poll-upstream-pr.use-case.d.ts.map +1 -0
  17. package/dist/packages/core/src/application/use-cases/features/poll-upstream-pr.use-case.js +84 -0
  18. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -1
  19. package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.js +2 -0
  20. package/dist/packages/core/src/domain/generated/output.d.ts +21 -0
  21. package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
  22. package/dist/packages/core/src/domain/generated/output.js +1 -0
  23. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  24. package/dist/packages/core/src/infrastructure/di/container.js +2 -0
  25. package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/feature.mapper.d.ts +5 -0
  26. package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/feature.mapper.d.ts.map +1 -1
  27. package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/feature.mapper.js +12 -0
  28. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/045-add-fork-and-pr-columns.d.ts +13 -0
  29. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/045-add-fork-and-pr-columns.d.ts.map +1 -0
  30. package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/045-add-fork-and-pr-columns.js +30 -0
  31. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/fast-feature-agent-graph.d.ts +10 -0
  32. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/fast-feature-agent-graph.d.ts.map +1 -1
  33. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +34 -0
  34. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
  35. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +2 -0
  36. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
  37. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +6 -0
  38. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +2 -0
  39. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  40. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +11 -0
  41. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts +2 -0
  42. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
  43. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +50 -0
  44. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.d.ts +2 -0
  45. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.d.ts.map +1 -1
  46. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.js +8 -0
  47. package/dist/packages/core/src/infrastructure/services/git/git-fork.service.d.ts +25 -0
  48. package/dist/packages/core/src/infrastructure/services/git/git-fork.service.d.ts.map +1 -0
  49. package/dist/packages/core/src/infrastructure/services/git/git-fork.service.js +145 -0
  50. package/dist/packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.d.ts +17 -3
  51. package/dist/packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.d.ts.map +1 -1
  52. package/dist/packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.js +98 -15
  53. package/dist/src/presentation/cli/commands/ui.command.d.ts.map +1 -1
  54. package/dist/src/presentation/cli/commands/ui.command.js +2 -1
  55. package/dist/src/presentation/web/app/api/agent-events/route.d.ts.map +1 -1
  56. package/dist/src/presentation/web/app/api/agent-events/route.js +1 -0
  57. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts +4 -0
  58. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
  59. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +23 -6
  60. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts +11 -0
  61. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts.map +1 -1
  62. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.js +34 -0
  63. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts +1 -1
  64. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts.map +1 -1
  65. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.js +12 -0
  66. package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
  67. package/dist/src/presentation/web/components/common/feature-node/feature-node.js +1 -1
  68. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map +1 -1
  69. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.js +1 -0
  70. package/dist/src/presentation/web/dev-server.js +2 -1
  71. package/dist/tsconfig.build.tsbuildinfo +1 -1
  72. package/package.json +1 -1
  73. package/web/.next/BUILD_ID +1 -1
  74. package/web/.next/build-manifest.json +2 -2
  75. package/web/.next/fallback-build-manifest.json +2 -2
  76. package/web/.next/prerender-manifest.json +3 -3
  77. package/web/.next/required-server-files.js +3 -3
  78. package/web/.next/required-server-files.json +3 -3
  79. package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +28 -28
  80. package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
  81. package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
  82. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +28 -28
  83. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  84. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  85. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
  86. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  87. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  88. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +36 -36
  89. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  90. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
  92. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  93. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  94. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +28 -28
  95. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  96. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  97. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
  98. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  99. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  100. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +36 -36
  101. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  102. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  103. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +26 -26
  104. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  105. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  106. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
  107. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  108. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  109. package/web/.next/server/app/_global-error.html +2 -2
  110. package/web/.next/server/app/_global-error.rsc +1 -1
  111. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  112. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  113. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  114. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  115. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  116. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +3 -3
  117. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  118. package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  119. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  120. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  121. package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
  122. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  123. package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
  124. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  125. package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
  126. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  127. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js +2 -2
  128. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_4d623b8e.js.map +1 -1
  129. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  130. package/web/.next/server/chunks/[root-of-the-server]__c6e32a23._.js +1 -1
  131. package/web/.next/server/chunks/[root-of-the-server]__c6e32a23._.js.map +1 -1
  132. package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js +1 -1
  133. package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js.map +1 -1
  134. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  135. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  136. package/web/.next/server/chunks/ssr/[root-of-the-server]__2bdf88a0._.js +1 -1
  137. package/web/.next/server/chunks/ssr/[root-of-the-server]__2bdf88a0._.js.map +1 -1
  138. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  139. package/web/.next/server/chunks/ssr/[root-of-the-server]__3ef34e4c._.js +1 -1
  140. package/web/.next/server/chunks/ssr/[root-of-the-server]__42faf5ae._.js +1 -1
  141. package/web/.next/server/chunks/ssr/[root-of-the-server]__42faf5ae._.js.map +1 -1
  142. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
  143. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
  144. package/web/.next/server/chunks/ssr/[root-of-the-server]__685ee565._.js +1 -1
  145. package/web/.next/server/chunks/ssr/[root-of-the-server]__685ee565._.js.map +1 -1
  146. package/web/.next/server/chunks/ssr/[root-of-the-server]__6ec59045._.js +1 -1
  147. package/web/.next/server/chunks/ssr/[root-of-the-server]__6ec59045._.js.map +1 -1
  148. package/web/.next/server/chunks/ssr/[root-of-the-server]__74756aae._.js +1 -1
  149. package/web/.next/server/chunks/ssr/[root-of-the-server]__74756aae._.js.map +1 -1
  150. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
  151. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
  152. package/web/.next/server/chunks/ssr/[root-of-the-server]__a5f9c6e5._.js +2 -2
  153. package/web/.next/server/chunks/ssr/[root-of-the-server]__a5f9c6e5._.js.map +1 -1
  154. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +2 -2
  155. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  156. package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js +1 -1
  157. package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js.map +1 -1
  158. package/web/.next/server/chunks/ssr/[root-of-the-server]__df7c1cd3._.js +3 -0
  159. package/web/.next/server/chunks/ssr/[root-of-the-server]__df7c1cd3._.js.map +1 -0
  160. package/web/.next/server/chunks/ssr/_02ec1aea._.js +1 -1
  161. package/web/.next/server/chunks/ssr/_02ec1aea._.js.map +1 -1
  162. package/web/.next/server/chunks/ssr/_0c5f56e3._.js +2 -2
  163. package/web/.next/server/chunks/ssr/_0c5f56e3._.js.map +1 -1
  164. package/web/.next/server/chunks/ssr/_1b719e7f._.js +1 -1
  165. package/web/.next/server/chunks/ssr/_1b719e7f._.js.map +1 -1
  166. package/web/.next/server/chunks/ssr/_37e8548b._.js +1 -1
  167. package/web/.next/server/chunks/ssr/_37e8548b._.js.map +1 -1
  168. package/web/.next/server/chunks/ssr/_55d763e2._.js +1 -1
  169. package/web/.next/server/chunks/ssr/_55d763e2._.js.map +1 -1
  170. package/web/.next/server/chunks/ssr/_64bdfc6f._.js +2 -2
  171. package/web/.next/server/chunks/ssr/_64bdfc6f._.js.map +1 -1
  172. package/web/.next/server/chunks/ssr/_6a83b821._.js +3 -0
  173. package/web/.next/server/chunks/ssr/{_bbb3a0fc._.js.map → _6a83b821._.js.map} +1 -1
  174. package/web/.next/server/chunks/ssr/_7dca1882._.js +1 -1
  175. package/web/.next/server/chunks/ssr/_7dca1882._.js.map +1 -1
  176. package/web/.next/server/chunks/ssr/_8fcc39d4._.js +3 -0
  177. package/web/.next/server/chunks/ssr/_8fcc39d4._.js.map +1 -0
  178. package/web/.next/server/chunks/ssr/_b71645b4._.js +1 -1
  179. package/web/.next/server/chunks/ssr/_b71645b4._.js.map +1 -1
  180. package/web/.next/server/chunks/ssr/{_0a69ebd5._.js → _c5657bb7._.js} +2 -2
  181. package/web/.next/server/chunks/ssr/{_0a69ebd5._.js.map → _c5657bb7._.js.map} +1 -1
  182. package/web/.next/server/chunks/ssr/_d4b20e29._.js.map +1 -1
  183. package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
  184. package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
  185. package/web/.next/server/chunks/ssr/_f39a1adb._.js +1 -1
  186. package/web/.next/server/chunks/ssr/_f39a1adb._.js.map +1 -1
  187. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  188. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  189. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
  190. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
  191. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
  192. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
  193. package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
  194. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  195. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  196. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  197. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  198. package/web/.next/server/chunks/ssr/{src_presentation_web_340a9d64._.js → src_presentation_web_e05921f6._.js} +2 -2
  199. package/web/.next/server/chunks/ssr/{src_presentation_web_340a9d64._.js.map → src_presentation_web_e05921f6._.js.map} +1 -1
  200. package/web/.next/server/pages/500.html +2 -2
  201. package/web/.next/server/server-reference-manifest.js +1 -1
  202. package/web/.next/server/server-reference-manifest.json +44 -44
  203. package/web/.next/static/chunks/{8ae10749f2e8db60.js → 026580606b8b7231.js} +1 -1
  204. package/web/.next/static/chunks/09131550e55102d1.css +1 -0
  205. package/web/.next/static/chunks/{2349b8618faac5df.js → 3a2cf0e09f1a0159.js} +1 -1
  206. package/web/.next/static/chunks/{3c5c3a51c24cf5c8.js → 3a3726fb6c94f651.js} +1 -1
  207. package/web/.next/static/chunks/{e65c4ae61b6f8045.js → 3a61077325daf0c3.js} +1 -1
  208. package/web/.next/static/chunks/{41e43675a8864a3f.js → 65268efa9fd1584d.js} +1 -1
  209. package/web/.next/static/chunks/{ec05de0bd9d358e4.js → 74675bf4df9bc445.js} +1 -1
  210. package/web/.next/static/chunks/{9eff18338e76d253.js → 8a65fc8ff0c02d79.js} +2 -2
  211. package/web/.next/static/chunks/a63b3e9232d9429c.js +1 -0
  212. package/web/.next/static/chunks/c56bedce824cd983.js +1 -0
  213. package/web/.next/static/chunks/{7b850f14e5ef6865.js → e005665fcc9cf8d5.js} +1 -1
  214. package/web/.next/static/chunks/{5bea21d249dc35f8.js → e013cc94f105db24.js} +2 -2
  215. package/web/.next/static/chunks/{523ad15a08ac9fe7.js → f08792db31cb4046.js} +1 -1
  216. package/web/.next/static/chunks/fa556c575c788679.js +1 -0
  217. package/web/.next/server/chunks/ssr/[root-of-the-server]__cb850066._.js +0 -3
  218. package/web/.next/server/chunks/ssr/[root-of-the-server]__cb850066._.js.map +0 -1
  219. package/web/.next/server/chunks/ssr/_a9f57758._.js +0 -3
  220. package/web/.next/server/chunks/ssr/_a9f57758._.js.map +0 -1
  221. package/web/.next/server/chunks/ssr/_bbb3a0fc._.js +0 -3
  222. package/web/.next/static/chunks/1df0c0594135d736.css +0 -1
  223. package/web/.next/static/chunks/6a370f2709c81d83.js +0 -1
  224. package/web/.next/static/chunks/7ac8f98c0d991dda.js +0 -1
  225. package/web/.next/static/chunks/b705d6e7529f010b.js +0 -1
  226. /package/web/.next/static/{VLtWZeBgMjP_Lk91OEpmY → C5RqIopAMg1O7JgTQ3P_o}/_buildManifest.js +0 -0
  227. /package/web/.next/static/{VLtWZeBgMjP_Lk91OEpmY → C5RqIopAMg1O7JgTQ3P_o}/_clientMiddlewareManifest.json +0 -0
  228. /package/web/.next/static/{VLtWZeBgMjP_Lk91OEpmY → C5RqIopAMg1O7JgTQ3P_o}/_ssgManifest.js +0 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Git Fork Service Implementation
3
+ *
4
+ * Manages GitHub fork operations: forking repos, pushing to forks,
5
+ * creating upstream PRs, and polling upstream PR status.
6
+ * Uses `gh` CLI for all GitHub API interactions.
7
+ */
8
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
9
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
10
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
11
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
12
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
13
+ };
14
+ var __metadata = (this && this.__metadata) || function (k, v) {
15
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
16
+ };
17
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
18
+ return function (target, key) { decorator(target, key, paramIndex); }
19
+ };
20
+ import { injectable, inject } from 'tsyringe';
21
+ import { GitForkError, GitForkErrorCode, } from '../../../application/ports/output/services/git-fork-service.interface.js';
22
+ import { PrStatus } from '../../../domain/generated/output.js';
23
+ let GitForkService = class GitForkService {
24
+ execFile;
25
+ constructor(execFile) {
26
+ this.execFile = execFile;
27
+ }
28
+ async forkRepository(cwd) {
29
+ // Check if origin is already a fork — if so, just ensure upstream remote exists
30
+ try {
31
+ const { stdout } = await this.execFile('gh', ['repo', 'view', '--json', 'isFork,parent'], {
32
+ cwd,
33
+ });
34
+ const repoInfo = JSON.parse(stdout);
35
+ if (repoInfo.isFork && repoInfo.parent) {
36
+ // Origin is already a fork — ensure upstream remote points to parent
37
+ const parentUrl = `https://github.com/${repoInfo.parent.owner.login}/${repoInfo.parent.name}.git`;
38
+ try {
39
+ await this.execFile('git', ['remote', 'add', 'upstream', parentUrl], { cwd });
40
+ }
41
+ catch {
42
+ // Remote may already exist — update it
43
+ await this.execFile('git', ['remote', 'set-url', 'upstream', parentUrl], { cwd });
44
+ }
45
+ return;
46
+ }
47
+ }
48
+ catch {
49
+ // gh repo view failed — could be auth issue or not a GitHub repo
50
+ }
51
+ // Fork the repository: gh repo fork --remote remaps origin to fork, adds upstream
52
+ try {
53
+ await this.execFile('gh', ['repo', 'fork', '--remote', '--remote-name', 'origin'], { cwd });
54
+ }
55
+ catch (err) {
56
+ const message = err instanceof Error ? err.message : String(err);
57
+ if (message.includes('auth') || message.includes('login')) {
58
+ throw new GitForkError('GitHub authentication required to fork', GitForkErrorCode.AUTH_FAILURE, err instanceof Error ? err : undefined);
59
+ }
60
+ throw new GitForkError(`Failed to fork repository: ${message}`, GitForkErrorCode.FORK_FAILED, err instanceof Error ? err : undefined);
61
+ }
62
+ }
63
+ async pushToFork(cwd, branch) {
64
+ try {
65
+ await this.execFile('git', ['push', '-u', 'origin', branch], { cwd });
66
+ }
67
+ catch (err) {
68
+ const message = err instanceof Error ? err.message : String(err);
69
+ throw new GitForkError(`Failed to push to fork: ${message}`, GitForkErrorCode.PUSH_FAILED, err instanceof Error ? err : undefined);
70
+ }
71
+ }
72
+ async createUpstreamPr(cwd, title, body, head, base) {
73
+ try {
74
+ // Get the upstream repo identifier
75
+ const { stdout: upstreamUrl } = await this.execFile('git', ['remote', 'get-url', 'upstream'], { cwd });
76
+ const upstreamRepo = this.extractRepoFromUrl(upstreamUrl.trim());
77
+ // Get the fork owner for the head ref (owner:branch format)
78
+ const { stdout: forkUrl } = await this.execFile('git', ['remote', 'get-url', 'origin'], {
79
+ cwd,
80
+ });
81
+ const forkRepo = this.extractRepoFromUrl(forkUrl.trim());
82
+ const forkOwner = forkRepo.split('/')[0];
83
+ const { stdout } = await this.execFile('gh', [
84
+ 'pr',
85
+ 'create',
86
+ '--repo',
87
+ upstreamRepo,
88
+ '--title',
89
+ title,
90
+ '--body',
91
+ body,
92
+ '--head',
93
+ `${forkOwner}:${head}`,
94
+ '--base',
95
+ base,
96
+ '--json',
97
+ 'url,number',
98
+ ], { cwd });
99
+ const result = JSON.parse(stdout);
100
+ return { url: result.url, number: result.number };
101
+ }
102
+ catch (err) {
103
+ const message = err instanceof Error ? err.message : String(err);
104
+ throw new GitForkError(`Failed to create upstream PR: ${message}`, GitForkErrorCode.PR_CREATE_FAILED, err instanceof Error ? err : undefined);
105
+ }
106
+ }
107
+ async getUpstreamPrStatus(upstreamRepo, prNumber) {
108
+ try {
109
+ const { stdout } = await this.execFile('gh', ['pr', 'view', String(prNumber), '--repo', upstreamRepo, '--json', 'state'], {});
110
+ const result = JSON.parse(stdout);
111
+ const state = (result.state ?? '').toUpperCase();
112
+ if (state === 'MERGED')
113
+ return PrStatus.Merged;
114
+ if (state === 'CLOSED')
115
+ return PrStatus.Closed;
116
+ return PrStatus.Open;
117
+ }
118
+ catch (err) {
119
+ const message = err instanceof Error ? err.message : String(err);
120
+ throw new GitForkError(`Failed to get upstream PR status: ${message}`, GitForkErrorCode.PR_STATUS_FAILED, err instanceof Error ? err : undefined);
121
+ }
122
+ }
123
+ /**
124
+ * Extract owner/repo from a git remote URL.
125
+ * Handles both HTTPS and SSH formats.
126
+ */
127
+ extractRepoFromUrl(url) {
128
+ // SSH: git@github.com:owner/repo.git
129
+ const sshMatch = url.match(/git@[^:]+:([^/]+\/[^/.]+)/);
130
+ if (sshMatch)
131
+ return sshMatch[1];
132
+ // HTTPS: https://github.com/owner/repo.git
133
+ const httpsMatch = url.match(/github\.com\/([^/]+\/[^/.]+)/);
134
+ if (httpsMatch)
135
+ return httpsMatch[1];
136
+ // Strip .git suffix and return as-is
137
+ return url.replace(/\.git$/, '');
138
+ }
139
+ };
140
+ GitForkService = __decorate([
141
+ injectable(),
142
+ __param(0, inject('ExecFunction')),
143
+ __metadata("design:paramtypes", [Function])
144
+ ], GitForkService);
145
+ export { GitForkService };
@@ -2,7 +2,8 @@
2
2
  * PR Sync Watcher Service
3
3
  *
4
4
  * Polls GitHub PR status and CI status for features in the Review lifecycle
5
- * stage, updating feature records and emitting notifications when transitions
5
+ * stage, and upstream PR status for features in the AwaitingUpstream stage,
6
+ * updating feature records and emitting notifications when transitions
6
7
  * are detected. Follows the NotificationWatcherService polling pattern.
7
8
  *
8
9
  * Maintains in-memory tracking of last-known PR and CI status per feature
@@ -13,12 +14,14 @@ import type { IFeatureRepository } from '../../../application/ports/output/repos
13
14
  import type { IAgentRunRepository } from '../../../application/ports/output/agents/agent-run-repository.interface.js';
14
15
  import type { IGitPrService } from '../../../application/ports/output/services/git-pr-service.interface.js';
15
16
  import type { INotificationService } from '../../../application/ports/output/services/notification-service.interface.js';
17
+ import type { IGitForkService } from '../../../application/ports/output/services/git-fork-service.interface.js';
16
18
  import type Database from 'better-sqlite3';
17
19
  export declare class PrSyncWatcherService {
18
20
  private readonly featureRepo;
19
21
  private readonly agentRunRepo;
20
22
  private readonly gitPrService;
21
23
  private readonly notificationService;
24
+ private readonly gitForkService;
22
25
  private readonly pollIntervalMs;
23
26
  private readonly trackedFeatures;
24
27
  private readonly skippedRepos;
@@ -27,7 +30,7 @@ export declare class PrSyncWatcherService {
27
30
  private readonly processId;
28
31
  private intervalId;
29
32
  private pollCycle;
30
- constructor(featureRepo: IFeatureRepository, agentRunRepo: IAgentRunRepository, gitPrService: IGitPrService, notificationService: INotificationService, pollIntervalMs?: number, db?: Database.Database | null);
33
+ constructor(featureRepo: IFeatureRepository, agentRunRepo: IAgentRunRepository, gitPrService: IGitPrService, notificationService: INotificationService, pollIntervalMs?: number, db?: Database.Database | null, gitForkService?: IGitForkService | null);
31
34
  isRunning(): boolean;
32
35
  start(): void;
33
36
  stop(): void;
@@ -40,6 +43,17 @@ export declare class PrSyncWatcherService {
40
43
  private handleRateLimitError;
41
44
  private processRepository;
42
45
  private processFeature;
46
+ /**
47
+ * Extract upstream repo (owner/name) from an upstream PR URL.
48
+ * Expected format: https://github.com/owner/repo/pull/123
49
+ */
50
+ private extractUpstreamRepo;
51
+ /**
52
+ * Poll upstream PR status for a feature in AwaitingUpstream lifecycle.
53
+ * If the upstream PR is merged, transition to Maintain.
54
+ * If the upstream PR is closed, update upstreamPrStatus to Closed.
55
+ */
56
+ private processAwaitingUpstreamFeature;
43
57
  /** Mark associated agent run as completed so the UI reflects "done" state. */
44
58
  private completeAgentRun;
45
59
  private emitNotification;
@@ -50,7 +64,7 @@ export declare class PrSyncWatcherService {
50
64
  *
51
65
  * @throws Error if the watcher is already initialized
52
66
  */
53
- export declare function initializePrSyncWatcher(featureRepo: IFeatureRepository, agentRunRepo: IAgentRunRepository, gitPrService: IGitPrService, notificationService: INotificationService, pollIntervalMs?: number, db?: Database.Database | null): void;
67
+ export declare function initializePrSyncWatcher(featureRepo: IFeatureRepository, agentRunRepo: IAgentRunRepository, gitPrService: IGitPrService, notificationService: INotificationService, pollIntervalMs?: number, db?: Database.Database | null, gitForkService?: IGitForkService | null): void;
54
68
  /**
55
69
  * Get the PR sync watcher singleton.
56
70
  *
@@ -1 +1 @@
1
- {"version":3,"file":"pr-sync-watcher.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAWH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gFAAgF,CAAC;AACzH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4EAA4E,CAAC;AACtH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wEAAwE,CAAC;AAK5G,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8EAA8E,CAAC;AACzH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAqB3C,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAuB;IAC3D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqC;IACrE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA2B;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,SAAS,CAAK;gBAGpB,WAAW,EAAE,kBAAkB,EAC/B,YAAY,EAAE,mBAAmB,EACjC,YAAY,EAAE,aAAa,EAC3B,mBAAmB,EAAE,oBAAoB,EACzC,cAAc,GAAE,MAAiC,EACjD,EAAE,GAAE,QAAQ,CAAC,QAAQ,GAAG,IAAW;IAWrC,SAAS,IAAI,OAAO;IAIpB,KAAK,IAAI,IAAI;IAcb,IAAI,IAAI,IAAI;IASZ,gFAAgF;IAChF,OAAO,CAAC,cAAc;IAiBtB,0FAA0F;IAC1F,OAAO,CAAC,iBAAiB;YAUX,IAAI;IA6ClB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,oBAAoB;YAYd,iBAAiB;YA+CjB,cAAc;IAkM5B,8EAA8E;YAChE,gBAAgB;IAW9B,OAAO,CAAC,gBAAgB;CAoBzB;AAMD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,kBAAkB,EAC/B,YAAY,EAAE,mBAAmB,EACjC,YAAY,EAAE,aAAa,EAC3B,mBAAmB,EAAE,oBAAoB,EACzC,cAAc,CAAC,EAAE,MAAM,EACvB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,GAC5B,IAAI,CAaN;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,oBAAoB,CAQvD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}
1
+ {"version":3,"file":"pr-sync-watcher.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/pr-sync/pr-sync-watcher.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gFAAgF,CAAC;AACzH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4EAA4E,CAAC;AACtH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wEAAwE,CAAC;AAK5G,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,8EAA8E,CAAC;AACzH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0EAA0E,CAAC;AAChH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAqB3C,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAuB;IAC3D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAyB;IACxD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqC;IACrE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA2B;IAC9C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,UAAU,CAA+C;IACjE,OAAO,CAAC,SAAS,CAAK;gBAGpB,WAAW,EAAE,kBAAkB,EAC/B,YAAY,EAAE,mBAAmB,EACjC,YAAY,EAAE,aAAa,EAC3B,mBAAmB,EAAE,oBAAoB,EACzC,cAAc,GAAE,MAAiC,EACjD,EAAE,GAAE,QAAQ,CAAC,QAAQ,GAAG,IAAW,EACnC,cAAc,GAAE,eAAe,GAAG,IAAW;IAY/C,SAAS,IAAI,OAAO;IAIpB,KAAK,IAAI,IAAI;IAcb,IAAI,IAAI,IAAI;IASZ,gFAAgF;IAChF,OAAO,CAAC,cAAc;IAiBtB,0FAA0F;IAC1F,OAAO,CAAC,iBAAiB;YAUX,IAAI;IAmDlB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,oBAAoB;YAYd,iBAAiB;YA+CjB,cAAc;IAkM5B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAK3B;;;;OAIG;YACW,8BAA8B;IA0F5C,8EAA8E;YAChE,gBAAgB;IAW9B,OAAO,CAAC,gBAAgB;CAoBzB;AAMD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,kBAAkB,EAC/B,YAAY,EAAE,mBAAmB,EACjC,YAAY,EAAE,aAAa,EAC3B,mBAAmB,EAAE,oBAAoB,EACzC,cAAc,CAAC,EAAE,MAAM,EACvB,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,EAC7B,cAAc,CAAC,EAAE,eAAe,GAAG,IAAI,GACtC,IAAI,CAcN;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,IAAI,oBAAoB,CAQvD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}
@@ -2,7 +2,8 @@
2
2
  * PR Sync Watcher Service
3
3
  *
4
4
  * Polls GitHub PR status and CI status for features in the Review lifecycle
5
- * stage, updating feature records and emitting notifications when transitions
5
+ * stage, and upstream PR status for features in the AwaitingUpstream stage,
6
+ * updating feature records and emitting notifications when transitions
6
7
  * are detected. Follows the NotificationWatcherService polling pattern.
7
8
  *
8
9
  * Maintains in-memory tracking of last-known PR and CI status per feature
@@ -24,6 +25,7 @@ export class PrSyncWatcherService {
24
25
  agentRunRepo;
25
26
  gitPrService;
26
27
  notificationService;
28
+ gitForkService;
27
29
  pollIntervalMs;
28
30
  trackedFeatures = new Map();
29
31
  skippedRepos = new Set();
@@ -32,11 +34,12 @@ export class PrSyncWatcherService {
32
34
  processId;
33
35
  intervalId = null;
34
36
  pollCycle = 0;
35
- constructor(featureRepo, agentRunRepo, gitPrService, notificationService, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, db = null) {
37
+ constructor(featureRepo, agentRunRepo, gitPrService, notificationService, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, db = null, gitForkService = null) {
36
38
  this.featureRepo = featureRepo;
37
39
  this.agentRunRepo = agentRunRepo;
38
40
  this.gitPrService = gitPrService;
39
41
  this.notificationService = notificationService;
42
+ this.gitForkService = gitForkService;
40
43
  this.pollIntervalMs = pollIntervalMs;
41
44
  this.db = db;
42
45
  this.processId = `${process.pid}-${Date.now()}`;
@@ -97,26 +100,32 @@ export class PrSyncWatcherService {
97
100
  return; // another process holds the lock — skip this cycle
98
101
  }
99
102
  this.pollCycle++;
100
- const allFeatures = await this.featureRepo.list({ lifecycle: SdlcLifecycle.Review });
103
+ const allReviewFeatures = await this.featureRepo.list({ lifecycle: SdlcLifecycle.Review });
101
104
  // Include features with a valid repositoryPath (with or without PR data)
102
- const features = allFeatures.filter((f) => f.repositoryPath);
103
- if (features.length === 0) {
104
- this.trackedFeatures.clear();
105
- return;
106
- }
107
- // Group features by repositoryPath for batch queries
105
+ const reviewFeatures = allReviewFeatures.filter((f) => f.repositoryPath);
106
+ // Group Review features by repositoryPath for batch queries
108
107
  const byRepo = new Map();
109
- for (const feature of features) {
108
+ for (const feature of reviewFeatures) {
110
109
  const group = byRepo.get(feature.repositoryPath) ?? [];
111
110
  group.push(feature);
112
111
  byRepo.set(feature.repositoryPath, group);
113
112
  }
114
- // Process each repository
113
+ // Process each repository (Review features)
115
114
  for (const [repoPath, repoFeatures] of byRepo) {
116
115
  await this.processRepository(repoPath, repoFeatures);
117
116
  }
118
- // Prune features no longer in Review
119
- const currentFeatureIds = new Set(features.map((f) => f.id));
117
+ // Process AwaitingUpstream features (poll upstream PR status individually)
118
+ const awaitingFeatures = await this.featureRepo.list({
119
+ lifecycle: SdlcLifecycle.AwaitingUpstream,
120
+ });
121
+ for (const feature of awaitingFeatures) {
122
+ await this.processAwaitingUpstreamFeature(feature);
123
+ }
124
+ // Prune features no longer in Review or AwaitingUpstream
125
+ const currentFeatureIds = new Set([
126
+ ...reviewFeatures.map((f) => f.id),
127
+ ...awaitingFeatures.map((f) => f.id),
128
+ ]);
120
129
  for (const trackedId of this.trackedFeatures.keys()) {
121
130
  if (!currentFeatureIds.has(trackedId)) {
122
131
  this.trackedFeatures.delete(trackedId);
@@ -319,6 +328,80 @@ export class PrSyncWatcherService {
319
328
  tracked.unchangedCycles++;
320
329
  }
321
330
  }
331
+ /**
332
+ * Extract upstream repo (owner/name) from an upstream PR URL.
333
+ * Expected format: https://github.com/owner/repo/pull/123
334
+ */
335
+ extractUpstreamRepo(upstreamPrUrl) {
336
+ const match = upstreamPrUrl.match(/github\.com\/([^/]+\/[^/]+)\/pull\//);
337
+ return match?.[1] ?? null;
338
+ }
339
+ /**
340
+ * Poll upstream PR status for a feature in AwaitingUpstream lifecycle.
341
+ * If the upstream PR is merged, transition to Maintain.
342
+ * If the upstream PR is closed, update upstreamPrStatus to Closed.
343
+ */
344
+ async processAwaitingUpstreamFeature(feature) {
345
+ if (!this.gitForkService)
346
+ return;
347
+ if (!feature.pr?.upstreamPrUrl || !feature.pr?.upstreamPrNumber)
348
+ return;
349
+ // Check exponential backoff — skip features that haven't changed recently
350
+ if (!this.shouldPollFeature(feature.id)) {
351
+ return;
352
+ }
353
+ const upstreamRepo = this.extractUpstreamRepo(feature.pr.upstreamPrUrl);
354
+ if (!upstreamRepo) {
355
+ // eslint-disable-next-line no-console
356
+ console.warn(`${TAG} Could not extract upstream repo from URL: ${feature.pr.upstreamPrUrl}`);
357
+ return;
358
+ }
359
+ let upstreamStatus;
360
+ try {
361
+ upstreamStatus = await this.gitForkService.getUpstreamPrStatus(upstreamRepo, feature.pr.upstreamPrNumber);
362
+ }
363
+ catch (error) {
364
+ const msg = error instanceof Error ? error.message : String(error);
365
+ // eslint-disable-next-line no-console
366
+ console.warn(`${TAG} getUpstreamPrStatus failed for "${feature.name}" (${upstreamRepo}#${feature.pr.upstreamPrNumber}): ${msg}`);
367
+ return;
368
+ }
369
+ // Initialize tracking if needed
370
+ const prevState = this.trackedFeatures.get(feature.id);
371
+ if (!prevState) {
372
+ this.trackedFeatures.set(feature.id, {
373
+ prStatus: feature.pr.upstreamPrStatus ?? PrStatus.Open,
374
+ ciStatus: undefined,
375
+ mergeable: undefined,
376
+ featureName: feature.name,
377
+ unchangedCycles: 0,
378
+ });
379
+ }
380
+ const tracked = this.trackedFeatures.get(feature.id);
381
+ const previousStatus = tracked.prStatus;
382
+ if (upstreamStatus === previousStatus) {
383
+ tracked.unchangedCycles++;
384
+ return;
385
+ }
386
+ // eslint-disable-next-line no-console
387
+ console.log(`${TAG} Upstream PR #${feature.pr.upstreamPrNumber} status changed: ${previousStatus} -> ${upstreamStatus} for "${feature.name}"`);
388
+ tracked.prStatus = upstreamStatus;
389
+ tracked.unchangedCycles = 0;
390
+ if (upstreamStatus === PrStatus.Merged) {
391
+ feature.lifecycle = SdlcLifecycle.Maintain;
392
+ feature.pr = { ...feature.pr, upstreamPrStatus: PrStatus.Merged };
393
+ feature.updatedAt = new Date();
394
+ await this.featureRepo.update(feature);
395
+ await this.completeAgentRun(feature);
396
+ this.emitNotification(NotificationEventType.PrMerged, feature.id, feature.agentRunId ?? '', feature.name, `Upstream PR #${feature.pr.upstreamPrNumber} merged for ${feature.name}`, NotificationSeverity.Success);
397
+ }
398
+ else if (upstreamStatus === PrStatus.Closed) {
399
+ feature.pr = { ...feature.pr, upstreamPrStatus: PrStatus.Closed };
400
+ feature.updatedAt = new Date();
401
+ await this.featureRepo.update(feature);
402
+ this.emitNotification(NotificationEventType.PrClosed, feature.id, feature.agentRunId ?? '', feature.name, `Upstream PR #${feature.pr.upstreamPrNumber} closed for ${feature.name}`, NotificationSeverity.Warning);
403
+ }
404
+ }
322
405
  /** Mark associated agent run as completed so the UI reflects "done" state. */
323
406
  async completeAgentRun(feature) {
324
407
  if (!feature.agentRunId)
@@ -353,11 +436,11 @@ let watcherInstance = null;
353
436
  *
354
437
  * @throws Error if the watcher is already initialized
355
438
  */
356
- export function initializePrSyncWatcher(featureRepo, agentRunRepo, gitPrService, notificationService, pollIntervalMs, db) {
439
+ export function initializePrSyncWatcher(featureRepo, agentRunRepo, gitPrService, notificationService, pollIntervalMs, db, gitForkService) {
357
440
  if (watcherInstance !== null) {
358
441
  throw new Error('PR sync watcher already initialized. Cannot re-initialize.');
359
442
  }
360
- watcherInstance = new PrSyncWatcherService(featureRepo, agentRunRepo, gitPrService, notificationService, pollIntervalMs, db ?? null);
443
+ watcherInstance = new PrSyncWatcherService(featureRepo, agentRunRepo, gitPrService, notificationService, pollIntervalMs, db ?? null, gitForkService ?? null);
361
444
  }
362
445
  /**
363
446
  * Get the PR sync watcher singleton.
@@ -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;AAgC1D;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CA0FzC"}
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;AAiC1D;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CA4FzC"}
@@ -67,8 +67,9 @@ Examples:
67
67
  getNotificationWatcher().start();
68
68
  // Start PR sync watcher to detect PR/CI status transitions on GitHub
69
69
  const gitPrService = container.resolve('IGitPrService');
70
+ const gitForkService = container.resolve('IGitForkService');
70
71
  const db = getExistingConnection();
71
- initializePrSyncWatcher(featureRepo, runRepo, gitPrService, notificationService, undefined, db);
72
+ initializePrSyncWatcher(featureRepo, runRepo, gitPrService, notificationService, undefined, db, gitForkService);
72
73
  getPrSyncWatcher().start();
73
74
  const url = `http://localhost:${port}`;
74
75
  messages.success(`Server ready at ${fmt.code(url)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/agent-events/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAiBH,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAuEvC,wBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CA4R9C"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/app/api/agent-events/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAiBH,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAwEvC,wBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CA4R9C"}
@@ -36,6 +36,7 @@ const LIFECYCLE_TO_NODE = {
36
36
  [SdlcLifecycle.Blocked]: 'blocked',
37
37
  [SdlcLifecycle.Pending]: 'pending',
38
38
  [SdlcLifecycle.Deleting]: 'blocked',
39
+ [SdlcLifecycle.AwaitingUpstream]: 'merge',
39
40
  [SdlcLifecycle.Archived]: 'archived',
40
41
  };
41
42
  const STATUS_TO_EVENT = {
@@ -39,6 +39,10 @@ export interface FeatureCreatePayload {
39
39
  fast: boolean;
40
40
  /** When true, create the feature in pending state (no agent spawned). */
41
41
  pending?: boolean;
42
+ /** Fork repo and create PR to upstream at merge time. */
43
+ forkAndPr: boolean;
44
+ /** Commit specs/evidences into the repo (defaults false when forkAndPr is enabled). */
45
+ commitSpecs: boolean;
42
46
  /** Optional agent type override for this feature run */
43
47
  agentType?: string;
44
48
  /** Optional model override for this feature run */
@@ -1 +1 @@
1
- {"version":3,"file":"feature-create-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"feature-create-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useState, useCallback, useEffect, useRef } from 'react';
4
- import { PaperclipIcon, ChevronsUpDown, CheckIcon, Zap, Clock, FolderPlus, Loader2, } from 'lucide-react';
4
+ import { PaperclipIcon, ChevronsUpDown, CheckIcon, Zap, Clock, FolderPlus, Loader2, GitFork, FileText, } from 'lucide-react';
5
5
  import { cn } from '../../../lib/utils.js';
6
6
  import { useSoundAction } from '../../../hooks/use-sound-action.js';
7
7
  import { BaseDrawer } from '../../common/base-drawer/index.js';
@@ -131,6 +131,8 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
131
131
  const [parentId, setParentId] = useState(undefined);
132
132
  const [fast, setFast] = useState(false);
133
133
  const [pending, setPending] = useState(false);
134
+ const [forkAndPr, setForkAndPr] = useState(false);
135
+ const [commitSpecs, setCommitSpecs] = useState(true);
134
136
  const [overrideAgent, setOverrideAgent] = useState(undefined);
135
137
  const [overrideModel, setOverrideModel] = useState(undefined);
136
138
  const [selectedRepoPath, setSelectedRepoPath] = useState(validRepoPath || undefined);
@@ -177,6 +179,8 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
177
179
  setLocalRepos(repositories ?? []);
178
180
  setFast(false);
179
181
  setPending(false);
182
+ setForkAndPr(false);
183
+ setCommitSpecs(true);
180
184
  setOverrideAgent(undefined);
181
185
  setOverrideModel(undefined);
182
186
  setUploadError(null);
@@ -320,12 +324,14 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
320
324
  allowPlan: approvalGates.allowPlan ?? false,
321
325
  allowMerge: approvalGates.allowMerge ?? false,
322
326
  },
323
- push: push || openPr,
324
- openPr,
327
+ push: forkAndPr ? true : push || openPr,
328
+ openPr: forkAndPr ? true : openPr,
325
329
  ciWatchEnabled,
326
330
  enableEvidence,
327
331
  commitEvidence,
328
332
  fast,
333
+ forkAndPr,
334
+ commitSpecs,
329
335
  ...(pending ? { pending } : {}),
330
336
  ...(overrideAgent ? { agentType: overrideAgent } : {}),
331
337
  ...(overrideModel ? { model: overrideModel } : {}),
@@ -346,6 +352,8 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
346
352
  ciWatchEnabled,
347
353
  commitEvidence,
348
354
  fast,
355
+ forkAndPr,
356
+ commitSpecs,
349
357
  pending,
350
358
  overrideAgent,
351
359
  overrideModel,
@@ -453,15 +461,24 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
453
461
  ? 'Requires PR to be enabled'
454
462
  : !enableEvidence
455
463
  ? 'Requires evidence collection to be enabled'
456
- : 'Include evidence in the pull request body.' })] })] })] }), _jsxs("div", { className: "border-input flex items-center gap-4 rounded-md border px-3 py-2.5", children: [_jsx("span", { className: "text-muted-foreground w-16 shrink-0 text-xs font-semibold tracking-wider", children: "GIT" }), _jsxs("div", { className: "flex flex-1 items-center gap-4", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "push", size: "sm", checked: push || openPr, onCheckedChange: (v) => {
464
+ : 'Include evidence in the pull request body.' })] })] })] }), _jsxs("div", { className: "border-input flex items-center gap-4 rounded-md border px-3 py-2.5", children: [_jsx("span", { className: "text-muted-foreground w-16 shrink-0 text-xs font-semibold tracking-wider", children: "GIT" }), _jsxs("div", { className: "flex flex-1 items-center gap-4", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "push", size: "sm", checked: forkAndPr ? true : push || openPr, onCheckedChange: (v) => {
457
465
  setPush(v);
458
466
  if (!v && openPr)
459
467
  setOpenPr(false);
460
- }, disabled: isSubmitting }), _jsx(Label, { htmlFor: "push", className: "cursor-pointer text-xs font-medium", children: "Push" })] }) }), _jsx(TooltipContent, { side: "bottom", children: "Push branch to remote after implementation." })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "open-pr", size: "sm", checked: openPr, onCheckedChange: (v) => {
468
+ }, disabled: isSubmitting || forkAndPr }), _jsx(Label, { htmlFor: "push", className: cn('cursor-pointer text-xs font-medium', forkAndPr && 'opacity-50'), children: "Push" })] }) }), _jsx(TooltipContent, { side: "bottom", children: forkAndPr
469
+ ? 'Implicitly enabled by fork-and-PR mode'
470
+ : 'Push branch to remote after implementation.' })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "open-pr", size: "sm", checked: forkAndPr ? true : openPr, onCheckedChange: (v) => {
461
471
  setOpenPr(v);
462
472
  if (!v)
463
473
  setCommitEvidence(false);
464
- }, disabled: isSubmitting }), _jsx(Label, { htmlFor: "open-pr", className: "cursor-pointer text-xs font-medium", children: "PR" })] }) }), _jsx(TooltipContent, { side: "bottom", children: "Open a pull request after pushing." })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "ci-watch", size: "sm", checked: ciWatchEnabled, onCheckedChange: setCiWatchEnabled, disabled: isSubmitting }), _jsx(Label, { htmlFor: "ci-watch", className: "cursor-pointer text-xs font-medium", children: "Watch" })] }) }), _jsx(TooltipContent, { side: "bottom", children: "Watch CI and auto-fix after push." })] })] })] })] })] }) }) }) }));
474
+ }, disabled: isSubmitting || forkAndPr }), _jsx(Label, { htmlFor: "open-pr", className: cn('cursor-pointer text-xs font-medium', forkAndPr && 'opacity-50'), children: "PR" })] }) }), _jsx(TooltipContent, { side: "bottom", children: forkAndPr
475
+ ? 'Implicitly enabled by fork-and-PR mode'
476
+ : 'Open a pull request after pushing.' })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "ci-watch", size: "sm", checked: ciWatchEnabled, onCheckedChange: setCiWatchEnabled, disabled: isSubmitting }), _jsx(Label, { htmlFor: "ci-watch", className: "cursor-pointer text-xs font-medium", children: "Watch" })] }) }), _jsx(TooltipContent, { side: "bottom", children: "Watch CI and auto-fix after push." })] })] })] }), _jsxs("div", { className: "border-input flex items-center gap-4 rounded-md border px-3 py-2.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "text-muted-foreground w-16 shrink-0 cursor-default text-xs font-semibold tracking-wider", children: "FORK" }) }), _jsx(TooltipContent, { side: "bottom", children: "Fork the repository and create a PR to the upstream repo." })] }), _jsxs("div", { className: "flex flex-1 items-center gap-4", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "fork-and-pr", size: "sm", checked: forkAndPr, onCheckedChange: (v) => {
477
+ setForkAndPr(v);
478
+ // Auto-flip commitSpecs to false when enabling fork mode
479
+ if (v)
480
+ setCommitSpecs(false);
481
+ }, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "fork-and-pr", className: "flex cursor-pointer items-center gap-1 text-xs font-medium", children: [_jsx(GitFork, { className: "h-3 w-3" }), "Fork & PR"] })] }) }), _jsx(TooltipContent, { side: "bottom", children: "Contribute via fork (PR to upstream)." })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex cursor-pointer items-center gap-1.5", children: [_jsx(Switch, { id: "commit-specs", size: "sm", checked: commitSpecs, onCheckedChange: setCommitSpecs, disabled: isSubmitting }), _jsxs(Label, { htmlFor: "commit-specs", className: "flex cursor-pointer items-center gap-1 text-xs font-medium", children: [_jsx(FileText, { className: "h-3 w-3" }), "Commit Specs"] })] }) }), _jsx(TooltipContent, { side: "bottom", children: "Commit specs to repository." })] })] })] })] })] }) }) }) }));
465
482
  }
466
483
  function ParentFeatureCombobox({ features, value, onChange, disabled, }) {
467
484
  const [open, setOpen] = useState(false);
@@ -120,6 +120,17 @@ export declare const DiscardConfirmation: Story;
120
120
  */
121
121
  export declare const DragDropReady: Story;
122
122
  export declare const Interactive: Story;
123
+ /**
124
+ * Fork & PR enabled — the "Fork & PR" toggle is checked. When enabled,
125
+ * Push and PR toggles are implicitly locked to `true` (disabled), and
126
+ * `commitSpecs` auto-flips to `false`.
127
+ */
128
+ export declare const ForkAndPrEnabled: Story;
129
+ /**
130
+ * Fork & PR with Commit Specs re-enabled — after enabling fork mode
131
+ * (which auto-disables commitSpecs), the user overrides commitSpecs back to `true`.
132
+ */
133
+ export declare const ForkAndPrWithCommitSpecs: Story;
123
134
  /**
124
135
  * With repository selector — opened from sidebar without repo context.
125
136
  * Shows the searchable repository combobox at the top of the form.
@@ -1 +1 @@
1
- {"version":3,"file":"feature-create-drawer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAU9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAgC1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAmDlD,uFAAuF;AACvF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,KAiBvB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAMhC,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,KAUxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,KAUrB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,KAUvB,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,KAUtB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,KAUvB,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,KAUxB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAgBjC,CAAC;AAeF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAWlC,CAAC;AAkDF,+EAA+E;AAC/E,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAwCF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAgBjC,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,KAY3B,CAAC;AAMF,eAAO,MAAM,WAAW,EAAE,KAwCzB,CAAC;AAuCF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AA6BF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAMnC,CAAC"}
1
+ {"version":3,"file":"feature-create-drawer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAU9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,mBAAmB,CAgC1C,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAmDlD,uFAAuF;AACvF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,KAiBvB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAE,KAMhC,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,EAAE,KAUxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,KAUrB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,KAUvB,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,KAUtB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,EAAE,KAUvB,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,KAUxB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAgBjC,CAAC;AAeF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAWlC,CAAC;AAkDF,+EAA+E;AAC/E,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAwCF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAM/B,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAgBjC,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,aAAa,EAAE,KAY3B,CAAC;AAMF,eAAO,MAAM,WAAW,EAAE,KAwCzB,CAAC;AAMF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAU9B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EAAE,KAatC,CAAC;AAuCF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC;AA6BF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAMnC,CAAC"}
@@ -398,6 +398,40 @@ export const Interactive = {
398
398
  }, repositoryPath: "/Users/dev/my-repo", currentAgentType: "claude-code", currentModel: "claude-sonnet-4-6" })] }));
399
399
  },
400
400
  };
401
+ /* ---------------------------------------------------------------------------
402
+ * Fork & PR stories
403
+ * ------------------------------------------------------------------------- */
404
+ /**
405
+ * Fork & PR enabled — the "Fork & PR" toggle is checked. When enabled,
406
+ * Push and PR toggles are implicitly locked to `true` (disabled), and
407
+ * `commitSpecs` auto-flips to `false`.
408
+ */
409
+ export const ForkAndPrEnabled = {
410
+ render: () => _jsx(CreateDrawerTrigger, { label: "Open (Fork & PR)" }),
411
+ play: async ({ canvasElement }) => {
412
+ const canvas = within(canvasElement);
413
+ await userEvent.click(canvas.getByRole('button', { name: 'Open (Fork & PR)' }));
414
+ const body = within(canvasElement.ownerDocument.body);
415
+ const forkToggle = await body.findByLabelText('Fork & PR');
416
+ await userEvent.click(forkToggle);
417
+ },
418
+ };
419
+ /**
420
+ * Fork & PR with Commit Specs re-enabled — after enabling fork mode
421
+ * (which auto-disables commitSpecs), the user overrides commitSpecs back to `true`.
422
+ */
423
+ export const ForkAndPrWithCommitSpecs = {
424
+ render: () => _jsx(CreateDrawerTrigger, { label: "Open (Fork + Specs)" }),
425
+ play: async ({ canvasElement }) => {
426
+ const canvas = within(canvasElement);
427
+ await userEvent.click(canvas.getByRole('button', { name: 'Open (Fork + Specs)' }));
428
+ const body = within(canvasElement.ownerDocument.body);
429
+ const forkToggle = await body.findByLabelText('Fork & PR');
430
+ await userEvent.click(forkToggle);
431
+ const specsToggle = body.getByLabelText('Commit Specs');
432
+ await userEvent.click(specsToggle);
433
+ },
434
+ };
401
435
  /* ---------------------------------------------------------------------------
402
436
  * Repository selector stories
403
437
  * ------------------------------------------------------------------------- */
@@ -3,7 +3,7 @@ import type { Node } from '@xyflow/react';
3
3
  import type { PrStatus, CiStatus, DeploymentState } from '../../../../../../packages/core/src/domain/generated/output.js';
4
4
  import type { AgentTypeValue } from './agent-type-icons.js';
5
5
  export type FeatureNodeState = 'creating' | 'running' | 'action-required' | 'done' | 'blocked' | 'pending' | 'error' | 'deleting' | 'archived';
6
- export type FeatureLifecyclePhase = 'pending' | 'requirements' | 'research' | 'implementation' | 'review' | 'deploy' | 'maintain';
6
+ export type FeatureLifecyclePhase = 'pending' | 'requirements' | 'research' | 'implementation' | 'review' | 'awaitingUpstream' | 'deploy' | 'maintain';
7
7
  /** Human-readable display labels for lifecycle phases. */
8
8
  export declare const lifecycleDisplayLabels: Record<FeatureLifecyclePhase, string>;
9
9
  /** Left border color for each lifecycle phase. */