@oracle-agent/oracle 0.35.51 → 0.35.52

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.
Files changed (31) hide show
  1. package/dist/agent-sessions.mjs +21 -21
  2. package/dist/assets/skills/oracle-desk-product/SKILL.md +1 -1
  3. package/dist/bin/desk-server.mjs +28 -28
  4. package/dist/bin/oracle-data-mcp.mjs +13 -13
  5. package/dist/bin/oracle-public-server.mjs +4 -4
  6. package/dist/bin/oracle-route.mjs +12 -12
  7. package/dist/cli/commands/agent-session.mjs +19 -19
  8. package/dist/cli/commands/chat.mjs +262 -230
  9. package/dist/cli/commands/data.mjs +31 -31
  10. package/dist/cli/commands/doctor.mjs +1 -1
  11. package/dist/cli/commands/eval.mjs +199 -167
  12. package/dist/cli/commands/extension-policy.mjs +1 -1
  13. package/dist/cli/commands/model.mjs +266 -234
  14. package/dist/cli/commands/swap.mjs +6 -6
  15. package/dist/data/desk-data.mjs +26 -26
  16. package/dist/data/providers/lp-destination-discovery.mjs +2 -2
  17. package/dist/index.mjs +42 -42
  18. package/dist/router/index.mjs +2 -2
  19. package/dist/router/prepare-bridge.mjs +1 -1
  20. package/dist/router/prepare-route.mjs +2 -2
  21. package/dist/tui/permission-modes.mjs +4 -0
  22. package/dist/tui/standalone-client.mjs +132 -100
  23. package/package.json +2 -1
  24. package/public/oracle-splash/docs/browser-and-web/index.html +2 -2
  25. package/public/oracle-splash/docs/connectors/index.html +2 -2
  26. package/public/oracle-splash/docs/getting-started/index.html +2 -2
  27. package/public/oracle-splash/docs/index.html +3 -3
  28. package/public/oracle-splash/docs/reference/index.html +2 -2
  29. package/public/oracle-splash/docs/security/index.html +2 -2
  30. package/public/oracle-splash/docs/using-oracle/index.html +2 -2
  31. package/server.json +2 -2
@@ -0,0 +1,4 @@
1
+ import g from"node:fs";import f from"node:path";import{homedir as Z}from"node:os";import{randomBytes as x}from"node:crypto";import re from"node:fs";import y from"node:path";import T from"node:path";import{homedir as Q}from"node:os";var q=(process.env.ORACLE_REDACT_SECRETS??"true").toLowerCase(),Ie=["1","true","yes","on"].includes(q);var X=new Set(["access_token","refresh_token","id_token","token","api_key","apikey","client_secret","password","auth","jwt","session","secret","key","code","signature","x-amz-signature","private_key","authorization"]),je=new Set([...X].map(e=>e.replace(/[^a-z0-9]/gi,"").toLowerCase()));var De=process.env.ORACLE_CONFIG_DIR||T.join(Q(),".config","oracle"),Me=128*1024,Ge=200*1024,ee=[[/(^|\/)keys(\/|$)/i,"key material directory (keys/)"],[/(^|\/)(?:[^/]*\.env|\.env\.[^/]+)$/i,"environment file"],[/(^|\/)(?:\.aws|\.azure|\.gnupg|\.kube|\.docker)(\/|$)/i,"credential configuration directory"],[/(^|\/)signer[^/]*/i,"signer material"],[/\.key$/i,"private key file"],[/\.pem$/i,"PEM key or certificate"],[/(^|\/)id_(?:rsa|dsa|ecdsa|ed25519)/i,"SSH private key"],[/(^|\/)\.git-credentials$/i,"Git credentials"],[/(^|\/)\.ssh(\/|$)/i,"SSH configuration directory"],[/^\/dev(\/|$)/i,"device filesystem"],[/^\/proc(\/|$)/i,"kernel process filesystem"]];function m(e){let t=e.split(T.sep).join("/");for(let[r,s]of ee)if(r.test(t))return s;return null}var te=2e3,j=2e3;var Fe=5*1024*1024,ze=64*1024,Be=1536*1024;var Ue=[{type:"function",function:{name:"file_read",description:"Read a UTF-8 text file from the agent workspace or an operator-allowed project folder. Key material and paths outside those folders are refused.",parameters:{type:"object",properties:{path:{type:"string",description:"Path relative to the agent workspace"},offset:{type:"integer",minimum:1,description:"1-indexed line to start from (default 1)"},limit:{type:"integer",minimum:1,maximum:j,description:`Maximum lines to return (default ${te}, max ${j})`}},required:["path"],additionalProperties:!1}}},{type:"function",function:{name:"file_write",description:"Write a UTF-8 text file into the agent workspace or an operator-allowed project folder. Writes still ask first. Key material stays refused.",parameters:{type:"object",properties:{path:{type:"string",description:"Path relative to the agent workspace"},content:{type:"string",description:"File contents to write"}},required:["path","content"],additionalProperties:!1}}}];var Ve=Object.freeze(["read","write","network","denied"]);var ne=10*6e4,qe=64*1024,se=256*1024,R=256,L=8192;function P(e){if(typeof e!="string")return{ok:!1,argv:[],operators:[],error:"command must be a string"};let t=[],r=[],s="",n=!1,i=null;for(let a=0;a<e.length;a+=1){let c=e[a],u=e[a+1];if(i==="'"){c==="'"?i=null:s+=c;continue}if(i==='"'){if(c==='"'){i=null;continue}if(c==="\\"&&u!==void 0&&'"\\$`'.includes(u)){s+=u,a+=1;continue}c==="$"&&r.push("$"),c==="`"&&r.push("`"),s+=c;continue}if(c==="'"||c==='"'){i=c,n=!0;continue}if(c==="\\"){if(u===void 0){r.push("\\");break}if(u===`
2
+ `){a+=1;continue}s+=u,n=!0,a+=1;continue}if(c===" "||c===" "){n&&(t.push(s),s="",n=!1);continue}if(c===`
3
+ `||c==="\r"){r.push("newline");continue}if(c==="|"){r.push(u==="|"?"||":"|"),u==="|"&&(a+=1);continue}if(c==="&"){r.push(u==="&"?"&&":"&"),u==="&"&&(a+=1);continue}if(c===";"){r.push(";");continue}if(c===">"||c==="<"){r.push(c);continue}if(c==="`"){r.push("`");continue}if(c==="$"){r.push(u==="("?"$(":"$"),s+=c,n=!0;continue}if(c==="("||c===")"){r.push(c);continue}(c==="*"||c==="?"||c==="[")&&r.push("glob"),c==="~"&&!n&&r.push("~"),s+=c,n=!0}return i?{ok:!1,argv:[],operators:r,error:"unterminated quote"}:(n&&t.push(s),{ok:r.filter(a=>a!=="glob"&&a!=="~").length===0&&t.length>0,argv:t,operators:[...new Set(r)],...t.length?{}:{error:"empty command"}})}var oe=[[/oracle[-_]?signer/i,"signer process or material"],[/(^|[\\/])\.oracle[\\/]keys/i,"Oracle key directory"],[/keystore/i,"keystore"],[/(^|[\\/=])\.ssh([\\/]|$)/i,"SSH directory"],[/(^|[\\/=])\.gnupg([\\/]|$)/i,"GPG directory"],[/(^|[\\/=])id_(?:rsa|dsa|ecdsa|ed25519)/i,"SSH private key"],[/\.key$/i,"private key file"],[/\.pem$/i,"PEM key or certificate"],[/wallet/i,"wallet material"],[/connector[-_]?vault/i,"connector vault"],[/(^|[\\/])exec\.env$/i,"Oracle exec env"],[/mnemonic|seed[-_ ]?phrase|private[-_]?key/i,"secret key material"],[/(^|[\\/])\.config[\\/]oracle([\\/]|$)/i,"Oracle config directory"],[/(^|[\\/])\.git-credentials$/i,"Git credentials"],[/(^|[\\/])\.npmrc$/i,"npm credentials"]],ie=new Set(["sudo","su","doas","pkexec","runas","gsudo","sudoedit"]),ae=new Set(["sh","bash","zsh","dash","ksh","fish","csh","tcsh","ash","pwsh","powershell","cmd","eval","exec","source","osascript"]),ce=new Set(["ssh","scp","sftp","ssh-add","ssh-agent","ssh-keygen","ssh-copy-id","gpg","gpg2","gpg-agent","security","keychain","secret-tool","pass","op","bw","vault"]),le=new Set(["systemctl","launchctl","sc","service","kill","pkill","killall","taskkill"]),ue=new Set(["mkfs","dd","fdisk","parted","diskutil","format","shutdown","reboot","halt","poweroff","chown","chroot","mount","umount","crontab","at"]),fe=new Set(["env","nice","nohup","time","command","stdbuf","ionice","timeout"]),C=new Set(["ls","dir","cat","head","tail","wc","pwd","echo","printf","rg","grep","egrep","fgrep","tree","stat","file","du","df","which","whereis","whoami","uname","date","diff","cmp","uniq","cut","jq","basename","dirname","realpath","readlink","sha256sum","sha1sum","md5sum","shasum","true","false","nl","column","hostname","id","type","fd","ag","bat","less","more","od","hexdump","strings","comm","tr","test","seq","printenv","find","sort"]),de={find:[/^-(exec|execdir|ok|okdir|delete|fprint|fprint0|fprintf|fls)$/],sort:[/^-o/,/^--output/],rg:[/^--pre(=|$)/,/^--pre-glob/],tree:[/^-o$/],fd:[/^-x$/,/^-X$/,/^--exec/]},F=new Set(["--version","-v","-V","version","--help","-h"]),pe=new Set(["node","npm","npx","pnpm","yarn","bun","deno","python","python3","pip","pip3","uv","git","cargo","rustc","go","java","javac","ruby","gem","forge","cast","anvil","solana","anchor","docker","make","cmake","gcc","clang","tsc","eslint","prettier","rg","jq","gh","hermes","oracle"]),he=new Set(["curl","wget","nc","ncat","netcat","telnet","ftp","http","https","xh","aria2c","rsync","gh","npx","pnpx","bunx","ping","dig","nslookup","host","traceroute"]),me=new Set(["npm","pnpm","yarn","bun"]),D=new Set(["test","lint","typecheck","check","format:check"]),ge=new Set(["install","i","ci","add","update","upgrade","up","publish","unpublish","login","logout","adduser","exec","dlx","x","create","init","outdated","view","info","audit","dedupe","fetch","link","pack","deprecate","dist-tag","owner","token","whoami","remove","rm","uninstall"]),ye=new Set(["status","log","diff","show","rev-parse","ls-files","blame","describe","shortlog","reflog","ls-tree","cat-file","grep","whatchanged","name-rev","merge-base","rev-list","count-objects","check-ignore","var"]),we=new Set(["fetch","pull","push","clone","ls-remote","remote-update","send-email","request-pull","archive","submodule","lfs"]),ke=[/^--output(=|$)/,/^--ext-diff$/,/^--textconv$/,/^-o$/,/^--exec(=|$)/,/^--upload-pack/,/^--receive-pack/],_e=[[e=>p(e[0])==="cast"&&/^(send|publish|mktx|wallet|sign|sign-auth|batch-send|erc20)$/.test(e[1]||""),"cast sign/send"],[e=>p(e[0])==="forge"&&e.some(t=>/^--broadcast$/.test(t)),"forge --broadcast"],[e=>p(e[0])==="forge"&&/^create$/.test(e[1]||""),"forge create deploys a contract"],[e=>/^(solana|spl-token)$/.test(p(e[0]))&&/^(transfer|deploy|program|pay|create-account|stake|delegate-stake|withdraw|close|mint|burn|authorize|vote)/.test(e[1]||""),"solana transaction"],[e=>/^(hardhat|npx)$/.test(p(e[0]))&&e.includes("--network"),"hardhat network deploy"],[e=>/^(oracle|hermes)$/.test(p(e[0]))&&e.slice(1).some(t=>/^(send|sign|execute|broadcast|arm|swap|bridge|transfer|signer|keys|wallet)$/i.test(t)),"Oracle sign/execute path"],[e=>e.some(t=>/^--(private-key|mnemonic|keystore|ledger|trezor|unlocked|interactive-key|account)(=|$)/i.test(t)),"signing credential flag"],[e=>e.some(t=>/(eth_sendRawTransaction|eth_sendTransaction|eth_sign|personal_sign|sendRawTransaction|signTransaction|signTypedData)/i.test(t)),"RPC sign/broadcast method"]];function p(e){return(String(e||"").split(/[\\/]/).pop()||"").replace(/\.(exe|cmd|bat|com|ps1)$/i,"").toLowerCase()}function A(e,t){if(t===e)return!0;let r=y.relative(e,t);return r!==""&&!r.startsWith("..")&&!y.isAbsolute(r)}function w(e){try{return re.realpathSync(e)}catch{return y.resolve(e)}}function z(e){return typeof e!="string"||!e||/^-{1,2}[A-Za-z]/.test(e)&&!e.includes("=")?!1:e.startsWith("/")||e.startsWith("~")||e.startsWith(".")||e.includes("/")||e.includes("\\")||/^[a-z]:/i.test(e)}function B(e){let t=e.indexOf("=");return e.startsWith("-")&&t>0?e.slice(t+1):e}function l(e,t,r={}){return Object.freeze({class:e,reasons:Object.freeze([...t]),...r})}function M(e,{cwd:t,projectRoot:r}={}){let s=[],n=p(e[0]);ie.has(n)&&s.push(`privilege escalation (${n}) is never allowed`),ce.has(n)&&s.push(`${n} uses key material and is never allowed`),ae.has(n)&&s.push(`${n} runs an unparsed shell program and is never allowed`),ue.has(n)&&s.push(`${n} changes the system outside the project`);for(let i of e){let o=String(i);for(let[a,c]of oe)if(a.test(o)){s.push(`argument touches ${c}: ${o.slice(0,80)}`);break}if(z(o)){let a=m(B(o));a&&s.push(`argument touches ${a}`)}}if(le.has(n)&&e.slice(1).some(i=>/io\.oracle|oracle[-_.]?(signer|runner|desk|agent)/i.test(i))&&s.push("controlling Oracle signer/runner services is never allowed"),n==="rm"||n==="rmdir"||n==="del"||n==="rd"||n==="shred"){let i=e.slice(1).filter(a=>a.startsWith("-")),o=i.some(a=>/^-[a-zA-Z]*[rR]/.test(a)||a==="--recursive")||n==="rd";if(i.includes("--no-preserve-root")&&s.push("rm --no-preserve-root is never allowed"),o){let a=e.slice(1).filter(c=>!c.startsWith("-"));for(let c of a){if(/^[~/\\]$|^~[\\/]?$|^\*$|^\.{1,2}[\\/]?\*?$|^[a-z]:[\\/]?$/i.test(c)){s.push(`recursive delete of ${c} is never allowed`);continue}if(r){let u=w(y.resolve(t||r,c)),d=w(r);u===d||A(u,d)?s.push("recursive delete of the project root or a parent is never allowed"):A(d,u)||s.push("recursive delete outside the project is never allowed")}}}}for(let[i,o]of _e)try{i(e)&&s.push(`${o}: signing or broadcasting is never allowed from run_command`)}catch{}return s}function Ee(e){let t=[...e];for(let r=0;r<8&&t.length;r+=1){let s=p(t[0]);if(!fe.has(s))break;if(t=t.slice(1),s==="env")for(;t.length&&(/^[A-Za-z_][A-Za-z0-9_]*=/.test(t[0])||/^-/.test(t[0]));){if(/^-(S|-split-string)/.test(t[0]))return{argv:t,splitString:!0};t=t.slice(1)}else if(s==="timeout"){for(;t.length&&/^-/.test(t[0]);)t=t.slice(1);t.length&&/^\d/.test(t[0])&&(t=t.slice(1))}else for(;t.length&&/^-/.test(t[0]);)t=t.slice(1)}return{argv:t,splitString:!1}}function be(e,t){let r=1,s=[];for(;r<e.length&&e[r].startsWith("-");){let o=e[r];if(o==="-C"||o==="--git-dir"||o==="--work-tree"){let a=e[r+1];if(t.projectRoot&&a){let c=w(y.resolve(t.cwd||t.projectRoot,a));if(!A(w(t.projectRoot),c))return l("write",["git -C points outside the project"],{contained:!1})}r+=2;continue}if(o==="-c"||o.startsWith("--config-env")||o.startsWith("--exec-path"))return l("write",["git config override can run programs (core.pager, core.sshCommand)"]);if(o==="--version"||o==="--help")return l("read",["git version/help"]);r+=1}let n=e[r]||"",i=e.slice(r+1);return we.has(n)?l("network",[`git ${n} contacts a remote`]):i.some(o=>ke.some(a=>a.test(o)))?l("write",[`git ${n} with an output/exec flag`]):ye.has(n)?l("read",[`git ${n} is read-only`],s.length?{notes:s}:{}):n==="branch"&&i.every(o=>/^(-a|-r|-v|-vv|--list|--all|--remotes|--show-current|--verbose|--no-color|--color)$/.test(o))?l("read",["git branch listing"]):n==="remote"&&i.every(o=>/^(-v|--verbose|show|get-url)$/.test(o)||!o.startsWith("-"))&&(!i.length||/^(-v|--verbose|get-url)$/.test(i[0]))?l("read",["git remote listing"]):n==="tag"&&i.every(o=>/^(-l|--list|-n\d*)$/.test(o))?l("read",["git tag listing"]):n==="config"&&i.length&&/^(--get|--get-all|--list|-l|--get-regexp)$/.test(i[0])?l("read",["git config read"]):n==="stash"&&/^(list|show)$/.test(i[0]||"")?l("read",["git stash listing"]):l("write",[`git ${n||"(no subcommand)"} may change the repository`])}function Se(e,t){let r=t[1]||"";return F.has(r)&&t.length===2?l("read",[`${e} version/help`]):r==="test"||r==="t"?l("read",[`${e} test runs the project's own test script`]):(r==="run"||r==="run-script")&&D.has(t[2]||"")?l("read",[`${e} run ${t[2]} runs a project check script`]):e!=="npm"&&D.has(r)?l("read",[`${e} ${r} runs a project check script`]):r==="ls"||r==="list"||r==="why"||r==="explain"||r==="config"&&t[2]==="list"?l("read",[`${e} ${r} lists local packages`]):ge.has(r)?l("network",[`${e} ${r} contacts the package registry`]):l("write",[`${e} ${r||"(no args)"} runs a project script or changes packages`])}function G(e,t){if(!t.projectRoot)return!0;let r=w(t.projectRoot);for(let s of e.slice(1)){let n=B(s);if(!z(n))continue;if(n.startsWith("~"))return!1;let i=w(y.resolve(t.cwd||t.projectRoot,n));if(!A(r,i))return!1}return!0}function S(e,t={}){if(!Array.isArray(e)||e.length===0)return l("denied",["argv must be a non-empty array of strings"]);if(e.length>R)return l("denied",[`argv has more than ${R} entries`]);for(let o of e){if(typeof o!="string")return l("denied",["every argv entry must be a string"]);if(o.includes("\0"))return l("denied",["argv contains a null byte"]);if(o.length>L)return l("denied",[`argv entry longer than ${L} characters`])}if(!e[0].trim())return l("denied",["empty program name"]);let r=M(e,t),s=Ee(e);s.splitString&&r.push("env -S re-parses a shell string and is never allowed");let n=s.argv;if(!n.length)return r.length?l("denied",r):l("read",["wrapper with no command"]);if(n!==e&&n.length!==e.length&&r.push(...M(n,t)),r.length)return l("denied",[...new Set(r)]);let i=p(n[0]);if(n.length===2&&F.has(n[1])&&(pe.has(i)||C.has(i)))return l("read",[`${i} ${n[1]} is read-only`],{contained:!0});if(i==="git"){let o=be(n,t);return o.class!=="read"?o:l("read",o.reasons,{contained:o.contained!==!1&&G(n,t)})}if(me.has(i)){let o=Se(i,n);return o.class==="read"?l("read",o.reasons,{contained:!0}):o}if(he.has(i))return l("network",[`${i} contacts the network`]);if(i==="docker"||i==="podman")return/^(pull|push|login|build|run|compose)$/.test(n[1]||"")?l("network",[`${i} ${n[1]} may contact a registry`]):l("write",[`${i} ${n[1]||""} changes containers`]);if(/^(pip|pip3|uv|cargo|go|gem|brew|apt|apt-get|dnf|pacman|yum|choco|winget)$/.test(i))return/^(install|add|get|update|upgrade|sync|fetch|download|publish|login)$/.test(n[1]||"")?l("network",[`${i} ${n[1]} contacts a package registry`]):/^(list|show|freeze|check|tree)$/.test(n[1]||"")?l("read",[`${i} ${n[1]} lists local state`],{contained:!0}):i==="cargo"&&/^(test|check|clippy|fmt)$/.test(n[1]||"")?l("read",[`cargo ${n[1]} is a project check`],{contained:!0}):i==="go"&&/^(test|vet|version|env)$/.test(n[1]||"")?l("read",[`go ${n[1]} is a project check`],{contained:!0}):l("write",[`${i} ${n[1]||""} may change the environment`]);if(C.has(i)){let o=de[i]||[];if(n.slice(1).some(c=>o.some(u=>u.test(c))))return l("write",[`${i} with a flag that writes or executes`]);let a=G(n,t);return l("read",[a?`${i} is read-only`:`${i} is read-only but reads outside the project`],{contained:a})}return l("write",[`${i} is not on the read-only allowlist`])}function U(e,t={}){let r=String(e||"");if(/\b(curl|wget|iwr|invoke-webrequest|fetch)\b[^|]*\|\s*(sudo\s+)?(ba|z|da|k|fi)?sh\b/i.test(r)||/\b(ba|z)?sh\s+<\s*\(\s*(curl|wget)/i.test(r)||/\b(curl|wget)\b[^|]*\|\s*(python3?|node|perl|ruby|iex|powershell|pwsh)\b/i.test(r))return l("denied",["piping a download into an interpreter (curl|sh) is never allowed"],{argv:[],operators:["|"]});let s=P(r);if(!s.argv.length)return l("denied",[s.error||"empty command"],{argv:[],operators:s.operators});let n=S(s.argv,t);if(n.class==="denied")return l("denied",n.reasons,{argv:s.argv,operators:s.operators});let i=s.operators.filter(o=>o!=="glob"&&o!=="~");if(i.length){for(let o of r.split(/\|\||&&|[|;&\n]/)){let a=P(o.replace(/[<>`$()]/g," "));if(a.argv.length){let c=S(a.argv,t);if(c.class==="denied")return l("denied",c.reasons,{argv:s.argv,operators:s.operators})}}return l("write",[`shell operators (${i.join(" ")}) need the exact string approved in ask mode`],{argv:s.argv,operators:s.operators,requiresExactStringApproval:!0})}return l(n.class,n.reasons,{argv:s.argv,operators:s.operators,...n.contained!==void 0?{contained:n.contained}:{}})}var Xe=Object.freeze([{type:"function",function:{name:"run_command",description:"Run a program inside a granted project folder. Pass argv as an array (no shell: pipes, redirects and && are not interpreted). Output is capped and secrets are never in the environment. Signer, wallet, keystore, SSH/GPG, sudo and sign/broadcast commands are always refused. Depending on the permission mode the operator is asked first.",parameters:{type:"object",properties:{argv:{type:"array",items:{type:"string"},minItems:1,maxItems:R,description:'Program and arguments, e.g. ["git","status"]'},cwd:{type:"string",description:"Working directory inside a granted project folder (default: session folder)"},timeout_ms:{type:"integer",minimum:1e3,maximum:ne},max_output_bytes:{type:"integer",minimum:1024,maximum:se}},required:["argv"],additionalProperties:!1}}}]);var k=Object.freeze(["ask","smart","accept-edits","plan"]),H="ask",ot=Object.freeze(["file_write","command","folder_access","mcp_tool"]),Ae=Object.freeze([Object.freeze({id:"once",label:"Allow once"}),Object.freeze({id:"session",label:"Allow for this session"}),Object.freeze({id:"always",label:"Always allow in this project"}),Object.freeze({id:"deny",label:"Deny"})]),it=Object.freeze({ask:"Ask",smart:"Smart","accept-edits":"Accept edits",plan:"Plan"});function N(e){return k.includes(e)?e:H}function at(e){let t=k.indexOf(N(e));return k[(t+1)%k.length]}function Y(e=process.env){return e&&e.ORACLE_CONFIG_DIR||f.join(Z(),".config","oracle")}function ve(e,t){if(t===e)return!0;let r=f.relative(e,t);return r!==""&&!r.startsWith("..")&&!f.isAbsolute(r)}function E(e,t){try{let r=JSON.parse(g.readFileSync(e,"utf8"));return r&&typeof r=="object"?r:t}catch{return t}}function I(e,t){g.mkdirSync(f.dirname(e),{recursive:!0,mode:448});let r=`${e}.${x(6).toString("hex")}.tmp`;g.writeFileSync(r,`${JSON.stringify(t,null,2)}
4
+ `,{mode:384}),g.renameSync(r,e)}function V(e=process.env){return f.join(Y(e),"permission-modes.json")}function ct(e,{env:t=process.env}={}){if(!e)return H;let r=E(V(t),{});return N(r.sessions?.[String(e)])}function lt(e,t,{env:r=process.env}={}){if(!e)throw new Error("permission mode: session id is required");if(!k.includes(t))throw new Error(`permission mode must be one of ${k.join(", ")}`);let s=V(r),i={...E(s,{}).sessions||{},[String(e)]:t},o=Object.keys(i);for(let a of o.slice(0,Math.max(0,o.length-500)))delete i[a];return I(s,{version:1,sessions:i}),t}function v(e=process.env){return f.join(Y(e),"permission-rules.json")}function h(e){try{return g.realpathSync(e)}catch{return f.resolve(String(e||""))}}function $e(e){let t="";for(let r=0;r<e.length;r+=1){let s=e[r];if(s==="*"&&e[r+1]==="*"){t+=".*",r+=1,e[r+1]==="/"&&(r+=1);continue}if(s==="*"){t+="[^/]*";continue}if(s==="?"){t+="[^/]";continue}t+=s.replace(/[.+^${}()|[\]\\]/g,"\\$&")}return new RegExp(`^${t}$`)}function _(e){if(!e||typeof e!="object")return"rule must be an object";if(e.kind==="command"){if(!Array.isArray(e.argvPrefix)||!e.argvPrefix.length||e.argvPrefix.some(r=>typeof r!="string"||!r))return"command rule needs a non-empty argv prefix";let t=S(e.argvPrefix);return t.class==="denied"?`denied commands can never be persisted (${t.reasons[0]})`:t.class==="network"?"network commands can never be persisted":["read","write"].includes(e.classification)?null:"command rule classification must be read or write"}return e.kind==="file_write"?typeof e.pathGlob!="string"||!e.pathGlob?"file rule needs a path glob":f.isAbsolute(e.pathGlob)||e.pathGlob.split(/[\\/]/).includes("..")?"file rule glob must be relative to the project":/^\*\*?$/.test(e.pathGlob.trim())?"file rule glob must name a subfolder or file pattern, not the whole project":m(e.pathGlob.replace(/\*+/g,"x"))?"file rule glob covers sensitive files":null:"rule kind must be command or file_write"}function ut(e,{env:t=process.env}={}){let r=E(v(t),{}),s=h(e);return(r.projects?.[s]||[]).filter(n=>!_(n))}function ft({env:e=process.env}={}){let t=E(v(e),{});return Object.entries(t.projects||{}).map(([r,s])=>({root:r,rules:(s||[]).filter(n=>!_(n))}))}function W(e,t,{env:r=process.env,now:s=Date.now}={}){let n=_(t);if(n)throw new Error(`permission rule refused: ${n}`);let i=h(e),o=v(r),c={...E(o,{}).projects||{}},u=(c[i]||[]).filter($=>!_($)),d=t.kind==="command"?{id:x(6).toString("hex"),kind:"command",argvPrefix:[...t.argvPrefix],classification:t.classification,createdAt:s()}:{id:x(6).toString("hex"),kind:"file_write",pathGlob:t.pathGlob.replace(/\\/g,"/"),createdAt:s()},b=u.find($=>JSON.stringify({...$,id:0,createdAt:0})===JSON.stringify({...d,id:0,createdAt:0}));return b||(c[i]=[...u,d].slice(-200),I(o,{version:1,projects:c}),d)}function dt(e,t,{env:r=process.env}={}){let s=h(e),n=v(r),o={...E(n,{}).projects||{}},a=o[s]||[],c=a.filter(u=>u.id!==t);return c.length===a.length?!1:(c.length?o[s]=c:delete o[s],I(n,{version:1,projects:o}),!0)}function K(e,t,r){if(e.kind==="command"&&t.kind==="command"){let s=t.argv||[];return t.exactString||t.classification==="network"||t.classification==="denied"||e.classification==="read"&&t.classification!=="read"?!1:e.argvPrefix.length<=s.length&&e.argvPrefix.every((n,i)=>s[i]===n)}if(e.kind==="file_write"&&t.kind==="file_write"&&t.path){let s=h(f.dirname(t.path)),n=f.join(s,f.basename(t.path));if(!ve(r,n))return!1;let i=f.relative(r,n).split(f.sep).join("/");return $e(e.pathGlob).test(i)}return!1}function pt(e,t={}){let r=N(t.mode),s=e?.kind,n=e?.access||"none";if(s==="file_read")return n==="none"?{decision:"ask",reason:"folder not granted",needsFolderAccess:"read",persistable:!1}:r==="smart"||r==="accept-edits"||r==="plan"?{decision:"allow",reason:`${r}: read inside a granted folder`,persistable:!1}:{decision:"allow",reason:"read inside a granted folder",persistable:!1};if(s==="folder_access")return r==="plan"&&e.access==="write"?{decision:"deny",reason:"plan mode is read-only",persistable:!1}:{decision:"ask",reason:"folder access always asks",persistable:!1};if(s==="mcp_tool")return r==="plan"&&e.readOnly!==!0?{decision:"deny",reason:"plan mode is read-only",persistable:!1}:r==="smart"&&e.readOnly===!0?{decision:"allow",reason:"smart: read-only connector tool",persistable:!1}:{decision:"ask",reason:"connector tool asks",persistable:!!e.readOnly};if(s==="file_write"){if(r==="plan")return{decision:"deny",reason:"plan mode: no writes",persistable:!1};if(e.path&&m(e.path))return{decision:"deny",reason:`${m(e.path)} is never writable`,persistable:!1};if(n!=="write")return{decision:"ask",reason:"folder not granted for writes",needsFolderAccess:"write",persistable:!1};let i=O(e);if(t.sessionAllows?.has?.(i))return{decision:"allow",reason:"allowed for this session",persistable:!0};let o=e.projectRoot?h(e.projectRoot):null;return o&&(t.rules||[]).some(a=>!_(a)&&K(a,e,o))?{decision:"allow",reason:"project rule",persistable:!0}:r==="accept-edits"?{decision:"allow",reason:"accept-edits: write inside a granted write folder",persistable:!0}:{decision:"ask",reason:`${r}: file writes ask`,persistable:!0}}if(s==="command"){let i={cwd:e.cwd,projectRoot:e.projectRoot},o=Array.isArray(e.argv)?S(e.argv,i):U(e.command,i),a=o.class;if(a==="denied")return{decision:"deny",reason:o.reasons.join("; "),classification:a,persistable:!1};if(r==="plan")return{decision:"deny",reason:"plan mode: no commands",classification:a,persistable:!1};if(n==="none")return{decision:"ask",reason:"command cwd is not in a granted folder",classification:a,needsFolderAccess:a==="read"?"read":"write",persistable:!1};if(a!=="read"&&n!=="write")return{decision:"ask",reason:"command needs a write grant",classification:a,needsFolderAccess:"write",persistable:!1};if(o.requiresExactStringApproval)return r!=="ask"?{decision:"deny",reason:"shell operators need ask mode and exact-string approval",classification:a,persistable:!1}:{decision:"ask",reason:o.reasons.join("; "),classification:a,exactString:!0,persistable:!1,sessionable:!1};let c=a==="read"||a==="write";if(a!=="network"){let u=O({...e,argv:o.argv||e.argv});if(t.sessionAllows?.has?.(u))return{decision:"allow",reason:"allowed for this session",classification:a,persistable:c};let d=e.projectRoot?h(e.projectRoot):null;if(d&&(t.rules||[]).some(b=>!_(b)&&K(b,{...e,argv:o.argv||e.argv,classification:a},d)))return{decision:"allow",reason:"project rule",classification:a,persistable:c}}return r==="smart"&&a==="read"&&o.contained!==!1?{decision:"allow",reason:`smart: ${o.reasons[0]}`,classification:a,persistable:c}:{decision:"ask",reason:`${r}: ${o.reasons[0]||"commands ask"}`,classification:a,persistable:c&&a!=="network",sessionable:a!=="network"}}return{decision:"deny",reason:`unknown action kind ${String(s)}`,persistable:!1}}function O(e){return e.kind==="command"?`command:${JSON.stringify(e.argv||[e.command])}`:e.kind==="file_write"?`file_write:${e.path}`:e.kind==="mcp_tool"?`mcp_tool:${e.name}`:`${e.kind}:${e.path||""}`}function ht(e,t,r={}){let s=e.kind==="file_read"?"folder_access":e.kind,n=Ae.filter(o=>o.id==="always"?t.persistable===!0&&t.classification!=="network"&&t.classification!=="denied":o.id==="session"?t.sessionable!==!1&&t.classification!=="network":!0),i=r.summary||Re(e,t);return{kind:s,summary:i,...Array.isArray(e.argv)?{argv:[...e.argv]}:{},...typeof e.command=="string"?{command:e.command}:{},...e.path?{path:e.path}:{},...e.cwd?{cwd:e.cwd}:{},...e.projectRoot?{projectRoot:e.projectRoot}:{},...t.classification?{classification:t.classification}:{},...t.needsFolderAccess?{access:t.needsFolderAccess}:e.kind==="folder_access"?{access:e.access||"read"}:{},...typeof r.diff=="string"&&r.diff?{diff:r.diff.slice(0,2e5)}:{},...t.exactString?{exactString:!0}:{},reason:t.reason,choices:n.map(o=>({...o}))}}function Re(e,t){return e.kind==="command"?`Run ${Array.isArray(e.argv)?e.argv.join(" "):e.command}${t.classification?` (${t.classification})`:""}`:e.kind==="file_write"?`Write ${e.path}`:e.kind==="folder_access"||e.kind==="file_read"?`Grant ${t.needsFolderAccess||e.access||"read"} access to ${e.path}`:e.kind==="mcp_tool"?`Call connector tool ${e.name}`:"Approval required"}function mt(e,t,r,{sessionAllows:s,env:n=process.env,grantFolder:i}={}){if(r==="deny"||!r)return{allow:!1};if(t.decision==="deny")return{allow:!1};if(e.kind==="folder_access"||t.needsFolderAccess){if(typeof i!="function")return{allow:!1,error:"folder grants are unavailable here"};let o=t.needsFolderAccess||e.access||"read";return{allow:!0,granted:i(e.folder||e.projectRoot||e.cwd||f.dirname(e.path||""),o)}}if(r==="session")return t.sessionable===!1||t.classification==="network"?{allow:!0}:(s?.add?.(O(e)),{allow:!0});if(r==="always"){if(!t.persistable||t.classification==="network"||t.classification==="denied"||!e.projectRoot)return{allow:!0};if(e.kind==="command")return Array.isArray(e.argv)?{allow:!0,persisted:W(e.projectRoot,{kind:"command",argvPrefix:e.argv,classification:t.classification},{env:n})}:{allow:!0};if(e.kind==="file_write"){let o=h(e.projectRoot),a=f.relative(o,f.join(h(f.dirname(e.path)),f.basename(e.path))).split(f.sep).join("/");return{allow:!0,persisted:W(o,{kind:"file_write",pathGlob:a},{env:n})}}return{allow:!0}}return{allow:!0}}function xe({platform:e=process.platform,env:t=process.env,home:r=Z()}={}){if(e==="win32"){let s=t.USERPROFILE||r;return f.win32.join(s,"Oracle","Projects")}return f.join(r,"Oracle","Projects")}function Oe(e={}){let t=xe(e);return(e.fsModule||g).mkdirSync(t,{recursive:!0,mode:493}),t}function Ne(e){let t=String(e||"").normalize("NFKD").replace(/[^\w\s.-]/g,"").trim().replace(/\s+/g,"-").replace(/^[.-]+/,"").slice(0,64);return!t||/^(con|prn|aux|nul|com\d|lpt\d)$/i.test(t)||m(t)||/^(keys|\.ssh|\.gnupg|wallet)/i.test(t)?null:t}function gt(e,{grant:t,...r}={}){let s=Ne(e);if(!s)throw new Error("project name is empty or not allowed");let n=Oe(r),i=f.join(n,s),o=2,a=r.fsModule||g;for(;a.existsSync(i)&&o<100;)i=f.join(n,`${s}-${o}`),o+=1;if(a.mkdirSync(i,{recursive:!0}),typeof t!="function")throw new Error("saveAsProject needs a grant function");let c=t(i,"write");return{folder:i,granted:c}}export{Ae as APPROVAL_CHOICES,ot as APPROVAL_KINDS,H as DEFAULT_PERMISSION_MODE,it as MODE_LABELS,k as PERMISSION_MODES,W as addProjectRule,mt as applyApprovalChoice,ht as buildApprovalRequest,pt as decidePermission,xe as defaultProjectsFolder,Oe as ensureProjectsFolder,ct as getSessionPermissionMode,ft as listAllProjectRules,ut as listProjectRules,at as nextPermissionMode,N as normalizePermissionMode,V as permissionModesPath,v as permissionRulesPath,dt as revokeProjectRule,_ as ruleError,Ne as safeProjectSlug,gt as saveAsProject,O as sessionKey,lt as setSessionPermissionMode};