@cortexkit/pi-openai-auth 1.0.0 → 1.0.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/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -110,7 +110,7 @@ ${z.url}
|
|
|
110
110
|
${z.instructions}
|
|
111
111
|
|
|
112
112
|
The account is added when you finish.`,Q=z.completion.then(async(Y)=>{let B=await $.mainIdentity?.();if(Y.accountId&&B&&Y.accountId===B)throw $6.warn("account add rejected (main identity)",{id:Y.id}),new j0("main-account",q5);return $6.info("account added",{id:Y.id}),P5(Y)});return{status:"pending",message:G,completion:Q}}}}function J4($){return{id:"session",title:"This session",build:async(Z)=>{let X=Z.sessionId;if(!X)return{lines:["No current session"]};let J=await $.getPin?.(X);return{lines:[J?`Pinned to ${J}`:"No sticky pin"],actions:$.clearPin?[{id:"clear-pin",label:"Clear this session's pin",description:"The next request may still choose the same account.",run:async({invocation:z})=>{if(!z.sessionId)return"No current session.";return await $.clearPin?.(z.sessionId),$6.info("routing session pin cleared"),"This session's pin was cleared. The next request may choose the same account if it remains the best selection."}}]:[]}}}}function z4($){let{vault:Z}=$;return{id:"vault",title:"Vault",build:async()=>{let X=await Z.status(),J=await Z.authority()!=="local",z=Z.routes().length;return{lines:[J?`Connected · ${X.accounts.length} account${X.accounts.length===1?"":"s"}`:X.enrollment.state==="idle"?"Not connected":`Enrollment ${X.enrollment.state}`,Q5(X.host,X.name,X.enrollment),...E3(X.name,X.enrollment),...J?[X.accounts.length===0?"The vault serves no OpenAI account to this host yet.":`The vault serves ${X.accounts.length} OpenAI account${X.accounts.length===1?"":"s"}; ${z} can route now.`]:[],...J&&Z.snapshot()?.complete===!1?["The vault's last list had records this host could not read; accounts it did not list are kept as they were until a complete list arrives."]:[],...X.lastError?[`Last error: ${X.lastError}`]:[]],items:X.accounts.map((G)=>({id:G.routeId,label:F1(G),group:"Accounts",status:G.enabled?G.state:"disabled",detail:[G.credentialType==="api_key"?"API key":"login",G.state==="active"?"active":`vault state ${G.state}`,G.enabled?"enabled":"disabled here"].join(", "),actions:[G.enabled?{id:"disable",label:"Disable on this host",description:"It stays in the vault and in this list, and is never sent from this host until enabled again.",run:async()=>{return await Z.decline(G.routeId),await $.changed?.(),`${F1(G)} is disabled on this host.`}}:{id:"enable",label:"Enable on this host",run:async()=>{return await Z.accept(G.routeId),await $.changed?.(),`${F1(G)} is enabled on this host.`}}]})),actions:J?[{id:"disconnect",label:"Disconnect",description:"Forgets this host's vault token; its vault accounts stop routing at once. Revoke the enrollment itself with `ck auth enroll revoke`.",confirm:"Disconnect from the vault? Connecting again needs a new approval with `ck`.",run:async()=>{return await Z.disconnect(),await $.changed?.(),`Disconnected: ${Z.name} no longer reads from the vault. Run \`ck auth enroll revoke --name ${Z.name}\` to revoke it in the vault too.`}}]:[{id:"connect",label:"Connect",description:"Asks the vault to enroll this host; you approve the request with `ck`.",run:async({invocation:G})=>{let Q=await Z.connectStep();if(Q.state!=="pending"&&Q.state!=="busy")return await $.changed?.(),n2(Z,Q);return Z.waitForApproval($.wait).then(async(Y)=>{await $.changed?.();let B=n2(Z,Y);G.notify(B.text,B.ok?"info":"warning")}).catch((Y)=>{G.notify(`Connecting to the vault failed: ${Y instanceof Error?Y.message:String(Y)}`,"error")}),{ok:!0,text:[...E3(Z.name,Q),"Waiting for the approval; you are told here when it lands."].join(`
|
|
113
|
-
`)}}}]}}}}var _5=[{value:"main-first",label:"Main first"},{value:"fallback-first",label:"Fallback first"}],C5=["primary","secondary"];function G4($){let Z={command:P1,title:X4,store:e2(M5(L5($.store,{...$.rowLocks?{rowLocks:$.rowLocks}:{}}))),...$.extraLocks?{extraLocks:$.extraLocks}:{},accounts:{...$.login?{login:O5($.login)}:{},...$.protect?{protect:$.protect}:{},...$.describeIdentity?{describeIdentity:$.describeIdentity}:{}},quota:$.quotaCheck?{check:$.quotaCheck}:{},routing:{orderedVariants:_5,formerMainId:q$},limits:{labels:C5},...$.cache?{cache:$.cache}:{},...$.diagnostics?{diagnostics:$.diagnostics}:{},...$.extras?{extras:$.extras}:{},...$.logger?{logger:$.logger}:{},...$.now?{now:$.now}:{}},X=$.vault?j5(Z,$.vault):R1(Z),J=(z)=>{let{sessionId:G}=z,Q=z.notify.bind(z);return{...G!==void 0?{sessionId:G}:{},notify:Q}};return{command:P1,async open(z){let G=J(z),Q=$.vault&&await $.vault.authority()!=="local"?void 0:await $.migration?.();if(Q&&!Q.migrated)return{command:P1,menu:Z4(Q.blockers)};return X.open(G)},async apply(z,G){let Q=J(G),Y=$.vault&&await $.vault.authority()!=="local"?void 0:await $.migration?.();if(Y&&!Y.migrated)return{command:P1,ok:!1,text:"Nothing was changed: the accounts have not moved to the new layout yet.",menu:Z4(Y.blockers)};let B=await X.apply(z,Q);if(B.ok)await $.afterApply?.();return B}}}var pN=s("quota");function Z6($,Z){let X=Z?$.split(Z).join("[credential]"):$;return e9(X).replaceAll("***REDACTED***","[credential]")}var T5={name:"@cortexkit/pi-openai-auth",version:"1.0.0",license:"MIT",type:"module",repository:{type:"git",url:"git+https://github.com/cortexkit/openai-auth.git",directory:"packages/pi"},main:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},files:["dist","README.md","LICENSE"],keywords:["pi-package"],pi:{extensions:["./dist/index.js"]},scripts:{build:"rm -rf dist && bun build src/index.ts --outdir dist --target node --format esm --external '@earendil-works/pi-ai' --external '@earendil-works/pi-ai/*' --external '@earendil-works/pi-coding-agent' --external '@earendil-works/pi-coding-agent/*' --external '@earendil-works/pi-tui' --external '@earendil-works/pi-tui/*' --minify && bun run build:types","build:types":"cd ../core && bun run build && cd ../pi && tsdown --config tsdown.config.ts --config-loader native",test:"bun test src/tests",typecheck:"tsc",types:"tsc",prepublishOnly:"bun run build"},devDependencies:{"@cortexkit/claustrum-client":"^0.6.2","@cortexkit/common-auth":"^0.14.2","@cortexkit/openai-auth-core":"workspace:*"},peerDependencies:{"@earendil-works/pi-ai":">=1.0.1","@earendil-works/pi-coding-agent":">=1.0.1","@earendil-works/pi-tui":">=1.0.1"}};var K$=new Map;function A5($){return K$.get($)?.accountId}function R5($){return K$.delete($)}function S5($){let Z=K$.get($.sessionId),X=new Set($.validPinnedAccountIds);if(Z&&!$.excludeAccountIds.includes(Z.accountId)&&L$(Z,X,$.wireAccountIdByAccount[Z.accountId])){if($.persist){let Q=$.quotaCheckedAtByAccount[Z.accountId];K$.set($.sessionId,{accountId:Z.accountId,inputBytes:$.requestBytes,...Z.wireIdentity!==void 0?{wireIdentity:Z.wireIdentity}:{},...Q!==void 0?{quotaCheckedAt:Q}:{}})}return{accountId:Z.accountId}}let J=new Map(Object.entries($.quotaCheckedAtByAccount)),z=a3(K$,J,$.sessionId),G=$.select(z);if(!G)return;if($.persist){let Q=$.wireAccountIdByAccount[G.accountId];K$.set($.sessionId,{accountId:G.accountId,inputBytes:$.requestBytes,...Q!==void 0?{wireIdentity:Q}:{},...G.quotaCheckedAt!==void 0?{quotaCheckedAt:G.quotaCheckedAt}:{}})}return{accountId:G.accountId}}import{join as w5}from"node:path";import{createHash as JB}from"node:crypto";import{constants as E5}from"node:fs";import{lstat as g5,mkdir as k5,open as h5,unlink as zB}from"node:fs/promises";import{dirname as g3,resolve as f5}from"node:path";import{setTimeout as GB}from"node:timers/promises";import{rmdirSync as oY,statSync as tY}from"node:fs";import{mkdir as eY,rmdir as $B,stat as v3,utimes as x5}from"node:fs/promises";var ZB=30000,y3=1e4,XB=3000,Q4,X6=new Map;process.once("exit",()=>{for(let[$,Z]of X6)try{if(Z.renewedAt+y3<Date.now())continue;let X=tY($);if(Y4(X,Z)&&X.mtime.getTime()===Z.mtime)oY($)}catch{}});function Y4($,Z){return $.dev===Z.dev&&$.ino===Z.ino}function J6($){return typeof $==="object"&&$!==null&&"code"in $?$.code:void 0}function I5(){return Object.assign(Error("Pi auth lock held"),{code:"ELOCKED"})}async function B4($){try{await $B($)}catch(Z){if(J6(Z)!=="ENOENT")throw Z}}async function W4($,Z){try{await eY($)}catch(X){if(J6(X)!=="EEXIST")throw X;if(Z<=0)throw I5();let J;try{J=(await v3($)).mtime.getTime()}catch(z){if(J6(z)==="ENOENT")return W4($,0);throw z}if(!(J<Date.now()-Z))throw I5();return await B4($),W4($,0)}try{if(!Q4){let z=new Date(Math.ceil(Date.now()/1000)*1000+5);await x5($,z,z)}let X=await v3($),J=X.mtime.getTime();return Q4??=J%1000===0?"s":"ms",{dev:X.dev,ino:X.ino,mtime:J}}catch(X){throw await B4($).catch(()=>{}),X}}async function b5($,Z,X){let J=`${$}.lock`,z=await W4(J,ZB),G=z.mtime,Q=Date.now(),Y=!1,B;X6.set(J,{...z,renewedAt:Q});function H(){if(Y=!0,B)clearTimeout(B);X6.delete(J),Z()}function W(){if(!Y&&Q+y3<Date.now())H()}function V(U=XB){if(Y)return;B=setTimeout(()=>{q()},U),B.unref()}function j(U){if(Y)return;if(J6(U)==="ENOENT"||Q+y3<Date.now())H();else V(1000)}async function q(){if(W(),Y)return;let U;try{U=await v3(J)}catch(N){j(N);return}if(W(),Y)return;if(!Y4(U,z)||U.mtime.getTime()!==G){H();return}let L=new Date(Q4==="s"?Math.ceil(Date.now()/1000)*1000:Date.now());try{await x5(J,L,L)}catch(N){j(N);return}if(Y)return;G=L.getTime(),Q=Date.now(),X6.set(J,{...z,mtime:G,renewedAt:Q}),V()}return X?.(async()=>{if(B)clearTimeout(B);await q()}),V(),{assertFresh:W,async release(){if(Y)return;if(Y=!0,B)clearTimeout(B);X6.delete(J);let U=()=>Q+y3<Date.now();if(U()){H();return}let L;try{L=await v3(J)}catch(N){if(J6(N)!=="ENOENT")throw N;H();return}if(U()||!Y4(L,z)||G!==L.mtime.getTime()){H();return}await B4(J)}}}class a extends Error{code;constructor($){super(`Pi slot: ${$}`);this.code=$,this.name="PiSlotError"}}function QB($){let Z=$.indexOf("{")+1,X={offset:Z-1,children:[]},J=()=>{while(/\s/.test($[Z]??"")&&Z<$.length)Z++},z=()=>{Z++;while(Z<$.length){if($[Z++]==='"')return;if($[Z-1]==="\\")Z++}};J();while($[Z]!=="}"){let G=Z;z();let Q=JSON.parse($.slice(G,Z));J(),Z++,J();let Y=Z,B=0;while(Z<$.length){let W=$[Z];if(W==='"'){z();continue}if(W==="{"||W==="[")B++;if(W==="}"||W==="]"){if(B===0)break;B--}if(W===","&&B===0)break;Z++}let H=Z;while(/\s/.test($[H-1]??""))H--;if(X.children.push({key:Q,offset:G,length:H-G,value:{offset:Y,length:H-Y}}),J(),$[Z]==="}")break;Z++,J()}return X}function z6($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function V4($){if(Array.isArray($))return`[${$.map(V4).join(",")}]`;if(z6($))return`{${Object.keys($).sort().map((Z)=>`${JSON.stringify(Z)}:${V4($[Z])}`).join(",")}}`;return JSON.stringify($)}function d0($){return JB("sha256").update(V4($)).digest("hex")}function h3($){return z6($)?$.code:void 0}async function y5($,Z=!1,X){let J;try{J=await h5($,E5.O_RDONLY|E5.O_NOFOLLOW);let z=await J.stat();if(!z.isFile()||Z&&(z.mode&511)!==384)throw new a("unsafe-path");await X?.($);let G=await g5($);if(!G.isFile()||G.dev!==z.dev||G.ino!==z.ino)throw new a("unsafe-path");let Q=await J.readFile(),Y=Q.toString("utf8");if(!Q.equals(Buffer.from(Y)))throw new a(Z?"invalid-stash":"invalid-auth");return Y}catch(z){if(h3(z)==="ENOENT"&&!J)return;if(h3(z)==="ELOOP"||h3(z)==="ENOENT")throw new a("unsafe-path");throw z}finally{await J?.close()}}function YB($,Z){try{let X=JSON.parse($);if(!z6(X))throw Error();let J=QB($),z=J.children,G=z.map((B)=>B.key);if(new Set(G).size!==G.length)throw Error();let Q=z.find((B)=>B.key===Z),Y=Q?X[Z]:null;if(Y!==null&&!z6(Y))throw Error();if(Q&&Y===null)throw Error();return{text:$,root:J,property:Q,entry:Y}}catch{throw new a("invalid-auth")}}function BB($){let Z=$.property?.value;return Z?$.text.slice(Z.offset,Z.offset+Z.length):null}function v5($,Z,X){let{text:J,root:z,property:G}=$,Q=z.children??[];if(G){let H=G.value;if(!H)throw new a("invalid-auth");if(X!==null)return J.slice(0,H.offset)+X+J.slice(H.offset+H.length);let W=Q.indexOf(G),V=Q[W-1],j=Q[W+1],q=V?V.offset+V.length:G.offset,U=!V&&j?j.offset:G.offset+G.length;return J.slice(0,q)+J.slice(U)}if(X===null)return J;let Y=Q.at(-1),B=Y?Y.offset+Y.length:z.offset+1;return`${J.slice(0,B)}${Y?",":""}${JSON.stringify(Z)}:${X}${J.slice(B)}`}async function WB($){let Z=await h5($,"r");try{await Z.sync()}finally{await Z.close()}}async function H4($,Z,X,J){await P0($,null,{serialize:()=>Z,durable:!0,beforeRename:async()=>{await J?.($),X()}})}function j4($){return HB($)}function HB($,Z,X){let{provider:J,placeholderKey:z}=$,G=$.lockTimeoutMs??30000;if(!J||!$.authPath||!$.stashPath||!z||z.startsWith("!")||z.includes("$")||!Number.isFinite(G)||G<0)throw new a("invalid-options");let Q=f5($.authPath),Y=f5($.stashPath);if(Q===Y||Y===`${Q}.lock`)throw new a("invalid-options");let B=d0(Q),H=d0(z),W={type:"api_key",key:z},V=(N)=>d0(N)===d0(W);async function j(){let N=await y5(Y,!0,X?.afterReadCheck);if(N===void 0)return;try{let K=JSON.parse(N);if(K.version!==1||K.provider!==J||K.authIdentity!==B||K.placeholderIdentity!==H||K.entry!==null&&!z6(K.entry)||K.sha256!==d0(K.entry)||(K.entry===null?K.entryJson!==null:typeof K.entryJson!=="string"||d0(JSON.parse(K.entryJson))!==K.sha256))throw Error();return K}catch{throw new a("invalid-stash")}}async function q(N){let K,F,C=!1,M=()=>{if(F?.(),C)throw new a("lock-compromised")};try{await k5(g3(Q),{recursive:!0,mode:448});let D=Date.now()+G,P=0;while(!K)try{let f=await b5(Q,()=>{C=!0},X?.onRenew);K=f.release,F=f.assertFresh}catch(f){if(h3(f)!=="ELOCKED")throw f;let n=D-Date.now();if(n<=0)throw new a("lock-timeout");await GB(Math.min(Math.round(Math.min(10*2**P++,1000)*(1+Math.random())),n))}M();let S=await N(M);return M(),S}catch(D){if(D instanceof a)throw D;throw new a("io")}finally{await K?.().catch(()=>{}),M()}}async function U(){let N=YB(await y5(Q,!1,X?.afterReadCheck)??"{}",J),K=await j();return{auth:N,stash:K}}async function L(N){N(),await zB(Y),await WB(g3(Y)),Z?.("stash-deleted")}return{inspect:()=>q(async()=>{let{auth:N,stash:K}=await U();return{slot:V(N.entry)?"placeholder":N.entry===null?"empty":!K||d0(N.entry)===K.sha256?"original":"foreign",stash:K?"valid":"missing"}}),enterVault:()=>q(async(N)=>{let{auth:K,stash:F}=await U();if(V(K.entry)){if(!F)throw new a("missing-stash");return}if(F&&d0(K.entry)!==F.sha256)throw new a("conflict");if(!F){await k5(g3(Y),{recursive:!0,mode:448});let C=await g5(g3(Y));if(!C.isDirectory()||(C.mode&511)!==448)throw new a("unsafe-path");let M={version:1,provider:J,authIdentity:B,placeholderIdentity:H,entry:K.entry,entryJson:BB(K),sha256:d0(K.entry)};await H4(Y,JSON.stringify(M),N,X?.beforeRename),Z?.("stash-written")}await H4(Q,v5(K,J,JSON.stringify(W)),N,X?.beforeRename),Z?.("auth-written")}),exitVault:()=>q(async(N)=>{let{auth:K,stash:F}=await U();if(!F){if(V(K.entry))throw new a("missing-stash");return"nothing-to-do"}if(V(K.entry))await H4(Q,v5(K,J,F.entryJson),N,X?.beforeRename),Z?.("auth-written");else if(d0(K.entry)!==F.sha256)return"conflict";return await L(N),"restored"})}}import{getAgentDir as VB}from"@earendil-works/pi-coding-agent";var G6="openai-auth-vault-mode-not-a-credential",m5="Request refused locally: Pi has not loaded the credential vault placeholder. Reopen the session or disconnect Pi from the vault in /openai; local credentials are not used while connected.",p5="A Pi login was added while connected to the vault. Both that login and the stashed original are kept; neither was overwritten.";function u5($){return j4({authPath:w5(VB(),"auth.json"),provider:"openai-codex",stashPath:w5(x3($),"pi-openai-codex-login.json"),placeholderKey:G6})}function jB($){return{id:"pi-login",title:"Pi login",build:()=>{let Z=$(),X=Date.now(),J=c({limits:["primary","secondary"].flatMap((G)=>{let Q=Z?.[G];return Q?[{...Q,kind:"reading",scope:"all",label:G,checkedAt:Q.checkedAt??X}]:[]}),...Z?.spendControl?{budget:{...Z.spendControl,kind:"reading",checkedAt:X}}:{}}),z=p1(J,{now:X});return{lines:["Managed by Pi /login",...z.length>0?z:[T0(J,{now:X})]]}}}}function UB($,Z={}){let X=Z.beginAccountLogin??QZ,J=Z.packageVersion??T5.version,z=z4({vault:$.vault,changed:Z.afterApply,...Z.vaultWait?{wait:Z.vaultWait}:{}}),G=G4({store:$.store(),vault:$.vault,login:{begin:(Q)=>X({...Q,version:J}),mainIdentity:async()=>$.mainIdentity()},quotaCheck:async(Q)=>{if(Q.length===1){let B=$.store();for(let H of Q)await B.requestReading(H);await B.pullsSettled();return}let Y=(await $.refreshAllQuota()).filter((B)=>!B.ok);if(Y.length>0)throw new j0("quota-check-failed",Y.map((B)=>`${B.account}: ${B.error??"quota check failed"}`).join(`
|
|
113
|
+
`)}}}]}}}}var _5=[{value:"main-first",label:"Main first"},{value:"fallback-first",label:"Fallback first"}],C5=["primary","secondary"];function G4($){let Z={command:P1,title:X4,store:e2(M5(L5($.store,{...$.rowLocks?{rowLocks:$.rowLocks}:{}}))),...$.extraLocks?{extraLocks:$.extraLocks}:{},accounts:{...$.login?{login:O5($.login)}:{},...$.protect?{protect:$.protect}:{},...$.describeIdentity?{describeIdentity:$.describeIdentity}:{}},quota:$.quotaCheck?{check:$.quotaCheck}:{},routing:{orderedVariants:_5,formerMainId:q$},limits:{labels:C5},...$.cache?{cache:$.cache}:{},...$.diagnostics?{diagnostics:$.diagnostics}:{},...$.extras?{extras:$.extras}:{},...$.logger?{logger:$.logger}:{},...$.now?{now:$.now}:{}},X=$.vault?j5(Z,$.vault):R1(Z),J=(z)=>{let{sessionId:G}=z,Q=z.notify.bind(z);return{...G!==void 0?{sessionId:G}:{},notify:Q}};return{command:P1,async open(z){let G=J(z),Q=$.vault&&await $.vault.authority()!=="local"?void 0:await $.migration?.();if(Q&&!Q.migrated)return{command:P1,menu:Z4(Q.blockers)};return X.open(G)},async apply(z,G){let Q=J(G),Y=$.vault&&await $.vault.authority()!=="local"?void 0:await $.migration?.();if(Y&&!Y.migrated)return{command:P1,ok:!1,text:"Nothing was changed: the accounts have not moved to the new layout yet.",menu:Z4(Y.blockers)};let B=await X.apply(z,Q);if(B.ok)await $.afterApply?.();return B}}}var pN=s("quota");function Z6($,Z){let X=Z?$.split(Z).join("[credential]"):$;return e9(X).replaceAll("***REDACTED***","[credential]")}var T5={name:"@cortexkit/pi-openai-auth",version:"1.0.1",license:"MIT",type:"module",repository:{type:"git",url:"git+https://github.com/cortexkit/openai-auth.git",directory:"packages/pi"},main:"./dist/index.js",types:"./dist/index.d.ts",exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"}},files:["dist","README.md","LICENSE"],keywords:["pi-package"],pi:{extensions:["./dist/index.js"]},scripts:{build:"rm -rf dist && bun build src/index.ts --outdir dist --target node --format esm --external '@earendil-works/pi-ai' --external '@earendil-works/pi-ai/*' --external '@earendil-works/pi-coding-agent' --external '@earendil-works/pi-coding-agent/*' --external '@earendil-works/pi-tui' --external '@earendil-works/pi-tui/*' --minify && bun run build:types","build:types":"cd ../core && bun run build && cd ../pi && tsdown --config tsdown.config.ts --config-loader native",test:"bun test src/tests",typecheck:"tsc",types:"tsc",prepublishOnly:"bun run build"},devDependencies:{"@cortexkit/claustrum-client":"^0.6.2","@cortexkit/common-auth":"^0.14.2","@cortexkit/openai-auth-core":"workspace:*"},peerDependencies:{"@earendil-works/pi-ai":">=1.0.1","@earendil-works/pi-coding-agent":">=1.0.1","@earendil-works/pi-tui":">=1.0.1"}};var K$=new Map;function A5($){return K$.get($)?.accountId}function R5($){return K$.delete($)}function S5($){let Z=K$.get($.sessionId),X=new Set($.validPinnedAccountIds);if(Z&&!$.excludeAccountIds.includes(Z.accountId)&&L$(Z,X,$.wireAccountIdByAccount[Z.accountId])){if($.persist){let Q=$.quotaCheckedAtByAccount[Z.accountId];K$.set($.sessionId,{accountId:Z.accountId,inputBytes:$.requestBytes,...Z.wireIdentity!==void 0?{wireIdentity:Z.wireIdentity}:{},...Q!==void 0?{quotaCheckedAt:Q}:{}})}return{accountId:Z.accountId}}let J=new Map(Object.entries($.quotaCheckedAtByAccount)),z=a3(K$,J,$.sessionId),G=$.select(z);if(!G)return;if($.persist){let Q=$.wireAccountIdByAccount[G.accountId];K$.set($.sessionId,{accountId:G.accountId,inputBytes:$.requestBytes,...Q!==void 0?{wireIdentity:Q}:{},...G.quotaCheckedAt!==void 0?{quotaCheckedAt:G.quotaCheckedAt}:{}})}return{accountId:G.accountId}}import{join as w5}from"node:path";import{createHash as JB}from"node:crypto";import{constants as E5}from"node:fs";import{lstat as g5,mkdir as k5,open as h5,unlink as zB}from"node:fs/promises";import{dirname as g3,resolve as f5}from"node:path";import{setTimeout as GB}from"node:timers/promises";import{rmdirSync as oY,statSync as tY}from"node:fs";import{mkdir as eY,rmdir as $B,stat as v3,utimes as x5}from"node:fs/promises";var ZB=30000,y3=1e4,XB=3000,Q4,X6=new Map;process.once("exit",()=>{for(let[$,Z]of X6)try{if(Z.renewedAt+y3<Date.now())continue;let X=tY($);if(Y4(X,Z)&&X.mtime.getTime()===Z.mtime)oY($)}catch{}});function Y4($,Z){return $.dev===Z.dev&&$.ino===Z.ino}function J6($){return typeof $==="object"&&$!==null&&"code"in $?$.code:void 0}function I5(){return Object.assign(Error("Pi auth lock held"),{code:"ELOCKED"})}async function B4($){try{await $B($)}catch(Z){if(J6(Z)!=="ENOENT")throw Z}}async function W4($,Z){try{await eY($)}catch(X){if(J6(X)!=="EEXIST")throw X;if(Z<=0)throw I5();let J;try{J=(await v3($)).mtime.getTime()}catch(z){if(J6(z)==="ENOENT")return W4($,0);throw z}if(!(J<Date.now()-Z))throw I5();return await B4($),W4($,0)}try{if(!Q4){let z=new Date(Math.ceil(Date.now()/1000)*1000+5);await x5($,z,z)}let X=await v3($),J=X.mtime.getTime();return Q4??=J%1000===0?"s":"ms",{dev:X.dev,ino:X.ino,mtime:J}}catch(X){throw await B4($).catch(()=>{}),X}}async function b5($,Z,X){let J=`${$}.lock`,z=await W4(J,ZB),G=z.mtime,Q=Date.now(),Y=!1,B;X6.set(J,{...z,renewedAt:Q});function H(){if(Y=!0,B)clearTimeout(B);X6.delete(J),Z()}function W(){if(!Y&&Q+y3<Date.now())H()}function V(U=XB){if(Y)return;B=setTimeout(()=>{q()},U),B.unref()}function j(U){if(Y)return;if(J6(U)==="ENOENT"||Q+y3<Date.now())H();else V(1000)}async function q(){if(W(),Y)return;let U;try{U=await v3(J)}catch(N){j(N);return}if(W(),Y)return;if(!Y4(U,z)||U.mtime.getTime()!==G){H();return}let L=new Date(Q4==="s"?Math.ceil(Date.now()/1000)*1000:Date.now());try{await x5(J,L,L)}catch(N){j(N);return}if(Y)return;G=L.getTime(),Q=Date.now(),X6.set(J,{...z,mtime:G,renewedAt:Q}),V()}return X?.(async()=>{if(B)clearTimeout(B);await q()}),V(),{assertFresh:W,async release(){if(Y)return;if(Y=!0,B)clearTimeout(B);X6.delete(J);let U=()=>Q+y3<Date.now();if(U()){H();return}let L;try{L=await v3(J)}catch(N){if(J6(N)!=="ENOENT")throw N;H();return}if(U()||!Y4(L,z)||G!==L.mtime.getTime()){H();return}await B4(J)}}}class a extends Error{code;constructor($){super(`Pi slot: ${$}`);this.code=$,this.name="PiSlotError"}}function QB($){let Z=$.indexOf("{")+1,X={offset:Z-1,children:[]},J=()=>{while(/\s/.test($[Z]??"")&&Z<$.length)Z++},z=()=>{Z++;while(Z<$.length){if($[Z++]==='"')return;if($[Z-1]==="\\")Z++}};J();while($[Z]!=="}"){let G=Z;z();let Q=JSON.parse($.slice(G,Z));J(),Z++,J();let Y=Z,B=0;while(Z<$.length){let W=$[Z];if(W==='"'){z();continue}if(W==="{"||W==="[")B++;if(W==="}"||W==="]"){if(B===0)break;B--}if(W===","&&B===0)break;Z++}let H=Z;while(/\s/.test($[H-1]??""))H--;if(X.children.push({key:Q,offset:G,length:H-G,value:{offset:Y,length:H-Y}}),J(),$[Z]==="}")break;Z++,J()}return X}function z6($){return typeof $==="object"&&$!==null&&!Array.isArray($)}function V4($){if(Array.isArray($))return`[${$.map(V4).join(",")}]`;if(z6($))return`{${Object.keys($).sort().map((Z)=>`${JSON.stringify(Z)}:${V4($[Z])}`).join(",")}}`;return JSON.stringify($)}function d0($){return JB("sha256").update(V4($)).digest("hex")}function h3($){return z6($)?$.code:void 0}async function y5($,Z=!1,X){let J;try{J=await h5($,E5.O_RDONLY|E5.O_NOFOLLOW);let z=await J.stat();if(!z.isFile()||Z&&(z.mode&511)!==384)throw new a("unsafe-path");await X?.($);let G=await g5($);if(!G.isFile()||G.dev!==z.dev||G.ino!==z.ino)throw new a("unsafe-path");let Q=await J.readFile(),Y=Q.toString("utf8");if(!Q.equals(Buffer.from(Y)))throw new a(Z?"invalid-stash":"invalid-auth");return Y}catch(z){if(h3(z)==="ENOENT"&&!J)return;if(h3(z)==="ELOOP"||h3(z)==="ENOENT")throw new a("unsafe-path");throw z}finally{await J?.close()}}function YB($,Z){try{let X=JSON.parse($);if(!z6(X))throw Error();let J=QB($),z=J.children,G=z.map((B)=>B.key);if(new Set(G).size!==G.length)throw Error();let Q=z.find((B)=>B.key===Z),Y=Q?X[Z]:null;if(Y!==null&&!z6(Y))throw Error();if(Q&&Y===null)throw Error();return{text:$,root:J,property:Q,entry:Y}}catch{throw new a("invalid-auth")}}function BB($){let Z=$.property?.value;return Z?$.text.slice(Z.offset,Z.offset+Z.length):null}function v5($,Z,X){let{text:J,root:z,property:G}=$,Q=z.children??[];if(G){let H=G.value;if(!H)throw new a("invalid-auth");if(X!==null)return J.slice(0,H.offset)+X+J.slice(H.offset+H.length);let W=Q.indexOf(G),V=Q[W-1],j=Q[W+1],q=V?V.offset+V.length:G.offset,U=!V&&j?j.offset:G.offset+G.length;return J.slice(0,q)+J.slice(U)}if(X===null)return J;let Y=Q.at(-1),B=Y?Y.offset+Y.length:z.offset+1;return`${J.slice(0,B)}${Y?",":""}${JSON.stringify(Z)}:${X}${J.slice(B)}`}async function WB($){let Z=await h5($,"r");try{await Z.sync()}finally{await Z.close()}}async function H4($,Z,X,J){await P0($,null,{serialize:()=>Z,durable:!0,beforeRename:async()=>{await J?.($),X()}})}function j4($){return HB($)}function HB($,Z,X){let{provider:J,placeholderKey:z}=$,G=$.lockTimeoutMs??30000;if(!J||!$.authPath||!$.stashPath||!z||z.startsWith("!")||z.includes("$")||!Number.isFinite(G)||G<0)throw new a("invalid-options");let Q=f5($.authPath),Y=f5($.stashPath);if(Q===Y||Y===`${Q}.lock`)throw new a("invalid-options");let B=d0(Q),H=d0(z),W={type:"api_key",key:z},V=(N)=>d0(N)===d0(W);async function j(){let N=await y5(Y,!0,X?.afterReadCheck);if(N===void 0)return;try{let K=JSON.parse(N);if(K.version!==1||K.provider!==J||K.authIdentity!==B||K.placeholderIdentity!==H||K.entry!==null&&!z6(K.entry)||K.sha256!==d0(K.entry)||(K.entry===null?K.entryJson!==null:typeof K.entryJson!=="string"||d0(JSON.parse(K.entryJson))!==K.sha256))throw Error();return K}catch{throw new a("invalid-stash")}}async function q(N){let K,F,C=!1,M=()=>{if(F?.(),C)throw new a("lock-compromised")};try{await k5(g3(Q),{recursive:!0,mode:448});let D=Date.now()+G,P=0;while(!K)try{let f=await b5(Q,()=>{C=!0},X?.onRenew);K=f.release,F=f.assertFresh}catch(f){if(h3(f)!=="ELOCKED")throw f;let n=D-Date.now();if(n<=0)throw new a("lock-timeout");await GB(Math.min(Math.round(Math.min(10*2**P++,1000)*(1+Math.random())),n))}M();let S=await N(M);return M(),S}catch(D){if(D instanceof a)throw D;throw new a("io")}finally{await K?.().catch(()=>{}),M()}}async function U(){let N=YB(await y5(Q,!1,X?.afterReadCheck)??"{}",J),K=await j();return{auth:N,stash:K}}async function L(N){N(),await zB(Y),await WB(g3(Y)),Z?.("stash-deleted")}return{inspect:()=>q(async()=>{let{auth:N,stash:K}=await U();return{slot:V(N.entry)?"placeholder":N.entry===null?"empty":!K||d0(N.entry)===K.sha256?"original":"foreign",stash:K?"valid":"missing"}}),enterVault:()=>q(async(N)=>{let{auth:K,stash:F}=await U();if(V(K.entry)){if(!F)throw new a("missing-stash");return}if(F&&d0(K.entry)!==F.sha256)throw new a("conflict");if(!F){await k5(g3(Y),{recursive:!0,mode:448});let C=await g5(g3(Y));if(!C.isDirectory()||(C.mode&511)!==448)throw new a("unsafe-path");let M={version:1,provider:J,authIdentity:B,placeholderIdentity:H,entry:K.entry,entryJson:BB(K),sha256:d0(K.entry)};await H4(Y,JSON.stringify(M),N,X?.beforeRename),Z?.("stash-written")}await H4(Q,v5(K,J,JSON.stringify(W)),N,X?.beforeRename),Z?.("auth-written")}),exitVault:()=>q(async(N)=>{let{auth:K,stash:F}=await U();if(!F){if(V(K.entry))throw new a("missing-stash");return"nothing-to-do"}if(V(K.entry))await H4(Q,v5(K,J,F.entryJson),N,X?.beforeRename),Z?.("auth-written");else if(d0(K.entry)!==F.sha256)return"conflict";return await L(N),"restored"})}}import{getAgentDir as VB}from"@earendil-works/pi-coding-agent";var G6="openai-auth-vault-mode-not-a-credential",m5="Request refused locally: Pi has not loaded the credential vault placeholder. Reopen the session or disconnect Pi from the vault in /openai; local credentials are not used while connected.",p5="A Pi login was added while connected to the vault. Both that login and the stashed original are kept; neither was overwritten.";function u5($){return j4({authPath:w5(VB(),"auth.json"),provider:"openai-codex",stashPath:w5(x3($),"pi-openai-codex-login.json"),placeholderKey:G6})}function jB($){return{id:"pi-login",title:"Pi login",build:()=>{let Z=$(),X=Date.now(),J=c({limits:["primary","secondary"].flatMap((G)=>{let Q=Z?.[G];return Q?[{...Q,kind:"reading",scope:"all",label:G,checkedAt:Q.checkedAt??X}]:[]}),...Z?.spendControl?{budget:{...Z.spendControl,kind:"reading",checkedAt:X}}:{}}),z=p1(J,{now:X});return{lines:["Managed by Pi /login",...z.length>0?z:[T0(J,{now:X})]]}}}}function UB($,Z={}){let X=Z.beginAccountLogin??QZ,J=Z.packageVersion??T5.version,z=z4({vault:$.vault,changed:Z.afterApply,...Z.vaultWait?{wait:Z.vaultWait}:{}}),G=G4({store:$.store(),vault:$.vault,login:{begin:(Q)=>X({...Q,version:J}),mainIdentity:async()=>$.mainIdentity()},quotaCheck:async(Q)=>{if(Q.length===1){let B=$.store();for(let H of Q)await B.requestReading(H);await B.pullsSettled();return}let Y=(await $.refreshAllQuota()).filter((B)=>!B.ok);if(Y.length>0)throw new j0("quota-check-failed",Y.map((B)=>`${B.account}: ${B.error??"quota check failed"}`).join(`
|
|
114
114
|
`))},extras:[jB(()=>$.mainQuota()),J4({getPin:async(Q)=>A5(Q),clearPin:async(Q)=>R5(Q)}),{...z,build:async(Q)=>{let Y=await z.build(Q),B={id:"disconnect",label:"Disconnect",confirm:"Disconnect this Pi host from the vault and restore its original login?",run:async()=>{let W;try{W=await $.disconnectVault?.()}catch{let V=!1;try{await Z.afterApply?.()}catch{V=!0}let j=await $.readAuthority();throw new j0("vault-disconnect-failed",[j==="local"?"Disconnect did not finish cleanly; local accounts are active. Retry Disconnect if Pi login restoration did not complete.":"Disconnect failed; Pi is still enrolled or enrollment is unreadable. Local accounts remain disabled; retry Disconnect to restore the login.",...V?["Pi could not reload its auth snapshot; reopen the session."]:[]].join(`
|
|
115
115
|
`))}return await Z.afterApply?.(),[`Disconnected: ${$.vault.name} no longer reads from the vault. Run \`ck auth enroll revoke --name ${$.vault.name}\` to revoke it in the vault too.`,...W==="conflict"?[p5]:[]].join(`
|
|
116
116
|
`)}},H=Y.actions??[];return{...Y,actions:[...H.map((W)=>W.id==="disconnect"&&$.disconnectVault?{...W,run:B.run}:W),...$.vaultMode()&&$.disconnectVault&&!H.some((W)=>W.id==="disconnect")?[B]:[]]}}}],afterApply:async()=>{return await Z.afterApply?.(),$.reload()}});return{command:G.command,open:async(Q)=>{return await $.readAuthority(),G.open(Q)},apply:async(Q,Y)=>{return await $.readAuthority(),G.apply(Q,Y)}}}async function qB($,Z){let X=Z.pool;if(!X){$.ui.notify("The OpenAI account pool is not available.","error");return}if(Z.onContext?.($),Z.afterApply)await Z.afterApply();else await X.syncVaultSlot?.(()=>$.modelRegistry.refresh(),!0);if(!X.vaultMode())try{await X.observeLogin(await $.modelRegistry?.getApiKeyForProvider("openai-codex"))}catch{}await k8(UB(X,Z),$.ui,{sessionId:$.sessionManager.getSessionId()})}function l5($,Z={}){$.registerCommand(P1,{description:"OpenAI accounts: add and manage accounts, quota, routing and limits",handler:(X,J)=>qB(J,Z)})}import{connect as KB}from"node:net";import{connect as DB}from"node:tls";var NB="258EAFA5-E914-47DA-95CA-C5AB0DC85B11",d5=["chatgpt-account-id","authorization","user-agent","originator","openai-beta","version","x-codex-beta-features","x-codex-turn-metadata","x-client-request-id","session-id","thread-id","x-codex-window-id"];class U4{url;readyState=0;socket;listeners={open:new Set,message:new Set,error:new Set,close:new Set};rxBuffer=new Uint8Array(0);handshakeDone=!1;expectedAccept="";fragOpcode=0;fragChunks=[];constructor($,Z){this.url=$,this.connect($,Z)}addEventListener($,Z,X){this.listeners[$]?.add(Z)}removeEventListener($,Z){this.listeners[$]?.delete(Z)}emit($,Z){for(let X of[...this.listeners[$]??[]])try{X(Z)}catch{}}async connect($,Z){let X=new URL($.replace(/^ws:/,"http:").replace(/^wss:/,"https:")),J=X.hostname,z=X.port?Number(X.port):X.protocol==="https:"?443:80,G=`${X.pathname}${X.search}`,Q=crypto.getRandomValues(new Uint8Array(16)),Y=Buffer.from(Q).toString("base64"),B=await crypto.subtle.digest("SHA-1",new TextEncoder().encode(Y+NB));this.expectedAccept=Buffer.from(new Uint8Array(B)).toString("base64");let H={};for(let[j,q]of Object.entries(Z))H[j.toLowerCase()]=q;let W=[`GET ${G} HTTP/1.1`,`Host: ${J}`,"Connection: Upgrade","Upgrade: websocket","Sec-WebSocket-Version: 13",`Sec-WebSocket-Key: ${Y}`];for(let j of d5)if(H[j]!==void 0)W.push(`${MB(j)}: ${H[j]}`);for(let[j,q]of Object.entries(Z))if(!d5.includes(j.toLowerCase())&&j.toLowerCase()!=="content-length")W.push(`${j}: ${q}`);let V=`${W.join(`\r
|