@shepai/cli 1.129.0 → 1.129.1

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 (167) hide show
  1. package/dist/packages/core/src/application/use-cases/repositories/add-repository.use-case.d.ts.map +1 -1
  2. package/dist/packages/core/src/application/use-cases/repositories/add-repository.use-case.js +5 -2
  3. package/dist/packages/core/src/infrastructure/repositories/sqlite-repository.repository.js +2 -2
  4. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts +8 -0
  5. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts.map +1 -1
  6. package/dist/src/presentation/web/app/(dashboard)/get-graph-data.js +75 -22
  7. package/dist/src/presentation/web/app/build-graph-nodes.d.ts +2 -0
  8. package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
  9. package/dist/src/presentation/web/app/build-graph-nodes.js +2 -0
  10. package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
  11. package/dist/src/presentation/web/components/common/feature-node/feature-node.js +3 -3
  12. package/dist/src/presentation/web/components/common/repository-node/repository-node-config.d.ts +2 -0
  13. package/dist/src/presentation/web/components/common/repository-node/repository-node-config.d.ts.map +1 -1
  14. package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
  15. package/dist/src/presentation/web/components/common/repository-node/repository-node.js +7 -3
  16. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.d.ts +2 -0
  17. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.d.ts.map +1 -1
  18. package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.js +14 -0
  19. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +1 -0
  21. package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -1
  22. package/dist/src/presentation/web/lib/derive-graph.js +5 -2
  23. package/dist/src/presentation/web/lib/layout-with-dagre.js +2 -2
  24. package/dist/tsconfig.build.tsbuildinfo +1 -1
  25. package/package.json +1 -1
  26. package/web/.next/BUILD_ID +1 -1
  27. package/web/.next/build-manifest.json +2 -2
  28. package/web/.next/fallback-build-manifest.json +2 -2
  29. package/web/.next/prerender-manifest.json +3 -3
  30. package/web/.next/required-server-files.js +2 -2
  31. package/web/.next/required-server-files.json +2 -2
  32. package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +24 -24
  33. package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
  34. package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
  35. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +24 -24
  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 +30 -30
  39. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  40. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  41. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +30 -30
  42. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  43. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  44. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +22 -22
  45. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  46. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  47. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +24 -24
  48. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  49. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  50. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +30 -30
  51. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  52. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  53. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +30 -30
  54. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  55. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  56. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +22 -22
  57. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  58. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  59. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +22 -22
  60. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  61. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  62. package/web/.next/server/app/_global-error.html +2 -2
  63. package/web/.next/server/app/_global-error.rsc +1 -1
  64. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  65. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  66. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  67. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  68. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  69. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +3 -3
  70. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  71. package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  72. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  73. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  74. package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
  75. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  76. package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
  77. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  78. package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
  79. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  80. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
  81. package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
  82. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  83. package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_4e741df2.js +1 -1
  84. package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_4e741df2.js.map +1 -1
  85. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  86. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  87. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_026fdffa.js +1 -1
  88. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_026fdffa.js.map +1 -1
  89. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_8b91e197.js +1 -1
  90. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_8b91e197.js.map +1 -1
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__0e842eba._.js +1 -1
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__0e842eba._.js.map +1 -1
  93. package/web/.next/server/chunks/ssr/[root-of-the-server]__2f886f77._.js +2 -2
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
  96. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
  97. package/web/.next/server/chunks/ssr/[root-of-the-server]__60684242._.js +2 -2
  98. package/web/.next/server/chunks/ssr/[root-of-the-server]__60684242._.js.map +1 -1
  99. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
  100. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
  101. package/web/.next/server/chunks/ssr/[root-of-the-server]__755cfe02._.js +1 -1
  102. package/web/.next/server/chunks/ssr/[root-of-the-server]__755cfe02._.js.map +1 -1
  103. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
  104. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
  105. package/web/.next/server/chunks/ssr/[root-of-the-server]__a628fb91._.js +1 -1
  106. package/web/.next/server/chunks/ssr/[root-of-the-server]__a628fb91._.js.map +1 -1
  107. package/web/.next/server/chunks/ssr/[root-of-the-server]__bfba58e6._.js +1 -1
  108. package/web/.next/server/chunks/ssr/[root-of-the-server]__bfba58e6._.js.map +1 -1
  109. package/web/.next/server/chunks/ssr/[root-of-the-server]__c3ab8422._.js +1 -1
  110. package/web/.next/server/chunks/ssr/[root-of-the-server]__c3ab8422._.js.map +1 -1
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__f4a463ee._.js +2 -2
  112. package/web/.next/server/chunks/ssr/[root-of-the-server]__f4a463ee._.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/_02ec1aea._.js +1 -1
  114. package/web/.next/server/chunks/ssr/_02ec1aea._.js.map +1 -1
  115. package/web/.next/server/chunks/ssr/_7dca1882._.js +1 -1
  116. package/web/.next/server/chunks/ssr/_7dca1882._.js.map +1 -1
  117. package/web/.next/server/chunks/ssr/{_ade68272._.js → _92acff95._.js} +2 -2
  118. package/web/.next/server/chunks/ssr/{_ade68272._.js.map → _92acff95._.js.map} +1 -1
  119. package/web/.next/server/chunks/ssr/{_04c9e229._.js → _a11d42e8._.js} +2 -2
  120. package/web/.next/server/chunks/ssr/{_04c9e229._.js.map → _a11d42e8._.js.map} +1 -1
  121. package/web/.next/server/chunks/ssr/_a9f57758._.js +1 -1
  122. package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
  123. package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
  124. package/web/.next/server/chunks/ssr/_f39a1adb._.js +1 -1
  125. package/web/.next/server/chunks/ssr/_f39a1adb._.js.map +1 -1
  126. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  127. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  128. package/web/.next/server/chunks/ssr/src_presentation_web_8e7fe0d1._.js +2 -2
  129. package/web/.next/server/chunks/ssr/src_presentation_web_8e7fe0d1._.js.map +1 -1
  130. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ca051134.js +1 -1
  131. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ca051134.js.map +1 -1
  132. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
  133. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
  134. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
  135. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
  136. package/web/.next/server/chunks/ssr/src_presentation_web_b9023017._.js +2 -2
  137. package/web/.next/server/chunks/ssr/src_presentation_web_b9023017._.js.map +1 -1
  138. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
  139. package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
  140. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  141. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  142. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  143. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  144. package/web/.next/server/chunks/ssr/{src_presentation_web_12d7d3c5._.js → src_presentation_web_efa91543._.js} +2 -2
  145. package/web/.next/server/chunks/ssr/{src_presentation_web_12d7d3c5._.js.map → src_presentation_web_efa91543._.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 +38 -38
  149. package/web/.next/static/chunks/0a83031808867bca.js +1 -0
  150. package/web/.next/static/chunks/{6c6ab4d42b07fb4b.js → 2672ec79b6eb1b94.js} +1 -1
  151. package/web/.next/static/chunks/{20ff528aadba66aa.js → 475b22f4bf14af2d.js} +1 -1
  152. package/web/.next/static/chunks/{c975a20b880c47ea.js → 4ee40070e69205bc.js} +1 -1
  153. package/web/.next/static/chunks/{278f99f8cc87ab17.js → 5da0c2f16502fddd.js} +1 -1
  154. package/web/.next/static/chunks/{ab3f7ac1960397d9.js → 5e11fe79741cd049.js} +1 -1
  155. package/web/.next/static/chunks/{29535b9b36889453.js → 792cdceb624c561d.js} +1 -1
  156. package/web/.next/static/chunks/{60fabfee2f9ae935.js → cc974a8f14de58d0.js} +1 -1
  157. package/web/.next/static/chunks/{83ae4f574f3dee4d.js → e4ff24651224d4d2.js} +1 -1
  158. package/web/.next/static/chunks/f569a6dc0496430f.css +1 -0
  159. package/web/.next/static/chunks/{60464e75e7dff8f4.js → f84bbfe2662f35ed.js} +2 -2
  160. package/web/.next/static/chunks/fd2ccf8f2022f2fb.js +1 -0
  161. package/web/.next/static/chunks/{98b6ea0af565042f.js → fdff2d35956e7448.js} +2 -2
  162. package/web/.next/static/chunks/114347d98fd69f40.js +0 -1
  163. package/web/.next/static/chunks/6cba93f351d29ae4.js +0 -1
  164. package/web/.next/static/chunks/98dfbecc5ee30ce1.css +0 -1
  165. /package/web/.next/static/{_hAwvNHgk12VPT5IIxRV6 → yH8b83VvOS2P5F2XwxoFX}/_buildManifest.js +0 -0
  166. /package/web/.next/static/{_hAwvNHgk12VPT5IIxRV6 → yH8b83VvOS2P5F2XwxoFX}/_clientMiddlewareManifest.json +0 -0
  167. /package/web/.next/static/{_hAwvNHgk12VPT5IIxRV6 → yH8b83VvOS2P5F2XwxoFX}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"add-repository.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/repositories/add-repository.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oEAAoE,CAAC;AAEhH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAcD,qBACa,oBAAoB;IAG7B,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,qBAAqB;IAGlD,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC;CA8B9D"}
1
+ {"version":3,"file":"add-repository.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/repositories/add-repository.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oEAAoE,CAAC;AAEhH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAcD,qBACa,oBAAoB;IAG7B,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,qBAAqB;IAGlD,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC;CAiC9D"}
@@ -41,11 +41,14 @@ let AddRepositoryUseCase = class AddRepositoryUseCase {
41
41
  if (existing) {
42
42
  return existing;
43
43
  }
44
- // Check for soft-deleted repository — restore it instead of creating a duplicate
44
+ // Check for soft-deleted repository — restore it instead of creating a duplicate.
45
+ // Reset createdAt so the restored repo sorts as "newest" on the canvas
46
+ // (otherwise the old createdAt would place it above repos added later).
45
47
  const deleted = await this.repositoryRepo.findByPathIncludingDeleted(normalizedPath);
46
48
  if (deleted) {
49
+ const now = new Date();
47
50
  await this.repositoryRepo.restore(deleted.id);
48
- return { ...deleted, deletedAt: undefined, updatedAt: new Date() };
51
+ return { ...deleted, deletedAt: undefined, createdAt: now, updatedAt: now };
49
52
  }
50
53
  const now = new Date();
51
54
  const name = input.name ?? normalizedPath.split('/').pop() ?? normalizedPath;
@@ -94,8 +94,8 @@ let SQLiteRepositoryRepository = SQLiteRepositoryRepository_1 = class SQLiteRepo
94
94
  }
95
95
  async restore(id) {
96
96
  const now = Date.now();
97
- const stmt = this.db.prepare('UPDATE repositories SET deleted_at = NULL, updated_at = ? WHERE id = ?');
98
- stmt.run(now, id);
97
+ const stmt = this.db.prepare('UPDATE repositories SET deleted_at = NULL, created_at = ?, updated_at = ? WHERE id = ?');
98
+ stmt.run(now, now, id);
99
99
  }
100
100
  static normalizeRemoteUrl(url) {
101
101
  return url.replace(/\.git$/, '').toLowerCase();
@@ -6,6 +6,14 @@ export interface RepoGitInfo {
6
6
  committer: string;
7
7
  behindCount: number | null;
8
8
  }
9
+ export type GitInfoResult = {
10
+ status: 'loading';
11
+ } | {
12
+ status: 'ready';
13
+ data: RepoGitInfo;
14
+ } | {
15
+ status: 'not-a-repo';
16
+ };
9
17
  export declare function getGraphData(): Promise<{
10
18
  nodes: CanvasNodeType[];
11
19
  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":"AAYA,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;AAqDD,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC,CAyDxF"}
1
+ {"version":3,"file":"get-graph-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/(dashboard)/get-graph-data.ts"],"names":[],"mappings":"AAYA,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;AAwFD,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GACtC;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC;AA6B7B,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC,CA6DxF"}
@@ -6,6 +6,11 @@ import { getSettings } from '../../../../../packages/core/src/infrastructure/ser
6
6
  import { layoutWithDagre, CANVAS_LAYOUT_DEFAULTS } from '../../lib/layout-with-dagre.js';
7
7
  import { buildGraphNodes } from '../build-graph-nodes.js';
8
8
  const execFileAsync = promisify(execFileCb);
9
+ // Cache git info per repo — refreshed every GIT_INFO_TTL_MS via background-style check.
10
+ // getGraphData() always reads from cache (zero git calls), and only spawns git
11
+ // processes when the cache entry is older than the TTL.
12
+ const GIT_INFO_TTL_MS = 30_000;
13
+ const gitInfoCache = new Map();
9
14
  async function gitCommand(cwd, args) {
10
15
  try {
11
16
  const opts = IS_WINDOWS ? { cwd, windowsHide: true } : { cwd };
@@ -16,22 +21,38 @@ async function gitCommand(cwd, args) {
16
21
  return null;
17
22
  }
18
23
  }
19
- async function fetchRepoGitInfo(repo) {
24
+ const FIELD_SEP = '\x1f'; // ASCII Unit Separator — safe in git output and child_process
25
+ /** Refresh git info for a single repo (spawns git processes). */
26
+ async function refreshRepoGitInfo(repo) {
20
27
  try {
21
- const [currentBranch, commitMessage, committer] = await Promise.all([
28
+ const headSha = await gitCommand(repo.path, ['rev-parse', 'HEAD']);
29
+ if (!headSha) {
30
+ // Not a git repo (or bare/broken) — cache this so the UI can show it
31
+ gitInfoCache.set(repo.path, { kind: 'not-a-repo', checkedAt: Date.now() });
32
+ return;
33
+ }
34
+ const cached = gitInfoCache.get(repo.path);
35
+ if (cached?.kind === 'repo' && cached.sha === headSha) {
36
+ // HEAD unchanged — just bump checkedAt
37
+ cached.checkedAt = Date.now();
38
+ return;
39
+ }
40
+ // HEAD changed — fetch branch + subject & author in parallel
41
+ const [currentBranch, logLine] = await Promise.all([
22
42
  gitCommand(repo.path, ['symbolic-ref', '--short', 'HEAD']),
23
- gitCommand(repo.path, ['log', '-1', '--format=%s']),
24
- gitCommand(repo.path, ['log', '-1', '--format=%an']),
43
+ gitCommand(repo.path, ['log', '-1', `--format=%s${FIELD_SEP}%an`]),
25
44
  ]);
26
45
  if (!currentBranch)
27
- return null;
28
- // Try to determine the default branch to compute behind count
46
+ return;
47
+ const [commitMessage, committer] = (logLine ?? '').split(FIELD_SEP);
48
+ // Behind count
29
49
  let behindCount = null;
30
- const defaultBranch = await gitCommand(repo.path, [
50
+ const defaultBranchRef = await gitCommand(repo.path, [
31
51
  'symbolic-ref',
32
52
  '--short',
33
53
  'refs/remotes/origin/HEAD',
34
- ]).then((ref) => ref?.replace('origin/', '') ?? null);
54
+ ]);
55
+ const defaultBranch = defaultBranchRef?.replace('origin/', '') ?? null;
35
56
  if (defaultBranch && currentBranch !== defaultBranch) {
36
57
  const behind = await gitCommand(repo.path, [
37
58
  'rev-list',
@@ -42,32 +63,63 @@ async function fetchRepoGitInfo(repo) {
42
63
  if (isNaN(behindCount))
43
64
  behindCount = null;
44
65
  }
45
- else if (!defaultBranch || currentBranch === defaultBranch) {
66
+ else {
46
67
  behindCount = 0;
47
68
  }
48
- return {
49
- branch: currentBranch,
50
- commitMessage: commitMessage ?? 'unknown',
51
- committer: committer ?? 'unknown',
52
- behindCount,
53
- };
69
+ gitInfoCache.set(repo.path, {
70
+ kind: 'repo',
71
+ sha: headSha,
72
+ checkedAt: Date.now(),
73
+ data: {
74
+ branch: currentBranch,
75
+ commitMessage: commitMessage ?? 'unknown',
76
+ committer: committer ?? 'unknown',
77
+ behindCount,
78
+ },
79
+ });
54
80
  }
55
81
  catch {
56
- return null;
82
+ // ignore — stale cache is better than no data
57
83
  }
58
84
  }
85
+ /**
86
+ * Return cached git info for a repo. If the cache is stale (> TTL),
87
+ * kick off a fire-and-forget refresh so the NEXT call gets fresh data.
88
+ * Never blocks getGraphData() with git subprocess calls.
89
+ */
90
+ function getRepoGitInfo(repo) {
91
+ const cached = gitInfoCache.get(repo.path);
92
+ const now = Date.now();
93
+ if (!cached) {
94
+ // First time — trigger async refresh, return loading for this call
95
+ void refreshRepoGitInfo(repo);
96
+ return { status: 'loading' };
97
+ }
98
+ if (now - cached.checkedAt >= GIT_INFO_TTL_MS) {
99
+ // Stale — trigger async refresh, return current data immediately
100
+ void refreshRepoGitInfo(repo);
101
+ }
102
+ if (cached.kind === 'not-a-repo') {
103
+ return { status: 'not-a-repo' };
104
+ }
105
+ return { status: 'ready', data: cached.data };
106
+ }
59
107
  export async function getGraphData() {
60
108
  const listFeatures = resolve('ListFeaturesUseCase');
61
109
  const listRepos = resolve('ListRepositoriesUseCase');
62
110
  const agentRunRepo = resolve('IAgentRunRepository');
63
111
  const [features, repositories] = await Promise.all([listFeatures.execute(), listRepos.execute()]);
64
- // Fetch git info (branch, commit, behind count) for each repository
112
+ // Read git info from cache (zero git calls). Stale entries trigger
113
+ // a fire-and-forget background refresh for the next poll cycle.
65
114
  const repoGitInfoMap = new Map();
66
- await Promise.all(repositories.map(async (repo) => {
67
- const info = await fetchRepoGitInfo(repo);
68
- if (info)
69
- repoGitInfoMap.set(repo.path, info);
70
- }));
115
+ const repoGitStatusMap = new Map();
116
+ for (const repo of repositories) {
117
+ const result = getRepoGitInfo(repo);
118
+ repoGitStatusMap.set(repo.path, result.status);
119
+ if (result.status === 'ready') {
120
+ repoGitInfoMap.set(repo.path, result.data);
121
+ }
122
+ }
71
123
  // PR/CI status is kept fresh by PrSyncWatcher (30s background poll).
72
124
  // No live GitHub calls here — use cached DB values for fast response.
73
125
  const featuresWithRuns = await Promise.all(features.map(async (feature) => {
@@ -80,6 +132,7 @@ export async function getGraphData() {
80
132
  commitEvidence: workflow.commitEvidence,
81
133
  ciWatchEnabled: workflow.ciWatchEnabled,
82
134
  repoGitInfo: repoGitInfoMap,
135
+ repoGitStatus: repoGitStatusMap,
83
136
  });
84
137
  // Enrich feature nodes with deployment status
85
138
  let deploymentService = null;
@@ -27,6 +27,8 @@ export interface BuildGraphNodesOptions {
27
27
  committer: string;
28
28
  behindCount: number | null;
29
29
  }>;
30
+ /** Git info resolution status keyed by repository path */
31
+ repoGitStatus?: Map<string, 'loading' | 'ready' | 'not-a-repo'>;
30
32
  }
31
33
  export declare function buildGraphNodes(repositories: Repository[], featuresWithRuns: FeatureWithRun[], options?: BuildGraphNodesOptions): {
32
34
  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;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"}
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;IACF,0DAA0D;IAC1D,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC,CAAC;CACjE;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,CAoG5C"}
@@ -32,6 +32,7 @@ export function buildGraphNodes(repositories, featuresWithRuns, options) {
32
32
  coveredPaths.add(normalizedRepoPath);
33
33
  const repoNodeId = `repo-${repo.id}`;
34
34
  const gitInfo = options?.repoGitInfo?.get(repo.path);
35
+ const gitInfoStatus = options?.repoGitStatus?.get(repo.path) ?? 'loading';
35
36
  nodes.push({
36
37
  id: repoNodeId,
37
38
  type: 'repositoryNode',
@@ -41,6 +42,7 @@ export function buildGraphNodes(repositories, featuresWithRuns, options) {
41
42
  repositoryPath: normalizedRepoPath,
42
43
  id: repo.id,
43
44
  createdAt: repo.createdAt instanceof Date ? repo.createdAt.getTime() : Number(repo.createdAt),
45
+ gitInfoStatus,
44
46
  ...(gitInfo && {
45
47
  branch: gitInfo.branch,
46
48
  commitMessage: gitInfo.commitMessage,
@@ -1 +1 @@
1
- {"version":3,"file":"feature-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA6DnE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,2CAkWA"}
1
+ {"version":3,"file":"feature-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA6DnE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,2CAqWA"}
@@ -70,7 +70,7 @@ export function FeatureNode({ data, selected, }) {
70
70
  const config = featureNodeStateConfig[data.state];
71
71
  const Icon = config.icon;
72
72
  const [confirmOpen, setConfirmOpen] = useState(false);
73
- return (_jsxs("div", { className: "animate-in fade-in group relative duration-300", children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!" })) : null, data.onDelete && data.featureId && data.state !== 'deleting' ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute top-1/2 -left-10 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100", onPointerDown: (e) => e.stopPropagation(), children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Delete feature", "data-testid": "feature-node-delete-button", onClick: (e) => {
73
+ return (_jsxs("div", { className: "animate-in fade-in group relative duration-300", children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null, data.onDelete && data.featureId && data.state !== 'deleting' ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute top-1/2 -left-10 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100", onPointerDown: (e) => e.stopPropagation(), children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Delete feature", "data-testid": "feature-node-delete-button", onClick: (e) => {
74
74
  e.stopPropagation();
75
75
  setConfirmOpen(true);
76
76
  }, className: "bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Delete feature" })] }) }) }), _jsx(DeleteFeatureDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, onConfirm: (cleanup, cascadeDelete, closePr) => {
@@ -109,8 +109,8 @@ export function FeatureNode({ data, selected, }) {
109
109
  }, className: "nodrag flex shrink-0 cursor-pointer items-center gap-1 rounded-full bg-red-100 px-2.5 py-1 text-[11px] font-medium text-red-700 transition-colors hover:bg-red-200", children: [_jsx(RotateCcw, { className: "h-3 w-3" }), "Retry"] })) : null, data.state === 'pending' && data.onStart ? (_jsxs("button", { type: "button", "aria-label": "Start feature", "data-testid": "feature-node-start-button", onClick: (e) => {
110
110
  e.stopPropagation();
111
111
  data.onStart(data.featureId);
112
- }, className: "nodrag flex shrink-0 cursor-pointer items-center gap-1 rounded-full bg-slate-100 px-2.5 py-1 text-[11px] font-medium text-slate-700 transition-colors hover:bg-slate-200", children: [_jsx(Play, { className: "h-3 w-3" }), "Start"] })) : null] })] })) })] }), data.onAction && data.state !== 'deleting' ? (_jsx(Handle, { type: "source", position: Position.Right, className: "h-0! w-0! border-0! bg-transparent!", children: _jsx("button", { type: "button", "aria-label": "Add", "data-testid": "feature-node-action-button", onClick: (e) => {
112
+ }, className: "nodrag flex shrink-0 cursor-pointer items-center gap-1 rounded-full bg-slate-100 px-2.5 py-1 text-[11px] font-medium text-slate-700 transition-colors hover:bg-slate-200", children: [_jsx(Play, { className: "h-3 w-3" }), "Start"] })) : null] })] })) })] }), data.onAction && data.state !== 'deleting' ? (_jsx(Handle, { type: "source", position: Position.Right, className: "h-0! w-0! border-0! bg-transparent!", style: { top: 70 }, children: _jsx("button", { type: "button", "aria-label": "Add", "data-testid": "feature-node-action-button", onClick: (e) => {
113
113
  e.stopPropagation();
114
114
  data.onAction?.();
115
- }, className: "nodrag absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-blue-500 text-white opacity-0 shadow-md transition-opacity group-hover:opacity-100 hover:bg-blue-600", children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) })) : data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: false, className: "opacity-0!" })) : null] }));
115
+ }, className: "nodrag absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-blue-500 text-white opacity-0 shadow-md transition-opacity group-hover:opacity-100 hover:bg-blue-600", children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) })) : data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null] }));
116
116
  }
@@ -17,6 +17,8 @@ export interface RepositoryNodeData {
17
17
  committer?: string;
18
18
  /** Number of commits the current branch is behind the default branch. null if on default branch or unknown. */
19
19
  behindCount?: number | null;
20
+ /** Git info resolution status. undefined/'loading' = fetching, 'ready' = resolved, 'not-a-repo' = not a git repo */
21
+ gitInfoStatus?: 'loading' | 'ready' | 'not-a-repo';
20
22
  onClick?: () => void;
21
23
  onAdd?: () => void;
22
24
  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,+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
+ {"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,oHAAoH;IACpH,aAAa,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC;IACnD,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":"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,2CAkX5F"}
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,2CA2Z5F"}
@@ -56,7 +56,7 @@ export function RepositoryNode({ data }) {
56
56
  });
57
57
  router.push(`/create?${params.toString()}`);
58
58
  }, [data.repositoryPath, router]);
59
- return (_jsxs("div", { className: cn('group relative', data.onDelete && data.id && 'pl-10'), children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!" })) : null, data.onDelete && data.id ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute top-1/2 left-0 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100", children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Remove repository", "data-testid": "repository-node-delete-button", onClick: (e) => {
59
+ return (_jsxs("div", { className: cn('group relative', data.onDelete && data.id && 'pl-10'), children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null, data.onDelete && data.id ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute top-1/2 left-0 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100", children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Remove repository", "data-testid": "repository-node-delete-button", onClick: (e) => {
60
60
  e.stopPropagation();
61
61
  setConfirmOpen(true);
62
62
  }, className: "bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Remove repository" })] }) }) }), _jsx(Dialog, { open: confirmOpen, onOpenChange: setConfirmOpen, children: _jsxs(DialogContent, { className: "max-w-xs", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Remove repository?" }), _jsxs(DialogDescription, { children: ["This will remove ", _jsx("strong", { children: data.name }), " and all its features from your workspace. The repository files on disk won't be affected."] })] }), _jsxs(DialogFooter, { className: "grid grid-cols-2 gap-2 sm:flex-none", children: [_jsx(DialogClose, { asChild: true, children: _jsx(Button, { variant: "outline", children: "Cancel" }) }), _jsx(Button, { variant: "destructive", onClick: () => {
@@ -75,9 +75,13 @@ export function RepositoryNode({ data }) {
75
75
  e.stopPropagation();
76
76
  data.onAdd?.();
77
77
  }, 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 &&
78
- '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, featureFlags.envDeploy && data.repositoryPath ? (_jsx("div", { "data-testid": "repository-node-dev-preview", className: "border-t px-4 py-2", onClick: (e) => e.stopPropagation(), children: _jsxs("div", { className: "flex items-center gap-2 text-xs", children: [deployAction.deployError ? (_jsx("span", { className: "truncate text-xs text-red-500", children: deployAction.deployError })) : isDeploymentActive ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "mr-0.5 inline-block h-2 w-2 shrink-0 rounded-full bg-green-500" }), deployAction.url ? (_jsx("a", { href: deployAction.url, target: "_blank", rel: "noopener noreferrer", className: "truncate text-green-700 hover:underline dark:text-green-400", children: deployAction.url })) : (_jsx("span", { className: "text-muted-foreground", children: "Starting..." }))] })) : (_jsxs("span", { className: "text-muted-foreground", children: ["Run", _jsx("span", { className: "text-muted-foreground/50 ml-2 text-[10px]", children: "start local environment" })] })), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "ml-auto flex items-center", children: _jsx(ActionButton, { label: deployAction.deployError
78
+ '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 ? (_jsxs(_Fragment, { children: [_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] }) }), 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.gitInfoStatus === 'not-a-repo' ? (
79
+ /* Not a git repo — two rows for consistency with loading/ready states */
80
+ _jsxs(_Fragment, { children: [_jsx("div", { "data-testid": "repository-node-not-repo", className: "text-muted-foreground border-t px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-2 text-xs", children: [_jsx(FolderOpen, { className: "h-3 w-3 shrink-0" }), _jsx("span", { className: "min-w-0 truncate opacity-60", children: data.repositoryPath ?? 'Unknown path' })] }) }), _jsx("div", { className: "text-muted-foreground border-t px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-2 text-xs opacity-40", children: [_jsx(GitBranch, { className: "h-3 w-3 shrink-0" }), _jsx("span", { children: "Not a git repository" })] }) })] })) : data.gitInfoStatus !== 'ready' ? (
81
+ /* Loading — show skeleton placeholders for both rows */
82
+ _jsxs(_Fragment, { children: [_jsx("div", { "data-testid": "repository-node-git-loading", className: "border-t px-4 py-2", children: _jsxs("div", { className: "flex h-4 items-center gap-2 text-xs", children: [_jsx(GitBranch, { className: "text-muted-foreground h-3 w-3 shrink-0" }), _jsx("span", { className: "bg-muted h-3 w-20 animate-pulse rounded" })] }) }), _jsx("div", { className: "border-t px-4 py-2", children: _jsxs("div", { className: "flex h-4 items-center gap-2 text-xs", children: [_jsx(GitCommitHorizontal, { className: "text-muted-foreground h-3 w-3 shrink-0" }), _jsx("span", { className: "bg-muted h-3 w-36 animate-pulse rounded" })] }) })] })) : null, featureFlags.envDeploy && data.repositoryPath ? (_jsx("div", { "data-testid": "repository-node-dev-preview", className: "border-t px-4 py-2", onClick: (e) => e.stopPropagation(), children: _jsxs("div", { className: "flex items-center gap-2 text-xs", children: [deployAction.deployError ? (_jsx("span", { className: "truncate text-xs text-red-500", children: deployAction.deployError })) : isDeploymentActive ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "mr-0.5 inline-block h-2 w-2 shrink-0 rounded-full bg-green-500" }), deployAction.url ? (_jsx("a", { href: deployAction.url, target: "_blank", rel: "noopener noreferrer", className: "truncate text-green-700 hover:underline dark:text-green-400", children: deployAction.url })) : (_jsx("span", { className: "text-muted-foreground", children: "Starting..." }))] })) : (_jsxs("span", { className: "text-muted-foreground", children: ["Run", _jsx("span", { className: "text-muted-foreground/50 ml-2 text-[10px]", children: "start local environment" })] })), _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "ml-auto flex items-center", children: _jsx(ActionButton, { label: deployAction.deployError
79
83
  ? 'Retry'
80
84
  : isDeploymentActive
81
85
  ? 'Stop Dev Server'
82
- : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: false, icon: deployAction.deployError ? RotateCcw : isDeploymentActive ? Square : Play, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) })] }) })) : null] }), data.onAdd || data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: !data.showHandles, className: "opacity-0!" })) : null] }));
86
+ : 'Start Dev Server', onClick: isDeploymentActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: false, icon: deployAction.deployError ? RotateCcw : isDeploymentActive ? Square : Play, iconOnly: true, variant: "ghost", size: "icon-xs" }) }) }), _jsx(TooltipContent, { children: isDeploymentActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) })] }) })) : null] }), data.onAdd || data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: !data.showHandles, className: "opacity-0!", style: { top: 70 } })) : null] }));
83
87
  }
@@ -16,4 +16,6 @@ export declare const WithDeleteButton: Story;
16
16
  export declare const MultipleWithActions: Story;
17
17
  export declare const WithGitInfo: Story;
18
18
  export declare const WithGitInfoBehind: Story;
19
+ export declare const GitInfoLoading: Story;
20
+ export declare const NotAGitRepo: Story;
19
21
  //# 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,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"}
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;AAEF,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC"}
@@ -235,3 +235,17 @@ export const WithGitInfoBehind = {
235
235
  },
236
236
  render: (args) => _jsx(RepositoryNodeCanvas, { data: args }),
237
237
  };
238
+ export const GitInfoLoading = {
239
+ args: {
240
+ repositoryPath: '/home/user/shep-ai/cli',
241
+ gitInfoStatus: 'loading',
242
+ },
243
+ render: (args) => _jsx(RepositoryNodeCanvas, { data: args }),
244
+ };
245
+ export const NotAGitRepo = {
246
+ args: {
247
+ repositoryPath: '/home/user/my-project',
248
+ gitInfoStatus: 'not-a-repo',
249
+ },
250
+ render: (args) => _jsx(RepositoryNodeCanvas, { data: args }),
251
+ };
@@ -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;AAgBjC,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,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,EACjB,aAAa,CAAC,EAAE,OAAO,EACvB,OAAO,CAAC,EAAE,OAAO,KACd,IAAI,CAAC;IACV,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,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,CAuhBpB"}
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;AAgBjC,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,CACnB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,EACjB,aAAa,CAAC,EAAE,OAAO,EACvB,OAAO,CAAC,EAAE,OAAO,KACd,IAAI,CAAC;IACV,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,iBAAiB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,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,CAwhBpB"}
@@ -415,6 +415,7 @@ export function useControlCenterState(initialNodes, initialEdges) {
415
415
  repositoryPath: path,
416
416
  id: tempId,
417
417
  createdAt: Date.now(),
418
+ gitInfoStatus: 'loading',
418
419
  });
419
420
  addRepository({ path, name: repoName })
420
421
  .then((result) => {
@@ -1 +1 @@
1
- {"version":3,"file":"derive-graph.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/lib/derive-graph.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,CAAC;IACtB,sGAAsG;IACtG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,kBAAkB,CAAC;CAC1B;AAED,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,4FAA4F;IAC5F,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,qEAAqE;IACrE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,8CAA8C;IAC9C,eAAe,CAAC,EAAE,CAChB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,EACjB,aAAa,CAAC,EAAE,OAAO,EACvB,OAAO,CAAC,EAAE,OAAO,KACd,IAAI,CAAC;IACV,6EAA6E;IAC7E,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,qDAAqD;IACrD,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,qDAAqD;IACrD,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,oDAAoD;IACpD,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACrC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAC/B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACrC,SAAS,CAAC,EAAE,cAAc,GACzB;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CA8J5C"}
1
+ {"version":3,"file":"derive-graph.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/lib/derive-graph.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,eAAe,CAAC;IACtB,sGAAsG;IACtG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wDAAwD;AACxD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,kBAAkB,CAAC;CAC1B;AAED,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC7B,4FAA4F;IAC5F,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,qEAAqE;IACrE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,8CAA8C;IAC9C,eAAe,CAAC,EAAE,CAChB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,OAAO,EACjB,aAAa,CAAC,EAAE,OAAO,EACvB,OAAO,CAAC,EAAE,OAAO,KACd,IAAI,CAAC;IACV,6EAA6E;IAC7E,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,iDAAiD;IACjD,kBAAkB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,qDAAqD;IACrD,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,qDAAqD;IACrD,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,oDAAoD;IACpD,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACrC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAC/B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACrC,SAAS,CAAC,EAAE,cAAc,GACzB;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAiK5C"}
@@ -46,9 +46,12 @@ export function deriveGraph(featureMap, repoMap, pendingMap, callbacks) {
46
46
  // Add repo nodes (real ones) — sorted by createdAt for stable vertical order.
47
47
  // The server-side layoutWithDagre may reorder the node array (connected vs
48
48
  // disconnected split), so we cannot rely on Map insertion order alone.
49
+ // Use Infinity fallback so repos without createdAt sort last (appear at bottom).
49
50
  const sortedRepoEntries = [...repoMap.entries()].sort((a, b) => {
50
- const aTime = a[1].data.createdAt ?? 0;
51
- const bTime = b[1].data.createdAt ?? 0;
51
+ const aRaw = a[1].data.createdAt;
52
+ const bRaw = b[1].data.createdAt;
53
+ const aTime = typeof aRaw === 'number' && !Number.isNaN(aRaw) ? aRaw : Infinity;
54
+ const bTime = typeof bRaw === 'number' && !Number.isNaN(bRaw) ? bRaw : Infinity;
52
55
  return aTime - bTime;
53
56
  });
54
57
  for (const [nodeId, entry] of sortedRepoEntries) {
@@ -7,8 +7,8 @@ export const CANVAS_LAYOUT_DEFAULTS = {
7
7
  };
8
8
  /** Known node-type dimensions for the canvas node types */
9
9
  const NODE_DIMENSIONS = {
10
- featureNode: { width: 288, height: 160 },
11
- repositoryNode: { width: 400, height: 160 },
10
+ featureNode: { width: 288, height: 140 },
11
+ repositoryNode: { width: 400, height: 140 },
12
12
  };
13
13
  function getNodeSize(node, defaultSize) {
14
14
  // Prefer per-node size from data, then type-based lookup, then default