dsh-coding-subscription-oauth 0.5.8 → 0.6.2
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/CHANGELOG.md +217 -188
- package/CONTRIBUTING.md +120 -120
- package/INSTALL.md +241 -209
- package/LICENSE +19 -19
- package/NOTICE +11 -11
- package/README.de.md +298 -294
- package/README.es.md +299 -295
- package/README.fr.md +299 -295
- package/README.ja.md +299 -295
- package/README.ko.md +299 -295
- package/README.md +313 -307
- package/README.pt-BR.md +299 -295
- package/README.ru.md +299 -295
- package/README.zh-CN.md +311 -305
- package/compatibility/dsh-bom.json +30 -0
- package/cordis.patch.yml +13 -13
- package/docs/00-project-rules.md +195 -195
- package/docs/02-architecture.md +134 -129
- package/docs/02-architecture.zh-CN.md +134 -129
- package/lib/adapter.d.ts.map +1 -1
- package/lib/alias-adapter.d.ts +3 -1
- package/lib/alias-adapter.d.ts.map +1 -1
- package/lib/auth-routes.d.ts +8 -15
- package/lib/auth-routes.d.ts.map +1 -1
- package/lib/bin.js +746 -1402
- package/lib/bin.js.map +4 -4
- package/lib/capability-routes.d.ts +3 -3
- package/lib/capability-routes.d.ts.map +1 -1
- package/lib/capability-settings.d.ts +5 -4
- package/lib/capability-settings.d.ts.map +1 -1
- package/lib/client.js +27 -8
- package/lib/client.js.map +4 -4
- package/lib/compatibility.d.ts +46 -0
- package/lib/compatibility.d.ts.map +1 -0
- package/lib/dsh-host-adapter.d.ts +18 -0
- package/lib/dsh-host-adapter.d.ts.map +1 -0
- package/lib/gateway-auth.d.ts +1 -2
- package/lib/gateway-auth.d.ts.map +1 -1
- package/lib/gateway-routes.d.ts +3 -4
- package/lib/gateway-routes.d.ts.map +1 -1
- package/lib/gateway.d.ts +4 -0
- package/lib/gateway.d.ts.map +1 -1
- package/lib/ids.d.ts +3 -32
- package/lib/ids.d.ts.map +1 -1
- package/lib/imagine-routes.d.ts +2 -0
- package/lib/imagine-routes.d.ts.map +1 -1
- package/lib/index.d.ts +19 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +26627 -1047
- package/lib/index.js.map +4 -4
- package/lib/invariant.js.map +1 -1
- package/lib/oauth-import-routes.d.ts +3 -4
- package/lib/oauth-import-routes.d.ts.map +1 -1
- package/lib/proxy.d.ts +3 -16
- package/lib/proxy.d.ts.map +1 -1
- package/lib/web-origin.d.ts +28 -4
- package/lib/web-origin.d.ts.map +1 -1
- package/lib/web-routes.d.ts.map +1 -1
- package/media/en/settings_accounts.png +0 -0
- package/media/en/settings_capabilities.png +0 -0
- package/media/en/settings_gateway.png +0 -0
- package/media/settings_accounts.png +0 -0
- package/media/settings_capabilities.png +0 -0
- package/media/settings_gateway.png +0 -0
- package/media/settings_overview.png +0 -0
- package/media/zh-CN/settings_accounts.png +0 -0
- package/media/zh-CN/settings_capabilities.png +0 -0
- package/media/zh-CN/settings_gateway.png +0 -0
- package/package.json +211 -174
- package/patches/dsh-agy@0.1.2.patch +25 -25
- package/scripts/release.mjs +186 -170
- package/scripts/smoke-deployed-routes.mjs +146 -146
- package/scripts/verify-deployed-catalog.mjs +87 -87
- package/src/adapter.ts +329 -268
- package/src/alias-adapter.ts +141 -147
- package/src/auth-routes.ts +921 -871
- package/src/auth.ts +67 -67
- package/src/bin.ts +350 -350
- package/src/capability-routes.ts +279 -275
- package/src/capability-runtime.ts +313 -313
- package/src/capability-settings.ts +658 -657
- package/src/capability-tools.ts +666 -666
- package/src/catalog.ts +271 -271
- package/src/client/GrokBuildSettings.tsx +770 -718
- package/src/client/api.ts +88 -88
- package/src/client/components/AboutTab.tsx +30 -30
- package/src/client/components/AccountsTab.tsx +241 -224
- package/src/client/components/Badge.tsx +33 -33
- package/src/client/components/CapabilitiesTab.tsx +265 -227
- package/src/client/components/CliPullPreview.tsx +116 -107
- package/src/client/components/CopyButton.tsx +57 -57
- package/src/client/components/GatewayTab.tsx +469 -409
- package/src/client/components/NoticeBanner.tsx +46 -46
- package/src/client/components/ProgressBar.tsx +53 -53
- package/src/client/components/ProviderCard.tsx +606 -502
- package/src/client/components/SettingsTabs.tsx +75 -75
- package/src/client/components/ToggleSwitch.tsx +71 -62
- package/src/client/constants.ts +224 -206
- package/src/client/display.ts +61 -61
- package/src/client/dshClientAdapter.ts +127 -0
- package/src/client/gatewaySnippets.ts +37 -36
- package/src/client/index.tsx +156 -37
- package/src/client/locales.ts +535 -491
- package/src/client/microStyles.ts +52 -33
- package/src/client/parsers.ts +396 -386
- package/src/client/styles.ts +325 -307
- package/src/client/types.ts +197 -185
- package/src/codex-http.ts +447 -447
- package/src/codex-images.ts +485 -485
- package/src/codex-model-capabilities.ts +320 -320
- package/src/codex-search.ts +245 -245
- package/src/codex-usage.ts +263 -263
- package/src/compatibility.ts +55 -0
- package/src/dsh-host-adapter.ts +173 -0
- package/src/gateway-anthropic-messages.ts +84 -84
- package/src/gateway-auth.ts +102 -100
- package/src/gateway-backend.ts +274 -274
- package/src/gateway-body.ts +49 -49
- package/src/gateway-config.ts +76 -76
- package/src/gateway-http.ts +104 -104
- package/src/gateway-openai-chat.ts +124 -124
- package/src/gateway-openai-responses.ts +53 -53
- package/src/gateway-parse.ts +224 -224
- package/src/gateway-protocol.ts +52 -52
- package/src/gateway-routes.ts +158 -152
- package/src/gateway.ts +258 -242
- package/src/grok-errors.ts +24 -24
- package/src/grok-imagine.ts +1627 -1627
- package/src/grok-import.ts +151 -151
- package/src/http-json.ts +82 -82
- package/src/ids.ts +59 -45
- package/src/imagine-routes.ts +463 -461
- package/src/index.ts +729 -592
- package/src/invariant.ts +17 -17
- package/src/kimi-errors.ts +26 -26
- package/src/media-store.ts +927 -927
- package/src/oauth-import-routes.ts +324 -314
- package/src/oauth-providers.ts +152 -152
- package/src/oauth-session.ts +183 -183
- package/src/oauth-sources.ts +1104 -1104
- package/src/oauth.ts +620 -620
- package/src/provider.ts +128 -128
- package/src/proxy.ts +11 -99
- package/src/redact.ts +72 -72
- package/src/session.ts +218 -218
- package/src/store.ts +217 -217
- package/src/web-origin.ts +296 -60
- package/src/web-routes.ts +38 -75
package/src/index.ts
CHANGED
|
@@ -1,598 +1,735 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Optional xAI Grok Build bundle with OAuth, account model catalog,
|
|
3
|
-
* and an account section inside dsh Settings.
|
|
4
|
-
* @module dsh-coding-subscription-oauth
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { dirname, join } from "node:path";
|
|
8
|
-
import type { Context } from "@deepseek-ai/cordis";
|
|
9
|
-
import type { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
10
|
-
import type { CredentialInfo, CredentialProvider, CredentialRef } from "@deepseek-ai/dsh-credentials";
|
|
11
|
-
import type {} from "@deepseek-ai/dsh-host-webserver";
|
|
12
|
-
import { assertUsableApiKey, type RetryPolicyConfig, RetryPolicySchema } from "@deepseek-ai/dsh-llm";
|
|
13
|
-
import z from "@deepseek-ai/schemastery";
|
|
14
|
-
import type { Credential, OAuthCredential } from "@earendil-works/pi-ai";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
type
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
47
|
-
import {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
import {
|
|
73
|
-
import {
|
|
74
|
-
import {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
export {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
export {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
} from "./
|
|
166
|
-
export type {
|
|
167
|
-
export {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
} from "./
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
export const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Optional xAI Grok Build bundle with OAuth, account model catalog,
|
|
3
|
+
* and an account section inside dsh Settings.
|
|
4
|
+
* @module dsh-coding-subscription-oauth
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import type { Context, Fiber } from "@deepseek-ai/cordis";
|
|
9
|
+
import type { AttachmentStore } from "@deepseek-ai/dsh-attachment";
|
|
10
|
+
import type { CredentialInfo, CredentialProvider, CredentialRef } from "@deepseek-ai/dsh-credentials";
|
|
11
|
+
import type {} from "@deepseek-ai/dsh-host-webserver";
|
|
12
|
+
import { assertUsableApiKey, type RetryPolicyConfig, RetryPolicySchema } from "@deepseek-ai/dsh-llm";
|
|
13
|
+
import z from "@deepseek-ai/schemastery";
|
|
14
|
+
import type { Credential, OAuthCredential } from "@earendil-works/pi-ai";
|
|
15
|
+
import { acquireCodingOAuthRuntime, CODING_OAUTH_CORE_ABI, type CodingOAuthRuntime } from "dsh-coding-oauth-core";
|
|
16
|
+
import { createCodingOAuthAdapter } from "./adapter.ts";
|
|
17
|
+
import { registerCodingOAuthRoutes } from "./auth-routes.ts";
|
|
18
|
+
import { registerCapabilityRoutes } from "./capability-routes.ts";
|
|
19
|
+
import {
|
|
20
|
+
bindCapabilitySearch,
|
|
21
|
+
bindCapabilityTools,
|
|
22
|
+
bindCodexFastRoute,
|
|
23
|
+
CapabilityRuntimeState,
|
|
24
|
+
type CapabilitySearchRegistry,
|
|
25
|
+
type CapabilityToolRegistry,
|
|
26
|
+
} from "./capability-runtime.ts";
|
|
27
|
+
import {
|
|
28
|
+
type CapabilitySettingsPatch,
|
|
29
|
+
CapabilitySettingsSchema,
|
|
30
|
+
type CapabilitySettingsService,
|
|
31
|
+
createCapabilitySettingsController,
|
|
32
|
+
resolveCapabilitySettings,
|
|
33
|
+
} from "./capability-settings.ts";
|
|
34
|
+
import {
|
|
35
|
+
CODEX_IMAGE_EDIT_TOOL,
|
|
36
|
+
CODEX_IMAGE_GENERATE_TOOL,
|
|
37
|
+
createCapabilityTools,
|
|
38
|
+
type ResolveCodexImageRoute,
|
|
39
|
+
resolveCodexImageRouteFromLlm,
|
|
40
|
+
} from "./capability-tools.ts";
|
|
41
|
+
import { codexAuthFromSession } from "./codex-http.ts";
|
|
42
|
+
import { createCodexModelCapabilities } from "./codex-model-capabilities.ts";
|
|
43
|
+
import { createCodexSearchProvider } from "./codex-search.ts";
|
|
44
|
+
import { createCodexUsageReader } from "./codex-usage.ts";
|
|
45
|
+
import { createDshHostAdapter } from "./dsh-host-adapter.ts";
|
|
46
|
+
import { createCodingOAuthGatewayController } from "./gateway.ts";
|
|
47
|
+
import { type GatewayConfig, GatewayConfigSchema } from "./gateway-config.ts";
|
|
48
|
+
import { registerGatewayRoutes } from "./gateway-routes.ts";
|
|
49
|
+
import {
|
|
50
|
+
createGrokImagineClient,
|
|
51
|
+
GROK_IMAGINE_IMAGE_TOOL,
|
|
52
|
+
GROK_IMAGINE_VIDEO_STATUS_TOOL,
|
|
53
|
+
GROK_IMAGINE_VIDEO_TOOL,
|
|
54
|
+
GrokImagineError,
|
|
55
|
+
type ImagineOperation,
|
|
56
|
+
} from "./grok-imagine.ts";
|
|
57
|
+
import {
|
|
58
|
+
CLAUDE_PI_PROVIDER,
|
|
59
|
+
CODEX_PI_PROVIDER,
|
|
60
|
+
CODING_OAUTH_ROUTES,
|
|
61
|
+
IMAGINE_MEDIA_STORE_DIRNAME,
|
|
62
|
+
KIMI_PI_PROVIDER,
|
|
63
|
+
XAI_PI_PROVIDER,
|
|
64
|
+
} from "./ids.ts";
|
|
65
|
+
import { registerImagineRoutes } from "./imagine-routes.ts";
|
|
66
|
+
import { MediaStore } from "./media-store.ts";
|
|
67
|
+
import {
|
|
68
|
+
type OAuthImportDestinationStore,
|
|
69
|
+
type OAuthImportDestinations,
|
|
70
|
+
registerOAuthImportRoutes,
|
|
71
|
+
} from "./oauth-import-routes.ts";
|
|
72
|
+
import { OAUTH_PROVIDER_DEFINITIONS } from "./oauth-providers.ts";
|
|
73
|
+
import { OAuthProviderSession } from "./oauth-session.ts";
|
|
74
|
+
import type { OAuthSourceCredential } from "./oauth-sources.ts";
|
|
75
|
+
import { acquireCodingOAuthProxy } from "./proxy.ts";
|
|
76
|
+
import { GrokBuildSession } from "./session.ts";
|
|
77
|
+
import { GrokBuildCredentialStore, type OAuthCredentialFileStore } from "./store.ts";
|
|
78
|
+
import { createOwnerRequestPolicy, safeguardOwnerRequestPolicy } from "./web-origin.ts";
|
|
79
|
+
|
|
80
|
+
export type {
|
|
81
|
+
CodingOAuthParticipant,
|
|
82
|
+
CodingOAuthRuntime,
|
|
83
|
+
DshHostCapabilities,
|
|
84
|
+
OwnerRequestPolicy as CoreOwnerRequestPolicy,
|
|
85
|
+
} from "dsh-coding-oauth-core";
|
|
86
|
+
export {
|
|
87
|
+
acquireCodingOAuthRuntime,
|
|
88
|
+
CODING_OAUTH_CORE_ABI,
|
|
89
|
+
} from "dsh-coding-oauth-core";
|
|
90
|
+
export { createCodingOAuthAdapter, createGrokBuildAdapter, preferredGrokBuildModel } from "./adapter.ts";
|
|
91
|
+
export type { AliasLlmRoutePolicy } from "./alias-adapter.ts";
|
|
92
|
+
export { AliasLlmAdapter } from "./alias-adapter.ts";
|
|
93
|
+
export type { GrokBuildAuthStatus } from "./auth.ts";
|
|
94
|
+
export {
|
|
95
|
+
grokBuildAuthStatus,
|
|
96
|
+
importGrokBuildFromGrok,
|
|
97
|
+
importGrokBuildSession,
|
|
98
|
+
loginGrokBuild,
|
|
99
|
+
loginGrokBuildSession,
|
|
100
|
+
logoutGrokBuild,
|
|
101
|
+
} from "./auth.ts";
|
|
102
|
+
export type {
|
|
103
|
+
CodingOAuthWebStatus,
|
|
104
|
+
GrokBuildLoginMethod,
|
|
105
|
+
GrokBuildWebAuthStatus,
|
|
106
|
+
LoginChallenge,
|
|
107
|
+
SubscriptionLoginChallenge,
|
|
108
|
+
SubscriptionWebAuthStatus,
|
|
109
|
+
} from "./auth-routes.ts";
|
|
110
|
+
export {
|
|
111
|
+
CODING_OAUTH_LOGIN_CANCEL_PATH,
|
|
112
|
+
CODING_OAUTH_LOGIN_CODE_PATH,
|
|
113
|
+
CODING_OAUTH_LOGIN_PATH,
|
|
114
|
+
CODING_OAUTH_LOGOUT_PATH,
|
|
115
|
+
CODING_OAUTH_MODELS_PATH,
|
|
116
|
+
CODING_OAUTH_STATUS_PATH,
|
|
117
|
+
GROK_BUILD_AUTH_IMPORT_PATH,
|
|
118
|
+
GROK_BUILD_AUTH_LOGIN_CANCEL_PATH,
|
|
119
|
+
GROK_BUILD_AUTH_LOGIN_CODE_PATH,
|
|
120
|
+
GROK_BUILD_AUTH_LOGIN_PATH,
|
|
121
|
+
GROK_BUILD_AUTH_LOGOUT_PATH,
|
|
122
|
+
GROK_BUILD_AUTH_MODELS_PATH,
|
|
123
|
+
GROK_BUILD_AUTH_STATUS_PATH,
|
|
124
|
+
GrokBuildWebAuth,
|
|
125
|
+
registerCodingOAuthRoutes,
|
|
126
|
+
registerGrokBuildAuthRoutes,
|
|
127
|
+
SubscriptionWebAuth,
|
|
128
|
+
} from "./auth-routes.ts";
|
|
129
|
+
export type { CatalogSource, LiveModelDescriptor } from "./catalog.ts";
|
|
130
|
+
export {
|
|
131
|
+
extractLiveModels,
|
|
132
|
+
extractModelIds,
|
|
133
|
+
fetchLiveModelIds,
|
|
134
|
+
fetchLiveModels,
|
|
135
|
+
materializeLiveModel,
|
|
136
|
+
mergeLiveCatalog,
|
|
137
|
+
preferredGrokBuildModelFrom,
|
|
138
|
+
thinkingLevelMapFromLiveEfforts,
|
|
139
|
+
} from "./catalog.ts";
|
|
140
|
+
export { createDshHostAdapter } from "./dsh-host-adapter.ts";
|
|
141
|
+
export type { GrokImportProbe } from "./grok-import.ts";
|
|
142
|
+
export { grokAuthPath, importGrokAuth, parseGrokAuthDocument, probeGrokAuth } from "./grok-import.ts";
|
|
143
|
+
export type { CodingOAuthProviderSlug, CodingOAuthRoute } from "./ids.ts";
|
|
144
|
+
export {
|
|
145
|
+
ANTIGRAVITY_ROUTE,
|
|
146
|
+
CLAUDE_CODE_OAUTH_AUTH_FILENAME,
|
|
147
|
+
CLAUDE_CODE_OAUTH_MODELS_CACHE_FILENAME,
|
|
148
|
+
CLAUDE_CODE_OAUTH_ROUTE,
|
|
149
|
+
CLAUDE_PI_PROVIDER,
|
|
150
|
+
CODEX_OAUTH_AUTH_FILENAME,
|
|
151
|
+
CODEX_OAUTH_MODELS_CACHE_FILENAME,
|
|
152
|
+
CODEX_OAUTH_ROUTE,
|
|
153
|
+
CODEX_PI_PROVIDER,
|
|
154
|
+
CODING_OAUTH_ROUTES,
|
|
155
|
+
DEFAULT_GROK_BUILD_MODEL,
|
|
156
|
+
GROK_BUILD_AUTH_FILENAME,
|
|
157
|
+
GROK_BUILD_MODELS_CACHE_FILENAME,
|
|
158
|
+
GROK_BUILD_ROUTE,
|
|
159
|
+
GROK_BUILD_STREAM_IDLE_TIMEOUT_MS,
|
|
160
|
+
KIMI_CODE_OAUTH_AUTH_FILENAME,
|
|
161
|
+
KIMI_CODE_OAUTH_MODELS_CACHE_FILENAME,
|
|
162
|
+
KIMI_CODE_OAUTH_ROUTE,
|
|
163
|
+
KIMI_PI_PROVIDER,
|
|
164
|
+
XAI_PI_PROVIDER,
|
|
165
|
+
} from "./ids.ts";
|
|
166
|
+
export type { GrokBuildOAuthErrorCode, GrokBuildOAuthParams, PkceLoginCallbacks } from "./oauth.ts";
|
|
167
|
+
export {
|
|
168
|
+
buildAuthorizeUrl,
|
|
169
|
+
discoverOAuthEndpoints,
|
|
170
|
+
extractCode,
|
|
171
|
+
GROK_BUILD_OAUTH_CLIENT_ID,
|
|
172
|
+
GROK_BUILD_OAUTH_DEFAULT_PORT,
|
|
173
|
+
GROK_BUILD_OAUTH_ISSUER,
|
|
174
|
+
GROK_BUILD_OAUTH_SCOPE,
|
|
175
|
+
GrokBuildOAuthError,
|
|
176
|
+
generatePkce,
|
|
177
|
+
loginGrokBuildPkce,
|
|
178
|
+
refreshGrokBuildToken,
|
|
179
|
+
resolveOAuthParams,
|
|
180
|
+
} from "./oauth.ts";
|
|
181
|
+
export type { OAuthProviderDefinition, SubscriptionLoginMethod, SubscriptionProviderSlug } from "./oauth-providers.ts";
|
|
182
|
+
export {
|
|
183
|
+
CLAUDE_CODE_OAUTH_PROVIDER,
|
|
184
|
+
CODEX_OAUTH_PROVIDER,
|
|
185
|
+
KIMI_CODE_OAUTH_PROVIDER,
|
|
186
|
+
OAUTH_PROVIDER_DEFINITIONS,
|
|
187
|
+
oauthProviderDefinition,
|
|
188
|
+
} from "./oauth-providers.ts";
|
|
189
|
+
export type { OAuthProviderStatus } from "./oauth-session.ts";
|
|
190
|
+
export { OAuthProviderSession, oauthModelsCachePath } from "./oauth-session.ts";
|
|
191
|
+
export {
|
|
192
|
+
GROK_BUILD_BASE_URL,
|
|
193
|
+
GROK_BUILD_MODELS_URL,
|
|
194
|
+
GROK_CLIENT_VERSION,
|
|
195
|
+
grokBuildBaselineModels,
|
|
196
|
+
grokBuildFingerprintHeaders,
|
|
197
|
+
grokBuildProvider,
|
|
198
|
+
grokBuildReasoningMap,
|
|
199
|
+
} from "./provider.ts";
|
|
200
|
+
export type { CodingOAuthProxyOptions } from "./proxy.ts";
|
|
201
|
+
export {
|
|
202
|
+
codingOAuthProxyInEffect,
|
|
203
|
+
codingOAuthProxyUnreachableHint,
|
|
204
|
+
ensureCodingOAuthProxy,
|
|
205
|
+
ensureGrokBuildProxy,
|
|
206
|
+
grokBuildProxyInEffect,
|
|
207
|
+
} from "./proxy.ts";
|
|
208
|
+
export { redactProxyUrl, safeMessage } from "./redact.ts";
|
|
209
|
+
export { GrokBuildSession } from "./session.ts";
|
|
210
|
+
export {
|
|
211
|
+
GrokBuildCredentialStore,
|
|
212
|
+
grokBuildAuthPath,
|
|
213
|
+
OAuthCredentialFileStore,
|
|
214
|
+
oauthCredentialPath,
|
|
215
|
+
} from "./store.ts";
|
|
216
|
+
export type { OwnerRequestPolicy, OwnerRequestPolicyConfig } from "./web-origin.ts";
|
|
217
|
+
export {
|
|
218
|
+
createOwnerRequestPolicy,
|
|
219
|
+
LOOPBACK_OWNER_REQUEST_POLICY,
|
|
220
|
+
OWNER_CSRF_HEADER,
|
|
221
|
+
OWNER_PROOF_HEADER,
|
|
222
|
+
} from "./web-origin.ts";
|
|
223
|
+
|
|
224
|
+
/** Stable Cordis plugin name. */
|
|
225
|
+
export const name = "llm-grok-build-oauth";
|
|
226
|
+
|
|
227
|
+
/** Separate API-key credential used only by official xAI Imagine REST calls. */
|
|
228
|
+
export const XAI_API_KEY_CREDENTIAL = "XAI_API_KEY";
|
|
229
|
+
/** Validate locally because `credentialRef()` is a value export of the optional credentials peer. */
|
|
230
|
+
const XAI_API_KEY_REF = fixedCredentialRef(XAI_API_KEY_CREDENTIAL);
|
|
231
|
+
|
|
232
|
+
function fixedCredentialRef(value: string): CredentialRef {
|
|
233
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(value)) {
|
|
234
|
+
throw new TypeError(`invalid credential reference ${JSON.stringify(value)}`);
|
|
235
|
+
}
|
|
236
|
+
return value as CredentialRef;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Owner-private artifact directory below the resolved DSH home. */
|
|
240
|
+
export { IMAGINE_MEDIA_STORE_DIRNAME } from "./ids.ts";
|
|
241
|
+
|
|
242
|
+
/** Optional host services are acquired inside the elected child fiber. */
|
|
243
|
+
export const inject = ["webServer"] as const;
|
|
244
|
+
|
|
245
|
+
/** Plugin configuration; every field is optional. */
|
|
246
|
+
export interface Config {
|
|
247
|
+
/** HTTP(S) proxy URL for the audited coding-subscription host allowlist. */
|
|
248
|
+
proxy?: string;
|
|
249
|
+
/** Kimi China traffic stays direct unless explicitly opted into the proxy. */
|
|
250
|
+
proxyKimi?: boolean;
|
|
251
|
+
/**
|
|
252
|
+
* Optional provider retry policy override for the four OAuth routes. When
|
|
253
|
+
* omitted, the plugin retries transient failures (rate limit, server,
|
|
254
|
+
* timeout, transport, empty response) plus AUTH — the latter is safe because
|
|
255
|
+
* the stored credential is invalidated on every AUTH finish, so the retried
|
|
256
|
+
* step refreshes before reuse. Quota exhaustion is never retried.
|
|
257
|
+
*/
|
|
258
|
+
retryPolicy?: RetryPolicyConfig;
|
|
259
|
+
/** Secret-free composition/YAML defaults below live user settings. */
|
|
260
|
+
capabilities?: CapabilitySettingsPatch;
|
|
261
|
+
/** Opt-in isolated local OpenAI-compatible gateway. Default off. */
|
|
262
|
+
gateway?: Partial<GatewayConfig>;
|
|
263
|
+
/** Owner-only request authorization for loopback, SSH tunnels, and trusted HTTPS proxies. */
|
|
264
|
+
ownerRequest?: {
|
|
265
|
+
loopbackAccessMode?: "loopback" | "ssh-tunnel";
|
|
266
|
+
trustedProxy?: {
|
|
267
|
+
peers?: string[];
|
|
268
|
+
origins?: string[];
|
|
269
|
+
ownerProof?: string;
|
|
270
|
+
csrfToken?: string;
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export const Config: z<Config> = z.object({
|
|
276
|
+
proxy: z.string(),
|
|
277
|
+
proxyKimi: z.boolean().default(false),
|
|
278
|
+
retryPolicy: RetryPolicySchema,
|
|
279
|
+
capabilities: CapabilitySettingsSchema,
|
|
280
|
+
gateway: GatewayConfigSchema,
|
|
281
|
+
ownerRequest: z.object({
|
|
282
|
+
loopbackAccessMode: z.union([z.const("loopback"), z.const("ssh-tunnel")]),
|
|
283
|
+
trustedProxy: z.object({
|
|
284
|
+
peers: z.array(z.string()),
|
|
285
|
+
origins: z.array(z.string()),
|
|
286
|
+
ownerProof: z.string(),
|
|
287
|
+
csrfToken: z.string(),
|
|
288
|
+
}),
|
|
289
|
+
}),
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const CODEX_TOOL_NAMES = new Set<string>([CODEX_IMAGE_GENERATE_TOOL, CODEX_IMAGE_EDIT_TOOL]);
|
|
293
|
+
const IMAGINE_TOOL_NAMES = new Set<string>([
|
|
294
|
+
GROK_IMAGINE_IMAGE_TOOL,
|
|
295
|
+
GROK_IMAGINE_VIDEO_TOOL,
|
|
296
|
+
GROK_IMAGINE_VIDEO_STATUS_TOOL,
|
|
297
|
+
]);
|
|
298
|
+
|
|
299
|
+
function requireSubscription(
|
|
300
|
+
subscriptions: readonly OAuthProviderSession[],
|
|
301
|
+
nativeProviderId: string,
|
|
302
|
+
): OAuthProviderSession {
|
|
303
|
+
const session = subscriptions.find((candidate) => candidate.definition.nativeProviderId === nativeProviderId);
|
|
304
|
+
if (session === undefined) throw new Error(`missing built-in OAuth provider ${nativeProviderId}`);
|
|
305
|
+
return session;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function asSourceCredential(credential: Credential | undefined): OAuthSourceCredential | undefined {
|
|
309
|
+
if (credential === undefined) return undefined;
|
|
310
|
+
if (credential.type !== "oauth") throw new Error("OAuth import destination contains a non-OAuth credential");
|
|
311
|
+
const accountId =
|
|
312
|
+
typeof credential.accountId === "string" && credential.accountId.length > 0 ? credential.accountId : undefined;
|
|
313
|
+
return {
|
|
314
|
+
type: "oauth",
|
|
315
|
+
access: credential.access,
|
|
316
|
+
refresh: credential.refresh,
|
|
317
|
+
expires: credential.expires,
|
|
318
|
+
...(accountId === undefined ? {} : { accountId }),
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function asStoredCredential(credential: OAuthSourceCredential): OAuthCredential {
|
|
323
|
+
return {
|
|
324
|
+
type: "oauth",
|
|
325
|
+
access: credential.access,
|
|
326
|
+
refresh: credential.refresh,
|
|
327
|
+
expires: credential.expires,
|
|
328
|
+
...(credential.accountId === undefined ? {} : { accountId: credential.accountId }),
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function oauthImportStore(store: OAuthCredentialFileStore): OAuthImportDestinationStore {
|
|
333
|
+
return {
|
|
334
|
+
filename: store.filename,
|
|
335
|
+
async modify(providerId, fn) {
|
|
336
|
+
const result = await store.modify(providerId, async (current) => {
|
|
337
|
+
const next = await fn(asSourceCredential(current));
|
|
338
|
+
return next === undefined ? current : asStoredCredential(next);
|
|
339
|
+
});
|
|
340
|
+
return asSourceCredential(result);
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function oauthImportDestinations(
|
|
346
|
+
grok: GrokBuildSession,
|
|
347
|
+
subscriptions: readonly OAuthProviderSession[],
|
|
348
|
+
): OAuthImportDestinations {
|
|
349
|
+
const codex = requireSubscription(subscriptions, CODEX_PI_PROVIDER);
|
|
350
|
+
const kimi = requireSubscription(subscriptions, KIMI_PI_PROVIDER);
|
|
351
|
+
const claude = requireSubscription(subscriptions, CLAUDE_PI_PROVIDER);
|
|
352
|
+
return {
|
|
353
|
+
grok: { providerId: XAI_PI_PROVIDER, store: oauthImportStore(grok.store) },
|
|
354
|
+
codex: { providerId: codex.definition.nativeProviderId, store: oauthImportStore(codex.store) },
|
|
355
|
+
kimi: { providerId: kimi.definition.nativeProviderId, store: oauthImportStore(kimi.store) },
|
|
356
|
+
claude: { providerId: claude.definition.nativeProviderId, store: oauthImportStore(claude.store) },
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async function describeImagineCredential(credentials: CredentialProvider | undefined): Promise<CredentialInfo> {
|
|
361
|
+
if (credentials === undefined) return { configured: false, writable: false };
|
|
362
|
+
return credentials.describe(XAI_API_KEY_REF);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async function resolveImagineApiKey(credentials: CredentialProvider, operation: ImagineOperation): Promise<string> {
|
|
366
|
+
const resolved = await credentials.resolve(XAI_API_KEY_REF);
|
|
367
|
+
if (resolved === undefined) {
|
|
368
|
+
throw new GrokImagineError(
|
|
369
|
+
"MISSING_CREDENTIAL",
|
|
370
|
+
`${XAI_API_KEY_CREDENTIAL} is not configured for ${operation}. Grok Imagine does not use OAuth.`,
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
return assertUsableApiKey(resolved.value, "dsh-coding-subscription-oauth", XAI_API_KEY_CREDENTIAL);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function unavailableImagineClient(): {
|
|
377
|
+
generateImage(): Promise<never>;
|
|
378
|
+
startVideo(): Promise<never>;
|
|
379
|
+
videoStatus(): Promise<never>;
|
|
380
|
+
} {
|
|
381
|
+
const unavailable = async (): Promise<never> => {
|
|
382
|
+
throw new GrokImagineError("MISSING_CREDENTIAL", "Grok Imagine services are not composed");
|
|
383
|
+
};
|
|
384
|
+
return { generateImage: unavailable, startVideo: unavailable, videoStatus: unavailable };
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Register the `grok-build` LLM route with a provider-native OAuth store.
|
|
389
|
+
* @param ctx - plugin context carrying the LLM registry plus optional web server.
|
|
390
|
+
*/
|
|
391
|
+
export function apply(ctx: Context, config: Config = {}): void {
|
|
392
|
+
const host = createDshHostAdapter(ctx);
|
|
393
|
+
const lease: CodingOAuthRuntime = acquireCodingOAuthRuntime(host.scope(), {
|
|
394
|
+
id: "dsh-coding-subscription-oauth",
|
|
395
|
+
role: "standalone",
|
|
396
|
+
coreAbi: CODING_OAUTH_CORE_ABI,
|
|
397
|
+
async activate() {
|
|
398
|
+
let fiber: Fiber | undefined;
|
|
399
|
+
let ownerMounted = false;
|
|
400
|
+
fiber = ctx.inject([], async (injected) => {
|
|
401
|
+
await applyOwned(injected, config);
|
|
402
|
+
ownerMounted = true;
|
|
403
|
+
return () => {
|
|
404
|
+
ownerMounted = false;
|
|
405
|
+
};
|
|
406
|
+
});
|
|
407
|
+
try {
|
|
408
|
+
await fiber.await();
|
|
409
|
+
if (!ownerMounted) throw new Error("standalone Coding OAuth owner fiber did not activate");
|
|
410
|
+
} catch (error) {
|
|
411
|
+
try {
|
|
412
|
+
await fiber.dispose();
|
|
413
|
+
} catch {
|
|
414
|
+
// Preserve the startup error; Cordis already logs cleanup failures.
|
|
415
|
+
}
|
|
416
|
+
throw error;
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
async dispose() {
|
|
420
|
+
await fiber?.dispose();
|
|
421
|
+
},
|
|
422
|
+
};
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
ctx.effect(() => () => lease.release(), "dsh-coding-subscription-oauth: release shared runtime ownership");
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Owner runtime that survives optional LLM service churn. OAuth sessions and
|
|
430
|
+
* same-origin Web routes are deliberately owned here, rather than by the LLM
|
|
431
|
+
* child fiber, so a transient LLM unload cannot make account recovery vanish.
|
|
432
|
+
*/
|
|
433
|
+
async function applyOwned(ctx: Context, config: Config): Promise<void> {
|
|
434
|
+
const host = createDshHostAdapter(ctx);
|
|
435
|
+
const ownerRequestPolicy = safeguardOwnerRequestPolicy(
|
|
436
|
+
host.ownerRequestPolicy() ?? createOwnerRequestPolicy(config.ownerRequest),
|
|
437
|
+
);
|
|
438
|
+
const proxyLease = acquireCodingOAuthProxy(
|
|
439
|
+
config.proxy,
|
|
440
|
+
config.proxyKimi === undefined ? {} : { proxyKimi: config.proxyKimi },
|
|
441
|
+
);
|
|
442
|
+
ctx.effect(() => () => proxyLease.release(), "dsh-coding-subscription-oauth: scoped proxy policy");
|
|
443
|
+
const logger = ctx.logger(name);
|
|
444
|
+
const baseCapabilities = resolveCapabilitySettings(config.capabilities);
|
|
445
|
+
const runtime = new CapabilityRuntimeState(baseCapabilities, () => {
|
|
446
|
+
logger.warn("an optional capability listener failed");
|
|
447
|
+
});
|
|
448
|
+
let active = true;
|
|
449
|
+
ctx.effect(
|
|
450
|
+
() => () => {
|
|
451
|
+
active = false;
|
|
452
|
+
},
|
|
453
|
+
"dsh-coding-subscription-oauth: startup lifetime",
|
|
454
|
+
);
|
|
455
|
+
let invalidateOptionalAuthState = (): void => undefined;
|
|
456
|
+
const notifyCatalogChange = (): void => {
|
|
457
|
+
if (!active) return;
|
|
458
|
+
try {
|
|
459
|
+
ctx.emit("llm/adapters-updated");
|
|
460
|
+
} catch (error) {
|
|
461
|
+
// Catalog observers are advisory; a broken listener must not turn an
|
|
462
|
+
// already-persisted OAuth login/logout into an apparent auth failure.
|
|
463
|
+
logger.warn("an llm/adapters-updated listener failed");
|
|
464
|
+
logger.warn(error);
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
const grok = new GrokBuildSession(new GrokBuildCredentialStore(), notifyCatalogChange);
|
|
468
|
+
const subscriptions = OAUTH_PROVIDER_DEFINITIONS.map(
|
|
469
|
+
(definition) =>
|
|
470
|
+
new OAuthProviderSession(definition, () => {
|
|
471
|
+
if (definition.nativeProviderId === CODEX_PI_PROVIDER) invalidateOptionalAuthState();
|
|
472
|
+
notifyCatalogChange();
|
|
473
|
+
}),
|
|
474
|
+
);
|
|
475
|
+
const codex = requireSubscription(subscriptions, CODEX_PI_PROVIDER);
|
|
476
|
+
const codexAuth = codexAuthFromSession(codex);
|
|
477
|
+
const usage = createCodexUsageReader({ auth: codexAuth });
|
|
478
|
+
const codexModels = createCodexModelCapabilities({ auth: codexAuth });
|
|
479
|
+
invalidateOptionalAuthState = () => {
|
|
480
|
+
usage.clear();
|
|
481
|
+
codexModels.clear();
|
|
482
|
+
runtime.refresh();
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
void Promise.allSettled([grok.loadCachedCatalog(), ...subscriptions.map((session) => session.loadCachedModels())])
|
|
486
|
+
.then(async (results) => {
|
|
487
|
+
if (!active) return;
|
|
488
|
+
if (results.some((result) => result.status === "rejected")) {
|
|
489
|
+
logger.warn("one or more OAuth model caches could not be loaded; using in-memory fallbacks");
|
|
490
|
+
}
|
|
491
|
+
await grok.refreshLiveCatalog();
|
|
492
|
+
})
|
|
493
|
+
.catch(() => {
|
|
494
|
+
// Contain every startup refresh failure so plugin activation cannot leave
|
|
495
|
+
// an unhandled rejection. The static provider catalogs remain usable.
|
|
496
|
+
if (active) logger.warn("background OAuth model catalog initialization failed; using static fallbacks");
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
let settingsOwner = 0;
|
|
500
|
+
const createFallbackCapabilityController = (): ReturnType<typeof createCapabilitySettingsController> =>
|
|
501
|
+
createCapabilitySettingsController({
|
|
502
|
+
...(config.capabilities === undefined ? {} : { base: config.capabilities }),
|
|
503
|
+
onListenerError: () => logger.warn("a capability settings listener failed"),
|
|
504
|
+
});
|
|
505
|
+
let capabilityController = createFallbackCapabilityController();
|
|
506
|
+
const capabilityRoutesController = {
|
|
507
|
+
snapshot: () => capabilityController.snapshot(),
|
|
508
|
+
current: () => capabilityController.current(),
|
|
509
|
+
patch: (patch: CapabilitySettingsPatch, expectedRevision: number) =>
|
|
510
|
+
capabilityController.patch(patch, expectedRevision),
|
|
511
|
+
replace: (section: CapabilitySettingsPatch, expectedRevision: number) =>
|
|
512
|
+
capabilityController.replace(section, expectedRevision),
|
|
513
|
+
};
|
|
514
|
+
let releaseActiveSettings = (): void => undefined;
|
|
515
|
+
ctx.effect(
|
|
516
|
+
() => () => {
|
|
517
|
+
releaseActiveSettings();
|
|
518
|
+
capabilityController.dispose();
|
|
519
|
+
},
|
|
520
|
+
"dsh-coding-subscription-oauth: capability settings bridge",
|
|
521
|
+
);
|
|
522
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
523
|
+
// Re-injection may happen before Cordis runs the previous child effect's
|
|
524
|
+
// disposer. Release it synchronously so an obsolete watcher cannot race a
|
|
525
|
+
// newly attached settings service.
|
|
526
|
+
releaseActiveSettings();
|
|
527
|
+
const owner = ++settingsOwner;
|
|
528
|
+
const previousController = capabilityController;
|
|
529
|
+
const controller = createCapabilitySettingsController({
|
|
530
|
+
settings: settingsCtx.get("settings") as CapabilitySettingsService,
|
|
531
|
+
...(config.capabilities === undefined ? {} : { base: config.capabilities }),
|
|
532
|
+
onListenerError: () => logger.warn("a capability settings listener failed"),
|
|
533
|
+
});
|
|
534
|
+
capabilityController = controller;
|
|
535
|
+
previousController.dispose();
|
|
536
|
+
runtime.set(controller.current());
|
|
537
|
+
const unsubscribe = controller.subscribe((snapshot) => {
|
|
538
|
+
runtime.set(snapshot.value);
|
|
539
|
+
});
|
|
540
|
+
let released = false;
|
|
541
|
+
const release = (): void => {
|
|
542
|
+
if (released) return;
|
|
543
|
+
released = true;
|
|
544
|
+
unsubscribe();
|
|
545
|
+
controller.dispose();
|
|
546
|
+
if (owner === settingsOwner) {
|
|
547
|
+
releaseActiveSettings = (): void => undefined;
|
|
548
|
+
capabilityController = createFallbackCapabilityController();
|
|
549
|
+
runtime.set(capabilityController.current());
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
releaseActiveSettings = release;
|
|
553
|
+
settingsCtx.effect(() => release, "dsh-coding-subscription-oauth: capability settings");
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
const gateway = createCodingOAuthGatewayController({
|
|
557
|
+
...(config.gateway === undefined ? {} : { config: config.gateway }),
|
|
558
|
+
grok,
|
|
559
|
+
subscriptions,
|
|
560
|
+
onError: (error) => {
|
|
561
|
+
logger.warn("local API gateway failed to start; LLM routes are unchanged");
|
|
562
|
+
logger.warn(error);
|
|
563
|
+
},
|
|
564
|
+
});
|
|
565
|
+
ctx.effect(() => {
|
|
566
|
+
void gateway.startIfEnabled().then((started) => {
|
|
567
|
+
if (started !== undefined) {
|
|
568
|
+
logger.warn("local API gateway is enabled; exposing a subscription as a local API can violate provider ToS");
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
return () => gateway.stop();
|
|
572
|
+
}, "dsh-coding-subscription-oauth: local API gateway");
|
|
573
|
+
|
|
574
|
+
registerCapabilityRoutes(ctx, {
|
|
575
|
+
controller: capabilityRoutesController,
|
|
576
|
+
usage: () => usage.read(),
|
|
577
|
+
credentialInfo: () => describeImagineCredential(ctx.get("credentials") as CredentialProvider | undefined),
|
|
578
|
+
ownerRequestPolicy,
|
|
356
579
|
});
|
|
357
|
-
|
|
358
|
-
ctx
|
|
359
|
-
(
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
);
|
|
364
|
-
let invalidateOptionalAuthState = (): void => undefined;
|
|
365
|
-
const notifyCatalogChange = (): void => {
|
|
366
|
-
if (!active) return;
|
|
367
|
-
try {
|
|
368
|
-
ctx.emit("llm/adapters-updated");
|
|
369
|
-
} catch (error) {
|
|
370
|
-
// Catalog observers are advisory; a broken listener must not turn an
|
|
371
|
-
// already-persisted OAuth login/logout into an apparent auth failure.
|
|
372
|
-
logger.warn("an llm/adapters-updated listener failed");
|
|
373
|
-
logger.warn(error);
|
|
374
|
-
}
|
|
375
|
-
};
|
|
376
|
-
const grok = new GrokBuildSession(new GrokBuildCredentialStore(), notifyCatalogChange);
|
|
377
|
-
const subscriptions = OAUTH_PROVIDER_DEFINITIONS.map(
|
|
378
|
-
(definition) =>
|
|
379
|
-
new OAuthProviderSession(definition, () => {
|
|
380
|
-
if (definition.nativeProviderId === CODEX_PI_PROVIDER) invalidateOptionalAuthState();
|
|
381
|
-
notifyCatalogChange();
|
|
382
|
-
}),
|
|
383
|
-
);
|
|
384
|
-
const codex = requireSubscription(subscriptions, CODEX_PI_PROVIDER);
|
|
385
|
-
const codexAuth = codexAuthFromSession(codex);
|
|
386
|
-
const usage = createCodexUsageReader({ auth: codexAuth });
|
|
387
|
-
const codexModels = createCodexModelCapabilities({ auth: codexAuth });
|
|
388
|
-
const resolveCodexImageRoute: ResolveCodexImageRoute = (exec) =>
|
|
389
|
-
resolveCodexImageRouteFromLlm(exec, (provider, model, signal) => ctx.llm.resolveModelInfo(provider, model, signal));
|
|
390
|
-
invalidateOptionalAuthState = () => {
|
|
391
|
-
usage.clear();
|
|
392
|
-
codexModels.clear();
|
|
393
|
-
runtime.refresh();
|
|
394
|
-
};
|
|
395
|
-
const adapterRegistration = ctx.llm.registerAdapter(
|
|
396
|
-
[...CODING_OAUTH_ROUTES],
|
|
397
|
-
createCodingOAuthAdapter(grok, subscriptions, () => ctx.get("attachments"), config.retryPolicy, {
|
|
398
|
-
codexFast: {
|
|
399
|
-
isEligible: (modelId) => runtime.current().codexFast && codexModels.isPriorityEligible(modelId),
|
|
400
|
-
},
|
|
580
|
+
registerGatewayRoutes(ctx, gateway, ownerRequestPolicy);
|
|
581
|
+
registerCodingOAuthRoutes(ctx, grok, subscriptions, ownerRequestPolicy, (accessMode) =>
|
|
582
|
+
host.compatibility({
|
|
583
|
+
accessMode,
|
|
584
|
+
uiOwner: "standalone",
|
|
585
|
+
diagnostics: ownerRequestPolicy.diagnostics(),
|
|
401
586
|
}),
|
|
402
587
|
);
|
|
403
|
-
ctx
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
"dsh-coding-subscription-oauth: Codex Fast route",
|
|
409
|
-
);
|
|
410
|
-
|
|
411
|
-
void Promise.allSettled([grok.loadCachedCatalog(), ...subscriptions.map((session) => session.loadCachedModels())])
|
|
412
|
-
.then(async (results) => {
|
|
413
|
-
if (!active) return;
|
|
414
|
-
if (results.some((result) => result.status === "rejected")) {
|
|
415
|
-
logger.warn("one or more OAuth model caches could not be loaded; using in-memory fallbacks");
|
|
416
|
-
}
|
|
417
|
-
await grok.refreshLiveCatalog();
|
|
418
|
-
})
|
|
419
|
-
.catch(() => {
|
|
420
|
-
// Contain every startup refresh failure so plugin activation cannot leave
|
|
421
|
-
// an unhandled rejection. The static provider catalogs remain usable.
|
|
422
|
-
if (active) logger.warn("background OAuth model catalog initialization failed; using static fallbacks");
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
let settingsOwner = 0;
|
|
426
|
-
let releaseActiveSettings = (): void => undefined;
|
|
427
|
-
ctx.effect(() => () => releaseActiveSettings(), "dsh-coding-subscription-oauth: capability settings bridge");
|
|
428
|
-
ctx.inject(["settings"], (settingsCtx) => {
|
|
429
|
-
// Re-injection may happen before Cordis runs the previous child effect's
|
|
430
|
-
// disposer. Release it synchronously so an obsolete watcher cannot race a
|
|
431
|
-
// newly attached settings service.
|
|
432
|
-
releaseActiveSettings();
|
|
433
|
-
const owner = ++settingsOwner;
|
|
434
|
-
const controller = createCapabilitySettingsController({
|
|
435
|
-
settings: settingsCtx.get("settings") as CapabilitySettingsService,
|
|
436
|
-
...(config.capabilities === undefined ? {} : { base: config.capabilities }),
|
|
437
|
-
onListenerError: () => logger.warn("a capability settings listener failed"),
|
|
438
|
-
});
|
|
439
|
-
runtime.set(controller.current());
|
|
440
|
-
const unsubscribe = controller.subscribe((snapshot) => {
|
|
441
|
-
runtime.set(snapshot.value);
|
|
442
|
-
});
|
|
443
|
-
let released = false;
|
|
444
|
-
const release = (): void => {
|
|
445
|
-
if (released) return;
|
|
446
|
-
released = true;
|
|
447
|
-
unsubscribe();
|
|
448
|
-
controller.dispose();
|
|
449
|
-
if (owner === settingsOwner) {
|
|
450
|
-
releaseActiveSettings = (): void => undefined;
|
|
451
|
-
runtime.set(baseCapabilities);
|
|
452
|
-
}
|
|
453
|
-
};
|
|
454
|
-
releaseActiveSettings = release;
|
|
455
|
-
settingsCtx.effect(() => release, "dsh-coding-subscription-oauth: capability settings");
|
|
456
|
-
settingsCtx.inject(["webServer"], (webCtx) => {
|
|
457
|
-
registerCapabilityRoutes(webCtx, {
|
|
458
|
-
controller,
|
|
459
|
-
usage: () => usage.read(),
|
|
460
|
-
credentialInfo: () => describeImagineCredential(webCtx.get("credentials") as CredentialProvider | undefined),
|
|
461
|
-
});
|
|
462
|
-
});
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
const gateway = createCodingOAuthGatewayController({
|
|
466
|
-
...(config.gateway === undefined ? {} : { config: config.gateway }),
|
|
467
|
-
grok,
|
|
468
|
-
subscriptions,
|
|
469
|
-
onError: (error) => {
|
|
470
|
-
logger.warn("local API gateway failed to start; LLM routes are unchanged");
|
|
471
|
-
logger.warn(error);
|
|
588
|
+
registerOAuthImportRoutes(ctx, oauthImportDestinations(grok, subscriptions), {
|
|
589
|
+
ownerRequestPolicy,
|
|
590
|
+
onImported: (event) => {
|
|
591
|
+
if (event.kind === "codex") invalidateOptionalAuthState();
|
|
592
|
+
notifyCatalogChange();
|
|
472
593
|
},
|
|
473
594
|
});
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
resolveCodexImageRoute,
|
|
566
|
-
})
|
|
567
|
-
).filter((definition) => IMAGINE_TOOL_NAMES.has(definition.name));
|
|
568
|
-
let previousSettings = runtime.current();
|
|
569
|
-
const releaseRetention = runtime.subscribe((settings) => {
|
|
570
|
-
const previous = previousSettings;
|
|
571
|
-
previousSettings = settings;
|
|
572
|
-
if (previous.grokImagineImage && !settings.grokImagineImage) routeRegistry.revokeImages();
|
|
573
|
-
if (previous.grokImagineVideo && !settings.grokImagineVideo) routeRegistry.revokeArtifacts();
|
|
574
|
-
return media
|
|
575
|
-
.applyRetentionMs(settings.videoArtifactTtlMs)
|
|
576
|
-
.then(() => undefined)
|
|
577
|
-
.catch(() => logger.warn("Imagine media retention cleanup failed"));
|
|
578
|
-
});
|
|
579
|
-
toolCtx.effect(
|
|
580
|
-
() => bindCapabilityTools(runtime, tools, definitions),
|
|
581
|
-
"dsh-coding-subscription-oauth: Grok Imagine tools",
|
|
582
|
-
);
|
|
583
|
-
toolCtx.effect(
|
|
584
|
-
() => async () => {
|
|
585
|
-
// Abort new/in-flight work before cleanup regardless of Cordis disposer
|
|
586
|
-
// ordering. GrokImagineClient.dispose() is intentionally idempotent.
|
|
587
|
-
imagine.dispose();
|
|
588
|
-
releaseRetention();
|
|
589
|
-
try {
|
|
590
|
-
await media.cleanup();
|
|
591
|
-
} catch {
|
|
592
|
-
logger.warn("Imagine media cleanup failed");
|
|
593
|
-
}
|
|
594
|
-
},
|
|
595
|
-
"dsh-coding-subscription-oauth: Imagine client and media lifetime",
|
|
596
|
-
);
|
|
597
|
-
});
|
|
595
|
+
|
|
596
|
+
const search = createCodexSearchProvider({
|
|
597
|
+
auth: codexAuth,
|
|
598
|
+
// Login, import, model selection, and catalog refreshes can all change the
|
|
599
|
+
// first visible Codex model after plugin startup.
|
|
600
|
+
model: () => codex.visibleModels()[0]?.id ?? "",
|
|
601
|
+
});
|
|
602
|
+
ctx.inject(["web"], (webCtx) => {
|
|
603
|
+
const web = webCtx.get("web") as CapabilitySearchRegistry;
|
|
604
|
+
webCtx.effect(() => bindCapabilitySearch(runtime, web, search), "dsh-coding-subscription-oauth: Codex search");
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
ctx.inject(["tools", "attachments", "credentials", "webServer"], async (toolCtx) => {
|
|
608
|
+
const tools = toolCtx.get("tools") as CapabilityToolRegistry;
|
|
609
|
+
const attachments = toolCtx.get("attachments") as AttachmentStore;
|
|
610
|
+
const credentials = toolCtx.get("credentials") as CredentialProvider;
|
|
611
|
+
const media = new MediaStore(join(dirname(grok.store.filename), IMAGINE_MEDIA_STORE_DIRNAME), {
|
|
612
|
+
retentionMs: runtime.current().videoArtifactTtlMs,
|
|
613
|
+
});
|
|
614
|
+
const routeRegistry = registerImagineRoutes(toolCtx, {
|
|
615
|
+
attachments,
|
|
616
|
+
media: { readForDownload: (artifactId, authz) => media.openDownload(artifactId, authz) },
|
|
617
|
+
ownerRequestPolicy,
|
|
618
|
+
});
|
|
619
|
+
const imagine = createGrokImagineClient({
|
|
620
|
+
resolveApiKey: (operation) => resolveImagineApiKey(credentials, operation),
|
|
621
|
+
attachments,
|
|
622
|
+
media,
|
|
623
|
+
});
|
|
624
|
+
const routedImagine = {
|
|
625
|
+
async generateImage(input: Parameters<typeof imagine.generateImage>[0], signal?: AbortSignal) {
|
|
626
|
+
const result = await imagine.generateImage(input, signal);
|
|
627
|
+
if (runtime.current().grokImagineImage) {
|
|
628
|
+
routeRegistry.rememberImages(result.images.map((image) => image.attachment));
|
|
629
|
+
}
|
|
630
|
+
return result;
|
|
631
|
+
},
|
|
632
|
+
startVideo: (input: Parameters<typeof imagine.startVideo>[0], signal?: AbortSignal) =>
|
|
633
|
+
imagine.startVideo(input, signal),
|
|
634
|
+
async videoStatus(requestId: string, options?: Parameters<typeof imagine.videoStatus>[1]) {
|
|
635
|
+
const result = await imagine.videoStatus(requestId, options);
|
|
636
|
+
if (result.artifact !== undefined && runtime.current().grokImagineVideo) {
|
|
637
|
+
routeRegistry.rememberArtifact(result.artifact);
|
|
638
|
+
}
|
|
639
|
+
return result;
|
|
640
|
+
},
|
|
641
|
+
};
|
|
642
|
+
const definitions = (
|
|
643
|
+
await createCapabilityTools({
|
|
644
|
+
current: () => runtime.current(),
|
|
645
|
+
auth: codexAuth,
|
|
646
|
+
attachments,
|
|
647
|
+
imagine: routedImagine,
|
|
648
|
+
})
|
|
649
|
+
).filter((definition) => IMAGINE_TOOL_NAMES.has(definition.name));
|
|
650
|
+
let previousSettings = runtime.current();
|
|
651
|
+
const releaseRetention = runtime.subscribe((settings) => {
|
|
652
|
+
const previous = previousSettings;
|
|
653
|
+
previousSettings = settings;
|
|
654
|
+
if (previous.grokImagineImage && !settings.grokImagineImage) routeRegistry.revokeImages();
|
|
655
|
+
if (previous.grokImagineVideo && !settings.grokImagineVideo) routeRegistry.revokeArtifacts();
|
|
656
|
+
return media
|
|
657
|
+
.applyRetentionMs(settings.videoArtifactTtlMs)
|
|
658
|
+
.then(() => undefined)
|
|
659
|
+
.catch(() => logger.warn("Imagine media retention cleanup failed"));
|
|
660
|
+
});
|
|
661
|
+
toolCtx.effect(
|
|
662
|
+
() => bindCapabilityTools(runtime, tools, definitions),
|
|
663
|
+
"dsh-coding-subscription-oauth: Grok Imagine tools",
|
|
664
|
+
);
|
|
665
|
+
toolCtx.effect(
|
|
666
|
+
() => async () => {
|
|
667
|
+
// Abort new/in-flight work before cleanup regardless of Cordis disposer
|
|
668
|
+
// ordering. GrokImagineClient.dispose() is intentionally idempotent.
|
|
669
|
+
imagine.dispose();
|
|
670
|
+
releaseRetention();
|
|
671
|
+
try {
|
|
672
|
+
await media.cleanup();
|
|
673
|
+
} catch {
|
|
674
|
+
logger.warn("Imagine media cleanup failed");
|
|
675
|
+
}
|
|
676
|
+
},
|
|
677
|
+
"dsh-coding-subscription-oauth: Imagine client and media lifetime",
|
|
678
|
+
);
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// Only adapters and LLM-backed model resolution depend on this service. Its
|
|
682
|
+
// child fiber may unload and reload without disturbing OAuth/Web ownership.
|
|
683
|
+
ctx.inject(["llm"], (llmCtx) =>
|
|
684
|
+
applyOwnedLlm(llmCtx, config, { grok, subscriptions, runtime, codexAuth, codexModels, logger }),
|
|
685
|
+
);
|
|
598
686
|
}
|
|
687
|
+
|
|
688
|
+
interface OwnedLlmDependencies {
|
|
689
|
+
readonly grok: GrokBuildSession;
|
|
690
|
+
readonly subscriptions: readonly OAuthProviderSession[];
|
|
691
|
+
readonly runtime: CapabilityRuntimeState;
|
|
692
|
+
readonly codexAuth: ReturnType<typeof codexAuthFromSession>;
|
|
693
|
+
readonly codexModels: ReturnType<typeof createCodexModelCapabilities>;
|
|
694
|
+
readonly logger: ReturnType<Context["logger"]>;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/** LLM-only child runtime, independently restarted by Cordis when LLM changes. */
|
|
698
|
+
function applyOwnedLlm(ctx: Context, config: Config, owner: OwnedLlmDependencies): void {
|
|
699
|
+
createDshHostAdapter(ctx).assertCompatible();
|
|
700
|
+
const resolveCodexImageRoute: ResolveCodexImageRoute = (exec) =>
|
|
701
|
+
resolveCodexImageRouteFromLlm(exec, (provider, model, signal) => ctx.llm.resolveModelInfo(provider, model, signal));
|
|
702
|
+
const adapterRegistration = ctx.llm.registerAdapter(
|
|
703
|
+
[...CODING_OAUTH_ROUTES],
|
|
704
|
+
createCodingOAuthAdapter(owner.grok, owner.subscriptions, () => ctx.get("attachments"), config.retryPolicy, {
|
|
705
|
+
codexFast: {
|
|
706
|
+
isEligible: (modelId) => owner.runtime.current().codexFast && owner.codexModels.isPriorityEligible(modelId),
|
|
707
|
+
},
|
|
708
|
+
}),
|
|
709
|
+
);
|
|
710
|
+
ctx.effect(() => adapterRegistration, "dsh-coding-subscription-oauth: OAuth LLM adapters");
|
|
711
|
+
ctx.effect(
|
|
712
|
+
() =>
|
|
713
|
+
bindCodexFastRoute(owner.runtime, owner.codexModels, adapterRegistration, {
|
|
714
|
+
onError: () => owner.logger.warn("Codex Fast eligibility refresh failed closed"),
|
|
715
|
+
}),
|
|
716
|
+
"dsh-coding-subscription-oauth: Codex Fast route",
|
|
717
|
+
);
|
|
718
|
+
ctx.inject(["tools", "attachments"], async (toolCtx) => {
|
|
719
|
+
const tools = toolCtx.get("tools") as CapabilityToolRegistry;
|
|
720
|
+
const attachments = toolCtx.get("attachments") as AttachmentStore;
|
|
721
|
+
const definitions = (
|
|
722
|
+
await createCapabilityTools({
|
|
723
|
+
current: () => owner.runtime.current(),
|
|
724
|
+
auth: owner.codexAuth,
|
|
725
|
+
attachments,
|
|
726
|
+
imagine: unavailableImagineClient(),
|
|
727
|
+
resolveCodexImageRoute,
|
|
728
|
+
})
|
|
729
|
+
).filter((definition) => CODEX_TOOL_NAMES.has(definition.name));
|
|
730
|
+
toolCtx.effect(
|
|
731
|
+
() => bindCapabilityTools(owner.runtime, tools, definitions),
|
|
732
|
+
"dsh-coding-subscription-oauth: Codex image tools",
|
|
733
|
+
);
|
|
734
|
+
});
|
|
735
|
+
}
|