dsh-codex-subscription 0.2.8 → 0.3.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/AGENTS.md +14 -12
- package/README.en.md +7 -3
- package/README.md +7 -3
- package/dsh-codex.ps1 +33 -12
- package/lib/client.js +93 -3
- package/lib/index.js +230 -13
- package/package.json +12 -4
package/AGENTS.md
CHANGED
|
@@ -6,7 +6,7 @@ Use this guide when a user asks an Agent to install, update, verify, or remove
|
|
|
6
6
|
## Safety
|
|
7
7
|
|
|
8
8
|
- Confirm the target DSH profile; use `web` only when it is the user's target.
|
|
9
|
-
- Use the pinned `v0.
|
|
9
|
+
- Use the pinned `v0.3.1` release assets for a first install, never a moving branch.
|
|
10
10
|
- Never print OAuth credentials, account IDs, authorization callbacks, or the
|
|
11
11
|
credential store.
|
|
12
12
|
- Do not start, stop, or restart DSH without explicit permission.
|
|
@@ -51,7 +51,7 @@ the user which installation is the target.
|
|
|
51
51
|
Download the fixed release asset to a visible file, then invoke the requested action:
|
|
52
52
|
|
|
53
53
|
```powershell
|
|
54
|
-
curl.exe -fL https://github.com/WSL043/dsh-codex-subscription/releases/download/v0.
|
|
54
|
+
curl.exe -fL https://github.com/WSL043/dsh-codex-subscription/releases/download/v0.3.1/dsh-codex.ps1 -o "$env:TEMP\dsh-codex.ps1"
|
|
55
55
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$env:TEMP\dsh-codex.ps1" Install
|
|
56
56
|
```
|
|
57
57
|
|
|
@@ -59,7 +59,7 @@ If `curl.exe` is unavailable, download the same pinned asset without executing
|
|
|
59
59
|
remote text in memory:
|
|
60
60
|
|
|
61
61
|
```powershell
|
|
62
|
-
Invoke-WebRequest -UseBasicParsing -Uri 'https://github.com/WSL043/dsh-codex-subscription/releases/download/v0.
|
|
62
|
+
Invoke-WebRequest -UseBasicParsing -Uri 'https://github.com/WSL043/dsh-codex-subscription/releases/download/v0.3.1/dsh-codex.ps1' -OutFile "$env:TEMP\dsh-codex.ps1"
|
|
63
63
|
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$env:TEMP\dsh-codex.ps1" Install
|
|
64
64
|
```
|
|
65
65
|
|
|
@@ -89,17 +89,18 @@ profile and saved login.
|
|
|
89
89
|
|
|
90
90
|
## Existing DSH CLI
|
|
91
91
|
|
|
92
|
-
When `dsh`, Node.js, and pnpm are already available, install the
|
|
93
|
-
|
|
92
|
+
When `dsh`, Node.js, and pnpm are already available, install the pinned npm
|
|
93
|
+
package directly:
|
|
94
94
|
|
|
95
95
|
```sh
|
|
96
|
-
dsh plugin --profile web add
|
|
96
|
+
dsh plugin --profile web add dsh-codex-subscription@0.3.1
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
Update
|
|
100
|
-
hand, remove `@wsl043/dsh-codex-subscription` only
|
|
101
|
-
verification. The Windows manager performs this
|
|
102
|
-
preserves the stored login. Uninstall the current
|
|
99
|
+
Update with `dsh plugin --profile web update dsh-codex-subscription`. When
|
|
100
|
+
migrating from v0.2.1 by hand, remove `@wsl043/dsh-codex-subscription` only
|
|
101
|
+
after the new package passes verification. The Windows manager performs this
|
|
102
|
+
migration automatically and preserves the stored login. Uninstall the current
|
|
103
|
+
package with:
|
|
103
104
|
|
|
104
105
|
```sh
|
|
105
106
|
dsh plugin --profile web remove dsh-codex-subscription
|
|
@@ -127,8 +128,9 @@ If the user authorizes a live check, restart DSH manually, open
|
|
|
127
128
|
**Settings -> Codex**, and verify the page loads. Confirm that Web
|
|
128
129
|
search offers both **DSH default** and **Codex subscription**, and that the Beta
|
|
129
130
|
composer quota switch starts off. Weekly-only usage is valid; Spark remains a
|
|
130
|
-
separate bucket.
|
|
131
|
-
explicitly
|
|
131
|
+
separate bucket. Confirm that `codex_image_generate` is available. Only when the
|
|
132
|
+
user explicitly requests a quota-consuming live check, ask the Agent to generate
|
|
133
|
+
one simple image and confirm that it appears in the conversation.
|
|
132
134
|
|
|
133
135
|
## Failure handling
|
|
134
136
|
|
package/README.en.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# DSH Codex Subscription
|
|
2
2
|
|
|
3
3
|
[](https://github.com/WSL043/dsh-codex-subscription/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/dsh-codex-subscription)
|
|
4
5
|
[](LICENSE)
|
|
5
6
|
[](https://github.com/WSL043/dsh-codex-subscription/stargazers)
|
|
6
7
|
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
|
|
9
10
|
Sign in to ChatGPT and use a Codex subscription directly in DeepSeek Harness.
|
|
10
11
|
No OpenAI API key or Codex CLI installation is required. DSH conversations,
|
|
11
|
-
tools, permissions, search choice, and quota stay in one place.
|
|
12
|
+
tools, permissions, image generation, search choice, and quota stay in one place.
|
|
12
13
|
|
|
13
14
|
[Agent install](#let-an-agent-install-it-recommended) · [Windows install](#manual-windows-install) · [Update or uninstall](#update-and-uninstall)
|
|
14
15
|
|
|
@@ -23,6 +24,7 @@ If this helps, open the [GitHub repository](https://github.com/WSL043/dsh-codex-
|
|
|
23
24
|
|
|
24
25
|
- Uses your ChatGPT / Codex subscription directly inside DSH, with no OpenAI API key or Codex CLI required;
|
|
25
26
|
- Signs in to ChatGPT from Settings and keeps credentials on the host;
|
|
27
|
+
- Supports Codex image generation and shows the result directly in the DSH conversation;
|
|
26
28
|
- Switches between DSH's default search and Codex subscription search;
|
|
27
29
|
- Shows the quota, reset time, and freshness actually returned by the backend;
|
|
28
30
|
- Can show the selected Codex model's remaining quota before the model name (Beta, off by default);
|
|
@@ -79,7 +81,7 @@ once and install again. Restart DSH manually after installation.
|
|
|
79
81
|
<summary>macOS, Linux, or an existing <code>dsh</code> command</summary>
|
|
80
82
|
|
|
81
83
|
```sh
|
|
82
|
-
dsh plugin --profile web add
|
|
84
|
+
dsh plugin --profile web add dsh-codex-subscription
|
|
83
85
|
dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
84
86
|
dsh --profile web --dump-config
|
|
85
87
|
```
|
|
@@ -96,6 +98,8 @@ contain one `codex-subscription` entry.
|
|
|
96
98
|
3. Choose DSH default search or Codex subscription search.
|
|
97
99
|
4. Choose a Codex model from the model selector.
|
|
98
100
|
|
|
101
|
+
Describe the image you want. The Agent can generate it through Codex and show the result in the conversation.
|
|
102
|
+
|
|
99
103
|
Codex subscription search reuses the same ChatGPT sign-in and does not need an
|
|
100
104
|
OpenAI API key. Changing the search source does not change the conversation
|
|
101
105
|
model, and a failed source never silently falls back to another paid service.
|
|
@@ -136,7 +140,7 @@ the two Windows first-install commands above once.
|
|
|
136
140
|
Update and verify:
|
|
137
141
|
|
|
138
142
|
```sh
|
|
139
|
-
dsh plugin --profile web
|
|
143
|
+
dsh plugin --profile web update dsh-codex-subscription
|
|
140
144
|
dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
141
145
|
dsh --profile web --dump-config
|
|
142
146
|
```
|
package/README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# DSH Codex Subscription
|
|
2
2
|
|
|
3
3
|
[](https://github.com/WSL043/dsh-codex-subscription/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/dsh-codex-subscription)
|
|
4
5
|
[](LICENSE)
|
|
5
6
|
[](https://github.com/WSL043/dsh-codex-subscription/stargazers)
|
|
6
7
|
|
|
7
8
|
[English](README.en.md)
|
|
8
9
|
|
|
9
10
|
在 DeepSeek Harness 中直接登录 ChatGPT 并使用 Codex 订阅,不需要 OpenAI API Key,
|
|
10
|
-
也不依赖 Codex CLI。保留 DSH
|
|
11
|
+
也不依赖 Codex CLI。保留 DSH 原有的会话、工具和权限,还能生成图片、切换联网搜索来源并查看额度。
|
|
11
12
|
|
|
12
13
|
[交给 Agent 安装](#交给-agent推荐) · [Windows 手动安装](#windows-手动安装) · [更新与卸载](#更新与卸载)
|
|
13
14
|
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
|
|
22
23
|
- 在 DSH 中直接使用 ChatGPT / Codex 订阅,不需要 OpenAI API Key 或 Codex CLI;
|
|
23
24
|
- 在设置页登录 ChatGPT,凭据保留在本机;
|
|
25
|
+
- 支持 Codex 图片生成,结果直接显示在 DSH 会话中;
|
|
24
26
|
- 可在 DSH 默认搜索与 Codex 订阅搜索之间切换;
|
|
25
27
|
- 展示服务端实际返回的额度、重置时间和更新时间;
|
|
26
28
|
- 可在模型名称左侧显示当前 Codex 模型的剩余额度(Beta,默认关闭);
|
|
@@ -70,7 +72,7 @@ powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$env:TEMP\dsh-codex.ps1
|
|
|
70
72
|
<summary>macOS、Linux,或已有 <code>dsh</code> 命令</summary>
|
|
71
73
|
|
|
72
74
|
```sh
|
|
73
|
-
dsh plugin --profile web add
|
|
75
|
+
dsh plugin --profile web add dsh-codex-subscription
|
|
74
76
|
dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
75
77
|
dsh --profile web --dump-config
|
|
76
78
|
```
|
|
@@ -87,6 +89,8 @@ dsh --profile web --dump-config
|
|
|
87
89
|
3. 选择使用 DSH 默认搜索,或使用 Codex 订阅搜索;
|
|
88
90
|
4. 在模型选择器中选择 Codex 模型。
|
|
89
91
|
|
|
92
|
+
需要图片时直接描述想要的画面,Agent 会调用 Codex 图片生成并在会话中显示结果。
|
|
93
|
+
|
|
90
94
|
Codex 订阅搜索复用同一份 ChatGPT 登录,不需要 OpenAI API Key。切换搜索来源不会改变
|
|
91
95
|
当前对话模型,也不会在失败时自动改走另一个付费服务。升级后默认保留 DSH 原有搜索,
|
|
92
96
|
需要使用 Codex 订阅搜索时再主动切换。
|
|
@@ -124,7 +128,7 @@ Windows 首次安装命令即可。
|
|
|
124
128
|
更新并检查:
|
|
125
129
|
|
|
126
130
|
```sh
|
|
127
|
-
dsh plugin --profile web
|
|
131
|
+
dsh plugin --profile web update dsh-codex-subscription
|
|
128
132
|
dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
129
133
|
dsh --profile web --dump-config
|
|
130
134
|
```
|
package/dsh-codex.ps1
CHANGED
|
@@ -32,8 +32,8 @@ if ($Managed -and -not $PSBoundParameters.ContainsKey('Action')) {
|
|
|
32
32
|
|
|
33
33
|
$PackageName = 'dsh-codex-subscription'
|
|
34
34
|
$LegacyPackageName = '@wsl043/dsh-codex-subscription'
|
|
35
|
-
$PackageVersion = '0.
|
|
36
|
-
$PackageSpec = 'https://github.com/WSL043/dsh-codex-subscription/releases/download/v0.
|
|
35
|
+
$PackageVersion = '0.3.1'
|
|
36
|
+
$PackageSpec = 'https://github.com/WSL043/dsh-codex-subscription/releases/download/v0.3.1/dsh-codex-subscription.tgz'
|
|
37
37
|
$PnpmVersion = '11.19.0'
|
|
38
38
|
$PnpmUrl = 'https://registry.npmjs.org/pnpm/-/pnpm-11.19.0.tgz'
|
|
39
39
|
$PnpmSha512 = '7881F3ED590D472C4A955E2B88B2121791116066DCC88CBCA3849EC9B60F1BBAA6D2CCB221FA91DA4E1C65BEF2BCBE379365AEA7AC539C7BF86DEDC3A1B22DCE'
|
|
@@ -71,8 +71,12 @@ function Invoke-LatestManager {
|
|
|
71
71
|
param([Parameter(Mandatory = $true)][string] $InstalledCommandRoot)
|
|
72
72
|
|
|
73
73
|
Write-Host 'Checking the latest immutable release...'
|
|
74
|
-
$
|
|
74
|
+
$releaseSeparator = if ($ReleaseApi.Contains('?')) { '&' } else { '?' }
|
|
75
|
+
$releaseUri = $ReleaseApi + $releaseSeparator + 'cache_bust=' + [DateTime]::UtcNow.Ticks
|
|
76
|
+
$releaseResponse = Invoke-WebRequest -UseBasicParsing -Uri $releaseUri -Headers @{
|
|
75
77
|
Accept = 'application/vnd.github+json'
|
|
78
|
+
'Cache-Control' = 'no-cache'
|
|
79
|
+
Pragma = 'no-cache'
|
|
76
80
|
'User-Agent' = 'dsh-codex'
|
|
77
81
|
}
|
|
78
82
|
try {
|
|
@@ -599,7 +603,7 @@ function Invoke-DshCommand {
|
|
|
599
603
|
if ($LASTEXITCODE -ne 0) { throw "dsh failed with exit code $LASTEXITCODE." }
|
|
600
604
|
}
|
|
601
605
|
|
|
602
|
-
function Get-
|
|
606
|
+
function Get-InstalledPackages {
|
|
603
607
|
param([Parameter(Mandatory = $true)] $Target)
|
|
604
608
|
|
|
605
609
|
$json = Invoke-DshCommand -Target $Target -Arguments @(
|
|
@@ -618,7 +622,17 @@ function Get-InstalledPackageNames {
|
|
|
618
622
|
$dependenciesProperty = $project.PSObject.Properties['dependencies']
|
|
619
623
|
if ($null -eq $dependenciesProperty -or $null -eq $dependenciesProperty.Value) { continue }
|
|
620
624
|
foreach ($property in $dependenciesProperty.Value.PSObject.Properties) {
|
|
621
|
-
|
|
625
|
+
$version = $null
|
|
626
|
+
if ($null -ne $property.Value) {
|
|
627
|
+
$versionProperty = $property.Value.PSObject.Properties['version']
|
|
628
|
+
if ($null -ne $versionProperty -and $null -ne $versionProperty.Value) {
|
|
629
|
+
$version = [string] $versionProperty.Value
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
Write-Output ([pscustomobject]@{
|
|
633
|
+
Name = [string] $property.Name
|
|
634
|
+
Version = $version
|
|
635
|
+
})
|
|
622
636
|
}
|
|
623
637
|
}
|
|
624
638
|
}
|
|
@@ -686,9 +700,10 @@ try {
|
|
|
686
700
|
$env:npm_config_store_dir = $pnpmStore
|
|
687
701
|
}
|
|
688
702
|
|
|
689
|
-
$installedBefore = @(Get-
|
|
690
|
-
$
|
|
691
|
-
$
|
|
703
|
+
$installedBefore = @(Get-InstalledPackages -Target $target)
|
|
704
|
+
$installedBeforeNames = @($installedBefore | ForEach-Object { $_.Name })
|
|
705
|
+
$hadPackage = $installedBeforeNames -contains $PackageName
|
|
706
|
+
$hadLegacyPackage = $installedBeforeNames -contains $LegacyPackageName
|
|
692
707
|
|
|
693
708
|
if ($Action -eq 'Uninstall') {
|
|
694
709
|
if ($hadPackage) {
|
|
@@ -726,9 +741,10 @@ try {
|
|
|
726
741
|
$config = Invoke-DshCommand -Target $target -Arguments @('--profile', $Profile, '--dump-config') -Capture
|
|
727
742
|
$entryCount = ([regex]::Matches($config, '(?<![A-Za-z0-9_-])codex-subscription(?![A-Za-z0-9_-])')).Count
|
|
728
743
|
$legacyEntryCount = ([regex]::Matches($config, '(?<![A-Za-z0-9_-])wsl043-codex-subscription(?![A-Za-z0-9_-])')).Count
|
|
729
|
-
$installedAfter = @(Get-
|
|
744
|
+
$installedAfter = @(Get-InstalledPackages -Target $target)
|
|
745
|
+
$installedAfterNames = @($installedAfter | ForEach-Object { $_.Name })
|
|
730
746
|
if ($Action -eq 'Uninstall') {
|
|
731
|
-
if (($
|
|
747
|
+
if (($installedAfterNames -contains $PackageName) -or ($installedAfterNames -contains $LegacyPackageName)) {
|
|
732
748
|
throw 'The plugin package is still present after uninstall.'
|
|
733
749
|
}
|
|
734
750
|
if ($entryCount -ne 0 -or $legacyEntryCount -ne 0) {
|
|
@@ -737,8 +753,13 @@ try {
|
|
|
737
753
|
Remove-ManagerCommand -Directory $managerCommandRoot
|
|
738
754
|
Write-Host 'Uninstalled. The DSH profile and saved credentials were kept.'
|
|
739
755
|
} else {
|
|
740
|
-
|
|
741
|
-
if ($
|
|
756
|
+
$installedPackage = @($installedAfter | Where-Object { $_.Name -eq $PackageName } | Select-Object -First 1)
|
|
757
|
+
if ($installedPackage.Count -eq 0) { throw 'The installed package did not appear in the DSH plugin list.' }
|
|
758
|
+
if ($installedPackage[0].Version -ne $PackageVersion) {
|
|
759
|
+
$foundVersion = if ($installedPackage[0].Version) { $installedPackage[0].Version } else { 'unknown' }
|
|
760
|
+
throw "DSH did not install the requested package version: expected $PackageVersion, found $foundVersion."
|
|
761
|
+
}
|
|
762
|
+
if ($installedAfterNames -contains $LegacyPackageName) { throw 'The legacy package is still present after migration.' }
|
|
742
763
|
if ($entryCount -ne 1) { throw "Expected one plugin profile entry, found $entryCount." }
|
|
743
764
|
if ($legacyEntryCount -ne 0) { throw 'The legacy plugin profile entry is still present after migration.' }
|
|
744
765
|
Install-ManagerCommand -Directory $managerCommandRoot
|
package/lib/client.js
CHANGED
|
@@ -6,6 +6,7 @@ window.__ModuleLoader__.load({
|
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
|
+
let _deepseek_ai_dsh_client_ui_attachment = require("@deepseek-ai/dsh-client-ui-attachment");
|
|
9
10
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
11
|
//#region src/settings-contract.js
|
|
11
12
|
const QUICK_QUOTA_FIELD = "quickQuotaVisible";
|
|
@@ -36,7 +37,8 @@ window.__ModuleLoader__.load({
|
|
|
36
37
|
"slots",
|
|
37
38
|
"locale",
|
|
38
39
|
"connection",
|
|
39
|
-
"modelDirectories"
|
|
40
|
+
"modelDirectories",
|
|
41
|
+
"conversation"
|
|
40
42
|
];
|
|
41
43
|
const NS = "settings.codexSubscription";
|
|
42
44
|
const CHANNEL = "/codex-subscription";
|
|
@@ -94,7 +96,18 @@ window.__ModuleLoader__.load({
|
|
|
94
96
|
unavailable: "暂无数据",
|
|
95
97
|
quickQuotaSetting: "输入框额度",
|
|
96
98
|
quickQuotaBeta: "Beta",
|
|
97
|
-
quickQuotaStatus: "Codex 剩余额度 {value}%"
|
|
99
|
+
quickQuotaStatus: "Codex 剩余额度 {value}%",
|
|
100
|
+
imageGenerate: "生成图片",
|
|
101
|
+
imageGenerating: "正在生成…",
|
|
102
|
+
imageGenerated: "已生成",
|
|
103
|
+
imageFailed: "生成失败",
|
|
104
|
+
imageLabel: "生成的图片",
|
|
105
|
+
imageOpen: "查看原图",
|
|
106
|
+
imageOpenNamed: "查看 {value}",
|
|
107
|
+
imageLoading: "正在加载图片…",
|
|
108
|
+
imageLoadFailed: "图片加载失败,点击重试",
|
|
109
|
+
imagePreview: "图片预览",
|
|
110
|
+
imageClosePreview: "关闭预览"
|
|
98
111
|
};
|
|
99
112
|
const en = {
|
|
100
113
|
nav: "Codex",
|
|
@@ -148,7 +161,18 @@ window.__ModuleLoader__.load({
|
|
|
148
161
|
unavailable: "No data yet",
|
|
149
162
|
quickQuotaSetting: "Composer quota",
|
|
150
163
|
quickQuotaBeta: "Beta",
|
|
151
|
-
quickQuotaStatus: "Codex quota: {value}% remaining"
|
|
164
|
+
quickQuotaStatus: "Codex quota: {value}% remaining",
|
|
165
|
+
imageGenerate: "Generate image",
|
|
166
|
+
imageGenerating: "Generating…",
|
|
167
|
+
imageGenerated: "Generated",
|
|
168
|
+
imageFailed: "Generation failed",
|
|
169
|
+
imageLabel: "Generated image",
|
|
170
|
+
imageOpen: "View original",
|
|
171
|
+
imageOpenNamed: "View {value}",
|
|
172
|
+
imageLoading: "Loading image…",
|
|
173
|
+
imageLoadFailed: "Image failed to load. Click to retry",
|
|
174
|
+
imagePreview: "Image preview",
|
|
175
|
+
imageClosePreview: "Close preview"
|
|
152
176
|
};
|
|
153
177
|
const STYLE = `
|
|
154
178
|
.codexSubscription{display:flex;flex-direction:column;gap:10px;max-width:720px;color:var(--dsw-alias-label-primary);container-type:inline-size}
|
|
@@ -176,6 +200,7 @@ window.__ModuleLoader__.load({
|
|
|
176
200
|
.codexSubscriptionCreditBalance{display:flex;flex-direction:column;gap:6px}.codexSubscriptionCreditBalance span,.codexSubscriptionCreditLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.codexSubscriptionCreditBalance strong{font:600 18px/24px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
|
|
177
201
|
.codexSubscriptionSpendLimit{display:flex;flex-direction:column;gap:8px}.codexSubscriptionSpendTop{display:flex;align-items:baseline;justify-content:space-between;gap:12px}.codexSubscriptionSpendTop strong{font:600 16px/22px ui-monospace,SFMono-Regular,Consolas,monospace;font-variant-numeric:tabular-nums}.codexSubscriptionSpendLimit progress{width:100%;height:6px;border:0;border-radius:999px;overflow:hidden;background:var(--dsw-alias-border-l3);accent-color:var(--dsw-alias-brand-primary,#3964fe);-webkit-appearance:none;appearance:none}.codexSubscriptionSpendLimit progress::-webkit-progress-bar{background:var(--dsw-alias-border-l3);border-radius:999px}.codexSubscriptionSpendLimit progress::-webkit-progress-value{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}.codexSubscriptionSpendLimit progress::-moz-progress-bar{background:var(--dsw-alias-brand-primary,#3964fe);border-radius:999px}
|
|
178
202
|
.codexComposerQuota{display:inline-flex;align-items:center;flex:0 0 auto;height:28px;box-sizing:border-box;margin-right:-4px;padding:0;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;line-height:20px;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap;user-select:none}
|
|
203
|
+
.codexImageTool{display:flex;flex-direction:column;gap:8px;margin:4px 0;color:var(--dsw-alias-label-primary)}.codexImageToolRow{display:flex;align-items:center;min-height:24px;gap:8px;font-size:13px;line-height:20px}.codexImageToolIcon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--dsw-alias-label-secondary)}.codexImageToolIcon::before{content:'';width:8px;height:8px;border:1.5px solid currentColor;border-radius:3px}.codexImageTool[data-state=running] .codexImageToolIcon::before{border-radius:50%;border-right-color:transparent;animation:codexImageSpin 800ms linear infinite}.codexImageTool[data-state=error] .codexImageToolIcon::before{border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-primary)}.codexImageToolTitle{font-weight:500}.codexImageToolState{color:var(--dsw-alias-label-tertiary)}.codexImageToolError{margin:0 0 0 24px;font-size:12px;line-height:18px;color:var(--dsw-alias-state-error-primary)}.codexImageToolGallery{margin-left:24px}@keyframes codexImageSpin{to{transform:rotate(360deg)}}
|
|
179
204
|
@container (max-width:560px){.codexSubscriptionCreditRows{grid-template-columns:1fr}}
|
|
180
205
|
@container (max-width:480px){.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{align-items:flex-start;flex-direction:column}.codexSubscriptionActions{width:100%}.codexSubscriptionSearchChoices{grid-template-columns:1fr}}
|
|
181
206
|
@media(max-width:640px){.codexSubscriptionCard{padding:14px}}
|
|
@@ -200,6 +225,61 @@ window.__ModuleLoader__.load({
|
|
|
200
225
|
const date = new Date(value);
|
|
201
226
|
return Number.isFinite(date.getTime()) ? date : void 0;
|
|
202
227
|
};
|
|
228
|
+
const imageGalleryLabels = (t) => ({
|
|
229
|
+
image: t("imageLabel"),
|
|
230
|
+
open: t("imageOpen"),
|
|
231
|
+
openNamed: (value) => fill(t("imageOpenNamed"), { value }),
|
|
232
|
+
loading: t("imageLoading"),
|
|
233
|
+
loadFailed: t("imageLoadFailed"),
|
|
234
|
+
lightbox: {
|
|
235
|
+
dialog: t("imagePreview"),
|
|
236
|
+
close: t("imageClosePreview")
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
function CodexImageToolRow({ block, loadImage, t }) {
|
|
240
|
+
const settled = block?.kind === "tool-result";
|
|
241
|
+
const image = settled ? block.content.find((item) => item?.type === "image" && item.attachment !== void 0) : void 0;
|
|
242
|
+
const failed = settled && block.isError === true;
|
|
243
|
+
const state = !settled ? "running" : failed ? "error" : "done";
|
|
244
|
+
const status = !settled ? t("imageGenerating") : failed ? t("imageFailed") : t("imageGenerated");
|
|
245
|
+
const error = failed ? block.content.find((item) => item?.type === "text" && typeof item.text === "string")?.text : void 0;
|
|
246
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
247
|
+
className: "codexImageTool",
|
|
248
|
+
"data-state": state,
|
|
249
|
+
children: [
|
|
250
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
251
|
+
className: "codexImageToolRow",
|
|
252
|
+
children: [
|
|
253
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
254
|
+
className: "codexImageToolIcon",
|
|
255
|
+
"aria-hidden": "true"
|
|
256
|
+
}),
|
|
257
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
258
|
+
className: "codexImageToolTitle",
|
|
259
|
+
children: t("imageGenerate")
|
|
260
|
+
}),
|
|
261
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
262
|
+
className: "codexImageToolState",
|
|
263
|
+
children: status
|
|
264
|
+
})
|
|
265
|
+
]
|
|
266
|
+
}),
|
|
267
|
+
image === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
268
|
+
className: "codexImageToolGallery",
|
|
269
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_attachment.ImageGallery, {
|
|
270
|
+
images: [{ attachment: image.attachment }],
|
|
271
|
+
load: loadImage,
|
|
272
|
+
align: "start",
|
|
273
|
+
labels: imageGalleryLabels(t)
|
|
274
|
+
})
|
|
275
|
+
}),
|
|
276
|
+
error === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
277
|
+
className: "codexImageToolError",
|
|
278
|
+
children: error
|
|
279
|
+
})
|
|
280
|
+
]
|
|
281
|
+
});
|
|
282
|
+
}
|
|
203
283
|
function createPreferenceController(rpc) {
|
|
204
284
|
let snapshot = Object.freeze({
|
|
205
285
|
status: "loading",
|
|
@@ -854,6 +934,16 @@ window.__ModuleLoader__.load({
|
|
|
854
934
|
directory: ctx.modelDirectories.directoryFor(sessionId).store
|
|
855
935
|
})
|
|
856
936
|
}, CodexComposerQuota));
|
|
937
|
+
const conversation = ctx.get("conversation");
|
|
938
|
+
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
939
|
+
name: "tool.call.toolview",
|
|
940
|
+
key: "codex_image_generate",
|
|
941
|
+
locale: NS,
|
|
942
|
+
inject: (sessionId) => ({
|
|
943
|
+
t,
|
|
944
|
+
loadImage: (attachment) => conversation.resolveImage(sessionId, attachment)
|
|
945
|
+
})
|
|
946
|
+
}, CodexImageToolRow));
|
|
857
947
|
}
|
|
858
948
|
//#endregion
|
|
859
949
|
exports.apply = apply;
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { credentialRef } from "@deepseek-ai/dsh-credentials";
|
|
2
|
-
import { LlmError } from "@deepseek-ai/dsh-llm";
|
|
2
|
+
import { LlmError, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
3
3
|
import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
|
|
4
4
|
import { settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
5
5
|
import z from "@deepseek-ai/schemastery";
|
|
@@ -8,6 +8,7 @@ import { openaiCodexProvider as createOpenAICodexProvider } from "@earendil-work
|
|
|
8
8
|
import { createModels } from "@earendil-works/pi-ai";
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
import { WebError } from "@deepseek-ai/dsh-web";
|
|
11
|
+
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
11
12
|
//#region src/credential-store.js
|
|
12
13
|
const PROVIDER$1 = "openai-codex";
|
|
13
14
|
const abortIfNeeded = (options) => options?.signal?.throwIfAborted();
|
|
@@ -466,10 +467,10 @@ const CODEX_SEARCH_URL = "https://chatgpt.com/backend-api/codex/alpha/search";
|
|
|
466
467
|
const DEFAULT_MODEL = "gpt-5.6-luna";
|
|
467
468
|
const MAX_OUTPUT_TOKENS = 4096;
|
|
468
469
|
const MAX_SOURCE_DATE = 64;
|
|
469
|
-
const record$
|
|
470
|
-
const nonEmpty = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
|
|
470
|
+
const record$2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
471
|
+
const nonEmpty$1 = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
|
|
471
472
|
const displayText = (value) => {
|
|
472
|
-
const text = nonEmpty(value)?.replace(/\s+/gu, " ").trim();
|
|
473
|
+
const text = nonEmpty$1(value)?.replace(/\s+/gu, " ").trim();
|
|
473
474
|
if (text === void 0 || text.length === 0) return void 0;
|
|
474
475
|
return text;
|
|
475
476
|
};
|
|
@@ -479,8 +480,8 @@ const boundedDisplayText = (value, maximum) => {
|
|
|
479
480
|
return `${text.slice(0, maximum - 1)}…`;
|
|
480
481
|
};
|
|
481
482
|
function sourceOf(value) {
|
|
482
|
-
if (!record$
|
|
483
|
-
const url = nonEmpty(value.url);
|
|
483
|
+
if (!record$2(value)) return void 0;
|
|
484
|
+
const url = nonEmpty$1(value.url);
|
|
484
485
|
if (url === void 0) return void 0;
|
|
485
486
|
let parsed;
|
|
486
487
|
try {
|
|
@@ -500,7 +501,7 @@ function sourceOf(value) {
|
|
|
500
501
|
};
|
|
501
502
|
}
|
|
502
503
|
function parseSearchResponse(value) {
|
|
503
|
-
if (!record$
|
|
504
|
+
if (!record$2(value) || !Array.isArray(value.results)) throw new Error("Codex returned a malformed search response");
|
|
504
505
|
const seen = /* @__PURE__ */ new Set();
|
|
505
506
|
const sources = [];
|
|
506
507
|
for (const result of value.results ?? []) {
|
|
@@ -526,8 +527,8 @@ function createCodexSearchProvider(options) {
|
|
|
526
527
|
const access = auth?.auth?.apiKey;
|
|
527
528
|
const accountId = credential?.type === "oauth" ? credential.accountId : void 0;
|
|
528
529
|
if (typeof access !== "string" || access.length === 0 || typeof accountId !== "string" || accountId.length === 0) throw new WebError("ChatGPT subscription is not signed in", "WEB_PROVIDER_CREDENTIAL_MISSING");
|
|
529
|
-
const model = nonEmpty(options.resolveModel?.()) ?? DEFAULT_MODEL;
|
|
530
|
-
const id = nonEmpty(options.resolveSessionId?.()) ?? randomUUID();
|
|
530
|
+
const model = nonEmpty$1(options.resolveModel?.()) ?? DEFAULT_MODEL;
|
|
531
|
+
const id = nonEmpty$1(options.resolveSessionId?.()) ?? randomUUID();
|
|
531
532
|
let response;
|
|
532
533
|
try {
|
|
533
534
|
response = await fetchSearch(CODEX_SEARCH_URL, {
|
|
@@ -539,7 +540,7 @@ function createCodexSearchProvider(options) {
|
|
|
539
540
|
accept: "application/json",
|
|
540
541
|
"content-type": "application/json",
|
|
541
542
|
originator: "pi",
|
|
542
|
-
"user-agent": "dsh-codex-subscription/0.
|
|
543
|
+
"user-agent": "dsh-codex-subscription/0.3.1"
|
|
543
544
|
},
|
|
544
545
|
body: JSON.stringify({
|
|
545
546
|
id,
|
|
@@ -577,6 +578,215 @@ function createCodexSearchProvider(options) {
|
|
|
577
578
|
});
|
|
578
579
|
}
|
|
579
580
|
//#endregion
|
|
581
|
+
//#region src/codex-images.js
|
|
582
|
+
const CODEX_IMAGE_TOOL_NAME = "codex_image_generate";
|
|
583
|
+
const CODEX_IMAGE_GENERATION_URL = "https://chatgpt.com/backend-api/codex/images/generations";
|
|
584
|
+
const IMAGE_MODEL = "gpt-image-2";
|
|
585
|
+
const RESPONSE_ENVELOPE_BYTES = 1024 * 1024;
|
|
586
|
+
const PNG_SIGNATURE = Buffer.from([
|
|
587
|
+
137,
|
|
588
|
+
80,
|
|
589
|
+
78,
|
|
590
|
+
71,
|
|
591
|
+
13,
|
|
592
|
+
10,
|
|
593
|
+
26,
|
|
594
|
+
10
|
|
595
|
+
]);
|
|
596
|
+
const record$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
597
|
+
const nonEmpty = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
598
|
+
function encodedLimit(decodedBytes) {
|
|
599
|
+
return Math.ceil(decodedBytes / 3) * 4;
|
|
600
|
+
}
|
|
601
|
+
async function readJsonWithin(response, maximumBytes) {
|
|
602
|
+
const contentLength = Number(response.headers.get("content-length"));
|
|
603
|
+
if (Number.isFinite(contentLength) && contentLength > maximumBytes) throw new Error("Codex image response exceeds the image size limit");
|
|
604
|
+
if (response.body === null) throw new Error("Codex returned an unreadable image response");
|
|
605
|
+
const reader = response.body.getReader();
|
|
606
|
+
const chunks = [];
|
|
607
|
+
let bytes = 0;
|
|
608
|
+
while (true) {
|
|
609
|
+
const { done, value } = await reader.read();
|
|
610
|
+
if (done) break;
|
|
611
|
+
bytes += value.byteLength;
|
|
612
|
+
if (bytes > maximumBytes) {
|
|
613
|
+
await reader.cancel();
|
|
614
|
+
throw new Error("Codex image response exceeds the image size limit");
|
|
615
|
+
}
|
|
616
|
+
chunks.push(value);
|
|
617
|
+
}
|
|
618
|
+
const body = Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)), bytes).toString("utf8");
|
|
619
|
+
try {
|
|
620
|
+
return JSON.parse(body);
|
|
621
|
+
} catch {
|
|
622
|
+
throw new Error("Codex returned an unreadable image response");
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
/** Strictly decode one PNG returned by the subscription backend. */
|
|
626
|
+
function decodeCodexPng(value, maximumBytes) {
|
|
627
|
+
const encoded = nonEmpty(value);
|
|
628
|
+
if (encoded === void 0 || encoded.length % 4 !== 0 || !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u.test(encoded)) throw new Error("Codex returned an invalid base64 PNG");
|
|
629
|
+
const padding = encoded.endsWith("==") ? 2 : encoded.endsWith("=") ? 1 : 0;
|
|
630
|
+
const decodedBytes = encoded.length / 4 * 3 - padding;
|
|
631
|
+
if (decodedBytes > maximumBytes) throw new Error("Codex image exceeds the image size limit");
|
|
632
|
+
const data = Buffer.from(encoded, "base64");
|
|
633
|
+
if (data.length !== decodedBytes || data.length < PNG_SIGNATURE.length || !data.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE)) throw new Error("Codex returned an invalid PNG");
|
|
634
|
+
return new Uint8Array(data);
|
|
635
|
+
}
|
|
636
|
+
function imageReference(value) {
|
|
637
|
+
return {
|
|
638
|
+
attachmentId: value.attachmentId,
|
|
639
|
+
mediaType: value.mediaType,
|
|
640
|
+
bytes: value.bytes,
|
|
641
|
+
width: value.width,
|
|
642
|
+
height: value.height,
|
|
643
|
+
...value.name === void 0 ? {} : { name: value.name }
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
function imageContent(value) {
|
|
647
|
+
return [{
|
|
648
|
+
type: "text",
|
|
649
|
+
text: typeof value.size === "string" && value.size.length > 0 ? `Generated a ${value.size} image.` : "Generated an image."
|
|
650
|
+
}, {
|
|
651
|
+
type: "image",
|
|
652
|
+
attachment: imageReference(value.image)
|
|
653
|
+
}];
|
|
654
|
+
}
|
|
655
|
+
function imageOutputSchema() {
|
|
656
|
+
return {
|
|
657
|
+
type: "object",
|
|
658
|
+
additionalProperties: false,
|
|
659
|
+
properties: {
|
|
660
|
+
image: {
|
|
661
|
+
type: "object",
|
|
662
|
+
required: true,
|
|
663
|
+
additionalProperties: false,
|
|
664
|
+
properties: {
|
|
665
|
+
attachmentId: {
|
|
666
|
+
type: "string",
|
|
667
|
+
required: true
|
|
668
|
+
},
|
|
669
|
+
mediaType: {
|
|
670
|
+
type: "string",
|
|
671
|
+
enum: ["image/png"],
|
|
672
|
+
required: true
|
|
673
|
+
},
|
|
674
|
+
bytes: {
|
|
675
|
+
type: "integer",
|
|
676
|
+
required: true
|
|
677
|
+
},
|
|
678
|
+
width: {
|
|
679
|
+
type: "integer",
|
|
680
|
+
required: true
|
|
681
|
+
},
|
|
682
|
+
height: {
|
|
683
|
+
type: "integer",
|
|
684
|
+
required: true
|
|
685
|
+
},
|
|
686
|
+
name: { type: "string" }
|
|
687
|
+
}
|
|
688
|
+
},
|
|
689
|
+
background: { type: "string" },
|
|
690
|
+
quality: { type: "string" },
|
|
691
|
+
size: { type: "string" }
|
|
692
|
+
}
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function responseMetadata(value) {
|
|
696
|
+
const data = Array.isArray(value?.data) ? value.data[0] : void 0;
|
|
697
|
+
const encoded = record$1(data) ? data.b64_json : void 0;
|
|
698
|
+
if (typeof encoded !== "string") throw new Error("Codex returned no image data");
|
|
699
|
+
return {
|
|
700
|
+
encoded,
|
|
701
|
+
background: nonEmpty(value.background),
|
|
702
|
+
quality: nonEmpty(value.quality),
|
|
703
|
+
size: nonEmpty(value.size)
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
/** Create the DSH-native image-generation tool backed only by the ChatGPT subscription. */
|
|
707
|
+
function createCodexImageTool(options) {
|
|
708
|
+
const fetchImage = options.fetch ?? fetch;
|
|
709
|
+
const attachments = options.attachments;
|
|
710
|
+
return defineTool({
|
|
711
|
+
name: CODEX_IMAGE_TOOL_NAME,
|
|
712
|
+
description: "Generate an image from a detailed description using the signed-in Codex subscription. Use this whenever the user asks to create an image.",
|
|
713
|
+
parameters: { prompt: {
|
|
714
|
+
type: "string",
|
|
715
|
+
required: true,
|
|
716
|
+
description: "A complete, production-ready description of the image to generate."
|
|
717
|
+
} },
|
|
718
|
+
output: {
|
|
719
|
+
schema: imageOutputSchema(),
|
|
720
|
+
render: (_args, value) => imageContent(value)
|
|
721
|
+
},
|
|
722
|
+
timeoutMs: 300 * 1e3,
|
|
723
|
+
isConcurrencySafe: () => false,
|
|
724
|
+
async execute(args, exec) {
|
|
725
|
+
const prompt = nonEmpty(args.prompt);
|
|
726
|
+
if (prompt === void 0) throw new Error("prompt must be a non-empty string");
|
|
727
|
+
const auth = await options.getAuth({ signal: exec.signal });
|
|
728
|
+
const credential = await options.readCredential({ signal: exec.signal });
|
|
729
|
+
const access = auth?.auth?.apiKey;
|
|
730
|
+
const accountId = credential?.type === "oauth" ? credential.accountId : void 0;
|
|
731
|
+
if (typeof access !== "string" || access.length === 0 || typeof accountId !== "string" || accountId.length === 0) throw new Error("ChatGPT subscription is not signed in");
|
|
732
|
+
if (!attachments.imageLimits.mediaTypes.includes("image/png")) throw new Error("This DSH installation does not accept PNG image attachments");
|
|
733
|
+
const maximumBytes = Math.min(attachments.imageLimits.maxImageBytes, attachments.imageLimits.maxMessageImageBytes);
|
|
734
|
+
let response;
|
|
735
|
+
try {
|
|
736
|
+
response = await fetchImage(CODEX_IMAGE_GENERATION_URL, {
|
|
737
|
+
method: "POST",
|
|
738
|
+
redirect: "error",
|
|
739
|
+
headers: {
|
|
740
|
+
authorization: `Bearer ${access}`,
|
|
741
|
+
"chatgpt-account-id": accountId,
|
|
742
|
+
accept: "application/json",
|
|
743
|
+
"content-type": "application/json",
|
|
744
|
+
originator: "pi",
|
|
745
|
+
"x-codex-image-turn-id": String(exec.callId),
|
|
746
|
+
"user-agent": "dsh-codex-subscription"
|
|
747
|
+
},
|
|
748
|
+
body: JSON.stringify({
|
|
749
|
+
prompt,
|
|
750
|
+
background: "auto",
|
|
751
|
+
model: IMAGE_MODEL,
|
|
752
|
+
quality: "auto",
|
|
753
|
+
size: "auto"
|
|
754
|
+
}),
|
|
755
|
+
signal: exec.signal
|
|
756
|
+
});
|
|
757
|
+
} catch (error) {
|
|
758
|
+
if (exec.signal.aborted) throw exec.signal.reason;
|
|
759
|
+
throw new Error("Codex image generation request failed", { cause: error });
|
|
760
|
+
}
|
|
761
|
+
if (!response.ok) {
|
|
762
|
+
if (response.status === 401 || response.status === 403) throw new Error("ChatGPT sign-in needs to be renewed");
|
|
763
|
+
if (response.status === 429) throw new Error("Codex image generation quota is unavailable");
|
|
764
|
+
throw new Error(`Codex image generation failed (HTTP ${response.status})`);
|
|
765
|
+
}
|
|
766
|
+
const metadata = responseMetadata(await readJsonWithin(response, encodedLimit(maximumBytes) + RESPONSE_ENVELOPE_BYTES));
|
|
767
|
+
const data = decodeCodexPng(metadata.encoded, maximumBytes);
|
|
768
|
+
const result = {
|
|
769
|
+
image: imageReference(await attachments.saveImage({
|
|
770
|
+
data,
|
|
771
|
+
mediaType: "image/png",
|
|
772
|
+
name: "codex-generated.png"
|
|
773
|
+
})),
|
|
774
|
+
...metadata.background === void 0 ? {} : { background: metadata.background },
|
|
775
|
+
...metadata.quality === void 0 ? {} : { quality: metadata.quality },
|
|
776
|
+
...metadata.size === void 0 ? {} : { size: metadata.size }
|
|
777
|
+
};
|
|
778
|
+
if (exec.parent !== void 0) exec.deferContext(createUserMessage({
|
|
779
|
+
content: imageContent(result),
|
|
780
|
+
source: {
|
|
781
|
+
kind: "plugin",
|
|
782
|
+
plugin: "codex-subscription"
|
|
783
|
+
}
|
|
784
|
+
}));
|
|
785
|
+
return result;
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
//#endregion
|
|
580
790
|
//#region src/settings-contract.js
|
|
581
791
|
const SETTINGS_NAMESPACE = "codex-subscription";
|
|
582
792
|
const QUICK_QUOTA_FIELD = "quickQuotaVisible";
|
|
@@ -719,7 +929,7 @@ function createCodexUsageReader(options) {
|
|
|
719
929
|
"chatgpt-account-id": accountId,
|
|
720
930
|
accept: "application/json",
|
|
721
931
|
"cache-control": "no-store",
|
|
722
|
-
"user-agent": "dsh-codex-subscription/0.
|
|
932
|
+
"user-agent": "dsh-codex-subscription/0.3.1"
|
|
723
933
|
},
|
|
724
934
|
signal: requestSignal(signal, timeoutMs)
|
|
725
935
|
});
|
|
@@ -762,7 +972,9 @@ const inject = [
|
|
|
762
972
|
"connection",
|
|
763
973
|
"settings",
|
|
764
974
|
"web",
|
|
765
|
-
"loader"
|
|
975
|
+
"loader",
|
|
976
|
+
"tools",
|
|
977
|
+
"attachments"
|
|
766
978
|
];
|
|
767
979
|
const PROVIDER = "openai-codex";
|
|
768
980
|
const CREDENTIAL_REF = credentialRef("OPENAI_CODEX_SUBSCRIPTION_OAUTH");
|
|
@@ -879,6 +1091,11 @@ function apply(ctx) {
|
|
|
879
1091
|
});
|
|
880
1092
|
const profiles = /* @__PURE__ */ new Map([[PROVIDER, profile]]);
|
|
881
1093
|
const resolveAuth = () => authModels.getAuth(PROVIDER);
|
|
1094
|
+
ctx.tools.register(createCodexImageTool({
|
|
1095
|
+
getAuth: resolveAuth,
|
|
1096
|
+
readCredential: (options) => store.read(PROVIDER, options),
|
|
1097
|
+
attachments: ctx.attachments
|
|
1098
|
+
}));
|
|
882
1099
|
const adapter = new PiAiAdapter({
|
|
883
1100
|
profiles: () => profiles,
|
|
884
1101
|
resolveApiKey: async () => {
|
|
@@ -922,4 +1139,4 @@ function apply(ctx) {
|
|
|
922
1139
|
ctx.effect(() => ctx.connection.rpc.handle(CHANNEL, handler, { authority: "loopback" }), "codex-subscription: loopback account RPC");
|
|
923
1140
|
}
|
|
924
1141
|
//#endregion
|
|
925
|
-
export { CODEX_USAGE_URL, CodexLoginCoordinator, DshOAuthCredentialStore, apply, assertCodexAuthUrl, commandForCodexAuthUrl, createCodexAuthService, createCodexRpcHandler, createCodexUsageReader, createSearchProviderSwitcher, createSubscriptionRpcHandler, inject, name, openCodexAuthUrl, parseCodexUsage };
|
|
1142
|
+
export { CODEX_IMAGE_GENERATION_URL, CODEX_IMAGE_TOOL_NAME, CODEX_USAGE_URL, CodexLoginCoordinator, DshOAuthCredentialStore, apply, assertCodexAuthUrl, commandForCodexAuthUrl, createCodexAuthService, createCodexImageTool, createCodexRpcHandler, createCodexUsageReader, createSearchProviderSwitcher, createSubscriptionRpcHandler, decodeCodexPng, inject, name, openCodexAuthUrl, parseCodexUsage };
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"packageManager": "pnpm@11.19.0",
|
|
5
|
-
"description": "ChatGPT and Codex subscriptions for DeepSeek Harness with OAuth login, quota, and subscription web search",
|
|
5
|
+
"description": "ChatGPT and Codex subscriptions for DeepSeek Harness with OAuth login, image generation, quota, and subscription web search",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./lib/index.js",
|
|
8
8
|
"exports": {
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"@deepseek-ai/dsh-client-runtime",
|
|
35
35
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
36
36
|
"@deepseek-ai/dsh-client-ui-model-selection",
|
|
37
|
-
"@deepseek-ai/dsh-client-ui-settings"
|
|
37
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
38
|
+
"@deepseek-ai/dsh-client-ui-tool"
|
|
38
39
|
],
|
|
39
40
|
"platform": "web"
|
|
40
41
|
}
|
|
@@ -57,7 +58,8 @@
|
|
|
57
58
|
"quota",
|
|
58
59
|
"usage",
|
|
59
60
|
"oauth",
|
|
60
|
-
"web-search"
|
|
61
|
+
"web-search",
|
|
62
|
+
"image-generation"
|
|
61
63
|
],
|
|
62
64
|
"author": "WSL043",
|
|
63
65
|
"license": "MIT",
|
|
@@ -80,15 +82,18 @@
|
|
|
80
82
|
"@deepseek-ai/dsh-client-connection": "0.1.0-rc.6",
|
|
81
83
|
"@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
|
|
82
84
|
"@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
|
|
85
|
+
"@deepseek-ai/dsh-client-ui-attachment": "0.1.0-rc.6",
|
|
83
86
|
"@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6",
|
|
84
87
|
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.6",
|
|
85
88
|
"@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6",
|
|
86
89
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6",
|
|
87
90
|
"@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
|
|
91
|
+
"@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6",
|
|
88
92
|
"@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
|
|
89
93
|
"@deepseek-ai/dsh-llm": "0.1.0-rc.6",
|
|
90
94
|
"@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6",
|
|
91
95
|
"@deepseek-ai/dsh-settings": "0.1.0-rc.6",
|
|
96
|
+
"@deepseek-ai/dsh-tools": "0.1.0-rc.6",
|
|
92
97
|
"@deepseek-ai/dsh-web": "0.1.0-rc.6",
|
|
93
98
|
"@deepseek-ai/schemastery": "3.18.1",
|
|
94
99
|
"@earendil-works/pi-ai": "0.82.1",
|
|
@@ -99,15 +104,18 @@
|
|
|
99
104
|
"@deepseek-ai/dsh-client-connection": "0.1.0-rc.6",
|
|
100
105
|
"@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
|
|
101
106
|
"@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
|
|
107
|
+
"@deepseek-ai/dsh-client-ui-attachment": "0.1.0-rc.6",
|
|
102
108
|
"@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6",
|
|
103
109
|
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.6",
|
|
104
110
|
"@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6",
|
|
105
111
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.6",
|
|
106
112
|
"@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
|
|
113
|
+
"@deepseek-ai/dsh-client-ui-tool": "0.1.0-rc.6",
|
|
107
114
|
"@deepseek-ai/dsh-credentials": "0.1.0-rc.6",
|
|
108
115
|
"@deepseek-ai/dsh-llm": "0.1.0-rc.6",
|
|
109
116
|
"@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.6",
|
|
110
117
|
"@deepseek-ai/dsh-settings": "0.1.0-rc.6",
|
|
118
|
+
"@deepseek-ai/dsh-tools": "0.1.0-rc.6",
|
|
111
119
|
"@deepseek-ai/dsh-web": "0.1.0-rc.6",
|
|
112
120
|
"@deepseek-ai/schemastery": "3.18.1",
|
|
113
121
|
"@earendil-works/pi-ai": "0.82.1",
|