@ours.network/mcp 0.12.0-nightly.2 → 0.12.0-nightly.4
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/cli.js
CHANGED
|
@@ -46,12 +46,12 @@ ${z}`,d++;break;case"id":u=z.includes("\0")?void 0:z;break;case"retry":/^\d+$/.t
|
|
|
46
46
|
`,{mode:384});try{Ie.chmodSync(t,384)}catch{}return t}var zs=".ours-identity";function Ps(e){if(!e.name.trim())throw new Error("identity name must not be empty");let t={identity:e.name.trim()};return e.force&&(t.force=!0),t.expose_local=e.exposeLocal??!0,t.local_auto_accept=e.localAutoAccept??!0,t}function fu(e){let t=Ss(e);return JS(t)===zs?t:lu(t,zs)}function Ig(e,t,r=!1){let n=Ps(t),o=fu(e);if(!r&&Ie.existsSync(o))throw new Error(`${o} already exists \u2014 pass overwrite to replace it`);return Ie.mkdirSync(du(o),{recursive:!0}),Ie.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
47
47
|
`),o}import Cg from"node:process";var Ts=class{append(t){this._buffer=this._buffer?Buffer.concat([this._buffer,t]):t}readMessage(){if(!this._buffer)return null;let t=this._buffer.indexOf(`
|
|
48
48
|
`);if(t===-1)return null;let r=this._buffer.toString("utf8",0,t).replace(/\r$/,"");return this._buffer=this._buffer.subarray(t+1),ek(r)}clear(){this._buffer=void 0}};function ek(e){return br.parse(JSON.parse(e))}function Og(e){return JSON.stringify(e)+`
|
|
49
|
-
`}var Rs=class{constructor(t=Cg.stdin,r=Cg.stdout){this._stdin=t,this._stdout=r,this._readBuffer=new Ts,this._started=!1,this._ondata=n=>{this._readBuffer.append(n),this.processReadBuffer()},this._onerror=n=>{this.onerror?.(n)}}async start(){if(this._started)throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0,this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror)}processReadBuffer(){for(;;)try{let t=this._readBuffer.readMessage();if(t===null)break;this.onmessage?.(t)}catch(t){this.onerror?.(t)}}async close(){this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.listenerCount("data")===0&&this._stdin.pause(),this._readBuffer.clear(),this.onclose?.()}send(t){return new Promise(r=>{let n=Og(t);this._stdout.write(n)?r():this._stdout.once("drain",r)})}};function Ag(e){let{selfVersion:t,daemonVersion:r}=e;return!r||r===t?null:`ours: version mismatch \u2014 this plugin/connector is v${t}, the running daemon is v${r}. Everything still works; for the best experience run matching versions. The daemon is a shared singleton and is never restarted automatically, so when no other session is mid-task run \`ours-mcp stop\` (the next session starts the daemon at the new version) \u2014 or update the lagging side to match. No action is required; this is advisory.`}import{mkdirSync as tk,writeFileSync as rk,readFileSync as nk,readdirSync as ok,statSync as Ng,unlinkSync as sk,chmodSync as jg}from"node:fs";import{join as Es}from"node:path";import{homedir as ik}from"node:os";var ak="0.12.0-nightly.
|
|
49
|
+
`}var Rs=class{constructor(t=Cg.stdin,r=Cg.stdout){this._stdin=t,this._stdout=r,this._readBuffer=new Ts,this._started=!1,this._ondata=n=>{this._readBuffer.append(n),this.processReadBuffer()},this._onerror=n=>{this.onerror?.(n)}}async start(){if(this._started)throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0,this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror)}processReadBuffer(){for(;;)try{let t=this._readBuffer.readMessage();if(t===null)break;this.onmessage?.(t)}catch(t){this.onerror?.(t)}}async close(){this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.listenerCount("data")===0&&this._stdin.pause(),this._readBuffer.clear(),this.onclose?.()}send(t){return new Promise(r=>{let n=Og(t);this._stdout.write(n)?r():this._stdout.once("drain",r)})}};function Ag(e){let{selfVersion:t,daemonVersion:r}=e;return!r||r===t?null:`ours: version mismatch \u2014 this plugin/connector is v${t}, the running daemon is v${r}. Everything still works; for the best experience run matching versions. The daemon is a shared singleton and is never restarted automatically, so when no other session is mid-task run \`ours-mcp stop\` (the next session starts the daemon at the new version) \u2014 or update the lagging side to match. No action is required; this is advisory.`}import{mkdirSync as tk,writeFileSync as rk,readFileSync as nk,readdirSync as ok,statSync as Ng,unlinkSync as sk,chmodSync as jg}from"node:fs";import{join as Es}from"node:path";import{homedir as ik}from"node:os";var ak="0.12.0-nightly.4",ck=new Set(["choose_identity","create_identity","create_root_identity"]),Zg=e=>new Promise(t=>setTimeout(t,e)),uk=e=>typeof e?.method=="string"&&e.id!==void 0&&e.id!==null,lk=e=>e&&typeof e=="object"&&!("method"in e)&&e.id!==void 0&&e.id!==null,Mg=e=>{let t=e.result;return!!e.error||!!(t&&t.isError)},Dg=Number(process.env.OURS_RESTORE_TTL_MS)>0?Number(process.env.OURS_RESTORE_TTL_MS):7*24*60*60*1e3,qg=["1","true","yes","on"].includes((process.env.OURS_NO_AUTORESTORE??"").trim().toLowerCase());async function Lg(e){let t=new URL(e.url),r=(...I)=>process.stderr.write(`[ours-proxy] ${I.join(" ")}
|
|
50
50
|
`),n=I=>Number.isInteger(I)&&I>1,o=Number(process.env.OURS_CLIENT_PID),s=n(o)?o:n(process.ppid)?process.ppid:process.pid,i=(process.env.CLAUDE_CODE_SESSION_ID??"").trim()||`client:${s}`,a=null,c=null,u,l=null,d=new Map,m=null,f=qg?null:(process.env.CLAUDE_CODE_SESSION_ID??"").trim()||null,h=e.stateDir??process.env.OURS_STATE_DIR??Es(ik(),".ours"),g=Es(h,"session-restore"),v=f&&/^[A-Za-z0-9._-]{1,200}$/.test(f)?f:null,w=v?Es(g,`${v}.json`):null,x=!1,$=null;function T(I){if(w)try{tk(g,{recursive:!0,mode:448}),rk(w,JSON.stringify({claudeSessionId:f,identity:I,boundAt:new Date().toISOString()}),{mode:384}),jg(g,448),jg(w,384)}catch(F){r("restore persist failed (non-fatal):",String(F))}}function y(){if(!w)return null;try{if(Date.now()-Ng(w).mtimeMs>Dg)return null;let I=JSON.parse(nk(w,"utf8"));return(typeof I.identity=="string"?I.identity.trim():"")||null}catch{return null}}function z(){try{let I=Date.now();for(let F of ok(g)){if(!F.endsWith(".json"))continue;let G=Es(g,F);try{I-Ng(G).mtimeMs>Dg&&(sk(G),r("session-restore: pruned expired record",F))}catch{}}}catch{}}let R=null,Y=!1,ee=!1,ge=!1,st=[],lr="__ours_proxy_init__",xt=0,Ae=new Set,dr=new Set,Zt=new Rs;Zt.onmessage=I=>{let F=[],G=!1;for(let Ge of Ug(I)){let _e=Ge;if(_e.method==="notifications/initialized"&&(G=!0),uk(_e)){if(_e.method==="initialize"&&(a=_e,c)){r("absorbed re-initialize locally \u2014 upstream session kept stable"),Zt.send({jsonrpc:"2.0",id:_e.id,result:c}).catch(we=>r("local initialize reply failed:",String(we)));continue}if(_e.method==="tools/call"){let we=_e.params;we&&ck.has(we.name??"")&&typeof we.arguments?.name=="string"&&d.set(_e.id,we.arguments.name)}}F.push(_e)}if(F.length){let Ge=Array.isArray(I)?F:F[0];bu(Ge)}G&&t_()},Zt.onclose=()=>void js(0),Zt.onerror=I=>r("downstream error:",String(I));function t_(){if(x||!l)return;x=!0;let I=`__ours_proxy_restore_${++xt}__`;Ae.add(I),$=I,r("session-restore: self-recovering bound identity",`"${l}"`),bu({jsonrpc:"2.0",id:I,method:"tools/call",params:{name:"choose_identity",arguments:{name:l}}})}function bu(I){if(Y&&R){let F=R;R.send(I).catch(G=>{r("upstream send failed:",String(G)),st.push(I),xu(F,"send failed")})}else st.push(I)}function xu(I,F){if(ee||ge||R!==null&&I!==R)return;r(`upstream dropped (${F}) \u2014 reconnecting`),Y=!1;let G=R;R=null;try{G?.close?.()}catch{}n_()}function r_(I){I.onmessage=F=>{let G=[];for(let Ge of Ug(F)){let _e=Ge;if(lk(_e)){let we=_e.id,Zs=_e.result?.protocolVersion;if(Zs&&(dr.has(we)||zu(we))){u=Zs;try{R?.setProtocolVersion?.(Zs)}catch{}if(c==null&&zu(we)&&!Ae.has(we)){let pt=_e.result??null;pt&&m&&(pt.instructions=`${pt.instructions?pt.instructions+`
|
|
51
51
|
|
|
52
52
|
`:""}${m}`),c=pt}dr.delete(we)}if(Ae.has(we)){Ae.delete(we),we===$&&($=null,Mg(_e)&&(l=null,r("session-restore: re-bind refused (identity live elsewhere) \u2014 staying unbound")));continue}if(d.has(we)){let pt=d.get(we);d.delete(we),Mg(_e)||(l=pt,r("bound identity tracked:",pt),T(pt))}}G.push(_e)}if(G.length){let Ge=Array.isArray(F)?G:G[0];Zt.send(Ge).catch(_e=>r("downstream send failed:",String(_e)))}},I.onerror=F=>r("upstream error:",String(F)),I.onclose=()=>xu(I,"closed")}let zu=I=>a!=null&&a.id===I;async function Su(){e.ensureDaemon&&await e.ensureDaemon().catch(F=>r("ensureDaemon:",String(F)));let I=new Fr(t,{requestInit:{headers:{"x-ours-lease-token":i,"x-ours-client-pid":String(s),...e.apiToken?{"x-ours-api-token":e.apiToken}:{}}}});if(r_(I),await I.start(),u)try{I.setProtocolVersion?.(u)}catch{}R=I}async function ku(I,F){F&&I.id!==void 0&&Ae.add(I.id),await R.send(I)}async function n_(){if(ge||ee)return;ge=!0;let I=500;for(;;){if(ee){ge=!1;return}try{if(await Su(),a){let G=`${lr}${xt}`;dr.add(G),await ku({...a,id:G},!0),await R.send({jsonrpc:"2.0",method:"notifications/initialized"})}if(l){let G=`__ours_proxy_rebind_${++xt}__`;await ku({jsonrpc:"2.0",id:G,method:"tools/call",params:{name:"choose_identity",arguments:{name:l}}},!0)}Y=!0;let F=st.splice(0);for(let G of F)await R.send(G).catch(Ge=>r("flush failed:",String(Ge)));r("upstream reconnected",l?`(re-bound "${l}")`:""),ge=!1;return}catch(F){r("reconnect attempt failed:",String(F)),await Zg(I),I=Math.min(Math.floor(I*1.5),1e4)}}}async function js(I){if(!ee){ee=!0;try{await R?.close()}catch{}try{await Zt.close()}catch{}process.exit(I)}}process.on("SIGINT",()=>void js(0)),process.on("SIGTERM",()=>void js(0));async function o_(){let I=new URL(t.href);I.pathname="/state-dir";let F;try{F=await(await fetch(I,{signal:AbortSignal.timeout(3e3)})).json()}catch(G){r("compat handshake: could not read daemon /state-dir, proceeding:",String(G));return}m=Ag({selfVersion:ak,daemonVersion:typeof F?.version=="string"?F.version:null}),m&&r(m)}if((async()=>{e.ensureDaemon&&await e.ensureDaemon().catch(G=>r("ensureDaemon:",String(G))),await o_();let I=500;for(;;)try{await Su();break}catch(G){r("initial upstream connect failed, retrying:",String(G)),await Zg(I),I=Math.min(Math.floor(I*1.5),1e4)}Y=!0;let F=st.splice(0);for(let G of F)await R.send(G).catch(Ge=>r("flush failed:",String(Ge)));r(`upstream ready \u2014 stdio \u21C4 ${t.href}`)})(),f){z();let I=y();I&&(l=I,r("session-restore: found prior binding for this session \u2014 will self-recover",`"${I}"`))}else qg&&r("session-restore: disabled via OURS_NO_AUTORESTORE \u2014 pure in-memory binding");await Zt.start(),r("proxy started (stdio transport up)")}function Ug(e){return Array.isArray(e)?e:[e]}if(!process.env.XDG_RUNTIME_DIR&&typeof process.getuid=="function"){let e=`/run/user/${process.getuid()}`;U.existsSync(e)&&(process.env.XDG_RUNTIME_DIR=e)}var Kr=pu(),qe=Kr.stateDir,ne=Kr.port,yu=Rg(Kr,{generate:!1})?.token??null,As=()=>yu?{"x-ours-api-token":yu}:{},Br=Kr.brokerUrl,cr=bt(qe,"daemon.pid"),ir=bt(qe,"daemon.log"),Jr=pk(import.meta.url),b=(...e)=>process.stdout.write(`${e.join(" ")}
|
|
53
53
|
`),W=(...e)=>process.stderr.write(`${e.join(" ")}
|
|
54
|
-
`),ar="0.12.0-nightly.
|
|
54
|
+
`),ar="0.12.0-nightly.4";async function vu(){for(let e of["/version","/state-dir"])try{let t=new AbortController,r=setTimeout(()=>t.abort(),1500),n=await fetch(`http://127.0.0.1:${ne}${e}`,{signal:t.signal});if(clearTimeout(r),n.ok){let o=await n.json();if(o&&typeof o.version=="string")return o}}catch{}return null}function Fg(e){if(b(` cli: v${ar}`),e?.version){let t=e.version!==ar;b(` daemon: v${e.version}${e.compat?` (compat ${e.compat})`:""}`+(t?` \u26A0 differs from CLI \u2014 \`ours-mcp restart\` to load v${ar}`:""))}else b(" daemon: version unknown (running build predates /version \u2014 restart to update)")}var Ns=e=>new Promise(t=>setTimeout(t,e));function mk(){try{let e=parseInt(U.readFileSync(cr,"utf8").trim(),10);return Number.isFinite(e)?e:null}catch{return null}}function wu(e){try{return process.kill(e,0),!0}catch{return!1}}function io(){let e=mk();if(e&&wu(e))return e;if(e)try{U.rmSync(cr,{force:!0})}catch{}return null}function ur(e,t=1e3){return new Promise(r=>{let n=dk({host:"127.0.0.1",port:e}),o=s=>{n.destroy(),r(s)};n.setTimeout(t),n.once("connect",()=>o(!0)),n.once("timeout",()=>o(!1)),n.once("error",()=>o(!1))})}async function Wg(e,t=3e4){let r=Date.now()+t;for(;Date.now()<r;){if(await ur(e))return!0;await Ns(400)}return!1}async function Vg(){let e=io();if(e){b(`ours-mcp is already running (pid ${e}, port ${ne}).`);return}U.mkdirSync(qe,{recursive:!0});let t=U.openSync(ir,"a"),r=Bg(process.execPath,[Jr,"serve"],{detached:!0,stdio:["ignore",t,t],env:{...process.env,OURS_TRANSPORT:"http",OURS_PORT:String(ne),OURS_BROKER_URL:Br,OURS_STATE_DIR:qe}});r.unref(),r.pid||(W("failed to spawn the daemon."),process.exit(1)),U.writeFileSync(cr,String(r.pid)),b(`starting ours-mcp (pid ${r.pid})\u2026`),await Wg(ne)?(b(`ours-mcp is up on http://localhost:${ne}/mcp`),b(` broker: ${Br}`),b(` state: ${qe}`),b(` logs: ${ir}`)):(W(`daemon started (pid ${r.pid}) but port ${ne} did not open within 30s \u2014 check ${ir}.`),process.exit(1))}async function hk(){if(!await ur(ne)){if(!io()){U.mkdirSync(qe,{recursive:!0});let e=U.openSync(ir,"a"),t=Bg(process.execPath,[Jr,"serve"],{detached:!0,stdio:["ignore",e,e],env:{...process.env,OURS_TRANSPORT:"http",OURS_PORT:String(ne),OURS_BROKER_URL:Br,OURS_STATE_DIR:qe}});if(t.unref(),t.pid)try{U.writeFileSync(cr,String(t.pid))}catch{}}await Wg(ne)}}async function Os(){let e=io();if(!e){b("ours-mcp is not running.");return}b(`stopping ours-mcp (pid ${e})\u2026`);try{process.kill(e,"SIGTERM")}catch(t){W(`failed to signal pid ${e}: ${String(t)}`)}for(let t=0;t<25&&wu(e);t++)await Ns(200);if(wu(e)){W(`pid ${e} did not exit; sending SIGKILL.`);try{process.kill(e,"SIGKILL")}catch{}}try{U.rmSync(cr,{force:!0})}catch{}b("stopped.")}async function gk(){let e=io();if(!e){if(await ur(ne)){let n=await vu();b("ours-mcp: running (no pidfile \u2014 likely a stale process or external launcher)"),b(` url: http://localhost:${ne}/mcp (reachable)`),Fg(n);return}b("ours-mcp: stopped"),b(` cli: v${ar}`),process.exitCode=1;return}let t=await ur(ne),r=t?await vu():null;b("ours-mcp: running"),b(` pid: ${e}`),b(` url: http://localhost:${ne}/mcp ${t?"(reachable)":"(port not answering!)"}`),b(` broker: ${Br}`),b(` state: ${qe}`),b(` logs: ${ir}`),Fg(r)}async function _k(){if(b(`ours-mcp v${ar}`),await ur(ne)){let e=await vu();e?.version?b(`running daemon: v${e.version}`+(e.version!==ar?" (differs \u2014 restart to update)":"")):b("running daemon: version unknown (predates /version)")}else b("daemon: not running")}async function yk(){let e=pu(),t=ks();b(`ours-mcp setup \u2014 ${t}`),b("Enter a value, or press Enter to keep the current [bracketed] one."),b("");let r=Is({input:process.stdin,output:process.stdout}),n;try{let u=async(T,y)=>{let z=(await r.question(` ${T} [${y}]: `)).trim();return z===""?y:z},l=await u("broker URL",e.brokerUrl),d=await u("HTTP port",String(e.port)),m=await u("state dir",e.stateDir),f=await u("GC interval (ms)",String(e.gcIntervalMs)),h=await u("proxy auto-starts daemon (true/false)",String(e.autoStart)),g=await u("HTTP visibility (owner=same-user only / shared=cross-user w/ token / open=all local users)",e.apiVisibility),v=parseInt(d,10);(!Number.isFinite(v)||v<=0)&&(W(`invalid port: ${d}`),process.exit(1));let w=parseInt(f,10);(!Number.isFinite(w)||w<=0)&&(W(`invalid GC interval: ${f}`),process.exit(1));let x=h.toLowerCase()==="true"||h==="1",$=g.trim().toLowerCase();oo.includes($)||(W(`invalid visibility: ${g} (expected one of ${oo.join(", ")})`),process.exit(1)),n={brokerUrl:l,port:v,stateDir:Gg(m),gcIntervalMs:w,autoStart:x,apiVisibility:$,...e.apiToken?{apiToken:e.apiToken}:{}}}finally{r.close()}Eg(n),b(""),b(`wrote ${t} (mode 0600):`),b(JSON.stringify(n,null,2));let o=["OURS_BROKER_URL","OURS_PORT","OURS_STATE_DIR","OURS_GC_INTERVAL_MS","OURS_AUTOSTART","OURS_API_VISIBILITY","OURS_API_TOKEN"].filter(u=>process.env[u]!==void 0);o.length&&(b(""),b(`note: these env vars are set and OVERRIDE the file at runtime: ${o.join(", ")}`));let s=io();if(!s)return;let i=Is({input:process.stdin,output:process.stdout}),a=!1;try{let u=(await i.question(`
|
|
55
55
|
daemon is running (pid ${s}); restart now to apply? [y/N]: `)).trim().toLowerCase();a=u==="y"||u==="yes"}finally{i.close()}if(!a){b("not restarting \u2014 changes apply on the next `ours-mcp restart`.");return}await Os();let c=Cs(process.execPath,[Jr,"start"],{stdio:"inherit"});c.status!==0&&process.exit(c.status??1)}function hu(e,t,r){return e.includes(r)?{value:!1,set:!0}:e.includes(t)?{value:!0,set:!0}:{value:void 0,set:!1}}function gu(e,t){let r=e.indexOf(t);return r>=0&&r+1<e.length?e[r+1]:void 0}async function vk(e){let t=gu(e,"--name"),r=hu(e,"--force-bind","--no-force-bind"),n=hu(e,"--local-book","--no-local-book"),o=hu(e,"--auto-accept-local","--no-auto-accept-local"),s=e.includes("--overwrite"),i=e.includes("--print"),a=gu(e,"--path")??gu(e,"--dir")??process.cwd(),c=t!==void 0||r.set||n.set||o.set||i,u;if(c?((!t||!t.trim())&&(W("define-local-identity-file: --name is required in non-interactive mode."),process.exit(1)),u={name:t.trim(),force:r.value??!1,exposeLocal:n.value??!0,localAutoAccept:o.value??!0}):u=await wk(),i){b(JSON.stringify(Ps(u),null,2));return}let l=fu(a);if(!s&&U.existsSync(l)){c&&(W(`define-local-identity-file: ${l} already exists \u2014 pass --overwrite to replace it.`),process.exit(1));let m=Is({input:process.stdin,output:process.stdout}),f=!1;try{let h=(await m.question(`
|
|
56
56
|
${l} already exists \u2014 overwrite? [y/N]: `)).trim().toLowerCase();f=h==="y"||h==="yes"}finally{m.close()}if(!f){b("aborted \u2014 nothing written.");return}}let d=Ig(a,u,!0);b(""),b(`wrote ${d}:`),b(JSON.stringify(Ps(u),null,2))}async function wk(){b("ours-mcp define-local-identity-file \u2014 interactive"),b(`Answer the prompts; the result is written to ${bt(process.cwd(),zs)}.`),b("");let e=Is({input:process.stdin,output:process.stdout});try{let t=async(i,a)=>{let c=a?"Y/n":"y/N",u=(await e.question(` ${i} [${c}]: `)).trim().toLowerCase();return u===""?a:u==="y"||u==="yes"},r="";for(;!r;)r=(await e.question(" Identity name: ")).trim(),r||b(" (name is required)");let n=await t("Force-bind (pin pre-authorizes evicting another session)?",!1),o=await t("Add to the host-local contact book?",!0),s=await t("Auto-accept local invites/introductions?",!0);return{name:r,force:n,exposeLocal:o,localAutoAccept:s}}finally{e.close()}}async function $k(e){let t=(e[0]??"").trim();(!t||t.startsWith("--"))&&(W('usage: ours-mcp create-root "<your name>"'),process.exit(1)),await ur(ne)||(W(`create-root: the daemon is not running on port ${ne} \u2014 start it with \`ours-mcp start\`.`),process.exit(1));let r=new Fr(new URL(`http://127.0.0.1:${ne}/mcp`),{requestInit:{headers:As()}}),n=new $s({name:"ours-mcp-cli",version:ar});try{await n.connect(r);let o=await n.callTool({name:"create_root_identity",arguments:{name:t}}),s=(Array.isArray(o.content)?o.content:[]).map(i=>typeof i.text=="string"?i.text:"").join(" ").split(/\n\nAsk the user\b/)[0].replace(/^create_root_identity failed: /,"").trim();if(o.isError){if(/a root identity already exists/i.test(s)){b(`create-root: ${s.split("\u2014")[0].trim()} \u2014 nothing to do.`);return}W(`create-root failed: ${s}`),process.exit(1)}b(s)}finally{try{await r.terminateSession()}catch{}try{await n.close()}catch{}}}function Yg(e,t){t.event==="local_contact_request"?b(`[${e}] pending local introduction from ${t.from??"?"} \u2014 respond_to_introduction to approve/reject`):t.event==="pending_message"?b(`[${e}] ${t.from??"?"} queued a message awaiting introduction approval (${t.queued??"?"} queued)`):b(`[${e}] new message from ${t.from??"?"}`+(t.msg_id!==void 0?` (#${t.msg_id})`:"")+(t.date?` (${t.date})`:""))}function jt(e){W(`ours-mcp watch: ${e}`),process.exit(1)}async function bk(){try{let e=new AbortController,t=setTimeout(()=>e.abort(),1500),r=await fetch(`http://127.0.0.1:${ne}/state-dir`,{signal:e.signal});if(clearTimeout(t),r.ok){let n=await r.json();return typeof n.stateDir=="string"&&n.stateDir?Gg(n.stateDir):qe}}catch{}return null}var xk=e=>`http://127.0.0.1:${ne}/identities/${encodeURIComponent(e)}/notifications`;async function Hg(e){let t=async o=>{let s=new AbortController,i=setTimeout(()=>s.abort(),35e3),a;try{a=await fetch(`${xk(e)}?since=${o}`,{headers:As(),signal:s.signal})}finally{clearTimeout(i)}if(a.status===401&&jt(`daemon rejected the API token (401) for identity "${e}". Set OURS_API_TOKEN to the daemon's token (shared mode) or run watch as the daemon owner (owner mode).`),!a.ok)throw new Error(`daemon returned HTTP ${a.status}`);return await a.json()},r=(await t("tip")).cursor??0,n=0;for(;;)try{let o=await t(String(r));if(n=0,Array.isArray(o.events))for(let s of o.events)Yg(e,s);typeof o.cursor=="number"&&(r=o.cursor)}catch(o){n=Math.min(n+1e3,5e3),W(`ours-mcp watch: notifications stream for "${e}" hiccupped (${String(o?.message??o)}), retrying\u2026`),await Ns(n)}}async function zk(e){if(e){await Hg(e);return}let t=new Set;for(;;){try{let r=await fetch(`http://127.0.0.1:${ne}/identities`,{headers:As()});if(r.status===401&&jt("daemon rejected the API token (401). Set OURS_API_TOKEN or run watch as the daemon owner."),r.ok){let n=await r.json();for(let o of n.identities??[]){let s=typeof o?.name=="string"?o.name:void 0;s&&!t.has(s)&&(t.add(s),Hg(s))}}}catch{}await Ns(3e3)}}var _u=e=>{let t=e?.code;return t==="EACCES"||t==="EPERM"};function Sk(e,t){try{U.readdirSync(e)}catch(i){jt(`cannot watch \u2014 the daemon API is unreachable AND ${e} is not readable (${i?.code??i}). On a multi-user host, run watch as the daemon owner, or enable the daemon API (start the daemon) so watch can stream over HTTP.`)}if(t)try{U.readdirSync(bt(e,t))}catch(i){jt(`cannot watch identity "${t}" \u2014 ${bt(e,t)} is not readable (${i?.code??i}). Is the daemon running and the name correct?`)}let r=new Map,n=i=>{let a;try{a=U.readdirSync(e,{withFileTypes:!0}).filter(c=>c.isDirectory()).map(c=>c.name)}catch(c){_u(c)&&jt(`lost read access to ${e} (${c.code}) \u2014 cannot watch.`);return}for(let c of a){if(t&&c!==t)continue;let u=bt(e,c,"notifications.log"),l;try{l=U.statSync(u).size}catch(f){_u(f)&&jt(`cannot read ${u} (${f.code}) \u2014 cannot watch identity "${c}".`);continue}let d=r.get(u);if(d===void 0&&(d=i?l:0,r.set(u,d),i))continue;if(l<=d){l<d&&r.set(u,l);continue}let m;try{let f=U.openSync(u,"r"),h=Buffer.alloc(l-d);U.readSync(f,h,0,h.length,d),U.closeSync(f),m=h.toString("utf8")}catch(f){_u(f)&&jt(`cannot read ${u} (${f.code}) \u2014 cannot watch identity "${c}".`);continue}r.set(u,l);for(let f of m.split(`
|
|
57
57
|
`))if(f.trim())try{Yg(c,JSON.parse(f))}catch{}}};W(`ours-mcp watch: daemon API unreachable \u2014 falling back to file poll of ${e} (Ctrl-C to stop)`),n(!0);let o=setInterval(()=>n(!1),1e3),s=()=>{clearInterval(o),process.exit(0)};process.on("SIGINT",s),process.on("SIGTERM",s)}async function kk(){try{let e=await fetch(`http://127.0.0.1:${ne}/identities`,{headers:As()});return e.status===401&&jt("daemon rejected the API token (401). Set OURS_API_TOKEN to the daemon's token (shared mode) or run watch as the daemon owner (owner mode)."),e.status===404?"file":e.ok?"api":"file"}catch{return"file"}}async function Pk(e){let t=()=>process.exit(0);if(process.on("SIGINT",t),process.on("SIGTERM",t),await bk()!==null&&await kk()==="api"){W(`ours-mcp watch: streaming ${e?`identity "${e}"`:"all identities"} from the daemon API on port ${ne} (Ctrl-C to stop)`),await zk(e);return}Sk(qe,e)}var so="ours.service",Qg="solutions.adaptframework.ours";function Xg(){return bt(Jg(),".config","systemd","user",so)}function e_(){return bt(Jg(),"Library","LaunchAgents",`${Qg}.plist`)}function Hr(e,t){return Cs(e,t,{stdio:"inherit"}).status===0}function Tk(){let e=Xg();U.mkdirSync($u(e),{recursive:!0});let t=`[Unit]
|
package/dist/index.js
CHANGED
|
@@ -53,7 +53,7 @@ data:
|
|
|
53
53
|
|
|
54
54
|
`,e.enqueue(r.encode(s)),!0}catch(s){return this.onerror?.(s),!1}}handleUnsupportedRequest(){return this.onerror?.(new Error("Method not allowed.")),new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Method not allowed."},id:null}),{status:405,headers:{Allow:"GET, POST, DELETE","Content-Type":"application/json"}})}async handlePostRequest(e,r){try{let n=e.headers.get("accept");if(!n?.includes("application/json")||!n.includes("text/event-stream"))return this.onerror?.(new Error("Not Acceptable: Client must accept both application/json and text/event-stream")),this.createJsonErrorResponse(406,-32e3,"Not Acceptable: Client must accept both application/json and text/event-stream");let o=e.headers.get("content-type");if(!o||!o.includes("application/json"))return this.onerror?.(new Error("Unsupported Media Type: Content-Type must be application/json")),this.createJsonErrorResponse(415,-32e3,"Unsupported Media Type: Content-Type must be application/json");let s={headers:Object.fromEntries(e.headers.entries()),url:new URL(e.url)},i;if(r?.parsedBody!==void 0)i=r.parsedBody;else try{i=await e.json()}catch{return this.onerror?.(new Error("Parse error: Invalid JSON")),this.createJsonErrorResponse(400,-32700,"Parse error: Invalid JSON")}let a;try{Array.isArray(i)?a=i.map(y=>po.parse(y)):a=[po.parse(i)]}catch{return this.onerror?.(new Error("Parse error: Invalid JSON-RPC message")),this.createJsonErrorResponse(400,-32700,"Parse error: Invalid JSON-RPC message")}let c=a.some(mo);if(c){if(this._initialized&&this.sessionId!==void 0)return this.onerror?.(new Error("Invalid Request: Server already initialized")),this.createJsonErrorResponse(400,-32600,"Invalid Request: Server already initialized");if(a.length>1)return this.onerror?.(new Error("Invalid Request: Only one initialization request is allowed")),this.createJsonErrorResponse(400,-32600,"Invalid Request: Only one initialization request is allowed");this.sessionId=this.sessionIdGenerator?.(),this._initialized=!0,this.sessionId&&this._onsessioninitialized&&await Promise.resolve(this._onsessioninitialized(this.sessionId))}if(!c){let y=this.validateSession(e);if(y)return y;let v=this.validateProtocolVersion(e);if(v)return v}if(!a.some(rr)){for(let y of a)this.onmessage?.(y,{authInfo:r?.authInfo,requestInfo:s});return new Response(null,{status:202})}let l=crypto.randomUUID(),d=a.find(y=>mo(y)),p=d?d.params.protocolVersion:e.headers.get("mcp-protocol-version")??Rm;if(this._enableJsonResponse)return new Promise(y=>{this._streamMapping.set(l,{resolveJson:y,cleanup:()=>{this._streamMapping.delete(l)}});for(let v of a)rr(v)&&this._requestToStreamMapping.set(v.id,l);for(let v of a)this.onmessage?.(v,{authInfo:r?.authInfo,requestInfo:s})});let f=new TextEncoder,m,h=new ReadableStream({start:y=>{m=y},cancel:()=>{this._streamMapping.delete(l)}}),g={"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"};this.sessionId!==void 0&&(g["mcp-session-id"]=this.sessionId);for(let y of a)rr(y)&&(this._streamMapping.set(l,{controller:m,encoder:f,cleanup:()=>{this._streamMapping.delete(l);try{m.close()}catch{}}}),this._requestToStreamMapping.set(y.id,l));await this.writePrimingEvent(m,f,l,p);for(let y of a){let v,w;rr(y)&&this._eventStore&&p>="2025-11-25"&&(v=()=>{this.closeSSEStream(y.id)},w=()=>{this.closeStandaloneSSEStream()}),this.onmessage?.(y,{authInfo:r?.authInfo,requestInfo:s,closeSSEStream:v,closeStandaloneSSEStream:w})}return new Response(h,{status:200,headers:g})}catch(n){return this.onerror?.(n),this.createJsonErrorResponse(400,-32700,"Parse error",{data:String(n)})}}async handleDeleteRequest(e){let r=this.validateSession(e);if(r)return r;let n=this.validateProtocolVersion(e);return n||(await Promise.resolve(this._onsessionclosed?.(this.sessionId)),await this.close(),new Response(null,{status:200}))}validateSession(e){if(this.sessionIdGenerator===void 0)return;if(!this._initialized)return this.onerror?.(new Error("Bad Request: Server not initialized")),this.createJsonErrorResponse(400,-32e3,"Bad Request: Server not initialized");let r=e.headers.get("mcp-session-id");if(!r)return this.onerror?.(new Error("Bad Request: Mcp-Session-Id header is required")),this.createJsonErrorResponse(400,-32e3,"Bad Request: Mcp-Session-Id header is required");if(r!==this.sessionId)return this.onerror?.(new Error("Session not found")),this.createJsonErrorResponse(404,-32001,"Session not found")}validateProtocolVersion(e){let r=e.headers.get("mcp-protocol-version");if(r!==null&&!hn.includes(r))return this.onerror?.(new Error(`Bad Request: Unsupported protocol version: ${r} (supported versions: ${hn.join(", ")})`)),this.createJsonErrorResponse(400,-32e3,`Bad Request: Unsupported protocol version: ${r} (supported versions: ${hn.join(", ")})`)}async close(){this._streamMapping.forEach(({cleanup:e})=>{e()}),this._streamMapping.clear(),this._requestResponseMap.clear(),this.onclose?.()}closeSSEStream(e){let r=this._requestToStreamMapping.get(e);if(!r)return;let n=this._streamMapping.get(r);n&&n.cleanup()}closeStandaloneSSEStream(){let e=this._streamMapping.get(this._standaloneSseStreamId);e&&e.cleanup()}async send(e,r){let n=r?.relatedRequestId;if((Vt(e)||gn(e))&&(n=e.id),n===void 0){if(Vt(e)||gn(e))throw new Error("Cannot send a response on a standalone SSE stream unless resuming a previous client request");let i;this._eventStore&&(i=await this._eventStore.storeEvent(this._standaloneSseStreamId,e));let a=this._streamMapping.get(this._standaloneSseStreamId);if(a===void 0)return;a.controller&&a.encoder&&this.writeSSEEvent(a.controller,a.encoder,e,i);return}let o=this._requestToStreamMapping.get(n);if(!o)throw new Error(`No connection established for request ID: ${String(n)}`);let s=this._streamMapping.get(o);if(!this._enableJsonResponse&&s?.controller&&s?.encoder){let i;this._eventStore&&(i=await this._eventStore.storeEvent(o,e)),this.writeSSEEvent(s.controller,s.encoder,e,i)}if(Vt(e)||gn(e)){this._requestResponseMap.set(n,e);let i=Array.from(this._requestToStreamMapping.entries()).filter(([c,u])=>u===o).map(([c])=>c);if(i.every(c=>this._requestResponseMap.has(c))){if(!s)throw new Error(`No connection established for request ID: ${String(n)}`);if(this._enableJsonResponse&&s.resolveJson){let c={"Content-Type":"application/json"};this.sessionId!==void 0&&(c["mcp-session-id"]=this.sessionId);let u=i.map(l=>this._requestResponseMap.get(l));u.length===1?s.resolveJson(new Response(JSON.stringify(u[0]),{status:200,headers:c})):s.resolveJson(new Response(JSON.stringify(u),{status:200,headers:c}))}else s.cleanup();for(let c of i)this._requestResponseMap.delete(c),this._requestToStreamMapping.delete(c)}}}};var ta=class{constructor(e={}){this._requestContext=new WeakMap,this._webStandardTransport=new ea(e),this._requestListener=tp(async r=>{let n=this._requestContext.get(r);return this._webStandardTransport.handleRequest(r,{authInfo:n?.authInfo,parsedBody:n?.parsedBody})},{overrideGlobalObjects:!1})}get sessionId(){return this._webStandardTransport.sessionId}set onclose(e){this._webStandardTransport.onclose=e}get onclose(){return this._webStandardTransport.onclose}set onerror(e){this._webStandardTransport.onerror=e}get onerror(){return this._webStandardTransport.onerror}set onmessage(e){this._webStandardTransport.onmessage=e}get onmessage(){return this._webStandardTransport.onmessage}async start(){return this._webStandardTransport.start()}async close(){return this._webStandardTransport.close()}async send(e,r){return this._webStandardTransport.send(e,r)}async handleRequest(e,r,n){let o=e.auth;await tp(async i=>this._webStandardTransport.handleRequest(i,{authInfo:o,parsedBody:n}),{overrideGlobalObjects:!1})(e,r)}closeSSEStream(e){this._webStandardTransport.closeSSEStream(e)}closeStandaloneSSEStream(){this._webStandardTransport.closeStandaloneSSEStream()}};import{resolve as hE,join as Te,dirname as gE,isAbsolute as yE,basename as _E}from"node:path";import{fileURLToPath as vE}from"node:url";import{randomBytes as ov,randomInt as sv,randomUUID as bE,timingSafeEqual as wE}from"node:crypto";import{createServer as $E}from"node:http";import{brotliCompressSync as xE,brotliDecompressSync as kE}from"node:zlib";import*as j from"node:fs";import{readFile as SE,mkdir as zE,writeFile as RE}from"node:fs/promises";import{adapt_wrapper as TE}from"@adapt-toolkit/sdk/executables";import{PacketWrapperConfigurator as PE}from"@adapt-toolkit/sdk/wrappers";import{object_to_adapt_value as iv}from"@adapt-toolkit/sdk/wrapper";import{AdaptObjectLifetime as wp}from"@adapt-toolkit/sdk/common";import*as ot from"node:fs";import{randomBytes as nE}from"node:crypto";import{homedir as M_}from"node:os";import{resolve as ra,join as rp,dirname as q_,basename as oE}from"node:path";var D_=["owner","shared","open"],Un={brokerUrl:"wss://broker1.ours.network",port:3050,stateDir:ra(M_(),".ours"),gcIntervalMs:36e5,autoStart:!1,apiVisibility:"owner"};function sE(){return process.env.OURS_CONFIG??rp(M_(),".ours","config.json")}function iE(){let t;try{t=ot.readFileSync(sE(),"utf8")}catch{return{}}let e;try{e=JSON.parse(t)}catch{return{}}let r={};return typeof e.brokerUrl=="string"&&(r.brokerUrl=e.brokerUrl),typeof e.port=="number"&&Number.isFinite(e.port)&&(r.port=e.port),typeof e.stateDir=="string"&&(r.stateDir=ra(e.stateDir)),typeof e.gcIntervalMs=="number"&&Number.isFinite(e.gcIntervalMs)&&(r.gcIntervalMs=e.gcIntervalMs),typeof e.autoStart=="boolean"&&(r.autoStart=e.autoStart),typeof e.apiVisibility=="string"&&D_.includes(e.apiVisibility)&&(r.apiVisibility=e.apiVisibility),typeof e.apiToken=="string"&&e.apiToken.trim()&&(r.apiToken=e.apiToken.trim()),r}function aE(){let t=process.env.OURS_API_VISIBILITY?.trim().toLowerCase();return t&&D_.includes(t)?t:void 0}function cE(t){let e=process.env[t];if(e!==void 0)return e==="1"||e.toLowerCase()==="true"}function j_(t){let e=process.env[t];if(e===void 0)return;let r=parseInt(e,10);return Number.isNaN(r)?void 0:r}function V_(){let t=iE();return{brokerUrl:process.env.OURS_BROKER_URL??t.brokerUrl??Un.brokerUrl,port:j_("OURS_PORT")??t.port??Un.port,stateDir:ra(process.env.OURS_STATE_DIR??t.stateDir??Un.stateDir),gcIntervalMs:j_("OURS_GC_INTERVAL_MS")??t.gcIntervalMs??Un.gcIntervalMs,autoStart:cE("OURS_AUTOSTART")??t.autoStart??Un.autoStart,apiVisibility:aE()??t.apiVisibility??Un.apiVisibility,apiToken:process.env.OURS_API_TOKEN?.trim()||t.apiToken}}var uE="daemon-token";function np(t){return rp(t.stateDir,uE)}function L_(t){let e=process.env.OURS_API_TOKEN?.trim();return e||t.apiToken?.trim()||void 0}function U_(t,e={}){let r=process.env.OURS_API_TOKEN?.trim();if(r)return{token:r,source:"env"};let n=t.apiToken?.trim();if(n)return{token:n,source:"config"};let o=np(t);try{let i=ot.readFileSync(o,"utf8").trim();if(i)return{token:i,source:"file"}}catch{}if(!e.generate)return null;let s=nE(32).toString("hex");try{ot.mkdirSync(q_(o),{recursive:!0}),ot.writeFileSync(o,s+`
|
|
55
55
|
`,{mode:384}),ot.chmodSync(o,384)}catch{}return{token:s,source:"generated"}}var Z_=".ours-identity";function op(t){if(!t.name.trim())throw new Error("identity name must not be empty");let e={identity:t.name.trim()};return t.force&&(e.force=!0),e.expose_local=t.exposeLocal??!0,e.local_auto_accept=t.localAutoAccept??!0,e}function lE(t){let e=ra(t);return oE(e)===Z_?e:rp(e,Z_)}function F_(t,e,r=!1){let n=op(e),o=lE(t);if(!r&&ot.existsSync(o))throw new Error(`${o} already exists \u2014 pass overwrite to replace it`);return ot.mkdirSync(q_(o),{recursive:!0}),ot.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
56
|
-
`),o}import{basename as dE,extname as pE}from"node:path";var fE={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml",".bmp":"image/bmp",".ico":"image/x-icon",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".json":"application/json",".csv":"text/csv",".html":"text/html",".xml":"application/xml",".zip":"application/zip",".gz":"application/gzip",".tar":"application/x-tar",".mp3":"audio/mpeg",".wav":"audio/wav",".mp4":"video/mp4",".mov":"video/quicktime"};function B_(t){return fE[pE(t).toLowerCase()]??"application/octet-stream"}function H_(t){let e=dE(t).replace(/[^A-Za-z0-9._-]/g,"_");return e.length?e.slice(0,200):"file"}function mE(t){let{selfVersion:e,daemonVersion:r}=t;return!r||r===e?null:`ours: version mismatch \u2014 this plugin/connector is v${e}, the running daemon is v${r}. Everything still works; for the best experience run matching versions. The daemon is a shared singleton and is never restarted automatically, so when no other session is mid-task run \`ours-mcp stop\` (the next session starts the daemon at the new version) \u2014 or update the lagging side to match. No action is required; this is advisory.`}var ts="0.12.0-nightly.
|
|
56
|
+
`),o}import{basename as dE,extname as pE}from"node:path";var fE={".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml",".bmp":"image/bmp",".ico":"image/x-icon",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".json":"application/json",".csv":"text/csv",".html":"text/html",".xml":"application/xml",".zip":"application/zip",".gz":"application/gzip",".tar":"application/x-tar",".mp3":"audio/mpeg",".wav":"audio/wav",".mp4":"video/mp4",".mov":"video/quicktime"};function B_(t){return fE[pE(t).toLowerCase()]??"application/octet-stream"}function H_(t){let e=dE(t).replace(/[^A-Za-z0-9._-]/g,"_");return e.length?e.slice(0,200):"file"}function mE(t){let{selfVersion:e,daemonVersion:r}=t;return!r||r===e?null:`ours: version mismatch \u2014 this plugin/connector is v${e}, the running daemon is v${r}. Everything still works; for the best experience run matching versions. The daemon is a shared singleton and is never restarted automatically, so when no other session is mid-task run \`ours-mcp stop\` (the next session starts the daemon at the new version) \u2014 or update the lagging side to match. No action is required; this is advisory.`}var ts="0.12.0-nightly.4",fr=V_(),qe=fr.stateDir,ca=fr.brokerUrl,EE=process.env.OURS_TRANSPORT??"http",sp=fr.port,J_=fr.gcIntervalMs,pp=fr.apiVisibility,R=(...t)=>process.stderr.write(`ours: ${t.join(" ")}
|
|
57
57
|
`);function IE(){if(pp==="open")return null;if(pp==="shared"){let t=L_(fr);if(!t)throw new Error(`apiVisibility=shared requires an operator-supplied token so it can be distributed to cross-user agents \u2014 set OURS_API_TOKEN or "apiToken" in config (${np(fr)} is not used for shared mode). Use apiVisibility=owner for a same-user-only auto-token, or =open to disable auth.`);return t}return U_(fr,{generate:!0}).token}var K_=IE();function OE(t){let e=t.headers["x-ours-api-token"];if(typeof e=="string"&&e)return e;let r=t.headers.authorization;if(typeof r=="string"){let n=/^Bearer\s+(.+)$/i.exec(r.trim());if(n)return n[1]}}function NE(t){if(K_===null)return!0;let e=OE(t);if(!e)return!1;let r=Buffer.from(e),n=Buffer.from(K_);return r.length===n.length&&wE(r,n)}function na(t,e){return NE(t)?!0:(e.writeHead(401,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"unauthorized"})),!1)}var CE=/^[A-Za-z0-9 _.@-]{1,64}$/,ua="contact-book";function la(t){return CE.test(t)?t==="."||t===".."||t.includes("/")||t.includes("\\")?"invalid name":t===ua?`"${ua}" is reserved for the local contact book`:t==="root.json"||t==="bindings.json"?`"${t}" is reserved for daemon bookkeeping`:null:"name must be 1-64 chars of letters, digits, space, _ . @ or -"}function AE(){let t=gE(vE(import.meta.url)),e=process.env.OURS_UNIT_DIR,r=process.env.OURS_ADVERTISE_MIGRATE==="0",n=s=>r?[`${s}-nocap`]:[s],o=e?n(hE(e)):[Te(t,"mufl_code"),Te(t,"..","mufl_code")].flatMap(n);for(let s of o){if(!j.existsSync(s))continue;let i=j.readdirSync(s).find(a=>a.endsWith(".muflo"));if(i){let a=i.slice(0,-6),c=new Uint8Array(j.readFileSync(Te(s,i)));return{dir:s,hash:a,contents:c}}}throw new Error(`no compiled .muflo packet found (looked in: ${o.join(", ")})`+(r?' \u2014 OURS_ADVERTISE_MIGRATE=0 requires a "<dir>-nocap" packet variant (compiled with $advertise = [core.e2e] only); build it or unset the env.':""))}var rs,ns,J=new Map,gt=null,fp=null,Re=new Map,fa=new Set,st=new Map;function mp(t){if(!Number.isInteger(t)||t<=0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function av(t){for(let e of Re.values())if(e.token===t)return e}var W_=()=>Te(qe,"bindings.json");function as(){try{j.mkdirSync(qe,{recursive:!0});let t=`${W_()}.tmp`;j.writeFileSync(t,JSON.stringify({pid:process.pid,bound:[...Re.keys()],holders:[...Re.values()].map(e=>({identity:e.identity,pid:e.pid}))})),j.renameSync(t,W_())}catch(t){R("failed to persist bindings snapshot:",String(t))}}var cv=t=>Te(qe,t),$p=t=>Te(t,"identity.key"),Qr=t=>Te(t,"state_data.bin"),uv=t=>Te(t,"notifications.log"),hp=t=>Te(t,"unread.json"),jE=t=>Te(t.dir,"files");function ZE(){return j.existsSync(qe)?j.readdirSync(qe,{withFileTypes:!0}).filter(t=>t.isDirectory()&&j.existsSync($p(Te(qe,t.name)))).map(t=>t.name):[]}var ss=()=>Te(qe,ua),Y_=()=>Te(ss(),"registrar.key"),gp=()=>Te(ss(),"book.json");function ma(){try{let t=JSON.parse(j.readFileSync(gp(),"utf8"));return t&&typeof t.entries=="object"?t.entries:{}}catch{return{}}}function lv(t){j.mkdirSync(ss(),{recursive:!0});let e=`${gp()}.tmp`;j.writeFileSync(e,JSON.stringify({v:1,entries:t},null,2),{mode:384}),j.renameSync(e,gp())}function Bn(t){return et(e=>Buffer.from(xe(t,"::actor::export_address_document",e).GetBinary()))}function dv(t){return et(e=>Buffer.from(xe(t,"::actor::export_signing_secret",e).Serialize()).toString("hex"))}async function pv(t){if(!gt)throw new Error("registrar is not available");let e=Bn(t),r=await Q(async o=>{let s=await L(gt,"::actor::sign_book_entry",{name:t.name,ad:gt.pw.packet.NewBinaryFromBuffer(e).Attach(o)},o);return Buffer.from(s.Reduce("sig").GetBinary()).toString("base64url")}),n=ma();n[t.name]={v:1,name:t.name,container_id:t.cid,address_document:e.toString("base64url"),published_at:new Date().toISOString(),registrar_sig:r},lv(n),R(`[${t.name}] published to the local contact book`)}function fv(t){let e=ma();t in e&&(delete e[t],lv(e),R(`[${t}] removed from the local contact book`))}async function mv(t){if(!fp)throw new Error("registrar is not available");await Q(async e=>{await L(t,"::actor::pin_registrar",{registrar_ad:t.pw.packet.NewBinaryFromBuffer(fp).Attach(e)},e)})}var da=()=>Te(qe,"root.json"),le=null;function ME(){try{let t=JSON.parse(j.readFileSync(da(),"utf8"));return typeof t.name=="string"?t.name:null}catch{return null}}function qE(t){j.mkdirSync(qe,{recursive:!0});let e=`${da()}.tmp`;j.writeFileSync(e,JSON.stringify({v:1,name:t})),j.renameSync(e,da())}function hv(){j.rmSync(da(),{force:!0})}function zt(t){return et(e=>{let r=xe(t,"::actor::describe_identity",e);return{bio:r.Reduce("bio").Visualize(),persona:r.Reduce("persona").Visualize(),roleId:r.Reduce("role_id").Visualize(),rootCid:r.Reduce("root_cid").Visualize(),rootName:r.Reduce("root_name").Visualize(),monitoringEnabled:r.Reduce("monitoring_enabled").GetBoolean()}})}async function sa(t,e){await Q(async r=>{let n=Bn(e),o=await L(t,"::actor::sign_delegation",{role_ad:t.pw.packet.NewBinaryFromBuffer(n).Attach(r),role_id:e.name},r),s=Buffer.from(o.Reduce("cert").GetBinary()),i=await L(t,"::actor::export_root_profile",{},r),a=Buffer.from(i.Reduce("profile").GetBinary()),c=Bn(t);await L(e,"::actor::set_delegation",{cert:e.pw.packet.NewBinaryFromBuffer(s).Attach(r),root_ad:e.pw.packet.NewBinaryFromBuffer(c).Attach(r),root_profile:e.pw.packet.NewBinaryFromBuffer(a).Attach(r)},r)}),R(`[${e.name}] delegated as a role under root "${t.name}"`)}function DE(t,e){if(!le||!J.has(le))return null;let r=J.get(e)??[...J.values()].find(o=>o.cid===e);if(!r||r.name===t.name)return null;let n=o=>o.name===le||zt(o).roleId!=="";return n(t)&&n(r)?r:null}async function VE(t,e,r){let n=Bn(e);return await Q(async o=>{await L(t,"::actor::connect_sibling",{name:e.name,target_ad:t.pw.packet.NewBinaryFromBuffer(n).Attach(o),text:r},o)}),`"${e.name}" was not a contact yet \u2014 connected as an intra-root sibling (delegation-cert auto-accept) and delivered the message.`}async function LE(t,e,r){if(!gt)throw new Error(`"${e}" is not a contact, and the local contact book is unavailable.`);let n=ma(),o=n[e]??Object.values(n).find(c=>c.container_id===e);if(!o)throw new Error(`"${e}" is not a contact and has no local contact-book entry. Use generate_invite/add_contact for remote peers, or list_local_contact_book to see local ones.`);if(o.container_id===t.cid)throw new Error("that contact-book entry is this identity itself.");let s=Buffer.from(o.address_document,"base64url"),i=Buffer.from(o.registrar_sig,"base64url"),a=Bn(t);return await Q(async c=>{let u=await L(gt,"::actor::mint_introduction",{joiner_ad:gt.pw.packet.NewBinaryFromBuffer(a).Attach(c),target_ad:gt.pw.packet.NewBinaryFromBuffer(s).Attach(c)},c),l=Buffer.from(u.Reduce("intro").GetBinary());await L(t,"::actor::connect_local",{name:o.name,target_ad:t.pw.packet.NewBinaryFromBuffer(s).Attach(c),intro:t.pw.packet.NewBinaryFromBuffer(l).Attach(c),entry_sig:t.pw.packet.NewBinaryFromBuffer(i).Attach(c),text:r},c)}),`"${o.name}" was not a contact yet \u2014 connected via the local contact book and sent the message with the introduction. If "${o.name}" requires approval for local introductions, delivery completes once they approve.`}function cs(t){return et(e=>{let r=xe(t,"::a2a_messaging::get_monitoring_status",e),n=xe(t,"::actor::get_monitoring_status",e);return{enabled:r.Reduce("monitored").GetBoolean(),proxyCid:r.Reduce("proxy_cid").Visualize(),proxyPending:r.Reduce("proxy_pending").GetBoolean(),copiesQueued:parseInt(n.Reduce("copies_queued").Visualize(),10)||0,controlQueued:parseInt(n.Reduce("control_queued").Visualize(),10)||0}})}async function os(t,e,r){await Q(async n=>{await L(t,"::a2a_control::send_control",{contact:e,payload:JSON.stringify(r)},n)})}function gv(t){try{return et(e=>{let r=xe(t,"::a2a_capabilities::get_manifest",e).Reduce("capabilities");return r.IsNil()?[]:[...r.GetKeys()].map(n=>typeof n=="string"?n:n.Visualize())})}catch{return[]}}function UE(t){let e="",r="",n="",o="",s=[];try{et(i=>{let a=xe(t,"::a2a_capabilities::get_manifest",i),c=l=>{let d=a.Reduce(l);return d.IsNil()?"":d.Visualize()};e=c("app_id"),r=c("name"),n=c("description"),o=c("version");let u=a.Reduce("capabilities");u.IsNil()||(s=[...u.GetKeys()].map(l=>typeof l=="string"?l:l.Visualize()))})}catch{}return{app_id:e,name:r,description:n,version:o,capabilities:s,monitoring_status:cs(t).proxyCid?"bound":"unbound"}}function FE(t){let e=[];for(let r of J.values()){if(r.name===t.name)continue;let n=zt(r);n.rootCid===t.cid&&e.push({name:r.name,cid:r.cid,role_id:n.roleId,bio:n.bio,monitoring:n.monitoringEnabled,capabilities:gv(r)})}return e}function yv(t){try{ns.remove_packet(t.cid)}catch(e){R(`remove_packet(${t.cid}) failed:`,String(e))}J.delete(t.name);try{fv(t.name)}catch(e){R(`failed to unpublish "${t.name}" from the contact book:`,String(e))}Re.has(t.name)&&(Re.delete(t.name),as()),t.name===le&&(le=null,hv());try{j.rmSync(t.dir,{recursive:!0,force:!0})}catch(e){return`deleting ${t.dir} failed: ${String(e)}`}return null}var xp=!0,_v=xp?2:1,BE=6e5,yp=new Map,_p=(t,e)=>`${t}:${e}`;function vv(t,e,r){e&&yp.set(_p(t,e),{response:r,at:Date.now()})}function HE(t,e){if(!e)return;let r=yp.get(_p(t,e));if(r){if(Date.now()-r.at>BE){yp.delete(_p(t,e));return}return r.response}}async function GE(t,e,r){let n=is(r);if(!n||typeof n!="object")return;let o=n,s=o.result;if(s&&typeof s=="object"&&s.pending===!0)return;let i=String(o.req_id??"");i&&(await os(t,e,o),vv(e,i,o))}async function JE(t,e,r,n,o,s){let i;try{let d=JSON.parse(o);if(!d||typeof d!="object")throw new Error("not an object");i=d}catch{R(`[${t.name}] dropping unparseable control payload from ${n}`);return}if(i.v===1){i.t==="get_manifest"?await os(t,r,{v:1,t:"res",id:i.id??null,ok:!0,manifest:{...UE(t),protocol_version:_v}}):await os(t,r,{v:1,t:"res",id:i.id??null,error:{code:"protocol_upgraded",message:"This host now speaks the ours control-envelope protocol (v2). Refresh / cache-bust the control plane."}});return}let a=String(i.req_id??""),c=HE(r,a);if(c){await os(t,r,c);return}let u=i.args&&typeof i.args=="object"?i.args:{},l={cap:String(i.cap??""),verb:String(i.verb??""),args:u,req_id:a};await Q(async d=>{let p;try{p=await L(t,"::actor::process_control_envelope",{sender_id:e,sender_name:n,envelope:l,date:s},d)}catch(f){R(`[${t.name}] dispatch of "${l.cap}.${l.verb}" from ${n} failed:`,String(f));return}if(await GE(t,r,p),l.cap==="core.monitoring"&&l.verb==="bind")try{let f=is(p);f&&(f.ok===!0||f.$ok===!0)&&eI(t,r)}catch{}})}async function KE(t){for(;;)if(await Q(async r=>{let o=(await L(t,"::actor::get_control_requests",{},r)).Reduce("requests"),s=o.GetKeys();if(s.length===0)return!0;for(let i=0;i<s.length;i++){let a=o.Reduce(i),c=a.Reduce("sender_cid");await JE(t,c,c.Visualize(),a.Reduce("sender_name").Visualize(),a.Reduce("payload").Visualize(),a.Reduce("date"))}return!1}))return}function WE(){return String(sv(0,1e6)).padStart(6,"0")}var Xr=new Map;function ha(t){return[...J.values()].find(e=>e.cid===t)}async function us(t,e){let r=e.Reduce("target").Visualize(),n=is(e.Reduce("response"));if(!n||typeof n!="object")return;await os(t,r,n);let o=String(n.req_id??"");o&&vv(r,o,n)}async function YE(t,e,r,n){try{if(J.has(e)){R(`[${t.name}] host_provision_child("${e}") rejected: name exists (settles via sweep timeout)`);return}let o=await bp(e);await Q(async s=>{r&&await L(o,"::a2a_messaging::set_my_bio",{bio:r},s),await sa(t,o);let i=zt(o).roleId,a=xe(o,"::actor::export_address_document_native",s),c=await L(t,"::a2a_cluster::register_provisioned_child",{pending_handle:n,role_id:i,child_ad:a},s);await us(t,c)})}catch(o){R(`[${t.name}] host_provision_child("${e}") failed (settles via sweep timeout):`,String(o))}}async function QE(t,e,r){try{let n=ha(e.Visualize());if(n){let o=yv(n);o&&R(`[${t.name}] host_destroy_child teardown warning:`,o)}Xr.delete(e.Visualize()),await Q(async o=>{let s=await L(t,"::a2a_cluster::confirm_child_destroyed",{pending_handle:r,cid:e},o);await us(t,s)})}catch(n){R(`[${t.name}] host_destroy_child failed (settles via sweep timeout):`,String(n))}}async function XE(t,e,r){try{let n=ha(e.Visualize());if(!n){R(`[${t.name}] host_mint_child_invite: unknown child ${e.Visualize()} (settles via sweep timeout)`);return}await Q(async o=>{let s=await L(n,"::a2a_messaging::generate_invite",{},o),i=t.pw.packet.NewBinaryFromBuffer(Buffer.from(s.Reduce("invite").GetBinary())).Attach(o),a=await L(t,"::a2a_cluster::register_child_invite",{pending_handle:r,invite:i},o);await us(t,a)})}catch(n){R(`[${t.name}] host_mint_child_invite failed (settles via sweep timeout):`,String(n))}}async function vp(t,e,r,n){await Q(async o=>{if(e){n&&await L(t,"::a2a_messaging::host_register_monitoring_cp",{cp_ad:n},o);let s=WE();await L(t,"::a2a_messaging::set_proxy_pending",{code:s,proxy:r},o),await L(t,"::a2a_messaging::verify_proxy_code",{code:s,sender:r},o),Xr.set(t.cid,r??"")}else await L(t,"::a2a_messaging::host_clear_child_monitoring",{},o),Xr.delete(t.cid)})}async function Q_(t,e,r,n,o,s){try{let i=ha(e.Visualize());if(!i){R(`[${t.name}] host_set_child_monitoring: unknown child ${e.Visualize()} (settles via sweep timeout)`);return}r?await vp(i,!0,o?.Visualize(),s):await vp(i,!1),await Q(async a=>{let c=await L(t,"::a2a_cluster::confirm_child_monitoring",{pending_handle:n,cid:e,enabled:r},a);await us(t,c)})}catch(i){R(`[${t.name}] host_set_child_monitoring failed (settles via sweep timeout):`,String(i))}}async function eI(t,e){for(let[r,n]of[...Xr.entries()]){if(n===e)continue;let o=ha(r);if(!o){Xr.delete(r);continue}await vp(o,!1).catch(s=>R(`[${t.name}] CP-rebind clear of child ${r} failed:`,String(s)))}}function tI(t,e){let r=[];for(let n of J.values()){if(n.name===t.name)continue;let o=zt(n);if(o.rootCid!==t.cid)continue;let s=xe(n,"::actor::export_address_document_native",e);r.push({cid:s.Reduce("identity").Reduce("container_id"),role_id:o.roleId,name:n.name,bio:o.bio,persona:o.persona,caps:gv(n),child_ad:s})}return r}var ip=new Set;async function bv(t){if(!ip.has(t.name)){ip.add(t.name);try{await Q(async e=>{await L(t,"::a2a_cluster::reconcile",{pending_handle:"",children:tI(t,e)},e);let n=(await L(t,"::a2a_cluster::sweep_and_settle",{},e)).Reduce("settled"),o=n.GetKeys();for(let s=0;s<o.length;s++)await us(t,n.Reduce(s))})}catch(e){R(`[${t.name}] cluster sweep failed:`,String(e))}finally{ip.delete(t.name)}}}var rI=6e4;function nI(){setInterval(()=>{if(xp)for(let t of J.values())zt(t).roleId===""&&bv(t)},rI).unref()}function oI(){for(let t of J.values())if(zt(t).roleId!=="")try{let e=cs(t).proxyCid;e&&Xr.set(t.cid,e)}catch(e){Xr.set(t.cid,""),R(`[${t.name}] monitoredChildren rebuild read failed (added clear-on-repoint):`,String(e))}}var ap=new Set;async function kp(t){if(!ap.has(t.name)){ap.add(t.name);try{await KE(t)}catch(e){R(`[${t.name}] control dispatch failed:`,String(e))}finally{ap.delete(t.name)}if(J.has(t.name)&&cs(t).controlQueued>0)return kp(t)}}async function sI(){j.mkdirSync(ss(),{recursive:!0});let t;try{t=j.readFileSync(Y_(),"utf8").trim()}catch{}let e=ov(24).toString("hex");gt=await Sp(ua,e,ss(),!1,t),t||j.writeFileSync(Y_(),dv(gt),{mode:384}),fp=Bn(gt),R(`contact-book registrar ready (${gt.cid})`)}function iI(t){try{return j.existsSync(Qr(t))&&j.statSync(Qr(t)).size>0}catch{return!1}}function pa(t){try{let e=et(n=>Buffer.from(xe(t,"::actor::export_state",n).Serialize()));j.mkdirSync(t.dir,{recursive:!0});let r=`${Qr(t.dir)}.tmp`;j.writeFileSync(r,e),j.renameSync(r,Qr(t.dir))}catch(e){R(`[${t.name}] failed to save state:`,String(e))}}function aI(t){let e=[],r=t.Reduce("degraded");if(r.IsNil())return e;for(let n=0;;n++){let o=r.Reduce(n);if(o.IsNil())break;e.push({cid:o.Reduce("container_id").Visualize(),name:o.Reduce("name").Visualize(),attempts:Number(o.Reduce("attempts").Visualize()),queued:Number(o.Reduce("queued").Visualize())})}return e}function cI(t){let e=[],r=t.Reduce("queues");if(r.IsNil())return e;for(let n=0;;n++){let o=r.Reduce(n);if(o.IsNil())break;e.push({cid:o.Reduce("container_id").Visualize(),queued:Number(o.Reduce("queued").Visualize()),degraded:o.Reduce("degraded").GetBoolean()})}return e}async function wv(t,e){try{let r=await Q(async n=>{let o=await L(t,"::a2a_messaging::flush_deferred",{contact:e},n);return Number(o.Reduce("flushed").Visualize())});r>0&&R(`[${t.name}] flushed ${r} deferred message(s) to ${e.slice(0,12)}\u2026`)}catch(r){R(`[${t.name}] deferred flush to ${e.slice(0,12)}\u2026 failed:`,String(r))}}async function $v(t){try{let e=await Q(async n=>{let o=await L(t,"::a2a_messaging::restore_degraded_contacts",{},n);return Number(o.Reduce("requested").Visualize())});e>0&&R(`[${t.name}] contact restore requested for ${e} degraded contact(s)`);let r=et(n=>cI(xe(t,"::a2a_messaging::list_deferred_queues",n)));for(let n of r)n.degraded||await wv(t,n.cid)}catch(e){R(`[${t.name}] contact-restore sweep failed:`,String(e))}}var ia=new Map;function uI(t){let e=ia.get(t);if(!(!e||e.size===0))for(let r of[...e])try{r()}catch{}}function lI(t,e){return new Promise(r=>{let n=ia.get(t);n||(n=new Set,ia.set(t,n));let o=!1,s=()=>{o||(o=!0,n.delete(i),n.size===0&&ia.delete(t),clearTimeout(a),r())},i=s,a=setTimeout(s,e);n.add(i)})}function Xe(t,e){try{j.mkdirSync(t.dir,{recursive:!0}),j.appendFileSync(uv(t.dir),JSON.stringify(e)+`
|
|
58
58
|
`)}catch(r){R(`[${t.name}] failed to append notifications.log:`,String(r))}uI(t.name)}function oa(t,e){let r=t.Reduce(e);return r.IsNil()?"":Buffer.from(r.GetBinary()).toString("hex")}var dI=Number(process.env.OURS_NOTIFY_LONGPOLL_MS)>0?Number(process.env.OURS_NOTIFY_LONGPOLL_MS):25e3,pI=250;function cp(t){try{return j.statSync(t).size}catch{return 0}}function fI(t,e,r){if(r<=e)return{events:[],cursor:e};let n=Buffer.alloc(r-e),o=0;try{let c=j.openSync(t,"r");try{o=j.readSync(c,n,0,n.length,e)}finally{j.closeSync(c)}}catch{return{events:[],cursor:e}}let s=n.subarray(0,o),i=s.lastIndexOf(10);if(i===-1)return{events:[],cursor:e};let a=[];for(let c of s.subarray(0,i+1).toString("utf8").split(`
|
|
59
59
|
`))if(c.trim())try{a.push(JSON.parse(c))}catch{}return{events:a,cursor:e+i+1}}async function mI(t,e,r,n){let o=uv(Te(qe,r)),s=(u,l)=>{e.writableEnded||(e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({cursor:u,events:l})))};if(n===null||n==="tip"){s(cp(o),[]);return}let i=parseInt(n,10);if(!Number.isFinite(i)||i<0){e.writableEnded||(e.writeHead(400,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"invalid since cursor"})));return}let a=!1;t.on("close",()=>{a=!0});let c=Date.now()+dI;for(;!a;){let u=cp(o);if(i>u&&(i=0),u>i){let{events:l,cursor:d}=fI(o,i,u);if(l.length>0){s(d,l);return}i=d}if(Date.now()>=c)break;await lI(r,Math.min(pI,c-Date.now()))}a||s(cp(o),[])}function Yr(t){try{let{unread:e,unreadFiles:r}=et(s=>{let a=aa(xe(t,"::actor::list_incoming_messages",s)).filter(l=>l.status==="unread"),c=xe(t,"::actor::list_incoming_files",s),u=[];if(!c.IsNil())for(let l=0;;l++){let d=c.Reduce(l);if(d.IsNil())break;d.Reduce("status").Visualize()==="unread"&&u.push({file_id:d.Reduce("file_id").Visualize(),from:d.Reduce("sender_name").Visualize(),filename:d.Reduce("filename").Visualize(),mime:d.Reduce("mime").Visualize(),wire_id:d.Reduce("wire_id").Visualize()})}return{unread:a,unreadFiles:u}}),n={count:e.length,recent:e.slice(-10).map(s=>({from:s.sender_name,msg_id:s.msg_id,date:s.date})),files:r.length,unread_files:r.slice(-10)};j.mkdirSync(t.dir,{recursive:!0});let o=`${hp(t.dir)}.tmp`;j.writeFileSync(o,JSON.stringify(n)),j.renameSync(o,hp(t.dir))}catch(e){R(`[${t.name}] failed to refresh unread snapshot:`,String(e))}}function hI(){let t=[],e=[];try{e=j.readdirSync(qe,{withFileTypes:!0})}catch{return{identities:t}}for(let r of e){if(!r.isDirectory()||la(r.name)!==null)continue;let n;try{n=JSON.parse(j.readFileSync(hp(Te(qe,r.name)),"utf8"))}catch{continue}let o=Number.isSafeInteger(n.count)&&Number(n.count)>=0?Number(n.count):0,s=Number.isSafeInteger(n.files)&&Number(n.files)>=0?Number(n.files):0;if(o===0&&s===0)continue;let i=Array.isArray(n.recent)?n.recent.slice(-10).flatMap(c=>{if(!c||typeof c!="object")return[];let u=c;return typeof u.from!="string"||!["string","number"].includes(typeof u.msg_id)||typeof u.date!="string"?[]:[{from:u.from,msg_id:u.msg_id,date:u.date}]}):[],a=Array.isArray(n.unread_files)?n.unread_files.slice(-10).flatMap(c=>{if(!c||typeof c!="object")return[];let u=c;return typeof u.from!="string"||typeof u.filename!="string"||typeof u.mime!="string"||typeof u.wire_id!="string"?[]:[{from:u.from,filename:u.filename,mime:u.mime,wire_id:u.wire_id}]}):[];t.push({name:r.name,count:o,recent:i,files:s,unread_files:a})}return t.sort((r,n)=>String(r.name).localeCompare(String(n.name))),{identities:t}}var Wr=new Map,xv=t=>`ours://inbox/${encodeURIComponent(t)}`;function Ht(t,e){R(`[${t}] notify:`,e);let r=Re.get(t)?.sid;if(!r)return;let n=Wr.get(r);if(n){try{n.sendLoggingMessage({level:"info",logger:"ours",data:e})}catch(o){R("sendLoggingMessage failed:",String(o))}try{n.server.sendResourceUpdated({uri:xv(t)})}catch{}}}function et(t){let e=new wp;try{return t(e)}finally{e.Finalize()}}async function Q(t){let e=new wp;try{return await t(e)}finally{e.Finalize()}}function xe(t,e,r){let n=iv({name:e,targ:void 0}),o=t.pw.packet.ExecuteTransaction(n);return n.Destroy(),r?o.Attach(r):o}async function gI(t,e){let r=t.lock,n;t.lock=new Promise(o=>n=o),await r;try{return await e()}finally{n()}}function yI(t,e,r=25e3){return new Promise((n,o)=>{let s=setTimeout(()=>{let i=t.pending.findIndex(a=>a.timer===s);i>=0&&t.pending.splice(i,1),o(new Error("timed out waiting for the transaction result"))},r);t.pending.push({resolve:n,reject:o,timer:s}),t.pw.add_client_message(e)})}function L(t,e,r,n,o){let s=iv({name:e,targ:r});return gI(t,()=>yI(t,s,o)).then(i=>(s.Destroy(),n?i.Attach(n):i),i=>{try{s.Destroy()}catch{}throw i})}function _I(t){t.pw.on_return_data=e=>{let r=new wp;e.Attach(r);try{let n=e.Reduce("kind").Visualize();if(n==="save_state"){pa(t);return}if(n==="notify_agent"){let s=e.Reduce("payload"),i=s.Reduce("event").Visualize();if(i==="message_received"){let a=s.Reduce("sender_name").Visualize(),c=s.Reduce("msg_id").Visualize(),u=s.Reduce("date").Visualize();Xe(t,{event:"message_received",from:a,msg_id:c,date:u}),Yr(t),process.nextTick(()=>Ht(t.name,`[${t.name}] new message from ${a} (#${c})`))}else if(i==="file_received"){let a=s.Reduce("sender_name").Visualize(),c=s.Reduce("file_id").Visualize(),u=s.Reduce("filename").Visualize(),l=s.Reduce("mime").Visualize(),d=s.Reduce("bytes").Visualize(),p=s.Reduce("date").Visualize();Xe(t,{event:"file_received",from:a,file_id:c,filename:u,mime:l,bytes:d,date:p}),Yr(t),process.nextTick(()=>Ht(t.name,`[${t.name}] new file ${u} (${d} B) from ${a} (#${c})`))}else if(i==="contact_accepted"){let a=s.Reduce("name").Visualize(),c=s.Reduce("container_id").Visualize();process.nextTick(()=>Ht(t.name,`[${t.name}] contact "${a}" (${c}) accepted your invite.`))}else if(i==="local_contact_added"){let a=s.Reduce("name").Visualize(),c=s.Reduce("container_id").Visualize();process.nextTick(()=>Ht(t.name,`[${t.name}] local contact "${a}" (${c}) connected via the contact book.`))}else if(i==="sibling_contact_added"){let a=s.Reduce("name").Visualize(),c=s.Reduce("container_id").Visualize();Xe(t,{event:"sibling_contact_added",from:a}),process.nextTick(()=>Ht(t.name,`[${t.name}] sibling "${a}" (${c}) connected (intra-root auto-accept).`))}else if(i==="local_contact_request"){let a=s.Reduce("name").Visualize(),c=s.Reduce("container_id").Visualize();Xe(t,{event:"local_contact_request",from:a}),process.nextTick(()=>Ht(t.name,`[${t.name}] pending local introduction from "${a}" (${c}) \u2014 approve or reject with respond_to_introduction.`))}else if(i==="pending_message"){let a=s.Reduce("sender_name").Visualize(),c=s.Reduce("queued").Visualize();Xe(t,{event:"pending_message",from:a,queued:c}),process.nextTick(()=>Ht(t.name,`[${t.name}] "${a}" queued a message awaiting introduction approval (${c} queued).`))}else if(i==="contact_restored"){let a=s.Reduce("name").Visualize(),c=s.Reduce("container_id").Visualize();Xe(t,{event:"contact_restored",from:a}),R(`[${t.name}] contact "${a}" restored (re-keyed)`),process.nextTick(()=>void wv(t,String(c)))}else if(i==="migration_active"){let a=s.Reduce("cid").Visualize(),c=s.Reduce("role").Visualize(),u=oa(s,"epoch"),l=oa(s,"session_id");Xe(t,{event:"migration_active",cid:String(a),role:String(c),...u?{epoch:u}:{},...l?{session_id:l}:{}}),R(`[migration] active cid=${a} role=${c}${u?` epoch=${u}`:""}${l?` session_id=${l}`:""}`)}else if(i==="e2e_app_send"){let a=s.Reduce("cid").Visualize(),c=oa(s,"session_id"),u=s.Reduce("olm_type").Visualize(),l=s.Reduce("wire_id").Visualize();Xe(t,{event:"e2e_app_send",cid:String(a),session_id:c,olm_type:String(u),wire_id:String(l)}),R(`[e2e-app] send cid=${a} session_id=${c} olm_type=${u} wire_id=${l}`)}else if(i==="e2e_app_recv"){let a=s.Reduce("cid").Visualize(),c=oa(s,"session_id"),u=s.Reduce("ok").GetBoolean(),l=s.Reduce("wire_id").Visualize();Xe(t,{event:"e2e_app_recv",cid:String(a),session_id:c,ok:u,wire_id:String(l)}),R(`[e2e-app] recv cid=${a} session_id=${c} ok=${u} wire_id=${l}`)}else if(i==="migration_deferred_flush"){let a=s.Reduce("cid").Visualize(),c=s.Reduce("wire_id").Visualize();Xe(t,{event:"migration_deferred_flush",cid:String(a),wire_id:String(c)}),R(`[migration] flush-notify cid=${a} wire_id=${c} (deferred\u2192e2e; core delivers)`)}else if(i==="migration_stalled"){let a=s.Reduce("cid").Visualize(),c=s.Reduce("phase").Visualize(),u=s.Reduce("attempts").Visualize();Xe(t,{event:"migration_stalled",cid:String(a),phase:String(c),attempts:String(u)}),R(`[migration] stalled-notify cid=${a} phase=${c} attempts=${u} (core re-drives via sweep)`)}else if(i==="downgrade_refused"){let a=s.Reduce("cid").Visualize(),c=s.Reduce("wire_id"),u=c.IsNil()?"":String(c.Visualize());Xe(t,{event:"downgrade_refused",cid:String(a),...u?{wire_id:u}:{}}),R(`[e2e-route] downgrade-dropped cid=${a}${u?` wire_id=${u}`:""} (legacy plaintext from a migrated peer \u2014 dropped by core)`),process.nextTick(()=>Ht(t.name,`[${t.name}] a message from a migrated contact was rejected as an unsafe downgrade (dropped).`))}else if(i==="control_request"){let a=s.Reduce("sender_name").Visualize();R(`[${t.name}] control request queued by ${a}`),process.nextTick(()=>void kp(t))}else if(i==="host_provision_child"){let a=s.Reduce("name").Visualize(),c=s.Reduce("bio").Visualize(),u=s.Reduce("pending_handle").Visualize();process.nextTick(()=>void YE(t,a,c,u))}else if(i==="host_destroy_child"){let a=s.Reduce("cid").Detach(),c=s.Reduce("pending_handle").Visualize();process.nextTick(()=>void QE(t,a,c).finally(()=>a.Destroy()))}else if(i==="host_mint_child_invite"){let a=s.Reduce("cid").Detach(),c=s.Reduce("pending_handle").Visualize();process.nextTick(()=>void XE(t,a,c).finally(()=>a.Destroy()))}else if(i==="host_set_child_monitoring"){let a=s.Reduce("cid").Detach(),c=s.Reduce("enabled").GetBoolean(),u=s.Reduce("pending_handle").Visualize();if(c){let l=s.Reduce("cp_cid").Detach(),d=s.Reduce("cp_ad").Detach();process.nextTick(()=>void Q_(t,a,!0,u,l,d).finally(()=>{a.Destroy(),l.Destroy(),d.Destroy()}))}else process.nextTick(()=>void Q_(t,a,!1,u).finally(()=>a.Destroy()))}return}let o=t.pending.shift();if(!o)return;clearTimeout(o.timer),o.resolve(e.Reduce("payload").Detach())}finally{r.Finalize()}},t.pw.on_transaction_failure=e=>{let r=t.pending.shift();r?(clearTimeout(r.timer),r.reject(new Error(e))):(R(`[${t.name}] inbound transaction rejected:`,e),Xe(t,{event:"inbound_error",message:e}),process.nextTick(()=>Ht(t.name,`[${t.name}] inbound transaction rejected: ${e}`)))}}function Sp(t,e,r,n=!0,o){let s=new PE,i=["--unit_hash",rs.hash,"--seed_phrase",e,"--unit_dir_path",rs.dir];return o&&i.push("--init_trn_argument",JSON.stringify(o)),s.process_arguments(i),new Promise((a,c)=>{let u=setTimeout(()=>c(new Error(`packet creation for "${t}" timed out`)),3e4);ns.packet_manager.create_packet(s,l=>{clearTimeout(u);let d={name:t,cid:et(p=>l.packet.GetContainerID().Attach(p).Visualize()),pw:l,dir:r,pending:[],lock:Promise.resolve()};_I(d),n&&J.set(t,d),R(`[${t}] packet created \u2014 container id ${d.cid}`),a(d)},rs.contents)})}async function bp(t,e={exposeLocal:!0,localAutoAccept:!0}){let r=cv(t);j.mkdirSync(r,{recursive:!0});let n=ov(24).toString("hex"),o=await Sp(t,n,r);return j.writeFileSync($p(r),dv(o),{mode:384}),await Q(async s=>{await L(o,"::a2a_messaging::set_my_name",{name:t},s)}),await mv(o),e.localAutoAccept||await Q(async s=>{await L(o,"::actor::set_local_policy",{auto_accept:!1},s)}),e.exposeLocal&&await pv(o),pa(o),o}async function vI(t){let e=cv(t),r=j.readFileSync($p(e),"utf8").trim(),n=await Sp(t,"",e,!0,r);if(iI(e))try{let o=j.readFileSync(Qr(e));await Q(async s=>{let i=n.pw.packet.ParseValue(new Uint8Array(o)).Attach(s);await L(n,"::actor::import_state",i,s)})}catch(o){R(`[${t}] FAILED TO IMPORT SAVED STATE \u2014 continuing with the reseeded identity; surviving contacts (if the blob was partially migrated) self-heal via contact restore:`,String(o)),Xe(n,{event:"state_import_failed",error:String(o).slice(0,300)});try{j.renameSync(Qr(e),`${Qr(e)}.failed-${Date.now()}`),R(`[${t}] unreadable state blob preserved as state_data.bin.failed-*`)}catch{}}return await $v(n),Yr(n),n}async function X_(){rs=AE();let t=["--broker_address",ca,"--test_mode","--logger_config","--level","INFO","--stdout","stderr","--logger_config_end"];R(`booting wrapper (unit ${rs.hash.slice(0,12)}\u2026, broker ${ca})`),ns=await TE.start(t),ns.on_packet_created_cb=n=>R(`wrapper: packet ready ${n.slice(0,12)}\u2026`),ns.start();try{await sI()}catch(n){R("failed to start the contact-book registrar (local contact book disabled):",String(n))}let e=ZE();if(e.length===0)R("no persisted identities \u2014 start with create_identity");else{R(`restoring ${e.length} identit${e.length===1?"y":"ies"}: ${e.join(", ")}`);for(let n of e)try{let o=await vI(n);gt&&await mv(o)}catch(o){R(`failed to restore "${n}":`,String(o))}}oI(),nI(),le=ME(),le&&!J.has(le)&&(R(`root marker names a missing identity "${le}" \u2014 clearing it`),le=null,hv()),le&&R(`root identity: ${le}`);let r=le?J.get(le):void 0;if(r)try{cs(r).controlQueued>0&&kp(r)}catch(n){R("boot-time monitoring/control drain failed:",String(n))}as()}function ev(t){let e=st.get(t)?.token;if(!e)return{error:"No identity bound to this session. Call choose_identity (or create_identity) first."};if(fa.has(e))return{error:"Your identity binding was reassigned to another session. Call choose_identity again to continue."};let r=av(e);if(!r)return{error:"No identity bound to this session. Call choose_identity (or create_identity) first."};let n=J.get(r.identity);if(!n)return Re.delete(r.identity),as(),{error:`The bound identity "${r.identity}" no longer exists. Choose another with choose_identity.`};r.sid=t;let o=st.get(t)?.pid;return o&&(r.pid=o),{id:n}}function up(t,e){let r=st.get(t),n=r?.token;if(!n)return;for(let[s,i]of[...Re])i.token===n&&s!==e&&Re.delete(s);let o=Re.get(e)?.epoch??0;Re.set(e,{identity:e,token:n,pid:r?.pid??0,sid:t,epoch:o+1,boundAt:Date.now()}),fa.delete(n),as()}function bI(t){let e=[];if(t.IsNil())return e;for(let r of t.GetKeys()){let n=t.Reduce(r);n.IsNil()||e.push({name:n.Reduce("name").Visualize(),container_id:n.Reduce("container_id").Visualize()})}return e}function aa(t){let e=[];if(t.IsNil())return e;for(let r=0;;r++){let n=t.Reduce(r);if(n.IsNil())break;let o=n.Reduce("reply_to"),s=null;if(!o.IsNil()){s={wire_id:o.Reduce("wire_id").Visualize()};let i=o.Reduce("sentence");i.IsNil()||(s.sentence=parseInt(i.Visualize(),10))}e.push({msg_id:parseInt(n.Reduce("msg_id").Visualize(),10),sender_id:n.Reduce("sender_id").Visualize(),sender_name:n.Reduce("sender_name").Visualize(),text:n.Reduce("text").Visualize(),date:n.Reduce("date").Visualize(),status:n.Reduce("status").Visualize(),wire_id:n.Reduce("wire_id").Visualize(),reply_to:s})}return e}function wI(t){if(t.IsNil())return"No files received.";let e=[];for(let r=0;;r++){let n=t.Reduce(r);if(n.IsNil())break;let o=n.Reduce("filename").Visualize(),s=n.Reduce("mime").Visualize(),i=n.Reduce("sender_name").Visualize(),a=n.Reduce("status").Visualize(),c=n.Reduce("wire_id").Visualize();e.push(` \u2022 ${o} (${s||"application/octet-stream"}) from ${i} [${a}] {${c}}`)}return e.length===0?"No files received.":`${e.length} file(s):
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/mcp",
|
|
3
|
-
"version": "0.12.0-nightly.
|
|
3
|
+
"version": "0.12.0-nightly.4",
|
|
4
4
|
"description": "MCP server daemon for ours — one native ADAPT wrapper hosting N self-sovereign identities, exposing secure agent-to-agent messaging tools over HTTP (Streamable HTTP). Run `ours-mcp start`.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|