@sleep2agi/agent-network 0.0.13 → 0.0.14
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/dist/bin/cli.js +55 -17
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{createRequire as n}from"node:module";var m=Object.defineProperty;var c=(z)=>z;function p(z,B){this[z]=c.bind(null,B)}var d=(z,B)=>{for(var Q in B)m(z,Q,{get:B[Q],enumerable:!0,configurable:!0,set:p.bind(B,Q)})};var l=(z,B)=>()=>(z&&(B=z(z=0)),B);var t=n(import.meta.url);var
|
|
3
|
-
`);W=R.pop()||"";for(let
|
|
4
|
-
`)}function
|
|
5
|
-
`)}function y(){let z=
|
|
2
|
+
import{createRequire as n}from"node:module";var m=Object.defineProperty;var c=(z)=>z;function p(z,B){this[z]=c.bind(null,B)}var d=(z,B)=>{for(var Q in B)m(z,Q,{get:B[Q],enumerable:!0,configurable:!0,set:p.bind(B,Q)})};var l=(z,B)=>()=>(z&&(B=z(z=0)),B);var t=n(import.meta.url);var C={};d(C,{default:()=>o,CommHub:()=>H});import{EventEmitter as r}from"events";import{hostname as w}from"os";var H,o;var j=l(()=>{H=class H extends r{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,B){let Q={"Content-Type":"application/json"};if(this.token)Q.Authorization=`Bearer ${this.token}`;let X=await(await fetch(`${this.url}/mcp`,{method:"POST",headers:Q,body:JSON.stringify({jsonrpc:"2.0",id:Date.now(),method:"tools/call",params:{name:z,arguments:B}})})).json(),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((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,B,Q="normal"){return this.call("send_task",{alias:z,task:B,priority:Q,from_session:this.alias})}async message(z,B){return this.call("send_message",{alias:z,message:B,from_session:this.alias})}async reply(z,B,Q="completed"){return this.call("reply",{task_id:z,text:B,status:Q})}async status(z,B){return this.call("report_status",{resume_id:this.resumeId,alias:this.alias,status:z,server:w(),hostname:w(),agent:this.agent,project_dir:process.cwd(),...B})}async getAllStatus(){return this.call("get_all_status",{})}async broadcast(z,B){return this.call("broadcast",{message:z,filter_server:B?.server,filter_status:B?.status})}async connectSSE(){let z=encodeURIComponent(this.alias),B=`${this.url}/events/${z}`,Q=this.reconnectDelay;while(this.running){try{this.sseAbort=new AbortController;let V={Accept:"text/event-stream"};if(this.token)V.Authorization=`Bearer ${this.token}`;let X=await fetch(B,{headers:V,signal:this.sseAbort.signal});if(!X.ok||!X.body){this.log(`SSE failed: ${X.status}`),await this.sleep(Q),Q=Math.min(Q*1.5,60000);continue}Q=this.reconnectDelay;let Z=X.body.getReader(),U=new TextDecoder,W="";while(this.running){let{done:Y,value:$}=await Z.read();if(Y)break;W+=U.decode($,{stream:!0});let R=W.split(`
|
|
3
|
+
`);W=R.pop()||"";for(let q of R){if(!q.startsWith("data: "))continue;try{let T=JSON.parse(q.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(V){if(V.name==="AbortError")break;this.emit("error",V),this.log(`SSE error: ${V.message}`)}if(this.running)this.emit("disconnected"),this.log(`SSE reconnecting in ${Q/1000}s...`),await this.sleep(Q),Q=Math.min(Q*1.5,60000)}}async processInbox(){try{let B=(await this.call("get_inbox",{alias:this.alias,limit:10}))?.messages||[];for(let Q of B)await this.call("ack_inbox",{alias:this.alias,message_id:Q.id}),this.log(`← ${Q.from_session}: ${Q.content.slice(0,60)}`),this.emit("task",Q),this.emit("message",Q)}catch(z){this.log(`inbox error: ${z.message}`)}}sleep(z){return new Promise((B)=>setTimeout(B,z))}};o=H});import{readFileSync as E,writeFileSync as K,existsSync as _,mkdirSync as G,readdirSync as b}from"fs";import{join as N}from"path";import{spawn as a}from"child_process";var L=process.argv.slice(2),A=L[0],O=process.env.HOME||process.env.USERPROFILE||"~";function S(){return N(O,".anet","config.json")}function k(){return N(process.cwd(),".anet","profiles")}function I(){let z=S();if(_(z))try{return JSON.parse(E(z,"utf-8"))}catch{}return{}}function i(z){let B=N(O,".anet");G(B,{recursive:!0}),K(N(B,"config.json"),JSON.stringify(z,null,2)+`
|
|
4
|
+
`)}function M(z){let B=N(k(),`${z}.json`);if(_(B))try{return JSON.parse(E(B,"utf-8"))}catch{}return null}function e(z,B){let Q=k();G(Q,{recursive:!0}),K(N(Q,`${z}.json`),JSON.stringify(B,null,2)+`
|
|
5
|
+
`)}function y(){let z=k();if(!_(z))return[];return b(z).filter((B)=>B.endsWith(".json")).map((B)=>B.replace(/\.json$/,""))}function F(){let z={_channels:[],_envs:[]};for(let B=0;B<L.length;B++){if(L[B]==="--channel"&&L[B+1]){z._channels.push(L[++B]);continue}if(L[B]==="--env"&&L[B+1]){z._envs.push(L[++B]);continue}if(L[B].startsWith("--")&&L[B+1]&&!L[B+1].startsWith("--"))z[L[B].slice(2)]=L[++B]}return z}function P(){console.log(`
|
|
6
6
|
anet — AI Agent Network CLI
|
|
7
7
|
|
|
8
8
|
anet init Configure hub URL (global, once)
|
|
@@ -20,20 +20,58 @@ Quick start:
|
|
|
20
20
|
anet init profile 指挥室 --alias 指挥室 --channel server:commhub
|
|
21
21
|
anet start 指挥室 # 新建
|
|
22
22
|
anet resume 指挥室 # 下次恢复
|
|
23
|
-
`)}async function s(){let z=
|
|
24
|
-
Saved to ${S()}`),console.log("Next: anet init project")}async function zz(){let B=I().hub;if(!B)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let Q=N(process.cwd(),".anet");
|
|
25
|
-
`),console.log(`CommHub URL: ${B}`);let
|
|
26
|
-
`),console.log(".mcp.json: commhub → .anet/server.ts");else console.log(".mcp.json: commhub already set");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
`)}async function s(){let z=F(),B=z.hub;if(!B)process.stdout.write("CommHub URL (e.g. http://YOUR_IP:9200): "),B=await new Promise((V)=>{process.stdin.setEncoding("utf-8"),process.stdin.once("data",(X)=>{process.stdin.unref(),V(X.toString().trim())})});if(!B)console.error("Error: hub URL required"),process.exit(1);try{let X=await(await fetch(`${B}/health`)).json();console.log(`✅ CommHub v${X.version} — ${X.sessions} sessions, ${X.sse_connections} SSE`)}catch(V){console.error(`❌ Cannot reach ${B}: ${V.message}`),process.exit(1)}let Q=I();if(Q.hub=B,z.token)Q.token=z.token;i(Q),console.log(`
|
|
24
|
+
Saved to ${S()}`),console.log("Next: anet init project")}async function zz(){let B=I().hub;if(!B)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let Q=N(process.cwd(),".anet");G(Q,{recursive:!0});let V=N(Q,"server.ts");if(!_(V)){console.log("Downloading Channel plugin...");try{let $=await fetch("https://raw.githubusercontent.com/sleep2agi/agent-comm-hub/main/channel/server.ts");if($.ok)K(V,await $.text()),console.log(" ✅ .anet/server.ts")}catch($){console.log(` ❌ Failed: ${$.message}`),console.log(" Manual: curl -sL https://raw.githubusercontent.com/sleep2agi/agent-comm-hub/main/channel/server.ts -o .anet/server.ts")}}else console.log("Channel plugin: exists");let X=N(Q,"package.json");if(!_(X))try{let $=await fetch("https://raw.githubusercontent.com/sleep2agi/agent-comm-hub/main/channel/package.json");if($.ok){K(X,await $.text());try{let{execSync:R}=await import("child_process");R("bun install",{cwd:Q,stdio:"pipe"}),console.log(" ✅ Dependencies installed")}catch{console.log(" ⚠️ Run: cd .anet && bun install")}}}catch{}let Z=N(Q,".env");K(Z,`COMMHUB_URL=${B}
|
|
25
|
+
`),console.log(`CommHub URL: ${B}`);let U=N(process.cwd(),".mcp.json"),W={};if(_(U))try{W=JSON.parse(E(U,"utf-8"))}catch{}if(!W.mcpServers?.commhub)W.mcpServers=W.mcpServers||{},W.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/server.ts"]},K(U,JSON.stringify(W,null,2)+`
|
|
26
|
+
`),console.log(".mcp.json: commhub → .anet/server.ts");else console.log(".mcp.json: commhub already set");let Y=N(process.cwd(),"CLAUDE.md");if(!_(Y))K(Y,`# Agent Network (CommHub)
|
|
27
|
+
|
|
28
|
+
## 通信方式
|
|
29
|
+
|
|
30
|
+
你已接入 CommHub 通信网络。用以下 MCP 工具和其他 Agent/指挥室通信:
|
|
31
|
+
|
|
32
|
+
### 给别人发消息
|
|
33
|
+
\`\`\`
|
|
34
|
+
commhub_send_task(alias="指挥室", task="你要说的内容", priority="normal")
|
|
35
|
+
\`\`\`
|
|
36
|
+
|
|
37
|
+
### 回复任务
|
|
38
|
+
\`\`\`
|
|
39
|
+
commhub_reply(task_id="从消息 meta 里拿", text="回复内容", status="completed")
|
|
40
|
+
\`\`\`
|
|
41
|
+
|
|
42
|
+
### 上报状态
|
|
43
|
+
\`\`\`
|
|
44
|
+
commhub_report_status(status="working", task="正在做什么")
|
|
45
|
+
\`\`\`
|
|
46
|
+
|
|
47
|
+
### 查看谁在线
|
|
48
|
+
\`\`\`
|
|
49
|
+
commhub_get_all_status()
|
|
50
|
+
\`\`\`
|
|
51
|
+
|
|
52
|
+
## 收到消息
|
|
53
|
+
|
|
54
|
+
来自 CommHub 的消息会以 \`<channel source="commhub" sender="..." task_id="...">\` 格式出现在对话中。收到后:
|
|
55
|
+
1. 立即用 commhub_send_task 回复发送者确认收到
|
|
56
|
+
2. 执行任务
|
|
57
|
+
3. 用 commhub_send_task 回复结果
|
|
58
|
+
|
|
59
|
+
## 规则
|
|
60
|
+
|
|
61
|
+
- 收到任务必须回应:确认→执行→汇报
|
|
62
|
+
- 回复指挥室用 commhub_send_task(不是 commhub_reply,reply 不推送)
|
|
63
|
+
- 不要猜 alias,用 get_all_status 查
|
|
64
|
+
`),console.log("CLAUDE.md: created");else console.log("CLAUDE.md: already exists");console.log(`
|
|
65
|
+
✅ Project ready. Next: anet init profile <id> --alias <名字> --channel server:commhub`)}function Bz(){let z=L[2];if(!z)console.error("Usage: anet init profile <id> --alias <名字> [--channel ...] [--env ...]"),process.exit(1);let B=I(),Q=F(),V=Q.alias||z,X=Q.hub||B.hub;if(!X)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let Z={};for(let R of Q._envs){let q=R.indexOf("=");if(q>0)Z[R.slice(0,q)]=R.slice(q+1)}let U={anet_version:"0.0.11",...Q.name?{name:Q.name}:{},alias:V,hub:X,channels:Q._channels.length>0?Q._channels:["server:commhub"],env:Z,flags:{dangerouslySkipPermissions:!0,...Q["teammate-mode"]?{teammateMode:Q["teammate-mode"]}:{}},...Q.resume?{resume:Q.resume}:{},...Q["resume-alias"]?{resumeAlias:Q["resume-alias"]}:{}},W=N(O,".claude","channels","commhub"),Y=process.cwd().replace(/\//g,"-"),$=N(W,Y);if(G($,{recursive:!0}),K(N($,".env"),`COMMHUB_ALIAS=${V}
|
|
66
|
+
`),e(z,U),console.log(`
|
|
67
|
+
✅ Profile "${z}" saved`),console.log(` alias: ${V}`),console.log(` channels: ${U.channels.join(", ")}`),Object.keys(Z).length)console.log(` env: ${Object.keys(Z).join(", ")}`);console.log(`
|
|
68
|
+
Start: anet start ${z}`)}function u(z,B){let Q=M(z);if(!Q)console.error(`Profile "${z}" not found. Run: anet ls`),process.exit(1);let V={...process.env,COMMHUB_ALIAS:Q.alias};for(let[W,Y]of Object.entries(Q.env))V[W]=Y.replace(/^~/,O);let X=[];if(Q.flags.dangerouslySkipPermissions)X.push("--dangerously-skip-permissions");for(let W of Q.channels)if(W.startsWith("server:"))X.push("--dangerously-load-development-channels",W);else X.push("--channels",W);if(Q.flags.teammateMode)X.push("--teammate-mode",Q.flags.teammateMode);if(B==="resume"){let W=Q.resumeAlias||Q.name||Q.alias;X.push("--resume",W)}X.push("-n",Q.name||Q.alias),console.log(`[anet] ${B==="start"?"Starting new":"Resuming"} "${z}" (${Q.alias})...
|
|
69
|
+
`),a("claude",X,{env:V,stdio:"inherit",shell:!0}).on("exit",(W)=>process.exit(W||0))}function v(){let z=L[1];if(!z){h("start");return}u(z,"start")}function Qz(){let z=L[1];if(!z){h("resume");return}u(z,"resume")}function h(z){let B=y();if(B.length===0){console.log("No profiles. Run: anet init profile <id> --alias <名字>");return}console.log(`
|
|
32
70
|
Profiles:
|
|
33
|
-
`);for(let Q of B){let V=
|
|
71
|
+
`);for(let Q of B){let V=M(Q);console.log(` ${Q}${V?.name?` (${V.name})`:""} → ${V?.alias} [${V?.channels.join(", ")}]`)}console.log(`
|
|
34
72
|
anet ${z} <id>
|
|
35
73
|
`)}async function Vz(){let z=y();if(z.length>0){console.log(`
|
|
36
74
|
Profiles:
|
|
37
|
-
`);for(let W of z){let Y=
|
|
38
|
-
`);return}let X=I(),Z=[],
|
|
39
|
-
`),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let W of V){let Y=W.sessionId.slice(0,18)
|
|
75
|
+
`);for(let W of z){let Y=M(W);console.log(` ${W}${Y?.name?` (${Y.name})`:""} → ${Y?.alias} [${Y?.channels.join(", ")}]`)}console.log()}let B=process.cwd(),Q=N(O,".claude","sessions"),V=[];if(_(Q))for(let W of b(Q).filter((Y)=>Y.endsWith(".json")))try{let Y=JSON.parse(E(N(Q,W),"utf-8"));if(Y.cwd===B)V.push(Y)}catch{}if(V.length===0&&z.length===0){console.log("No sessions or profiles in this directory."),console.log(`Get started: anet init
|
|
76
|
+
`);return}let X=I(),Z=[],U={};if(X.hub)try{let[W,Y]=await Promise.all([fetch(`${X.hub}/api/status`).then(($)=>$.json()),fetch(`${X.hub}/health`).then(($)=>$.json())]);Z=W.sessions||[],U=Y.sse_sessions||{}}catch{}if(V.length>0){console.log(`Sessions (${B}):
|
|
77
|
+
`),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let W of V){let Y=W.sessionId.slice(0,18),$=!1;try{process.kill(W.pid,0),$=!0}catch{}let R="(not in network)",q=B.replace(/\//g,"-"),T=N(O,".claude","channels","commhub",q,".env");if(_(T)){let D=E(T,"utf-8").match(/COMMHUB_ALIAS=(.+)/);if(D){let J=D[1].trim(),x=Z.find((g)=>g.alias===J),f=U[J]?"●":"○";R=x?`${J} ${x.status} ${f}`:`${J} (not registered)`}}console.log(` ${Y} ${($?`${W.pid}`:`${W.pid}✕`).padEnd(7)} ${R}`)}console.log()}}async function Wz(){let z=I(),B=F(),Q=process.env.COMMHUB_URL||B.hub||z.hub||"http://127.0.0.1:9200",V=process.env.COMMHUB_ALIAS||B.alias;if(!V)console.error("Error: --alias required"),process.exit(1);let{CommHub:X}=await Promise.resolve().then(() => (j(),C)),Z=new X({url:Q,alias:V});Z.on("task",async(U)=>{console.log(`[${V}] ← ${U.from_session}: ${U.content.slice(0,100)}`),await Z.send(U.from_session,`[${V}] 收到: ${U.content.slice(0,200)}`)}),Z.on("connected",()=>console.log(`[${V}] Connected`)),Z.on("disconnected",()=>console.log(`[${V}] Reconnecting...`)),process.on("SIGINT",()=>Z.disconnect().then(()=>process.exit(0))),console.log(`[${V}] Listening on ${Q}`)}switch(A){case"init":if(L[1]==="project")zz();else if(L[1]==="profile")Bz();else s();break;case"start":v();break;case"resume":Qz();break;case"ls":case"list":Vz();break;case"run":Wz();break;case"--help":case"-h":case void 0:P();break;default:if(M(A))L.unshift("start"),v();else console.error(`Unknown: ${A}`),P(),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.14",
|
|
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",
|