@sleep2agi/agent-network 0.0.37 → 0.0.39
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 +44 -38
- package/package.json +1 -1
- package/src/node-server.ts +12 -2
package/dist/bin/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`);
|
|
4
|
-
`)}function
|
|
5
|
-
`)}function A(
|
|
6
|
-
`)}function
|
|
2
|
+
var QB=Object.defineProperty;var WB=(Q)=>Q;function XB(Q,W){this[Q]=WB.bind(null,W)}var YB=(Q,W)=>{for(var B in W)QB(Q,B,{get:W[B],enumerable:!0,configurable:!0,set:XB.bind(W,B)})};var ZB=(Q,W)=>()=>(Q&&(W=Q(Q=0)),W);var g={};YB(g,{default:()=>zB,CommHub:()=>w});import{EventEmitter as $B}from"events";import{hostname as f}from"os";var w,zB;var m=ZB(()=>{w=class w extends $B{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,W){let B={"Content-Type":"application/json",Accept:"application/json, text/event-stream"};if(this.token)B.Authorization=`Bearer ${this.token}`;let N=await(await fetch(`${this.url}/mcp`,{method:"POST",headers:B,body:JSON.stringify({jsonrpc:"2.0",id:Date.now(),method:"tools/call",params:{name:Q,arguments:W}})})).text(),Y=N.match(/data: (.+)/),U=Y?JSON.parse(Y[1]):JSON.parse(N),Z=U?.result?.content?.[0]?.text;return Z?JSON.parse(Z):U}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,W,B="normal"){return this.call("send_task",{alias:Q,task:W,priority:B,from_session:this.alias})}async message(Q,W){return this.call("send_message",{alias:Q,message:W,from_session:this.alias})}async reply(Q,W,B="completed"){return this.call("reply",{task_id:Q,text:W,status:B})}async status(Q,W){return this.call("report_status",{resume_id:this.resumeId,alias:this.alias,status:Q,server:f(),hostname:f(),agent:this.agent,project_dir:process.cwd(),...W})}async getAllStatus(){return this.call("get_all_status",{})}async broadcast(Q,W){return this.call("broadcast",{message:Q,filter_server:W?.server,filter_status:W?.status})}async connectSSE(){let Q=encodeURIComponent(this.alias),W=`${this.url}/events/${Q}`,B=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 N=await fetch(W,{headers:X,signal:this.sseAbort.signal});if(!N.ok||!N.body){this.log(`SSE failed: ${N.status}`),await this.sleep(B),B=Math.min(B*1.5,60000);continue}B=this.reconnectDelay;let Y=N.body.getReader(),U=new TextDecoder,Z="";while(this.running){let{done:$,value:z}=await Y.read();if($)break;Z+=U.decode(z,{stream:!0});let K=Z.split(`
|
|
3
|
+
`);Z=K.pop()||"";for(let V of K){if(!V.startsWith("data: "))continue;try{let R=JSON.parse(V.slice(6));if(R.type==="connected"){this.log("SSE connected"),this.emit("connected");continue}if(R.type==="new_task"||R.type==="new_message"||R.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 ${B/1000}s...`),await this.sleep(B),B=Math.min(B*1.5,60000)}}async processInbox(){try{let W=(await this.call("get_inbox",{alias:this.alias,limit:10}))?.messages||[];for(let B of W)await this.call("ack_inbox",{alias:this.alias,message_id:B.id}),this.log(`← ${B.from_session}: ${B.content.slice(0,60)}`),this.emit("task",B),this.emit("message",B)}catch(Q){this.log(`inbox error: ${Q.message}`)}}sleep(Q){return new Promise((W)=>setTimeout(W,Q))}};zB=w});import{readFileSync as I,writeFileSync as q,existsSync as _,mkdirSync as M,readdirSync as j,statSync as P}from"fs";import{join as L}from"path";import{spawn as k,execSync as n}from"child_process";import{createInterface as KB}from"readline";var E=process.argv.slice(2),C=E[0],O=process.env.HOME||process.env.USERPROFILE||"~";function r(){return L(O,".anet","config.json")}function v(){return L(O,".anet","server","config.json")}function y(){return L(process.cwd(),".anet","nodes")}function D(){return G().token||process.env.COMMHUB_TOKEN||H().token||""}function b(Q){let W=Q||D();return W?{Authorization:`Bearer ${W}`}:{}}function H(){let Q=r();if(_(Q))try{return JSON.parse(I(Q,"utf-8"))}catch{}return{}}function a(Q){let W=L(O,".anet");M(W,{recursive:!0}),q(L(W,"config.json"),JSON.stringify(Q,null,2)+`
|
|
4
|
+
`)}function c(){let Q=v();if(_(Q))try{return JSON.parse(I(Q,"utf-8"))}catch{}return{}}function p(Q){let W=L(O,".anet","server");M(W,{recursive:!0}),q(L(W,"config.json"),JSON.stringify(Q,null,2)+`
|
|
5
|
+
`)}function A(Q){let W=L(y(),Q,"config.json");if(_(W))try{return JSON.parse(I(W,"utf-8"))}catch{}return null}function S(Q,W){let B=L(y(),Q);M(B,{recursive:!0}),q(L(B,"config.json"),JSON.stringify(W,null,2)+`
|
|
6
|
+
`)}function t(){let Q=y();if(!_(Q))return[];return j(Q).filter((W)=>_(L(Q,W,"config.json")))}function G(){let Q={_channels:[],_envs:[]};for(let W=0;W<E.length;W++){if(E[W]==="--channel"&&E[W+1]){Q._channels.push(E[++W]);continue}if(E[W]==="--env"&&E[W+1]){Q._envs.push(E[++W]);continue}if(E[W].startsWith("--")&&E[W+1]&&!E[W+1].startsWith("--"))Q[E[W].slice(2)]=E[++W]}return Q}function d(){console.log(`
|
|
7
7
|
anet — AI Agent Network CLI
|
|
8
8
|
|
|
9
9
|
anet init Configure hub URL (global, once)
|
|
@@ -23,12 +23,12 @@ Quick start:
|
|
|
23
23
|
anet init --hub http://IP:9200
|
|
24
24
|
anet start 指挥室 # Claude Code Agent
|
|
25
25
|
anet start 小明 # MiniMax Agent (runtime: agent-sdk)
|
|
26
|
-
`)}async function
|
|
27
|
-
Saved to ${r()}`),console.log("Next: anet init project")}async function
|
|
28
|
-
`);try{
|
|
29
|
-
`;if(U)
|
|
30
|
-
`;
|
|
31
|
-
`),console.log(".mcp.json: commhub → .anet/node-server.ts");else console.log(".mcp.json: commhub already set");let L
|
|
26
|
+
`)}async function NB(){let Q=G(),W=Q.hub;if(!W)W=await J("CommHub URL (e.g. http://YOUR_IP:9200)"),i();if(!W)console.error("Error: hub URL required"),process.exit(1);W=W.replace(/\/+$/,"");let B=Q.token||"";try{let Y=await(await fetch(`${W}/health`,{headers:B?{Authorization:`Bearer ${B}`}:{}})).json();console.log(`✅ CommHub v${Y.version} — ${Y.sessions} sessions, ${Y.sse_connections} SSE`)}catch(N){console.error(`❌ Cannot reach ${W}: ${N.message}`),process.exit(1)}let X=H();if(X.hub=W,B)X.token=B;a(X),console.log(`
|
|
27
|
+
Saved to ${r()}`),console.log("Next: anet init project")}async function UB(){let Q=H(),W=Q.hub;if(!W)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let B=L(process.cwd(),".anet");M(B,{recursive:!0});let X=L(B,"node-server.ts");if(!_(X)){let V=[L(new URL(".",import.meta.url).pathname,"..","..","src","node-server.ts"),L(new URL(".",import.meta.url).pathname,"..","src","node-server.ts"),L(process.argv[1],"..","..","src","node-server.ts")],R=!1;for(let T of V)if(_(T)){q(X,I(T,"utf-8")),console.log(" ✅ .anet/node-server.ts"),R=!0;break}if(!R)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=L(B,"package.json");if(!_(N)){q(N,JSON.stringify({private:!0,dependencies:{"@modelcontextprotocol/sdk":"^1.12.0"}},null,2)+`
|
|
28
|
+
`);try{n("bun install",{cwd:B,stdio:"pipe"}),console.log(" ✅ Dependencies installed")}catch{console.log(" ⚠️ Run: cd .anet && bun install")}}let Y=L(B,".env"),U=Q.token||"",Z=`COMMHUB_URL=${W}
|
|
29
|
+
`;if(U)Z+=`COMMHUB_TOKEN=${U}
|
|
30
|
+
`;q(Y,Z),console.log(`CommHub URL: ${W}${U?" (with token)":""}`);let $=L(process.cwd(),".mcp.json"),z={};if(_($))try{z=JSON.parse(I($,"utf-8"))}catch{}if(!z.mcpServers?.commhub)z.mcpServers=z.mcpServers||{},z.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},q($,JSON.stringify(z,null,2)+`
|
|
31
|
+
`),console.log(".mcp.json: commhub → .anet/node-server.ts");else console.log(".mcp.json: commhub already set");let K=L(process.cwd(),"CLAUDE.md");if(!_(K))q(K,`# Agent Network (CommHub)
|
|
32
32
|
|
|
33
33
|
## 通信方式
|
|
34
34
|
|
|
@@ -67,31 +67,31 @@ commhub_get_all_status()
|
|
|
67
67
|
- 回复指挥室用 commhub_send_task(不是 commhub_reply,reply 不推送)
|
|
68
68
|
- 不要猜 alias,用 get_all_status 查
|
|
69
69
|
`),console.log("CLAUDE.md: created");else console.log("CLAUDE.md: already exists");console.log(`
|
|
70
|
-
✅ Project ready. Next: anet init profile <id> --alias <名字> --channel server:commhub`)}function
|
|
71
|
-
`),
|
|
72
|
-
✅ Profile "${
|
|
73
|
-
Start: anet start ${
|
|
74
|
-
Profile "${
|
|
75
|
-
`);let
|
|
76
|
-
Run 'anet init' first to configure hub URL`),process.exit(1);let
|
|
77
|
-
✅ Profile "${
|
|
78
|
-
`),
|
|
79
|
-
`);try{
|
|
80
|
-
`;if(
|
|
81
|
-
`;
|
|
82
|
-
`),console.log("[anet] .mcp.json: added commhub channel server")}async function
|
|
83
|
-
`),
|
|
84
|
-
`),console.log(`Quick setup: anet resume ${
|
|
85
|
-
`)}await
|
|
70
|
+
✅ Project ready. Next: anet init profile <id> --alias <名字> --channel server:commhub`)}function LB(){let Q=E[2];if(!Q)console.error("Usage: anet init profile <id> --alias <名字> [--channel ...] [--env ...]"),process.exit(1);let W=H(),B=G(),X=B.alias||Q,N=B.hub||W.hub;if(!N)console.error("Run 'anet init' first to configure hub URL"),process.exit(1);let Y={};for(let V of B._envs){let R=V.indexOf("=");if(R>0)Y[V.slice(0,R)]=V.slice(R+1)}let U=B.runtime||"claude-code",Z={anet_version:"0.0.24",...B.name?{name:B.name}:{},runtime:U,alias:X,hub:N,...B.model?{model:B.model}:{},...B.tools?{tools:B.tools.split(",").map((V)=>V.trim())}:{},channels:B._channels.length>0?B._channels:U==="claude-code"?["server:commhub"]:[],env:Y,flags:{dangerouslySkipPermissions:!0,...U==="claude-code"?{teammateMode:B["teammate-mode"]||"in-process"}:{},...B["max-turns"]?{maxTurns:parseInt(B["max-turns"])}:{}},...B.resume?{resume:B.resume}:{},...B["resume-alias"]?{resumeAlias:B["resume-alias"]}:{}},$=L(O,".claude","channels","commhub"),z=process.cwd().replace(/\//g,"-"),K=L($,z);if(M(K,{recursive:!0}),q(L(K,".env"),`COMMHUB_ALIAS=${X}
|
|
71
|
+
`),S(Q,Z),console.log(`
|
|
72
|
+
✅ Profile "${Q}" saved`),console.log(` alias: ${X}`),console.log(` channels: ${Z.channels.join(", ")}`),Object.keys(Y).length)console.log(` env: ${Object.keys(Y).join(", ")}`);console.log(`
|
|
73
|
+
Start: anet start ${Q}`)}var F=null;function RB(){if(!F)F=KB({input:process.stdin,output:process.stdout});return F}function i(){if(F)F.close(),F=null}function J(Q,W){let B=W?` [${W}]`:"";return new Promise((X)=>{RB().question(`${Q}${B}: `,(N)=>{X(N.trim()||W||"")})})}async function EB(Q){let W=H();console.log(`
|
|
74
|
+
Profile "${Q}" not found. Let's create it:
|
|
75
|
+
`);let B=await J("Runtime (claude-code / agent-sdk)","claude-code"),X=await J("Alias",Q),N,Y=[],U=[],Z="";if(B==="agent-sdk")N=await J("Model","MiniMax-M2.7"),Y=(await J("Tools (comma-separated)","Read,Bash,Grep")).split(",").map((T)=>T.trim()).filter(Boolean);else U=(await J("Channels (comma-separated)","server:commhub")).split(",").map((T)=>T.trim()).filter(Boolean),Z=await J("Teammate mode","in-process");let $=await J("Extra env (K=V, comma-separated, empty to skip)"),z={};if($)for(let R of $.split(",")){let T=R.trim().indexOf("=");if(T>0)z[R.trim().slice(0,T)]=R.trim().slice(T+1)}let K=W.hub;if(!K)console.error(`
|
|
76
|
+
Run 'anet init' first to configure hub URL`),process.exit(1);let V={anet_version:"0.0.23",alias:X,hub:K,runtime:B,...N?{model:N}:{},...Y.length?{tools:Y}:{},channels:U,env:z,flags:{dangerouslySkipPermissions:!0,...Z?{teammateMode:Z}:{}}};return S(Q,V),i(),console.log(`
|
|
77
|
+
✅ Profile "${Q}" saved
|
|
78
|
+
`),V}function VB(Q){if((Q.runtime||"claude-code")!=="claude-code")return;if(!Q.channels?.some((K)=>K.includes("commhub")))return;let W=L(process.cwd(),".mcp.json"),B={};if(_(W))try{B=JSON.parse(I(W,"utf-8"))}catch{}if(B.mcpServers?.commhub)return;let X=L(process.cwd(),".anet"),N=L(X,"node-server.ts");if(!_(N)){M(X,{recursive:!0});let K=[L(new URL(".",import.meta.url).pathname,"..","..","src","node-server.ts"),L(new URL(".",import.meta.url).pathname,"..","src","node-server.ts"),L(process.argv[1],"..","..","src","node-server.ts")];for(let V of K)if(_(V)){q(N,I(V,"utf-8")),console.log("[anet] Created .anet/node-server.ts");break}}let Y=L(X,"package.json");if(!_(Y)){M(X,{recursive:!0}),q(Y,JSON.stringify({private:!0,dependencies:{"@modelcontextprotocol/sdk":"^1.12.0"}},null,2)+`
|
|
79
|
+
`);try{n("bun install",{cwd:X,stdio:"pipe"})}catch{}}let U=L(X,".env"),Z=H(),$=Q.token||D(),z=`COMMHUB_URL=${Q.hub||Z.hub||"http://127.0.0.1:9200"}
|
|
80
|
+
`;if($)z+=`COMMHUB_TOKEN=${$}
|
|
81
|
+
`;q(U,z),B.mcpServers=B.mcpServers||{},B.mcpServers.commhub={type:"stdio",command:"bun",args:[".anet/node-server.ts"]},q(W,JSON.stringify(B,null,2)+`
|
|
82
|
+
`),console.log("[anet] .mcp.json: added commhub channel server")}async function o(Q,W){let B=A(Q);if(!B)B=await EB(Q);let X=B.runtime||"claude-code";console.log(`[anet] ${W==="start"?"Starting new":"Resuming"} "${Q}" (${B.alias}) [${X}]...
|
|
83
|
+
`),VB(B);let Y=B.token||D();if(X==="agent-sdk"){let U=["@sleep2agi/agent-node","--alias",B.alias,"--hub",B.hub];if(B.model)U.push("--model",B.model);if(B.tools?.length)U.push("--tools",B.tools.join(","));if(B.flags?.maxTurns)U.push("--max-turns",String(B.flags.maxTurns));let Z={...process.env,...Y?{COMMHUB_TOKEN:Y}:{}};for(let[z,K]of Object.entries(B.env))Z[z]=K.replace(/^~/,O);k("npx",U,{env:Z,stdio:"inherit",shell:!0}).on("exit",(z)=>process.exit(z||0))}else{let U={...process.env,COMMHUB_ALIAS:B.alias,...Y?{COMMHUB_TOKEN:Y}:{}};for(let[z,K]of Object.entries(B.env))U[z]=K.replace(/^~/,O);let Z=[];if(B.flags.dangerouslySkipPermissions)Z.push("--dangerously-skip-permissions");for(let z of B.channels)if(z.startsWith("server:"))Z.push("--dangerously-load-development-channels",z);else Z.push("--channels",z);if(B.flags.teammateMode)Z.push("--teammate-mode",B.flags.teammateMode);if(W==="resume"){let z=B.resume||B.resumeAlias||B.name||B.alias;Z.push("--resume",z)}Z.push("-n",B.name||B.alias),k("claude",Z,{env:U,stdio:"inherit",shell:!0}).on("exit",(z)=>process.exit(z||0))}}async function l(){let Q=E[1];if(!Q){s("start");return}await o(Q,"start")}async function _B(){let Q=E[1];if(!Q){s("resume");return}let W=A(Q);if(!W){let B=G(),X=H(),N=B.hub||X.hub,Y=B.session;if(!Y)console.log(`Profile "${Q}" not found.
|
|
84
|
+
`),console.log(`Quick setup: anet resume ${Q} --session <session-id>`),console.log(`Or create: anet init profile ${Q} --alias ${Q} --resume <session-id>`),process.exit(1);if(!N)console.error("Run 'anet init' first"),process.exit(1);W={runtime:"claude-code",alias:B.alias||Q,hub:N,channels:["server:commhub"],env:{},flags:{dangerouslySkipPermissions:!0,teammateMode:"in-process"},resume:Y},S(Q,W),console.log(`[anet] Created .anet/nodes/${Q}/config.json (resume: ${Y.slice(0,8)}...)
|
|
85
|
+
`)}await o(Q,"resume")}function s(Q){let W=t();if(W.length===0){console.log("No profiles. Run: anet init profile <id> --alias <名字>");return}console.log(`
|
|
86
86
|
Profiles:
|
|
87
|
-
`);for(let
|
|
88
|
-
anet ${
|
|
89
|
-
`)}async function
|
|
87
|
+
`);for(let B of W){let X=A(B);console.log(` ${B}${X?.name?` (${X.name})`:""} → ${X?.alias} [${X?.channels.join(", ")}]`)}console.log(`
|
|
88
|
+
anet ${Q} <id>
|
|
89
|
+
`)}async function qB(){let Q=t();if(Q.length>0){console.log(`
|
|
90
90
|
Profiles:
|
|
91
|
-
`);for(let
|
|
92
|
-
`);return}let N=H(),
|
|
93
|
-
`),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let
|
|
94
|
-
`);
|
|
91
|
+
`);for(let Z of Q){let $=A(Z);console.log(` ${Z}${$?.name?` (${$.name})`:""} → ${$?.alias} [${$?.channels.join(", ")}]`)}console.log()}let W=process.cwd(),B=L(O,".claude","sessions"),X=[];if(_(B))for(let Z of j(B).filter(($)=>$.endsWith(".json")))try{let $=JSON.parse(I(L(B,Z),"utf-8"));if($.cwd===W)X.push($)}catch{}if(X.length===0&&Q.length===0){console.log("No sessions or profiles in this directory."),console.log(`Get started: anet init
|
|
92
|
+
`);return}let N=H(),Y=[],U={};if(N.hub)try{let[Z,$]=await Promise.all([fetch(`${N.hub}/api/status`,{headers:b()}).then((z)=>z.json()),fetch(`${N.hub}/health`,{headers:b()}).then((z)=>z.json())]);Y=Z.sessions||[],U=$.sse_sessions||{}}catch{}if(X.length>0){console.log(`Sessions (${W}):
|
|
93
|
+
`),console.log(" SESSION PID NETWORK"),console.log(" ──────────────────── ─────── ─────────────────────");for(let Z of X){let $=Z.sessionId.slice(0,18),z=!1;try{process.kill(Z.pid,0),z=!0}catch{}let K="(not in network)",V=W.replace(/\//g,"-"),R=L(O,".claude","channels","commhub",V,".env");if(_(R)){let u=I(R,"utf-8").match(/COMMHUB_ALIAS=(.+)/);if(u){let x=u[1].trim(),h=Y.find((BB)=>BB.alias===x),e=U[x]?"●":"○";K=h?`${x} ${h.status} ${e}`:`${x} (not registered)`}}console.log(` ${$} ${(z?`${Z.pid}`:`${Z.pid}✕`).padEnd(7)} ${K}`)}console.log()}}async function TB(){let Q=H(),W=G(),B=process.env.COMMHUB_URL||W.hub||Q.hub||"http://127.0.0.1:9200",X=process.env.COMMHUB_ALIAS||W.alias;if(!X)console.error("Error: --alias required"),process.exit(1);let{CommHub:N}=await Promise.resolve().then(() => (m(),g)),Y=new N({url:B,alias:X});Y.on("task",async(U)=>{console.log(`[${X}] ← ${U.from_session}: ${U.content.slice(0,100)}`),await Y.send(U.from_session,`[${X}] 收到: ${U.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 ${B}`)}async function HB(){let Q=E[1];if(Q==="start"){let W=G(),B=c(),X=W.port||B.port||"9200",N=W.host||B.host||"0.0.0.0",Y=W.token||B.token||D();if(!Y)Y=crypto.randomUUID().replace(/-/g,""),console.log(`[anet] Generated auth token: ${Y}`),console.log(`[anet] Save this token — agents need it to connect.
|
|
94
|
+
`);p({port:X,host:N,token:Y});let U=H();if(!U.token)U.token=Y,a(U);console.log(`[anet] Starting CommHub Server on ${N}:${X}${Y?" (auth enabled)":""}...`);let Z={...process.env,PORT:X,HOST:N};if(Y)Z.COMMHUB_AUTH_TOKEN=Y;k("bunx",["@sleep2agi/commhub-server"],{env:Z,stdio:"inherit",shell:!0}).on("exit",(z)=>process.exit(z||0))}else if(Q==="config"){let W=G(),B=c();if(W.port)B.port=W.port;if(W.host)B.host=W.host;if(W.token)B.token=W.token;if(W.port||W.host||W.token)p(B),console.log(`Server config saved: ${v()}`);console.log(JSON.stringify(B,null,2))}else console.log(`
|
|
95
95
|
anet server <command>
|
|
96
96
|
|
|
97
97
|
start [options] Start CommHub Server
|
|
@@ -102,13 +102,19 @@ Options:
|
|
|
102
102
|
--host <host> Bind address (default: 0.0.0.0)
|
|
103
103
|
--token <token> Auth token
|
|
104
104
|
|
|
105
|
-
Config: ${
|
|
105
|
+
Config: ${v()}
|
|
106
106
|
First 'anet server start' saves config, after that just 'anet server start'.
|
|
107
107
|
|
|
108
108
|
Example:
|
|
109
109
|
anet server start --port 9200 --token my-secret # 首次,保存配置
|
|
110
110
|
anet server start # 之后直接启动
|
|
111
111
|
anet server config # 查看配置
|
|
112
|
-
`)}async function
|
|
113
|
-
`),console.log(` ✅ ${
|
|
114
|
-
Imported ${
|
|
112
|
+
`)}async function OB(){let Q=H(),B=G().hub||Q.hub;if(!B)console.error("Run 'anet init' first"),process.exit(1);let X=[];try{X=(await(await fetch(`${B}/api/status`,{headers:b()})).json()).sessions||[]}catch($){console.error(`Cannot reach ${B}: ${$.message}`),process.exit(1)}if(X.length===0){console.log("No sessions in CommHub.");return}let N=X.filter(($)=>$.agent==="claude-code"&&$.project_dir);if(N.length===0){console.log("No claude-code sessions found.");return}let Y=E[1],U=Y?N.filter(($)=>$.alias===Y):N;if(U.length===0){console.log(`No session found for "${Y}".`);return}let Z=0;for(let $ of U){let z=$.project_dir,K=L(z,".anet","nodes",$.alias),V=L(K,"config.json");if(_(V)){console.log(` ⏭ ${$.alias} — already exists (${z})`);continue}if(!_(z)){console.log(` ⚠ ${$.alias} — project_dir not found: ${z}`);continue}let R={runtime:"claude-code",alias:$.alias,hub:B,channels:["server:commhub"],env:{},flags:{dangerouslySkipPermissions:!0,teammateMode:"in-process"},resume:$.resume_id};M(K,{recursive:!0}),q(V,JSON.stringify(R,null,2)+`
|
|
113
|
+
`),console.log(` ✅ ${$.alias} → ${z}/.anet/nodes/${$.alias}/config.json`),Z++}console.log(`
|
|
114
|
+
Imported ${Z} session(s). Use: cd <project> && anet resume <alias>`)}function IB(){let Q=E[1];if(Q==="ls"||Q==="list"||!Q){let W=process.cwd(),B=W.replace(/\//g,"-"),X=L(O,".claude","projects",B);if(!_(X)){console.log(`No sessions for ${W}`);return}let N=j(X).filter((Y)=>Y.endsWith(".jsonl")).sort((Y,U)=>{let Z=P(L(X,Y));return P(L(X,U)).mtimeMs-Z.mtimeMs});if(N.length===0){console.log("No sessions.");return}console.log(`
|
|
115
|
+
Sessions in ${W} (${N.length} total):
|
|
116
|
+
`),console.log(" SESSION ID SIZE MODIFIED"),console.log(" ────────────────────────────────────── ──────── ────────────────");for(let Y of N){let U=Y.replace(".jsonl",""),Z=P(L(X,Y)),$=Z.size<1024?`${Z.size}B`:Z.size<1048576?`${(Z.size/1024).toFixed(0)}KB`:`${(Z.size/1024/1024).toFixed(1)}MB`,z=Z.mtime.toISOString().replace("T"," ").slice(0,16);console.log(` ${U} ${$.padStart(8)} ${z}`)}console.log()}else console.log(`
|
|
117
|
+
anet session <command>
|
|
118
|
+
|
|
119
|
+
ls List Claude Code sessions in current project
|
|
120
|
+
`)}switch(C){case"init":if(E[1]==="project")UB();else if(E[1]==="profile")LB();else NB();break;case"server":HB();break;case"start":l();break;case"resume":_B();break;case"import":OB();break;case"session":IB();break;case"ls":case"list":qB();break;case"run":TB();break;case"--help":case"-h":case void 0:d();break;default:if(A(C))E.unshift("start"),l();else console.error(`Unknown: ${C}`),d(),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.39",
|
|
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",
|
package/src/node-server.ts
CHANGED
|
@@ -58,11 +58,21 @@ import {
|
|
|
58
58
|
CallToolRequestSchema,
|
|
59
59
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
// ── Load ~/.anet/config.json for token fallback ──────
|
|
62
|
+
function loadAnetConfig(): Record<string, string> {
|
|
63
|
+
try {
|
|
64
|
+
const p = join(HOME, ".anet", "config.json");
|
|
65
|
+
if (existsSync(p)) return JSON.parse(readFileSync(p, "utf-8"));
|
|
66
|
+
} catch {}
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
const ANET_CONFIG = loadAnetConfig();
|
|
70
|
+
|
|
71
|
+
const COMMHUB_URL = process.env.COMMHUB_URL || ANET_CONFIG.hub || "http://127.0.0.1:9200";
|
|
62
72
|
const TMUX_NAME = process.env.COMMHUB_TMUX || getTmuxSessionName();
|
|
63
73
|
const ALIAS = process.env.COMMHUB_ALIAS || TMUX_NAME || hostname();
|
|
64
74
|
const RESUME_ID = process.env.COMMHUB_RESUME_ID || process.env.CLAUDE_RESUME_ID || crypto.randomUUID();
|
|
65
|
-
const AUTH_TOKEN = process.env.COMMHUB_TOKEN || "";
|
|
75
|
+
const AUTH_TOKEN = process.env.COMMHUB_TOKEN || ANET_CONFIG.token || "";
|
|
66
76
|
|
|
67
77
|
function log(msg: string) {
|
|
68
78
|
const ts = new Date().toTimeString().slice(0, 8);
|