dsh-codex-share 0.5.2 → 0.6.0
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.d.mts +1 -1
- package/dist/index.mjs +37 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ For development from this checkout, from its directory:
|
|
|
24
24
|
dsh plugin --profile web add .
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Restart the profile after installation or update. The bundle
|
|
27
|
+
Restart the profile after installation or update. The bundle discovers home directories whose names start with `.codex` and contain an `auth.json` file (including symlinked directories). Each gets a separate provider group labeled with its directory name, such as **OpenAI Codex (.codex)** and **OpenAI Codex (.codex-p)**, in the model picker. The primary account retains `openai-codex-local`; other accounts use stable routes such as `openai-codex-local-.codex-p`. Each route offers the same catalog and additional model IDs, and reads only that account’s current credentials for each request. Invalid logins never fall back to another account. Discovery runs when the plugin starts; restart the profile after adding or removing account directories. Directory labels distinguish homes without exposing account email addresses. The primary route comes with the model catalog supplied by the Harness's pi-ai 1.x, including GPT-6 Astra, Sol, and Luna, and GPT-6.1 Sol (`gpt-6.1-sol`). GPT-6.1 Luna is not listed in the current OpenAI or Codex catalogs; use `gpt-6-luna` for Luna. This route replaces the plugin's earlier `openai-codex` route, which collides with pi-ai's configurable provider directory; update any saved model selection to `openai-codex-local`. The plugin appears in **Settings → Plugins → Plugin list**. Open **Settings → Models** and use **Edit model IDs** in the OpenAI Codex row to add subscription model IDs (one per line). The IDs are saved as `additionalModelIds` on the `llm-codex-share` entry in the profile's `cordis.patch.yml` and take effect without a restart. The installed catalog remains available; clearing the additional IDs restores it. For example, enter a model ID that your account can use but the catalog does not list yet. An unrecognized ID can be listed, but requests to it will fail if the Codex endpoint rejects it. Select a listed model in the model picker or agent preset. To select the primary Codex home (while still discovering other home directories), set the absolute `CODEX_HOME` path in the environment that launches the harness. Direct Cordis composition can configure `codexHome` on the `dsh-codex-share` plugin instead.
|
|
28
28
|
|
|
29
29
|
The plugin intentionally does not refresh a stale token. When Codex writes a replacement, the next harness request reads it. When Codex's current access token has expired, harness calls fail until Codex refreshes its own login. An API-key-only Codex login is rejected; this route never falls back to `OPENAI_API_KEY`.
|
|
30
30
|
|
package/dist/index.d.mts
CHANGED
|
@@ -19,7 +19,7 @@ declare const name = "llm-codex-share";
|
|
|
19
19
|
declare const inject: string[];
|
|
20
20
|
/** Settings namespace: the Loader entry id this bundle's patch inserts. */
|
|
21
21
|
declare const SETTINGS_NS = "llm-codex-share";
|
|
22
|
-
/**
|
|
22
|
+
/** codexHome/CODEX_HOME selects the primary route; other ~/.codex* homes are discovered. */
|
|
23
23
|
interface Config {
|
|
24
24
|
codexHome?: string;
|
|
25
25
|
/** Extra subscription model IDs alongside the installed pi-ai catalog; edits apply without a restart. */
|
package/dist/index.mjs
CHANGED
|
@@ -5,9 +5,10 @@ import { envApiKeyAuth } from "@earendil-works/pi-ai";
|
|
|
5
5
|
import { openaiCodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
|
|
6
6
|
import { zaiProvider } from "@earendil-works/pi-ai/providers/zai";
|
|
7
7
|
import { launchEnvironmentOf } from "@deepseek-ai/dsh-launch-environment";
|
|
8
|
+
import { readdirSync, statSync } from "node:fs";
|
|
8
9
|
import { readFile } from "node:fs/promises";
|
|
9
10
|
import { homedir } from "node:os";
|
|
10
|
-
import { isAbsolute, join } from "node:path";
|
|
11
|
+
import { basename, dirname, isAbsolute, join } from "node:path";
|
|
11
12
|
//#region src/auth.ts
|
|
12
13
|
/** Read the exact ChatGPT access token currently stored by Codex CLI. */
|
|
13
14
|
/** Resolve Codex's current auth.json path without retaining a token. */
|
|
@@ -38,6 +39,24 @@ async function readCodexAccessToken(codexHome) {
|
|
|
38
39
|
if (auth === null || auth.auth_mode !== void 0 && auth.auth_mode !== "chatgpt" || typeof auth.OPENAI_API_KEY === "string" && auth.OPENAI_API_KEY.length > 0 || typeof auth.tokens?.access_token !== "string" || auth.tokens.access_token.length === 0) throw new LlmError(`Codex login at ${path} has no ChatGPT access token; run codex login with ChatGPT`, "MISSING_CREDENTIAL");
|
|
39
40
|
return auth.tokens.access_token;
|
|
40
41
|
}
|
|
42
|
+
/** Discover account homes at plugin startup; retain only paths, never credentials. */
|
|
43
|
+
function discoverCodexHomes(codexHome) {
|
|
44
|
+
const primary = dirname(codexAuthPath(codexHome));
|
|
45
|
+
const homes = /* @__PURE__ */ new Set([primary]);
|
|
46
|
+
try {
|
|
47
|
+
for (const entry of readdirSync(homedir()).sort()) {
|
|
48
|
+
if (!entry.startsWith(".codex")) continue;
|
|
49
|
+
const home = join(homedir(), entry);
|
|
50
|
+
try {
|
|
51
|
+
if (statSync(home).isDirectory() && statSync(join(home, "auth.json")).isFile()) homes.add(home);
|
|
52
|
+
} catch {}
|
|
53
|
+
}
|
|
54
|
+
} catch {}
|
|
55
|
+
return [...homes].map((home) => ({
|
|
56
|
+
home,
|
|
57
|
+
label: basename(home)
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
41
60
|
//#endregion
|
|
42
61
|
//#region src/index.ts
|
|
43
62
|
/** Harness route for subscription-backed Codex models. */
|
|
@@ -84,6 +103,12 @@ function apply(ctx, config = Config({})) {
|
|
|
84
103
|
if (this === ctx.fiber) validateModelIds(Config(raw).additionalModelIds.get());
|
|
85
104
|
return raw;
|
|
86
105
|
});
|
|
106
|
+
const accounts = discoverCodexHomes(config.codexHome).map((account, index) => ({
|
|
107
|
+
...account,
|
|
108
|
+
provider: index === 0 ? PROVIDER : `${PROVIDER}-${encodeURIComponent(account.label)}`,
|
|
109
|
+
displayName: `OpenAI Codex (${account.label})`
|
|
110
|
+
}));
|
|
111
|
+
const accountHomes = new Map(accounts.map((account) => [account.provider, account.home]));
|
|
87
112
|
let lastIds;
|
|
88
113
|
let profiles;
|
|
89
114
|
const upstream = openaiCodexProvider();
|
|
@@ -158,17 +183,18 @@ function apply(ctx, config = Config({})) {
|
|
|
158
183
|
name: id
|
|
159
184
|
};
|
|
160
185
|
})];
|
|
161
|
-
|
|
162
|
-
profiles = new Map([[PROVIDER, {
|
|
186
|
+
profiles = new Map([...accounts.map((account) => [account.provider, {
|
|
163
187
|
...profileBase,
|
|
164
|
-
|
|
165
|
-
|
|
188
|
+
provider: account.provider,
|
|
189
|
+
displayName: account.displayName,
|
|
190
|
+
piProvider: routeProvider(upstream, account.provider, account.displayName, "Codex CLI login", models)
|
|
191
|
+
}]), ...glmProfile === void 0 ? [] : [[GLM_PROVIDER, glmProfile]]]);
|
|
166
192
|
lastIds = configured;
|
|
167
193
|
return profiles;
|
|
168
194
|
};
|
|
169
195
|
const adapter = new PiAiAdapter({
|
|
170
196
|
profiles: resolveProfiles,
|
|
171
|
-
resolveApiKey: async (provider) => provider === "glm-coding-global" ? glmKey : readCodexAccessToken(
|
|
197
|
+
resolveApiKey: async (provider) => provider === "glm-coding-global" ? glmKey : accountHomes.has(provider) ? readCodexAccessToken(accountHomes.get(provider)) : Promise.reject(new LlmError("Unknown Codex account route", "NO_ADAPTER")),
|
|
172
198
|
resolveAttachments: () => ctx.get("attachments"),
|
|
173
199
|
resolveImageAccess: (attachments, ref) => resolveImageAttachmentAccess(attachments, (hostPath) => ctx.get("fs")?.processPathFromHostPath(hostPath), ref),
|
|
174
200
|
auth: {
|
|
@@ -188,13 +214,13 @@ function apply(ctx, config = Config({})) {
|
|
|
188
214
|
}
|
|
189
215
|
}
|
|
190
216
|
});
|
|
191
|
-
ctx.llm.registerConfigurableProviders([{
|
|
192
|
-
provider
|
|
193
|
-
displayName
|
|
217
|
+
ctx.llm.registerConfigurableProviders([...accounts.map(({ provider, displayName }) => ({
|
|
218
|
+
provider,
|
|
219
|
+
displayName,
|
|
194
220
|
settingsNs: SETTINGS_NS,
|
|
195
221
|
settingsPath: []
|
|
196
|
-
}]);
|
|
197
|
-
ctx.llm.registerAdapter(glmProfile === void 0 ? [
|
|
222
|
+
}))]);
|
|
223
|
+
ctx.llm.registerAdapter([...accountHomes.keys(), ...glmProfile === void 0 ? [] : [GLM_PROVIDER]], adapter);
|
|
198
224
|
}
|
|
199
225
|
//#endregion
|
|
200
226
|
export { Config, GLM_PROVIDER, PROVIDER, SETTINGS_NS, apply, codexAuthPath, inject, name, readCodexAccessToken };
|