@ours.network/mcp 0.14.0 → 0.14.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/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(v=>ho.parse(v)):a=[ho.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(yo);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 v=this.validateSession(e);if(v)return v;let y=this.validateProtocolVersion(e);if(y)return y}if(!a.some(nr)){for(let v of a)this.onmessage?.(v,{authInfo:r?.authInfo,requestInfo:s});return new Response(null,{status:202})}let l=crypto.randomUUID(),d=a.find(v=>yo(v)),p=d?d.params.protocolVersion:e.headers.get("mcp-protocol-version")??Dm;if(this._enableJsonResponse)return new Promise(v=>{this._streamMapping.set(l,{resolveJson:v,cleanup:()=>{this._streamMapping.delete(l)}});for(let y of a)nr(y)&&this._requestToStreamMapping.set(y.id,l);for(let y of a)this.onmessage?.(y,{authInfo:r?.authInfo,requestInfo:s})});let f=new TextEncoder,m,h=new ReadableStream({start:v=>{m=v},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 v of a)nr(v)&&(this._streamMapping.set(l,{controller:m,encoder:f,cleanup:()=>{this._streamMapping.delete(l);try{m.close()}catch{}}}),this._requestToStreamMapping.set(v.id,l));await this.writePrimingEvent(m,f,l,p);for(let v of a){let y,$;nr(v)&&this._eventStore&&p>="2025-11-25"&&(y=()=>{this.closeSSEStream(v.id)},$=()=>{this.closeStandaloneSSEStream()}),this.onmessage?.(v,{authInfo:r?.authInfo,requestInfo:s,closeSSEStream:y,closeStandaloneSSEStream:$})}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&&!yn.includes(r))return this.onerror?.(new Error(`Bad Request: Unsupported protocol version: ${r} (supported versions: ${yn.join(", ")})`)),this.createJsonErrorResponse(400,-32e3,`Bad Request: Unsupported protocol version: ${r} (supported versions: ${yn.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((Ut(e)||_n(e))&&(n=e.id),n===void 0){if(Ut(e)||_n(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(Ut(e)||_n(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 sa=class{constructor(e={}){this._requestContext=new WeakMap,this._webStandardTransport=new oa(e),this._requestListener=sp(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 sp(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 HI,join as Re,dirname as GI,isAbsolute as JI,basename as KI}from"node:path";import{fileURLToPath as WI}from"node:url";import{randomBytes as $v,randomInt as xv,randomUUID as YI,timingSafeEqual as XI}from"node:crypto";import{createServer as QI}from"node:http";import{brotliCompressSync as eP,brotliDecompressSync as tP}from"node:zlib";import*as T from"node:fs";import{readFile as rP,mkdir as nP,writeFile as oP}from"node:fs/promises";import{adapt_wrapper as sP}from"@adapt-toolkit/sdk/executables";import{PacketWrapperConfigurator as iP}from"@adapt-toolkit/sdk/wrappers";import{object_to_adapt_value as Sv}from"@adapt-toolkit/sdk/wrapper";import{AdaptObjectLifetime as Pp}from"@adapt-toolkit/sdk/common";import*as st from"node:fs";import{randomBytes as wI}from"node:crypto";import{homedir as W_}from"node:os";import{resolve as ia,join as ip,dirname as Y_,basename as $I}from"node:path";var X_=["owner","shared","open"],Bn={brokerUrl:"wss://broker1.ours.network",port:3050,stateDir:ia(W_(),".ours"),gcIntervalMs:36e5,autoStart:!1,apiVisibility:"owner"};function xI(){return process.env.OURS_CONFIG??ip(W_(),".ours","config.json")}function SI(){let t;try{t=st.readFileSync(xI(),"utf8")}catch{return{}}let e;try{e=JSON.parse(t)}catch{return{}}let r={};if(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=ia(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"&&X_.includes(e.apiVisibility)&&(r.apiVisibility=e.apiVisibility),typeof e.apiToken=="string"&&e.apiToken.trim()&&(r.apiToken=e.apiToken.trim()),e.stt&&typeof e.stt=="object"){let n=e.stt,o={};typeof n.provider=="string"&&(o.provider=n.provider),typeof n.apiKey=="string"&&(o.apiKey=n.apiKey),typeof n.model=="string"&&(o.model=n.model),typeof n.baseUrl=="string"&&(o.baseUrl=n.baseUrl),typeof n.language=="string"&&(o.language=n.language),typeof n.maxBytes=="number"&&Number.isFinite(n.maxBytes)&&(o.maxBytes=n.maxBytes),typeof n.timeoutMs=="number"&&Number.isFinite(n.timeoutMs)&&(o.timeoutMs=n.timeoutMs),n.custom&&typeof n.custom=="object"&&(o.custom=n.custom),r.stt=o}return r}function kI(){let t=process.env.OURS_API_VISIBILITY?.trim().toLowerCase();return t&&X_.includes(t)?t:void 0}function zI(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 Q_(){let t=SI();return{brokerUrl:process.env.OURS_BROKER_URL??t.brokerUrl??Bn.brokerUrl,port:J_("OURS_PORT")??t.port??Bn.port,stateDir:ia(process.env.OURS_STATE_DIR??t.stateDir??Bn.stateDir),gcIntervalMs:J_("OURS_GC_INTERVAL_MS")??t.gcIntervalMs??Bn.gcIntervalMs,autoStart:zI("OURS_AUTOSTART")??t.autoStart??Bn.autoStart,apiVisibility:kI()??t.apiVisibility??Bn.apiVisibility,apiToken:process.env.OURS_API_TOKEN?.trim()||t.apiToken,stt:RI(t.stt)}}function RI(t){let e={};process.env.OURS_STT_PROVIDER?.trim()&&(e.provider=process.env.OURS_STT_PROVIDER.trim()),process.env.OURS_STT_API_KEY?.trim()&&(e.apiKey=process.env.OURS_STT_API_KEY.trim()),process.env.OURS_STT_MODEL?.trim()&&(e.model=process.env.OURS_STT_MODEL.trim()),process.env.OURS_STT_BASE_URL?.trim()&&(e.baseUrl=process.env.OURS_STT_BASE_URL.trim()),process.env.OURS_STT_LANGUAGE?.trim()&&(e.language=process.env.OURS_STT_LANGUAGE.trim());let r={...t??{},...e};return Object.keys(r).length?r:void 0}var TI="daemon-token";function ap(t){return ip(t.stateDir,TI)}function ev(t){let e=process.env.OURS_API_TOKEN?.trim();return e||t.apiToken?.trim()||void 0}function tv(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=ap(t);try{let i=st.readFileSync(o,"utf8").trim();if(i)return{token:i,source:"file"}}catch{}if(!e.generate)return null;let s=wI(32).toString("hex");try{st.mkdirSync(Y_(o),{recursive:!0}),st.writeFileSync(o,s+`
55
55
  `,{mode:384}),st.chmodSync(o,384)}catch{}return{token:s,source:"generated"}}var K_=".ours-identity";function cp(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 EI(t){let e=ia(t);return $I(e)===K_?e:ip(e,K_)}function rv(t,e,r=!1){let n=cp(e),o=EI(t);if(!r&&st.existsSync(o))throw new Error(`${o} already exists \u2014 pass overwrite to replace it`);return st.mkdirSync(Y_(o),{recursive:!0}),st.writeFileSync(o,JSON.stringify(n,null,2)+`
56
- `),o}import{basename as II,extname as PI}from"node:path";var OI={".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 nv(t){return OI[PI(t).toLowerCase()]??"application/octet-stream"}function ov(t){let e=II(t).replace(/[^A-Za-z0-9._-]/g,"_");return e.length?e.slice(0,200):"file"}var NI=new Set(["e2e_app_recv","migration_deferred_flush"]);function sv(t){let e=new Set;for(let r of t){if(!r||typeof r!="object")continue;let n=r.event;if(typeof n!="string"||!NI.has(n))continue;let o=r.wire_id;typeof o=="string"&&o.length>0&&e.add(o)}return e}function AI(t,e){return t&&e.has(t)?"e2e":"legacy"}function CI(t,e){let r=AI(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 iv(t,e){let r=t.map(n=>CI(n,e));return{count:r.length,messages:r}}var jI="x-ours-kind=voice-message",MI="voice-message-";function lp(t,e){let r=(t??"").toLowerCase().split(";").map(n=>n.trim());return r.slice(1).includes(jI)?!0:e.toLowerCase().startsWith(MI)&&r[0].startsWith("audio/")}function dp(t){return(t??"").split(";")[0].trim()||"application/octet-stream"}var up=["openai-compatible","elevenlabs","deepgram","custom"],ZI=5*1024*1024,DI=6e4;function pp(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: ${up.join(" | ")}) \u2014 ${e}`};let r=t.provider.trim().toLowerCase();if(!up.includes(r))return{ready:!1,reason:`unknown STT provider "${t.provider}" (expected: ${up.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 aa(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 ca(t,e,r){let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{let s=await fetch(t,{...e,signal:n.signal});if(!s.ok){let i=await s.text().catch(()=>"");return{ok:!1,error:`STT HTTP ${s.status}${i?`: ${i.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(o)}}var fp=(t,e)=>new Blob([new Uint8Array(t)],{type:dp(e)}),qI=async(t,e,r,n,o)=>{let s=new FormData;s.set("file",fp(t,r),e),s.set("model",n.model.trim()),s.set("response_format","json"),n.language?.trim()&&s.set("language",n.language.trim());let i=await ca(`${n.baseUrl.trim().replace(/\/$/,"")}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${n.apiKey.trim()}`},body:s},o);if(!i.ok)return i;let a=aa(i.json,"text");return a!==void 0?{ok:!0,text:a}:{ok:!1,error:"STT response missing text"}},VI=async(t,e,r,n,o)=>{let s=new FormData;s.set("file",fp(t,r),e),s.set("model_id",n.model.trim()),n.language?.trim()&&s.set("language_code",n.language.trim());let i=await ca(`${(n.baseUrl?.trim()||"https://api.elevenlabs.io").replace(/\/$/,"")}/v1/speech-to-text`,{method:"POST",headers:{"xi-api-key":n.apiKey.trim()},body:s},o);if(!i.ok)return i;let a=aa(i.json,"text");return a!==void 0?{ok:!0,text:a}:{ok:!1,error:"STT response missing text"}},LI=async(t,e,r,n,o)=>{let s=new URLSearchParams;n.model?.trim()&&s.set("model",n.model.trim()),n.language?.trim()&&s.set("language",n.language.trim());let i=s.toString(),a=await ca(`${(n.baseUrl?.trim()||"https://api.deepgram.com").replace(/\/$/,"")}/v1/listen${i?`?${i}`:""}`,{method:"POST",headers:{Authorization:`Token ${n.apiKey.trim()}`,"Content-Type":dp(r)},body:new Uint8Array(t)},o);if(!a.ok)return a;let c=aa(a.json,"results.channels.0.alternatives.0.transcript");return c!==void 0?{ok:!0,text:c}:{ok:!1,error:"STT response missing transcript"}},UI=async(t,e,r,n,o)=>{let s=n.custom,i=n.model?.trim()??"",a=s.url.replaceAll("{model}",encodeURIComponent(i)),c={},u=s.authHeaderName?.trim()||"Authorization",l=(s.authHeaderTemplate??"Bearer {key}").replaceAll("{key}",n.apiKey.trim());l&&(c[u]=l);let d=s.bodyMode??"multipart",p=s.fileField?.trim()||"file",f=s.modelField===void 0?"model":s.modelField.trim(),m;if(d==="multipart"){let v=new FormData;v.set(p,fp(t,r),e),f&&i&&v.set(f,i);for(let[y,$]of Object.entries(s.extraFields??{}))v.set(y,$);m=v}else d==="raw"?(c["Content-Type"]=dp(r),m=new Uint8Array(t)):(c["Content-Type"]="application/json",m=JSON.stringify({[p]:t.toString("base64"),...f&&i?{[f]:i}:{},...s.extraFields??{}}));let h=await ca(a,{method:s.method?.trim()||"POST",headers:c,body:m},o);if(!h.ok)return h;let g=aa(h.json,s.responseTextPath?.trim()||"text");return g!==void 0?{ok:!0,text:g}:{ok:!1,error:`STT response has no text at "${s.responseTextPath?.trim()||"text"}"`}},FI={"openai-compatible":qI,elevenlabs:VI,deepgram:LI,custom:UI};async function av(t,e,r,n){let o=pp(n);if(!o.ready)return{ok:!1,error:o.reason};let s=n.maxBytes??ZI;if(t.length>s)return{ok:!1,error:`voice message is ${t.length} B \u2014 over the ${s} B STT limit (stt.maxBytes)`};let i=n.timeoutMs??DI;try{return await FI[o.provider](t,e,r,n,i)}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a)}}}function cv(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}`}}function BI(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 ss="0.14.0",Mt=Q_(),je=Mt.stateDir,fa=Mt.brokerUrl,aP=process.env.OURS_TRANSPORT??"http",mp=Mt.port,lv=Mt.gcIntervalMs,vp=Mt.apiVisibility,w=(...t)=>process.stderr.write(`ours: ${t.join(" ")}
56
+ `),o}import{basename as II,extname as PI}from"node:path";var OI={".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 nv(t){return OI[PI(t).toLowerCase()]??"application/octet-stream"}function ov(t){let e=II(t).replace(/[^A-Za-z0-9._-]/g,"_");return e.length?e.slice(0,200):"file"}var NI=new Set(["e2e_app_recv","migration_deferred_flush"]);function sv(t){let e=new Set;for(let r of t){if(!r||typeof r!="object")continue;let n=r.event;if(typeof n!="string"||!NI.has(n))continue;let o=r.wire_id;typeof o=="string"&&o.length>0&&e.add(o)}return e}function AI(t,e){return t&&e.has(t)?"e2e":"legacy"}function CI(t,e){let r=AI(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 iv(t,e){let r=t.map(n=>CI(n,e));return{count:r.length,messages:r}}var jI="x-ours-kind=voice-message",MI="voice-message-";function lp(t,e){let r=(t??"").toLowerCase().split(";").map(n=>n.trim());return r[0].startsWith("audio/")&&r.slice(1).includes(jI)?!0:e.toLowerCase().startsWith(MI)&&r[0].startsWith("audio/")}function dp(t){return(t??"").split(";")[0].trim()||"application/octet-stream"}var up=["openai-compatible","elevenlabs","deepgram","custom"],ZI=5*1024*1024,DI=6e4;function pp(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: ${up.join(" | ")}) \u2014 ${e}`};let r=t.provider.trim().toLowerCase();if(!up.includes(r))return{ready:!1,reason:`unknown STT provider "${t.provider}" (expected: ${up.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 aa(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 ca(t,e,r,n=[]){let o=new AbortController,s=setTimeout(()=>o.abort(),r);try{let i=await fetch(t,{...e,signal:o.signal});if(!i.ok){let a=await i.text().catch(()=>"");for(let c of n)c&&(a=a.split(c).join("[redacted]"));return{ok:!1,error:`STT HTTP ${i.status}${a?`: ${a.slice(0,200)}`:""}`}}return{ok:!0,json:await i.json()}}catch(i){return i?.name==="AbortError"?{ok:!1,error:`STT timeout after ${r}ms`}:{ok:!1,error:i instanceof Error?i.message:String(i)}}finally{clearTimeout(s)}}var fp=(t,e)=>new Blob([new Uint8Array(t)],{type:dp(e)}),qI=async(t,e,r,n,o)=>{let s=new FormData;s.set("file",fp(t,r),e),s.set("model",n.model.trim()),s.set("response_format","json"),n.language?.trim()&&s.set("language",n.language.trim());let i=await ca(`${n.baseUrl.trim().replace(/\/$/,"")}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${n.apiKey.trim()}`},body:s},o,[n.apiKey.trim()]);if(!i.ok)return i;let a=aa(i.json,"text");return a!==void 0?{ok:!0,text:a}:{ok:!1,error:"STT response missing text"}},VI=async(t,e,r,n,o)=>{let s=new FormData;s.set("file",fp(t,r),e),s.set("model_id",n.model.trim()),n.language?.trim()&&s.set("language_code",n.language.trim());let i=await ca(`${(n.baseUrl?.trim()||"https://api.elevenlabs.io").replace(/\/$/,"")}/v1/speech-to-text`,{method:"POST",headers:{"xi-api-key":n.apiKey.trim()},body:s},o,[n.apiKey.trim()]);if(!i.ok)return i;let a=aa(i.json,"text");return a!==void 0?{ok:!0,text:a}:{ok:!1,error:"STT response missing text"}},LI=async(t,e,r,n,o)=>{let s=new URLSearchParams;n.model?.trim()&&s.set("model",n.model.trim()),n.language?.trim()&&s.set("language",n.language.trim());let i=s.toString(),a=await ca(`${(n.baseUrl?.trim()||"https://api.deepgram.com").replace(/\/$/,"")}/v1/listen${i?`?${i}`:""}`,{method:"POST",headers:{Authorization:`Token ${n.apiKey.trim()}`,"Content-Type":dp(r)},body:new Uint8Array(t)},o,[n.apiKey.trim()]);if(!a.ok)return a;let c=aa(a.json,"results.channels.0.alternatives.0.transcript");return c!==void 0?{ok:!0,text:c}:{ok:!1,error:"STT response missing transcript"}},UI=async(t,e,r,n,o)=>{let s=n.custom,i=n.model?.trim()??"",a=s.url.replaceAll("{model}",encodeURIComponent(i)),c={},u=s.authHeaderName?.trim()||"Authorization",l=(s.authHeaderTemplate??"Bearer {key}").replaceAll("{key}",n.apiKey.trim());l&&(c[u]=l);let d=s.bodyMode??"multipart",p=s.fileField?.trim()||"file",f=s.modelField===void 0?"model":s.modelField.trim(),m;if(d==="multipart"){let v=new FormData;v.set(p,fp(t,r),e),f&&i&&v.set(f,i);for(let[y,$]of Object.entries(s.extraFields??{}))v.set(y,$);m=v}else d==="raw"?(c["Content-Type"]=dp(r),m=new Uint8Array(t)):(c["Content-Type"]="application/json",m=JSON.stringify({[p]:t.toString("base64"),...f&&i?{[f]:i}:{},...s.extraFields??{}}));let h=await ca(a,{method:s.method?.trim()||"POST",headers:c,body:m},o,[n.apiKey.trim()]);if(!h.ok)return h;let g=aa(h.json,s.responseTextPath?.trim()||"text");return g!==void 0?{ok:!0,text:g}:{ok:!1,error:`STT response has no text at "${s.responseTextPath?.trim()||"text"}"`}},FI={"openai-compatible":qI,elevenlabs:VI,deepgram:LI,custom:UI};async function av(t,e,r,n){let o=pp(n);if(!o.ready)return{ok:!1,error:o.reason};let s=n.maxBytes??ZI;if(t.length>s)return{ok:!1,error:`voice message is ${t.length} B \u2014 over the ${s} B STT limit (stt.maxBytes)`};let i=n.timeoutMs??DI;try{return await FI[o.provider](t,e,r,n,i)}catch(a){return{ok:!1,error:a instanceof Error?a.message:String(a)}}}function cv(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}`}}function BI(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 ss="0.14.1",Mt=Q_(),je=Mt.stateDir,fa=Mt.brokerUrl,aP=process.env.OURS_TRANSPORT??"http",mp=Mt.port,lv=Mt.gcIntervalMs,vp=Mt.apiVisibility,w=(...t)=>process.stderr.write(`ours: ${t.join(" ")}
57
57
  `);function cP(){if(vp==="open")return null;if(vp==="shared"){let t=ev(Mt);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 (${ap(Mt)} is not used for shared mode). Use apiVisibility=owner for a same-user-only auto-token, or =open to disable auth.`);return t}return tv(Mt,{generate:!0}).token}var dv=cP();function uP(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(dv===null)return!0;let e=uP(t);if(!e)return!1;let r=Buffer.from(e),n=Buffer.from(dv);return r.length===n.length&&XI(r,n)}function ua(t,e){return lP(t)?!0:(e.writeHead(401,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"unauthorized"})),!1)}var dP=/^[A-Za-z0-9 _.@-]{1,64}$/,ma="contact-book";function ha(t){return dP.test(t)?t==="."||t===".."||t.includes("/")||t.includes("\\")?"invalid name":t===ma?`"${ma}" 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 pP(){let t=GI(WI(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(HI(e)):[Re(t,"mufl_code"),Re(t,"..","mufl_code")].flatMap(n);for(let s of o){if(!T.existsSync(s))continue;let i=T.readdirSync(s).find(a=>a.endsWith(".muflo"));if(i){let a=i.slice(0,-6),c=new Uint8Array(T.readFileSync(Re(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 is,Qr,L=new Map,_t=null,bp=null,Ee=new Map,ya=new Set,it=new Map;function wp(t){if(!Number.isInteger(t)||t<=0)return!1;try{return process.kill(t,0),!0}catch(e){return e.code==="EPERM"}}function kv(t){for(let e of Ee.values())if(e.token===t)return e}var pv=()=>Re(je,"bindings.json");function ls(){try{T.mkdirSync(je,{recursive:!0});let t=`${pv()}.tmp`;T.writeFileSync(t,JSON.stringify({pid:process.pid,bound:[...Ee.keys()],holders:[...Ee.values()].map(e=>({identity:e.identity,pid:e.pid}))})),T.renameSync(t,pv())}catch(t){w("failed to persist bindings snapshot:",String(t))}}var zv=t=>Re(je,t),ds=t=>Re(t,"identity.key"),en=t=>Re(t,"state_data.bin"),Op=t=>Re(t,"notifications.log"),$p=t=>Re(t,"unread.json"),fP=t=>Re(t.dir,"files");function mP(){for(let t of Np()){let e=Re(je,t);try{T.chmodSync(e,448)}catch(r){w(`[${t}] chmod 0700 failed:`,String(r))}for(let r of[en(e),ds(e)])if(T.existsSync(r))try{T.chmodSync(r,384)}catch(n){w(`[${t}] chmod 0600 ${r} failed:`,String(n))}}}function Np(){return T.existsSync(je)?T.readdirSync(je,{withFileTypes:!0}).filter(t=>t.isDirectory()&&T.existsSync(ds(Re(je,t.name)))).map(t=>t.name):[]}var cs=()=>Re(je,ma),fv=()=>Re(cs(),"registrar.key"),xp=()=>Re(cs(),"book.json");function _a(){try{let t=JSON.parse(T.readFileSync(xp(),"utf8"));return t&&typeof t.entries=="object"?t.entries:{}}catch{return{}}}function Rv(t){T.mkdirSync(cs(),{recursive:!0});let e=`${xp()}.tmp`;T.writeFileSync(e,JSON.stringify({v:1,entries:t},null,2),{mode:384}),T.renameSync(e,xp())}function Jn(t){return He(e=>Buffer.from(Se(t,"::actor::export_address_document",e).GetBinary()))}function Tv(t){return He(e=>Buffer.from(Se(t,"::actor::export_signing_secret",e).Serialize()).toString("hex"))}async function Ev(t){if(!_t)throw new Error("registrar is not available");let e=Jn(t),r=await B(async o=>{let s=await M(_t,"::actor::sign_book_entry",{name:t.name,ad:_t.pw.packet.NewBinaryFromBuffer(e).Attach(o)},o);return Buffer.from(s.Reduce("sig").GetBinary()).toString("base64url")}),n=_a();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},Rv(n),w(`[${t.name}] published to the local contact book`)}function Iv(t){let e=_a();t in e&&(delete e[t],Rv(e),w(`[${t}] removed from the local contact book`))}async function Pv(t){if(!bp)throw new Error("registrar is not available");await B(async e=>{await M(t,"::actor::pin_registrar",{registrar_ad:t.pw.packet.NewBinaryFromBuffer(bp).Attach(e)},e)})}var ga=()=>Re(je,"root.json"),ie=null;function hP(){try{let t=JSON.parse(T.readFileSync(ga(),"utf8"));return typeof t.name=="string"?t.name:null}catch{return null}}function gP(t){T.mkdirSync(je,{recursive:!0});let e=`${ga()}.tmp`;T.writeFileSync(e,JSON.stringify({v:1,name:t})),T.renameSync(e,ga())}function Ov(){T.rmSync(ga(),{force:!0})}function yt(t){return He(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 Hn(t,e){await B(async r=>{let n=Jn(e),o=await M(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 M(t,"::actor::export_root_profile",{},r),a=Buffer.from(i.Reduce("profile").GetBinary()),c=Jn(t),u=Buffer.from((await M(e,"::actor::export_v1_address_document",{},r)).Reduce("ad").GetBinary()),l=await M(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 M(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),cert_v1:e.pw.packet.NewBinaryFromBuffer(d).Attach(r)},r)}),w(`[${e.name}] delegated as a role under root "${t.name}"`)}async function mv(t){ie=t.name,gP(t.name);let e=[],r=[];for(let n of L.values())if(n.name!==t.name)try{await Hn(t,n),e.push(n.name)}catch(o){w(`failed to adopt "${n.name}" as a role under new root "${t.name}":`,String(o)),r.push(n.name)}return w(`[${t.name}] established as the host root${e.length?` (adopted ${e.length} role(s))`:""}`),{adopted:e,failed:r}}function yP(t,e){if(!ie||!L.has(ie))return null;let r=L.get(e)??[...L.values()].find(o=>o.cid===e);if(!r||r.name===t.name)return null;let n=o=>o.name===ie||yt(o).roleId!=="";return n(t)&&n(r)?r:null}async function _P(t,e,r){let n=Jn(e);return await B(async o=>{await M(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 vP(t,e,r){if(!_t)throw new Error(`"${e}" is not a contact, and the local contact book is unavailable.`);let n=_a(),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=Jn(t);return await B(async c=>{let u=await M(_t,"::actor::mint_introduction",{joiner_ad:_t.pw.packet.NewBinaryFromBuffer(a).Attach(c),target_ad:_t.pw.packet.NewBinaryFromBuffer(s).Attach(c)},c),l=Buffer.from(u.Reduce("intro").GetBinary());await M(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 ps(t){return He(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 as(t,e,r){await B(async n=>{await M(t,"::a2a_control::send_control",{contact:e,payload:JSON.stringify(r)},n)})}function Nv(t){try{return He(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 bP(t){let e="",r="",n="",o="",s=[];try{He(i=>{let a=Se(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:ps(t).proxyCid?"bound":"unbound"}}function wP(t){let e=[];for(let r of L.values()){if(r.name===t.name)continue;let n=yt(r);n.rootCid===t.cid&&e.push({name:r.name,cid:r.cid,role_id:n.roleId,bio:n.bio,monitoring:n.monitoringEnabled,capabilities:Nv(r)})}return e}function Av(t){try{Qr.remove_packet(t.cid)}catch(e){w(`remove_packet(${t.cid}) failed:`,String(e))}L.delete(t.name);try{Iv(t.name)}catch(e){w(`failed to unpublish "${t.name}" from the contact book:`,String(e))}Ee.has(t.name)&&(Ee.delete(t.name),ls()),t.name===ie&&(ie=null,Ov());try{T.rmSync(t.dir,{recursive:!0,force:!0}),mr.delete(t.name)}catch(e){return`deleting ${t.dir} failed: ${String(e)}`}return null}var Ap=!0,Cv=Ap?2:1,$P=6e5,Sp=new Map,kp=(t,e)=>`${t}:${e}`;function jv(t,e,r){e&&Sp.set(kp(t,e),{response:r,at:Date.now()})}function xP(t,e){if(!e)return;let r=Sp.get(kp(t,e));if(r){if(Date.now()-r.at>$P){Sp.delete(kp(t,e));return}return r.response}}async function SP(t,e,r){let n=us(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 as(t,e,o),jv(e,i,o))}async function kP(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{w(`[${t.name}] dropping unparseable control payload from ${n}`);return}if(i.v===1){i.t==="get_manifest"?await as(t,r,{v:1,t:"res",id:i.id??null,ok:!0,manifest:{...bP(t),protocol_version:Cv}}):await as(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=xP(r,a);if(c){await as(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 B(async d=>{let p;try{p=await M(t,"::actor::process_control_envelope",{sender_id:e,sender_name:n,envelope:l,date:s},d)}catch(f){w(`[${t.name}] dispatch of "${l.cap}.${l.verb}" from ${n} failed:`,String(f));return}if(await SP(t,r,p),l.cap==="core.monitoring"&&l.verb==="bind")try{let f=us(p);f&&(f.ok===!0||f.$ok===!0)&&PP(t,r)}catch{}})}async function zP(t){for(;;)if(await B(async r=>{let o=(await M(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 kP(t,c,c.Visualize(),a.Reduce("sender_name").Visualize(),a.Reduce("payload").Visualize(),a.Reduce("date"))}return!1}))return}function RP(){return String(xv(0,1e6)).padStart(6,"0")}var tn=new Map;function va(t){return[...L.values()].find(e=>e.cid===t)}async function fs(t,e){let r=e.Reduce("target").Visualize(),n=us(e.Reduce("response"));if(!n||typeof n!="object")return;await as(t,r,n);let o=String(n.req_id??"");o&&jv(r,o,n)}async function TP(t,e,r,n){try{if(L.has(e)){w(`[${t.name}] host_provision_child("${e}") rejected: name exists (settles via sweep timeout)`);return}let o=await Ip(e);await B(async s=>{r&&await M(o,"::a2a_messaging::set_my_bio",{bio:r},s),await Hn(t,o);let i=yt(o).roleId,a=Se(o,"::actor::export_address_document_native",s),c=await M(t,"::a2a_cluster::register_provisioned_child",{pending_handle:n,role_id:i,child_ad:a},s);await fs(t,c)})}catch(o){w(`[${t.name}] host_provision_child("${e}") failed (settles via sweep timeout):`,String(o))}}async function EP(t,e,r){try{let n=va(e.Visualize());if(n){let o=Av(n);o&&w(`[${t.name}] host_destroy_child teardown warning:`,o)}tn.delete(e.Visualize()),await B(async o=>{let s=await M(t,"::a2a_cluster::confirm_child_destroyed",{pending_handle:r,cid:e},o);await fs(t,s)})}catch(n){w(`[${t.name}] host_destroy_child failed (settles via sweep timeout):`,String(n))}}async function IP(t,e,r){try{let n=va(e.Visualize());if(!n){w(`[${t.name}] host_mint_child_invite: unknown child ${e.Visualize()} (settles via sweep timeout)`);return}await B(async o=>{let s=await M(n,"::a2a_messaging::generate_invite",{},o),i=t.pw.packet.NewBinaryFromBuffer(Buffer.from(s.Reduce("invite").GetBinary())).Attach(o),a=await M(t,"::a2a_cluster::register_child_invite",{pending_handle:r,invite:i},o);await fs(t,a)})}catch(n){w(`[${t.name}] host_mint_child_invite failed (settles via sweep timeout):`,String(n))}}async function zp(t,e,r,n){await B(async o=>{if(e){n&&await M(t,"::a2a_messaging::host_register_monitoring_cp",{cp_ad:n},o);let s=RP();await M(t,"::a2a_messaging::set_proxy_pending",{code:s,proxy:r},o),await M(t,"::a2a_messaging::verify_proxy_code",{code:s,sender:r},o),tn.set(t.cid,r??"")}else await M(t,"::a2a_messaging::host_clear_child_monitoring",{},o),tn.delete(t.cid)})}async function hv(t,e,r,n,o,s){try{let i=va(e.Visualize());if(!i){w(`[${t.name}] host_set_child_monitoring: unknown child ${e.Visualize()} (settles via sweep timeout)`);return}r?await zp(i,!0,o?.Visualize(),s):await zp(i,!1),await B(async a=>{let c=await M(t,"::a2a_cluster::confirm_child_monitoring",{pending_handle:n,cid:e,enabled:r},a);await fs(t,c)})}catch(i){w(`[${t.name}] host_set_child_monitoring failed (settles via sweep timeout):`,String(i))}}async function PP(t,e){for(let[r,n]of[...tn.entries()]){if(n===e)continue;let o=va(r);if(!o){tn.delete(r);continue}await zp(o,!1).catch(s=>w(`[${t.name}] CP-rebind clear of child ${r} failed:`,String(s)))}}function OP(t,e){let r=[];for(let n of L.values()){if(n.name===t.name)continue;let o=yt(n);if(o.rootCid!==t.cid)continue;let s=Se(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:Nv(n),child_ad:s})}return r}var hp=new Set;async function Mv(t){if(!hp.has(t.name)){hp.add(t.name);try{await B(async e=>{await M(t,"::a2a_cluster::reconcile",{pending_handle:"",children:OP(t,e)},e);let n=(await M(t,"::a2a_cluster::sweep_and_settle",{},e)).Reduce("settled"),o=n.GetKeys();for(let s=0;s<o.length;s++)await fs(t,n.Reduce(s))})}catch(e){w(`[${t.name}] cluster sweep failed:`,String(e))}finally{hp.delete(t.name)}}}var NP=6e4;function AP(){setInterval(()=>{if(Ap)for(let t of L.values())yt(t).roleId===""&&Mv(t)},NP).unref()}function CP(){for(let t of L.values())if(yt(t).roleId!=="")try{let e=ps(t).proxyCid;e&&tn.set(t.cid,e)}catch(e){tn.set(t.cid,""),w(`[${t.name}] monitoredChildren rebuild read failed (added clear-on-repoint):`,String(e))}}var gp=new Set;async function Cp(t){if(!gp.has(t.name)){gp.add(t.name);try{await zP(t)}catch(e){w(`[${t.name}] control dispatch failed:`,String(e))}finally{gp.delete(t.name)}if(L.has(t.name)&&ps(t).controlQueued>0)return Cp(t)}}async function jP(){T.mkdirSync(cs(),{recursive:!0});let t;try{t=T.readFileSync(fv(),"utf8").trim()}catch{}let e=$v(24).toString("hex");_t=await Mp(ma,e,cs(),!1,t),t||T.writeFileSync(fv(),Tv(_t),{mode:384}),bp=Jn(_t),w(`contact-book registrar ready (${_t.cid})`)}function MP(t){try{return T.existsSync(en(t))&&T.statSync(en(t)).size>0}catch{return!1}}function Rp(t){let e=He(s=>Buffer.from(Se(t,"::actor::export_state",s).Serialize()));T.mkdirSync(t.dir,{recursive:!0,mode:448});let r=en(t.dir),n=`${r}.tmp`,o;try{o=T.openSync(n,"w",384),T.fchmodSync(o,384),T.writeFileSync(o,e),T.fsyncSync(o),T.closeSync(o),o=void 0,T.renameSync(n,r),T.chmodSync(r,384);try{T.chmodSync(ds(t.dir),384)}catch{}let s=T.openSync(t.dir,"r");try{T.fsyncSync(s)}finally{T.closeSync(s)}}catch(s){if(o!==void 0)try{T.closeSync(o)}catch{}try{T.rmSync(n,{force:!0})}catch{}throw s}}function jp(t){try{Rp(t),t.persistFailed&&(t.persistFailed=!1,w(`[${t.name}] persist recovered \u2014 quarantine lifted`),me(t,{event:"persist_recovered"}))}catch(e){t.persistFailed=!0,w(`[${t.name}] PERSIST FAILED \u2014 identity quarantined (fail-closed), outbound of this txn withheld:`,String(e));try{me(t,{event:"persist_failed",error:String(e).slice(0,300)})}catch{}throw process.nextTick(()=>tt(t.name,`[${t.name}] PERSIST FAILED \u2014 messaging quarantined until the state file is writable again`)),e}}function ZP(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 DP(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 Zv(t,e){try{let r=await B(async n=>{let o=await M(t,"::a2a_messaging::flush_deferred",{contact:e},n);return Number(o.Reduce("flushed").Visualize())});r>0&&w(`[${t.name}] flushed ${r} deferred message(s) to ${e.slice(0,12)}\u2026`)}catch(r){w(`[${t.name}] deferred flush to ${e.slice(0,12)}\u2026 failed:`,String(r))}}async function Dv(t){try{let e=await B(async n=>{let o=await M(t,"::a2a_messaging::restore_degraded_contacts",{},n);return Number(o.Reduce("requested").Visualize())});e>0&&w(`[${t.name}] contact restore requested for ${e} degraded contact(s)`);let r=He(n=>DP(Se(t,"::a2a_messaging::list_deferred_queues",n)));for(let n of r)n.degraded||await Zv(t,n.cid)}catch(e){w(`[${t.name}] contact-restore sweep failed:`,String(e))}}async function Tp(t){try{let e=await B(async r=>{let n=await M(t,"::a2a_messaging::reconcile_advertise",{},r),o=s=>n.Reduce(s).IsNil()?0:Number(n.Reduce(s).Visualize());return{changed:/true/i.test(n.Reduce("changed").Visualize()),capabilityAdvertised:o("capability_advertised"),legacyReadvertised:o("legacy_readvertised")}});(e.capabilityAdvertised>0||e.legacyReadvertised>0)&&w(`[${t.name}] capability reconcile: changed=${e.changed} advertised=${e.capabilityAdvertised} legacy_migration_bootstrap=${e.legacyReadvertised}`)}catch(e){w(`[${t.name}] capability reconcile sweep failed:`,String(e))}}async function Ep(t){try{let e=await B(async r=>{let n=await M(t,"::a2a_messaging::readvertise_e2e_recovery",{},r);return Number(n.Reduce("readvertised").Visualize())});e>0&&w(`[${t.name}] re-advertised fresh AD to ${e} e2e contact(s) (session recovery)`)}catch(e){w(`[${t.name}] e2e recovery re-advertise failed:`,String(e))}try{await B(async e=>{await M(t,"::a2a_messaging::sweep_e2e_migrations",{},e)})}catch(e){w(`[${t.name}] e2e migration sweep failed:`,String(e))}try{let e=await B(async r=>{let n=await M(t,"::a2a_messaging::redrive_unacked_sweep",{},r),o=s=>n.Reduce(s).IsNil()?0:Number(n.Reduce(s).Visualize());return{redriven:o("redriven_contacts"),purged:o("purged_contacts"),deferred:o("deferred_contacts")}});(e.redriven>0||e.purged>0||e.deferred>0)&&w(`[${t.name}] unacked sweep: redriven=${e.redriven} ttl_purged=${e.purged} deferred=${e.deferred} contact(s)`)}catch(e){w(`[${t.name}] unacked redrive sweep failed:`,String(e))}}var da=new Map;function qP(t){let e=da.get(t);if(!(!e||e.size===0))for(let r of[...e])try{r()}catch{}}function VP(t,e){return new Promise(r=>{let n=da.get(t);n||(n=new Set,da.set(t,n));let o=!1,s=()=>{o||(o=!0,n.delete(i),n.size===0&&da.delete(t),clearTimeout(a),r())},i=s,a=setTimeout(s,e);n.add(i)})}function me(t,e){try{T.mkdirSync(t.dir,{recursive:!0,mode:448}),T.appendFileSync(Op(t.dir),JSON.stringify(e)+`
58
58
  `)}catch(r){w(`[${t.name}] failed to append notifications.log:`,String(r))}qP(t.name)}function LP(t){let e=Op(t.dir),r="";try{r=T.readFileSync(e,"utf8")}catch{return new Set}let n=[];for(let o of r.split(`
59
59
  `))if(o.trim())try{n.push(JSON.parse(o))}catch{}return sv(n)}function os(t,e){let r=t.Reduce(e);return r.IsNil()?"":Buffer.from(r.GetBinary()).toString("hex")}var UP=Number(process.env.OURS_NOTIFY_LONGPOLL_MS)>0?Number(process.env.OURS_NOTIFY_LONGPOLL_MS):25e3,FP=250;function yp(t){try{return T.statSync(t).size}catch{return 0}}function BP(t,e,r){if(r<=e)return{events:[],cursor:e};let n=Buffer.alloc(r-e),o=0;try{let c=T.openSync(t,"r");try{o=T.readSync(c,n,0,n.length,e)}finally{T.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(`
@@ -1,2 +1,2 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
- var w="x-ours-kind=voice-message",_="voice-message-";function F(e,n){let o=(e??"").toLowerCase().split(";").map(r=>r.trim());return o.slice(1).includes(w)?!0:n.toLowerCase().startsWith(_)&&o[0].startsWith("audio/")}function g(e){return(e??"").split(";")[0].trim()||"application/octet-stream"}var T=["openai-compatible","elevenlabs","deepgram","custom"],A=5*1024*1024,E=6e4;function P(e){let n="configure it in config.json `stt: {}` or via OURS_STT_* env";if(!e?.provider)return{ready:!1,reason:`no STT provider configured (stt.provider: ${T.join(" | ")}) \u2014 ${n}`};let o=e.provider.trim().toLowerCase();if(!T.includes(o))return{ready:!1,reason:`unknown STT provider "${e.provider}" (expected: ${T.join(" | ")})`};if(!e.apiKey?.trim())return{ready:!1,reason:`STT provider "${o}" is set but the API key is missing (stt.apiKey / OURS_STT_API_KEY)`};if(o==="openai-compatible"){if(!e.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(!e.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(o==="elevenlabs"&&!e.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(o==="custom"){if(!e.custom?.url?.trim())return{ready:!1,reason:"custom STT needs stt.custom.url (the full endpoint URL of your provider)"};if((e.custom.url.includes("{model}")||e.custom.modelField!==void 0&&e.custom.modelField!=="")&&!e.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:o}}function c(e,n){let o=e;for(let r of n.split(".")){if(o===null||typeof o!="object")return;o=o[r]}return typeof o=="string"?o:void 0}async function p(e,n,o){let r=new AbortController,a=setTimeout(()=>r.abort(),o);try{let t=await fetch(e,{...n,signal:r.signal});if(!t.ok){let s=await t.text().catch(()=>"");return{ok:!1,error:`STT HTTP ${t.status}${s?`: ${s.slice(0,200)}`:""}`}}return{ok:!0,json:await t.json()}}catch(t){return t?.name==="AbortError"?{ok:!1,error:`STT timeout after ${o}ms`}:{ok:!1,error:t instanceof Error?t.message:String(t)}}finally{clearTimeout(a)}}var S=(e,n)=>new Blob([new Uint8Array(e)],{type:g(n)}),U=async(e,n,o,r,a)=>{let t=new FormData;t.set("file",S(e,o),n),t.set("model",r.model.trim()),t.set("response_format","json"),r.language?.trim()&&t.set("language",r.language.trim());let s=await p(`${r.baseUrl.trim().replace(/\/$/,"")}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${r.apiKey.trim()}`},body:t},a);if(!s.ok)return s;let i=c(s.json,"text");return i!==void 0?{ok:!0,text:i}:{ok:!1,error:"STT response missing text"}},R=async(e,n,o,r,a)=>{let t=new FormData;t.set("file",S(e,o),n),t.set("model_id",r.model.trim()),r.language?.trim()&&t.set("language_code",r.language.trim());let s=await p(`${(r.baseUrl?.trim()||"https://api.elevenlabs.io").replace(/\/$/,"")}/v1/speech-to-text`,{method:"POST",headers:{"xi-api-key":r.apiKey.trim()},body:t},a);if(!s.ok)return s;let i=c(s.json,"text");return i!==void 0?{ok:!0,text:i}:{ok:!1,error:"STT response missing text"}},O=async(e,n,o,r,a)=>{let t=new URLSearchParams;r.model?.trim()&&t.set("model",r.model.trim()),r.language?.trim()&&t.set("language",r.language.trim());let s=t.toString(),i=await p(`${(r.baseUrl?.trim()||"https://api.deepgram.com").replace(/\/$/,"")}/v1/listen${s?`?${s}`:""}`,{method:"POST",headers:{Authorization:`Token ${r.apiKey.trim()}`,"Content-Type":g(o)},body:new Uint8Array(e)},a);if(!i.ok)return i;let l=c(i.json,"results.channels.0.alternatives.0.transcript");return l!==void 0?{ok:!0,text:l}:{ok:!1,error:"STT response missing transcript"}},M=async(e,n,o,r,a)=>{let t=r.custom,s=r.model?.trim()??"",i=t.url.replaceAll("{model}",encodeURIComponent(s)),l={},v=t.authHeaderName?.trim()||"Authorization",y=(t.authHeaderTemplate??"Bearer {key}").replaceAll("{key}",r.apiKey.trim());y&&(l[v]=y);let h=t.bodyMode??"multipart",x=t.fileField?.trim()||"file",d=t.modelField===void 0?"model":t.modelField.trim(),m;if(h==="multipart"){let u=new FormData;u.set(x,S(e,o),n),d&&s&&u.set(d,s);for(let[k,$]of Object.entries(t.extraFields??{}))u.set(k,$);m=u}else h==="raw"?(l["Content-Type"]=g(o),m=new Uint8Array(e)):(l["Content-Type"]="application/json",m=JSON.stringify({[x]:e.toString("base64"),...d&&s?{[d]:s}:{},...t.extraFields??{}}));let f=await p(i,{method:t.method?.trim()||"POST",headers:l,body:m},a);if(!f.ok)return f;let b=c(f.json,t.responseTextPath?.trim()||"text");return b!==void 0?{ok:!0,text:b}:{ok:!1,error:`STT response has no text at "${t.responseTextPath?.trim()||"text"}"`}},B={"openai-compatible":U,elevenlabs:R,deepgram:O,custom:M};async function C(e,n,o,r){let a=P(r);if(!a.ready)return{ok:!1,error:a.reason};let t=r.maxBytes??A;if(e.length>t)return{ok:!1,error:`voice message is ${e.length} B \u2014 over the ${t} B STT limit (stt.maxBytes)`};let s=r.timeoutMs??E;try{return await B[a.provider](e,n,o,r,s)}catch(i){return{ok:!1,error:i instanceof Error?i.message:String(i)}}}function j(e,n){let o=` \u2022 \u{1F3A4} voice message from ${e.sender} (${e.sizeBytes} B)`,r=`audio saved \u2192 ${e.savedPath} {${e.wire}}`;switch(n.kind){case"transcript":return`${o}: "${n.text}" \u2014 transcribed from voice message (STT); ${r}`;case"unconfigured":return`${o}: cannot transcribe \u2014 ${n.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; ${r}`;case"failed":return`${o}: transcription failed (${n.error}). Tell the user their voice message could not be transcribed right now and ask them to send text or retry; ${r}`}}export{A as STT_MAX_BYTES_DEFAULT,T as STT_PROVIDERS,E as STT_TIMEOUT_MS_DEFAULT,_ as VOICE_MESSAGE_FILENAME_PREFIX,w as VOICE_MESSAGE_MIME_PARAM,g as baseMime,F as isVoiceMessage,P as sttStatus,c as textAtPath,C as transcribeVoice,j as voiceDeliveryLine};
2
+ var w="x-ours-kind=voice-message",_="voice-message-";function F(t,n){let r=(t??"").toLowerCase().split(";").map(e=>e.trim());return r[0].startsWith("audio/")&&r.slice(1).includes(w)?!0:n.toLowerCase().startsWith(_)&&r[0].startsWith("audio/")}function S(t){return(t??"").split(";")[0].trim()||"application/octet-stream"}var T=["openai-compatible","elevenlabs","deepgram","custom"],A=5*1024*1024,E=6e4;function P(t){let n="configure it in config.json `stt: {}` or via OURS_STT_* env";if(!t?.provider)return{ready:!1,reason:`no STT provider configured (stt.provider: ${T.join(" | ")}) \u2014 ${n}`};let r=t.provider.trim().toLowerCase();if(!T.includes(r))return{ready:!1,reason:`unknown STT provider "${t.provider}" (expected: ${T.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 p(t,n){let r=t;for(let e of n.split(".")){if(r===null||typeof r!="object")return;r=r[e]}return typeof r=="string"?r:void 0}async function c(t,n,r,e=[]){let a=new AbortController,o=setTimeout(()=>a.abort(),r);try{let s=await fetch(t,{...n,signal:a.signal});if(!s.ok){let i=await s.text().catch(()=>"");for(let l of e)l&&(i=i.split(l).join("[redacted]"));return{ok:!1,error:`STT HTTP ${s.status}${i?`: ${i.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(o)}}var g=(t,n)=>new Blob([new Uint8Array(t)],{type:S(n)}),U=async(t,n,r,e,a)=>{let o=new FormData;o.set("file",g(t,r),n),o.set("model",e.model.trim()),o.set("response_format","json"),e.language?.trim()&&o.set("language",e.language.trim());let s=await c(`${e.baseUrl.trim().replace(/\/$/,"")}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${e.apiKey.trim()}`},body:o},a,[e.apiKey.trim()]);if(!s.ok)return s;let i=p(s.json,"text");return i!==void 0?{ok:!0,text:i}:{ok:!1,error:"STT response missing text"}},R=async(t,n,r,e,a)=>{let o=new FormData;o.set("file",g(t,r),n),o.set("model_id",e.model.trim()),e.language?.trim()&&o.set("language_code",e.language.trim());let s=await c(`${(e.baseUrl?.trim()||"https://api.elevenlabs.io").replace(/\/$/,"")}/v1/speech-to-text`,{method:"POST",headers:{"xi-api-key":e.apiKey.trim()},body:o},a,[e.apiKey.trim()]);if(!s.ok)return s;let i=p(s.json,"text");return i!==void 0?{ok:!0,text:i}:{ok:!1,error:"STT response missing text"}},O=async(t,n,r,e,a)=>{let o=new URLSearchParams;e.model?.trim()&&o.set("model",e.model.trim()),e.language?.trim()&&o.set("language",e.language.trim());let s=o.toString(),i=await c(`${(e.baseUrl?.trim()||"https://api.deepgram.com").replace(/\/$/,"")}/v1/listen${s?`?${s}`:""}`,{method:"POST",headers:{Authorization:`Token ${e.apiKey.trim()}`,"Content-Type":S(r)},body:new Uint8Array(t)},a,[e.apiKey.trim()]);if(!i.ok)return i;let l=p(i.json,"results.channels.0.alternatives.0.transcript");return l!==void 0?{ok:!0,text:l}:{ok:!1,error:"STT response missing transcript"}},M=async(t,n,r,e,a)=>{let o=e.custom,s=e.model?.trim()??"",i=o.url.replaceAll("{model}",encodeURIComponent(s)),l={},v=o.authHeaderName?.trim()||"Authorization",y=(o.authHeaderTemplate??"Bearer {key}").replaceAll("{key}",e.apiKey.trim());y&&(l[v]=y);let h=o.bodyMode??"multipart",x=o.fileField?.trim()||"file",d=o.modelField===void 0?"model":o.modelField.trim(),m;if(h==="multipart"){let u=new FormData;u.set(x,g(t,r),n),d&&s&&u.set(d,s);for(let[k,$]of Object.entries(o.extraFields??{}))u.set(k,$);m=u}else h==="raw"?(l["Content-Type"]=S(r),m=new Uint8Array(t)):(l["Content-Type"]="application/json",m=JSON.stringify({[x]:t.toString("base64"),...d&&s?{[d]:s}:{},...o.extraFields??{}}));let f=await c(i,{method:o.method?.trim()||"POST",headers:l,body:m},a,[e.apiKey.trim()]);if(!f.ok)return f;let b=p(f.json,o.responseTextPath?.trim()||"text");return b!==void 0?{ok:!0,text:b}:{ok:!1,error:`STT response has no text at "${o.responseTextPath?.trim()||"text"}"`}},B={"openai-compatible":U,elevenlabs:R,deepgram:O,custom:M};async function C(t,n,r,e){let a=P(e);if(!a.ready)return{ok:!1,error:a.reason};let o=e.maxBytes??A;if(t.length>o)return{ok:!1,error:`voice message is ${t.length} B \u2014 over the ${o} B STT limit (stt.maxBytes)`};let s=e.timeoutMs??E;try{return await B[a.provider](t,n,r,e,s)}catch(i){return{ok:!1,error:i instanceof Error?i.message:String(i)}}}function j(t,n){let r=` \u2022 \u{1F3A4} voice message from ${t.sender} (${t.sizeBytes} B)`,e=`audio saved \u2192 ${t.savedPath} {${t.wire}}`;switch(n.kind){case"transcript":return`${r}: "${n.text}" \u2014 transcribed from voice message (STT); ${e}`;case"unconfigured":return`${r}: cannot transcribe \u2014 ${n.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; ${e}`;case"failed":return`${r}: transcription failed (${n.error}). Tell the user their voice message could not be transcribed right now and ask them to send text or retry; ${e}`}}export{A as STT_MAX_BYTES_DEFAULT,T as STT_PROVIDERS,E as STT_TIMEOUT_MS_DEFAULT,_ as VOICE_MESSAGE_FILENAME_PREFIX,w as VOICE_MESSAGE_MIME_PARAM,S as baseMime,F as isVoiceMessage,P as sttStatus,p as textAtPath,C as transcribeVoice,j as voiceDeliveryLine};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/mcp",
3
- "version": "0.14.0",
3
+ "version": "0.14.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",
@@ -48,7 +48,7 @@
48
48
  "serve": "node dist/cli.js serve",
49
49
  "prepublishOnly": "node build.mjs",
50
50
  "typecheck": "tsc -p tsconfig.json --noEmit",
51
- "test": "bash ../../scripts/test-receipts-mufl.sh && bash ../../scripts/test-notifications-mufl.sh && node test/loopback-bind.test.mjs && node test/lease-binding.test.mjs && node test/session-restore.test.mjs && node test/daemon-restart-resume.test.mjs && node test/version-advisory.test.mjs && node test/files-helpers.test.mjs && node test/inbox-encryption.test.mjs && node test/validate-name.test.mjs && node test/port-visibility.test.mjs && node test/notify-http-api.test.mjs && node test/unread-http-api.test.mjs && node test/create-root-cli.test.mjs && node test/session-reaper.test.mjs && node test/mig1867-verify.test.mjs && node test/single-root-policy.test.mjs && node test/pre137-blob-import-regression.test.mjs && node test/transcribe-detect.test.mjs && node test/transcribe-stt.test.mjs"
51
+ "test": "bash ../../scripts/test-receipts-mufl.sh && bash ../../scripts/test-notifications-mufl.sh && node test/loopback-bind.test.mjs && node test/lease-binding.test.mjs && node test/session-restore.test.mjs && node test/daemon-restart-resume.test.mjs && node test/version-advisory.test.mjs && node test/files-helpers.test.mjs && node test/inbox-encryption.test.mjs && node test/validate-name.test.mjs && node test/port-visibility.test.mjs && node test/notify-http-api.test.mjs && node test/unread-http-api.test.mjs && node test/create-root-cli.test.mjs && node test/session-reaper.test.mjs && node test/mig1867-verify.test.mjs && node test/single-root-policy.test.mjs && node test/pre137-blob-import-regression.test.mjs && node test/transcribe-detect.test.mjs && node test/transcribe-stt.test.mjs && node test/voice-status-cli.test.mjs"
52
52
  },
53
53
  "dependencies": {
54
54
  "@adapt-toolkit/sdk": "0.10.12",