oioxo-mcp 0.5.3 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -14
- package/bundle/cli.js +5 -4
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ OIOXO does two things from one CLI:
|
|
|
6
6
|
1. **Context engine** — sits between your codebase and your AI agents (GitHub Copilot, Claude Code, Cursor, Windsurf, Gemini CLI, Codex) and hands them the *minimal relevant slice* of your project instead of letting them read whole files.
|
|
7
7
|
2. **Coding agent** — `oioxo code "<task>"` plans, edits, and verifies in your repo, using your own key **or a local Ollama model** — nothing leaves your machine. See [Code in your terminal](#code-in-your-terminal--oioxo-code).
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
**90–92% fewer context tokens per question, measured on a real production codebase.** A question that costs an agent ~50,000 tokens of file reading comes back as a ~5,000-token capsule — same answer, a fraction of the cost.
|
|
10
10
|
|
|
11
11
|
## Quick start
|
|
12
12
|
|
|
@@ -34,16 +34,24 @@ ANTHROPIC_API_KEY=… oioxo code "fix the failing test" --verify "npm test"
|
|
|
34
34
|
OIOXO_PROVIDER=ollama OIOXO_MODEL=qwen2.5-coder oioxo code "add input validation to the signup form"
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
- **Verified, not vibes** — every change
|
|
37
|
+
- **Verified, not vibes** — every change runs through your tests/typecheck on a shadow copy; a red result is fed back and repaired. Your real files are touched only after you approve the diff.
|
|
38
38
|
- **Bring any model** — OpenAI, Anthropic, Groq, Mistral, Together, local Ollama, or any OpenAI-compatible base (`OIOXO_PROVIDER` / `OIOXO_BASE_URL` / `OIOXO_MODEL` / `OIOXO_API_KEY`).
|
|
39
|
-
- **Or fully local, no key** — point it at [Ollama](https://ollama.com) (`OIOXO_PROVIDER=ollama OIOXO_MODEL=qwen2.5-coder`) and nothing leaves your machine.
|
|
39
|
+
- **Or fully local, no key** — point it at [Ollama](https://ollama.com) (`OIOXO_PROVIDER=ollama OIOXO_MODEL=qwen2.5-coder`) and nothing leaves your machine. Or run the built-in on-device coder with **`oioxo code --local`** (open model via llama.cpp; one-time `npm i -g node-llama-cpp`) — no key, nothing uploaded.
|
|
40
40
|
|
|
41
|
-
Flags: `--verify "<cmd>"` (override the test command) · `--yes` (apply without the prompt) · `--max-iters N
|
|
41
|
+
Flags: `--verify "<cmd>"` (override the test command) · `--yes` (apply without the prompt) · `--max-iters N` · `--local` (built-in on-device coder, no key — one-time `npm i -g node-llama-cpp`).
|
|
42
|
+
|
|
43
|
+
## Compute Mesh — lend a hand, or borrow one
|
|
44
|
+
|
|
45
|
+
On the same Wi-Fi, your devices work as one engine — and the CLI is a lend-only peer. Add a
|
|
46
|
+
device with `oioxo invite` (or `oioxo join`) and this machine lends its coder to another
|
|
47
|
+
device's build, so your phone or a thin laptop builds on *this* machine's GPU. The handshake
|
|
48
|
+
is a short code — a QR or a string — with no signaling server and nothing relayed through
|
|
49
|
+
OIOXO. Lend compute and you earn free coding time for it.
|
|
42
50
|
|
|
43
51
|
## Why developers use it
|
|
44
52
|
|
|
45
|
-
- 💸 **Subscriptions go further** — Copilot premium requests, Claude limits, API keys all
|
|
46
|
-
- ⚡ **Better answers** — focused context beats 75k tokens of noise
|
|
53
|
+
- 💸 **Subscriptions go further** — Copilot premium requests, Claude limits, and API keys all last longer.
|
|
54
|
+
- ⚡ **Better answers** — focused context beats 75k tokens of noise. Your agent gets the exact code in play, plus the parts of the project it actually depends on.
|
|
47
55
|
- 🔒 **100% on-device** — your code is indexed and queried locally, never uploaded. Only the saved-token *count* is metered.
|
|
48
56
|
- 🪄 **One command** — `init` detects Claude Code, VS Code/Copilot, Cursor, Windsurf, Gemini CLI and Codex, and merges their configs without touching your other MCP servers.
|
|
49
57
|
|
|
@@ -65,16 +73,40 @@ Flags: `--verify "<cmd>"` (override the test command) · `--yes` (apply without
|
|
|
65
73
|
## Commands
|
|
66
74
|
|
|
67
75
|
```
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
oioxo
|
|
76
|
+
# Code
|
|
77
|
+
oioxo code "<task>" code in this repo: capsule-grounded, verified, then asks
|
|
78
|
+
before writing (--verify "<cmd>" · --yes · --max-iters · --local)
|
|
79
|
+
--local runs the built-in on-device coder, no key
|
|
80
|
+
|
|
81
|
+
# Account
|
|
82
|
+
oioxo login | logout connect / disconnect your OIOXO account
|
|
83
|
+
oioxo whoami | usage who you're signed in as · your saved-token allowance
|
|
84
|
+
oioxo status plan, savings and on-device index stats
|
|
85
|
+
|
|
86
|
+
# Devices (Compute Mesh) — build together on the same Wi-Fi, one account
|
|
87
|
+
oioxo invite show a code; the device that HAS the project scans it,
|
|
88
|
+
and this machine lends its coder to that build
|
|
89
|
+
oioxo join scan/paste the code from the device that has the project,
|
|
90
|
+
and lend this machine's compute to it
|
|
91
|
+
oioxo devices find your other same-account devices on this Wi-Fi
|
|
92
|
+
oioxo stop-helping how to stop lending (Ctrl+C in the helper's terminal)
|
|
93
|
+
|
|
94
|
+
# AI / model
|
|
95
|
+
oioxo model list | use <p> [m] show providers / pin one (and a model)
|
|
96
|
+
oioxo config set|get|list|unset persist provider/model/baseUrl/apiKey
|
|
97
|
+
|
|
98
|
+
# Agents (MCP)
|
|
99
|
+
oioxo init [--all] wire OIOXO into the AI agents in this project
|
|
100
|
+
oioxo mcp list show which agents OIOXO is wired into
|
|
101
|
+
oioxo serve run the MCP server over stdio (agents call this)
|
|
102
|
+
|
|
103
|
+
# Maintenance
|
|
104
|
+
oioxo doctor check creds, connection, coder config, agent wiring
|
|
105
|
+
oioxo update how to update the CLI
|
|
106
|
+
oioxo --version | --help
|
|
75
107
|
```
|
|
76
108
|
|
|
77
|
-
> The binary is published as `oioxo-mcp`; `oioxo
|
|
109
|
+
> The binary is published as `oioxo-mcp`; `oioxo …` and `oioxo-mcp …` are the same command.
|
|
78
110
|
|
|
79
111
|
## Pricing
|
|
80
112
|
|
package/bundle/cli.js
CHANGED
|
@@ -258,7 +258,7 @@ ${a.ok?"\u2713 verified green":"\u26A0 best attempt (did not fully verify)"} \u2
|
|
|
258
258
|
OIOXO saved ~${a.savedTokens.toLocaleString()} tokens of context on this task.`),!r.yes&&!await x$(`
|
|
259
259
|
Apply these changes to your files?`)){console.log("Discarded. Nothing was written.");return}await Mne(t,a.edits),console.log(`
|
|
260
260
|
\u2713 applied ${a.edits.length} file(s).${a.ok?"":" (unverified \u2014 run your tests)"}`),await ms("report",a.savedTokens).catch(()=>{})}async function Mne(t,e){let r=Zi.resolve(t),n=Zi.join(r,".oioxo","backups"),s=Zi.join(n,jne()),i=0;await dk(n,{recursive:!0}).then(()=>lk(Zi.join(n,".gitignore"),`*
|
|
261
|
-
`)).catch(()=>{});for(let o of e){if(!Vc(o.path)){console.error(` \u26A0 skipped unsafe path: ${o.path}`);continue}let a=Zi.resolve(r,o.path);if(a!==r&&!a.startsWith(r+Zi.sep)){console.error(` \u26A0 skipped path escaping repo: ${o.path}`);continue}let c=await b$(a,"utf8").catch(()=>null);if(c!==null){let u=Zi.join(s,o.path);try{await dk(Zi.dirname(u),{recursive:!0}),await lk(u,c,"utf8"),i++}catch{}}await dk(Zi.dirname(a),{recursive:!0}),await lk(a,o.content,"utf8")}if(i){let o=Zi.relative(r,s)||s;console.log(` \u21B6 backed up ${i} overwritten file(s) \u2192 ${o} (restore: copy them back)`)}}function jne(){return new Date().toISOString().replace(/[-:]/g,"").replace(/\.\d+Z$/,"Z")}async function x$(t){if(!process.stdin.isTTY)return console.log(`${t} (no TTY \u2014 pass --yes to apply non-interactively)`),!1;let e=_$({input:process.stdin,output:process.stdout});try{let r=(await e.question(`${t} [y/N] `)).trim().toLowerCase();return r==="y"||r==="yes"}finally{e.close()}}import{createInterface as _ge}from"node:readline";P_();function E$(t,e,r){return JSON.stringify(["hello",t,e,r])}var R_=16*1024,Dne=3e4,C$=1500,Une=4e3;async function hk(t,e){let r=e.now??(()=>Date.now()),n=e.setTimer??((S,C)=>setTimeout(S,C)),s=e.clearTimer??(S=>clearTimeout(S)),i=e.rand??(()=>Math.random().toString(36).slice(2)+r().toString(36)),o=fk(e.keyLookup),a=r(),c=!1,u=new Map,l=new Map,d={},f=null;function p(S){if(c)return;let C=JSON.stringify(S);if(C.length<=R_){t.send(C);return}let E=i(),B=Math.ceil(C.length/R_);for(let G=0;G<B;G++)t.send(JSON.stringify({t:"chunk",id:E,i:G,total:B,part:C.slice(G*R_,(G+1)*R_)}))}let m=i(),y=await e.identity.sign(E$(e.identity.deviceId,t.channelId,m)),_={t:"hello",v:1,profile:e.profile,publicKeyJwk:e.identity.publicKeyJwk,nonce:m,sig:y};return await new Promise((S,C)=>{let E=null,B=null,G=new Set,se=!1;function _e(){if(!se){se=!0,c=!0,B&&s(B);for(let ut of u.values())ut.reject(new Error("link lost"));u.clear();try{t.close()}catch{}for(let ut of G)try{ut()}catch{}}}function he(ut){if(!c){c=!0,B&&s(B);for(let ze of u.values())ze.reject(new Error("link closed"));u.clear(),t.close(),C(new Error(ut))}}function Y(ut,ze){return{peerId:ut,profile:ze,idleMs:()=>r()-a,sendProject:$=>p({t:"project",v:1,code:$}),onProject:$=>{f=$},serve:$=>{d=$},onLost:$=>{se?$():G.add($)},call:(($,U)=>new Promise((be,ke)=>{let Le=i(),k=n(()=>{u.delete(Le),ke(new Error(`rpc ${$} timed out`))},Dne);u.set(Le,{resolve:P=>{s(k),be(P)},reject:P=>{s(k),ke(P)}}),p({t:"rpc",v:1,id:Le,method:$,arg:U})})),close:()=>{_e()}}}async function ct(ut){a=r();let ze;try{ze=JSON.parse(ut)}catch{return}if(ze.t==="chunk"){let $=ze,U=l.get($.id)??{total:$.total,parts:new Array($.total).fill("")};U.parts[$.i]=$.part,l.set($.id,U),U.parts.every(be=>be!=="")&&(l.delete($.id),await ct(U.parts.join("")));return}let z=ze;switch(z.t){case"hello":{if(E)return;let $=await nh(z.publicKeyJwk).catch(()=>null);if(!$)return he("hello: bad key");if(!await o(E$($,t.channelId,z.nonce),z.sig,$))return he("hello: signature/identity rejected");E={peerId:$,profile:z.profile};let be=Y($,z.profile);B=n(function ke(){if(!c){if(r()-a>Une){_e();return}p({t:"ping",v:1,ts:r()}),B=n(ke,C$)}},C$),S(be);return}case"ping":return p({t:"pong",v:1,ts:z.ts});case"pong":return;case"project":{f?.(z.code);return}case"rpc":{try{if(z.method==="generate"){if(!d.generate)throw new Error("generate not served here");let $=await d.generate(z.arg);p({t:"rpc-result",v:1,id:z.id,result:$.result,receipt:$.receipt})}else{if(!d.verify)throw new Error("verify not served here");let $=await d.verify(z.arg);p({t:"rpc-result",v:1,id:z.id,result:$.result})}}catch($){p({t:"rpc-error",v:1,id:z.id,error:String($?.message??$)})}return}case"rpc-result":{let $=u.get(z.id);if(!$)return;u.delete(z.id),$.resolve({result:z.result,receipt:z.receipt});return}case"rpc-error":{let $=u.get(z.id);if(!$)return;u.delete(z.id),$.reject(new Error(z.error));return}}}t.onClose(()=>{E?_e():he("channel closed before handshake")}),t.onMessage(ut=>{ct(ut)}),p(_)})}I_();I_();import{gzipSync as Fne,gunzipSync as Vne}from"zlib";var qne=1;function Hne(t){try{let e=JSON.parse(w$(t.trim()));if(!Array.isArray(e)||e[0]!==qne)return null;let[r,n,s,i,o,a]=e;return n!=="offer"&&n!=="answer"||typeof s!="string"||!s||typeof i!="string"||typeof o!="string"||!o?null:{v:r,role:n,sdp:s,token:i,deviceId:o,label:a||void 0}}catch{return null}}function k$(t,e){let r=t.token,n=e;if(r.length!==n.length)return!1;let s=0;for(let i=0;i<r.length;i++)s|=r.charCodeAt(i)^n.charCodeAt(i);return s===0}var pk="oiop1";function mk(t){let e=new TextEncoder().encode(JSON.stringify([t.v,t.role,t.sdp,t.token,t.deviceId,t.label??""]));return pk+T_(Fne(Buffer.from(e)))}function T$(t){let e=t.trim();if(!e.startsWith(pk))return Hne(e);try{let r=Vne(Buffer.from(Bm(e.slice(pk.length)))).toString("utf8"),n=JSON.parse(r);if(!Array.isArray(n)||n[0]!==1)return null;let[s,i,o,a,c,u]=n;return i!=="offer"&&i!=="answer"||typeof o!="string"||!o||typeof a!="string"||typeof c!="string"||!c?null:{v:s,role:i,sdp:o,token:a,deviceId:c,label:u||void 0}}catch{return null}}var l1;async function uge(){if(l1!==void 0)return l1;try{l1=await Promise.resolve().then(()=>(RW(),PW))}catch{l1=null}return l1}function OW(t,e=3e3){return t.iceGatheringState==="complete"?Promise.resolve():new Promise(r=>{let n=setTimeout(r,e);t.iceGatheringStateChange.subscribe(()=>{t.iceGatheringState==="complete"&&(clearTimeout(n),r())})})}function NW(t){let e=null,r=[];return t.onMessage.subscribe(n=>{let s=typeof n=="string"?n:n.toString();e?e(s):r.push(s)}),{channelId:t.label||"oioxo-mesh",send:n=>t.send(n),onMessage:n=>{e=n;let s=r.splice(0);for(let i of s)n(i)},onClose:n=>t.stateChanged.subscribe(s=>{s==="closed"&&n()}),close:()=>{try{t.close()}catch{}}}}var YA=class{deps;constructor(e){this.deps=e}async newPc(){let e=await uge();if(!e)throw new Error("mesh transport unavailable (werift not installed)");return new e.RTCPeerConnection({iceServers:[]})}async hostOffer(){let e=await this.newPc(),r=e.createDataChannel("oioxo-mesh"),n=this.linkWhenOpen(r);return await e.setLocalDescription(await e.createOffer()),await OW(e),{offerCode:mk({v:1,role:"offer",sdp:e.localDescription.sdp,token:this.deps.token,deviceId:this.deps.identity.deviceId}),pending:{pc:e,link:n}}}async joinFromOffer(e){let r=this.accept(e,"offer"),n=await this.newPc(),s=new Promise((o,a)=>{n.onDataChannel.subscribe(c=>{hk(NW(c),this.linkDeps()).then(o,a)})});return await n.setRemoteDescription({sdp:r.sdp,type:"offer"}),await n.setLocalDescription(await n.createAnswer()),await OW(n),{answerCode:mk({v:1,role:"answer",sdp:n.localDescription.sdp,token:this.deps.token,deviceId:this.deps.identity.deviceId}),link:s}}async completeWithAnswer(e,r){let n=this.accept(r,"answer");return await e.pc.setRemoteDescription({sdp:n.sdp,type:"answer"}),e.link}accept(e,r){let n=T$(e);if(!n||n.role!==r)throw new Error("invalid pairing code");if(!k$(n,this.deps.token))throw new Error("this code is for a different account");return n}linkWhenOpen(e){return new Promise((r,n)=>{let s=()=>hk(NW(e),this.linkDeps()).then(r,n);e.readyState==="open"?s():e.stateChanged.subscribe(i=>{i==="open"&&s()})})}linkDeps(){return{identity:this.deps.identity,profile:this.deps.profile,keyLookup:this.deps.keyLookup}}};import lge from"node:os";import jW from"node:path";import{readFile as dge,writeFile as fge,mkdir as hge}from"node:fs/promises";var zW=process.env.OIOXO_HOME||jW.join(lge.homedir(),".oioxo"),BW=jW.join(zW,"mesh-identity.json"),L5={name:"ECDSA",namedCurve:"P-256"},pge={name:"ECDSA",hash:"SHA-256"},mge=new TextEncoder;function $W(t){return Buffer.from(new Uint8Array(t)).toString("base64url")}async function MW(t,e){let r=await crypto.subtle.importKey("jwk",t,L5,!0,["verify"]),n=await crypto.subtle.importKey("jwk",e,L5,!1,["sign"]);return{deviceId:$W(await crypto.subtle.digest("SHA-256",await crypto.subtle.exportKey("raw",r))),publicKeyJwk:t,sign:async i=>$W(await crypto.subtle.sign(pge,n,mge.encode(i)))}}async function D5(){try{let n=JSON.parse(await dge(BW,"utf8"));if(n.pub&&n.priv)return MW(n.pub,n.priv)}catch{}let t=await crypto.subtle.generateKey(L5,!0,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",t.publicKey),r=await crypto.subtle.exportKey("jwk",t.privateKey);try{await hge(zW,{recursive:!0}),await fge(BW,JSON.stringify({pub:e,priv:r}),{mode:384})}catch{}return MW(e,r)}P_();function gge(t){return JSON.stringify([t.v,t.deviceId,t.seq,t.nonce,t.jobHash,t.servedSec,t.tokensOut,t.issuedAt])}async function LW(t,e){let r={v:1,deviceId:t.deviceId,seq:t.seq,nonce:(t.nonce??yge)(),jobHash:t.jobHash,servedSec:Math.max(0,Math.round(t.servedSec)),tokensOut:Math.max(0,Math.round(t.tokensOut)),issuedAt:(t.now??Date.now)()},n=await e(gge(r));return{...r,sig:n}}var nOe={secPerServedSec:1,secPerToken:.02,maxPerReceiptSec:300,dailyCapSec:3600,maxAgeMs:168*3600*1e3};function yge(){let t=new Uint8Array(8);(globalThis.crypto??globalThis.crypto)?.getRandomValues(t);let e="";for(let r of t)e+=r.toString(16).padStart(2,"0");return e}E_();jo();function JA(t){let e=_ge({input:process.stdin,output:process.stdout});return new Promise(r=>e.question(t,n=>{e.close(),r(n.trim())}))}async function GW(t){return Buffer.from(new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)))).toString("base64url")}async function QA(){return(await za())?.token??null}async function WW(t){let e={},r=await QA(),n={"content-type":"application/json",...r?{authorization:`Bearer ${r}`}:{}};try{await fetch(`${gn}/api/devices/register`,{method:"POST",headers:n,body:JSON.stringify({publicKeyJwk:t,label:"CLI peer"})});let s=await fetch(`${gn}/api/devices/register`,{headers:n});if(s.ok){let i=await s.json();for(let o of i.devices??[])e[o.deviceId]=o.publicKeyJwk}}catch{}return e}var vge=0,eE=new Set;function KW(t,e,r,n){let s=Rm();eE.add(t),t.onLost(()=>{eE.delete(t)}),t.serve({generate:async({ctx:i})=>{if("error"in s)return{result:[]};let o=Date.now(),a=await s.coder.generate({task:i.task,grounding:wge(i),error:i.error,attempt:i.attempt}).catch(()=>[]),c;try{if(a.length){let u=await GW(JSON.stringify([i.task,a.map(l=>[l.path,l.content]).sort()]));c=await LW({deviceId:n,seq:++vge,jobHash:u,servedSec:(Date.now()-o)/1e3,tokensOut:Math.ceil(a.reduce((l,d)=>l+d.content.length,0)/4)},r)}}catch{}return{result:a,receipt:c}}}),console.log(` \u2713 connected \u2014 lending "${e}" to ${t.profile.label??t.peerId.slice(0,8)}.`)}function wge(t){return(t.files??[]).map(e=>`--- ${e.path} ---
|
|
261
|
+
`)).catch(()=>{});for(let o of e){if(!Vc(o.path)){console.error(` \u26A0 skipped unsafe path: ${o.path}`);continue}let a=Zi.resolve(r,o.path);if(a!==r&&!a.startsWith(r+Zi.sep)){console.error(` \u26A0 skipped path escaping repo: ${o.path}`);continue}let c=await b$(a).catch(()=>null);if(c!==null){let u=Zi.join(s,o.path);try{await dk(Zi.dirname(u),{recursive:!0}),await lk(u,c),i++}catch{}}await dk(Zi.dirname(a),{recursive:!0}),await lk(a,o.content,"utf8")}if(i){let o=Zi.relative(r,s)||s;console.log(` \u21B6 backed up ${i} overwritten file(s) \u2192 ${o} (restore: copy them back)`)}}function jne(){return new Date().toISOString().replace(/[-:]/g,"").replace(/\.\d+Z$/,"Z")}async function x$(t){if(!process.stdin.isTTY)return console.log(`${t} (no TTY \u2014 pass --yes to apply non-interactively)`),!1;let e=_$({input:process.stdin,output:process.stdout});try{let r=(await e.question(`${t} [y/N] `)).trim().toLowerCase();return r==="y"||r==="yes"}finally{e.close()}}import{createInterface as _ge}from"node:readline";P_();function E$(t,e,r){return JSON.stringify(["hello",t,e,r])}var R_=16*1024,Dne=3e4,C$=1500,Une=4e3;async function hk(t,e){let r=e.now??(()=>Date.now()),n=e.setTimer??((S,C)=>setTimeout(S,C)),s=e.clearTimer??(S=>clearTimeout(S)),i=e.rand??(()=>Math.random().toString(36).slice(2)+r().toString(36)),o=fk(e.keyLookup),a=r(),c=!1,u=new Map,l=new Map,d={},f=null;function p(S){if(c)return;let C=JSON.stringify(S);if(C.length<=R_){t.send(C);return}let E=i(),B=Math.ceil(C.length/R_);for(let G=0;G<B;G++)t.send(JSON.stringify({t:"chunk",id:E,i:G,total:B,part:C.slice(G*R_,(G+1)*R_)}))}let m=i(),y=await e.identity.sign(E$(e.identity.deviceId,t.channelId,m)),_={t:"hello",v:1,profile:e.profile,publicKeyJwk:e.identity.publicKeyJwk,nonce:m,sig:y};return await new Promise((S,C)=>{let E=null,B=null,G=new Set,se=!1;function _e(){if(!se){se=!0,c=!0,B&&s(B);for(let ut of u.values())ut.reject(new Error("link lost"));u.clear();try{t.close()}catch{}for(let ut of G)try{ut()}catch{}}}function he(ut){if(!c){c=!0,B&&s(B);for(let ze of u.values())ze.reject(new Error("link closed"));u.clear(),t.close(),C(new Error(ut))}}function Y(ut,ze){return{peerId:ut,profile:ze,idleMs:()=>r()-a,sendProject:$=>p({t:"project",v:1,code:$}),onProject:$=>{f=$},serve:$=>{d=$},onLost:$=>{se?$():G.add($)},call:(($,U)=>new Promise((be,ke)=>{let Le=i(),k=n(()=>{u.delete(Le),ke(new Error(`rpc ${$} timed out`))},Dne);u.set(Le,{resolve:P=>{s(k),be(P)},reject:P=>{s(k),ke(P)}}),p({t:"rpc",v:1,id:Le,method:$,arg:U})})),close:()=>{_e()}}}async function ct(ut){a=r();let ze;try{ze=JSON.parse(ut)}catch{return}if(ze.t==="chunk"){let $=ze,U=l.get($.id)??{total:$.total,parts:new Array($.total).fill("")};U.parts[$.i]=$.part,l.set($.id,U),U.parts.every(be=>be!=="")&&(l.delete($.id),await ct(U.parts.join("")));return}let z=ze;switch(z.t){case"hello":{if(E)return;let $=await nh(z.publicKeyJwk).catch(()=>null);if(!$)return he("hello: bad key");if(!await o(E$($,t.channelId,z.nonce),z.sig,$))return he("hello: signature/identity rejected");E={peerId:$,profile:z.profile};let be=Y($,z.profile);B=n(function ke(){if(!c){if(r()-a>Une){_e();return}p({t:"ping",v:1,ts:r()}),B=n(ke,C$)}},C$),S(be);return}case"ping":return p({t:"pong",v:1,ts:z.ts});case"pong":return;case"project":{f?.(z.code);return}case"rpc":{try{if(z.method==="generate"){if(!d.generate)throw new Error("generate not served here");let $=await d.generate(z.arg);p({t:"rpc-result",v:1,id:z.id,result:$.result,receipt:$.receipt})}else{if(!d.verify)throw new Error("verify not served here");let $=await d.verify(z.arg);p({t:"rpc-result",v:1,id:z.id,result:$.result})}}catch($){p({t:"rpc-error",v:1,id:z.id,error:String($?.message??$)})}return}case"rpc-result":{let $=u.get(z.id);if(!$)return;u.delete(z.id),$.resolve({result:z.result,receipt:z.receipt});return}case"rpc-error":{let $=u.get(z.id);if(!$)return;u.delete(z.id),$.reject(new Error(z.error));return}}}t.onClose(()=>{E?_e():he("channel closed before handshake")}),t.onMessage(ut=>{ct(ut)}),p(_)})}I_();I_();import{gzipSync as Fne,gunzipSync as Vne}from"zlib";var qne=1;function Hne(t){try{let e=JSON.parse(w$(t.trim()));if(!Array.isArray(e)||e[0]!==qne)return null;let[r,n,s,i,o,a]=e;return n!=="offer"&&n!=="answer"||typeof s!="string"||!s||typeof i!="string"||typeof o!="string"||!o?null:{v:r,role:n,sdp:s,token:i,deviceId:o,label:a||void 0}}catch{return null}}function k$(t,e){let r=t.token,n=e;if(r.length!==n.length)return!1;let s=0;for(let i=0;i<r.length;i++)s|=r.charCodeAt(i)^n.charCodeAt(i);return s===0}var pk="oiop1";function mk(t){let e=new TextEncoder().encode(JSON.stringify([t.v,t.role,t.sdp,t.token,t.deviceId,t.label??""]));return pk+T_(Fne(Buffer.from(e)))}function T$(t){let e=t.trim();if(!e.startsWith(pk))return Hne(e);try{let r=Vne(Buffer.from(Bm(e.slice(pk.length)))).toString("utf8"),n=JSON.parse(r);if(!Array.isArray(n)||n[0]!==1)return null;let[s,i,o,a,c,u]=n;return i!=="offer"&&i!=="answer"||typeof o!="string"||!o||typeof a!="string"||typeof c!="string"||!c?null:{v:s,role:i,sdp:o,token:a,deviceId:c,label:u||void 0}}catch{return null}}var l1;async function uge(){if(l1!==void 0)return l1;try{l1=await Promise.resolve().then(()=>(RW(),PW))}catch{l1=null}return l1}function OW(t,e=3e3){return t.iceGatheringState==="complete"?Promise.resolve():new Promise(r=>{let n=setTimeout(r,e);t.iceGatheringStateChange.subscribe(()=>{t.iceGatheringState==="complete"&&(clearTimeout(n),r())})})}function NW(t){let e=null,r=[];return t.onMessage.subscribe(n=>{let s=typeof n=="string"?n:n.toString();e?e(s):r.push(s)}),{channelId:t.label||"oioxo-mesh",send:n=>t.send(n),onMessage:n=>{e=n;let s=r.splice(0);for(let i of s)n(i)},onClose:n=>t.stateChanged.subscribe(s=>{s==="closed"&&n()}),close:()=>{try{t.close()}catch{}}}}var YA=class{deps;constructor(e){this.deps=e}async newPc(){let e=await uge();if(!e)throw new Error("mesh transport unavailable (werift not installed)");return new e.RTCPeerConnection({iceServers:[]})}async hostOffer(){let e=await this.newPc(),r=e.createDataChannel("oioxo-mesh"),n=this.linkWhenOpen(r);return await e.setLocalDescription(await e.createOffer()),await OW(e),{offerCode:mk({v:1,role:"offer",sdp:e.localDescription.sdp,token:this.deps.token,deviceId:this.deps.identity.deviceId}),pending:{pc:e,link:n}}}async joinFromOffer(e){let r=this.accept(e,"offer"),n=await this.newPc(),s=new Promise((o,a)=>{n.onDataChannel.subscribe(c=>{hk(NW(c),this.linkDeps()).then(o,a)})});return await n.setRemoteDescription({sdp:r.sdp,type:"offer"}),await n.setLocalDescription(await n.createAnswer()),await OW(n),{answerCode:mk({v:1,role:"answer",sdp:n.localDescription.sdp,token:this.deps.token,deviceId:this.deps.identity.deviceId}),link:s}}async completeWithAnswer(e,r){let n=this.accept(r,"answer");return await e.pc.setRemoteDescription({sdp:n.sdp,type:"answer"}),e.link}accept(e,r){let n=T$(e);if(!n||n.role!==r)throw new Error("invalid pairing code");if(!k$(n,this.deps.token))throw new Error("this code is for a different account");return n}linkWhenOpen(e){return new Promise((r,n)=>{let s=()=>hk(NW(e),this.linkDeps()).then(r,n);e.readyState==="open"?s():e.stateChanged.subscribe(i=>{i==="open"&&s()})})}linkDeps(){return{identity:this.deps.identity,profile:this.deps.profile,keyLookup:this.deps.keyLookup}}};import lge from"node:os";import jW from"node:path";import{readFile as dge,writeFile as fge,mkdir as hge}from"node:fs/promises";var zW=process.env.OIOXO_HOME||jW.join(lge.homedir(),".oioxo"),BW=jW.join(zW,"mesh-identity.json"),L5={name:"ECDSA",namedCurve:"P-256"},pge={name:"ECDSA",hash:"SHA-256"},mge=new TextEncoder;function $W(t){return Buffer.from(new Uint8Array(t)).toString("base64url")}async function MW(t,e){let r=await crypto.subtle.importKey("jwk",t,L5,!0,["verify"]),n=await crypto.subtle.importKey("jwk",e,L5,!1,["sign"]);return{deviceId:$W(await crypto.subtle.digest("SHA-256",await crypto.subtle.exportKey("raw",r))),publicKeyJwk:t,sign:async i=>$W(await crypto.subtle.sign(pge,n,mge.encode(i)))}}async function D5(){try{let n=JSON.parse(await dge(BW,"utf8"));if(n.pub&&n.priv)return MW(n.pub,n.priv)}catch{}let t=await crypto.subtle.generateKey(L5,!0,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",t.publicKey),r=await crypto.subtle.exportKey("jwk",t.privateKey);try{await hge(zW,{recursive:!0}),await fge(BW,JSON.stringify({pub:e,priv:r}),{mode:384})}catch{}return MW(e,r)}P_();function gge(t){return JSON.stringify([t.v,t.deviceId,t.seq,t.nonce,t.jobHash,t.servedSec,t.tokensOut,t.issuedAt])}async function LW(t,e){let r={v:1,deviceId:t.deviceId,seq:t.seq,nonce:(t.nonce??yge)(),jobHash:t.jobHash,servedSec:Math.max(0,Math.round(t.servedSec)),tokensOut:Math.max(0,Math.round(t.tokensOut)),issuedAt:(t.now??Date.now)()},n=await e(gge(r));return{...r,sig:n}}var nOe={secPerServedSec:1,secPerToken:.02,maxPerReceiptSec:300,dailyCapSec:3600,maxAgeMs:168*3600*1e3};function yge(){let t=new Uint8Array(8);(globalThis.crypto??globalThis.crypto)?.getRandomValues(t);let e="";for(let r of t)e+=r.toString(16).padStart(2,"0");return e}E_();jo();function JA(t){let e=_ge({input:process.stdin,output:process.stdout});return new Promise(r=>e.question(t,n=>{e.close(),r(n.trim())}))}async function GW(t){return Buffer.from(new Uint8Array(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(t)))).toString("base64url")}async function QA(){return(await za())?.token??null}async function WW(t){let e={},r=await QA(),n={"content-type":"application/json",...r?{authorization:`Bearer ${r}`}:{}};try{await fetch(`${gn}/api/devices/register`,{method:"POST",headers:n,body:JSON.stringify({publicKeyJwk:t,label:"CLI peer"})});let s=await fetch(`${gn}/api/devices/register`,{headers:n});if(s.ok){let i=await s.json();for(let o of i.devices??[])e[o.deviceId]=o.publicKeyJwk}}catch{}return e}var vge=0,eE=new Set;function KW(t,e,r,n){let s=Rm();eE.add(t),t.onLost(()=>{eE.delete(t)}),t.serve({generate:async({ctx:i})=>{if("error"in s)return{result:[]};let o=Date.now(),a=await s.coder.generate({task:i.task,grounding:wge(i),error:i.error,attempt:i.attempt}).catch(()=>[]),c;try{if(a.length){let u=await GW(JSON.stringify([i.task,a.map(l=>[l.path,l.content]).sort()]));c=await LW({deviceId:n,seq:++vge,jobHash:u,servedSec:(Date.now()-o)/1e3,tokensOut:Math.ceil(a.reduce((l,d)=>l+d.content.length,0)/4)},r)}}catch{}return{result:a,receipt:c}}}),console.log(` \u2713 connected \u2014 lending "${e}" to ${t.profile.label??t.peerId.slice(0,8)}.`)}function wge(t){return(t.files??[]).map(e=>`--- ${e.path} ---
|
|
262
262
|
${e.content}`).join(`
|
|
263
263
|
|
|
264
264
|
`)}async function d1(t){if(!await Ki()){console.log("Compute Mesh is account-scoped (same account, same Wi-Fi). Sign in first: `oioxo login`.");return}let e=t[0];if(e==="host"&&(e="invite"),e==="help"&&(e="join"),e==="devices"||e==="scan"){await Sge();return}if(e!=="invite"&&e!=="join"){console.log(`Compute Mesh \u2014 lend this machine's compute to a device that has a project (same
|
|
@@ -352,14 +352,15 @@ ${f.map(m=>` ${m}`).join(`
|
|
|
352
352
|
|
|
353
353
|
IMPORTED BY (changing ${l} may break these):
|
|
354
354
|
${p.map(m=>` ${m}`).join(`
|
|
355
|
-
`)||" (none \u2014 no in-project callers)"}`)}),e.tool("remember","Save one durable fact about THIS project to .oioxo/memory.md (on-device, shared with the OIOXO IDEs). Use for decisions, conventions, gotchas worth keeping.",{fact:Rf.string().describe("The fact, one concise sentence.")},async({fact:c})=>(await tre(t,c),$a("Saved to .oioxo/memory.md."))),e.tool("recall","This project's rules and learned memory from .oioxo/ (same files the OIOXO IDEs maintain). Call when starting work in an unfamiliar repo.",{},async()=>{let c=AB(await SB(t));return $a(c||"No .oioxo/rules.md or memory.md in this project yet.")});let a=new qC;await e.connect(a)}jo();var CB=(()=>{try{return"0.5.
|
|
355
|
+
`)||" (none \u2014 no in-project callers)"}`)}),e.tool("remember","Save one durable fact about THIS project to .oioxo/memory.md (on-device, shared with the OIOXO IDEs). Use for decisions, conventions, gotchas worth keeping.",{fact:Rf.string().describe("The fact, one concise sentence.")},async({fact:c})=>(await tre(t,c),$a("Saved to .oioxo/memory.md."))),e.tool("recall","This project's rules and learned memory from .oioxo/ (same files the OIOXO IDEs maintain). Call when starting work in an unfamiliar repo.",{},async()=>{let c=AB(await SB(t));return $a(c||"No .oioxo/rules.md or memory.md in this project yet.")});let a=new qC;await e.connect(a)}jo();var CB=(()=>{try{return"0.5.4"}catch{}try{return sre(import.meta.url)("../../package.json").version}catch{return"0.0.0"}})(),nre=`OIOXO ${CB} \u2014 context engine + terminal coding agent (https://oioxo.com)
|
|
356
356
|
|
|
357
357
|
Usage: oioxo <command> [options]
|
|
358
358
|
|
|
359
359
|
Code:
|
|
360
360
|
code "<task>" Build/fix in this repo: capsule-grounded, verified on a shadow copy,
|
|
361
|
-
then asks before writing. Flags: --verify "<cmd>" \xB7 --yes \xB7 --max-iters N
|
|
362
|
-
|
|
361
|
+
then asks before writing. Flags: --verify "<cmd>" \xB7 --yes \xB7 --max-iters N \xB7 --local
|
|
362
|
+
--local runs the built-in on-device coder, no key (one-time: npm i -g node-llama-cpp).
|
|
363
|
+
(Or use a local Ollama server: OIOXO_PROVIDER=ollama OIOXO_MODEL=qwen2.5-coder)
|
|
363
364
|
|
|
364
365
|
Account:
|
|
365
366
|
login Connect your OIOXO account (opens the browser)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oioxo-mcp",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "OIOXO
|
|
3
|
+
"version": "0.5.4",
|
|
4
|
+
"description": "OIOXO — a private terminal coding agent (`oioxo code`, on-device with --local or any key) plus the context engine that feeds Claude Code, Copilot, Cursor and any MCP agent the minimal relevant slice of your codebase. On-device, token-saving, and a lend-only Compute Mesh peer.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -36,7 +36,12 @@
|
|
|
36
36
|
"copilot",
|
|
37
37
|
"cursor",
|
|
38
38
|
"oioxo",
|
|
39
|
-
"token-saver"
|
|
39
|
+
"token-saver",
|
|
40
|
+
"code-agent",
|
|
41
|
+
"on-device",
|
|
42
|
+
"local-llm",
|
|
43
|
+
"compute-mesh",
|
|
44
|
+
"private-ai"
|
|
40
45
|
],
|
|
41
46
|
"homepage": "https://oioxo.com",
|
|
42
47
|
"dependencies": {
|