@sleep2agi/agent-network 0.0.4 → 0.0.6
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 +116 -70
- package/dist/bin/cli.js +32 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,83 +2,146 @@
|
|
|
2
2
|
|
|
3
3
|
AI Agent 通信网络 — 让 AI Agent 互相发消息、派任务、协作。
|
|
4
4
|
|
|
5
|
-
Server + Client + CLI,一个包搞定。
|
|
6
|
-
|
|
7
5
|
## 安装
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
|
-
# 全局安装(提供 anet 命令)
|
|
11
8
|
npm install -g @sleep2agi/agent-network
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 30 秒上手
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# 1. 配 hub(全局,一次性)
|
|
15
|
+
anet init
|
|
16
|
+
|
|
17
|
+
# 2. 配项目(下载 channel 插件 + 配 MCP)
|
|
18
|
+
anet init project
|
|
12
19
|
|
|
13
|
-
#
|
|
14
|
-
|
|
20
|
+
# 3. 创建 profile(保存启动参数)
|
|
21
|
+
anet init profile commander --alias 指挥室 --channel server:commhub
|
|
22
|
+
|
|
23
|
+
# 4. 启动
|
|
24
|
+
anet start commander
|
|
25
|
+
|
|
26
|
+
# 5. 查看状态
|
|
27
|
+
anet ls
|
|
15
28
|
```
|
|
16
29
|
|
|
17
|
-
##
|
|
30
|
+
## 为什么需要 Profile?
|
|
18
31
|
|
|
19
|
-
|
|
32
|
+
Claude Code 启动参数可以非常长:
|
|
20
33
|
|
|
21
34
|
```bash
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
35
|
+
COMMHUB_ALIAS="指挥室" TELEGRAM_STATE_DIR=~/.claude/channels/telegram-vincent \
|
|
36
|
+
claude --dangerously-skip-permissions \
|
|
37
|
+
--channels plugin:telegram@claude-plugins-official \
|
|
38
|
+
--dangerously-load-development-channels server:commhub \
|
|
39
|
+
--teammate-mode in-process --resume 98039093-...
|
|
26
40
|
```
|
|
27
41
|
|
|
28
|
-
|
|
42
|
+
Profile 把这些参数存到 JSON,以后只需:**`anet start commander`**
|
|
43
|
+
|
|
44
|
+
同一目录可以有多个 profile(指挥室、通信龙、SDK马)。
|
|
45
|
+
|
|
46
|
+
## CLI 命令
|
|
47
|
+
|
|
48
|
+
### anet init
|
|
49
|
+
|
|
50
|
+
三级初始化:
|
|
29
51
|
|
|
30
52
|
```bash
|
|
31
|
-
|
|
32
|
-
anet
|
|
53
|
+
anet init # → ~/.anet/config.json(hub URL)
|
|
54
|
+
anet init project # → 下载 channel 插件 + 配 MCP + .env
|
|
55
|
+
anet init profile <id> [options] # → .anet/profiles/<id>.json
|
|
33
56
|
```
|
|
34
57
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
58
|
+
配置文件位置:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
~/.anet/config.json 全局(hub URL)
|
|
62
|
+
{workpath}/.anet/profiles/cmd.json 项目 profile
|
|
63
|
+
```
|
|
40
64
|
|
|
41
|
-
|
|
65
|
+
#### anet init
|
|
42
66
|
|
|
43
|
-
|
|
44
|
-
# 自动从 .anet/config.json 读取配置
|
|
45
|
-
anet run
|
|
67
|
+
交互式输入 hub URL,测试连接,保存到 `~/.anet/config.json`。
|
|
46
68
|
|
|
47
|
-
|
|
48
|
-
anet
|
|
69
|
+
```bash
|
|
70
|
+
anet init
|
|
71
|
+
# CommHub URL: http://YOUR_IP:9200
|
|
72
|
+
# ✅ CommHub v0.4.1 — 26 sessions, 18 SSE
|
|
49
73
|
```
|
|
50
74
|
|
|
51
|
-
|
|
75
|
+
或直接传参:`anet init --hub http://YOUR_IP:9200`
|
|
52
76
|
|
|
53
|
-
|
|
77
|
+
#### anet init project
|
|
78
|
+
|
|
79
|
+
下载 Channel 插件 + 安装依赖 + 配 `~/.claude.json` + 写 .env。
|
|
54
80
|
|
|
81
|
+
```bash
|
|
82
|
+
cd ~/my-project
|
|
83
|
+
anet init project
|
|
55
84
|
```
|
|
56
|
-
|
|
57
|
-
anet
|
|
58
|
-
|
|
59
|
-
|
|
85
|
+
|
|
86
|
+
#### anet init profile
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
anet init profile <id> --alias <别名> [options]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
| 参数 | 说明 |
|
|
93
|
+
|------|------|
|
|
94
|
+
| `<id>` | Profile ID(英文,作为文件名) |
|
|
95
|
+
| `--alias` | CommHub session 别名 |
|
|
96
|
+
| `--name` | 显示名 |
|
|
97
|
+
| `--channel` | 添加 channel(可重复) |
|
|
98
|
+
| `--env` | 环境变量 K=V(可重复) |
|
|
99
|
+
| `--resume` | Session resume ID |
|
|
100
|
+
| `--teammate-mode` | 如 in-process |
|
|
101
|
+
|
|
102
|
+
示例:
|
|
103
|
+
```bash
|
|
104
|
+
# 带 Telegram 双 channel
|
|
105
|
+
anet init profile commander --alias 指挥室 \
|
|
106
|
+
--channel server:commhub \
|
|
107
|
+
--channel plugin:telegram@claude-plugins-official \
|
|
108
|
+
--env TELEGRAM_STATE_DIR=~/.claude/channels/telegram-vincent \
|
|
109
|
+
--teammate-mode in-process
|
|
110
|
+
|
|
111
|
+
# 简单 agent
|
|
112
|
+
anet init profile worker --alias 开发马 --channel server:commhub
|
|
60
113
|
```
|
|
61
114
|
|
|
62
|
-
### anet
|
|
115
|
+
### anet start
|
|
63
116
|
|
|
64
117
|
```bash
|
|
65
|
-
anet
|
|
118
|
+
anet start commander # 启动指定 profile
|
|
119
|
+
anet start # 列出所有 profile
|
|
120
|
+
anet commander # 快捷方式(等于 anet start commander)
|
|
66
121
|
```
|
|
67
122
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
123
|
+
### anet ls
|
|
124
|
+
|
|
125
|
+
显示当前目录的 sessions + 网络状态:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Profiles:
|
|
129
|
+
commander (指挥室) → 指挥室 [server:commhub, plugin:telegram]
|
|
130
|
+
|
|
131
|
+
Sessions (/home/vansin/agent-orchestra/channel):
|
|
132
|
+
SESSION PID NETWORK
|
|
133
|
+
──────────────────── ─────── ─────────────────────
|
|
134
|
+
fef0eb55-b39c-4abc 64269 通信龙 offline ●
|
|
135
|
+
```
|
|
73
136
|
|
|
74
137
|
### anet run
|
|
75
138
|
|
|
139
|
+
独立 SSE Agent(不需要 Claude Code):
|
|
140
|
+
|
|
76
141
|
```bash
|
|
77
|
-
anet run
|
|
142
|
+
anet run --alias SDK马 --hub http://YOUR_IP:9200
|
|
78
143
|
```
|
|
79
144
|
|
|
80
|
-
参数自动从 `.anet/config.json` 读取,setup 过的项目直接 `anet run` 即可。
|
|
81
|
-
|
|
82
145
|
## SDK 代码引用
|
|
83
146
|
|
|
84
147
|
```typescript
|
|
@@ -90,7 +153,6 @@ const hub = new CommHub({
|
|
|
90
153
|
});
|
|
91
154
|
|
|
92
155
|
hub.on('task', async (msg) => {
|
|
93
|
-
console.log(`来自 ${msg.from_session}: ${msg.content}`);
|
|
94
156
|
await hub.send(msg.from_session, '任务完成!');
|
|
95
157
|
});
|
|
96
158
|
```
|
|
@@ -98,8 +160,6 @@ hub.on('task', async (msg) => {
|
|
|
98
160
|
```javascript
|
|
99
161
|
// CommonJS
|
|
100
162
|
const { CommHub } = require('@sleep2agi/agent-network');
|
|
101
|
-
const hub = new CommHub({ url: 'http://YOUR_COMMHUB_IP:9200', alias: '我的Agent' });
|
|
102
|
-
hub.on('task', (msg) => console.log(msg));
|
|
103
163
|
```
|
|
104
164
|
|
|
105
165
|
### SDK API
|
|
@@ -107,49 +167,35 @@ hub.on('task', (msg) => console.log(msg));
|
|
|
107
167
|
| 方法 | 说明 |
|
|
108
168
|
|------|------|
|
|
109
169
|
| `hub.send(alias, content, priority?)` | 发任务 |
|
|
110
|
-
| `hub.message(alias, content)` |
|
|
170
|
+
| `hub.message(alias, content)` | 发消息 |
|
|
111
171
|
| `hub.reply(taskId, text, status?)` | 回复任务 |
|
|
112
172
|
| `hub.status(state, extra?)` | 更新状态 |
|
|
113
173
|
| `hub.broadcast(content, filter?)` | 广播 |
|
|
114
174
|
| `hub.disconnect()` | 断开 |
|
|
115
175
|
|
|
116
|
-
### 事件
|
|
117
|
-
|
|
118
176
|
| 事件 | 说明 |
|
|
119
177
|
|------|------|
|
|
120
178
|
| `task` | 收到任务(已自动 ACK) |
|
|
121
179
|
| `connected` | SSE 连接成功 |
|
|
122
180
|
| `disconnected` | SSE 断开(自动重连) |
|
|
123
|
-
| `error` | 错误 |
|
|
124
|
-
|
|
125
|
-
## 配置文件
|
|
126
|
-
|
|
127
|
-
优先级:环境变量 > 命令行参数 > 项目 `.anet/config.json` > 全局 `~/.anet/config.json`
|
|
128
|
-
|
|
129
|
-
**全局** `~/.anet/config.json`:
|
|
130
|
-
```json
|
|
131
|
-
{ "hub": "http://YOUR_COMMHUB_IP:9200", "token": "your-token" }
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
**项目** `.anet/config.json`:
|
|
135
|
-
```json
|
|
136
|
-
{ "alias": "我的Agent", "type": "claude-code" }
|
|
137
|
-
```
|
|
138
181
|
|
|
139
182
|
## 运行时要求
|
|
140
183
|
|
|
141
184
|
| 组件 | 运行时 |
|
|
142
185
|
|------|--------|
|
|
143
|
-
| anet
|
|
144
|
-
|
|
|
186
|
+
| anet CLI / SDK | Node.js 18+ 或 Bun |
|
|
187
|
+
| CommHub Server | Bun 1.2+(单独部署) |
|
|
145
188
|
|
|
146
|
-
##
|
|
189
|
+
## 版本历史
|
|
147
190
|
|
|
148
|
-
|
|
|
149
|
-
|
|
150
|
-
|
|
|
151
|
-
|
|
|
152
|
-
|
|
|
191
|
+
| 版本 | 变更 |
|
|
192
|
+
|------|------|
|
|
193
|
+
| 0.0.6 | 三级 init(全局/项目/profile),`anet ls` 简化为当前目录 |
|
|
194
|
+
| 0.0.5 | `anet ls` 显示本地 sessions + CommHub 网络状态 |
|
|
195
|
+
| 0.0.4 | CLI 瘦身 580KB→13KB,Node.js 兼容,profile 系统 |
|
|
196
|
+
| 0.0.3 | `anet setup` 一键配置 Channel 插件 |
|
|
197
|
+
| 0.0.2 | CLI shebang 改为 node |
|
|
198
|
+
| 0.0.1 | 首次发布 |
|
|
153
199
|
|
|
154
200
|
## License
|
|
155
201
|
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,51 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var h=Object.defineProperty;var
|
|
3
|
-
`);
|
|
4
|
-
`)}function
|
|
2
|
+
import{createRequire as d}from"node:module";var h=Object.defineProperty;var g=(Q)=>Q;function m(Q,z){this[Q]=g.bind(null,z)}var p=(Q,z)=>{for(var V in z)h(Q,V,{get:z[V],enumerable:!0,configurable:!0,set:m.bind(z,V)})};var c=(Q,z)=>()=>(Q&&(z=Q(Q=0)),z);var t=d(import.meta.url);var D={};p(D,{default:()=>n,CommHub:()=>H});import{EventEmitter as l}from"events";import{hostname as x}from"os";var H,n;var P=c(()=>{H=class H extends l{url;alias;token;agent;resumeId;heartbeatInterval;reconnectDelay;heartbeatTimer;sseAbort;running=!1;constructor(Q){super();if(this.url=Q.url.replace(/\/$/,""),this.alias=Q.alias,this.token=Q.token,this.agent=Q.agent||"sdk",this.resumeId=`sdk-${Q.alias}-${Date.now().toString(36)}`,this.heartbeatInterval=Q.heartbeatInterval??180000,this.reconnectDelay=Q.reconnectDelay??3000,Q.autoConnect!==!1)this.connect()}log(Q){console.log(`[${new Date().toTimeString().slice(0,8)}] [commhub:${this.alias}] ${Q}`)}async call(Q,z){let V={"Content-Type":"application/json"};if(this.token)V.Authorization=`Bearer ${this.token}`;let $=await(await fetch(`${this.url}/mcp`,{method:"POST",headers:V,body:JSON.stringify({jsonrpc:"2.0",id:Date.now(),method:"tools/call",params:{name:Q,arguments:z}})})).json(),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((Q)=>this.log(`heartbeat failed: ${Q.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(Q,z,V="normal"){return this.call("send_task",{alias:Q,task:z,priority:V,from_session:this.alias})}async message(Q,z){return this.call("send_message",{alias:Q,message:z,from_session:this.alias})}async reply(Q,z,V="completed"){return this.call("reply",{task_id:Q,text:z,status:V})}async status(Q,z){return this.call("report_status",{resume_id:this.resumeId,alias:this.alias,status:Q,server:x(),hostname:x(),agent:this.agent,project_dir:process.cwd(),...z})}async getAllStatus(){return this.call("get_all_status",{})}async broadcast(Q,z){return this.call("broadcast",{message:Q,filter_server:z?.server,filter_status:z?.status})}async connectSSE(){let Q=encodeURIComponent(this.alias),z=`${this.url}/events/${Q}`,V=this.reconnectDelay;while(this.running){try{this.sseAbort=new AbortController;let X={Accept:"text/event-stream"};if(this.token)X.Authorization=`Bearer ${this.token}`;let $=await fetch(z,{headers:X,signal:this.sseAbort.signal});if(!$.ok||!$.body){this.log(`SSE failed: ${$.status}`),await this.sleep(V),V=Math.min(V*1.5,60000);continue}V=this.reconnectDelay;let Y=$.body.getReader(),N=new TextDecoder,Z="";while(this.running){let{done:L,value:U}=await Y.read();if(L)break;Z+=N.decode(U,{stream:!0});let _=Z.split(`
|
|
3
|
+
`);Z=_.pop()||"";for(let B of _){if(!B.startsWith("data: "))continue;try{let O=JSON.parse(B.slice(6));if(O.type==="connected"){this.log("SSE connected"),this.emit("connected");continue}if(O.type==="new_task"||O.type==="new_message"||O.type==="broadcast")await this.processInbox()}catch{}}}}catch(X){if(X.name==="AbortError")break;this.emit("error",X),this.log(`SSE error: ${X.message}`)}if(this.running)this.emit("disconnected"),this.log(`SSE reconnecting in ${V/1000}s...`),await this.sleep(V),V=Math.min(V*1.5,60000)}}async processInbox(){try{let z=(await this.call("get_inbox",{alias:this.alias,limit:10}))?.messages||[];for(let V of z)await this.call("ack_inbox",{alias:this.alias,message_id:V.id}),this.log(`← ${V.from_session}: ${V.content.slice(0,60)}`),this.emit("task",V),this.emit("message",V)}catch(Q){this.log(`inbox error: ${Q.message}`)}}sleep(Q){return new Promise((z)=>setTimeout(z,Q))}};n=H});import{readFileSync as I,writeFileSync as E,existsSync as q,mkdirSync as J,readdirSync as v}from"fs";import{join as R}from"path";import{spawn as o}from"child_process";var W=process.argv.slice(2),A=W[0],K=process.env.HOME||process.env.USERPROFILE||"~";function S(){return R(K,".anet","config.json")}function C(){return R(process.cwd(),".anet","profiles")}function M(){let Q=S();if(q(Q))try{return JSON.parse(I(Q,"utf-8"))}catch{}return{}}function r(Q){let z=R(K,".anet");J(z,{recursive:!0}),E(R(z,"config.json"),JSON.stringify(Q,null,2)+`
|
|
4
|
+
`)}function G(Q){let z=R(C(),`${Q}.json`);if(q(z))try{return JSON.parse(I(z,"utf-8"))}catch{}return null}function a(Q,z){let V=C();J(V,{recursive:!0}),E(R(V,`${Q}.json`),JSON.stringify(z,null,2)+`
|
|
5
|
+
`)}function y(){let Q=C();if(!q(Q))return[];return v(Q).filter((z)=>z.endsWith(".json")).map((z)=>z.replace(/\.json$/,""))}function F(){let Q={_channels:[],_envs:[]};for(let z=0;z<W.length;z++){if(W[z]==="--channel"&&W[z+1]){Q._channels.push(W[++z]);continue}if(W[z]==="--env"&&W[z+1]){Q._envs.push(W[++z]);continue}if(W[z].startsWith("--")&&W[z+1]&&!W[z+1].startsWith("--"))Q[W[z].slice(2)]=W[++z]}return Q}function j(){console.log(`
|
|
5
6
|
anet — AI Agent Network CLI
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
anet init Configure hub URL (global, once)
|
|
9
|
+
anet init project Setup current project (channel plugin + config)
|
|
10
|
+
anet init profile <id> Create a launch profile
|
|
11
|
+
anet start <id> Start Claude Code with profile
|
|
12
|
+
anet ls Show sessions + network status
|
|
13
|
+
anet run Run standalone SSE agent
|
|
14
|
+
anet --help This help
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
anet
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
--env TELEGRAM_STATE_DIR=~/.claude/channels/telegram-vincent
|
|
33
|
-
|
|
34
|
-
anet start commander
|
|
35
|
-
anet list
|
|
36
|
-
`)}async function l(){let z=C(),B=k(),L=z.profile,Q=z.name,R=z.alias,W=z.hub||B.hub,V=z.type||"claude-code",X=z.resume,Z=z["teammate-mode"];if(!L||!R)console.error("Error: --profile and --alias are required"),console.error("Usage: anet setup --profile hub-01 --name 指挥室 --alias 指挥室 --hub http://YOUR_IP:9200 --channel server:commhub"),process.exit(1);if(!W)console.error("Error: --hub is required (first time) or set in ~/.anet/config.json"),process.exit(1);let $={};for(let T of z._envs){let j=T.indexOf("=");if(j>0)$[T.slice(0,j)]=T.slice(j+1)}let q={...Q?{name:Q}:{},alias:R,hub:W,channels:z._channels.length>0?z._channels:["server:commhub"],env:$,flags:{dangerouslySkipPermissions:!0,...Z?{teammateMode:Z}:{}},...X?{resume:X}:{}},J=G(E,".anet");K(J,{recursive:!0});let O=k();if(O.hub=W,_(S(),JSON.stringify(O,null,2)+`
|
|
37
|
-
`),o(L,q),console.log(`
|
|
38
|
-
✅ Profile "${L}" saved to .anet/profiles/${L}.json`),V==="claude-code")await i(W,R);let y=b(q);console.log(`
|
|
39
|
-
启动命令 (anet start ${L}):
|
|
40
|
-
${y}
|
|
41
|
-
`)}async function i(z,B){let L=`${E}/.claude/channels/commhub`;K(L,{recursive:!0});let Q=`${L}/server.ts`;if(!I(Q)){console.log("Downloading Channel plugin...");try{let $=await fetch("https://raw.githubusercontent.com/sleep2agi/agent-comm-hub/main/channel/server.ts");if($.ok)_(Q,await $.text()),console.log(` ✅ ${Q}`)}catch{}try{let $=await fetch("https://raw.githubusercontent.com/sleep2agi/agent-comm-hub/main/channel/package.json");if($.ok){_(`${L}/package.json`,await $.text());try{n("bun install",{cwd:L,stdio:"pipe"})}catch{}}}catch{}}let R=`${L}/.env`;if(!I(R))_(R,`COMMHUB_URL=${z}
|
|
42
|
-
`);let W=process.cwd().replace(/\//g,"-"),V=`${L}/${W}`;K(V,{recursive:!0}),_(`${V}/.env`,`COMMHUB_ALIAS=${B}
|
|
43
|
-
`);let X=`${E}/.claude.json`,Z={};if(I(X))try{Z=JSON.parse(N(X,"utf-8"))}catch{}if(!Z.mcpServers?.commhub)Z.mcpServers=Z.mcpServers||{},Z.mcpServers.commhub={type:"stdio",command:"bun",args:["run",Q]},_(X,JSON.stringify(Z,null,2)+`
|
|
44
|
-
`)}function b(z){let B=[];B.push(`COMMHUB_ALIAS="${z.alias}"`);for(let[L,Q]of Object.entries(z.env))B.push(`${L}=${Q}`);if(B.push("claude"),z.flags.dangerouslySkipPermissions)B.push("--dangerously-skip-permissions");for(let L of z.channels)if(L.startsWith("server:"))B.push(`--dangerously-load-development-channels ${L}`);else B.push(`--channels ${L}`);if(z.flags.teammateMode)B.push(`--teammate-mode ${z.flags.teammateMode}`);if(z.resume)B.push(`--resume ${z.resume}`);return B.join(" ")}function v(){let z=Y[1];if(!z){let V=F();if(V.length===0)console.log("No profiles found. Create one with: anet setup --profile <name> --alias <alias> --hub <url>"),process.exit(1);console.log(`
|
|
45
|
-
Available profiles:
|
|
46
|
-
`);for(let X of V){let Z=M(X);console.log(` ${X} → alias: ${Z?.alias}, channels: ${Z?.channels.join(", ")}`)}console.log(`
|
|
47
|
-
Start with: anet start <profile>
|
|
48
|
-
`);return}let B=M(z);if(!B)console.error(`Profile "${z}" not found in .anet/profiles/`),console.error(`Available: ${F().join(", ")||"(none)"}`),process.exit(1);let L=b(B);console.log(`[anet] Starting "${z}"...`),console.log(`[anet] ${L}
|
|
49
|
-
`);let Q={...process.env,COMMHUB_ALIAS:B.alias};for(let[V,X]of Object.entries(B.env))Q[V]=X.replace(/^~/,E);let R=[];if(B.flags.dangerouslySkipPermissions)R.push("--dangerously-skip-permissions");for(let V of B.channels)if(V.startsWith("server:"))R.push("--dangerously-load-development-channels",V);else R.push("--channels",V);if(B.flags.teammateMode)R.push("--teammate-mode",B.flags.teammateMode);if(B.resume)R.push("--resume",B.resume);t("claude",R,{env:Q,stdio:"inherit",shell:!0}).on("exit",(V)=>process.exit(V||0))}function s(){let z=F();if(z.length===0){console.log("No profiles. Create one: anet setup --profile <name> --alias <alias> --hub <url>");return}console.log(`
|
|
16
|
+
Quick start:
|
|
17
|
+
anet init
|
|
18
|
+
anet init project
|
|
19
|
+
anet init profile cmd --alias 指挥室 --channel server:commhub
|
|
20
|
+
anet start cmd
|
|
21
|
+
`)}async function i(){let Q=F(),z=Q.hub;if(!z)process.stdout.write("CommHub URL (e.g. http://YOUR_IP:9200): "),z=await new Promise((X)=>{let $="";process.stdin.setEncoding("utf-8"),process.stdin.once("data",(Y)=>{X(Y.toString().trim())})});if(!z)console.error("Error: hub URL required"),process.exit(1);try{let $=await(await fetch(`${z}/health`)).json();console.log(`✅ CommHub v${$.version} — ${$.sessions} sessions, ${$.sse_connections} SSE`)}catch(X){console.error(`❌ Cannot reach ${z}: ${X.message}`),process.exit(1)}let V=M();if(V.hub=z,Q.token)V.token=Q.token;r(V),console.log(`
|
|
22
|
+
Saved to ${S()}`),console.log("Next: anet init project")}async function e(){let z=M().hub;if(!z)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let V=R(K,".claude","channels","commhub");J(V,{recursive:!0});let X=R(V,"server.ts");if(!q(X)){console.log("Downloading Channel plugin...");try{let L=await fetch("https://raw.githubusercontent.com/sleep2agi/agent-comm-hub/main/channel/server.ts");if(L.ok)E(X,await L.text()),console.log(` ✅ ${X}`)}catch(L){console.log(` ❌ Failed: ${L.message}`),console.log(` Manual: curl -sL https://raw.githubusercontent.com/sleep2agi/agent-comm-hub/main/channel/server.ts -o ${X}`)}}else console.log("Channel plugin: exists");let $=R(V,"package.json");if(!q($))try{let L=await fetch("https://raw.githubusercontent.com/sleep2agi/agent-comm-hub/main/channel/package.json");if(L.ok){E($,await L.text());try{let{execSync:U}=await import("child_process");U("bun install",{cwd:V,stdio:"pipe"}),console.log("Dependencies installed")}catch{console.log("⚠️ Run: cd ~/.claude/channels/commhub && bun install")}}}catch{}let Y=R(V,".env");if(!q(Y))E(Y,`COMMHUB_URL=${z}
|
|
23
|
+
`);console.log(`CommHub URL: ${z}`);let N=R(K,".claude.json"),Z={};if(q(N))try{Z=JSON.parse(I(N,"utf-8"))}catch{}if(!Z.mcpServers?.commhub)Z.mcpServers=Z.mcpServers||{},Z.mcpServers.commhub={type:"stdio",command:"bun",args:["run",X]},E(N,JSON.stringify(Z,null,2)+`
|
|
24
|
+
`),console.log(`MCP config: ${N}`);else console.log("MCP config: already set");console.log(`
|
|
25
|
+
✅ Project ready. Next: anet init profile <id> --alias <名字> --channel server:commhub`)}function s(){let Q=W[2];if(!Q)console.error("Usage: anet init profile <id> --alias <名字> [--channel ...] [--env ...]"),process.exit(1);let z=M(),V=F(),X=V.alias||Q,$=V.hub||z.hub;if(!$)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let Y={};for(let _ of V._envs){let B=_.indexOf("=");if(B>0)Y[_.slice(0,B)]=_.slice(B+1)}let N={...V.name?{name:V.name}:{},alias:X,hub:$,channels:V._channels.length>0?V._channels:["server:commhub"],env:Y,flags:{dangerouslySkipPermissions:!0,...V["teammate-mode"]?{teammateMode:V["teammate-mode"]}:{}},...V.resume?{resume:V.resume}:{}},Z=R(K,".claude","channels","commhub"),L=process.cwd().replace(/\//g,"-"),U=R(Z,L);if(J(U,{recursive:!0}),E(R(U,".env"),`COMMHUB_ALIAS=${X}
|
|
26
|
+
`),a(Q,N),console.log(`
|
|
27
|
+
✅ Profile "${Q}" saved`),console.log(` alias: ${X}`),console.log(` channels: ${N.channels.join(", ")}`),Object.keys(Y).length)console.log(` env: ${Object.keys(Y).join(", ")}`);console.log(`
|
|
28
|
+
Start: anet start ${Q}`)}function b(){let Q=W[1];if(!Q){let Y=y();if(Y.length===0){console.log("No profiles. Run: anet init profile <id> --alias <名字>");return}console.log(`
|
|
29
|
+
Profiles:
|
|
30
|
+
`);for(let N of Y){let Z=G(N);console.log(` ${N}${Z?.name?` (${Z.name})`:""} → ${Z?.alias} [${Z?.channels.join(", ")}]`)}console.log(`
|
|
31
|
+
anet start <id>
|
|
32
|
+
`);return}let z=G(Q);if(!z)console.error(`Profile "${Q}" not found. Run: anet ls`),process.exit(1);let V={...process.env,COMMHUB_ALIAS:z.alias};for(let[Y,N]of Object.entries(z.env))V[Y]=N.replace(/^~/,K);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(z.resume)X.push("--resume",z.resume);X.push("-n",z.name||z.alias),console.log(`[anet] Starting "${Q}" (${z.alias})...
|
|
33
|
+
`),o("claude",X,{env:V,stdio:"inherit",shell:!0}).on("exit",(Y)=>process.exit(Y||0))}async function zz(){let Q=y();if(Q.length>0){console.log(`
|
|
50
34
|
Profiles:
|
|
51
|
-
`);for(let
|
|
35
|
+
`);for(let Z of Q){let L=G(Z);console.log(` ${Z}${L?.name?` (${L.name})`:""} → ${L?.alias} [${L?.channels.join(", ")}]`)}console.log()}let z=process.cwd(),V=R(K,".claude","sessions"),X=[];if(q(V))for(let Z of v(V).filter((L)=>L.endsWith(".json")))try{let L=JSON.parse(I(R(V,Z),"utf-8"));if(L.cwd===z)X.push(L)}catch{}if(X.length===0&&Q.length===0){console.log("No sessions or profiles in this directory."),console.log(`Get started: anet init
|
|
36
|
+
`);return}let $=M(),Y=[],N={};if($.hub)try{let[Z,L]=await Promise.all([fetch(`${$.hub}/api/status`).then((U)=>U.json()),fetch(`${$.hub}/health`).then((U)=>U.json())]);Y=Z.sessions||[],N=L.sse_sessions||{}}catch{}if(X.length>0){console.log(`Sessions (${z}):
|
|
37
|
+
`),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let Z of X){let L=Z.sessionId.slice(0,18),U=!1;try{process.kill(Z.pid,0),U=!0}catch{}let _="(not in network)",B=z.replace(/\//g,"-"),O=R(K,".claude","channels","commhub",B,".env");if(q(O)){let k=I(O,"utf-8").match(/COMMHUB_ALIAS=(.+)/);if(k){let T=k[1].trim(),w=Y.find((f)=>f.alias===T),u=N[T]?"●":"○";_=w?`${T} ${w.status} ${u}`:`${T} (not registered)`}}console.log(` ${L} ${(U?`${Z.pid}`:`${Z.pid}✕`).padEnd(7)} ${_}`)}console.log()}}async function Qz(){let Q=M(),z=F(),V=process.env.COMMHUB_URL||z.hub||Q.hub||"http://127.0.0.1:9200",X=process.env.COMMHUB_ALIAS||z.alias;if(!X)console.error("Error: --alias required"),process.exit(1);let{CommHub:$}=await Promise.resolve().then(() => (P(),D)),Y=new $({url:V,alias:X});Y.on("task",async(N)=>{console.log(`[${X}] ← ${N.from_session}: ${N.content.slice(0,100)}`),await Y.send(N.from_session,`[${X}] 收到: ${N.content.slice(0,200)}`)}),Y.on("connected",()=>console.log(`[${X}] Connected`)),Y.on("disconnected",()=>console.log(`[${X}] Reconnecting...`)),process.on("SIGINT",()=>Y.disconnect().then(()=>process.exit(0))),console.log(`[${X}] Listening on ${V}`)}switch(A){case"init":if(W[1]==="project")e();else if(W[1]==="profile")s();else i();break;case"start":b();break;case"ls":case"list":zz();break;case"run":Qz();break;case"--help":case"-h":case void 0:j();break;default:if(G(A))W.unshift("start"),b();else console.error(`Unknown: ${A}`),j(),process.exit(1)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleep2agi/agent-network",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
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",
|