@ours.network/mcp 0.18.0-nightly.5 → 1.0.0

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  The agent-facing MCP adapter for the shared ours daemon.
4
4
 
5
5
  `ours-mcp` does not contain, start, configure, or install a daemon. Install
6
- `@ours.network/cli@2.0.1`, configure it with `ours config setup`, and start the
6
+ `@ours.network/cli@2.2.0`, configure it with `ours config setup`, and start the
7
7
  single shared service with `ours daemon start` (or `ours daemon install-service`).
8
8
 
9
9
  ## MCP configuration
@@ -19,7 +19,7 @@ single shared service with `ours daemon start` (or `ours daemon install-service`
19
19
  }
20
20
  ```
21
21
 
22
- `proxy` attaches through `@ours.network/sdk@3.0.1`. It uses the SDK's coherent
22
+ `proxy` attaches through `@ours.network/sdk@3.2.2`. It uses the SDK's coherent
23
23
  daemon selection (`OURS_CONFIG`, or matching `OURS_PORT` and `OURS_STATE_DIR`)
24
24
  and verifies `/state-dir` before credentials are sent. An unavailable daemon is
25
25
  reported with install/start guidance; it is never started inside the MCP process.
@@ -79,8 +79,8 @@ that finds old packet state refuses startup without changing it. Operators may
79
79
  back it up and must remove it themselves before starting clean; installers never
80
80
  delete identity state implicitly.
81
81
 
82
- The external-history integration requires the published `@ours.network/sdk@3.0.1`
83
- and `@ours.network/cli@2.0.1` artifacts. Both are pinned exactly so registry-only
82
+ The external-history integration requires the published `@ours.network/sdk@3.2.2`
83
+ and `@ours.network/cli@2.2.0` artifacts. Both are pinned exactly so registry-only
84
84
  installs use the validated contract; there is no compatibility fallback.
85
85
 
86
86
  ## Development
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{spawn as k}from"node:child_process";import{realpathSync as y}from"node:fs";import{fileURLToPath as L}from"node:url";import{attachOursClient as j,resolveDaemonConfig as J}from"@ours.network/sdk";import{randomUUID as N}from"node:crypto";import{chmod as O,mkdir as C,readFile as _,rename as P,unlink as A,writeFile as D}from"node:fs/promises";import{homedir as R}from"node:os";import{dirname as T,resolve as d}from"node:path";var g=1,b="OURS_MCP_CONFIG",$=()=>({version:1,daemons:{}});function x(e=process.env){let t=(e[b]??"").trim();return d(t||d(R(),".ours-mcp","config.json"))}function U(e,t){let i;try{i=JSON.parse(e)}catch(o){throw new Error(`Invalid ours-mcp application identity config at ${t}: ${String(o)}`)}if(!i||typeof i!="object"||Array.isArray(i))throw new Error(`Invalid ours-mcp application identity config at ${t}: expected an object.`);let n=i;if(n.version!==g)throw new Error(`Unsupported ours-mcp application identity config version at ${t}: expected ${g}, found ${String(n.version)}.`);if(!n.daemons||typeof n.daemons!="object"||Array.isArray(n.daemons))throw new Error(`Invalid ours-mcp application identity config at ${t}: "daemons" must be an object.`);let s={};for(let[o,a]of Object.entries(n.daemons)){if(!a||typeof a!="object"||Array.isArray(a))throw new Error(`Invalid ours-mcp application identity config at ${t}: daemon ${JSON.stringify(o)} must be an object.`);let c=a;if(!Array.isArray(c.identities)||c.identities.some(f=>typeof f!="string"||f.length===0))throw new Error(`Invalid ours-mcp application identity config at ${t}: daemon ${JSON.stringify(o)} has an invalid identity list.`);s[d(o)]={identities:[...new Set(c.identities)].sort()}}return{version:1,daemons:s}}async function m(e){try{return U(await _(e,"utf8"),e)}catch(t){if(t.code==="ENOENT")return $();throw t}}async function w(e,t){let i=T(e);await C(i,{recursive:!0,mode:448});let n=`${e}.${process.pid}.${N()}.tmp`;try{await D(n,`${JSON.stringify(t,null,2)}
3
- `,{mode:384,flag:"wx"}),await P(n,e),await O(e,384)}catch(s){try{await A(n)}catch{}throw s}}var p=class{stateDir;path;constructor(t,i={}){this.stateDir=d(t),this.path=d(i.path??x(i.env))}async list(){return[...(await m(this.path)).daemons[this.stateDir]?.identities??[]]}async has(t){return(await this.list()).includes(t)}async add(t){if(!t)throw new Error("Cannot add an empty identity name to ours-mcp.");let i=await m(this.path),n=i.daemons[this.stateDir]?.identities??[];n.includes(t)||(i.daemons[this.stateDir]={identities:[...n,t].sort()},await w(this.path,i))}async remove(t){let i=await m(this.path),n=i.daemons[this.stateDir];if(!n?.identities.includes(t))return;let s=n.identities.filter(o=>o!==t);s.length===0?delete i.daemons[this.stateDir]:i.daemons[this.stateDir]={identities:s},await w(this.path,i)}};async function h(e,t){let i=new Set(await e.list());return t.filter(n=>i.has(n.name))}var u="0.18.0-nightly.5",r=e=>{process.stdout.write(`${e}
4
- `)},E=e=>{process.stderr.write(`${e}
5
- `)},v=e=>Number.isInteger(e)&&e>1,I=Number(process.env.OURS_CLIENT_PID),l=v(I)?I:v(process.ppid)?process.ppid:process.pid,S=(process.env.CLAUDE_CODE_SESSION_ID??"").trim()||`ours-mcp:${l}`,M=(process.env.OURS_BIND_IDENTITY??"").trim()||void 0,V=new Set(["start","stop","restart","serve","run","status","install-service","uninstall-service"]);function F(e){if(e.some(t=>t==="--application"||t.startsWith("--application=")))throw new Error("`--application` is no longer supported. ours-mcp connects to one coherently selected shared daemon; use OURS_CONFIG or a matching OURS_PORT + OURS_STATE_DIR selection.")}async function G(e){let i=(process.env.OURS_CLI??"").trim()||"ours";await new Promise((n,s)=>{let o=k(i,e,{stdio:"inherit",env:process.env});o.once("error",a=>{if(a.code==="ENOENT"){s(new Error(`Cannot find the ${JSON.stringify(i)} CLI. Install @ours.network/cli@1.0.1, put \`ours\` on PATH, or set OURS_CLI to its executable path.`));return}s(a)}),o.once("exit",(a,c)=>{if(c){process.kill(process.pid,c);return}process.exitCode=a??1,n()})})}async function W(){let e=new URL("./connector.js",import.meta.url),{runConnector:t}=await import(e.href);await t({leaseToken:S,clientPid:l,version:u,bindIdentity:M})}function B(e,t){return JSON.stringify({identity:e,...t})}async function Y(e,t,i){for await(let n of e.watchNotifications(t,{kinds:["inbound"],signal:i}))r(B(t,n))}async function q(e){if(e.length>1||e[0]?.startsWith("-"))throw new Error("Usage: ours-mcp watch [identity]");let t=J(),i=new p(t.expectStateDir);await i.list();let n=await j({leaseToken:S,clientPid:l}),s=e[0]?.trim(),o;s?o=[s]:o=(await h(i,await n.identities())).map(c=>c.name);let a=new AbortController;process.once("SIGINT",()=>a.abort()),process.once("SIGTERM",()=>a.abort()),E(`ours-mcp watch: ${o.length===0?"no application identities":`watching ${o.join(", ")}`}`),await Promise.all(o.map(c=>Y(n,c,a.signal)))}function H(){r(`ours-mcp ${u} \u2014 MCP adapter for the shared ours daemon`),r(""),r("Usage: ours-mcp <command> [options]"),r(" proxy run the stdio MCP server (never starts a daemon)"),r(" watch [identity] stream inbound JSON Lines; without a name, only ours-mcp identities"),r(" start|stop|restart|serve|status"),r(" install-service|uninstall-service"),r(" compatibility aliases for `ours daemon <command>`"),r(" version print the ours-mcp package version"),r(""),r("Daemon configuration and identity CLI operations moved to @ours.network/cli@1.0.1:"),r(" ours config setup"),r(" ours identity --help")}async function K(){let e=process.argv.slice(2);F(e);let t=e.shift()??"help";if(V.has(t)){await G(["daemon",t==="run"?"serve":t,...e]);return}switch(t){case"proxy":if(e.length)throw new Error("Usage: ours-mcp proxy");await W();return;case"watch":await q(e);return;case"setup":throw new Error("ours-mcp no longer owns daemon configuration. Run `ours config setup` instead.");case"create-root":case"define-local-identity-file":case"voice-setup":case"voice-status":case"stt-setup":case"stt-status":throw new Error(`ours-mcp ${t} moved to the \`ours\` CLI. Run \`ours --help\` for the typed replacement.`);case"version":case"--version":case"-v":r(u);return;case"help":case"--help":case"-h":H();return;default:throw new Error(`Unknown command ${JSON.stringify(t)}. Run \`ours-mcp --help\`.`)}}function z(){if(!process.argv[1])return!1;try{return y(process.argv[1])===y(L(import.meta.url))}catch{return!1}}var Q=z();Q&&K().catch(e=>{E(`ours-mcp error: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1});
2
+ import{spawn as L}from"node:child_process";import{realpathSync as v}from"node:fs";import{fileURLToPath as j}from"node:url";import{attachOursClient as S,resolveDaemonConfig as J}from"@ours.network/sdk";import{randomUUID as O}from"node:crypto";import{chmod as C,mkdir as _,readFile as P,rename as A,unlink as D,writeFile as T}from"node:fs/promises";import{homedir as R}from"node:os";import{dirname as b,resolve as d}from"node:path";var g=1,$="OURS_MCP_CONFIG",x=()=>({version:1,daemons:{}});function U(t=process.env){let e=(t[$]??"").trim();return d(e||d(R(),".ours-mcp","config.json"))}function k(t,e){let i;try{i=JSON.parse(t)}catch(o){throw new Error(`Invalid ours-mcp application identity config at ${e}: ${String(o)}`)}if(!i||typeof i!="object"||Array.isArray(i))throw new Error(`Invalid ours-mcp application identity config at ${e}: expected an object.`);let n=i;if(n.version!==g)throw new Error(`Unsupported ours-mcp application identity config version at ${e}: expected ${g}, found ${String(n.version)}.`);if(!n.daemons||typeof n.daemons!="object"||Array.isArray(n.daemons))throw new Error(`Invalid ours-mcp application identity config at ${e}: "daemons" must be an object.`);let s={};for(let[o,a]of Object.entries(n.daemons)){if(!a||typeof a!="object"||Array.isArray(a))throw new Error(`Invalid ours-mcp application identity config at ${e}: daemon ${JSON.stringify(o)} must be an object.`);let c=a;if(!Array.isArray(c.identities)||c.identities.some(w=>typeof w!="string"||w.length===0))throw new Error(`Invalid ours-mcp application identity config at ${e}: daemon ${JSON.stringify(o)} has an invalid identity list.`);s[d(o)]={identities:[...new Set(c.identities)].sort()}}return{version:1,daemons:s}}async function m(t){try{return k(await P(t,"utf8"),t)}catch(e){if(e.code==="ENOENT")return x();throw e}}async function h(t,e){let i=b(t);await _(i,{recursive:!0,mode:448});let n=`${t}.${process.pid}.${O()}.tmp`;try{await T(n,`${JSON.stringify(e,null,2)}
3
+ `,{mode:384,flag:"wx"}),await A(n,t),await C(t,384)}catch(s){try{await D(n)}catch{}throw s}}var p=class{stateDir;path;constructor(e,i={}){this.stateDir=d(e),this.path=d(i.path??U(i.env))}async list(){return[...(await m(this.path)).daemons[this.stateDir]?.identities??[]]}async has(e){return(await this.list()).includes(e)}async add(e){if(!e)throw new Error("Cannot add an empty identity name to ours-mcp.");let i=await m(this.path),n=i.daemons[this.stateDir]?.identities??[];n.includes(e)||(i.daemons[this.stateDir]={identities:[...n,e].sort()},await h(this.path,i))}async remove(e){let i=await m(this.path),n=i.daemons[this.stateDir];if(!n?.identities.includes(e))return;let s=n.identities.filter(o=>o!==e);s.length===0?delete i.daemons[this.stateDir]:i.daemons[this.stateDir]={identities:s},await h(this.path,i)}};async function y(t,e){let i=new Set(await t.list());return e.filter(n=>i.has(n.name))}var l="1.0.0",r=t=>{process.stdout.write(`${t}
4
+ `)},N=t=>{process.stderr.write(`${t}
5
+ `)},I=t=>Number.isInteger(t)&&t>1,E=Number(process.env.OURS_CLIENT_PID),u=I(E)?E:I(process.ppid)?process.ppid:process.pid,f=(process.env.CLAUDE_CODE_SESSION_ID??"").trim()||`ours-mcp:${u}`,M=(process.env.OURS_BIND_IDENTITY??"").trim()||void 0,V=new Set(["start","stop","restart","serve","run","status","install-service","uninstall-service"]);function F(t){if(t.some(e=>e==="--application"||e.startsWith("--application=")))throw new Error("`--application` is no longer supported. ours-mcp connects to one coherently selected shared daemon; use OURS_CONFIG or a matching OURS_PORT + OURS_STATE_DIR selection.")}async function G(t){let i=(process.env.OURS_CLI??"").trim()||"ours";await new Promise((n,s)=>{let o=L(i,t,{stdio:"inherit",env:process.env});o.once("error",a=>{if(a.code==="ENOENT"){s(new Error(`Cannot find the ${JSON.stringify(i)} CLI. Install @ours.network/cli@2.2.0, put \`ours\` on PATH, or set OURS_CLI to its executable path.`));return}s(a)}),o.once("exit",(a,c)=>{if(c){process.kill(process.pid,c);return}process.exitCode=a??1,n()})})}async function W(){let t=new URL("./connector.js",import.meta.url),{runConnector:e}=await import(t.href);await e({leaseToken:f,clientPid:u,version:l,bindIdentity:M})}async function B(){await(await S({leaseToken:f,clientPid:u})).releaseLease()}function Y(t,e){return JSON.stringify({identity:t,...e})}async function q(t,e,i){for await(let n of t.watchNotifications(e,{kinds:["inbound"],signal:i}))r(Y(e,n))}async function H(t){if(t.length>1||t[0]?.startsWith("-"))throw new Error("Usage: ours-mcp watch [identity]");let e=J(),i=new p(e.expectStateDir);await i.list();let n=await S({leaseToken:f,clientPid:u}),s=t[0]?.trim(),o;s?o=[s]:o=(await y(i,await n.identities())).map(c=>c.name);let a=new AbortController;process.once("SIGINT",()=>a.abort()),process.once("SIGTERM",()=>a.abort()),N(`ours-mcp watch: ${o.length===0?"no application identities":`watching ${o.join(", ")}`}`),await Promise.all(o.map(c=>q(n,c,a.signal)))}function K(){r(`ours-mcp ${l} \u2014 MCP adapter for the shared ours daemon`),r(""),r("Usage: ours-mcp <command> [options]"),r(" proxy run the stdio MCP server (never starts a daemon)"),r(" session-end release this harness session and clean up its temporary identities"),r(" watch [identity] stream inbound JSON Lines; without a name, only ours-mcp identities"),r(" start|stop|restart|serve|status"),r(" install-service|uninstall-service"),r(" compatibility aliases for `ours daemon <command>`"),r(" version print the ours-mcp package version"),r(""),r("Daemon configuration and identity CLI operations moved to @ours.network/cli@2.2.0:"),r(" ours config setup"),r(" ours identity --help")}async function z(){let t=process.argv.slice(2);F(t);let e=t.shift()??"help";if(V.has(e)){await G(["daemon",e==="run"?"serve":e,...t]);return}switch(e){case"proxy":if(t.length)throw new Error("Usage: ours-mcp proxy");await W();return;case"session-end":if(t.length)throw new Error("Usage: ours-mcp session-end");await B();return;case"watch":await H(t);return;case"setup":throw new Error("ours-mcp no longer owns daemon configuration. Run `ours config setup` instead.");case"create-root":case"define-local-identity-file":case"voice-setup":case"voice-status":case"stt-setup":case"stt-status":throw new Error(`ours-mcp ${e} moved to the \`ours\` CLI. Run \`ours --help\` for the typed replacement.`);case"version":case"--version":case"-v":r(l);return;case"help":case"--help":case"-h":K();return;default:throw new Error(`Unknown command ${JSON.stringify(e)}. Run \`ours-mcp --help\`.`)}}function Q(){if(!process.argv[1])return!1;try{return v(process.argv[1])===v(j(import.meta.url))}catch{return!1}}var X=Q();X&&z().catch(t=>{N(`ours-mcp error: ${t instanceof Error?t.message:String(t)}`),process.exitCode=1});