@pixelbyte-software/pixcode 1.33.9 → 1.33.11
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/api-docs.html +373 -857
- package/dist/assets/{index-DpIcI9Q1.js → index-oLYHJ2X5.js} +154 -166
- package/dist/index.html +1 -1
- package/dist/openapi.yaml +1311 -0
- package/dist-server/server/gemini-cli.js +59 -0
- package/dist-server/server/gemini-cli.js.map +1 -1
- package/dist-server/server/index.js +6 -1
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/middleware/auth.js +51 -9
- package/dist-server/server/middleware/auth.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +54 -15
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/qwen/qwen-sessions.provider.js +46 -0
- package/dist-server/server/modules/providers/list/qwen/qwen-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/provider.routes.js +32 -1
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
- package/dist-server/server/opencode-cli.js +41 -2
- package/dist-server/server/opencode-cli.js.map +1 -1
- package/dist-server/server/opencode-response-handler.js +36 -34
- package/dist-server/server/opencode-response-handler.js.map +1 -1
- package/dist-server/server/routes/agent.js +187 -56
- package/dist-server/server/routes/agent.js.map +1 -1
- package/dist-server/server/routes/projects.js +134 -8
- package/dist-server/server/routes/projects.js.map +1 -1
- package/dist-server/server/services/provider-credentials.js +42 -8
- package/dist-server/server/services/provider-credentials.js.map +1 -1
- package/package.json +1 -1
- package/server/gemini-cli.js +60 -0
- package/server/index.js +6 -1
- package/server/middleware/auth.js +50 -9
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +60 -21
- package/server/modules/providers/list/qwen/qwen-sessions.provider.ts +47 -0
- package/server/modules/providers/provider.routes.ts +37 -4
- package/server/opencode-cli.js +41 -2
- package/server/opencode-response-handler.js +36 -29
- package/server/routes/agent.js +178 -58
- package/server/routes/projects.js +136 -8
- package/server/services/provider-credentials.js +42 -8
|
@@ -0,0 +1,1311 @@
|
|
|
1
|
+
openapi: 3.1.0
|
|
2
|
+
info:
|
|
3
|
+
title: Pixcode REST API
|
|
4
|
+
version: 1.33.10
|
|
5
|
+
description: |
|
|
6
|
+
REST API for Pixcode — the multi-CLI web UI for Claude Code, Cursor CLI,
|
|
7
|
+
Codex, Gemini CLI, Qwen Code, and OpenCode.
|
|
8
|
+
|
|
9
|
+
## Authentication
|
|
10
|
+
|
|
11
|
+
Most endpoints require authentication. Two schemes are accepted:
|
|
12
|
+
|
|
13
|
+
- **JWT cookie** (`token` HTTP-only cookie) — set automatically when the
|
|
14
|
+
browser logs in via `POST /api/auth/login`.
|
|
15
|
+
- **API key** (`Authorization: Bearer ck_...`) — generated under
|
|
16
|
+
Settings → API. API keys never expire and survive server restarts.
|
|
17
|
+
|
|
18
|
+
Endpoints flagged `apiKey` accept both.
|
|
19
|
+
|
|
20
|
+
## Streaming endpoints
|
|
21
|
+
|
|
22
|
+
Three classes of endpoint stream beyond plain JSON:
|
|
23
|
+
|
|
24
|
+
- **WebSocket** (`/ws`, `/shell`) — chat session bidirectional traffic. Not
|
|
25
|
+
documented here; see `docs/websocket-protocol.md` if it exists, or read
|
|
26
|
+
`server/index.js` `handleChatConnection`.
|
|
27
|
+
- **SSE** (Server-Sent Events) — long-running jobs. Each `data:` frame
|
|
28
|
+
contains a JSON event; the stream ends with `event: done` or `event: error`.
|
|
29
|
+
- **NDJSON** — provider chat output (one JSON event per line) when the
|
|
30
|
+
backend forwards from a CLI's `--format json` mode.
|
|
31
|
+
|
|
32
|
+
## Errors
|
|
33
|
+
|
|
34
|
+
Errors share a consistent envelope:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{ "success": false, "error": { "code": "ROUTE_NOT_FOUND", "message": "..." } }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
contact:
|
|
41
|
+
name: Pixcode on GitHub
|
|
42
|
+
url: https://github.com/alicomert/pixcode
|
|
43
|
+
license:
|
|
44
|
+
name: AGPL-3.0-or-later
|
|
45
|
+
url: https://www.gnu.org/licenses/agpl-3.0.txt
|
|
46
|
+
|
|
47
|
+
servers:
|
|
48
|
+
- url: http://localhost:3001
|
|
49
|
+
description: Local development server
|
|
50
|
+
- url: '{protocol}://{host}'
|
|
51
|
+
description: Self-hosted Pixcode instance
|
|
52
|
+
variables:
|
|
53
|
+
protocol:
|
|
54
|
+
enum: [http, https]
|
|
55
|
+
default: http
|
|
56
|
+
host:
|
|
57
|
+
default: localhost:3001
|
|
58
|
+
|
|
59
|
+
tags:
|
|
60
|
+
- name: System
|
|
61
|
+
description: Health, version, and self-update.
|
|
62
|
+
- name: Authentication
|
|
63
|
+
description: Login, register, JWT lifecycle, API keys.
|
|
64
|
+
- name: Projects
|
|
65
|
+
description: Project CRUD and session enumeration.
|
|
66
|
+
- name: Files
|
|
67
|
+
description: Project filesystem read/write and directory traversal.
|
|
68
|
+
- name: Sessions
|
|
69
|
+
description: Conversation sessions across providers.
|
|
70
|
+
- name: Git
|
|
71
|
+
description: Git status, diffs, branches, commits, push/pull.
|
|
72
|
+
- name: Providers
|
|
73
|
+
description: Multi-CLI provider auth, install, sessions, configuration.
|
|
74
|
+
- name: Network
|
|
75
|
+
description: LAN discovery, UPnP, public tunnel.
|
|
76
|
+
- name: Settings
|
|
77
|
+
description: User-scoped preferences and notification channels.
|
|
78
|
+
- name: Search
|
|
79
|
+
description: Full-text search across conversations.
|
|
80
|
+
- name: MCP
|
|
81
|
+
description: Model Context Protocol servers and tooling.
|
|
82
|
+
|
|
83
|
+
components:
|
|
84
|
+
securitySchemes:
|
|
85
|
+
bearerAuth:
|
|
86
|
+
type: http
|
|
87
|
+
scheme: bearer
|
|
88
|
+
bearerFormat: JWT
|
|
89
|
+
description: |
|
|
90
|
+
`Authorization: Bearer <token>` — token may be a JWT (issued by
|
|
91
|
+
`/api/auth/login`) or an API key (prefix `ck_`, generated under
|
|
92
|
+
Settings → API). The middleware sniffs the prefix to decide.
|
|
93
|
+
apiKeyAuth:
|
|
94
|
+
type: apiKey
|
|
95
|
+
in: header
|
|
96
|
+
name: X-API-Key
|
|
97
|
+
description: |
|
|
98
|
+
Alternative for tools that can't set `Authorization`. Accepts the same
|
|
99
|
+
`ck_...` keys as `bearerAuth`. Either header works on every secured
|
|
100
|
+
endpoint — pick whichever your client supports.
|
|
101
|
+
cookieAuth:
|
|
102
|
+
type: apiKey
|
|
103
|
+
in: cookie
|
|
104
|
+
name: token
|
|
105
|
+
description: HTTP-only `token` cookie set by `/api/auth/login`.
|
|
106
|
+
|
|
107
|
+
schemas:
|
|
108
|
+
Error:
|
|
109
|
+
type: object
|
|
110
|
+
required: [success, error]
|
|
111
|
+
properties:
|
|
112
|
+
success: { type: boolean, enum: [false] }
|
|
113
|
+
error:
|
|
114
|
+
type: object
|
|
115
|
+
required: [code, message]
|
|
116
|
+
properties:
|
|
117
|
+
code: { type: string, example: ROUTE_NOT_FOUND }
|
|
118
|
+
message: { type: string }
|
|
119
|
+
|
|
120
|
+
Health:
|
|
121
|
+
type: object
|
|
122
|
+
required: [status, timestamp]
|
|
123
|
+
properties:
|
|
124
|
+
status: { type: string, enum: [ok] }
|
|
125
|
+
timestamp: { type: string, format: date-time }
|
|
126
|
+
version:
|
|
127
|
+
type: string
|
|
128
|
+
description: Server version (matches semver `MAJOR.MINOR.PATCH`).
|
|
129
|
+
example: 1.33.9
|
|
130
|
+
installMode:
|
|
131
|
+
type: string
|
|
132
|
+
enum: [git, npm-global, runtime-dir, docker]
|
|
133
|
+
|
|
134
|
+
User:
|
|
135
|
+
type: object
|
|
136
|
+
properties:
|
|
137
|
+
id: { type: integer }
|
|
138
|
+
username: { type: string }
|
|
139
|
+
email: { type: string, format: email, nullable: true }
|
|
140
|
+
created_at: { type: string, format: date-time }
|
|
141
|
+
|
|
142
|
+
AuthStatus:
|
|
143
|
+
type: object
|
|
144
|
+
properties:
|
|
145
|
+
success: { type: boolean }
|
|
146
|
+
isAuthenticated: { type: boolean }
|
|
147
|
+
needsSetup: { type: boolean, description: 'true if no users exist yet — UI shows registration screen.' }
|
|
148
|
+
user: { $ref: '#/components/schemas/User' }
|
|
149
|
+
|
|
150
|
+
LoginRequest:
|
|
151
|
+
type: object
|
|
152
|
+
required: [username, password]
|
|
153
|
+
properties:
|
|
154
|
+
username: { type: string }
|
|
155
|
+
password: { type: string, format: password }
|
|
156
|
+
|
|
157
|
+
LoginResponse:
|
|
158
|
+
type: object
|
|
159
|
+
properties:
|
|
160
|
+
success: { type: boolean }
|
|
161
|
+
token: { type: string, description: JWT (also set as `token` cookie). }
|
|
162
|
+
user: { $ref: '#/components/schemas/User' }
|
|
163
|
+
|
|
164
|
+
ApiKey:
|
|
165
|
+
type: object
|
|
166
|
+
properties:
|
|
167
|
+
id: { type: integer }
|
|
168
|
+
key_name: { type: string }
|
|
169
|
+
api_key: { type: string, description: 'Format: `ck_<32-hex>`. Returned in full on creation only.' }
|
|
170
|
+
created_at: { type: string, format: date-time }
|
|
171
|
+
last_used: { type: string, format: date-time, nullable: true }
|
|
172
|
+
is_active: { type: boolean }
|
|
173
|
+
|
|
174
|
+
Project:
|
|
175
|
+
type: object
|
|
176
|
+
properties:
|
|
177
|
+
name: { type: string }
|
|
178
|
+
displayName: { type: string }
|
|
179
|
+
path: { type: string }
|
|
180
|
+
fullPath: { type: string }
|
|
181
|
+
sessions:
|
|
182
|
+
type: array
|
|
183
|
+
items: { $ref: '#/components/schemas/SessionMeta' }
|
|
184
|
+
|
|
185
|
+
SessionMeta:
|
|
186
|
+
type: object
|
|
187
|
+
properties:
|
|
188
|
+
id: { type: string }
|
|
189
|
+
title: { type: string, nullable: true }
|
|
190
|
+
provider:
|
|
191
|
+
type: string
|
|
192
|
+
enum: [claude, cursor, codex, gemini, qwen, opencode]
|
|
193
|
+
lastActivity: { type: string, format: date-time }
|
|
194
|
+
|
|
195
|
+
GitStatus:
|
|
196
|
+
type: object
|
|
197
|
+
properties:
|
|
198
|
+
branch: { type: string }
|
|
199
|
+
ahead: { type: integer }
|
|
200
|
+
behind: { type: integer }
|
|
201
|
+
modified: { type: array, items: { type: string } }
|
|
202
|
+
added: { type: array, items: { type: string } }
|
|
203
|
+
deleted: { type: array, items: { type: string } }
|
|
204
|
+
untracked: { type: array, items: { type: string } }
|
|
205
|
+
|
|
206
|
+
ProviderInfo:
|
|
207
|
+
type: object
|
|
208
|
+
properties:
|
|
209
|
+
id:
|
|
210
|
+
type: string
|
|
211
|
+
enum: [claude, cursor, codex, gemini, qwen, opencode]
|
|
212
|
+
installed: { type: boolean }
|
|
213
|
+
authenticated: { type: boolean }
|
|
214
|
+
version: { type: string, nullable: true }
|
|
215
|
+
binaryPath: { type: string, nullable: true }
|
|
216
|
+
|
|
217
|
+
InstallJob:
|
|
218
|
+
type: object
|
|
219
|
+
properties:
|
|
220
|
+
jobId: { type: string }
|
|
221
|
+
provider: { type: string }
|
|
222
|
+
status: { type: string, enum: [pending, running, succeeded, failed, cancelled] }
|
|
223
|
+
|
|
224
|
+
security:
|
|
225
|
+
- bearerAuth: []
|
|
226
|
+
- apiKeyAuth: []
|
|
227
|
+
- cookieAuth: []
|
|
228
|
+
|
|
229
|
+
paths:
|
|
230
|
+
/health:
|
|
231
|
+
get:
|
|
232
|
+
tags: [System]
|
|
233
|
+
summary: Liveness + version probe
|
|
234
|
+
description: |
|
|
235
|
+
Public, unauthenticated. Returns server version and install mode so the
|
|
236
|
+
UI can detect updates and stale daemons. Used by:
|
|
237
|
+
|
|
238
|
+
- The version-upgrade modal — polls during/after `/api/system/update`
|
|
239
|
+
to detect when the new version is up.
|
|
240
|
+
- `useVersionCheck` — falls back to the bundle's baked
|
|
241
|
+
`__PIXCODE_UI_VERSION__` if `version` is missing or non-semver.
|
|
242
|
+
security: []
|
|
243
|
+
responses:
|
|
244
|
+
'200':
|
|
245
|
+
description: Server is up.
|
|
246
|
+
content:
|
|
247
|
+
application/json:
|
|
248
|
+
schema: { $ref: '#/components/schemas/Health' }
|
|
249
|
+
|
|
250
|
+
/api/system/update:
|
|
251
|
+
post:
|
|
252
|
+
tags: [System]
|
|
253
|
+
summary: Self-update (SSE)
|
|
254
|
+
description: |
|
|
255
|
+
Streams the update process via SSE. Behavior depends on
|
|
256
|
+
`installMode`:
|
|
257
|
+
|
|
258
|
+
- **runtime-dir** (desktop wrapper): downloads the latest npm tarball,
|
|
259
|
+
atomically swaps files, emits `done { selfRestarting: true }`, then
|
|
260
|
+
`process.exit(42)` so the wrapper respawns. **Don't `POST /restart`
|
|
261
|
+
when `selfRestarting` is true.**
|
|
262
|
+
- **git/npm-global**: runs `git pull && npm install` or
|
|
263
|
+
`npm install -g`. The supervising daemon may restart the server
|
|
264
|
+
mid-stream — clients should treat a bare close + `/health` version
|
|
265
|
+
bump as success.
|
|
266
|
+
responses:
|
|
267
|
+
'200':
|
|
268
|
+
description: 'SSE stream of `event: log`, `event: progress`, `event: done`, `event: error`.'
|
|
269
|
+
content:
|
|
270
|
+
text/event-stream:
|
|
271
|
+
schema: { type: string }
|
|
272
|
+
|
|
273
|
+
/api/system/restart:
|
|
274
|
+
post:
|
|
275
|
+
tags: [System]
|
|
276
|
+
summary: Restart the server process
|
|
277
|
+
description: |
|
|
278
|
+
Triggers a graceful exit; the supervising daemon (systemd/pm2/electron
|
|
279
|
+
wrapper) is expected to respawn. Don't call after a `selfRestarting`
|
|
280
|
+
update event — the wrapper has already been signalled.
|
|
281
|
+
responses:
|
|
282
|
+
'200':
|
|
283
|
+
description: Restart scheduled.
|
|
284
|
+
|
|
285
|
+
/api/auth/status:
|
|
286
|
+
get:
|
|
287
|
+
tags: [Authentication]
|
|
288
|
+
summary: Probe authentication state
|
|
289
|
+
description: Returns whether the current request carries a valid token, and whether the system has any users at all (`needsSetup`).
|
|
290
|
+
security: []
|
|
291
|
+
responses:
|
|
292
|
+
'200':
|
|
293
|
+
description: Auth status.
|
|
294
|
+
content:
|
|
295
|
+
application/json:
|
|
296
|
+
schema: { $ref: '#/components/schemas/AuthStatus' }
|
|
297
|
+
|
|
298
|
+
/api/auth/register:
|
|
299
|
+
post:
|
|
300
|
+
tags: [Authentication]
|
|
301
|
+
summary: Register the first user
|
|
302
|
+
description: Only allowed while `needsSetup` is true. Subsequent calls return 403.
|
|
303
|
+
security: []
|
|
304
|
+
requestBody:
|
|
305
|
+
required: true
|
|
306
|
+
content:
|
|
307
|
+
application/json:
|
|
308
|
+
schema: { $ref: '#/components/schemas/LoginRequest' }
|
|
309
|
+
responses:
|
|
310
|
+
'200':
|
|
311
|
+
description: Registered + auto-logged-in.
|
|
312
|
+
content:
|
|
313
|
+
application/json:
|
|
314
|
+
schema: { $ref: '#/components/schemas/LoginResponse' }
|
|
315
|
+
'403':
|
|
316
|
+
description: Setup already complete.
|
|
317
|
+
content:
|
|
318
|
+
application/json:
|
|
319
|
+
schema: { $ref: '#/components/schemas/Error' }
|
|
320
|
+
|
|
321
|
+
/api/auth/login:
|
|
322
|
+
post:
|
|
323
|
+
tags: [Authentication]
|
|
324
|
+
summary: Log in
|
|
325
|
+
security: []
|
|
326
|
+
requestBody:
|
|
327
|
+
required: true
|
|
328
|
+
content:
|
|
329
|
+
application/json:
|
|
330
|
+
schema: { $ref: '#/components/schemas/LoginRequest' }
|
|
331
|
+
responses:
|
|
332
|
+
'200':
|
|
333
|
+
description: Login OK; sets `token` cookie + returns JWT in body.
|
|
334
|
+
content:
|
|
335
|
+
application/json:
|
|
336
|
+
schema: { $ref: '#/components/schemas/LoginResponse' }
|
|
337
|
+
'401':
|
|
338
|
+
description: Invalid credentials.
|
|
339
|
+
|
|
340
|
+
/api/auth/user:
|
|
341
|
+
get:
|
|
342
|
+
tags: [Authentication]
|
|
343
|
+
summary: Current user
|
|
344
|
+
responses:
|
|
345
|
+
'200':
|
|
346
|
+
description: Authenticated user details.
|
|
347
|
+
content:
|
|
348
|
+
application/json:
|
|
349
|
+
schema:
|
|
350
|
+
type: object
|
|
351
|
+
properties:
|
|
352
|
+
user: { $ref: '#/components/schemas/User' }
|
|
353
|
+
|
|
354
|
+
/api/auth/logout:
|
|
355
|
+
post:
|
|
356
|
+
tags: [Authentication]
|
|
357
|
+
summary: Log out
|
|
358
|
+
description: Clears the `token` cookie. JWT remains valid until expiry — server-side blacklist isn't implemented.
|
|
359
|
+
responses:
|
|
360
|
+
'200': { description: OK }
|
|
361
|
+
|
|
362
|
+
/api/settings/api-keys:
|
|
363
|
+
get:
|
|
364
|
+
tags: [Authentication]
|
|
365
|
+
summary: List user API keys
|
|
366
|
+
responses:
|
|
367
|
+
'200':
|
|
368
|
+
description: List of keys (the `api_key` field is masked except on creation).
|
|
369
|
+
content:
|
|
370
|
+
application/json:
|
|
371
|
+
schema:
|
|
372
|
+
type: array
|
|
373
|
+
items: { $ref: '#/components/schemas/ApiKey' }
|
|
374
|
+
post:
|
|
375
|
+
tags: [Authentication]
|
|
376
|
+
summary: Create an API key
|
|
377
|
+
requestBody:
|
|
378
|
+
required: true
|
|
379
|
+
content:
|
|
380
|
+
application/json:
|
|
381
|
+
schema:
|
|
382
|
+
type: object
|
|
383
|
+
required: [name]
|
|
384
|
+
properties:
|
|
385
|
+
name: { type: string, description: 'Human-readable label.' }
|
|
386
|
+
responses:
|
|
387
|
+
'201':
|
|
388
|
+
description: Key created. The full `api_key` value is returned **once** — store it.
|
|
389
|
+
content:
|
|
390
|
+
application/json:
|
|
391
|
+
schema: { $ref: '#/components/schemas/ApiKey' }
|
|
392
|
+
|
|
393
|
+
/api/settings/api-keys/{keyId}:
|
|
394
|
+
delete:
|
|
395
|
+
tags: [Authentication]
|
|
396
|
+
summary: Delete an API key
|
|
397
|
+
parameters:
|
|
398
|
+
- name: keyId
|
|
399
|
+
in: path
|
|
400
|
+
required: true
|
|
401
|
+
schema: { type: integer }
|
|
402
|
+
responses:
|
|
403
|
+
'200': { description: Deleted. }
|
|
404
|
+
|
|
405
|
+
/api/settings/api-keys/{keyId}/toggle:
|
|
406
|
+
patch:
|
|
407
|
+
tags: [Authentication]
|
|
408
|
+
summary: Activate / deactivate an API key
|
|
409
|
+
parameters:
|
|
410
|
+
- name: keyId
|
|
411
|
+
in: path
|
|
412
|
+
required: true
|
|
413
|
+
schema: { type: integer }
|
|
414
|
+
requestBody:
|
|
415
|
+
required: true
|
|
416
|
+
content:
|
|
417
|
+
application/json:
|
|
418
|
+
schema:
|
|
419
|
+
type: object
|
|
420
|
+
properties:
|
|
421
|
+
is_active: { type: boolean }
|
|
422
|
+
responses:
|
|
423
|
+
'200': { description: Updated. }
|
|
424
|
+
|
|
425
|
+
/api/projects:
|
|
426
|
+
get:
|
|
427
|
+
tags: [Projects]
|
|
428
|
+
summary: List all projects
|
|
429
|
+
description: Walks `~/.claude/projects/*` plus any registered workspaces and returns a unified list. Sessions are flattened by provider.
|
|
430
|
+
responses:
|
|
431
|
+
'200':
|
|
432
|
+
description: Project list.
|
|
433
|
+
content:
|
|
434
|
+
application/json:
|
|
435
|
+
schema:
|
|
436
|
+
type: array
|
|
437
|
+
items: { $ref: '#/components/schemas/Project' }
|
|
438
|
+
|
|
439
|
+
/api/projects/quick-start:
|
|
440
|
+
post:
|
|
441
|
+
tags: [Projects]
|
|
442
|
+
summary: Open or create a project from an absolute path
|
|
443
|
+
requestBody:
|
|
444
|
+
required: true
|
|
445
|
+
content:
|
|
446
|
+
application/json:
|
|
447
|
+
schema:
|
|
448
|
+
type: object
|
|
449
|
+
required: [path]
|
|
450
|
+
properties:
|
|
451
|
+
path: { type: string, description: 'Absolute filesystem path.' }
|
|
452
|
+
responses:
|
|
453
|
+
'200':
|
|
454
|
+
description: Project record (created if it didn't exist).
|
|
455
|
+
content:
|
|
456
|
+
application/json:
|
|
457
|
+
schema: { $ref: '#/components/schemas/Project' }
|
|
458
|
+
|
|
459
|
+
/api/projects/{projectName}/rename:
|
|
460
|
+
put:
|
|
461
|
+
tags: [Projects]
|
|
462
|
+
summary: Rename project display
|
|
463
|
+
parameters:
|
|
464
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
465
|
+
requestBody:
|
|
466
|
+
required: true
|
|
467
|
+
content:
|
|
468
|
+
application/json:
|
|
469
|
+
schema:
|
|
470
|
+
type: object
|
|
471
|
+
properties:
|
|
472
|
+
displayName: { type: string }
|
|
473
|
+
responses:
|
|
474
|
+
'200': { description: Renamed. }
|
|
475
|
+
|
|
476
|
+
/api/projects/{projectName}:
|
|
477
|
+
delete:
|
|
478
|
+
tags: [Projects]
|
|
479
|
+
summary: Delete (deregister) a project
|
|
480
|
+
parameters:
|
|
481
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
482
|
+
responses:
|
|
483
|
+
'200': { description: Deleted. }
|
|
484
|
+
|
|
485
|
+
/api/projects/{projectName}/sessions:
|
|
486
|
+
get:
|
|
487
|
+
tags: [Sessions]
|
|
488
|
+
summary: List sessions for a project
|
|
489
|
+
parameters:
|
|
490
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
491
|
+
responses:
|
|
492
|
+
'200':
|
|
493
|
+
description: Sessions sorted by lastActivity desc.
|
|
494
|
+
content:
|
|
495
|
+
application/json:
|
|
496
|
+
schema:
|
|
497
|
+
type: array
|
|
498
|
+
items: { $ref: '#/components/schemas/SessionMeta' }
|
|
499
|
+
|
|
500
|
+
/api/projects/{projectName}/sessions/{sessionId}:
|
|
501
|
+
delete:
|
|
502
|
+
tags: [Sessions]
|
|
503
|
+
summary: Delete a session
|
|
504
|
+
parameters:
|
|
505
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
506
|
+
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
507
|
+
responses:
|
|
508
|
+
'200': { description: Deleted. }
|
|
509
|
+
|
|
510
|
+
/api/sessions/{sessionId}/rename:
|
|
511
|
+
put:
|
|
512
|
+
tags: [Sessions]
|
|
513
|
+
summary: Rename a session
|
|
514
|
+
parameters:
|
|
515
|
+
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
516
|
+
requestBody:
|
|
517
|
+
required: true
|
|
518
|
+
content:
|
|
519
|
+
application/json:
|
|
520
|
+
schema:
|
|
521
|
+
type: object
|
|
522
|
+
properties:
|
|
523
|
+
title: { type: string }
|
|
524
|
+
responses:
|
|
525
|
+
'200': { description: Renamed. }
|
|
526
|
+
|
|
527
|
+
/api/sessions/{sessionId}/messages:
|
|
528
|
+
get:
|
|
529
|
+
tags: [Sessions]
|
|
530
|
+
summary: Get session message history
|
|
531
|
+
description: |
|
|
532
|
+
Note: this is mounted at `/api/sessions`, NOT under `/api/projects` — the
|
|
533
|
+
`projectName` is supplied as a query parameter rather than a path
|
|
534
|
+
segment. The mount lives in `server/routes/messages.js`.
|
|
535
|
+
parameters:
|
|
536
|
+
- { name: sessionId, in: path, required: true, schema: { type: string } }
|
|
537
|
+
- { name: projectName, in: query, required: true, schema: { type: string }, description: Pixcode project the session belongs to. }
|
|
538
|
+
- { name: limit, in: query, required: false, schema: { type: integer, default: 100 } }
|
|
539
|
+
- { name: offset, in: query, required: false, schema: { type: integer, default: 0 } }
|
|
540
|
+
responses:
|
|
541
|
+
'200':
|
|
542
|
+
description: Normalized message stream.
|
|
543
|
+
content:
|
|
544
|
+
application/json:
|
|
545
|
+
schema:
|
|
546
|
+
type: object
|
|
547
|
+
properties:
|
|
548
|
+
messages: { type: array, items: { type: object, additionalProperties: true } }
|
|
549
|
+
total: { type: integer }
|
|
550
|
+
hasMore: { type: boolean }
|
|
551
|
+
|
|
552
|
+
/api/search/conversations:
|
|
553
|
+
get:
|
|
554
|
+
tags: [Search]
|
|
555
|
+
summary: Full-text search across all sessions
|
|
556
|
+
parameters:
|
|
557
|
+
- { name: q, in: query, required: true, schema: { type: string }, description: Search query. }
|
|
558
|
+
- { name: provider, in: query, required: false, schema: { type: string, enum: [claude, cursor, codex, gemini, qwen, opencode] } }
|
|
559
|
+
- { name: limit, in: query, required: false, schema: { type: integer, default: 50 } }
|
|
560
|
+
responses:
|
|
561
|
+
'200':
|
|
562
|
+
description: Ranked matches.
|
|
563
|
+
content:
|
|
564
|
+
application/json:
|
|
565
|
+
schema:
|
|
566
|
+
type: object
|
|
567
|
+
properties:
|
|
568
|
+
results: { type: array, items: { type: object, additionalProperties: true } }
|
|
569
|
+
total: { type: integer }
|
|
570
|
+
|
|
571
|
+
/api/projects/{projectName}/files:
|
|
572
|
+
get:
|
|
573
|
+
tags: [Files]
|
|
574
|
+
summary: List files in a project subtree
|
|
575
|
+
parameters:
|
|
576
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
577
|
+
- { name: path, in: query, required: false, schema: { type: string }, description: Subdirectory relative to project root. }
|
|
578
|
+
responses:
|
|
579
|
+
'200':
|
|
580
|
+
description: Directory listing.
|
|
581
|
+
content:
|
|
582
|
+
application/json:
|
|
583
|
+
schema:
|
|
584
|
+
type: array
|
|
585
|
+
items:
|
|
586
|
+
type: object
|
|
587
|
+
properties:
|
|
588
|
+
name: { type: string }
|
|
589
|
+
path: { type: string }
|
|
590
|
+
type: { type: string, enum: [file, directory] }
|
|
591
|
+
size: { type: integer, nullable: true }
|
|
592
|
+
delete:
|
|
593
|
+
tags: [Files]
|
|
594
|
+
summary: Delete a file or folder (path in body)
|
|
595
|
+
description: |
|
|
596
|
+
Same path as the listing endpoint above — discriminated by HTTP method.
|
|
597
|
+
The target's project-relative path goes in the body, NOT the query
|
|
598
|
+
string (so directory deletes can't be partially URL-encoded into a
|
|
599
|
+
broken state).
|
|
600
|
+
parameters:
|
|
601
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
602
|
+
requestBody:
|
|
603
|
+
required: true
|
|
604
|
+
content:
|
|
605
|
+
application/json:
|
|
606
|
+
schema:
|
|
607
|
+
type: object
|
|
608
|
+
required: [path]
|
|
609
|
+
properties:
|
|
610
|
+
path: { type: string, description: 'Project-relative path of the file or directory to delete.' }
|
|
611
|
+
type: { type: string, enum: [file, directory], description: 'Optional hint; server detects automatically if omitted.' }
|
|
612
|
+
responses:
|
|
613
|
+
'200': { description: Deleted. }
|
|
614
|
+
|
|
615
|
+
/api/projects/{projectName}/file:
|
|
616
|
+
get:
|
|
617
|
+
tags: [Files]
|
|
618
|
+
summary: Read a single file
|
|
619
|
+
parameters:
|
|
620
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
621
|
+
- { name: path, in: query, required: true, schema: { type: string } }
|
|
622
|
+
responses:
|
|
623
|
+
'200':
|
|
624
|
+
description: File contents (utf-8 text or base64 binary).
|
|
625
|
+
content:
|
|
626
|
+
application/json:
|
|
627
|
+
schema:
|
|
628
|
+
type: object
|
|
629
|
+
properties:
|
|
630
|
+
content: { type: string }
|
|
631
|
+
encoding: { type: string, enum: [utf-8, base64] }
|
|
632
|
+
put:
|
|
633
|
+
tags: [Files]
|
|
634
|
+
summary: Overwrite a file
|
|
635
|
+
parameters:
|
|
636
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
637
|
+
requestBody:
|
|
638
|
+
required: true
|
|
639
|
+
content:
|
|
640
|
+
application/json:
|
|
641
|
+
schema:
|
|
642
|
+
type: object
|
|
643
|
+
required: [path, content]
|
|
644
|
+
properties:
|
|
645
|
+
path: { type: string }
|
|
646
|
+
content: { type: string }
|
|
647
|
+
responses:
|
|
648
|
+
'200': { description: Saved. }
|
|
649
|
+
|
|
650
|
+
/api/projects/{projectName}/files/create:
|
|
651
|
+
post:
|
|
652
|
+
tags: [Files]
|
|
653
|
+
summary: Create a new file or folder
|
|
654
|
+
parameters:
|
|
655
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
656
|
+
requestBody:
|
|
657
|
+
required: true
|
|
658
|
+
content:
|
|
659
|
+
application/json:
|
|
660
|
+
schema:
|
|
661
|
+
type: object
|
|
662
|
+
required: [path, type]
|
|
663
|
+
properties:
|
|
664
|
+
path: { type: string }
|
|
665
|
+
type: { type: string, enum: [file, directory] }
|
|
666
|
+
content: { type: string, description: 'Initial content for files; ignored for directories.' }
|
|
667
|
+
responses:
|
|
668
|
+
'201': { description: Created. }
|
|
669
|
+
|
|
670
|
+
/api/projects/{projectName}/files/rename:
|
|
671
|
+
put:
|
|
672
|
+
tags: [Files]
|
|
673
|
+
summary: Rename / move a file
|
|
674
|
+
parameters:
|
|
675
|
+
- { name: projectName, in: path, required: true, schema: { type: string } }
|
|
676
|
+
requestBody:
|
|
677
|
+
required: true
|
|
678
|
+
content:
|
|
679
|
+
application/json:
|
|
680
|
+
schema:
|
|
681
|
+
type: object
|
|
682
|
+
required: [oldPath, newPath]
|
|
683
|
+
properties:
|
|
684
|
+
oldPath: { type: string }
|
|
685
|
+
newPath: { type: string }
|
|
686
|
+
responses:
|
|
687
|
+
'200': { description: Renamed. }
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
/api/browse-filesystem:
|
|
691
|
+
get:
|
|
692
|
+
tags: [Files]
|
|
693
|
+
summary: Native filesystem browser (outside project tree)
|
|
694
|
+
description: Used by Quick Start to let the user pick a folder anywhere on the host. Honours `~` expansion.
|
|
695
|
+
parameters:
|
|
696
|
+
- { name: path, in: query, required: false, schema: { type: string, default: '~' } }
|
|
697
|
+
responses:
|
|
698
|
+
'200':
|
|
699
|
+
description: Directory listing.
|
|
700
|
+
content:
|
|
701
|
+
application/json:
|
|
702
|
+
schema:
|
|
703
|
+
type: object
|
|
704
|
+
properties:
|
|
705
|
+
path: { type: string }
|
|
706
|
+
parent: { type: string, nullable: true }
|
|
707
|
+
entries:
|
|
708
|
+
type: array
|
|
709
|
+
items:
|
|
710
|
+
type: object
|
|
711
|
+
properties:
|
|
712
|
+
name: { type: string }
|
|
713
|
+
type: { type: string, enum: [file, directory] }
|
|
714
|
+
|
|
715
|
+
/api/git/status:
|
|
716
|
+
get:
|
|
717
|
+
tags: [Git]
|
|
718
|
+
summary: Working tree status
|
|
719
|
+
parameters:
|
|
720
|
+
- { name: project, in: query, required: true, schema: { type: string } }
|
|
721
|
+
responses:
|
|
722
|
+
'200':
|
|
723
|
+
description: Git status snapshot.
|
|
724
|
+
content:
|
|
725
|
+
application/json:
|
|
726
|
+
schema: { $ref: '#/components/schemas/GitStatus' }
|
|
727
|
+
|
|
728
|
+
/api/git/diff:
|
|
729
|
+
get:
|
|
730
|
+
tags: [Git]
|
|
731
|
+
summary: Unified diff for one file or the whole tree
|
|
732
|
+
parameters:
|
|
733
|
+
- { name: project, in: query, required: true, schema: { type: string } }
|
|
734
|
+
- { name: file, in: query, required: false, schema: { type: string } }
|
|
735
|
+
- { name: staged, in: query, required: false, schema: { type: boolean, default: false } }
|
|
736
|
+
responses:
|
|
737
|
+
'200':
|
|
738
|
+
description: Diff text.
|
|
739
|
+
content:
|
|
740
|
+
application/json:
|
|
741
|
+
schema:
|
|
742
|
+
type: object
|
|
743
|
+
properties:
|
|
744
|
+
diff: { type: string }
|
|
745
|
+
|
|
746
|
+
/api/git/branches:
|
|
747
|
+
get:
|
|
748
|
+
tags: [Git]
|
|
749
|
+
summary: List local + remote branches
|
|
750
|
+
parameters:
|
|
751
|
+
- { name: project, in: query, required: true, schema: { type: string } }
|
|
752
|
+
responses:
|
|
753
|
+
'200':
|
|
754
|
+
description: Branch list.
|
|
755
|
+
content:
|
|
756
|
+
application/json:
|
|
757
|
+
schema:
|
|
758
|
+
type: object
|
|
759
|
+
properties:
|
|
760
|
+
current: { type: string }
|
|
761
|
+
local: { type: array, items: { type: string } }
|
|
762
|
+
remote: { type: array, items: { type: string } }
|
|
763
|
+
|
|
764
|
+
/api/git/commit:
|
|
765
|
+
post:
|
|
766
|
+
tags: [Git]
|
|
767
|
+
summary: Create a commit
|
|
768
|
+
requestBody:
|
|
769
|
+
required: true
|
|
770
|
+
content:
|
|
771
|
+
application/json:
|
|
772
|
+
schema:
|
|
773
|
+
type: object
|
|
774
|
+
required: [project, message]
|
|
775
|
+
properties:
|
|
776
|
+
project: { type: string }
|
|
777
|
+
message: { type: string }
|
|
778
|
+
files: { type: array, items: { type: string }, description: 'When omitted, all staged changes are committed.' }
|
|
779
|
+
responses:
|
|
780
|
+
'200': { description: Commit created. }
|
|
781
|
+
|
|
782
|
+
/api/git/push:
|
|
783
|
+
post:
|
|
784
|
+
tags: [Git]
|
|
785
|
+
summary: Push to remote
|
|
786
|
+
requestBody:
|
|
787
|
+
required: true
|
|
788
|
+
content:
|
|
789
|
+
application/json:
|
|
790
|
+
schema:
|
|
791
|
+
type: object
|
|
792
|
+
required: [project]
|
|
793
|
+
properties:
|
|
794
|
+
project: { type: string }
|
|
795
|
+
remote: { type: string, default: origin }
|
|
796
|
+
branch: { type: string }
|
|
797
|
+
force: { type: boolean, default: false }
|
|
798
|
+
responses:
|
|
799
|
+
'200': { description: Pushed. }
|
|
800
|
+
|
|
801
|
+
/api/git/pull:
|
|
802
|
+
post:
|
|
803
|
+
tags: [Git]
|
|
804
|
+
summary: Pull from remote
|
|
805
|
+
requestBody:
|
|
806
|
+
required: true
|
|
807
|
+
content:
|
|
808
|
+
application/json:
|
|
809
|
+
schema:
|
|
810
|
+
type: object
|
|
811
|
+
required: [project]
|
|
812
|
+
properties:
|
|
813
|
+
project: { type: string }
|
|
814
|
+
responses:
|
|
815
|
+
'200': { description: Pulled. }
|
|
816
|
+
|
|
817
|
+
/api/git/checkout:
|
|
818
|
+
post:
|
|
819
|
+
tags: [Git]
|
|
820
|
+
summary: Switch branch
|
|
821
|
+
requestBody:
|
|
822
|
+
required: true
|
|
823
|
+
content:
|
|
824
|
+
application/json:
|
|
825
|
+
schema:
|
|
826
|
+
type: object
|
|
827
|
+
required: [project, branch]
|
|
828
|
+
properties:
|
|
829
|
+
project: { type: string }
|
|
830
|
+
branch: { type: string }
|
|
831
|
+
responses:
|
|
832
|
+
'200': { description: Switched. }
|
|
833
|
+
|
|
834
|
+
/api/providers/credentials:
|
|
835
|
+
get:
|
|
836
|
+
tags: [Providers]
|
|
837
|
+
summary: List stored credentials across providers
|
|
838
|
+
description: Returns a sanitised inventory of API keys / OAuth tokens Pixcode is currently holding for each provider. Real secret values are NOT returned — only presence + masked tail.
|
|
839
|
+
responses:
|
|
840
|
+
'200':
|
|
841
|
+
description: Credentials inventory.
|
|
842
|
+
content:
|
|
843
|
+
application/json:
|
|
844
|
+
schema:
|
|
845
|
+
type: object
|
|
846
|
+
additionalProperties:
|
|
847
|
+
type: object
|
|
848
|
+
properties:
|
|
849
|
+
hasCredential: { type: boolean }
|
|
850
|
+
masked: { type: string, nullable: true, example: '...beef' }
|
|
851
|
+
|
|
852
|
+
/api/providers/{provider}/auth/status:
|
|
853
|
+
get:
|
|
854
|
+
tags: [Providers]
|
|
855
|
+
summary: Auth status for a single provider
|
|
856
|
+
description: |
|
|
857
|
+
Returns whether the provider's CLI is installed, whether it has a
|
|
858
|
+
valid auth credential (api key / OAuth token), and the resolved
|
|
859
|
+
binary path the spawn layer will use.
|
|
860
|
+
parameters:
|
|
861
|
+
- { name: provider, in: path, required: true, schema: { type: string, enum: [claude, cursor, codex, gemini, qwen, opencode] } }
|
|
862
|
+
responses:
|
|
863
|
+
'200':
|
|
864
|
+
description: Auth status snapshot.
|
|
865
|
+
content:
|
|
866
|
+
application/json:
|
|
867
|
+
schema: { $ref: '#/components/schemas/ProviderInfo' }
|
|
868
|
+
|
|
869
|
+
/api/providers/{provider}/auth/api-key:
|
|
870
|
+
post:
|
|
871
|
+
tags: [Providers]
|
|
872
|
+
summary: Save / replace an API-key credential for a provider
|
|
873
|
+
parameters:
|
|
874
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
875
|
+
requestBody:
|
|
876
|
+
required: true
|
|
877
|
+
content:
|
|
878
|
+
application/json:
|
|
879
|
+
schema:
|
|
880
|
+
type: object
|
|
881
|
+
required: [apiKey]
|
|
882
|
+
properties:
|
|
883
|
+
apiKey: { type: string }
|
|
884
|
+
baseUrl: { type: string, description: Optional override (e.g. self-hosted Anthropic compat endpoint). }
|
|
885
|
+
responses:
|
|
886
|
+
'200': { description: Credential saved. }
|
|
887
|
+
|
|
888
|
+
/api/providers/{provider}/oauth-paste:
|
|
889
|
+
post:
|
|
890
|
+
tags: [Providers]
|
|
891
|
+
summary: Paste an OAuth callback URL to complete login
|
|
892
|
+
description: |
|
|
893
|
+
For providers (Claude, Cursor) whose login flow opens a browser tab and
|
|
894
|
+
bounces back to a URL the user copies into Pixcode. The handler parses
|
|
895
|
+
the token and stores it as the active credential.
|
|
896
|
+
parameters:
|
|
897
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
898
|
+
requestBody:
|
|
899
|
+
required: true
|
|
900
|
+
content:
|
|
901
|
+
application/json:
|
|
902
|
+
schema:
|
|
903
|
+
type: object
|
|
904
|
+
required: [url]
|
|
905
|
+
properties:
|
|
906
|
+
url: { type: string, format: uri }
|
|
907
|
+
responses:
|
|
908
|
+
'200': { description: Token extracted and stored. }
|
|
909
|
+
'400': { description: URL did not contain a recognisable token. }
|
|
910
|
+
|
|
911
|
+
/api/providers/{provider}/models:
|
|
912
|
+
get:
|
|
913
|
+
tags: [Providers]
|
|
914
|
+
summary: List models the provider's CLI exposes
|
|
915
|
+
description: |
|
|
916
|
+
Pixcode caches the model list per provider on first call (or when the
|
|
917
|
+
cache is busted via `DELETE …/models/cache`). Each entry is the
|
|
918
|
+
`provider/model` form OpenCode expects.
|
|
919
|
+
parameters:
|
|
920
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
921
|
+
responses:
|
|
922
|
+
'200':
|
|
923
|
+
description: Model catalog.
|
|
924
|
+
content:
|
|
925
|
+
application/json:
|
|
926
|
+
schema:
|
|
927
|
+
type: array
|
|
928
|
+
items:
|
|
929
|
+
type: object
|
|
930
|
+
properties:
|
|
931
|
+
id: { type: string, example: 'opencode/gpt-5.2' }
|
|
932
|
+
name: { type: string }
|
|
933
|
+
contextWindow: { type: integer, nullable: true }
|
|
934
|
+
|
|
935
|
+
/api/providers/{provider}/models/cache:
|
|
936
|
+
delete:
|
|
937
|
+
tags: [Providers]
|
|
938
|
+
summary: Bust the cached model list for one provider
|
|
939
|
+
parameters:
|
|
940
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
941
|
+
responses:
|
|
942
|
+
'200': { description: Cache cleared; next GET re-fetches. }
|
|
943
|
+
|
|
944
|
+
/api/providers/{provider}/install:
|
|
945
|
+
post:
|
|
946
|
+
tags: [Providers]
|
|
947
|
+
summary: Install / update a provider CLI in the Pixcode sandbox
|
|
948
|
+
description: |
|
|
949
|
+
Installs the provider's npm package into `~/.pixcode/cli-bin/` (no
|
|
950
|
+
`-g`, no sudo/UAC). Returns a `jobId` immediately; subscribe to
|
|
951
|
+
`/install/{jobId}/stream` for live logs.
|
|
952
|
+
parameters:
|
|
953
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
954
|
+
responses:
|
|
955
|
+
'202':
|
|
956
|
+
description: Job accepted.
|
|
957
|
+
content:
|
|
958
|
+
application/json:
|
|
959
|
+
schema: { $ref: '#/components/schemas/InstallJob' }
|
|
960
|
+
|
|
961
|
+
/api/providers/{provider}/install/{jobId}/stream:
|
|
962
|
+
get:
|
|
963
|
+
tags: [Providers]
|
|
964
|
+
summary: Stream install job output (SSE)
|
|
965
|
+
description: Replays buffered output, then streams live until the job ends. Send `Last-Event-ID` to resume after disconnect.
|
|
966
|
+
parameters:
|
|
967
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
968
|
+
- { name: jobId, in: path, required: true, schema: { type: string } }
|
|
969
|
+
responses:
|
|
970
|
+
'200':
|
|
971
|
+
description: 'SSE event stream — `event: log`, `event: status`, `event: done`, `event: error`.'
|
|
972
|
+
content:
|
|
973
|
+
text/event-stream:
|
|
974
|
+
schema: { type: string }
|
|
975
|
+
|
|
976
|
+
/api/providers/{provider}/install/{jobId}:
|
|
977
|
+
delete:
|
|
978
|
+
tags: [Providers]
|
|
979
|
+
summary: Cancel an in-flight install
|
|
980
|
+
parameters:
|
|
981
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
982
|
+
- { name: jobId, in: path, required: true, schema: { type: string } }
|
|
983
|
+
responses:
|
|
984
|
+
'200': { description: Cancelled. }
|
|
985
|
+
|
|
986
|
+
/api/providers/{provider}/mcp/servers:
|
|
987
|
+
get:
|
|
988
|
+
tags: [MCP]
|
|
989
|
+
summary: List MCP servers configured for one provider
|
|
990
|
+
parameters:
|
|
991
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
992
|
+
responses:
|
|
993
|
+
'200':
|
|
994
|
+
description: MCP server list (matches the provider's native config schema).
|
|
995
|
+
content:
|
|
996
|
+
application/json:
|
|
997
|
+
schema:
|
|
998
|
+
type: array
|
|
999
|
+
items: { type: object, additionalProperties: true }
|
|
1000
|
+
post:
|
|
1001
|
+
tags: [MCP]
|
|
1002
|
+
summary: Add or replace an MCP server entry
|
|
1003
|
+
parameters:
|
|
1004
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
1005
|
+
requestBody:
|
|
1006
|
+
required: true
|
|
1007
|
+
content:
|
|
1008
|
+
application/json:
|
|
1009
|
+
schema:
|
|
1010
|
+
type: object
|
|
1011
|
+
required: [name, command]
|
|
1012
|
+
properties:
|
|
1013
|
+
name: { type: string }
|
|
1014
|
+
command: { type: string }
|
|
1015
|
+
args: { type: array, items: { type: string } }
|
|
1016
|
+
env: { type: object, additionalProperties: { type: string } }
|
|
1017
|
+
scope: { type: string, enum: [local, user], default: user }
|
|
1018
|
+
responses:
|
|
1019
|
+
'200': { description: Server saved. }
|
|
1020
|
+
|
|
1021
|
+
/api/providers/{provider}/mcp/servers/{name}:
|
|
1022
|
+
delete:
|
|
1023
|
+
tags: [MCP]
|
|
1024
|
+
summary: Remove an MCP server entry
|
|
1025
|
+
parameters:
|
|
1026
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
1027
|
+
- { name: name, in: path, required: true, schema: { type: string } }
|
|
1028
|
+
responses:
|
|
1029
|
+
'200': { description: Removed. }
|
|
1030
|
+
|
|
1031
|
+
/api/providers/mcp/servers/global:
|
|
1032
|
+
post:
|
|
1033
|
+
tags: [MCP]
|
|
1034
|
+
summary: Add an MCP server to every provider that supports MCP
|
|
1035
|
+
description: Convenience endpoint that fans out the same server config to all MCP-capable providers (Claude, Cursor, Codex, OpenCode). Per-provider edits override.
|
|
1036
|
+
requestBody:
|
|
1037
|
+
required: true
|
|
1038
|
+
content:
|
|
1039
|
+
application/json:
|
|
1040
|
+
schema:
|
|
1041
|
+
type: object
|
|
1042
|
+
required: [name, command]
|
|
1043
|
+
properties:
|
|
1044
|
+
name: { type: string }
|
|
1045
|
+
command: { type: string }
|
|
1046
|
+
args: { type: array, items: { type: string } }
|
|
1047
|
+
env: { type: object, additionalProperties: { type: string } }
|
|
1048
|
+
responses:
|
|
1049
|
+
'200': { description: Server fanned out. }
|
|
1050
|
+
|
|
1051
|
+
/api/providers/{provider}/config-files:
|
|
1052
|
+
get:
|
|
1053
|
+
tags: [Providers]
|
|
1054
|
+
summary: List config files Pixcode knows about for a provider
|
|
1055
|
+
description: |
|
|
1056
|
+
Returns the catalog of editable config files for a provider — typically
|
|
1057
|
+
`settings.json`, `auth.json`, `opencode.json`, etc. Each entry has an
|
|
1058
|
+
opaque `fileId` used by `GET/PUT …/{fileId}`.
|
|
1059
|
+
parameters:
|
|
1060
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
1061
|
+
responses:
|
|
1062
|
+
'200':
|
|
1063
|
+
description: Config file catalog.
|
|
1064
|
+
content:
|
|
1065
|
+
application/json:
|
|
1066
|
+
schema:
|
|
1067
|
+
type: array
|
|
1068
|
+
items:
|
|
1069
|
+
type: object
|
|
1070
|
+
properties:
|
|
1071
|
+
fileId: { type: string }
|
|
1072
|
+
path: { type: string }
|
|
1073
|
+
label: { type: string }
|
|
1074
|
+
exists: { type: boolean }
|
|
1075
|
+
size: { type: integer, nullable: true }
|
|
1076
|
+
|
|
1077
|
+
/api/providers/{provider}/config-files/{fileId}:
|
|
1078
|
+
get:
|
|
1079
|
+
tags: [Providers]
|
|
1080
|
+
summary: Read a provider config file's contents
|
|
1081
|
+
parameters:
|
|
1082
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
1083
|
+
- { name: fileId, in: path, required: true, schema: { type: string } }
|
|
1084
|
+
responses:
|
|
1085
|
+
'200':
|
|
1086
|
+
description: File contents.
|
|
1087
|
+
content:
|
|
1088
|
+
application/json:
|
|
1089
|
+
schema:
|
|
1090
|
+
type: object
|
|
1091
|
+
properties:
|
|
1092
|
+
content: { type: string }
|
|
1093
|
+
path: { type: string }
|
|
1094
|
+
encoding: { type: string, enum: [utf-8] }
|
|
1095
|
+
put:
|
|
1096
|
+
tags: [Providers]
|
|
1097
|
+
summary: Overwrite a provider config file
|
|
1098
|
+
parameters:
|
|
1099
|
+
- { name: provider, in: path, required: true, schema: { type: string } }
|
|
1100
|
+
- { name: fileId, in: path, required: true, schema: { type: string } }
|
|
1101
|
+
requestBody:
|
|
1102
|
+
required: true
|
|
1103
|
+
content:
|
|
1104
|
+
application/json:
|
|
1105
|
+
schema:
|
|
1106
|
+
type: object
|
|
1107
|
+
required: [content]
|
|
1108
|
+
properties:
|
|
1109
|
+
content: { type: string }
|
|
1110
|
+
responses:
|
|
1111
|
+
'200': { description: Saved. }
|
|
1112
|
+
'400': { description: Content failed validation (e.g. malformed JSON). }
|
|
1113
|
+
|
|
1114
|
+
/api/network/endpoints:
|
|
1115
|
+
get:
|
|
1116
|
+
tags: [Network]
|
|
1117
|
+
summary: LAN endpoints for mobile QR pairing
|
|
1118
|
+
description: Returns every reachable IPv4 the host has bound, formatted as `http://<ip>:<port>`.
|
|
1119
|
+
responses:
|
|
1120
|
+
'200':
|
|
1121
|
+
description: LAN endpoint list.
|
|
1122
|
+
content:
|
|
1123
|
+
application/json:
|
|
1124
|
+
schema:
|
|
1125
|
+
type: object
|
|
1126
|
+
properties:
|
|
1127
|
+
endpoints: { type: array, items: { type: string } }
|
|
1128
|
+
port: { type: integer }
|
|
1129
|
+
|
|
1130
|
+
/api/network/external:
|
|
1131
|
+
get:
|
|
1132
|
+
tags: [Network]
|
|
1133
|
+
summary: Current external-access state (UPnP + tunnel)
|
|
1134
|
+
responses:
|
|
1135
|
+
'200':
|
|
1136
|
+
description: Snapshot.
|
|
1137
|
+
content:
|
|
1138
|
+
application/json:
|
|
1139
|
+
schema:
|
|
1140
|
+
type: object
|
|
1141
|
+
properties:
|
|
1142
|
+
upnp:
|
|
1143
|
+
type: object
|
|
1144
|
+
properties:
|
|
1145
|
+
active: { type: boolean }
|
|
1146
|
+
externalIp: { type: string, nullable: true }
|
|
1147
|
+
mappedPort: { type: integer, nullable: true }
|
|
1148
|
+
tunnel:
|
|
1149
|
+
type: object
|
|
1150
|
+
properties:
|
|
1151
|
+
active: { type: boolean }
|
|
1152
|
+
provider: { type: string, enum: [cloudflared, ngrok], nullable: true }
|
|
1153
|
+
url: { type: string, nullable: true }
|
|
1154
|
+
|
|
1155
|
+
/api/network/upnp:
|
|
1156
|
+
post:
|
|
1157
|
+
tags: [Network]
|
|
1158
|
+
summary: Open the LAN port on the router
|
|
1159
|
+
responses:
|
|
1160
|
+
'200': { description: Mapping created (or already present). }
|
|
1161
|
+
delete:
|
|
1162
|
+
tags: [Network]
|
|
1163
|
+
summary: Remove the UPnP mapping
|
|
1164
|
+
responses:
|
|
1165
|
+
'200': { description: Removed. }
|
|
1166
|
+
|
|
1167
|
+
/api/network/tunnel:
|
|
1168
|
+
post:
|
|
1169
|
+
tags: [Network]
|
|
1170
|
+
summary: Start a public tunnel (cloudflared / ngrok auto-detect)
|
|
1171
|
+
responses:
|
|
1172
|
+
'200':
|
|
1173
|
+
description: Tunnel started; URL returned.
|
|
1174
|
+
content:
|
|
1175
|
+
application/json:
|
|
1176
|
+
schema:
|
|
1177
|
+
type: object
|
|
1178
|
+
properties:
|
|
1179
|
+
url: { type: string, format: uri }
|
|
1180
|
+
provider: { type: string }
|
|
1181
|
+
delete:
|
|
1182
|
+
tags: [Network]
|
|
1183
|
+
summary: Stop the tunnel
|
|
1184
|
+
responses:
|
|
1185
|
+
'200': { description: Stopped. }
|
|
1186
|
+
|
|
1187
|
+
/api/settings/notification-preferences:
|
|
1188
|
+
get:
|
|
1189
|
+
tags: [Settings]
|
|
1190
|
+
summary: Get notification preferences
|
|
1191
|
+
responses:
|
|
1192
|
+
'200':
|
|
1193
|
+
description: Per-channel + per-event toggles.
|
|
1194
|
+
content:
|
|
1195
|
+
application/json:
|
|
1196
|
+
schema:
|
|
1197
|
+
type: object
|
|
1198
|
+
properties:
|
|
1199
|
+
preferences:
|
|
1200
|
+
type: object
|
|
1201
|
+
properties:
|
|
1202
|
+
channels:
|
|
1203
|
+
type: object
|
|
1204
|
+
properties:
|
|
1205
|
+
inApp: { type: boolean }
|
|
1206
|
+
webPush: { type: boolean }
|
|
1207
|
+
events:
|
|
1208
|
+
type: object
|
|
1209
|
+
properties:
|
|
1210
|
+
actionRequired: { type: boolean }
|
|
1211
|
+
stop: { type: boolean }
|
|
1212
|
+
error: { type: boolean }
|
|
1213
|
+
put:
|
|
1214
|
+
tags: [Settings]
|
|
1215
|
+
summary: Update notification preferences
|
|
1216
|
+
requestBody:
|
|
1217
|
+
required: true
|
|
1218
|
+
content:
|
|
1219
|
+
application/json:
|
|
1220
|
+
schema: { type: object }
|
|
1221
|
+
responses:
|
|
1222
|
+
'200': { description: Saved. }
|
|
1223
|
+
|
|
1224
|
+
/api/agent:
|
|
1225
|
+
post:
|
|
1226
|
+
tags: [Providers]
|
|
1227
|
+
summary: External REST entry point (API-key authenticated)
|
|
1228
|
+
description: |
|
|
1229
|
+
One-shot non-interactive run for automation/CI. Spawns the chosen
|
|
1230
|
+
provider, optionally cloning a GitHub repo first, optionally cutting
|
|
1231
|
+
a branch + opening a PR. **API key required** — accepts the same `ck_`
|
|
1232
|
+
keys as the rest of the API on `Authorization: Bearer`, `X-API-Key`,
|
|
1233
|
+
or `?apiKey=`.
|
|
1234
|
+
|
|
1235
|
+
Default response is an SSE stream of provider-native events; pass
|
|
1236
|
+
`stream: false` to buffer and return JSON.
|
|
1237
|
+
security:
|
|
1238
|
+
- bearerAuth: []
|
|
1239
|
+
- apiKeyAuth: []
|
|
1240
|
+
requestBody:
|
|
1241
|
+
required: true
|
|
1242
|
+
content:
|
|
1243
|
+
application/json:
|
|
1244
|
+
schema:
|
|
1245
|
+
type: object
|
|
1246
|
+
required: [message]
|
|
1247
|
+
properties:
|
|
1248
|
+
message:
|
|
1249
|
+
type: string
|
|
1250
|
+
description: Prompt text to send to the agent.
|
|
1251
|
+
provider:
|
|
1252
|
+
type: string
|
|
1253
|
+
enum: [claude, cursor, codex, gemini, qwen, opencode]
|
|
1254
|
+
default: claude
|
|
1255
|
+
model:
|
|
1256
|
+
type: string
|
|
1257
|
+
description: Provider-specific model id (e.g. `opencode/gpt-5.2`).
|
|
1258
|
+
projectPath:
|
|
1259
|
+
type: string
|
|
1260
|
+
description: Absolute path on the host. Required if `githubUrl` is omitted.
|
|
1261
|
+
githubUrl:
|
|
1262
|
+
type: string
|
|
1263
|
+
format: uri
|
|
1264
|
+
description: Clone this repo before running. Mutually inclusive with `projectPath` (used as the clone target if both are given).
|
|
1265
|
+
githubToken:
|
|
1266
|
+
type: string
|
|
1267
|
+
description: Optional override for the per-user GitHub PAT stored under Settings → Git.
|
|
1268
|
+
branchName:
|
|
1269
|
+
type: string
|
|
1270
|
+
description: 'Cutting `branchName` implies `createBranch: true`.'
|
|
1271
|
+
createBranch:
|
|
1272
|
+
type: boolean
|
|
1273
|
+
default: false
|
|
1274
|
+
createPR:
|
|
1275
|
+
type: boolean
|
|
1276
|
+
default: false
|
|
1277
|
+
sessionId:
|
|
1278
|
+
type: string
|
|
1279
|
+
description: Resume an existing session instead of starting a new one.
|
|
1280
|
+
stream:
|
|
1281
|
+
type: boolean
|
|
1282
|
+
default: true
|
|
1283
|
+
description: 'Set false to buffer to a single JSON response.'
|
|
1284
|
+
cleanup:
|
|
1285
|
+
type: boolean
|
|
1286
|
+
default: true
|
|
1287
|
+
description: When `githubUrl` was used, delete the temp clone after the run.
|
|
1288
|
+
responses:
|
|
1289
|
+
'200':
|
|
1290
|
+
description: |
|
|
1291
|
+
When `stream:true` — SSE stream of provider events. When `stream:false` — final JSON payload with `text` + `sessionId` + `usage`.
|
|
1292
|
+
content:
|
|
1293
|
+
application/json:
|
|
1294
|
+
schema:
|
|
1295
|
+
type: object
|
|
1296
|
+
properties:
|
|
1297
|
+
text: { type: string }
|
|
1298
|
+
sessionId: { type: string }
|
|
1299
|
+
usage:
|
|
1300
|
+
type: object
|
|
1301
|
+
properties:
|
|
1302
|
+
input: { type: integer }
|
|
1303
|
+
output: { type: integer }
|
|
1304
|
+
total: { type: integer }
|
|
1305
|
+
cost: { type: number }
|
|
1306
|
+
text/event-stream:
|
|
1307
|
+
schema: { type: string }
|
|
1308
|
+
'400':
|
|
1309
|
+
description: 'Missing required fields, unknown provider, or invalid GitHub URL.'
|
|
1310
|
+
'401':
|
|
1311
|
+
description: Missing or invalid API key.
|