@assistkick/create 1.6.0 → 1.8.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 (214) hide show
  1. package/package.json +2 -2
  2. package/templates/assistkick-product-system/.env.example +1 -0
  3. package/templates/assistkick-product-system/local.db +0 -0
  4. package/templates/assistkick-product-system/package.json +4 -2
  5. package/templates/assistkick-product-system/packages/backend/package.json +2 -0
  6. package/templates/assistkick-product-system/packages/backend/src/routes/agents.ts +165 -0
  7. package/templates/assistkick-product-system/packages/backend/src/routes/files.test.ts +358 -0
  8. package/templates/assistkick-product-system/packages/backend/src/routes/files.ts +356 -0
  9. package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +96 -1
  10. package/templates/assistkick-product-system/packages/backend/src/routes/graph.ts +1 -0
  11. package/templates/assistkick-product-system/packages/backend/src/routes/kanban.ts +43 -4
  12. package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +200 -84
  13. package/templates/assistkick-product-system/packages/backend/src/routes/projects.ts +6 -3
  14. package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +53 -17
  15. package/templates/assistkick-product-system/packages/backend/src/routes/video.ts +218 -0
  16. package/templates/assistkick-product-system/packages/backend/src/routes/workflow_groups.ts +119 -0
  17. package/templates/assistkick-product-system/packages/backend/src/routes/workflows.ts +154 -0
  18. package/templates/assistkick-product-system/packages/backend/src/server.ts +81 -9
  19. package/templates/assistkick-product-system/packages/backend/src/services/agent_service.test.ts +489 -0
  20. package/templates/assistkick-product-system/packages/backend/src/services/agent_service.ts +416 -0
  21. package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.test.ts +189 -0
  22. package/templates/assistkick-product-system/packages/backend/src/services/bundle_service.ts +182 -0
  23. package/templates/assistkick-product-system/packages/backend/src/services/init.ts +28 -78
  24. package/templates/assistkick-product-system/packages/backend/src/services/project_service.test.ts +16 -0
  25. package/templates/assistkick-product-system/packages/backend/src/services/project_service.ts +73 -2
  26. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +4 -4
  27. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +87 -11
  28. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +210 -69
  29. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.ts +210 -215
  30. package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.test.ts +162 -0
  31. package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.ts +148 -0
  32. package/templates/assistkick-product-system/packages/backend/src/services/terminal_ws_handler.ts +11 -5
  33. package/templates/assistkick-product-system/packages/backend/src/services/tts_service.test.ts +64 -0
  34. package/templates/assistkick-product-system/packages/backend/src/services/tts_service.ts +134 -0
  35. package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.test.ts +256 -0
  36. package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.ts +258 -0
  37. package/templates/assistkick-product-system/packages/backend/src/services/workflow_group_service.ts +106 -0
  38. package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.test.ts +275 -0
  39. package/templates/assistkick-product-system/packages/backend/src/services/workflow_service.ts +222 -0
  40. package/templates/assistkick-product-system/packages/frontend/index.html +3 -0
  41. package/templates/assistkick-product-system/packages/frontend/package-lock.json +800 -11
  42. package/templates/assistkick-product-system/packages/frontend/package.json +11 -1
  43. package/templates/assistkick-product-system/packages/frontend/src/App.tsx +24 -7
  44. package/templates/assistkick-product-system/packages/frontend/src/api/client.ts +456 -16
  45. package/templates/assistkick-product-system/packages/frontend/src/api/client_files.test.ts +172 -0
  46. package/templates/assistkick-product-system/packages/frontend/src/api/client_video.test.ts +238 -0
  47. package/templates/assistkick-product-system/packages/frontend/src/components/AgentsView.tsx +307 -0
  48. package/templates/assistkick-product-system/packages/frontend/src/components/CoherenceView.tsx +82 -66
  49. package/templates/assistkick-product-system/packages/frontend/src/components/CompositionPlaceholder.tsx +97 -0
  50. package/templates/assistkick-product-system/packages/frontend/src/components/DesignSystemView.tsx +383 -0
  51. package/templates/assistkick-product-system/packages/frontend/src/components/EditorTabBar.tsx +57 -0
  52. package/templates/assistkick-product-system/packages/frontend/src/components/FileTree.tsx +313 -0
  53. package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeContextMenu.tsx +61 -0
  54. package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeInlineInput.tsx +73 -0
  55. package/templates/assistkick-product-system/packages/frontend/src/components/FilesView.tsx +404 -0
  56. package/templates/assistkick-product-system/packages/frontend/src/components/GitRepoModal.tsx +193 -64
  57. package/templates/assistkick-product-system/packages/frontend/src/components/GraphLegend.tsx +71 -73
  58. package/templates/assistkick-product-system/packages/frontend/src/components/GraphSettings.tsx +8 -8
  59. package/templates/assistkick-product-system/packages/frontend/src/components/GraphView.tsx +1 -1
  60. package/templates/assistkick-product-system/packages/frontend/src/components/InviteUserDialog.tsx +15 -11
  61. package/templates/assistkick-product-system/packages/frontend/src/components/KanbanView.tsx +226 -291
  62. package/templates/assistkick-product-system/packages/frontend/src/components/LoginPage.tsx +14 -14
  63. package/templates/assistkick-product-system/packages/frontend/src/components/ProjectSelector.tsx +54 -33
  64. package/templates/assistkick-product-system/packages/frontend/src/components/QaIssueSheet.tsx +40 -66
  65. package/templates/assistkick-product-system/packages/frontend/src/components/SidePanel.tsx +55 -115
  66. package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +121 -52
  67. package/templates/assistkick-product-system/packages/frontend/src/components/Toolbar.tsx +155 -77
  68. package/templates/assistkick-product-system/packages/frontend/src/components/UsersView.tsx +52 -52
  69. package/templates/assistkick-product-system/packages/frontend/src/components/VideoGallery.tsx +313 -0
  70. package/templates/assistkick-product-system/packages/frontend/src/components/VideographyView.tsx +250 -0
  71. package/templates/assistkick-product-system/packages/frontend/src/components/WorkflowsView.tsx +474 -0
  72. package/templates/assistkick-product-system/packages/frontend/src/components/ds/AccentBorderList.tsx +53 -0
  73. package/templates/assistkick-product-system/packages/frontend/src/components/ds/Button.tsx +87 -0
  74. package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonGroup.tsx +29 -0
  75. package/templates/assistkick-product-system/packages/frontend/src/components/ds/ButtonShowcase.tsx +221 -0
  76. package/templates/assistkick-product-system/packages/frontend/src/components/ds/CardGlass.tsx +141 -0
  77. package/templates/assistkick-product-system/packages/frontend/src/components/ds/CompletionRing.tsx +30 -0
  78. package/templates/assistkick-product-system/packages/frontend/src/components/ds/ContentCard.tsx +34 -0
  79. package/templates/assistkick-product-system/packages/frontend/src/components/ds/IconButton.tsx +74 -0
  80. package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCard.tsx +270 -0
  81. package/templates/assistkick-product-system/packages/frontend/src/components/ds/KanbanCardShowcase.tsx +37 -0
  82. package/templates/assistkick-product-system/packages/frontend/src/components/ds/Kbd.tsx +11 -0
  83. package/templates/assistkick-product-system/packages/frontend/src/components/ds/KindBadge.tsx +21 -0
  84. package/templates/assistkick-product-system/packages/frontend/src/components/ds/NavBarSidekick.tsx +207 -0
  85. package/templates/assistkick-product-system/packages/frontend/src/components/ds/SidePanelShowcase.tsx +370 -0
  86. package/templates/assistkick-product-system/packages/frontend/src/components/ds/SideSheet.tsx +64 -0
  87. package/templates/assistkick-product-system/packages/frontend/src/components/ds/StatusDot.tsx +18 -0
  88. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCardPositionNode.tsx +36 -0
  89. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/CheckCycleCountNode.tsx +60 -0
  90. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/EndNode.tsx +42 -0
  91. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GroupNode.tsx +189 -0
  92. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/NodePalette.tsx +123 -0
  93. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/RunAgentNode.tsx +51 -0
  94. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/SetCardMetadataNode.tsx +53 -0
  95. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/StartNode.tsx +18 -0
  96. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/TransitionCardNode.tsx +59 -0
  97. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowCanvas.tsx +335 -0
  98. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowMonitorModal.tsx +634 -0
  99. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/autoLayout.ts +103 -0
  100. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/edgeColors.ts +35 -0
  101. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/monitor_nodes.tsx +208 -0
  102. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.test.ts +119 -0
  103. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.ts +107 -0
  104. package/templates/assistkick-product-system/packages/frontend/src/constants/graph.ts +13 -11
  105. package/templates/assistkick-product-system/packages/frontend/src/hooks/useAutoSave.ts +75 -0
  106. package/templates/assistkick-product-system/packages/frontend/src/hooks/useGraph.ts +6 -21
  107. package/templates/assistkick-product-system/packages/frontend/src/hooks/useProjects.ts +15 -80
  108. package/templates/assistkick-product-system/packages/frontend/src/hooks/useToast.tsx +16 -3
  109. package/templates/assistkick-product-system/packages/frontend/src/pages/accept_invitation_page.tsx +30 -27
  110. package/templates/assistkick-product-system/packages/frontend/src/pages/forgot_password_page.tsx +18 -15
  111. package/templates/assistkick-product-system/packages/frontend/src/pages/register_page.tsx +21 -18
  112. package/templates/assistkick-product-system/packages/frontend/src/pages/reset_password_page.tsx +28 -25
  113. package/templates/assistkick-product-system/packages/frontend/src/routes/AgentsRoute.tsx +6 -0
  114. package/templates/assistkick-product-system/packages/frontend/src/routes/CoherenceRoute.tsx +19 -0
  115. package/templates/assistkick-product-system/packages/frontend/src/routes/DashboardLayout.tsx +54 -0
  116. package/templates/assistkick-product-system/packages/frontend/src/routes/DesignSystemRoute.tsx +6 -0
  117. package/templates/assistkick-product-system/packages/frontend/src/routes/FilesRoute.tsx +13 -0
  118. package/templates/assistkick-product-system/packages/frontend/src/routes/GraphRoute.tsx +93 -0
  119. package/templates/assistkick-product-system/packages/frontend/src/routes/KanbanRoute.tsx +30 -0
  120. package/templates/assistkick-product-system/packages/frontend/src/routes/TerminalRoute.tsx +9 -0
  121. package/templates/assistkick-product-system/packages/frontend/src/routes/UsersRoute.tsx +6 -0
  122. package/templates/assistkick-product-system/packages/frontend/src/routes/VideographyRoute.tsx +13 -0
  123. package/templates/assistkick-product-system/packages/frontend/src/routes/WorkflowsRoute.tsx +6 -0
  124. package/templates/assistkick-product-system/packages/frontend/src/stores/useGitModalStore.ts +14 -0
  125. package/templates/assistkick-product-system/packages/frontend/src/stores/useGraphStore.ts +36 -0
  126. package/templates/assistkick-product-system/packages/frontend/src/stores/useGraphUIStore.ts +25 -0
  127. package/templates/assistkick-product-system/packages/frontend/src/stores/useProjectStore.ts +90 -0
  128. package/templates/assistkick-product-system/packages/frontend/src/stores/useQaSheetStore.ts +27 -0
  129. package/templates/assistkick-product-system/packages/frontend/src/stores/useSidePanelStore.ts +76 -0
  130. package/templates/assistkick-product-system/packages/frontend/src/styles/index.css +336 -3632
  131. package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.test.ts +167 -0
  132. package/templates/assistkick-product-system/packages/frontend/src/utils/auto_save_service.ts +101 -0
  133. package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.test.ts +42 -0
  134. package/templates/assistkick-product-system/packages/frontend/src/utils/composition_matcher.ts +17 -0
  135. package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.test.ts +145 -0
  136. package/templates/assistkick-product-system/packages/frontend/src/utils/file_utils.ts +42 -0
  137. package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.test.ts +4 -10
  138. package/templates/assistkick-product-system/packages/frontend/src/utils/task_status.ts +19 -1
  139. package/templates/assistkick-product-system/packages/frontend/vite.config.ts +7 -1
  140. package/templates/assistkick-product-system/packages/shared/db/local.db +0 -0
  141. package/templates/assistkick-product-system/packages/shared/db/migrations/0004_tidy_matthew_murdock.sql +9 -0
  142. package/templates/assistkick-product-system/packages/shared/db/migrations/0005_mysterious_falcon.sql +692 -0
  143. package/templates/assistkick-product-system/packages/shared/db/migrations/0006_next_venom.sql +9 -0
  144. package/templates/assistkick-product-system/packages/shared/db/migrations/0007_deep_barracuda.sql +39 -0
  145. package/templates/assistkick-product-system/packages/shared/db/migrations/0008_puzzling_hannibal_king.sql +1 -0
  146. package/templates/assistkick-product-system/packages/shared/db/migrations/0009_amused_beast.sql +8 -0
  147. package/templates/assistkick-product-system/packages/shared/db/migrations/0010_spotty_moira_mactaggert.sql +9 -0
  148. package/templates/assistkick-product-system/packages/shared/db/migrations/0011_goofy_snowbird.sql +3 -0
  149. package/templates/assistkick-product-system/packages/shared/db/migrations/0011_supreme_doctor_octopus.sql +3 -0
  150. package/templates/assistkick-product-system/packages/shared/db/migrations/0013_reflective_prowler.sql +15 -0
  151. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0004_snapshot.json +921 -0
  152. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0005_snapshot.json +1042 -0
  153. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0006_snapshot.json +1101 -0
  154. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0007_snapshot.json +1336 -0
  155. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0008_snapshot.json +1275 -0
  156. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0009_snapshot.json +1327 -0
  157. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0010_snapshot.json +1393 -0
  158. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0011_snapshot.json +1436 -0
  159. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0013_snapshot.json +1538 -0
  160. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +70 -0
  161. package/templates/assistkick-product-system/packages/shared/db/schema.ts +113 -0
  162. package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +32 -7
  163. package/templates/assistkick-product-system/packages/shared/lib/constants.ts +9 -0
  164. package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +12 -4
  165. package/templates/assistkick-product-system/packages/shared/lib/graph.ts +16 -5
  166. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +1753 -0
  167. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +1281 -0
  168. package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +211 -0
  169. package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +43 -0
  170. package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +13 -2
  171. package/templates/assistkick-product-system/packages/shared/tools/get_kanban.ts +1 -1
  172. package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.test.ts +226 -0
  173. package/templates/assistkick-product-system/packages/shared/tools/migrate_epics.ts +251 -0
  174. package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -2
  175. package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.test.ts +10 -0
  176. package/templates/assistkick-product-system/packages/shared/utils/hello_workflow.ts +6 -0
  177. package/templates/assistkick-product-system/packages/video/Root.tsx +85 -0
  178. package/templates/assistkick-product-system/packages/video/components/email_scene.tsx +231 -0
  179. package/templates/assistkick-product-system/packages/video/components/outro_scene.tsx +153 -0
  180. package/templates/assistkick-product-system/packages/video/components/part_divider.tsx +90 -0
  181. package/templates/assistkick-product-system/packages/video/components/scene.tsx +226 -0
  182. package/templates/assistkick-product-system/packages/video/components/theme.ts +22 -0
  183. package/templates/assistkick-product-system/packages/video/components/title_scene.tsx +169 -0
  184. package/templates/assistkick-product-system/packages/video/components/video_split_layout.tsx +84 -0
  185. package/templates/assistkick-product-system/packages/video/compositions/.gitkeep +0 -0
  186. package/templates/assistkick-product-system/packages/video/index.ts +4 -0
  187. package/templates/assistkick-product-system/packages/video/package.json +28 -0
  188. package/templates/assistkick-product-system/packages/video/remotion.config.ts +11 -0
  189. package/templates/assistkick-product-system/packages/video/scripts/process_script.test.ts +326 -0
  190. package/templates/assistkick-product-system/packages/video/scripts/process_script.ts +630 -0
  191. package/templates/assistkick-product-system/packages/video/style.css +1 -0
  192. package/templates/assistkick-product-system/packages/video/tsconfig.json +18 -0
  193. package/templates/assistkick-product-system/tests/graph_legend.test.ts +2 -1
  194. package/templates/assistkick-product-system/tests/video_render_service.test.ts +179 -0
  195. package/templates/assistkick-product-system/tests/web_terminal.test.ts +219 -455
  196. package/templates/assistkick-product-system/tests/workflow_integration.test.ts +341 -0
  197. package/templates/skills/assistkick-bootstrap/SKILL.md +3 -3
  198. package/templates/skills/assistkick-code-reviewer/SKILL.md +2 -2
  199. package/templates/skills/assistkick-debugger/SKILL.md +2 -2
  200. package/templates/skills/assistkick-developer/SKILL.md +6 -3
  201. package/templates/skills/assistkick-developer/references/react_development_guidelines.md +225 -0
  202. package/templates/skills/assistkick-interview/SKILL.md +2 -2
  203. package/templates/skills/product-system/graph.json +1890 -0
  204. package/templates/skills/product-system/kanban.json +304 -0
  205. package/templates/skills/product-system/nodes/comp_001.md +56 -0
  206. package/templates/skills/product-system/nodes/comp_002.md +57 -0
  207. package/templates/skills/product-system/nodes/data_001.md +51 -0
  208. package/templates/skills/product-system/nodes/data_002.md +40 -0
  209. package/templates/skills/product-system/nodes/data_004.md +38 -0
  210. package/templates/skills/product-system/nodes/dec_001.md +34 -0
  211. package/templates/skills/product-system/nodes/dec_016.md +32 -0
  212. package/templates/skills/product-system/nodes/feat_008.md +30 -0
  213. package/templates/skills/video-composition-agent/SKILL.md +232 -0
  214. package/templates/skills/video-script-writer/SKILL.md +136 -0
@@ -1,63 +1,18 @@
1
- import React, { useState, useCallback } from 'react';
1
+ import React from 'react';
2
2
  import { marked } from 'marked';
3
- import { apiClient } from '../api/client';
4
- import { getTaskIcon, getTaskCssClass, shouldShowTaskList } from '../utils/task_status';
3
+ import { useSidePanelStore } from '../stores/useSidePanelStore';
4
+ import { useGraphStore } from '../stores/useGraphStore';
5
+ import { useGraphUIStore } from '../stores/useGraphUIStore';
6
+ import { getTaskCssClass, getTaskIcon, getTaskIconClass, getTaskNameClass, shouldShowTaskList } from '../utils/task_status';
7
+ import { SideSheet } from './ds/SideSheet';
5
8
 
6
- interface WorkSummary {
7
- cycle: number;
8
- filesCreated: string[];
9
- filesUpdated: string[];
10
- filesDeleted: string[];
11
- approach: string;
12
- decisions: string[];
13
- timestamp: string;
14
- }
15
-
16
- interface SidePanelProps {
17
- graphData: any;
18
- onEdgeClick: (neighborId: string) => void;
19
- }
20
-
21
- export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
22
- const [isOpen, setIsOpen] = useState(false);
23
- const [node, setNode] = useState<any>(null);
24
- const [content, setContent] = useState('');
25
- const [workSummaries, setWorkSummaries] = useState<WorkSummary[]>([]);
26
- const [expandedSummaries, setExpandedSummaries] = useState(false);
27
- const [tasks, setTasks] = useState<{ total: number; completed: number; items: any[] } | null>(null);
28
- const [expandedTasks, setExpandedTasks] = useState(false);
29
-
30
- const open = useCallback(async (n: any) => {
31
- setNode(n);
32
- setWorkSummaries([]);
33
- setExpandedSummaries(false);
34
- setTasks(null);
35
- setExpandedTasks(false);
36
- try {
37
- const detail = await apiClient.fetchNode(n.id);
38
- setContent(detail.content);
39
- setIsOpen(true);
40
-
41
- // Fetch pipeline status for feature nodes to get work summaries
42
- if (n.type === 'feature' || n.id?.startsWith('feat_')) {
43
- try {
44
- const pStatus = await apiClient.getPipelineStatus(n.id);
45
- if (pStatus?.workSummaries?.length > 0) {
46
- setWorkSummaries(pStatus.workSummaries);
47
- }
48
- if (pStatus?.tasks) {
49
- setTasks(pStatus.tasks);
50
- }
51
- } catch {
52
- // Pipeline status may not exist for all features
53
- }
54
- }
55
- } catch (err) {
56
- console.error('Failed to fetch node:', err);
57
- }
58
- }, []);
59
-
60
- const close = useCallback(() => setIsOpen(false), []);
9
+ export function SidePanel() {
10
+ const {
11
+ isOpen, node, content, workSummaries, expandedSummaries,
12
+ tasks, expandedTasks, close, toggleSummaries, toggleTasks,
13
+ } = useSidePanelStore();
14
+ const graphData = useGraphStore((s) => s.graphData);
15
+ const onEdgeClick = useGraphUIStore((s) => s.onEdgeClick);
61
16
 
62
17
  const renderMarkdown = (md: string) => {
63
18
  const stripped = md.replace(/^---[\s\S]*?---\n*/m, '');
@@ -78,19 +33,12 @@ export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
78
33
  return edges;
79
34
  };
80
35
 
81
- // Expose open/close via ref-like approach on the component instance
82
- // We'll use a callback pattern instead
83
- (SidePanel as any).__open = open;
84
- (SidePanel as any).__close = close;
36
+ const title = node ? `${node.name} (${node.id})` : '';
85
37
 
86
38
  if (!node) return (
87
- <div className={`side-panel${isOpen ? ' open' : ''}`} id="side-panel">
88
- <div className="panel-header">
89
- <span className="panel-title" />
90
- <button className="panel-close" onClick={close}>&times;</button>
91
- </div>
92
- <div className="panel-body" />
93
- </div>
39
+ <SideSheet isOpen={isOpen} onClose={close} title="" zIndex={200}>
40
+ <div className="panel-body text-sm leading-relaxed" />
41
+ </SideSheet>
94
42
  );
95
43
 
96
44
  const statusLabel = (node.status || 'draft').replace(/_/g, ' ');
@@ -99,34 +47,30 @@ export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
99
47
  const edges = findEdges(node.id);
100
48
 
101
49
  return (
102
- <div className={`side-panel${isOpen ? ' open' : ''}`} id="side-panel">
103
- <div className="panel-header">
104
- <span className="panel-title">{node.name} ({node.id})</span>
105
- <button className="panel-close" onClick={close}>&times;</button>
106
- </div>
107
- <div className="panel-body">
108
- <div className="panel-status-section">
109
- <span className="panel-type-badge">{typeLabel}</span>
110
- <span className={`panel-status-badge panel-status-${node.status || 'draft'}`}>{statusLabel}</span>
111
- <span className="panel-completeness">{completeness}% complete</span>
50
+ <SideSheet isOpen={isOpen} onClose={close} title={title} zIndex={200}>
51
+ <div className="panel-body text-sm leading-relaxed">
52
+ <div className="flex items-center gap-2 mb-3 pb-2.5 border-b border-edge flex-wrap">
53
+ <span className="text-[10px] text-content-muted uppercase tracking-wide bg-surface-raised px-2 py-0.5 rounded-sm">{typeLabel}</span>
54
+ <span className={`text-[10px] px-2 py-0.5 rounded-sm font-semibold capitalize panel-status-${node.status || 'draft'}`}>{statusLabel}</span>
55
+ <span className="text-[11px] text-content-secondary ml-auto">{completeness}% complete</span>
112
56
  </div>
113
57
  {shouldShowTaskList(tasks) && (
114
- <div className="panel-task-list">
58
+ <div className="my-2 border border-edge rounded">
115
59
  <button
116
- className="panel-task-list-toggle"
117
- onClick={() => setExpandedTasks(prev => !prev)}
60
+ className="bg-none border-none text-content font-mono text-xs cursor-pointer py-1.5 px-2 w-full text-left flex items-center gap-1.5 hover:text-content hover:bg-surface-raised"
61
+ onClick={toggleTasks}
118
62
  >
119
- <span className={`panel-task-list-chevron${expandedTasks ? ' expanded' : ''}`}>{'\u25B6'}</span>
63
+ <span className={`inline-block text-[9px] transition-transform duration-150${expandedTasks ? ' rotate-90' : ''}`}>{'\u25B6'}</span>
120
64
  Tasks ({tasks!.completed}/{tasks!.total})
121
65
  </button>
122
66
  {expandedTasks && tasks!.items?.length > 0 && (
123
- <div className="panel-task-list-items">
67
+ <div className="px-2 pt-1 pb-1.5 flex flex-col gap-[3px] border-t border-edge">
124
68
  {tasks!.items.map((task: any, idx: number) => (
125
69
  <div key={idx} className={getTaskCssClass(task.status)}>
126
- <span className="kanban-task-icon">
70
+ <span className={`shrink-0 w-3 text-center text-[10px] ${getTaskIconClass(task.status)}`}>
127
71
  {getTaskIcon(task.status)}
128
72
  </span>
129
- <span className="kanban-task-name">{task.name}</span>
73
+ <span className={getTaskNameClass(task.status)}>{task.name}</span>
130
74
  </div>
131
75
  ))}
132
76
  </div>
@@ -135,21 +79,21 @@ export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
135
79
  )}
136
80
  <div dangerouslySetInnerHTML={{ __html: renderMarkdown(content) }} />
137
81
  {workSummaries.length > 0 && (
138
- <div className="panel-work-summary">
82
+ <div className="mt-3 border-t border-edge pt-2">
139
83
  <button
140
- className="panel-work-summary-toggle"
141
- onClick={() => setExpandedSummaries(prev => !prev)}
84
+ className="bg-none border-none text-content-secondary text-[13px] font-mono cursor-pointer py-1 w-full text-left hover:text-content"
85
+ onClick={toggleSummaries}
142
86
  >
143
87
  {expandedSummaries ? '\u25BC' : '\u25B6'} Work Summary ({workSummaries.length} cycle{workSummaries.length !== 1 ? 's' : ''})
144
88
  </button>
145
89
  {expandedSummaries && (
146
- <div className="panel-work-summary-details">
90
+ <div className="mt-2 text-xs text-content-secondary">
147
91
  {workSummaries.map((ws, idx) => (
148
- <div key={idx} className="panel-work-summary-cycle">
149
- <div className="panel-work-summary-cycle-header">Cycle {ws.cycle}</div>
92
+ <div key={idx} className="mb-3 pb-2 border-b border-edge last:border-b-0 last:mb-0">
93
+ <div className="font-semibold font-mono text-content mb-1">Cycle {ws.cycle}</div>
150
94
  {ws.filesCreated?.length > 0 && (
151
- <div className="panel-work-summary-files panel-work-summary-files-created">
152
- <span className="panel-work-summary-label">Created:</span>
95
+ <div>
96
+ <span className="font-semibold text-content-secondary font-mono text-[11px] uppercase tracking-wider" style={{ color: '#4caf50' }}>Created:</span>
153
97
  <ul>
154
98
  {ws.filesCreated.map((f, fi) => (
155
99
  <li key={fi}>{f}</li>
@@ -158,8 +102,8 @@ export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
158
102
  </div>
159
103
  )}
160
104
  {ws.filesUpdated?.length > 0 && (
161
- <div className="panel-work-summary-files panel-work-summary-files-updated">
162
- <span className="panel-work-summary-label">Updated:</span>
105
+ <div>
106
+ <span className="font-semibold text-content-secondary font-mono text-[11px] uppercase tracking-wider" style={{ color: '#ff9800' }}>Updated:</span>
163
107
  <ul>
164
108
  {ws.filesUpdated.map((f, fi) => (
165
109
  <li key={fi}>{f}</li>
@@ -168,8 +112,8 @@ export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
168
112
  </div>
169
113
  )}
170
114
  {ws.filesDeleted?.length > 0 && (
171
- <div className="panel-work-summary-files panel-work-summary-files-deleted">
172
- <span className="panel-work-summary-label">Deleted:</span>
115
+ <div>
116
+ <span className="font-semibold text-content-secondary font-mono text-[11px] uppercase tracking-wider" style={{ color: '#f44336' }}>Deleted:</span>
173
117
  <ul>
174
118
  {ws.filesDeleted.map((f, fi) => (
175
119
  <li key={fi}>{f}</li>
@@ -178,14 +122,14 @@ export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
178
122
  </div>
179
123
  )}
180
124
  {ws.approach && (
181
- <div className="panel-work-summary-approach">
182
- <span className="panel-work-summary-label">Approach:</span>
125
+ <div>
126
+ <span className="font-semibold text-content-secondary font-mono text-[11px] uppercase tracking-wider">Approach:</span>
183
127
  <p>{ws.approach}</p>
184
128
  </div>
185
129
  )}
186
130
  {ws.decisions?.length > 0 && (
187
- <div className="panel-work-summary-decisions">
188
- <span className="panel-work-summary-label">Decisions:</span>
131
+ <div>
132
+ <span className="font-semibold text-content-secondary font-mono text-[11px] uppercase tracking-wider">Decisions:</span>
189
133
  <ul>
190
134
  {ws.decisions.map((d, di) => (
191
135
  <li key={di}>{d}</li>
@@ -200,21 +144,21 @@ export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
200
144
  </div>
201
145
  )}
202
146
  {edges.length > 0 && (
203
- <div className="panel-edges-section">
204
- <h3>Relationships</h3>
205
- <ul className="panel-edge-list">
147
+ <div className="mt-4 pt-3 border-t border-edge">
148
+ <h3 className="text-xs text-content mb-2 uppercase tracking-wide">Relationships</h3>
149
+ <ul className="list-none p-0 m-0 flex flex-col gap-1">
206
150
  {edges.map((edge, i) => {
207
151
  const neighborNode = graphData?.nodes.find((n: any) => n.id === edge.neighborId);
208
152
  const name = neighborNode ? neighborNode.name : edge.neighborId;
209
153
  const direction = edge.direction === 'outgoing' ? '\u2192' : '\u2190';
210
154
  return (
211
- <li key={i} className="panel-edge-item">
212
- <span className="panel-edge-direction">{direction}</span>
213
- <span className="panel-edge-relation">{edge.relation.replace(/_/g, ' ')}</span>
214
- <a className="panel-edge-link" href="#" onClick={(e) => { e.preventDefault(); onEdgeClick(edge.neighborId); }}>
155
+ <li key={i} className="flex items-center gap-1.5 px-1.5 py-1 rounded-sm transition-background duration-150 hover:bg-surface-raised">
156
+ <span className="text-[11px] text-content-muted w-3.5 text-center shrink-0">{direction}</span>
157
+ <span className="text-[10px] text-content-muted min-w-20 shrink-0">{edge.relation.replace(/_/g, ' ')}</span>
158
+ <a className="text-xs text-accent no-underline cursor-pointer flex-1 overflow-hidden text-ellipsis whitespace-nowrap hover:underline" href="#" onClick={(e) => { e.preventDefault(); onEdgeClick?.(edge.neighborId); }}>
215
159
  {name}
216
160
  </a>
217
- <span className="panel-edge-id">{edge.neighborId}</span>
161
+ <span className="text-[10px] text-content-muted shrink-0">{edge.neighborId}</span>
218
162
  </li>
219
163
  );
220
164
  })}
@@ -222,10 +166,6 @@ export function SidePanel({ graphData, onEdgeClick }: SidePanelProps) {
222
166
  </div>
223
167
  )}
224
168
  </div>
225
- </div>
169
+ </SideSheet>
226
170
  );
227
171
  }
228
-
229
- // Export the static methods for imperative use
230
- export const openSidePanel = (node: any) => (SidePanel as any).__open?.(node);
231
- export const closeSidePanel = () => (SidePanel as any).__close?.();
@@ -2,6 +2,7 @@
2
2
  * Terminal view — multi-session manager with chat-like layout.
3
3
  * Left sidebar lists all terminal sessions; right panel shows the active session's terminal.
4
4
  * Each session is permanently bound to a project chosen at creation time.
5
+ * Sessions persist across server restarts — suspended sessions are auto-resumed on connect.
5
6
  * Admin-only access.
6
7
  */
7
8
 
@@ -12,6 +13,10 @@ import { WebLinksAddon } from '@xterm/addon-web-links';
12
13
  import '@xterm/xterm/css/xterm.css';
13
14
  import { apiClient } from '../api/client';
14
15
  import type { Project } from '../hooks/useProjects';
16
+ import { useProjectStore } from '../stores/useProjectStore';
17
+ import { Button } from './ds/Button';
18
+ import { IconButton } from './ds/IconButton';
19
+ import { X, Plus, RefreshCw } from 'lucide-react';
15
20
 
16
21
  interface TerminalViewProps {
17
22
  visible: boolean;
@@ -20,11 +25,13 @@ interface TerminalViewProps {
20
25
 
21
26
  interface SessionInfo {
22
27
  id: string;
28
+ claudeSessionId: string;
23
29
  name: string;
24
30
  projectId: string;
25
31
  projectName: string;
26
- state: 'idle' | 'running';
32
+ state: 'suspended' | 'running';
27
33
  createdAt: string;
34
+ lastUsedAt: string;
28
35
  }
29
36
 
30
37
  type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'error';
@@ -43,15 +50,11 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
43
50
  const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
44
51
  const [status, setStatus] = useState<ConnectionStatus>('disconnected');
45
52
  const [errorMsg, setErrorMsg] = useState('');
46
- const [newSessionProjectId, setNewSessionProjectId] = useState<string>('');
47
53
  const [creating, setCreating] = useState(false);
54
+ const [isDragging, setIsDragging] = useState(false);
55
+ const dragCounterRef = useRef(0);
48
56
 
49
- // Default new session project picker to first project
50
- useEffect(() => {
51
- if (projects.length > 0 && !newSessionProjectId) {
52
- setNewSessionProjectId(projects[0].id);
53
- }
54
- }, [projects, newSessionProjectId]);
57
+ const selectedProjectId = useProjectStore((s) => s.selectedProjectId);
55
58
 
56
59
  const fetchSessions = useCallback(async () => {
57
60
  try {
@@ -120,8 +123,10 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
120
123
  terminal.open(containerRef.current);
121
124
  fitAddon.fit();
122
125
 
126
+ // Pass terminal dimensions so the server can resume with correct size
127
+ const { cols, rows } = terminal;
123
128
  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
124
- const wsUrl = `${protocol}//${window.location.host}/api/terminal?sessionId=${encodeURIComponent(sessionId)}`;
129
+ const wsUrl = `${protocol}//${window.location.host}/api/terminal?sessionId=${encodeURIComponent(sessionId)}&cols=${cols}&rows=${rows}`;
125
130
 
126
131
  setStatus('connecting');
127
132
  setErrorMsg('');
@@ -132,8 +137,10 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
132
137
  ws.onopen = () => {
133
138
  setStatus('connected');
134
139
  fitAddon.fit();
135
- const { cols, rows } = terminal;
136
- ws.send(JSON.stringify({ type: 'resize', cols, rows }));
140
+ const dims = terminal;
141
+ ws.send(JSON.stringify({ type: 'resize', cols: dims.cols, rows: dims.rows }));
142
+ // Refresh sessions to update state from suspended → running
143
+ fetchSessions();
137
144
  };
138
145
 
139
146
  ws.onmessage = (event) => {
@@ -159,7 +166,7 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
159
166
  setErrorMsg('Access denied. Admin privileges required.');
160
167
  } else if (event.code === 4004) {
161
168
  setStatus('error');
162
- setErrorMsg('Session not found. It may have been killed.');
169
+ setErrorMsg('Session not found. It may have been deleted.');
163
170
  fetchSessions();
164
171
  } else {
165
172
  setStatus('disconnected');
@@ -188,7 +195,7 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
188
195
  }, [connectToSession]);
189
196
 
190
197
  const handleCreateSession = useCallback(async () => {
191
- const projectId = newSessionProjectId || projects[0]?.id;
198
+ const projectId = selectedProjectId || projects[0]?.id;
192
199
  if (!projectId) return;
193
200
 
194
201
  const project = projects.find(p => p.id === projectId) || projects[0];
@@ -207,7 +214,7 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
207
214
  } finally {
208
215
  setCreating(false);
209
216
  }
210
- }, [newSessionProjectId, projects, fetchSessions, connectToSession]);
217
+ }, [selectedProjectId, projects, fetchSessions, connectToSession]);
211
218
 
212
219
  const handleKillSession = useCallback(async (sessionId: string, e: React.MouseEvent) => {
213
220
  e.stopPropagation();
@@ -249,82 +256,144 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
249
256
  };
250
257
  }, [disconnectCurrent]);
251
258
 
259
+ // --- Image drag-and-drop handlers ---
260
+ const handleDragEnter = useCallback((e: React.DragEvent) => {
261
+ e.preventDefault();
262
+ e.stopPropagation();
263
+ dragCounterRef.current++;
264
+ if (e.dataTransfer.types.includes('Files')) {
265
+ setIsDragging(true);
266
+ }
267
+ }, []);
268
+
269
+ const handleDragLeave = useCallback((e: React.DragEvent) => {
270
+ e.preventDefault();
271
+ e.stopPropagation();
272
+ dragCounterRef.current--;
273
+ if (dragCounterRef.current === 0) {
274
+ setIsDragging(false);
275
+ }
276
+ }, []);
277
+
278
+ const handleDragOver = useCallback((e: React.DragEvent) => {
279
+ e.preventDefault();
280
+ e.stopPropagation();
281
+ }, []);
282
+
283
+ const handleDrop = useCallback(async (e: React.DragEvent) => {
284
+ e.preventDefault();
285
+ e.stopPropagation();
286
+ dragCounterRef.current = 0;
287
+ setIsDragging(false);
288
+
289
+ const conn = connectionRef.current;
290
+ if (!conn || conn.ws.readyState !== WebSocket.OPEN) return;
291
+
292
+ const files = Array.from(e.dataTransfer.files);
293
+ const imageFiles = files.filter(f => f.type.startsWith('image/'));
294
+ if (imageFiles.length === 0) return;
295
+
296
+ for (const file of imageFiles) {
297
+ try {
298
+ const { path } = await apiClient.uploadTerminalImage(file);
299
+ conn.ws.send(JSON.stringify({ type: 'input', data: path + ' ' }));
300
+ } catch (err) {
301
+ console.error('Failed to upload image:', err);
302
+ }
303
+ }
304
+ }, []);
305
+
252
306
  const activeSession = sessions.find(s => s.id === activeSessionId);
253
307
 
254
308
  return (
255
- <div className="terminal-view" style={{ display: visible ? 'flex' : 'none' }}>
309
+ <div className="flex flex-row h-full w-full overflow-hidden" style={{ display: visible ? 'flex' : 'none' }}>
256
310
  {/* Left sidebar — session list */}
257
- <div className="terminal-sidebar">
258
- <div className="terminal-sidebar-header">Sessions</div>
259
- <div className="terminal-session-list">
311
+ <div className="flex flex-col w-[280px] min-w-[280px] border-r border-edge bg-surface-alt overflow-hidden">
312
+ <div className="px-3 py-2.5 text-[11px] font-mono uppercase tracking-widest text-content-muted border-b border-edge shrink-0">Sessions</div>
313
+ <div className="flex-1 overflow-y-auto">
260
314
  {sessions.length === 0 && (
261
- <div className="terminal-no-sessions">No sessions yet</div>
315
+ <div className="px-3 py-4 text-xs text-content-muted font-mono">No sessions yet</div>
262
316
  )}
263
317
  {sessions.map(session => (
264
318
  <div
265
319
  key={session.id}
266
- className={`terminal-session-item${session.id === activeSessionId ? ' terminal-session-item--active' : ''}`}
320
+ className={`flex flex-col px-2.5 py-2 cursor-pointer border-b border-edge relative hover:bg-tab-hover${session.id === activeSessionId ? ' bg-tab-active border-l-2 border-l-accent pl-2' : ''}`}
267
321
  onClick={() => handleSelectSession(session.id)}
268
322
  >
269
- <div className="terminal-session-name">{session.name}</div>
270
- <div className="terminal-session-project">{session.projectName}</div>
271
- <button
272
- className="terminal-session-kill"
323
+ <div className="text-xs font-mono text-content whitespace-nowrap overflow-hidden text-ellipsis pr-5 flex items-center gap-1">
324
+ {session.state === 'suspended' && (
325
+ <span className="shrink-0 text-[10px] leading-none text-content-muted opacity-70" title="Suspended — will resume on connect">&#x23F8;</span>
326
+ )}
327
+ {session.name}
328
+ </div>
329
+ <div className="text-[11px] text-content-muted font-mono whitespace-nowrap overflow-hidden text-ellipsis pr-5 mt-0.5">{session.projectName}</div>
330
+ <IconButton
331
+ label="Kill session"
332
+ variant="danger"
333
+ size="sm"
334
+ className="absolute top-2 right-2"
273
335
  onClick={(e) => handleKillSession(session.id, e)}
274
- title="Kill session"
275
336
  >
276
-
277
- </button>
337
+ <X size={10} strokeWidth={2} />
338
+ </IconButton>
278
339
  </div>
279
340
  ))}
280
341
  </div>
281
342
 
282
- {/* New session controls */}
283
- <div className="terminal-new-session">
284
- <select
285
- className="terminal-project-picker"
286
- value={newSessionProjectId}
287
- onChange={e => setNewSessionProjectId(e.target.value)}
288
- disabled={creating || projects.length === 0}
289
- >
290
- {projects.map(p => (
291
- <option key={p.id} value={p.id}>{p.name}</option>
292
- ))}
293
- </select>
294
- <button
295
- className="terminal-new-session-btn"
343
+ {/* New session uses the project selected in the navbar */}
344
+ <div className="flex flex-col gap-1.5 p-2.5 border-t border-edge shrink-0">
345
+ <Button
346
+ variant="primary"
347
+ size="sm"
348
+ icon={!creating ? <Plus size={12} strokeWidth={2} /> : undefined}
349
+ className="w-full"
296
350
  onClick={handleCreateSession}
297
- disabled={creating || projects.length === 0}
351
+ disabled={creating || !selectedProjectId}
298
352
  >
299
- {creating ? '' : '+ New'}
300
- </button>
353
+ {creating ? '...' : 'New'}
354
+ </Button>
301
355
  </div>
302
356
  </div>
303
357
 
304
358
  {/* Right panel — terminal content */}
305
- <div className="terminal-panel">
359
+ <div
360
+ className="flex-1 flex flex-col min-w-0 relative"
361
+ onDragEnter={handleDragEnter}
362
+ onDragLeave={handleDragLeave}
363
+ onDragOver={handleDragOver}
364
+ onDrop={handleDrop}
365
+ >
366
+ {isDragging && (
367
+ <div className="absolute inset-0 z-10 flex items-center justify-center bg-[rgba(30,30,46,0.85)] border-2 border-dashed border-[#89b4fa] rounded-lg pointer-events-none">
368
+ <div className="text-[#89b4fa] text-lg font-mono font-semibold">Drop image here</div>
369
+ </div>
370
+ )}
306
371
  {!activeSessionId && (
307
- <div className="terminal-empty-state">
372
+ <div className="flex-1 flex items-center justify-center text-content-muted text-[13px] font-mono">
308
373
  Select a session or create a new one
309
374
  </div>
310
375
  )}
311
376
  {activeSession && errorMsg && (
312
- <div className="terminal-error">
377
+ <div className="flex items-center gap-3 px-4 py-2 bg-error text-[#1e1e2e] text-[13px] font-mono shrink-0">
313
378
  <span>{errorMsg}</span>
314
- <button
315
- className="terminal-reconnect-btn"
379
+ <Button
380
+ variant="secondary"
381
+ size="sm"
382
+ icon={<RefreshCw size={12} strokeWidth={2} />}
316
383
  onClick={() => connectToSession(activeSessionId!)}
317
384
  >
318
385
  Reconnect
319
- </button>
386
+ </Button>
320
387
  </div>
321
388
  )}
322
389
  {activeSession && status === 'connecting' && (
323
- <div className="terminal-status">Connecting…</div>
390
+ <div className="px-4 py-2 text-content-secondary text-[13px] font-mono shrink-0">
391
+ {activeSession.state === 'suspended' ? 'Resuming session...' : 'Connecting...'}
392
+ </div>
324
393
  )}
325
394
  <div
326
395
  ref={containerRef}
327
- className="terminal-container"
396
+ className="terminal-container flex-1 p-1 bg-[#1e1e2e] min-h-0"
328
397
  style={{ display: activeSessionId ? 'flex' : 'none' }}
329
398
  />
330
399
  </div>