@assistkick/create 1.9.0 → 1.11.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.
- package/dist/src/scaffolder.d.ts +12 -1
- package/dist/src/scaffolder.js +40 -3
- package/dist/src/scaffolder.js.map +1 -1
- package/package.json +1 -1
- package/templates/assistkick-product-system/package.json +1 -1
- package/templates/assistkick-product-system/packages/backend/package.json +1 -0
- package/templates/assistkick-product-system/packages/backend/src/mcp/permission_mcp_server.ts +196 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/agents.ts +31 -7
- package/templates/assistkick-product-system/packages/backend/src/routes/auth.ts +15 -12
- package/templates/assistkick-product-system/packages/backend/src/routes/chat_files.test.ts +95 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/chat_files.ts +97 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/chat_permission.ts +94 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/chat_sessions.ts +189 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/chat_upload.test.ts +131 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/chat_upload.ts +94 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/files.test.ts +12 -3
- package/templates/assistkick-product-system/packages/backend/src/routes/files.ts +2 -2
- package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +391 -23
- package/templates/assistkick-product-system/packages/backend/src/routes/git_branches.test.ts +306 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/git_connect.test.ts +133 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +66 -9
- package/templates/assistkick-product-system/packages/backend/src/routes/preview.ts +204 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/projects.test.ts +205 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/projects.ts +37 -9
- package/templates/assistkick-product-system/packages/backend/src/routes/skills.test.ts +139 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/skills.ts +95 -0
- package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +5 -4
- package/templates/assistkick-product-system/packages/backend/src/routes/users.ts +4 -4
- package/templates/assistkick-product-system/packages/backend/src/routes/video.ts +8 -8
- package/templates/assistkick-product-system/packages/backend/src/routes/workflow_groups.ts +5 -5
- package/templates/assistkick-product-system/packages/backend/src/routes/workflows.ts +6 -6
- package/templates/assistkick-product-system/packages/backend/src/server.ts +107 -27
- package/templates/assistkick-product-system/packages/backend/src/services/agent_service.test.ts +105 -203
- package/templates/assistkick-product-system/packages/backend/src/services/agent_service.ts +76 -266
- package/templates/assistkick-product-system/packages/backend/src/services/chat_cli_bridge.test.ts +427 -0
- package/templates/assistkick-product-system/packages/backend/src/services/chat_cli_bridge.ts +345 -0
- package/templates/assistkick-product-system/packages/backend/src/services/chat_message_repository.test.ts +170 -0
- package/templates/assistkick-product-system/packages/backend/src/services/chat_message_repository.ts +106 -0
- package/templates/assistkick-product-system/packages/backend/src/services/chat_session_service.test.ts +217 -0
- package/templates/assistkick-product-system/packages/backend/src/services/chat_session_service.ts +188 -0
- package/templates/assistkick-product-system/packages/backend/src/services/chat_ws_handler.test.ts +1243 -0
- package/templates/assistkick-product-system/packages/backend/src/services/chat_ws_handler.ts +894 -0
- package/templates/assistkick-product-system/packages/backend/src/services/coherence-review.ts +3 -3
- package/templates/assistkick-product-system/packages/backend/src/services/dev_command_detector.test.ts +85 -0
- package/templates/assistkick-product-system/packages/backend/src/services/dev_command_detector.ts +54 -0
- package/templates/assistkick-product-system/packages/backend/src/services/email_service.ts +13 -10
- package/templates/assistkick-product-system/packages/backend/src/services/init.ts +11 -3
- package/templates/assistkick-product-system/packages/backend/src/services/invitation_service.ts +1 -1
- package/templates/assistkick-product-system/packages/backend/src/services/password_reset_service.ts +1 -1
- package/templates/assistkick-product-system/packages/backend/src/services/permission_service.test.ts +243 -0
- package/templates/assistkick-product-system/packages/backend/src/services/permission_service.ts +259 -0
- package/templates/assistkick-product-system/packages/backend/src/services/preview_server_manager.test.ts +172 -0
- package/templates/assistkick-product-system/packages/backend/src/services/preview_server_manager.ts +225 -0
- package/templates/assistkick-product-system/packages/backend/src/services/project_service.test.ts +29 -0
- package/templates/assistkick-product-system/packages/backend/src/services/project_service.ts +17 -0
- package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +255 -0
- package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +300 -25
- package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +44 -0
- package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.ts +62 -7
- package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.test.ts +77 -6
- package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.ts +149 -14
- package/templates/assistkick-product-system/packages/backend/src/services/terminal_ws_handler.ts +2 -1
- package/templates/assistkick-product-system/packages/backend/src/services/title_generator_service.test.ts +45 -0
- package/templates/assistkick-product-system/packages/backend/src/services/title_generator_service.ts +157 -0
- package/templates/assistkick-product-system/packages/backend/src/services/tts_service.ts +4 -3
- package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.ts +3 -3
- package/templates/assistkick-product-system/packages/frontend/package.json +5 -0
- package/templates/assistkick-product-system/packages/frontend/src/App.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/api/client.ts +336 -5
- package/templates/assistkick-product-system/packages/frontend/src/components/AgentsView.tsx +192 -12
- package/templates/assistkick-product-system/packages/frontend/src/components/AttachmentPreviewList.tsx +98 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/AutocompleteDropdown.tsx +65 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatAttachButton.tsx +56 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatDropZone.tsx +80 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageBubble.tsx +155 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageContent.tsx +182 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageInput.tsx +233 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatSessionSidebar.tsx +218 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatStopButton.tsx +32 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatTodoSidebar.tsx +113 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ChatView.tsx +842 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/CommitMessageModal.tsx +82 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/DiagramOverlay.tsx +160 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/EditorTabBar.tsx +5 -5
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTree.tsx +9 -10
- package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeInlineInput.tsx +5 -5
- package/templates/assistkick-product-system/packages/frontend/src/components/FilesView.tsx +112 -41
- package/templates/assistkick-product-system/packages/frontend/src/components/GraphLegend.tsx +2 -2
- package/templates/assistkick-product-system/packages/frontend/src/components/HighlightedText.tsx +87 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ImageLightbox.tsx +192 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/KanbanView.tsx +2 -2
- package/templates/assistkick-product-system/packages/frontend/src/components/MentionPill.tsx +33 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/MermaidBlock.tsx +148 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/PermissionDialog.tsx +91 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/PermissionModeSelector.tsx +229 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ProjectSelector.tsx +249 -83
- package/templates/assistkick-product-system/packages/frontend/src/components/QueuedMessageBubble.tsx +38 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/SidePanel.tsx +212 -117
- package/templates/assistkick-product-system/packages/frontend/src/components/SystemPromptAccordion.tsx +48 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/TaskIcon.tsx +11 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +25 -9
- package/templates/assistkick-product-system/packages/frontend/src/components/ToolDiffView.tsx +114 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ToolResultCard.tsx +87 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/ToolUseCard.tsx +149 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/Toolbar.tsx +25 -8
- package/templates/assistkick-product-system/packages/frontend/src/components/UnifiedGitWidget.tsx +722 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GroupNode.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/NodePalette.tsx +2 -1
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/ProgrammableNode.tsx +178 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowCanvas.tsx +3 -0
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowMonitorModal.tsx +103 -9
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/monitor_nodes.tsx +26 -2
- package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.ts +42 -1
- package/templates/assistkick-product-system/packages/frontend/src/hooks/useDocumentTitle.ts +11 -0
- package/templates/assistkick-product-system/packages/frontend/src/hooks/useProjects.ts +1 -0
- package/templates/assistkick-product-system/packages/frontend/src/hooks/use_chat_stream.ts +826 -0
- package/templates/assistkick-product-system/packages/frontend/src/hooks/use_file_tree_cache.ts +69 -0
- package/templates/assistkick-product-system/packages/frontend/src/hooks/use_mention_autocomplete.ts +284 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/attachment_manager.test.ts +183 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/attachment_manager.ts +150 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/chat_message_helpers.test.ts +305 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/chat_message_helpers.ts +113 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/context_usage_helpers.test.ts +157 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/context_usage_helpers.ts +95 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/mermaid_helpers.test.ts +65 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/mermaid_helpers.ts +110 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/message_queue.ts +66 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/tool_use_summary.test.ts +124 -0
- package/templates/assistkick-product-system/packages/frontend/src/lib/tool_use_summary.ts +112 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/AgentsRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/ChatRoute.tsx +8 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/CoherenceRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/DashboardLayout.tsx +0 -4
- package/templates/assistkick-product-system/packages/frontend/src/routes/DesignSystemRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/FilesRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/GraphRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/KanbanRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/TerminalRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/UsersRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/VideographyRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/WorkflowsRoute.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/accept_invitation.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/forgot_password.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/login.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/register.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/routes/reset_password.tsx +2 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/useAttachmentStore.ts +66 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/useChatSessionStore.ts +107 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/useMessageQueueStore.ts +110 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/usePreviewStore.ts +78 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/useProjectStore.ts +7 -0
- package/templates/assistkick-product-system/packages/frontend/src/stores/useSidePanelStore.ts +6 -1
- package/templates/assistkick-product-system/packages/frontend/src/styles/index.css +30 -357
- package/templates/assistkick-product-system/packages/frontend/src/utils/parse_node_markdown.test.ts +115 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/parse_node_markdown.ts +91 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/preview_utils.test.ts +30 -0
- package/templates/assistkick-product-system/packages/frontend/src/utils/preview_utils.ts +3 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0015_magenta_jazinda.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0016_giant_xorn.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0017_sloppy_mentor.sql +6 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0018_vengeful_kabuki.sql +9 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0019_careful_sentinels.sql +8 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0020_clever_spot.sql +27 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0021_graceful_hex.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0022_short_kingpin.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0023_ambiguous_sharon_carter.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/0024_fat_unus.sql +1 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0015_snapshot.json +1552 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0016_snapshot.json +1560 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0017_snapshot.json +1598 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0018_snapshot.json +1657 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0019_snapshot.json +1709 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0020_snapshot.json +1733 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0021_snapshot.json +1740 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0022_snapshot.json +1755 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0023_snapshot.json +1762 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0024_snapshot.json +1769 -0
- package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +70 -0
- package/templates/assistkick-product-system/packages/shared/db/schema.ts +40 -1
- package/templates/assistkick-product-system/packages/shared/lib/claude-service.test.ts +236 -0
- package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +46 -5
- package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +65 -39
- package/templates/assistkick-product-system/packages/shared/lib/programmable_node_executor.test.ts +173 -0
- package/templates/assistkick-product-system/packages/shared/lib/programmable_node_executor.ts +213 -0
- package/templates/assistkick-product-system/packages/shared/lib/validator.test.ts +70 -0
- package/templates/assistkick-product-system/packages/shared/lib/validator.ts +17 -1
- package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +803 -27
- package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +502 -68
- package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +4 -4
- package/templates/assistkick-product-system/packages/shared/package.json +2 -1
- package/templates/assistkick-product-system/packages/shared/test_fixtures/hanging_stream.mjs +46 -0
- package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +44 -0
- package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +7 -0
- package/templates/assistkick-product-system/packages/shared/tools/remove_node.ts +2 -1
- package/templates/assistkick-product-system/packages/shared/tools/resolve_question.ts +2 -1
- package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -1
- package/templates/assistkick-product-system/tests/message_queue.test.ts +178 -0
- package/templates/assistkick-product-system/tests/message_queue_per_session.test.ts +143 -0
- package/templates/skills/assistkick-bootstrap/SKILL.md +26 -26
- package/templates/skills/assistkick-code-reviewer/SKILL.md +45 -46
- package/templates/skills/assistkick-db-explorer/SKILL.md +13 -13
- package/templates/skills/assistkick-debugger/SKILL.md +23 -23
- package/templates/skills/assistkick-developer/SKILL.md +59 -63
- package/templates/skills/assistkick-interview/SKILL.md +26 -26
- package/templates/skills/assistkick-video-composition-agent/SKILL.md +231 -0
- package/templates/skills/assistkick-video-script-writer/SKILL.md +136 -0
|
@@ -1,31 +1,39 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { marked } from 'marked';
|
|
2
|
+
import {
|
|
3
|
+
ArrowRight, ArrowLeft, FileText, FolderPlus, Trash2, Lightbulb,
|
|
4
|
+
GitBranch, Activity, ListTodo, AlignLeft, ClipboardCheck,
|
|
5
|
+
HelpCircle, CheckSquare, StickyNote,
|
|
6
|
+
} from 'lucide-react';
|
|
3
7
|
import { useSidePanelStore } from '../stores/useSidePanelStore';
|
|
4
8
|
import { useGraphStore } from '../stores/useGraphStore';
|
|
5
9
|
import { useGraphUIStore } from '../stores/useGraphUIStore';
|
|
6
|
-
import {
|
|
10
|
+
import { shouldShowTaskList } from '../utils/task_status';
|
|
7
11
|
import { SideSheet } from './ds/SideSheet';
|
|
12
|
+
import { ContentCard } from './ds/ContentCard';
|
|
13
|
+
import { AccentBorderList, AccentBorderItem } from './ds/AccentBorderList';
|
|
14
|
+
import { CompletionRing } from './ds/CompletionRing';
|
|
15
|
+
import { StatusDot } from './ds/StatusDot';
|
|
16
|
+
import { TaskIcon } from './TaskIcon';
|
|
17
|
+
|
|
18
|
+
const renderMarkdownSection = (md: string): string => {
|
|
19
|
+
try {
|
|
20
|
+
return marked.parse(md) as string;
|
|
21
|
+
} catch {
|
|
22
|
+
return md;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
8
25
|
|
|
9
26
|
export function SidePanel() {
|
|
10
27
|
const {
|
|
11
|
-
isOpen, node,
|
|
12
|
-
tasks,
|
|
28
|
+
isOpen, node, parsedContent, workSummaries,
|
|
29
|
+
tasks, close,
|
|
13
30
|
} = useSidePanelStore();
|
|
14
31
|
const graphData = useGraphStore((s) => s.graphData);
|
|
15
32
|
const onEdgeClick = useGraphUIStore((s) => s.onEdgeClick);
|
|
16
33
|
|
|
17
|
-
const renderMarkdown = (md: string) => {
|
|
18
|
-
const stripped = md.replace(/^---[\s\S]*?---\n*/m, '');
|
|
19
|
-
try {
|
|
20
|
-
return marked.parse(stripped) as string;
|
|
21
|
-
} catch {
|
|
22
|
-
return stripped;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
34
|
const findEdges = (nodeId: string) => {
|
|
27
35
|
if (!graphData) return [];
|
|
28
|
-
const edges:
|
|
36
|
+
const edges: { neighborId: string; relation: string; direction: string }[] = [];
|
|
29
37
|
graphData.edges.forEach((e: any) => {
|
|
30
38
|
if (e.from === nodeId) edges.push({ neighborId: e.to, relation: e.relation, direction: 'outgoing' });
|
|
31
39
|
else if (e.to === nodeId) edges.push({ neighborId: e.from, relation: e.relation, direction: 'incoming' });
|
|
@@ -37,132 +45,219 @@ export function SidePanel() {
|
|
|
37
45
|
|
|
38
46
|
if (!node) return (
|
|
39
47
|
<SideSheet isOpen={isOpen} onClose={close} title="" zIndex={200}>
|
|
40
|
-
<div
|
|
48
|
+
<div />
|
|
41
49
|
</SideSheet>
|
|
42
50
|
);
|
|
43
51
|
|
|
44
52
|
const statusLabel = (node.status || 'draft').replace(/_/g, ' ');
|
|
45
|
-
const completeness =
|
|
53
|
+
const completeness = node.completeness || 0;
|
|
46
54
|
const typeLabel = node.type ? node.type.replace(/_/g, ' ') : '';
|
|
47
55
|
const edges = findEdges(node.id);
|
|
56
|
+
const isFeature = node.type === 'feature' || node.id?.startsWith('feat_');
|
|
48
57
|
|
|
49
58
|
return (
|
|
50
59
|
<SideSheet isOpen={isOpen} onClose={close} title={title} zIndex={200}>
|
|
51
|
-
<div className="
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<
|
|
55
|
-
<
|
|
60
|
+
<div className="flex flex-col gap-3">
|
|
61
|
+
{/* Status card */}
|
|
62
|
+
<div className="flex items-center gap-3 rounded-xl border border-edge bg-surface-alt p-3">
|
|
63
|
+
<CompletionRing pct={completeness} />
|
|
64
|
+
<div className="flex-1 min-w-0">
|
|
65
|
+
<div className="flex items-center gap-2">
|
|
66
|
+
<span className="rounded-md bg-surface-raised px-2 py-0.5 text-[11px] font-medium text-content-secondary capitalize">
|
|
67
|
+
{typeLabel}
|
|
68
|
+
</span>
|
|
69
|
+
<StatusDot status={node.status || 'draft'} />
|
|
70
|
+
<span className="text-[11px] text-content-secondary capitalize">
|
|
71
|
+
{statusLabel}
|
|
72
|
+
</span>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
56
75
|
</div>
|
|
76
|
+
|
|
77
|
+
{/* Tasks */}
|
|
57
78
|
{shouldShowTaskList(tasks) && (
|
|
58
|
-
<
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
</
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
</
|
|
79
|
+
<ContentCard
|
|
80
|
+
icon={<ListTodo size={13} />}
|
|
81
|
+
label="Tasks"
|
|
82
|
+
badge={
|
|
83
|
+
<span className="rounded-full bg-accent/15 px-2 py-0.5 text-[10px] font-semibold text-accent">
|
|
84
|
+
{tasks!.completed}/{tasks!.total}
|
|
85
|
+
</span>
|
|
86
|
+
}
|
|
87
|
+
defaultOpen
|
|
88
|
+
>
|
|
89
|
+
<div className="space-y-1.5">
|
|
90
|
+
{tasks!.items.map((task: any, idx: number) => (
|
|
91
|
+
<div key={idx} className="flex items-center gap-2">
|
|
92
|
+
<TaskIcon status={task.status} />
|
|
93
|
+
<span className={`text-[12px] ${task.status === 'completed' ? 'text-content-muted line-through' : 'text-content'}`}>
|
|
94
|
+
{task.name}
|
|
95
|
+
</span>
|
|
96
|
+
</div>
|
|
97
|
+
))}
|
|
98
|
+
</div>
|
|
99
|
+
</ContentCard>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
{/* Description */}
|
|
103
|
+
{parsedContent?.description && (
|
|
104
|
+
<ContentCard icon={<AlignLeft size={13} />} label="Description" defaultOpen>
|
|
105
|
+
<div
|
|
106
|
+
className="text-[12px] leading-relaxed text-content-secondary [&_h1]:text-[15px] [&_h1]:mt-2 [&_h1]:mb-1.5 [&_h1]:text-content [&_h2]:text-[14px] [&_h2]:mt-2 [&_h2]:mb-1 [&_h2]:text-content [&_h3]:text-[13px] [&_h3]:mt-1.5 [&_h3]:mb-[3px] [&_h3]:text-content [&_p]:my-[3px] [&_ul]:pl-[18px] [&_ul]:my-[3px] [&_li]:my-px [&_code]:bg-surface-raised [&_code]:px-1 [&_code]:py-px [&_code]:rounded-[3px] [&_code]:text-[11px] [&_blockquote]:border-l-[3px] [&_blockquote]:border-edge [&_blockquote]:pl-2.5 [&_blockquote]:text-content-secondary [&_blockquote]:my-1.5 [&_strong]:text-content [&_pre]:bg-surface-raised [&_pre]:px-2.5 [&_pre]:py-2 [&_pre]:rounded [&_pre]:overflow-x-auto [&_pre]:text-[11px] [&_pre_code]:bg-transparent [&_pre_code]:p-0"
|
|
107
|
+
dangerouslySetInnerHTML={{ __html: renderMarkdownSection(parsedContent.description) }}
|
|
108
|
+
/>
|
|
109
|
+
</ContentCard>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
{/* Acceptance Criteria */}
|
|
113
|
+
{parsedContent && parsedContent.acceptanceCriteria.length > 0 && (
|
|
114
|
+
<ContentCard
|
|
115
|
+
icon={<ClipboardCheck size={13} />}
|
|
116
|
+
label="Acceptance Criteria"
|
|
117
|
+
badge={<span className="text-[10px] text-content-muted">{parsedContent.acceptanceCriteria.length} criteria</span>}
|
|
118
|
+
>
|
|
119
|
+
<AccentBorderList>
|
|
120
|
+
{parsedContent.acceptanceCriteria.map((ac, i) => (
|
|
121
|
+
<AccentBorderItem key={i} color="accent" index={i + 1}>
|
|
122
|
+
<p className="text-[12px] leading-[1.75] text-content-secondary">{ac}</p>
|
|
123
|
+
</AccentBorderItem>
|
|
124
|
+
))}
|
|
125
|
+
</AccentBorderList>
|
|
126
|
+
</ContentCard>
|
|
79
127
|
)}
|
|
80
|
-
|
|
81
|
-
{
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
128
|
+
|
|
129
|
+
{/* Open Questions */}
|
|
130
|
+
{parsedContent && parsedContent.openQuestions.length > 0 && (
|
|
131
|
+
<ContentCard
|
|
132
|
+
icon={<HelpCircle size={13} />}
|
|
133
|
+
label="Open Questions"
|
|
134
|
+
badge={
|
|
135
|
+
<span className="rounded-full bg-accent-secondary/15 px-2 py-0.5 text-[10px] font-semibold text-accent-secondary">
|
|
136
|
+
{parsedContent.openQuestions.length}
|
|
137
|
+
</span>
|
|
138
|
+
}
|
|
139
|
+
>
|
|
140
|
+
<AccentBorderList>
|
|
141
|
+
{parsedContent.openQuestions.map((q, i) => (
|
|
142
|
+
<AccentBorderItem key={i} color="secondary" index={i + 1}>
|
|
143
|
+
<p className="text-[12px] leading-[1.75] text-content">{q}</p>
|
|
144
|
+
</AccentBorderItem>
|
|
145
|
+
))}
|
|
146
|
+
</AccentBorderList>
|
|
147
|
+
</ContentCard>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
{/* Resolved Questions */}
|
|
151
|
+
{parsedContent && parsedContent.resolvedQuestions.length > 0 && (
|
|
152
|
+
<ContentCard
|
|
153
|
+
icon={<CheckSquare size={13} />}
|
|
154
|
+
label="Resolved Questions"
|
|
155
|
+
badge={
|
|
156
|
+
<span className="rounded-full bg-accent/15 px-2 py-0.5 text-[10px] font-semibold text-accent">
|
|
157
|
+
{parsedContent.resolvedQuestions.length}
|
|
158
|
+
</span>
|
|
159
|
+
}
|
|
160
|
+
>
|
|
161
|
+
<AccentBorderList>
|
|
162
|
+
{parsedContent.resolvedQuestions.map((q, i) => (
|
|
163
|
+
<AccentBorderItem key={i} color="accent" index={i + 1}>
|
|
164
|
+
<p className="text-[12px] leading-[1.75] text-content">{q.question}</p>
|
|
165
|
+
{q.resolution && (
|
|
166
|
+
<p className="text-[12px] leading-[1.75] text-content-secondary mt-1">{q.resolution}</p>
|
|
167
|
+
)}
|
|
168
|
+
</AccentBorderItem>
|
|
169
|
+
))}
|
|
170
|
+
</AccentBorderList>
|
|
171
|
+
</ContentCard>
|
|
172
|
+
)}
|
|
173
|
+
|
|
174
|
+
{/* Notes */}
|
|
175
|
+
{parsedContent?.notes && (
|
|
176
|
+
<ContentCard icon={<StickyNote size={13} />} label="Notes">
|
|
177
|
+
<div
|
|
178
|
+
className="text-[12px] leading-relaxed text-content-secondary [&_h1]:text-[15px] [&_h1]:mt-2 [&_h1]:mb-1.5 [&_h1]:text-content [&_h2]:text-[14px] [&_h2]:mt-2 [&_h2]:mb-1 [&_h2]:text-content [&_h3]:text-[13px] [&_h3]:mt-1.5 [&_h3]:mb-[3px] [&_h3]:text-content [&_p]:my-[3px] [&_ul]:pl-[18px] [&_ul]:my-[3px] [&_li]:my-px [&_code]:bg-surface-raised [&_code]:px-1 [&_code]:py-px [&_code]:rounded-[3px] [&_code]:text-[11px] [&_blockquote]:border-l-[3px] [&_blockquote]:border-edge [&_blockquote]:pl-2.5 [&_blockquote]:text-content-secondary [&_blockquote]:my-1.5 [&_strong]:text-content [&_pre]:bg-surface-raised [&_pre]:px-2.5 [&_pre]:py-2 [&_pre]:rounded [&_pre]:overflow-x-auto [&_pre]:text-[11px] [&_pre_code]:bg-transparent [&_pre_code]:p-0"
|
|
179
|
+
dangerouslySetInnerHTML={{ __html: renderMarkdownSection(parsedContent.notes) }}
|
|
180
|
+
/>
|
|
181
|
+
</ContentCard>
|
|
182
|
+
)}
|
|
183
|
+
|
|
184
|
+
{/* Work Summary */}
|
|
185
|
+
{isFeature && workSummaries.length > 0 && (
|
|
186
|
+
<ContentCard
|
|
187
|
+
icon={<Activity size={13} />}
|
|
188
|
+
label="Work Summary"
|
|
189
|
+
badge={<span className="text-[10px] text-content-muted">{workSummaries.length} cycles</span>}
|
|
190
|
+
>
|
|
191
|
+
<AccentBorderList>
|
|
192
|
+
{workSummaries.map((ws, i) => (
|
|
193
|
+
<AccentBorderItem key={i} index={`Cycle ${ws.cycle}`}>
|
|
194
|
+
{ws.approach && (
|
|
195
|
+
<p className="text-[12px] leading-[1.75] text-content-secondary mt-1 mb-2">{ws.approach}</p>
|
|
196
|
+
)}
|
|
197
|
+
<div className="flex flex-wrap gap-1.5 mb-1.5">
|
|
198
|
+
{ws.filesCreated?.map((f, fi) => (
|
|
199
|
+
<span key={`c${fi}`} className="inline-flex items-center gap-1 rounded-md bg-accent/10 px-1.5 py-0.5 text-[10px] text-accent">
|
|
200
|
+
<FolderPlus size={10} />{f.split('/').pop()}
|
|
201
|
+
</span>
|
|
202
|
+
))}
|
|
203
|
+
{ws.filesUpdated?.map((f, fi) => (
|
|
204
|
+
<span key={`u${fi}`} className="inline-flex items-center gap-1 rounded-md bg-accent-secondary/10 px-1.5 py-0.5 text-[10px] text-accent-secondary">
|
|
205
|
+
<FileText size={10} />{f.split('/').pop()}
|
|
206
|
+
</span>
|
|
207
|
+
))}
|
|
208
|
+
{ws.filesDeleted?.map((f, fi) => (
|
|
209
|
+
<span key={`d${fi}`} className="inline-flex items-center gap-1 rounded-md bg-error/10 px-1.5 py-0.5 text-[10px] text-error">
|
|
210
|
+
<Trash2 size={10} />{f.split('/').pop()}
|
|
211
|
+
</span>
|
|
212
|
+
))}
|
|
140
213
|
</div>
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
214
|
+
{ws.decisions?.length > 0 && (
|
|
215
|
+
<div className="space-y-1">
|
|
216
|
+
{ws.decisions.map((d, di) => (
|
|
217
|
+
<div key={di} className="flex items-start gap-1.5 text-[10px] text-content-muted">
|
|
218
|
+
<Lightbulb size={10} className="mt-0.5 shrink-0 text-accent-secondary" />
|
|
219
|
+
{d}
|
|
220
|
+
</div>
|
|
221
|
+
))}
|
|
222
|
+
</div>
|
|
223
|
+
)}
|
|
224
|
+
</AccentBorderItem>
|
|
225
|
+
))}
|
|
226
|
+
</AccentBorderList>
|
|
227
|
+
</ContentCard>
|
|
145
228
|
)}
|
|
229
|
+
|
|
230
|
+
{/* Relationships */}
|
|
146
231
|
{edges.length > 0 && (
|
|
147
|
-
<div className="
|
|
148
|
-
<
|
|
149
|
-
|
|
232
|
+
<div className="rounded-xl border border-edge bg-surface-alt p-3">
|
|
233
|
+
<div className="flex items-center gap-2 mb-2">
|
|
234
|
+
<GitBranch size={13} className="text-content-muted" />
|
|
235
|
+
<span className="text-[12px] font-medium text-content">Relationships</span>
|
|
236
|
+
<span className="text-[10px] text-content-muted">{edges.length}</span>
|
|
237
|
+
</div>
|
|
238
|
+
<div className="space-y-1.5">
|
|
150
239
|
{edges.map((edge, i) => {
|
|
151
240
|
const neighborNode = graphData?.nodes.find((n: any) => n.id === edge.neighborId);
|
|
152
241
|
const name = neighborNode ? neighborNode.name : edge.neighborId;
|
|
153
|
-
const direction = edge.direction === 'outgoing' ? '\u2192' : '\u2190';
|
|
154
242
|
return (
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
243
|
+
<div key={i} className="flex items-center gap-2 rounded-lg px-2 py-1.5 hover:bg-surface-raised/50 transition-colors group">
|
|
244
|
+
{edge.direction === 'outgoing'
|
|
245
|
+
? <ArrowRight size={12} className="text-accent shrink-0" />
|
|
246
|
+
: <ArrowLeft size={12} className="text-accent-secondary shrink-0" />}
|
|
247
|
+
<span className="text-[11px] text-content-muted capitalize flex-shrink-0">
|
|
248
|
+
{edge.relation.replace(/_/g, ' ')}
|
|
249
|
+
</span>
|
|
250
|
+
<a
|
|
251
|
+
className="text-[12px] text-accent font-medium truncate group-hover:underline cursor-pointer"
|
|
252
|
+
href="#"
|
|
253
|
+
onClick={(e) => { e.preventDefault(); onEdgeClick?.(edge.neighborId); }}
|
|
254
|
+
>
|
|
159
255
|
{name}
|
|
160
256
|
</a>
|
|
161
|
-
|
|
162
|
-
</li>
|
|
257
|
+
</div>
|
|
163
258
|
);
|
|
164
259
|
})}
|
|
165
|
-
</
|
|
260
|
+
</div>
|
|
166
261
|
</div>
|
|
167
262
|
)}
|
|
168
263
|
</div>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SystemPromptAccordion — displays the composed system prompt as a collapsible
|
|
3
|
+
* accordion at the top of the chat message area.
|
|
4
|
+
*
|
|
5
|
+
* Collapsed by default with a 'System Prompt' label.
|
|
6
|
+
* Expanding reveals the full read-only system prompt text.
|
|
7
|
+
* Scrolls with messages (not pinned).
|
|
8
|
+
*
|
|
9
|
+
* Follows the design system: surface-alt background, edge borders,
|
|
10
|
+
* content-secondary text, monospace font. Consistent with ToolUseCard.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { useState } from 'react';
|
|
14
|
+
import { ChevronDown, ChevronRight, Terminal } from 'lucide-react';
|
|
15
|
+
|
|
16
|
+
interface SystemPromptAccordionProps {
|
|
17
|
+
prompt: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const SystemPromptAccordion = ({ prompt }: SystemPromptAccordionProps) => {
|
|
21
|
+
const [expanded, setExpanded] = useState(false);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="rounded-lg border border-edge bg-surface-alt overflow-hidden">
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
onClick={() => setExpanded(prev => !prev)}
|
|
28
|
+
className="flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-surface-raised/50 transition-colors cursor-pointer"
|
|
29
|
+
>
|
|
30
|
+
<Terminal size={13} className="text-content-muted shrink-0" />
|
|
31
|
+
<span className="text-[12px] font-mono text-content-secondary flex-1">
|
|
32
|
+
System Prompt
|
|
33
|
+
</span>
|
|
34
|
+
{expanded
|
|
35
|
+
? <ChevronDown size={13} className="text-content-muted shrink-0" />
|
|
36
|
+
: <ChevronRight size={13} className="text-content-muted shrink-0" />}
|
|
37
|
+
</button>
|
|
38
|
+
|
|
39
|
+
{expanded && (
|
|
40
|
+
<div className="border-t border-edge px-3 py-2">
|
|
41
|
+
<pre className="text-[12px] font-mono text-content-secondary whitespace-pre-wrap break-words m-0 max-h-[400px] overflow-y-auto">
|
|
42
|
+
{prompt}
|
|
43
|
+
</pre>
|
|
44
|
+
</div>
|
|
45
|
+
)}
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CheckCircle2, Circle, Loader2 } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
interface TaskIconProps {
|
|
4
|
+
status: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const TaskIcon = ({ status }: TaskIconProps) => {
|
|
8
|
+
if (status === 'completed') return <CheckCircle2 size={14} className="text-accent shrink-0" />;
|
|
9
|
+
if (status === 'in_progress') return <Loader2 size={14} className="text-accent-secondary shrink-0 animate-spin" />;
|
|
10
|
+
return <Circle size={14} className="text-content-muted shrink-0" />;
|
|
11
|
+
};
|
package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx
CHANGED
|
@@ -16,7 +16,7 @@ import type { Project } from '../hooks/useProjects';
|
|
|
16
16
|
import { useProjectStore } from '../stores/useProjectStore';
|
|
17
17
|
import { Button } from './ds/Button';
|
|
18
18
|
import { IconButton } from './ds/IconButton';
|
|
19
|
-
import { X,
|
|
19
|
+
import { X, RefreshCw, Sparkles, TerminalSquare } from 'lucide-react';
|
|
20
20
|
|
|
21
21
|
interface TerminalViewProps {
|
|
22
22
|
visible: boolean;
|
|
@@ -29,6 +29,7 @@ interface SessionInfo {
|
|
|
29
29
|
name: string;
|
|
30
30
|
projectId: string;
|
|
31
31
|
projectName: string;
|
|
32
|
+
sessionType: 'claude' | 'terminal';
|
|
32
33
|
state: 'suspended' | 'running';
|
|
33
34
|
createdAt: string;
|
|
34
35
|
lastUsedAt: string;
|
|
@@ -194,7 +195,7 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
|
|
|
194
195
|
connectToSession(sessionId);
|
|
195
196
|
}, [connectToSession]);
|
|
196
197
|
|
|
197
|
-
const handleCreateSession = useCallback(async () => {
|
|
198
|
+
const handleCreateSession = useCallback(async (sessionType: 'claude' | 'terminal') => {
|
|
198
199
|
const projectId = selectedProjectId || projects[0]?.id;
|
|
199
200
|
if (!projectId) return;
|
|
200
201
|
|
|
@@ -203,7 +204,7 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
|
|
|
203
204
|
|
|
204
205
|
setCreating(true);
|
|
205
206
|
try {
|
|
206
|
-
const data = await apiClient.createTerminalSession(project.id, project.name);
|
|
207
|
+
const data = await apiClient.createTerminalSession(project.id, project.name, sessionType);
|
|
207
208
|
const newSession: SessionInfo = data.session;
|
|
208
209
|
const updated = await fetchSessions();
|
|
209
210
|
const created = updated.find(s => s.id === newSession.id) || newSession;
|
|
@@ -324,6 +325,11 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
|
|
|
324
325
|
{session.state === 'suspended' && (
|
|
325
326
|
<span className="shrink-0 text-[10px] leading-none text-content-muted opacity-70" title="Suspended — will resume on connect">⏸</span>
|
|
326
327
|
)}
|
|
328
|
+
{session.sessionType === 'terminal' ? (
|
|
329
|
+
<TerminalSquare size={11} strokeWidth={2} className="shrink-0 text-content-muted" title="Plain shell" />
|
|
330
|
+
) : (
|
|
331
|
+
<Sparkles size={11} strokeWidth={2} className="shrink-0 text-accent" title="Claude session" />
|
|
332
|
+
)}
|
|
327
333
|
{session.name}
|
|
328
334
|
</div>
|
|
329
335
|
<div className="text-[11px] text-content-muted font-mono whitespace-nowrap overflow-hidden text-ellipsis pr-5 mt-0.5">{session.projectName}</div>
|
|
@@ -340,17 +346,27 @@ export function TerminalView({ visible, projects }: TerminalViewProps) {
|
|
|
340
346
|
))}
|
|
341
347
|
</div>
|
|
342
348
|
|
|
343
|
-
{/* New session — uses the project selected in the navbar */}
|
|
344
|
-
<div className="flex flex-
|
|
349
|
+
{/* New session buttons — uses the project selected in the navbar */}
|
|
350
|
+
<div className="flex flex-row gap-1.5 p-2.5 border-t border-edge shrink-0">
|
|
345
351
|
<Button
|
|
346
352
|
variant="primary"
|
|
347
353
|
size="sm"
|
|
348
|
-
icon={!creating ? <
|
|
349
|
-
className="
|
|
350
|
-
onClick={handleCreateSession}
|
|
354
|
+
icon={!creating ? <Sparkles size={12} strokeWidth={2} /> : undefined}
|
|
355
|
+
className="flex-1"
|
|
356
|
+
onClick={() => handleCreateSession('claude')}
|
|
357
|
+
disabled={creating || !selectedProjectId}
|
|
358
|
+
>
|
|
359
|
+
{creating ? '...' : 'Claude'}
|
|
360
|
+
</Button>
|
|
361
|
+
<Button
|
|
362
|
+
variant="secondary"
|
|
363
|
+
size="sm"
|
|
364
|
+
icon={!creating ? <TerminalSquare size={12} strokeWidth={2} /> : undefined}
|
|
365
|
+
className="flex-1"
|
|
366
|
+
onClick={() => handleCreateSession('terminal')}
|
|
351
367
|
disabled={creating || !selectedProjectId}
|
|
352
368
|
>
|
|
353
|
-
{creating ? '...' : '
|
|
369
|
+
{creating ? '...' : 'Terminal'}
|
|
354
370
|
</Button>
|
|
355
371
|
</div>
|
|
356
372
|
</div>
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToolDiffView — humanized side-by-side diff view for Edit and Write tool calls.
|
|
3
|
+
* Shows old_string vs new_string for Edit, or the full content for Write,
|
|
4
|
+
* rendered as syntax-highlighted, read-only code blocks.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
8
|
+
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
9
|
+
|
|
10
|
+
/** Map common file extensions to Prism language identifiers. */
|
|
11
|
+
const extToLang: Record<string, string> = {
|
|
12
|
+
ts: 'typescript', tsx: 'tsx', js: 'javascript', jsx: 'jsx',
|
|
13
|
+
py: 'python', rb: 'ruby', rs: 'rust', go: 'go',
|
|
14
|
+
java: 'java', kt: 'kotlin', cs: 'csharp', cpp: 'cpp', c: 'c',
|
|
15
|
+
css: 'css', scss: 'scss', html: 'html', vue: 'html',
|
|
16
|
+
json: 'json', yaml: 'yaml', yml: 'yaml', toml: 'toml',
|
|
17
|
+
md: 'markdown', sql: 'sql', sh: 'bash', bash: 'bash', zsh: 'bash',
|
|
18
|
+
xml: 'xml', svg: 'xml', graphql: 'graphql', prisma: 'prisma',
|
|
19
|
+
dockerfile: 'docker',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const inferLang = (filePath: string): string => {
|
|
23
|
+
const name = filePath.split('/').pop() ?? '';
|
|
24
|
+
if (name.toLowerCase() === 'dockerfile') return 'docker';
|
|
25
|
+
const ext = name.split('.').pop()?.toLowerCase() ?? '';
|
|
26
|
+
return extToLang[ext] ?? 'text';
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** Shared customStyle for the syntax highlighter to blend with our theme. */
|
|
30
|
+
const codeStyle: React.CSSProperties = {
|
|
31
|
+
margin: 0,
|
|
32
|
+
padding: '0.75rem',
|
|
33
|
+
fontSize: '12px',
|
|
34
|
+
lineHeight: '1.5',
|
|
35
|
+
background: 'transparent',
|
|
36
|
+
borderRadius: 0,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
interface CodePanelProps {
|
|
40
|
+
label: string;
|
|
41
|
+
code: string;
|
|
42
|
+
language: string;
|
|
43
|
+
accent?: 'red' | 'green' | 'neutral';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const accentClasses: Record<string, string> = {
|
|
47
|
+
red: 'border-red-500/30 bg-red-500/5',
|
|
48
|
+
green: 'border-green-500/30 bg-green-500/5',
|
|
49
|
+
neutral: 'border-edge bg-surface-alt',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const labelClasses: Record<string, string> = {
|
|
53
|
+
red: 'text-red-400',
|
|
54
|
+
green: 'text-green-400',
|
|
55
|
+
neutral: 'text-content-muted',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const CodePanel = ({ label, code, language, accent = 'neutral' }: CodePanelProps) => (
|
|
59
|
+
<div className={`flex flex-col min-w-0 flex-1 border rounded-md overflow-hidden ${accentClasses[accent]}`}>
|
|
60
|
+
<div className={`text-[10px] font-mono uppercase tracking-wider px-3 py-1.5 border-b border-edge/50 ${labelClasses[accent]}`}>
|
|
61
|
+
{label}
|
|
62
|
+
</div>
|
|
63
|
+
<div className="overflow-auto max-h-[400px]">
|
|
64
|
+
<SyntaxHighlighter
|
|
65
|
+
language={language}
|
|
66
|
+
style={oneDark}
|
|
67
|
+
customStyle={codeStyle}
|
|
68
|
+
wrapLongLines
|
|
69
|
+
>
|
|
70
|
+
{code || '(empty)'}
|
|
71
|
+
</SyntaxHighlighter>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
interface ToolDiffViewProps {
|
|
77
|
+
toolName: 'Edit' | 'Write';
|
|
78
|
+
input: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const ToolDiffView = ({ toolName, input }: ToolDiffViewProps) => {
|
|
82
|
+
const filePath = (input.file_path as string) ?? '';
|
|
83
|
+
const language = inferLang(filePath);
|
|
84
|
+
|
|
85
|
+
if (toolName === 'Edit') {
|
|
86
|
+
const oldStr = (input.old_string as string) ?? '';
|
|
87
|
+
const newStr = (input.new_string as string) ?? '';
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div className="flex flex-col gap-2">
|
|
91
|
+
<div className="text-[10px] font-mono text-content-muted truncate px-1">
|
|
92
|
+
{filePath}
|
|
93
|
+
{input.replace_all && <span className="ml-2 text-amber-400">(replace all)</span>}
|
|
94
|
+
</div>
|
|
95
|
+
<div className="flex gap-2 min-h-0">
|
|
96
|
+
<CodePanel label="Old" code={oldStr} language={language} accent="red" />
|
|
97
|
+
<CodePanel label="New" code={newStr} language={language} accent="green" />
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Write tool — single panel with content
|
|
104
|
+
const content = (input.content as string) ?? '';
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div className="flex flex-col gap-2">
|
|
108
|
+
<div className="text-[10px] font-mono text-content-muted truncate px-1">
|
|
109
|
+
{filePath}
|
|
110
|
+
</div>
|
|
111
|
+
<CodePanel label="Content" code={content} language={language} />
|
|
112
|
+
</div>
|
|
113
|
+
);
|
|
114
|
+
};
|