@assistkick/create 1.10.0 → 1.12.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 (209) hide show
  1. package/dist/src/scaffolder.d.ts +12 -1
  2. package/dist/src/scaffolder.js +40 -3
  3. package/dist/src/scaffolder.js.map +1 -1
  4. package/package.json +1 -1
  5. package/templates/assistkick-product-system/package.json +1 -1
  6. package/templates/assistkick-product-system/packages/backend/package.json +1 -0
  7. package/templates/assistkick-product-system/packages/backend/src/mcp/permission_mcp_server.ts +196 -0
  8. package/templates/assistkick-product-system/packages/backend/src/routes/agents.ts +31 -7
  9. package/templates/assistkick-product-system/packages/backend/src/routes/auth.ts +15 -12
  10. package/templates/assistkick-product-system/packages/backend/src/routes/chat_files.test.ts +95 -0
  11. package/templates/assistkick-product-system/packages/backend/src/routes/chat_files.ts +97 -0
  12. package/templates/assistkick-product-system/packages/backend/src/routes/chat_permission.ts +94 -0
  13. package/templates/assistkick-product-system/packages/backend/src/routes/chat_sessions.ts +189 -0
  14. package/templates/assistkick-product-system/packages/backend/src/routes/chat_upload.test.ts +131 -0
  15. package/templates/assistkick-product-system/packages/backend/src/routes/chat_upload.ts +94 -0
  16. package/templates/assistkick-product-system/packages/backend/src/routes/files.test.ts +12 -3
  17. package/templates/assistkick-product-system/packages/backend/src/routes/files.ts +2 -2
  18. package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +390 -22
  19. package/templates/assistkick-product-system/packages/backend/src/routes/git_branches.test.ts +306 -0
  20. package/templates/assistkick-product-system/packages/backend/src/routes/git_connect.test.ts +133 -0
  21. package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +66 -9
  22. package/templates/assistkick-product-system/packages/backend/src/routes/preview.ts +204 -0
  23. package/templates/assistkick-product-system/packages/backend/src/routes/projects.test.ts +205 -0
  24. package/templates/assistkick-product-system/packages/backend/src/routes/projects.ts +37 -9
  25. package/templates/assistkick-product-system/packages/backend/src/routes/skills.test.ts +139 -0
  26. package/templates/assistkick-product-system/packages/backend/src/routes/skills.ts +95 -0
  27. package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +5 -4
  28. package/templates/assistkick-product-system/packages/backend/src/routes/users.ts +4 -4
  29. package/templates/assistkick-product-system/packages/backend/src/routes/video.ts +8 -8
  30. package/templates/assistkick-product-system/packages/backend/src/routes/workflow_groups.ts +5 -5
  31. package/templates/assistkick-product-system/packages/backend/src/routes/workflows.ts +6 -6
  32. package/templates/assistkick-product-system/packages/backend/src/server.ts +107 -27
  33. package/templates/assistkick-product-system/packages/backend/src/services/agent_service.test.ts +105 -203
  34. package/templates/assistkick-product-system/packages/backend/src/services/agent_service.ts +76 -266
  35. package/templates/assistkick-product-system/packages/backend/src/services/chat_cli_bridge.test.ts +427 -0
  36. package/templates/assistkick-product-system/packages/backend/src/services/chat_cli_bridge.ts +345 -0
  37. package/templates/assistkick-product-system/packages/backend/src/services/chat_message_repository.test.ts +170 -0
  38. package/templates/assistkick-product-system/packages/backend/src/services/chat_message_repository.ts +106 -0
  39. package/templates/assistkick-product-system/packages/backend/src/services/chat_session_service.test.ts +217 -0
  40. package/templates/assistkick-product-system/packages/backend/src/services/chat_session_service.ts +188 -0
  41. package/templates/assistkick-product-system/packages/backend/src/services/chat_ws_handler.test.ts +1243 -0
  42. package/templates/assistkick-product-system/packages/backend/src/services/chat_ws_handler.ts +894 -0
  43. package/templates/assistkick-product-system/packages/backend/src/services/coherence-review.ts +3 -3
  44. package/templates/assistkick-product-system/packages/backend/src/services/dev_command_detector.test.ts +85 -0
  45. package/templates/assistkick-product-system/packages/backend/src/services/dev_command_detector.ts +54 -0
  46. package/templates/assistkick-product-system/packages/backend/src/services/email_service.ts +13 -10
  47. package/templates/assistkick-product-system/packages/backend/src/services/init.ts +11 -3
  48. package/templates/assistkick-product-system/packages/backend/src/services/invitation_service.ts +1 -1
  49. package/templates/assistkick-product-system/packages/backend/src/services/password_reset_service.ts +1 -1
  50. package/templates/assistkick-product-system/packages/backend/src/services/permission_service.test.ts +243 -0
  51. package/templates/assistkick-product-system/packages/backend/src/services/permission_service.ts +259 -0
  52. package/templates/assistkick-product-system/packages/backend/src/services/preview_server_manager.test.ts +172 -0
  53. package/templates/assistkick-product-system/packages/backend/src/services/preview_server_manager.ts +225 -0
  54. package/templates/assistkick-product-system/packages/backend/src/services/project_service.test.ts +29 -0
  55. package/templates/assistkick-product-system/packages/backend/src/services/project_service.ts +17 -0
  56. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +255 -0
  57. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +300 -25
  58. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +44 -0
  59. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.ts +62 -7
  60. package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.test.ts +77 -6
  61. package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.ts +129 -8
  62. package/templates/assistkick-product-system/packages/backend/src/services/terminal_ws_handler.ts +2 -1
  63. package/templates/assistkick-product-system/packages/backend/src/services/title_generator_service.test.ts +45 -0
  64. package/templates/assistkick-product-system/packages/backend/src/services/title_generator_service.ts +157 -0
  65. package/templates/assistkick-product-system/packages/backend/src/services/tts_service.ts +4 -3
  66. package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.ts +3 -3
  67. package/templates/assistkick-product-system/packages/frontend/package.json +5 -0
  68. package/templates/assistkick-product-system/packages/frontend/src/App.tsx +2 -0
  69. package/templates/assistkick-product-system/packages/frontend/src/api/client.ts +336 -5
  70. package/templates/assistkick-product-system/packages/frontend/src/components/AgentsView.tsx +192 -12
  71. package/templates/assistkick-product-system/packages/frontend/src/components/AttachmentPreviewList.tsx +98 -0
  72. package/templates/assistkick-product-system/packages/frontend/src/components/AutocompleteDropdown.tsx +65 -0
  73. package/templates/assistkick-product-system/packages/frontend/src/components/ChatAttachButton.tsx +56 -0
  74. package/templates/assistkick-product-system/packages/frontend/src/components/ChatDropZone.tsx +80 -0
  75. package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageBubble.tsx +155 -0
  76. package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageContent.tsx +182 -0
  77. package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageInput.tsx +233 -0
  78. package/templates/assistkick-product-system/packages/frontend/src/components/ChatSessionSidebar.tsx +218 -0
  79. package/templates/assistkick-product-system/packages/frontend/src/components/ChatStopButton.tsx +32 -0
  80. package/templates/assistkick-product-system/packages/frontend/src/components/ChatTodoSidebar.tsx +113 -0
  81. package/templates/assistkick-product-system/packages/frontend/src/components/ChatView.tsx +842 -0
  82. package/templates/assistkick-product-system/packages/frontend/src/components/CommitMessageModal.tsx +82 -0
  83. package/templates/assistkick-product-system/packages/frontend/src/components/DiagramOverlay.tsx +160 -0
  84. package/templates/assistkick-product-system/packages/frontend/src/components/EditorTabBar.tsx +5 -5
  85. package/templates/assistkick-product-system/packages/frontend/src/components/FileTree.tsx +9 -10
  86. package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeInlineInput.tsx +5 -5
  87. package/templates/assistkick-product-system/packages/frontend/src/components/FilesView.tsx +112 -41
  88. package/templates/assistkick-product-system/packages/frontend/src/components/GraphLegend.tsx +2 -2
  89. package/templates/assistkick-product-system/packages/frontend/src/components/HighlightedText.tsx +87 -0
  90. package/templates/assistkick-product-system/packages/frontend/src/components/ImageLightbox.tsx +192 -0
  91. package/templates/assistkick-product-system/packages/frontend/src/components/KanbanView.tsx +2 -2
  92. package/templates/assistkick-product-system/packages/frontend/src/components/MentionPill.tsx +33 -0
  93. package/templates/assistkick-product-system/packages/frontend/src/components/MermaidBlock.tsx +148 -0
  94. package/templates/assistkick-product-system/packages/frontend/src/components/PermissionDialog.tsx +91 -0
  95. package/templates/assistkick-product-system/packages/frontend/src/components/PermissionModeSelector.tsx +229 -0
  96. package/templates/assistkick-product-system/packages/frontend/src/components/ProjectSelector.tsx +249 -83
  97. package/templates/assistkick-product-system/packages/frontend/src/components/QueuedMessageBubble.tsx +38 -0
  98. package/templates/assistkick-product-system/packages/frontend/src/components/SidePanel.tsx +212 -117
  99. package/templates/assistkick-product-system/packages/frontend/src/components/SystemPromptAccordion.tsx +48 -0
  100. package/templates/assistkick-product-system/packages/frontend/src/components/TaskIcon.tsx +11 -0
  101. package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +25 -9
  102. package/templates/assistkick-product-system/packages/frontend/src/components/ToolDiffView.tsx +114 -0
  103. package/templates/assistkick-product-system/packages/frontend/src/components/ToolResultCard.tsx +87 -0
  104. package/templates/assistkick-product-system/packages/frontend/src/components/ToolUseCard.tsx +149 -0
  105. package/templates/assistkick-product-system/packages/frontend/src/components/Toolbar.tsx +25 -8
  106. package/templates/assistkick-product-system/packages/frontend/src/components/UnifiedGitWidget.tsx +722 -0
  107. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GroupNode.tsx +2 -0
  108. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/NodePalette.tsx +2 -1
  109. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/ProgrammableNode.tsx +178 -0
  110. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowCanvas.tsx +3 -0
  111. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowMonitorModal.tsx +103 -9
  112. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/monitor_nodes.tsx +26 -2
  113. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.ts +42 -1
  114. package/templates/assistkick-product-system/packages/frontend/src/hooks/useDocumentTitle.ts +11 -0
  115. package/templates/assistkick-product-system/packages/frontend/src/hooks/useProjects.ts +1 -0
  116. package/templates/assistkick-product-system/packages/frontend/src/hooks/use_chat_stream.ts +826 -0
  117. package/templates/assistkick-product-system/packages/frontend/src/hooks/use_file_tree_cache.ts +69 -0
  118. package/templates/assistkick-product-system/packages/frontend/src/hooks/use_mention_autocomplete.ts +284 -0
  119. package/templates/assistkick-product-system/packages/frontend/src/lib/attachment_manager.test.ts +183 -0
  120. package/templates/assistkick-product-system/packages/frontend/src/lib/attachment_manager.ts +150 -0
  121. package/templates/assistkick-product-system/packages/frontend/src/lib/chat_message_helpers.test.ts +305 -0
  122. package/templates/assistkick-product-system/packages/frontend/src/lib/chat_message_helpers.ts +113 -0
  123. package/templates/assistkick-product-system/packages/frontend/src/lib/context_usage_helpers.test.ts +157 -0
  124. package/templates/assistkick-product-system/packages/frontend/src/lib/context_usage_helpers.ts +95 -0
  125. package/templates/assistkick-product-system/packages/frontend/src/lib/mermaid_helpers.test.ts +65 -0
  126. package/templates/assistkick-product-system/packages/frontend/src/lib/mermaid_helpers.ts +110 -0
  127. package/templates/assistkick-product-system/packages/frontend/src/lib/message_queue.ts +66 -0
  128. package/templates/assistkick-product-system/packages/frontend/src/lib/tool_use_summary.test.ts +124 -0
  129. package/templates/assistkick-product-system/packages/frontend/src/lib/tool_use_summary.ts +112 -0
  130. package/templates/assistkick-product-system/packages/frontend/src/routes/AgentsRoute.tsx +2 -0
  131. package/templates/assistkick-product-system/packages/frontend/src/routes/ChatRoute.tsx +8 -0
  132. package/templates/assistkick-product-system/packages/frontend/src/routes/CoherenceRoute.tsx +2 -0
  133. package/templates/assistkick-product-system/packages/frontend/src/routes/DashboardLayout.tsx +0 -4
  134. package/templates/assistkick-product-system/packages/frontend/src/routes/DesignSystemRoute.tsx +2 -0
  135. package/templates/assistkick-product-system/packages/frontend/src/routes/FilesRoute.tsx +2 -0
  136. package/templates/assistkick-product-system/packages/frontend/src/routes/GraphRoute.tsx +2 -0
  137. package/templates/assistkick-product-system/packages/frontend/src/routes/KanbanRoute.tsx +2 -0
  138. package/templates/assistkick-product-system/packages/frontend/src/routes/TerminalRoute.tsx +2 -0
  139. package/templates/assistkick-product-system/packages/frontend/src/routes/UsersRoute.tsx +2 -0
  140. package/templates/assistkick-product-system/packages/frontend/src/routes/VideographyRoute.tsx +2 -0
  141. package/templates/assistkick-product-system/packages/frontend/src/routes/WorkflowsRoute.tsx +2 -0
  142. package/templates/assistkick-product-system/packages/frontend/src/routes/accept_invitation.tsx +2 -0
  143. package/templates/assistkick-product-system/packages/frontend/src/routes/forgot_password.tsx +2 -0
  144. package/templates/assistkick-product-system/packages/frontend/src/routes/login.tsx +2 -0
  145. package/templates/assistkick-product-system/packages/frontend/src/routes/register.tsx +2 -0
  146. package/templates/assistkick-product-system/packages/frontend/src/routes/reset_password.tsx +2 -0
  147. package/templates/assistkick-product-system/packages/frontend/src/stores/useAttachmentStore.ts +66 -0
  148. package/templates/assistkick-product-system/packages/frontend/src/stores/useChatSessionStore.ts +107 -0
  149. package/templates/assistkick-product-system/packages/frontend/src/stores/useMessageQueueStore.ts +110 -0
  150. package/templates/assistkick-product-system/packages/frontend/src/stores/usePreviewStore.ts +78 -0
  151. package/templates/assistkick-product-system/packages/frontend/src/stores/useProjectStore.ts +7 -0
  152. package/templates/assistkick-product-system/packages/frontend/src/stores/useSidePanelStore.ts +6 -1
  153. package/templates/assistkick-product-system/packages/frontend/src/styles/index.css +30 -357
  154. package/templates/assistkick-product-system/packages/frontend/src/utils/parse_node_markdown.test.ts +115 -0
  155. package/templates/assistkick-product-system/packages/frontend/src/utils/parse_node_markdown.ts +91 -0
  156. package/templates/assistkick-product-system/packages/frontend/src/utils/preview_utils.test.ts +30 -0
  157. package/templates/assistkick-product-system/packages/frontend/src/utils/preview_utils.ts +3 -0
  158. package/templates/assistkick-product-system/packages/shared/db/migrate.ts +82 -0
  159. package/templates/assistkick-product-system/packages/shared/db/migrations/0000_outgoing_ultron.sql +277 -0
  160. package/templates/assistkick-product-system/packages/shared/db/migrations/0015_magenta_jazinda.sql +1 -0
  161. package/templates/assistkick-product-system/packages/shared/db/migrations/0016_giant_xorn.sql +1 -0
  162. package/templates/assistkick-product-system/packages/shared/db/migrations/0017_sloppy_mentor.sql +6 -0
  163. package/templates/assistkick-product-system/packages/shared/db/migrations/0018_vengeful_kabuki.sql +9 -0
  164. package/templates/assistkick-product-system/packages/shared/db/migrations/0019_careful_sentinels.sql +8 -0
  165. package/templates/assistkick-product-system/packages/shared/db/migrations/0020_clever_spot.sql +27 -0
  166. package/templates/assistkick-product-system/packages/shared/db/migrations/0021_graceful_hex.sql +1 -0
  167. package/templates/assistkick-product-system/packages/shared/db/migrations/0022_short_kingpin.sql +1 -0
  168. package/templates/assistkick-product-system/packages/shared/db/migrations/0023_ambiguous_sharon_carter.sql +1 -0
  169. package/templates/assistkick-product-system/packages/shared/db/migrations/0024_fat_unus.sql +1 -0
  170. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0000_snapshot.json +972 -22
  171. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0015_snapshot.json +1552 -0
  172. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0016_snapshot.json +1560 -0
  173. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0017_snapshot.json +1598 -0
  174. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0018_snapshot.json +1657 -0
  175. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0019_snapshot.json +1709 -0
  176. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0020_snapshot.json +1733 -0
  177. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0021_snapshot.json +1740 -0
  178. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0022_snapshot.json +1755 -0
  179. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0023_snapshot.json +1762 -0
  180. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0024_snapshot.json +1769 -0
  181. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +2 -100
  182. package/templates/assistkick-product-system/packages/shared/db/schema.ts +40 -1
  183. package/templates/assistkick-product-system/packages/shared/lib/claude-service.test.ts +236 -0
  184. package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +46 -5
  185. package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +65 -39
  186. package/templates/assistkick-product-system/packages/shared/lib/programmable_node_executor.test.ts +173 -0
  187. package/templates/assistkick-product-system/packages/shared/lib/programmable_node_executor.ts +213 -0
  188. package/templates/assistkick-product-system/packages/shared/lib/validator.test.ts +70 -0
  189. package/templates/assistkick-product-system/packages/shared/lib/validator.ts +17 -1
  190. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +803 -27
  191. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +502 -68
  192. package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +4 -4
  193. package/templates/assistkick-product-system/packages/shared/package.json +2 -1
  194. package/templates/assistkick-product-system/packages/shared/test_fixtures/hanging_stream.mjs +46 -0
  195. package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +44 -0
  196. package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +7 -0
  197. package/templates/assistkick-product-system/packages/shared/tools/remove_node.ts +2 -1
  198. package/templates/assistkick-product-system/packages/shared/tools/resolve_question.ts +2 -1
  199. package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -1
  200. package/templates/assistkick-product-system/tests/message_queue.test.ts +178 -0
  201. package/templates/assistkick-product-system/tests/message_queue_per_session.test.ts +143 -0
  202. package/templates/skills/assistkick-bootstrap/SKILL.md +26 -26
  203. package/templates/skills/assistkick-code-reviewer/SKILL.md +45 -46
  204. package/templates/skills/assistkick-db-explorer/SKILL.md +13 -13
  205. package/templates/skills/assistkick-debugger/SKILL.md +23 -23
  206. package/templates/skills/assistkick-developer/SKILL.md +59 -63
  207. package/templates/skills/assistkick-interview/SKILL.md +26 -26
  208. package/templates/skills/assistkick-video-composition-agent/SKILL.md +231 -0
  209. package/templates/skills/assistkick-video-script-writer/SKILL.md +136 -0
@@ -0,0 +1,218 @@
1
+ /**
2
+ * ChatSessionSidebar — session list for Chat v2, mirroring the terminal sidebar pattern.
3
+ * Displays all chat sessions for the current project, allows creating new sessions,
4
+ * renaming, and deleting existing ones.
5
+ */
6
+
7
+ import React, { useEffect, useCallback, useState, useRef } from 'react';
8
+ import { useChatSessionStore } from '../stores/useChatSessionStore';
9
+ import type { ChatSession } from '../stores/useChatSessionStore';
10
+ import { useProjectStore } from '../stores/useProjectStore';
11
+ import { Button } from './ds/Button';
12
+ import { IconButton } from './ds/IconButton';
13
+ import { X, Plus, Pencil, Check } from 'lucide-react';
14
+
15
+ interface ChatSessionSidebarProps {
16
+ visible: boolean;
17
+ onSelectSession: (session: ChatSession) => void;
18
+ onNewSessionCreated?: (session: ChatSession) => void;
19
+ }
20
+
21
+ export function ChatSessionSidebar({ visible, onSelectSession, onNewSessionCreated }: ChatSessionSidebarProps) {
22
+ const sessions = useChatSessionStore((s) => s.sessions);
23
+ const activeSessionId = useChatSessionStore((s) => s.activeSessionId);
24
+ const loading = useChatSessionStore((s) => s.loading);
25
+ const fetchSessions = useChatSessionStore((s) => s.fetchSessions);
26
+ const selectSession = useChatSessionStore((s) => s.selectSession);
27
+ const createSession = useChatSessionStore((s) => s.createSession);
28
+ const renameSession = useChatSessionStore((s) => s.renameSession);
29
+ const deleteSession = useChatSessionStore((s) => s.deleteSession);
30
+
31
+ const selectedProjectId = useProjectStore((s) => s.selectedProjectId);
32
+
33
+ const [creating, setCreating] = useState(false);
34
+ const [editingId, setEditingId] = useState<string | null>(null);
35
+ const [editName, setEditName] = useState('');
36
+ const editInputRef = useRef<HTMLInputElement>(null);
37
+
38
+ // Load sessions when visible and project changes
39
+ useEffect(() => {
40
+ if (visible && selectedProjectId) {
41
+ fetchSessions(selectedProjectId);
42
+ }
43
+ }, [visible, selectedProjectId, fetchSessions]);
44
+
45
+ // Focus the edit input when entering rename mode
46
+ useEffect(() => {
47
+ if (editingId && editInputRef.current) {
48
+ editInputRef.current.focus();
49
+ editInputRef.current.select();
50
+ }
51
+ }, [editingId]);
52
+
53
+ const handleSelectSession = useCallback(
54
+ (session: ChatSession) => {
55
+ selectSession(session.id);
56
+ onSelectSession(session);
57
+ },
58
+ [selectSession, onSelectSession],
59
+ );
60
+
61
+ const handleCreateSession = useCallback(async () => {
62
+ if (!selectedProjectId || creating) return;
63
+ setCreating(true);
64
+ try {
65
+ const session = await createSession(selectedProjectId);
66
+ if (onNewSessionCreated) {
67
+ onNewSessionCreated(session);
68
+ } else {
69
+ onSelectSession(session);
70
+ }
71
+ } catch {
72
+ // silently ignore
73
+ } finally {
74
+ setCreating(false);
75
+ }
76
+ }, [selectedProjectId, creating, createSession, onSelectSession, onNewSessionCreated]);
77
+
78
+ const handleDeleteSession = useCallback(
79
+ async (sessionId: string, e: React.MouseEvent) => {
80
+ e.stopPropagation();
81
+ if (!selectedProjectId) return;
82
+ try {
83
+ await deleteSession(sessionId, selectedProjectId);
84
+ } catch {
85
+ // silently ignore
86
+ }
87
+ },
88
+ [selectedProjectId, deleteSession],
89
+ );
90
+
91
+ const handleStartRename = useCallback(
92
+ (session: ChatSession, e: React.MouseEvent) => {
93
+ e.stopPropagation();
94
+ setEditingId(session.id);
95
+ setEditName(session.name);
96
+ },
97
+ [],
98
+ );
99
+
100
+ const handleConfirmRename = useCallback(
101
+ async (sessionId: string) => {
102
+ const trimmed = editName.trim();
103
+ if (trimmed) {
104
+ try {
105
+ await renameSession(sessionId, trimmed);
106
+ } catch {
107
+ // silently ignore
108
+ }
109
+ }
110
+ setEditingId(null);
111
+ setEditName('');
112
+ },
113
+ [editName, renameSession],
114
+ );
115
+
116
+ const handleRenameKeyDown = useCallback(
117
+ (sessionId: string, e: React.KeyboardEvent) => {
118
+ if (e.key === 'Enter') {
119
+ handleConfirmRename(sessionId);
120
+ } else if (e.key === 'Escape') {
121
+ setEditingId(null);
122
+ setEditName('');
123
+ }
124
+ },
125
+ [handleConfirmRename],
126
+ );
127
+
128
+ return (
129
+ <div className="flex flex-col w-[280px] min-w-[280px] border-r border-edge bg-surface-alt overflow-hidden">
130
+ <div className="px-3 py-2.5 text-[11px] font-mono uppercase tracking-widest text-content-muted border-b border-edge shrink-0">
131
+ Chat Sessions
132
+ </div>
133
+ <div className="flex-1 overflow-y-auto">
134
+ {!loading && sessions.length === 0 && (
135
+ <div className="px-3 py-4 text-xs text-content-muted font-mono">No sessions yet</div>
136
+ )}
137
+ {sessions.map((session) => (
138
+ <div
139
+ key={session.id}
140
+ className={`flex flex-col px-2.5 py-2 cursor-pointer border-b border-edge relative hover:bg-tab-hover${
141
+ session.id === activeSessionId
142
+ ? ' bg-tab-active border-l-2 border-l-accent pl-2'
143
+ : ''
144
+ }`}
145
+ onClick={() => handleSelectSession(session)}
146
+ >
147
+ {editingId === session.id ? (
148
+ <div className="flex items-center gap-1 pr-5">
149
+ <input
150
+ ref={editInputRef}
151
+ type="text"
152
+ value={editName}
153
+ onChange={(e) => setEditName(e.target.value)}
154
+ onKeyDown={(e) => handleRenameKeyDown(session.id, e)}
155
+ onBlur={() => handleConfirmRename(session.id)}
156
+ className="flex-1 min-w-0 bg-surface border border-edge rounded px-1.5 py-0.5 text-xs font-mono text-content outline-none focus:border-accent"
157
+ onClick={(e) => e.stopPropagation()}
158
+ />
159
+ <IconButton
160
+ label="Confirm rename"
161
+ variant="accent"
162
+ size="sm"
163
+ onClick={(e) => {
164
+ e.stopPropagation();
165
+ handleConfirmRename(session.id);
166
+ }}
167
+ >
168
+ <Check size={10} strokeWidth={2} />
169
+ </IconButton>
170
+ </div>
171
+ ) : (
172
+ <>
173
+ <div className="text-xs font-mono text-content whitespace-nowrap overflow-hidden text-ellipsis pr-12">
174
+ {session.name}
175
+ </div>
176
+ <div className="text-[11px] text-content-muted font-mono whitespace-nowrap overflow-hidden text-ellipsis pr-12 mt-0.5">
177
+ {new Date(session.updatedAt).toLocaleDateString()}
178
+ </div>
179
+ <div className="absolute top-2 right-2 flex items-center gap-0.5">
180
+ <IconButton
181
+ label="Rename session"
182
+ variant="ghost"
183
+ size="sm"
184
+ onClick={(e) => handleStartRename(session, e)}
185
+ >
186
+ <Pencil size={10} strokeWidth={2} />
187
+ </IconButton>
188
+ <IconButton
189
+ label="Delete session"
190
+ variant="danger"
191
+ size="sm"
192
+ onClick={(e) => handleDeleteSession(session.id, e)}
193
+ >
194
+ <X size={10} strokeWidth={2} />
195
+ </IconButton>
196
+ </div>
197
+ </>
198
+ )}
199
+ </div>
200
+ ))}
201
+ </div>
202
+
203
+ {/* New session button */}
204
+ <div className="flex flex-col gap-1.5 p-2.5 border-t border-edge shrink-0">
205
+ <Button
206
+ variant="primary"
207
+ size="sm"
208
+ icon={!creating ? <Plus size={12} strokeWidth={2} /> : undefined}
209
+ className="w-full"
210
+ onClick={handleCreateSession}
211
+ disabled={creating || !selectedProjectId}
212
+ >
213
+ {creating ? '...' : 'New Chat'}
214
+ </Button>
215
+ </div>
216
+ </div>
217
+ );
218
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * ChatStopButton — shown while Claude is actively streaming a response.
3
+ * Clicking it sends a stop_stream WebSocket message that kills the CLI subprocess.
4
+ * The partial response and triggering user message are discarded (handled by useChatStream).
5
+ */
6
+
7
+ import { Square } from 'lucide-react';
8
+ import { Button } from './ds/Button';
9
+
10
+ interface ChatStopButtonProps {
11
+ /** Whether Claude is currently streaming a response */
12
+ streaming: boolean;
13
+ /** Callback to send the stop_stream message */
14
+ onStop: () => void;
15
+ }
16
+
17
+ export function ChatStopButton({ streaming, onStop }: ChatStopButtonProps) {
18
+ if (!streaming) return null;
19
+
20
+ return (
21
+ <Button
22
+ variant="danger"
23
+ size="sm"
24
+ icon={<Square size={10} strokeWidth={2.5} fill="currentColor" />}
25
+ onClick={onStop}
26
+ aria-label="Stop response"
27
+ title="Stop response — discards partial reply and restores your message"
28
+ >
29
+ Stop
30
+ </Button>
31
+ );
32
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * ChatTodoSidebar — displays the current task list extracted from
3
+ * TodoWrite tool_use blocks in the chat stream. Shown as a sidebar
4
+ * panel beside the chat messages area.
5
+ */
6
+
7
+ import { useMemo } from 'react';
8
+ import { CheckCircle2, Circle, Loader2 } from 'lucide-react';
9
+ import type { ChatMessage } from '../hooks/use_chat_stream';
10
+
11
+ interface TodoItem {
12
+ content: string;
13
+ status: 'pending' | 'in_progress' | 'completed';
14
+ activeForm: string;
15
+ }
16
+
17
+ interface ChatTodoSidebarProps {
18
+ messages: ChatMessage[];
19
+ }
20
+
21
+ /**
22
+ * Extract the latest TodoWrite list from the chat messages.
23
+ * Scans all assistant messages in reverse to find the most recent
24
+ * TodoWrite tool_use block with a valid todos array.
25
+ */
26
+ const extractTodos = (messages: ChatMessage[]): TodoItem[] | null => {
27
+ for (let i = messages.length - 1; i >= 0; i--) {
28
+ const msg = messages[i];
29
+ if (msg.role !== 'assistant') continue;
30
+
31
+ // Scan content blocks in reverse within the message
32
+ for (let j = msg.content.length - 1; j >= 0; j--) {
33
+ const block = msg.content[j];
34
+ if (block.type === 'tool_use' && block.name === 'TodoWrite') {
35
+ const todos = block.input?.todos;
36
+ if (Array.isArray(todos) && todos.length > 0) {
37
+ return todos as TodoItem[];
38
+ }
39
+ }
40
+ }
41
+ }
42
+ return null;
43
+ };
44
+
45
+ const statusIcon = (status: TodoItem['status']) => {
46
+ switch (status) {
47
+ case 'completed':
48
+ return <CheckCircle2 size={14} className="text-green-400 shrink-0" />;
49
+ case 'in_progress':
50
+ return <Loader2 size={14} className="text-accent shrink-0 animate-spin" />;
51
+ case 'pending':
52
+ default:
53
+ return <Circle size={14} className="text-content-muted shrink-0" />;
54
+ }
55
+ };
56
+
57
+ export function ChatTodoSidebar({ messages }: ChatTodoSidebarProps) {
58
+ const todos = useMemo(() => extractTodos(messages), [messages]);
59
+
60
+ if (!todos || todos.length === 0) return null;
61
+
62
+ const completed = todos.filter(t => t.status === 'completed').length;
63
+ const total = todos.length;
64
+ const progressPct = total > 0 ? Math.round((completed / total) * 100) : 0;
65
+
66
+ return (
67
+ <div className="w-[280px] shrink-0 h-full flex flex-col border-l border-edge bg-surface overflow-hidden">
68
+ {/* Header */}
69
+ <div className="px-3 py-2 border-b border-edge shrink-0">
70
+ <div className="flex items-center justify-between">
71
+ <span className="text-[12px] font-mono font-medium text-content">Tasks</span>
72
+ <span className="text-[11px] font-mono text-content-muted">
73
+ {completed}/{total}
74
+ </span>
75
+ </div>
76
+ {/* Progress bar */}
77
+ <div className="mt-1.5 h-1 bg-edge rounded-full overflow-hidden">
78
+ <div
79
+ className="h-full bg-green-400 rounded-full transition-all duration-300"
80
+ style={{ width: `${progressPct}%` }}
81
+ />
82
+ </div>
83
+ </div>
84
+
85
+ {/* Todo list */}
86
+ <div className="flex-1 overflow-y-auto px-2 py-2 space-y-0.5">
87
+ {todos.map((todo, idx) => (
88
+ <div
89
+ key={idx}
90
+ className={`flex items-start gap-2 px-2 py-1.5 rounded-md transition-colors ${
91
+ todo.status === 'in_progress'
92
+ ? 'bg-accent/10'
93
+ : todo.status === 'completed'
94
+ ? 'opacity-60'
95
+ : ''
96
+ }`}
97
+ >
98
+ <div className="mt-0.5">{statusIcon(todo.status)}</div>
99
+ <span className={`text-[12px] font-mono leading-tight ${
100
+ todo.status === 'completed'
101
+ ? 'text-content-muted line-through'
102
+ : todo.status === 'in_progress'
103
+ ? 'text-content'
104
+ : 'text-content-secondary'
105
+ }`}>
106
+ {todo.status === 'in_progress' ? todo.activeForm : todo.content}
107
+ </span>
108
+ </div>
109
+ ))}
110
+ </div>
111
+ </div>
112
+ );
113
+ }