nx-ce 0.1.6 → 0.1.7
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/README.md +93 -67
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,12 +41,13 @@ nx-ce query "用中文回答:1+1=?" --model claude-haiku-4-5
|
|
|
41
41
|
# Start WebSocket server (persistent, multi-session)
|
|
42
42
|
nx-ce serve --port 3100
|
|
43
43
|
|
|
44
|
-
# In another terminal,
|
|
44
|
+
# In another terminal, run tests
|
|
45
|
+
node test/serve-test.mjs
|
|
45
46
|
```
|
|
46
47
|
|
|
47
48
|
---
|
|
48
49
|
|
|
49
|
-
## `nx-ce query` — One-
|
|
50
|
+
## `nx-ce query` — One-Shot Cold-Start Query / 一次性冷启动查询
|
|
50
51
|
|
|
51
52
|
```bash
|
|
52
53
|
nx-ce query "解释这段代码" --model claude-sonnet-4-6
|
|
@@ -80,9 +81,9 @@ nx-ce query "Analyze" --skill all
|
|
|
80
81
|
|
|
81
82
|
## `nx-ce serve` — WebSocket Multi-Session Server / WebSocket 多会话服务器
|
|
82
83
|
|
|
83
|
-
**Single process. Multiple concurrent sessions.
|
|
84
|
+
**Single process. Multiple concurrent sessions. Each session has its own cwd.**
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
单例进程。多会话隔离。每个会话可指定自己的工作目录。
|
|
86
87
|
|
|
87
88
|
```bash
|
|
88
89
|
nx-ce serve # default port 3100
|
|
@@ -96,7 +97,7 @@ nx-ce serve --name "main" --port 3100 --cwd "D:/project"
|
|
|
96
97
|
| `--port <port>` | WebSocket port (default `3100`) / 端口 |
|
|
97
98
|
| `--model <id>` | Model override / 模型 ID |
|
|
98
99
|
| `--claude-path <path>` | Path to Claude CLI / CLI 路径 |
|
|
99
|
-
| `--cwd <path>` |
|
|
100
|
+
| `--cwd <path>` | Default working directory / 默认工作目录 |
|
|
100
101
|
| `--env "KEY=val,..."` | Extra env vars / 额外环境变量 |
|
|
101
102
|
|
|
102
103
|
> WebSocket address: `ws://127.0.0.1:3100` (localhost only)
|
|
@@ -105,7 +106,58 @@ nx-ce serve --name "main" --port 3100 --cwd "D:/project"
|
|
|
105
106
|
|
|
106
107
|
```bash
|
|
107
108
|
nx-ce serve --port 3100 # first → OK
|
|
108
|
-
nx-ce serve --port 3100 # second → Port
|
|
109
|
+
nx-ce serve --port 3100 # second → Port already in use — another instance is running
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Multi-Session / 多会话管理
|
|
115
|
+
|
|
116
|
+
### Auto-create on first query / 首次 query 自动创建
|
|
117
|
+
|
|
118
|
+
Session 是**隐式创建**的。第一次发 `query` 时自动创建 SDK 会话,之后同名的 query 续接上下文:
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
// 新会话 "proj-a",工作目录 D:/project-a
|
|
122
|
+
→ { "type": "query", "session": "proj-a", "cwd": "D:/project-a", "prompt": "分析目录结构" }
|
|
123
|
+
|
|
124
|
+
// 新会话 "proj-b",工作目录 D:/project-b(不同的 session 名 = 不同的 agentQuery)
|
|
125
|
+
→ { "type": "query", "session": "proj-b", "cwd": "D:/project-b", "prompt": "分析目录结构" }
|
|
126
|
+
|
|
127
|
+
// 同一 session 名 + 不同 cwd → 也是独立的 agentQuery
|
|
128
|
+
→ { "type": "query", "session": "proj-a", "cwd": "D:/project-a/src", "prompt": "分析 src" }
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
内部标识 key 格式为 `{name}:{cwd}`:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
proj-a:D~project-a → SDK 会话 A
|
|
135
|
+
proj-b:D~project-b → SDK 会话 B
|
|
136
|
+
proj-a:D~project-a~src → SDK 会话 C
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Close session / 关闭会话
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
// 关闭精确会话(指定 cwd)
|
|
143
|
+
→ { "type": "closeSession", "session": "proj-a", "cwd": "D:/project-a" }
|
|
144
|
+
|
|
145
|
+
// 关闭该 name 下所有 cwd 变体
|
|
146
|
+
→ { "type": "closeSession", "session": "proj-a" }
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Idle auto-reclaim / 空闲自动回收
|
|
150
|
+
|
|
151
|
+
客户端断开连接 5 分钟后,session 自动销毁并清理状态文件。
|
|
152
|
+
|
|
153
|
+
### List sessions / 查看会话
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
→ { "type": "listSessions" }
|
|
157
|
+
← { "type": "session_list", "sessions": [
|
|
158
|
+
{ "name": "proj-a", "cwd": "D:/project-a", "sessionId": "sess_xxx", "processing": false },
|
|
159
|
+
{ "name": "proj-b", "cwd": "D:/project-b", "sessionId": "sess_yyy", "processing": true }
|
|
160
|
+
]}
|
|
109
161
|
```
|
|
110
162
|
|
|
111
163
|
---
|
|
@@ -118,21 +170,22 @@ Server: `ws://127.0.0.1:PORT`. All messages are JSON (no length prefix).
|
|
|
118
170
|
|
|
119
171
|
| type | Fields / 字段 | Description / 说明 |
|
|
120
172
|
|------|---------------|-------------------|
|
|
121
|
-
| `query` | `prompt: string`, `session?: string`, `id?: string` | Submit a query / 发起查询 |
|
|
173
|
+
| `query` | `prompt: string`, `session?: string`, `cwd?: string`, `id?: string` | Submit a query / 发起查询 |
|
|
122
174
|
| `ping` | — | Heartbeat / 心跳 |
|
|
123
|
-
| `getSkills` | `session?: string` | Fetch skills/tools/agents / 拉取元数据 |
|
|
124
|
-
| `getStatus` | `session?: string` | Query session status / 查询状态 |
|
|
125
|
-
| `closeSession` | `session: string` | Close
|
|
175
|
+
| `getSkills` | `session?: string`, `cwd?: string` | Fetch skills/tools/agents / 拉取元数据 |
|
|
176
|
+
| `getStatus` | `session?: string`, `cwd?: string` | Query session status / 查询状态 |
|
|
177
|
+
| `closeSession` | `session: string`, `cwd?: string` | Close session(s) / 关闭会话 |
|
|
126
178
|
| `listSessions` | — | List all active sessions / 列出会话 |
|
|
127
179
|
|
|
128
|
-
`session` defaults to `"default"
|
|
180
|
+
`session` defaults to `"default"`.
|
|
129
181
|
|
|
130
182
|
```json
|
|
131
|
-
→ { "type": "query",
|
|
183
|
+
→ { "type": "query", "session": "proj-a", "cwd": "D:/project-a", "prompt": "分析" }
|
|
132
184
|
→ { "type": "ping" }
|
|
133
|
-
→ { "type": "getSkills",
|
|
134
|
-
→ { "type": "getStatus",
|
|
135
|
-
→ { "type": "closeSession",
|
|
185
|
+
→ { "type": "getSkills", "session": "proj-a" }
|
|
186
|
+
→ { "type": "getStatus", "session": "proj-a", "cwd": "D:/project-a" }
|
|
187
|
+
→ { "type": "closeSession", "session": "proj-a", "cwd": "D:/project-a" }
|
|
188
|
+
→ { "type": "closeSession", "session": "proj-a" }
|
|
136
189
|
→ { "type": "listSessions" }
|
|
137
190
|
```
|
|
138
191
|
|
|
@@ -142,7 +195,7 @@ Server: `ws://127.0.0.1:PORT`. All messages are JSON (no length prefix).
|
|
|
142
195
|
|
|
143
196
|
```json
|
|
144
197
|
← { "type": "connected", "port": 3100, "host": "MY-PC",
|
|
145
|
-
"machineId": "744e51b9
|
|
198
|
+
"machineId": "744e51b9-...", "serverTime": 1780736149028 }
|
|
146
199
|
```
|
|
147
200
|
|
|
148
201
|
**Session init (auto-push on first query per session) / 会话初始化(自动推送):**
|
|
@@ -161,7 +214,7 @@ Server: `ws://127.0.0.1:PORT`. All messages are JSON (no length prefix).
|
|
|
161
214
|
← { "type": "turn_start", "turn": "turn_xxx", "time": ... }
|
|
162
215
|
← { "type": "text", "content": "这是一段回复...", "time": ... }
|
|
163
216
|
← { "type": "thinking", "content": "模型思考过程...", "time": ... }
|
|
164
|
-
← { "type": "tool_use", "name": "readFile", "input": {...}
|
|
217
|
+
← { "type": "tool_use", "name": "readFile", "input": {...} }
|
|
165
218
|
← { "type": "done", "sessionId": "sess_xxx", "time": ... }
|
|
166
219
|
```
|
|
167
220
|
|
|
@@ -170,19 +223,19 @@ Server: `ws://127.0.0.1:PORT`. All messages are JSON (no length prefix).
|
|
|
170
223
|
```json
|
|
171
224
|
← { "type": "pong", "sessionId": "sess_xxx", "serverTime": ... }
|
|
172
225
|
← { "type": "skills", "skills": [...], "tools": [...], ... }
|
|
173
|
-
← { "type": "status", "session": "
|
|
174
|
-
← { "type": "session_list", "sessions": [{ "name": "
|
|
175
|
-
← { "type": "session_closed","session": "
|
|
226
|
+
← { "type": "status", "session": "proj-a", "cwd": "D:/project-a", "sessionId": "...", "isActive": true }
|
|
227
|
+
← { "type": "session_list", "sessions": [{ "name":"proj-a", "cwd":"D:/project-a", ... }, ...] }
|
|
228
|
+
← { "type": "session_closed","session": "proj-a", "cwd": "D:/project-a" }
|
|
176
229
|
← { "type": "error", "content": "error message" }
|
|
177
230
|
```
|
|
178
231
|
|
|
179
232
|
### Full exchange example / 完整示例
|
|
180
233
|
|
|
181
234
|
```
|
|
182
|
-
→ { "type":"query", "session":"
|
|
235
|
+
→ { "type":"query", "session":"proj-a", "cwd":"D:/project-a", "prompt":"Hello" }
|
|
183
236
|
← { "type":"turn_start", "turn":"turn_xxx", "time":... }
|
|
184
|
-
← { "type":"text",
|
|
185
|
-
← { "type":"done",
|
|
237
|
+
← { "type":"text", "content":"Hello! How can I help?" }
|
|
238
|
+
← { "type":"done", "sessionId":"sess_abc", "time":... }
|
|
186
239
|
|
|
187
240
|
→ { "type":"ping" }
|
|
188
241
|
← { "type":"pong", "sessionId":"sess_abc", "serverTime":... }
|
|
@@ -190,51 +243,41 @@ Server: `ws://127.0.0.1:PORT`. All messages are JSON (no length prefix).
|
|
|
190
243
|
|
|
191
244
|
---
|
|
192
245
|
|
|
193
|
-
##
|
|
246
|
+
## Architecture / 架构
|
|
194
247
|
|
|
195
248
|
```
|
|
196
249
|
nx-ce serve (single Node.js process)
|
|
197
|
-
|
|
250
|
+
┌──────────────────────────────────────────────────────────┐
|
|
198
251
|
│ WebSocket Server (127.0.0.1:3100) │
|
|
199
252
|
│ │
|
|
200
253
|
│ SessionManager │
|
|
201
254
|
│ ┌─────────────────────────────────────────────────────┐ │
|
|
202
|
-
│ │ "
|
|
203
|
-
│ │ "
|
|
204
|
-
│ │ "
|
|
255
|
+
│ │ "proj-a:D~/project-a" → agentQuery(cwd: project-a) │ │
|
|
256
|
+
│ │ "proj-b:D~/project-b" → agentQuery(cwd: project-b) │ │
|
|
257
|
+
│ │ "proj-a:D~/other" → agentQuery(cwd: other) │ │
|
|
205
258
|
│ └──────────────────────┬──────────────────────────────┘ │
|
|
206
259
|
│ spawn each | (SDK manages CLI processes) │
|
|
207
|
-
│
|
|
260
|
+
│ Claude CLI ──────────┴── Claude CLI ──── Claude CLI │
|
|
208
261
|
└───────────────────────────────────────────────────────────┘
|
|
209
262
|
```
|
|
210
263
|
|
|
264
|
+
### Session identity / 会话标识
|
|
265
|
+
|
|
266
|
+
Session key = `{name}:{cwd}`. Same name + different cwd = different SDK session.
|
|
267
|
+
Each session has its own `agentQuery()`, `MessageChannel`, `MonotonicClock`, and state file.
|
|
268
|
+
|
|
211
269
|
### Concurrency guarantees / 竞态保护
|
|
212
270
|
|
|
213
271
|
| Race / 竞态 | Solution / 方案 |
|
|
214
272
|
|-------------|----------------|
|
|
215
273
|
| Concurrent session creation | `_pendingCreates` Map deduplicates in-flight creation promises |
|
|
216
274
|
| SDK response routing | Each session has independent `for await` loop, writes only to `session.client` |
|
|
217
|
-
| State file overwrite | Per-session files (`{name}.json`)
|
|
218
|
-
| Message ordering | Per-session `MonotonicClock` ensures strict
|
|
275
|
+
| State file overwrite | Per-session files (`{name~cwd}.json`) |
|
|
276
|
+
| Message ordering | Per-session `MonotonicClock` ensures strict ordering |
|
|
219
277
|
| Client disconnect cleanup | Null client ref + clear queue + 5-min idle timeout auto-destroy |
|
|
220
278
|
|
|
221
279
|
---
|
|
222
280
|
|
|
223
|
-
## `nx-ce status` — Instance Status / 查看实例状态
|
|
224
|
-
|
|
225
|
-
```bash
|
|
226
|
-
nx-ce status # List all instances
|
|
227
|
-
nx-ce status --name chat-1 # Show specific instance
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
```json
|
|
231
|
-
{ "name": "chat-1", "pid": 12345, "lifecycleState": "running",
|
|
232
|
-
"sessionId": "sess_abc", "model": "claude-sonnet-4-6",
|
|
233
|
-
"port": 3100, "host": "MY-PC" }
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
281
|
## `nx-ce skills` — List Available Skills / 列出可用 Skill
|
|
239
282
|
|
|
240
283
|
```bash
|
|
@@ -252,18 +295,16 @@ nx-ce skills --cwd "D:/project"
|
|
|
252
295
|
|
|
253
296
|
## State Persistence / 状态持久化
|
|
254
297
|
|
|
255
|
-
State files at `~/.nx-ce/instances/{
|
|
298
|
+
State files at `~/.nx-ce/instances/{key}.json`. Key format: `{name}~{cwd}`.
|
|
256
299
|
|
|
257
300
|
```json
|
|
258
301
|
{
|
|
259
|
-
"name": "
|
|
260
|
-
"pid": 12345,
|
|
261
|
-
"startedAt": "2026-06-06T10:30:00.000Z",
|
|
262
|
-
"updatedAt": "2026-06-06T11:00:00.000Z",
|
|
302
|
+
"name": "proj-a:D~/project-a",
|
|
263
303
|
"sessionId": "sess_abc123",
|
|
264
304
|
"model": "claude-sonnet-4-6",
|
|
305
|
+
"cwd": "D:/project-a",
|
|
265
306
|
"host": "MY-PC",
|
|
266
|
-
"machineId": "
|
|
307
|
+
"machineId": "744e51b9-...",
|
|
267
308
|
"lifecycleState": "running",
|
|
268
309
|
"port": 3100,
|
|
269
310
|
"usage": { "inputTokens": 1500, "outputTokens": 3200, ... }
|
|
@@ -279,21 +320,6 @@ State files at `~/.nx-ce/instances/{name}.json`:
|
|
|
279
320
|
|
|
280
321
|
---
|
|
281
322
|
|
|
282
|
-
## Architecture / 架构
|
|
283
|
-
|
|
284
|
-
```
|
|
285
|
-
Chrome Extension / 浏览器扩展
|
|
286
|
-
↕ WebSocket (ws://127.0.0.1:3100)
|
|
287
|
-
nx-ce serve (Node.js)
|
|
288
|
-
├─ SessionManager → agentQuery()
|
|
289
|
-
│ ↕
|
|
290
|
-
│ Claude CLI
|
|
291
|
-
│
|
|
292
|
-
└─ (Native Host via exec.Command → nx-ce query --resume)
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
323
|
## Development / 开发
|
|
298
324
|
|
|
299
325
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx-ce",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Claude Engine — SDK adapter layer for native messaging host. Bridges @anthropic-ai/claude-agent-sdk calls over a length-prefixed JSON protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|