@atercates/claude-deck 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +123 -0
- package/app/api/claude/hidden/route.ts +66 -0
- package/app/api/claude/projects/[name]/sessions/route.ts +71 -0
- package/app/api/claude/projects/route.ts +44 -0
- package/app/api/code-search/available/route.ts +12 -0
- package/app/api/code-search/route.ts +47 -0
- package/app/api/dev-servers/[id]/logs/route.ts +23 -0
- package/app/api/dev-servers/[id]/restart/route.ts +20 -0
- package/app/api/dev-servers/[id]/route.ts +51 -0
- package/app/api/dev-servers/[id]/stop/route.ts +20 -0
- package/app/api/dev-servers/detect/route.ts +39 -0
- package/app/api/dev-servers/route.ts +48 -0
- package/app/api/exec/route.ts +60 -0
- package/app/api/files/content/route.ts +76 -0
- package/app/api/files/route.ts +37 -0
- package/app/api/files/upload-temp/route.ts +41 -0
- package/app/api/git/check/route.ts +54 -0
- package/app/api/git/clone/route.ts +99 -0
- package/app/api/git/commit/route.ts +75 -0
- package/app/api/git/discard/route.ts +38 -0
- package/app/api/git/file-content/route.ts +64 -0
- package/app/api/git/history/[hash]/diff/route.ts +38 -0
- package/app/api/git/history/[hash]/route.ts +34 -0
- package/app/api/git/history/route.ts +27 -0
- package/app/api/git/multi-status/route.ts +46 -0
- package/app/api/git/pr/route.ts +164 -0
- package/app/api/git/push/route.ts +64 -0
- package/app/api/git/stage/route.ts +40 -0
- package/app/api/git/status/route.ts +51 -0
- package/app/api/git/unstage/route.ts +46 -0
- package/app/api/groups/[...path]/route.ts +136 -0
- package/app/api/groups/route.ts +93 -0
- package/app/api/orchestrate/spawn/route.ts +45 -0
- package/app/api/orchestrate/workers/[id]/route.ts +89 -0
- package/app/api/orchestrate/workers/route.ts +31 -0
- package/app/api/projects/[id]/detect/route.ts +27 -0
- package/app/api/projects/[id]/dev-servers/[dsId]/route.ts +66 -0
- package/app/api/projects/[id]/dev-servers/route.ts +51 -0
- package/app/api/projects/[id]/repositories/[repoId]/route.ts +67 -0
- package/app/api/projects/[id]/repositories/route.ts +74 -0
- package/app/api/projects/[id]/route.ts +108 -0
- package/app/api/projects/detect/route.ts +33 -0
- package/app/api/projects/route.ts +59 -0
- package/app/api/sessions/[id]/claude-session/route.ts +42 -0
- package/app/api/sessions/[id]/fork/route.ts +74 -0
- package/app/api/sessions/[id]/mcp-config/route.ts +34 -0
- package/app/api/sessions/[id]/messages/route.ts +60 -0
- package/app/api/sessions/[id]/pr/route.ts +188 -0
- package/app/api/sessions/[id]/preview/route.ts +42 -0
- package/app/api/sessions/[id]/route.ts +229 -0
- package/app/api/sessions/[id]/send-keys/route.ts +119 -0
- package/app/api/sessions/[id]/summarize/route.ts +331 -0
- package/app/api/sessions/init-script/route.ts +84 -0
- package/app/api/sessions/route.ts +209 -0
- package/app/api/sessions/status/route.ts +237 -0
- package/app/api/system/route.ts +9 -0
- package/app/api/tmux/kill-all/route.ts +57 -0
- package/app/api/tmux/rename/route.ts +30 -0
- package/app/globals.css +174 -0
- package/app/icon.svg +11 -0
- package/app/layout.tsx +122 -0
- package/app/page.tsx +629 -0
- package/components/ChatMessage.tsx +65 -0
- package/components/ChatView.tsx +276 -0
- package/components/ClaudeProjects/ClaudeProjectCard.tsx +195 -0
- package/components/ClaudeProjects/ClaudeProjectsSection.tsx +89 -0
- package/components/ClaudeProjects/ClaudeSessionCard.tsx +100 -0
- package/components/ClaudeProjects/index.ts +1 -0
- package/components/CodeSearch/CodeSearchResults.tsx +177 -0
- package/components/ConductorPanel.tsx +256 -0
- package/components/DevServers/DevServerCard.tsx +311 -0
- package/components/DevServers/DevServersSection.tsx +91 -0
- package/components/DevServers/ServerLogsModal.tsx +151 -0
- package/components/DevServers/StartServerDialog.tsx +359 -0
- package/components/DevServers/index.ts +4 -0
- package/components/DiffViewer/DiffModal.tsx +151 -0
- package/components/DiffViewer/UnifiedDiff.tsx +185 -0
- package/components/DiffViewer/index.tsx +2 -0
- package/components/DirectoryPicker.tsx +355 -0
- package/components/FileExplorer/FileEditor.tsx +276 -0
- package/components/FileExplorer/FileTabs.tsx +118 -0
- package/components/FileExplorer/FileTree.tsx +214 -0
- package/components/FileExplorer/HtmlRenderer.tsx +16 -0
- package/components/FileExplorer/MarkdownRenderer.tsx +18 -0
- package/components/FileExplorer/index.tsx +520 -0
- package/components/FilePicker.tsx +339 -0
- package/components/FolderPicker.tsx +201 -0
- package/components/GitDrawer/FileEditDialog.tsx +400 -0
- package/components/GitDrawer/index.tsx +464 -0
- package/components/GitPanel/CommitForm.tsx +205 -0
- package/components/GitPanel/CommitHistory.tsx +174 -0
- package/components/GitPanel/CommitItem.tsx +196 -0
- package/components/GitPanel/FileChanges.tsx +414 -0
- package/components/GitPanel/GitPanelTabs.tsx +39 -0
- package/components/GitPanel/index.tsx +817 -0
- package/components/MessageInput.tsx +82 -0
- package/components/NewClaudeSessionDialog.tsx +166 -0
- package/components/NewSessionDialog/AdvancedSettings.tsx +78 -0
- package/components/NewSessionDialog/AgentSelector.tsx +37 -0
- package/components/NewSessionDialog/CreatingOverlay.tsx +94 -0
- package/components/NewSessionDialog/NewSessionDialog.types.ts +136 -0
- package/components/NewSessionDialog/ProjectSelector.tsx +146 -0
- package/components/NewSessionDialog/WorkingDirectoryInput.tsx +55 -0
- package/components/NewSessionDialog/WorktreeSection.tsx +92 -0
- package/components/NewSessionDialog/hooks/useNewSessionForm.ts +370 -0
- package/components/NewSessionDialog/index.tsx +106 -0
- package/components/NotificationSettings.tsx +127 -0
- package/components/PRCreationModal.tsx +272 -0
- package/components/Pane/DesktopTabBar.tsx +353 -0
- package/components/Pane/MobileTabBar.tsx +210 -0
- package/components/Pane/OpenInVSCode.tsx +69 -0
- package/components/Pane/PaneSkeletons.tsx +57 -0
- package/components/Pane/index.tsx +558 -0
- package/components/PaneLayout.tsx +60 -0
- package/components/Projects/DevServersSection.tsx +140 -0
- package/components/Projects/DirectoryField.tsx +92 -0
- package/components/Projects/NewProjectDialog.tsx +188 -0
- package/components/Projects/NewProjectDialog.types.ts +46 -0
- package/components/Projects/ProjectCard.tsx +276 -0
- package/components/Projects/ProjectSettingsDialog.tsx +811 -0
- package/components/Projects/hooks/useNewProjectForm.ts +249 -0
- package/components/Projects/index.ts +3 -0
- package/components/Providers.tsx +49 -0
- package/components/QuickSwitcher.tsx +306 -0
- package/components/SessionList/KillAllConfirm.tsx +46 -0
- package/components/SessionList/SelectionToolbar.tsx +164 -0
- package/components/SessionList/SessionList.types.ts +37 -0
- package/components/SessionList/SessionListHeader.tsx +71 -0
- package/components/SessionList/hooks/useSessionListMutations.ts +269 -0
- package/components/SessionList/index.tsx +189 -0
- package/components/ShellDrawer/index.tsx +106 -0
- package/components/SidebarFooter.tsx +55 -0
- package/components/Terminal/KeybarToggleButton.tsx +45 -0
- package/components/Terminal/ScrollToBottomButton.tsx +32 -0
- package/components/Terminal/SearchBar.tsx +71 -0
- package/components/Terminal/TerminalToolbar.tsx +551 -0
- package/components/Terminal/VirtualKeyboard.tsx +711 -0
- package/components/Terminal/constants.ts +20 -0
- package/components/Terminal/hooks/index.ts +5 -0
- package/components/Terminal/hooks/resize-handlers.ts +140 -0
- package/components/Terminal/hooks/terminal-init.ts +151 -0
- package/components/Terminal/hooks/touch-scroll.ts +155 -0
- package/components/Terminal/hooks/useTerminalConnection.ts +282 -0
- package/components/Terminal/hooks/useTerminalConnection.types.ts +39 -0
- package/components/Terminal/hooks/useTerminalSearch.ts +103 -0
- package/components/Terminal/hooks/websocket-connection.ts +274 -0
- package/components/Terminal/index.tsx +320 -0
- package/components/ThemeToggle.tsx +168 -0
- package/components/TmuxSessions.tsx +132 -0
- package/components/ToolCallDisplay.tsx +71 -0
- package/components/WorkerCard.tsx +245 -0
- package/components/a/ABadge.tsx +115 -0
- package/components/a/AButton.tsx +163 -0
- package/components/a/ADialog.tsx +93 -0
- package/components/a/ADropdownMenu.tsx +279 -0
- package/components/a/AIconButton.tsx +190 -0
- package/components/a/ASheet.tsx +150 -0
- package/components/a/ATooltip.tsx +77 -0
- package/components/a/index.ts +64 -0
- package/components/mobile/SwipeSidebar.tsx +122 -0
- package/components/ui/badge.tsx +41 -0
- package/components/ui/button.tsx +60 -0
- package/components/ui/context-menu.tsx +197 -0
- package/components/ui/dialog.tsx +143 -0
- package/components/ui/dropdown-menu.tsx +257 -0
- package/components/ui/input.tsx +21 -0
- package/components/ui/scroll-area.tsx +52 -0
- package/components/ui/select.tsx +159 -0
- package/components/ui/skeleton.tsx +111 -0
- package/components/ui/switch.tsx +31 -0
- package/components/ui/textarea.tsx +21 -0
- package/components/ui/tooltip.tsx +32 -0
- package/components/views/DesktopView.tsx +244 -0
- package/components/views/MobileView.tsx +110 -0
- package/components/views/types.ts +75 -0
- package/contexts/PaneContext.tsx +336 -0
- package/data/claude/index.ts +9 -0
- package/data/claude/keys.ts +6 -0
- package/data/claude/queries.ts +120 -0
- package/data/claude/useClaudeUpdates.ts +37 -0
- package/data/code-search/index.ts +2 -0
- package/data/code-search/keys.ts +7 -0
- package/data/code-search/queries.ts +61 -0
- package/data/dev-servers/index.ts +8 -0
- package/data/dev-servers/keys.ts +4 -0
- package/data/dev-servers/queries.ts +104 -0
- package/data/files/index.ts +3 -0
- package/data/files/keys.ts +4 -0
- package/data/files/queries.ts +25 -0
- package/data/git/keys.ts +15 -0
- package/data/git/queries.ts +395 -0
- package/data/groups/index.ts +1 -0
- package/data/groups/mutations.ts +95 -0
- package/data/projects/index.ts +10 -0
- package/data/projects/keys.ts +4 -0
- package/data/projects/queries.ts +193 -0
- package/data/repositories/index.ts +7 -0
- package/data/repositories/keys.ts +5 -0
- package/data/repositories/queries.ts +122 -0
- package/data/sessions/index.ts +12 -0
- package/data/sessions/keys.ts +8 -0
- package/data/sessions/queries.ts +218 -0
- package/data/statuses/index.ts +1 -0
- package/data/statuses/queries.ts +69 -0
- package/hooks/useCopyToClipboard.ts +48 -0
- package/hooks/useDevServersManager.ts +73 -0
- package/hooks/useDirectoryBrowser.ts +90 -0
- package/hooks/useDrawerAnimation.ts +27 -0
- package/hooks/useFileDrop.ts +87 -0
- package/hooks/useFileEditor.ts +184 -0
- package/hooks/useGroups.ts +37 -0
- package/hooks/useHomePath.ts +34 -0
- package/hooks/useKeyRepeat.ts +55 -0
- package/hooks/useKeybarVisibility.ts +42 -0
- package/hooks/useNotifications.ts +257 -0
- package/hooks/useProjects.ts +53 -0
- package/hooks/useSessionStatuses.ts +30 -0
- package/hooks/useSessions.ts +86 -0
- package/hooks/useSpeechRecognition.ts +124 -0
- package/hooks/useViewport.ts +32 -0
- package/hooks/useViewportHeight.ts +50 -0
- package/lib/async-operations.ts +35 -0
- package/lib/banner.ts +81 -0
- package/lib/claude/jsonl-cache.ts +86 -0
- package/lib/claude/jsonl-reader.ts +271 -0
- package/lib/claude/process-manager.ts +278 -0
- package/lib/claude/stream-parser.ts +173 -0
- package/lib/claude/types.ts +154 -0
- package/lib/claude/watcher.ts +71 -0
- package/lib/client/session-registry.ts +111 -0
- package/lib/code-search.ts +121 -0
- package/lib/db/index.ts +48 -0
- package/lib/db/migrations.ts +45 -0
- package/lib/db/queries.ts +460 -0
- package/lib/db/schema.ts +114 -0
- package/lib/db/types.ts +92 -0
- package/lib/db.ts +2 -0
- package/lib/dev-servers.ts +509 -0
- package/lib/diff-parser.ts +221 -0
- package/lib/env-setup.ts +285 -0
- package/lib/file-upload.ts +34 -0
- package/lib/file-utils.ts +50 -0
- package/lib/files.ts +207 -0
- package/lib/git-history.ts +294 -0
- package/lib/git-status.ts +391 -0
- package/lib/git.ts +257 -0
- package/lib/mcp-config.ts +81 -0
- package/lib/multi-repo-git.ts +179 -0
- package/lib/notifications.ts +219 -0
- package/lib/orchestration.ts +448 -0
- package/lib/panes.ts +232 -0
- package/lib/ports.ts +97 -0
- package/lib/pr-generation.ts +307 -0
- package/lib/pr.ts +234 -0
- package/lib/projects.ts +578 -0
- package/lib/providers/registry.ts +70 -0
- package/lib/providers.ts +121 -0
- package/lib/query-client.ts +14 -0
- package/lib/rangeSelectionUtils.ts +65 -0
- package/lib/status-detector.ts +375 -0
- package/lib/terminal-themes.ts +265 -0
- package/lib/theme-config.ts +327 -0
- package/lib/utils.ts +6 -0
- package/lib/worktrees.ts +262 -0
- package/mcp/orchestration-server.ts +438 -0
- package/package.json +139 -0
- package/postcss.config.mjs +7 -0
- package/public/icon.svg +10 -0
- package/public/icons/icon-128x128.png +0 -0
- package/public/icons/icon-144x144.png +0 -0
- package/public/icons/icon-152x152.png +0 -0
- package/public/icons/icon-192x192.png +0 -0
- package/public/icons/icon-384x384.png +0 -0
- package/public/icons/icon-512x512.png +0 -0
- package/public/icons/icon-72x72.png +0 -0
- package/public/icons/icon-96x96.png +0 -0
- package/public/manifest.json +61 -0
- package/public/sw.js +64 -0
- package/scripts/agent-os +91 -0
- package/scripts/install.sh +48 -0
- package/scripts/lib/ai-clis.sh +132 -0
- package/scripts/lib/commands.sh +487 -0
- package/scripts/lib/common.sh +89 -0
- package/scripts/lib/prerequisites.sh +462 -0
- package/scripts/setup.sh +134 -0
- package/server.ts +155 -0
- package/stores/fileOpen.ts +26 -0
- package/stores/index.ts +1 -0
- package/stores/initialPrompt.ts +24 -0
- package/stores/sessionSelection.ts +48 -0
- package/styles/themes.css +603 -0
- package/tsconfig.json +33 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import {
|
|
3
|
+
getWorkerOutput,
|
|
4
|
+
sendToWorker,
|
|
5
|
+
completeWorker,
|
|
6
|
+
failWorker,
|
|
7
|
+
killWorker,
|
|
8
|
+
} from "@/lib/orchestration";
|
|
9
|
+
|
|
10
|
+
interface RouteParams {
|
|
11
|
+
params: Promise<{ id: string }>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// GET /api/orchestrate/workers/[id] - Get worker output
|
|
15
|
+
export async function GET(request: Request, { params }: RouteParams) {
|
|
16
|
+
try {
|
|
17
|
+
const { id } = await params;
|
|
18
|
+
const { searchParams } = new URL(request.url);
|
|
19
|
+
const lines = parseInt(searchParams.get("lines") || "50", 10);
|
|
20
|
+
|
|
21
|
+
const output = await getWorkerOutput(id, lines);
|
|
22
|
+
return NextResponse.json({ output });
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error("Failed to get worker output:", error);
|
|
25
|
+
return NextResponse.json(
|
|
26
|
+
{ error: "Failed to get worker output" },
|
|
27
|
+
{ status: 500 }
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// POST /api/orchestrate/workers/[id] - Send message or update status
|
|
33
|
+
export async function POST(request: Request, { params }: RouteParams) {
|
|
34
|
+
try {
|
|
35
|
+
const { id } = await params;
|
|
36
|
+
const body = await request.json();
|
|
37
|
+
const { action, message } = body;
|
|
38
|
+
|
|
39
|
+
switch (action) {
|
|
40
|
+
case "send":
|
|
41
|
+
if (!message) {
|
|
42
|
+
return NextResponse.json(
|
|
43
|
+
{ error: "Missing message" },
|
|
44
|
+
{ status: 400 }
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
const sent = await sendToWorker(id, message);
|
|
48
|
+
return NextResponse.json({ success: sent });
|
|
49
|
+
|
|
50
|
+
case "complete":
|
|
51
|
+
completeWorker(id);
|
|
52
|
+
return NextResponse.json({ success: true });
|
|
53
|
+
|
|
54
|
+
case "fail":
|
|
55
|
+
failWorker(id);
|
|
56
|
+
return NextResponse.json({ success: true });
|
|
57
|
+
|
|
58
|
+
default:
|
|
59
|
+
return NextResponse.json(
|
|
60
|
+
{ error: "Invalid action. Use: send, complete, or fail" },
|
|
61
|
+
{ status: 400 }
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("Failed to perform worker action:", error);
|
|
66
|
+
return NextResponse.json(
|
|
67
|
+
{ error: "Failed to perform worker action" },
|
|
68
|
+
{ status: 500 }
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// DELETE /api/orchestrate/workers/[id] - Kill worker
|
|
74
|
+
export async function DELETE(request: Request, { params }: RouteParams) {
|
|
75
|
+
try {
|
|
76
|
+
const { id } = await params;
|
|
77
|
+
const { searchParams } = new URL(request.url);
|
|
78
|
+
const cleanupWorktree = searchParams.get("cleanup") === "true";
|
|
79
|
+
|
|
80
|
+
await killWorker(id, cleanupWorktree);
|
|
81
|
+
return NextResponse.json({ success: true });
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("Failed to kill worker:", error);
|
|
84
|
+
return NextResponse.json(
|
|
85
|
+
{ error: "Failed to kill worker" },
|
|
86
|
+
{ status: 500 }
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getWorkers, getWorkersSummary } from "@/lib/orchestration";
|
|
3
|
+
|
|
4
|
+
export async function GET(request: Request) {
|
|
5
|
+
try {
|
|
6
|
+
const { searchParams } = new URL(request.url);
|
|
7
|
+
const conductorId = searchParams.get("conductorId");
|
|
8
|
+
const summaryOnly = searchParams.get("summary") === "true";
|
|
9
|
+
|
|
10
|
+
if (!conductorId) {
|
|
11
|
+
return NextResponse.json(
|
|
12
|
+
{ error: "Missing conductorId parameter" },
|
|
13
|
+
{ status: 400 }
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (summaryOnly) {
|
|
18
|
+
const summary = await getWorkersSummary(conductorId);
|
|
19
|
+
return NextResponse.json({ summary });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const workers = await getWorkers(conductorId);
|
|
23
|
+
return NextResponse.json({ workers });
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error("Failed to get workers:", error);
|
|
26
|
+
return NextResponse.json(
|
|
27
|
+
{ error: "Failed to get workers" },
|
|
28
|
+
{ status: 500 }
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import { getProject, detectDevServers } from "@/lib/projects";
|
|
3
|
+
|
|
4
|
+
interface RouteParams {
|
|
5
|
+
params: Promise<{ id: string }>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// GET /api/projects/[id]/detect - Detect available dev servers for a project
|
|
9
|
+
export async function GET(request: NextRequest, { params }: RouteParams) {
|
|
10
|
+
try {
|
|
11
|
+
const { id } = await params;
|
|
12
|
+
const project = await getProject(id);
|
|
13
|
+
|
|
14
|
+
if (!project) {
|
|
15
|
+
return NextResponse.json({ error: "Project not found" }, { status: 404 });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const detected = await detectDevServers(project.working_directory);
|
|
19
|
+
return NextResponse.json({ detected });
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error("Error detecting dev servers:", error);
|
|
22
|
+
return NextResponse.json(
|
|
23
|
+
{ error: "Failed to detect dev servers" },
|
|
24
|
+
{ status: 500 }
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import { updateProjectDevServer, deleteProjectDevServer } from "@/lib/projects";
|
|
3
|
+
import { queries, type ProjectDevServer } from "@/lib/db";
|
|
4
|
+
|
|
5
|
+
interface RouteParams {
|
|
6
|
+
params: Promise<{ id: string; dsId: string }>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// PATCH /api/projects/[id]/dev-servers/[dsId] - Update a dev server config
|
|
10
|
+
export async function PATCH(request: NextRequest, { params }: RouteParams) {
|
|
11
|
+
try {
|
|
12
|
+
const { dsId } = await params;
|
|
13
|
+
|
|
14
|
+
const existing = await queries.getProjectDevServer(dsId);
|
|
15
|
+
if (!existing) {
|
|
16
|
+
return NextResponse.json(
|
|
17
|
+
{ error: "Dev server config not found" },
|
|
18
|
+
{ status: 404 }
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const body = await request.json();
|
|
23
|
+
const { name, type, command, port, portEnvVar, sortOrder } = body;
|
|
24
|
+
|
|
25
|
+
const devServer = await updateProjectDevServer(dsId, {
|
|
26
|
+
name,
|
|
27
|
+
type,
|
|
28
|
+
command,
|
|
29
|
+
port,
|
|
30
|
+
portEnvVar,
|
|
31
|
+
sortOrder,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return NextResponse.json({ devServer });
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error("Error updating dev server config:", error);
|
|
37
|
+
return NextResponse.json(
|
|
38
|
+
{ error: "Failed to update dev server config" },
|
|
39
|
+
{ status: 500 }
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// DELETE /api/projects/[id]/dev-servers/[dsId] - Delete a dev server config
|
|
45
|
+
export async function DELETE(request: NextRequest, { params }: RouteParams) {
|
|
46
|
+
try {
|
|
47
|
+
const { dsId } = await params;
|
|
48
|
+
|
|
49
|
+
const existing = await queries.getProjectDevServer(dsId);
|
|
50
|
+
if (!existing) {
|
|
51
|
+
return NextResponse.json(
|
|
52
|
+
{ error: "Dev server config not found" },
|
|
53
|
+
{ status: 404 }
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await deleteProjectDevServer(dsId);
|
|
58
|
+
return NextResponse.json({ success: true });
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.error("Error deleting dev server config:", error);
|
|
61
|
+
return NextResponse.json(
|
|
62
|
+
{ error: "Failed to delete dev server config" },
|
|
63
|
+
{ status: 500 }
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import { getProject, addProjectDevServer } from "@/lib/projects";
|
|
3
|
+
|
|
4
|
+
interface RouteParams {
|
|
5
|
+
params: Promise<{ id: string }>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// POST /api/projects/[id]/dev-servers - Add a dev server config to a project
|
|
9
|
+
export async function POST(request: NextRequest, { params }: RouteParams) {
|
|
10
|
+
try {
|
|
11
|
+
const { id } = await params;
|
|
12
|
+
const project = await getProject(id);
|
|
13
|
+
|
|
14
|
+
if (!project) {
|
|
15
|
+
return NextResponse.json({ error: "Project not found" }, { status: 404 });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (project.is_uncategorized) {
|
|
19
|
+
return NextResponse.json(
|
|
20
|
+
{ error: "Cannot add dev servers to Uncategorized project" },
|
|
21
|
+
{ status: 400 }
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const body = await request.json();
|
|
26
|
+
const { name, type, command, port, portEnvVar } = body;
|
|
27
|
+
|
|
28
|
+
if (!name || !type || !command) {
|
|
29
|
+
return NextResponse.json(
|
|
30
|
+
{ error: "Name, type, and command are required" },
|
|
31
|
+
{ status: 400 }
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const devServer = await addProjectDevServer(id, {
|
|
36
|
+
name,
|
|
37
|
+
type,
|
|
38
|
+
command,
|
|
39
|
+
port,
|
|
40
|
+
portEnvVar,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
return NextResponse.json({ devServer }, { status: 201 });
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error("Error adding dev server config:", error);
|
|
46
|
+
return NextResponse.json(
|
|
47
|
+
{ error: "Failed to add dev server config" },
|
|
48
|
+
{ status: 500 }
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import {
|
|
3
|
+
updateProjectRepository,
|
|
4
|
+
deleteProjectRepository,
|
|
5
|
+
} from "@/lib/projects";
|
|
6
|
+
import { queries, type ProjectRepository } from "@/lib/db";
|
|
7
|
+
|
|
8
|
+
interface RouteParams {
|
|
9
|
+
params: Promise<{ id: string; repoId: string }>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// PATCH /api/projects/[id]/repositories/[repoId] - Update a repository
|
|
13
|
+
export async function PATCH(request: NextRequest, { params }: RouteParams) {
|
|
14
|
+
try {
|
|
15
|
+
const { repoId } = await params;
|
|
16
|
+
|
|
17
|
+
const existing = await queries.getProjectRepository(repoId);
|
|
18
|
+
if (!existing) {
|
|
19
|
+
return NextResponse.json(
|
|
20
|
+
{ error: "Repository not found" },
|
|
21
|
+
{ status: 404 }
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const body = await request.json();
|
|
26
|
+
const { name, path, isPrimary, sortOrder } = body;
|
|
27
|
+
|
|
28
|
+
const repository = await updateProjectRepository(repoId, {
|
|
29
|
+
name,
|
|
30
|
+
path,
|
|
31
|
+
isPrimary,
|
|
32
|
+
sortOrder,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return NextResponse.json({ repository });
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error("Error updating repository:", error);
|
|
38
|
+
return NextResponse.json(
|
|
39
|
+
{ error: "Failed to update repository" },
|
|
40
|
+
{ status: 500 }
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// DELETE /api/projects/[id]/repositories/[repoId] - Delete a repository
|
|
46
|
+
export async function DELETE(request: NextRequest, { params }: RouteParams) {
|
|
47
|
+
try {
|
|
48
|
+
const { repoId } = await params;
|
|
49
|
+
|
|
50
|
+
const existing = await queries.getProjectRepository(repoId);
|
|
51
|
+
if (!existing) {
|
|
52
|
+
return NextResponse.json(
|
|
53
|
+
{ error: "Repository not found" },
|
|
54
|
+
{ status: 404 }
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
await deleteProjectRepository(repoId);
|
|
59
|
+
return NextResponse.json({ success: true });
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error("Error deleting repository:", error);
|
|
62
|
+
return NextResponse.json(
|
|
63
|
+
{ error: "Failed to delete repository" },
|
|
64
|
+
{ status: 500 }
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import {
|
|
3
|
+
getProject,
|
|
4
|
+
getProjectRepositories,
|
|
5
|
+
addProjectRepository,
|
|
6
|
+
} from "@/lib/projects";
|
|
7
|
+
|
|
8
|
+
interface RouteParams {
|
|
9
|
+
params: Promise<{ id: string }>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// GET /api/projects/[id]/repositories - List repositories for a project
|
|
13
|
+
export async function GET(request: NextRequest, { params }: RouteParams) {
|
|
14
|
+
try {
|
|
15
|
+
const { id } = await params;
|
|
16
|
+
const project = await getProject(id);
|
|
17
|
+
|
|
18
|
+
if (!project) {
|
|
19
|
+
return NextResponse.json({ error: "Project not found" }, { status: 404 });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const repositories = await getProjectRepositories(id);
|
|
23
|
+
return NextResponse.json({ repositories });
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error("Error fetching repositories:", error);
|
|
26
|
+
return NextResponse.json(
|
|
27
|
+
{ error: "Failed to fetch repositories" },
|
|
28
|
+
{ status: 500 }
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// POST /api/projects/[id]/repositories - Add a repository to a project
|
|
34
|
+
export async function POST(request: NextRequest, { params }: RouteParams) {
|
|
35
|
+
try {
|
|
36
|
+
const { id } = await params;
|
|
37
|
+
const project = await getProject(id);
|
|
38
|
+
|
|
39
|
+
if (!project) {
|
|
40
|
+
return NextResponse.json({ error: "Project not found" }, { status: 404 });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (project.is_uncategorized) {
|
|
44
|
+
return NextResponse.json(
|
|
45
|
+
{ error: "Cannot add repositories to Uncategorized project" },
|
|
46
|
+
{ status: 400 }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const body = await request.json();
|
|
51
|
+
const { name, path, isPrimary } = body;
|
|
52
|
+
|
|
53
|
+
if (!name || !path) {
|
|
54
|
+
return NextResponse.json(
|
|
55
|
+
{ error: "Name and path are required" },
|
|
56
|
+
{ status: 400 }
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const repository = await addProjectRepository(id, {
|
|
61
|
+
name,
|
|
62
|
+
path,
|
|
63
|
+
isPrimary,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return NextResponse.json({ repository }, { status: 201 });
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error("Error adding repository:", error);
|
|
69
|
+
return NextResponse.json(
|
|
70
|
+
{ error: "Failed to add repository" },
|
|
71
|
+
{ status: 500 }
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import {
|
|
3
|
+
getProjectWithDevServers,
|
|
4
|
+
updateProject,
|
|
5
|
+
deleteProject,
|
|
6
|
+
toggleProjectExpanded,
|
|
7
|
+
} from "@/lib/projects";
|
|
8
|
+
|
|
9
|
+
interface RouteParams {
|
|
10
|
+
params: Promise<{ id: string }>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// GET /api/projects/[id] - Get a single project with dev servers
|
|
14
|
+
export async function GET(request: NextRequest, { params }: RouteParams) {
|
|
15
|
+
try {
|
|
16
|
+
const { id } = await params;
|
|
17
|
+
const project = await getProjectWithDevServers(id);
|
|
18
|
+
|
|
19
|
+
if (!project) {
|
|
20
|
+
return NextResponse.json({ error: "Project not found" }, { status: 404 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return NextResponse.json({ project });
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error("Error getting project:", error);
|
|
26
|
+
return NextResponse.json(
|
|
27
|
+
{ error: "Failed to get project" },
|
|
28
|
+
{ status: 500 }
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// PATCH /api/projects/[id] - Update a project
|
|
34
|
+
export async function PATCH(request: NextRequest, { params }: RouteParams) {
|
|
35
|
+
try {
|
|
36
|
+
const { id } = await params;
|
|
37
|
+
const body = await request.json();
|
|
38
|
+
const {
|
|
39
|
+
name,
|
|
40
|
+
workingDirectory,
|
|
41
|
+
agentType,
|
|
42
|
+
defaultModel,
|
|
43
|
+
initialPrompt,
|
|
44
|
+
expanded,
|
|
45
|
+
} = body;
|
|
46
|
+
|
|
47
|
+
// Handle expanded toggle separately
|
|
48
|
+
if (typeof expanded === "boolean") {
|
|
49
|
+
await toggleProjectExpanded(id, expanded);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Update other fields if provided
|
|
53
|
+
if (
|
|
54
|
+
name ||
|
|
55
|
+
workingDirectory ||
|
|
56
|
+
agentType ||
|
|
57
|
+
defaultModel ||
|
|
58
|
+
initialPrompt !== undefined
|
|
59
|
+
) {
|
|
60
|
+
const project = await updateProject(id, {
|
|
61
|
+
name,
|
|
62
|
+
working_directory: workingDirectory,
|
|
63
|
+
agent_type: agentType,
|
|
64
|
+
default_model: defaultModel,
|
|
65
|
+
initial_prompt: initialPrompt,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (!project) {
|
|
69
|
+
return NextResponse.json(
|
|
70
|
+
{ error: "Project not found or cannot be modified" },
|
|
71
|
+
{ status: 404 }
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const updated = await getProjectWithDevServers(id);
|
|
77
|
+
return NextResponse.json({ project: updated });
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error("Error updating project:", error);
|
|
80
|
+
return NextResponse.json(
|
|
81
|
+
{ error: "Failed to update project" },
|
|
82
|
+
{ status: 500 }
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// DELETE /api/projects/[id] - Delete a project
|
|
88
|
+
export async function DELETE(request: NextRequest, { params }: RouteParams) {
|
|
89
|
+
try {
|
|
90
|
+
const { id } = await params;
|
|
91
|
+
const deleted = await deleteProject(id);
|
|
92
|
+
|
|
93
|
+
if (!deleted) {
|
|
94
|
+
return NextResponse.json(
|
|
95
|
+
{ error: "Project not found or cannot be deleted" },
|
|
96
|
+
{ status: 404 }
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return NextResponse.json({ success: true });
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error("Error deleting project:", error);
|
|
103
|
+
return NextResponse.json(
|
|
104
|
+
{ error: "Failed to delete project" },
|
|
105
|
+
{ status: 500 }
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import { detectDevServers, validateWorkingDirectory } from "@/lib/projects";
|
|
3
|
+
|
|
4
|
+
// POST /api/projects/detect - Detect available dev servers in a directory
|
|
5
|
+
export async function POST(request: NextRequest) {
|
|
6
|
+
try {
|
|
7
|
+
const body = await request.json();
|
|
8
|
+
const { workingDirectory } = body;
|
|
9
|
+
|
|
10
|
+
if (!workingDirectory) {
|
|
11
|
+
return NextResponse.json(
|
|
12
|
+
{ error: "Working directory is required" },
|
|
13
|
+
{ status: 400 }
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!validateWorkingDirectory(workingDirectory)) {
|
|
18
|
+
return NextResponse.json(
|
|
19
|
+
{ error: "Working directory does not exist" },
|
|
20
|
+
{ status: 400 }
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const detected = await detectDevServers(workingDirectory);
|
|
25
|
+
return NextResponse.json({ detected });
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error("Error detecting dev servers:", error);
|
|
28
|
+
return NextResponse.json(
|
|
29
|
+
{ error: "Failed to detect dev servers" },
|
|
30
|
+
{ status: 500 }
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import {
|
|
3
|
+
getAllProjectsWithDevServers,
|
|
4
|
+
createProject,
|
|
5
|
+
validateWorkingDirectory,
|
|
6
|
+
} from "@/lib/projects";
|
|
7
|
+
|
|
8
|
+
// GET /api/projects - List all projects with dev server configs
|
|
9
|
+
export async function GET() {
|
|
10
|
+
try {
|
|
11
|
+
const projects = await getAllProjectsWithDevServers();
|
|
12
|
+
return NextResponse.json({ projects });
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error("Error getting projects:", error);
|
|
15
|
+
return NextResponse.json(
|
|
16
|
+
{ error: "Failed to get projects" },
|
|
17
|
+
{ status: 500 }
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// POST /api/projects - Create a new project
|
|
23
|
+
export async function POST(request: NextRequest) {
|
|
24
|
+
try {
|
|
25
|
+
const body = await request.json();
|
|
26
|
+
const { name, workingDirectory, agentType, defaultModel, devServers } =
|
|
27
|
+
body;
|
|
28
|
+
|
|
29
|
+
if (!name || !workingDirectory) {
|
|
30
|
+
return NextResponse.json(
|
|
31
|
+
{ error: "Name and working directory are required" },
|
|
32
|
+
{ status: 400 }
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!validateWorkingDirectory(workingDirectory)) {
|
|
37
|
+
return NextResponse.json(
|
|
38
|
+
{ error: "Working directory does not exist" },
|
|
39
|
+
{ status: 400 }
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const project = await createProject({
|
|
44
|
+
name,
|
|
45
|
+
workingDirectory,
|
|
46
|
+
agentType,
|
|
47
|
+
defaultModel,
|
|
48
|
+
devServers,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return NextResponse.json({ project }, { status: 201 });
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error("Error creating project:", error);
|
|
54
|
+
return NextResponse.json(
|
|
55
|
+
{ error: "Failed to create project" },
|
|
56
|
+
{ status: 500 }
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { exec } from "child_process";
|
|
3
|
+
import { promisify } from "util";
|
|
4
|
+
import { getDb } from "@/lib/db";
|
|
5
|
+
|
|
6
|
+
const execAsync = promisify(exec);
|
|
7
|
+
|
|
8
|
+
// GET: Check tmux environment for Claude session ID
|
|
9
|
+
export async function GET(
|
|
10
|
+
request: Request,
|
|
11
|
+
{ params }: { params: Promise<{ id: string }> }
|
|
12
|
+
) {
|
|
13
|
+
const { id } = await params;
|
|
14
|
+
const tmuxSession = `claude-${id}`;
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Check tmux environment for CLAUDE_SESSION_ID
|
|
18
|
+
const { stdout } = await execAsync(
|
|
19
|
+
`tmux show-environment -t "${tmuxSession}" CLAUDE_SESSION_ID 2>/dev/null || echo ""`
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const line = stdout.trim();
|
|
23
|
+
if (line.startsWith("CLAUDE_SESSION_ID=")) {
|
|
24
|
+
const sessionId = line.replace("CLAUDE_SESSION_ID=", "");
|
|
25
|
+
if (sessionId && sessionId !== "null") {
|
|
26
|
+
// Update database with the session ID
|
|
27
|
+
getDb()
|
|
28
|
+
.prepare(
|
|
29
|
+
"UPDATE sessions SET claude_session_id = ?, updated_at = datetime('now') WHERE id = ?"
|
|
30
|
+
)
|
|
31
|
+
.run(sessionId, id);
|
|
32
|
+
|
|
33
|
+
return NextResponse.json({ claude_session_id: sessionId });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return NextResponse.json({ claude_session_id: null });
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error("Error getting Claude session ID:", error);
|
|
40
|
+
return NextResponse.json({ claude_session_id: null });
|
|
41
|
+
}
|
|
42
|
+
}
|