@assistkick/create 1.0.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/src/scaffolder.d.ts +6 -1
  2. package/dist/src/scaffolder.js +20 -9
  3. package/dist/src/scaffolder.js.map +1 -1
  4. package/package.json +3 -2
  5. package/templates/{product-system → assistkick-product-system}/CLAUDE.md +4 -4
  6. package/templates/{product-system → assistkick-product-system}/package.json +5 -5
  7. package/templates/{product-system → assistkick-product-system}/packages/backend/package.json +2 -2
  8. package/templates/{product-system → assistkick-product-system}/packages/backend/src/routes/auth.ts +1 -1
  9. package/templates/{product-system → assistkick-product-system}/packages/backend/src/routes/coherence.ts +1 -1
  10. package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +231 -0
  11. package/templates/{product-system → assistkick-product-system}/packages/backend/src/routes/graph.ts +3 -3
  12. package/templates/{product-system → assistkick-product-system}/packages/backend/src/routes/kanban.ts +6 -6
  13. package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +88 -0
  14. package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +82 -0
  15. package/templates/{product-system → assistkick-product-system}/packages/backend/src/server.ts +23 -10
  16. package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/coherence-review.ts +4 -4
  17. package/templates/assistkick-product-system/packages/backend/src/services/github_app_service.ts +146 -0
  18. package/templates/assistkick-product-system/packages/backend/src/services/init.ts +147 -0
  19. package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/invitation_service.ts +1 -1
  20. package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/password_reset_service.ts +1 -1
  21. package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/project_service.ts +72 -1
  22. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +87 -0
  23. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +194 -0
  24. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +159 -0
  25. package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/pty_session_manager.ts +114 -39
  26. package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/terminal_ws_handler.ts +28 -14
  27. package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/user_management_service.ts +1 -1
  28. package/templates/{product-system → assistkick-product-system}/packages/frontend/package.json +1 -1
  29. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/App.tsx +1 -1
  30. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/api/client.ts +151 -0
  31. package/templates/assistkick-product-system/packages/frontend/src/components/GitRepoModal.tsx +352 -0
  32. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/KanbanView.tsx +208 -95
  33. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/ProjectSelector.tsx +17 -1
  34. package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +333 -0
  35. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/Toolbar.tsx +15 -13
  36. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/constants/graph.ts +1 -0
  37. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/hooks/useProjects.ts +4 -0
  38. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/routes/dashboard.tsx +22 -4
  39. package/templates/{product-system → assistkick-product-system}/packages/frontend/src/styles/index.css +486 -38
  40. package/templates/assistkick-product-system/packages/frontend/vite.config.ts +31 -0
  41. package/templates/assistkick-product-system/packages/shared/db/migrations/0001_vengeful_wallop.sql +1 -0
  42. package/templates/assistkick-product-system/packages/shared/db/migrations/0002_greedy_excalibur.sql +4 -0
  43. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0001_snapshot.json +826 -0
  44. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0002_snapshot.json +854 -0
  45. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +27 -0
  46. package/templates/{product-system → assistkick-product-system}/packages/shared/db/schema.ts +5 -0
  47. package/templates/{product-system → assistkick-product-system}/packages/shared/lib/claude-service.ts +54 -1
  48. package/templates/{product-system → assistkick-product-system}/packages/shared/lib/db.ts +1 -1
  49. package/templates/{product-system → assistkick-product-system}/packages/shared/lib/git_workflow.ts +25 -0
  50. package/templates/{product-system → assistkick-product-system}/packages/shared/lib/pipeline-state-store.ts +4 -0
  51. package/templates/{product-system → assistkick-product-system}/packages/shared/lib/pipeline.ts +329 -89
  52. package/templates/assistkick-product-system/packages/shared/lib/pipeline_orchestrator.ts +186 -0
  53. package/templates/{product-system → assistkick-product-system}/packages/shared/lib/prompt_builder.ts +2 -2
  54. package/templates/{product-system → assistkick-product-system}/packages/shared/package.json +1 -1
  55. package/templates/assistkick-product-system/packages/shared/tools/db_explorer.ts +275 -0
  56. package/templates/{product-system → assistkick-product-system}/packages/shared/tools/get_kanban.ts +2 -1
  57. package/templates/{product-system → assistkick-product-system}/packages/shared/tools/move_card.ts +3 -2
  58. package/templates/{product-system → assistkick-product-system}/packages/shared/tools/update_node.ts +2 -2
  59. package/templates/{product-system → assistkick-product-system}/tests/db_sqlite_fallback.test.ts +1 -1
  60. package/templates/{product-system → assistkick-product-system}/tests/kanban.test.ts +1 -1
  61. package/templates/{product-system → assistkick-product-system}/tests/pipeline_stats_all_cards.test.ts +1 -1
  62. package/templates/{product-system → assistkick-product-system}/tests/web_terminal.test.ts +189 -150
  63. package/templates/skills/{product-bootstrap → assistkick-bootstrap}/SKILL.md +36 -28
  64. package/templates/skills/{product-code-reviewer → assistkick-code-reviewer}/SKILL.md +26 -18
  65. package/templates/skills/assistkick-db-explorer/SKILL.md +86 -0
  66. package/templates/skills/{product-debugger → assistkick-debugger}/SKILL.md +35 -27
  67. package/templates/skills/{product-developer → assistkick-developer}/SKILL.md +40 -32
  68. package/templates/skills/{product-interview → assistkick-interview}/SKILL.md +37 -29
  69. package/templates/product-system/packages/backend/src/routes/pipeline.ts +0 -41
  70. package/templates/product-system/packages/backend/src/services/init.ts +0 -80
  71. package/templates/product-system/packages/backend/src/services/pty_session_manager.test.ts +0 -88
  72. package/templates/product-system/packages/frontend/src/components/TerminalView.tsx +0 -200
  73. package/templates/product-system/packages/frontend/vite.config.ts +0 -20
  74. package/templates/product-system/packages/shared/db/migrations/meta/_journal.json +0 -13
  75. /package/templates/{product-system → assistkick-product-system}/.env.example +0 -0
  76. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/middleware/auth_middleware.test.ts +0 -0
  77. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/middleware/auth_middleware.ts +0 -0
  78. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/routes/projects.ts +0 -0
  79. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/routes/users.ts +0 -0
  80. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/auth_service.test.ts +0 -0
  81. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/auth_service.ts +0 -0
  82. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/email_service.ts +0 -0
  83. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/invitation_service.test.ts +0 -0
  84. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/password_reset_service.test.ts +0 -0
  85. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/project_service.test.ts +0 -0
  86. /package/templates/{product-system → assistkick-product-system}/packages/backend/src/services/user_management_service.test.ts +0 -0
  87. /package/templates/{product-system → assistkick-product-system}/packages/backend/tsconfig.json +0 -0
  88. /package/templates/{product-system → assistkick-product-system}/packages/frontend/index.html +0 -0
  89. /package/templates/{product-system → assistkick-product-system}/packages/frontend/package-lock.json +0 -0
  90. /package/templates/{product-system → assistkick-product-system}/packages/frontend/public/favicon.svg +0 -0
  91. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/api/client_projects.test.ts +0 -0
  92. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/api/client_refresh.test.ts +0 -0
  93. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/CoherenceView.tsx +0 -0
  94. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/GraphLegend.tsx +0 -0
  95. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/GraphSettings.tsx +0 -0
  96. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/GraphView.tsx +0 -0
  97. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/InviteUserDialog.tsx +0 -0
  98. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/LoginPage.tsx +0 -0
  99. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/QaIssueSheet.tsx +0 -0
  100. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/SidePanel.tsx +0 -0
  101. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/components/UsersView.tsx +0 -0
  102. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/hooks/useAuth.tsx +0 -0
  103. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/hooks/useGraph.ts +0 -0
  104. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/hooks/useKanban.ts +0 -0
  105. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/hooks/useTheme.ts +0 -0
  106. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/hooks/useToast.tsx +0 -0
  107. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/hooks/use_projects_logic.test.ts +0 -0
  108. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/main.tsx +0 -0
  109. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/pages/accept_invitation_page.tsx +0 -0
  110. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/pages/forgot_password_page.tsx +0 -0
  111. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/pages/register_page.tsx +0 -0
  112. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/pages/reset_password_page.tsx +0 -0
  113. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/routes/ProtectedRoute.tsx +0 -0
  114. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/routes/accept_invitation.tsx +0 -0
  115. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/routes/forgot_password.tsx +0 -0
  116. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/routes/login.tsx +0 -0
  117. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/routes/register.tsx +0 -0
  118. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/routes/reset_password.tsx +0 -0
  119. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/auth_validation.test.ts +0 -0
  120. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/auth_validation.ts +0 -0
  121. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/login_validation.test.ts +0 -0
  122. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/login_validation.ts +0 -0
  123. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/logout.test.ts +0 -0
  124. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/node_sizing.test.ts +0 -0
  125. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/node_sizing.ts +0 -0
  126. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/task_status.test.ts +0 -0
  127. /package/templates/{product-system → assistkick-product-system}/packages/frontend/src/utils/task_status.ts +0 -0
  128. /package/templates/{product-system → assistkick-product-system}/packages/frontend/tsconfig.json +0 -0
  129. /package/templates/{product-system → assistkick-product-system}/packages/shared/.env.example +0 -0
  130. /package/templates/{product-system → assistkick-product-system}/packages/shared/README.md +0 -0
  131. /package/templates/{product-system → assistkick-product-system}/packages/shared/db/migrate.ts +0 -0
  132. /package/templates/{product-system → assistkick-product-system}/packages/shared/db/migrations/0000_dashing_gorgon.sql +0 -0
  133. /package/templates/{product-system → assistkick-product-system}/packages/shared/db/migrations/meta/0000_snapshot.json +0 -0
  134. /package/templates/{product-system → assistkick-product-system}/packages/shared/drizzle.config.js +0 -0
  135. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/coherence.ts +0 -0
  136. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/completeness.ts +0 -0
  137. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/constants.ts +0 -0
  138. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/graph.ts +0 -0
  139. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/kanban.ts +0 -0
  140. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/markdown.ts +0 -0
  141. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/relevance_search.ts +0 -0
  142. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/session.ts +0 -0
  143. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/validator.ts +0 -0
  144. /package/templates/{product-system → assistkick-product-system}/packages/shared/lib/work_summary_parser.ts +0 -0
  145. /package/templates/{product-system → assistkick-product-system}/packages/shared/scripts/assign-project.ts +0 -0
  146. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/add_edge.ts +0 -0
  147. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/add_node.ts +0 -0
  148. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/end_session.ts +0 -0
  149. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/get_gaps.ts +0 -0
  150. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/get_node.ts +0 -0
  151. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/get_status.ts +0 -0
  152. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/migrate_to_turso.ts +0 -0
  153. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/rebuild_index.ts +0 -0
  154. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/remove_edge.ts +0 -0
  155. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/remove_node.ts +0 -0
  156. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/resolve_question.ts +0 -0
  157. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/search_nodes.ts +0 -0
  158. /package/templates/{product-system → assistkick-product-system}/packages/shared/tools/start_session.ts +0 -0
  159. /package/templates/{product-system → assistkick-product-system}/packages/shared/tsconfig.json +0 -0
  160. /package/templates/{product-system → assistkick-product-system}/pnpm-workspace.yaml +0 -0
  161. /package/templates/{product-system → assistkick-product-system}/smoke_test.ts +0 -0
  162. /package/templates/{product-system → assistkick-product-system}/tests/coherence_review.test.ts +0 -0
  163. /package/templates/{product-system → assistkick-product-system}/tests/edge_type_color_coding.test.ts +0 -0
  164. /package/templates/{product-system → assistkick-product-system}/tests/emit-tool-use-events.test.ts +0 -0
  165. /package/templates/{product-system → assistkick-product-system}/tests/feature_kind.test.ts +0 -0
  166. /package/templates/{product-system → assistkick-product-system}/tests/gap_indicators.test.ts +0 -0
  167. /package/templates/{product-system → assistkick-product-system}/tests/graceful_init.test.ts +0 -0
  168. /package/templates/{product-system → assistkick-product-system}/tests/graph_legend.test.ts +0 -0
  169. /package/templates/{product-system → assistkick-product-system}/tests/graph_settings_sheet.test.ts +0 -0
  170. /package/templates/{product-system → assistkick-product-system}/tests/hide_defined_filter.test.ts +0 -0
  171. /package/templates/{product-system → assistkick-product-system}/tests/neighborhood_focus.test.ts +0 -0
  172. /package/templates/{product-system → assistkick-product-system}/tests/node_search.test.ts +0 -0
  173. /package/templates/{product-system → assistkick-product-system}/tests/node_sizing.test.ts +0 -0
  174. /package/templates/{product-system → assistkick-product-system}/tests/node_type_toggle_filters.test.ts +0 -0
  175. /package/templates/{product-system → assistkick-product-system}/tests/node_type_visual_encoding.test.ts +0 -0
  176. /package/templates/{product-system → assistkick-product-system}/tests/pipeline-state-store.test.ts +0 -0
  177. /package/templates/{product-system → assistkick-product-system}/tests/pipeline-unit.test.ts +0 -0
  178. /package/templates/{product-system → assistkick-product-system}/tests/pipeline.test.ts +0 -0
  179. /package/templates/{product-system → assistkick-product-system}/tests/play_all.test.ts +0 -0
  180. /package/templates/{product-system → assistkick-product-system}/tests/qa_issue_sheet.test.ts +0 -0
  181. /package/templates/{product-system → assistkick-product-system}/tests/relevance_search.test.ts +0 -0
  182. /package/templates/{product-system → assistkick-product-system}/tests/search_reorder.test.ts +0 -0
  183. /package/templates/{product-system → assistkick-product-system}/tests/serve_ui.test.ts +0 -0
  184. /package/templates/{product-system → assistkick-product-system}/tests/serve_ui_drizzle.test.ts +0 -0
  185. /package/templates/{product-system → assistkick-product-system}/tests/session_context_recall.test.ts +0 -0
  186. /package/templates/{product-system → assistkick-product-system}/tests/side_panel.test.ts +0 -0
  187. /package/templates/{product-system → assistkick-product-system}/tests/spec_completeness_label.test.ts +0 -0
  188. /package/templates/{product-system → assistkick-product-system}/tests/url_routing_test.ts +0 -0
  189. /package/templates/{product-system → assistkick-product-system}/tests/user_login.test.ts +0 -0
  190. /package/templates/{product-system → assistkick-product-system}/tests/user_registration.test.ts +0 -0
  191. /package/templates/{product-system → assistkick-product-system}/tests/work_summary.test.ts +0 -0
  192. /package/templates/{product-system → assistkick-product-system}/tests/zoom_pan.test.ts +0 -0
  193. /package/templates/{product-system → assistkick-product-system}/tsconfig.json +0 -0
  194. /package/templates/skills/{product-debugger → assistkick-debugger}/references/agent-browser.md +0 -0
@@ -0,0 +1,352 @@
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import { apiClient } from '../api/client';
3
+ import type { Project } from '../hooks/useProjects';
4
+
5
+ interface GitRepoModalProps {
6
+ project: Project;
7
+ onClose: () => void;
8
+ onProjectUpdated: () => void;
9
+ }
10
+
11
+ interface Installation {
12
+ id: number;
13
+ account: string;
14
+ accountType: string;
15
+ }
16
+
17
+ interface Repo {
18
+ id: number;
19
+ fullName: string;
20
+ private: boolean;
21
+ defaultBranch: string;
22
+ cloneUrl: string;
23
+ }
24
+
25
+ type Tab = 'status' | 'github' | 'url' | 'init';
26
+
27
+ export function GitRepoModal({ project, onClose, onProjectUpdated }: GitRepoModalProps) {
28
+ const [tab, setTab] = useState<Tab>('status');
29
+ const [loading, setLoading] = useState(false);
30
+ const [error, setError] = useState<string | null>(null);
31
+ const [success, setSuccess] = useState<string | null>(null);
32
+
33
+ // Status tab
34
+ const [gitStatus, setGitStatus] = useState<any>(null);
35
+
36
+ // GitHub tab
37
+ const [installations, setInstallations] = useState<Installation[]>([]);
38
+ const [selectedInstallation, setSelectedInstallation] = useState<string>('');
39
+ const [repos, setRepos] = useState<Repo[]>([]);
40
+ const [selectedRepo, setSelectedRepo] = useState<string>('');
41
+ const [githubConfigured, setGithubConfigured] = useState(false);
42
+
43
+ // URL tab
44
+ const [cloneUrl, setCloneUrl] = useState('');
45
+
46
+ const loadStatus = useCallback(async () => {
47
+ try {
48
+ const data = await apiClient.getGitStatus(project.id);
49
+ setGitStatus(data);
50
+ setGithubConfigured(data.githubAppConfigured);
51
+ } catch (err: any) {
52
+ setError(err.message);
53
+ }
54
+ }, [project.id]);
55
+
56
+ useEffect(() => {
57
+ loadStatus();
58
+ }, [loadStatus]);
59
+
60
+ const handleTestConnection = async () => {
61
+ setLoading(true);
62
+ setError(null);
63
+ try {
64
+ const data = await apiClient.testGitHubApp(project.id);
65
+ if (!data.configured) {
66
+ setError(data.error || 'GitHub App not configured');
67
+ } else if (data.error) {
68
+ setError(data.error);
69
+ } else {
70
+ setInstallations(data.installations || []);
71
+ setSuccess('GitHub App connection successful');
72
+ }
73
+ } catch (err: any) {
74
+ setError(err.message);
75
+ } finally {
76
+ setLoading(false);
77
+ }
78
+ };
79
+
80
+ const handleLoadInstallations = async () => {
81
+ setLoading(true);
82
+ setError(null);
83
+ try {
84
+ const data = await apiClient.listGitHubInstallations(project.id);
85
+ setInstallations(data.installations || []);
86
+ setGithubConfigured(data.configured);
87
+ } catch (err: any) {
88
+ setError(err.message);
89
+ } finally {
90
+ setLoading(false);
91
+ }
92
+ };
93
+
94
+ const handleLoadRepos = async (installationId: string) => {
95
+ setSelectedInstallation(installationId);
96
+ setLoading(true);
97
+ setError(null);
98
+ try {
99
+ const data = await apiClient.listGitHubRepos(project.id, installationId);
100
+ setRepos(data.repos || []);
101
+ } catch (err: any) {
102
+ setError(err.message);
103
+ } finally {
104
+ setLoading(false);
105
+ }
106
+ };
107
+
108
+ const handleConnectGitHub = async () => {
109
+ if (!selectedRepo || !selectedInstallation) return;
110
+ const repo = repos.find(r => r.fullName === selectedRepo);
111
+ if (!repo) return;
112
+
113
+ setLoading(true);
114
+ setError(null);
115
+ try {
116
+ await apiClient.connectGitRepo(project.id, {
117
+ githubInstallationId: selectedInstallation,
118
+ githubRepoFullName: repo.fullName,
119
+ baseBranch: repo.defaultBranch,
120
+ });
121
+ setSuccess(`Connected to ${repo.fullName}`);
122
+ onProjectUpdated();
123
+ await loadStatus();
124
+ } catch (err: any) {
125
+ setError(err.message);
126
+ } finally {
127
+ setLoading(false);
128
+ }
129
+ };
130
+
131
+ const handleConnectUrl = async () => {
132
+ if (!cloneUrl.trim()) return;
133
+ setLoading(true);
134
+ setError(null);
135
+ try {
136
+ await apiClient.connectGitRepo(project.id, { repoUrl: cloneUrl.trim() });
137
+ setSuccess('Repository connected successfully');
138
+ onProjectUpdated();
139
+ await loadStatus();
140
+ } catch (err: any) {
141
+ setError(err.message);
142
+ } finally {
143
+ setLoading(false);
144
+ }
145
+ };
146
+
147
+ const handleInit = async () => {
148
+ setLoading(true);
149
+ setError(null);
150
+ try {
151
+ await apiClient.initGitRepo(project.id);
152
+ setSuccess('Local git repository initialized');
153
+ onProjectUpdated();
154
+ await loadStatus();
155
+ } catch (err: any) {
156
+ setError(err.message);
157
+ } finally {
158
+ setLoading(false);
159
+ }
160
+ };
161
+
162
+ const handleDisconnect = async () => {
163
+ setLoading(true);
164
+ setError(null);
165
+ try {
166
+ await apiClient.disconnectGitRepo(project.id);
167
+ setSuccess('Repository disconnected');
168
+ onProjectUpdated();
169
+ await loadStatus();
170
+ } catch (err: any) {
171
+ setError(err.message);
172
+ } finally {
173
+ setLoading(false);
174
+ }
175
+ };
176
+
177
+ return (
178
+ <div className="git-modal-overlay" onClick={onClose}>
179
+ <div className="git-modal" onClick={e => e.stopPropagation()}>
180
+ <div className="git-modal-header">
181
+ <h3>Git Repository &mdash; {project.name}</h3>
182
+ <button className="git-modal-close" onClick={onClose}>&times;</button>
183
+ </div>
184
+
185
+ {error && <div className="git-modal-error">{error}</div>}
186
+ {success && <div className="git-modal-success">{success}</div>}
187
+
188
+ <div className="git-modal-tabs">
189
+ <button className={`git-modal-tab${tab === 'status' ? ' active' : ''}`} onClick={() => { setTab('status'); setError(null); setSuccess(null); }}>Status</button>
190
+ <button className={`git-modal-tab${tab === 'github' ? ' active' : ''}`} onClick={() => { setTab('github'); setError(null); setSuccess(null); handleLoadInstallations(); }}>GitHub</button>
191
+ <button className={`git-modal-tab${tab === 'url' ? ' active' : ''}`} onClick={() => { setTab('url'); setError(null); setSuccess(null); }}>Clone URL</button>
192
+ <button className={`git-modal-tab${tab === 'init' ? ' active' : ''}`} onClick={() => { setTab('init'); setError(null); setSuccess(null); }}>Init</button>
193
+ </div>
194
+
195
+ <div className="git-modal-body">
196
+ {tab === 'status' && (
197
+ <div className="git-modal-status">
198
+ {gitStatus ? (
199
+ <>
200
+ <div className="git-status-row">
201
+ <span className="git-status-label">Workspace:</span>
202
+ <span className={`git-status-value ${gitStatus.hasWorkspace ? 'connected' : ''}`}>
203
+ {gitStatus.hasWorkspace ? 'Configured' : 'Not configured'}
204
+ </span>
205
+ </div>
206
+ {gitStatus.hasWorkspace && (
207
+ <>
208
+ <div className="git-status-row">
209
+ <span className="git-status-label">Remote:</span>
210
+ <span className={`git-status-value ${gitStatus.hasRemote ? 'connected' : ''}`}>
211
+ {gitStatus.hasRemote ? 'Connected' : 'Local only'}
212
+ </span>
213
+ </div>
214
+ <div className="git-status-row">
215
+ <span className="git-status-label">Branch:</span>
216
+ <span className="git-status-value">{gitStatus.currentBranch || '-'}</span>
217
+ </div>
218
+ </>
219
+ )}
220
+ {project.githubRepoFullName && (
221
+ <div className="git-status-row">
222
+ <span className="git-status-label">GitHub Repo:</span>
223
+ <span className="git-status-value">{project.githubRepoFullName}</span>
224
+ </div>
225
+ )}
226
+ {project.repoUrl && !project.githubRepoFullName && (
227
+ <div className="git-status-row">
228
+ <span className="git-status-label">Clone URL:</span>
229
+ <span className="git-status-value git-status-url">{project.repoUrl}</span>
230
+ </div>
231
+ )}
232
+ <div className="git-status-row">
233
+ <span className="git-status-label">GitHub App:</span>
234
+ <span className={`git-status-value ${gitStatus.githubAppConfigured ? 'connected' : ''}`}>
235
+ {gitStatus.githubAppConfigured ? 'Configured' : 'Not configured'}
236
+ </span>
237
+ </div>
238
+ {gitStatus.hasWorkspace && (
239
+ <button className="git-modal-btn git-modal-btn-danger" onClick={handleDisconnect} disabled={loading}>
240
+ Disconnect
241
+ </button>
242
+ )}
243
+ </>
244
+ ) : (
245
+ <div className="git-modal-loading">Loading...</div>
246
+ )}
247
+ </div>
248
+ )}
249
+
250
+ {tab === 'github' && (
251
+ <div className="git-modal-github">
252
+ {!githubConfigured ? (
253
+ <div className="git-modal-info">
254
+ GitHub App not configured. Set GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY environment variables.
255
+ <button className="git-modal-btn" onClick={handleTestConnection} disabled={loading}>
256
+ Test Connection
257
+ </button>
258
+ </div>
259
+ ) : (
260
+ <>
261
+ {installations.length === 0 ? (
262
+ <div className="git-modal-info">
263
+ No GitHub App installations found. Install the app on your GitHub organization or account.
264
+ </div>
265
+ ) : (
266
+ <div className="git-modal-installations">
267
+ <label className="git-modal-label">Installation:</label>
268
+ <select
269
+ className="git-modal-select"
270
+ value={selectedInstallation}
271
+ onChange={e => handleLoadRepos(e.target.value)}
272
+ >
273
+ <option value="">Select installation...</option>
274
+ {installations.map(i => (
275
+ <option key={i.id} value={String(i.id)}>
276
+ {i.account} ({i.accountType})
277
+ </option>
278
+ ))}
279
+ </select>
280
+ </div>
281
+ )}
282
+
283
+ {repos.length > 0 && (
284
+ <div className="git-modal-repos">
285
+ <label className="git-modal-label">Repository:</label>
286
+ <select
287
+ className="git-modal-select"
288
+ value={selectedRepo}
289
+ onChange={e => setSelectedRepo(e.target.value)}
290
+ >
291
+ <option value="">Select repository...</option>
292
+ {repos.map(r => (
293
+ <option key={r.id} value={r.fullName}>
294
+ {r.fullName} ({r.defaultBranch})
295
+ </option>
296
+ ))}
297
+ </select>
298
+ <button
299
+ className="git-modal-btn git-modal-btn-primary"
300
+ onClick={handleConnectGitHub}
301
+ disabled={loading || !selectedRepo}
302
+ >
303
+ {loading ? 'Connecting...' : 'Connect'}
304
+ </button>
305
+ </div>
306
+ )}
307
+ </>
308
+ )}
309
+ </div>
310
+ )}
311
+
312
+ {tab === 'url' && (
313
+ <div className="git-modal-url">
314
+ <label className="git-modal-label">Git clone URL:</label>
315
+ <input
316
+ className="git-modal-input"
317
+ type="text"
318
+ placeholder="https://github.com/org/repo.git"
319
+ value={cloneUrl}
320
+ onChange={e => setCloneUrl(e.target.value)}
321
+ onKeyDown={e => { if (e.key === 'Enter') handleConnectUrl(); }}
322
+ />
323
+ <button
324
+ className="git-modal-btn git-modal-btn-primary"
325
+ onClick={handleConnectUrl}
326
+ disabled={loading || !cloneUrl.trim()}
327
+ >
328
+ {loading ? 'Cloning...' : 'Clone & Connect'}
329
+ </button>
330
+ </div>
331
+ )}
332
+
333
+ {tab === 'init' && (
334
+ <div className="git-modal-init">
335
+ <p className="git-modal-info">
336
+ Initialize a new empty local git repository for this project.
337
+ You can connect it to a remote later.
338
+ </p>
339
+ <button
340
+ className="git-modal-btn git-modal-btn-primary"
341
+ onClick={handleInit}
342
+ disabled={loading}
343
+ >
344
+ {loading ? 'Initializing...' : 'Initialize Repository'}
345
+ </button>
346
+ </div>
347
+ )}
348
+ </div>
349
+ </div>
350
+ </div>
351
+ );
352
+ }