@sleep2agi/agent-network 0.0.27 → 0.0.29

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 +110 -118
  2. package/dist/bin/cli.js +23 -23
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,177 +1,153 @@
1
1
  # @sleep2agi/agent-network
2
2
 
3
- AI Agent 通信网络 — AI Agent 互相发消息、派任务、协作。
3
+ AI Agent 通信网络 — Server + Agent + CLI,一个包搞定。
4
4
 
5
- 支持两种 Agent 运行时:
6
- - **claude-code** — Claude Code CLI(交互式开发)
7
- - **agent-sdk** — Claude Agent SDK + 任意模型(MiniMax/Claude,自动化)
5
+ 支持 MiniMax / 书生 Intern-S1 / Claude 等任意 Anthropic API 兼容模型。
8
6
 
9
7
  ## 安装
10
8
 
11
9
  ```bash
12
- # 必装:anet CLI + CommHub SDK
13
10
  npm install -g @sleep2agi/agent-network
14
-
15
- # 按需装:
16
- npm install -g @anthropic-ai/claude-code # claude-code runtime
17
- npm install -g @sleep2agi/agent-node # agent-sdk runtime
18
11
  ```
19
12
 
20
- ## 快速开始
13
+ ## 一分钟上手
21
14
 
22
- ### Claude Code Agent
15
+ ### 1. 启动 Server
23
16
 
17
+ ```bash
18
+ anet server start --port 9200
19
+ ```
20
+
21
+ ### 2. 启动 Agent
22
+
23
+ **Claude Code(交互式):**
24
24
  ```bash
25
25
  anet init --hub http://YOUR_IP:9200
26
26
  anet init project
27
- anet init profile 指挥室 --alias 指挥室 --channel server:commhub
28
27
  anet start 指挥室
29
28
  ```
30
29
 
31
- ### MiniMax Agent(低成本)
32
-
30
+ **MiniMax(低成本自动化):**
33
31
  ```bash
34
32
  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号
33
+ anet init profile 小明 --runtime agent-sdk --alias 小明 --model MiniMax-M2.7 --tools all \
34
+ --env "ANTHROPIC_BASE_URL=https://api.minimaxi.com/anthropic" \
35
+ --env "ANTHROPIC_AUTH_TOKEN=your-key"
36
+ anet start 小明
43
37
  ```
44
38
 
45
- ## 工作原理
39
+ **书生 Intern-S1-Pro:**
40
+ ```bash
41
+ anet init profile 书生 --runtime agent-sdk --alias 书生 --model intern-s1-pro --tools all \
42
+ --env "ANTHROPIC_BASE_URL=https://chat.intern-ai.org.cn" \
43
+ --env "ANTHROPIC_AUTH_TOKEN=your-key"
44
+ anet start 书生
45
+ ```
46
46
 
47
- `anet start` 读 profile,根据 `runtime` 自动选择启动方式:
47
+ ### 3. 查看状态
48
48
 
49
+ ```bash
50
+ anet ls
49
51
  ```
50
- anet start 指挥室 → runtime: claude-code → spawn claude CLI
51
- anet start 小明1号 → runtime: agent-sdk → spawn agent-node (MiniMax)
52
+
53
+ ## CLI 命令
54
+
55
+ ### Server
56
+
57
+ ```bash
58
+ anet server start # 启动 CommHub Server(自动拉 @sleep2agi/commhub-server)
59
+ anet server start --port 9200 # 指定端口
60
+ anet server start --token my-secret # 加认证
52
61
  ```
53
62
 
54
- 同一目录可以有多个 profile,不同 runtime 共存。
63
+ 需要 Bun 运行时(`curl -fsSL https://bun.sh/install | bash`)。
55
64
 
56
- ## CLI 命令
65
+ ### Agent 初始化
57
66
 
67
+ ```bash
68
+ anet init # 配 hub URL(全局,一次性)
69
+ anet init project # 配项目(claude-code 用:channel 插件 + .mcp.json + CLAUDE.md)
70
+ anet init profile <id> [options] # 创建启动 profile
58
71
  ```
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 + 网络状态
72
+
73
+ ### Agent 启动
74
+
75
+ ```bash
76
+ anet start <id> # 新建 session
77
+ anet resume <id> # 恢复上次 session
78
+ anet start # 列出所有 profile
79
+ anet <id> # 快捷启动
65
80
  ```
66
81
 
67
- ### anet init profile
82
+ profile 不存在时自动进入交互式创建。
83
+
84
+ `anet start` 根据 profile 的 `runtime` 自动选择:
85
+ - `claude-code` → spawn claude CLI
86
+ - `agent-sdk` → spawn @sleep2agi/agent-node
87
+
88
+ ### 状态查看
68
89
 
69
90
  ```bash
70
- anet init profile <id> [options]
91
+ anet ls # profiles + sessions + 网络状态
71
92
  ```
72
93
 
73
- **共用参数:**
94
+ ## anet init profile 参数
95
+
96
+ **共用:**
74
97
 
75
98
  | 参数 | 说明 |
76
99
  |------|------|
77
- | `--alias` | CommHub session 别名 |
100
+ | `--alias` | Agent 名称 |
78
101
  | `--runtime` | `claude-code`(默认)或 `agent-sdk` |
79
102
  | `--env` | 环境变量 K=V(可重复) |
80
103
 
81
- **claude-code 参数:**
104
+ **claude-code:**
82
105
 
83
106
  | 参数 | 说明 |
84
107
  |------|------|
85
108
  | `--channel` | Channel(可重复,默认 server:commhub) |
86
109
  | `--teammate-mode` | 默认 in-process |
87
- | `--resume-alias` | 恢复搜索名 |
88
110
 
89
- **agent-sdk 参数:**
111
+ **agent-sdk:**
90
112
 
91
113
  | 参数 | 说明 |
92
114
  |------|------|
93
- | `--model` | 模型名(如 MiniMax-M2.7) |
94
- | `--tools` | 工具列表,逗号分隔 |
115
+ | `--model` | 模型名 |
116
+ | `--tools` | `all` 或逗号分隔(Read,Write,Edit,Bash,Glob,Grep,WebSearch,WebFetch) |
95
117
  | `--max-turns` | 每任务最大轮次 |
96
-
97
- ### anet start / resume
98
-
99
- ```bash
100
- anet start 指挥室 # 新建 session
101
- anet resume 指挥室 # 恢复上次 session
102
- anet start # 列出所有 profile
103
- anet 指挥室 # 快捷方式
104
- ```
105
-
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
- ```
119
-
120
- agent-sdk runtime 不需要 init project。
121
-
122
- ### anet ls
123
-
124
- ```
125
- Profiles:
126
- 指挥室 → 指挥室 [server:commhub, plugin:telegram]
127
- 小明1号 → 小明1号 []
128
-
129
- Sessions (/home/vansin/project):
130
- SESSION PID NETWORK
131
- ──────────────────── ─────── ─────────────────────
132
- fef0eb55-b39c-4abc 64269 通信龙 offline ●
133
- ```
118
+ | `--max-budget` | 每任务预算(美元) |
134
119
 
135
120
  ## Profile 格式
136
121
 
137
- 路径:`.anet/profiles/<id>.json`
138
-
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)
122
+ 路径:`.anet/profiles/<id>.json`,anet 和 agent-node 共用。
155
123
 
156
124
  ```json
157
125
  {
158
126
  "runtime": "agent-sdk",
159
- "alias": "小明1号",
127
+ "alias": "小明",
160
128
  "hub": "http://YOUR_IP:9200",
161
129
  "model": "MiniMax-M2.7",
162
- "tools": ["Read", "Bash", "Grep"],
130
+ "tools": ["Read", "Write", "Edit", "Bash", "Glob", "Grep", "WebSearch", "WebFetch"],
163
131
  "env": {
164
- "ANTHROPIC_BASE_URL": "https://api.minimax.chat/anthropic",
132
+ "ANTHROPIC_BASE_URL": "https://api.minimaxi.com/anthropic",
165
133
  "ANTHROPIC_AUTH_TOKEN": "your-key"
166
134
  }
167
135
  }
168
136
  ```
169
137
 
170
- ### 配置优先级
138
+ 配置优先级:`CLI 参数 > profile env > 系统环境变量 > ~/.anet/config.json > 默认值`
171
139
 
172
- ```
173
- CLI 参数 > profile env > 系统环境变量 > ~/.anet/config.json > 默认值
174
- ```
140
+ ## 支持的模型
141
+
142
+ | 模型 | ANTHROPIC_BASE_URL | 已验证 |
143
+ |------|-------------------|--------|
144
+ | MiniMax M2.7(国际) | `https://api.minimaxi.com/anthropic` | ✅ 对话 + tool_use |
145
+ | MiniMax M2.7(国内) | `https://api.minimax.chat/anthropic` | ✅ |
146
+ | 书生 Intern-S1-Pro | `https://chat.intern-ai.org.cn` | ✅ |
147
+ | Claude(默认) | 不设 | ✅ |
148
+ | 任意 Anthropic 兼容 | 对应端点 | — |
149
+
150
+ 两个环境变量切模型,零代码修改。
175
151
 
176
152
  ## SDK 代码引用
177
153
 
@@ -188,25 +164,41 @@ hub.on('task', async (msg) => {
188
164
  |------|------|
189
165
  | `hub.send(alias, content)` | 发任务 |
190
166
  | `hub.message(alias, content)` | 发消息 |
167
+ | `hub.reply(taskId, text, status?)` | 回复任务 |
191
168
  | `hub.status(state, extra?)` | 更新状态 |
169
+ | `hub.broadcast(content)` | 广播 |
170
+ | `hub.getAllStatus()` | 查看所有 session |
192
171
  | `hub.disconnect()` | 断开 |
193
172
 
173
+ | 事件 | 说明 |
174
+ |------|------|
175
+ | `task` | 收到任务(已自动 ACK) |
176
+ | `connected` | SSE 连接成功 |
177
+ | `disconnected` | SSE 断开(自动重连) |
178
+
194
179
  ## 依赖
195
180
 
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 |
181
+ | 组件 | 什么时候需要 | 安装 |
182
+ |------|------------|------|
183
+ | @sleep2agi/agent-network | 所有人 | `npm i -g @sleep2agi/agent-network` |
184
+ | @anthropic-ai/claude-code | Claude Code Agent | `npm i -g @anthropic-ai/claude-code` |
185
+ | @sleep2agi/agent-node | agent-sdk Agent | `npm i -g @sleep2agi/agent-node` |
186
+ | @anthropic-ai/claude-agent-sdk | agent-sdk Agent(运行时依赖) | `npm i @anthropic-ai/claude-agent-sdk` |
187
+ | Bun | 启动 CommHub Server | `curl -fsSL https://bun.sh/install \| bash` |
188
+
189
+ ## npm 包
190
+
191
+ | 包 | 说明 | 大小 |
192
+ |---|------|------|
193
+ | [@sleep2agi/agent-network](https://www.npmjs.com/package/@sleep2agi/agent-network) | anet CLI + CommHub SDK | ~15KB |
194
+ | [@sleep2agi/agent-node](https://www.npmjs.com/package/@sleep2agi/agent-node) | Agent 运行时 | ~5KB |
195
+ | [@sleep2agi/commhub-server](https://www.npmjs.com/package/@sleep2agi/commhub-server) | CommHub Server | ~10KB |
202
196
 
203
- ## 相关包
197
+ ## 文档
204
198
 
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 |
199
+ - [CLI 设计](docs/cli-design.md) 命令 + Profile 规范
200
+ - [架构设计](docs/architecture.md) — 系统架构
201
+ - [操作手册](https://github.com/sleep2agi/agent-ops)(private) 服务器/启动命令/Key
210
202
 
211
203
  ## License
212
204
 
package/dist/bin/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import{createRequire as e}from"node:module";var r=Object.defineProperty;var o=(B)=>B;function a(B,Q){this[B]=o.bind(null,Q)}var i=(B,Q)=>{for(var z in Q)r(B,z,{get:Q[z],enumerable:!0,configurable:!0,set:a.bind(Q,z)})};var s=(B,Q)=>()=>(B&&(Q=B(B=0)),Q);var b=e(import.meta.url);var S={};i(S,{default:()=>Bz,CommHub:()=>x});import{EventEmitter as zz}from"events";import{hostname as v}from"os";var x,Bz;var y=s(()=>{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",Accept:"application/json, text/event-stream"};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}})})).text(),$=N.match(/data: (.+)/),X=$?JSON.parse($[1]):JSON.parse(N),Z=X?.result?.content?.[0]?.text;return Z?JSON.parse(Z):X}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:v(),hostname:v(),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 $=N.body.getReader(),X=new TextDecoder,Z="";while(this.running){let{done:Y,value:U}=await $.read();if(Y)break;Z+=X.decode(U,{stream:!0});let O=Z.split(`
3
- `);Z=O.pop()||"";for(let T of O){if(!T.startsWith("data: "))continue;try{let E=JSON.parse(T.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 ${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 G,writeFileSync as H,existsSync as I,mkdirSync as F,readdirSync as f}from"fs";import{join as K}from"path";import{spawn as w}from"child_process";import{createInterface as Zz}from"readline";var L=process.argv.slice(2),A=L[0],J=process.env.HOME||process.env.USERPROFILE||"~";function g(){return K(J,".anet","config.json")}function k(){return K(process.cwd(),".anet","profiles")}function _(){let B=g();if(I(B))try{return JSON.parse(G(B,"utf-8"))}catch{}return{}}function Qz(B){let Q=K(J,".anet");F(Q,{recursive:!0}),H(K(Q,"config.json"),JSON.stringify(B,null,2)+`
4
- `)}function M(B){let Q=K(k(),`${B}.json`);if(I(Q))try{return JSON.parse(G(Q,"utf-8"))}catch{}return null}function m(B,Q){let z=k();F(z,{recursive:!0}),H(K(z,`${B}.json`),JSON.stringify(Q,null,2)+`
5
- `)}function c(){let B=k();if(!I(B))return[];return f(B).filter((Q)=>Q.endsWith(".json")).map((Q)=>Q.replace(/\.json$/,""))}function C(){let B={_channels:[],_envs:[]};for(let Q=0;Q<L.length;Q++){if(L[Q]==="--channel"&&L[Q+1]){B._channels.push(L[++Q]);continue}if(L[Q]==="--env"&&L[Q+1]){B._envs.push(L[++Q]);continue}if(L[Q].startsWith("--")&&L[Q+1]&&!L[Q+1].startsWith("--"))B[L[Q].slice(2)]=L[++Q]}return B}function u(){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:()=>C});import{EventEmitter as zz}from"events";import{hostname as b}from"os";var C,Bz;var S=i(()=>{C=class C 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",Accept:"application/json, text/event-stream"};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}})})).text(),Z=N.match(/data: (.+)/),$=Z?JSON.parse(Z[1]):JSON.parse(N),Y=$?.result?.content?.[0]?.text;return Y?JSON.parse(Y):$}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:b(),hostname:b(),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 Z=N.body.getReader(),$=new TextDecoder,Y="";while(this.running){let{done:X,value:U}=await Z.read();if(X)break;Y+=$.decode(U,{stream:!0});let O=Y.split(`
3
+ `);Y=O.pop()||"";for(let E of O){if(!E.startsWith("data: "))continue;try{let T=JSON.parse(E.slice(6));if(T.type==="connected"){this.log("SSE connected"),this.emit("connected");continue}if(T.type==="new_task"||T.type==="new_message"||T.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=C});import{readFileSync as G,writeFileSync as V,existsSync as R,mkdirSync as F,readdirSync as h}from"fs";import{join as K}from"path";import{spawn as w}from"child_process";import{createInterface as Zz}from"readline";var L=process.argv.slice(2),A=L[0],H=process.env.HOME||process.env.USERPROFILE||"~";function g(){return K(H,".anet","config.json")}function P(){return K(process.cwd(),".anet","profiles")}function _(){let B=g();if(R(B))try{return JSON.parse(G(B,"utf-8"))}catch{}return{}}function Qz(B){let Q=K(H,".anet");F(Q,{recursive:!0}),V(K(Q,"config.json"),JSON.stringify(B,null,2)+`
4
+ `)}function M(B){let Q=K(P(),`${B}.json`);if(R(Q))try{return JSON.parse(G(Q,"utf-8"))}catch{}return null}function f(B,Q){let z=P();F(z,{recursive:!0}),V(K(z,`${B}.json`),JSON.stringify(Q,null,2)+`
5
+ `)}function m(){let B=P();if(!R(B))return[];return h(B).filter((Q)=>Q.endsWith(".json")).map((Q)=>Q.replace(/\.json$/,""))}function x(){let B={_channels:[],_envs:[]};for(let Q=0;Q<L.length;Q++){if(L[Q]==="--channel"&&L[Q+1]){B._channels.push(L[++Q]);continue}if(L[Q]==="--env"&&L[Q+1]){B._envs.push(L[++Q]);continue}if(L[Q].startsWith("--")&&L[Q+1]&&!L[Q+1].startsWith("--"))B[L[Q].slice(2)]=L[++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,11 +20,11 @@ Quick start:
20
20
  anet init --hub http://IP:9200
21
21
  anet start 指挥室 # Claude Code Agent
22
22
  anet start 小明 # MiniMax Agent (runtime: agent-sdk)
23
- `)}async function Wz(){let B=C(),Q=B.hub;if(!Q)Q=await V("CommHub URL (e.g. http://YOUR_IP:9200)"),p();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=_();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=_().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(!I(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")],O=!1;for(let T of U)if(I(T)){H(W,G(T,"utf-8")),console.log(" ✅ .anet/node-server.ts"),O=!0;break}if(!O)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(!I(N)){H(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 $=K(z,".env");H($,`COMMHUB_URL=${Q}
26
- `),console.log(`CommHub URL: ${Q}`);let X=K(process.cwd(),".mcp.json"),Z={};if(I(X))try{Z=JSON.parse(G(X,"utf-8"))}catch{}if(!Z.mcpServers?.commhub)Z.mcpServers=Z.mcpServers||{},Z.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},H(X,JSON.stringify(Z,null,2)+`
27
- `),console.log(".mcp.json: commhub → .anet/node-server.ts");else console.log(".mcp.json: commhub already set");let Y=K(process.cwd(),"CLAUDE.md");if(!I(Y))H(Y,`# Agent Network (CommHub)
23
+ `)}async function Wz(){let B=x(),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=_();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=_().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")],O=!1;for(let E of U)if(R(E)){V(W,G(E,"utf-8")),console.log(" ✅ .anet/node-server.ts"),O=!0;break}if(!O)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 Z=K(z,".env");V(Z,`COMMHUB_URL=${Q}
26
+ `),console.log(`CommHub URL: ${Q}`);let $=K(process.cwd(),".mcp.json"),Y={};if(R($))try{Y=JSON.parse(G($,"utf-8"))}catch{}if(!Y.mcpServers?.commhub)Y.mcpServers=Y.mcpServers||{},Y.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},V($,JSON.stringify(Y,null,2)+`
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
  ## 通信方式
30
30
 
@@ -63,27 +63,27 @@ 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 B=L[2];if(!B)console.error("Usage: anet init profile <id> --alias <名字> [--channel ...] [--env ...]"),process.exit(1);let Q=_(),z=C(),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 $={};for(let T of z._envs){let E=T.indexOf("=");if(E>0)$[T.slice(0,E)]=T.slice(E+1)}let X=z.runtime||"claude-code",Z={anet_version:"0.0.24",...z.name?{name:z.name}:{},runtime:X,alias:W,hub:N,...z.model?{model:z.model}:{},...z.tools?{tools:z.tools.split(",").map((T)=>T.trim())}:{},channels:z._channels.length>0?z._channels:X==="claude-code"?["server:commhub"]:[],env:$,flags:{dangerouslySkipPermissions:!0,...X==="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"]}:{}},Y=K(J,".claude","channels","commhub"),U=process.cwd().replace(/\//g,"-"),O=K(Y,U);if(F(O,{recursive:!0}),H(K(O,".env"),`COMMHUB_ALIAS=${W}
67
- `),m(B,Z),console.log(`
68
- ✅ Profile "${B}" saved`),console.log(` alias: ${W}`),console.log(` channels: ${Z.channels.join(", ")}`),Object.keys($).length)console.log(` env: ${Object.keys($).join(", ")}`);console.log(`
69
- Start: anet start ${B}`)}var q=null;function $z(){if(!q)q=Zz({input:process.stdin,output:process.stdout});return q}function p(){if(q)q.close(),q=null}function V(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=_();console.log(`
66
+ ✅ Project ready. Next: anet init profile <id> --alias <名字> --channel server:commhub`)}function Yz(){let B=L[2];if(!B)console.error("Usage: anet init profile <id> --alias <名字> [--channel ...] [--env ...]"),process.exit(1);let Q=_(),z=x(),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 Z={};for(let E of z._envs){let T=E.indexOf("=");if(T>0)Z[E.slice(0,T)]=E.slice(T+1)}let $=z.runtime||"claude-code",Y={anet_version:"0.0.24",...z.name?{name:z.name}:{},runtime:$,alias:W,hub:N,...z.model?{model:z.model}:{},...z.tools?{tools:z.tools.split(",").map((E)=>E.trim())}:{},channels:z._channels.length>0?z._channels:$==="claude-code"?["server:commhub"]:[],env:Z,flags:{dangerouslySkipPermissions:!0,...$==="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(H,".claude","channels","commhub"),U=process.cwd().replace(/\//g,"-"),O=K(X,U);if(F(O,{recursive:!0}),V(K(O,".env"),`COMMHUB_ALIAS=${W}
67
+ `),f(B,Y),console.log(`
68
+ ✅ Profile "${B}" saved`),console.log(` alias: ${W}`),console.log(` channels: ${Y.channels.join(", ")}`),Object.keys(Z).length)console.log(` env: ${Object.keys(Z).join(", ")}`);console.log(`
69
+ Start: anet start ${B}`)}var q=null;function $z(){if(!q)q=Zz({input:process.stdin,output:process.stdout});return q}function c(){if(q)q.close(),q=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=_();console.log(`
70
70
  Profile "${B}" not found. Let's create it:
71
- `);let z=await V("Runtime (claude-code / agent-sdk)","claude-code"),W=await V("Alias",B),N,$=[],X=[],Z="";if(z==="agent-sdk")N=await V("Model","MiniMax-M2.7"),$=(await V("Tools (comma-separated)","Read,Bash,Grep")).split(",").map((R)=>R.trim()).filter(Boolean);else X=(await V("Channels (comma-separated)","server:commhub")).split(",").map((R)=>R.trim()).filter(Boolean),Z=await V("Teammate mode","in-process");let Y=await V("Extra env (K=V, comma-separated, empty to skip)"),U={};if(Y)for(let E of Y.split(",")){let R=E.trim().indexOf("=");if(R>0)U[E.trim().slice(0,R)]=E.trim().slice(R+1)}let O=Q.hub;if(!O)console.error(`
72
- Run 'anet init' first to configure hub URL`),process.exit(1);let T={anet_version:"0.0.23",alias:W,hub:O,runtime:z,...N?{model:N}:{},...$.length?{tools:$}:{},channels:X,env:U,flags:{dangerouslySkipPermissions:!0,...Z?{teammateMode:Z}:{}}};return m(B,T),p(),console.log(`
71
+ `);let z=await J("Runtime (claude-code / agent-sdk)","claude-code"),W=await J("Alias",B),N,Z=[],$=[],Y="";if(z==="agent-sdk")N=await J("Model","MiniMax-M2.7"),Z=(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),Y=await J("Teammate mode","in-process");let X=await J("Extra env (K=V, comma-separated, empty to skip)"),U={};if(X)for(let T of X.split(",")){let I=T.trim().indexOf("=");if(I>0)U[T.trim().slice(0,I)]=T.trim().slice(I+1)}let O=Q.hub;if(!O)console.error(`
72
+ Run 'anet init' first to configure hub URL`),process.exit(1);let E={anet_version:"0.0.23",alias:W,hub:O,runtime:z,...N?{model:N}:{},...Z.length?{tools:Z}:{},channels:$,env:U,flags:{dangerouslySkipPermissions:!0,...Y?{teammateMode:Y}:{}}};return f(B,E),c(),console.log(`
73
73
  ✅ Profile "${B}" saved
74
- `),T}async function d(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 $=["@sleep2agi/agent-node","--alias",z.alias,"--hub",z.hub];if(z.model)$.push("--model",z.model);if(z.tools?.length)$.push("--tools",z.tools.join(","));if(z.flags?.maxTurns)$.push("--max-turns",String(z.flags.maxTurns));let X={...process.env};for(let[Y,U]of Object.entries(z.env))X[Y]=U.replace(/^~/,J);w("npx",$,{env:X,stdio:"inherit",shell:!0}).on("exit",(Y)=>process.exit(Y||0))}else{let $={...process.env,COMMHUB_ALIAS:z.alias};for(let[Y,U]of Object.entries(z.env))$[Y]=U.replace(/^~/,J);let X=[];if(z.flags.dangerouslySkipPermissions)X.push("--dangerously-skip-permissions");for(let Y of z.channels)if(Y.startsWith("server:"))X.push("--dangerously-load-development-channels",Y);else X.push("--channels",Y);if(z.flags.teammateMode)X.push("--teammate-mode",z.flags.teammateMode);if(Q==="resume"){let Y=z.resumeAlias||z.name||z.alias;X.push("--resume",Y)}X.push("-n",z.name||z.alias),w("claude",X,{env:$,stdio:"inherit",shell:!0}).on("exit",(Y)=>process.exit(Y||0))}}async function h(){let B=L[1];if(!B){l("start");return}await d(B,"start")}async function Uz(){let B=L[1];if(!B){l("resume");return}if(!M(B))console.log(`Profile "${B}" not found. Create one first:
74
+ `),E}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 Z=["@sleep2agi/agent-node","--alias",z.alias,"--hub",z.hub];if(z.model)Z.push("--model",z.model);if(z.tools?.length)Z.push("--tools",z.tools.join(","));if(z.flags?.maxTurns)Z.push("--max-turns",String(z.flags.maxTurns));let $={...process.env};for(let[X,U]of Object.entries(z.env))$[X]=U.replace(/^~/,H);w("npx",Z,{env:$,stdio:"inherit",shell:!0}).on("exit",(X)=>process.exit(X||0))}else{let Z={...process.env,COMMHUB_ALIAS:z.alias};for(let[X,U]of Object.entries(z.env))Z[X]=U.replace(/^~/,H);let $=[];if(z.flags.dangerouslySkipPermissions)$.push("--dangerously-skip-permissions");for(let X of z.channels)if(X.startsWith("server:"))$.push("--dangerously-load-development-channels",X);else $.push("--channels",X);if(z.flags.teammateMode)$.push("--teammate-mode",z.flags.teammateMode);if(Q==="resume"){let X=z.resumeAlias||z.name||z.alias;$.push("--resume",X)}$.push("-n",z.name||z.alias),w("claude",$,{env:Z,stdio:"inherit",shell:!0}).on("exit",(X)=>process.exit(X||0))}}async function u(){let B=L[1];if(!B){d("start");return}await p(B,"start")}async function Uz(){let B=L[1];if(!B){d("resume");return}if(!M(B))console.log(`Profile "${B}" not found. Create one first:
76
76
 
77
77
  anet start ${B}
78
- `),process.exit(1);await d(B,"resume")}function l(B){let Q=c();if(Q.length===0){console.log("No profiles. Run: anet init profile <id> --alias <名字>");return}console.log(`
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
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
81
  anet ${B} <id>
82
- `)}async function Kz(){let B=c();if(B.length>0){console.log(`
82
+ `)}async function Kz(){let B=m();if(B.length>0){console.log(`
83
83
  Profiles:
84
- `);for(let Z of B){let Y=M(Z);console.log(` ${Z}${Y?.name?` (${Y.name})`:""} → ${Y?.alias} [${Y?.channels.join(", ")}]`)}console.log()}let Q=process.cwd(),z=K(J,".claude","sessions"),W=[];if(I(z))for(let Z of f(z).filter((Y)=>Y.endsWith(".json")))try{let Y=JSON.parse(G(K(z,Z),"utf-8"));if(Y.cwd===Q)W.push(Y)}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=_(),$=[],X={};if(N.hub)try{let[Z,Y]=await Promise.all([fetch(`${N.hub}/api/status`).then((U)=>U.json()),fetch(`${N.hub}/health`).then((U)=>U.json())]);$=Z.sessions||[],X=Y.sse_sessions||{}}catch{}if(W.length>0){console.log(`Sessions (${Q}):
86
- `),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let Z of W){let Y=Z.sessionId.slice(0,18),U=!1;try{process.kill(Z.pid,0),U=!0}catch{}let O="(not in network)",T=Q.replace(/\//g,"-"),E=K(J,".claude","channels","commhub",T,".env");if(I(E)){let j=G(E,"utf-8").match(/COMMHUB_ALIAS=(.+)/);if(j){let D=j[1].trim(),P=$.find((t)=>t.alias===D),n=X[D]?"●":"○";O=P?`${D} ${P.status} ${n}`:`${D} (not registered)`}}console.log(` ${Y} ${(U?`${Z.pid}`:`${Z.pid}✕`).padEnd(7)} ${O}`)}console.log()}}async function Lz(){let B=_(),Q=C(),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(() => (y(),S)),$=new N({url:z,alias:W});$.on("task",async(X)=>{console.log(`[${W}] ← ${X.from_session}: ${X.content.slice(0,100)}`),await $.send(X.from_session,`[${W}] 收到: ${X.content.slice(0,200)}`)}),$.on("connected",()=>console.log(`[${W}] Connected`)),$.on("disconnected",()=>console.log(`[${W}] Reconnecting...`)),process.on("SIGINT",()=>$.disconnect().then(()=>process.exit(0))),console.log(`[${W}] Listening on ${z}`)}async function Tz(){if(L[1]==="start"){let Q=C(),z=Q.port||"9200",W=Q.host||"0.0.0.0",N=Q.token||"",$=[K(process.cwd(),"server","src","index.ts"),K(J,"agent-orchestra","server","src","index.ts"),K(J,"agent-network","server","src","index.ts")],X="";for(let U of $)if(I(U)){X=U;break}if(!X)try{let{execSync:U}=await import("child_process"),O=U("npm root -g",{encoding:"utf-8"}).trim(),T=K(O,"@sleep2agi","commhub-server","src","index.ts");if(I(T))X=T}catch{}if(!X)console.error("CommHub Server not found."),console.error("Install: npm install -g @sleep2agi/commhub-server"),console.error("Or clone: git clone https://github.com/sleep2agi/agent-network.git && cd agent-network/server && bun install"),process.exit(1);console.log(`[anet] Starting CommHub Server on ${W}:${z}...`);let Z={...process.env,PORT:z,HOST:W};if(N)Z.COMMHUB_AUTH_TOKEN=N;w("bun",["run",X],{env:Z,stdio:"inherit"}).on("exit",(U)=>process.exit(U||0))}else console.log(`
84
+ `);for(let Y of B){let X=M(Y);console.log(` ${Y}${X?.name?` (${X.name})`:""} → ${X?.alias} [${X?.channels.join(", ")}]`)}console.log()}let Q=process.cwd(),z=K(H,".claude","sessions"),W=[];if(R(z))for(let Y of h(z).filter((X)=>X.endsWith(".json")))try{let X=JSON.parse(G(K(z,Y),"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=_(),Z=[],$={};if(N.hub)try{let[Y,X]=await Promise.all([fetch(`${N.hub}/api/status`).then((U)=>U.json()),fetch(`${N.hub}/health`).then((U)=>U.json())]);Z=Y.sessions||[],$=X.sse_sessions||{}}catch{}if(W.length>0){console.log(`Sessions (${Q}):
86
+ `),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let Y of W){let X=Y.sessionId.slice(0,18),U=!1;try{process.kill(Y.pid,0),U=!0}catch{}let O="(not in network)",E=Q.replace(/\//g,"-"),T=K(H,".claude","channels","commhub",E,".env");if(R(T)){let j=G(T,"utf-8").match(/COMMHUB_ALIAS=(.+)/);if(j){let D=j[1].trim(),k=Z.find((l)=>l.alias===D),n=$[D]?"●":"○";O=k?`${D} ${k.status} ${n}`:`${D} (not registered)`}}console.log(` ${X} ${(U?`${Y.pid}`:`${Y.pid}✕`).padEnd(7)} ${O}`)}console.log()}}async function Lz(){let B=_(),Q=x(),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(() => (S(),v)),Z=new N({url:z,alias:W});Z.on("task",async($)=>{console.log(`[${W}] ← ${$.from_session}: ${$.content.slice(0,100)}`),await Z.send($.from_session,`[${W}] 收到: ${$.content.slice(0,200)}`)}),Z.on("connected",()=>console.log(`[${W}] Connected`)),Z.on("disconnected",()=>console.log(`[${W}] Reconnecting...`)),process.on("SIGINT",()=>Z.disconnect().then(()=>process.exit(0))),console.log(`[${W}] Listening on ${z}`)}async function Tz(){if(L[1]==="start"){let Q=x(),z=Q.port||"9200",W=Q.host||"0.0.0.0",N=Q.token||"";console.log(`[anet] Starting CommHub Server on ${W}:${z}...`);let Z={...process.env,PORT:z,HOST:W};if(N)Z.COMMHUB_AUTH_TOKEN=N;w("npx",["--yes","@sleep2agi/commhub-server"],{env:Z,stdio:"inherit",shell:!0}).on("exit",(Y)=>process.exit(Y||0))}else console.log(`
87
87
  anet server <command>
88
88
 
89
89
  start [options] Start CommHub Server
@@ -97,4 +97,4 @@ Example:
97
97
  anet server start
98
98
  anet server start --port 9200 --token my-secret
99
99
  anet server start --host 0.0.0.0 --port 9200
100
- `)}switch(A){case"init":if(L[1]==="project")Xz();else if(L[1]==="profile")Yz();else Wz();break;case"server":Tz();break;case"start":h();break;case"resume":Uz();break;case"ls":case"list":Kz();break;case"run":Lz();break;case"--help":case"-h":case void 0:u();break;default:if(M(A))L.unshift("start"),h();else console.error(`Unknown: ${A}`),u(),process.exit(1)}
100
+ `)}switch(A){case"init":if(L[1]==="project")Xz();else if(L[1]==="profile")Yz();else Wz();break;case"server":Tz();break;case"start":u();break;case"resume":Uz();break;case"ls":case"list":Kz();break;case"run":Lz();break;case"--help":case"-h":case void 0:y();break;default:if(M(A))L.unshift("start"),u();else console.error(`Unknown: ${A}`),y(),process.exit(1)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleep2agi/agent-network",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
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",