oioxo-mcp 0.5.55 → 0.5.57
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/bundle/cli.js +4 -4
- package/package.json +1 -1
package/bundle/cli.js
CHANGED
|
@@ -80,7 +80,7 @@ FILE: <relative/path>
|
|
|
80
80
|
\`\`\`
|
|
81
81
|
|
|
82
82
|
HARD RULES:
|
|
83
|
-
-
|
|
83
|
+
- Say a short sentence in your own voice before the first FILE block if it helps (what you're doing or why); keep prose tight and let the code carry the rest.
|
|
84
84
|
- NEVER output a diff/patch (no \`diff\`, no \`@@\`, no +/- lines). Emit WHOLE files.
|
|
85
85
|
- NEVER output JSON. Use the FILE: + fenced-block format only.
|
|
86
86
|
- Preserve required keywords the task implies (e.g. \`export\` for an exported function).
|
|
@@ -119,7 +119,7 @@ FILE: <relative/path>
|
|
|
119
119
|
Rules:
|
|
120
120
|
- Emit the COMPLETE file content, never a diff or "// unchanged" placeholder.
|
|
121
121
|
- Touch as few files as possible. Do not invent files you weren't shown unless the task needs a new one.
|
|
122
|
-
-
|
|
122
|
+
- Say a short sentence in your own voice before the first FILE block if it helps; keep prose tight.`;Ide={openai:"https://api.openai.com/v1",groq:"https://api.groq.com/openai/v1",mistral:"https://api.mistral.ai/v1",together:"https://api.together.xyz/v1",ollama:"http://localhost:11434/v1",anthropic:"https://api.anthropic.com",custom:""},_d=class{cfg;label;constructor(e){this.cfg=e,this.label=`your ${e.provider} key (${e.model})`}async generate(e){let r=KJe(e),n=this.cfg.provider==="anthropic"?await this.callAnthropic(r):await this.callOpenAICompatible(r);return C$(n,[],{lenient:!1})}async complete(e,r){return this.cfg.provider==="anthropic"?this.callAnthropic(e,r):this.callOpenAICompatible(e,r)}async callOpenAICompatible(e,r){let n=(this.cfg.baseUrl||Ide[this.cfg.provider]).replace(/\/$/,"");if(!n)throw new Error("a baseUrl is required for the custom provider");let i={"content-type":"application/json"};this.cfg.key&&(i.authorization=`Bearer ${this.cfg.key}`);let s=await fetch(`${n}/chat/completions`,{method:"POST",headers:i,body:JSON.stringify({model:this.cfg.model,temperature:r?.temperature??.2,messages:[{role:"system",content:Dde},{role:"user",content:e}]})});if(!s.ok){let c=(await s.text()).slice(0,300);if(this.cfg.provider==="ollama"&&s.status===404){let d="";try{d=((await(await fetch(`${n}/models`)).json()).data??[]).map(p=>p.id).filter(Boolean).join(", ")||"(none)"}catch{d="(could not query /v1/models)"}throw new Error(`ollama 404: model '${this.cfg.model}' isn't served by Ollama's OpenAI-compatible API.
|
|
123
123
|
Ollama's /v1 currently exposes: ${d}
|
|
124
124
|
Fix: run \`ollama run ${this.cfg.model}\` once (loads + registers it), pin a model that IS listed via \`oioxo config set model <id>\`, or restart Ollama if the list looks stale.`)}throw new Error(`${this.cfg.provider} ${s.status}: ${c}`)}return(await s.json()).choices?.[0]?.message?.content??""}async callAnthropic(e,r){let n=(this.cfg.baseUrl||Ide.anthropic).replace(/\/$/,""),i=await fetch(`${n}/v1/messages`,{method:"POST",headers:{"content-type":"application/json","x-api-key":this.cfg.key??"","anthropic-version":"2023-06-01"},body:JSON.stringify({model:this.cfg.model,max_tokens:8192,temperature:r?.temperature??.2,system:Dde,messages:[{role:"user",content:e}]})});if(!i.ok)throw new Error(`anthropic ${i.status}: ${(await i.text()).slice(0,300)}`);return((await i.json()).content??[]).map(a=>a.text??"").join("")}},Kv=class{onNote;label="OIOXO on-device (private)";impl=null;constructor(e=()=>{}){this.onNote=e}async generate(e){if(!this.impl){let{DeviceCoderLocal:r}=await Promise.resolve().then(()=>(e5(),T$));this.impl=new r(this.onNote)}return this.impl.generate(e)}async complete(e,r){if(!this.impl){let{DeviceCoderLocal:n}=await Promise.resolve().then(()=>(e5(),T$));this.impl=new n(this.onNote)}return this.impl.complete?this.impl.complete(e,r):""}}});function BA(t){return t5.find(e=>e.id===t)??t5[0]}var t5,r5=ce(()=>{"use strict";t5=[{id:"build",label:"Builder",blurb:"Full agent \u2014 edits and verifies.",systemPrompt:"",edits:!0},{id:"reviewer",label:"Reviewer",blurb:"Reviews code for bugs and risks; read-only.",systemPrompt:"Act as a meticulous senior code reviewer. Report concrete, prioritized findings (correctness, then security, then maintainability): the file, the problem, why it matters, and a specific fix. Do not rewrite the codebase \u2014 review it.",edits:!1},{id:"test-writer",label:"Test Writer",blurb:"Writes and runs tests.",systemPrompt:"Write thorough, idiomatic tests using the project's existing framework and conventions. Cover the happy path, edge cases, and error handling. Keep tests readable and independent.",edits:!0},{id:"debugger",label:"Debugger",blurb:"Reproduces, locates, and fixes a bug.",systemPrompt:"Act as a debugging specialist. Confirm the root cause before changing anything, then make the SMALLEST fix that resolves it. Do not refactor unrelated code.",edits:!0},{id:"ask",label:"Ask",blurb:"Explains code; read-only.",systemPrompt:"Explain the code and answer the question clearly and concisely. Cite the files you used; say what you are unsure about rather than guessing. Do not change files.",edits:!1}]});function Pde(t){return t.trim().toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)||"item"}function k$(t){return`---
|
|
125
125
|
${["oioxo: agent",`id: ${t.id}`,`label: ${t.label}`,`blurb: ${ZJe(t.blurb)}`,`edits: ${t.edits?"true":"false"}`,`tools: ${t.allowedTools.join(", ")}`,`mode: ${t.defaultMode}`].join(`
|
|
@@ -684,7 +684,7 @@ How to work, like a real IDE:
|
|
|
684
684
|
1. Just START BUILDING. For a multi-file task, your FIRST action should usually be writeFile of the first real file \u2014 don't burn a turn explaining or restating the goal. (For a big/unfamiliar task you MAY call the plan tool once to set a todo list, then immediately do the first step the same way \u2014 but planning is optional and never the whole turn.) When changing existing code, readFile/listFiles first to see what's there.
|
|
685
685
|
2. Build the project FILE BY FILE: writeFile a new file with real, complete code (not a stub); for changes to existing files, editFile with a small patch. The files on disk are your memory \u2014 you don't hold everything in your head. Keep going file by file until every file exists \u2014 never stop after only describing what you'll do.
|
|
686
686
|
FOLDERS ARE IMPLICIT \u2014 there is NO createFolder/mkdir tool. To make a package folder, just writeFile a file with that path, e.g. writeFile "taskflow/__init__.py" or "taskflow/storage.py" and the "taskflow/" folder is created automatically. Never try to create a directory as a separate step.
|
|
687
|
-
3.
|
|
687
|
+
3. BUILD BEFORE YOU VERIFY. Only AFTER all the files exist do you typecheck / runTests / shell / open the app \u2014 and then FIX what's broken. Never run a build/test command (pytest, npm test, flutter test, etc.) before the files exist; testing an empty project just fails. Write every file first, THEN verify.
|
|
688
688
|
4. Keep the PROGRESS note current. Work one concrete thing at a time.
|
|
689
689
|
5. Make real, working code \u2014 never empty placeholders or "// TODO" stubs. A file you create must actually do its job. Keep each file FOCUSED and COMPLETE: write one cohesive module per writeFile with every function fully closed \u2014 don't try to cram the whole project into one giant file (split into the planned modules). A complete 60-line module beats a truncated 300-line one.
|
|
690
690
|
6. Call done only when the project actually works end-to-end. Call ask only when you genuinely need the user to decide.`});function wwe(t){return fG=(fG+1)%1e6,"t"+t.toString(36)+fG.toString(36)}function dG(t,e,r){let n={id:e.id??wwe(r),role:e.role,text:e.text,ts:e.ts??r,...e.step!=null?{step:e.step}:{}};return{...t,turns:[...t.turns,n],updatedAt:r}}function Swe(t,e,r){return{...t,trajectory:[...t.trajectory,{...e,ts:e.ts??r}],updatedAt:r}}function vft(t){let e=0;for(let r of t)e+=r.text.length+16;return e}function hG(t,e=uC){return t.turns.length>e.maxTurns||vft(t.turns)>e.maxBytes}async function Awe(t,e,r,n=uC){if(!hG(t,n))return t;let i=t.turns[0]?.role==="summary",s=i?t.turns.slice(0,1):[],a=i?t.turns.slice(1):t.turns,c=Math.max(1,Math.floor(a.length*n.compactFraction)),d=a.slice(0,c),h=a.slice(c);if(!d.length)return t;let p="";try{p=(await e([...s,...d])).trim()}catch{return t}if(!p)return t;let x={id:wwe(r),role:"summary",text:p.slice(0,4e3),ts:r};return{...t,turns:[x,...h],compactedCount:(t.compactedCount??0)+d.length+(i?1:0),updatedAt:r}}function Ewe(t){let e=t.trajectory.length,r=t.turns.filter(i=>i.role==="user"||i.role==="assistant").length,n=new Date(t.updatedAt).toLocaleString();return`${t.title||t.goal.slice(0,48)||"Untitled"} \xB7 ${e} step${e===1?"":"s"}, ${r} message${r===1?"":"s"} \xB7 ${n}`}function Twe(t,e,r,n){return{id:t,title:n??e.slice(0,60),goal:e,createdAt:r,updatedAt:r,turns:[],trajectory:[]}}function lC(t){let e=t.filter(i=>i.role==="user").map(i=>i.text),r=t.filter(i=>i.role==="assistant"||i.role==="narration").map(i=>i.text),n=[];return e[0]&&n.push(`Asked: ${e[0].slice(0,200)}`),e.length>1&&n.push(`Then: ${e.slice(1).map(i=>i.slice(0,80)).join("; ").slice(0,300)}`),r.length&&n.push(`Did: ${r.slice(-3).map(i=>i.slice(0,100)).join(" ").slice(0,300)}`),n.join(`
|
|
@@ -1250,7 +1250,7 @@ ${T.snippet}`:""}`).join(`
|
|
|
1250
1250
|
`);return Gs(A||"No results.")}catch(v){return Gs(`web_search failed: ${v instanceof Error?v.message:"error"}`)}}),e.tool("fetch_url","Fetch a web page (http/https only) and return its readable text. Use to read a doc/article \u2014 typically a URL found via web_search.",{url:ao.string().describe("The full http(s) URL.")},async({url:x})=>{let y=await VS();if(!y.ok)return HS(y.message);try{let _=await(await fetch(`${Us}/tools/fetch?url=${encodeURIComponent(x)}`,{signal:AbortSignal.timeout(12e3)})).json();return Gs(_.error?`fetch_url failed: ${_.error}`:_.text??"(empty)")}catch(v){return Gs(`fetch_url failed: ${v instanceof Error?v.message:"error"}`)}});let c=null,d=!1,h=async x=>{if(d=x,c)return c;let{makePlaywrightBackend:y}=await Promise.resolve().then(()=>(mce(),pce)),{BrowserController:v}=await Promise.resolve().then(()=>(RM(),QMe)),_=await y({headless:!1});return c=new v(_,{confirmNavigate:async()=>d,allowEvaluate:!1}),c};e.tool("browser",'Drive a REAL browser on this machine to see and test web pages \u2014 navigate, read a numbered snapshot of clickable elements, click/type by ref, screenshot. Runs LOCALLY (the page never leaves the device). Local URLs (localhost) are always allowed; set allow_external:true to permit other sites. Call one verb at a time; after navigate the result lists elements like [3] button "Sign in" \u2014 click by that ref.',{verb:ao.enum(["navigate","snapshot","screenshot","click","type","waitFor","scrollTo","back","reload","close"]).describe("The action."),url:ao.string().optional().describe("For navigate: the URL."),ref:ao.number().optional().describe("For click/type/scrollTo: element number from the latest snapshot."),text:ao.string().optional().describe("For type: text to enter. For click: visible text to match. For waitFor: text to wait for."),selector:ao.string().optional().describe("Optional CSS selector (prefer ref)."),submit:ao.boolean().optional().describe("For type: press Enter after typing."),allow_external:ao.boolean().optional().describe("Permit navigating to non-local sites (privacy gate; default false).")},async({verb:x,url:y,ref:v,text:_,selector:A,submit:T,allow_external:k})=>{let C=await VS();if(!C.ok)return HS(C.message);try{let E=await h(!!k);if(x==="close")return await E.dispose(),c=null,Gs("Browser closed.");let I=await E.run({verb:x,url:y,ref:v,text:_,selector:A,submit:T});if(!I.ok)return Gs(`browser ${x} failed: ${I.error??"unknown error"}`);let R=`${I.title||""} \u2014 ${I.url}`.trim(),B=I.snapshot?`
|
|
1251
1251
|
${I.snapshot}`:"",U=I.consoleErrors?.length?`
|
|
1252
1252
|
console errors: ${I.consoleErrors.slice(0,3).join(" | ")}`:"",H=I.screenshot?`
|
|
1253
|
-
(screenshot captured: ${I.screenshot.length} bytes \u2014 not shown as text)`:"";return Gs(`${R}${B}${U}${H}`.trim()||"OK")}catch(E){return Gs(`browser failed: ${E instanceof Error?E.message:"error"}`)}});let p=new FM;await e.connect(p)}L8();$8();_l();var kce=(()=>{try{return"0.5.
|
|
1253
|
+
(screenshot captured: ${I.screenshot.length} bytes \u2014 not shown as text)`:"";return Gs(`${R}${B}${U}${H}`.trim()||"OK")}catch(E){return Gs(`browser failed: ${E instanceof Error?E.message:"error"}`)}});let p=new FM;await e.connect(p)}L8();$8();_l();var kce=(()=>{try{return"0.5.57"}catch{}try{return _Le(import.meta.url)("../../package.json").version}catch{return"0.0.0"}})(),_It=`OIOXO ${kce} \u2014 context engine + terminal coding agent (https://oioxo.com)
|
|
1254
1254
|
|
|
1255
1255
|
Private, on your device. Cut your AI bill by up to ~90% in Copilot, Cursor & Claude,
|
|
1256
1256
|
and code from your terminal \u2014 nothing leaves your machine.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oioxo-mcp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.57",
|
|
4
4
|
"description": "OIOXO — cut your AI bill by up to ~90%: it feeds Claude Code, Copilot, Cursor and any MCP agent only the relevant slice of your codebase instead of whole files. Also a private terminal coding agent (`oioxo code`, on-device with --local or any key). Runs on your device; your own devices can build together over Wi-Fi.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"type": "module",
|