@atercates/claude-deck 0.2.4 → 0.2.6
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/app/api/sessions/[id]/fork/route.ts +0 -1
- package/app/api/sessions/[id]/route.ts +0 -5
- package/app/api/sessions/[id]/summarize/route.ts +2 -3
- package/app/api/sessions/route.ts +2 -11
- package/app/api/system/route.ts +2 -0
- package/app/page.tsx +4 -45
- package/components/ClaudeProjects/ClaudeProjectCard.tsx +19 -31
- package/components/ClaudeProjects/ClaudeSessionCard.tsx +20 -31
- package/components/NewSessionDialog/AdvancedSettings.tsx +3 -12
- package/components/NewSessionDialog/NewSessionDialog.types.ts +0 -10
- package/components/NewSessionDialog/ProjectSelector.tsx +2 -7
- package/components/NewSessionDialog/hooks/useNewSessionForm.ts +3 -36
- package/components/NewSessionDialog/index.tsx +0 -7
- package/components/Pane/OpenInVSCode.tsx +6 -1
- package/components/Projects/index.ts +0 -1
- package/components/SessionList/hooks/useSessionListMutations.ts +0 -35
- package/components/views/DesktopView.tsx +1 -6
- package/components/views/MobileView.tsx +6 -1
- package/components/views/types.ts +1 -1
- package/data/sessions/index.ts +0 -1
- package/data/sessions/queries.ts +1 -27
- package/hooks/useSessions.ts +0 -12
- package/lib/db/queries.ts +4 -64
- package/lib/db/types.ts +0 -8
- package/lib/orchestration.ts +10 -15
- package/lib/providers/registry.ts +2 -56
- package/lib/providers.ts +19 -100
- package/lib/status-monitor.ts +40 -15
- package/package.json +1 -1
- package/server.ts +1 -1
- package/app/api/groups/[...path]/route.ts +0 -136
- package/app/api/groups/route.ts +0 -93
- package/components/NewSessionDialog/AgentSelector.tsx +0 -37
- package/components/Projects/ProjectCard.tsx +0 -276
- package/components/TmuxSessions.tsx +0 -132
- package/data/groups/index.ts +0 -1
- package/data/groups/mutations.ts +0 -95
- package/hooks/useGroups.ts +0 -37
- package/hooks/useKeybarVisibility.ts +0 -42
- package/lib/claude/process-manager.ts +0 -278
|
@@ -48,7 +48,6 @@ export function DesktopView({
|
|
|
48
48
|
updateSettings,
|
|
49
49
|
requestPermission,
|
|
50
50
|
attachToSession,
|
|
51
|
-
attachToActiveTmux,
|
|
52
51
|
openSessionInNewTab,
|
|
53
52
|
handleNewSessionInProject,
|
|
54
53
|
handleOpenTerminal,
|
|
@@ -62,18 +61,14 @@ export function DesktopView({
|
|
|
62
61
|
resumeClaudeSession,
|
|
63
62
|
renderPane,
|
|
64
63
|
}: ViewProps) {
|
|
65
|
-
// Select a session by ID — handles both DB sessions and tmux-only sessions
|
|
66
64
|
const selectSessionById = (id: string) => {
|
|
67
65
|
const session = sessions.find((s) => s.id === id);
|
|
68
66
|
if (session) {
|
|
69
67
|
attachToSession(session);
|
|
70
68
|
return;
|
|
71
69
|
}
|
|
72
|
-
// Not in DB — attach directly to the running tmux session
|
|
73
70
|
const status = sessionStatuses[id];
|
|
74
|
-
|
|
75
|
-
attachToActiveTmux(id, status.sessionName);
|
|
76
|
-
}
|
|
71
|
+
resumeClaudeSession(id, status?.cwd || "~");
|
|
77
72
|
};
|
|
78
73
|
|
|
79
74
|
return (
|
|
@@ -49,7 +49,12 @@ export function MobileView({
|
|
|
49
49
|
sessionStatuses={sessionStatuses}
|
|
50
50
|
onSelect={(id) => {
|
|
51
51
|
const session = sessions.find((s) => s.id === id);
|
|
52
|
-
if (session)
|
|
52
|
+
if (session) {
|
|
53
|
+
attachToSession(session);
|
|
54
|
+
} else {
|
|
55
|
+
const status = sessionStatuses[id];
|
|
56
|
+
resumeClaudeSession(id, status?.cwd || "~");
|
|
57
|
+
}
|
|
53
58
|
setSidebarOpen(false);
|
|
54
59
|
}}
|
|
55
60
|
onOpenInTab={(id) => {
|
|
@@ -5,6 +5,7 @@ import type { TabData } from "@/lib/panes";
|
|
|
5
5
|
|
|
6
6
|
export interface SessionStatus {
|
|
7
7
|
sessionName: string;
|
|
8
|
+
cwd?: string | null;
|
|
8
9
|
status: "idle" | "running" | "waiting" | "error" | "dead";
|
|
9
10
|
lastLine?: string;
|
|
10
11
|
waitingContext?: string;
|
|
@@ -39,7 +40,6 @@ export interface ViewProps {
|
|
|
39
40
|
|
|
40
41
|
// Handlers
|
|
41
42
|
attachToSession: (session: Session) => void;
|
|
42
|
-
attachToActiveTmux: (sessionId: string, tmuxSessionName: string) => void;
|
|
43
43
|
openSessionInNewTab: (session: Session) => void;
|
|
44
44
|
handleNewSessionInProject: (projectId: string) => void;
|
|
45
45
|
handleOpenTerminal: (projectId: string) => void;
|
package/data/sessions/index.ts
CHANGED
package/data/sessions/queries.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
-
import type { Session
|
|
2
|
+
import type { Session } from "@/lib/db";
|
|
3
3
|
import type { AgentType } from "@/lib/providers";
|
|
4
4
|
import { sessionKeys } from "./keys";
|
|
5
5
|
|
|
6
6
|
interface SessionsResponse {
|
|
7
7
|
sessions: Session[];
|
|
8
|
-
groups: Group[];
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
async function fetchSessions(): Promise<SessionsResponse> {
|
|
@@ -124,31 +123,6 @@ export function useSummarizeSession() {
|
|
|
124
123
|
});
|
|
125
124
|
}
|
|
126
125
|
|
|
127
|
-
export function useMoveSessionToGroup() {
|
|
128
|
-
const queryClient = useQueryClient();
|
|
129
|
-
|
|
130
|
-
return useMutation({
|
|
131
|
-
mutationFn: async ({
|
|
132
|
-
sessionId,
|
|
133
|
-
groupPath,
|
|
134
|
-
}: {
|
|
135
|
-
sessionId: string;
|
|
136
|
-
groupPath: string;
|
|
137
|
-
}) => {
|
|
138
|
-
const res = await fetch(`/api/sessions/${sessionId}`, {
|
|
139
|
-
method: "PATCH",
|
|
140
|
-
headers: { "Content-Type": "application/json" },
|
|
141
|
-
body: JSON.stringify({ groupPath }),
|
|
142
|
-
});
|
|
143
|
-
if (!res.ok) throw new Error("Failed to move session");
|
|
144
|
-
return res.json();
|
|
145
|
-
},
|
|
146
|
-
onSuccess: () => {
|
|
147
|
-
queryClient.invalidateQueries({ queryKey: sessionKeys.list() });
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
126
|
export function useMoveSessionToProject() {
|
|
153
127
|
const queryClient = useQueryClient();
|
|
154
128
|
|
package/hooks/useSessions.ts
CHANGED
|
@@ -6,20 +6,17 @@ import {
|
|
|
6
6
|
useRenameSession,
|
|
7
7
|
useForkSession,
|
|
8
8
|
useSummarizeSession,
|
|
9
|
-
useMoveSessionToGroup,
|
|
10
9
|
useMoveSessionToProject,
|
|
11
10
|
} from "@/data/sessions";
|
|
12
11
|
|
|
13
12
|
export function useSessions() {
|
|
14
13
|
const { data, refetch } = useSessionsQuery();
|
|
15
14
|
const sessions = data?.sessions ?? [];
|
|
16
|
-
const groups = data?.groups ?? [];
|
|
17
15
|
|
|
18
16
|
const deleteMutation = useDeleteSession();
|
|
19
17
|
const renameMutation = useRenameSession();
|
|
20
18
|
const forkMutation = useForkSession();
|
|
21
19
|
const summarizeMutation = useSummarizeSession();
|
|
22
|
-
const moveToGroupMutation = useMoveSessionToGroup();
|
|
23
20
|
const moveToProjectMutation = useMoveSessionToProject();
|
|
24
21
|
|
|
25
22
|
const fetchSessions = useCallback(async () => {
|
|
@@ -55,13 +52,6 @@ export function useSessions() {
|
|
|
55
52
|
[summarizeMutation]
|
|
56
53
|
);
|
|
57
54
|
|
|
58
|
-
const moveSessionToGroup = useCallback(
|
|
59
|
-
async (sessionId: string, groupPath: string) => {
|
|
60
|
-
await moveToGroupMutation.mutateAsync({ sessionId, groupPath });
|
|
61
|
-
},
|
|
62
|
-
[moveToGroupMutation]
|
|
63
|
-
);
|
|
64
|
-
|
|
65
55
|
const moveSessionToProject = useCallback(
|
|
66
56
|
async (sessionId: string, projectId: string) => {
|
|
67
57
|
await moveToProjectMutation.mutateAsync({ sessionId, projectId });
|
|
@@ -71,7 +61,6 @@ export function useSessions() {
|
|
|
71
61
|
|
|
72
62
|
return {
|
|
73
63
|
sessions,
|
|
74
|
-
groups,
|
|
75
64
|
summarizingSessionId: summarizeMutation.isPending
|
|
76
65
|
? (summarizeMutation.variables as string)
|
|
77
66
|
: null,
|
|
@@ -80,7 +69,6 @@ export function useSessions() {
|
|
|
80
69
|
renameSession,
|
|
81
70
|
forkSession,
|
|
82
71
|
summarizeSession,
|
|
83
|
-
moveSessionToGroup,
|
|
84
72
|
moveSessionToProject,
|
|
85
73
|
};
|
|
86
74
|
}
|
package/lib/db/queries.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getDb } from "./index";
|
|
2
2
|
import type {
|
|
3
3
|
Session,
|
|
4
|
-
Group,
|
|
5
4
|
Project,
|
|
6
5
|
ProjectDevServer,
|
|
7
6
|
ProjectRepository,
|
|
@@ -39,14 +38,13 @@ export const queries = {
|
|
|
39
38
|
parentSessionId: string | null,
|
|
40
39
|
model: string | null,
|
|
41
40
|
systemPrompt: string | null,
|
|
42
|
-
groupPath: string,
|
|
43
41
|
agentType: string,
|
|
44
42
|
autoApprove: boolean,
|
|
45
43
|
projectId: string | null
|
|
46
44
|
) =>
|
|
47
45
|
execute(
|
|
48
|
-
`INSERT INTO sessions (id, name, tmux_name, working_directory, parent_session_id, model, system_prompt,
|
|
49
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,
|
|
46
|
+
`INSERT INTO sessions (id, name, tmux_name, working_directory, parent_session_id, model, system_prompt, agent_type, auto_approve, project_id)
|
|
47
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
50
48
|
[
|
|
51
49
|
id,
|
|
52
50
|
name,
|
|
@@ -55,7 +53,6 @@ export const queries = {
|
|
|
55
53
|
parentSessionId,
|
|
56
54
|
model,
|
|
57
55
|
systemPrompt,
|
|
58
|
-
groupPath,
|
|
59
56
|
agentType,
|
|
60
57
|
autoApprove ? 1 : 0,
|
|
61
58
|
projectId,
|
|
@@ -68,12 +65,6 @@ export const queries = {
|
|
|
68
65
|
getAllSessions: () =>
|
|
69
66
|
query<Session>("SELECT * FROM sessions ORDER BY updated_at DESC"),
|
|
70
67
|
|
|
71
|
-
updateSessionStatus: (status: string, id: string) =>
|
|
72
|
-
execute(
|
|
73
|
-
"UPDATE sessions SET status = ?, updated_at = datetime('now') WHERE id = ?",
|
|
74
|
-
[status, id]
|
|
75
|
-
),
|
|
76
|
-
|
|
77
68
|
updateSessionClaudeId: (claudeSessionId: string, id: string) =>
|
|
78
69
|
execute(
|
|
79
70
|
"UPDATE sessions SET claude_session_id = ?, updated_at = datetime('now') WHERE id = ?",
|
|
@@ -112,24 +103,6 @@ export const queries = {
|
|
|
112
103
|
[prUrl, prNumber, prStatus, id]
|
|
113
104
|
),
|
|
114
105
|
|
|
115
|
-
updateSessionGroup: (groupPath: string, id: string) =>
|
|
116
|
-
execute(
|
|
117
|
-
"UPDATE sessions SET group_path = ?, updated_at = datetime('now') WHERE id = ?",
|
|
118
|
-
[groupPath, id]
|
|
119
|
-
),
|
|
120
|
-
|
|
121
|
-
getSessionsByGroup: (groupPath: string) =>
|
|
122
|
-
query<Session>(
|
|
123
|
-
"SELECT * FROM sessions WHERE group_path = ? ORDER BY updated_at DESC",
|
|
124
|
-
[groupPath]
|
|
125
|
-
),
|
|
126
|
-
|
|
127
|
-
moveSessionsToGroup: (newGroupPath: string, oldGroupPath: string) =>
|
|
128
|
-
execute(
|
|
129
|
-
"UPDATE sessions SET group_path = ?, updated_at = datetime('now') WHERE group_path = ?",
|
|
130
|
-
[newGroupPath, oldGroupPath]
|
|
131
|
-
),
|
|
132
|
-
|
|
133
106
|
updateSessionProject: (projectId: string, id: string) =>
|
|
134
107
|
execute(
|
|
135
108
|
"UPDATE sessions SET project_id = ?, updated_at = datetime('now') WHERE id = ?",
|
|
@@ -162,13 +135,12 @@ export const queries = {
|
|
|
162
135
|
conductorSessionId: string,
|
|
163
136
|
workerTask: string,
|
|
164
137
|
model: string | null,
|
|
165
|
-
groupPath: string,
|
|
166
138
|
agentType: string,
|
|
167
139
|
projectId: string | null
|
|
168
140
|
) =>
|
|
169
141
|
execute(
|
|
170
|
-
`INSERT INTO sessions (id, name, tmux_name, working_directory, conductor_session_id, worker_task, worker_status, model,
|
|
171
|
-
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?,
|
|
142
|
+
`INSERT INTO sessions (id, name, tmux_name, working_directory, conductor_session_id, worker_task, worker_status, model, agent_type, project_id)
|
|
143
|
+
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?)`,
|
|
172
144
|
[
|
|
173
145
|
id,
|
|
174
146
|
name,
|
|
@@ -177,43 +149,11 @@ export const queries = {
|
|
|
177
149
|
conductorSessionId,
|
|
178
150
|
workerTask,
|
|
179
151
|
model,
|
|
180
|
-
groupPath,
|
|
181
152
|
agentType,
|
|
182
153
|
projectId,
|
|
183
154
|
]
|
|
184
155
|
),
|
|
185
156
|
|
|
186
|
-
getAllGroups: () =>
|
|
187
|
-
query<Group>("SELECT * FROM groups ORDER BY sort_order ASC, name ASC"),
|
|
188
|
-
|
|
189
|
-
getGroup: (path: string) =>
|
|
190
|
-
queryOne<Group>("SELECT * FROM groups WHERE path = ?", [path]),
|
|
191
|
-
|
|
192
|
-
createGroup: (path: string, name: string, sortOrder: number) =>
|
|
193
|
-
execute("INSERT INTO groups (path, name, sort_order) VALUES (?, ?, ?)", [
|
|
194
|
-
path,
|
|
195
|
-
name,
|
|
196
|
-
sortOrder,
|
|
197
|
-
]),
|
|
198
|
-
|
|
199
|
-
updateGroupName: (name: string, path: string) =>
|
|
200
|
-
execute("UPDATE groups SET name = ? WHERE path = ?", [name, path]),
|
|
201
|
-
|
|
202
|
-
updateGroupExpanded: (expanded: boolean, path: string) =>
|
|
203
|
-
execute("UPDATE groups SET expanded = ? WHERE path = ?", [
|
|
204
|
-
expanded ? 1 : 0,
|
|
205
|
-
path,
|
|
206
|
-
]),
|
|
207
|
-
|
|
208
|
-
updateGroupOrder: (sortOrder: number, path: string) =>
|
|
209
|
-
execute("UPDATE groups SET sort_order = ? WHERE path = ?", [
|
|
210
|
-
sortOrder,
|
|
211
|
-
path,
|
|
212
|
-
]),
|
|
213
|
-
|
|
214
|
-
deleteGroup: (path: string) =>
|
|
215
|
-
execute("DELETE FROM groups WHERE path = ?", [path]),
|
|
216
|
-
|
|
217
157
|
createProject: (
|
|
218
158
|
id: string,
|
|
219
159
|
name: string,
|
package/lib/db/types.ts
CHANGED
|
@@ -31,14 +31,6 @@ export interface Session {
|
|
|
31
31
|
worker_status: "pending" | "running" | "completed" | "failed" | null;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export interface Group {
|
|
35
|
-
path: string;
|
|
36
|
-
name: string;
|
|
37
|
-
expanded: boolean;
|
|
38
|
-
sort_order: number;
|
|
39
|
-
created_at: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
34
|
export interface Project {
|
|
43
35
|
id: string;
|
|
44
36
|
name: string;
|
package/lib/orchestration.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { promisify } from "util";
|
|
|
11
11
|
import { queries, type Session } from "./db";
|
|
12
12
|
import { createWorktree, deleteWorktree } from "./worktrees";
|
|
13
13
|
import { setupWorktree } from "./env-setup";
|
|
14
|
-
import { type AgentType,
|
|
14
|
+
import { type AgentType, CLAUDE_COMMAND, buildClaudeFlags } from "./providers";
|
|
15
15
|
import { getStatusSnapshot } from "./status-monitor";
|
|
16
16
|
import { getSessionIdFromName } from "./providers/registry";
|
|
17
17
|
import { wrapWithBanner } from "./banner";
|
|
@@ -95,7 +95,7 @@ export async function spawnWorker(
|
|
|
95
95
|
|
|
96
96
|
const sessionId = randomUUID();
|
|
97
97
|
const sessionName = taskToSessionName(task);
|
|
98
|
-
|
|
98
|
+
// Provider is always claude
|
|
99
99
|
|
|
100
100
|
let worktreePath: string | null = null;
|
|
101
101
|
let actualWorkingDir = workingDirectory;
|
|
@@ -132,7 +132,7 @@ export async function spawnWorker(
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
// Create session in database
|
|
135
|
-
const tmuxName =
|
|
135
|
+
const tmuxName = `claude-${sessionId}`;
|
|
136
136
|
await queries.createWorkerSession(
|
|
137
137
|
sessionId,
|
|
138
138
|
sessionName,
|
|
@@ -141,7 +141,6 @@ export async function spawnWorker(
|
|
|
141
141
|
conductorSessionId,
|
|
142
142
|
task,
|
|
143
143
|
model,
|
|
144
|
-
"sessions", // group_path
|
|
145
144
|
agentType,
|
|
146
145
|
"uncategorized" // project_id
|
|
147
146
|
);
|
|
@@ -158,15 +157,15 @@ export async function spawnWorker(
|
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
// Create tmux session and start the agent
|
|
161
|
-
const tmuxSessionName =
|
|
160
|
+
const tmuxSessionName = `claude-${sessionId}`;
|
|
162
161
|
const cwd = actualWorkingDir.replace("~", "$HOME");
|
|
163
162
|
|
|
164
163
|
// Build the initial prompt command (workers use auto-approve by default for automation)
|
|
165
|
-
const flags =
|
|
164
|
+
const flags = buildClaudeFlags({ model, autoApprove: true });
|
|
166
165
|
const flagsStr = flags.join(" ");
|
|
167
166
|
|
|
168
167
|
// Create tmux session with the agent and banner
|
|
169
|
-
const agentCmd = `${
|
|
168
|
+
const agentCmd = `${CLAUDE_COMMAND} ${flagsStr}`;
|
|
170
169
|
const newSessionCmd = wrapWithBanner(agentCmd);
|
|
171
170
|
const createCmd = `tmux set -g mouse on 2>/dev/null; tmux new-session -d -s "${tmuxSessionName}" -c "${cwd}" "${newSessionCmd}"`;
|
|
172
171
|
|
|
@@ -271,8 +270,7 @@ export async function getWorkers(
|
|
|
271
270
|
const workerInfos: WorkerInfo[] = [];
|
|
272
271
|
|
|
273
272
|
for (const worker of workers) {
|
|
274
|
-
const
|
|
275
|
-
const tmuxSessionName = worker.tmux_name || `${provider.id}-${worker.id}`;
|
|
273
|
+
const tmuxSessionName = worker.tmux_name || `claude-${worker.id}`;
|
|
276
274
|
|
|
277
275
|
// Get live status from cached monitor snapshot
|
|
278
276
|
const sessionId = getSessionIdFromName(tmuxSessionName);
|
|
@@ -318,8 +316,7 @@ export async function getWorkerOutput(
|
|
|
318
316
|
throw new Error(`Worker ${workerId} not found`);
|
|
319
317
|
}
|
|
320
318
|
|
|
321
|
-
const
|
|
322
|
-
const tmuxSessionName = session.tmux_name || `${provider.id}-${workerId}`;
|
|
319
|
+
const tmuxSessionName = session.tmux_name || `claude-${workerId}`;
|
|
323
320
|
|
|
324
321
|
try {
|
|
325
322
|
const { stdout } = await execAsync(
|
|
@@ -343,8 +340,7 @@ export async function sendToWorker(
|
|
|
343
340
|
throw new Error(`Worker ${workerId} not found`);
|
|
344
341
|
}
|
|
345
342
|
|
|
346
|
-
const
|
|
347
|
-
const tmuxSessionName = session.tmux_name || `${provider.id}-${workerId}`;
|
|
343
|
+
const tmuxSessionName = session.tmux_name || `claude-${workerId}`;
|
|
348
344
|
|
|
349
345
|
try {
|
|
350
346
|
const escapedMessage = message.replace(/"/g, '\\"').replace(/\$/g, "\\$");
|
|
@@ -383,8 +379,7 @@ export async function killWorker(
|
|
|
383
379
|
return;
|
|
384
380
|
}
|
|
385
381
|
|
|
386
|
-
const
|
|
387
|
-
const tmuxSessionName = session.tmux_name || `${provider.id}-${workerId}`;
|
|
382
|
+
const tmuxSessionName = session.tmux_name || `claude-${workerId}`;
|
|
388
383
|
|
|
389
384
|
// Kill tmux session
|
|
390
385
|
try {
|
|
@@ -1,56 +1,4 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
export type ProviderId = (typeof PROVIDER_IDS)[number];
|
|
4
|
-
|
|
5
|
-
export interface ProviderDefinition {
|
|
6
|
-
id: ProviderId;
|
|
7
|
-
name: string;
|
|
8
|
-
description: string;
|
|
9
|
-
cli: string;
|
|
10
|
-
configDir: string;
|
|
11
|
-
autoApproveFlag?: string;
|
|
12
|
-
supportsResume: boolean;
|
|
13
|
-
supportsFork: boolean;
|
|
14
|
-
resumeFlag?: string;
|
|
15
|
-
modelFlag?: string;
|
|
16
|
-
initialPromptFlag?: string;
|
|
17
|
-
defaultArgs?: string[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const PROVIDERS: ProviderDefinition[] = [
|
|
21
|
-
{
|
|
22
|
-
id: "claude",
|
|
23
|
-
name: "Claude Code",
|
|
24
|
-
description: "Anthropic's official CLI",
|
|
25
|
-
cli: "claude",
|
|
26
|
-
configDir: "~/.claude",
|
|
27
|
-
autoApproveFlag: "--dangerously-skip-permissions",
|
|
28
|
-
supportsResume: true,
|
|
29
|
-
supportsFork: true,
|
|
30
|
-
resumeFlag: "--resume",
|
|
31
|
-
initialPromptFlag: "",
|
|
32
|
-
},
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
export const PROVIDER_MAP = new Map<ProviderId, ProviderDefinition>(
|
|
36
|
-
PROVIDERS.map((provider) => [provider.id, provider])
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
export function getProviderDefinition(id: ProviderId): ProviderDefinition {
|
|
40
|
-
const provider = PROVIDER_MAP.get(id);
|
|
41
|
-
if (!provider) {
|
|
42
|
-
throw new Error(`Unknown provider: ${id}`);
|
|
43
|
-
}
|
|
44
|
-
return provider;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function getAllProviderDefinitions(): ProviderDefinition[] {
|
|
48
|
-
return PROVIDERS;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function isValidProviderId(value: string): value is ProviderId {
|
|
52
|
-
return PROVIDER_MAP.has(value as ProviderId);
|
|
53
|
-
}
|
|
1
|
+
export type ProviderId = "claude";
|
|
54
2
|
|
|
55
3
|
export function getManagedSessionPattern(): RegExp {
|
|
56
4
|
return /^claude-(new-)?[0-9a-z]{4,}/i;
|
|
@@ -59,9 +7,7 @@ export function getManagedSessionPattern(): RegExp {
|
|
|
59
7
|
export function getProviderIdFromSessionName(
|
|
60
8
|
sessionName: string
|
|
61
9
|
): ProviderId | null {
|
|
62
|
-
if (sessionName.startsWith("claude-"))
|
|
63
|
-
return "claude";
|
|
64
|
-
}
|
|
10
|
+
if (sessionName.startsWith("claude-")) return "claude";
|
|
65
11
|
return null;
|
|
66
12
|
}
|
|
67
13
|
|
package/lib/providers.ts
CHANGED
|
@@ -1,25 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type ProviderId,
|
|
3
|
-
getProviderDefinition,
|
|
4
|
-
isValidProviderId,
|
|
5
|
-
} from "./providers/registry";
|
|
1
|
+
import type { ProviderId } from "./providers/registry";
|
|
6
2
|
|
|
7
3
|
export type AgentType = ProviderId;
|
|
8
4
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
name: string;
|
|
12
|
-
description: string;
|
|
13
|
-
command: string;
|
|
14
|
-
supportsResume: boolean;
|
|
15
|
-
supportsFork: boolean;
|
|
16
|
-
buildFlags(options: BuildFlagsOptions): string[];
|
|
17
|
-
waitingPatterns: RegExp[];
|
|
18
|
-
runningPatterns: RegExp[];
|
|
19
|
-
idlePatterns: RegExp[];
|
|
20
|
-
getSessionId?: (projectPath: string) => string | null;
|
|
21
|
-
configDir: string;
|
|
22
|
-
}
|
|
5
|
+
export const CLAUDE_COMMAND = "claude";
|
|
6
|
+
export const CLAUDE_AUTO_APPROVE_FLAG = "--dangerously-skip-permissions";
|
|
23
7
|
|
|
24
8
|
export interface BuildFlagsOptions {
|
|
25
9
|
sessionId?: string | null;
|
|
@@ -30,92 +14,27 @@ export interface BuildFlagsOptions {
|
|
|
30
14
|
initialPrompt?: string;
|
|
31
15
|
}
|
|
32
16
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export const claudeProvider: AgentProvider = {
|
|
36
|
-
id: "claude",
|
|
37
|
-
name: "Claude Code",
|
|
38
|
-
description: "Anthropic's official CLI",
|
|
39
|
-
command: "claude",
|
|
40
|
-
configDir: "~/.claude",
|
|
41
|
-
supportsResume: true,
|
|
42
|
-
supportsFork: true,
|
|
43
|
-
|
|
44
|
-
buildFlags(options: BuildFlagsOptions): string[] {
|
|
45
|
-
const def = getProviderDefinition("claude");
|
|
46
|
-
const flags: string[] = [];
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
(options.skipPermissions || options.autoApprove) &&
|
|
50
|
-
def.autoApproveFlag
|
|
51
|
-
) {
|
|
52
|
-
flags.push(def.autoApproveFlag);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (options.sessionId && def.resumeFlag) {
|
|
56
|
-
flags.push(`${def.resumeFlag} ${options.sessionId}`);
|
|
57
|
-
} else if (options.parentSessionId && def.resumeFlag) {
|
|
58
|
-
flags.push(`${def.resumeFlag} ${options.parentSessionId}`);
|
|
59
|
-
flags.push("--fork-session");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (options.initialPrompt?.trim() && def.initialPromptFlag !== undefined) {
|
|
63
|
-
const prompt = options.initialPrompt.trim();
|
|
64
|
-
const escapedPrompt = prompt.replace(/'/g, "'\\''");
|
|
65
|
-
flags.push(`'${escapedPrompt}'`);
|
|
66
|
-
}
|
|
17
|
+
export function buildClaudeFlags(options: BuildFlagsOptions): string[] {
|
|
18
|
+
const flags: string[] = [];
|
|
67
19
|
|
|
68
|
-
|
|
69
|
-
|
|
20
|
+
if (options.skipPermissions || options.autoApprove) {
|
|
21
|
+
flags.push(CLAUDE_AUTO_APPROVE_FLAG);
|
|
22
|
+
}
|
|
70
23
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
/Continue\?/i,
|
|
77
|
-
/Press Enter/i,
|
|
78
|
-
/waiting for/i,
|
|
79
|
-
/\(yes\/no\)/i,
|
|
80
|
-
/Do you want to/i,
|
|
81
|
-
/Esc to cancel/i,
|
|
82
|
-
/>\s*1\.\s*Yes/,
|
|
83
|
-
/Yes, allow all/i,
|
|
84
|
-
/allow all edits/i,
|
|
85
|
-
/allow all commands/i,
|
|
86
|
-
],
|
|
24
|
+
if (options.sessionId) {
|
|
25
|
+
flags.push("--resume", options.sessionId);
|
|
26
|
+
} else if (options.parentSessionId) {
|
|
27
|
+
flags.push("--resume", options.parentSessionId, "--fork-session");
|
|
28
|
+
}
|
|
87
29
|
|
|
88
|
-
|
|
89
|
-
/
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
/Writing/i,
|
|
93
|
-
/Searching/i,
|
|
94
|
-
/Running/i,
|
|
95
|
-
/Executing/i,
|
|
96
|
-
SPINNER_CHARS,
|
|
97
|
-
],
|
|
30
|
+
if (options.initialPrompt?.trim()) {
|
|
31
|
+
const escapedPrompt = options.initialPrompt.trim().replace(/'/g, "'\\''");
|
|
32
|
+
flags.push(`'${escapedPrompt}'`);
|
|
33
|
+
}
|
|
98
34
|
|
|
99
|
-
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
export const providers: Record<AgentType, AgentProvider> = {
|
|
103
|
-
claude: claudeProvider,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
export function getProvider(agentType: AgentType): AgentProvider {
|
|
107
|
-
return providers[agentType] || claudeProvider;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function getAllProviders(): AgentProvider[] {
|
|
111
|
-
return Object.values(providers);
|
|
35
|
+
return flags;
|
|
112
36
|
}
|
|
113
37
|
|
|
114
38
|
export function isValidAgentType(value: string): value is AgentType {
|
|
115
|
-
return
|
|
39
|
+
return value === "claude";
|
|
116
40
|
}
|
|
117
|
-
|
|
118
|
-
export {
|
|
119
|
-
getProviderDefinition,
|
|
120
|
-
getAllProviderDefinitions,
|
|
121
|
-
} from "./providers/registry";
|