-
-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Expand file tree
/
Copy pathhttp-client.ts
More file actions
130 lines (114 loc) · 4.02 KB
/
Copy pathhttp-client.ts
File metadata and controls
130 lines (114 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
export type SessionListItem = {
id: string
title: string
createdAt: string
modifiedAt: string
messageCount: number
projectPath: string
workDir: string
workDirExists: boolean
}
export type RecentProject = {
projectPath: string
realPath: string
projectName: string
isGit: boolean
repoName: string | null
branch: string | null
modifiedAt: string
sessionCount: number
}
export type GitInfo = {
branch: string | null
repoName: string | null
workDir: string
changedFiles: number
}
export type SessionTask = {
id: string
subject: string
status: 'pending' | 'in_progress' | 'completed'
}
export class AdapterHttpClient {
readonly httpBaseUrl: string
constructor(wsUrl: string) {
this.httpBaseUrl = wsUrl
.replace(/^ws:/, 'http:')
.replace(/^wss:/, 'https:')
.replace(/\/$/, '')
}
async createSession(workDir: string): Promise<string> {
const res = await fetch(`${this.httpBaseUrl}/api/sessions`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ workDir }),
})
if (!res.ok) {
const err = await res.json().catch(() => ({ message: res.statusText }))
throw new Error(`Failed to create session: ${(err as any).message}`)
}
const data = (await res.json()) as { sessionId: string }
return data.sessionId
}
async listRecentProjects(): Promise<RecentProject[]> {
const res = await fetch(`${this.httpBaseUrl}/api/sessions/recent-projects`)
if (!res.ok) {
throw new Error(`Failed to list projects: ${res.statusText}`)
}
const data = (await res.json()) as { projects: RecentProject[] }
return data.projects
}
/**
* Match a project by index (1-based) or fuzzy name from recent projects.
* Returns { project, ambiguous[] } — ambiguous is set when multiple projects match.
*/
async matchProject(query: string): Promise<{ project?: RecentProject; ambiguous?: RecentProject[] }> {
const projects = await this.listRecentProjects()
// Try as 1-based index
const num = parseInt(query, 10)
if (!isNaN(num) && num >= 1 && num <= projects.length && String(num) === query.trim()) {
return { project: projects[num - 1] }
}
const q = query.toLowerCase()
// Exact project name match
const exact = projects.find(p => p.projectName.toLowerCase() === q)
if (exact) return { project: exact }
// Fuzzy: name or path contains query
const matches = projects.filter(p =>
p.projectName.toLowerCase().includes(q) ||
p.realPath.toLowerCase().includes(q)
)
if (matches.length === 1) return { project: matches[0] }
if (matches.length > 1) return { ambiguous: matches }
return {}
}
async listSessions(limit = 10, project?: string): Promise<SessionListItem[]> {
const params = new URLSearchParams()
params.set('limit', String(limit))
if (project) params.set('project', project)
const res = await fetch(`${this.httpBaseUrl}/api/sessions?${params}`)
if (!res.ok) {
throw new Error(`Failed to list sessions: ${res.statusText}`)
}
const data = (await res.json()) as { sessions: SessionListItem[] }
return data.sessions
}
async getGitInfo(sessionId: string): Promise<GitInfo> {
const res = await fetch(`${this.httpBaseUrl}/api/sessions/${encodeURIComponent(sessionId)}/git-info`)
if (!res.ok) {
const err = await res.json().catch(() => ({ message: res.statusText }))
throw new Error(`Failed to load git info: ${(err as any).message}`)
}
return (await res.json()) as GitInfo
}
async getTasksForSession(sessionId: string): Promise<SessionTask[]> {
const res = await fetch(`${this.httpBaseUrl}/api/tasks/lists/${encodeURIComponent(sessionId)}`)
if (!res.ok) {
if (res.status === 404) return []
const err = await res.json().catch(() => ({ message: res.statusText }))
throw new Error(`Failed to load tasks: ${(err as any).message}`)
}
const data = (await res.json()) as { tasks?: SessionTask[] }
return Array.isArray(data.tasks) ? data.tasks : []
}
}