@cortexkit/opencode-openai-auth 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -60
- package/dist/bin.js +13 -0
- package/dist/index-2hch7e8n.js +8 -0
- package/dist/{index-766sfrh5.js → index-45qgkb0m.js} +1 -1
- package/dist/index-5dg931q0.js +65 -0
- package/dist/index-99esnzg0.js +157 -0
- package/dist/index-9reyazwh.js +2 -0
- package/dist/index-bgq9d21h.js +2 -0
- package/dist/index-dryydk6b.js +2 -0
- package/dist/index-egrty6tz.js +12 -0
- package/dist/index-envpbt0k.js +3 -0
- package/dist/index-jye6vccc.js +2 -0
- package/dist/index-k4eacw7x.js +2 -0
- package/dist/{index-hy9030jh.js → index-yeyp8t0k.js} +1 -1
- package/dist/index-yf6arn5w.js +2 -0
- package/dist/index.d.ts +2 -56
- package/dist/index.js +1 -1
- package/dist/map-CCbSZIhT.d.ts +56 -0
- package/dist/{pool-lifecycle-YLz2B8A5.d.ts → pool-lifecycle-DqKq8Eej.d.ts} +99 -789
- package/dist/{port-file-Do3lQIEk.d.ts → port-file-CZ9MIdy2.d.ts} +1 -1
- package/dist/{protocol-BOBdkqqm.d.ts → protocol-CSIDDBDf.d.ts} +1 -1
- package/dist/rpc/port-file.d.ts +1 -1
- package/dist/rpc/port-file.js +1 -1
- package/dist/rpc/protocol.d.ts +1 -1
- package/dist/rpc/protocol.js +1 -1
- package/dist/rpc/rpc-client.d.ts +3 -3
- package/dist/rpc/rpc-client.js +1 -1
- package/dist/rpc/rpc-dir.js +1 -1
- package/dist/{sidebar-state-D6cUKgkm.d.ts → sidebar-state-BCxFpH68.d.ts} +5 -3
- package/dist/sidebar-state.d.ts +1 -1
- package/dist/sidebar-state.js +1 -1
- package/dist/token-util-gmn5yaqc.js +1 -0
- package/dist/{token-ypk61xj0.js → token-vykm9bxh.js} +1 -1
- package/dist/tui-preferences.d.ts +2 -1
- package/dist/tui-preferences.js +3 -3
- package/dist/tui.d.ts +2 -2
- package/dist/v2/server.d.ts +1 -1
- package/dist/v2/server.js +3 -4
- package/package.json +13 -8
- package/src/tui-compiled/raw/logger.js +10 -2
- package/src/tui-compiled/raw/shared/053cc17b5419261e-codec.js +2 -1
- package/src/tui-compiled/raw/shared/0766d78c6f481f18-watcher.js +26 -10
- package/src/tui-compiled/raw/shared/375d9cca2def037d-private-files.js +302 -0
- package/src/tui-compiled/raw/shared/39c3cb05738fcf6d-projection.js +3 -1
- package/src/tui-compiled/raw/shared/43fc9e6b994519c7-refresh-lock.js +5 -0
- package/src/tui-compiled/raw/shared/458b934e92490331-mutate.js +2 -2
- package/src/tui-compiled/raw/shared/4825e03209d6ae3e-with-lock.js +4 -0
- package/src/tui-compiled/raw/shared/4f36d333d081d040-merge.js +21 -5
- package/src/tui-compiled/raw/shared/7211cfec06a298bc-atomic-write.js +21 -0
- package/src/tui-compiled/raw/shared/905bffc0220f43d0-map.js +36 -1
- package/src/tui-compiled/raw/shared/a09b6a533c11858f-tui-preferences.js +6 -4
- package/src/tui-compiled/raw/shared/c14988621dc60a75-port-file.js +30 -8
- package/src/tui-compiled/raw/shared/c64d7afbc14ca125-sidebar-file.js +17 -8
- package/src/tui-compiled/raw/shared/c852a15cfe489d12-pool.js +3 -0
- package/src/tui-compiled/raw/shared/cd94316a888b0a8e-schema.js +3 -2
- package/src/tui-compiled/raw/shared/d5a8f1061ee2f114-index.js +1 -1
- package/src/tui-compiled/raw/shared/d7dcba96fea1685c-engine.js +126 -11
- package/src/tui-compiled/raw/shared/e8cd4929507508d8-refresh-file-lock.js +254 -37
- package/src/tui-compiled/raw/shared/ec971142548df90e-index.js +1 -0
- package/src/tui-compiled/raw/shared/fbcdcd0f925e74c0-rpc-client.js +15 -1
- package/src/tui-compiled/runtime/logger.js +10 -2
- package/src/tui-compiled/runtime/shared/053cc17b5419261e-codec.js +2 -1
- package/src/tui-compiled/runtime/shared/0766d78c6f481f18-watcher.js +26 -10
- package/src/tui-compiled/runtime/shared/375d9cca2def037d-private-files.js +302 -0
- package/src/tui-compiled/runtime/shared/39c3cb05738fcf6d-projection.js +3 -1
- package/src/tui-compiled/runtime/shared/43fc9e6b994519c7-refresh-lock.js +5 -0
- package/src/tui-compiled/runtime/shared/458b934e92490331-mutate.js +2 -2
- package/src/tui-compiled/runtime/shared/4825e03209d6ae3e-with-lock.js +4 -0
- package/src/tui-compiled/runtime/shared/4f36d333d081d040-merge.js +21 -5
- package/src/tui-compiled/runtime/shared/7211cfec06a298bc-atomic-write.js +21 -0
- package/src/tui-compiled/runtime/shared/905bffc0220f43d0-map.js +36 -1
- package/src/tui-compiled/runtime/shared/a09b6a533c11858f-tui-preferences.js +6 -4
- package/src/tui-compiled/runtime/shared/c14988621dc60a75-port-file.js +30 -8
- package/src/tui-compiled/runtime/shared/c64d7afbc14ca125-sidebar-file.js +17 -8
- package/src/tui-compiled/runtime/shared/c852a15cfe489d12-pool.js +3 -0
- package/src/tui-compiled/runtime/shared/cd94316a888b0a8e-schema.js +3 -2
- package/src/tui-compiled/runtime/shared/d5a8f1061ee2f114-index.js +1 -1
- package/src/tui-compiled/runtime/shared/d7dcba96fea1685c-engine.js +126 -11
- package/src/tui-compiled/runtime/shared/e8cd4929507508d8-refresh-file-lock.js +254 -37
- package/src/tui-compiled/runtime/shared/ec971142548df90e-index.js +1 -0
- package/src/tui-compiled/runtime/shared/fbcdcd0f925e74c0-rpc-client.js +15 -1
- package/dist/index-8kj7sa1p.js +0 -12
- package/dist/index-b3q3j39x.js +0 -2
- package/dist/index-bmd7x5aq.js +0 -2
- package/dist/index-ff1jy44a.js +0 -222
- package/dist/index-jyr8y8k4.js +0 -7
- package/dist/index-rv08jmd4.js +0 -2
- package/dist/index-sjx8t1nr.js +0 -2
- package/dist/token-util-wdza526f.js +0 -1
package/README.md
CHANGED
|
@@ -1,71 +1,23 @@
|
|
|
1
1
|
# @cortexkit/opencode-openai-auth
|
|
2
2
|
|
|
3
|
-
ChatGPT Plus
|
|
3
|
+
The OpenCode package of [CortexKit OpenAI Auth](https://github.com/cortexkit/openai-auth). It lets OpenCode 1 and 2 use a ChatGPT Plus or Pro subscription through the OpenAI Codex backend, with several accounts and sticky routing (keeping each session on one account), usage limits per account, prompt-cache keep-warm on OpenCode 1 (keeping idle sessions' prompts cached), and optional Claustrum vault integration. The Pi package is [`@cortexkit/pi-openai-auth`](https://www.npmjs.com/package/@cortexkit/pi-openai-auth).
|
|
4
4
|
|
|
5
|
-
This
|
|
6
|
-
|
|
7
|
-
The plugin registers the built-in `openai` provider id. OpenCode loads external plugins after its built-ins, so this package supersedes OpenCode's internal OpenAI auth hook without any change to your model configuration.
|
|
5
|
+
> This plugin is not affiliated with or endorsed by OpenAI. Using a subscription this way may be against OpenAI's terms, and OpenAI may limit or suspend accounts. You use it at your own risk; the authors accept no responsibility for any action the provider takes.
|
|
8
6
|
|
|
9
7
|
## Install
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
{
|
|
13
|
-
"plugin": ["@cortexkit/opencode-openai-auth@1.0.3"]
|
|
14
|
-
}
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Restart OpenCode after changing plugin config, then authenticate:
|
|
18
|
-
|
|
19
|
-
```text
|
|
20
|
-
/login openai
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
If this OpenCode host is already enrolled in the Claustrum vault, choose **ChatGPT accounts in the vault** instead of signing in to ChatGPT. This no-browser activation creates no local account and gives OpenCode only a non-routable placeholder. OpenCode 1 refuses to replace any existing `openai` record in `auth.json`, and refuses malformed or unreadable files without changing them; a missing file is allowed on a fresh install. Enrollment is checked again before activation completes.
|
|
24
|
-
|
|
25
|
-
## OpenCode 2
|
|
26
|
-
|
|
27
|
-
On OpenCode 2 (`@opencode/cli`, tested on 2.0.22) list the same package under `plugins`; OpenCode 2 loads its `./server` entry. OpenCode 2's own OpenAI driver sends the requests, and the plugin chooses the account from the shared account pool and sets its credential through OpenCode 2's session hooks. Signing in with one of the plugin's pool methods (`opencode auth login openai`, then **ChatGPT (openai-auth pool, …)**) puts the login in the pool, and OpenCode 2 keeps only a placeholder; OpenCode 2's own ChatGPT login and API keys pass through untouched. The `/openai` menu, the sidebar, keep-warm and OpenCode 1's Codex request shaping are not available there yet. See the [repository README](https://github.com/cortexkit/openai-auth#opencode-2) for the details.
|
|
28
|
-
|
|
29
|
-
Choose **ChatGPT (openai-auth pool, browser)** or **ChatGPT (openai-auth pool, headless)** in `opencode auth login openai` to use the pool. The plugin serves a request only when the host-prepared Authorization bearer equals its pool placeholder exactly. API keys, environment keys and OpenCode's own ChatGPT logins pass through unchanged, without pool quota or attribution; switching connections takes effect on the next request. A placeholder with no usable pool account is refused locally, never sent upstream. Existing host ChatGPT logins are never copied into the pool: choose a pool login to obtain a separate OAuth token family, leaving the host's login and refresh methods intact.
|
|
30
|
-
|
|
31
|
-
For vault-only use on OpenCode 2, choose **ChatGPT accounts in the vault**, or run `opencode2 auth login openai --method openai-auth-vault` (substitute the name of your OpenCode 2 executable). Activation requires enrollment under `openai-auth-opencode`, shared with OpenCode 1, performs no OAuth and writes no account to the pool. The host receives only the placeholder under this method's ID.
|
|
32
|
-
|
|
33
|
-
## Features
|
|
34
|
-
|
|
35
|
-
- ChatGPT Plus/Pro OAuth login (browser and headless device flows), plus a manual API-key fallback.
|
|
36
|
-
- Codex request rewriting for OAuth requests, with Codex identity parity.
|
|
37
|
-
- OAuth model filtering and zero-cost display.
|
|
38
|
-
- Multiple ChatGPT accounts with automatic reactive fallback on rate limits, `main-first`, `fallback-first`, or sticky-balanced routing, and a per-account quota killswitch.
|
|
39
|
-
- Per-turn quota tracking (5-hour + weekly windows) on both transports, with a sidebar readout and an explicit all-accounts refresh.
|
|
40
|
-
- Idle prompt-cache keep-warm, with an optional subagent mode and main-only sustain mode.
|
|
41
|
-
- Leveled, secret-redacting, rotating log file.
|
|
42
|
-
- One interactive `/openai` menu in the TUI, including account management and headless device-code authentication.
|
|
43
|
-
- Optional OpenAI Responses WebSocket transport (HTTP is the default).
|
|
44
|
-
|
|
45
|
-
## Commands
|
|
46
|
-
|
|
47
|
-
One command, `/openai`, opens one menu in the TUI: Accounts (add with browser or device-code sign-in, disable, enable, move, remove), Quota, Routing, Limits (the killswitch and per-account floors), Cache (keep-warm), Diagnostics (request dumps, log level), Reset credits, This session (the sticky pin) and Vault (connect this host to the Claustrum vault, whose OpenAI accounts then serve in place of yours until you disconnect; disable or enable each vault account). The menu works on the account pool; until the accounts have moved to it, `/openai` shows only that notice and the processes holding the move back. The earlier per-feature commands (`/openai-account`, `/openai-quota`, `/openai-routing`, `/openai-killswitch`, `/openai-cachekeep`, `/openai-dump`, `/openai-logging`, `/openai-reset`) are gone.
|
|
48
|
-
|
|
49
|
-
On a headless machine, where `/openai` is out of reach, `opencode auth login` offers the account actions — add, re-authenticate, remove, enable or disable, check quotas, the auth doctor, connect to the Claustrum vault (it prints the `ck auth enroll approve` and `ck auth grant` commands to run, and waits for the approval), or delete every account except `main`. It prints `Failed to authorize` on return even when the action succeeded, because the menu writes its own changes and reports none of them as a sign-in; confirm with `/openai`.
|
|
50
|
-
|
|
51
|
-
## Configuration
|
|
52
|
-
|
|
53
|
-
Settings resolve as environment variable → config file (`~/.config/opencode/openai-auth.json`) → default.
|
|
54
|
-
|
|
55
|
-
| Config field | Environment variable | Default | Purpose |
|
|
56
|
-
| --- | --- | --- | --- |
|
|
57
|
-
| `webSockets` | `CORTEXKIT_OPENAI_AUTH_WEBSOCKETS` | `false` | Use the Codex Responses WebSocket transport instead of HTTP. |
|
|
58
|
-
| `rawWebSocket` | `CORTEXKIT_OPENAI_AUTH_RAW_WS` | `false` | Use the hand-rolled raw TCP/TLS client with Codex-style incremental streaming. Bun uses `Bun.connect`; Node/OpenCode Desktop uses `node:net`/`node:tls`. |
|
|
59
|
-
| `responsesLite` | `CORTEXKIT_OPENAI_AUTH_RESPONSES_LITE` | `false` | Send `gpt-5.6-sol`/`-terra`/`-luna` requests in Codex's Responses Lite shape, matching the Codex CLI. |
|
|
60
|
-
| `dump` | `CORTEXKIT_OPENAI_AUTH_DUMP` | `false` | Dump final Codex request bodies for cache debugging. |
|
|
61
|
-
| `dumpDir` | `OPENCODE_OPENAI_AUTH_DUMP_DIR` | OS temp dir: `opencode-openai-auth-dumps` | Directory for request dump files. |
|
|
62
|
-
| `codexApiEndpoint` | `CORTEXKIT_OPENAI_AUTH_CODEX_ENDPOINT` | `https://chatgpt.com/backend-api/codex/responses` | Send rewritten Codex requests to a compatible proxy/relay instead of ChatGPT's backend endpoint. |
|
|
63
|
-
|
|
64
|
-
See the [repository README](https://github.com/cortexkit/openai-auth#readme) for transport differences.
|
|
9
|
+
See [Install](https://github.com/cortexkit/openai-auth#install) in the repository README. Manual installation is described in [Configuration](https://github.com/cortexkit/openai-auth/blob/main/docs/configuration.md#manual-install) for OpenCode 1 and in [OpenCode 2](https://github.com/cortexkit/openai-auth/blob/main/docs/opencode-2.md#manual-install).
|
|
65
10
|
|
|
66
|
-
|
|
11
|
+
## Documentation
|
|
67
12
|
|
|
68
|
-
|
|
13
|
+
- [Configuration](https://github.com/cortexkit/openai-auth/blob/main/docs/configuration.md)
|
|
14
|
+
- [Accounts and routing](https://github.com/cortexkit/openai-auth/blob/main/docs/accounts-and-routing.md)
|
|
15
|
+
- [Claustrum vault](https://github.com/cortexkit/openai-auth/blob/main/docs/vault.md)
|
|
16
|
+
- [Commands](https://github.com/cortexkit/openai-auth/blob/main/docs/commands.md)
|
|
17
|
+
- [Cache keep-warm](https://github.com/cortexkit/openai-auth/blob/main/docs/cache-keep-warm.md)
|
|
18
|
+
- [OpenCode 2](https://github.com/cortexkit/openai-auth/blob/main/docs/opencode-2.md)
|
|
19
|
+
- [Transports](https://github.com/cortexkit/openai-auth/blob/main/docs/transports.md)
|
|
20
|
+
- [Troubleshooting](https://github.com/cortexkit/openai-auth/blob/main/docs/troubleshooting.md)
|
|
69
21
|
|
|
70
22
|
## License
|
|
71
23
|
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{c as T0}from"./index-envpbt0k.js";import{Ab as Q0,Ba as Y0,Ga as E,Ha as N,Ia as R0,Ja as t,cc as j0,mb as W0,nb as L,ob as a,uc as M0,wb as K0,xb as P,yb as R,zb as y}from"./index-99esnzg0.js";import"./index-yf6arn5w.js";import"./index-2hch7e8n.js";import{Yd as q0,Zd as B0,ae as x0}from"./index-k4eacw7x.js";import"./index-dryydk6b.js";import"./index-bgq9d21h.js";import{execFile as F0}from"node:child_process";var V={run(b,G,D={}){return new Promise((X)=>{let z=performance.now(),J=D.timeoutMs??15000;F0(b,[...G],{env:D.env??process.env,timeout:J,windowsHide:!0,windowsVerbatimArguments:D.windowsVerbatimArguments,maxBuffer:1048576},(Q,q,Z)=>{let K=performance.now()-z;X({exitCode:Q?typeof Q.code==="number"?Q.code:1:0,stdout:String(q??""),stderr:String(Z??""),signal:Q?.signal??null,timedOut:Q?.killed===!0&&typeof Q.code!=="string"&&Q.signal==="SIGTERM"&&K>=J&&J>0,durationMs:K})})})}};function S(b,G,D,X,z,J=15000){if(G==="win32"&&/\.(cmd|bat)$/i.test(D)){if(/["%!\r\n]/.test(D)||X.some((Q)=>!/^[a-zA-Z0-9@:/._+-]+$/.test(Q)))throw Error("Unsafe batch launcher or argument; use an executable instead.");return b.run("cmd.exe",["/d","/s","/c",`""${D}" ${X.join(" ")}"`],{env:z,timeoutMs:J,windowsVerbatimArguments:!0})}return b.run(D,X,{env:z,timeoutMs:J})}import{accessSync as w0,constants as L0,existsSync as I0,readFileSync as S0,realpathSync as E0,statSync as y0}from"node:fs";import{mkdtemp as P0,rm as v0}from"node:fs/promises";import{tmpdir as f0}from"node:os";import{join as g0}from"node:path";import{parse as d0}from"jsonc-parser";import{homedir as k0}from"node:os";import{posix as N0,win32 as A0}from"node:path";import{fileURLToPath as C0}from"node:url";function T(b={}){let G=b.env??process.env,D=b.platform??process.platform,X=D==="win32"?A0:N0,z=b.home??(D==="win32"?G.USERPROFILE:G.HOME)??k0(),J=b.cwd??process.cwd(),Q=(O)=>X.resolve(J,O),q=G.OPENCODE_CONFIG_DIR?.trim(),Z=G.XDG_CONFIG_HOME?.trim(),K=G.PI_CODING_AGENT_DIR?.trim()||X.join(z,".pi","agent");if(K==="~")K=z;else if(/^~[/\\]/.test(K))K=X.join(z,K.slice(2));if(K.startsWith("file://"))K=C0(K);return{env:G,platform:D,path:X,home:z,cwd:J,opencode:q?Q(q):Z?X.join(Q(Z),"opencode"):X.join(z,".config","opencode"),pi:Q(K)}}function f(b,G){try{return y0(b)[G]()}catch{return!1}}var F={exists:I0,isFile:(b)=>f(b,"isFile"),isDirectory:(b)=>f(b,"isDirectory"),isExecutable(b){try{return w0(b,L0.X_OK),f(b,"isFile")}catch{return!1}},readText:(b)=>S0(b,"utf8"),realpath:E0};function H(b,G={}){let{env:D,platform:X,path:z,cwd:J}=T(G),Q=G.fs??F,q=Object.entries(D).find(([K])=>X==="win32"?K.toUpperCase()==="PATH":K==="PATH")?.[1]??"",Z=X==="win32"?[".exe",".cmd",".bat",""]:[""];for(let K of q.split(X==="win32"?";":":")){let O=K.trim().replace(/^"|"$/g,"");if(!O)continue;for(let B of Z){let $=z.resolve(J,O,b+B);if(X==="win32"?Q.isFile($):Q.isExecutable($))return $}}return null}function i(b={}){let{platform:G,home:D,env:X,path:z}=T(b);if(G==="darwin")return["/Applications/OpenCode.app","/Applications/OpenCode Beta.app",z.join(D,"Applications","OpenCode.app"),z.join(D,"Applications","OpenCode Beta.app")];if(G==="win32"){let J=X.LOCALAPPDATA||z.join(D,"AppData","Local");return[z.join(J,"Programs","opencode"),z.join(J,"opencode")]}return["/opt/OpenCode","/usr/lib/opencode",z.join(D,".local","share","applications","opencode.desktop")]}function g(b,G){let D=G.fs??F,{path:X}=T(G);try{let z=D.readText(b);if(z.length>65536)return b;let J=[...z.matchAll(/"%~?dp0%?\\([^"%\r\n]+)"/g)];if(!J.length)J.push(...z.matchAll(/"\$basedir\/([^"$\r\n]+)"/g));let Q=J.at(-1)?.[1];if(Q){let q=X.join(X.dirname(b),...Q.split(/[/\\]+/));if(D.isFile(q))return D.realpath(q)}return D.realpath(b)}catch{return b}}function c0(b,G){let D=G.fs??F,{path:X}=T(G),z=X.dirname(g(b,G));for(;;){try{let Q=JSON.parse(D.readText(X.join(z,"package.json")));if(["@opencode/cli","@opencode-ai/cli"].includes(Q.name))return"2";if(Q.name==="opencode-ai")return/^(?:[2-9]\d*|1\d+)\.|^0\.0\.0-(?:beta|dev)-/.test(Q.version??"")?"2":"1"}catch{}let J=X.dirname(z);if(J===z)return null;z=J}}function s(b={}){let G=H("opencode",b),D=H("opencode2",b),X=G&&D&&g(G,b)===g(D,b),z=b.fs??F,{path:J,opencode:Q}=T(b),q="1";for(let K of["jsonc","json"]){let O=J.join(Q,`opencode.${K}`);if(!z.exists(O))continue;try{if(Object.hasOwn(d0(z.readText(O))??{},"plugins"))q="2"}catch{}break}let Z=G?c0(G,b)??(X?"2":q):null;if(D&&Z==="1"&&!X)return"ambiguous";return D||X?"2":Z??q}async function d(b,G={}){let D=G.fs??F,{env:X,platform:z,opencode:J,pi:Q}=T(G),q=G.runner??V,Z=H("opencode",G)??H("opencode2",G),K=H("pi",G),O=H("ck",G),B=async(x)=>{if(!x)return null;let W;try{W=await P0(g0(f0(),"common-auth-setup-version-"));let I={...X,HOME:W,USERPROFILE:W,XDG_CONFIG_HOME:W,XDG_DATA_HOME:W,XDG_STATE_HOME:W,XDG_CACHE_HOME:W,OPENCODE_CONFIG_DIR:W,OPENCODE_CONFIG:void 0,OPENCODE_CONFIG_CONTENT:void 0,OPENCODE_AUTH_CONTENT:void 0,PI_CODING_AGENT_DIR:W},_=await S(q,z,x,["--version"],I,2000);return _.exitCode===0?/\b\d+\.\d+\.\d+(?:-[\w.-]+)?/.exec(_.stdout)?.[0]??null:null}catch{return null}finally{if(W)await v0(W,{recursive:!0,force:!0}).catch(()=>{})}},$=!1;if(O&&D.exists(b.vault.connectionFile))try{(await(G.connect??E)({connectionFile:b.vault.connectionFile,handshakeTimeoutMs:2000})).close(),$=!0}catch{$=!1}let[Y,U]=await Promise.all([B(Z),B(K)]);return{opencode:{installed:D.isDirectory(J)||i(G).some((x)=>D.exists(x))||Z!==null,executable:Z,version:Y,directory:J,generation:s(G)},pi:{installed:K!==null||D.isDirectory(Q),executable:K,version:U,directory:Q},claustrum:{available:$,executable:O}}}import{setTimeout as s0}from"node:timers/promises";import{writeEnrollmentTokenFile as r0}from"@cortexkit/claustrum-client";var h0=45000,r=new Set(["opencode","litecode","opencode2","pi"]),u0=new Set(["node","bun"]),m0=/(?:^|[/\\])pi-coding-agent[/\\]dist[/\\](?:(?:bundle|bun)[/\\])?cli\.m?js$/i;function p0(b){return[...b.matchAll(/"([^"]*)"|(\S+)/g)].map((G)=>G[1]??G[2]??"")}function n(b){return(b.split(/[/\\]/).pop()??"").toLowerCase().replace(/\.(?:exe|cmd|bat|m?js)$/,"")}var l0=new Set(["-r","--require","--import","--loader","--experimental-loader","-C","--conditions","--env-file","--title","--input-type","--preload","--cwd","-c","--config","--tsconfig-override","-d","--define","-l","--main-fields"]),a0=new Set(["-e","--eval","-p","--print"]);function i0(b,G){for(let D=0;D<G.length;D++){let X=G[D]??"";if(X==="--")return G[D+1];if(a0.has(X))return;if(X.startsWith("-")){if(!X.includes("=")&&l0.has(X))D++;continue}if(b==="bun"&&X==="run")continue;return X}return}function o(b){let[G,...D]=p0(b);if(G===void 0)return null;let X=n(G);if(r.has(X))return X;if(!u0.has(X))return null;let z=i0(X,D);if(z===void 0)return null;let J=n(z);if(r.has(J))return J;return m0.test(z)?"pi":null}class j extends Error{code="process-inspection-failed";step;exitCode;signal;timedOut;durationMs;constructor(b){super("Process inspection failed; setup cannot prove hosts are stopped.");this.name="ProcessInspectionError",this.step=b.step,this.exitCode=b.exitCode,this.signal=b.signal,this.timedOut=b.timedOut,this.durationMs=b.durationMs}get refusalText(){let b=this.timedOut?"timed out":this.signal?`signal ${this.signal}`:this.exitCode===null?"could not start or complete":this.exitCode===0?"invalid output (exit code 0)":`exit code ${this.exitCode}`;return`${this.message} ${this.step}: ${b} after ${Math.round(this.durationMs)} ms.`}}class k extends Error{activeHosts;constructor(b){let G=b.map((D)=>({pid:D.pid,command:o(D.command)??"host"}));super(`OpenCode or Pi processes are currently running:
|
|
3
|
+
${G.map((D)=>` - PID ${D.pid}: ${D.command}`).join(`
|
|
4
|
+
`)}
|
|
5
|
+
|
|
6
|
+
Please quit all OpenCode, LiteCode, and Pi processes before running setup.`);this.activeHosts=G,this.name="ProcessFenceViolationError"}}async function c(b=V,G={}){let D=(G.platform??process.platform)==="win32",X={step:D?"tasklist":"ps",exitCode:null,signal:null,timedOut:!1,durationMs:0},z=async(J,Q,q,Z)=>{let K=performance.now();X={step:J,exitCode:null,signal:null,timedOut:!1,durationMs:0};try{let O=await b.run(Q,q,{env:G.env,timeoutMs:Z});return X={step:J,exitCode:O.exitCode,signal:O.signal??null,timedOut:O.timedOut??!1,durationMs:O.durationMs??performance.now()-K},O}finally{if(X.exitCode===null)X.durationMs=performance.now()-K;G.onStep?.({...X})}};try{let J=await z(D?"tasklist":"ps",D?"tasklist.exe":"ps",D?["/fo","csv","/nh"]:["-eo","pid,command"]);if(J.exitCode!==0)throw new j(X);let Q=[];for(let Z of J.stdout.split(/\r?\n/)){let K=Z.trim();if(!K)continue;let O,B;if(D){let $=/^"([^"]+)","(\d+)"(?:,|$)/.exec(K);if(!$)throw new j(X);B=$[1]??"",O=Number($[2])}else{let $=/^(\d+)\s+(.+)$/.exec(K);if(!$){if(/^PID\s+COMMAND$/i.test(K))continue;throw new j(X)}O=Number($[1]),B=$[2]??""}if(!Number.isSafeInteger(O)||O<0)throw new j(X);Q.push({pid:O,command:B})}if(!Q.length)throw new j(X);let q=Q.filter((Z)=>Z.pid!==process.pid&&/^(?:node|bun)\.exe$/i.test(Z.command));if(D&&q.length&&G.inspectRuntimes!==!1){let Z=await z("CIM","powershell.exe",["-NoProfile","-NonInteractive","-Command",`$ErrorActionPreference = 'Stop'; Get-CimInstance Win32_Process -Filter "Name = 'node.exe' OR Name = 'bun.exe'" | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress`],h0);if(Z.exitCode!==0)throw new j(X);let K=JSON.parse(Z.stdout||"null"),O=K===null?[]:Array.isArray(K)?K:[K],B=new Map;for(let $ of O){if(!$||typeof $!=="object"||!("ProcessId"in $)||!("CommandLine"in $)||!Number.isSafeInteger($.ProcessId))throw new j(X);if(typeof $.CommandLine==="string")B.set(Number($.ProcessId),$.CommandLine);else if(q.some((Y)=>Y.pid===$.ProcessId))throw new j(X)}for(let $ of q)$.command=B.get($.pid)??""}return Q}catch(J){if(J instanceof j)throw J;throw new j(X)}}function C(b=V,G={}){let D=(X)=>X.pid!==process.pid&&o(X.command)!==null;return{async listRunningHosts(X){return(await c(b,{...G,env:X})).filter(D)},async previewRunningHosts(X){let z=await c(b,{...G,env:X,inspectRuntimes:!1}),J=(G.platform??process.platform)==="win32";return{hosts:z.filter(D),uncheckedRuntimes:J?z.filter((Q)=>Q.pid!==process.pid&&/^(?:node|bun)\.exe$/i.test(Q.command)).length:0}}}}async function w(b,G){let D=await b.listRunningHosts(G);if(D.length)throw new k(D)}async function e(b,G,D,X,z){let{name:J,paths:Q}=b.vault.hosts[G],q=N(Q);await z();let Z=await(D.connect??E)({connectionFile:b.vault.connectionFile,handshakeTimeoutMs:2000}).catch(()=>{throw Error("Claustrum connection failed; start ck and rerun setup.")});try{let K=new t({proposedName:J,paths:q,client:{enrollPropose:async(B)=>{return await z(),Z.enrollPropose(B)},enrollPoll:async(B)=>{return await z(),Z.enrollPoll(B)}},writeTokenFile:async(B,$)=>{await z(),await r0(B,$)}}),O;for(let B=0;B<300;B++){await z();let $=await K.reconcile();if($.state==="approved"){R(X,`Connected ${G} to Claustrum.`);return}if($.state!=="pending"&&$.state!=="busy")throw Error("Claustrum enrollment refused; inspect its status with ck before rerunning setup.");if($.state==="pending"&&$.requestId&&$.requestId!==O){if(!/^[a-zA-Z0-9_-]+$/.test($.requestId))throw Error("Invalid enrollment request id.");O=$.requestId,R(X,"Waiting for approval. In another terminal, run:"),R(X,` ck auth enroll approve --request-id ${$.requestId} --name ${J}`),R(X,`Enrollment files: ${q.statePath}, ${q.tokenPath}`)}await(D.wait??s0)(1000)}throw Error("Claustrum approval is still pending; approve with ck and rerun setup.")}catch(K){if(K instanceof k||K instanceof j)throw K;throw Error("Claustrum enrollment did not complete. Inspect and approve with ck, then rerun setup.")}finally{Z.close()}}async function b0(b,G){let D=new Set(G);for(;;){let X=await y(b,[...["opencode","pi"].map((z)=>({value:z,label:`[${D.has(z)?"x":" "}] ${z==="opencode"?"OpenCode":"Pi"}`,hint:G.includes(z)?"found":"not found"})),{value:"done",label:"Continue with selected hosts"}],{message:"Select hosts to set up",subtitle:"Enter toggles a host; choose Continue when ready."});if(X===null)return null;if(X==="done")return[...D];if(D.has(X))D.delete(X);else D.add(X)}}import{applyEdits as h,createScanner as K1,findNodeAtLocation as Q1,modify as D0,parse as Z1,parseTree as $1}from"jsonc-parser";import{randomUUID as n0}from"node:crypto";import{mkdir as o0,open as t0,rename as e0,stat as b1,unlink as G1}from"node:fs/promises";import{basename as D1,dirname as X1,join as z1}from"node:path";import{setTimeout as J1}from"node:timers/promises";async function G0(b,G,D={}){let X=(D.platform??process.platform)==="win32",z=X1(b);await o0(z,{recursive:!0});let J;if(!X)try{J=(await b1(b)).mode&4095}catch(Z){if(Z.code!=="ENOENT")throw Z}let Q=z1(z,`.${D1(b)}.${(D.stageName??n0)()}.tmp`),q=!1;try{let Z=await t0(Q,"wx",J??438);q=!0;try{if(await Z.writeFile(G,"utf8"),J!==void 0)await Z.chmod(J)}finally{await Z.close()}let K=D.now??(()=>performance.now()),O=K();for(let B=0;;B++){await D.beforeRename?.();try{await(D.rename??e0)(Q,b),q=!1;return}catch($){let Y=$.code,U=2000-(K()-O);if(!X||!["EPERM","EBUSY","EACCES"].includes(Y??"")||U<=0||B>=40)throw Error(`Unable to replace host config ${b}. Close editors or other programs using the file, then rerun setup.`);await(D.wait??J1)(Math.min(U,25*2**Math.min(B,2)))}}}finally{if(q)await G1(Q).catch(()=>{})}}function X0(b){let G=typeof b==="string"?b:Array.isArray(b)?b[0]:b&&typeof b==="object"&&("package"in b)?b.package:null;if(typeof G!=="string")return null;let D=G.indexOf("@",G.startsWith("@")?1:0);return D<0?G:G.slice(0,D)}function z0(b,G,D){let X=$1(b),z=X&&Q1(X,[G]),J=z?.children??[],Q=J[D];if(!Q||!z)throw Error("Invalid plugin array edit.");let q=[{offset:Q.offset,length:Q.length,content:""}],Z=(K,O)=>{let B=K1(b.slice(K,O),!0);if(B.scan(),b[K+B.getTokenOffset()]===",")q.push({offset:K+B.getTokenOffset(),length:1,content:""})};if(D===J.length-1){let K=J[D-1];if(K)Z(K.offset+K.length,Q.offset);Z(Q.offset+Q.length,z.offset+z.length-1)}else Z(Q.offset+Q.length,J[D+1]?.offset??Q.offset+Q.length);return h(b,q)}function J0(b,G,D,X){let z=[],J=Z1(b,z,{allowTrailingComma:!0});if(z.length||!J||typeof J!=="object"||Array.isArray(J))throw Error("Invalid OpenCode config; refusing to overwrite it.");let Q={formattingOptions:{insertSpaces:!/^\t+/m.test(b),tabSize:/^([ ]+)"/m.exec(b)?.[1]?.length??2,eol:b.includes(`\r
|
|
7
|
+
`)?`\r
|
|
8
|
+
`:`
|
|
9
|
+
`}},q=b,Z=J[G];if(Z!==void 0&&!Array.isArray(Z))throw Error(`OpenCode ${G} must be an array.`);let K=Array.isArray(Z)?[...Z]:[],O=K.flatMap((Y,U)=>X0(Y)===D?[U]:[]),B=`${D}@${X}`;if(!O.length)q=h(q,D0(q,Z===void 0?[G]:[G,K.length],Z===void 0?[B]:B,Q));else{let Y=O[0],U=K[Y],x=Array.isArray(U)?[B,...U.slice(1)]:U&&typeof U==="object"?{...U,package:B}:B;if(JSON.stringify(U)!==JSON.stringify(x))q=h(q,D0(q,[G,Y],x,Q));for(let W of O.slice(1).reverse())q=z0(q,G,W)}let $=G==="plugin"?"plugins":"plugin";if(Array.isArray(J[$])){let Y=J[$];for(let U=Y.length-1;U>=0;U--)if(X0(Y[U])===D)q=z0(q,$,U)}return q}function u(b,G,D={}){let X=D.fs??F,{path:z,opencode:J}=T(D),Q=G==="2"?"plugins":"plugin";return(G==="2"?["opencode"]:["opencode","tui"]).map((Z)=>{let K=z.join(J,`${Z}.jsonc`),O=z.join(J,`${Z}.json`),B=X.exists(K)?K:X.exists(O)?O:K,$=X.exists(B),Y=$?X.readText(B):`${JSON.stringify({$schema:`https://opencode.ai/${Z==="tui"?"tui":"config"}.json`},null,2)}
|
|
10
|
+
`,U=J0(Y,Q,b.packages.opencode,b.version);return{path:B,content:U,changed:!$||U!==Y}})}async function m(b,G){for(let D of b){if(!D.changed)continue;await G?.(),await G0(D.path,D.content,{beforeRename:G})}}async function p(b,G,D={}){let{platform:X,env:z}=T(D);if((await S(D.runner??V,X,G,["install",`npm:${b.packages.pi}@${b.version}`],z)).exitCode!==0)throw Error("Pi install failed; run pi install after checking your npm connection.")}var Z0="Multiple OpenCode generations found. Choose --opencode=1|2|both before running noninteractive setup.";function q1(b){let G={yes:!1,dryRun:!1,claustrum:!1,noClaustrum:!1,login:!1,opencode:void 0};for(let D of b)if(D==="--yes")G.yes=!0;else if(D==="--dry-run")G.dryRun=!0;else if(D==="--claustrum")G.claustrum=!0;else if(D==="--no-claustrum")G.noClaustrum=!0;else if(D==="--login")G.login=!0;else if(/^--opencode=(1|2|both)$/.test(D))G.opencode=D.slice(11);else throw Error(`Unknown setup argument: ${D}`);if(G.claustrum&&G.noClaustrum)throw Error("--claustrum and --no-claustrum cannot be used together.");if(G.login&&G.claustrum)throw Error("--login and --claustrum cannot be used together.");return G}function B1(b){for(let G of Object.values(b.packages))if(!/^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/.test(G))throw Error("Setup requires npm package names.");if(!/^\d+\.\d+\.\d+(?:-[a-zA-Z0-9.-]+)?(?:\+[a-zA-Z0-9.-]+)?$/.test(b.version))throw Error("Setup requires a concrete package version.");for(let G of Object.values(b.vault.hosts))if(!/^[a-z0-9][a-z0-9-]*$/.test(G.name))throw Error("Setup requires lowercase vault names containing only letters, digits and dashes.")}async function l(b,G=[],D={}){let X=q1(G);B1(b);let z=D.terminal??K0(),J=await d(b,D);R(z,`${b.displayName} setup`);for(let[_,M]of[["OpenCode",J.opencode],["Pi",J.pi]])R(z,`${_}: ${M.installed?`found (version ${M.version??"unknown"})`:"not found"} — ${M.directory}`);R(z,`Claustrum: ${J.claustrum.available?"available":"not available"}`);let Q=J.pi.installed&&!J.pi.executable;if(Q)R(z,"Pi: skipped, because its folder exists but pi is not on PATH. Install the Pi CLI and rerun setup to add it.");let q=["opencode","pi"].filter((_)=>J[_].installed&&!(_==="pi"&&Q)),Z=X.yes||X.dryRun&&!P(z);if(!Z&&!P(z))throw Error("Setup requires a TTY or --yes.");let K=Z?q:await b0(z,q)??[],O=X.opencode??(J.opencode.generation==="ambiguous"?"1":J.opencode.generation);if(K.includes("opencode")&&!X.opencode&&J.opencode.generation==="ambiguous"){if(Z||!P(z))throw Error(Z0);let _=await y(z,[{value:"1",label:"OpenCode 1"},{value:"2",label:"OpenCode 2"},{value:"both",label:"Both (one compatible registration)"}],{message:"Which OpenCode generation should be registered?"});if(_===null)return{hosts:[],dryRun:X.dryRun,mode:"local",detection:J};O=_}if(!K.length)return R(z,"No hosts selected. Install OpenCode or Pi and rerun setup."),{hosts:K,dryRun:X.dryRun,mode:"local",detection:J};let{env:B,platform:$}=T(D),Y=D.fence??C(D.runner??V,{platform:$}),U=async()=>{try{await w(Y,B)}catch(_){if(_ instanceof j)R(z,_.refusalText);throw _}};if(R(z,"Checking that OpenCode and Pi are not running…"),X.dryRun)try{let _=Y.previewRunningHosts?await Y.previewRunningHosts(B):{hosts:await Y.listRunningHosts(B),uncheckedRuntimes:0},M=_.hosts;if(_.uncheckedRuntimes>0)R(z,"Node or Bun programs are running; a real run checks whether any of them is OpenCode or Pi.");let V0=new Set(new k(M).activeHosts.map((v)=>v.command.toLowerCase()==="pi"?"Pi":"OpenCode"));for(let v of V0)R(z,`${v} is running; setup will ask you to quit it.`)}catch(_){if(R(z,"Process inspection failed; real setup will require successful inspection and stopped OpenCode/Pi hosts."),_ instanceof j)R(z,_.refusalText)}else await U();if(X.claustrum&&!J.claustrum.available)throw Error("Claustrum is not available. Start ck or use --no-claustrum for local sign-in.");let x=X.claustrum||!X.login&&!X.noClaustrum&&!Z&&J.claustrum.available&&await Q0(z,"Connect these hosts to the Claustrum vault?"),W=x?"claustrum":"local",I=K.includes("opencode")?u(b,O,D):[];if(X.dryRun){R(z,"Dry run: no registrations, enrollment, sign-in or migration will be performed.");for(let _ of K){if(b.beforeSignIn)R(z,`Would run beforeSignIn(${_}, ${W}).`);if(x){let M=N(b.vault.hosts[_].paths);R(z,`Would Connect ${_}: write ${M.statePath} and ${M.tokenPath}; wait for ck auth enroll approve.`)}else R(z,`Would sign in locally for ${_}.`);if(b.beforeRegister)R(z,`Would run beforeRegister(${_}, ${W}).`)}for(let _ of I)R(z,`${_.changed?"Would write":"Unchanged"} ${_.path}:
|
|
11
|
+
${_.content}`);if(K.includes("pi"))R(z,`Would run ${J.pi.executable} install npm:${b.packages.pi}@${b.version}`);for(let _ of K)R(z,`Would migrate ${_} using the plugin callback (provider-specific writes).`)}else{let _={opencodeGeneration:O,mode:W,hosts:Object.freeze([...K]),piAgentDir:J.pi.directory};for(let M of K){if(await U(),await b.beforeSignIn?.(M,_),await U(),x)await e(b,M,D,z,U);else await b.signInLocal(M,_);if(await U(),await b.beforeRegister?.(M,W,_),await U(),M==="opencode")await m(I,U);else await p(b,J.pi.executable,D);await U(),await b.migrate(M,_)}}return R(z,`${X.dryRun?"Planned":"Configured"} ${b.displayName} for ${K.join(", ")} (${W}).`),R(z,`Next: ${K.includes("opencode")?"start OpenCode":"start Pi"} and run ${b.slashCommand}.`),{hosts:K,dryRun:X.dryRun,mode:W,detection:J}}import{basename as W1}from"node:path";import{resolveClaustrumConnectionPath as x1}from"@cortexkit/claustrum-client";var $0={name:"@cortexkit/pi-openai-auth",version:"1.0.4",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/*' --external @cortexkit/private-files --external @cortexkit/claustrum-client --external @cortexkit/subc-client --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/common-auth":"^0.17.0","@cortexkit/openai-auth-core":"workspace:*"},dependencies:{"@cortexkit/claustrum-client":"^0.9.0","@cortexkit/private-files":"^0.2.1","@cortexkit/subc-client":"^0.16.0"},peerDependencies:{"@earendil-works/pi-ai":">=1.0.1","@earendil-works/pi-coding-agent":">=1.0.1","@earendil-works/pi-tui":">=1.0.1"}};import{homedir as _1}from"node:os";import{join as O0}from"node:path";function U1(){return process.env.PI_AGENT_DIR?.trim()||O0(_1(),".pi","agent")}function _0(){return process.env.PI_OPENAI_AUTH_FILE?.trim()||O0(U1(),q0)}function Y1(b=_0()){return process.env.PI_OPENAI_AUTH_STATE_FILE?.trim()||B0(b)}function U0(b=_0()){return{configPath:b,statePath:Y1(b)}}var A={name:"@cortexkit/opencode-openai-auth",version:"1.0.4",license:"MIT",type:"module",repository:{type:"git",url:"git+https://github.com/cortexkit/openai-auth.git",directory:"packages/opencode"},main:"./dist/index.js",types:"./dist/index.d.ts",bin:{"opencode-openai-auth":"./dist/bin.js"},exports:{".":{import:"./dist/index.js",types:"./dist/index.d.ts"},"./tui":{types:"./dist/tui.d.ts",import:"./src/tui/entry.mjs"},"./tui-prefs":{types:"./dist/tui-preferences.d.ts",import:"./dist/tui-preferences.js"},"./server":{types:"./dist/v2/server.d.ts",import:"./dist/v2/server.js"}},"oc-plugin":["server","tui"],engines:{bun:"1.3.14"},files:["dist","src/tui/entry.mjs","src/tui-compiled","README.md","LICENSE"],scripts:{build:"rm -rf dist && bun build src/index.ts src/v2/server.ts src/sidebar-state.ts src/tui-preferences.ts src/rpc/rpc-client.ts src/rpc/port-file.ts src/rpc/protocol.ts src/rpc/rpc-dir.ts src/bin.ts --root src --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin --external @opencode/plugin --external @cortexkit/private-files --external jsonc-parser --external @cortexkit/claustrum-client --external @cortexkit/subc-client --minify && bun run build:types && bun run build:tui","build:tui":"bun scripts/build-tui.ts","build:types":"cd ../core && bun run build && cd ../opencode && tsdown --config tsdown.config.ts --config-loader native","build:dev":"rm -rf dist && tsc -p tsconfig.build.json",test:"bun test src/tests",typecheck:"tsc",types:"tsc",prepublishOnly:"bun run build"},peerDependencies:{"@opencode-ai/plugin":"*","@opencode/plugin":">=2.0.21"},peerDependenciesMeta:{"@opencode/plugin":{optional:!0}},devDependencies:{"@ai-sdk/openai":"3.0.88","@cortexkit/common-auth":"^0.17.0","@cortexkit/openai-auth-core":"workspace:*","@opencode/plugin":"2.0.27"},dependencies:{"@cortexkit/claustrum-client":"^0.9.0","@cortexkit/private-files":"^0.2.1","@cortexkit/subc-client":"^0.16.0","@opentui/core":">=0.6.1","@opentui/solid":">=0.6.1",ai:"^7.0.137","jsonc-parser":"^3.3.1","solid-js":"1.9.12"}};function H0(b={}){let G=b.print??console.log,D=b.fence??C(),X={opencode:{stateDir:a(j0().statePath),host:"opencode"},pi:{stateDir:a(U0().statePath),host:"pi"}},z=async(J)=>{if(await R0(N(X[J]),L(J))!=="local")throw Error(`${J} is enrolled in Claustrum or its enrollment is unreadable. Disconnect it from the vault before using local sign-in.`)};return{packages:{opencode:A.name,pi:$0.name},version:A.version,displayName:"OpenAI Auth",slashCommand:"/openai",vault:{connectionFile:x1(),hosts:{opencode:{name:L("opencode"),paths:X.opencode},pi:{name:L("pi"),paths:X.pi}}},async beforeRegister(J,Q){if(Q==="claustrum"){if(G(`Allow this host to read OpenAI accounts with:
|
|
12
|
+
ck auth grant --principal enrolled:${L(J)} --selector-kind category --selector ${W0.category} --operation read`),J==="opencode")G("Then run opencode auth login and choose ChatGPT accounts in the vault to activate vault routing without local sign-in.");return}await z(J)},async signInLocal(J,Q){if(await z(J),J==="pi"){G("Start Pi and run /login openai-codex to sign in with Pi itself.");return}if(Q.opencodeGeneration!=="1"){let W=W1(H("opencode2",b.io)??H("opencode",b.io)??"opencode");G(`In OpenCode 2, run ${W} auth login openai and choose "ChatGPT (openai-auth pool, browser)" or "ChatGPT (openai-auth pool, headless)" to sign in to the account pool and activate it.`)}if(Q.opencodeGeneration==="2")return;if(M0(process.env))throw Error("Unset OPENCODE_AUTH_CONTENT before local setup sign-in.");let q=T0(),Z={path:{id:"openai"}};if(await q.get(Z)!==void 0){G("OpenCode already has an OpenAI login. Use opencode auth login to change it.");return}let K=b.beginLogin??Y0,O=new AbortController,B=Boolean(process.env.SSH_CONNECTION||process.env.SSH_TTY||process.platform==="linux"&&!process.env.DISPLAY&&!process.env.WAYLAND_DISPLAY),$={version:A.version,signal:O.signal},Y,U=!B;try{Y=await K({...$,headless:B})}catch(W){if(B)throw W;U=!1,G("Browser callback unavailable; using device-code sign-in."),Y=await K({version:A.version,headless:!0})}if(U){if(!(b.openBrowser??x0)(Y.url))O.abort(),await Y.completion.catch(()=>{}),G("Browser unavailable; using device-code sign-in."),Y=await K({version:A.version,headless:!0})}G(`${Y.url}
|
|
13
|
+
${Y.instructions}`);let x=await Y.completion;await w(D),await z(J),await q.set({...Z,body:{type:"oauth",access:x.access,refresh:x.refresh,expires:x.expires,...x.accountId?{accountId:x.accountId}:{}}}),G("Signed in to OpenCode. The first plugin start adopts this login into the account pool.")},async migrate(J){G(`${J}: account migration runs on first plugin start; setup leaves existing credentials unchanged.`)}}}if(process.argv[2]!=="setup")console.log("Usage: opencode-openai-auth setup [options]");else try{await l(H0(),process.argv.slice(3))}catch(b){console.error(b instanceof Error?b.message:String(b)),process.exitCode=1}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{be as G,ce as q,de as V0,fe as U,ge as h,he as S,ie as v,je as _0,le as b}from"./index-dryydk6b.js";import{randomUUID as I}from"node:crypto";import{mkdir as G0,open as x0,readFile as H0,rename as Q0,rm as L,stat as Y0,writeFile as Z0}from"node:fs/promises";import{dirname as P,join as J0}from"node:path";function N0($,W){return`${$}.${W}.lock`}class W0 extends Error{details;constructor($){super(`Timed out acquiring ${$.name} lock for ${$.target}`);this.name="LockContentionError",this.details=$}}class R extends Error{details;constructor($){super(`Lost ${$.name} lock for ${$.target}`);this.name="LockOwnershipError",this.details=$}}async function O0($,W,Q){let Y=performance.now();for(;;){let Z=await K0({path:$,name:W.name,ttlMs:W.ttlMs,renew:W.renew??!1,...W.onStep?{onStep:W.onStep}:{},...W.onRenewalTimer?{onRenewalTimer:W.onRenewalTimer}:{}});if(Z)try{return await Q(Z)}finally{await Z.release()}let J=W.timeoutMs-(performance.now()-Y);if(J<=0)throw new W0({target:$,name:W.name,timeoutMs:W.timeoutMs});await new Promise((_)=>setTimeout(_,Math.min(25,Math.ceil(J))))}}var g0=globalThis.setTimeout.bind(globalThis),D0=globalThis.clearTimeout.bind(globalThis);function q0($){let W=$?.code;return W==="ENOENT"||!G&&(W==="EINVAL"||W==="ENOTDIR")}async function K0($){let W=N0($.path,$.name),Q=J0(W,"owner.json"),Y=I(),Z=$.now??Date.now,J=null,_=!1,g=!1,B,l,X0=new Promise((z)=>{l=z});function p(z){try{let K=$.onRenewalTimer?.(z);if(K&&(typeof K==="object"||typeof K==="function")&&"then"in K&&typeof K.then==="function")Promise.resolve(K).catch(()=>{})}catch{}}function d(){if(!J)return;D0(J),J=null,p("cancelled")}function C(z,K){if(B||_)return;B=Object.freeze({reason:z,expectedOwnerId:Y,...typeof K?.ownerId==="string"?{observedOwnerId:K.ownerId}:{},...typeof K?.expiresAt==="number"?{observedExpiresAt:K.expiresAt}:{}}),d(),l(B)}let E,f=null,x=`${W}.evicting`,M=J0(x,"owner.json"),a=I(),j0=5000,y=8;async function j(){if(G)try{return JSON.parse(await S(W,!0))}catch(z){if(z.code!=="EISDIR"&&z.reason!=="wrong-kind")throw z;return await U(W,"directory",!0),JSON.parse(await S(Q,!0))}try{return JSON.parse(await H0(W,"utf8"))}catch(z){if(z.code!=="EISDIR")throw z;return JSON.parse(await H0(Q,"utf8"))}}async function C0(){if(G){let H=await j(),V=Number(H?.expiresAt)-Z();await b(W,`${JSON.stringify({ownerId:Y,expiresAt:Z()+$.ttlMs})}
|
|
2
|
+
`,{deadline:performance.now()+Math.max(0,V),beforeRename:async()=>{let A=await j();if(A?.ownerId!==Y||!(Number(A?.expiresAt)>Z())||!await X())throw new R({target:$.path,name:$.name})}});return}let z=`${W}.${I()}.tmp`,K,N=!1;try{K=await x0(z,"wx",384),N=!0,await K.writeFile(`${JSON.stringify({ownerId:Y,expiresAt:Z()+$.ttlMs})}
|
|
3
|
+
`,"utf8"),await K.chmod(384),await K.close(),K=void 0;let H=await j();if(H?.ownerId!==Y||!(Number(H?.expiresAt)>Z())||!await X())throw new R({target:$.path,name:$.name});await Q0(z,W),N=!1}finally{if(await K?.close().catch(()=>{}),N)await L(z,{force:!0}).catch(()=>{})}}async function s(){let z=`${JSON.stringify({ownerId:Y,expiresAt:Z()+$.ttlMs})}
|
|
4
|
+
`;if(G)await v(W,z);else await Z0(W,z,{encoding:"utf8",mode:384,flag:"wx"})}async function n(z){let K=z.code;if(K==="EEXIST"){if(G)await j();return!0}if(K==="EISDIR"){if(G)await U(W,"directory",!0),await S(Q,!0);return!0}return!1}async function k(){if(G)await h(P(W));try{return await s(),!0}catch(z){let K=z.code;if(await n(z))return!1;if(K==="ENOENT"){if(G)await h(P(W));else await G0(P(W),{recursive:!0});try{return await s(),!0}catch(N){if(await n(N))return!1;throw N}}throw z}}async function O(){await new Promise((z)=>setTimeout(z,Math.floor(Math.random()*4)))}async function m(z=!0){if(z&&$.onStep)await $.onStep("lock-read-ready");let K;try{K=await j()}catch(H){if(G&&H.code!=="ENOENT")throw H}let N=Number(K?.expiresAt);if(Number.isFinite(N)&&N>Z())return{status:"live"};if(typeof K?.ownerId==="string"&&Number.isFinite(N))return{status:"stale",identity:{kind:"owner",ownerId:K.ownerId,expiresAt:N}};try{let H=await Y0(W),V=Number.isFinite(N)?N:H.mtimeMs+$.ttlMs;if(V>Z())return{status:"live"};return{status:"stale",identity:{kind:"stat",dev:H.dev,ino:H.ino,mtimeMs:H.mtimeMs,expiresAt:V}}}catch(H){if(H.code==="ENOENT"){if($.onStep)await $.onStep("lock-missing");return{status:"missing"}}throw H}}function i(z,K){if(K.status!=="stale")return!1;let N=K.identity;if(z.kind==="owner"&&N.kind==="owner")return z.ownerId===N.ownerId&&z.expiresAt===N.expiresAt;return z.kind==="stat"&&N.kind==="stat"&&z.dev===N.dev&&z.ino===N.ino&&z.mtimeMs===N.mtimeMs&&z.expiresAt===N.expiresAt}async function X(){try{return JSON.parse(await S(M,G))?.ownerId===a}catch(z){if(G&&z.code!=="ENOENT")throw z;return!1}}async function T(z){if(G)await V0(z,"remove",()=>L(z,{recursive:!0,force:!0}));else await L(z,{recursive:!0,force:!0}).catch(()=>{})}async function u(){if(await X())await T(x)}async function t(){if(G)await _0(x);else await G0(x);try{let z=`${JSON.stringify({ownerId:a,createdAt:Z()})}
|
|
5
|
+
`;if(G)await v(M,z);else await Z0(M,z,{encoding:"utf8",mode:384,flag:"wx"})}catch(z){if(q0(z))return!1;throw await u(),z}if($.onStep)await $.onStep("eviction-marker-acquired");return!0}async function r(){let z;try{z=await Y0(x)}catch(N){if(N.code==="ENOENT")return"missing";throw N}if(G)await U(x,"directory",!0);if(z.mtimeMs+j0>Z())return"fresh";if($.onStep)await $.onStep("stale-marker-stat");let K=`${x}.${I()}`;try{await Q0(x,K)}catch(N){if(N.code==="ENOENT")return"missing";throw N}if($.onStep)await $.onStep("stale-marker-claimed");return await T(K),"recovered"}async function o(z){try{if(!await t())return!1}catch(K){if(K.code==="EEXIST"){if(G){await U(x,"directory",!0);try{await S(M,!0)}catch(N){if(N.code!=="ENOENT")throw N}}return!1}throw K}try{await z()}finally{await u()}return!0}async function e(){for(let z=0;z<y;z++){if($.onStep)await $.onStep("relinquish-read");let K;try{K=await j()}catch(N){if(G)throw N;return}if(K?.ownerId!==Y)return;try{await L(W,{recursive:!0,force:!0});return}catch(N){if(G)throw N;await O()}}}function $0(){if(!$.renew||_||B)return;let z=$.renewIntervalMs??Math.max(1000,Math.floor($.ttlMs/3));if(J=g0(()=>{J=null;let K=(async()=>{let N=!_;try{if(!await o(async()=>{let V=await j(),A=Z();if(_||B){N=!1;return}if(V?.ownerId!==Y){C("taken-over",V),N=!1;return}if(!(Number(V?.expiresAt)>A)){C("expired",V),N=!1;return}if($.onStep)await $.onStep("renewal-owner-confirmed");if(_||B){N=!1;return}if(!await X())return;if($.onStep)await $.onStep("renewal-write-fenced");if(_||B){N=!1;return}if(!await X())return;if($.onStep)await $.onStep("renewal-write-ready");if(_||B){N=!1;return}if(await C0(),$.onStep)await $.onStep("renewal-write-finished");if(!await X()){C("marker-lost"),N=!1,await e();return}})&&$.onStep)await $.onStep("renewal-marker-unavailable")}catch(H){if(G&&H instanceof q)E=H,C("renewal-failed"),N=!1;try{let V=await j();if(V?.ownerId!==Y)C("taken-over",V);else if(!(Number(V?.expiresAt)>Z()))C("expired",V)}catch{C("renewal-failed")}}finally{if($.onStep)try{await $.onStep("renewal-finished")}catch{}if(N&&!_&&!B)$0()}})();f=K,K.finally(()=>{if(f===K)f=null})},z),"unref"in J)J.unref();p("scheduled")}function z0(){try{let z=$.onContended?.();if(z&&(typeof z==="object"||typeof z==="function")&&"then"in z&&typeof z.then==="function")Promise.resolve(z).catch(()=>{})}catch{}return null}let D=await k();if(!D)for(let z=0;z<y;z++){if(D=await k(),D)break;let K=await m();if(K.status==="live")return z0();if(K.status==="missing")continue;if($.onStep)await $.onStep("stale-lock-observed");try{if(!await t()){await O();continue}}catch(N){if(N.code!=="EEXIST")throw N;if(await r()==="fresh")return null;await O();continue}try{let N=await m();if(N.status==="live")return z0();if(!i(K.identity,N))continue;if(!await X())return null;if($.onStep)await $.onStep("stale-lock-confirmed");if(!await X())return null;let H=await m(!1);if(!i(K.identity,H))continue;if(await T(W),!await X())return null;if($.onStep)await $.onStep("stale-lock-removed");if(D=await k(),!D)return null;if($.onStep)await $.onStep("stale-lock-recreated");if(!await X())return await e(),D=!1,null;break}finally{await u()}}if(!D)return null;return $0(),{ownerId:Y,whenLost:()=>X0,hasLost:()=>B!==void 0,assertOwned:async()=>{if(E)throw E;let z;try{let K=await j();if(z=K,!_&&!B&&K?.ownerId===Y&&Number(K?.expiresAt)>Z())return;C(K?.ownerId!==Y?"taken-over":"expired",K)}catch(K){if(C("unreadable"),G&&K instanceof q)throw K}throw new R({target:$.path,name:$.name,expectedOwnerId:Y,...typeof z?.ownerId==="string"?{observedOwnerId:z.ownerId}:{},...typeof z?.expiresAt==="number"?{observedExpiresAt:z.expiresAt}:{}})},release:async()=>{if(G&&g)return;_=!0,d(),await f;for(let z=0;z<y;z++){try{let K=!1;if(await o(async()=>{let H;try{H=await j()}catch(V){if(G&&V.code==="ENOENT"){K=!0;return}throw V}if(H?.ownerId!==Y){K=!0;return}if($.onStep)await $.onStep("release-owner-confirmed");if(!await X())return;await T(W),K=!0})){if(G&&!K)throw new q(W,"release-not-confirmed",{code:"EIO"});g=K;return}await r()}catch(K){if(G)throw K;return}await O()}if(G)throw new q(W,"release-not-confirmed",{code:"ETIMEDOUT"})}}}import{randomUUID as B0}from"node:crypto";import{mkdir as U0,open as F,rename as S0,rm as R0}from"node:fs/promises";import{dirname as w}from"node:path";class c extends Error{constructor($){super("file or directory sync failed",{cause:$});this.name="AtomicSyncError"}}async function P0($,W,Q={}){await f0($,W,Q)}async function f0($,W,Q,Y){if(G)return b($,Q.serialize?Q.serialize(W):`${JSON.stringify(W,null,2)}
|
|
6
|
+
`,{beforeRename:Q.beforeRename,stagePath:`${$}.${(Q.stageName??B0)()}.tmp`,onRenamed:Y,durable:Q.durable,durability:Q.durability,onOutcome:Q.onOutcome});await U0(w($),{recursive:!0});let Z=`${$}.${(Q.stageName??B0)()}.tmp`,J,_=!1;try{if(J=await F(Z,"wx",384),_=!0,await J.writeFile(Q.serialize?Q.serialize(W):`${JSON.stringify(W,null,2)}
|
|
7
|
+
`,"utf8"),await J.chmod(384),Q.durable)try{await J.sync()}catch(g){throw new c(g)}if(await J.close(),J=void 0,await Q.beforeRename?.(),await S0(Z,$),_=!1,Y?.(),Q.durable){let g=await F(w($),"r");try{await g.sync()}catch(B){throw new c(B)}finally{await g.close()}}}finally{if(await J?.close().catch(()=>{}),_)await R0(Z,{force:!0}).catch(()=>{})}}async function h0($){if(G){await U($,"file");let Y=new q($,"directory-sync-unsupported",{code:"ENOTSUP"});throw Y.published=!0,Y}let W=await F($,"r");try{await W.sync()}finally{await W.close()}let Q=await F(w($),"r");try{await Q.sync()}finally{await Q.close()}}var w0=Object.freeze({sidebar:Object.freeze({name:"sidebar-write",ttlMs:1e4,timeoutMs:15000,renew:!0}),preferences:Object.freeze({name:"preferences",ttlMs:1e4,timeoutMs:2000,renew:!0})});
|
|
8
|
+
export{c as xd,P0 as yd,f0 as zd,h0 as Ad,K0 as Bd,W0 as Cd,R as Dd,O0 as Ed,w0 as Fd};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash as B}from"node:crypto";import{homedir as G,tmpdir as W}from"node:os";import{dirname as J,join as w,resolve as z}from"node:path";var A="OPENCODE_OPENAI_AUTH_RPC_DIR",K="openai-auth-";function L(k){return B("sha256").update(k).digest("hex").slice(0,16)}function M(){let k=process.env.XDG_STATE_HOME||w(G(),".local","state");return w(k,"cortexkit","openai-auth","rpc")}function Q(k){let q=process.env[A]?.trim();if(q)return z(k,q);return w(M(),`${K}${L(k)}`)}async function $(k){let q=process.env[A]?.trim();if(q)return{dir:z(k,q),secureDir:!1};let x=Q(k);return{dir:x,secureDir:!0,sweepRoot:J(x)}}export{W as
|
|
1
|
+
import{createHash as B}from"node:crypto";import{homedir as G,tmpdir as W}from"node:os";import{dirname as J,join as w,resolve as z}from"node:path";var A="OPENCODE_OPENAI_AUTH_RPC_DIR",K="openai-auth-";function L(k){return B("sha256").update(k).digest("hex").slice(0,16)}function M(){let k=process.env.XDG_STATE_HOME||w(G(),".local","state");return w(k,"cortexkit","openai-auth","rpc")}function Q(k){let q=process.env[A]?.trim();if(q)return z(k,q);return w(M(),`${K}${L(k)}`)}async function $(k){let q=process.env[A]?.trim();if(q)return{dir:z(k,q),secureDir:!1};let x=Q(k);return{dir:x,secureDir:!0,sweepRoot:J(x)}}export{W as me,K as ne,Q as oe,$ as pe};
|