dsh-codex-share 0.1.1 → 0.2.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 +2 -2
- package/dist/index.d.mts +7 -2
- package/dist/index.mjs +65 -11
- package/lib/client.js +119 -0
- package/package.json +27 -7
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ A DeepSeek Harness LLM adapter that uses the same ChatGPT subscription login as
|
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Install the bundle into a harness profile:
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
16
|
dsh plugin --profile web add dsh-codex-share
|
|
@@ -22,7 +22,7 @@ For this checkout before publication, from its directory:
|
|
|
22
22
|
dsh plugin --profile web add .
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Restart the profile after installation or update. The bundle mounts one provider route, `openai-codex`, with the model catalog supplied by pi-ai.
|
|
25
|
+
Restart the profile after installation or update. The bundle mounts one provider route, `openai-codex-local`, with the model catalog supplied by pi-ai. 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 installed catalog remains available; clearing the additional IDs restores it. For example, enter `gpt-6-sol` and `gpt-6-luna` if your account can use them. 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. For a local Codex home outside the default location, 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.
|
|
26
26
|
|
|
27
27
|
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`.
|
|
28
28
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
1
2
|
import { Context } from "@deepseek-ai/cordis";
|
|
2
3
|
//#region src/auth.d.ts
|
|
3
4
|
/** Resolve Codex's current auth.json path without retaining a token. */
|
|
@@ -11,14 +12,18 @@ declare function readCodexAccessToken(codexHome?: string): Promise<string>;
|
|
|
11
12
|
//#endregion
|
|
12
13
|
//#region src/index.d.ts
|
|
13
14
|
/** Harness route for subscription-backed Codex models. */
|
|
14
|
-
declare const PROVIDER = "openai-codex";
|
|
15
|
+
declare const PROVIDER = "openai-codex-local";
|
|
15
16
|
declare const name = "llm-codex-share";
|
|
16
17
|
declare const inject: string[];
|
|
18
|
+
declare const SETTINGS_NS = "llm-codex-share";
|
|
17
19
|
/** Plugin configuration. Omit codexHome to follow CODEX_HOME or ~/.codex. */
|
|
18
20
|
interface Config {
|
|
19
21
|
codexHome?: string;
|
|
22
|
+
/** Extra subscription model IDs alongside the installed pi-ai catalog. */
|
|
23
|
+
additionalModelIds?: string[];
|
|
20
24
|
}
|
|
25
|
+
declare const Config: z<Config>;
|
|
21
26
|
/** Register the Codex subscription model catalog and stream adapter. */
|
|
22
27
|
declare function apply(ctx: Context, config?: Config): void;
|
|
23
28
|
//#endregion
|
|
24
|
-
export { Config, PROVIDER, apply, codexAuthPath, inject, name, readCodexAccessToken };
|
|
29
|
+
export { Config, PROVIDER, SETTINGS_NS, apply, codexAuthPath, inject, name, readCodexAccessToken };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
1
2
|
import { LlmError, resolveImageAttachmentAccess } from "@deepseek-ai/dsh-llm";
|
|
2
3
|
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
3
4
|
import { envApiKeyAuth } from "@earendil-works/pi-ai";
|
|
@@ -38,19 +39,29 @@ async function readCodexAccessToken(codexHome) {
|
|
|
38
39
|
//#endregion
|
|
39
40
|
//#region src/index.ts
|
|
40
41
|
/** Harness route for subscription-backed Codex models. */
|
|
41
|
-
const PROVIDER = "openai-codex";
|
|
42
|
+
const PROVIDER = "openai-codex-local";
|
|
42
43
|
const name = "llm-codex-share";
|
|
43
44
|
const inject = ["llm"];
|
|
45
|
+
const SETTINGS_NS = "llm-codex-share";
|
|
46
|
+
const Config = z.object({
|
|
47
|
+
codexHome: z.string(),
|
|
48
|
+
additionalModelIds: z.array(z.string().min(1))
|
|
49
|
+
});
|
|
50
|
+
function validateModelIds(config) {
|
|
51
|
+
const ids = config.additionalModelIds;
|
|
52
|
+
if (ids !== void 0 && (new Set(ids).size !== ids.length || ids.some((id) => id.trim() !== id))) throw new TypeError("Additional Codex model IDs must be unique, non-empty, and trimmed");
|
|
53
|
+
}
|
|
44
54
|
/** Register the Codex subscription model catalog and stream adapter. */
|
|
45
55
|
function apply(ctx, config = {}) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
56
|
+
validateModelIds(config);
|
|
57
|
+
let current = () => config;
|
|
58
|
+
let lastConfig;
|
|
59
|
+
let profiles;
|
|
60
|
+
const upstream = openaiCodexProvider();
|
|
61
|
+
const catalog = upstream.getModels();
|
|
62
|
+
const profileBase = {
|
|
51
63
|
provider: PROVIDER,
|
|
52
64
|
displayName: "OpenAI Codex (local login)",
|
|
53
|
-
piProvider: provider,
|
|
54
65
|
modelErrors: /* @__PURE__ */ new Map(),
|
|
55
66
|
configuredMaxTokens: /* @__PURE__ */ new Map(),
|
|
56
67
|
streamIdleTimeoutMs: 12e4,
|
|
@@ -66,10 +77,38 @@ function apply(ctx, config = {}) {
|
|
|
66
77
|
maxDelayMs: 0,
|
|
67
78
|
jitterRatio: 0
|
|
68
79
|
}
|
|
69
|
-
}
|
|
80
|
+
};
|
|
81
|
+
const resolveProfiles = () => {
|
|
82
|
+
const active = current();
|
|
83
|
+
if (active === lastConfig && profiles !== void 0) return profiles;
|
|
84
|
+
const ids = active.additionalModelIds?.filter((id) => !catalog.some((model) => model.id === id)) ?? [];
|
|
85
|
+
const models = [...catalog, ...ids.map((id) => {
|
|
86
|
+
const family = id.endsWith("-luna") ? "gpt-5.6-luna" : id.endsWith("-sol") ? "gpt-5.6-sol" : "gpt-6-astra";
|
|
87
|
+
return {
|
|
88
|
+
...catalog.find((model) => model.id === family) ?? catalog[0],
|
|
89
|
+
id,
|
|
90
|
+
name: id
|
|
91
|
+
};
|
|
92
|
+
})].map((model) => ({
|
|
93
|
+
...model,
|
|
94
|
+
provider: PROVIDER
|
|
95
|
+
}));
|
|
96
|
+
const provider = {
|
|
97
|
+
...upstream,
|
|
98
|
+
id: PROVIDER,
|
|
99
|
+
auth: { apiKey: envApiKeyAuth("Codex CLI login", []) },
|
|
100
|
+
getModels: () => models
|
|
101
|
+
};
|
|
102
|
+
profiles = /* @__PURE__ */ new Map([[PROVIDER, {
|
|
103
|
+
...profileBase,
|
|
104
|
+
piProvider: provider
|
|
105
|
+
}]]);
|
|
106
|
+
lastConfig = active;
|
|
107
|
+
return profiles;
|
|
108
|
+
};
|
|
70
109
|
const adapter = new PiAiAdapter({
|
|
71
|
-
profiles:
|
|
72
|
-
resolveApiKey: async () => readCodexAccessToken(
|
|
110
|
+
profiles: resolveProfiles,
|
|
111
|
+
resolveApiKey: async () => readCodexAccessToken(current().codexHome),
|
|
73
112
|
resolveAttachments: () => ctx.get("attachments"),
|
|
74
113
|
resolveImageAccess: (attachments, ref) => resolveImageAttachmentAccess(attachments, (hostPath) => ctx.get("fs")?.processPathFromHostPath(hostPath), ref),
|
|
75
114
|
auth: {
|
|
@@ -89,7 +128,22 @@ function apply(ctx, config = {}) {
|
|
|
89
128
|
}
|
|
90
129
|
}
|
|
91
130
|
});
|
|
131
|
+
ctx.llm.registerConfigurableProviders([{
|
|
132
|
+
provider: PROVIDER,
|
|
133
|
+
displayName: "OpenAI Codex (local login)",
|
|
134
|
+
settingsNs: SETTINGS_NS,
|
|
135
|
+
settingsPath: []
|
|
136
|
+
}]);
|
|
92
137
|
ctx.llm.registerAdapter([PROVIDER], adapter);
|
|
138
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
139
|
+
settingsCtx.settings.installSection(ctx, SETTINGS_NS, Config, config, {
|
|
140
|
+
validate: validateModelIds,
|
|
141
|
+
setSource: (source) => {
|
|
142
|
+
current = source;
|
|
143
|
+
},
|
|
144
|
+
onChange: () => {}
|
|
145
|
+
});
|
|
146
|
+
});
|
|
93
147
|
}
|
|
94
148
|
//#endregion
|
|
95
|
-
export { PROVIDER, apply, codexAuthPath, inject, name, readCodexAccessToken };
|
|
149
|
+
export { Config, PROVIDER, SETTINGS_NS, apply, codexAuthPath, inject, name, readCodexAccessToken };
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({ id: 'dsh-codex-share', factory: (require) => {
|
|
2
|
+
const module = { exports: {} }; const exports = module.exports;
|
|
3
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
4
|
+
let react = require("react");
|
|
5
|
+
//#region src/client/index.ts
|
|
6
|
+
function CodexModelsCard(props) {
|
|
7
|
+
const settings = props.useSettings((snapshot) => snapshot);
|
|
8
|
+
const configured = settings.value?.additionalModelIds ?? [];
|
|
9
|
+
const [draft, setDraft] = (0, react.useState)(() => configured.join("\n"));
|
|
10
|
+
const [editing, setEditing] = (0, react.useState)(false);
|
|
11
|
+
const [busy, setBusy] = (0, react.useState)(false);
|
|
12
|
+
const [message, setMessage] = (0, react.useState)();
|
|
13
|
+
(0, react.useEffect)(() => {
|
|
14
|
+
if (!editing) setDraft(configured.join("\n"));
|
|
15
|
+
}, [settings.revision, editing]);
|
|
16
|
+
const submit = async () => {
|
|
17
|
+
const ids = draft.split(/\r?\n/).map((id) => id.trim()).filter(Boolean);
|
|
18
|
+
if (new Set(ids).size !== ids.length) {
|
|
19
|
+
setMessage("Each model ID must appear only once.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (settings.revision === void 0) return;
|
|
23
|
+
setBusy(true);
|
|
24
|
+
setMessage(void 0);
|
|
25
|
+
try {
|
|
26
|
+
const error = await props.save(ids, settings.revision);
|
|
27
|
+
if (error === void 0) {
|
|
28
|
+
setEditing(false);
|
|
29
|
+
setMessage("Codex model IDs saved.");
|
|
30
|
+
} else setMessage(error);
|
|
31
|
+
} finally {
|
|
32
|
+
setBusy(false);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const children = editing ? [
|
|
36
|
+
(0, react.createElement)("label", {
|
|
37
|
+
key: "label",
|
|
38
|
+
htmlFor: "codex-share-model-ids"
|
|
39
|
+
}, "Additional model IDs (one per line)"),
|
|
40
|
+
(0, react.createElement)("textarea", {
|
|
41
|
+
key: "input",
|
|
42
|
+
id: "codex-share-model-ids",
|
|
43
|
+
rows: 4,
|
|
44
|
+
value: draft,
|
|
45
|
+
placeholder: "gpt-6-sol\ngpt-6-luna",
|
|
46
|
+
disabled: busy || !settings.writable,
|
|
47
|
+
onChange: (event) => setDraft(event.target.value),
|
|
48
|
+
style: {
|
|
49
|
+
display: "block",
|
|
50
|
+
width: "100%",
|
|
51
|
+
boxSizing: "border-box",
|
|
52
|
+
margin: "8px 0"
|
|
53
|
+
}
|
|
54
|
+
}),
|
|
55
|
+
(0, react.createElement)("p", { key: "hint" }, "These IDs are added to the installed Codex catalog. The subscription endpoint must accept each ID."),
|
|
56
|
+
(0, react.createElement)("button", {
|
|
57
|
+
key: "save",
|
|
58
|
+
type: "button",
|
|
59
|
+
disabled: busy || !settings.writable,
|
|
60
|
+
onClick: () => {
|
|
61
|
+
submit();
|
|
62
|
+
}
|
|
63
|
+
}, busy ? "Saving…" : "Save model IDs"),
|
|
64
|
+
(0, react.createElement)("button", {
|
|
65
|
+
key: "cancel",
|
|
66
|
+
type: "button",
|
|
67
|
+
disabled: busy,
|
|
68
|
+
onClick: () => {
|
|
69
|
+
setEditing(false);
|
|
70
|
+
setMessage(void 0);
|
|
71
|
+
},
|
|
72
|
+
style: { marginLeft: 8 }
|
|
73
|
+
}, "Cancel")
|
|
74
|
+
] : [(0, react.createElement)("span", { key: "list" }, configured.length > 0 ? `Additional models: ${configured.join(", ")}` : "Using installed Codex model catalog"), (0, react.createElement)("button", {
|
|
75
|
+
key: "edit",
|
|
76
|
+
type: "button",
|
|
77
|
+
disabled: !settings.writable,
|
|
78
|
+
onClick: () => {
|
|
79
|
+
setDraft(configured.join("\n"));
|
|
80
|
+
setMessage(void 0);
|
|
81
|
+
setEditing(true);
|
|
82
|
+
},
|
|
83
|
+
style: { marginLeft: 8 }
|
|
84
|
+
}, "Edit model IDs")];
|
|
85
|
+
return (0, react.createElement)("div", { style: { padding: "8px 0" } }, ...children, message === void 0 ? null : (0, react.createElement)("p", { role: "status" }, message));
|
|
86
|
+
}
|
|
87
|
+
const inject = [
|
|
88
|
+
"slots",
|
|
89
|
+
"settingsScope",
|
|
90
|
+
"remote",
|
|
91
|
+
"remote.settings"
|
|
92
|
+
];
|
|
93
|
+
function apply(ctx) {
|
|
94
|
+
const scope = ctx.settingsScope.bind({ namespace: "llm-codex-share" });
|
|
95
|
+
ctx.slots.inject("settings.models.provider-card", () => ctx.slots.register({
|
|
96
|
+
name: "settings.models.provider-card",
|
|
97
|
+
key: "llm-codex-share",
|
|
98
|
+
inject: () => ({
|
|
99
|
+
hooks: { settings: scope },
|
|
100
|
+
save: async (ids, revision) => {
|
|
101
|
+
const response = await ctx.remote.settings.mutate("llm-codex-share", [ids.length === 0 ? {
|
|
102
|
+
op: "unset",
|
|
103
|
+
path: ["additionalModelIds"]
|
|
104
|
+
} : {
|
|
105
|
+
op: "set",
|
|
106
|
+
path: ["additionalModelIds"],
|
|
107
|
+
value: ids
|
|
108
|
+
}], revision);
|
|
109
|
+
return response.ok ? void 0 : response.error.message;
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
}, CodexModelsCard));
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
exports.apply = apply;
|
|
116
|
+
exports.inject = inject;
|
|
117
|
+
|
|
118
|
+
return module.exports;
|
|
119
|
+
} });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-share",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Use the local Codex CLI ChatGPT subscription login as a DeepSeek Harness LLM provider",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
"types": "./dist/index.d.mts",
|
|
12
12
|
"default": "./dist/index.mjs"
|
|
13
13
|
},
|
|
14
|
+
"./client": "./lib/client.js",
|
|
14
15
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
15
16
|
"./package.json": "./package.json"
|
|
16
17
|
},
|
|
17
18
|
"files": [
|
|
18
19
|
"dist",
|
|
20
|
+
"lib/client.js",
|
|
19
21
|
"cordis.patch.yml",
|
|
20
22
|
"README.md",
|
|
21
23
|
"LICENSE"
|
|
@@ -25,34 +27,52 @@
|
|
|
25
27
|
},
|
|
26
28
|
"packageManager": "pnpm@11.7.0",
|
|
27
29
|
"scripts": {
|
|
28
|
-
"build": "tsdown src/index.ts --dts --platform node --format esm",
|
|
30
|
+
"build": "tsdown src/index.ts --dts --platform node --format esm && pnpm build:client",
|
|
31
|
+
"build:client": "tsdown src/client/index.ts --platform browser --format cjs --out-dir lib --no-clean --external react --external @deepseek-ai/cordis --external @deepseek-ai/dsh-client-ui-slots && node scripts/wrap-client.mjs",
|
|
29
32
|
"typecheck": "tsc --noEmit",
|
|
30
33
|
"test": "vitest run",
|
|
31
34
|
"prepack": "pnpm build"
|
|
32
35
|
},
|
|
33
36
|
"peerDependencies": {
|
|
34
37
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
35
|
-
"@deepseek-ai/dsh-llm": "^0.1.5-rc.3",
|
|
36
38
|
"@deepseek-ai/dsh-attachment": "^0.1.5-rc.3",
|
|
37
39
|
"@deepseek-ai/dsh-fs": "^0.1.5-rc.3",
|
|
38
|
-
"@deepseek-ai/dsh-llm
|
|
40
|
+
"@deepseek-ai/dsh-llm": "^0.1.5-rc.3",
|
|
41
|
+
"@deepseek-ai/dsh-llm-pi-ai": "^0.1.5-rc.3",
|
|
42
|
+
"@deepseek-ai/dsh-settings": "^0.1.5-rc.3",
|
|
43
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
39
44
|
},
|
|
40
45
|
"dependencies": {
|
|
41
46
|
"@earendil-works/pi-ai": "^0.85.1"
|
|
42
47
|
},
|
|
43
48
|
"devDependencies": {
|
|
44
49
|
"@deepseek-ai/cordis": "link:../deepseek-harness/vendor/cordis",
|
|
45
|
-
"@deepseek-ai/dsh-
|
|
50
|
+
"@deepseek-ai/dsh-api-remotes": "link:../deepseek-harness/packages/api/remotes",
|
|
51
|
+
"@deepseek-ai/dsh-app-boot": "link:../deepseek-harness/packages/boot/app-boot",
|
|
46
52
|
"@deepseek-ai/dsh-attachment": "link:../deepseek-harness/packages/attachment/attachment",
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-renderer": "link:../deepseek-harness/packages/client/ui-renderer",
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-settings": "link:../deepseek-harness/packages/client/ui-settings",
|
|
55
|
+
"@deepseek-ai/dsh-client-ui-settings-models": "link:../deepseek-harness/packages/client/ui-settings-models",
|
|
56
|
+
"@deepseek-ai/dsh-client-ui-slots": "link:../deepseek-harness/packages/client/ui-slots",
|
|
47
57
|
"@deepseek-ai/dsh-fs": "link:../deepseek-harness/packages/fs/fs",
|
|
58
|
+
"@deepseek-ai/dsh-llm": "link:../deepseek-harness/packages/llm/llm",
|
|
48
59
|
"@deepseek-ai/dsh-llm-pi-ai": "link:../deepseek-harness/packages/llm/llm-pi-ai",
|
|
60
|
+
"@deepseek-ai/dsh-settings": "link:../deepseek-harness/packages/settings/settings",
|
|
61
|
+
"@deepseek-ai/schemastery": "link:../deepseek-harness/vendor/schemastery",
|
|
49
62
|
"@types/node": "^22.20.0",
|
|
63
|
+
"@types/react": "~18.3.31",
|
|
64
|
+
"react": "^18.3.1",
|
|
50
65
|
"tsdown": "^0.22.2",
|
|
51
66
|
"typescript": "^6.0.3",
|
|
52
|
-
"vitest": "^4.1.8"
|
|
53
|
-
"@deepseek-ai/dsh-app-boot": "link:../deepseek-harness/packages/boot/app-boot"
|
|
67
|
+
"vitest": "^4.1.8"
|
|
54
68
|
},
|
|
55
69
|
"dsh": {
|
|
70
|
+
"client": {
|
|
71
|
+
"platform": "web",
|
|
72
|
+
"inject": [
|
|
73
|
+
"@deepseek-ai/dsh-client-ui-settings-models"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
56
76
|
"bundle": {
|
|
57
77
|
"patch": "./cordis.patch.yml"
|
|
58
78
|
}
|