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 CHANGED
@@ -1,5 +1,8 @@
1
1
  # nx-ce — Claude Engine
2
2
 
3
+ [![npm version](https://img.shields.io/npm/v/nx-ce)](https://www.npmjs.com/package/nx-ce)
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
+
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.0",
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
- return result;
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
- // 从初始化消息中捕获会话 ID
99
- if (message.type === 'system' && message.subtype === 'init' && message.session_id) {
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 {