nx-ce 0.1.3 → 0.1.5

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 CHANGED
@@ -3,194 +3,332 @@
3
3
  [![npm version](https://img.shields.io/npm/v/nx-ce)](https://www.npmjs.com/package/nx-ce)
4
4
  [![CI](https://github.com/joke-lx/nx-ce/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/joke-lx/nx-ce/actions/workflows/npm-publish.yml)
5
5
 
6
- **nx-ce** 是一个轻量级 Node.js 适配器,封装了 `@anthropic-ai/claude-agent-sdk`。
7
- 通过长度前缀的 JSON 协议(与 Chrome Native Messaging 格式一致)在 stdin/stdout 上暴露 SDK 接口,
8
- 支持一次性冷启动查询与持久化服务两种运行模式。
6
+ **nx-ce** is a lightweight Node.js adapter for `@anthropic-ai/claude-agent-sdk`. It provides two modes:
9
7
 
10
- **nx-ce** is a lightweight Node.js adapter for `@anthropic-ai/claude-agent-sdk`.
11
- It exposes the SDK over stdin/stdout via a length-prefixed JSON protocol (identical to Chrome native messaging),
12
- supporting both one-shot cold-start queries and persistent serve sessions.
8
+ - **`nx-ce query`** one-shot cold-start queries (stateless, CLI-friendly)
9
+ - **`nx-ce serve`** WebSocket multi-session server (persistent, concurrent clients)
10
+
11
+ **nx-ce** 是一个轻量级 Node.js 适配器,封装了 `@anthropic-ai/claude-agent-sdk`。支持两种运行模式:
12
+ 一次性冷启动查询与多会话 WebSocket 持久化服务器。
13
13
 
14
14
  ---
15
15
 
16
- ## 项目家族 / Family
16
+ ## Family / 项目家族
17
17
 
18
- | Package | 角色 / Role |
18
+ | Package | Role / 角色 |
19
19
  |---------|-------------|
20
- | **nx-ce** | Claude Engine — SDK 适配层 / SDK adapter layer |
21
- | [nx-sx](https://github.com/jokelx/nx-sx) | Sandbox eXecution — 窗口/终端管理器 / window & terminal manager |
20
+ | **nx-ce** | Claude Engine — SDK adapter layer / SDK 适配层 |
21
+ | [nx-sx](https://github.com/jokelx/nx-sx) | Sandbox eXecution — window & terminal manager / 窗口终端管理器 |
22
22
 
23
23
  ---
24
24
 
25
- ## 安装 / Install
25
+ ## Install / 安装
26
26
 
27
27
  ```bash
28
28
  npm install nx-ce
29
- # 或全局安装 / or install globally
29
+ # or globally
30
30
  npm install -g nx-ce
31
31
  ```
32
32
 
33
33
  ---
34
34
 
35
- ## 命令行用法 / CLI Usage
35
+ ## Quick Start / 快速开始
36
+
37
+ ```bash
38
+ # One-shot query (stateless)
39
+ nx-ce query "用中文回答:1+1=?" --model claude-haiku-4-5
36
40
 
37
- ### `nx-ce query <prompt>` 一次性冷启动查询 / One-shot cold-start query
41
+ # Start WebSocket server (persistent, multi-session)
42
+ nx-ce serve --port 3100
43
+
44
+ # In another terminal, connect via WebSocket (see test/serve-test.mjs)
45
+ ```
46
+
47
+ ---
48
+
49
+ ## `nx-ce query` — One-shot Cold-Start Query / 一次性冷启动查询
38
50
 
39
51
  ```bash
40
52
  nx-ce query "解释这段代码" --model claude-sonnet-4-6
41
- nx-ce query "Explain this code" --model claude-haiku-4-5 --no-persist
42
53
  nx-ce query "继续之前的对话" --resume sess_abc123
43
54
  nx-ce query "Analyze" --skill git-workflow,code-review
44
55
  nx-ce query "Analyze" --skill all
45
56
  ```
46
57
 
47
- | 选项 / Flag | 说明 / Description |
48
- |-------------|-------------------|
49
- | `--model <id>` | 模型 ID 覆盖(默认 `claude-sonnet-4-6`)/ Model override |
50
- | `--claude-path <path>` | Claude CLI 可执行文件路径 / Path to Claude CLI binary |
51
- | `--system-prompt <text>` | 系统提示词覆盖 / System prompt override |
52
- | `--resume <sessionId>` | 续接之前的会话(长对话)/ Resume a prior session |
53
- | `--skill <name>[,<name>...]` | 加载指定 Skill(逗号分隔,传 `all` 加载全部)/ Load specific skills |
54
- | `--include-metadata` | 输出中附带 skills/tools/slash_commands 信息 / Include skill/tool metadata in output |
55
- | `--no-persist` | 不持久化会话 / Don't persist session |
56
- | `--env "KEY=value,KEY2=val"` | 额外环境变量 / Extra environment variables |
58
+ | Flag | Description / 说明 |
59
+ |------|-------------------|
60
+ | `--model <id>` | Model override (default `claude-sonnet-4-6`) / 模型 ID |
61
+ | `--claude-path <path>` | Path to Claude CLI binary / Claude CLI 路径 |
62
+ | `--system-prompt <text>` | System prompt override / 系统提示词覆盖 |
63
+ | `--resume <sessionId>` | Resume a prior session (long conversation) / 续接会话 |
64
+ | `--skill <name>[,<name>...]` | Load specific skills (comma-separated, or `all`) / 加载 Skill |
65
+ | `--include-metadata` | Include skills/tools/slashCommands in output / 附带元数据 |
66
+ | `--no-persist` | Don't persist session / 不持久化 |
67
+ | `--env "KEY=val,KEY2=val"` | Extra environment variables / 额外环境变量 |
57
68
 
58
- ### `nx-ce serve` — 持久化管理器进程 / Persistent manager process
69
+ ### JSON output
59
70
 
60
- ```bash
61
- nx-ce serve --name chat-tab-1
62
- nx-ce serve --name default --model claude-sonnet-4-6
71
+ ```json
72
+ // Default
73
+ { "text": "2", "sessionId": "sess_abc" }
74
+
75
+ // With --include-metadata
76
+ { "text": "2", "sessionId": "sess_abc", "metadata": { "skills": [...], "tools": [...], ... } }
63
77
  ```
64
78
 
65
- 通过 stdin/stdout 接收 4B+JSON 协议消息,保持一个持久化的 SDK 会话。
66
- Reads/writes 4B+JSON protocol messages over stdin/stdout, maintaining a persistent SDK session.
79
+ ---
80
+
81
+ ## `nx-ce serve` — WebSocket Multi-Session Server / WebSocket 多会话服务器
67
82
 
68
- | 选项 / Flag | 说明 / Description |
69
- |-------------|-------------------|
70
- | `--name <name>` | 实例名称(默认 `"default"`)/ Instance name |
71
- | `--model <id>` | 模型 ID 覆盖 / Model override |
72
- | `--claude-path <path>` | Claude CLI 可执行文件路径 / Path to Claude CLI binary |
73
- | `--env "KEY=value,..."` | 额外环境变量 / Extra environment variables |
83
+ **Single process. Multiple concurrent sessions. FIFO queries per session.**
74
84
 
75
- ### `nx-ce status` — 查看实例状态 / Show instance state
85
+ 单例进程。多会话隔离。每个会话独立 SDK agentQuery,互不阻塞。
76
86
 
77
87
  ```bash
78
- nx-ce status # 列出所有实例 / List all instances
79
- nx-ce status --name chat-tab-1 # 查看指定实例 / Show specific instance
88
+ nx-ce serve # default port 3100
89
+ nx-ce serve --port 3100
90
+ nx-ce serve --name "main" --port 3100 --cwd "D:/project"
80
91
  ```
81
92
 
82
- ### `nx-ce help` 显示帮助 / Show help
93
+ | Flag | Description / 说明 |
94
+ |------|-------------------|
95
+ | `--name <name>` | Instance name (default `default`) / 实例名称 |
96
+ | `--port <port>` | WebSocket port (default `3100`) / 端口 |
97
+ | `--model <id>` | Model override / 模型 ID |
98
+ | `--claude-path <path>` | Path to Claude CLI / CLI 路径 |
99
+ | `--cwd <path>` | Working directory / 工作目录 |
100
+ | `--env "KEY=val,..."` | Extra env vars / 额外环境变量 |
101
+
102
+ > WebSocket address: `ws://127.0.0.1:3100` (localhost only)
103
+
104
+ ### Singleton guarantee / 单例保证
83
105
 
84
106
  ```bash
85
- nx-ce help
107
+ nx-ce serve --port 3100 # first → OK
108
+ nx-ce serve --port 3100 # second → Port 3100 already in use — another nx-ce serve is running
86
109
  ```
87
110
 
88
111
  ---
89
112
 
90
- ## 协议 / Protocol
113
+ ## WebSocket Protocol / WebSocket 协议
114
+
115
+ Server: `ws://127.0.0.1:PORT`. All messages are JSON (no length prefix).
116
+
117
+ ### Client → Server / 客户端发送
91
118
 
92
- 所有 IPC 使用与 Chrome Native Messaging 一致的线缆格式:
119
+ | type | Fields / 字段 | Description / 说明 |
120
+ |------|---------------|-------------------|
121
+ | `query` | `prompt: string`, `session?: string`, `id?: string` | Submit a query / 发起查询 |
122
+ | `ping` | — | Heartbeat / 心跳 |
123
+ | `getSkills` | `session?: string` | Fetch skills/tools/agents / 拉取元数据 |
124
+ | `getStatus` | `session?: string` | Query session status / 查询状态 |
125
+ | `closeSession` | `session: string` | Close a session / 关闭会话 |
126
+ | `listSessions` | — | List all active sessions / 列出会话 |
93
127
 
94
- All IPC uses the same wire format as Chrome native messaging:
128
+ `session` defaults to `"default"` if omitted.
95
129
 
130
+ ```json
131
+ → { "type": "query", "session": "tab-1", "prompt": "分析这个目录" }
132
+ → { "type": "ping" }
133
+ → { "type": "getSkills", "session": "tab-1" }
134
+ → { "type": "getStatus", "session": "tab-1" }
135
+ → { "type": "closeSession", "session": "tab-1" }
136
+ → { "type": "listSessions" }
137
+ ```
138
+
139
+ ### Server → Client / 服务端发送
140
+
141
+ **Connection / 连接建立:**
142
+
143
+ ```json
144
+ ← { "type": "connected", "port": 3100, "host": "MY-PC",
145
+ "machineId": "744e51b9-ad7d-85bb-1600-bbfb", "serverTime": 1780736149028 }
96
146
  ```
97
- [4 bytes LE uint32 = 负载长度 / payload length][UTF-8 JSON payload]
147
+
148
+ **Session init (auto-push on first query per session) / 会话初始化(自动推送):**
149
+
150
+ ```json
151
+ ← { "type": "init", "sessionId": "sess_xxx", "model": "claude-sonnet-4-6",
152
+ "skills": ["browse", "code-review", ...],
153
+ "tools": ["Read", "Edit", "Bash", ...],
154
+ "slashCommands": ["code-review", "ship", ...],
155
+ "agents": ["Explore", "code-reviewer", ...] }
98
156
  ```
99
157
 
100
- ### 查询(一次性)/ Query (one-shot)
158
+ **Query response (streamed chunks) / 查询响应(流式块):**
101
159
 
160
+ ```json
161
+ ← { "type": "turn_start", "turn": "turn_xxx", "time": ... }
162
+ ← { "type": "text", "content": "这是一段回复...", "time": ... }
163
+ ← { "type": "thinking", "content": "模型思考过程...", "time": ... }
164
+ ← { "type": "tool_use", "name": "readFile", "input": {...}, "id": "toolu_xxx" }
165
+ ← { "type": "done", "sessionId": "sess_xxx", "time": ... }
102
166
  ```
103
- → { "prompt": "...", "model": "...", "systemPrompt": "..." }
104
- ← { "text": "...", "sessionId": "sess_xxx" }
105
167
 
106
- # --include-metadata 时返回 metadata
107
- # With --include-metadata, response includes metadata:
108
- ← { "text": "...", "sessionId": "sess_xxx", "metadata": { "skills": [...], "tools": [...], "slashCommands": [...] } }
168
+ **Other / 其他:**
169
+
170
+ ```json
171
+ ← { "type": "pong", "sessionId": "sess_xxx", "serverTime": ... }
172
+ ← { "type": "skills", "skills": [...], "tools": [...], ... }
173
+ ← { "type": "status", "session": "tab-1", "sessionId": "sess_xxx", "isActive": true, "queueLength": 0, "processing": false }
174
+ ← { "type": "session_list", "sessions": [{ "name": "tab-1", ... }, ...] }
175
+ ← { "type": "session_closed","session": "tab-1" }
176
+ ← { "type": "error", "content": "error message" }
109
177
  ```
110
178
 
111
- ### 服务(持久化)/ Serve (persistent)
179
+ ### Full exchange example / 完整示例
112
180
 
113
181
  ```
114
- → { "id":"1", "type":"query", "prompt":"..." }
115
- ← { "id":"1", "type":"text", "content":"..." }
116
- ← { "id":"1", "type":"tool_use", "name":"readFile", "input":{...} }
117
- ← { "id":"1", "type":"thinking", "content":"..." }
118
- ← { "id":"1", "type":"done", "sessionId":"..." }
182
+ → { "type":"query", "session":"tab-1", "prompt":"Hello" }
183
+ ← { "type":"turn_start", "turn":"turn_xxx", "time":... }
184
+ ← { "type":"text", "content":"Hello! How can I help you today?" }
185
+ ← { "type":"done", "sessionId":"sess_abc", "time":... }
119
186
 
120
187
  → { "type":"ping" }
121
- ← { "type":"pong", "sessionId":"..." }
188
+ ← { "type":"pong", "sessionId":"sess_abc", "serverTime":... }
189
+ ```
190
+
191
+ ---
122
192
 
123
- { "type":"getSkills" }
124
- ← { "type":"skills", "skills":["browse",...], "tools":["Read",...], "slashCommands":[...], "agents":[...] }
193
+ ## Multi-Session Architecture / 多会话架构
125
194
 
126
- (首次 init 自动推送)
127
- { "type":"init", "skills":[...], "tools":[...], ... }
195
+ ```
196
+ nx-ce serve (single Node.js process)
197
+ ┌───────────────────────────────────────────────────────────┐
198
+ │ WebSocket Server (127.0.0.1:3100) │
199
+ │ │
200
+ │ SessionManager │
201
+ │ ┌─────────────────────────────────────────────────────┐ │
202
+ │ │ "tab-1": { agentQuery(), messageChannel, queue } │ │
203
+ │ │ "tab-2": { agentQuery(), messageChannel, queue } │ │
204
+ │ │ "tab-3": { agentQuery(), messageChannel, queue } │ │
205
+ │ └──────────────────────┬──────────────────────────────┘ │
206
+ │ spawn each | (SDK manages CLI processes) │
207
+ │ Claude CLI ─────┴──── Claude CLI ───── Claude CLI │
208
+ └───────────────────────────────────────────────────────────┘
128
209
  ```
129
210
 
130
- 协议消息类型 / Message types:
211
+ ### Concurrency guarantees / 竞态保护
131
212
 
132
- | 方向 / Dir | type | 说明 / Description |
133
- |------------|------|-------------------|
134
- | | `query` | 用户输入 / User input |
135
- | | `text` | 文本回复 / Text response |
136
- | | `tool_use` | 工具调用请求 / Tool use request |
137
- | | `thinking` | 思考过程 / Model thinking |
138
- | | `done` | 本轮完成,含会话 ID / Turn complete with session ID |
139
- | ← | `error` | 错误消息 / Error message |
140
- | → | `ping` | 心跳检测 / Heartbeat |
141
- | ← | `pong` | 心跳回复 / Heartbeat response |
142
- | → | `getSkills` | Go 端按需拉取技能/工具列表 / Fetch skills/tools list |
143
- | ← | `init` / `skills` | 技能列表回复 / Skills metadata response |
213
+ | Race / 竞态 | Solution / 方案 |
214
+ |-------------|----------------|
215
+ | Concurrent session creation | `_pendingCreates` Map deduplicates in-flight creation promises |
216
+ | SDK response routing | Each session has independent `for await` loop, writes only to `session.client` |
217
+ | State file overwrite | Per-session files (`{name}.json`) + write lock |
218
+ | Message ordering | Per-session `MonotonicClock` ensures strict time ordering |
219
+ | Client disconnect cleanup | Null client ref + clear queue + 5-min idle timeout auto-destroy |
144
220
 
145
221
  ---
146
222
 
147
- ## 架构 / Architecture
223
+ ## `nx-ce status` — Instance Status / 查看实例状态
148
224
 
225
+ ```bash
226
+ nx-ce status # List all instances
227
+ nx-ce status --name chat-1 # Show specific instance
149
228
  ```
150
- Chrome Extension / 浏览器扩展
151
- ↕ Native Messaging (4B+JSON)
152
- Native Host (Go)
153
- 4B+JSON (via executor.startProcess)
154
- nx-ce serve (Node.js)
155
- ↕ @anthropic-ai/claude-agent-sdk
156
- Claude Code CLI (子进程 / subprocess)
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" }
157
234
  ```
158
235
 
159
236
  ---
160
237
 
161
- ## 状态持久化 / State
238
+ ## `nx-ce skills` — List Available Skills / 列出可用 Skill
239
+
240
+ ```bash
241
+ nx-ce skills --cwd "D:/project"
242
+ ```
243
+
244
+ ```json
245
+ { "skills": ["code-review", "browse", ...],
246
+ "tools": ["Read", "Edit", "Bash", ...],
247
+ "slashCommands": ["code-review", ...],
248
+ "agents": ["Explore", ...] }
249
+ ```
162
250
 
163
- 状态持久化到 `~/.nx-ce/instances/{name}.json`。
164
- 每个命名实例存储其 PID、会话 ID 和启动时间,用于崩溃恢复和会话续接。
251
+ ---
165
252
 
166
- Persisted to `~/.nx-ce/instances/{name}.json`. Each named instance stores its PID, session ID, and start time for crash recovery and session resumption.
253
+ ## State Persistence / 状态持久化
167
254
 
168
- 示例状态文件 / Example state file:
255
+ State files at `~/.nx-ce/instances/{name}.json`:
169
256
 
170
257
  ```json
171
258
  {
172
259
  "name": "chat-tab-1",
173
260
  "pid": 12345,
174
261
  "startedAt": "2026-06-06T10:30:00.000Z",
262
+ "updatedAt": "2026-06-06T11:00:00.000Z",
175
263
  "sessionId": "sess_abc123",
176
- "model": "claude-sonnet-4-6"
264
+ "model": "claude-sonnet-4-6",
265
+ "host": "MY-PC",
266
+ "machineId": "a1b2c3d4-e5f6-...",
267
+ "lifecycleState": "running",
268
+ "port": 3100,
269
+ "usage": { "inputTokens": 1500, "outputTokens": 3200, ... }
177
270
  }
178
271
  ```
179
272
 
273
+ | lifecycleState | Meaning / 含义 |
274
+ |----------------|----------------|
275
+ | `running` | Normal operation / 正常运行 |
276
+ | `stopped` | Clean shutdown / 正常关闭 |
277
+ | `crashed` | Unexpected exit / 异常退出 |
278
+ | `resuming` | Session recovery in progress / 恢复中 |
279
+
280
+ ---
281
+
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
+
180
295
  ---
181
296
 
182
- ## 开发 / Development
297
+ ## Development / 开发
183
298
 
184
299
  ```bash
185
- # 本地运行 / Run locally
300
+ # One-shot query
186
301
  node ./bin/nx-ce.js query "你好"
187
302
 
188
- # 检查语法 / Check syntax
303
+ # Start server
304
+ node ./bin/nx-ce.js serve --port 3100
305
+
306
+ # Run tests (in another terminal)
307
+ node test/serve-test.mjs
308
+
309
+ # Syntax check
189
310
  node -c src/*.js
190
311
  ```
191
312
 
192
313
  ---
193
314
 
194
- ## License / 许可证
315
+ ## Test / 测试
316
+
317
+ ```bash
318
+ # Terminal 1: start server
319
+ node bin/nx-ce.js serve --port 3100
320
+
321
+ # Terminal 2: run tests
322
+ node test/serve-test.mjs
323
+
324
+ # Expected output:
325
+ # PASS: 14 FAIL: 0
326
+ ```
327
+
328
+ Tests cover: connection, ping/pong, single-session query, multi-session isolation, 3 concurrent sessions, long conversation resume, listSessions, closeSession, getSkills, getStatus.
329
+
330
+ ---
331
+
332
+ ## License
195
333
 
196
334
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx-ce",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
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",
@@ -30,6 +30,7 @@
30
30
  ],
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@anthropic-ai/claude-agent-sdk": "^0.3.159"
33
+ "@anthropic-ai/claude-agent-sdk": "^0.3.159",
34
+ "ws": "^8.21.0"
34
35
  }
35
36
  }
package/src/cli.js CHANGED
@@ -83,7 +83,7 @@ export async function runCli() {
83
83
  }
84
84
 
85
85
  case 'serve': {
86
- // 持久化服务模式
86
+ // WebSocket 持久化服务模式
87
87
  const name = flags.name || 'default';
88
88
 
89
89
  const result = await startServe({
@@ -92,6 +92,7 @@ export async function runCli() {
92
92
  model: flags.model,
93
93
  cwd: flags.cwd || process.cwd(),
94
94
  env: flags.env ? parseEnvString(flags.env) : undefined,
95
+ port: flags.port ? parseInt(flags.port, 10) : undefined,
95
96
  });
96
97
 
97
98
  return result;
@@ -132,8 +133,9 @@ export async function runCli() {
132
133
  --no-persist 不持久化会话
133
134
  --env "KEY=value,KEY2=val" 额外环境变量
134
135
 
135
- nx-ce serve 持久化管理器进程(stdin/stdout)
136
+ nx-ce serve WebSocket 持久化服务器(单一进程 / 多客户端)
136
137
  --name <name> 实例名称(默认: "default")
138
+ --port <port> WebSocket 端口(默认: 3100)
137
139
  --model <id> 模型覆盖
138
140
  --claude-path <path> Claude CLI 路径
139
141
  --env "KEY=value,..." 额外环境变量
package/src/index.js CHANGED
@@ -8,5 +8,13 @@
8
8
 
9
9
  export { runQuery } from './query.js';
10
10
  export { listSkills } from './skills.js';
11
- export { readState, writeState, deleteState, listStates } from './session-store.js';
11
+ export {
12
+ readState,
13
+ writeState,
14
+ deleteState,
15
+ listStates,
16
+ LifecycleState,
17
+ createState,
18
+ } from './session-store.js';
12
19
  export { readMessage, writeMessage } from './protocol.js';
20
+ export { generateId, MonotonicClock, getMachineId, formatBytes } from './util.js';