@shepai/cli 1.76.0 → 1.77.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts +1 -0
  2. package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/ports/output/services/spec-initializer.interface.d.ts +4 -1
  4. package/dist/packages/core/src/application/ports/output/services/spec-initializer.interface.d.ts.map +1 -1
  5. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
  6. package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +5 -2
  7. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts +2 -0
  8. package/dist/packages/core/src/application/use-cases/features/create/types.d.ts.map +1 -1
  9. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/fast-feature-agent-graph.d.ts +220 -0
  10. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/fast-feature-agent-graph.d.ts.map +1 -0
  11. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/fast-feature-agent-graph.js +66 -0
  12. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +1 -0
  13. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
  14. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +3 -0
  15. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +1 -0
  16. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  17. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +10 -1
  18. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/lifecycle-context.d.ts.map +1 -1
  19. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/lifecycle-context.js +1 -0
  20. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.d.ts +21 -0
  21. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.d.ts.map +1 -0
  22. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.js +60 -0
  23. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/fast-implement.prompt.d.ts +25 -0
  24. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/fast-implement.prompt.d.ts.map +1 -0
  25. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/fast-implement.prompt.js +176 -0
  26. package/dist/packages/core/src/infrastructure/services/spec/spec-initializer.service.d.ts +1 -1
  27. package/dist/packages/core/src/infrastructure/services/spec/spec-initializer.service.d.ts.map +1 -1
  28. package/dist/packages/core/src/infrastructure/services/spec/spec-initializer.service.js +8 -3
  29. package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
  30. package/dist/src/presentation/cli/commands/feat/new.command.js +2 -0
  31. package/dist/src/presentation/web/app/actions/create-feature.d.ts +2 -0
  32. package/dist/src/presentation/web/app/actions/create-feature.d.ts.map +1 -1
  33. package/dist/src/presentation/web/app/actions/create-feature.js +3 -1
  34. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts +2 -0
  35. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
  36. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +5 -1
  37. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts +18 -0
  38. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.d.ts.map +1 -1
  39. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.js +49 -0
  40. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  41. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +28 -4
  42. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +4 -1
  43. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  44. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +6 -3
  45. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +1 -1
  46. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.d.ts +1 -0
  47. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.d.ts.map +1 -1
  48. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.js +71 -2
  49. package/dist/src/presentation/web/hooks/use-graph-state.d.ts +2 -0
  50. package/dist/src/presentation/web/hooks/use-graph-state.d.ts.map +1 -1
  51. package/dist/src/presentation/web/hooks/use-graph-state.js +4 -0
  52. package/dist/src/presentation/web/hooks/use-viewport-persistence.d.ts +1 -0
  53. package/dist/src/presentation/web/hooks/use-viewport-persistence.d.ts.map +1 -1
  54. package/dist/tsconfig.build.tsbuildinfo +1 -1
  55. package/package.json +1 -1
  56. package/web/.next/BUILD_ID +1 -1
  57. package/web/.next/build-manifest.json +2 -2
  58. package/web/.next/cache/.previewinfo +1 -1
  59. package/web/.next/cache/.rscinfo +1 -1
  60. package/web/.next/cache/.tsbuildinfo +1 -1
  61. package/web/.next/cache/config.json +3 -3
  62. package/web/.next/fallback-build-manifest.json +2 -2
  63. package/web/.next/prerender-manifest.json +3 -3
  64. package/web/.next/required-server-files.js +1 -1
  65. package/web/.next/required-server-files.json +1 -1
  66. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +16 -16
  67. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  68. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  69. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +19 -19
  70. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  71. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  72. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  73. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  74. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  75. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +16 -16
  76. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  77. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  78. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +19 -19
  79. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  80. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  81. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +14 -14
  82. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  83. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  84. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  85. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  86. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  87. package/web/.next/server/app/_global-error.html +2 -2
  88. package/web/.next/server/app/_global-error.rsc +1 -1
  89. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  90. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  91. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  92. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  93. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  94. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  95. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  96. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  97. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  98. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  99. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  100. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  101. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  102. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  103. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  104. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +1 -1
  105. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js.map +1 -1
  106. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +1 -1
  107. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js.map +1 -1
  108. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  109. package/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js.map +1 -1
  110. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  112. package/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js +1 -1
  114. package/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js.map +1 -1
  115. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  116. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  117. package/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  118. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  119. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  120. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js +1 -1
  121. package/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js.map +1 -1
  122. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  123. package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
  124. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  125. package/web/.next/server/chunks/ssr/_0e9d6bf7._.js.map +1 -1
  126. package/web/.next/server/chunks/ssr/{_a3854150._.js → _2a862f34._.js} +2 -2
  127. package/web/.next/server/chunks/ssr/{_a3854150._.js.map → _2a862f34._.js.map} +1 -1
  128. package/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  129. package/web/.next/server/chunks/ssr/_61351ed3._.js.map +1 -1
  130. package/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  131. package/web/.next/server/chunks/ssr/_8400c8bb._.js.map +1 -1
  132. package/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  133. package/web/.next/server/chunks/ssr/_9f940437._.js.map +1 -1
  134. package/web/.next/server/chunks/ssr/src_presentation_web_163038ba._.js +2 -2
  135. package/web/.next/server/chunks/ssr/src_presentation_web_163038ba._.js.map +1 -1
  136. package/web/.next/server/chunks/ssr/src_presentation_web_30d7eeda._.js +1 -1
  137. package/web/.next/server/chunks/ssr/src_presentation_web_30d7eeda._.js.map +1 -1
  138. package/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js +2 -2
  139. package/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js.map +1 -1
  140. package/web/.next/server/chunks/ssr/src_presentation_web_565a14f8._.js +1 -1
  141. package/web/.next/server/chunks/ssr/src_presentation_web_565a14f8._.js.map +1 -1
  142. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +1 -1
  143. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js.map +1 -1
  144. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  145. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  146. package/web/.next/server/pages/500.html +2 -2
  147. package/web/.next/server/server-reference-manifest.js +1 -1
  148. package/web/.next/server/server-reference-manifest.json +22 -22
  149. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  150. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  151. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  152. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  153. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +16 -16
  154. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  155. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  156. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +19 -19
  157. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  158. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  159. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  160. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  161. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  162. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +16 -16
  163. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  164. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  165. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +19 -19
  166. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  167. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  168. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +14 -14
  169. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  170. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  171. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +14 -14
  172. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  173. package/web/.next/standalone/src/presentation/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  174. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  175. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  176. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  177. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  178. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  179. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  180. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  181. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  182. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  183. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  184. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  185. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  186. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  187. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  188. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  189. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  190. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_da7eef33.js +1 -1
  191. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_0a9251aa.js +1 -1
  192. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__17a611f0._.js +2 -2
  193. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  194. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__45dbf93d._.js +2 -2
  195. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6258349c._.js +1 -1
  196. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  197. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6cbc1149._.js +2 -2
  198. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  199. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__94a6d275._.js +1 -1
  200. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js +1 -1
  201. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_0e9d6bf7._.js +1 -1
  202. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/{_a3854150._.js → _2a862f34._.js} +2 -2
  203. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_61351ed3._.js +1 -1
  204. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_8400c8bb._.js +1 -1
  205. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_9f940437._.js +1 -1
  206. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_163038ba._.js +2 -2
  207. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_30d7eeda._.js +1 -1
  208. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_459cb687._.js +2 -2
  209. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_565a14f8._.js +1 -1
  210. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_021a05f2.js +1 -1
  211. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  212. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  213. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  214. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +22 -22
  215. package/web/.next/standalone/src/presentation/web/app/actions/create-feature.ts +6 -1
  216. package/web/.next/standalone/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.stories.tsx +57 -0
  217. package/web/.next/standalone/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx +21 -0
  218. package/web/.next/standalone/src/presentation/web/components/features/control-center/control-center-inner.tsx +32 -4
  219. package/web/.next/standalone/src/presentation/web/components/features/control-center/use-control-center-state.ts +9 -4
  220. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.stories.tsx +81 -2
  221. package/web/.next/standalone/src/presentation/web/components/features/features-canvas/features-canvas.tsx +1 -1
  222. package/web/.next/standalone/src/presentation/web/hooks/use-graph-state.ts +7 -0
  223. package/web/.next/standalone/src/presentation/web/hooks/use-viewport-persistence.ts +2 -0
  224. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  225. package/web/.next/static/chunks/{293231ccc0b144fa.js → 5968047406179daf.js} +1 -1
  226. package/web/.next/static/chunks/{255140c45a023ff4.js → 6a45ff0fe9faf80e.js} +1 -1
  227. package/web/.next/static/chunks/{9a765e022ef2b815.js → 7ea9e0b8236d5f48.js} +1 -1
  228. package/web/.next/static/chunks/{6931ae67c2484ddf.js → a3a1392c422107d6.js} +1 -1
  229. package/web/.next/static/chunks/{3bc2a07d02372939.js → c558d0da468011b6.js} +1 -1
  230. package/web/.next/static/chunks/{c1dbeb3307dab443.js → ce67a6fcc19c61dc.js} +3 -3
  231. package/web/.next/static/chunks/d5b885838e1da36a.js +1 -0
  232. package/web/.next/static/chunks/{d7786685ec8efe10.js → e8637d52f6093074.js} +1 -1
  233. package/web/.next/static/chunks/{716547ef8d13139d.js → efaf0f0eb50be73f.js} +1 -1
  234. package/web/.next/trace +1 -1
  235. package/web/.next/trace-build +1 -1
  236. package/web/.next/static/chunks/11a6c88ffcbac93f.js +0 -1
  237. /package/web/.next/static/{L6_6jZ4TnQuuDXIF5GZEf → TkQduVaaKmOXMiLB6CK5h}/_buildManifest.js +0 -0
  238. /package/web/.next/static/{L6_6jZ4TnQuuDXIF5GZEf → TkQduVaaKmOXMiLB6CK5h}/_clientMiddlewareManifest.json +0 -0
  239. /package/web/.next/static/{L6_6jZ4TnQuuDXIF5GZEf → TkQduVaaKmOXMiLB6CK5h}/_ssgManifest.js +0 -0
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Fast-Implement Prompt Builder
3
+ *
4
+ * Builds a single-pass implementation prompt for fast mode.
5
+ * Combines the user's raw query with lightweight codebase context
6
+ * (CLAUDE.md, package.json, shallow directory listing).
7
+ *
8
+ * The prompt instructs the executor to implement changes and run tests,
9
+ * but NOT to commit, push, or create PRs (that's the merge node's job).
10
+ */
11
+ import { readFileSync, readdirSync, statSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import yaml from 'js-yaml';
14
+ import { readSpecFile } from '../node-helpers.js';
15
+ /**
16
+ * Read a file from the worktree, returning empty string if not found.
17
+ */
18
+ function readWorktreeFile(worktreePath, filename) {
19
+ try {
20
+ return readFileSync(join(worktreePath, filename), 'utf-8');
21
+ }
22
+ catch {
23
+ return '';
24
+ }
25
+ }
26
+ /**
27
+ * Build a shallow directory listing (depth 1-2) of the worktree.
28
+ * Returns a tree-style string. Skips common noise directories.
29
+ */
30
+ function buildDirectoryListing(worktreePath) {
31
+ const SKIP_DIRS = new Set([
32
+ 'node_modules',
33
+ '.git',
34
+ '.next',
35
+ 'dist',
36
+ 'build',
37
+ 'coverage',
38
+ '.turbo',
39
+ '.cache',
40
+ '.shep',
41
+ ]);
42
+ const lines = [];
43
+ try {
44
+ const topLevel = readdirSync(worktreePath);
45
+ for (const entry of topLevel) {
46
+ if (SKIP_DIRS.has(entry))
47
+ continue;
48
+ const fullPath = join(worktreePath, entry);
49
+ let isDir = false;
50
+ try {
51
+ isDir = statSync(fullPath).isDirectory();
52
+ }
53
+ catch {
54
+ continue;
55
+ }
56
+ if (isDir) {
57
+ lines.push(`${entry}/`);
58
+ try {
59
+ const children = readdirSync(fullPath);
60
+ for (const child of children) {
61
+ if (SKIP_DIRS.has(child))
62
+ continue;
63
+ const childPath = join(fullPath, child);
64
+ let childIsDir = false;
65
+ try {
66
+ childIsDir = statSync(childPath).isDirectory();
67
+ }
68
+ catch {
69
+ continue;
70
+ }
71
+ lines.push(` ${child}${childIsDir ? '/' : ''}`);
72
+ }
73
+ }
74
+ catch {
75
+ // Cannot read subdirectory — skip
76
+ }
77
+ }
78
+ else {
79
+ lines.push(entry);
80
+ }
81
+ }
82
+ }
83
+ catch {
84
+ return '(unable to list directory)';
85
+ }
86
+ return lines.join('\n');
87
+ }
88
+ /**
89
+ * Extract the user query from spec.yaml's userQuery field.
90
+ * Falls back to the raw YAML content if parsing fails.
91
+ */
92
+ function extractUserQuery(specDir) {
93
+ const specContent = readSpecFile(specDir, 'spec.yaml');
94
+ if (!specContent)
95
+ return '';
96
+ try {
97
+ const data = yaml.load(specContent);
98
+ const userQuery = data?.userQuery;
99
+ if (typeof userQuery === 'string' && userQuery.trim()) {
100
+ return userQuery.trim();
101
+ }
102
+ }
103
+ catch {
104
+ // Fall through to raw content
105
+ }
106
+ return specContent;
107
+ }
108
+ /**
109
+ * Build the fast-implement prompt from user query + codebase context.
110
+ *
111
+ * The prompt includes:
112
+ * 1. User's raw query (from spec.yaml userQuery field)
113
+ * 2. CLAUDE.md content (if exists)
114
+ * 3. package.json (if exists)
115
+ * 4. Shallow directory listing (depth 1-2)
116
+ *
117
+ * Instructs the executor to implement, test, and validate — but NOT
118
+ * commit/push/PR (that's the merge node's job).
119
+ */
120
+ export function buildFastImplementPrompt(state) {
121
+ const cwd = state.worktreePath || state.repositoryPath;
122
+ const userQuery = extractUserQuery(state.specDir);
123
+ // Read optional context files
124
+ const claudeMd = readWorktreeFile(cwd, 'CLAUDE.md');
125
+ const packageJson = readWorktreeFile(cwd, 'package.json');
126
+ const dirListing = buildDirectoryListing(cwd);
127
+ // Build sections conditionally
128
+ const sections = [];
129
+ sections.push(`You are a senior software engineer implementing a change directly from a user request.
130
+
131
+ ## User Request
132
+
133
+ ${userQuery}
134
+
135
+ ## Implementation Instructions
136
+
137
+ 1. Implement the requested changes in the codebase
138
+ 2. Write tests for your changes where appropriate
139
+ 3. Run the test suite and fix any failures
140
+ 4. Run the linter and fix any issues
141
+ 5. Ensure the project builds successfully
142
+ 6. Do NOT commit, push, or create a PR — just make the code changes
143
+
144
+ ## Working Directory
145
+
146
+ ${cwd}`);
147
+ if (claudeMd) {
148
+ sections.push(`## Project Guidelines (CLAUDE.md)
149
+
150
+ ${claudeMd}`);
151
+ }
152
+ if (packageJson) {
153
+ // Truncate large package.json to stay within prompt budget
154
+ const truncated = packageJson.length > 3000 ? `${packageJson.slice(0, 3000)}\n...(truncated)` : packageJson;
155
+ sections.push(`## Package Configuration (package.json)
156
+
157
+ \`\`\`json
158
+ ${truncated}
159
+ \`\`\``);
160
+ }
161
+ if (dirListing && dirListing !== '(unable to list directory)') {
162
+ sections.push(`## Project Structure
163
+
164
+ \`\`\`
165
+ ${dirListing}
166
+ \`\`\``);
167
+ }
168
+ sections.push(`## Constraints
169
+
170
+ - Implement ONLY what the user requested — nothing more
171
+ - Follow existing codebase conventions and patterns
172
+ - Do NOT commit, push, or create pull requests
173
+ - Do NOT modify any spec YAML files
174
+ - Keep changes focused and minimal`);
175
+ return sections.join('\n\n');
176
+ }
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { ISpecInitializerService, SpecInitializerResult } from '../../../application/ports/output/services/spec-initializer.interface.js';
9
9
  export declare class SpecInitializerService implements ISpecInitializerService {
10
- initialize(basePath: string, slug: string, featureNumber: number, description: string): Promise<SpecInitializerResult>;
10
+ initialize(basePath: string, slug: string, featureNumber: number, description: string, mode?: 'fast'): Promise<SpecInitializerResult>;
11
11
  /**
12
12
  * Scan specs/ for existing NNN-* directories and return the next available number.
13
13
  * Uses the DB-derived hint as a minimum, but always respects filesystem state.
@@ -1 +1 @@
1
- {"version":3,"file":"spec-initializer.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/spec/spec-initializer.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,mEAAmE,CAAC;AA8P3E,qBAAa,sBAAuB,YAAW,uBAAuB;IAC9D,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,qBAAqB,CAAC;IA4BjC;;;OAGG;YACW,iBAAiB;CAoBhC"}
1
+ {"version":3,"file":"spec-initializer.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/spec/spec-initializer.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,mEAAmE,CAAC;AA8P3E,qBAAa,sBAAuB,YAAW,uBAAuB;IAC9D,UAAU,CACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,qBAAqB,CAAC;IAqCjC;;;OAGG;YACW,iBAAiB;CAoBhC"}
@@ -240,7 +240,7 @@ const TEMPLATES = [
240
240
  { filename: 'feature.yaml', content: FEATURE_YAML },
241
241
  ];
242
242
  export class SpecInitializerService {
243
- async initialize(basePath, slug, featureNumber, description) {
243
+ async initialize(basePath, slug, featureNumber, description, mode) {
244
244
  // Scan existing specs/ directory for highest NNN prefix to avoid collisions
245
245
  // (specs may have been created outside the DB, e.g., via /shep-kit:new-feature)
246
246
  const resolvedNumber = await this.resolveNextNumber(basePath, featureNumber);
@@ -253,8 +253,13 @@ export class SpecInitializerService {
253
253
  const date = now.toISOString().split('T')[0];
254
254
  const timestamp = now.toISOString().replace(/\.\d{3}Z$/, 'Z');
255
255
  const vars = { nnn, slug, featureNumber: resolvedNumber, date, timestamp, description };
256
- // Write all template files
257
- await Promise.all(TEMPLATES.map(({ filename, content }) => writeFile(join(specDir, filename), applyTemplate(content, vars), 'utf-8')));
256
+ // In fast mode, write feature.yaml + spec.yaml (spec.yaml stores the user query
257
+ // which the fast-implement node reads; no research/plan/tasks needed)
258
+ const templates = mode === 'fast'
259
+ ? TEMPLATES.filter(({ filename }) => filename === 'feature.yaml' || filename === 'spec.yaml')
260
+ : TEMPLATES;
261
+ // Write template files
262
+ await Promise.all(templates.map(({ filename, content }) => writeFile(join(specDir, filename), applyTemplate(content, vars), 'utf-8')));
258
263
  return { specDir, featureNumber: nnn };
259
264
  }
260
265
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"new.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/new.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiDpC;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CA4G1C"}
1
+ {"version":3,"file":"new.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/new.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkDpC;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CA8G1C"}
@@ -48,6 +48,7 @@ export function createNewCommand() {
48
48
  .option('--allow-merge', 'Auto-approve merge phase')
49
49
  .option('--allow-all', 'Run fully autonomous (no approval pauses)')
50
50
  .option('--parent <fid>', 'Parent feature ID (full or partial prefix)')
51
+ .option('--fast', 'Skip SDLC phases and implement directly from your prompt')
51
52
  .action(async (description, options) => {
52
53
  try {
53
54
  const useCase = container.resolve(CreateFeatureUseCase);
@@ -83,6 +84,7 @@ export function createNewCommand() {
83
84
  push,
84
85
  openPr,
85
86
  ...(parentId !== undefined && { parentId }),
87
+ ...(options.fast && { fast: true }),
86
88
  }));
87
89
  const { feature, warning } = result;
88
90
  const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
@@ -15,6 +15,8 @@ interface CreateFeatureInput {
15
15
  push?: boolean;
16
16
  openPr?: boolean;
17
17
  parentId?: string;
18
+ /** When true, skip SDLC phases and implement directly from the prompt. */
19
+ fast?: boolean;
18
20
  }
19
21
  export declare function createFeature(input: CreateFeatureInput): Promise<{
20
22
  feature?: Feature;
@@ -1 +1 @@
1
- {"version":3,"file":"create-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/create-feature.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAEpE,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAQD,UAAU,kBAAkB;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,aAAa,CAAC,EAAE;QACd,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAaD,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyDhD"}
1
+ {"version":3,"file":"create-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/create-feature.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAEpE,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAQD,UAAU,kBAAkB;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,aAAa,CAAC,EAAE;QACd,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAaD,wBAAsB,aAAa,CACjC,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA4DhD"}
@@ -9,7 +9,7 @@ function composeUserInput(description, attachments) {
9
9
  return userInput;
10
10
  }
11
11
  export async function createFeature(input) {
12
- const { description, repositoryPath, attachments, approvalGates, push, openPr, parentId } = input;
12
+ const { description, repositoryPath, attachments, approvalGates, push, openPr, parentId, fast } = input;
13
13
  if (!description?.trim()) {
14
14
  return { error: 'description is required' };
15
15
  }
@@ -33,6 +33,7 @@ export async function createFeature(input) {
33
33
  openPr: openPr ?? false,
34
34
  ...(parentId ? { parentId } : {}),
35
35
  description,
36
+ ...(fast ? { fast } : {}),
36
37
  });
37
38
  // Phase 2 (background): metadata generation, worktree, spec, agent spawn
38
39
  // Fire-and-forget — the UI gets the real feature ID immediately
@@ -44,6 +45,7 @@ export async function createFeature(input) {
44
45
  push: push ?? false,
45
46
  openPr: openPr ?? false,
46
47
  ...(parentId ? { parentId } : {}),
48
+ ...(fast ? { fast } : {}),
47
49
  }, shouldSpawn)
48
50
  .catch((err) => {
49
51
  // eslint-disable-next-line no-console
@@ -18,6 +18,8 @@ export interface FeatureCreatePayload {
18
18
  push: boolean;
19
19
  openPr: boolean;
20
20
  parentId?: string;
21
+ /** When true, skip SDLC phases and implement directly from the prompt. */
22
+ fast: boolean;
21
23
  }
22
24
  export interface FeatureCreateDrawerProps {
23
25
  open: boolean;
@@ -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":"AA2BA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAG5E,YAAY,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAE/F,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE;QACb,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAcD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,kGAAkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAoB,EACpB,gBAAgB,EAChB,QAAQ,EACR,eAAe,GAChB,EAAE,wBAAwB,2CA4P1B"}
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":"AA2BA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAC/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAG5E,YAAY,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAE/F,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE;QACb,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAC;CACf;AAcD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,kGAAkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAoB,EACpB,gBAAgB,EAChB,QAAQ,EACR,eAAe,GAChB,EAAE,wBAAwB,2CA+Q1B"}
@@ -37,6 +37,7 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
37
37
  const [push, setPush] = useState(defaultPush);
38
38
  const [openPr, setOpenPr] = useState(defaultOpenPr);
39
39
  const [parentId, setParentId] = useState(undefined);
40
+ const [fast, setFast] = useState(false);
40
41
  // Sync state when workflowDefaults load asynchronously
41
42
  useEffect(() => {
42
43
  if (workflowDefaults) {
@@ -58,6 +59,7 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
58
59
  setPush(defaultPush);
59
60
  setOpenPr(defaultOpenPr);
60
61
  setParentId(undefined);
62
+ setFast(false);
61
63
  }, [defaultGates, defaultPush, defaultOpenPr]);
62
64
  // Track whether the form has unsaved data
63
65
  const isDirty = description.trim() !== '' || attachments.length > 0;
@@ -79,6 +81,7 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
79
81
  },
80
82
  push: push || openPr,
81
83
  openPr,
84
+ fast,
82
85
  ...(parentId ? { parentId } : {}),
83
86
  });
84
87
  resetForm();
@@ -90,6 +93,7 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
90
93
  onSubmit,
91
94
  push,
92
95
  openPr,
96
+ fast,
93
97
  parentId,
94
98
  createSound,
95
99
  resetForm,
@@ -109,7 +113,7 @@ export function FeatureCreateDrawer({ open, onClose, onSubmit, repositoryPath, i
109
113
  setAttachments((prev) => prev.filter((f) => f.path !== path));
110
114
  }, []);
111
115
  const hasFeatures = features && features.length > 0;
112
- return (_jsx(BaseDrawer, { open: open, onClose: attemptClose, size: "md", modal: false, dismissOnOutsideClick: true, "data-testid": "feature-create-drawer", header: _jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-2.5 w-2.5 shrink-0 rounded-full bg-blue-500" }), _jsx(DrawerTitle, { children: "NEW FEATURE" })] }), isSubmitting ? (_jsx(DrawerDescription, { asChild: true, children: _jsx("div", { children: _jsx(Badge, { variant: "secondary", children: "Creating..." }) }) })) : null] }), footer: _jsxs("div", { className: "flex flex-row justify-end gap-2", children: [_jsx(Button, { variant: "outline", onClick: attemptClose, disabled: isSubmitting, children: "Cancel" }), _jsx(Button, { type: "submit", form: "create-feature-form", disabled: !description.trim() || isSubmitting, children: isSubmitting ? 'Creating...' : '+ Create Feature' })] }), children: _jsx("div", { className: "overflow-y-auto p-4", children: _jsxs("form", { id: "create-feature-form", onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "feature-description", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "DESCRIBE YOUR FEATURE" }), _jsx(Textarea, { id: "feature-description", placeholder: "e.g. Add GitHub OAuth login with callback handling and token refresh...", value: description, onChange: (e) => setDescription(e.target.value), rows: 4, required: true, disabled: isSubmitting })] }), hasFeatures ? (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "parent-feature", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "PARENT FEATURE" }), _jsx(ParentFeatureCombobox, { features: features, value: parentId, onChange: setParentId, disabled: isSubmitting })] })) : null, _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "APPROVE" }), _jsx(CheckboxGroup, { label: "Autonomous Mode", description: "YOLO!", parentAriaLabel: "Auto approve all", options: AUTO_APPROVE_OPTIONS, value: approvalGates, onValueChange: setApprovalGates, disabled: isSubmitting })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "GIT" }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(CheckboxGroupItem, { id: "push", label: "Push", description: "Push branch to remote after implementation.", checked: push || openPr, onCheckedChange: setPush, disabled: openPr || isSubmitting }), _jsx(CheckboxGroupItem, { id: "open-pr", label: "Create PR", description: "Open a pull request after pushing.", checked: openPr, onCheckedChange: setOpenPr, disabled: isSubmitting })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: ["ATTACHMENTS", attachments.length > 0 && (_jsxs("span", { className: "text-muted-foreground/60 ml-1.5", children: ["(", attachments.length, ")"] }))] }), _jsxs(Button, { type: "button", variant: "outline", size: "xs", onClick: handleAddFiles, disabled: isSubmitting, children: [_jsx(PlusIcon, { className: "size-3" }), "Add Files"] })] }), attachments.length > 0 && (_jsx("div", { className: "flex flex-col gap-2", children: attachments.map((file) => (_jsx(AttachmentCard, { file: file, onRemove: () => handleRemoveFile(file.path), disabled: isSubmitting }, file.path))) }))] })] }) }) }));
116
+ return (_jsx(BaseDrawer, { open: open, onClose: attemptClose, size: "md", modal: false, dismissOnOutsideClick: true, "data-testid": "feature-create-drawer", header: _jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "h-2.5 w-2.5 shrink-0 rounded-full bg-blue-500" }), _jsx(DrawerTitle, { children: "NEW FEATURE" })] }), isSubmitting ? (_jsx(DrawerDescription, { asChild: true, children: _jsx("div", { children: _jsx(Badge, { variant: "secondary", children: "Creating..." }) }) })) : null] }), footer: _jsxs("div", { className: "flex flex-row justify-end gap-2", children: [_jsx(Button, { variant: "outline", onClick: attemptClose, disabled: isSubmitting, children: "Cancel" }), _jsx(Button, { type: "submit", form: "create-feature-form", disabled: !description.trim() || isSubmitting, children: isSubmitting ? 'Creating...' : '+ Create Feature' })] }), children: _jsx("div", { className: "overflow-y-auto p-4", children: _jsxs("form", { id: "create-feature-form", onSubmit: handleSubmit, className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "feature-description", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "DESCRIBE YOUR FEATURE" }), _jsx(Textarea, { id: "feature-description", placeholder: "e.g. Add GitHub OAuth login with callback handling and token refresh...", value: description, onChange: (e) => setDescription(e.target.value), rows: 4, required: true, disabled: isSubmitting })] }), hasFeatures ? (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { htmlFor: "parent-feature", className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "PARENT FEATURE" }), _jsx(ParentFeatureCombobox, { features: features, value: parentId, onChange: setParentId, disabled: isSubmitting })] })) : null, _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "MODE" }), _jsx(CheckboxGroupItem, { id: "fast-mode", label: "Fast Mode", description: "Skip SDLC phases and implement directly from your prompt.", checked: fast, onCheckedChange: setFast, disabled: isSubmitting })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "APPROVE" }), _jsx(CheckboxGroup, { label: "Autonomous Mode", description: "YOLO!", parentAriaLabel: "Auto approve all", options: AUTO_APPROVE_OPTIONS, value: approvalGates, onValueChange: setApprovalGates, disabled: isSubmitting })] }), _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: "GIT" }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(CheckboxGroupItem, { id: "push", label: "Push", description: "Push branch to remote after implementation.", checked: push || openPr, onCheckedChange: setPush, disabled: openPr || isSubmitting }), _jsx(CheckboxGroupItem, { id: "open-pr", label: "Create PR", description: "Open a pull request after pushing.", checked: openPr, onCheckedChange: setOpenPr, disabled: isSubmitting })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs(Label, { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: ["ATTACHMENTS", attachments.length > 0 && (_jsxs("span", { className: "text-muted-foreground/60 ml-1.5", children: ["(", attachments.length, ")"] }))] }), _jsxs(Button, { type: "button", variant: "outline", size: "xs", onClick: handleAddFiles, disabled: isSubmitting, children: [_jsx(PlusIcon, { className: "size-3" }), "Add Files"] })] }), attachments.length > 0 && (_jsx("div", { className: "flex flex-col gap-2", children: attachments.map((file) => (_jsx(AttachmentCard, { file: file, onRemove: () => handleRemoveFile(file.path), disabled: isSubmitting }, file.path))) }))] })] }) }) }));
113
117
  }
114
118
  function ParentFeatureCombobox({ features, value, onChange, disabled, }) {
115
119
  const [open, setOpen] = useState(false);
@@ -77,6 +77,24 @@ export declare const PushOnly: Story;
77
77
  * checked, but "Push" is non-interactive (disabled).
78
78
  */
79
79
  export declare const PrChecked: Story;
80
+ /**
81
+ * Fast Mode off (default) — the "Fast Mode" checkbox in the MODE section
82
+ * is unchecked. The full SDLC pipeline (analyze, requirements, research,
83
+ * plan, implement) will run.
84
+ */
85
+ export declare const FastModeOff: Story;
86
+ /**
87
+ * Fast Mode on — the "Fast Mode" checkbox is checked. When submitted,
88
+ * `fast: true` is included in the payload, skipping SDLC phases and
89
+ * implementing directly from the user's prompt.
90
+ */
91
+ export declare const FastModeOn: Story;
92
+ /**
93
+ * Fast Mode combined with approval gates and git options — demonstrates
94
+ * that fast mode works alongside other form controls. Here fast mode,
95
+ * auto-approve all, push, and create PR are all enabled.
96
+ */
97
+ export declare const FastModeWithOptions: Story;
80
98
  /**
81
99
  * Drawer pre-populated from workflow settings — PRD and Plan approval gates
82
100
  * are checked, Push and Create PR are enabled. These values come from
@@ -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;AAiDlD,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;AAYF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAWlC,CAAC;AAgDF,+EAA+E;AAC/E,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAgBjC,CAAC;AAMF,eAAO,MAAM,WAAW,EAAE,KAsCzB,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;AAiDlD,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;AAYF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAWlC,CAAC;AAgDF,+EAA+E;AAC/E,eAAO,MAAM,QAAQ,EAAE,KAEtB,CAAC;AAMF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAgBjC,CAAC;AAMF,eAAO,MAAM,WAAW,EAAE,KAsCzB,CAAC"}
@@ -212,6 +212,55 @@ export const PrChecked = {
212
212
  await userEvent.click(prCheckbox);
213
213
  },
214
214
  };
215
+ /* ---------------------------------------------------------------------------
216
+ * Fast mode stories
217
+ * ------------------------------------------------------------------------- */
218
+ /**
219
+ * Fast Mode off (default) — the "Fast Mode" checkbox in the MODE section
220
+ * is unchecked. The full SDLC pipeline (analyze, requirements, research,
221
+ * plan, implement) will run.
222
+ */
223
+ export const FastModeOff = {
224
+ render: () => _jsx(CreateDrawerTrigger, { label: "Open (Fast Mode Off)" }),
225
+ play: async ({ canvasElement }) => {
226
+ const canvas = within(canvasElement);
227
+ await userEvent.click(canvas.getByRole('button', { name: 'Open (Fast Mode Off)' }));
228
+ },
229
+ };
230
+ /**
231
+ * Fast Mode on — the "Fast Mode" checkbox is checked. When submitted,
232
+ * `fast: true` is included in the payload, skipping SDLC phases and
233
+ * implementing directly from the user's prompt.
234
+ */
235
+ export const FastModeOn = {
236
+ render: () => _jsx(CreateDrawerTrigger, { label: "Open (Fast Mode On)" }),
237
+ play: async ({ canvasElement }) => {
238
+ const canvas = within(canvasElement);
239
+ await userEvent.click(canvas.getByRole('button', { name: 'Open (Fast Mode On)' }));
240
+ const body = within(canvasElement.ownerDocument.body);
241
+ const fastCheckbox = await body.findByLabelText('Fast Mode');
242
+ await userEvent.click(fastCheckbox);
243
+ },
244
+ };
245
+ /**
246
+ * Fast Mode combined with approval gates and git options — demonstrates
247
+ * that fast mode works alongside other form controls. Here fast mode,
248
+ * auto-approve all, push, and create PR are all enabled.
249
+ */
250
+ export const FastModeWithOptions = {
251
+ render: () => _jsx(CreateDrawerTrigger, { label: "Open (Fast + Options)" }),
252
+ play: async ({ canvasElement }) => {
253
+ const canvas = within(canvasElement);
254
+ await userEvent.click(canvas.getByRole('button', { name: 'Open (Fast + Options)' }));
255
+ const body = within(canvasElement.ownerDocument.body);
256
+ const fastCheckbox = await body.findByLabelText('Fast Mode');
257
+ await userEvent.click(fastCheckbox);
258
+ const autoApprove = body.getByLabelText('Auto approve all');
259
+ await userEvent.click(autoApprove);
260
+ const prCheckbox = body.getByLabelText('Create PR');
261
+ await userEvent.click(prCheckbox);
262
+ },
263
+ };
215
264
  /* ---------------------------------------------------------------------------
216
265
  * Workflow defaults stories
217
266
  * ------------------------------------------------------------------------- */
@@ -1 +1 @@
1
- {"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAc5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAoPzF"}
1
+ {"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,eAAe,CAAC;AAGpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAsB5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAuQzF"}
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { useCallback, useEffect, useMemo } from 'react';
3
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
4
4
  import { useRouter, usePathname } from 'next/navigation';
5
+ import { useReactFlow } from '@xyflow/react';
5
6
  import { FeaturesCanvas } from '../../features/features-canvas/index.js';
6
7
  import { useSidebarFeaturesContext, mapNodeStateToSidebarStatus, } from '../../../hooks/sidebar-features-context.js';
7
8
  import { useSelectedFeatureId } from '../../../hooks/use-selected-feature-id.js';
@@ -10,12 +11,20 @@ import { useDrawerCloseGuard } from '../../../hooks/drawer-close-guard.js';
10
11
  import { useViewportPersistence } from '../../../hooks/use-viewport-persistence.js';
11
12
  import { ControlCenterEmptyState } from './control-center-empty-state.js';
12
13
  import { useControlCenterState } from './use-control-center-state.js';
14
+ const AUTO_FOCUS_OPTIONS = {
15
+ maxZoom: 1.0,
16
+ padding: 0.5,
17
+ duration: 500,
18
+ };
19
+ const AUTO_FOCUS_DRAWER_DELAY_MS = 600;
13
20
  export function ControlCenterInner({ initialNodes, initialEdges }) {
14
21
  const router = useRouter();
15
22
  const pathname = usePathname();
16
23
  const selectedFeatureId = useSelectedFeatureId();
17
24
  const clickSound = useSoundAction('click');
18
25
  const { guardedNavigate } = useDrawerCloseGuard();
26
+ const { fitView } = useReactFlow();
27
+ const drawerTimerRef = useRef(null);
19
28
  const { defaultViewport, onMoveEnd: handleViewportChange, resetViewport, } = useViewportPersistence();
20
29
  const { nodes, edges, onNodesChange, handleConnect, handleAddRepository, handleDeleteFeature, handleDeleteRepository, createFeatureNode, setCallbacks, } = useControlCenterState(initialNodes, initialEdges);
21
30
  // Publish sidebar features to context whenever feature node data changes
@@ -107,11 +116,26 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
107
116
  useEffect(() => {
108
117
  const handler = (e) => {
109
118
  const path = e.detail.path;
110
- handleAddRepository(path);
119
+ const { wasEmpty, repoPath } = handleAddRepository(path);
120
+ if (wasEmpty) {
121
+ // Wait for next render so the repo node exists in the DOM, then auto-focus
122
+ setTimeout(() => {
123
+ fitView(AUTO_FOCUS_OPTIONS);
124
+ // Open the create-feature drawer after the fitView animation completes
125
+ drawerTimerRef.current = setTimeout(() => {
126
+ guardedNavigate(() => router.push(`/create?repo=${encodeURIComponent(repoPath)}`));
127
+ }, AUTO_FOCUS_DRAWER_DELAY_MS);
128
+ }, 0);
129
+ }
111
130
  };
112
131
  window.addEventListener('shep:add-repository', handler);
113
- return () => window.removeEventListener('shep:add-repository', handler);
114
- }, [handleAddRepository]);
132
+ return () => {
133
+ window.removeEventListener('shep:add-repository', handler);
134
+ if (drawerTimerRef.current != null) {
135
+ clearTimeout(drawerTimerRef.current);
136
+ }
137
+ };
138
+ }, [handleAddRepository, fitView, guardedNavigate, router]);
115
139
  // Listen for create events from the create drawer (with real feature ID from server)
116
140
  useEffect(() => {
117
141
  const handler = (e) => {
@@ -9,7 +9,10 @@ export interface ControlCenterState {
9
9
  edges: Edge[];
10
10
  onNodesChange: (changes: NodeChange<CanvasNodeType>[]) => void;
11
11
  handleConnect: (connection: Connection) => void;
12
- handleAddRepository: (path: string) => void;
12
+ handleAddRepository: (path: string) => {
13
+ wasEmpty: boolean;
14
+ repoPath: string;
15
+ };
13
16
  handleLayout: (direction: LayoutDirection) => void;
14
17
  handleDeleteFeature: (featureId: string) => void;
15
18
  handleDeleteRepository: (repositoryId: string) => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAcjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAM7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAOD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CAmXpB"}
1
+ {"version":3,"file":"use-control-center-state.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/use-control-center-state.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AAcjC,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAM7E,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,KAAK,IAAI,CAAC;IAC/D,aAAa,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAChD,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/E,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,sBAAsB,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACvC,QAAQ,CAAC,EAAE,MAAM,KACd,MAAM,CAAC;IACZ,wDAAwD;IACxD,wBAAwB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACxE,gDAAgD;IAChD,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IACtE,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAC;CACnD;AAQD,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,cAAc,EAAE,EAC9B,YAAY,EAAE,IAAI,EAAE,GACnB,kBAAkB,CAuXpB"}
@@ -18,11 +18,12 @@ const POLL_INTERVAL_MS = 3_000;
18
18
  /** Must match the message string emitted by the SSE route in agent-events/route.ts */
19
19
  const METADATA_UPDATED_MESSAGE = 'Feature metadata updated';
20
20
  let nextFeatureId = 0;
21
+ let nextRepoTempId = 0;
21
22
  export function useControlCenterState(initialNodes, initialEdges) {
22
23
  const router = useRouter();
23
24
  const deleteSound = useSoundAction('delete');
24
25
  const createSound = useSoundAction('create');
25
- const { nodes, edges, reconcile, updateFeature, addPendingFeature, removeFeature, restoreFeature, addRepository: addRepositoryToMap, removeRepository, replaceRepository, getFeatureRepositoryPath, getRepositoryData, setCallbacks, } = useGraphState(initialNodes, initialEdges);
26
+ const { nodes, edges, reconcile, updateFeature, addPendingFeature, removeFeature, restoreFeature, addRepository: addRepositoryToMap, removeRepository, replaceRepository, getFeatureRepositoryPath, getRepositoryData, getRepoMapSize, setCallbacks, } = useGraphState(initialNodes, initialEdges);
26
27
  // Refs for stable access to latest nodes/edges without callback recreation
27
28
  const nodesRef = useRef(nodes);
28
29
  const edgesRef = useRef(edges);
@@ -274,7 +275,8 @@ export function useControlCenterState(initialNodes, initialEdges) {
274
275
  reconcile(result.nodes, result.edges);
275
276
  }, [reconcile]);
276
277
  const handleAddRepository = useCallback((path) => {
277
- const tempId = `repo-temp-${Date.now()}`;
278
+ const wasEmpty = getRepoMapSize() === 0;
279
+ const tempId = `repo-temp-${++nextRepoTempId}`;
278
280
  const repoName = path
279
281
  .replace(/[\\/]+$/, '')
280
282
  .split(/[\\/]/)
@@ -300,7 +302,8 @@ export function useControlCenterState(initialNodes, initialEdges) {
300
302
  removeRepository(tempId);
301
303
  toast.error('Failed to add repository');
302
304
  });
303
- }, [addRepositoryToMap, removeRepository, replaceRepository, createSound]);
305
+ return { wasEmpty, repoPath: path };
306
+ }, [addRepositoryToMap, removeRepository, replaceRepository, createSound, getRepoMapSize]);
304
307
  return {
305
308
  nodes,
306
309
  edges,
@@ -15,7 +15,7 @@ function ResetButton({ onResetViewport }) {
15
15
  const viewport = onResetViewport();
16
16
  setViewport(viewport, { duration: 400 });
17
17
  }, [onResetViewport, setViewport]);
18
- return (_jsx(ControlButton, { onClick: handleReset, title: "Reset view", "aria-label": "Reset view", children: _jsx(RotateCcw, {}) }));
18
+ return (_jsx(ControlButton, { onClick: handleReset, title: "Reset view", "aria-label": "Reset view", children: _jsx(RotateCcw, { style: { fill: 'none' } }) }));
19
19
  }
20
20
  export function FeaturesCanvas({ nodes, edges, selectedFeatureId, defaultViewport, onNodesChange, onAddFeature, onConnect, onNodeClick, onPaneClick, onCanvasDrag, onMoveEnd, onResetViewport, toolbar, emptyState, }) {
21
21
  const nodeTypes = useMemo(() => ({
@@ -16,4 +16,5 @@ export declare const MultipleRepositoriesMixedConnections: Story;
16
16
  export declare const InteractiveWithRepository: Story;
17
17
  export declare const WithSavedViewport: Story;
18
18
  export declare const ZoomedOutViewport: Story;
19
+ export declare const FastModeFeatures: Story;
19
20
  //# sourceMappingURL=features-canvas.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"features-canvas.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/features-canvas/features-canvas.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAMnD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAcrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAwKnC,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAKxB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAK3B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAK5B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KASzB,CAAC;AAoDF,eAAO,MAAM,mCAAmC,EAAE,KAKjD,CAAC;AA4BF,eAAO,MAAM,gCAAgC,EAAE,KAO9C,CAAC;AA0DF,eAAO,MAAM,gCAAgC,EAAE,KAS9C,CAAC;AAiDF,eAAO,MAAM,oBAAoB,EAAE,KAQlC,CAAC;AAqGF,eAAO,MAAM,oCAAoC,EAAE,KAKlD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,KAMvC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAO/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAO/B,CAAC"}
1
+ {"version":3,"file":"features-canvas.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/features-canvas/features-canvas.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAOnD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAcrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAwKnC,eAAO,MAAM,KAAK,EAAE,KAMnB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KAKxB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAK3B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAK5B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KASzB,CAAC;AAoDF,eAAO,MAAM,mCAAmC,EAAE,KAKjD,CAAC;AA4BF,eAAO,MAAM,gCAAgC,EAAE,KAO9C,CAAC;AA0DF,eAAO,MAAM,gCAAgC,EAAE,KAS9C,CAAC;AAiDF,eAAO,MAAM,oBAAoB,EAAE,KAQlC,CAAC;AAqGF,eAAO,MAAM,oCAAoC,EAAE,KAKlD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,KAMvC,CAAC;AAIF,eAAO,MAAM,iBAAiB,EAAE,KAO/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAO/B,CAAC;AAsEF,eAAO,MAAM,gBAAgB,EAAE,KAM9B,CAAC"}