@ours.network/mcp 0.14.1 → 0.15.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.
@@ -0,0 +1,2 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ function e(n){let t=n.lastIndexOf(")");if(t<0)return null;let r=n.slice(t+1).trimStart();return/^[A-Za-z](?:\s|$)/.test(r)?r[0]:null}function s(n){let t=e(n);return t==="Z"||t==="X"||t==="x"}export{s as linuxProcHasExited,e as linuxProcState};
@@ -0,0 +1,4 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import*as a from"node:fs";import{join as v}from"node:path";var A="startup-progress.json",b=1,y={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 h(e){return v(e,A)}function R(e){return typeof e=="string"&&Object.hasOwn(y,e)}function x(e){try{let t=JSON.parse(a.readFileSync(h(e),"utf8"));return t.version!==b||!Number.isInteger(t.pid)||(t.pid??0)<=0||typeof t.bootId!="string"||!t.bootId||!R(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 I(e,t={}){let s=t.pid??process.pid,n=t.now??Date.now,o=n(),p=h(e),d=`${p}.${s}.tmp`,u=Math.max(100,t.heartbeatMs??2e3),r=!1,i=!1,l={version:b,pid:s,bootId:`${s}-${o}`,phase:"initializing",startedAt:o,updatedAt:o},c=()=>{if(!i)try{a.mkdirSync(e,{recursive:!0,mode:448}),a.writeFileSync(d,`${JSON.stringify(l)}
3
+ `,{mode:384}),a.renameSync(d,p);try{a.chmodSync(p,384)}catch{}}catch{i=!0;try{a.rmSync(d,{force:!0})}catch{}}},m=(f,S)=>{l={version:b,pid:s,bootId:l.bootId,phase:f,...S?{completed:S.completed,total:S.total}:{},startedAt:o,updatedAt:n()},c()};c();let g=setInterval(()=>{r||(l={...l,updatedAt:n()},c())},u);g.unref?.();let P=f=>{r||(m(f),r=!0,clearInterval(g))};return{update:m,ready:()=>P("ready"),failed:()=>P("failed")}}function w(e){let t=y[e.phase];return e.phase==="identities"&&e.completed!==void 0&&e.total!==void 0?`${t} ${e.completed}/${e.total}`:t}function $(e,t){let s=`startup: ${w(e)}`;return t?`\r${s}\x1B[K`:`${s}
4
+ `}async function O(e){let t=e.now??Date.now,s=e.sleep??(r=>new Promise(i=>setTimeout(i,r))),n=t(),o=n,p=-1,d="",u=null;for(;;){if(await e.isReady())return{ok:!0,elapsedMs:t()-n,lastProgress:u};let r=e.readProgress();if(r?.pid===e.pid){u=r,r.updatedAt>p&&(p=r.updatedAt,o=t());let m=`${r.phase}:${r.completed??""}:${r.total??""}`;if(m!==d&&(d=m,e.onProgress?.(r)),r.phase==="failed")return{ok:!1,reason:"daemon-reported-failure",elapsedMs:t()-n,lastProgress:u}}if(!e.isProcessAlive())return{ok:!1,reason:"process-exited",elapsedMs:t()-n,lastProgress:u};let i=t()-n;if(i>=e.absoluteMs)return{ok:!1,reason:"absolute-timeout",elapsedMs:i,lastProgress:u};if(t()-o>=e.inactivityMs)return{ok:!1,reason:"inactivity-timeout",elapsedMs:i,lastProgress:u};let l=e.absoluteMs-i,c=e.inactivityMs-(t()-o);await s(Math.max(1,Math.min(e.pollMs,l,c)))}}export{A as STARTUP_PROGRESS_FILENAME,b as STARTUP_PROGRESS_VERSION,I as createStartupProgressReporter,w as formatStartupProgress,x as readStartupProgress,$ as renderStartupProgress,h as startupProgressPath,O as waitForStartup};
@@ -0,0 +1,28 @@
1
+ import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
+ import{chmodSync as U,closeSync as J,existsSync as I,mkdirSync as H,openSync as P,readFileSync as L,readSync as B,renameSync as Y,statSync as W,unlinkSync as V,writeFileSync as q,writeSync as z}from"node:fs";import{spawnSync as T}from"node:child_process";import{dirname as G}from"node:path";var _=["openai-compatible","elevenlabs","deepgram","custom"],ce=5*1024*1024;function $(e){let r="configure it in config.json `stt: {}` or via OURS_STT_* env";if(!e?.provider)return{ready:!1,reason:`no STT provider configured (stt.provider: ${_.join(" | ")}) \u2014 ${r}`};let o=e.provider.trim().toLowerCase();if(!_.includes(o))return{ready:!1,reason:`unknown STT provider "${e.provider}" (expected: ${_.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}}var d=[{value:"openai-compatible",label:"OpenAI-compatible",detail:"an OpenAI-style /v1 transcription endpoint"},{value:"elevenlabs",label:"ElevenLabs",detail:"ElevenLabs speech-to-text"},{value:"deepgram",label:"Deepgram",detail:"Deepgram speech-to-text"},{value:"custom",label:"Custom HTTP endpoint",detail:"a fully specified transcription URL"}],c=class extends Error{constructor(o){super(o);this.reason=o}};function X(e){if(!I(e))return{};let r=JSON.parse(L(e,"utf8"));if(!r||typeof r!="object"||Array.isArray(r))throw new Error("config root must be a JSON object");return r}function Z(e){return I(e)?{exists:!0,text:L(e,"utf8"),mode:W(e).mode&511}:{exists:!1}}function Q(e,r){F(e,`${JSON.stringify(r,null,2)}
3
+ `,384)}function F(e,r,o){H(G(e),{recursive:!0,mode:448});let t=`${e}.tmp-${process.pid}-${Date.now()}`;try{q(t,r,{encoding:"utf8",mode:o,flag:"wx"}),U(t,o),Y(t,e),U(e,o)}catch(s){try{V(t)}catch{}throw s}}function ee(e,r){if(!r.exists){try{V(e)}catch{}return}F(e,r.text,r.mode)}async function te(e,r,o,t){let s=Z(e);try{Q(e,r)}catch{return{ok:!1,stage:"write",rolledBack:!0,daemonRestored:!0}}if(o!=="managed")return{ok:!0,stage:"write"};let n;try{n=t?await t():{ok:!1}}catch{n={ok:!1}}if(n.ok)return{ok:!0,stage:"apply"};try{ee(e,s)}catch{return{ok:!1,stage:"rollback",rolledBack:!1,daemonRestored:!1}}let i;try{i=t?await t():{ok:!1}}catch{i={ok:!1}}return{ok:!1,stage:i.ok?"apply":"rollback",rolledBack:!0,daemonRestored:i.ok}}function C(e,r){let o={...e},t=[["provider",r.OURS_STT_PROVIDER],["apiKey",r.OURS_STT_API_KEY],["model",r.OURS_STT_MODEL],["baseUrl",r.OURS_STT_BASE_URL],["language",r.OURS_STT_LANGUAGE]];for(let[s,n]of t)n?.trim()&&(o[s]=n.trim());return o}function re(e){let r=e.trim();return r.length<8?{ok:!1,reason:"API key must contain at least 8 characters"}:/[\s\x00-\x1f\x7f]/.test(r)?{ok:!1,reason:"API key must not contain whitespace or control characters"}:{ok:!0,value:r}}function ne(){try{return P("/dev/tty","r+")}catch{if(process.stdin.isTTY&&process.stdout.isTTY)try{return P("/dev/stdin","r+")}catch{}return null}}function m(e,r){z(e,r)}function E(e){let r=Buffer.alloc(1);try{return B(e,r,0,1,null)===1?r[0]:null}catch(o){throw o.code==="EINTR"?new c("cancel"):o}}function D(e){let r="";for(let o=0;o<12;o++){let t=E(e);if(t===null)break;let s=String.fromCharCode(t);if(r+=s,/[A-Za-z~]$/.test(r))break}return r}function M(e,r){let o=T("stty",["-g"],{stdio:[e,"pipe","ignore"],encoding:"utf8"}),t=(o.stdout||"").trim();if(o.status!==0||!t)throw new c("unavailable");if(T("stty",["-icanon","-echo","-isig","min","1","time","0"],{stdio:[e,"ignore","ignore"]}).status!==0)throw new c("unavailable");let n=!1,i=()=>{if(n)return;n=!0,T("stty",[t],{stdio:[e,"ignore","ignore"]}).status!==0&&T("stty",["sane"],{stdio:[e,"ignore","ignore"]})};process.once("exit",i);try{return r()}finally{process.removeListener("exit",i),i()}}function oe(e,r,o,t){return M(e,()=>{m(e,r);let s="";for(;;){let i=E(e);if(i===null||i===4)throw new c("eof");if(i===3)throw new c("cancel");if(i===10||i===13){m(e,`
4
+ `);break}if(i===127||i===8){s.length&&(s=s.slice(0,-1),t||m(e,"\b \b"));continue}if(i===27){D(e);continue}if(i<32||s.length>=16384)continue;let a=String.fromCharCode(i);s+=a,t||m(e,a)}let n=s.trim();return n===""?o:n})}function w(e,r,o=""){m(e,r);let t=[],s=0;for(;;){let i=Buffer.alloc(1024),a;try{a=B(e,i,0,i.length,null)}catch(b){throw b.code==="EINTR"?new c("cancel"):b}if(a===0)throw new c("eof");let g=i.subarray(0,a).indexOf(10),v=g>=0?i.subarray(0,g):i.subarray(0,a);if(t.push(v),s+=v.length,s>16384)throw new Error("prompt input too long");if(g>=0)break}let n=Buffer.concat(t).toString("utf8").replace(/\r$/,"").trim();return n===""?o:n}function f(e,r,o="",t=!1){try{return oe(e,r,o,t)}catch(s){if(s instanceof c&&s.reason==="unavailable"&&!t)return w(e,r,o);throw s}}function ie(e,r,o){let t=f(e,`${r} ${o?"[Y/n]":"[y/N]"} `,o?"y":"n");return/^y(?:es)?$/i.test(t)}function se(e,r){let o=d.findIndex(t=>t.value===r);o<0&&(o=0);try{return M(e,()=>{m(e,`Choose one transcription provider (\u2191/\u2193 or j/k, then Enter; q cancels):
5
+ `);let t=!1,s=()=>{t&&m(e,`\x1B[${d.length}A`),t=!0,d.forEach((n,i)=>{m(e,`\r\x1B[K ${i===o?">":" "} ${i===o?"(*)":"( )"} ${n.label} \u2014 ${n.detail}
6
+ `)})};for(s();;){let n=E(e);if(n===null||n===4)throw new c("eof");if(n===3||n===113||n===81)throw new c("cancel");if(n===10||n===13)return m(e,`
7
+ `),d[o].value;if(n>=49&&n<=52)o=n-49;else if(n===107||n===75)o=(o-1+d.length)%d.length;else if(n===106||n===74)o=(o+1)%d.length;else if(n===27){let i=D(e);i==="[A"||i==="OA"?o=(o-1+d.length)%d.length:(i==="[B"||i==="OB")&&(o=(o+1)%d.length)}else continue;s()}})}catch(t){if(!(t instanceof c)||t.reason!=="unavailable")throw t;m(e,`Choose one transcription provider:
8
+ `),d.forEach((n,i)=>{m(e,` ${i+1}. ${n.label} \u2014 ${n.detail}
9
+ `)});let s=w(e,`Select 1-${d.length}: `);if(!/^[1-4]$/.test(s))throw new c("cancel");return d[Number(s)-1].value}}function ae(e){let r=e.stt;return r&&typeof r=="object"&&!Array.isArray(r)?{...r}:{}}async function ge(e){let r=e.env??process.env,o=e.stdout??(i=>process.stdout.write(i)),t=(i="")=>o(`${i}
10
+ `),s=e.daemonState??"stopped",n=null;try{let i;try{i=X(e.configFile)}catch{return t(`voice setup: ${e.configFile} is not valid JSON; no changes made.`),1}let a=ae(i),g=$(C(a,r)),v=r.OURS_STT_API_KEY?.trim()?"environment":a.apiKey?.trim()?"config":"missing";if(n=r.OURS_ASSUME_YES?null:ne(),t(`ours-mcp voice-setup \u2014 ${e.configFile}`),g.ready){if(t(`voice transcription is already ready (${g.provider}; API key from ${v}).`),n===null)return 0;if(!ie(n,"Change the current voice settings?",!1))return t("kept the current voice settings; no changes made."),0}else if(t("Voice transcription is not ready. This command keeps the provider key hidden."),n===null)return t("No interactive terminal is available; no changes made."),t("Run `ours-mcp voice-setup` in a terminal, or configure OURS_STT_* environment values."),0;t("");let b=String(r.OURS_STT_PROVIDER||a.provider||"").trim().toLowerCase(),p=se(n,b),l=String(r.OURS_STT_MODEL||a.model||"").trim(),u=String(r.OURS_STT_BASE_URL||a.baseUrl||"").trim(),y=String(a.custom?.url||"").trim();p==="openai-compatible"?(u=f(n,`Provider /v1 base URL${u?` [${u}]`:""}: `,u),l=f(n,`Model name (sent verbatim)${l?` [${l}]`:""}: `,l)):p==="elevenlabs"?(l=f(n,`ElevenLabs model id${l?` [${l}]`:""}: `,l),u=f(n,`Custom base URL (Enter for provider default)${u?` [${u}]`:""}: `,u)):p==="deepgram"?(l=f(n,`Model (optional; Enter for provider default)${l?` [${l}]`:""}: `,l),u=f(n,`Custom base URL (optional)${u?` [${u}]`:""}: `,u)):(y=f(n,`Full transcription endpoint URL${y?` [${y}]`:""}: `,y),l=f(n,`Model (optional unless URL contains {model})${l?` [${l}]`:""}: `,l));let j=r.OURS_STT_API_KEY?.trim(),S=String(a.apiKey||"").trim();if(j)t("API key: using OURS_STT_API_KEY from the environment; it will not be copied to config.");else{let N=S?"Provider API key [configured; Enter keeps it]: ":"Provider API key (input hidden): ",k;try{k=f(n,N,S,!0)}catch(R){if(!(R instanceof c)||R.reason!=="unavailable")throw R;if(m(n,`
11
+ Secure hidden input is unavailable on this terminal.
12
+ `),m(n,`Visible fallback will echo the token on screen and may leave it in scrollback.
13
+ `),w(n,"Type SHOW to enter the token visibly, or press Enter to cancel: ")!=="SHOW")throw new c("cancel");k=w(n,"Provider API key (VISIBLE): ",S)}let x=re(k);if(!x.ok)return t(`Voice setup was not saved: ${x.reason}.`),1;S=x.value}let O={...a,provider:p,...S?{apiKey:S}:{},...l?{model:l}:{},...u?{baseUrl:u}:{},...p==="custom"&&y?{custom:{...a.custom??{},url:y}}:{}},A=$(C(O,r));if(!A.ready)return t(`Voice setup was not saved: ${A.reason}.`),1;if(e.dryRun)return t(`voice transcription would be configured (${p}); API key stays hidden.`),t("dry-run: config, daemon, and existing settings were not changed."),0;let K={...i,stt:O};s==="managed"&&t("Restarting ours-mcp to apply and verify voice transcription\u2026");let h=await te(e.configFile,K,s,e.apply);return!h.ok&&h.stage==="write"?(t(`Could not write ${e.configFile}; the prior config is intact.`),1):s==="stopped"?(t(`voice transcription configured (${p}); API key saved in mode-0600 config.`),t("The daemon is stopped; run `ours-mcp start` to apply it."),0):s==="external"?(t(`voice transcription configured (${p}); API key saved in mode-0600 config.`),t("The daemon has no managed PID; restart its external launcher to apply the new settings."),0):h.ok?(t(`voice transcription: ready (${p}).`),t("API key saved in mode-0600 config and never displayed."),0):h.rolledBack?(t("Voice readiness check failed; restored the exact prior config."),h.daemonRestored?(t("The prior config and daemon state were restored; voice setup was not changed."),2):(t("The prior config is restored, but the daemon did not restart; run `ours-mcp status`."),2)):(t("Voice setup failed and automatic config rollback also failed; inspect the config before restarting."),2)}catch(i){return i instanceof c?i.reason==="cancel"?(t(""),t("voice setup cancelled; no configuration changes were made."),130):i.reason==="eof"?(t(""),t("voice setup ended at EOF; no configuration changes were made."),1):(t("Secure interactive input is unavailable on this terminal; no changes made."),1):(t("voice setup failed unexpectedly; no credential was displayed."),1)}finally{if(n!==null)try{J(n)}catch{}}}var ye=`ours-mcp voice-setup \u2014 configure voice transcription securely
14
+
15
+ Usage: ours-mcp voice-setup [--dry-run]
16
+
17
+ Interactively choose exactly one provider, collect provider-specific fields, and
18
+ read the provider API key with hidden input. The key is never accepted as a CLI
19
+ argument. Configuration is written atomically with mode 0600. When the managed
20
+ daemon is running, it is restarted and readiness-checked; a failure restores the
21
+ exact prior config.
22
+
23
+ --dry-run walk the prompts without writing config or restarting the daemon
24
+ --help show this help and exit
25
+
26
+ Headless automation remains environment-driven through OURS_STT_PROVIDER,
27
+ OURS_STT_API_KEY, OURS_STT_MODEL, OURS_STT_BASE_URL, and OURS_STT_LANGUAGE.
28
+ Exit 2 means restart/readiness failed after a write and rollback was attempted.`;export{d as VOICE_PROVIDER_CHOICES,ye as VOICE_SETUP_HELP,Q as atomicWriteVoiceConfig,ge as runVoiceSetup,te as transactVoiceConfig};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ours.network/mcp",
3
- "version": "0.14.1",
3
+ "version": "0.15.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 && node test/voice-status-cli.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 && node test/process-state.test.mjs && node test/voice-setup-config.test.mjs && node test/voice-setup-cli.test.mjs && node test/startup-progress.test.mjs && node test/startup-cli.test.mjs"
52
52
  },
53
53
  "dependencies": {
54
54
  "@adapt-toolkit/sdk": "0.10.12",