cicy-desktop 2.1.237 → 2.1.239
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/package.json +9 -16
- package/src/sidecar/cicy-code.js +32 -9
- package/src/sidecar/container-scripts/cicy-code-update.sh +6 -1
- package/src/sidecar/host-mihomo.js +40 -10
- package/src/sidecar/runtime.js +144 -64
- package/src/tabbrowser/tab-shell.html +5 -1
- package/.kiro/steering/dev-workflow.md +0 -166
- package/AGENTS.md +0 -275
- package/CLAUDE_HANDOFF.md +0 -168
- package/DESIGN.md +0 -66
- package/DOCKER.md +0 -85
- package/Dockerfile +0 -46
- package/TODO-anti-detection.md +0 -326
- package/copy-to-desktop.sh +0 -26
- package/docs/AUTOMATION-API.md +0 -342
- package/docs/REQUEST_MONITORING.md +0 -435
- package/docs/REST-API-FEATURE.md +0 -155
- package/docs/REST-API.md +0 -276
- package/docs/backend-selector-design.md +0 -204
- package/docs/chrome-proxy.md +0 -142
- package/docs/cicy-desktop-current-execution-bridge.md +0 -509
- package/docs/feature-distributed-multi-agent.md +0 -555
- package/docs/worklog-2026-03-27.md +0 -108
- package/docs/yaml.md +0 -255
- package/generate-openapi.js +0 -162
- package/jest.config.js +0 -13
- package/jest.setup.global.js +0 -16
- package/jest.teardown.global.js +0 -10
- package/service.sh +0 -164
- package/update-desktop.sh +0 -33
package/docs/REST-API.md
DELETED
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
# REST API
|
|
2
|
-
|
|
3
|
-
This document describes the current HTTP API exposed by the CiCy Desktop worker.
|
|
4
|
-
|
|
5
|
-
Source of truth:
|
|
6
|
-
- worker entry: `src/main.js`
|
|
7
|
-
- OpenAPI/docs routes: `src/server/express-app.js`
|
|
8
|
-
|
|
9
|
-
## Endpoint summary
|
|
10
|
-
|
|
11
|
-
### Public endpoints
|
|
12
|
-
|
|
13
|
-
These do **not** require auth:
|
|
14
|
-
|
|
15
|
-
- `GET /ping` — basic health check
|
|
16
|
-
- `GET /docs` — Swagger-style API UI
|
|
17
|
-
- `GET /openapi.json` — generated OpenAPI spec
|
|
18
|
-
|
|
19
|
-
### Authenticated RPC endpoints
|
|
20
|
-
|
|
21
|
-
These **do** require auth:
|
|
22
|
-
|
|
23
|
-
- `GET /rpc/tools`
|
|
24
|
-
- `POST /rpc/tools/call`
|
|
25
|
-
- `POST /rpc/:toolName`
|
|
26
|
-
- `POST /rpc/upload/*`
|
|
27
|
-
- `POST /rpc/exec/:type`
|
|
28
|
-
- `GET /files`
|
|
29
|
-
- `GET /api/worker`
|
|
30
|
-
- `GET /api/agents`
|
|
31
|
-
- `GET /api/artifacts`
|
|
32
|
-
|
|
33
|
-
## Authentication
|
|
34
|
-
|
|
35
|
-
Authenticated routes expect:
|
|
36
|
-
|
|
37
|
-
```http
|
|
38
|
-
Authorization: Bearer <token>
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Tokens are usually stored in `~/global.json` and are the same tokens used by `cicy-rpc`.
|
|
42
|
-
|
|
43
|
-
If auth fails, the worker responds with:
|
|
44
|
-
|
|
45
|
-
```json
|
|
46
|
-
{
|
|
47
|
-
"error": "Unauthorized"
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Core RPC routes
|
|
52
|
-
|
|
53
|
-
### `GET /rpc/tools`
|
|
54
|
-
|
|
55
|
-
Returns the current tool catalog.
|
|
56
|
-
|
|
57
|
-
Example:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
curl http://localhost:8101/rpc/tools \
|
|
61
|
-
-H "Authorization: Bearer $TOKEN"
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
JSON response shape:
|
|
65
|
-
|
|
66
|
-
```json
|
|
67
|
-
{
|
|
68
|
-
"tools": [
|
|
69
|
-
{
|
|
70
|
-
"name": "open_window",
|
|
71
|
-
"description": "...",
|
|
72
|
-
"inputSchema": {
|
|
73
|
-
"type": "object"
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
]
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
YAML is also supported by setting:
|
|
81
|
-
|
|
82
|
-
```http
|
|
83
|
-
Accept: application/yaml
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### `POST /rpc/tools/call`
|
|
87
|
-
|
|
88
|
-
Calls a tool by name using a generic wrapper endpoint.
|
|
89
|
-
|
|
90
|
-
Example:
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
curl -X POST http://localhost:8101/rpc/tools/call \
|
|
94
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
95
|
-
-H "Content-Type: application/json" \
|
|
96
|
-
-d '{
|
|
97
|
-
"name": "open_window",
|
|
98
|
-
"arguments": {
|
|
99
|
-
"url": "https://example.com"
|
|
100
|
-
}
|
|
101
|
-
}'
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Request shape:
|
|
105
|
-
|
|
106
|
-
```json
|
|
107
|
-
{
|
|
108
|
-
"name": "tool_name",
|
|
109
|
-
"arguments": {
|
|
110
|
-
"key": "value"
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### `POST /rpc/:toolName`
|
|
116
|
-
|
|
117
|
-
Calls a tool directly.
|
|
118
|
-
|
|
119
|
-
Example:
|
|
120
|
-
|
|
121
|
-
```bash
|
|
122
|
-
curl -X POST http://localhost:8101/rpc/open_window \
|
|
123
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
124
|
-
-H "Content-Type: application/json" \
|
|
125
|
-
-d '{
|
|
126
|
-
"url": "https://example.com",
|
|
127
|
-
"accountIdx": 0
|
|
128
|
-
}'
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
This is the simplest REST form when you already know the tool name.
|
|
132
|
-
|
|
133
|
-
## Response format
|
|
134
|
-
|
|
135
|
-
Successful tool responses are wrapped like this:
|
|
136
|
-
|
|
137
|
-
```json
|
|
138
|
-
{
|
|
139
|
-
"result": {
|
|
140
|
-
"content": [
|
|
141
|
-
{
|
|
142
|
-
"type": "text",
|
|
143
|
-
"text": "Pong"
|
|
144
|
-
}
|
|
145
|
-
]
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Some tools return text content, some return structured JSON encoded in text, and some may return image content.
|
|
151
|
-
|
|
152
|
-
If the client sends:
|
|
153
|
-
|
|
154
|
-
```http
|
|
155
|
-
Accept: application/yaml
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
then tool responses are returned as YAML.
|
|
159
|
-
|
|
160
|
-
## JSON and YAML support
|
|
161
|
-
|
|
162
|
-
Current worker behavior:
|
|
163
|
-
|
|
164
|
-
- `GET /rpc/tools` supports JSON and YAML output via `Accept`
|
|
165
|
-
- `POST /rpc/tools/call` accepts JSON, and also accepts YAML when `Content-Type: application/yaml`
|
|
166
|
-
- `POST /rpc/:toolName` accepts JSON, and also accepts YAML when `Content-Type: application/yaml`
|
|
167
|
-
- tool responses can be returned as YAML when `Accept: application/yaml`
|
|
168
|
-
|
|
169
|
-
Example YAML tool call:
|
|
170
|
-
|
|
171
|
-
```bash
|
|
172
|
-
curl -X POST http://localhost:8101/rpc/exec_js \
|
|
173
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
174
|
-
-H "Content-Type: application/yaml" \
|
|
175
|
-
-H "Accept: application/yaml" \
|
|
176
|
-
--data-binary $'win_id: 1\ncode: document.title\n'
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## Common examples
|
|
180
|
-
|
|
181
|
-
### Health check
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
curl http://localhost:8101/ping
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Ping tool
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
curl -X POST http://localhost:8101/rpc/ping \
|
|
191
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
192
|
-
-H "Content-Type: application/json" \
|
|
193
|
-
-d '{}'
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Get windows
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
|
-
curl -X POST http://localhost:8101/rpc/get_windows \
|
|
200
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
201
|
-
-H "Content-Type: application/json" \
|
|
202
|
-
-d '{}'
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### Open a window
|
|
206
|
-
|
|
207
|
-
```bash
|
|
208
|
-
curl -X POST http://localhost:8101/rpc/open_window \
|
|
209
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
210
|
-
-H "Content-Type: application/json" \
|
|
211
|
-
-d '{
|
|
212
|
-
"url": "https://example.com",
|
|
213
|
-
"accountIdx": 0,
|
|
214
|
-
"reuseWindow": true
|
|
215
|
-
}'
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Execute JavaScript
|
|
219
|
-
|
|
220
|
-
```bash
|
|
221
|
-
curl -X POST http://localhost:8101/rpc/exec_js \
|
|
222
|
-
-H "Authorization: Bearer $TOKEN" \
|
|
223
|
-
-H "Content-Type: application/json" \
|
|
224
|
-
-d '{
|
|
225
|
-
"win_id": 1,
|
|
226
|
-
"code": "document.title"
|
|
227
|
-
}'
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
## OpenAPI and interactive docs
|
|
231
|
-
|
|
232
|
-
The worker serves generated API docs directly:
|
|
233
|
-
|
|
234
|
-
- `GET /docs`
|
|
235
|
-
- `GET /openapi.json`
|
|
236
|
-
|
|
237
|
-
Examples:
|
|
238
|
-
|
|
239
|
-
```bash
|
|
240
|
-
open http://localhost:8101/docs
|
|
241
|
-
curl http://localhost:8101/openapi.json
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
## Errors
|
|
245
|
-
|
|
246
|
-
### 401 Unauthorized
|
|
247
|
-
|
|
248
|
-
```json
|
|
249
|
-
{
|
|
250
|
-
"error": "Unauthorized"
|
|
251
|
-
}
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### 400 Invalid YAML
|
|
255
|
-
|
|
256
|
-
```json
|
|
257
|
-
{
|
|
258
|
-
"error": "Invalid YAML: ..."
|
|
259
|
-
}
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### 500 Tool execution error
|
|
263
|
-
|
|
264
|
-
```json
|
|
265
|
-
{
|
|
266
|
-
"error": "..."
|
|
267
|
-
}
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
If a tool raises a Zod validation error, the worker returns a `result` payload with `isError: true` instead of a generic HTTP 500.
|
|
271
|
-
|
|
272
|
-
## Related docs
|
|
273
|
-
|
|
274
|
-
- [Root README](../README.md)
|
|
275
|
-
- [CLI split](../skills/cicy-cli/README.md)
|
|
276
|
-
- [RPC CLI README](../packages/cicy-rpc/README.md)
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
# Backend Selector — Design
|
|
2
|
-
|
|
3
|
-
Status: **draft for review**. Source of truth for `src/backends/` and the
|
|
4
|
-
multi-window backend model. Adopted from the Genymotion shape: the desktop is
|
|
5
|
-
a launcher / shell; the real environments (local sidecar, cloud cicy-code
|
|
6
|
-
instances) live behind it as switchable backends.
|
|
7
|
-
|
|
8
|
-
## Vision
|
|
9
|
-
|
|
10
|
-
One installable `cicy-desktop`. After launch the user lands on a **Launcher**
|
|
11
|
-
window listing every backend they can reach:
|
|
12
|
-
|
|
13
|
-
- **Local** — bundled `cicy-code` daemon spawned by the sidecar (already
|
|
14
|
-
wired). Always present, always single instance.
|
|
15
|
-
- **Cloud (catalog)** — instances the user owns on cicy-ai.com. Populated
|
|
16
|
-
by the cloud catalog API once it exists. (Phase 2)
|
|
17
|
-
- **Manual** — arbitrary URL + token the user pasted in. Lives forever
|
|
18
|
-
in the local registry until removed.
|
|
19
|
-
|
|
20
|
-
Each backend opens in its own `BrowserWindow`. Multiple windows can coexist
|
|
21
|
-
targeting different backends (one local + two cloud, etc.). Closing the last
|
|
22
|
-
local window keeps the sidecar running; quitting the app stops it.
|
|
23
|
-
|
|
24
|
-
## Phases
|
|
25
|
-
|
|
26
|
-
| Phase | Scope | Blockers |
|
|
27
|
-
|-------|-------|----------|
|
|
28
|
-
| **1** | Local sidecar + manual backends + multi-window + native HTML launcher | none |
|
|
29
|
-
| **2** | Cloud catalog: login to cicy-ai.com, pull "my instances", auto-add to registry | cicy-ai.com catalog endpoint must exist |
|
|
30
|
-
| **3** | Polish: per-window status pill, reconnect button, backend health monitor, drag-reorder | none, can be incremental |
|
|
31
|
-
|
|
32
|
-
## Phase 1 — detailed design
|
|
33
|
-
|
|
34
|
-
### Data model
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
type Backend = {
|
|
38
|
-
id: string; // uuid; "local" reserved for the sidecar entry
|
|
39
|
-
name: string; // user-visible label
|
|
40
|
-
kind: "local" | "manual"; // Phase 2 adds "cloud"
|
|
41
|
-
url: string; // base URL (no token); for local = http://127.0.0.1:8008
|
|
42
|
-
token?: string; // bearer; absent for local (sidecar reads ~/global.json itself)
|
|
43
|
-
addedAt: string; // ISO timestamp
|
|
44
|
-
lastUsedAt?: string;
|
|
45
|
-
};
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
Persistence: `<userData>/backends.json`, written atomically. Schema versioned
|
|
49
|
-
in a top-level `{ "version": 1, "backends": [...] }` envelope.
|
|
50
|
-
|
|
51
|
-
The `local` entry is **auto-upserted** on every startup so the user cannot
|
|
52
|
-
accidentally delete it; the Manage dialog hides the delete button for `local`.
|
|
53
|
-
|
|
54
|
-
### Modules
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
src/backends/
|
|
58
|
-
registry.js # BackendRegistry — file-backed CRUD + auto-upsert local
|
|
59
|
-
window-manager.js # openWindowForBackend / closeAll / focus
|
|
60
|
-
launcher.html # native HTML launcher (no React)
|
|
61
|
-
launcher.js # launcher window's IPC + render logic (renderer-side)
|
|
62
|
-
ipc.js # main-side IPC handlers backends:list / add / remove / open
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Sidecar lifecycle changes (small)
|
|
66
|
-
|
|
67
|
-
`src/sidecar/cicy-code.js` already starts on `whenReady`. Phase 1 keeps that —
|
|
68
|
-
the sidecar starts unconditionally on app launch so the local backend is
|
|
69
|
-
"warm." When the catalog API ships (Phase 2) and the user wants to skip the
|
|
70
|
-
local sidecar entirely, we'll add `--no-sidecar` and a per-launcher toggle.
|
|
71
|
-
|
|
72
|
-
No multi-spawn risk: `sidecar.start()` already early-returns when `child` is
|
|
73
|
-
non-null or when `:8008` already has a listener.
|
|
74
|
-
|
|
75
|
-
### UI flows
|
|
76
|
-
|
|
77
|
-
**On launch.** No START_URL set → open launcher window (loads
|
|
78
|
-
`backends/launcher.html`). The launcher renders the registry list and
|
|
79
|
-
provides "Open", "+ Add backend", "Manage".
|
|
80
|
-
|
|
81
|
-
If a `--backend <id>` argv is present, skip the launcher and open that
|
|
82
|
-
backend directly. (Lets the existing `cicy-dektop.command` Desktop launcher
|
|
83
|
-
keep its "always open my default" behavior.)
|
|
84
|
-
|
|
85
|
-
**Open Window.** From launcher or menu → `backends.open(id)` IPC →
|
|
86
|
-
`window-manager.openWindowForBackend(backend)`:
|
|
87
|
-
|
|
88
|
-
- For `local`: await `sidecar.start()`, then `createWindow({ url: <sidecar URL with token from ~/global.json> })`. URL identical to the current single-window default.
|
|
89
|
-
- For `manual` / `cloud`: `createWindow({ url: \`${backend.url}/console/chrome?token=${backend.token}\` })`. Token is injected at the URL level; window has no other env coupling.
|
|
90
|
-
|
|
91
|
-
Each window gets a `Window.backendId` attached (via a `WeakMap` keyed on the
|
|
92
|
-
BrowserWindow). On close, the entry is removed.
|
|
93
|
-
|
|
94
|
-
**Add backend.** Form fields: name, URL, token. Validates URL parses, probes
|
|
95
|
-
`<url>/health` with the token, on success writes to registry + refreshes
|
|
96
|
-
list. No probe → still saves (offline edit).
|
|
97
|
-
|
|
98
|
-
**Manage.** Lists all non-`local` entries with delete button. Local entry
|
|
99
|
-
shown read-only at the top.
|
|
100
|
-
|
|
101
|
-
### IPC contract
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
backends:list → Backend[]
|
|
105
|
-
backends:add (input: {name, url, token, kind:"manual"}) → Backend
|
|
106
|
-
backends:remove (id: string) → boolean
|
|
107
|
-
backends:open (id: string) → {windowId: number}
|
|
108
|
-
backends:probe ({url, token}) → {ok: bool, version?: string}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
All registered in `src/backends/ipc.js`; exposed to the launcher renderer
|
|
112
|
-
via `contextBridge` in a small preload.
|
|
113
|
-
|
|
114
|
-
### Menu changes
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
File
|
|
118
|
-
New Local Window Cmd+N
|
|
119
|
-
Open Backend Window… Cmd+Shift+N → launcher
|
|
120
|
-
Manage Backends…
|
|
121
|
-
----
|
|
122
|
-
Quit
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Sequence: app cold start with no argv
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
electronApp.whenReady
|
|
129
|
-
├─ ensureDesktopLauncher (existing)
|
|
130
|
-
├─ sidecarCicyCode.start (existing)
|
|
131
|
-
├─ server.listen 8101 (existing MCP)
|
|
132
|
-
└─ openLauncherWindow() ← new (replaces auto-createWindow(START_URL))
|
|
133
|
-
└─ user clicks "Open" on a backend
|
|
134
|
-
→ windowManager.openWindowForBackend(backend)
|
|
135
|
-
→ BrowserWindow loading backend URL
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Existing behavior preserved: if `START_URL` env / argv is set, skip launcher
|
|
139
|
-
and open it directly (keeps `node bin/cicy-desktop --url …` working).
|
|
140
|
-
|
|
141
|
-
## Phase 2 — cloud catalog (sketch only)
|
|
142
|
-
|
|
143
|
-
Once cicy-ai.com exposes:
|
|
144
|
-
|
|
145
|
-
```
|
|
146
|
-
GET https://cicy-ai.com/v1/instances (auth: Bearer <user token>)
|
|
147
|
-
→ { instances: [ { id, name, url, token, region, ... } ] }
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
we add:
|
|
151
|
-
|
|
152
|
-
- `src/auth/cicy-ai.js` — OAuth or token-paste flow against cicy-ai.com,
|
|
153
|
-
stores user token in `<userData>/cicy-ai-auth.json` (mode 0600).
|
|
154
|
-
- `BackendRegistry.refreshFromCloud()` — pulls /v1/instances, upserts
|
|
155
|
-
entries with `kind: "cloud"`. Removes cloud entries that disappeared.
|
|
156
|
-
- Launcher gains a "Sign in to cicy-ai.com" button + "Refresh" action.
|
|
157
|
-
|
|
158
|
-
Cloud backends differ from manual only in:
|
|
159
|
-
- They can be re-fetched and updated automatically.
|
|
160
|
-
- Manage shows them read-only (server is the source of truth).
|
|
161
|
-
|
|
162
|
-
## Phase 3 — polish
|
|
163
|
-
|
|
164
|
-
- Window title bar shows backend name + green/red dot for health (200 on
|
|
165
|
-
`<url>/health` within 5 s).
|
|
166
|
-
- "Reconnect" menu action for the active window.
|
|
167
|
-
- Background poller: every 30 s probe each backend with a listening window
|
|
168
|
-
open; surface disconnects as a notification.
|
|
169
|
-
- Launcher: drag to reorder, search box, group by kind.
|
|
170
|
-
|
|
171
|
-
## Open questions
|
|
172
|
-
|
|
173
|
-
1. **Default backend on first launch.** Open launcher window, or auto-open
|
|
174
|
-
the local backend (current behavior)? Lean toward launcher so the user
|
|
175
|
-
sees their list immediately, but a "Open local by default" preference
|
|
176
|
-
keeps the one-click path for power users.
|
|
177
|
-
2. **Sidecar autostart toggle.** When the user wants to use cloud-only and
|
|
178
|
-
the local sidecar wastes resources. Adding `prefs.sidecarAutostart` is
|
|
179
|
-
trivial; defer until someone asks.
|
|
180
|
-
3. **Per-backend window preferences.** Window position, zoom, devtools
|
|
181
|
-
state — currently keyed on URL by `WindowState`. Re-keying on backendId
|
|
182
|
-
would survive URL token rotation but is more code. Defer to Phase 3.
|
|
183
|
-
4. **Master/Worker cluster integration.** `src/master/` + `src/cluster/`
|
|
184
|
-
currently treat the desktop as a worker registering to a master. That
|
|
185
|
-
is **orthogonal** to backend selection; both can coexist. Worth
|
|
186
|
-
re-evaluating in Phase 3 whether the cluster code is still needed at
|
|
187
|
-
all once cloud catalog covers fleet view.
|
|
188
|
-
|
|
189
|
-
## Out of scope
|
|
190
|
-
|
|
191
|
-
- Auto-update / version-pin per backend.
|
|
192
|
-
- Backend-specific code-signing chains.
|
|
193
|
-
- Cross-machine session sync.
|
|
194
|
-
- Replacing the existing `src/master/` admin UI.
|
|
195
|
-
|
|
196
|
-
## Next concrete steps once approved
|
|
197
|
-
|
|
198
|
-
1. `src/backends/registry.js` + tests.
|
|
199
|
-
2. `src/backends/ipc.js` + `window-manager.js`.
|
|
200
|
-
3. `src/backends/launcher.html` + launcher renderer.
|
|
201
|
-
4. Wire menu items + initial-launch behavior into `src/main.js`.
|
|
202
|
-
5. Manual smoke: launch app → see launcher → open local → opens window →
|
|
203
|
-
add a fake manual backend pointing at the same local URL → open second
|
|
204
|
-
window → verify both windows render the chrome console independently.
|
package/docs/chrome-proxy.md
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# Worker Chrome HTTP 代理路由(/chrome)说明文档
|
|
2
|
-
|
|
3
|
-
## 背景 / 目标
|
|
4
|
-
|
|
5
|
-
现状:worker 的 HTTP 服务端口(例如 8101)已承载 REST/RPC(`/rpc/*`),但各 Chrome profile 的 CDP 实际监听在各自的本地 debugger port(例如 11001)。外部目前只能通过 `/rpc/chrome_*` 工具间接操作,无法通过 worker 的稳定入口直接访问 Chrome 的常用 HTTP 端点(如 `/json/version`、`/json/list`、`/json/activate/*`)或发起任意 CDP method call。
|
|
6
|
-
|
|
7
|
-
目标:在不改变现有 `/rpc/:toolName` 调用方式的前提下,新增 worker 侧 HTTP 路由,让外部可以通过统一的 8101(或 worker 实际监听端口)入口,按 `accountIdx` 路由到对应 profile 的 debugger port。
|
|
8
|
-
|
|
9
|
-
## 新增能力(HTTP 路由)
|
|
10
|
-
|
|
11
|
-
以下路由均挂载在 worker 的 HTTP 服务下,并与 `/rpc/*` 一样受 `authMiddleware` 保护(Bearer token)。
|
|
12
|
-
|
|
13
|
-
- `GET /chrome/:accountIdx/json/version`
|
|
14
|
-
- `GET /chrome/:accountIdx/json/list`
|
|
15
|
-
- `POST /chrome/:accountIdx/json/activate/:targetId`
|
|
16
|
-
- `POST /chrome/:accountIdx/cdp/call`
|
|
17
|
-
|
|
18
|
-
> 首版只做 HTTP facade(调用现有 helper),不做 websocket upgrade 透传。
|
|
19
|
-
|
|
20
|
-
## 端口解析规则(accountIdx -> debuggerPort)
|
|
21
|
-
|
|
22
|
-
与现有 `/rpc` 工具行为对齐,优先级如下:
|
|
23
|
-
|
|
24
|
-
1. 若 `~/cicy-ai/db/chrome.json` 中存在 `account_<idx>.port`,优先使用该 port
|
|
25
|
-
2. 否则回退到 `runtime-registry` 中 `registry.get(accountIdx)?.debuggerPort`
|
|
26
|
-
3. 都没有则返回错误(HTTP 404)
|
|
27
|
-
|
|
28
|
-
这部分被抽成共享逻辑,避免 `/rpc/chrome_*` 与 `/chrome/*` 对同一账号解析出不同端口。
|
|
29
|
-
|
|
30
|
-
## 认证
|
|
31
|
-
|
|
32
|
-
所有 `/chrome/*` 路由均复用既有 `authMiddleware`(与 `/rpc/*` 一致)。
|
|
33
|
-
|
|
34
|
-
请求示例(token 来自 `~/global.json` 的 `api_token`,或你自己的注入方式):
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
curl -H "Authorization: Bearer <token>" \
|
|
38
|
-
http://127.0.0.1:<PORT>/chrome/1/json/version
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## API 细节与示例
|
|
42
|
-
|
|
43
|
-
### 1) 获取版本信息
|
|
44
|
-
|
|
45
|
-
`GET /chrome/:accountIdx/json/version`
|
|
46
|
-
|
|
47
|
-
返回:Chrome 原始 `/json/version` JSON(不改写字段)。
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
curl -H "Authorization: Bearer <token>" \
|
|
51
|
-
http://127.0.0.1:<PORT>/chrome/1/json/version
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### 2) 获取 targets 列表
|
|
55
|
-
|
|
56
|
-
`GET /chrome/:accountIdx/json/list`
|
|
57
|
-
|
|
58
|
-
返回:Chrome 原始 `/json/list` 数组。
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
curl -H "Authorization: Bearer <token>" \
|
|
62
|
-
http://127.0.0.1:<PORT>/chrome/1/json/list
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### 3) 激活某个 target
|
|
66
|
-
|
|
67
|
-
`POST /chrome/:accountIdx/json/activate/:targetId`
|
|
68
|
-
|
|
69
|
-
返回:统一返回 JSON(避免 text/plain 不一致):
|
|
70
|
-
|
|
71
|
-
```json
|
|
72
|
-
{ "ok": true, "text": "Target activated" }
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
curl -X POST -H "Authorization: Bearer <token>" \
|
|
77
|
-
http://127.0.0.1:<PORT>/chrome/1/json/activate/<targetId>
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### 4) 发起任意 CDP method call
|
|
81
|
-
|
|
82
|
-
`POST /chrome/:accountIdx/cdp/call`
|
|
83
|
-
|
|
84
|
-
Body:
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{ "method": "Browser.getVersion", "params": {}, "target": "optional" }
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
返回:
|
|
91
|
-
|
|
92
|
-
```json
|
|
93
|
-
{ "result": { ... } }
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
curl -X POST \
|
|
98
|
-
-H "Authorization: Bearer <token>" \
|
|
99
|
-
-H "Content-Type: application/json" \
|
|
100
|
-
-d '{"method":"Browser.getVersion","params":{}}' \
|
|
101
|
-
http://127.0.0.1:<PORT>/chrome/1/cdp/call
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## 错误语义(HTTP)
|
|
105
|
-
|
|
106
|
-
- `accountIdx` 非整数:`400`
|
|
107
|
-
`{"error":"accountIdx must be an integer"}`
|
|
108
|
-
- account 找不到 port(private config + runtime 都没有):`404`
|
|
109
|
-
`{"error":"Missing debuggerPort for accountIdx=<n>"}`
|
|
110
|
-
- 上游 debugger port 不可达、或 CDP 调用失败:`502`
|
|
111
|
-
`{"error":"<message>","debuggerPort":11001,...}`
|
|
112
|
-
- `/cdp/call` 缺少 `method`:`400`
|
|
113
|
-
`{"error":"Missing method"}`
|
|
114
|
-
|
|
115
|
-
## 非目标(本次不做)
|
|
116
|
-
|
|
117
|
-
- 不做 websocket proxy / upgrade
|
|
118
|
-
因此也不改写 `/json/version` 和 `/json/list` 里的 `webSocketDebuggerUrl`,避免“看起来能连,实际无法 upgrade”的误导。
|
|
119
|
-
- 不引入通用反向代理依赖,不做字节级 raw reverse proxy。
|
|
120
|
-
|
|
121
|
-
## 代码变更点(关键文件)
|
|
122
|
-
|
|
123
|
-
- 新增:`src/server/chrome-proxy-routes.js`
|
|
124
|
-
实现 `/chrome/:accountIdx/...` 路由
|
|
125
|
-
- 新增:`src/chrome/debugger-port-resolver.js`
|
|
126
|
-
统一端口解析优先级(private config > runtime registry)
|
|
127
|
-
- 修改:`src/main.js`
|
|
128
|
-
挂载:`app.use("/chrome", authMiddleware, createChromeProxyRoutes(...))`
|
|
129
|
-
- 修改:`src/tools/chrome-tools.js`
|
|
130
|
-
让 `chrome_get_targets` / `chrome_cdp_call` 复用同一端口解析逻辑(保持行为一致)
|
|
131
|
-
- 新增测试:`tests/rpc/chrome-proxy-routes.test.js`
|
|
132
|
-
覆盖成功路径与关键错误语义
|
|
133
|
-
|
|
134
|
-
## 测试验证
|
|
135
|
-
|
|
136
|
-
已新增并通过的单测(只跑该文件):
|
|
137
|
-
|
|
138
|
-
```bash
|
|
139
|
-
npx jest tests/rpc/chrome-proxy-routes.test.js --runInBand
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
> 注:完整 `npm test` 当前在仓库内存在与本次变更无关的既有失败(例如其他 RPC suite 报 `sleep is not a function`),不属于本次引入回归。
|