@oracle-agent/oracle 0.27.0 → 0.28.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/README.md +1 -1
- package/SETUP.md +27 -1
- package/dist/assets/skills/oracle-desk-product/SKILL.md +1 -1
- package/dist/bin/oracle-gateway.mjs +1 -1
- package/dist/cli/commands/auth.mjs +3 -3
- package/dist/cli/commands/chat.mjs +148 -95
- package/dist/cli/commands/doctor.mjs +1 -1
- package/dist/cli/commands/eval.mjs +2 -2
- package/dist/cli/commands/harness.mjs +3 -3
- package/dist/cli/commands/init.mjs +2 -2
- package/dist/cli/commands/model.mjs +148 -96
- package/dist/cli/commands/setup.mjs +43 -39
- package/dist/cli/commands/venues.mjs +1 -1
- package/package.json +1 -1
- package/public/install.sh +20 -0
- package/public/oracle-splash/install.sh +20 -0
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ oracle doctor # verify local posture
|
|
|
13
13
|
|
|
14
14
|
`oracle setup model` offers Anthropic, OpenAI Codex, and Grok OAuth plus secure
|
|
15
15
|
API-key setup for OpenRouter, OpenAI, Anthropic, xAI, DeepSeek, Gemini, Kimi,
|
|
16
|
-
Mistral, and custom OpenAI-compatible providers. `oracle auth status` reports
|
|
16
|
+
Mistral, Nous, and custom OpenAI-compatible providers. `oracle auth status` reports
|
|
17
17
|
providers without printing credentials. Linux, Windows, and macOS apps are in beta.
|
|
18
18
|
|
|
19
19
|
The CLI, source, and desktop beta are public to everyone. Locals Only holders
|
package/SETUP.md
CHANGED
|
@@ -73,6 +73,12 @@ oracle --version
|
|
|
73
73
|
This installs into `~/.local/share/oracle` and puts `oracle` on `~/.local/bin`
|
|
74
74
|
(no sudo, no global `npm -g`). Re-run the same command to upgrade.
|
|
75
75
|
|
|
76
|
+
On an interactive terminal the installer prints a small ASCII globe banner
|
|
77
|
+
while it works. When stdout isn't a TTY (piped through another script, CI,
|
|
78
|
+
`TERM=dumb`, or `NO_COLOR` set), it skips the globe and stays to plain
|
|
79
|
+
`oracle-install: ...` log lines instead. Set `ORACLE_INSTALL_PLAIN=1` to force
|
|
80
|
+
the plain form even on an interactive terminal.
|
|
81
|
+
|
|
76
82
|
npm still works if you prefer:
|
|
77
83
|
|
|
78
84
|
```bash
|
|
@@ -108,7 +114,7 @@ model. Use `--no-browser` when the browser must be opened manually.
|
|
|
108
114
|
|
|
109
115
|
```bash
|
|
110
116
|
oracle setup model openrouter
|
|
111
|
-
# also supported: openai, anthropic, xai, deepseek, gemini, kimi, mistral, custom
|
|
117
|
+
# also supported: openai, anthropic, xai, deepseek, gemini, kimi, mistral, nous, custom
|
|
112
118
|
```
|
|
113
119
|
|
|
114
120
|
Interactive API-key entry is hidden. Do not put a key directly in the command
|
|
@@ -135,6 +141,17 @@ available, with a private `0600` local fallback.
|
|
|
135
141
|
oracle
|
|
136
142
|
```
|
|
137
143
|
|
|
144
|
+
On a fresh TTY, the first `oracle`/`oracle chat` run walks through, in order:
|
|
145
|
+
|
|
146
|
+
1. Model setup (`oracle setup model`) if no provider is configured yet —
|
|
147
|
+
OAuth first (`claude`, `codex`, `grok`), then API-key providers.
|
|
148
|
+
2. The onboarding splash: a welcome panel with the orb, Enter opens the
|
|
149
|
+
chain picker, arrow keys + Enter select a chain (Esc skips at either
|
|
150
|
+
screen), then a ready card. It shows once per install and is marked done
|
|
151
|
+
under `ORACLE_CONFIG_DIR`; `ORACLE_ONBOARDING=0` skips it, `oracle chat
|
|
152
|
+
--onboard` replays it.
|
|
153
|
+
3. Chat itself.
|
|
154
|
+
|
|
138
155
|
Useful first commands:
|
|
139
156
|
|
|
140
157
|
```bash
|
|
@@ -146,9 +163,18 @@ oracle doctor
|
|
|
146
163
|
|
|
147
164
|
Inside chat:
|
|
148
165
|
|
|
166
|
+
- `/sessions`, `/new [title]`, `/1`–`/9`, `/resume [n]`, `/session rm <n>` —
|
|
167
|
+
manage numbered chat sessions.
|
|
149
168
|
- `/chain` lists or selects the active chain.
|
|
150
169
|
- `/model` changes the model without changing the Oracle persona.
|
|
151
170
|
- `/setup` opens optional messaging setup.
|
|
171
|
+
- `/help` lists every in-chat command.
|
|
172
|
+
|
|
173
|
+
Chat always runs on Oracle's own native loop unless you explicitly opt into
|
|
174
|
+
Hermes with `ORACLE_CHAT_BACKEND=hermes` (or `oracle chat --backend
|
|
175
|
+
hermes`); the default `auto` resolution never selects Hermes on its own, and
|
|
176
|
+
an explicit `hermes` request fails closed with an actionable error if Hermes
|
|
177
|
+
isn't actually detected.
|
|
152
178
|
|
|
153
179
|
A model response is not authorization, a prepared object is not a transaction,
|
|
154
180
|
and a submitted transaction is not a confirmed receipt.
|
|
@@ -97,7 +97,7 @@ does not prove npm users receive it. A locally hosted model/data/policy loop doe
|
|
|
97
97
|
a bundled signer. A merged feature is not public until the npm artifact containing it is
|
|
98
98
|
published and inspected.
|
|
99
99
|
|
|
100
|
-
**Candidate release in this source tree:** public package `@oracle-agent/oracle@0.
|
|
100
|
+
**Candidate release in this source tree:** public package `@oracle-agent/oracle@0.28.1`
|
|
101
101
|
ships the encrypted local vault + short-lived loopback signer. Hosted/keyless
|
|
102
102
|
Oracle cannot hold keys or move funds. Self-host after `oracle sign init|import` is **auto-armed**
|
|
103
103
|
for user-initiated actions. Public still charges the disclosed fee card; Administrator
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var re=Object.defineProperty;var l=(e,o,r)=>()=>{if(r)throw r[0];try{return e&&(o=e(e=0)),o}catch(t){throw r=[t],t}};var y=(e,o)=>{for(var r in o)re(e,r,{get:o[r],enumerable:!0})};import _ from"node:fs";import te from"node:os";import m from"node:path";import{fileURLToPath as oe}from"node:url";function b(){return process.env.ORACLE_FAKE_HOME||te.homedir()}function ae(){return process.env.ORACLE_PUBLIC_DESKTOP==="1"}function S(){return ae()?process.env.ORACLE_CONFIG_DIR||m.join(b(),".config","oracle"):m.join(b(),".config","oracle")}function se(){return m.join(S(),"desk.json")}function ie(){return m.join(S(),"env")}function f({force:e=!1}={}){if(f._done&&!e)return f._result||null;f._done=!0;let o={},r=(n,a)=>{if(a==null)return;let s=String(a).trim();s&&(process.env[n]!=null&&String(process.env[n]).trim()!==""||(process.env[n]=s,o[n]=s))};try{let n=ie();if(_.existsSync(n))for(let a of _.readFileSync(n,"utf8").split(/\r?\n/)){let s=a.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);if(!s||s[2].startsWith("#"))continue;let i=s[2];(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'"))&&(i=i.slice(1,-1)),r(s[1],i)}}catch{}try{let n=se();if(_.existsSync(n)){let a=JSON.parse(_.readFileSync(n,"utf8"));a&&typeof a=="object"&&(r("ORACLE_DESK_URL",a.deskUrl||a.dataUrl||a.url),r("ORACLE_DATA_URL",a.dataUrl||a.deskUrl||a.url),r("ORACLE_API_URL",a.apiUrl||a.dataUrl||a.deskUrl),r("ORACLE_PUBLIC_URL",a.publicUrl||a.deskUrl||a.dataUrl),r("ORACLE_EXEC_URL",a.execUrl),r("MAD_DESK_URL",a.deskUrl||a.dataUrl))}}catch{}let t=process.env.ORACLE_DESK_URL||process.env.ORACLE_DATA_URL||"";return t&&(r("ORACLE_DESK_URL",t),r("ORACLE_DATA_URL",t),r("ORACLE_API_URL",t),r("ORACLE_PUBLIC_URL",t),r("MAD_DESK_URL",t)),f._result=Object.keys(o).length?o:null,f._result}var ne,sr,k=l(()=>{ne=m.dirname(oe(import.meta.url)),sr=m.resolve(ne,"../..");try{f()}catch{}});function E(e){return String(e||"").trim()||void 0}function le(e,{required:o=!1}={}){let r=E(e)?.toLowerCase();if(!r){if(o)throw new Error("model provider is required");return}if(!ce.has(r))throw new Error(`unsupported provider: ${r}`);return r}function de(e,{required:o=!1}={}){let r=E(e);if(!r){if(o)throw new Error("model is required");return}if(r.includes("..")||r.startsWith("/")||!/^[a-zA-Z0-9._:/-]{1,200}$/.test(r))throw new Error("invalid model id");return r}function pe(e){let o=E(e);if(!o||o.length>2048)throw new Error("invalid custom base URL");let r;try{r=new URL(o)}catch{throw new Error("invalid custom base URL")}let t=r.hostname.toLowerCase().replace(/^\[|\]$/g,""),n=t==="localhost"||t==="127.0.0.1"||t==="::1";if(r.protocol!=="https:"&&!(r.protocol==="http:"&&n)||r.username||r.password||r.search||r.hash)throw new Error("custom base URL must use HTTPS or loopback HTTP without credentials, query, or fragment");return r.toString().replace(/\/+$/,"")}function L({provider:e,model:o,baseUrl:r}={},{requireModel:t=!1}={}){let n=le(e),a=de(o,{required:t});if(n==="custom")return{provider:n,...a?{model:a}:{},baseUrl:pe(r)};if(E(r))throw new Error("baseUrl is only supported for the custom provider");return{...n?{provider:n}:{},...a?{model:a}:{}}}var ce,x=l(()=>{ce=new Set(["openrouter","openai","anthropic","xai","deepseek","gemini","kimi","mistral","custom","anthropic-oauth","openai-codex","xai-oauth"])});import U from"node:fs";import ue from"node:path";function me(){return ue.join(S(),"model.json")}function h(e){return String(e||"").trim()||void 0}function he(e={}){let o=h(e.backend)?.toLowerCase()||"auto",r=L({provider:e.provider,model:e.model,baseUrl:e.baseUrl},{requireModel:o==="standalone"}),t=h(e.apiKeyEnv),n=Number.parseInt(String(e.contextLength||""),10),a=h(e.reasoningEffort),s=h(e.computeHost||e.remoteHost),i=h(e.computeUser||e.remoteUser),c=h(e.computePath||e.remotePath);if(!fe.has(o))throw new Error(`unsupported backend: ${o}`);if(process.env.ORACLE_PUBLIC_DESKTOP==="1"&&["remote","arch"].includes(o))throw new Error("remote compute backends are disabled in the public desktop");if(t&&!/^[A-Z][A-Z0-9_]*$/.test(t))throw new Error("api key env must be an uppercase environment variable name");if(o==="remote"&&!s)throw new Error("remote backend requires computeHost");return{backend:o,...r,...t?{apiKeyEnv:t}:{},...Number.isFinite(n)&&n>0?{contextLength:n}:{},...a?{reasoningEffort:a}:{},...s?{computeHost:s}:{},...i?{computeUser:i}:{},...c?{computePath:c}:{}}}function $(){let e=me();if(!U.existsSync(e))return null;try{return he(JSON.parse(U.readFileSync(e,"utf8")))}catch{return null}}var fe,j=l(()=>{k();x();fe=new Set(["auto","standalone","hermes","remote","arch"])});import{execFile as we}from"node:child_process";import{existsSync as ge,mkdirSync as ye,readFileSync as P,realpathSync as _e,writeFileSync as Se}from"node:fs";import d from"node:path";import{promisify as Ee}from"node:util";import{fileURLToPath as I}from"node:url";function Ae(e=import.meta.url){try{let o=_e(I(e)),r=`${d.sep}node_modules${d.sep}`,t=o.lastIndexOf(r);if(t>0)return{root:o.slice(0,t),managed:!0}}catch{}return{root:null,managed:!1}}function v(e=import.meta.url){try{let o=d.dirname(I(e));for(let r=0;r<8;r+=1){let t=d.join(o,"package.json");if(ge(t)){let a=JSON.parse(P(t,"utf8"));if(a?.name===A&&a.version)return a.version}let n=d.dirname(o);if(n===o)break;o=n}}catch{return null}return null}function ve(e,o){let r=a=>String(a).replace(/^v/,"").split("-")[0].split(".").map(s=>Number.parseInt(s,10)||0),t=r(e),n=r(o);for(let a=0;a<Math.max(t.length,n.length);a+=1){let s=t[a]??0,i=n[a]??0;if(s>i)return 1;if(s<i)return-1}return 0}function D(e){let o=e?.stateDir||d.join(process.env.HOME||".",".oracle");return d.join(o,"update-check.json")}function be(e){try{return JSON.parse(P(D(e),"utf8"))}catch{return null}}function ke(e,o){try{let r=D(e);ye(d.dirname(r),{recursive:!0}),Se(r,`${JSON.stringify(o,null,2)}
|
|
2
|
+
var re=Object.defineProperty;var l=(e,o,r)=>()=>{if(r)throw r[0];try{return e&&(o=e(e=0)),o}catch(t){throw r=[t],t}};var y=(e,o)=>{for(var r in o)re(e,r,{get:o[r],enumerable:!0})};import _ from"node:fs";import te from"node:os";import m from"node:path";import{fileURLToPath as oe}from"node:url";function b(){return process.env.ORACLE_FAKE_HOME||te.homedir()}function ae(){return process.env.ORACLE_PUBLIC_DESKTOP==="1"}function S(){return ae()?process.env.ORACLE_CONFIG_DIR||m.join(b(),".config","oracle"):m.join(b(),".config","oracle")}function se(){return m.join(S(),"desk.json")}function ie(){return m.join(S(),"env")}function f({force:e=!1}={}){if(f._done&&!e)return f._result||null;f._done=!0;let o={},r=(n,a)=>{if(a==null)return;let s=String(a).trim();s&&(process.env[n]!=null&&String(process.env[n]).trim()!==""||(process.env[n]=s,o[n]=s))};try{let n=ie();if(_.existsSync(n))for(let a of _.readFileSync(n,"utf8").split(/\r?\n/)){let s=a.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);if(!s||s[2].startsWith("#"))continue;let i=s[2];(i.startsWith('"')&&i.endsWith('"')||i.startsWith("'")&&i.endsWith("'"))&&(i=i.slice(1,-1)),r(s[1],i)}}catch{}try{let n=se();if(_.existsSync(n)){let a=JSON.parse(_.readFileSync(n,"utf8"));a&&typeof a=="object"&&(r("ORACLE_DESK_URL",a.deskUrl||a.dataUrl||a.url),r("ORACLE_DATA_URL",a.dataUrl||a.deskUrl||a.url),r("ORACLE_API_URL",a.apiUrl||a.dataUrl||a.deskUrl),r("ORACLE_PUBLIC_URL",a.publicUrl||a.deskUrl||a.dataUrl),r("ORACLE_EXEC_URL",a.execUrl),r("MAD_DESK_URL",a.deskUrl||a.dataUrl))}}catch{}let t=process.env.ORACLE_DESK_URL||process.env.ORACLE_DATA_URL||"";return t&&(r("ORACLE_DESK_URL",t),r("ORACLE_DATA_URL",t),r("ORACLE_API_URL",t),r("ORACLE_PUBLIC_URL",t),r("MAD_DESK_URL",t)),f._result=Object.keys(o).length?o:null,f._result}var ne,sr,k=l(()=>{ne=m.dirname(oe(import.meta.url)),sr=m.resolve(ne,"../..");try{f()}catch{}});function E(e){return String(e||"").trim()||void 0}function le(e,{required:o=!1}={}){let r=E(e)?.toLowerCase();if(!r){if(o)throw new Error("model provider is required");return}if(!ce.has(r))throw new Error(`unsupported provider: ${r}`);return r}function de(e,{required:o=!1}={}){let r=E(e);if(!r){if(o)throw new Error("model is required");return}if(r.includes("..")||r.startsWith("/")||!/^[a-zA-Z0-9._:/-]{1,200}$/.test(r))throw new Error("invalid model id");return r}function pe(e){let o=E(e);if(!o||o.length>2048)throw new Error("invalid custom base URL");let r;try{r=new URL(o)}catch{throw new Error("invalid custom base URL")}let t=r.hostname.toLowerCase().replace(/^\[|\]$/g,""),n=t==="localhost"||t==="127.0.0.1"||t==="::1";if(r.protocol!=="https:"&&!(r.protocol==="http:"&&n)||r.username||r.password||r.search||r.hash)throw new Error("custom base URL must use HTTPS or loopback HTTP without credentials, query, or fragment");return r.toString().replace(/\/+$/,"")}function L({provider:e,model:o,baseUrl:r}={},{requireModel:t=!1}={}){let n=le(e),a=de(o,{required:t});if(n==="custom")return{provider:n,...a?{model:a}:{},baseUrl:pe(r)};if(E(r))throw new Error("baseUrl is only supported for the custom provider");return{...n?{provider:n}:{},...a?{model:a}:{}}}var ce,x=l(()=>{ce=new Set(["openrouter","openai","anthropic","xai","deepseek","gemini","kimi","mistral","nous","custom","anthropic-oauth","openai-codex","xai-oauth"])});import U from"node:fs";import ue from"node:path";function me(){return ue.join(S(),"model.json")}function h(e){return String(e||"").trim()||void 0}function he(e={}){let o=h(e.backend)?.toLowerCase()||"auto",r=L({provider:e.provider,model:e.model,baseUrl:e.baseUrl},{requireModel:o==="standalone"}),t=h(e.apiKeyEnv),n=Number.parseInt(String(e.contextLength||""),10),a=h(e.reasoningEffort),s=h(e.computeHost||e.remoteHost),i=h(e.computeUser||e.remoteUser),c=h(e.computePath||e.remotePath);if(!fe.has(o))throw new Error(`unsupported backend: ${o}`);if(process.env.ORACLE_PUBLIC_DESKTOP==="1"&&["remote","arch"].includes(o))throw new Error("remote compute backends are disabled in the public desktop");if(t&&!/^[A-Z][A-Z0-9_]*$/.test(t))throw new Error("api key env must be an uppercase environment variable name");if(o==="remote"&&!s)throw new Error("remote backend requires computeHost");return{backend:o,...r,...t?{apiKeyEnv:t}:{},...Number.isFinite(n)&&n>0?{contextLength:n}:{},...a?{reasoningEffort:a}:{},...s?{computeHost:s}:{},...i?{computeUser:i}:{},...c?{computePath:c}:{}}}function $(){let e=me();if(!U.existsSync(e))return null;try{return he(JSON.parse(U.readFileSync(e,"utf8")))}catch{return null}}var fe,j=l(()=>{k();x();fe=new Set(["auto","standalone","hermes","remote","arch"])});import{execFile as we}from"node:child_process";import{existsSync as ge,mkdirSync as ye,readFileSync as P,realpathSync as _e,writeFileSync as Se}from"node:fs";import d from"node:path";import{promisify as Ee}from"node:util";import{fileURLToPath as I}from"node:url";function Ae(e=import.meta.url){try{let o=_e(I(e)),r=`${d.sep}node_modules${d.sep}`,t=o.lastIndexOf(r);if(t>0)return{root:o.slice(0,t),managed:!0}}catch{}return{root:null,managed:!1}}function v(e=import.meta.url){try{let o=d.dirname(I(e));for(let r=0;r<8;r+=1){let t=d.join(o,"package.json");if(ge(t)){let a=JSON.parse(P(t,"utf8"));if(a?.name===A&&a.version)return a.version}let n=d.dirname(o);if(n===o)break;o=n}}catch{return null}return null}function ve(e,o){let r=a=>String(a).replace(/^v/,"").split("-")[0].split(".").map(s=>Number.parseInt(s,10)||0),t=r(e),n=r(o);for(let a=0;a<Math.max(t.length,n.length);a+=1){let s=t[a]??0,i=n[a]??0;if(s>i)return 1;if(s<i)return-1}return 0}function D(e){let o=e?.stateDir||d.join(process.env.HOME||".",".oracle");return d.join(o,"update-check.json")}function be(e){try{return JSON.parse(P(D(e),"utf8"))}catch{return null}}function ke(e,o){try{let r=D(e);ye(d.dirname(r),{recursive:!0}),Se(r,`${JSON.stringify(o,null,2)}
|
|
3
3
|
`)}catch{}}async function Le({timeoutMs:e=4e3}={}){try{let o=new AbortController,r=setTimeout(()=>o.abort(),e),t=await fetch(`${Oe}/${encodeURIComponent(A)}/latest`,{signal:o.signal});return clearTimeout(r),t.ok&&(await t.json())?.version||null}catch{return null}}async function N({paths:e,force:o=!1,timeoutMs:r=4e3}={}){let t=v(),n=o?null:be(e),s=n&&Date.now()-(n.checkedAt||0)<Re?n.latest:null;return s||(s=await Le({timeoutMs:r}),s&&ke(e,{latest:s,checkedAt:Date.now()})),!t||!s?{current:t,latest:s,updateAvailable:!1,checked:!!s}:{current:t,latest:s,updateAvailable:ve(s,t)>0,checked:!0}}async function T({version:e="latest",dryRun:o=!1}={}){let{root:r,managed:t}=Ae();if(!t||!r)return{ok:!1,reason:"unmanaged",message:`oracle is not running from a resolvable node_modules tree (source checkout or linked dev install).
|
|
4
4
|
Update it the same way you installed it \u2014 git pull, or npm install -g @oracle-agent/oracle@latest.`};let n=`${A}@${e}`,a=["install","--prefix",r,"--no-audit","--no-fund",n];if(o)return{ok:!0,dryRun:!0,root:r,command:`npm ${a.join(" ")}`};try{let{stdout:s,stderr:i}=await Ce("npm",a,{timeout:3e5,maxBuffer:16777216});return{ok:!0,root:r,stdout:s,stderr:i}}catch(s){return{ok:!1,reason:"npm-failed",root:r,message:s?.stderr||s?.message||"npm install failed"}}}var Ce,A,Oe,Re,M=l(()=>{Ce=Ee(we),A="@oracle-agent/oracle",Oe="https://registry.npmjs.org",Re=1440*60*1e3});import{spawn as xe}from"node:child_process";import{join as F}from"node:path";import{homedir as G}from"node:os";function je(e,o=process.env){let r=String(o[`ORACLE_OWNER_${String(e).toUpperCase()}`]||""),t=String(o.ORACLE_OWNER_IDS||"");return new Set(`${r},${t}`.split(",").map(n=>n.trim()).filter(Boolean))}function C({platform:e,senderId:o},r=process.env){let t=String(o||"").trim();return t?je(e,r).has(t):!1}function Pe(e){let o=String(e||"").trim();if(!o)return null;let r=o.replace(/^\/update(?:@[\w_]+)?\b/i,"update");return/^(?:oracle\s+)?update\s+--check\s*$/i.test(r)?{checkOnly:!0}:/^(?:oracle\s+)?update\s*$/i.test(r)?{checkOnly:!1}:null}async function Ie(e,{check:o=N,update:r=T,versionOf:t=v}={}){let n=await o({force:!0});if(e.checkOnly)return n.checked?n.updateAvailable?`oracle ${n.current} \u2192 ${n.latest} available. Send /update to install.`:`oracle ${n.current} is up to date`:`oracle ${n.current||"?"} \u2014 could not reach npm`;if(n.checked&&!n.updateAvailable)return`oracle ${n.current} is already up to date`;let a=n.latest||"latest",s=await r({version:a==="latest"?"latest":a});if(!s.ok)return`oracle update failed: ${s.message}`;let i=t();return[`oracle ${n.current||"?"} \u2192 ${i||a}`,"Restart the gateway to load it: oracle gateway"].join(`
|
|
5
5
|
`)}function De(e={}){return!!(e.forwarded||e.forward_from||e.forward_from_chat||e.forward_origin||e.forward_sender_name||e.forward_date)}function Ne({readConfig:e=$}={}){let o=e();return o?o.backend==="hermes"?{ok:!1,error:"model config delegates to hermes; the gateway runs Oracle's native loop. Set a standalone backend: oracle model --backend standalone"}:o.model?{ok:!0,provider:o.provider,model:o.model}:{ok:!1,error:"model config has no model \u2014 run: oracle model --backend standalone --provider <p> --model <m>"}:{ok:!1,error:"gateway has no model configured \u2014 run: oracle model --backend standalone --provider <p> --model <m>"}}async function u({platform:e,chatId:o,senderId:r,text:t,userName:n,meta:a={},updater:s}={}){if(!C({platform:e,senderId:r}))return process.stderr.write(`gateway: denied non-owner sender ${e}:${String(r||"unknown")}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import T from"node:fs";import F from"node:path";import j from"node:fs";import pe from"node:os";import O from"node:path";import{fileURLToPath as le}from"node:url";var fe=O.dirname(le(import.meta.url)),Ve=O.resolve(fe,"../..");function X(){return process.env.ORACLE_FAKE_HOME||pe.homedir()}function he(){return process.env.ORACLE_PUBLIC_DESKTOP==="1"}function b(){return he()?process.env.ORACLE_CONFIG_DIR||O.join(X(),".config","oracle"):O.join(X(),".config","oracle")}function me(){return O.join(b(),"desk.json")}function we(){return O.join(b(),"env")}function E({force:e=!1}={}){if(E._done&&!e)return E._result||null;E._done=!0;let t={},r=(n,i)=>{if(i==null)return;let s=String(i).trim();s&&(process.env[n]!=null&&String(process.env[n]).trim()!==""||(process.env[n]=s,t[n]=s))};try{let n=we();if(j.existsSync(n))for(let i of j.readFileSync(n,"utf8").split(/\r?\n/)){let s=i.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);if(!s||s[2].startsWith("#"))continue;let p=s[2];(p.startsWith('"')&&p.endsWith('"')||p.startsWith("'")&&p.endsWith("'"))&&(p=p.slice(1,-1)),r(s[1],p)}}catch{}try{let n=me();if(j.existsSync(n)){let i=JSON.parse(j.readFileSync(n,"utf8"));i&&typeof i=="object"&&(r("ORACLE_DESK_URL",i.deskUrl||i.dataUrl||i.url),r("ORACLE_DATA_URL",i.dataUrl||i.deskUrl||i.url),r("ORACLE_API_URL",i.apiUrl||i.dataUrl||i.deskUrl),r("ORACLE_PUBLIC_URL",i.publicUrl||i.deskUrl||i.dataUrl),r("ORACLE_EXEC_URL",i.execUrl),r("MAD_DESK_URL",i.deskUrl||i.dataUrl))}}catch{}let o=process.env.ORACLE_DESK_URL||process.env.ORACLE_DATA_URL||"";return o&&(r("ORACLE_DESK_URL",o),r("ORACLE_DATA_URL",o),r("ORACLE_API_URL",o),r("ORACLE_PUBLIC_URL",o),r("MAD_DESK_URL",o)),E._result=Object.keys(t).length?t:null,E._result}try{E()}catch{}function $(e){return j.mkdirSync(e,{recursive:!0}),e}var ge=new Set(["openrouter","openai","anthropic","xai","deepseek","gemini","kimi","mistral","custom","anthropic-oauth","openai-codex","xai-oauth"]);function I(e){return String(e||"").trim()||void 0}function ye(e,{required:t=!1}={}){let r=I(e)?.toLowerCase();if(!r){if(t)throw new Error("model provider is required");return}if(!ge.has(r))throw new Error(`unsupported provider: ${r}`);return r}function ve(e,{required:t=!1}={}){let r=I(e);if(!r){if(t)throw new Error("model is required");return}if(r.includes("..")||r.startsWith("/")||!/^[a-zA-Z0-9._:/-]{1,200}$/.test(r))throw new Error("invalid model id");return r}function ke(e){let t=I(e);if(!t||t.length>2048)throw new Error("invalid custom base URL");let r;try{r=new URL(t)}catch{throw new Error("invalid custom base URL")}let o=r.hostname.toLowerCase().replace(/^\[|\]$/g,""),n=o==="localhost"||o==="127.0.0.1"||o==="::1";if(r.protocol!=="https:"&&!(r.protocol==="http:"&&n)||r.username||r.password||r.search||r.hash)throw new Error("custom base URL must use HTTPS or loopback HTTP without credentials, query, or fragment");return r.toString().replace(/\/+$/,"")}function L({provider:e,model:t,baseUrl:r}={},{requireModel:o=!1}={}){let n=ye(e),i=ve(t,{required:o});if(n==="custom")return{provider:n,...i?{model:i}:{},baseUrl:ke(r)};if(I(r))throw new Error("baseUrl is only supported for the custom provider");return{...n?{provider:n}:{},...i?{model:i}:{}}}var xe=new Set(["auto","standalone","hermes","remote","arch"]);function _e(){return F.join(b(),"model.json")}function P(e){return String(e||"").trim()||void 0}function Ae(e={}){let t=P(e.backend)?.toLowerCase()||"auto",r=L({provider:e.provider,model:e.model,baseUrl:e.baseUrl},{requireModel:t==="standalone"}),o=P(e.apiKeyEnv),n=Number.parseInt(String(e.contextLength||""),10),i=P(e.reasoningEffort),s=P(e.computeHost||e.remoteHost),p=P(e.computeUser||e.remoteUser),u=P(e.computePath||e.remotePath);if(!xe.has(t))throw new Error(`unsupported backend: ${t}`);if(process.env.ORACLE_PUBLIC_DESKTOP==="1"&&["remote","arch"].includes(t))throw new Error("remote compute backends are disabled in the public desktop");if(o&&!/^[A-Z][A-Z0-9_]*$/.test(o))throw new Error("api key env must be an uppercase environment variable name");if(t==="remote"&&!s)throw new Error("remote backend requires computeHost");return{backend:t,...r,...o?{apiKeyEnv:o}:{},...Number.isFinite(n)&&n>0?{contextLength:n}:{},...i?{reasoningEffort:i}:{},...s?{computeHost:s}:{},...p?{computeUser:p}:{},...u?{computePath:u}:{}}}function Z(e){let t=Ae(e),r=_e();$(F.dirname(r)),process.platform!=="win32"&&T.chmodSync(F.dirname(r),448);let o=`${r}.${process.pid}.tmp`;return T.writeFileSync(o,`${JSON.stringify(t,null,2)}
|
|
1
|
+
import T from"node:fs";import F from"node:path";import j from"node:fs";import pe from"node:os";import O from"node:path";import{fileURLToPath as le}from"node:url";var fe=O.dirname(le(import.meta.url)),Ve=O.resolve(fe,"../..");function X(){return process.env.ORACLE_FAKE_HOME||pe.homedir()}function he(){return process.env.ORACLE_PUBLIC_DESKTOP==="1"}function b(){return he()?process.env.ORACLE_CONFIG_DIR||O.join(X(),".config","oracle"):O.join(X(),".config","oracle")}function me(){return O.join(b(),"desk.json")}function we(){return O.join(b(),"env")}function E({force:e=!1}={}){if(E._done&&!e)return E._result||null;E._done=!0;let t={},r=(n,i)=>{if(i==null)return;let s=String(i).trim();s&&(process.env[n]!=null&&String(process.env[n]).trim()!==""||(process.env[n]=s,t[n]=s))};try{let n=we();if(j.existsSync(n))for(let i of j.readFileSync(n,"utf8").split(/\r?\n/)){let s=i.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*?)\s*$/);if(!s||s[2].startsWith("#"))continue;let p=s[2];(p.startsWith('"')&&p.endsWith('"')||p.startsWith("'")&&p.endsWith("'"))&&(p=p.slice(1,-1)),r(s[1],p)}}catch{}try{let n=me();if(j.existsSync(n)){let i=JSON.parse(j.readFileSync(n,"utf8"));i&&typeof i=="object"&&(r("ORACLE_DESK_URL",i.deskUrl||i.dataUrl||i.url),r("ORACLE_DATA_URL",i.dataUrl||i.deskUrl||i.url),r("ORACLE_API_URL",i.apiUrl||i.dataUrl||i.deskUrl),r("ORACLE_PUBLIC_URL",i.publicUrl||i.deskUrl||i.dataUrl),r("ORACLE_EXEC_URL",i.execUrl),r("MAD_DESK_URL",i.deskUrl||i.dataUrl))}}catch{}let o=process.env.ORACLE_DESK_URL||process.env.ORACLE_DATA_URL||"";return o&&(r("ORACLE_DESK_URL",o),r("ORACLE_DATA_URL",o),r("ORACLE_API_URL",o),r("ORACLE_PUBLIC_URL",o),r("MAD_DESK_URL",o)),E._result=Object.keys(t).length?t:null,E._result}try{E()}catch{}function $(e){return j.mkdirSync(e,{recursive:!0}),e}var ge=new Set(["openrouter","openai","anthropic","xai","deepseek","gemini","kimi","mistral","nous","custom","anthropic-oauth","openai-codex","xai-oauth"]);function I(e){return String(e||"").trim()||void 0}function ye(e,{required:t=!1}={}){let r=I(e)?.toLowerCase();if(!r){if(t)throw new Error("model provider is required");return}if(!ge.has(r))throw new Error(`unsupported provider: ${r}`);return r}function ve(e,{required:t=!1}={}){let r=I(e);if(!r){if(t)throw new Error("model is required");return}if(r.includes("..")||r.startsWith("/")||!/^[a-zA-Z0-9._:/-]{1,200}$/.test(r))throw new Error("invalid model id");return r}function ke(e){let t=I(e);if(!t||t.length>2048)throw new Error("invalid custom base URL");let r;try{r=new URL(t)}catch{throw new Error("invalid custom base URL")}let o=r.hostname.toLowerCase().replace(/^\[|\]$/g,""),n=o==="localhost"||o==="127.0.0.1"||o==="::1";if(r.protocol!=="https:"&&!(r.protocol==="http:"&&n)||r.username||r.password||r.search||r.hash)throw new Error("custom base URL must use HTTPS or loopback HTTP without credentials, query, or fragment");return r.toString().replace(/\/+$/,"")}function L({provider:e,model:t,baseUrl:r}={},{requireModel:o=!1}={}){let n=ye(e),i=ve(t,{required:o});if(n==="custom")return{provider:n,...i?{model:i}:{},baseUrl:ke(r)};if(I(r))throw new Error("baseUrl is only supported for the custom provider");return{...n?{provider:n}:{},...i?{model:i}:{}}}var xe=new Set(["auto","standalone","hermes","remote","arch"]);function _e(){return F.join(b(),"model.json")}function P(e){return String(e||"").trim()||void 0}function Ae(e={}){let t=P(e.backend)?.toLowerCase()||"auto",r=L({provider:e.provider,model:e.model,baseUrl:e.baseUrl},{requireModel:t==="standalone"}),o=P(e.apiKeyEnv),n=Number.parseInt(String(e.contextLength||""),10),i=P(e.reasoningEffort),s=P(e.computeHost||e.remoteHost),p=P(e.computeUser||e.remoteUser),u=P(e.computePath||e.remotePath);if(!xe.has(t))throw new Error(`unsupported backend: ${t}`);if(process.env.ORACLE_PUBLIC_DESKTOP==="1"&&["remote","arch"].includes(t))throw new Error("remote compute backends are disabled in the public desktop");if(o&&!/^[A-Z][A-Z0-9_]*$/.test(o))throw new Error("api key env must be an uppercase environment variable name");if(t==="remote"&&!s)throw new Error("remote backend requires computeHost");return{backend:t,...r,...o?{apiKeyEnv:o}:{},...Number.isFinite(n)&&n>0?{contextLength:n}:{},...i?{reasoningEffort:i}:{},...s?{computeHost:s}:{},...p?{computeUser:p}:{},...u?{computePath:u}:{}}}function Z(e){let t=Ae(e),r=_e();$(F.dirname(r)),process.platform!=="win32"&&T.chmodSync(F.dirname(r),448);let o=`${r}.${process.pid}.tmp`;return T.writeFileSync(o,`${JSON.stringify(t,null,2)}
|
|
2
2
|
`,{mode:384}),T.renameSync(o,r),process.platform!=="win32"&&T.chmodSync(r,384),t}import{createHash as Se,randomBytes as N,timingSafeEqual as Ee}from"node:crypto";import g from"node:fs";import k from"node:path";import Oe from"node:readline/promises";import{spawn as be,spawnSync as Pe}from"node:child_process";var R=Object.freeze({"anthropic-oauth":{aliases:["anthropic-oauth","anthropic","claude","claude-oauth"],clientId:"9d1c250a-e61b-44d9-88ed-5944d1962f5e",authorizeUrl:"https://claude.ai/oauth/authorize",tokenUrl:"https://platform.claude.com/v1/oauth/token",redirectUri:"https://console.anthropic.com/oauth/code/callback",scope:"org:create_api_key user:profile user:inference",baseUrl:"https://api.anthropic.com/v1",model:"claude-sonnet-4-6",protocol:"anthropic-messages"},"openai-codex":{aliases:["openai-codex","openai-oauth","codex","codex-oauth"],clientId:"app_EMoamEEZ73f0CkXaXp7hrann",issuer:"https://auth.openai.com",tokenUrl:"https://auth.openai.com/oauth/token",baseUrl:"https://chatgpt.com/backend-api/codex",model:"gpt-5.6-sol",protocol:"responses"},"xai-oauth":{aliases:["xai-oauth","xai","grok","grok-oauth"],clientId:"b1a00492-073a-47ea-816f-4c329264a828",issuer:"https://auth.x.ai",discoveryUrl:"https://auth.x.ai/.well-known/openid-configuration",deviceUrl:"https://auth.x.ai/oauth2/device/code",scope:"openid profile email offline_access grok-cli:access api:access",baseUrl:"https://api.x.ai/v1",model:"grok-4.6",protocol:"responses"}}),Ce=12e4;function Re(e={}){return typeof e.now=="function"?Number(e.now()):Date.now()}function _(e){let t=String(e||"").trim().toLowerCase();for(let[r,o]of Object.entries(R))if(o.aliases.includes(t))return r;throw new Error(`unsupported OAuth provider: ${e||"(empty)"}`)}function Y(e){let t=_(e);return{id:t,...R[t]}}function m(e,t={}){if(!g.existsSync(e))return t;try{let r=JSON.parse(g.readFileSync(e,"utf8"));if(!r||typeof r!="object"||Array.isArray(r))throw new Error("invalid object");return r}catch{throw new Error(`credential store is unreadable or corrupt: ${k.basename(e)}`)}}function Q(e){$(e),process.platform!=="win32"&&g.chmodSync(e,448)}function x(e,t){Q(k.dirname(e));let r=`${e}.${process.pid}.${N(4).toString("hex")}.tmp`;g.writeFileSync(r,`${JSON.stringify(t,null,2)}
|
|
3
3
|
`,{mode:384}),g.renameSync(r,e),process.platform!=="win32"&&g.chmodSync(e,384)}function Ue(e){if(process.platform!=="linux")return!1;let t=e("secret-tool",["--version"],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return!t.error&&t.status===0}function D(e){let t=String(e||"").trim().toLowerCase();if(!/^[a-z0-9][a-z0-9._-]*$/.test(t))throw new Error(`invalid API-key provider: ${e||"(empty)"}`);return t}function C(e={}){let t=String(e.accessToken||e.access_token||"").trim(),r=String(e.refreshToken||e.refresh_token||"").trim(),o=Number(e.expiresAt||e.expires_at||0);if(Number.isFinite(o)&&o>=1e9&&o<1e12&&(o=o*1e3),!t)throw new Error("OAuth credential is missing access token");return{accessToken:t,refreshToken:r,expiresAt:Number.isFinite(o)?o:0,tokenType:String(e.tokenType||e.token_type||"Bearer"),source:String(e.source||"oracle"),...e.discovery?{discovery:e.discovery}:{},...e.scope?{scope:e.scope}:{},...e.idToken||e.id_token?{idToken:String(e.idToken||e.id_token)}:{}}}function je(e={}){let t=e.file||k.join(b(),"oauth.json"),r=e.metadataFile||k.join(k.dirname(t),"oauth-meta.json"),o=e.linksFile||k.join(k.dirname(t),"oauth-links.json"),n=()=>typeof e.now=="function"?Number(e.now()):Date.now(),i=e.spawnFn||Pe,s=e.keychain!==!1&&process.env.ORACLE_AUTH_FILE_STORE!=="1"&&Ue(i),p=s?"linux-secret-service":"private-file",u=`${t}.lock`;async function v(f){Q(k.dirname(u));let l;for(let c=0;c<400;c+=1)try{l=g.openSync(u,"wx",384);break}catch(a){if(a?.code!=="EEXIST")throw a;try{Date.now()-g.statSync(u).mtimeMs>3e5&&g.unlinkSync(u)}catch{}await new Promise(d=>setTimeout(d,25))}if(l===void 0)throw new Error("timed out waiting for OAuth credential lock");try{return await f()}finally{try{g.closeSync(l)}catch{}try{g.unlinkSync(u)}catch{}}}function w(f,l="oauth"){return["application","oracle","kind",l,"provider",f]}function U(f){if(!g.existsSync(o))return null;let c=m(o,{providers:{}}).providers?.[f];if(!Array.isArray(c))return null;let a=[];for(let d of c)if(k.isAbsolute(String(d||"")))try{let h=m(d,{});if(f==="anthropic-oauth"&&h.claudeAiOauth){let S=C(h.claudeAiOauth);a.push({...S,refreshToken:"",source:"external-access-only"});continue}let y=h.credential_pool&&typeof h.credential_pool=="object"?h.credential_pool:null;if(y){let S=y[f]||y[f.replace(/-oauth$/,"")]||[],ue=Array.isArray(S)?S:S?[S]:[];for(let z of ue)if(!(!z||typeof z!="object"))try{let de=C(z);a.push({...de,refreshToken:"",source:"external-access-only"})}catch{}}}catch{}return a.length?a.find(d=>!d.expiresAt||d.expiresAt>n()+Ce)||a[0]:null}function W(f){let l=_(f);if(s){let d=i("secret-tool",["lookup",...w(l)],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});if(!d.error&&d.status===0&&String(d.stdout||"").trim())try{return C(JSON.parse(String(d.stdout).trim()))}catch{}return U(l)}let a=m(t,{providers:{}}).providers?.[l];if(a)try{return C(a)}catch{}return U(l)}function ne(f,l){let c=_(f),a=C(l);if(s){let h=i("secret-tool",["store",`--label=Oracle ${c} OAuth`,...w(c)],{input:JSON.stringify(a),encoding:"utf8",stdio:["pipe","ignore","pipe"]});if(h.error||h.status!==0)throw new Error("OS credential store rejected OAuth credential");let y=m(r,{providers:{}});return y.providers||={},y.providers[c]={expiresAt:a.expiresAt,source:a.source},x(r,y),a}let d=m(t,{providers:{}});return d.providers||={},d.providers[c]=a,x(t,d),a}function ie(f){let l=_(f);if(s){let d=i("secret-tool",["clear",...w(l)],{encoding:"utf8",stdio:["ignore","ignore","pipe"]}),h=m(r,{providers:{}});return h.providers&&delete h.providers[l],x(r,h),!d.error&&d.status===0}let c=m(t,{providers:{}}),a=!!c.providers?.[l];return c.providers&&delete c.providers[l],x(t,c),a}function V(f){let l=D(f);if(s){let c=i("secret-tool",["lookup",...w(l,"api-key")],{encoding:"utf8",stdio:["ignore","pipe","ignore"]});return c.error||c.status!==0?"":String(c.stdout||"").trim()}return String(m(t,{apiKeys:{}}).apiKeys?.[l]||"").trim()}function se(f,l){let c=D(f),a=String(l||"").trim();if(!a)throw new Error("API key is empty");if(s){let h=i("secret-tool",["store",`--label=Oracle ${c} API key`,...w(c,"api-key")],{input:a,encoding:"utf8",stdio:["pipe","ignore","pipe"]});if(h.error||h.status!==0)throw new Error("OS credential store rejected API key");let y=m(r,{providers:{},apiKeys:{}});return y.apiKeys||={},y.apiKeys[c]={configured:!0},x(r,y),!0}let d=m(t,{providers:{},apiKeys:{}});return d.apiKeys||={},d.apiKeys[c]=a,x(t,d),!0}function ce(f){let l=D(f);if(s){let d=i("secret-tool",["clear",...w(l,"api-key")],{encoding:"utf8",stdio:["ignore","ignore","pipe"]}),h=m(r,{providers:{},apiKeys:{}});return h.apiKeys&&delete h.apiKeys[l],x(r,h),!d.error&&d.status===0}let c=m(t,{providers:{},apiKeys:{}}),a=!!c.apiKeys?.[l];return c.apiKeys&&delete c.apiKeys[l],x(t,c),a}function ae(){let f={},l={};if(s){let c=m(r,{providers:{},apiKeys:{}});for(let[a,d]of Object.entries(c.providers||{}))f[a]={loggedIn:!!W(a),expiresAt:Number(d.expiresAt||0),source:String(d.source||"oracle"),storage:p};for(let a of Object.keys(c.apiKeys||{}))l[a]={configured:!!V(a),storage:p}}else{let c=m(t,{providers:{},apiKeys:{}});for(let[a,d]of Object.entries(c.providers||{}))f[a]={loggedIn:!!d?.accessToken,expiresAt:Number(d?.expiresAt||0),source:String(d?.source||"oracle"),storage:p};for(let[a,d]of Object.entries(c.apiKeys||{}))l[a]={configured:!!d,storage:p}}for(let c of Object.keys(R)){if(f[c])continue;let a=U(c);a&&(f[c]={loggedIn:!0,expiresAt:a.expiresAt,source:a.source,storage:"external-access-source"})}return{storage:p,providers:f,apiKeys:l}}return Object.freeze({file:t,storage:p,get:W,set:ne,remove:ie,getApiKey:V,setApiKey:se,removeApiKey:ce,status:ae,withLock:v})}var G;function ee(){return G||=je(),G}function M(e){return Buffer.from(e).toString("base64url")}function $e(){let e=M(N(32));return{verifier:e,challenge:M(Se("sha256").update(e).digest()),state:M(N(24))}}function Ie(e,t){let r=Buffer.from(String(e||"")),o=Buffer.from(String(t||""));return r.length===o.length&&Ee(r,o)}function Le(e){let t=String(e),r=process.platform==="darwin"?["open",[t]]:process.platform==="win32"?["cmd.exe",["/d","/s","/c","start","",t]]:["xdg-open",[t]];try{return be(r[0],r[1],{detached:!0,stdio:"ignore"}).unref(),!0}catch{return!1}}function B(e){return new URLSearchParams(e).toString()}async function A(e,t){if(!e?.ok){let o="";try{o=String((await e.json())?.error||"")}catch{}throw new Error(`${t} failed (HTTP ${e?.status||"unknown"}${o?`, ${o}`:""})`)}let r=await e.json();if(!r||typeof r!="object")throw new Error(`${t} returned invalid JSON`);return r}async function Te(e){if(e)return String(await e()).trim();let t=Oe.createInterface({input:process.stdin,output:process.stdout});try{return String(await t.question("Authorization code: ")).trim()}finally{t.close()}}function H(e,t={}){let r=String(e.access_token||"").trim(),o=String(e.refresh_token||t.refreshToken||"").trim();if(!r)throw new Error("OAuth token response is missing access token");let n=Number(e.expires_in||3600);return C({accessToken:r,refreshToken:o,expiresAt:Re(t)+Math.max(1,n)*1e3,tokenType:e.token_type||"Bearer",idToken:e.id_token,source:"oracle",...t.discovery?{discovery:t.discovery}:{},...e.scope?{scope:e.scope}:{}})}async function Ke(e){let t=R["anthropic-oauth"],r=e.pkce||$e(),o=new URLSearchParams({code:"true",client_id:t.clientId,response_type:"code",redirect_uri:t.redirectUri,scope:t.scope,code_challenge:r.challenge,code_challenge_method:"S256",state:r.state}),n=`${t.authorizeUrl}?${o}`;e.output(`Open: ${n}`),e.openFn(n);let i=await Te(e.inputFn),[s,p]=i.split("#",2);if(!s||!Ie(p,r.state))throw new Error("Claude OAuth state mismatch");let u=await e.fetchFn(t.tokenUrl,{method:"POST",headers:{"content-type":"application/json","user-agent":"axios/1.7.9"},body:JSON.stringify({grant_type:"authorization_code",client_id:t.clientId,code:s,state:p,redirect_uri:t.redirectUri,code_verifier:r.verifier})});return H(await A(u,"Claude OAuth token exchange"),e)}async function ze(e){let t=R["openai-codex"],r=await A(await e.fetchFn(`${t.issuer}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:t.clientId})}),"Codex device authorization");if(!r.user_code||!r.device_auth_id)throw new Error("Codex device authorization returned incomplete data");let o=`${t.issuer}/codex/device`;e.output(`Open: ${o}`),e.output(`Code: ${r.user_code}`),e.openFn(o);let n=Math.max(3,Number(r.interval||5)),i;for(let p=0;p<Math.ceil(900/n);p+=1){await e.sleepFn(n*1e3);let u=await e.fetchFn(`${t.issuer}/api/accounts/deviceauth/token`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({device_auth_id:r.device_auth_id,user_code:r.user_code})});if(u.ok){i=await A(u,"Codex device authorization");break}if(![403,404].includes(u.status))throw new Error(`Codex device authorization failed (HTTP ${u.status})`)}if(!i)throw new Error("Codex device authorization timed out");let s=await e.fetchFn(t.tokenUrl,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded"},body:B({grant_type:"authorization_code",code:i.authorization_code,redirect_uri:`${t.issuer}/deviceauth/callback`,client_id:t.clientId,code_verifier:i.code_verifier})});return H(await A(s,"Codex OAuth token exchange"),e)}function K(e){let t=new URL(String(e)),r=t.hostname.toLowerCase();if(t.protocol!=="https:"||r!=="x.ai"&&!r.endsWith(".x.ai"))throw new Error("xAI OAuth discovery returned an untrusted endpoint");return t.toString()}async function Fe(e){let t=R["xai-oauth"],r=await A(await e.fetchFn(t.discoveryUrl,{headers:{accept:"application/json"}}),"xAI OAuth discovery");K(r.authorization_endpoint);let o=K(r.token_endpoint),n=await A(await e.fetchFn(t.deviceUrl,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded",accept:"application/json"},body:B({client_id:t.clientId,scope:t.scope})}),"xAI device authorization");if(!n.device_code||!n.user_code||!n.verification_uri)throw new Error("xAI device authorization returned incomplete data");let i=K(n.verification_uri_complete||n.verification_uri);e.output(`Open: ${i}`),e.output(`Code: ${n.user_code}`),e.openFn(i);let s=Math.max(1,Number(n.interval||5)),p=Math.ceil(Math.max(1,Number(n.expires_in||600))/s);for(let u=0;u<p;u+=1){let v=await e.fetchFn(o,{method:"POST",headers:{"content-type":"application/x-www-form-urlencoded",accept:"application/json"},body:B({grant_type:"urn:ietf:params:oauth:grant-type:device_code",client_id:t.clientId,device_code:n.device_code})});if(v.ok){let U=await A(v,"xAI OAuth token exchange");return H(U,{...e,discovery:{authorization_endpoint:K(r.authorization_endpoint),token_endpoint:o}})}let w="";try{w=String((await v.json())?.error||"")}catch{}if(w==="slow_down")await e.sleepFn((s+1)*1e3);else if(w==="authorization_pending")await e.sleepFn(s*1e3);else throw new Error(`xAI OAuth token exchange failed (HTTP ${v.status}${w?`, ${w}`:""})`)}throw new Error("xAI device authorization timed out")}async function te(e,t={}){let r=_(e),o={fetchFn:t.fetchFn||globalThis.fetch,inputFn:t.inputFn,sleepFn:t.sleepFn||(n=>new Promise(i=>setTimeout(i,n))),openFn:t.openFn||Le,output:t.output||(n=>process.stdout.write(`${n}
|
|
4
|
-
`)),now:t.now,pkce:t.pkce};return r==="anthropic-oauth"?Ke(o):r==="openai-codex"?ze(o):Fe(o)}var re=Object.freeze({openrouter:{model:"openrouter/auto"},openai:{model:"gpt-4.1-mini"},anthropic:{model:"claude-sonnet-4-6"},xai:{model:"grok-4.6"},deepseek:{model:"deepseek-chat"},gemini:{model:"gemini-2.5-flash"},kimi:{model:"kimi-k3"},mistral:{model:"mistral-large-latest"},custom:{model:""}});function J(e,t){let r=e.indexOf(t);return r>=0&&e[r+1]?e[r+1]:""}async function De(){let e="";for await(let t of process.stdin)e+=t;return e.trim()}function Me(e="API key: "){if(!process.stdin.isTTY||!process.stdin.setRawMode)throw new Error("non-interactive API-key input requires --stdin");return process.stdout.write(e),new Promise((t,r)=>{let o="",n=()=>{process.stdin.off("data",i),process.stdin.setRawMode(!1),process.stdin.pause(),process.stdout.write(`
|
|
4
|
+
`)),now:t.now,pkce:t.pkce};return r==="anthropic-oauth"?Ke(o):r==="openai-codex"?ze(o):Fe(o)}var re=Object.freeze({openrouter:{model:"openrouter/auto"},openai:{model:"gpt-4.1-mini"},anthropic:{model:"claude-sonnet-4-6"},xai:{model:"grok-4.6"},deepseek:{model:"deepseek-chat"},gemini:{model:"gemini-2.5-flash"},kimi:{model:"kimi-k3"},mistral:{model:"mistral-large-latest"},nous:{model:"moonshotai/kimi-k3"},custom:{model:""}});function J(e,t){let r=e.indexOf(t);return r>=0&&e[r+1]?e[r+1]:""}async function De(){let e="";for await(let t of process.stdin)e+=t;return e.trim()}function Me(e="API key: "){if(!process.stdin.isTTY||!process.stdin.setRawMode)throw new Error("non-interactive API-key input requires --stdin");return process.stdout.write(e),new Promise((t,r)=>{let o="",n=()=>{process.stdin.off("data",i),process.stdin.setRawMode(!1),process.stdin.pause(),process.stdout.write(`
|
|
5
5
|
`)},i=s=>{let p=String(s);for(let u of p){if(u==="\r"||u===`
|
|
6
6
|
`){n(),t(o.trim());return}if(u===""){n(),r(new Error("cancelled"));return}u==="\x7F"||u==="\b"?o=o.slice(0,-1):o+=u}};process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.on("data",i)})}function q(e,t,{baseUrl:r=""}={}){if(e==="custom"&&!String(r||"").trim())throw new Error("custom provider requires --base-url");return{backend:"standalone",...L({provider:e,model:t,baseUrl:r},{requireModel:!0})}}function oe(e,t,r={}){return Z(q(e,t,r))}function Ne(e){process.stdout.write(`storage: ${e.storage}
|
|
7
7
|
`);let t=Object.entries(e.providers||{}),r=Object.entries(e.apiKeys||{});if(!t.length&&!r.length){process.stdout.write(`no credentials configured
|
|
8
8
|
`);return}for(let[o,n]of t){let i=n.expiresAt?new Date(n.expiresAt).toISOString():"unknown";process.stdout.write(`${o}: ${n.loggedIn?"logged in":"missing"}, expires ${i}
|
|
9
9
|
`)}for(let[o,n]of r)process.stdout.write(`${o}: API key ${n.configured?"configured":"missing"}
|
|
10
|
-
`)}function Be(){return["oracle auth, configure OAuth or API-key authentication",""," oracle auth login claude|codex|grok [--model MODEL] [--no-browser]"," oracle auth api-key PROVIDER [--model MODEL] [--base-url URL]"," PROVIDER: openrouter|openai|anthropic|xai|deepseek|gemini|kimi|mistral|custom",` printf '%s\\n' "$KEY" | oracle auth api-key PROVIDER --stdin`," oracle auth status [--json]"," oracle auth logout PROVIDER","","OAuth and API keys are additive. Select any compatible model with oracle model --provider PROVIDER --model MODEL."].join(`
|
|
10
|
+
`)}function Be(){return["oracle auth, configure OAuth or API-key authentication",""," oracle auth login claude|codex|grok [--model MODEL] [--no-browser]"," oracle auth api-key PROVIDER [--model MODEL] [--base-url URL]"," PROVIDER: openrouter|openai|anthropic|xai|deepseek|gemini|kimi|mistral|nous|custom",` printf '%s\\n' "$KEY" | oracle auth api-key PROVIDER --stdin`," oracle auth status [--json]"," oracle auth logout PROVIDER","","OAuth and API keys are additive. Select any compatible model with oracle model --provider PROVIDER --model MODEL."].join(`
|
|
11
11
|
`)}var lt={name:"auth",summary:"login with Claude, Codex, or Grok OAuth; store provider API keys",group:"read",usage:Be(),async run(e){let t=[...e.argv],r=t.shift()||"status",o=ee();try{if(r==="status"){let n=o.status();return t.includes("--json")?process.stdout.write(`${JSON.stringify(n,null,2)}
|
|
12
12
|
`):Ne(n),0}if(r==="login"){let n=t.find(u=>!u.startsWith("-"));if(!n)throw new Error("usage: oracle auth login claude|codex|grok");let i=Y(n),s=J(t,"--model")||i.model;q(i.id,s);let p=await te(i.id,{openFn:t.includes("--no-browser")?()=>!1:void 0});return await o.withLock(async()=>{let u=o.get(i.id);o.set(i.id,p);try{oe(i.id,s)}catch(v){throw u?o.set(i.id,u):o.remove(i.id),v}}),process.stdout.write(`${i.id}: logged in, stored in ${o.storage}
|
|
13
13
|
`),0}if(r==="api-key"){let n=String(t.find(u=>!u.startsWith("-"))||"").trim().toLowerCase();if(!n)throw new Error("usage: oracle auth api-key PROVIDER [--stdin]");if(!Object.hasOwn(re,n))throw new Error(`unsupported API-key provider: ${n}`);let i=J(t,"--model")||re[n].model,s=J(t,"--base-url");q(n,i,{baseUrl:s});let p=t.includes("--stdin")?await De():await Me();return await o.withLock(async()=>{let u=o.getApiKey(n);o.setApiKey(n,p);try{oe(n,i,{baseUrl:s})}catch(v){throw u?o.setApiKey(n,u):o.removeApiKey(n),v}}),process.stdout.write(`${n}: API key configured in ${o.storage}
|