nx-ce 0.1.0 → 0.1.1
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 +16 -0
- package/package.json +1 -1
- package/src/cli.js +9 -1
- package/src/query.js +12 -4
- package/src/serve.js +26 -1
package/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# nx-ce — Claude Engine
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/nx-ce)
|
|
4
|
+
[](https://github.com/joke-lx/nx-ce/actions/workflows/npm-publish.yml)
|
|
5
|
+
|
|
3
6
|
**nx-ce** 是一个轻量级 Node.js 适配器,封装了 `@anthropic-ai/claude-agent-sdk`。
|
|
4
7
|
通过长度前缀的 JSON 协议(与 Chrome Native Messaging 格式一致)在 stdin/stdout 上暴露 SDK 接口,
|
|
5
8
|
支持一次性冷启动查询与持久化服务两种运行模式。
|
|
@@ -48,6 +51,7 @@ nx-ce query "Analyze" --skill all
|
|
|
48
51
|
| `--system-prompt <text>` | 系统提示词覆盖 / System prompt override |
|
|
49
52
|
| `--resume <sessionId>` | 续接之前的会话(长对话)/ Resume a prior session |
|
|
50
53
|
| `--skill <name>[,<name>...]` | 加载指定 Skill(逗号分隔,传 `all` 加载全部)/ Load specific skills |
|
|
54
|
+
| `--include-metadata` | 输出中附带 skills/tools/slash_commands 信息 / Include skill/tool metadata in output |
|
|
51
55
|
| `--no-persist` | 不持久化会话 / Don't persist session |
|
|
52
56
|
| `--env "KEY=value,KEY2=val"` | 额外环境变量 / Extra environment variables |
|
|
53
57
|
|
|
@@ -98,6 +102,10 @@ All IPC uses the same wire format as Chrome native messaging:
|
|
|
98
102
|
```
|
|
99
103
|
→ { "prompt": "...", "model": "...", "systemPrompt": "..." }
|
|
100
104
|
← { "text": "...", "sessionId": "sess_xxx" }
|
|
105
|
+
|
|
106
|
+
# 加 --include-metadata 时返回 metadata
|
|
107
|
+
# With --include-metadata, response includes metadata:
|
|
108
|
+
← { "text": "...", "sessionId": "sess_xxx", "metadata": { "skills": [...], "tools": [...], "slashCommands": [...] } }
|
|
101
109
|
```
|
|
102
110
|
|
|
103
111
|
### 服务(持久化)/ Serve (persistent)
|
|
@@ -111,6 +119,12 @@ All IPC uses the same wire format as Chrome native messaging:
|
|
|
111
119
|
|
|
112
120
|
→ { "type":"ping" }
|
|
113
121
|
← { "type":"pong", "sessionId":"..." }
|
|
122
|
+
|
|
123
|
+
→ { "type":"getSkills" }
|
|
124
|
+
← { "type":"skills", "skills":["browse",...], "tools":["Read",...], "slashCommands":[...], "agents":[...] }
|
|
125
|
+
|
|
126
|
+
(首次 init 自动推送)
|
|
127
|
+
← { "type":"init", "skills":[...], "tools":[...], ... }
|
|
114
128
|
```
|
|
115
129
|
|
|
116
130
|
协议消息类型 / Message types:
|
|
@@ -125,6 +139,8 @@ All IPC uses the same wire format as Chrome native messaging:
|
|
|
125
139
|
| ← | `error` | 错误消息 / Error message |
|
|
126
140
|
| → | `ping` | 心跳检测 / Heartbeat |
|
|
127
141
|
| ← | `pong` | 心跳回复 / Heartbeat response |
|
|
142
|
+
| → | `getSkills` | Go 端按需拉取技能/工具列表 / Fetch skills/tools list |
|
|
143
|
+
| ← | `init` / `skills` | 技能列表回复 / Skills metadata response |
|
|
128
144
|
|
|
129
145
|
---
|
|
130
146
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nx-ce",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
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",
|
package/src/cli.js
CHANGED
|
@@ -32,6 +32,9 @@ export function parseArgs(argv = process.argv.slice(2)) {
|
|
|
32
32
|
if (eqIdx !== -1) {
|
|
33
33
|
// --key=value 格式
|
|
34
34
|
flags[arg.slice(2, eqIdx)] = arg.slice(eqIdx + 1);
|
|
35
|
+
} else if (rest[i + 1] === undefined || rest[i + 1].startsWith('--')) {
|
|
36
|
+
// --key 后面没有值,或下一个参数也是 flag → boolean flag
|
|
37
|
+
flags[arg.slice(2)] = true;
|
|
35
38
|
} else {
|
|
36
39
|
// --key value 格式(下一个参数作为值)
|
|
37
40
|
flags[arg.slice(2)] = rest[++i] ?? true;
|
|
@@ -71,7 +74,11 @@ export async function runCli() {
|
|
|
71
74
|
env: flags.env ? parseEnvString(flags.env) : undefined,
|
|
72
75
|
});
|
|
73
76
|
|
|
74
|
-
|
|
77
|
+
// 默认只返回 text + sessionId,加 --include-metadata 才返回 metadata
|
|
78
|
+
if (flags['include-metadata']) {
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
return { text: result.text, sessionId: result.sessionId };
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
case 'serve': {
|
|
@@ -111,6 +118,7 @@ export async function runCli() {
|
|
|
111
118
|
--system-prompt <text> 系统提示词覆盖
|
|
112
119
|
--resume <sessionId> 续接之前的会话(长对话)
|
|
113
120
|
--skill <name>[,<name>...] 加载指定 Skill(逗号分隔,传 "all" 加载全部)
|
|
121
|
+
--include-metadata 输出中附带 skills/tools/slash_commands 列表
|
|
114
122
|
--no-persist 不持久化会话
|
|
115
123
|
--env "KEY=value,KEY2=val" 额外环境变量
|
|
116
124
|
|
package/src/query.js
CHANGED
|
@@ -22,7 +22,7 @@ import { query as agentQuery } from '@anthropic-ai/claude-agent-sdk';
|
|
|
22
22
|
* @param {string} [options.resumeSessionId] - 恢复之前的会话
|
|
23
23
|
* @param {string[]|'all'} [options.skills] - 加载哪些 Skill(数组或 'all')
|
|
24
24
|
* @param {AbortController} [options.signal] - 中止信号
|
|
25
|
-
* @returns {Promise<{ text: string, sessionId: string | null }>}
|
|
25
|
+
* @returns {Promise<{ text: string, sessionId: string | null, metadata: object | null }>}
|
|
26
26
|
*/
|
|
27
27
|
export async function runQuery(options) {
|
|
28
28
|
const {
|
|
@@ -86,6 +86,7 @@ export async function runQuery(options) {
|
|
|
86
86
|
|
|
87
87
|
let text = '';
|
|
88
88
|
let sessionId = null;
|
|
89
|
+
let metadata = null;
|
|
89
90
|
|
|
90
91
|
// 遍历 SDK 返回的流式消息
|
|
91
92
|
for await (const message of response) {
|
|
@@ -95,9 +96,16 @@ export async function runQuery(options) {
|
|
|
95
96
|
break;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
//
|
|
99
|
-
if (message.type === 'system' && message.subtype === 'init'
|
|
99
|
+
// 从 init 消息中捕获 sessionId + 技能/工具/命令 元数据
|
|
100
|
+
if (message.type === 'system' && message.subtype === 'init') {
|
|
100
101
|
sessionId = message.session_id;
|
|
102
|
+
metadata = {
|
|
103
|
+
model: message.model,
|
|
104
|
+
skills: message.skills || [],
|
|
105
|
+
tools: message.tools || [],
|
|
106
|
+
slashCommands: message.slash_commands || [],
|
|
107
|
+
agents: message.agents || [],
|
|
108
|
+
};
|
|
101
109
|
}
|
|
102
110
|
|
|
103
111
|
// 提取助手的文本回复内容
|
|
@@ -116,5 +124,5 @@ export async function runQuery(options) {
|
|
|
116
124
|
}
|
|
117
125
|
}
|
|
118
126
|
|
|
119
|
-
return { text, sessionId };
|
|
127
|
+
return { text, sessionId, metadata };
|
|
120
128
|
}
|
package/src/serve.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* ← { "id":"...", "type":"error", "content":"..." }
|
|
12
12
|
* → { "type":"ping" }
|
|
13
13
|
* ← { "type":"pong", "sessionId":"..." }
|
|
14
|
+
* → { "type":"getSkills" }
|
|
15
|
+
* ← { "type":"skills", "skills":[...], "tools":[...], ... }
|
|
14
16
|
*/
|
|
15
17
|
|
|
16
18
|
import { query as agentQuery } from '@anthropic-ai/claude-agent-sdk';
|
|
@@ -102,6 +104,8 @@ export async function startServe(options) {
|
|
|
102
104
|
});
|
|
103
105
|
|
|
104
106
|
let currentSessionId = existingState?.sessionId || null;
|
|
107
|
+
// 缓存 session 元数据,供 getSkills 按需查询
|
|
108
|
+
let sessionMetadata = null;
|
|
105
109
|
|
|
106
110
|
// 持久化初始状态
|
|
107
111
|
writeState(name, {
|
|
@@ -116,7 +120,7 @@ export async function startServe(options) {
|
|
|
116
120
|
const consumerPromise = (async () => {
|
|
117
121
|
try {
|
|
118
122
|
for await (const message of response) {
|
|
119
|
-
// 捕获初始化消息中的会话 ID
|
|
123
|
+
// 捕获初始化消息中的会话 ID + 元数据,更新持久化状态
|
|
120
124
|
if (message.type === 'system' && message.subtype === 'init' && message.session_id) {
|
|
121
125
|
currentSessionId = message.session_id;
|
|
122
126
|
writeState(name, {
|
|
@@ -126,6 +130,17 @@ export async function startServe(options) {
|
|
|
126
130
|
sessionId: currentSessionId,
|
|
127
131
|
model: sdkOptions.model,
|
|
128
132
|
});
|
|
133
|
+
// 将技能/工具/命令列表转发给客户端 + 缓存供 getSkills 查询
|
|
134
|
+
sessionMetadata = {
|
|
135
|
+
type: 'init',
|
|
136
|
+
sessionId: currentSessionId,
|
|
137
|
+
model: message.model,
|
|
138
|
+
skills: message.skills || [],
|
|
139
|
+
tools: message.tools || [],
|
|
140
|
+
slashCommands: message.slash_commands || [],
|
|
141
|
+
agents: message.agents || [],
|
|
142
|
+
};
|
|
143
|
+
writeMessage(process.stdout, sessionMetadata);
|
|
129
144
|
}
|
|
130
145
|
|
|
131
146
|
// 助手消息 → 区分为 text / tool_use / thinking 块写入 stdout
|
|
@@ -199,6 +214,16 @@ export async function startServe(options) {
|
|
|
199
214
|
} else if (req.type === 'ping') {
|
|
200
215
|
// ping/pong 心跳
|
|
201
216
|
writeMessage(process.stdout, { type: 'pong', sessionId: currentSessionId });
|
|
217
|
+
} else if (req.type === 'getSkills') {
|
|
218
|
+
// Go 端主动拉取 skill/工具/命令 列表(可重复查询)
|
|
219
|
+
writeMessage(process.stdout, sessionMetadata || {
|
|
220
|
+
type: 'skills',
|
|
221
|
+
skills: [],
|
|
222
|
+
tools: [],
|
|
223
|
+
slashCommands: [],
|
|
224
|
+
agents: [],
|
|
225
|
+
note: 'session not yet initialized',
|
|
226
|
+
});
|
|
202
227
|
}
|
|
203
228
|
}
|
|
204
229
|
} finally {
|