@shepai/cli 1.122.2-pr381.7d9e407 → 1.122.2-pr390.b1ef40f

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 (207) hide show
  1. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.js +1 -1
  2. package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts +8 -28
  3. package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts.map +1 -1
  4. package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.js +29 -187
  5. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  6. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +0 -9
  7. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts +0 -5
  8. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
  9. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +54 -82
  10. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +1 -1
  11. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +2 -2
  12. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts +6 -0
  13. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts.map +1 -1
  14. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.js +60 -0
  15. package/dist/src/presentation/web/app/build-graph-nodes.d.ts +7 -0
  16. package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
  17. package/dist/src/presentation/web/app/build-graph-nodes.js +7 -0
  18. package/dist/src/presentation/web/components/common/repository-node/repository-node-config.d.ts +8 -0
  19. package/dist/src/presentation/web/components/common/repository-node/repository-node-config.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
  21. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +6 -6
  22. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.d.ts +2 -0
  23. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.d.ts.map +1 -1
  24. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.js +107 -17
  25. package/dist/src/presentation/web/lib/layout-with-dagre.js +1 -1
  26. package/dist/tsconfig.build.tsbuildinfo +1 -1
  27. package/package.json +1 -1
  28. package/web/.next/BUILD_ID +1 -1
  29. package/web/.next/build-manifest.json +2 -2
  30. package/web/.next/fallback-build-manifest.json +2 -2
  31. package/web/.next/prerender-manifest.json +3 -3
  32. package/web/.next/required-server-files.js +1 -1
  33. package/web/.next/required-server-files.json +1 -1
  34. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +22 -22
  35. package/web/.next/server/app/(dashboard)/@drawer/create/page.js +2 -2
  36. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  37. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  38. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
  39. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js +3 -3
  40. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  41. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  42. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +28 -28
  43. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js +3 -3
  44. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  45. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  46. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
  47. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js +2 -2
  48. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  49. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  50. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +22 -22
  51. package/web/.next/server/app/(dashboard)/create/page.js +2 -2
  52. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  53. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  54. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
  55. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js +3 -3
  56. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  57. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  58. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +28 -28
  59. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js +3 -3
  60. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  61. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  62. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +20 -20
  63. package/web/.next/server/app/(dashboard)/page.js +2 -2
  64. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  65. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
  67. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js +2 -2
  68. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  69. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  70. package/web/.next/server/app/_global-error.html +2 -2
  71. package/web/.next/server/app/_global-error.rsc +1 -1
  72. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  73. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  74. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  75. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  76. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  77. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  78. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  79. package/web/.next/server/app/api/graph-data/route.js +1 -1
  80. package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
  81. package/web/.next/server/app/settings/page/server-reference-manifest.json +6 -6
  82. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  83. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  84. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  85. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  86. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  87. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  88. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  89. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  90. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  91. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
  92. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
  93. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  94. package/web/.next/server/chunks/[root-of-the-server]__dcd4f847._.js +3 -0
  95. package/web/.next/server/chunks/{[root-of-the-server]__42b7ab55._.js.map → [root-of-the-server]__dcd4f847._.js.map} +1 -1
  96. package/web/.next/server/chunks/ssr/403f9_next_dist_31ea46d3._.js +1 -1
  97. package/web/.next/server/chunks/ssr/403f9_next_dist_c9d9b4d7._.js +1 -1
  98. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  99. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  100. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js +1 -1
  101. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js.map +1 -1
  102. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js +1 -1
  103. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js.map +1 -1
  104. package/web/.next/server/chunks/ssr/[root-of-the-server]__06fef644._.js +1 -1
  105. package/web/.next/server/chunks/ssr/{[root-of-the-server]__a022445f._.js → [root-of-the-server]__14664e9b._.js} +3 -3
  106. package/web/.next/server/chunks/ssr/{[root-of-the-server]__a022445f._.js.map → [root-of-the-server]__14664e9b._.js.map} +1 -1
  107. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js +1 -1
  108. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js.map +1 -1
  109. package/web/.next/server/chunks/ssr/[root-of-the-server]__6677a82c._.js +3 -0
  110. package/web/.next/server/chunks/ssr/{[root-of-the-server]__b724df9e._.js.map → [root-of-the-server]__6677a82c._.js.map} +1 -1
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  112. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
  114. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
  115. package/web/.next/server/chunks/ssr/{[root-of-the-server]__8e3bf5d7._.js → [root-of-the-server]__7cbda1ea._.js} +2 -2
  116. package/web/.next/server/chunks/ssr/{[root-of-the-server]__8e3bf5d7._.js.map → [root-of-the-server]__7cbda1ea._.js.map} +1 -1
  117. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  118. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  119. package/web/.next/server/chunks/ssr/[root-of-the-server]__8c553503._.js +2 -2
  120. package/web/.next/server/chunks/ssr/{[root-of-the-server]__2698e9f4._.js → [root-of-the-server]__9e8b25ad._.js} +2 -2
  121. package/web/.next/server/chunks/ssr/{[root-of-the-server]__2698e9f4._.js.map → [root-of-the-server]__9e8b25ad._.js.map} +1 -1
  122. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +2 -2
  123. package/web/.next/server/chunks/ssr/{[root-of-the-server]__c07f9f79._.js → [root-of-the-server]__aed1d6f8._.js} +2 -2
  124. package/web/.next/server/chunks/ssr/{[root-of-the-server]__c07f9f79._.js.map → [root-of-the-server]__aed1d6f8._.js.map} +1 -1
  125. package/web/.next/server/chunks/ssr/{[root-of-the-server]__c605a375._.js → [root-of-the-server]__ce6057f6._.js} +2 -2
  126. package/web/.next/server/chunks/ssr/{[root-of-the-server]__c605a375._.js.map → [root-of-the-server]__ce6057f6._.js.map} +1 -1
  127. package/web/.next/server/chunks/ssr/[root-of-the-server]__e7258841._.js +3 -0
  128. package/web/.next/server/chunks/ssr/[root-of-the-server]__e7258841._.js.map +1 -0
  129. package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
  130. package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
  131. package/web/.next/server/chunks/ssr/{_434878d3._.js → _15fe9326._.js} +2 -2
  132. package/web/.next/server/chunks/ssr/_15fe9326._.js.map +1 -0
  133. package/web/.next/server/chunks/ssr/_2f6f48b8._.js +1 -1
  134. package/web/.next/server/chunks/ssr/_2f6f48b8._.js.map +1 -1
  135. package/web/.next/server/chunks/ssr/_3a4c94e3._.js +1 -1
  136. package/web/.next/server/chunks/ssr/_90a34ae9._.js +3 -0
  137. package/web/.next/server/chunks/ssr/{_204ecb5a._.js.map → _90a34ae9._.js.map} +1 -1
  138. package/web/.next/server/chunks/ssr/_b56e7571._.js +3 -0
  139. package/web/.next/server/chunks/ssr/_b56e7571._.js.map +1 -0
  140. package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
  141. package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
  142. package/web/.next/server/chunks/ssr/_e9703421._.js +3 -0
  143. package/web/.next/server/chunks/ssr/_e9703421._.js.map +1 -0
  144. package/web/.next/server/chunks/ssr/_f096ab6a._.js +3 -0
  145. package/web/.next/server/chunks/ssr/_f096ab6a._.js.map +1 -0
  146. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  147. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  148. package/web/.next/server/chunks/ssr/node_modules__pnpm_bc66dcc6._.js +3 -0
  149. package/web/.next/server/chunks/ssr/node_modules__pnpm_bc66dcc6._.js.map +1 -0
  150. package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js +2 -2
  151. package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js.map +1 -1
  152. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js +1 -1
  153. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js.map +1 -1
  154. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
  155. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
  156. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
  157. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
  158. package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js +2 -2
  159. package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js.map +1 -1
  160. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  161. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
  162. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
  163. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -1
  164. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
  165. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js.map +1 -1
  166. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  167. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  168. package/web/.next/server/pages/500.html +2 -2
  169. package/web/.next/server/server-reference-manifest.js +1 -1
  170. package/web/.next/server/server-reference-manifest.json +34 -34
  171. package/web/.next/static/chunks/{89ffd07cdb158389.js → 24a0b215d72d8f26.js} +1 -1
  172. package/web/.next/static/chunks/{50bf223ed146d4ed.js → 2c0cf874cda01236.js} +1 -1
  173. package/web/.next/static/chunks/4232eb19944a519e.js +1 -0
  174. package/web/.next/static/chunks/4443ee9c7733399b.js +1 -0
  175. package/web/.next/static/chunks/6b8c3e3d8d4ee08e.js +1 -0
  176. package/web/.next/static/chunks/{df88f3e08b196bbf.js → 9fba6bb38ff0cb38.js} +2 -2
  177. package/web/.next/static/chunks/a58429fc5be52aad.js +1 -0
  178. package/web/.next/static/chunks/b200a40ffcc15eb7.css +1 -0
  179. package/web/.next/static/chunks/{2c0191c062d5f7ae.js → b67d183d3c074a4c.js} +2 -2
  180. package/web/.next/static/chunks/ca946dcbfbb2df74.js +1 -0
  181. package/web/.next/static/chunks/{19401b65e1298cb0.js → cd2bb43fe9138791.js} +1 -1
  182. package/web/.next/static/chunks/d2bfdee31e1a7d8d.js +1 -0
  183. package/web/.next/static/chunks/{4da275e6ef808c4d.js → fadc79bbbae100a7.js} +1 -1
  184. package/web/.next/server/chunks/[root-of-the-server]__42b7ab55._.js +0 -3
  185. package/web/.next/server/chunks/ssr/[root-of-the-server]__9f155c0e._.js +0 -3
  186. package/web/.next/server/chunks/ssr/[root-of-the-server]__9f155c0e._.js.map +0 -1
  187. package/web/.next/server/chunks/ssr/[root-of-the-server]__b724df9e._.js +0 -3
  188. package/web/.next/server/chunks/ssr/_0dc2cfd3._.js +0 -3
  189. package/web/.next/server/chunks/ssr/_0dc2cfd3._.js.map +0 -1
  190. package/web/.next/server/chunks/ssr/_204ecb5a._.js +0 -3
  191. package/web/.next/server/chunks/ssr/_434878d3._.js.map +0 -1
  192. package/web/.next/server/chunks/ssr/_510be09a._.js +0 -3
  193. package/web/.next/server/chunks/ssr/_510be09a._.js.map +0 -1
  194. package/web/.next/server/chunks/ssr/_75f4ccb3._.js +0 -3
  195. package/web/.next/server/chunks/ssr/_75f4ccb3._.js.map +0 -1
  196. package/web/.next/server/chunks/ssr/node_modules__pnpm_b59e4b16._.js +0 -3
  197. package/web/.next/server/chunks/ssr/node_modules__pnpm_b59e4b16._.js.map +0 -1
  198. package/web/.next/static/chunks/0d2af96e64960ef5.css +0 -1
  199. package/web/.next/static/chunks/4562ee849ea13c3a.js +0 -1
  200. package/web/.next/static/chunks/5a9e671eb04de758.js +0 -1
  201. package/web/.next/static/chunks/6a8fb1992b738cc9.js +0 -1
  202. package/web/.next/static/chunks/845d8e58a91014e6.js +0 -1
  203. package/web/.next/static/chunks/a637e16d364af323.js +0 -1
  204. package/web/.next/static/chunks/bc1ce100834f414a.js +0 -1
  205. /package/web/.next/static/{NKkt3_PEmNxKD_ihRAzNE → Fr059mDxLxW71ARoHnB8W}/_buildManifest.js +0 -0
  206. /package/web/.next/static/{NKkt3_PEmNxKD_ihRAzNE → Fr059mDxLxW71ARoHnB8W}/_clientMiddlewareManifest.json +0 -0
  207. /package/web/.next/static/{NKkt3_PEmNxKD_ihRAzNE → Fr059mDxLxW71ARoHnB8W}/_ssgManifest.js +0 -0
@@ -98,94 +98,66 @@ export function createMergeNode(deps) {
98
98
  : undefined;
99
99
  // --- Agent Call 1: Commit + Push + PR (skip on approval resume) ---
100
100
  if (!isResumeAfterInterrupt) {
101
+ if (!remoteAvailable) {
102
+ log.info('No git remote configured — skipping push and PR, will merge locally');
103
+ }
101
104
  const effectiveState = remoteAvailable ? state : { ...state, push: false, openPr: false };
102
- const needsAgentCall = effectiveState.push || effectiveState.openPr;
103
- if (!needsAgentCall) {
104
- // Local-only: commit programmatically in worktree, no agent needed.
105
- // This avoids calling the agent executor just to run git commit,
106
- // which is slow/unreliable on some platforms (e.g. cursor on Windows hangs).
107
- log.info('Local-only mode — committing in worktree programmatically (no agent)');
108
- const worktreeCwd = state.worktreePath ?? cwd;
109
- try {
110
- const msg = `feat: ${branch}`;
111
- const hash = await deps.commitAll(worktreeCwd, msg);
112
- if (hash) {
113
- commitHash = hash;
114
- log.info(`Committed changes in worktree: ${commitHash}`);
115
- messages.push(`[merge] Programmatic commit: ${commitHash}`);
105
+ log.info('Agent call 1: commit + push + PR');
106
+ const commitPushPrPrompt = buildCommitPushPrPrompt(effectiveState, branch, baseBranch, repoUrl);
107
+ const commitResult = await retryExecute(executor, commitPushPrPrompt, options, {
108
+ logger: log,
109
+ });
110
+ totalInputTokens += commitResult.usage?.inputTokens ?? 0;
111
+ totalOutputTokens += commitResult.usage?.outputTokens ?? 0;
112
+ totalCostUsd += commitResult.usage?.costUsd ?? 0;
113
+ totalNumTurns += commitResult.usage?.numTurns ?? 0;
114
+ totalDurationApiMs += commitResult.usage?.durationApiMs ?? 0;
115
+ commitHash = parseCommitHash(commitResult.result) ?? state.commitHash;
116
+ messages.push(`[merge] Agent completed commit/push/PR operations`);
117
+ if (effectiveState.openPr) {
118
+ const prResult = parsePrUrl(commitResult.result);
119
+ if (prResult) {
120
+ prUrl = prResult.url;
121
+ prNumber = prResult.number;
122
+ // Cross-validate agent-parsed PR URL against authoritative source.
123
+ // The agent may hallucinate the repo URL or PR number, so we look up
124
+ // the real PR for this branch via the GitHub API.
125
+ try {
126
+ const prStatuses = await deps.gitPrService.listPrStatuses(cwd);
127
+ const matchingPr = prStatuses.find((pr) => pr.headRefName === branch);
128
+ if (matchingPr) {
129
+ prUrl = matchingPr.url;
130
+ prNumber = matchingPr.number;
131
+ }
116
132
  }
117
- else {
118
- log.info('No changes to commit in worktree');
119
- messages.push(`[merge] No changes to commit`);
133
+ catch {
134
+ // gh CLI unavailable or API failure — fall back to agent-parsed URL
120
135
  }
121
- }
122
- catch (commitErr) {
123
- const errMsg = commitErr instanceof Error ? commitErr.message : String(commitErr);
124
- log.info(`Programmatic commit failed: ${errMsg} — falling back to agent`);
125
- messages.push(`[merge] Programmatic commit failed, falling back to agent`);
126
- // Fall through — needsAgentCall stays false so agent won't run either.
127
- // The localMergeSquash will handle uncommitted changes via --squash.
136
+ messages.push(`[merge] PR created: ${prUrl}`);
128
137
  }
129
138
  }
130
- if (needsAgentCall) {
131
- if (!remoteAvailable) {
132
- log.info('No git remote configured — skipping push and PR, will merge locally');
133
- }
134
- log.info('Agent call 1: commit + push + PR');
135
- const commitPushPrPrompt = buildCommitPushPrPrompt(effectiveState, branch, baseBranch, repoUrl);
136
- const commitResult = await retryExecute(executor, commitPushPrPrompt, options, {
137
- logger: log,
139
+ // --- CI watch/fix loop (when push or openPr is enabled and CI watch is not disabled) ---
140
+ const ciWatchEnabled = getSettings().workflow?.ciWatchEnabled !== false;
141
+ if (ciWatchEnabled && (effectiveState.push || effectiveState.openPr)) {
142
+ const ciResult = await runCiWatchFixLoop({
143
+ executor,
144
+ gitPrService: deps.gitPrService,
145
+ featureRepository: deps.featureRepository,
146
+ }, {
147
+ cwd,
148
+ branch,
149
+ options,
150
+ feature,
151
+ prUrl,
152
+ prNumber,
153
+ existingAttempts: ciFixAttempts,
154
+ messages,
155
+ log,
138
156
  });
139
- totalInputTokens += commitResult.usage?.inputTokens ?? 0;
140
- totalOutputTokens += commitResult.usage?.outputTokens ?? 0;
141
- totalCostUsd += commitResult.usage?.costUsd ?? 0;
142
- totalNumTurns += commitResult.usage?.numTurns ?? 0;
143
- totalDurationApiMs += commitResult.usage?.durationApiMs ?? 0;
144
- commitHash = parseCommitHash(commitResult.result) ?? state.commitHash;
145
- messages.push(`[merge] Agent completed commit/push/PR operations`);
146
- if (effectiveState.openPr) {
147
- const prResult = parsePrUrl(commitResult.result);
148
- if (prResult) {
149
- prUrl = prResult.url;
150
- prNumber = prResult.number;
151
- // Cross-validate agent-parsed PR URL against authoritative source.
152
- try {
153
- const prStatuses = await deps.gitPrService.listPrStatuses(cwd);
154
- const matchingPr = prStatuses.find((pr) => pr.headRefName === branch);
155
- if (matchingPr) {
156
- prUrl = matchingPr.url;
157
- prNumber = matchingPr.number;
158
- }
159
- }
160
- catch {
161
- // gh CLI unavailable or API failure — fall back to agent-parsed URL
162
- }
163
- messages.push(`[merge] PR created: ${prUrl}`);
164
- }
165
- }
166
- // --- CI watch/fix loop (when push or openPr is enabled and CI watch is not disabled) ---
167
- const ciWatchEnabled = getSettings().workflow?.ciWatchEnabled !== false;
168
- if (ciWatchEnabled && (effectiveState.push || effectiveState.openPr)) {
169
- const ciResult = await runCiWatchFixLoop({
170
- executor,
171
- gitPrService: deps.gitPrService,
172
- featureRepository: deps.featureRepository,
173
- }, {
174
- cwd,
175
- branch,
176
- options,
177
- feature,
178
- prUrl,
179
- prNumber,
180
- existingAttempts: ciFixAttempts,
181
- messages,
182
- log,
183
- });
184
- ciStatus = ciResult.ciStatus;
185
- ciFixAttempts = ciResult.ciFixAttempts;
186
- ciFixHistory = ciResult.ciFixHistory;
187
- ciFixStatus = ciResult.ciFixStatus;
188
- }
157
+ ciStatus = ciResult.ciStatus;
158
+ ciFixAttempts = ciResult.ciFixAttempts;
159
+ ciFixHistory = ciResult.ciFixHistory;
160
+ ciFixStatus = ciResult.ciFixStatus;
189
161
  }
190
162
  // --- Persist lifecycle + PR data before approval gate ---
191
163
  // Setting lifecycle to Review serves as the resume detection marker
@@ -32,7 +32,7 @@ export declare function getStageTimeoutMs(nodeName: string): number;
32
32
  /**
33
33
  * Build executor options with cwd. Each node gets a clean agent context.
34
34
  * The timeout is resolved per-stage from settings (workflow.stageTimeouts)
35
- * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min per call, 30 min max with retries).
35
+ * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min).
36
36
  *
37
37
  * When no `nodeName` is provided, the current node from state is used.
38
38
  */
@@ -46,7 +46,7 @@ export function readSpecFile(specDir, filename) {
46
46
  }
47
47
  }
48
48
  /** Default timeout per agent call (30 minutes) — prevents infinite hangs. */
49
- const DEFAULT_STAGE_TIMEOUT_MS = 600_000; // 10 minutes per agent call (retryExecute retries 3x, so 30min max per phase)
49
+ const DEFAULT_STAGE_TIMEOUT_MS = 1_800_000;
50
50
  /**
51
51
  * Map from node name to the corresponding StageTimeouts field.
52
52
  * `fast-implement` reuses the implement timeout; `evidence` also reuses implement.
@@ -80,7 +80,7 @@ export function getStageTimeoutMs(nodeName) {
80
80
  /**
81
81
  * Build executor options with cwd. Each node gets a clean agent context.
82
82
  * The timeout is resolved per-stage from settings (workflow.stageTimeouts)
83
- * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min per call, 30 min max with retries).
83
+ * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min).
84
84
  *
85
85
  * When no `nodeName` is provided, the current node from state is used.
86
86
  */
@@ -1,5 +1,11 @@
1
1
  import type { CanvasNodeType } from '../../components/features/features-canvas/index.js';
2
2
  import type { Edge } from '@xyflow/react';
3
+ export interface RepoGitInfo {
4
+ branch: string;
5
+ commitMessage: string;
6
+ committer: string;
7
+ behindCount: number | null;
8
+ }
3
9
  export declare function getGraphData(): Promise<{
4
10
  nodes: CanvasNodeType[];
5
11
  edges: Edge[];
@@ -1 +1 @@
1
- {"version":3,"file":"get-graph-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/(dashboard)/get-graph-data.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAE5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC,CA+CxF"}
1
+ {"version":3,"file":"get-graph-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/(dashboard)/get-graph-data.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAE5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAI1C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAoDD,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC,CAyDxF"}
@@ -1,12 +1,71 @@
1
+ import { execFile as execFileCb } from 'node:child_process';
2
+ import { promisify } from 'node:util';
1
3
  import { resolve } from '../../lib/server-container.js';
2
4
  import { getSettings } from '../../../../../packages/core/src/infrastructure/services/settings.service.js';
3
5
  import { layoutWithDagre, CANVAS_LAYOUT_DEFAULTS } from '../../lib/layout-with-dagre.js';
4
6
  import { buildGraphNodes } from '../build-graph-nodes.js';
7
+ const execFileAsync = promisify(execFileCb);
8
+ async function gitCommand(cwd, args) {
9
+ try {
10
+ const { stdout } = await execFileAsync('git', args, { cwd });
11
+ return stdout.trim();
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ async function fetchRepoGitInfo(repo) {
18
+ try {
19
+ const [currentBranch, commitMessage, committer] = await Promise.all([
20
+ gitCommand(repo.path, ['symbolic-ref', '--short', 'HEAD']),
21
+ gitCommand(repo.path, ['log', '-1', '--format=%s']),
22
+ gitCommand(repo.path, ['log', '-1', '--format=%an']),
23
+ ]);
24
+ if (!currentBranch)
25
+ return null;
26
+ // Try to determine the default branch to compute behind count
27
+ let behindCount = null;
28
+ const defaultBranch = await gitCommand(repo.path, [
29
+ 'symbolic-ref',
30
+ '--short',
31
+ 'refs/remotes/origin/HEAD',
32
+ ]).then((ref) => ref?.replace('origin/', '') ?? null);
33
+ if (defaultBranch && currentBranch !== defaultBranch) {
34
+ const behind = await gitCommand(repo.path, [
35
+ 'rev-list',
36
+ '--count',
37
+ `${currentBranch}..origin/${defaultBranch}`,
38
+ ]);
39
+ behindCount = behind !== null ? parseInt(behind, 10) : null;
40
+ if (isNaN(behindCount))
41
+ behindCount = null;
42
+ }
43
+ else if (!defaultBranch || currentBranch === defaultBranch) {
44
+ behindCount = 0;
45
+ }
46
+ return {
47
+ branch: currentBranch,
48
+ commitMessage: commitMessage ?? 'unknown',
49
+ committer: committer ?? 'unknown',
50
+ behindCount,
51
+ };
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
5
57
  export async function getGraphData() {
6
58
  const listFeatures = resolve('ListFeaturesUseCase');
7
59
  const listRepos = resolve('ListRepositoriesUseCase');
8
60
  const agentRunRepo = resolve('IAgentRunRepository');
9
61
  const [features, repositories] = await Promise.all([listFeatures.execute(), listRepos.execute()]);
62
+ // Fetch git info (branch, commit, behind count) for each repository
63
+ const repoGitInfoMap = new Map();
64
+ await Promise.all(repositories.map(async (repo) => {
65
+ const info = await fetchRepoGitInfo(repo);
66
+ if (info)
67
+ repoGitInfoMap.set(repo.path, info);
68
+ }));
10
69
  // PR/CI status is kept fresh by PrSyncWatcher (30s background poll).
11
70
  // No live GitHub calls here — use cached DB values for fast response.
12
71
  const featuresWithRuns = await Promise.all(features.map(async (feature) => {
@@ -18,6 +77,7 @@ export async function getGraphData() {
18
77
  enableEvidence: workflow.enableEvidence,
19
78
  commitEvidence: workflow.commitEvidence,
20
79
  ciWatchEnabled: workflow.ciWatchEnabled,
80
+ repoGitInfo: repoGitInfoMap,
21
81
  });
22
82
  // Enrich feature nodes with deployment status
23
83
  let deploymentService = null;
@@ -20,6 +20,13 @@ export interface BuildGraphNodesOptions {
20
20
  commitEvidence?: boolean;
21
21
  /** Whether CI watch/fix loop is enabled (global workflow setting) */
22
22
  ciWatchEnabled?: boolean;
23
+ /** Git info (branch, commit message, committer, behind count) keyed by repository path */
24
+ repoGitInfo?: Map<string, {
25
+ branch: string;
26
+ commitMessage: string;
27
+ committer: string;
28
+ behindCount: number | null;
29
+ }>;
23
30
  }
24
31
  export declare function buildGraphNodes(repositories: Repository[], featuresWithRuns: FeatureWithRun[], options?: BuildGraphNodesOptions): {
25
32
  nodes: CanvasNodeType[];
@@ -1 +1 @@
1
- {"version":3,"file":"build-graph-nodes.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-graph-nodes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAS1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAU1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,UAAU,EAAE,EAC1B,gBAAgB,EAAE,cAAc,EAAE,EAClC,OAAO,CAAC,EAAE,sBAAsB,GAC/B;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CA2F5C"}
1
+ {"version":3,"file":"build-graph-nodes.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-graph-nodes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAS1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAU1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,GAAG,CACf,MAAM,EACN;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CACzF,CAAC;CACH;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,UAAU,EAAE,EAC1B,gBAAgB,EAAE,cAAc,EAAE,EAClC,OAAO,CAAC,EAAE,sBAAsB,GAC/B;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAkG5C"}
@@ -31,6 +31,7 @@ export function buildGraphNodes(repositories, featuresWithRuns, options) {
31
31
  const normalizedRepoPath = normalizePath(repo.path);
32
32
  coveredPaths.add(normalizedRepoPath);
33
33
  const repoNodeId = `repo-${repo.id}`;
34
+ const gitInfo = options?.repoGitInfo?.get(repo.path);
34
35
  nodes.push({
35
36
  id: repoNodeId,
36
37
  type: 'repositoryNode',
@@ -40,6 +41,12 @@ export function buildGraphNodes(repositories, featuresWithRuns, options) {
40
41
  repositoryPath: normalizedRepoPath,
41
42
  id: repo.id,
42
43
  createdAt: repo.createdAt instanceof Date ? repo.createdAt.getTime() : Number(repo.createdAt),
44
+ ...(gitInfo && {
45
+ branch: gitInfo.branch,
46
+ commitMessage: gitInfo.commitMessage,
47
+ committer: gitInfo.committer,
48
+ behindCount: gitInfo.behindCount,
49
+ }),
43
50
  },
44
51
  });
45
52
  const repoFeatures = featuresByRepo[normalizedRepoPath] ?? [];
@@ -9,6 +9,14 @@ export interface RepositoryNodeData {
9
9
  repositoryPath?: string;
10
10
  /** Creation timestamp (epoch ms) — used for stable vertical ordering. */
11
11
  createdAt?: number;
12
+ /** Current git branch name (e.g. "main", "feat/my-feature") */
13
+ branch?: string;
14
+ /** Commit message of the branch HEAD (first line only) */
15
+ commitMessage?: string;
16
+ /** Name of the person who made the latest commit */
17
+ committer?: string;
18
+ /** Number of commits the current branch is behind the default branch. null if on default branch or unknown. */
19
+ behindCount?: number | null;
12
20
  onClick?: () => void;
13
21
  onAdd?: () => void;
14
22
  onDelete?: (repositoryId: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"repository-node-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,WAAW,kBAAkB;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,qEAAqE;IACrE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"repository-node-config.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,MAAM,WAAW,kBAAkB;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,qEAAqE;IACrE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+GAA+G;IAC/G,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,kBAAkB,EAAE,gBAAgB,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"repository-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,2CAyR5F"}
1
+ {"version":3,"file":"repository-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAOnE,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,2CA+U5F"}
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { useState, useCallback } from 'react';
4
4
  import { Handle, Position } from '@xyflow/react';
5
5
  import { useRouter } from 'next/navigation';
6
- import { Github, Plus, Code2, Terminal, FolderOpen, Trash2, Play, Square } from 'lucide-react';
6
+ import { Github, Plus, Code2, Terminal, FolderOpen, Trash2, Play, Square, GitBranch, GitCommitHorizontal, ArrowDown, User, } from 'lucide-react';
7
7
  import { cn } from '../../../lib/utils.js';
8
8
  import { ActionButton } from '../../common/action-button/index.js';
9
9
  import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '../../ui/dialog.js';
@@ -72,9 +72,9 @@ export function RepositoryNode({ data }) {
72
72
  e.stopPropagation();
73
73
  data.onClick?.();
74
74
  }
75
- }, className: "nodrag bg-card flex min-w-[18rem] cursor-pointer items-center gap-3 rounded-full border px-4 py-3 shadow-sm", children: [_jsx(Github, { className: "text-muted-foreground h-5 w-5 shrink-0" }), _jsx("span", { "data-testid": "repository-node-name", className: "min-w-0 truncate text-sm font-medium", children: data.name }), _jsxs("div", { className: cn('flex shrink-0 items-center gap-2', (data.repositoryPath ?? data.onAdd) && 'ml-auto'), onClick: (e) => e.stopPropagation(), children: [data.repositoryPath ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in IDE", onClick: actions.openInIde, loading: actions.ideLoading, error: !!actions.ideError, icon: Code2, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in IDE" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in Shell", onClick: actions.openInShell, loading: actions.shellLoading, error: !!actions.shellError, icon: Terminal, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in Shell" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open Folder", onClick: actions.openFolder, loading: actions.folderLoading, error: !!actions.folderError, icon: FolderOpen, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open Folder" })] }) }), _jsx(FeatureSessionsDropdown, { repositoryPath: data.repositoryPath, onCreateFromSession: handleCreateFromSession }), featureFlags.envDeploy ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isDeploymentActive ? Square : Play, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isDeploymentActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: data.repositoryPath })) : null] })) : null] })) : null, data.onAdd ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Add feature", "data-testid": "repository-node-add-button", onClick: (e) => {
76
- e.stopPropagation();
77
- data.onAdd?.();
78
- }, className: cn('text-muted-foreground hover:bg-accent dark:hover:bg-accent/50 flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-full transition-colors hover:text-blue-500', data.pulseAdd &&
79
- 'animate-pulse-cta bg-blue-100 text-blue-500 dark:bg-blue-900/40'), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Add feature" })] }) })) : null] })] }), data.onAdd || data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: !data.showHandles, className: "opacity-0!" })) : null] }));
75
+ }, className: "nodrag bg-card flex w-[26rem] cursor-pointer flex-col overflow-hidden rounded-xl border shadow-sm", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-3", children: [_jsx(Github, { className: "text-muted-foreground h-5 w-5 shrink-0" }), _jsx("span", { "data-testid": "repository-node-name", className: "min-w-0 truncate text-sm font-medium", children: data.name }), _jsxs("div", { className: cn('flex shrink-0 items-center gap-2', (data.repositoryPath ?? data.onAdd) && 'ml-auto'), onClick: (e) => e.stopPropagation(), children: [data.repositoryPath ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in IDE", onClick: actions.openInIde, loading: actions.ideLoading, error: !!actions.ideError, icon: Code2, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in IDE" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open in Shell", onClick: actions.openInShell, loading: actions.shellLoading, error: !!actions.shellError, icon: Terminal, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open in Shell" })] }) }), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: "Open Folder", onClick: actions.openFolder, loading: actions.folderLoading, error: !!actions.folderError, icon: FolderOpen, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: "Open Folder" })] }) }), _jsx(FeatureSessionsDropdown, { repositoryPath: data.repositoryPath, onCreateFromSession: handleCreateFromSession }), featureFlags.envDeploy ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex items-center", children: _jsx(ActionButton, { label: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isDeploymentActive ? Square : Play, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isDeploymentActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: data.repositoryPath })) : null] })) : null] })) : null, data.onAdd ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Add feature", "data-testid": "repository-node-add-button", onClick: (e) => {
76
+ e.stopPropagation();
77
+ data.onAdd?.();
78
+ }, className: cn('text-muted-foreground hover:bg-accent dark:hover:bg-accent/50 flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-full transition-colors hover:text-blue-500', data.pulseAdd &&
79
+ 'animate-pulse-cta bg-blue-100 text-blue-500 dark:bg-blue-900/40'), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Add feature" })] }) })) : null] })] }), data.branch ? (_jsx("div", { "data-testid": "repository-node-git-info", className: "text-muted-foreground border-t px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-3 text-xs", children: [_jsxs("span", { className: "flex items-center gap-1 truncate", "data-testid": "repository-node-branch", children: [_jsx(GitBranch, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "truncate", children: data.branch })] }), data.behindCount != null && data.behindCount > 0 ? (_jsxs("span", { className: "flex shrink-0 items-center gap-1 whitespace-nowrap text-amber-500", "data-testid": "repository-node-behind", children: [_jsx(ArrowDown, { className: "h-3 w-3 shrink-0" }), data.behindCount, " behind"] })) : null] }) })) : null, data.commitMessage ? (_jsx("div", { "data-testid": "repository-node-commit-info", className: "text-muted-foreground border-t px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-2 text-xs", children: [_jsx(GitCommitHorizontal, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "min-w-0 truncate", "data-testid": "repository-node-commit-message", children: data.commitMessage }), data.committer ? (_jsxs("span", { className: "text-muted-foreground/70 ml-auto flex shrink-0 items-center gap-1", "data-testid": "repository-node-committer", children: [_jsx(User, { className: "h-3 w-3 shrink-0" }), _jsx("span", { children: data.committer })] })) : null] }) })) : null] }), data.onAdd || data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: !data.showHandles, className: "opacity-0!" })) : null] }));
80
80
  }
@@ -14,4 +14,6 @@ export declare const WithActions: Story;
14
14
  export declare const WithActionsAndAddButton: Story;
15
15
  export declare const WithDeleteButton: Story;
16
16
  export declare const MultipleWithActions: Story;
17
+ export declare const WithGitInfo: Story;
18
+ export declare const WithGitInfoBehind: Story;
17
19
  //# sourceMappingURL=repository-node.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repository-node.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,KAAK,EAAE,kBAAkB,EAAsB,MAAM,0BAA0B,CAAC;AAgCvF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,kBAAkB,CASlC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;AAE1C,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAK3B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAKtB,CAAC;AAWF,eAAO,MAAM,QAAQ,EAAE,KAwBtB,CAAC;AASF,eAAO,MAAM,kBAAkB,EAAE,KAwBhC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAS1B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,KAQrC,CAAC;AAIF,eAAO,MAAM,gBAAgB,EAAE,KAS9B,CAAC;AA2BF,eAAO,MAAM,mBAAmB,EAAE,KAwBjC,CAAC"}
1
+ {"version":3,"file":"repository-node.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/repository-node/repository-node.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGvD,OAAO,KAAK,EAAE,kBAAkB,EAAsB,MAAM,0BAA0B,CAAC;AAgCvF,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,kBAAkB,CAYlC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,kBAAkB,CAAC,CAAC;AAE1C,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAK3B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAKtB,CAAC;AAiCF,eAAO,MAAM,QAAQ,EAAE,KAwBtB,CAAC;AAkCF,eAAO,MAAM,kBAAkB,EAAE,KAwBhC,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,KAS1B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAKzB,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,KAQrC,CAAC;AAIF,eAAO,MAAM,gBAAgB,EAAE,KAS9B,CAAC;AA+CF,eAAO,MAAM,mBAAmB,EAAE,KAwBjC,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KASzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,KAS/B,CAAC"}
@@ -3,7 +3,7 @@ import { useMemo } from 'react';
3
3
  import { ReactFlowProvider, ReactFlow } from '@xyflow/react';
4
4
  import { RepositoryNode } from './repository-node.js';
5
5
  const nodeTypes = { repositoryNode: RepositoryNode };
6
- function RepositoryNodeCanvas({ data, style = { width: 500, height: 250 }, }) {
6
+ function RepositoryNodeCanvas({ data, style = { width: 550, height: 300 }, }) {
7
7
  const nodes = useMemo(() => [{ id: 'node-1', type: 'repositoryNode', position: { x: 0, y: 0 }, data }], [data]);
8
8
  return (_jsx("div", { style: style, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
9
9
  }
@@ -15,6 +15,9 @@ const meta = {
15
15
  },
16
16
  args: {
17
17
  name: 'shep-ai/cli',
18
+ branch: 'main',
19
+ commitMessage: 'feat: add dark mode toggle',
20
+ committer: 'Jane Doe',
18
21
  },
19
22
  };
20
23
  export default meta;
@@ -41,37 +44,84 @@ export const LongName = {
41
44
  };
42
45
  const onAdd = () => undefined;
43
46
  const multipleRepos = [
44
- { name: 'shep-ai/cli' },
45
- { name: 'vercel/edge-runtime' },
46
- { name: 'acme-corp/web-dashboard-v2' },
47
- { name: 'openai/tiktoken' },
47
+ {
48
+ name: 'shep-ai/cli',
49
+ branch: 'main',
50
+ commitMessage: 'feat: add dark mode toggle',
51
+ committer: 'Jane Doe',
52
+ },
53
+ {
54
+ name: 'vercel/edge-runtime',
55
+ branch: 'feat/streaming',
56
+ commitMessage: 'fix: handle edge cases in streaming',
57
+ committer: 'John Smith',
58
+ behindCount: 3,
59
+ },
60
+ {
61
+ name: 'acme-corp/web-dashboard-v2',
62
+ branch: 'develop',
63
+ commitMessage: 'chore: update dependencies',
64
+ committer: 'Bot',
65
+ behindCount: 12,
66
+ },
67
+ {
68
+ name: 'openai/tiktoken',
69
+ branch: 'main',
70
+ commitMessage: 'perf: optimize token encoding',
71
+ committer: 'Alice Chen',
72
+ },
48
73
  ];
49
74
  export const Multiple = {
50
75
  render: () => {
51
76
  const nodes = multipleRepos.map((data, i) => ({
52
77
  id: `repo-${i}`,
53
78
  type: 'repositoryNode',
54
- position: { x: 0, y: i * 80 },
79
+ position: { x: 0, y: i * 140 },
55
80
  data,
56
81
  }));
57
- return (_jsx("div", { style: { width: 500, height: 500 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
82
+ return (_jsx("div", { style: { width: 600, height: 750 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
58
83
  },
59
84
  };
60
85
  const multipleReposWithButton = [
61
- { name: 'shep-ai/cli', onAdd },
62
- { name: 'vercel/edge-runtime', onAdd },
63
- { name: 'acme-corp/web-dashboard-v2', onAdd },
64
- { name: 'openai/tiktoken', onAdd },
86
+ {
87
+ name: 'shep-ai/cli',
88
+ onAdd,
89
+ branch: 'main',
90
+ commitMessage: 'feat: add dark mode toggle',
91
+ committer: 'Jane Doe',
92
+ },
93
+ {
94
+ name: 'vercel/edge-runtime',
95
+ onAdd,
96
+ branch: 'feat/streaming',
97
+ commitMessage: 'fix: handle edge cases in streaming',
98
+ committer: 'John Smith',
99
+ behindCount: 3,
100
+ },
101
+ {
102
+ name: 'acme-corp/web-dashboard-v2',
103
+ onAdd,
104
+ branch: 'develop',
105
+ commitMessage: 'chore: update dependencies',
106
+ committer: 'Bot',
107
+ },
108
+ {
109
+ name: 'openai/tiktoken',
110
+ onAdd,
111
+ branch: 'main',
112
+ commitMessage: 'perf: optimize token encoding',
113
+ committer: 'Alice Chen',
114
+ },
65
115
  ];
66
116
  export const MultipleWithButton = {
67
117
  render: () => {
68
118
  const nodes = multipleReposWithButton.map((data, i) => ({
69
119
  id: `repo-${i}`,
70
120
  type: 'repositoryNode',
71
- position: { x: 0, y: i * 80 },
121
+ position: { x: 0, y: i * 140 },
72
122
  data,
73
123
  }));
74
- return (_jsx("div", { style: { width: 500, height: 500 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
124
+ return (_jsx("div", { style: { width: 600, height: 750 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
75
125
  },
76
126
  };
77
127
  export const WithPulseAdd = {
@@ -108,16 +158,29 @@ export const WithDeleteButton = {
108
158
  argTypes: {
109
159
  onDelete: { action: 'onDelete' },
110
160
  },
111
- render: (args) => _jsx(RepositoryNodeCanvas, { data: args, style: { width: 550, height: 250 } }),
161
+ render: (args) => _jsx(RepositoryNodeCanvas, { data: args, style: { width: 600, height: 300 } }),
112
162
  };
113
163
  const multipleReposWithActions = [
114
- { id: 'r1', name: 'shep-ai/cli', repositoryPath: '/home/user/shep-ai/cli', onAdd, onDelete },
164
+ {
165
+ id: 'r1',
166
+ name: 'shep-ai/cli',
167
+ repositoryPath: '/home/user/shep-ai/cli',
168
+ onAdd,
169
+ onDelete,
170
+ branch: 'main',
171
+ commitMessage: 'feat(web): enrich repository node with branch and commit info',
172
+ committer: 'Ariel Shadkhan',
173
+ },
115
174
  {
116
175
  id: 'r2',
117
176
  name: 'vercel/edge-runtime',
118
177
  repositoryPath: '/home/user/vercel/edge-runtime',
119
178
  onAdd,
120
179
  onDelete,
180
+ branch: 'feat/streaming-v2',
181
+ commitMessage: 'fix: handle edge cases in streaming response',
182
+ committer: 'John Smith',
183
+ behindCount: 5,
121
184
  },
122
185
  {
123
186
  id: 'r3',
@@ -125,6 +188,10 @@ const multipleReposWithActions = [
125
188
  repositoryPath: '/home/user/acme-corp/web-dashboard-v2',
126
189
  onAdd,
127
190
  onDelete,
191
+ branch: 'develop',
192
+ commitMessage: 'chore(deps): update all dependencies to latest',
193
+ committer: 'Renovate Bot',
194
+ behindCount: 23,
128
195
  },
129
196
  {
130
197
  id: 'r4',
@@ -132,6 +199,9 @@ const multipleReposWithActions = [
132
199
  repositoryPath: '/home/user/openai/tiktoken',
133
200
  onAdd,
134
201
  onDelete,
202
+ branch: 'main',
203
+ commitMessage: 'perf: optimize token encoding for large inputs',
204
+ committer: 'Alice Chen',
135
205
  },
136
206
  ];
137
207
  export const MultipleWithActions = {
@@ -139,9 +209,29 @@ export const MultipleWithActions = {
139
209
  const nodes = multipleReposWithActions.map((data, i) => ({
140
210
  id: `repo-${i}`,
141
211
  type: 'repositoryNode',
142
- position: { x: 0, y: i * 80 },
212
+ position: { x: 0, y: i * 140 },
143
213
  data,
144
214
  }));
145
- return (_jsx("div", { style: { width: 500, height: 500 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
215
+ return (_jsx("div", { style: { width: 600, height: 800 }, children: _jsx(ReactFlowProvider, { children: _jsx(ReactFlow, { nodes: nodes, nodeTypes: nodeTypes, nodesDraggable: false, nodesConnectable: false, proOptions: { hideAttribution: true }, fitView: true }) }) }));
216
+ },
217
+ };
218
+ export const WithGitInfo = {
219
+ args: {
220
+ repositoryPath: '/home/user/shep-ai/cli',
221
+ branch: 'feat/repo-node-enrichment',
222
+ commitMessage: 'feat(web): enrich repository node with branch and commit info',
223
+ committer: 'Ariel Shadkhan',
224
+ behindCount: 0,
146
225
  },
226
+ render: (args) => _jsx(RepositoryNodeCanvas, { data: args }),
227
+ };
228
+ export const WithGitInfoBehind = {
229
+ args: {
230
+ repositoryPath: '/home/user/shep-ai/cli',
231
+ branch: 'feat/old-feature-branch',
232
+ commitMessage: 'fix: resolve merge conflict in auth module',
233
+ committer: 'Jane Doe',
234
+ behindCount: 7,
235
+ },
236
+ render: (args) => _jsx(RepositoryNodeCanvas, { data: args }),
147
237
  };
@@ -8,7 +8,7 @@ export const CANVAS_LAYOUT_DEFAULTS = {
8
8
  /** Known node-type dimensions for the canvas node types */
9
9
  const NODE_DIMENSIONS = {
10
10
  featureNode: { width: 288, height: 140 },
11
- repositoryNode: { width: 328, height: 50 },
11
+ repositoryNode: { width: 400, height: 110 },
12
12
  };
13
13
  function getNodeSize(node, defaultSize) {
14
14
  // Prefer per-node size from data, then type-based lookup, then default