@ours.network/mcp 0.17.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -46,7 +46,7 @@ ${k}`,d++;break;case"id":u=k.includes("\0")?void 0:k;break;case"retry":/^\d+$/.t
|
|
|
46
46
|
`,{mode:384});try{Ne.chmodSync(t,384)}catch{}return t}var Fs=".ours-identity";function Hs(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 ju(e){let t=Vs(e);return Wz(t)===Fs?t:Ou(t,Fs)}function i_(e,t,r=!1){let n=Hs(t),o=ju(e);if(!r&&Ne.existsSync(o))throw new Error(`${o} already exists \u2014 pass overwrite to replace it`);return Ne.mkdirSync(Au(o),{recursive:!0}),Ne.writeFileSync(o,JSON.stringify(n,null,2)+`
|
|
47
47
|
`),o}import c_ from"node:process";var Bs=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),nT(r)}clear(){this._buffer=void 0}};function nT(e){return Cr.parse(JSON.parse(e))}function a_(e){return JSON.stringify(e)+`
|
|
49
|
-
`}var Ks=class{constructor(t=c_.stdin,r=c_.stdout){this._stdin=t,this._stdout=r,this._readBuffer=new Bs,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=a_(t);this._stdout.write(n)?r():this._stdout.once("drain",r)})}};function u_(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 l_,writeFileSync as oT,readFileSync as sT,readdirSync as iT,statSync as Mu,unlinkSync as aT,chmodSync as d_,createWriteStream as cT,accessSync as uT,constants as lT}from"node:fs";import{join as Js,dirname as dT,resolve as pT}from"node:path";import{homedir as fT}from"node:os";import{Readable as mT}from"node:stream";import{pipeline as hT}from"node:stream/promises";var gT="0.17.
|
|
49
|
+
`}var Ks=class{constructor(t=c_.stdin,r=c_.stdout){this._stdin=t,this._stdout=r,this._readBuffer=new Bs,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=a_(t);this._stdout.write(n)?r():this._stdout.once("drain",r)})}};function u_(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 l_,writeFileSync as oT,readFileSync as sT,readdirSync as iT,statSync as Mu,unlinkSync as aT,chmodSync as d_,createWriteStream as cT,accessSync as uT,constants as lT}from"node:fs";import{join as Js,dirname as dT,resolve as pT}from"node:path";import{homedir as fT}from"node:os";import{Readable as mT}from"node:stream";import{pipeline as hT}from"node:stream/promises";var gT="0.17.1",_T=new Set(["choose_identity","create_identity","create_root_identity"]),yT="save_file",vT="get_files",bT=["1","true","yes","on"].includes((process.env.OURS_FILES_ALWAYS_PROMPT??"").trim().toLowerCase()),wT=e=>{try{return uT(e,lT.R_OK),!0}catch{return!1}},$T=e=>` \u2022 ${e.filename} \u2014 ${e.mime||"application/octet-stream"}, ${e.size} B, sha256 ${e.sha256} \u2014 from ${e.sender} \u2014 wire_id ${e.wire_id}`;function ST(e,t){let r=e;if(!r||r.isError)return!1;let n=r.structuredContent?.files;if(!Array.isArray(n))return!1;let o=n.filter(a=>!!a&&typeof a=="object"&&typeof a.path=="string"&&typeof a.wire_id=="string");if(o.length===0)return!1;let s=o.filter(a=>a.kind!=="voice_message"&&!t(a.path));for(let a of o)a.readable=t(a.path);if(s.length===0)return!1;let i=[`${s.length} of ${o.length} received file(s) are NOT readable by your OS user: the ours daemon runs as a different OS user and keeps its files dir private. Nothing was lost \u2014 the bytes are safely on disk. IGNORE the on-disk paths reported below for these files; you cannot open them.`,"","TELL THE USER what arrived (details below) and ASK WHERE TO SAVE each file on this filesystem. Then call save_file({ wire_id, dest_path }) with the path they choose: the ours connector streams the bytes daemon\u2192proxy\u2192disk and writes them as YOUR OS user. The bytes never enter this conversation.","","Awaiting a destination:",...s.map($T)];return r.content=[{type:"text",text:i.join(`
|
|
50
50
|
`)},...r.content??[]],!0}var p_=e=>new Promise(t=>setTimeout(t,e)),Uu=e=>typeof e?.method=="string"&&e.id!==void 0&&e.id!==null,xT=e=>e&&typeof e=="object"&&!("method"in e)&&e.id!==void 0&&e.id!==null,f_=e=>{let t=e.result;return!!e.error||!!(t&&t.isError)},m_=Number(process.env.OURS_RESTORE_TTL_MS)>0?Number(process.env.OURS_RESTORE_TTL_MS):7*24*60*60*1e3,h_=["1","true","yes","on"].includes((process.env.OURS_NO_AUTORESTORE??"").trim().toLowerCase()),Du=(process.env.OURS_BIND_IDENTITY??"").trim()||null;async function g_(e){let t=new URL(e.url),r=!1,n=(...x)=>{if(!r)try{process.stderr.write(`[ours-proxy] ${x.join(" ")}
|
|
51
51
|
`)}catch{r=!0,xt(0)}},o=()=>{r=!0,xt(0)};process.stderr.on("error",o),process.stdout.on("error",o);let s=x=>Number.isInteger(x)&&x>1,i=Number(process.env.OURS_CLIENT_PID),a=s(i)?i:s(process.ppid)?process.ppid:process.pid,c=(process.env.CLAUDE_CODE_SESSION_ID??"").trim()||`client:${a}`,u=null,l=null,d,p=null,m=new Map,h=new Set,g=null,y=h_?null:(process.env.CLAUDE_CODE_SESSION_ID??"").trim()||null,S=e.stateDir??process.env.OURS_STATE_DIR??Js(fT(),".ours"),$=Js(S,"session-restore"),w=y&&/^[A-Za-z0-9._-]{1,200}$/.test(y)?y:null,P=w?Js($,`${w}.json`):null,v=!1,k=null,A="session-restore";function W(x){if(P)try{l_($,{recursive:!0,mode:448}),oT(P,JSON.stringify({claudeSessionId:y,identity:x,boundAt:new Date().toISOString()}),{mode:384}),d_($,448),d_(P,384)}catch(I){n("restore persist failed (non-fatal):",String(I))}}function ie(){if(!P)return null;try{if(Date.now()-Mu(P).mtimeMs>m_)return null;let x=JSON.parse(sT(P,"utf8"));return(typeof x.identity=="string"?x.identity.trim():"")||null}catch{return null}}function be(){try{let x=Date.now();for(let I of iT($)){if(!I.endsWith(".json"))continue;let N=Js($,I);try{x-Mu(N).mtimeMs>m_&&(aT(N),n("session-restore: pruned expired record",I))}catch{}}}catch{}}let qe=(()=>{let x=(process.env.OURS_REQUEST_TIMEOUT_MS??"").trim();if(x==="")return 12e4;let I=Number(x);return Number.isFinite(I)&&I>=0?I:12e4})(),je=new Map,St=new Map;function Qe(x,I,N){let B=je.get(x);if(!B)return;je.delete(x),B.progressToken!==void 0&&St.delete(B.progressToken);let M=Date.now()-B.sentAt;n(`FAILING BACK request id=${String(x)} method=${B.method} waited_ms=${M} reason=${N}`),mt.send({jsonrpc:"2.0",id:x,error:{code:I,message:`ours proxy: no response from the ours daemon for "${B.method}" after ${M}ms (${N}). The request was NOT retried \u2014 retry it yourself if it is safe to repeat.`,data:{reason:N,method:B.method,waitedMs:M}}}).catch(Z=>n("fail-back send failed:",String(Z)))}qe>0&&setInterval(()=>{let I=Date.now();for(let[N,B]of[...je])B.deadline<=I&&Qe(N,-32001,"watchdog timeout")},1e3).unref?.();let ko=6e4,Wu=3,ri=0,$r=0;function G_(x,I){mt.send({jsonrpc:"2.0",method:"notifications/message",params:{level:x,logger:"ours-proxy",data:I}}).catch(N=>n("downstream notify failed:",String(N)))}let Le=null,W_=()=>Le,zo=!1,cn=!1,Sr=!1,un=[],Y_="__ours_proxy_init__",ni=0,ln=new Set,oi=new Set,mt=new Ks;mt.onmessage=x=>{let I=[],N=!1;for(let B of Gs(x)){let M=B;if(M.method==="notifications/initialized"&&(N=!0),Uu(M)){if(M.method==="initialize"&&(u=M,l)){n("absorbed re-initialize locally \u2014 upstream session kept stable"),mt.send({jsonrpc:"2.0",id:M.id,result:l}).catch(Z=>n("local initialize reply failed:",String(Z)));continue}if(M.method==="tools/call"){let Z=M.params;if(Z&&_T.has(Z.name??"")&&typeof Z.arguments?.name=="string"&&m.set(M.id,Z.arguments.name),Z?.name===vT&&h.add(M.id),Z?.name===yT){let _e=M.params?.arguments??{};ey(M.id,_e);continue}}if(qe>0){let Z=M.id,_e=M.params?._meta,we=Date.now();je.set(Z,{method:typeof M.method=="string"?M.method:"unknown",sentAt:we,deadline:we+qe,transport:null,progressToken:_e?.progressToken}),_e?.progressToken!==void 0&&St.set(_e.progressToken,Z)}}I.push(M)}if(I.length){let B=Array.isArray(x)?I:I[0];Qu(B)}N&&Q_()},mt.onclose=()=>void xt(0),mt.onerror=x=>n("downstream error:",String(x));let Yu=x=>{n(`stdin ${x} \u2014 the client is gone; shutting down`),xt(0)};process.stdin.once("end",()=>Yu("reached EOF")),process.stdin.once("close",()=>Yu("closed"));function Q_(){if(v||!p)return;v=!0;let x=`__ours_proxy_restore_${++ni}__`;ln.add(x),k=x,n(`${A}: binding seeded identity`,`"${p}"`),Qu({jsonrpc:"2.0",id:x,method:"tools/call",params:{name:"choose_identity",arguments:{name:p}}})}function X_(x,I){if(!(qe<=0))for(let N of Gs(x)){let B=N.id;if(B===void 0)continue;let M=je.get(B);M&&(M.transport=I)}}async function ey(x,I){let N=String(I.wire_id??"").trim(),B=String(I.dest_path??"").trim(),M=(Z,_e=!1)=>mt.send({jsonrpc:"2.0",id:x,result:{content:[{type:"text",text:Z}],isError:_e}}).catch(we=>n("save_file reply failed:",String(we)));if(!N||!B){await M("save_file: both `wire_id` and `dest_path` are required.",!0);return}if(!/^[A-Za-z0-9]+$/.test(N)){await M("save_file: invalid wire_id.",!0);return}try{let Z=new URL(t.href);Z.pathname=`/files/${encodeURIComponent(N)}`,Z.search="";let _e={"x-ours-lease-token":c};e.apiToken&&(_e["x-ours-api-token"]=e.apiToken);let we=await fetch(Z,{headers:_e});if(we.status===401||we.status===403){await M("save_file: ours daemon authentication failed; the monitor may be disarmed.",!0);return}if(we.status===404){await M(`save_file: no file with wire_id ${N} is available to the bound identity. Run get_files first; it may already be saved, or it belongs to another identity.`,!0);return}if(!we.ok||!we.body){await M(`save_file: ours daemon returned HTTP ${we.status}. Your ours daemon may be too old to support save_file \u2014 update it, or use get_files and copy the returned path yourself.`,!0);return}let Me=pT(B);l_(dT(Me),{recursive:!0}),await hT(mT.fromWeb(we.body),cT(Me));let sy=Mu(Me).size;await M(`Saved file (wire_id ${N}) to ${Me} (${sy} bytes). The bytes were streamed daemon\u2192proxy\u2192disk and never entered this result.`)}catch(Z){await M(`save_file failed: ${String(Z)}`,!0)}}function Qu(x){if(zo&&Le){let I=Le;X_(x,I),Le.send(x).catch(N=>{n("upstream send failed:",String(N));let B=Gs(x),M=B.filter(Z=>!Uu(Z));M.length&&un.push(Array.isArray(x)?M:M[0]);for(let Z of B){let _e=Z;Uu(_e)&&je.has(_e.id)&&Qe(_e.id,-32e3,"upstream send failed")}si(I,"send failed")})}else un.push(x)}function si(x,I){if(cn||Sr||Le!==null&&x!==Le)return;n(`upstream dropped (${I}) \u2014 reconnecting`),zo=!1;let N=Le;Le=null;try{N?.close?.()}catch{}if(N)for(let[B,M]of[...je])M.transport===N&&Qe(B,-32e3,`upstream dropped (${I})`);ny()}function ty(x){x.onmessage=I=>{let N=[];for(let B of Gs(I)){let M=B;if(M.method==="notifications/progress"){let Z=M.params?.progressToken;if(Z!==void 0){let _e=St.get(Z),we=_e!==void 0?je.get(_e):void 0;we&&(we.deadline=Date.now()+qe)}}if(xT(M)){let Z=M.id,_e=je.get(Z);_e&&(je.delete(Z),_e.progressToken!==void 0&&St.delete(_e.progressToken));let we=M.result?.protocolVersion;if(we&&(oi.has(Z)||Xu(Z))){d=we;try{Le?.setProtocolVersion?.(we)}catch{}if(l==null&&Xu(Z)&&!ln.has(Z)){let Me=M.result??null;Me&&g&&(Me.instructions=`${Me.instructions?Me.instructions+`
|
|
52
52
|
|
|
@@ -79,7 +79,7 @@ OURS_STT_API_KEY, OURS_STT_MODEL, OURS_STT_BASE_URL, and OURS_STT_LANGUAGE.
|
|
|
79
79
|
Exit 2 means restart/readiness failed after a write and rollback was attempted.`;import*as yr from"node:fs";import{join as VT}from"node:path";var HT="startup-progress.json",BT=1,E_={initializing:"Initializing daemon",wrapper:"Starting protocol runtime",registrar:"Starting local contact book",identities:"Restoring identities",reconciliation:"Reconciling restored identities",server:"Opening local API",ready:"Daemon ready",failed:"Daemon startup failed"};function KT(e){return VT(e,HT)}function JT(e){return typeof e=="string"&&Object.hasOwn(E_,e)}function I_(e){try{let t=JSON.parse(yr.readFileSync(KT(e),"utf8"));return t.version!==BT||!Number.isInteger(t.pid)||(t.pid??0)<=0||typeof t.bootId!="string"||!t.bootId||!JT(t.phase)||!Number.isFinite(t.startedAt)||!Number.isFinite(t.updatedAt)||(t.completed!==void 0||t.total!==void 0)&&(!Number.isInteger(t.completed)||!Number.isInteger(t.total)||(t.completed??-1)<0||(t.total??-1)<0||(t.completed??0)>(t.total??0))?null:t}catch{return null}}function Lu(e){let t=E_[e.phase];return e.phase==="identities"&&e.completed!==void 0&&e.total!==void 0?`${t} ${e.completed}/${e.total}`:t}function O_(e,t){let r=`startup: ${Lu(e)}`;return t?`\r${r}\x1B[K`:`${r}
|
|
80
80
|
`}async function A_(e){let t=e.now??Date.now,r=e.sleep??(c=>new Promise(u=>setTimeout(u,c))),n=t(),o=n,s=-1,i="",a=null;for(;;){if(await e.isReady())return{ok:!0,elapsedMs:t()-n,lastProgress:a};let c=e.readProgress();if(c?.pid===e.pid){a=c,c.updatedAt>s&&(s=c.updatedAt,o=t());let p=`${c.phase}:${c.completed??""}:${c.total??""}`;if(p!==i&&(i=p,e.onProgress?.(c)),c.phase==="failed")return{ok:!1,reason:"daemon-reported-failure",elapsedMs:t()-n,lastProgress:a}}if(!e.isProcessAlive())return{ok:!1,reason:"process-exited",elapsedMs:t()-n,lastProgress:a};let u=t()-n;if(u>=e.absoluteMs)return{ok:!1,reason:"absolute-timeout",elapsedMs:u,lastProgress:a};if(t()-o>=e.inactivityMs)return{ok:!1,reason:"inactivity-timeout",elapsedMs:u,lastProgress:a};let l=e.absoluteMs-u,d=e.inactivityMs-(t()-o);await r(Math.max(1,Math.min(e.pollMs,l,d)))}}if(!process.env.XDG_RUNTIME_DIR&&typeof process.getuid=="function"){let e=`/run/user/${process.getuid()}`;H.existsSync(e)&&(process.env.XDG_RUNTIME_DIR=e)}var $t=Cu(),Ze=$t.stateDir,se=$t.port,xo=()=>{let e=Nu($t,{generate:!1})?.token??null;return e?{"x-ours-api-token":e}:{}},sn=$t.brokerUrl,wr=Ct(Ze,"daemon.pid"),vr=Ct(Ze,"daemon.log"),Jt=WT(import.meta.url),b=(...e)=>process.stdout.write(`${e.join(" ")}
|
|
81
81
|
`),ee=(...e)=>process.stderr.write(`${e.join(" ")}
|
|
82
|
-
`),br="0.17.
|
|
82
|
+
`),br="0.17.1";async function Ku(){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:${se}${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 C_(e){if(b(` cli: v${br}`),e?.version){let t=e.version!==br;b(` daemon: v${e.version}${e.compat?` (compat ${e.compat})`:""}`+(t?` \u26A0 differs from CLI \u2014 \`ours-mcp restart\` to load v${br}`:""))}else b(" daemon: version unknown (running build predates /version \u2014 restart to update)")}var ti=e=>new Promise(t=>setTimeout(t,e));function QT(){try{let e=parseInt(H.readFileSync(wr,"utf8").trim(),10);return Number.isFinite(e)?e:null}catch{return null}}function Xs(e){try{if(process.kill(e,0),process.platform==="linux")try{if(__(H.readFileSync(`/proc/${e}/stat`,"utf8")))return!1}catch{try{process.kill(e,0)}catch{return!1}}return!0}catch{return!1}}function an(){let e=QT();if(e&&Xs(e))return e;if(e)try{H.rmSync(wr,{force:!0})}catch{}return null}function Gt(e,t=1e3){return new Promise(r=>{let n=GT({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 XT(e,t=3e4){let r=Date.now()+t;for(;Date.now()<r;){if(await Gt(e))return!0;await ti(400)}return!1}function Gu(e,t){let r=Number(process.env[e]||"");return Number.isFinite(r)&&r>0?r:t}var L_=Gu("OURS_TEST_STARTUP_ABSOLUTE_MS",18e4),F_=Gu("OURS_TEST_STARTUP_INACTIVITY_MS",3e4),V_=Gu("OURS_TEST_STARTUP_POLL_MS",400);async function eP(e){let t=new AbortController,r=setTimeout(()=>t.abort(),Math.min(1e3,V_));try{let n=await fetch(`http://127.0.0.1:${e}/identities`,{signal:t.signal,headers:xo()}),o=n.ok;try{await n.body?.cancel()}catch{}return o}catch{return!1}finally{clearTimeout(r)}}function N_(e){return e<1e3?`${Math.round(e)}ms`:e%6e4===0?`${e/6e4}m`:`${Math.round(e/1e3)}s`}function tP(e,t){let r=t?` Last phase: ${Lu(t)}.`:"";return e==="process-exited"||e==="daemon-reported-failure"?`daemon exited before becoming ready.${r}`:e==="inactivity-timeout"?`daemon startup made no observable progress for ${N_(F_)}.${r} The process is still running, but startup is stalled.`:`daemon startup did not finish within ${N_(L_)}.${r} The bounded wait expired.`}async function j_(){let e=an();if(e){b(`ours-mcp is already running (pid ${e}, port ${se}).`);return}H.mkdirSync(Ze,{recursive:!0});let t=H.openSync(vr,"a"),r=D_(process.execPath,[Jt,"serve"],{detached:!0,stdio:["ignore",t,t],env:{...process.env,OURS_TRANSPORT:"http",OURS_PORT:String(se),OURS_BROKER_URL:sn,OURS_STATE_DIR:Ze}});r.unref(),r.pid||(ee("failed to spawn the daemon."),process.exit(1)),H.writeFileSync(wr,String(r.pid)),b(`starting ours-mcp (pid ${r.pid})\u2026`);let n=!!process.stderr.isTTY,o=!1,s=await A_({pid:r.pid,absoluteMs:L_,inactivityMs:F_,pollMs:V_,isProcessAlive:()=>Xs(r.pid),isReady:()=>eP(se),readProgress:()=>I_(Ze),onProgress:i=>{o=!0,process.stderr.write(O_(i,n))}});o&&n&&process.stderr.write(`
|
|
83
83
|
`),s.ok?(b(`ours-mcp is up on http://localhost:${se}/mcp`),b(` broker: ${sn}`),b(` state: ${Ze}`),b(` logs: ${vr}`)):(ee(`${tP(s.reason,s.lastProgress)} Check ${vr}.`),process.exit(1))}async function rP(){if(!await Gt(se)){if(!an()){H.mkdirSync(Ze,{recursive:!0});let e=H.openSync(vr,"a"),t=D_(process.execPath,[Jt,"serve"],{detached:!0,stdio:["ignore",e,e],env:{...process.env,OURS_TRANSPORT:"http",OURS_PORT:String(se),OURS_BROKER_URL:sn,OURS_STATE_DIR:Ze}});if(t.unref(),t.pid)try{H.writeFileSync(wr,String(t.pid))}catch{}}await XT(se)}}async function ei(){let e=an();if(!e){b("ours-mcp is not running.");return}b(`stopping ours-mcp (pid ${e})\u2026`);try{process.kill(e,"SIGTERM")}catch(t){ee(`failed to signal pid ${e}: ${String(t)}`)}for(let t=0;t<25&&Xs(e);t++)await ti(200);if(Xs(e)){ee(`pid ${e} did not exit; sending SIGKILL.`);try{process.kill(e,"SIGKILL")}catch{}}try{H.rmSync(wr,{force:!0})}catch{}b("stopped.")}async function nP(){let e=an();if(!e){if(await Gt(se)){let n=await Ku();b("ours-mcp: running (no pidfile \u2014 likely a stale process or external launcher)"),b(` url: http://localhost:${se}/mcp (reachable)`),C_(n);return}b("ours-mcp: stopped"),b(` cli: v${br}`),process.exitCode=1;return}let t=await Gt(se),r=t?await Ku():null;b("ours-mcp: running"),b(` pid: ${e}`),b(` url: http://localhost:${se}/mcp ${t?"(reachable)":"(port not answering!)"}`),b(` broker: ${sn}`),b(` state: ${Ze}`),b(` logs: ${vr}`),C_(r)}async function oP(){if(b(`ours-mcp v${br}`),await Gt(se)){let e=await Ku();e?.version?b(`running daemon: v${e.version}`+(e.version!==br?" (differs \u2014 restart to update)":"")):b("running daemon: version unknown (predates /version)")}else b("daemon: not running")}async function sP(){let e=Cu(),t=wo();b(`ours-mcp setup \u2014 ${t}`),b("Enter a value, or press Enter to keep the current [bracketed] one."),b("");let r=Qs({input:process.stdin,output:process.stdout}),n;try{let l=async(ie,be)=>{let qe=(await r.question(` ${ie} [${be}]: `)).trim();return qe===""?be:qe},d=await l("broker URL",e.brokerUrl),p=await l("HTTP port",String(e.port)),m=await l("state dir",e.stateDir),h=await l("GC interval (ms)",String(e.gcIntervalMs)),g=await l("proxy auto-starts daemon (true/false)",String(e.autoStart)),y=await l("HTTP visibility (owner=same-user only / shared=cross-user w/ token / open=all local users)",e.apiVisibility);b(""),b(" Voice-message transcription (STT). Leave provider empty to keep it off \u2014"),b(" agents then deterministically tell users voice messages cannot be read."),b(" No provider or model is assumed; model strings pass to your provider verbatim.");let S=(await r.question(` STT provider (openai-compatible / elevenlabs / deepgram / custom, empty=off) [${e.stt?.provider??""}]: `)).trim()||(e.stt?.provider??""),$=e.stt?.model??"",w=e.stt?.baseUrl??"";S&&($=await l("STT model (verbatim, e.g. whisper-large-v3-turbo / scribe_v1 / nova-2)",$),w=await l("STT base URL (required for openai-compatible; empty = provider default)",w),b(" (API key is not echoed here. Run `ours-mcp voice-setup` for guided hidden input,"),b(" or set OURS_STT_API_KEY for environment-only secret injection.)"));let P=parseInt(p,10);(!Number.isFinite(P)||P<=0)&&(ee(`invalid port: ${p}`),process.exit(1));let v=parseInt(h,10);(!Number.isFinite(v)||v<=0)&&(ee(`invalid GC interval: ${h}`),process.exit(1));let k=g.toLowerCase()==="true"||g==="1",A=y.trim().toLowerCase();bo.includes(A)||(ee(`invalid visibility: ${y} (expected one of ${bo.join(", ")})`),process.exit(1));let W=S?{...e.stt??{},provider:S,...$?{model:$}:{},...w?{baseUrl:w}:{}}:e.stt;n={brokerUrl:d,port:P,stateDir:q_(m),gcIntervalMs:v,autoStart:k,apiVisibility:A,...e.apiToken?{apiToken:e.apiToken}:{},...W?{stt:W}:{}}}finally{r.close()}s_(n),b(""),b(`wrote ${t} (mode 0600):`);let o={...n,...n.apiToken?{apiToken:"[redacted]"}:{},...n.stt?{stt:{...n.stt,...n.stt.apiKey?{apiKey:"[redacted]"}:{}}}:{}};b(JSON.stringify(o,null,2));let s=["OURS_BROKER_URL","OURS_PORT","OURS_STATE_DIR","OURS_GC_INTERVAL_MS","OURS_AUTOSTART","OURS_API_VISIBILITY","OURS_API_TOKEN","OURS_STT_PROVIDER","OURS_STT_API_KEY","OURS_STT_MODEL","OURS_STT_BASE_URL","OURS_STT_LANGUAGE"].filter(l=>process.env[l]!==void 0);s.length&&(b(""),b(`note: these env vars are set and OVERRIDE the file at runtime: ${s.join(", ")}`));let i=an();if(!i)return;let a=Qs({input:process.stdin,output:process.stdout}),c=!1;try{let l=(await a.question(`
|
|
84
84
|
daemon is running (pid ${i}); restart now to apply? [y/N]: `)).trim().toLowerCase();c=l==="y"||l==="yes"}finally{a.close()}if(!c){b("not restarting \u2014 changes apply on the next `ours-mcp restart`.");return}await ei();let u=on(process.execPath,[Jt,"start"],{stdio:"inherit"});u.status!==0&&process.exit(u.status??1)}function iP(e){let t=$o($t.stt),r=$t.stt?.provider?.trim().toLowerCase()||null,n=process.env.OURS_STT_API_KEY?.trim()?"environment":$t.stt?.apiKey?.trim()?"config":"missing",o=t.ready?{ready:!0,provider:t.provider,apiKey:"configured",keySource:n}:{ready:!1,provider:r,apiKey:n==="missing"?"missing":"configured",keySource:n,reason:t.reason};if(e.includes("--json")){b(JSON.stringify(o));return}o.ready?b(`voice transcription: ready (${o.provider}; API key from ${o.keySource})`):b(`voice transcription: not ready \u2014 ${o.reason}`)}async function aP(e){if(e.includes("--help")||e.includes("-h")){b(R_);return}let t=new Set(["--dry-run"]);if(e.filter(i=>!t.has(i)).length){ee("voice-setup: unsupported command-line option or argument"),ee("The provider key is never accepted as a CLI argument. Run `ours-mcp voice-setup --help`."),process.exitCode=1;return}let n=an()!==null,o=await Gt(se),s=await P_({configFile:wo(),env:process.env,dryRun:e.includes("--dry-run"),daemonState:n?"managed":o?"external":"stopped",apply:async()=>{let i=on(process.execPath,[Jt,"restart"],{stdio:"inherit"});if(i.error||i.status!==0)return{ok:!1};let a=on(process.execPath,[Jt,"voice-status","--json"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});if(a.error||a.status!==0)return{ok:!1};try{return{ok:JSON.parse(a.stdout||"{}").ready===!0}}catch{return{ok:!1}}}});s!==0&&(process.exitCode=s)}function Vu(e,t,r){return e.includes(r)?{value:!1,set:!0}:e.includes(t)?{value:!0,set:!0}:{value:void 0,set:!1}}function Hu(e,t){let r=e.indexOf(t);return r>=0&&r+1<e.length?e[r+1]:void 0}async function cP(e){let t=Hu(e,"--name"),r=Vu(e,"--force-bind","--no-force-bind"),n=Vu(e,"--local-book","--no-local-book"),o=Vu(e,"--auto-accept-local","--no-auto-accept-local"),s=e.includes("--overwrite"),i=e.includes("--print"),a=Hu(e,"--path")??Hu(e,"--dir")??process.cwd(),c=t!==void 0||r.set||n.set||o.set||i,u;if(c?((!t||!t.trim())&&(ee("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 uP(),i){b(JSON.stringify(Hs(u),null,2));return}let l=ju(a);if(!s&&H.existsSync(l)){c&&(ee(`define-local-identity-file: ${l} already exists \u2014 pass --overwrite to replace it.`),process.exit(1));let p=Qs({input:process.stdin,output:process.stdout}),m=!1;try{let h=(await p.question(`
|
|
85
85
|
${l} already exists \u2014 overwrite? [y/N]: `)).trim().toLowerCase();m=h==="y"||h==="yes"}finally{p.close()}if(!m){b("aborted \u2014 nothing written.");return}}let d=i_(a,u,!0);b(""),b(`wrote ${d}:`),b(JSON.stringify(Hs(u),null,2))}async function uP(){b("ours-mcp define-local-identity-file \u2014 interactive"),b(`Answer the prompts; the result is written to ${Ct(process.cwd(),Fs)}.`),b("");let e=Qs({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 lP(e){let t=(e[0]??"").trim();(!t||t.startsWith("--"))&&(ee('usage: ours-mcp create-root "<your name>"'),process.exit(1)),await Gt(se)||(ee(`create-root: the daemon is not running on port ${se} \u2014 start it with \`ours-mcp start\`.`),process.exit(1));let r=new tn(new URL(`http://127.0.0.1:${se}/mcp`),{requestInit:{headers:xo()}}),n=new Zs({name:"ours-mcp-cli",version:br});try{await n.connect(r);let o=await n.callTool({name:"create_root_identity",arguments:{name:t,skip_if_root_exists:!0}}),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}ee(`create-root failed: ${s}`),process.exit(1)}b(s)}finally{try{await r.terminateSession()}catch{}try{await n.close()}catch{}}}function H_(e,t){t.event==="message_received"?b(`[${e}] new message from ${t.from??"?"}`+(t.msg_id!==void 0?` (#${t.msg_id})`:"")+(t.date?` (${t.date})`:"")):t.event==="file_received"?b(`[${e}] new file ${t.filename??"?"} from ${t.from??"?"}`+(t.bytes!==void 0?` (${t.bytes} B)`:"")+(t.file_id!==void 0?` (#${t.file_id})`:"")+(t.date?` (${t.date})`:"")):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)`)}function Kt(e){ee(`ours-mcp watch: ${e}`),process.exit(1)}async function dP(){try{let e=new AbortController,t=setTimeout(()=>e.abort(),1500),r=await fetch(`http://127.0.0.1:${se}/state-dir`,{signal:e.signal});if(clearTimeout(t),r.ok){let n=await r.json();return typeof n.stateDir=="string"&&n.stateDir?q_(n.stateDir):Ze}}catch{}return null}var pP=e=>`http://127.0.0.1:${se}/identities/${encodeURIComponent(e)}/notifications`;async function M_(e){let t=async o=>{let s=new AbortController,i=setTimeout(()=>s.abort(),35e3),a;try{a=await fetch(`${pP(e)}?since=${o}`,{headers:xo(),signal:s.signal})}finally{clearTimeout(i)}if(a.status===401&&Kt(`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)H_(e,s);typeof o.cursor=="number"&&(r=o.cursor)}catch(o){n=Math.min(n+1e3,5e3),ee(`ours-mcp watch: notifications stream for "${e}" hiccupped (${String(o?.message??o)}), retrying\u2026`),await ti(n)}}async function fP(e){if(e){await M_(e);return}let t=new Set;for(;;){try{let r=await fetch(`http://127.0.0.1:${se}/identities`,{headers:xo()});if(r.status===401&&Kt("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),M_(s))}}}catch{}await ti(3e3)}}var Bu=e=>{let t=e?.code;return t==="EACCES"||t==="EPERM"};function mP(e,t){try{H.readdirSync(e)}catch(i){Kt(`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{H.readdirSync(Ct(e,t))}catch(i){Kt(`cannot watch identity "${t}" \u2014 ${Ct(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=H.readdirSync(e,{withFileTypes:!0}).filter(c=>c.isDirectory()).map(c=>c.name)}catch(c){Bu(c)&&Kt(`lost read access to ${e} (${c.code}) \u2014 cannot watch.`);return}for(let c of a){if(t&&c!==t)continue;let u=Ct(e,c,"notifications.log"),l;try{l=H.statSync(u).size}catch(m){Bu(m)&&Kt(`cannot read ${u} (${m.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 p;try{let m=H.openSync(u,"r"),h=Buffer.alloc(l-d);H.readSync(m,h,0,h.length,d),H.closeSync(m),p=h.toString("utf8")}catch(m){Bu(m)&&Kt(`cannot read ${u} (${m.code}) \u2014 cannot watch identity "${c}".`);continue}r.set(u,l);for(let m of p.split(`
|
package/dist/index.js
CHANGED
|
@@ -56,7 +56,7 @@ data:
|
|
|
56
56
|
`),o}import{basename as tP,extname as rP}from"node:path";var nP={".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 hv(t){return nP[rP(t).toLowerCase()]??"application/octet-stream"}function gv(t){let e=tP(t).replace(/[^A-Za-z0-9._-]/g,"_");return e.length?e.slice(0,200):"file"}var oP=new Set(["e2e_app_recv","migration_deferred_flush"]);function yv(t){let e=new Set;for(let r of t){if(!r||typeof r!="object")continue;let n=r.event;if(typeof n!="string"||!oP.has(n))continue;let o=r.wire_id;typeof o=="string"&&o.length>0&&e.add(o)}return e}function iP(t,e){return t&&e.has(t)?"e2e":"legacy"}function sP(t,e){let r=iP(t.wire_id,e);return{msg_id:t.msg_id,wire_id:t.wire_id,from:{id:t.sender_id,name:t.sender_name},encryption:r,transport:r==="e2e"?"double_ratchet":"legacy_box",text:t.text,date:t.date,status:t.status,reply_to:t.reply_to}}function _v(t,e){let r=t.map(n=>sP(n,e));return{count:r.length,messages:r}}var aP="x-ours-kind=voice-message",cP="voice-message-";function ya(t,e){let r=(t??"").toLowerCase().split(";").map(n=>n.trim());return r[0].startsWith("audio/")&&r.slice(1).includes(aP)?!0:e.toLowerCase().startsWith(cP)&&r[0].startsWith("audio/")}function $p(t){return(t??"").split(";")[0].trim()||"application/octet-stream"}var wp=["openai-compatible","elevenlabs","deepgram","custom"],uP=5*1024*1024,lP=6e4;function xp(t){let e="configure it in config.json `stt: {}` or via OURS_STT_* env";if(!t?.provider)return{ready:!1,reason:`no STT provider configured (stt.provider: ${wp.join(" | ")}) \u2014 ${e}`};let r=t.provider.trim().toLowerCase();if(!wp.includes(r))return{ready:!1,reason:`unknown STT provider "${t.provider}" (expected: ${wp.join(" | ")})`};if(!t.apiKey?.trim())return{ready:!1,reason:`STT provider "${r}" is set but the API key is missing (stt.apiKey / OURS_STT_API_KEY)`};if(r==="openai-compatible"){if(!t.baseUrl?.trim())return{ready:!1,reason:"openai-compatible STT needs stt.baseUrl / OURS_STT_BASE_URL (e.g. your provider's /v1 root) \u2014 no endpoint is assumed"};if(!t.model?.trim())return{ready:!1,reason:"openai-compatible STT needs stt.model / OURS_STT_MODEL (passed to the provider verbatim) \u2014 no model is assumed"}}if(r==="elevenlabs"&&!t.model?.trim())return{ready:!1,reason:"elevenlabs STT needs stt.model / OURS_STT_MODEL (the model_id, e.g. from your ElevenLabs account) \u2014 no model is assumed"};if(r==="custom"){if(!t.custom?.url?.trim())return{ready:!1,reason:"custom STT needs stt.custom.url (the full endpoint URL of your provider)"};if((t.custom.url.includes("{model}")||t.custom.modelField!==void 0&&t.custom.modelField!=="")&&!t.model?.trim())return{ready:!1,reason:"the custom STT template references a model (url {model} or modelField) but stt.model / OURS_STT_MODEL is not set"}}return{ready:!0,provider:r}}function _a(t,e){let r=t;for(let n of e.split(".")){if(r===null||typeof r!="object")return;r=r[n]}return typeof r=="string"?r:void 0}async function va(t,e,r,n=[]){let o=new AbortController,i=setTimeout(()=>o.abort(),r);try{let s=await fetch(t,{...e,signal:o.signal});if(!s.ok){let a=await s.text().catch(()=>"");for(let c of n)c&&(a=a.split(c).join("[redacted]"));return{ok:!1,error:`STT HTTP ${s.status}${a?`: ${a.slice(0,200)}`:""}`}}return{ok:!0,json:await s.json()}}catch(s){return s?.name==="AbortError"?{ok:!1,error:`STT timeout after ${r}ms`}:{ok:!1,error:s instanceof Error?s.message:String(s)}}finally{clearTimeout(i)}}var Sp=(t,e)=>new Blob([new Uint8Array(t)],{type:$p(e)}),dP=async(t,e,r,n,o)=>{let i=new FormData;i.set("file",Sp(t,r),e),i.set("model",n.model.trim()),i.set("response_format","json"),n.language?.trim()&&i.set("language",n.language.trim());let s=await va(`${n.baseUrl.trim().replace(/\/$/,"")}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${n.apiKey.trim()}`},body:i},o,[n.apiKey.trim()]);if(!s.ok)return s;let a=_a(s.json,"text");return a!==void 0?{ok:!0,text:a}:{ok:!1,error:"STT response missing text"}},pP=async(t,e,r,n,o)=>{let i=new FormData;i.set("file",Sp(t,r),e),i.set("model_id",n.model.trim()),n.language?.trim()&&i.set("language_code",n.language.trim());let s=await va(`${(n.baseUrl?.trim()||"https://api.elevenlabs.io").replace(/\/$/,"")}/v1/speech-to-text`,{method:"POST",headers:{"xi-api-key":n.apiKey.trim()},body:i},o,[n.apiKey.trim()]);if(!s.ok)return s;let a=_a(s.json,"text");return a!==void 0?{ok:!0,text:a}:{ok:!1,error:"STT response missing text"}},fP=async(t,e,r,n,o)=>{let i=new URLSearchParams;n.model?.trim()&&i.set("model",n.model.trim()),n.language?.trim()&&i.set("language",n.language.trim());let s=i.toString(),a=await va(`${(n.baseUrl?.trim()||"https://api.deepgram.com").replace(/\/$/,"")}/v1/listen${s?`?${s}`:""}`,{method:"POST",headers:{Authorization:`Token ${n.apiKey.trim()}`,"Content-Type":$p(r)},body:new Uint8Array(t)},o,[n.apiKey.trim()]);if(!a.ok)return a;let c=_a(a.json,"results.channels.0.alternatives.0.transcript");return c!==void 0?{ok:!0,text:c}:{ok:!1,error:"STT response missing transcript"}},mP=async(t,e,r,n,o)=>{let i=n.custom,s=n.model?.trim()??"",a=i.url.replaceAll("{model}",encodeURIComponent(s)),c={},u=i.authHeaderName?.trim()||"Authorization",l=(i.authHeaderTemplate??"Bearer {key}").replaceAll("{key}",n.apiKey.trim());l&&(c[u]=l);let d=i.bodyMode??"multipart",f=i.fileField?.trim()||"file",h=i.modelField===void 0?"model":i.modelField.trim(),p;if(d==="multipart"){let y=new FormData;y.set(f,Sp(t,r),e),h&&s&&y.set(h,s);for(let[_,w]of Object.entries(i.extraFields??{}))y.set(_,w);p=y}else d==="raw"?(c["Content-Type"]=$p(r),p=new Uint8Array(t)):(c["Content-Type"]="application/json",p=JSON.stringify({[f]:t.toString("base64"),...h&&s?{[h]:s}:{},...i.extraFields??{}}));let m=await va(a,{method:i.method?.trim()||"POST",headers:c,body:p},o,[n.apiKey.trim()]);if(!m.ok)return m;let g=_a(m.json,i.responseTextPath?.trim()||"text");return g!==void 0?{ok:!0,text:g}:{ok:!1,error:`STT response has no text at "${i.responseTextPath?.trim()||"text"}"`}},hP={"openai-compatible":dP,elevenlabs:pP,deepgram:fP,custom:mP};async function vv(t,e,r,n){let o=xp(n);if(!o.ready)return{ok:!1,error:o.reason};let i=n.maxBytes??uP;if(t.length>i)return{ok:!1,error:`voice message is ${t.length} B \u2014 over the ${i} B STT limit (stt.maxBytes)`};let s=n.timeoutMs??lP;try{return await hP[o.provider](t,e,r,n,s)}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a)}}}function gP(t){return/limit|over .* bytes/i.test(t)?"size_limit":/timeout/i.test(t)?"timeout":/HTTP \d+/i.test(t)?"provider_http":/missing|no text|no transcript/i.test(t)?"invalid_response":"provider_error"}function bv(t,e,r){return!t.ready||e.kind==="unconfigured"?{configured:!1,attempted:!1,status:"unavailable",provider:null,text:null,error_category:"not_configured",audio_path:r.audioPath,file_wire_id:r.wireId}:e.kind==="transcript"?{configured:!0,attempted:!0,status:"succeeded",provider:t.provider,text:e.text,error_category:null,audio_path:r.audioPath,file_wire_id:r.wireId}:{configured:!0,attempted:!0,status:"failed",provider:t.provider,text:null,error_category:gP(e.error),audio_path:r.audioPath,file_wire_id:r.wireId}}function wv(t,e){let r=` \u2022 \u{1F3A4} voice message from ${t.sender} (${t.sizeBytes} B)`,n=`audio saved \u2192 ${t.savedPath} {${t.wire}}`;switch(e.kind){case"transcript":return`${r}: "${e.text}" \u2014 transcribed from voice message (STT); ${n}`;case"unconfigured":return`${r}: cannot transcribe \u2014 ${e.reason}. Tell the user you can't listen to voice messages until the operator configures transcription on this ours-mcp server, and ask them to send text meanwhile; ${n}`;case"failed":return`${r}: transcription failed (${e.error}). Tell the user their voice message could not be transcribed right now and ask them to send text or retry; ${n}`}}import*as It from"node:fs";import{join as yP}from"node:path";var _P="startup-progress.json",$v=1;function vP(t){return yP(t,_P)}function xv(t,e={}){let r=e.pid??process.pid,n=e.now??Date.now,o=n(),i=vP(t),s=`${i}.${r}.tmp`,a=Math.max(100,e.heartbeatMs??2e3),c=!1,u=!1,l={version:$v,pid:r,bootId:`${r}-${o}`,phase:"initializing",startedAt:o,updatedAt:o},d=()=>{if(!u)try{It.mkdirSync(t,{recursive:!0,mode:448}),It.writeFileSync(s,`${JSON.stringify(l)}
|
|
57
57
|
`,{mode:384}),It.renameSync(s,i);try{It.chmodSync(i,384)}catch{}}catch{u=!0;try{It.rmSync(s,{force:!0})}catch{}}},f=(m,g)=>{l={version:$v,pid:r,bootId:l.bootId,phase:m,...g?{completed:g.completed,total:g.total}:{},startedAt:o,updatedAt:n()},d()};d();let h=setInterval(()=>{c||(l={...l,updatedAt:n()},d())},a);h.unref?.();let p=m=>{c||(f(m),c=!0,clearInterval(h))};return{update:f,ready:()=>p("ready"),failed:()=>p("failed")}}var bP=`: ka
|
|
58
58
|
|
|
59
|
-
`;function wP(t=process.env){let e=(t.OURS_SSE_KEEPALIVE_MS??"").trim();if(e==="")return 25e3;let r=Number(e);return Number.isFinite(r)&&r>=0?r:25e3}function ba(t,e=wP()){if(!(e>0))return;let r=!1,n=t.writeHead.bind(t);t.writeHead=(...s)=>{let a=typeof s[1]=="object"&&s[1]!==null?s[1]:s[2];if(a&&!Array.isArray(a))for(let[c,u]of Object.entries(a))c.toLowerCase()==="content-type"&&String(u).includes("text/event-stream")&&(r=!0);return n(...s)};let o=setInterval(()=>{if(!(!r||t.writableEnded||t.destroyed))try{t.write(bP)}catch{}},e);o.unref?.();let i=()=>clearInterval(o);t.once("close",i),t.once("finish",i)}function $P(t){let e=new Map;for(let r of t)e.set(r.name,(e.get(r.name)??0)+1);return e}function Sv(t){let e=$P(t);return t.map(r=>`\u2022 ${r.name} \u2014 ${r.container_id}${r.rootTag??""}${r.degradedQueued!==void 0?` \u2014 \u26A0 keys pending restore (${r.degradedQueued} queued)`:""}${(e.get(r.name)??0)>1?" \u2014 \u26A0 DUPLICATE NAME: sends to this name abort; address by container id, repair with rename_contact":""}${r.renamedFrom!==void 0?` \u2014 \u26A0 renamed on import (two contacts were named "${r.renamedFrom}"; do NOT assume the one keeping the bare name is the live one \u2014 verify by container id, settle with rename_contact)`:""}`)}function xP(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 fi="0.17.
|
|
59
|
+
`;function wP(t=process.env){let e=(t.OURS_SSE_KEEPALIVE_MS??"").trim();if(e==="")return 25e3;let r=Number(e);return Number.isFinite(r)&&r>=0?r:25e3}function ba(t,e=wP()){if(!(e>0))return;let r=!1,n=t.writeHead.bind(t);t.writeHead=(...s)=>{let a=typeof s[1]=="object"&&s[1]!==null?s[1]:s[2];if(a&&!Array.isArray(a))for(let[c,u]of Object.entries(a))c.toLowerCase()==="content-type"&&String(u).includes("text/event-stream")&&(r=!0);return n(...s)};let o=setInterval(()=>{if(!(!r||t.writableEnded||t.destroyed))try{t.write(bP)}catch{}},e);o.unref?.();let i=()=>clearInterval(o);t.once("close",i),t.once("finish",i)}function $P(t){let e=new Map;for(let r of t)e.set(r.name,(e.get(r.name)??0)+1);return e}function Sv(t){let e=$P(t);return t.map(r=>`\u2022 ${r.name} \u2014 ${r.container_id}${r.rootTag??""}${r.degradedQueued!==void 0?` \u2014 \u26A0 keys pending restore (${r.degradedQueued} queued)`:""}${(e.get(r.name)??0)>1?" \u2014 \u26A0 DUPLICATE NAME: sends to this name abort; address by container id, repair with rename_contact":""}${r.renamedFrom!==void 0?` \u2014 \u26A0 renamed on import (two contacts were named "${r.renamedFrom}"; do NOT assume the one keeping the bare name is the live one \u2014 verify by container id, settle with rename_contact)`:""}`)}function xP(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 fi="0.17.1",Lt=dv(),ze=Lt.stateDir,Sa=Lt.brokerUrl,Fv=process.env.OURS_TRANSPORT??"http",kp=Lt.port,Tv=Lt.gcIntervalMs,Op=Lt.apiVisibility,DP=Number(process.env.OURS_TEST_STARTUP_HEARTBEAT_MS||"")||void 0,Xt=Fv==="http"?xv(ze,{heartbeatMs:DP}):null,$=(...t)=>process.stderr.write(`ours: ${t.join(" ")}
|
|
60
60
|
`);function qP(){if(Op==="open")return null;if(Op==="shared"){let t=pv(Lt);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 (${vp(Lt)} is not used for shared mode). Use apiVisibility=owner for a same-user-only auto-token, or =open to disable auth.`);return t}return fv(Lt,{generate:!0}).token}var zv=qP();function VP(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 LP(t){if(zv===null)return!0;let e=VP(t);if(!e)return!1;let r=Buffer.from(e),n=Buffer.from(zv);return r.length===n.length&&zP(r,n)}function li(t,e){return LP(t)?!0:(e.writeHead(401,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"unauthorized"})),!1)}var UP=/^[A-Za-z0-9 _.@-]{1,64}$/,ka="contact-book";function mi(t){return UP.test(t)?t==="."||t===".."||t.includes("/")||t.includes("\\")?"invalid name":t===ka?`"${ka}" 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 FP(){let t=kP(TP(import.meta.url)),e=process.env.OURS_UNIT_DIR,r=process.env.OURS_ADVERTISE_MIGRATE==="0",n=i=>r?[`${i}-nocap`]:[i],o=e?n(SP(e)):[Re(t,"mufl_code"),Re(t,"..","mufl_code")].flatMap(n);for(let i of o){if(!R.existsSync(i))continue;let s=R.readdirSync(i).find(a=>a.endsWith(".muflo"));if(s){let a=s.slice(0,-6),c=new Uint8Array(R.readFileSync(Re(i,s)));return{dir:i,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 hi,on,D=new Map,bt=null,Np=null,Pe=new Map,Ia=new Set,qe=new Map,yi=new Set;function Pt(t){if(!Number.isInteger(t)||t<=0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function Ra(t){for(let e of Pe.values())if(e.token===t)return e}var Ev=()=>Re(ze,"bindings.json");function bi(){try{R.mkdirSync(ze,{recursive:!0});let t=`${Ev()}.tmp`;R.writeFileSync(t,JSON.stringify({pid:process.pid,bound:[...Pe.keys()],holders:[...Pe.values()].map(e=>({identity:e.identity,pid:e.pid}))})),R.renameSync(t,Ev())}catch(t){$("failed to persist bindings snapshot:",String(t))}}var Bv=t=>Re(ze,t),wi=t=>Re(t,"identity.key"),sn=t=>Re(t,"state_data.bin"),Up=t=>Re(t,"notifications.log"),Ap=t=>Re(t,"unread.json"),Hv=t=>Re(t.dir,"files"),Gv=t=>Re(t,"temp.json"),Yn=t=>qv("sha256").update(t).digest("hex");function Jv(t,e){R.writeFileSync(Gv(t),JSON.stringify({v:1,owner:{token_sha256:e.owner.tokenHash,pid:e.owner.pid},created_at:e.createdAt}),{mode:384})}function Kv(t){try{let e=JSON.parse(R.readFileSync(Gv(t),"utf8"));return e.v!==1||typeof e.owner?.token_sha256!="string"||typeof e.owner?.pid!="number"?null:{owner:{tokenHash:e.owner.token_sha256,pid:e.owner.pid},createdAt:typeof e.created_at=="number"?e.created_at:0}}catch{return null}}function BP(){for(let t of Fp()){let e=Re(ze,t);try{R.chmodSync(e,448)}catch(r){$(`[${t}] chmod 0700 failed:`,String(r))}for(let r of[sn(e),wi(e)])if(R.existsSync(r))try{R.chmodSync(r,384)}catch(n){$(`[${t}] chmod 0600 ${r} failed:`,String(n))}}}var HP=t=>/^[A-Za-z0-9]+$/.test(t)&&t.length>0&&t.length<=128,GP=t=>/^[A-Fa-f0-9]{64}$/.test(t),Rp=32;function Wv(t,e){if(!HP(e))return null;let r=Hv(t),n;try{n=R.readdirSync(r)}catch{return null}let o=`${e}-`,i=n.find(s=>s.startsWith(o));return i?Re(r,i):null}function Fp(){return R.existsSync(ze)?R.readdirSync(ze,{withFileTypes:!0}).filter(t=>t.isDirectory()&&R.existsSync(wi(Re(ze,t.name)))).map(t=>t.name):[]}var _i=()=>Re(ze,ka),Iv=()=>Re(_i(),"registrar.key"),Cp=()=>Re(_i(),"book.json");function Pa(){try{let t=JSON.parse(R.readFileSync(Cp(),"utf8"));return t&&typeof t.entries=="object"?t.entries:{}}catch{return{}}}function Yv(t){R.mkdirSync(_i(),{recursive:!0});let e=`${Cp()}.tmp`;R.writeFileSync(e,JSON.stringify({v:1,entries:t},null,2),{mode:384}),R.renameSync(e,Cp())}function eo(t){return Ve(e=>Buffer.from(Se(t,"::actor::export_address_document",e).GetBinary()))}function Qv(t){return Ve(e=>Buffer.from(Se(t,"::actor::export_signing_secret",e).Serialize()).toString("hex"))}async function Xv(t){if(!bt)throw new Error("registrar is not available");let e=eo(t),r=await F(async o=>{let i=await Z(bt,"::actor::sign_book_entry",{name:t.name,ad:bt.pw.packet.NewBinaryFromBuffer(e).Attach(o)},o);return Buffer.from(i.Reduce("sig").GetBinary()).toString("base64url")}),n=Pa();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},Yv(n),$(`[${t.name}] published to the local contact book`)}function eb(t){let e=Pa(),r=Object.entries(e).find(([,n])=>n.container_id===t.cid);r&&(delete e[r[0]],Yv(e),$(`[${t.name}] removed from the local contact book (entry "${r[0]}")`))}async function tb(t){if(!Np)throw new Error("registrar is not available");await F(async e=>{await Z(t,"::actor::pin_registrar",{registrar_ad:t.pw.packet.NewBinaryFromBuffer(Np).Attach(e)},e)})}var Ta=()=>Re(ze,"root.json"),se=null;function JP(){try{let t=JSON.parse(R.readFileSync(Ta(),"utf8"));return typeof t.name=="string"?t.name:null}catch{return null}}function KP(t){R.mkdirSync(ze,{recursive:!0});let e=`${Ta()}.tmp`;R.writeFileSync(e,JSON.stringify({v:1,name:t})),R.renameSync(e,Ta())}function rb(){R.rmSync(Ta(),{force:!0})}function vt(t){return Ve(e=>{let r=Se(t,"::actor::describe_identity",e);return{bio:r.Reduce("bio").Visualize(),persona:r.Reduce("persona").Visualize(),hasCert:r.Reduce("has_cert").GetBoolean(),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 Qn(t,e){await F(async r=>{let n=eo(e),o=await Z(t,"::actor::sign_delegation",{role_ad:t.pw.packet.NewBinaryFromBuffer(n).Attach(r),role_id:e.name},r),i=Buffer.from(o.Reduce("cert").GetBinary()),s=await Z(t,"::actor::export_root_profile",{},r),a=Buffer.from(s.Reduce("profile").GetBinary()),c=eo(t),u=Buffer.from((await Z(e,"::actor::export_v1_address_document",{},r)).Reduce("ad").GetBinary()),l=await Z(t,"::actor::sign_delegation",{role_ad:t.pw.packet.NewBinaryFromBuffer(u).Attach(r),role_id:e.name},r),d=Buffer.from(l.Reduce("cert").GetBinary());await Z(e,"::actor::set_delegation",{cert:e.pw.packet.NewBinaryFromBuffer(i).Attach(r),root_ad:e.pw.packet.NewBinaryFromBuffer(c).Attach(r),root_profile:e.pw.packet.NewBinaryFromBuffer(a).Attach(r),cert_v1:e.pw.packet.NewBinaryFromBuffer(d).Attach(r)},r)}),$(`[${e.name}] delegated as a role under root "${t.name}"`)}async function Pv(t){se=t.name,KP(t.name);let e=[],r=[];for(let n of D.values())if(n.name!==t.name&&!n.temp)try{await Qn(t,n),e.push(n.name)}catch(o){$(`failed to adopt "${n.name}" as a role under new root "${t.name}":`,String(o)),r.push(n.name)}return $(`[${t.name}] established as the host root${e.length?` (adopted ${e.length} role(s))`:""}`),{adopted:e,failed:r}}function WP(t,e){if(!se||!D.has(se))return null;let r=D.get(e)??[...D.values()].find(o=>o.cid===e);if(!r||r.name===t.name)return null;let n=o=>o.name===se||vt(o).roleId!=="";return n(t)&&n(r)?r:null}async function YP(t,e,r){let n=eo(e);return await F(async o=>{await Z(t,"::actor::connect_sibling",{name:e.name,target_ad:t.pw.packet.NewBinaryFromBuffer(n).Attach(o),text:r},o)}),an(t),`"${e.name}" was not a contact yet \u2014 connected as an intra-root sibling (delegation-cert auto-accept) and delivered the message.`}async function QP(t,e,r){if(!bt)throw new Error(`"${e}" is not a contact, and the local contact book is unavailable.`);let n=Pa(),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 i=Buffer.from(o.address_document,"base64url"),s=Buffer.from(o.registrar_sig,"base64url"),a=eo(t);return await F(async c=>{let u=await Z(bt,"::actor::mint_introduction",{joiner_ad:bt.pw.packet.NewBinaryFromBuffer(a).Attach(c),target_ad:bt.pw.packet.NewBinaryFromBuffer(i).Attach(c)},c),l=Buffer.from(u.Reduce("intro").GetBinary());await Z(t,"::actor::connect_local",{name:o.name,target_ad:t.pw.packet.NewBinaryFromBuffer(i).Attach(c),intro:t.pw.packet.NewBinaryFromBuffer(l).Attach(c),entry_sig:t.pw.packet.NewBinaryFromBuffer(s).Attach(c),text:r},c)}),an(t),`"${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 $i(t){return Ve(e=>{let r=Se(t,"::a2a_messaging::get_monitoring_status",e),n=Se(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 gi(t,e,r){await F(async n=>{await Z(t,"::a2a_control::send_control",{contact:e,payload:JSON.stringify(r)},n)})}function nb(t){try{return Ve(e=>{let r=Se(t,"::a2a_capabilities::get_manifest",e).Reduce("capabilities");return r.IsNil()?[]:[...r.GetKeys()].map(n=>typeof n=="string"?n:n.Visualize())})}catch{return[]}}function XP(t){let e="",r="",n="",o="",i=[];try{Ve(s=>{let a=Se(t,"::a2a_capabilities::get_manifest",s),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()||(i=[...u.GetKeys()].map(l=>typeof l=="string"?l:l.Visualize()))})}catch{}return{app_id:e,name:r,description:n,version:o,capabilities:i,monitoring_status:$i(t).proxyCid?"bound":"unbound"}}function eO(t){let e=[];for(let r of D.values()){if(r.name===t.name)continue;let n=vt(r);n.rootCid===t.cid&&e.push({name:r.name,cid:r.cid,role_id:n.roleId,bio:n.bio,monitoring:n.monitoringEnabled,capabilities:nb(r)})}return e}function Bp(t){try{on.remove_packet(t.cid)}catch(e){$(`remove_packet(${t.cid}) failed:`,String(e))}D.delete(t.name);try{eb(t)}catch(e){$(`failed to unpublish "${t.name}" from the contact book:`,String(e))}Pe.has(t.name)&&(Pe.delete(t.name),bi()),t.name===se&&(se=null,rb());try{R.rmSync(t.dir,{recursive:!0,force:!0}),Ot.delete(t.name)}catch(e){return`deleting ${t.dir} failed: ${String(e)}`}return null}function za(t,e){let r=t.temp;return r?(r.closing||(r.closing=(async()=>{$(`[${t.name}] closing temporary identity (${e})`);let n=[];try{n=Ve(a=>db(Se(t,"::a2a_messaging::list_contacts",a)))}catch(a){$(`[${t.name}] contact snapshot failed during close (continuing with local cleanup):`,String(a))}let o=0,i=0;yi.add(t.name);try{for(let a of n)try{await F(async u=>{let d=(await Z(t,"::a2a_messaging::remove_contact",{contact:a.container_id},u)).Reduce("notified");return d.IsNil()?!1:d.GetBoolean()})?o++:i++}catch(c){i++,$(`[${t.name}] remove-me to ${a.container_id} failed (continuing):`,String(c))}}finally{yi.delete(t.name)}let s=Bp(t);return $(s?`[${t.name}] temporary identity close: LOCAL DELETE FAILED \u2014 ${s}`:`[${t.name}] temporary identity closed: ${n.length} contact(s), ${o} remove-me notice(s) queued, ${i} not sent (delivery unverified by design)`),{attempted:n.length,notified:o,failed:i,deleteError:s}})()),r.closing):Promise.reject(new Error(`identity "${t.name}" is not temporary`))}function ob(){for(let t of[...D.values()]){let e=t.temp;if(!e||e.closing||Pt(e.owner.pid))continue;let r=Pe.get(t.name);r&&Pt(r.pid)||za(t,`stale lease \u2014 owner pid ${e.owner.pid} is dead`).catch(n=>$(`[${t.name}] stale-temp reclaim failed:`,String(n)))}}function tO(){if(R.existsSync(ze))for(let t of R.readdirSync(ze,{withFileTypes:!0})){if(!t.isDirectory()||D.has(t.name))continue;let e=Re(ze,t.name),r=Kv(e);if(!(!r||Pt(r.owner.pid)))try{R.rmSync(e,{recursive:!0,force:!0}),Ot.delete(t.name),$(`[${t.name}] removed orphaned temporary-identity dir (owner pid ${r.owner.pid} dead, no live packet)`)}catch(n){$(`[${t.name}] failed to remove orphaned temporary-identity dir:`,String(n))}}}var Hp=!0,ib=Hp?2:1,rO=6e5,jp=new Map,Mp=(t,e)=>`${t}:${e}`;function sb(t,e,r){e&&jp.set(Mp(t,e),{response:r,at:Date.now()})}function nO(t,e){if(!e)return;let r=jp.get(Mp(t,e));if(r){if(Date.now()-r.at>rO){jp.delete(Mp(t,e));return}return r.response}}async function oO(t,e,r){let n=vi(r);if(!n||typeof n!="object")return;let o=n,i=o.result;if(i&&typeof i=="object"&&i.pending===!0)return;let s=String(o.req_id??"");s&&(await gi(t,e,o),sb(e,s,o))}async function iO(t,e,r,n,o,i){let s;try{let d=JSON.parse(o);if(!d||typeof d!="object")throw new Error("not an object");s=d}catch{$(`[${t.name}] dropping unparseable control payload from ${n}`);return}if(s.v===1){s.t==="get_manifest"?await gi(t,r,{v:1,t:"res",id:s.id??null,ok:!0,manifest:{...XP(t),protocol_version:ib}}):await gi(t,r,{v:1,t:"res",id:s.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(s.req_id??""),c=nO(r,a);if(c){await gi(t,r,c);return}let u=s.args&&typeof s.args=="object"?s.args:{},l={cap:String(s.cap??""),verb:String(s.verb??""),args:u,req_id:a};await F(async d=>{let f;try{f=await Z(t,"::actor::process_control_envelope",{sender_id:e,sender_name:n,envelope:l,date:i},d)}catch(h){$(`[${t.name}] dispatch of "${l.cap}.${l.verb}" from ${n} failed:`,String(h));return}if(await oO(t,r,f),l.cap==="core.monitoring"&&l.verb==="bind")try{let h=vi(f);h&&(h.ok===!0||h.$ok===!0)&&dO(t,r)}catch{}})}async function sO(t){for(;;)if(await F(async r=>{let o=(await Z(t,"::actor::get_control_requests",{},r)).Reduce("requests"),i=o.GetKeys();if(i.length===0)return!0;for(let s=0;s<i.length;s++){let a=o.Reduce(s),c=a.Reduce("sender_cid");await iO(t,c,c.Visualize(),a.Reduce("sender_name").Visualize(),a.Reduce("payload").Visualize(),a.Reduce("date"))}return!1}))return}function aO(){return String(Vv(0,1e6)).padStart(6,"0")}var cn=new Map;function Oa(t){return[...D.values()].find(e=>e.cid===t)}async function xi(t,e){let r=e.Reduce("target").Visualize(),n=vi(e.Reduce("response"));if(!n||typeof n!="object")return;await gi(t,r,n);let o=String(n.req_id??"");o&&sb(r,o,n)}async function cO(t,e,r,n){try{if(D.has(e)){$(`[${t.name}] host_provision_child("${e}") rejected: name exists (settles via sweep timeout)`);return}let o=await $a(e);await F(async i=>{r&&await Z(o,"::a2a_messaging::set_my_bio",{bio:r},i),await Qn(t,o);let s=vt(o).roleId,a=Se(o,"::actor::export_address_document_native",i),c=await Z(t,"::a2a_cluster::register_provisioned_child",{pending_handle:n,role_id:s,child_ad:a},i);await xi(t,c)})}catch(o){$(`[${t.name}] host_provision_child("${e}") failed (settles via sweep timeout):`,String(o))}}async function uO(t,e,r){try{let n=Oa(e.Visualize());if(n){let o=Bp(n);o&&$(`[${t.name}] host_destroy_child teardown warning:`,o)}cn.delete(e.Visualize()),await F(async o=>{let i=await Z(t,"::a2a_cluster::confirm_child_destroyed",{pending_handle:r,cid:e},o);await xi(t,i)})}catch(n){$(`[${t.name}] host_destroy_child failed (settles via sweep timeout):`,String(n))}}async function lO(t,e,r){try{let n=Oa(e.Visualize());if(!n){$(`[${t.name}] host_mint_child_invite: unknown child ${e.Visualize()} (settles via sweep timeout)`);return}await F(async o=>{let i=await Z(n,"::a2a_messaging::generate_invite",{},o),s=t.pw.packet.NewBinaryFromBuffer(Buffer.from(i.Reduce("invite").GetBinary())).Attach(o),a=await Z(t,"::a2a_cluster::register_child_invite",{pending_handle:r,invite:s},o);await xi(t,a)})}catch(n){$(`[${t.name}] host_mint_child_invite failed (settles via sweep timeout):`,String(n))}}async function Zp(t,e,r,n){await F(async o=>{if(e){n&&await Z(t,"::a2a_messaging::host_register_monitoring_cp",{cp_ad:n},o);let i=aO();await Z(t,"::a2a_messaging::set_proxy_pending",{code:i,proxy:r},o),await Z(t,"::a2a_messaging::verify_proxy_code",{code:i,sender:r},o),cn.set(t.cid,r??"")}else await Z(t,"::a2a_messaging::host_clear_child_monitoring",{},o),cn.delete(t.cid)})}async function Ov(t,e,r,n,o,i){try{let s=Oa(e.Visualize());if(!s){$(`[${t.name}] host_set_child_monitoring: unknown child ${e.Visualize()} (settles via sweep timeout)`);return}r?await Zp(s,!0,o?.Visualize(),i):await Zp(s,!1),await F(async a=>{let c=await Z(t,"::a2a_cluster::confirm_child_monitoring",{pending_handle:n,cid:e,enabled:r},a);await xi(t,c)})}catch(s){$(`[${t.name}] host_set_child_monitoring failed (settles via sweep timeout):`,String(s))}}async function dO(t,e){for(let[r,n]of[...cn.entries()]){if(n===e)continue;let o=Oa(r);if(!o){cn.delete(r);continue}await Zp(o,!1).catch(i=>$(`[${t.name}] CP-rebind clear of child ${r} failed:`,String(i)))}}function pO(t,e){let r=[];for(let n of D.values()){if(n.name===t.name)continue;let o=vt(n);if(o.rootCid!==t.cid)continue;let i=Se(n,"::actor::export_address_document_native",e);r.push({cid:i.Reduce("identity").Reduce("container_id"),role_id:o.roleId,name:n.name,bio:o.bio,persona:o.persona,caps:nb(n),child_ad:i})}return r}var Tp=new Set;async function ab(t){if(!Tp.has(t.name)){Tp.add(t.name);try{await F(async e=>{await Z(t,"::a2a_cluster::reconcile",{pending_handle:"",children:pO(t,e)},e);let n=(await Z(t,"::a2a_cluster::sweep_and_settle",{},e)).Reduce("settled"),o=n.GetKeys();for(let i=0;i<o.length;i++)await xi(t,n.Reduce(i))})}catch(e){$(`[${t.name}] cluster sweep failed:`,String(e))}finally{Tp.delete(t.name)}}}var fO=6e4;function mO(){setInterval(()=>{if(Hp)for(let t of D.values())vt(t).roleId===""&&ab(t)},fO).unref()}function hO(){for(let t of D.values())if(vt(t).roleId!=="")try{let e=$i(t).proxyCid;e&&cn.set(t.cid,e)}catch(e){cn.set(t.cid,""),$(`[${t.name}] monitoredChildren rebuild read failed (added clear-on-repoint):`,String(e))}}var zp=new Set;async function Gp(t){if(!zp.has(t.name)){zp.add(t.name);try{await sO(t)}catch(e){$(`[${t.name}] control dispatch failed:`,String(e))}finally{zp.delete(t.name)}if(D.has(t.name)&&$i(t).controlQueued>0)return Gp(t)}}async function gO(){R.mkdirSync(_i(),{recursive:!0});let t;try{t=R.readFileSync(Iv(),"utf8").trim()}catch{}let e=Vp(24).toString("hex");bt=await Kp(ka,e,_i(),!1,t),t||R.writeFileSync(Iv(),Qv(bt),{mode:384}),Np=eo(bt),$(`contact-book registrar ready (${bt.cid})`)}function yO(t){try{return R.existsSync(sn(t))&&R.statSync(sn(t)).size>0}catch{return!1}}function Dp(t){let e=Ve(i=>Buffer.from(Se(t,"::actor::export_state",i).Serialize()));R.mkdirSync(t.dir,{recursive:!0,mode:448});let r=sn(t.dir),n=`${r}.tmp`,o;try{o=R.openSync(n,"w",384),R.fchmodSync(o,384),R.writeFileSync(o,e),R.fsyncSync(o),R.closeSync(o),o=void 0,R.renameSync(n,r),R.chmodSync(r,384);try{R.chmodSync(wi(t.dir),384)}catch{}let i=R.openSync(t.dir,"r");try{R.fsyncSync(i)}finally{R.closeSync(i)}}catch(i){if(o!==void 0)try{R.closeSync(o)}catch{}try{R.rmSync(n,{force:!0})}catch{}throw i}}function Jp(t){try{Dp(t),t.persistFailed&&(t.persistFailed=!1,$(`[${t.name}] persist recovered \u2014 quarantine lifted`),ce(t,{event:"persist_recovered"}))}catch(e){t.persistFailed=!0,$(`[${t.name}] PERSIST FAILED \u2014 identity quarantined (fail-closed), outbound of this txn withheld:`,String(e));try{ce(t,{event:"persist_failed",error:String(e).slice(0,300)})}catch{}throw process.nextTick(()=>De(t.name,`[${t.name}] PERSIST FAILED \u2014 messaging quarantined until the state file is writable again`)),e}}function _O(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 vO(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 cb(t,e){try{let r=await F(async n=>{let o=await Z(t,"::a2a_messaging::flush_deferred",{contact:e},n);return Number(o.Reduce("flushed").Visualize())});r>0&&$(`[${t.name}] flushed ${r} deferred message(s) to ${e.slice(0,12)}\u2026`)}catch(r){$(`[${t.name}] deferred flush to ${e.slice(0,12)}\u2026 failed:`,String(r))}}async function ub(t){try{let e=await F(async n=>{let o=await Z(t,"::a2a_messaging::restore_degraded_contacts",{},n);return Number(o.Reduce("requested").Visualize())});e>0&&$(`[${t.name}] contact restore requested for ${e} degraded contact(s)`);let r=Ve(n=>vO(Se(t,"::a2a_messaging::list_deferred_queues",n)));for(let n of r)n.degraded||await cb(t,n.cid)}catch(e){$(`[${t.name}] contact-restore sweep failed:`,String(e))}}async function Ea(t){try{let e=await F(async r=>{let n=await Z(t,"::a2a_messaging::reconcile_advertise",{},r),o=i=>n.Reduce(i).IsNil()?0:Number(n.Reduce(i).Visualize());return{changed:/true/i.test(n.Reduce("changed").Visualize()),capabilityAdvertised:o("capability_advertised"),legacyReadvertised:o("legacy_readvertised")}});(e.capabilityAdvertised>0||e.legacyReadvertised>0)&&$(`[${t.name}] capability reconcile: changed=${e.changed} advertised=${e.capabilityAdvertised} legacy_migration_bootstrap=${e.legacyReadvertised}`)}catch(e){$(`[${t.name}] capability reconcile sweep failed:`,String(e))}}var Ep=new Set;function an(t){if(!Ep.has(t.name)){Ep.add(t.name);for(let e of[2e3,15e3])setTimeout(()=>{e===15e3&&Ep.delete(t.name);let r=D.get(t.name);r&&Ea(r)},e)}}async function qp(t){try{let e=await F(async r=>{let n=await Z(t,"::a2a_messaging::readvertise_e2e_recovery",{},r);return Number(n.Reduce("readvertised").Visualize())});e>0&&$(`[${t.name}] re-advertised fresh AD to ${e} e2e contact(s) (session recovery)`)}catch(e){$(`[${t.name}] e2e recovery re-advertise failed:`,String(e))}try{await F(async e=>{await Z(t,"::a2a_messaging::sweep_e2e_migrations",{},e)})}catch(e){$(`[${t.name}] e2e migration sweep failed:`,String(e))}try{let e=await F(async r=>{let n=await Z(t,"::a2a_messaging::redrive_unacked_sweep",{},r),o=i=>n.Reduce(i).IsNil()?0:Number(n.Reduce(i).Visualize());return{redriven:o("redriven_contacts"),purged:o("purged_contacts"),deferred:o("deferred_contacts")}});(e.redriven>0||e.purged>0||e.deferred>0)&&$(`[${t.name}] unacked sweep: redriven=${e.redriven} ttl_purged=${e.purged} deferred=${e.deferred} contact(s)`)}catch(e){$(`[${t.name}] unacked redrive sweep failed:`,String(e))}}var wa=new Map;function bO(t){let e=wa.get(t);if(!(!e||e.size===0))for(let r of[...e])try{r()}catch{}}function wO(t,e){return new Promise(r=>{let n=wa.get(t);n||(n=new Set,wa.set(t,n));let o=!1,i=()=>{o||(o=!0,n.delete(s),n.size===0&&wa.delete(t),clearTimeout(a),r())},s=i,a=setTimeout(i,e);n.add(s)})}function ce(t,e){try{R.mkdirSync(t.dir,{recursive:!0,mode:448}),R.appendFileSync(Up(t.dir),JSON.stringify(e)+`
|
|
61
61
|
`)}catch(r){$(`[${t.name}] failed to append notifications.log:`,String(r))}bO(t.name)}function $O(t){let e=Up(t.dir),r="";try{r=R.readFileSync(e,"utf8")}catch{return new Set}let n=[];for(let o of r.split(`
|
|
62
62
|
`))if(o.trim())try{n.push(JSON.parse(o))}catch{}return yv(n)}function di(t,e){let r=t.Reduce(e);return r.IsNil()?"":Buffer.from(r.GetBinary()).toString("hex")}var xO=Number(process.env.OURS_NOTIFY_LONGPOLL_MS)>0?Number(process.env.OURS_NOTIFY_LONGPOLL_MS):25e3,SO=250;function Ip(t){try{return R.statSync(t).size}catch{return 0}}function kO(t,e,r){if(r<=e)return{events:[],cursor:e};let n=Buffer.alloc(r-e),o=0;try{let c=R.openSync(t,"r");try{o=R.readSync(c,n,0,n.length,e)}finally{R.closeSync(c)}}catch{return{events:[],cursor:e}}let i=n.subarray(0,o),s=i.lastIndexOf(10);if(s===-1)return{events:[],cursor:e};let a=[];for(let c of i.subarray(0,s+1).toString("utf8").split(`
|
package/dist/mufl_code/8ED6356B41CC689C75DA3302AD7856058131661A6ABBAC961E71BA838D8C97A3.muflo
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/mcp",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.1",
|
|
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",
|