@sleep2agi/agent-network 0.0.23 → 0.0.25

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.
Files changed (3) hide show
  1. package/README.md +129 -154
  2. package/dist/bin/cli.js +26 -26
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,168 +2,175 @@
2
2
 
3
3
  AI Agent 通信网络 — 让 AI Agent 互相发消息、派任务、协作。
4
4
 
5
+ 支持两种 Agent 运行时:
6
+ - **claude-code** — Claude Code CLI(交互式开发)
7
+ - **agent-sdk** — Claude Agent SDK + 任意模型(MiniMax/Claude,自动化)
8
+
5
9
  ## 安装
6
10
 
7
11
  ```bash
8
- # 全局安装(推荐)
12
+ # 必装:anet CLI + CommHub SDK
9
13
  npm install -g @sleep2agi/agent-network
10
14
 
11
- # 或不安装,直接用 npx
12
- npx @sleep2agi/agent-network --help
15
+ # 按需装:
16
+ npm install -g @anthropic-ai/claude-code # claude-code runtime
17
+ npm install -g @sleep2agi/agent-node # agent-sdk runtime
13
18
  ```
14
19
 
15
- ## 30 秒上手
16
-
17
- ```bash
18
- # 1. 配 hub(全局,一次性)
19
- npx @sleep2agi/agent-network init --hub http://YOUR_COMMHUB_IP:9200
20
-
21
- # 2. 配项目(下载 channel 插件 + 配 MCP + 生成 CLAUDE.md)
22
- cd ~/your-project
23
- npx @sleep2agi/agent-network init project
24
-
25
- # 3. 创建 profile(保存启动参数)
26
- npx anet init profile commander --alias 指挥室 --channel server:commhub
27
-
28
- # 4. 启动(新建 session)
29
- npx anet start commander
30
-
31
- # 5. 恢复上次 session
32
- npx anet resume commander
33
-
34
- # 6. 查看状态
35
- npx anet ls
36
- ```
20
+ ## 快速开始
37
21
 
38
- ## 为什么需要 Profile?
39
-
40
- Claude Code 启动参数可以非常长:
22
+ ### Claude Code Agent
41
23
 
42
24
  ```bash
43
- COMMHUB_ALIAS="指挥室" TELEGRAM_STATE_DIR=~/.claude/channels/telegram-vincent \
44
- claude --dangerously-skip-permissions \
45
- --channels plugin:telegram@claude-plugins-official \
46
- --dangerously-load-development-channels server:commhub \
47
- --teammate-mode in-process --resume 98039093-...
25
+ anet init --hub http://YOUR_IP:9200
26
+ anet init project
27
+ anet init profile 指挥室 --alias 指挥室 --channel server:commhub
28
+ anet start 指挥室
48
29
  ```
49
30
 
50
- Profile 把这些参数存到 JSON,以后只需:
31
+ ### MiniMax Agent(低成本)
51
32
 
52
33
  ```bash
53
- anet start 指挥室 # 新建 session
54
- anet resume 指挥室 # 恢复上次 session
34
+ anet init --hub http://YOUR_IP:9200
35
+ anet init profile 小明1号 \
36
+ --runtime agent-sdk \
37
+ --alias 小明1号 \
38
+ --model MiniMax-M2.7 \
39
+ --tools "Read,Bash,Grep" \
40
+ --env "ANTHROPIC_BASE_URL=https://api.minimax.chat/anthropic" \
41
+ --env "ANTHROPIC_AUTH_TOKEN=your-minimax-key"
42
+ anet start 小明1号
55
43
  ```
56
44
 
57
- 同一目录可以有多个 profile(指挥室、通信龙、SDK马)。
58
-
59
- ## CLI 命令
60
-
61
- ### anet init
45
+ ## 工作原理
62
46
 
63
- 三级初始化:
47
+ `anet start` 读 profile,根据 `runtime` 自动选择启动方式:
64
48
 
65
- ```bash
66
- anet init # → ~/.anet/config.json(hub URL)
67
- anet init project # → 下载 channel 插件 + 配 MCP + .env
68
- anet init profile <id> [options] # → .anet/profiles/<id>.json
69
49
  ```
70
-
71
- 配置文件位置:
72
-
50
+ anet start 指挥室 → runtime: claude-code → spawn claude CLI
51
+ anet start 小明1号 → runtime: agent-sdk → spawn agent-node (MiniMax)
73
52
  ```
74
- ~/.anet/config.json 全局(hub URL,一次性)
75
- {workpath}/.anet/node-server.ts Channel 插件
76
- {workpath}/.anet/package.json 依赖声明
77
- {workpath}/.anet/.env COMMHUB_URL
78
- {workpath}/.anet/profiles/cmd.json 启动 profile
79
- {workpath}/.mcp.json MCP 配置(commhub → .anet/node-server.ts)
80
- ```
81
-
82
- 全部在项目目录内,不碰全局 `~/.claude/`。
83
53
 
84
- #### anet init
54
+ 同一目录可以有多个 profile,不同 runtime 共存。
85
55
 
86
- hub URL(全局,一次性):
56
+ ## CLI 命令
87
57
 
88
- ```bash
89
- anet init
90
- # CommHub URL: http://YOUR_IP:9200
91
- # ✅ CommHub v0.4.1 — 26 sessions, 18 SSE
92
58
  ```
93
-
94
- 或直接传参:`anet init --hub http://YOUR_IP:9200`
95
-
96
- #### anet init project
97
-
98
- 下载 Channel 插件到 `.anet/` + 安装依赖 + `.mcp.json` + 写 `.env`:
99
-
100
- ```bash
101
- cd ~/my-project
102
- anet init project
103
- # ✅ .anet/node-server.ts
104
- # ✅ Dependencies installed
105
- # CommHub URL: http://YOUR_IP:9200
106
- # .mcp.json: commhub → .anet/node-server.ts
59
+ anet init 配 hub URL(全局,一次性)
60
+ anet init project 配项目(claude-code 用:channel 插件 + .mcp.json + CLAUDE.md)
61
+ anet init profile <id> 创建启动配置
62
+ anet start <id> 新建 session
63
+ anet resume <id> 恢复上次 session
64
+ anet ls 查看 profiles + sessions + 网络状态
107
65
  ```
108
66
 
109
- #### anet init profile
67
+ ### anet init profile
110
68
 
111
69
  ```bash
112
- anet init profile <id> --alias <别名> [options]
70
+ anet init profile <id> [options]
113
71
  ```
114
72
 
73
+ **共用参数:**
74
+
115
75
  | 参数 | 说明 |
116
76
  |------|------|
117
- | `<id>` | Profile ID(英文,作为文件名) |
118
77
  | `--alias` | CommHub session 别名 |
119
- | `--name` | 显示名 |
120
- | `--channel` | 添加 channel(可重复) |
78
+ | `--runtime` | `claude-code`(默认)或 `agent-sdk` |
121
79
  | `--env` | 环境变量 K=V(可重复) |
122
- | `--resume` | Session resume ID |
123
- | `--teammate-mode` | 如 in-process |
124
80
 
125
- 示例:
126
- ```bash
127
- # 带 Telegram 双 channel
128
- anet init profile commander --alias 指挥室 \
129
- --channel server:commhub \
130
- --channel plugin:telegram@claude-plugins-official \
131
- --env TELEGRAM_STATE_DIR=~/.claude/channels/telegram-vincent \
132
- --teammate-mode in-process
81
+ **claude-code 参数:**
133
82
 
134
- # 简单 agent
135
- anet init profile worker --alias 开发马 --channel server:commhub
136
- ```
83
+ | 参数 | 说明 |
84
+ |------|------|
85
+ | `--channel` | Channel(可重复,默认 server:commhub) |
86
+ | `--teammate-mode` | 默认 in-process |
87
+ | `--resume-alias` | 恢复搜索名 |
88
+
89
+ **agent-sdk 参数:**
90
+
91
+ | 参数 | 说明 |
92
+ |------|------|
93
+ | `--model` | 模型名(如 MiniMax-M2.7) |
94
+ | `--tools` | 工具列表,逗号分隔 |
95
+ | `--max-turns` | 每任务最大轮次 |
137
96
 
138
97
  ### anet start / resume
139
98
 
140
99
  ```bash
141
100
  anet start 指挥室 # 新建 session
142
- anet resume 指挥室 # 恢复上次 session(按名字搜索)
101
+ anet resume 指挥室 # 恢复上次 session
143
102
  anet start # 列出所有 profile
144
- anet 指挥室 # 快捷方式(等于 anet start 指挥室)
103
+ anet 指挥室 # 快捷方式
145
104
  ```
146
105
 
147
- ### anet ls
106
+ 交互式创建:profile 不存在时自动引导创建(选 runtime、填 alias、model 等)。
107
+
108
+ ### anet init project
109
+
110
+ 仅 claude-code runtime 需要:
111
+
112
+ ```bash
113
+ anet init project
114
+ # ✅ .anet/node-server.ts(Channel 插件)
115
+ # ✅ Dependencies installed
116
+ # ✅ .mcp.json
117
+ # ✅ CLAUDE.md
118
+ ```
148
119
 
149
- 显示当前目录的 sessions + 网络状态:
120
+ agent-sdk runtime 不需要 init project。
121
+
122
+ ### anet ls
150
123
 
151
124
  ```
152
125
  Profiles:
153
- commander (指挥室) → 指挥室 [server:commhub, plugin:telegram]
126
+ 指挥室 → 指挥室 [server:commhub, plugin:telegram]
127
+ 小明1号 → 小明1号 []
154
128
 
155
- Sessions (/home/vansin/agent-orchestra/channel):
129
+ Sessions (/home/vansin/project):
156
130
  SESSION PID NETWORK
157
131
  ──────────────────── ─────── ─────────────────────
158
132
  fef0eb55-b39c-4abc 64269 通信龙 offline ●
159
133
  ```
160
134
 
161
- ### anet run
135
+ ## Profile 格式
162
136
 
163
- 独立 SSE Agent(不需要 Claude Code):
137
+ 路径:`.anet/profiles/<id>.json`
164
138
 
165
- ```bash
166
- anet run --alias SDK马 --hub http://YOUR_IP:9200
139
+ anet 和 agent-node 共用同一套配置。
140
+
141
+ ### claude-code 示例
142
+
143
+ ```json
144
+ {
145
+ "runtime": "claude-code",
146
+ "alias": "指挥室",
147
+ "hub": "http://YOUR_IP:9200",
148
+ "channels": ["server:commhub", "plugin:telegram@claude-plugins-official"],
149
+ "env": { "TELEGRAM_STATE_DIR": "~/.claude/channels/telegram-vincent" },
150
+ "flags": { "dangerouslySkipPermissions": true, "teammateMode": "in-process" }
151
+ }
152
+ ```
153
+
154
+ ### agent-sdk 示例(MiniMax)
155
+
156
+ ```json
157
+ {
158
+ "runtime": "agent-sdk",
159
+ "alias": "小明1号",
160
+ "hub": "http://YOUR_IP:9200",
161
+ "model": "MiniMax-M2.7",
162
+ "tools": ["Read", "Bash", "Grep"],
163
+ "env": {
164
+ "ANTHROPIC_BASE_URL": "https://api.minimax.chat/anthropic",
165
+ "ANTHROPIC_AUTH_TOKEN": "your-key"
166
+ }
167
+ }
168
+ ```
169
+
170
+ ### 配置优先级
171
+
172
+ ```
173
+ CLI 参数 > profile env > 系统环境变量 > ~/.anet/config.json > 默认值
167
174
  ```
168
175
 
169
176
  ## SDK 代码引用
@@ -171,67 +178,35 @@ anet run --alias SDK马 --hub http://YOUR_IP:9200
171
178
  ```typescript
172
179
  import { CommHub } from '@sleep2agi/agent-network';
173
180
 
174
- const hub = new CommHub({
175
- url: 'http://YOUR_COMMHUB_IP:9200',
176
- alias: '我的Agent',
177
- });
178
-
181
+ const hub = new CommHub({ url: 'http://YOUR_IP:9200', alias: '我的Agent' });
179
182
  hub.on('task', async (msg) => {
180
- await hub.send(msg.from_session, '任务完成!');
183
+ await hub.send(msg.from_session, '完成!');
181
184
  });
182
185
  ```
183
186
 
184
- ```javascript
185
- // CommonJS
186
- const { CommHub } = require('@sleep2agi/agent-network');
187
- ```
188
-
189
- ### SDK API
190
-
191
187
  | 方法 | 说明 |
192
188
  |------|------|
193
- | `hub.send(alias, content, priority?)` | 发任务 |
189
+ | `hub.send(alias, content)` | 发任务 |
194
190
  | `hub.message(alias, content)` | 发消息 |
195
- | `hub.reply(taskId, text, status?)` | 回复任务 |
196
191
  | `hub.status(state, extra?)` | 更新状态 |
197
- | `hub.broadcast(content, filter?)` | 广播 |
198
192
  | `hub.disconnect()` | 断开 |
199
193
 
200
- | 事件 | 说明 |
201
- |------|------|
202
- | `task` | 收到任务(已自动 ACK) |
203
- | `connected` | SSE 连接成功 |
204
- | `disconnected` | SSE 断开(自动重连) |
205
-
206
- ## 运行时要求
194
+ ## 依赖
207
195
 
208
- | 组件 | 运行时 |
209
- |------|--------|
210
- | anet CLI / SDK | Node.js 18+ 或 Bun |
211
- | CommHub Server | Bun 1.2+(单独部署) |
196
+ | | 什么时候装 |
197
+ |---|---------|
198
+ | @sleep2agi/agent-network | 必装(anet CLI) |
199
+ | @anthropic-ai/claude-code | runtime: claude-code |
200
+ | @sleep2agi/agent-node | runtime: agent-sdk |
201
+ | Bun 1.2+ | 部署 CommHub Server |
212
202
 
213
- ## 版本历史
203
+ ## 相关包
214
204
 
215
- | 版本 | 变更 |
216
- |------|------|
217
- | 0.0.18 | node-server.ts 多路径查找,兼容 npx/global/local |
218
- | 0.0.17 | 修复 npx 模式下路径解析 |
219
- | 0.0.16 | server.ts → node-server.ts,从 npm 包内 copy |
220
- | 0.0.15 | 自动去掉 hub URL 结尾斜杠 |
221
- | 0.0.14 | init project 自动生成 CLAUDE.md |
222
- | 0.0.13 | init 交互输入后不再卡住 |
223
- | 0.0.12 | README 同步 |
224
- | 0.0.11 | node config 加 anet_version 字段 |
225
- | 0.0.10 | resumeAlias 字段,resume 按名字搜索 |
226
- | 0.0.9 | start/resume 分离 |
227
- | 0.0.8 | init project 所有文件放 .anet/(不碰全局 ~/.claude/) |
228
- | 0.0.7 | init project 改写 .mcp.json(不写 ~/.claude.json) |
229
- | 0.0.6 | 三级 init(全局/项目/profile),`anet ls` 简化为当前目录 |
230
- | 0.0.5 | `anet ls` 显示本地 sessions + CommHub 网络状态 |
231
- | 0.0.4 | CLI 瘦身 580KB→13KB,Node.js 兼容,profile 系统 |
232
- | 0.0.3 | `anet setup` 一键配置 Channel 插件 |
233
- | 0.0.2 | CLI shebang 改为 node |
234
- | 0.0.1 | 首次发布 |
205
+ | | 说明 |
206
+ |---|------|
207
+ | [@sleep2agi/agent-network](https://www.npmjs.com/package/@sleep2agi/agent-network) | anet CLI + CommHub SDK |
208
+ | [@sleep2agi/agent-node](https://www.npmjs.com/package/@sleep2agi/agent-node) | Agent 运行时 |
209
+ | [@sleep2agi/commhub-server](https://www.npmjs.com/package/@sleep2agi/commhub-server) | CommHub Server |
235
210
 
236
211
  ## License
237
212
 
package/dist/bin/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import{createRequire as s}from"node:module";var t=Object.defineProperty;var r=(z)=>z;function o(z,Q){this[z]=r.bind(null,Q)}var a=(z,Q)=>{for(var B in Q)t(z,B,{get:Q[B],enumerable:!0,configurable:!0,set:o.bind(Q,B)})};var i=(z,Q)=>()=>(z&&(Q=z(z=0)),Q);var e=s(import.meta.url);var v={};a(v,{default:()=>Bz,CommHub:()=>x});import{EventEmitter as zz}from"events";import{hostname as P}from"os";var x,Bz;var b=i(()=>{x=class x extends zz{url;alias;token;agent;resumeId;heartbeatInterval;reconnectDelay;heartbeatTimer;sseAbort;running=!1;constructor(z){super();if(this.url=z.url.replace(/\/$/,""),this.alias=z.alias,this.token=z.token,this.agent=z.agent||"sdk",this.resumeId=`sdk-${z.alias}-${Date.now().toString(36)}`,this.heartbeatInterval=z.heartbeatInterval??180000,this.reconnectDelay=z.reconnectDelay??3000,z.autoConnect!==!1)this.connect()}log(z){console.log(`[${new Date().toTimeString().slice(0,8)}] [commhub:${this.alias}] ${z}`)}async call(z,Q){let B={"Content-Type":"application/json"};if(this.token)B.Authorization=`Bearer ${this.token}`;let Z=await(await fetch(`${this.url}/mcp`,{method:"POST",headers:B,body:JSON.stringify({jsonrpc:"2.0",id:Date.now(),method:"tools/call",params:{name:z,arguments:Q}})})).json(),Y=Z?.result?.content?.[0]?.text;return Y?JSON.parse(Y):Z}async connect(){if(this.running)return;this.running=!0,await this.status("idle"),this.log("registered"),this.heartbeatTimer=setInterval(()=>{this.status("idle").catch((z)=>this.log(`heartbeat failed: ${z.message}`))},this.heartbeatInterval),this.connectSSE()}async disconnect(){if(this.running=!1,this.sseAbort?.abort(),this.heartbeatTimer)clearInterval(this.heartbeatTimer);await this.status("offline").catch(()=>{}),this.log("disconnected")}async send(z,Q,B="normal"){return this.call("send_task",{alias:z,task:Q,priority:B,from_session:this.alias})}async message(z,Q){return this.call("send_message",{alias:z,message:Q,from_session:this.alias})}async reply(z,Q,B="completed"){return this.call("reply",{task_id:z,text:Q,status:B})}async status(z,Q){return this.call("report_status",{resume_id:this.resumeId,alias:this.alias,status:z,server:P(),hostname:P(),agent:this.agent,project_dir:process.cwd(),...Q})}async getAllStatus(){return this.call("get_all_status",{})}async broadcast(z,Q){return this.call("broadcast",{message:z,filter_server:Q?.server,filter_status:Q?.status})}async connectSSE(){let z=encodeURIComponent(this.alias),Q=`${this.url}/events/${z}`,B=this.reconnectDelay;while(this.running){try{this.sseAbort=new AbortController;let W={Accept:"text/event-stream"};if(this.token)W.Authorization=`Bearer ${this.token}`;let Z=await fetch(Q,{headers:W,signal:this.sseAbort.signal});if(!Z.ok||!Z.body){this.log(`SSE failed: ${Z.status}`),await this.sleep(B),B=Math.min(B*1.5,60000);continue}B=this.reconnectDelay;let Y=Z.body.getReader(),$=new TextDecoder,N="";while(this.running){let{done:X,value:U}=await Y.read();if(X)break;N+=$.decode(U,{stream:!0});let L=N.split(`
3
- `);N=L.pop()||"";for(let O of L){if(!O.startsWith("data: "))continue;try{let E=JSON.parse(O.slice(6));if(E.type==="connected"){this.log("SSE connected"),this.emit("connected");continue}if(E.type==="new_task"||E.type==="new_message"||E.type==="broadcast")await this.processInbox()}catch{}}}}catch(W){if(W.name==="AbortError")break;this.emit("error",W),this.log(`SSE error: ${W.message}`)}if(this.running)this.emit("disconnected"),this.log(`SSE reconnecting in ${B/1000}s...`),await this.sleep(B),B=Math.min(B*1.5,60000)}}async processInbox(){try{let Q=(await this.call("get_inbox",{alias:this.alias,limit:10}))?.messages||[];for(let B of Q)await this.call("ack_inbox",{alias:this.alias,message_id:B.id}),this.log(`← ${B.from_session}: ${B.content.slice(0,60)}`),this.emit("task",B),this.emit("message",B)}catch(z){this.log(`inbox error: ${z.message}`)}}sleep(z){return new Promise((Q)=>setTimeout(Q,z))}};Bz=x});import{readFileSync as _,writeFileSync as V,existsSync as R,mkdirSync as F,readdirSync as u}from"fs";import{join as K}from"path";import{spawn as S}from"child_process";import{createInterface as Zz}from"readline";var T=process.argv.slice(2),C=T[0],q=process.env.HOME||process.env.USERPROFILE||"~";function g(){return K(q,".anet","config.json")}function w(){return K(process.cwd(),".anet","profiles")}function H(){let z=g();if(R(z))try{return JSON.parse(_(z,"utf-8"))}catch{}return{}}function Qz(z){let Q=K(q,".anet");F(Q,{recursive:!0}),V(K(Q,"config.json"),JSON.stringify(z,null,2)+`
4
- `)}function M(z){let Q=K(w(),`${z}.json`);if(R(Q))try{return JSON.parse(_(Q,"utf-8"))}catch{}return null}function f(z,Q){let B=w();F(B,{recursive:!0}),V(K(B,`${z}.json`),JSON.stringify(Q,null,2)+`
5
- `)}function m(){let z=w();if(!R(z))return[];return u(z).filter((Q)=>Q.endsWith(".json")).map((Q)=>Q.replace(/\.json$/,""))}function A(){let z={_channels:[],_envs:[]};for(let Q=0;Q<T.length;Q++){if(T[Q]==="--channel"&&T[Q+1]){z._channels.push(T[++Q]);continue}if(T[Q]==="--env"&&T[Q+1]){z._envs.push(T[++Q]);continue}if(T[Q].startsWith("--")&&T[Q+1]&&!T[Q+1].startsWith("--"))z[T[Q].slice(2)]=T[++Q]}return z}function y(){console.log(`
2
+ import{createRequire as s}from"node:module";var t=Object.defineProperty;var r=(B)=>B;function o(B,Q){this[B]=r.bind(null,Q)}var a=(B,Q)=>{for(var z in Q)t(B,z,{get:Q[z],enumerable:!0,configurable:!0,set:o.bind(Q,z)})};var i=(B,Q)=>()=>(B&&(Q=B(B=0)),Q);var e=s(import.meta.url);var v={};a(v,{default:()=>Bz,CommHub:()=>x});import{EventEmitter as zz}from"events";import{hostname as P}from"os";var x,Bz;var b=i(()=>{x=class x extends zz{url;alias;token;agent;resumeId;heartbeatInterval;reconnectDelay;heartbeatTimer;sseAbort;running=!1;constructor(B){super();if(this.url=B.url.replace(/\/$/,""),this.alias=B.alias,this.token=B.token,this.agent=B.agent||"sdk",this.resumeId=`sdk-${B.alias}-${Date.now().toString(36)}`,this.heartbeatInterval=B.heartbeatInterval??180000,this.reconnectDelay=B.reconnectDelay??3000,B.autoConnect!==!1)this.connect()}log(B){console.log(`[${new Date().toTimeString().slice(0,8)}] [commhub:${this.alias}] ${B}`)}async call(B,Q){let z={"Content-Type":"application/json"};if(this.token)z.Authorization=`Bearer ${this.token}`;let N=await(await fetch(`${this.url}/mcp`,{method:"POST",headers:z,body:JSON.stringify({jsonrpc:"2.0",id:Date.now(),method:"tools/call",params:{name:B,arguments:Q}})})).json(),Y=N?.result?.content?.[0]?.text;return Y?JSON.parse(Y):N}async connect(){if(this.running)return;this.running=!0,await this.status("idle"),this.log("registered"),this.heartbeatTimer=setInterval(()=>{this.status("idle").catch((B)=>this.log(`heartbeat failed: ${B.message}`))},this.heartbeatInterval),this.connectSSE()}async disconnect(){if(this.running=!1,this.sseAbort?.abort(),this.heartbeatTimer)clearInterval(this.heartbeatTimer);await this.status("offline").catch(()=>{}),this.log("disconnected")}async send(B,Q,z="normal"){return this.call("send_task",{alias:B,task:Q,priority:z,from_session:this.alias})}async message(B,Q){return this.call("send_message",{alias:B,message:Q,from_session:this.alias})}async reply(B,Q,z="completed"){return this.call("reply",{task_id:B,text:Q,status:z})}async status(B,Q){return this.call("report_status",{resume_id:this.resumeId,alias:this.alias,status:B,server:P(),hostname:P(),agent:this.agent,project_dir:process.cwd(),...Q})}async getAllStatus(){return this.call("get_all_status",{})}async broadcast(B,Q){return this.call("broadcast",{message:B,filter_server:Q?.server,filter_status:Q?.status})}async connectSSE(){let B=encodeURIComponent(this.alias),Q=`${this.url}/events/${B}`,z=this.reconnectDelay;while(this.running){try{this.sseAbort=new AbortController;let W={Accept:"text/event-stream"};if(this.token)W.Authorization=`Bearer ${this.token}`;let N=await fetch(Q,{headers:W,signal:this.sseAbort.signal});if(!N.ok||!N.body){this.log(`SSE failed: ${N.status}`),await this.sleep(z),z=Math.min(z*1.5,60000);continue}z=this.reconnectDelay;let Y=N.body.getReader(),Z=new TextDecoder,$="";while(this.running){let{done:X,value:U}=await Y.read();if(X)break;$+=Z.decode(U,{stream:!0});let E=$.split(`
3
+ `);$=E.pop()||"";for(let O of E){if(!O.startsWith("data: "))continue;try{let L=JSON.parse(O.slice(6));if(L.type==="connected"){this.log("SSE connected"),this.emit("connected");continue}if(L.type==="new_task"||L.type==="new_message"||L.type==="broadcast")await this.processInbox()}catch{}}}}catch(W){if(W.name==="AbortError")break;this.emit("error",W),this.log(`SSE error: ${W.message}`)}if(this.running)this.emit("disconnected"),this.log(`SSE reconnecting in ${z/1000}s...`),await this.sleep(z),z=Math.min(z*1.5,60000)}}async processInbox(){try{let Q=(await this.call("get_inbox",{alias:this.alias,limit:10}))?.messages||[];for(let z of Q)await this.call("ack_inbox",{alias:this.alias,message_id:z.id}),this.log(`← ${z.from_session}: ${z.content.slice(0,60)}`),this.emit("task",z),this.emit("message",z)}catch(B){this.log(`inbox error: ${B.message}`)}}sleep(B){return new Promise((Q)=>setTimeout(Q,B))}};Bz=x});import{readFileSync as _,writeFileSync as V,existsSync as R,mkdirSync as F,readdirSync as u}from"fs";import{join as K}from"path";import{spawn as S}from"child_process";import{createInterface as Zz}from"readline";var T=process.argv.slice(2),C=T[0],q=process.env.HOME||process.env.USERPROFILE||"~";function g(){return K(q,".anet","config.json")}function w(){return K(process.cwd(),".anet","profiles")}function H(){let B=g();if(R(B))try{return JSON.parse(_(B,"utf-8"))}catch{}return{}}function Qz(B){let Q=K(q,".anet");F(Q,{recursive:!0}),V(K(Q,"config.json"),JSON.stringify(B,null,2)+`
4
+ `)}function M(B){let Q=K(w(),`${B}.json`);if(R(Q))try{return JSON.parse(_(Q,"utf-8"))}catch{}return null}function f(B,Q){let z=w();F(z,{recursive:!0}),V(K(z,`${B}.json`),JSON.stringify(Q,null,2)+`
5
+ `)}function m(){let B=w();if(!R(B))return[];return u(B).filter((Q)=>Q.endsWith(".json")).map((Q)=>Q.replace(/\.json$/,""))}function A(){let B={_channels:[],_envs:[]};for(let Q=0;Q<T.length;Q++){if(T[Q]==="--channel"&&T[Q+1]){B._channels.push(T[++Q]);continue}if(T[Q]==="--env"&&T[Q+1]){B._envs.push(T[++Q]);continue}if(T[Q].startsWith("--")&&T[Q+1]&&!T[Q+1].startsWith("--"))B[T[Q].slice(2)]=T[++Q]}return B}function y(){console.log(`
6
6
  anet — AI Agent Network CLI
7
7
 
8
8
  anet init Configure hub URL (global, once)
@@ -20,10 +20,10 @@ Quick start:
20
20
  anet init profile 指挥室 --alias 指挥室 --channel server:commhub
21
21
  anet start 指挥室 # 新建
22
22
  anet resume 指挥室 # 下次恢复
23
- `)}async function Wz(){let z=A(),Q=z.hub;if(!Q)Q=await J("CommHub URL (e.g. http://YOUR_IP:9200)"),c();if(!Q)console.error("Error: hub URL required"),process.exit(1);Q=Q.replace(/\/+$/,"");try{let Z=await(await fetch(`${Q}/health`)).json();console.log(`✅ CommHub v${Z.version} — ${Z.sessions} sessions, ${Z.sse_connections} SSE`)}catch(W){console.error(`❌ Cannot reach ${Q}: ${W.message}`),process.exit(1)}let B=H();if(B.hub=Q,z.token)B.token=z.token;Qz(B),console.log(`
24
- Saved to ${g()}`),console.log("Next: anet init project")}async function Xz(){let Q=H().hub;if(!Q)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let B=K(process.cwd(),".anet");F(B,{recursive:!0});let W=K(B,"node-server.ts");if(!R(W)){let U=[K(new URL(".",import.meta.url).pathname,"..","..","src","node-server.ts"),K(new URL(".",import.meta.url).pathname,"..","src","node-server.ts"),K(process.argv[1],"..","..","src","node-server.ts")],L=!1;for(let O of U)if(R(O)){V(W,_(O,"utf-8")),console.log(" ✅ .anet/node-server.ts"),L=!0;break}if(!L)console.log(" ❌ Cannot find node-server.ts"),console.log(" Fix: cp $(npm root -g)/@sleep2agi/agent-network/src/node-server.ts .anet/node-server.ts")}else console.log(" Channel plugin: exists");let Z=K(B,"package.json");if(!R(Z)){V(Z,JSON.stringify({private:!0,dependencies:{"@modelcontextprotocol/sdk":"^1.12.0"}},null,2)+`
25
- `);try{let{execSync:U}=await import("child_process");U("bun install",{cwd:B,stdio:"pipe"}),console.log(" ✅ Dependencies installed")}catch{console.log(" ⚠️ Run: cd .anet && bun install")}}let Y=K(B,".env");V(Y,`COMMHUB_URL=${Q}
26
- `),console.log(`CommHub URL: ${Q}`);let $=K(process.cwd(),".mcp.json"),N={};if(R($))try{N=JSON.parse(_($,"utf-8"))}catch{}if(!N.mcpServers?.commhub)N.mcpServers=N.mcpServers||{},N.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},V($,JSON.stringify(N,null,2)+`
23
+ `)}async function Wz(){let B=A(),Q=B.hub;if(!Q)Q=await J("CommHub URL (e.g. http://YOUR_IP:9200)"),c();if(!Q)console.error("Error: hub URL required"),process.exit(1);Q=Q.replace(/\/+$/,"");try{let N=await(await fetch(`${Q}/health`)).json();console.log(`✅ CommHub v${N.version} — ${N.sessions} sessions, ${N.sse_connections} SSE`)}catch(W){console.error(`❌ Cannot reach ${Q}: ${W.message}`),process.exit(1)}let z=H();if(z.hub=Q,B.token)z.token=B.token;Qz(z),console.log(`
24
+ Saved to ${g()}`),console.log("Next: anet init project")}async function Xz(){let Q=H().hub;if(!Q)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let z=K(process.cwd(),".anet");F(z,{recursive:!0});let W=K(z,"node-server.ts");if(!R(W)){let U=[K(new URL(".",import.meta.url).pathname,"..","..","src","node-server.ts"),K(new URL(".",import.meta.url).pathname,"..","src","node-server.ts"),K(process.argv[1],"..","..","src","node-server.ts")],E=!1;for(let O of U)if(R(O)){V(W,_(O,"utf-8")),console.log(" ✅ .anet/node-server.ts"),E=!0;break}if(!E)console.log(" ❌ Cannot find node-server.ts"),console.log(" Fix: cp $(npm root -g)/@sleep2agi/agent-network/src/node-server.ts .anet/node-server.ts")}else console.log(" Channel plugin: exists");let N=K(z,"package.json");if(!R(N)){V(N,JSON.stringify({private:!0,dependencies:{"@modelcontextprotocol/sdk":"^1.12.0"}},null,2)+`
25
+ `);try{let{execSync:U}=await import("child_process");U("bun install",{cwd:z,stdio:"pipe"}),console.log(" ✅ Dependencies installed")}catch{console.log(" ⚠️ Run: cd .anet && bun install")}}let Y=K(z,".env");V(Y,`COMMHUB_URL=${Q}
26
+ `),console.log(`CommHub URL: ${Q}`);let Z=K(process.cwd(),".mcp.json"),$={};if(R(Z))try{$=JSON.parse(_(Z,"utf-8"))}catch{}if(!$.mcpServers?.commhub)$.mcpServers=$.mcpServers||{},$.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},V(Z,JSON.stringify($,null,2)+`
27
27
  `),console.log(".mcp.json: commhub → .anet/node-server.ts");else console.log(".mcp.json: commhub already set");let X=K(process.cwd(),"CLAUDE.md");if(!R(X))V(X,`# Agent Network (CommHub)
28
28
 
29
29
  ## 通信方式
@@ -63,24 +63,24 @@ commhub_get_all_status()
63
63
  - 回复指挥室用 commhub_send_task(不是 commhub_reply,reply 不推送)
64
64
  - 不要猜 alias,用 get_all_status 查
65
65
  `),console.log("CLAUDE.md: created");else console.log("CLAUDE.md: already exists");console.log(`
66
- ✅ Project ready. Next: anet init profile <id> --alias <名字> --channel server:commhub`)}function Yz(){let z=T[2];if(!z)console.error("Usage: anet init profile <id> --alias <名字> [--channel ...] [--env ...]"),process.exit(1);let Q=H(),B=A(),W=B.alias||z,Z=B.hub||Q.hub;if(!Z)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let Y={};for(let L of B._envs){let O=L.indexOf("=");if(O>0)Y[L.slice(0,O)]=L.slice(O+1)}let $={anet_version:"0.0.11",...B.name?{name:B.name}:{},alias:W,hub:Z,channels:B._channels.length>0?B._channels:["server:commhub"],env:Y,flags:{dangerouslySkipPermissions:!0,teammateMode:B["teammate-mode"]||"in-process"},...B.resume?{resume:B.resume}:{},...B["resume-alias"]?{resumeAlias:B["resume-alias"]}:{}},N=K(q,".claude","channels","commhub"),X=process.cwd().replace(/\//g,"-"),U=K(N,X);if(F(U,{recursive:!0}),V(K(U,".env"),`COMMHUB_ALIAS=${W}
67
- `),f(z,$),console.log(`
68
- ✅ Profile "${z}" saved`),console.log(` alias: ${W}`),console.log(` channels: ${$.channels.join(", ")}`),Object.keys(Y).length)console.log(` env: ${Object.keys(Y).join(", ")}`);console.log(`
69
- Start: anet start ${z}`)}var G=null;function $z(){if(!G)G=Zz({input:process.stdin,output:process.stdout});return G}function c(){if(G)G.close(),G=null}function J(z,Q){let B=Q?` [${Q}]`:"";return new Promise((W)=>{$z().question(`${z}${B}: `,(Z)=>{W(Z.trim()||Q||"")})})}async function Nz(z){let Q=H();console.log(`
70
- Profile "${z}" not found. Let's create it:
71
- `);let B=await J("Runtime (claude-code / agent-sdk)","claude-code"),W=await J("Alias",z),Z,Y=[],$=[],N="";if(B==="agent-sdk")Z=await J("Model","MiniMax-M2.7"),Y=(await J("Tools (comma-separated)","Read,Bash,Grep")).split(",").map((I)=>I.trim()).filter(Boolean);else $=(await J("Channels (comma-separated)","server:commhub")).split(",").map((I)=>I.trim()).filter(Boolean),N=await J("Teammate mode","in-process");let X=await J("Extra env (K=V, comma-separated, empty to skip)"),U={};if(X)for(let E of X.split(",")){let I=E.trim().indexOf("=");if(I>0)U[E.trim().slice(0,I)]=E.trim().slice(I+1)}let L=Q.hub;if(!L)console.error(`
72
- Run 'anet init' first to configure hub URL`),process.exit(1);let O={anet_version:"0.0.23",alias:W,hub:L,runtime:B,...Z?{model:Z}:{},...Y.length?{tools:Y}:{},channels:$,env:U,flags:{dangerouslySkipPermissions:!0,...N?{teammateMode:N}:{}}};return f(z,O),c(),console.log(`
73
- ✅ Profile "${z}" saved
74
- `),O}async function p(z,Q){let B=M(z);if(!B)B=await Nz(z);let W=B.runtime||"claude-code";if(console.log(`[anet] ${Q==="start"?"Starting new":"Resuming"} "${z}" (${B.alias}) [${W}]...
75
- `),W==="agent-sdk"){let Y=["@sleep2agi/agent-node","--alias",B.alias,"--hub",B.hub];if(B.model)Y.push("--model",B.model);if(B.tools?.length)Y.push("--tools",B.tools.join(","));if(B.flags?.maxTurns)Y.push("--max-turns",String(B.flags.maxTurns));let $={...process.env};for(let[X,U]of Object.entries(B.env))$[X]=U.replace(/^~/,q);S("npx",Y,{env:$,stdio:"inherit",shell:!0}).on("exit",(X)=>process.exit(X||0))}else{let Y={...process.env,COMMHUB_ALIAS:B.alias};for(let[X,U]of Object.entries(B.env))Y[X]=U.replace(/^~/,q);let $=[];if(B.flags.dangerouslySkipPermissions)$.push("--dangerously-skip-permissions");for(let X of B.channels)if(X.startsWith("server:"))$.push("--dangerously-load-development-channels",X);else $.push("--channels",X);if(B.flags.teammateMode)$.push("--teammate-mode",B.flags.teammateMode);if(Q==="resume"){let X=B.resumeAlias||B.name||B.alias;$.push("--resume",X)}$.push("-n",B.name||B.alias),S("claude",$,{env:Y,stdio:"inherit",shell:!0}).on("exit",(X)=>process.exit(X||0))}}async function h(){let z=T[1];if(!z){d("start");return}await p(z,"start")}async function Uz(){let z=T[1];if(!z){d("resume");return}if(!M(z))console.log(`Profile "${z}" not found. Create one first:
66
+ ✅ Project ready. Next: anet init profile <id> --alias <名字> --channel server:commhub`)}function Yz(){let B=T[2];if(!B)console.error("Usage: anet init profile <id> --alias <名字> [--channel ...] [--env ...]"),process.exit(1);let Q=H(),z=A(),W=z.alias||B,N=z.hub||Q.hub;if(!N)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let Y={};for(let O of z._envs){let L=O.indexOf("=");if(L>0)Y[O.slice(0,L)]=O.slice(L+1)}let Z=z.runtime||"claude-code",$={anet_version:"0.0.24",...z.name?{name:z.name}:{},runtime:Z,alias:W,hub:N,...z.model?{model:z.model}:{},...z.tools?{tools:z.tools.split(",").map((O)=>O.trim())}:{},channels:z._channels.length>0?z._channels:Z==="claude-code"?["server:commhub"]:[],env:Y,flags:{dangerouslySkipPermissions:!0,...Z==="claude-code"?{teammateMode:z["teammate-mode"]||"in-process"}:{},...z["max-turns"]?{maxTurns:parseInt(z["max-turns"])}:{}},...z.resume?{resume:z.resume}:{},...z["resume-alias"]?{resumeAlias:z["resume-alias"]}:{}},X=K(q,".claude","channels","commhub"),U=process.cwd().replace(/\//g,"-"),E=K(X,U);if(F(E,{recursive:!0}),V(K(E,".env"),`COMMHUB_ALIAS=${W}
67
+ `),f(B,$),console.log(`
68
+ ✅ Profile "${B}" saved`),console.log(` alias: ${W}`),console.log(` channels: ${$.channels.join(", ")}`),Object.keys(Y).length)console.log(` env: ${Object.keys(Y).join(", ")}`);console.log(`
69
+ Start: anet start ${B}`)}var G=null;function $z(){if(!G)G=Zz({input:process.stdin,output:process.stdout});return G}function c(){if(G)G.close(),G=null}function J(B,Q){let z=Q?` [${Q}]`:"";return new Promise((W)=>{$z().question(`${B}${z}: `,(N)=>{W(N.trim()||Q||"")})})}async function Nz(B){let Q=H();console.log(`
70
+ Profile "${B}" not found. Let's create it:
71
+ `);let z=await J("Runtime (claude-code / agent-sdk)","claude-code"),W=await J("Alias",B),N,Y=[],Z=[],$="";if(z==="agent-sdk")N=await J("Model","MiniMax-M2.7"),Y=(await J("Tools (comma-separated)","Read,Bash,Grep")).split(",").map((I)=>I.trim()).filter(Boolean);else Z=(await J("Channels (comma-separated)","server:commhub")).split(",").map((I)=>I.trim()).filter(Boolean),$=await J("Teammate mode","in-process");let X=await J("Extra env (K=V, comma-separated, empty to skip)"),U={};if(X)for(let L of X.split(",")){let I=L.trim().indexOf("=");if(I>0)U[L.trim().slice(0,I)]=L.trim().slice(I+1)}let E=Q.hub;if(!E)console.error(`
72
+ Run 'anet init' first to configure hub URL`),process.exit(1);let O={anet_version:"0.0.23",alias:W,hub:E,runtime:z,...N?{model:N}:{},...Y.length?{tools:Y}:{},channels:Z,env:U,flags:{dangerouslySkipPermissions:!0,...$?{teammateMode:$}:{}}};return f(B,O),c(),console.log(`
73
+ ✅ Profile "${B}" saved
74
+ `),O}async function p(B,Q){let z=M(B);if(!z)z=await Nz(B);let W=z.runtime||"claude-code";if(console.log(`[anet] ${Q==="start"?"Starting new":"Resuming"} "${B}" (${z.alias}) [${W}]...
75
+ `),W==="agent-sdk"){let Y=["@sleep2agi/agent-node","--alias",z.alias,"--hub",z.hub];if(z.model)Y.push("--model",z.model);if(z.tools?.length)Y.push("--tools",z.tools.join(","));if(z.flags?.maxTurns)Y.push("--max-turns",String(z.flags.maxTurns));let Z={...process.env};for(let[X,U]of Object.entries(z.env))Z[X]=U.replace(/^~/,q);S("npx",Y,{env:Z,stdio:"inherit",shell:!0}).on("exit",(X)=>process.exit(X||0))}else{let Y={...process.env,COMMHUB_ALIAS:z.alias};for(let[X,U]of Object.entries(z.env))Y[X]=U.replace(/^~/,q);let Z=[];if(z.flags.dangerouslySkipPermissions)Z.push("--dangerously-skip-permissions");for(let X of z.channels)if(X.startsWith("server:"))Z.push("--dangerously-load-development-channels",X);else Z.push("--channels",X);if(z.flags.teammateMode)Z.push("--teammate-mode",z.flags.teammateMode);if(Q==="resume"){let X=z.resumeAlias||z.name||z.alias;Z.push("--resume",X)}Z.push("-n",z.name||z.alias),S("claude",Z,{env:Y,stdio:"inherit",shell:!0}).on("exit",(X)=>process.exit(X||0))}}async function h(){let B=T[1];if(!B){d("start");return}await p(B,"start")}async function Uz(){let B=T[1];if(!B){d("resume");return}if(!M(B))console.log(`Profile "${B}" not found. Create one first:
76
76
 
77
- anet start ${z}
78
- `),process.exit(1);await p(z,"resume")}function d(z){let Q=m();if(Q.length===0){console.log("No profiles. Run: anet init profile <id> --alias <名字>");return}console.log(`
77
+ anet start ${B}
78
+ `),process.exit(1);await p(B,"resume")}function d(B){let Q=m();if(Q.length===0){console.log("No profiles. Run: anet init profile <id> --alias <名字>");return}console.log(`
79
79
  Profiles:
80
- `);for(let B of Q){let W=M(B);console.log(` ${B}${W?.name?` (${W.name})`:""} → ${W?.alias} [${W?.channels.join(", ")}]`)}console.log(`
81
- anet ${z} <id>
82
- `)}async function Kz(){let z=m();if(z.length>0){console.log(`
80
+ `);for(let z of Q){let W=M(z);console.log(` ${z}${W?.name?` (${W.name})`:""} → ${W?.alias} [${W?.channels.join(", ")}]`)}console.log(`
81
+ anet ${B} <id>
82
+ `)}async function Kz(){let B=m();if(B.length>0){console.log(`
83
83
  Profiles:
84
- `);for(let N of z){let X=M(N);console.log(` ${N}${X?.name?` (${X.name})`:""} → ${X?.alias} [${X?.channels.join(", ")}]`)}console.log()}let Q=process.cwd(),B=K(q,".claude","sessions"),W=[];if(R(B))for(let N of u(B).filter((X)=>X.endsWith(".json")))try{let X=JSON.parse(_(K(B,N),"utf-8"));if(X.cwd===Q)W.push(X)}catch{}if(W.length===0&&z.length===0){console.log("No sessions or profiles in this directory."),console.log(`Get started: anet init
85
- `);return}let Z=H(),Y=[],$={};if(Z.hub)try{let[N,X]=await Promise.all([fetch(`${Z.hub}/api/status`).then((U)=>U.json()),fetch(`${Z.hub}/health`).then((U)=>U.json())]);Y=N.sessions||[],$=X.sse_sessions||{}}catch{}if(W.length>0){console.log(`Sessions (${Q}):
86
- `),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let N of W){let X=N.sessionId.slice(0,18),U=!1;try{process.kill(N.pid,0),U=!0}catch{}let L="(not in network)",O=Q.replace(/\//g,"-"),E=K(q,".claude","channels","commhub",O,".env");if(R(E)){let k=_(E,"utf-8").match(/COMMHUB_ALIAS=(.+)/);if(k){let D=k[1].trim(),j=Y.find((l)=>l.alias===D),n=$[D]?"●":"○";L=j?`${D} ${j.status} ${n}`:`${D} (not registered)`}}console.log(` ${X} ${(U?`${N.pid}`:`${N.pid}✕`).padEnd(7)} ${L}`)}console.log()}}async function Tz(){let z=H(),Q=A(),B=process.env.COMMHUB_URL||Q.hub||z.hub||"http://127.0.0.1:9200",W=process.env.COMMHUB_ALIAS||Q.alias;if(!W)console.error("Error: --alias required"),process.exit(1);let{CommHub:Z}=await Promise.resolve().then(() => (b(),v)),Y=new Z({url:B,alias:W});Y.on("task",async($)=>{console.log(`[${W}] ← ${$.from_session}: ${$.content.slice(0,100)}`),await Y.send($.from_session,`[${W}] 收到: ${$.content.slice(0,200)}`)}),Y.on("connected",()=>console.log(`[${W}] Connected`)),Y.on("disconnected",()=>console.log(`[${W}] Reconnecting...`)),process.on("SIGINT",()=>Y.disconnect().then(()=>process.exit(0))),console.log(`[${W}] Listening on ${B}`)}switch(C){case"init":if(T[1]==="project")Xz();else if(T[1]==="profile")Yz();else Wz();break;case"start":h();break;case"resume":Uz();break;case"ls":case"list":Kz();break;case"run":Tz();break;case"--help":case"-h":case void 0:y();break;default:if(M(C))T.unshift("start"),h();else console.error(`Unknown: ${C}`),y(),process.exit(1)}
84
+ `);for(let $ of B){let X=M($);console.log(` ${$}${X?.name?` (${X.name})`:""} → ${X?.alias} [${X?.channels.join(", ")}]`)}console.log()}let Q=process.cwd(),z=K(q,".claude","sessions"),W=[];if(R(z))for(let $ of u(z).filter((X)=>X.endsWith(".json")))try{let X=JSON.parse(_(K(z,$),"utf-8"));if(X.cwd===Q)W.push(X)}catch{}if(W.length===0&&B.length===0){console.log("No sessions or profiles in this directory."),console.log(`Get started: anet init
85
+ `);return}let N=H(),Y=[],Z={};if(N.hub)try{let[$,X]=await Promise.all([fetch(`${N.hub}/api/status`).then((U)=>U.json()),fetch(`${N.hub}/health`).then((U)=>U.json())]);Y=$.sessions||[],Z=X.sse_sessions||{}}catch{}if(W.length>0){console.log(`Sessions (${Q}):
86
+ `),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let $ of W){let X=$.sessionId.slice(0,18),U=!1;try{process.kill($.pid,0),U=!0}catch{}let E="(not in network)",O=Q.replace(/\//g,"-"),L=K(q,".claude","channels","commhub",O,".env");if(R(L)){let k=_(L,"utf-8").match(/COMMHUB_ALIAS=(.+)/);if(k){let D=k[1].trim(),j=Y.find((l)=>l.alias===D),n=Z[D]?"●":"○";E=j?`${D} ${j.status} ${n}`:`${D} (not registered)`}}console.log(` ${X} ${(U?`${$.pid}`:`${$.pid}✕`).padEnd(7)} ${E}`)}console.log()}}async function Tz(){let B=H(),Q=A(),z=process.env.COMMHUB_URL||Q.hub||B.hub||"http://127.0.0.1:9200",W=process.env.COMMHUB_ALIAS||Q.alias;if(!W)console.error("Error: --alias required"),process.exit(1);let{CommHub:N}=await Promise.resolve().then(() => (b(),v)),Y=new N({url:z,alias:W});Y.on("task",async(Z)=>{console.log(`[${W}] ← ${Z.from_session}: ${Z.content.slice(0,100)}`),await Y.send(Z.from_session,`[${W}] 收到: ${Z.content.slice(0,200)}`)}),Y.on("connected",()=>console.log(`[${W}] Connected`)),Y.on("disconnected",()=>console.log(`[${W}] Reconnecting...`)),process.on("SIGINT",()=>Y.disconnect().then(()=>process.exit(0))),console.log(`[${W}] Listening on ${z}`)}switch(C){case"init":if(T[1]==="project")Xz();else if(T[1]==="profile")Yz();else Wz();break;case"start":h();break;case"resume":Uz();break;case"ls":case"list":Kz();break;case"run":Tz();break;case"--help":case"-h":case void 0:y();break;default:if(M(C))T.unshift("start"),h();else console.error(`Unknown: ${C}`),y(),process.exit(1)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/agent-network",
3
- "version": "0.0.23",
3
+ "version": "0.0.25",
4
4
  "description": "AI Agent Network — Server + Client + Setup in one package. SSE real-time communication for multi-agent orchestration.",
5
5
  "type": "module",
6
6
  "main": "dist/src/client.js",