@sleep2agi/agent-network 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +48 -44
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`);
|
|
4
|
-
`)}function
|
|
5
|
-
`)}function
|
|
6
|
-
`)}function c(){let
|
|
2
|
+
var EB=Object.defineProperty;var HB=(B)=>B;function LB(B,Q){this[B]=HB.bind(null,Q)}var JB=(B,Q)=>{for(var X in Q)EB(B,X,{get:Q[X],enumerable:!0,configurable:!0,set:LB.bind(Q,X)})};var MB=(B,Q)=>()=>(B&&(Q=B(B=0)),Q);var s={};JB(s,{default:()=>GB,CommHub:()=>y});import{EventEmitter as zB}from"events";import{hostname as n}from"os";var y,GB;var o=MB(()=>{y=class y extends zB{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 X={"Content-Type":"application/json",Accept:"application/json, text/event-stream"};if(this.token)X.Authorization=`Bearer ${this.token}`;let U=await(await fetch(`${this.url}/mcp`,{method:"POST",headers:X,body:JSON.stringify({jsonrpc:"2.0",id:Date.now(),method:"tools/call",params:{name:B,arguments:Q}})})).text(),Z=U.match(/data: (.+)/),V=Z?JSON.parse(Z[1]):JSON.parse(U),W=V?.result?.content?.[0]?.text;return W?JSON.parse(W):V}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,X="normal"){return this.call("send_task",{alias:B,task:Q,priority:X,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,X="completed"){return this.call("reply",{task_id:B,text:Q,status:X})}async status(B,Q){return this.call("report_status",{resume_id:this.resumeId,alias:this.alias,status:B,server:n(),hostname:n(),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}`,X=this.reconnectDelay;while(this.running){try{this.sseAbort=new AbortController;let Y={Accept:"text/event-stream"};if(this.token)Y.Authorization=`Bearer ${this.token}`;let U=await fetch(Q,{headers:Y,signal:this.sseAbort.signal});if(!U.ok||!U.body){this.log(`SSE failed: ${U.status}`),await this.sleep(X),X=Math.min(X*1.5,60000);continue}X=this.reconnectDelay;let Z=U.body.getReader(),V=new TextDecoder,W="";while(this.running){let{done:$,value:_}=await Z.read();if($)break;W+=V.decode(_,{stream:!0});let q=W.split(`
|
|
3
|
+
`);W=q.pop()||"";for(let M of q){if(!M.startsWith("data: "))continue;try{let H=JSON.parse(M.slice(6));if(H.type==="connected"){this.log("SSE connected"),this.emit("connected");continue}if(H.type==="new_task"||H.type==="new_message"||H.type==="broadcast")await this.processInbox()}catch{}}}}catch(Y){if(Y.name==="AbortError")break;this.emit("error",Y),this.log(`SSE error: ${Y.message}`)}if(this.running)this.emit("disconnected"),this.log(`SSE reconnecting in ${X/1000}s...`),await this.sleep(X),X=Math.min(X*1.5,60000)}}async processInbox(){try{let Q=(await this.call("get_inbox",{alias:this.alias,limit:10}))?.messages||[];for(let X of Q)await this.call("ack_inbox",{alias:this.alias,message_id:X.id}),this.log(`← ${X.from_session}: ${X.content.slice(0,60)}`),this.emit("task",X),this.emit("message",X)}catch(B){this.log(`inbox error: ${B.message}`)}}sleep(B){return new Promise((Q)=>setTimeout(Q,B))}};GB=y});import{chmodSync as YB,readFileSync as G,writeFileSync as J,existsSync as L,mkdirSync as A,readdirSync as v,statSync as b}from"fs";import{join as K}from"path";import{spawn as g,execSync as p}from"child_process";import{createInterface as DB}from"readline";var E=process.argv.slice(2),S=E[0],F=process.env.HOME||process.env.USERPROFILE||"~";function ZB(){return K(F,".anet","config.json")}function h(){return K(F,".anet","server","config.json")}function I(){return K(process.cwd(),".anet","nodes")}function $B(){return N().token||process.env.COMMHUB_TOKEN||x().token||""}function f(B){let Q=B||$B();return Q?{Authorization:`Bearer ${Q}`}:{}}function x(){let B=ZB();if(L(B))try{return JSON.parse(G(B,"utf-8"))}catch{}return{}}function UB(B){let Q=K(F,".anet");A(Q,{recursive:!0}),J(K(Q,"config.json"),JSON.stringify(B,null,2)+`
|
|
4
|
+
`)}function i(){let B=h();if(L(B))try{return JSON.parse(G(B,"utf-8"))}catch{}return{}}function e(B){let Q=K(F,".anet","server");A(Q,{recursive:!0}),J(K(Q,"config.json"),JSON.stringify(B,null,2)+`
|
|
5
|
+
`)}function T(B){if(typeof B==="string"){if(B==="codex"||B==="codex-sdk")return"codex-sdk";if(B==="claude"||B==="claude-sdk"||B==="claude-agent-sdk")return"claude-agent-sdk";if(B==="agent-sdk")return"claude-agent-sdk";return"claude-code-cli"}let Q=B;if(!Q)return"claude-code-cli";if(Q.runtime==="agent-sdk")return Q.codexRuntime==="codex"?"codex-sdk":"claude-agent-sdk";return T(Q.runtime||"claude-code-cli")}function TB(B,Q){return Q?.name||Q?.alias||B}function j(B){return B.session||B.resume||""}function AB(B){return B.normalize("NFC")}function k(B){if(B!==AB(B))console.error(`Error: node-name must be Unicode NFC normalized: ${B}`),process.exit(1);if(!/^[^\s\/\\:*?"<>|.][^\s\/\\:*?"<>|.]*$/.test(B))console.error(`Error: invalid node-name "${B}"`),console.error(`Allowed: Chinese/letters/numbers/-/_ ; forbidden: whitespace, '.', / \\ : * ? " < > |`),process.exit(1)}function D(B){let Q=K(I(),B,"config.json");if(!L(Q))return null;try{let X=JSON.parse(G(Q,"utf-8")),Y=x();return{...X,name:X.name||X.alias||B,alias:X.alias||X.name||B,session:X.session||X.resume||"",hub:X.hub||Y.hub||"",token:X.token||Y.token||"",channels:Array.isArray(X.channels)?X.channels:[],env:{...X.env},flags:{...X.flags}}}catch{return null}}function WB(B){let Q=K(I(),B,"config.json");if(!L(Q))return null;try{let X=JSON.parse(G(Q,"utf-8"));return{...X,channels:Array.isArray(X.channels)?X.channels:[],env:{...X.env},flags:{...X.flags}}}catch{return null}}function C(B,Q){let X=K(I(),B);A(X,{recursive:!0}),J(K(X,"config.json"),JSON.stringify(Q,null,2)+`
|
|
6
|
+
`)}function c(){let B=I();if(!L(B))return[];return v(B).filter((Q)=>L(K(B,Q,"config.json")))}function N(){let B={_channels:[],_envs:[]};for(let Q=0;Q<E.length;Q++){if(E[Q]==="--channel"&&E[Q+1]){B._channels.push(E[++Q]);continue}if(E[Q]==="--env"&&E[Q+1]){B._envs.push(E[++Q]);continue}if(E[Q].startsWith("--")&&E[Q+1]&&!E[Q+1].startsWith("--"))B[E[Q].slice(2)]=E[++Q];else if(E[Q].startsWith("--"))B[E[Q].slice(2)]="true"}return B}function BB(B){try{return p(`command -v ${JSON.stringify(B)}`,{stdio:"ignore",shell:"/bin/bash"}),!0}catch{return!1}}function d(){console.log("[anet] claude-code-cli requires:"),console.log(" - Claude Pro / Team / Enterprise subscription"),console.log(' - Run "claude auth login" first'),console.log(" - Uses Anthropic Claude only"),console.log(" - For other models, use --runtime codex-sdk or claude-agent-sdk")}function l(B,Q){if(B==="claude-code-cli"){if(!BB("claude"))console.warn("[anet] Warning: claude CLI not found in PATH."),console.warn("[anet] Install: npm install -g @anthropic-ai/claude-code");if(Q==="start")d();return}if(!BB("npx"))console.warn("[anet] Warning: npx not found in PATH; cannot launch @sleep2agi/agent-node."),console.warn("[anet] Install Node.js/npm first, or install agent-node globally: npm install -g @sleep2agi/agent-node")}function QB(){console.log(`
|
|
7
7
|
anet — AI Agent Network CLI
|
|
8
8
|
|
|
9
9
|
anet init Configure hub URL (global, once)
|
|
@@ -24,12 +24,12 @@ Quick start:
|
|
|
24
24
|
anet init --hub http://IP:9200
|
|
25
25
|
anet create 指挥室
|
|
26
26
|
anet start 指挥室
|
|
27
|
-
`)}async function
|
|
28
|
-
Saved to ${
|
|
29
|
-
`);try{
|
|
30
|
-
`;if(
|
|
31
|
-
`;
|
|
32
|
-
`),console.log(".mcp.json: commhub → .anet/node-server.ts");else console.log(".mcp.json: commhub already set");let
|
|
27
|
+
`)}async function NB(){let B=N(),Q=B.hub;if(!Q)Q=await z("CommHub URL (e.g. http://YOUR_IP:9200)");if(!Q)R(),console.error("Error: hub URL required"),process.exit(1);Q=Q.replace(/\/+$/,"");let X=B.token||"";if(!X)X=await z("Auth token (empty to skip)");R();try{let Z=await(await fetch(`${Q}/health`,{headers:X?{Authorization:`Bearer ${X}`}:{}})).json();console.log(`✅ CommHub v${Z.version} — ${Z.sessions} sessions, ${Z.sse_connections} SSE`)}catch(U){console.error(`❌ Cannot reach ${Q}: ${U.message}`),process.exit(1)}let Y=x();if(Y.hub=Q,X)Y.token=X;else if(!Y.token)delete Y.token;UB(Y),console.log(`
|
|
28
|
+
Saved to ${ZB()}`),console.log("Next: anet init project")}async function FB(){let B=x(),Q=B.hub;if(!Q)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let X=K(process.cwd(),".anet");A(X,{recursive:!0});let Y=K(X,"node-server.ts");if(!L(Y)){let M=[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")],H=!1;for(let O of M)if(L(O)){J(Y,G(O,"utf-8")),console.log(" ✅ .anet/node-server.ts"),H=!0;break}if(!H)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 U=K(X,"package.json");if(!L(U)){J(U,JSON.stringify({private:!0,dependencies:{"@modelcontextprotocol/sdk":"^1.12.0"}},null,2)+`
|
|
29
|
+
`);try{p("bun install",{cwd:X,stdio:"pipe"}),console.log(" ✅ Dependencies installed")}catch{console.log(" ⚠️ Run: cd .anet && bun install")}}let Z=K(X,".env"),V=B.token||"",W=`COMMHUB_URL=${Q}
|
|
30
|
+
`;if(V)W+=`COMMHUB_TOKEN=${V}
|
|
31
|
+
`;J(Z,W),console.log(`CommHub URL: ${Q}${V?" (with token)":""}`);let $=K(process.cwd(),".mcp.json"),_={};if(L($))try{_=JSON.parse(G($,"utf-8"))}catch{}if(!_.mcpServers?.commhub)_.mcpServers=_.mcpServers||{},_.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},J($,JSON.stringify(_,null,2)+`
|
|
32
|
+
`),console.log(".mcp.json: commhub → .anet/node-server.ts");else console.log(".mcp.json: commhub already set");let q=K(process.cwd(),"CLAUDE.md");if(!L(q))J(q,`# Agent Network (CommHub)
|
|
33
33
|
|
|
34
34
|
## 通信方式
|
|
35
35
|
|
|
@@ -68,28 +68,32 @@ commhub_get_all_status()
|
|
|
68
68
|
- 回复指挥室用 commhub_send_task(不是 commhub_reply,reply 不推送)
|
|
69
69
|
- 不要猜 alias,用 get_all_status 查
|
|
70
70
|
`),console.log("CLAUDE.md: created");else console.log("CLAUDE.md: already exists");console.log(`
|
|
71
|
-
✅ Project ready. Next: anet create <node-name>`)}function
|
|
72
|
-
`)
|
|
73
|
-
`),
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
`)
|
|
81
|
-
`),
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
✅ Project ready. Next: anet create <node-name>`)}async function OB(){console.warn("[deprecated] anet init profile is now anet create."),console.warn(` Run: anet create <node-name> [--runtime ...]
|
|
72
|
+
`),await VB(E[2])}function a(B,Q){let X=x(),Y=Q.hub||X.hub;if(!Y)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let U={};for(let $ of Q._envs){let _=$.indexOf("=");if(_>0)U[$.slice(0,_)]=$.slice(_+1)}let Z=T(Q.runtime||"claude-code-cli"),V=Z==="codex-sdk"?"gpt-5.4":void 0;return{anet_version:"0.1.0",name:B,runtime:Z,...Q.hub?{hub:Y}:{},...Q.model||V?{model:Q.model||V}:{},...Q.tools?{tools:Q.tools.split(",").map(($)=>$.trim())}:{},channels:Q._channels.length>0?Q._channels:["server:commhub"],env:U,flags:{dangerouslySkipPermissions:!0,...Z==="claude-code-cli"?{teammateMode:Q["teammate-mode"]||"in-process"}:{},...Q["max-turns"]?{maxTurns:parseInt(Q["max-turns"])}:{}},...Q.session?{session:Q.session}:{}}}function KB(B,Q){let X=K(F,".claude","channels","commhub"),Y=process.cwd().replace(/\//g,"-"),U=K(X,Y);A(U,{recursive:!0}),J(K(U,".env"),`COMMHUB_ALIAS=${B}
|
|
73
|
+
`),C(B,Q)}function IB(B,Q){if(B.channels=B.channels||[],!B.channels.includes(Q))B.channels.push(Q)}function xB(B,Q,X){let Y=K(I(),B,"channels","telegram");A(Y,{recursive:!0}),A(K(Y,"inbox"),{recursive:!0});let U=K(Y,".env");J(U,`TELEGRAM_BOT_TOKEN=${Q}
|
|
74
|
+
`);try{YB(U,384)}catch{}return J(K(Y,"access.json"),JSON.stringify({dmPolicy:"allowlist",allowFrom:[X],groups:{},pending:{}},null,2)+`
|
|
75
|
+
`),Y}async function u(B,Q){console.log(B),Q.forEach((X,Y)=>{let U=X.description?` ${X.description}`:"";console.log(` ${Y+1}) ${X.label}${U}`)});while(!0){let X=await z("Select","1"),Y=Number.parseInt(X,10)-1;if(Y>=0&&Y<Q.length)return Q[Y].value;console.log(`Please enter 1-${Q.length}.`)}}async function RB(){let B=await z("Node name");if(!B)R(),console.error("Error: node-name required"),process.exit(1);if(k(B),D(B))R(),console.error(`Node "${B}" already exists: .anet/nodes/${B}/config.json`),process.exit(1);let Q=await u("Select runtime:",[{label:"claude-code-cli",value:"claude-code-cli",description:"Claude Code CLI(需要 Pro 订阅)"},{label:"codex-sdk",value:"codex-sdk",description:"Codex SDK(GPT-5.4)"},{label:"claude-agent-sdk",value:"claude-agent-sdk",description:"Claude Agent SDK(MiniMax/书生等)"}]),X=N();if(X.runtime=Q,Q==="codex-sdk"){let W=await u("Select model:",[{label:"gpt-5.4",value:"gpt-5.4"},{label:"o3",value:"o3"},{label:"custom",value:"__custom__"}]);X.model=W==="__custom__"?await z("Model"):W}else if(Q==="claude-agent-sdk"){let W=await u("Select model:",[{label:"MiniMax-M2.7",value:"MiniMax-M2.7"},{label:"intern-s1-pro",value:"intern-s1-pro"},{label:"claude-sonnet-4-6",value:"claude-sonnet-4-6"},{label:"custom",value:"__custom__"}]);if(X.model=W==="__custom__"?await z("Model"):W,X.model==="MiniMax-M2.7")X._envs.push("ANTHROPIC_BASE_URL=https://api.minimaxi.com/anthropic");else if(X.model==="intern-s1-pro")X._envs.push("ANTHROPIC_BASE_URL=https://chat.intern-ai.org.cn");let $=await z("ANTHROPIC_AUTH_TOKEN");if($)X._envs.push(`ANTHROPIC_AUTH_TOKEN=${$}`)}let Y=a(B,X),U=await z("Add Telegram channel? (y/n)","n"),Z=null;if(/^y(es)?$/i.test(U)){let W=await z("Telegram Bot Token"),$=await z("Allow User ID","7612221352");if(!W)R(),console.error("Error: Telegram Bot Token required"),process.exit(1);Z={botToken:W,allowId:$},IB(Y,"telegram")}let V=await z("Add WeChat channel? (y/n)","n");if(/^y(es)?$/i.test(V))console.log("[anet] WeChat channel is not implemented yet; skipped.");if(R(),KB(B,Y),Z)xB(B,Z.botToken,Z.allowId);if(l(T(Y),"create"),console.log(`
|
|
76
|
+
[anet] Created node "${B}" (${T(Y)})`),Z)console.log("[anet] ✅ Telegram channel added");if(T(Y)==="claude-code-cli")d();console.log("[anet] ⚠ dangerouslySkipPermissions and teammateMode enabled by default."),console.log(`[anet] To disable: edit .anet/nodes/${B}/config.json → flags`),console.log(`
|
|
77
|
+
Start: anet start ${B}`)}async function VB(B){let Q=B||E[1];if(!Q)return RB();if(Q.startsWith("--"))console.error("Usage: anet create <node-name> [--runtime claude-code-cli|codex-sdk|claude-agent-sdk] [--model ...] [--tools ...]"),console.error("Or run fully interactive: anet create"),process.exit(1);if(k(Q),D(Q))console.error(`Node "${Q}" already exists: .anet/nodes/${Q}/config.json`),process.exit(1);let X=N(),Y=a(Q,X);if(KB(Q,Y),l(T(Y),"create"),console.log(`
|
|
78
|
+
[anet] Created node "${Q}" (${T(Y)})`),T(Y)==="claude-code-cli")d();console.log("[anet] ⚠ dangerouslySkipPermissions and teammateMode enabled by default."),console.log(`[anet] To disable: edit .anet/nodes/${Q}/config.json → flags`),console.log(`
|
|
79
|
+
Start: anet start ${Q}`)}var P=null;function PB(){if(!P)P=DB({input:process.stdin,output:process.stdout});return P}function R(){if(P)P.close(),P=null}function z(B,Q){let X=Q?` [${Q}]`:"";return new Promise((Y)=>{PB().question(`${B}${X}: `,(U)=>{Y(U.trim()||Q||"")})})}function wB(B){if(T(B)!=="claude-code-cli")return;if(!B.channels?.some((M)=>M.includes("commhub")))return;let Q=K(process.cwd(),".mcp.json"),X={};if(L(Q))try{X=JSON.parse(G(Q,"utf-8"))}catch{}let Y=K(process.cwd(),".anet"),U=K(Y,"node-server.ts"),Z=[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")];for(let M of Z)if(L(M)){A(Y,{recursive:!0});let H=G(M,"utf-8"),O=L(U)?G(U,"utf-8"):"";if(H!==O)J(U,H),console.log("[anet] Updated .anet/node-server.ts");break}let V=K(Y,"package.json");if(!L(V)){A(Y,{recursive:!0}),J(V,JSON.stringify({private:!0,dependencies:{"@modelcontextprotocol/sdk":"^1.12.0"}},null,2)+`
|
|
80
|
+
`);try{p("bun install",{cwd:Y,stdio:"pipe"})}catch{}}if(X.mcpServers=X.mcpServers||{},!Object.keys(X.mcpServers).some((M)=>M.includes("commhub")))X.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},J(Q,JSON.stringify(X,null,2)+`
|
|
81
|
+
`),console.log("[anet] .mcp.json: added commhub");let $=K(Y,".env"),_=B.token||"",q=`COMMHUB_URL=${B.hub||"http://127.0.0.1:9200"}
|
|
82
|
+
`;if(_)q+=`COMMHUB_TOKEN=${_}
|
|
83
|
+
`;J($,q),X.mcpServers=X.mcpServers||{},X.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},J(Q,JSON.stringify(X,null,2)+`
|
|
84
|
+
`),console.log("[anet] .mcp.json: added commhub channel server")}async function m(B,Q=!1){let X=D(B);if(!X)console.error(`Node "${B}" not found. Create it first: anet create ${B}`),process.exit(1);let Y=T(X),U=TB(B,X),Z=j(X),V=!!Z&&!Q,W=V?`Resuming session ${Z.slice(0,8)}...`:"Starting new session";console.log(`[anet] ${W} for "${B}" [${Y}]...
|
|
85
|
+
`),l(Y,"start"),wB(X);let $=X.token||"";if(Y==="codex-sdk"||Y==="claude-agent-sdk"){let _=["@sleep2agi/agent-node","--config",K(I(),B,"config.json"),"--alias",U];if(Q)_.push("--new-session","true");let q={...process.env,...$?{COMMHUB_TOKEN:$}:{}};for(let[H,O]of Object.entries(X.env))q[H]=O.replace(/^~/,F);g("npx",_,{env:q,stdio:"inherit",shell:!0}).on("exit",(H)=>process.exit(H||0))}else{let _={...process.env,COMMHUB_ALIAS:X.alias,...$?{COMMHUB_TOKEN:$}:{}};for(let[H,O]of Object.entries(X.env))_[H]=O.replace(/^~/,F);if(X.channels.includes("telegram"))_.TELEGRAM_STATE_DIR=K(I(),B,"channels","telegram");let q=[];if(X.flags.dangerouslySkipPermissions)q.push("--dangerously-skip-permissions");for(let H of X.channels)if(H.startsWith("server:"))q.push("--dangerously-load-development-channels",H);else if(H==="telegram")q.push("--channels","plugin:telegram@claude-plugins-official");else q.push("--channels",H);if(X.flags.teammateMode)q.push("--teammate-mode",X.flags.teammateMode);if(V)q.push("--resume",Z);q.push("-n",U),g("claude",q,{env:_,stdio:"inherit",shell:!0}).on("exit",(H)=>{if(!V||Q){if(console.log(`
|
|
86
|
+
[anet] Tip: bind this Claude Code session with:`),console.log("[anet] anet session ls"),console.log(`[anet] anet resume ${B} --session <session-id>`),Q&&Z)console.log(`[anet] Next "anet start ${B}" will still resume ${Z.slice(0,8)}... until you rebind.`)}process.exit(H||0)})}}async function XB(){let B=E[1];if(!B){CB("start");return}await m(B,!!N()["new-session"])}async function bB(){let B=E[1];if(!B){console.error("Usage: anet resume <node-name> --session <session-id>"),console.error("Daily start/resume: anet start <node-name>");return}let Q=D(B),X=N(),Y=X.session;if(!Y){console.warn("[deprecated] anet resume <node-name> without --session is now anet start <node-name>."),await m(B,!1);return}if(k(B),!Q){let U={...X,session:Y,runtime:X.runtime||"claude-code-cli"};Q=a(B,U),C(B,Q),console.log(`[anet] Created node "${B}"`)}else{let U=j(Q);if(U&&U!==Y&&X.yes!=="true"){let V=await z(`[anet] ${B} already has session ${U.slice(0,8)}..., overwrite? (y/n)`,"n");if(R(),!/^y(es)?$/i.test(V)){console.log("[anet] Session unchanged.");return}}let Z=WB(B)||Q;Z.session=Y,delete Z.resume,delete Z.resumeAlias,C(B,Z)}console.log(`[anet] Saved session ${Y.slice(0,8)}... to .anet/nodes/${B}/config.json
|
|
87
|
+
`),await m(B,!1)}function CB(B){let Q=c();if(Q.length===0){console.log("No nodes. Run: anet create <node-name>");return}console.log(`
|
|
84
88
|
Nodes:
|
|
85
|
-
`);for(let
|
|
86
|
-
anet ${
|
|
87
|
-
`)}async function
|
|
89
|
+
`);for(let X of Q){let Y=D(X);console.log(` ${X} [${T(Y||void 0)}] session=${Y?j(Y).slice(0,8)||"-":"-"} channels=[${Y?.channels.join(", ")}]`)}console.log(`
|
|
90
|
+
anet ${B} <node-name>
|
|
91
|
+
`)}async function vB(){let B=c();if(B.length>0){console.log(`
|
|
88
92
|
Nodes:
|
|
89
|
-
`);for(let
|
|
90
|
-
`);return}let
|
|
91
|
-
`),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let
|
|
92
|
-
`);
|
|
93
|
+
`);for(let W of B){let $=D(W),_=$?j($).slice(0,8)||"-":"-";console.log(` ${W} [${T($||void 0)}] session=${_} channels=[${$?.channels.join(", ")}]`)}console.log()}let Q=process.cwd(),X=K(F,".claude","sessions"),Y=[];if(L(X))for(let W of v(X).filter(($)=>$.endsWith(".json")))try{let $=JSON.parse(G(K(X,W),"utf-8"));if($.cwd===Q)Y.push($)}catch{}if(Y.length===0&&B.length===0){console.log("No sessions or nodes in this directory."),console.log(`Get started: anet init
|
|
94
|
+
`);return}let U=x(),Z=[],V={};if(U.hub)try{let[W,$]=await Promise.all([fetch(`${U.hub}/api/status`,{headers:f()}).then((_)=>_.json()),fetch(`${U.hub}/health`,{headers:f()}).then((_)=>_.json())]);Z=W.sessions||[],V=$.sse_sessions||{}}catch{}if(Y.length>0){console.log(`Sessions (${Q}):
|
|
95
|
+
`),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let W of Y){let $=W.sessionId.slice(0,18),_=!1;try{process.kill(W.pid,0),_=!0}catch{}let q="(not in network)",M=Q.replace(/\//g,"-"),H=K(F,".claude","channels","commhub",M,".env");if(L(H)){let r=G(H,"utf-8").match(/COMMHUB_ALIAS=(.+)/);if(r){let w=r[1].trim(),t=Z.find((qB)=>qB.alias===w),_B=V[w]?"●":"○";q=t?`${w} ${t.status} ${_B}`:`${w} (not registered)`}}console.log(` ${$} ${(_?`${W.pid}`:`${W.pid}✕`).padEnd(7)} ${q}`)}console.log()}}async function jB(){let B=x(),Q=N(),X=process.env.COMMHUB_URL||Q.hub||B.hub||"http://127.0.0.1:9200",Y=process.env.COMMHUB_ALIAS||Q.alias;if(!Y)console.error("Error: --alias required"),process.exit(1);let{CommHub:U}=await Promise.resolve().then(() => (o(),s)),Z=new U({url:X,alias:Y});Z.on("task",async(V)=>{console.log(`[${Y}] ← ${V.from_session}: ${V.content.slice(0,100)}`),await Z.send(V.from_session,`[${Y}] 收到: ${V.content.slice(0,200)}`)}),Z.on("connected",()=>console.log(`[${Y}] Connected`)),Z.on("disconnected",()=>console.log(`[${Y}] Reconnecting...`)),process.on("SIGINT",()=>Z.disconnect().then(()=>process.exit(0))),console.log(`[${Y}] Listening on ${X}`)}async function kB(){let B=E[1];if(B==="start"){let Q=N(),X=i(),Y=Q.port||X.port||"9200",U=Q.host||X.host||"0.0.0.0",Z=Q.token||X.token||$B();if(!Z)Z=crypto.randomUUID().replace(/-/g,""),console.log(`[anet] Generated auth token: ${Z}`),console.log(`[anet] Save this token — agents need it to connect.
|
|
96
|
+
`);e({port:Y,host:U,token:Z});let V=x();if(!V.token)V.token=Z,UB(V);console.log(`[anet] Starting CommHub Server on ${U}:${Y}${Z?" (auth enabled)":""}...`);let W={...process.env,PORT:Y,HOST:U};if(Z)W.COMMHUB_AUTH_TOKEN=Z;g("bunx",["@sleep2agi/commhub-server"],{env:W,stdio:"inherit",shell:!0}).on("exit",(_)=>process.exit(_||0))}else if(B==="config"){let Q=N(),X=i();if(Q.port)X.port=Q.port;if(Q.host)X.host=Q.host;if(Q.token)X.token=Q.token;if(Q.port||Q.host||Q.token)e(X),console.log(`Server config saved: ${h()}`);console.log(JSON.stringify(X,null,2))}else console.log(`
|
|
93
97
|
anet server <command>
|
|
94
98
|
|
|
95
99
|
start [options] Start CommHub Server
|
|
@@ -100,22 +104,22 @@ Options:
|
|
|
100
104
|
--host <host> Bind address (default: 0.0.0.0)
|
|
101
105
|
--token <token> Auth token
|
|
102
106
|
|
|
103
|
-
Config: ${
|
|
107
|
+
Config: ${h()}
|
|
104
108
|
First 'anet server start' saves config, after that just 'anet server start'.
|
|
105
109
|
|
|
106
110
|
Example:
|
|
107
111
|
anet server start --port 9200 --token my-secret # 首次,保存配置
|
|
108
112
|
anet server start # 之后直接启动
|
|
109
113
|
anet server config # 查看配置
|
|
110
|
-
`)}async function
|
|
111
|
-
`),console.log(` ✅ ${
|
|
112
|
-
Imported ${
|
|
113
|
-
Sessions in ${
|
|
114
|
-
`),console.log(" SESSION ID SIZE MODIFIED"),console.log(" ────────────────────────────────────── ──────── ────────────────");for(let
|
|
114
|
+
`)}async function yB(){let B=x(),X=N().hub||B.hub;if(!X)console.error("Run 'anet init' first"),process.exit(1);let Y=[];try{Y=(await(await fetch(`${X}/api/status`,{headers:f()})).json()).sessions||[]}catch($){console.error(`Cannot reach ${X}: ${$.message}`),process.exit(1)}if(Y.length===0){console.log("No sessions in CommHub.");return}let U=Y.filter(($)=>$.agent==="claude-code"&&$.project_dir);if(U.length===0){console.log("No claude-code sessions found.");return}let Z=E[1],V=Z?U.filter(($)=>$.alias===Z):U;if(V.length===0){console.log(`No session found for "${Z}".`);return}let W=0;for(let $ of V){let _=$.project_dir,q=K(_,".anet","nodes",$.alias),M=K(q,"config.json");if(L(M)){console.log(` ⏭ ${$.alias} — already exists (${_})`);continue}if(!L(_)){console.log(` ⚠ ${$.alias} — project_dir not found: ${_}`);continue}let H={anet_version:"0.1.0",name:$.alias,runtime:"claude-code-cli",channels:["server:commhub"],env:{},flags:{dangerouslySkipPermissions:!0,teammateMode:"in-process"},session:$.resume_id};A(q,{recursive:!0}),J(M,JSON.stringify(H,null,2)+`
|
|
115
|
+
`),console.log(` ✅ ${$.alias} → ${_}/.anet/nodes/${$.alias}/config.json`),W++}console.log(`
|
|
116
|
+
Imported ${W} session(s). Use: cd <project> && anet resume <alias>`)}function SB(){let B=E[1];if(B==="ls"||B==="list"||!B){let Q=process.cwd(),X=Q.replace(/\//g,"-"),Y=K(F,".claude","projects",X);if(!L(Y)){console.log(`No sessions for ${Q}`);return}let U=v(Y).filter((Z)=>Z.endsWith(".jsonl")).sort((Z,V)=>{let W=b(K(Y,Z));return b(K(Y,V)).mtimeMs-W.mtimeMs});if(U.length===0){console.log("No sessions.");return}console.log(`
|
|
117
|
+
Sessions in ${Q} (${U.length} total):
|
|
118
|
+
`),console.log(" SESSION ID SIZE MODIFIED"),console.log(" ────────────────────────────────────── ──────── ────────────────");for(let Z of U){let V=Z.replace(".jsonl",""),W=b(K(Y,Z)),$=W.size<1024?`${W.size}B`:W.size<1048576?`${(W.size/1024).toFixed(0)}KB`:`${(W.size/1024/1024).toFixed(1)}MB`,_=W.mtime.toISOString().replace("T"," ").slice(0,16);console.log(` ${V} ${$.padStart(8)} ${_}`)}console.log()}else console.log(`
|
|
115
119
|
anet session <command>
|
|
116
120
|
|
|
117
121
|
ls List Claude Code sessions in current project
|
|
118
|
-
`)}async function
|
|
122
|
+
`)}async function uB(){let B=E[1],Q=N();if(B==="add"){let X=E[2],Y=E[3];if(!X||!Y){console.log(`
|
|
119
123
|
anet channel add <type> <node-id> [options]
|
|
120
124
|
|
|
121
125
|
Types: telegram
|
|
@@ -127,16 +131,16 @@ Options:
|
|
|
127
131
|
Example:
|
|
128
132
|
anet channel add telegram 指挥室 --bot-token 123:ABC --allow 7612221352
|
|
129
133
|
anet channel add telegram 指挥室 # 交互式
|
|
130
|
-
`);return}if(
|
|
131
|
-
`);try{
|
|
132
|
-
`),!
|
|
133
|
-
✅ ${
|
|
134
|
+
`);return}if(X!=="telegram")console.error(`P0 only supports telegram channels. Unsupported type: ${X}`),process.exit(1);k(Y);let U=D(Y),Z=WB(Y);if(!U)console.error(`Node "${Y}" not found. Create it first: anet create ${Y} --runtime codex-sdk`),process.exit(1);let V=Q["bot-token"],W=Q.allow;if(!V)V=await z(`${X} Bot Token`);if(!W)W=await z("Allow User ID (发 @userinfobot 获取数字ID)","7612221352");if(R(),!V||!W)console.error("Error: bot-token and allow required"),process.exit(1);let $=K(I(),Y,"channels",X);A($,{recursive:!0}),A(K($,"inbox"),{recursive:!0});let _="TELEGRAM_BOT_TOKEN",q=K($,".env");J(q,`${_}=${V}
|
|
135
|
+
`);try{YB(q,384)}catch{}if(J(K($,"access.json"),JSON.stringify({dmPolicy:"allowlist",allowFrom:[W],groups:{},pending:{}},null,2)+`
|
|
136
|
+
`),!Z)console.error(`Node "${Y}" not found. Create it first: anet create ${Y} --runtime codex-sdk`),process.exit(1);if(Z.channels=Z.channels||[],!Z.channels.includes("telegram"))Z.channels.push("telegram");C(Y,Z),console.log(`
|
|
137
|
+
✅ ${X} channel added to "${Y}"`),console.log(` ${$}/`),console.log(" config.json updated")}else if(B==="ls"){let X=E[2],Y=X?[X]:c(),U=!1;for(let Z of Y){let V=K(I(),Z,"channels");if(!L(V))continue;let W=v(V).filter(($)=>{try{return b(K(V,$)).isDirectory()}catch{return!1}});if(W.length===0)continue;if(!U)console.log(`
|
|
134
138
|
Node Channels:
|
|
135
|
-
`)
|
|
139
|
+
`),U=!0;for(let $ of W){let _=K(V,$,"access.json"),q="";if(L(_))try{q=JSON.parse(G(_,"utf-8")).allowFrom?.join(", ")||""}catch{}console.log(` ${Z.padEnd(20)} ${$.padEnd(12)} allow: ${q||"(none)"}`)}}if(!U)console.log("No channels. Add one: anet channel add telegram <node-id>");console.log()}else console.log(`
|
|
136
140
|
anet channel <command>
|
|
137
141
|
|
|
138
142
|
add <type> <node-id> Add channel to a node
|
|
139
143
|
ls [node-id] List channels
|
|
140
144
|
|
|
141
145
|
Data: .anet/nodes/<node-id>/channels/<type>/
|
|
142
|
-
`)}switch(
|
|
146
|
+
`)}switch(S){case"init":if(E[1]==="project")FB();else if(E[1]==="profile")await OB();else await NB();break;case"create":await VB();break;case"server":kB();break;case"start":XB();break;case"resume":bB();break;case"import":yB();break;case"channel":uB();break;case"session":SB();break;case"ls":case"list":vB();break;case"run":jB();break;case"-v":case"--version":case"version":{let B=JSON.parse(G(K(new URL(".",import.meta.url).pathname,"..","..","package.json"),"utf-8"));console.log(`anet v${B.version}`);break}case"--help":case"-h":case void 0:QB();break;default:if(D(S))E.unshift("start"),XB();else console.error(`Unknown: ${S}`),QB(),process.exit(1)}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sleep2agi/agent-network",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
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",
|