nx-ce 0.1.1 → 0.1.4

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
@@ -4,12 +4,12 @@
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
6
  **nx-ce** 是一个轻量级 Node.js 适配器,封装了 `@anthropic-ai/claude-agent-sdk`。
7
- 通过长度前缀的 JSON 协议(与 Chrome Native Messaging 格式一致)在 stdin/stdout 上暴露 SDK 接口,
8
- 支持一次性冷启动查询与持久化服务两种运行模式。
7
+ 通过长度前缀的 JSON 协议在 stdin/stdout 上暴露 SDK 接口,
8
+ 支持一次性冷启动查询与 WebSocket 持久化服务器两种运行模式。
9
9
 
10
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.
11
+ It exposes the SDK via a WebSocket server or stdin/stdout protocol,
12
+ supporting both one-shot cold-start queries and persistent server sessions.
13
13
 
14
14
  ---
15
15
 
@@ -55,23 +55,27 @@ nx-ce query "Analyze" --skill all
55
55
  | `--no-persist` | 不持久化会话 / Don't persist session |
56
56
  | `--env "KEY=value,KEY2=val"` | 额外环境变量 / Extra environment variables |
57
57
 
58
- ### `nx-ce serve` — 持久化管理器进程 / Persistent manager process
58
+ ### `nx-ce serve` — WebSocket 持久化服务器 / WebSocket server
59
+
60
+ 单例进程,多客户端共享一个 SDK 会话,请求排队处理。
61
+ Single process with multi-client support and FIFO query queue.
59
62
 
60
63
  ```bash
64
+ nx-ce serve # 默认端口 3100
65
+ nx-ce serve --port 3100 # 指定端口
61
66
  nx-ce serve --name chat-tab-1
62
- nx-ce serve --name default --model claude-sonnet-4-6
63
67
  ```
64
68
 
65
- 通过 stdin/stdout 接收 4B+JSON 协议消息,保持一个持久化的 SDK 会话。
66
- Reads/writes 4B+JSON protocol messages over stdin/stdout, maintaining a persistent SDK session.
67
-
68
69
  | 选项 / Flag | 说明 / Description |
69
70
  |-------------|-------------------|
70
71
  | `--name <name>` | 实例名称(默认 `"default"`)/ Instance name |
72
+ | `--port <port>` | WebSocket 端口(默认 `3100`)/ WebSocket port |
71
73
  | `--model <id>` | 模型 ID 覆盖 / Model override |
72
74
  | `--claude-path <path>` | Claude CLI 可执行文件路径 / Path to Claude CLI binary |
73
75
  | `--env "KEY=value,..."` | 额外环境变量 / Extra environment variables |
74
76
 
77
+ > WebSocket 地址: `ws://127.0.0.1:3100`
78
+
75
79
  ### `nx-ce status` — 查看实例状态 / Show instance state
76
80
 
77
81
  ```bash
@@ -87,60 +91,96 @@ nx-ce help
87
91
 
88
92
  ---
89
93
 
90
- ## 协议 / Protocol
94
+ ## WebSocket 协议 / WebSocket Protocol
95
+
96
+ 服务端地址 `ws://127.0.0.1:PORT`(默认 3100)。所有消息均为 JSON 字符串(不含长度前缀)。
97
+
98
+ Server at `ws://127.0.0.1:PORT` (default 3100). All messages are JSON strings (no length prefix).
91
99
 
92
- 所有 IPC 使用与 Chrome Native Messaging 一致的线缆格式:
100
+ ### 客户端发送 / Client Server
93
101
 
94
- All IPC uses the same wire format as Chrome native messaging:
102
+ | type | 字段 / Fields | 说明 / Description |
103
+ |------|---------------|-------------------|
104
+ | `query` | `prompt: string`, `id?: string` | 发起查询 / Submit a query |
105
+ | `ping` | 无 | 心跳检测 / Heartbeat |
106
+ | `getSkills` | 无 | 拉取技能/工具列表 / Fetch skills & tools |
95
107
 
108
+ ```json
109
+ → { "type": "query", "prompt": "解释这段代码" }
110
+ → { "type": "ping" }
111
+ → { "type": "getSkills" }
96
112
  ```
97
- [4 bytes LE uint32 = 负载长度 / payload length][UTF-8 JSON payload]
113
+
114
+ ### 服务端发送 / Server → Client
115
+
116
+ **连接建立 / On connect:**
117
+
118
+ ```json
119
+ ← { "type": "connected", "sessionId": "sess_xxx", "port": 3100 }
120
+ ← { "type": "init", "sessionId": "sess_xxx", "model": "claude-sonnet-4-6",
121
+ "skills": [...], "tools": [...], "slashCommands": [...], "agents": [...] }
98
122
  ```
99
123
 
100
- ### 查询(一次性)/ Query (one-shot)
124
+ **查询响应 / Query response (streamed chunks):**
101
125
 
126
+ ```json
127
+ ← { "type": "text", "content": "这是一段回复..." }
128
+ ← { "type": "thinking", "content": "模型思考过程..." }
129
+ ← { "type": "tool_use", "name": "readFile", "input": {...}, "id": "toolu_xxx" }
130
+ ← { "type": "done", "sessionId": "sess_xxx" }
102
131
  ```
103
- → { "prompt": "...", "model": "...", "systemPrompt": "..." }
104
- ← { "text": "...", "sessionId": "sess_xxx" }
105
132
 
106
- # --include-metadata 时返回 metadata
107
- # With --include-metadata, response includes metadata:
108
- ← { "text": "...", "sessionId": "sess_xxx", "metadata": { "skills": [...], "tools": [...], "slashCommands": [...] } }
133
+ **其他 / Other:**
134
+
135
+ ```json
136
+ ← { "type": "pong", "sessionId": "sess_xxx" }
137
+ ← { "type": "skills", "skills": [...], "tools": [...], "slashCommands": [...], "agents": [...] }
138
+ ← { "type": "error", "content": "error message" }
109
139
  ```
110
140
 
111
- ### 服务(持久化)/ Serve (persistent)
141
+ ### 完整示例 / Full exchange
112
142
 
113
143
  ```
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":"..." }
144
+ → { "type": "query", "prompt": "Hello" }
145
+ ← { "type": "text", "content": "Hello! How can I help you today?" }
146
+ ← { "type": "done", "sessionId": "sess_abc123" }
119
147
 
120
- → { "type":"ping" }
121
- ← { "type":"pong", "sessionId":"..." }
148
+ → { "type": "ping" }
149
+ ← { "type": "pong", "sessionId": "sess_abc123" }
150
+ ```
122
151
 
123
- { "type":"getSkills" }
124
- ← { "type":"skills", "skills":["browse",...], "tools":["Read",...], "slashCommands":[...], "agents":[...] }
152
+ ### 单例机制 / Singleton guarantee
125
153
 
126
- (首次 init 自动推送)
127
- ← { "type":"init", "skills":[...], "tools":[...], ... }
154
+ 重复启动 `nx-ce serve` 会在同一端口上失败:
155
+
156
+ ```
157
+ 端口 3100 已被占用 — nx-ce 单例进程已在运行中
158
+ Port 3100 already in use — another nx-ce instance is running
128
159
  ```
129
160
 
130
- 协议消息类型 / Message types:
161
+ ---
162
+
163
+ ## 协议 / Protocol (stdin/stdout)
164
+
165
+ `nx-ce query` 子命令仍使用长度前缀 JSON(Chrome Native Messaging 格式):
166
+
167
+ ```
168
+ [4 bytes LE uint32 = 负载长度 / payload length][UTF-8 JSON payload]
169
+ ```
131
170
 
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 |
171
+ ### 查询(一次性)/ Query (one-shot)
172
+
173
+ ```
174
+ { "prompt": "...", "model": "...", "systemPrompt": "..." }
175
+ { "text": "...", "sessionId": "sess_xxx" }
176
+ ```
177
+
178
+ ### 带元数据输出 / With metadata
179
+
180
+ ```
181
+ { "text": "...", "sessionId": "sess_xxx",
182
+ "metadata": { "skills": [...], "tools": [...], "slashCommands": [...] } }
183
+ ```
144
184
 
145
185
  ---
146
186
 
@@ -148,10 +188,8 @@ All IPC uses the same wire format as Chrome native messaging:
148
188
 
149
189
  ```
150
190
  Chrome Extension / 浏览器扩展
151
- Native Messaging (4B+JSON)
152
- Native Host (Go)
153
- ↕ 4B+JSON (via executor.startProcess)
154
- nx-ce serve (Node.js)
191
+ WebSocket (ws://127.0.0.1:3100)
192
+ nx-ce serve (Node.js) ← 单例进程 / singleton process
155
193
  ↕ @anthropic-ai/claude-agent-sdk
156
194
  Claude Code CLI (子进程 / subprocess)
157
195
  ```
@@ -165,8 +203,6 @@ Claude Code CLI (子进程 / subprocess)
165
203
 
166
204
  Persisted to `~/.nx-ce/instances/{name}.json`. Each named instance stores its PID, session ID, and start time for crash recovery and session resumption.
167
205
 
168
- 示例状态文件 / Example state file:
169
-
170
206
  ```json
171
207
  {
172
208
  "name": "chat-tab-1",
@@ -182,9 +218,12 @@ Persisted to `~/.nx-ce/instances/{name}.json`. Each named instance stores its PI
182
218
  ## 开发 / Development
183
219
 
184
220
  ```bash
185
- # 本地运行 / Run locally
221
+ # 本地运行一次查询 / Run a one-shot query
186
222
  node ./bin/nx-ce.js query "你好"
187
223
 
224
+ # 启动 WebSocket 服务 / Start WebSocket server
225
+ node ./bin/nx-ce.js serve --port 3100
226
+
188
227
  # 检查语法 / Check syntax
189
228
  node -c src/*.js
190
229
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx-ce",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
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
@@ -8,6 +8,7 @@
8
8
  import { existsSync } from 'node:fs';
9
9
  import { runQuery } from './query.js';
10
10
  import { startServe } from './serve.js';
11
+ import { listSkills } from './skills.js';
11
12
  import { readState, listStates } from './session-store.js';
12
13
 
13
14
  /**
@@ -82,7 +83,7 @@ export async function runCli() {
82
83
  }
83
84
 
84
85
  case 'serve': {
85
- // 持久化服务模式
86
+ // WebSocket 持久化服务模式
86
87
  const name = flags.name || 'default';
87
88
 
88
89
  const result = await startServe({
@@ -91,6 +92,7 @@ export async function runCli() {
91
92
  model: flags.model,
92
93
  cwd: flags.cwd || process.cwd(),
93
94
  env: flags.env ? parseEnvString(flags.env) : undefined,
95
+ port: flags.port ? parseInt(flags.port, 10) : undefined,
94
96
  });
95
97
 
96
98
  return result;
@@ -105,6 +107,15 @@ export async function runCli() {
105
107
  return listStates(); // 列出所有实例
106
108
  }
107
109
 
110
+ case 'skills': {
111
+ const result = await listSkills({
112
+ cwd: flags.cwd || process.cwd(),
113
+ claudePath: resolveClaudePath(flags['claude-path']),
114
+ env: flags.env ? parseEnvString(flags.env) : undefined,
115
+ });
116
+ return result;
117
+ }
118
+
108
119
  case 'help':
109
120
  default:
110
121
  // 显示帮助信息
@@ -122,14 +133,17 @@ export async function runCli() {
122
133
  --no-persist 不持久化会话
123
134
  --env "KEY=value,KEY2=val" 额外环境变量
124
135
 
125
- nx-ce serve 持久化管理器进程(stdin/stdout)
136
+ nx-ce serve WebSocket 持久化服务器(单一进程 / 多客户端)
126
137
  --name <name> 实例名称(默认: "default")
138
+ --port <port> WebSocket 端口(默认: 3100)
127
139
  --model <id> 模型覆盖
128
140
  --claude-path <path> Claude CLI 路径
129
141
  --env "KEY=value,..." 额外环境变量
130
142
 
131
143
  nx-ce status [--name <name>] 查看实例状态
132
144
 
145
+ nx-ce skills [--cwd <path>] 列出 SDK 可用 skill/tool/agent
146
+
133
147
  nx-ce help 显示此帮助
134
148
  `);
135
149
  return null;
package/src/index.js CHANGED
@@ -7,5 +7,14 @@
7
7
  */
8
8
 
9
9
  export { runQuery } from './query.js';
10
- export { readState, writeState, deleteState, listStates } from './session-store.js';
10
+ export { listSkills } from './skills.js';
11
+ export {
12
+ readState,
13
+ writeState,
14
+ deleteState,
15
+ listStates,
16
+ LifecycleState,
17
+ createState,
18
+ } from './session-store.js';
11
19
  export { readMessage, writeMessage } from './protocol.js';
20
+ export { generateId, MonotonicClock, getMachineId, formatBytes } from './util.js';