@edge-sky/dsh-oauth-adapter 0.1.1-rc.9 → 0.1.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +19 -5
- package/README.zh.md +19 -5
- package/lib/client.js +105 -31
- package/lib/index.d.ts +2 -0
- package/lib/index.js +77 -7
- package/lib/protocol.d.ts +27 -0
- package/lib/protocol.js +20 -0
- package/lib/types/client/locales.d.ts +1 -0
- package/lib/types/client/store.d.ts +2 -0
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/protocol.d.ts +27 -0
- package/package.json +23 -21
package/README.i18n.yaml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
# Bilingual-pair consistency record: the git blob hash of each side as of the
|
|
2
2
|
# last confirmed-consistent state. Both languages carry equal authority.
|
|
3
|
-
README.md:
|
|
4
|
-
README.zh.md:
|
|
3
|
+
README.md: ca7554635b97303928fe3ad09f3ee53c9ce96e94
|
|
4
|
+
README.zh.md: 8e53233889cfe60ca4c0c19b2a26064400eceaf4
|
package/README.md
CHANGED
|
@@ -2,10 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文](README.zh.md)
|
|
4
4
|
|
|
5
|
-
An OAuth account page for the DSH Web profile.
|
|
5
|
+
An OAuth account page for the DSH Web profile. With the pi-ai catalog bundled by DSH `0.1.1-rc.2`, it supports:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
7
|
+
| Provider | pi-ai sign-in path |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| OpenAI Codex | Browser callback or device code |
|
|
10
|
+
| GitHub Copilot | GitHub or GitHub Enterprise device code |
|
|
11
|
+
| Anthropic | Browser callback with manual code/redirect fallback |
|
|
12
|
+
| Kimi For Coding | Device code |
|
|
13
|
+
| OpenRouter | Browser PKCE callback |
|
|
14
|
+
| Radius | Browser PKCE callback or device code |
|
|
15
|
+
| xAI | Device code |
|
|
16
|
+
|
|
17
|
+
Each account is shown only as available when the installed `@deepseek-ai/dsh-llm-pi-ai` actually registers its OAuth flow. This keeps older or differently bundled pi-ai versions fail-closed instead of exposing a login button that cannot work.
|
|
9
18
|
|
|
10
19
|
The adapter has only been tested with DSH `0.1.1-rc.2`; compatibility with future versions is not guaranteed.
|
|
11
20
|
|
|
@@ -27,10 +36,15 @@ Start DSH:
|
|
|
27
36
|
npx @deepseek-ai/dsh web
|
|
28
37
|
```
|
|
29
38
|
|
|
39
|
+
<img width="2270" height="1524" alt="image" src="https://github.com/user-attachments/assets/78a59190-8029-4c60-bc50-b763312540f7" />
|
|
40
|
+
|
|
41
|
+
<img width="2270" height="1524" alt="image" src="https://github.com/user-attachments/assets/e0cc6591-73a4-4e87-9ef6-68950126b290" />
|
|
42
|
+
|
|
43
|
+
|
|
30
44
|
## How it works
|
|
31
45
|
|
|
32
|
-
DSH integrates pi-ai through the `@deepseek-ai/dsh-llm-pi-ai` adapter, but does not provide an OAuth entry point. `@edge-sky/dsh-oauth-adapter`
|
|
46
|
+
DSH integrates pi-ai through the `@deepseek-ai/dsh-llm-pi-ai` adapter, but does not provide an OAuth entry point. `@edge-sky/dsh-oauth-adapter` exposes pi-ai's existing provider login flows through the DSH Authorization Service. Browser links, device codes, text and secret input, method selection, cancellation, and withdrawn prompts all use the same provider-neutral transport.
|
|
33
47
|
|
|
34
48
|
Because DSH does not currently mount the `ctx.authorization` service, this plugin also mounts it manually.
|
|
35
49
|
|
|
36
|
-
The plugin itself does not manage OAuth credentials or maintain login state.
|
|
50
|
+
The plugin itself does not implement provider OAuth protocols, manage OAuth credentials, or maintain login state. pi-ai owns login and token refresh; the DSH Credentials Service owns persistence; this adapter owns only the local Web UI bridge and model-route activation.
|
package/README.zh.md
CHANGED
|
@@ -2,10 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | 中文
|
|
4
4
|
|
|
5
|
-
为 DSH Web profile 提供独立的 OAuth
|
|
5
|
+
为 DSH Web profile 提供独立的 OAuth 账户页面。配合 DSH `0.1.1-rc.2` 内置的 pi-ai catalog,当前支持:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
|
|
7
|
+
| 提供商 | pi-ai 登录路径 |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| OpenAI Codex | 浏览器回调或设备码 |
|
|
10
|
+
| GitHub Copilot | GitHub 或 GitHub Enterprise 设备码 |
|
|
11
|
+
| Anthropic | 浏览器回调,并支持手工粘贴授权码/重定向地址 |
|
|
12
|
+
| Kimi For Coding | 设备码 |
|
|
13
|
+
| OpenRouter | 浏览器 PKCE 回调 |
|
|
14
|
+
| Radius | 浏览器 PKCE 回调或设备码 |
|
|
15
|
+
| xAI | 设备码 |
|
|
16
|
+
|
|
17
|
+
只有当当前安装的 `@deepseek-ai/dsh-llm-pi-ai` 确实注册了对应 OAuth 流程时,账户才会显示为可用。这样旧版或采用不同 pi-ai bundle 的 DSH 会安全地禁用登录按钮,而不会暴露无法完成的流程。
|
|
9
18
|
|
|
10
19
|
当前仅对 DSH`0.1.1-rc.2`进行了测试,不保证未来版本的兼容性
|
|
11
20
|
|
|
@@ -27,10 +36,15 @@ npx @deepseek-ai/dsh plugin --profile web add @edge-sky/dsh-oauth-adapter
|
|
|
27
36
|
npx @deepseek-ai/dsh web
|
|
28
37
|
```
|
|
29
38
|
|
|
39
|
+
<img width="2270" height="1524" alt="image" src="https://github.com/user-attachments/assets/134ec856-e17b-4800-bb87-069851986d3e" />
|
|
40
|
+
|
|
41
|
+
<img width="2270" height="1524" alt="image" src="https://github.com/user-attachments/assets/8007002a-a036-4cf4-b015-d4e50eff25d9" />
|
|
42
|
+
|
|
43
|
+
|
|
30
44
|
## 工作原理
|
|
31
45
|
|
|
32
|
-
DSH 通过 `@deepseek-ai/dsh-llm-pi-ai` 适配器接入 pi-ai,但并没有提供 OAuth 的入口。`@edge-sky/dsh-oauth-adapter`
|
|
46
|
+
DSH 通过 `@deepseek-ai/dsh-llm-pi-ai` 适配器接入 pi-ai,但并没有提供 OAuth 的入口。`@edge-sky/dsh-oauth-adapter` 通过 DSH Authorization Service 暴露 pi-ai 已有的 provider 登录流程。浏览器链接、设备码、文本与密码输入、登录方式选择、取消和撤回提示均通过同一套 provider-neutral 传输完成。
|
|
33
47
|
|
|
34
48
|
由于 DSH 目前并没有挂载`ctx.authorization`服务,因此该插件同时手动对其进行了挂载
|
|
35
49
|
|
|
36
|
-
|
|
50
|
+
插件本身不实现各提供商的 OAuth 协议,也不管理 OAuth 凭证或维持登录态。登录与 token 刷新由 pi-ai 负责,持久化由 DSH Credentials Service 负责,本适配器只负责本机 Web UI 桥接和模型路由启用。
|
package/lib/client.js
CHANGED
|
@@ -6,6 +6,55 @@ window.__ModuleLoader__.load({
|
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
|
+
//#region src/protocol.ts
|
|
10
|
+
/** Shared browser/Host wire vocabulary for the OAuth account surface. */
|
|
11
|
+
const OAUTH_SOCKET_PATH = "/_edge-sky/dsh-oauth";
|
|
12
|
+
const OAUTH_SOCKET_PROTOCOL = "dsh-oauth-v1";
|
|
13
|
+
const PROVIDERS = [
|
|
14
|
+
{
|
|
15
|
+
id: "openai-codex",
|
|
16
|
+
key: "llm-pi-ai/openai-codex",
|
|
17
|
+
fallbackLabel: "OpenAI Codex",
|
|
18
|
+
modelGroupLabel: "OpenAI Codex (OAuth)"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "github-copilot",
|
|
22
|
+
key: "llm-pi-ai/github-copilot",
|
|
23
|
+
fallbackLabel: "GitHub Copilot",
|
|
24
|
+
modelGroupLabel: "GitHub Copilot (OAuth)"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "anthropic",
|
|
28
|
+
key: "llm-pi-ai/anthropic",
|
|
29
|
+
fallbackLabel: "Anthropic",
|
|
30
|
+
modelGroupLabel: "Anthropic (OAuth)"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: "kimi-coding",
|
|
34
|
+
key: "llm-pi-ai/kimi-coding",
|
|
35
|
+
fallbackLabel: "Kimi For Coding",
|
|
36
|
+
modelGroupLabel: "Kimi For Coding (OAuth)"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "openrouter",
|
|
40
|
+
key: "llm-pi-ai/openrouter",
|
|
41
|
+
fallbackLabel: "OpenRouter",
|
|
42
|
+
modelGroupLabel: "OpenRouter (OAuth)"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "radius",
|
|
46
|
+
key: "llm-pi-ai/radius",
|
|
47
|
+
fallbackLabel: "Radius",
|
|
48
|
+
modelGroupLabel: "Radius (OAuth)"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "xai",
|
|
52
|
+
key: "llm-pi-ai/xai",
|
|
53
|
+
fallbackLabel: "xAI",
|
|
54
|
+
modelGroupLabel: "xAI (OAuth)"
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
//#endregion
|
|
9
58
|
//#region src/client/OAuthAccountsSection.tsx
|
|
10
59
|
/** OAuth account settings page. */
|
|
11
60
|
function safeHttpUrl(value) {
|
|
@@ -92,6 +141,16 @@ window.__ModuleLoader__.load({
|
|
|
92
141
|
]
|
|
93
142
|
});
|
|
94
143
|
}
|
|
144
|
+
function ErrorPanel(props) {
|
|
145
|
+
const collapsible = props.detail !== void 0 && (props.detail.includes("\n") || props.detail.length > 240);
|
|
146
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
147
|
+
className: "dsh-oauth-error",
|
|
148
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: props.message }), props.detail !== void 0 && (collapsible ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
149
|
+
className: "dsh-oauth-error-details",
|
|
150
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: props.t("technicalDetails") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: props.detail })]
|
|
151
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: props.detail }))]
|
|
152
|
+
});
|
|
153
|
+
}
|
|
95
154
|
function AttemptPanel(props) {
|
|
96
155
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
97
156
|
const url = safeHttpUrl(props.attempt.notice?.url);
|
|
@@ -125,9 +184,10 @@ window.__ModuleLoader__.load({
|
|
|
125
184
|
controller: props.controller,
|
|
126
185
|
t: props.t
|
|
127
186
|
}, props.attempt.prompt.id),
|
|
128
|
-
props.attempt.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
129
|
-
|
|
130
|
-
|
|
187
|
+
props.attempt.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorPanel, {
|
|
188
|
+
message: props.attempt.error,
|
|
189
|
+
...props.attempt.errorDetail === void 0 ? {} : { detail: props.attempt.errorDetail },
|
|
190
|
+
t: props.t
|
|
131
191
|
}),
|
|
132
192
|
props.attempt.id !== void 0 && (props.attempt.phase === "running" || props.attempt.phase === "starting") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
133
193
|
className: "dsh-oauth-button",
|
|
@@ -158,9 +218,10 @@ window.__ModuleLoader__.load({
|
|
|
158
218
|
className: "dsh-oauth-intro",
|
|
159
219
|
children: t("intro")
|
|
160
220
|
}),
|
|
161
|
-
snapshot.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
162
|
-
|
|
163
|
-
|
|
221
|
+
snapshot.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorPanel, {
|
|
222
|
+
message: snapshot.error,
|
|
223
|
+
...snapshot.errorDetail === void 0 ? {} : { detail: snapshot.errorDetail },
|
|
224
|
+
t
|
|
164
225
|
}),
|
|
165
226
|
snapshot.connection !== "open" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
166
227
|
className: "dsh-oauth-button",
|
|
@@ -177,7 +238,7 @@ window.__ModuleLoader__.load({
|
|
|
177
238
|
}),
|
|
178
239
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
179
240
|
className: "dsh-oauth-list",
|
|
180
|
-
children:
|
|
241
|
+
children: PROVIDERS.map(({ id: provider }) => {
|
|
181
242
|
const account = accountByProvider.get(provider);
|
|
182
243
|
const attempt = snapshot.attempt?.provider === provider ? snapshot.attempt : void 0;
|
|
183
244
|
const busy = account?.inFlight === true || attempt?.phase === "running" || attempt?.phase === "starting";
|
|
@@ -261,6 +322,7 @@ window.__ModuleLoader__.load({
|
|
|
261
322
|
authorized: "Sign-in completed.",
|
|
262
323
|
cancelled: "Sign-in was cancelled.",
|
|
263
324
|
failed: "Sign-in failed.",
|
|
325
|
+
technicalDetails: "Technical details",
|
|
264
326
|
submit: "Continue",
|
|
265
327
|
copy: "Copy code",
|
|
266
328
|
copied: "Copied",
|
|
@@ -292,6 +354,7 @@ window.__ModuleLoader__.load({
|
|
|
292
354
|
authorized: "登录已完成。",
|
|
293
355
|
cancelled: "登录已取消。",
|
|
294
356
|
failed: "登录失败。",
|
|
357
|
+
technicalDetails: "技术详情",
|
|
295
358
|
submit: "继续",
|
|
296
359
|
copy: "复制代码",
|
|
297
360
|
copied: "已复制",
|
|
@@ -303,11 +366,6 @@ window.__ModuleLoader__.load({
|
|
|
303
366
|
hostDisconnected: "与 DSH 的 OAuth 连接已中断。"
|
|
304
367
|
};
|
|
305
368
|
//#endregion
|
|
306
|
-
//#region src/protocol.ts
|
|
307
|
-
/** Shared browser/Host wire vocabulary for the OAuth account surface. */
|
|
308
|
-
const OAUTH_SOCKET_PATH = "/_edge-sky/dsh-oauth";
|
|
309
|
-
const OAUTH_SOCKET_PROTOCOL = "dsh-oauth-v1";
|
|
310
|
-
//#endregion
|
|
311
369
|
//#region src/client/store.ts
|
|
312
370
|
/** Browser state machine for the plugin-owned OAuth WebSocket. */
|
|
313
371
|
function socketUrl() {
|
|
@@ -355,7 +413,7 @@ window.__ModuleLoader__.load({
|
|
|
355
413
|
getSnapshot = () => this.snapshot;
|
|
356
414
|
begin(provider) {
|
|
357
415
|
if (this.snapshot.attempt?.phase === "starting" || this.snapshot.attempt?.phase === "running") return;
|
|
358
|
-
const { error: _error, ...current } = this.snapshot;
|
|
416
|
+
const { error: _error, errorDetail: _errorDetail, ...current } = this.snapshot;
|
|
359
417
|
this.update({
|
|
360
418
|
...current,
|
|
361
419
|
attempt: {
|
|
@@ -426,7 +484,7 @@ window.__ModuleLoader__.load({
|
|
|
426
484
|
socket.addEventListener("open", () => {
|
|
427
485
|
if (this.socket !== socket) return;
|
|
428
486
|
this.reconnectDelay = 500;
|
|
429
|
-
const { error: _error, ...current } = this.snapshot;
|
|
487
|
+
const { error: _error, errorDetail: _errorDetail, ...current } = this.snapshot;
|
|
430
488
|
this.update({
|
|
431
489
|
...current,
|
|
432
490
|
connection: "open"
|
|
@@ -442,10 +500,12 @@ window.__ModuleLoader__.load({
|
|
|
442
500
|
try {
|
|
443
501
|
value = JSON.parse(event.data);
|
|
444
502
|
} catch {
|
|
445
|
-
|
|
503
|
+
const next = {
|
|
446
504
|
...this.snapshot,
|
|
447
505
|
error: "DSH returned an invalid OAuth message."
|
|
448
|
-
}
|
|
506
|
+
};
|
|
507
|
+
delete next.errorDetail;
|
|
508
|
+
this.update(next);
|
|
449
509
|
return;
|
|
450
510
|
}
|
|
451
511
|
if (isServerMessage(value)) this.receive(value);
|
|
@@ -461,7 +521,7 @@ window.__ModuleLoader__.load({
|
|
|
461
521
|
return;
|
|
462
522
|
}
|
|
463
523
|
const attempt = this.snapshot.attempt;
|
|
464
|
-
|
|
524
|
+
const interrupted = {
|
|
465
525
|
...this.snapshot,
|
|
466
526
|
connection: "reconnecting",
|
|
467
527
|
error: "The OAuth connection to DSH was interrupted.",
|
|
@@ -470,7 +530,10 @@ window.__ModuleLoader__.load({
|
|
|
470
530
|
phase: "failed",
|
|
471
531
|
error: "The OAuth connection to DSH was interrupted."
|
|
472
532
|
} }
|
|
473
|
-
}
|
|
533
|
+
};
|
|
534
|
+
delete interrupted.errorDetail;
|
|
535
|
+
if (interrupted.attempt?.error === "The OAuth connection to DSH was interrupted.") delete interrupted.attempt.errorDetail;
|
|
536
|
+
this.update(interrupted);
|
|
474
537
|
const delay = this.reconnectDelay;
|
|
475
538
|
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 5e3);
|
|
476
539
|
this.reconnectTimer = window.setTimeout(() => {
|
|
@@ -482,10 +545,12 @@ window.__ModuleLoader__.load({
|
|
|
482
545
|
}
|
|
483
546
|
send(command) {
|
|
484
547
|
if (this.socket?.readyState !== WebSocket.OPEN) {
|
|
485
|
-
|
|
548
|
+
const next = {
|
|
486
549
|
...this.snapshot,
|
|
487
550
|
error: "The OAuth connection to DSH is not ready."
|
|
488
|
-
}
|
|
551
|
+
};
|
|
552
|
+
delete next.errorDetail;
|
|
553
|
+
this.update(next);
|
|
489
554
|
return;
|
|
490
555
|
}
|
|
491
556
|
this.socket.send(JSON.stringify(command));
|
|
@@ -504,7 +569,7 @@ window.__ModuleLoader__.load({
|
|
|
504
569
|
this.update(nextSnapshot);
|
|
505
570
|
return;
|
|
506
571
|
case "started":
|
|
507
|
-
const { error: _error, ...current } = this.snapshot;
|
|
572
|
+
const { error: _error, errorDetail: _errorDetail, ...current } = this.snapshot;
|
|
508
573
|
this.update({
|
|
509
574
|
...current,
|
|
510
575
|
attempt: {
|
|
@@ -567,17 +632,26 @@ window.__ModuleLoader__.load({
|
|
|
567
632
|
}
|
|
568
633
|
case "error": {
|
|
569
634
|
const attempt = this.snapshot.attempt;
|
|
570
|
-
if (message.attemptId !== void 0 && attempt?.id === message.attemptId)
|
|
571
|
-
|
|
572
|
-
attempt: {
|
|
635
|
+
if (message.attemptId !== void 0 && attempt?.id === message.attemptId) {
|
|
636
|
+
const nextAttempt = {
|
|
573
637
|
...attempt,
|
|
574
638
|
error: message.message
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
639
|
+
};
|
|
640
|
+
if (message.detail === void 0) delete nextAttempt.errorDetail;
|
|
641
|
+
else nextAttempt.errorDetail = message.detail;
|
|
642
|
+
this.update({
|
|
643
|
+
...this.snapshot,
|
|
644
|
+
attempt: nextAttempt
|
|
645
|
+
});
|
|
646
|
+
} else {
|
|
647
|
+
const next = {
|
|
648
|
+
...this.snapshot,
|
|
649
|
+
error: message.message
|
|
650
|
+
};
|
|
651
|
+
if (message.detail === void 0) delete next.errorDetail;
|
|
652
|
+
else next.errorDetail = message.detail;
|
|
653
|
+
this.update(next);
|
|
654
|
+
}
|
|
581
655
|
return;
|
|
582
656
|
}
|
|
583
657
|
case "ack": return;
|
|
@@ -595,7 +669,7 @@ window.__ModuleLoader__.load({
|
|
|
595
669
|
.dsh-oauth-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}
|
|
596
670
|
.dsh-oauth-title{margin:0;font-size:16px;line-height:24px;font-weight:500}
|
|
597
671
|
.dsh-oauth-intro,.dsh-oauth-muted{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}
|
|
598
|
-
.dsh-oauth-error{margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}
|
|
672
|
+
.dsh-oauth-error{display:flex;flex-direction:column;gap:6px;margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.dsh-oauth-error p{margin:0}.dsh-oauth-error pre{box-sizing:border-box;max-width:100%;max-height:320px;margin:0;padding:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;overflow:auto;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:11px/17px ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.dsh-oauth-error-details summary{cursor:pointer;color:var(--dsw-alias-label-secondary);user-select:none}.dsh-oauth-error-details[open] summary{margin-bottom:6px}
|
|
599
673
|
.dsh-oauth-list{display:flex;flex-direction:column;gap:8px;margin:4px 0 0;padding:0;list-style:none}
|
|
600
674
|
.dsh-oauth-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}
|
|
601
675
|
.dsh-oauth-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dsh-oauth-name{font-size:14px;font-weight:500}.dsh-oauth-state{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;color:var(--dsw-alias-label-secondary)}
|
package/lib/index.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export declare function isLoopbackAddress(address: string | undefined): boolean;
|
|
|
33
33
|
export declare function safeNoticeUrl(value: string | undefined): string | undefined;
|
|
34
34
|
/** Validate the browser handshake before `ws` takes ownership of the socket. */
|
|
35
35
|
export declare function acceptsBrowserUpgrade(request: IncomingMessage): boolean;
|
|
36
|
+
/** Format one Host failure for browser diagnostics without forwarding credentials or unbounded data. */
|
|
37
|
+
export declare function formatErrorDetail(error: unknown): string;
|
|
36
38
|
/** Mount the loopback-only OAuth WebSocket over official rc2 services. */
|
|
37
39
|
export declare function apply(ctx: OAuthContext, config: Config): () => Promise<void>;
|
|
38
40
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* @module @edge-sky/dsh-oauth-adapter
|
|
5
5
|
*/
|
|
6
6
|
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import { inspect } from 'node:util';
|
|
7
8
|
import { settingsNamespace } from '@deepseek-ai/dsh-settings';
|
|
8
9
|
import z from '@deepseek-ai/schemastery';
|
|
9
10
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
@@ -55,6 +56,13 @@ function promptView(prompt, provider) {
|
|
|
55
56
|
: {},
|
|
56
57
|
};
|
|
57
58
|
}
|
|
59
|
+
function providerPromptAnswer(prompt, provider, value) {
|
|
60
|
+
if (provider === 'github-copilot' && prompt.kind === 'text'
|
|
61
|
+
&& prompt.message === GITHUB_DOMAIN_PROMPT && value.trim().length === 0) {
|
|
62
|
+
return 'github.com';
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
58
66
|
/** Whether a socket address belongs to the local host. */
|
|
59
67
|
export function isLoopbackAddress(address) {
|
|
60
68
|
return address === '127.0.0.1' || address === '::1' || address === '::ffff:127.0.0.1';
|
|
@@ -101,6 +109,67 @@ function rawLength(raw) {
|
|
|
101
109
|
return raw.reduce((total, chunk) => total + chunk.byteLength, 0);
|
|
102
110
|
return raw.byteLength;
|
|
103
111
|
}
|
|
112
|
+
const MAX_ERROR_DETAIL_LENGTH = 12 * 1024;
|
|
113
|
+
const MAX_ERROR_CAUSE_DEPTH = 6;
|
|
114
|
+
function redactErrorDetail(value) {
|
|
115
|
+
return value
|
|
116
|
+
.replace(/(\bAuthorization\b\s*["']?\s*[:=]\s*["']?)(?:Bearer\s+)?([^"'\s,}&]+)/giu, '$1[REDACTED]')
|
|
117
|
+
.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/giu, 'Bearer [REDACTED]')
|
|
118
|
+
.replace(/(\b(?:access[_-]?token|refresh[_-]?token|id[_-]?token|client[_-]?secret|api[_-]?key)\b\s*["']?\s*[:=]\s*["']?)([^"'\s,}&]+)/giu, '$1[REDACTED]')
|
|
119
|
+
.replace(/\b(?:github_pat_|gh[opusr]_|sk-)[A-Za-z0-9_-]{12,}\b/gu, '[REDACTED]');
|
|
120
|
+
}
|
|
121
|
+
function errorProperties(value) {
|
|
122
|
+
const record = value;
|
|
123
|
+
const properties = ['code', 'status', 'statusCode']
|
|
124
|
+
.flatMap((key) => {
|
|
125
|
+
const entry = record[key];
|
|
126
|
+
return typeof entry === 'string' || typeof entry === 'number' ? [`${key}: ${String(entry)}`] : [];
|
|
127
|
+
});
|
|
128
|
+
return properties.length === 0 ? undefined : properties.join(', ');
|
|
129
|
+
}
|
|
130
|
+
/** Format one Host failure for browser diagnostics without forwarding credentials or unbounded data. */
|
|
131
|
+
export function formatErrorDetail(error) {
|
|
132
|
+
const sections = [];
|
|
133
|
+
const seen = new Set();
|
|
134
|
+
let current = error;
|
|
135
|
+
for (let depth = 0; current !== undefined && depth < MAX_ERROR_CAUSE_DEPTH; depth += 1) {
|
|
136
|
+
if (typeof current === 'object' && current !== null) {
|
|
137
|
+
if (seen.has(current)) {
|
|
138
|
+
sections.push('Caused by: [circular error cause]');
|
|
139
|
+
current = undefined;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
seen.add(current);
|
|
143
|
+
}
|
|
144
|
+
const prefix = depth === 0 ? '' : 'Caused by: ';
|
|
145
|
+
if (current instanceof Error) {
|
|
146
|
+
const properties = errorProperties(current);
|
|
147
|
+
const rendered = current.stack ?? `${current.name}: ${current.message}`;
|
|
148
|
+
sections.push(`${prefix}${rendered}${properties === undefined ? '' : `\n${properties}`}`);
|
|
149
|
+
current = current.cause;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
sections.push(prefix + (typeof current === 'string'
|
|
153
|
+
? current
|
|
154
|
+
: inspect(current, {
|
|
155
|
+
breakLength: 120,
|
|
156
|
+
compact: false,
|
|
157
|
+
customInspect: false,
|
|
158
|
+
depth: 4,
|
|
159
|
+
maxArrayLength: 40,
|
|
160
|
+
maxStringLength: 4096,
|
|
161
|
+
sorted: true,
|
|
162
|
+
})));
|
|
163
|
+
current = undefined;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
if (current !== undefined)
|
|
167
|
+
sections.push('Caused by: [additional causes omitted]');
|
|
168
|
+
const redacted = redactErrorDetail(sections.join('\n'));
|
|
169
|
+
if (redacted.length <= MAX_ERROR_DETAIL_LENGTH)
|
|
170
|
+
return redacted;
|
|
171
|
+
return `${redacted.slice(0, MAX_ERROR_DETAIL_LENGTH)}\n[diagnostic truncated]`;
|
|
172
|
+
}
|
|
104
173
|
/** One ownership-scoped browser authorization connection. */
|
|
105
174
|
class OAuthConnection {
|
|
106
175
|
ctx;
|
|
@@ -124,7 +193,7 @@ class OAuthConnection {
|
|
|
124
193
|
this.queue = this.queue.then(() => this.receive(raw.toString())).catch((error) => {
|
|
125
194
|
this.ctx.logger.warn('dsh-oauth-adapter: command handling failed');
|
|
126
195
|
this.ctx.logger.warn(error);
|
|
127
|
-
this.sendError('operation-failed', 'the OAuth operation failed');
|
|
196
|
+
this.sendError('operation-failed', 'the OAuth operation failed', undefined, undefined, formatErrorDetail(error));
|
|
128
197
|
});
|
|
129
198
|
});
|
|
130
199
|
socket.on('close', () => {
|
|
@@ -150,11 +219,12 @@ class OAuthConnection {
|
|
|
150
219
|
if (this.socket.readyState === WebSocket.OPEN)
|
|
151
220
|
this.socket.send(JSON.stringify(message));
|
|
152
221
|
}
|
|
153
|
-
sendError(code, message, requestId, attemptId) {
|
|
222
|
+
sendError(code, message, requestId, attemptId, detail) {
|
|
154
223
|
this.send({
|
|
155
224
|
type: 'error', code, message,
|
|
156
225
|
...requestId === undefined ? {} : { requestId },
|
|
157
226
|
...attemptId === undefined ? {} : { attemptId },
|
|
227
|
+
...detail === undefined ? {} : { detail },
|
|
158
228
|
});
|
|
159
229
|
}
|
|
160
230
|
async receive(raw) {
|
|
@@ -226,7 +296,7 @@ class OAuthConnection {
|
|
|
226
296
|
catch (error) {
|
|
227
297
|
this.ctx.logger.warn('dsh-oauth-adapter: credential status read failed');
|
|
228
298
|
this.ctx.logger.warn(error);
|
|
229
|
-
this.sendError('operation-failed', 'account status is unavailable', requestId);
|
|
299
|
+
this.sendError('operation-failed', 'account status is unavailable', requestId, undefined, formatErrorDetail(error));
|
|
230
300
|
}
|
|
231
301
|
}
|
|
232
302
|
begin(command) {
|
|
@@ -278,14 +348,14 @@ class OAuthConnection {
|
|
|
278
348
|
catch (error) {
|
|
279
349
|
this.ctx.logger.warn('dsh-oauth-adapter: model route activation failed for %s', provider.id);
|
|
280
350
|
this.ctx.logger.warn(error);
|
|
281
|
-
this.sendError('model-route-unavailable', 'sign-in completed, but the OAuth model route could not be enabled', undefined, attempt.id);
|
|
351
|
+
this.sendError('model-route-unavailable', 'sign-in completed, but the OAuth model route could not be enabled', undefined, attempt.id, formatErrorDetail(error));
|
|
282
352
|
}
|
|
283
353
|
}
|
|
284
354
|
this.finish(attempt, outcome.status);
|
|
285
355
|
}, (error) => {
|
|
286
356
|
this.ctx.logger.warn('dsh-oauth-adapter: provider sign-in failed for %s', attempt.provider);
|
|
287
357
|
this.ctx.logger.warn(error);
|
|
288
|
-
this.sendError('sign-in-failed', 'sign-in failed
|
|
358
|
+
this.sendError('sign-in-failed', 'sign-in failed', undefined, attempt.id, formatErrorDetail(error));
|
|
289
359
|
this.finish(attempt, 'failed');
|
|
290
360
|
});
|
|
291
361
|
}
|
|
@@ -310,7 +380,7 @@ class OAuthConnection {
|
|
|
310
380
|
});
|
|
311
381
|
};
|
|
312
382
|
attempt.prompts.set(promptId, {
|
|
313
|
-
resolve: value => { finish(() => { resolve(value); }); },
|
|
383
|
+
resolve: value => { finish(() => { resolve(providerPromptAnswer(prompt, attempt.provider, value)); }); },
|
|
314
384
|
reject: reason => { finish(() => { reject(reason); }); },
|
|
315
385
|
});
|
|
316
386
|
prompt.signal?.addEventListener('abort', withdraw, { once: true });
|
|
@@ -370,7 +440,7 @@ class OAuthConnection {
|
|
|
370
440
|
catch (error) {
|
|
371
441
|
this.ctx.logger.warn('dsh-oauth-adapter: sign-out failed for %s', provider.id);
|
|
372
442
|
this.ctx.logger.warn(error);
|
|
373
|
-
this.sendError('operation-failed', 'sign-out failed
|
|
443
|
+
this.sendError('operation-failed', 'sign-out failed', command.requestId, undefined, formatErrorDetail(error));
|
|
374
444
|
}
|
|
375
445
|
}
|
|
376
446
|
finish(attempt, status) {
|
package/lib/protocol.d.ts
CHANGED
|
@@ -13,6 +13,31 @@ export declare const PROVIDERS: readonly [{
|
|
|
13
13
|
readonly key: "llm-pi-ai/github-copilot";
|
|
14
14
|
readonly fallbackLabel: "GitHub Copilot";
|
|
15
15
|
readonly modelGroupLabel: "GitHub Copilot (OAuth)";
|
|
16
|
+
}, {
|
|
17
|
+
readonly id: "anthropic";
|
|
18
|
+
readonly key: "llm-pi-ai/anthropic";
|
|
19
|
+
readonly fallbackLabel: "Anthropic";
|
|
20
|
+
readonly modelGroupLabel: "Anthropic (OAuth)";
|
|
21
|
+
}, {
|
|
22
|
+
readonly id: "kimi-coding";
|
|
23
|
+
readonly key: "llm-pi-ai/kimi-coding";
|
|
24
|
+
readonly fallbackLabel: "Kimi For Coding";
|
|
25
|
+
readonly modelGroupLabel: "Kimi For Coding (OAuth)";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "openrouter";
|
|
28
|
+
readonly key: "llm-pi-ai/openrouter";
|
|
29
|
+
readonly fallbackLabel: "OpenRouter";
|
|
30
|
+
readonly modelGroupLabel: "OpenRouter (OAuth)";
|
|
31
|
+
}, {
|
|
32
|
+
readonly id: "radius";
|
|
33
|
+
readonly key: "llm-pi-ai/radius";
|
|
34
|
+
readonly fallbackLabel: "Radius";
|
|
35
|
+
readonly modelGroupLabel: "Radius (OAuth)";
|
|
36
|
+
}, {
|
|
37
|
+
readonly id: "xai";
|
|
38
|
+
readonly key: "llm-pi-ai/xai";
|
|
39
|
+
readonly fallbackLabel: "xAI";
|
|
40
|
+
readonly modelGroupLabel: "xAI (OAuth)";
|
|
16
41
|
}];
|
|
17
42
|
export type ProviderId = (typeof PROVIDERS)[number]['id'];
|
|
18
43
|
export interface AccountView {
|
|
@@ -104,6 +129,8 @@ export type ServerMessage = {
|
|
|
104
129
|
attemptId?: string;
|
|
105
130
|
code: OAuthErrorCode;
|
|
106
131
|
message: string;
|
|
132
|
+
/** Bounded, credential-redacted Host diagnostic for optional UI expansion. */
|
|
133
|
+
detail?: string;
|
|
107
134
|
};
|
|
108
135
|
export type CommandParseResult = {
|
|
109
136
|
ok: true;
|
package/lib/protocol.js
CHANGED
|
@@ -12,6 +12,26 @@ export const PROVIDERS = [
|
|
|
12
12
|
id: 'github-copilot', key: 'llm-pi-ai/github-copilot', fallbackLabel: 'GitHub Copilot',
|
|
13
13
|
modelGroupLabel: 'GitHub Copilot (OAuth)',
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
id: 'anthropic', key: 'llm-pi-ai/anthropic', fallbackLabel: 'Anthropic',
|
|
17
|
+
modelGroupLabel: 'Anthropic (OAuth)',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'kimi-coding', key: 'llm-pi-ai/kimi-coding', fallbackLabel: 'Kimi For Coding',
|
|
21
|
+
modelGroupLabel: 'Kimi For Coding (OAuth)',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'openrouter', key: 'llm-pi-ai/openrouter', fallbackLabel: 'OpenRouter',
|
|
25
|
+
modelGroupLabel: 'OpenRouter (OAuth)',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'radius', key: 'llm-pi-ai/radius', fallbackLabel: 'Radius',
|
|
29
|
+
modelGroupLabel: 'Radius (OAuth)',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'xai', key: 'llm-pi-ai/xai', fallbackLabel: 'xAI',
|
|
33
|
+
modelGroupLabel: 'xAI (OAuth)',
|
|
34
|
+
},
|
|
15
35
|
];
|
|
16
36
|
const ID_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
|
|
17
37
|
function isRecord(value) {
|
|
@@ -19,6 +19,7 @@ export declare const en: {
|
|
|
19
19
|
readonly authorized: "Sign-in completed.";
|
|
20
20
|
readonly cancelled: "Sign-in was cancelled.";
|
|
21
21
|
readonly failed: "Sign-in failed.";
|
|
22
|
+
readonly technicalDetails: "Technical details";
|
|
22
23
|
readonly submit: "Continue";
|
|
23
24
|
readonly copy: "Copy code";
|
|
24
25
|
readonly copied: "Copied";
|
|
@@ -16,12 +16,14 @@ export interface AttemptView {
|
|
|
16
16
|
notice?: NoticeView;
|
|
17
17
|
prompt?: ActivePromptView;
|
|
18
18
|
error?: string;
|
|
19
|
+
errorDetail?: string;
|
|
19
20
|
}
|
|
20
21
|
export interface OAuthAccountsSnapshot {
|
|
21
22
|
connection: 'connecting' | 'open' | 'reconnecting' | 'closed';
|
|
22
23
|
accounts: readonly AccountView[];
|
|
23
24
|
attempt?: AttemptView;
|
|
24
25
|
error?: string;
|
|
26
|
+
errorDetail?: string;
|
|
25
27
|
}
|
|
26
28
|
type Listener = () => void;
|
|
27
29
|
/** Remove interaction-only content once an authorization attempt settles. */
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** Plugin-owned styles, injected and removed with the browser Cordis fiber. */
|
|
2
|
-
export declare const styles = "\n.dsh-oauth-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}\n.dsh-oauth-title{margin:0;font-size:16px;line-height:24px;font-weight:500}\n.dsh-oauth-intro,.dsh-oauth-muted{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}\n.dsh-oauth-error{margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}\n.dsh-oauth-list{display:flex;flex-direction:column;gap:8px;margin:4px 0 0;padding:0;list-style:none}\n.dsh-oauth-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}\n.dsh-oauth-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dsh-oauth-name{font-size:14px;font-weight:500}.dsh-oauth-state{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;color:var(--dsw-alias-label-secondary)}\n.dsh-oauth-dot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dsh-oauth-state[data-state=ready] .dsh-oauth-dot{background:var(--dsw-alias-state-success-primary)}.dsh-oauth-state[data-state=warning] .dsh-oauth-dot{background:var(--dsw-alias-state-error-primary)}.dsh-oauth-state[data-state=authorizing] .dsh-oauth-dot{background:var(--dsw-alias-button-info-fill)}\n.dsh-oauth-actions{display:flex;gap:6px;margin-left:auto}.dsh-oauth-button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:30px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:15px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;line-height:18px;cursor:pointer}.dsh-oauth-button[data-variant=primary]{border-color:transparent;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]{border-color:transparent;color:var(--dsw-alias-state-error-primary)}.dsh-oauth-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-button[data-variant=primary]:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.dsh-oauth-button:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.dsh-oauth-button:disabled{cursor:not-allowed;opacity:.4}\n.dsh-oauth-flow{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l3);font-size:13px;line-height:20px}.dsh-oauth-link{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);text-decoration:none}.dsh-oauth-link:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-link-label{font-weight:500}.dsh-oauth-link-host{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsh-oauth-link-icon{color:var(--dsw-alias-brand-text)}.dsh-oauth-code{display:flex;align-items:center;gap:8px}.dsh-oauth-code code{padding:5px 8px;border-radius:6px;background:var(--dsw-alias-bg-module-platform);font-size:14px;letter-spacing:.08em}\n.dsh-oauth-prompt{display:flex;flex-direction:column;gap:7px}.dsh-oauth-input,.dsh-oauth-select{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}\n";
|
|
2
|
+
export declare const styles = "\n.dsh-oauth-section{display:flex;flex-direction:column;gap:12px;max-width:720px;color:var(--dsw-alias-label-primary)}\n.dsh-oauth-title{margin:0;font-size:16px;line-height:24px;font-weight:500}\n.dsh-oauth-intro,.dsh-oauth-muted{margin:0;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}\n.dsh-oauth-error{display:flex;flex-direction:column;gap:6px;margin:0;padding:8px 10px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.dsh-oauth-error p{margin:0}.dsh-oauth-error pre{box-sizing:border-box;max-width:100%;max-height:320px;margin:0;padding:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;overflow:auto;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:11px/17px ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.dsh-oauth-error-details summary{cursor:pointer;color:var(--dsw-alias-label-secondary);user-select:none}.dsh-oauth-error-details[open] summary{margin-bottom:6px}\n.dsh-oauth-list{display:flex;flex-direction:column;gap:8px;margin:4px 0 0;padding:0;list-style:none}\n.dsh-oauth-card{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px}\n.dsh-oauth-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dsh-oauth-name{font-size:14px;font-weight:500}.dsh-oauth-state{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--dsw-alias-interactive-bg-hover);font-size:12px;color:var(--dsw-alias-label-secondary)}\n.dsh-oauth-dot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-tertiary)}.dsh-oauth-state[data-state=ready] .dsh-oauth-dot{background:var(--dsw-alias-state-success-primary)}.dsh-oauth-state[data-state=warning] .dsh-oauth-dot{background:var(--dsw-alias-state-error-primary)}.dsh-oauth-state[data-state=authorizing] .dsh-oauth-dot{background:var(--dsw-alias-button-info-fill)}\n.dsh-oauth-actions{display:flex;gap:6px;margin-left:auto}.dsh-oauth-button{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:30px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:15px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;line-height:18px;cursor:pointer}.dsh-oauth-button[data-variant=primary]{border-color:transparent;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]{border-color:transparent;color:var(--dsw-alias-state-error-primary)}.dsh-oauth-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-button[data-variant=primary]:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover);color:var(--dsw-alias-label-primary-foreground)}.dsh-oauth-button[data-variant=danger]:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.dsh-oauth-button:focus-visible{outline:none;box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.dsh-oauth-button:disabled{cursor:not-allowed;opacity:.4}\n.dsh-oauth-flow{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l3);font-size:13px;line-height:20px}.dsh-oauth-link{display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:8px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);text-decoration:none}.dsh-oauth-link:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.dsh-oauth-link-label{font-weight:500}.dsh-oauth-link-host{max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px}.dsh-oauth-link-icon{color:var(--dsw-alias-brand-text)}.dsh-oauth-code{display:flex;align-items:center;gap:8px}.dsh-oauth-code code{padding:5px 8px;border-radius:6px;background:var(--dsw-alias-bg-module-platform);font-size:14px;letter-spacing:.08em}\n.dsh-oauth-prompt{display:flex;flex-direction:column;gap:7px}.dsh-oauth-input,.dsh-oauth-select{box-sizing:border-box;width:100%;height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}\n";
|
|
3
3
|
//# sourceMappingURL=styles.d.ts.map
|
package/lib/types/protocol.d.ts
CHANGED
|
@@ -13,6 +13,31 @@ export declare const PROVIDERS: readonly [{
|
|
|
13
13
|
readonly key: "llm-pi-ai/github-copilot";
|
|
14
14
|
readonly fallbackLabel: "GitHub Copilot";
|
|
15
15
|
readonly modelGroupLabel: "GitHub Copilot (OAuth)";
|
|
16
|
+
}, {
|
|
17
|
+
readonly id: "anthropic";
|
|
18
|
+
readonly key: "llm-pi-ai/anthropic";
|
|
19
|
+
readonly fallbackLabel: "Anthropic";
|
|
20
|
+
readonly modelGroupLabel: "Anthropic (OAuth)";
|
|
21
|
+
}, {
|
|
22
|
+
readonly id: "kimi-coding";
|
|
23
|
+
readonly key: "llm-pi-ai/kimi-coding";
|
|
24
|
+
readonly fallbackLabel: "Kimi For Coding";
|
|
25
|
+
readonly modelGroupLabel: "Kimi For Coding (OAuth)";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "openrouter";
|
|
28
|
+
readonly key: "llm-pi-ai/openrouter";
|
|
29
|
+
readonly fallbackLabel: "OpenRouter";
|
|
30
|
+
readonly modelGroupLabel: "OpenRouter (OAuth)";
|
|
31
|
+
}, {
|
|
32
|
+
readonly id: "radius";
|
|
33
|
+
readonly key: "llm-pi-ai/radius";
|
|
34
|
+
readonly fallbackLabel: "Radius";
|
|
35
|
+
readonly modelGroupLabel: "Radius (OAuth)";
|
|
36
|
+
}, {
|
|
37
|
+
readonly id: "xai";
|
|
38
|
+
readonly key: "llm-pi-ai/xai";
|
|
39
|
+
readonly fallbackLabel: "xAI";
|
|
40
|
+
readonly modelGroupLabel: "xAI (OAuth)";
|
|
16
41
|
}];
|
|
17
42
|
export type ProviderId = (typeof PROVIDERS)[number]['id'];
|
|
18
43
|
export interface AccountView {
|
|
@@ -104,6 +129,8 @@ export type ServerMessage = {
|
|
|
104
129
|
attemptId?: string;
|
|
105
130
|
code: OAuthErrorCode;
|
|
106
131
|
message: string;
|
|
132
|
+
/** Bounded, credential-redacted Host diagnostic for optional UI expansion. */
|
|
133
|
+
detail?: string;
|
|
107
134
|
};
|
|
108
135
|
export type CommandParseResult = {
|
|
109
136
|
ok: true;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edge-sky/dsh-oauth-adapter",
|
|
3
3
|
"description": "Web OAuth account surface for official DSH authorization flows",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2-beta.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "edge-sky",
|
|
7
7
|
"url": "https://github.com/edge-sky"
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
},
|
|
12
12
|
"repository": {
|
|
13
13
|
"type": "git",
|
|
14
|
-
"url": "git+https://github.com/edge-sky/dsh-oauth.git"
|
|
14
|
+
"url": "git+https://github.com/edge-sky/dsh-oauth-adapter.git"
|
|
15
15
|
},
|
|
16
|
+
"packageManager": "pnpm@11.7.0",
|
|
16
17
|
"engines": {
|
|
17
18
|
"node": "^22.19.0 || >=24.0.0"
|
|
18
19
|
},
|
|
@@ -44,6 +45,13 @@
|
|
|
44
45
|
"lib/**/*.js",
|
|
45
46
|
"lib/**/*.d.ts"
|
|
46
47
|
],
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsdown && pnpm run build:host && pnpm run build:client:types",
|
|
50
|
+
"build:host": "tsc -p tsconfig.json",
|
|
51
|
+
"build:client:types": "tsc -p tsconfig.client.json",
|
|
52
|
+
"test": "pnpm run build && vitest run",
|
|
53
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit"
|
|
54
|
+
},
|
|
47
55
|
"license": "MIT",
|
|
48
56
|
"dsh": {
|
|
49
57
|
"bundle": {
|
|
@@ -60,16 +68,17 @@
|
|
|
60
68
|
},
|
|
61
69
|
"peerDependencies": {
|
|
62
70
|
"@deepseek-ai/cordis": ">=4.0.1",
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
"@deepseek-ai/dsh-client-
|
|
65
|
-
"@deepseek-ai/dsh-client-
|
|
66
|
-
"@deepseek-ai/dsh-client-ui-
|
|
67
|
-
"@deepseek-ai/dsh-
|
|
68
|
-
"@deepseek-ai/dsh-
|
|
69
|
-
"@deepseek-ai/dsh-
|
|
70
|
-
"@deepseek-ai/dsh-
|
|
71
|
-
"@deepseek-ai/dsh-llm
|
|
72
|
-
"@deepseek-ai/dsh-
|
|
71
|
+
"@deepseek-ai/dsh-authorization": ">=0.1.1-rc.2 <0.2.0-0",
|
|
72
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.1-rc.2 <0.2.0-0",
|
|
73
|
+
"@deepseek-ai/dsh-client-runtime": ">=0.1.1-rc.2 <0.2.0-0",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.1.1-rc.2 <0.2.0-0",
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.1-rc.2 <0.2.0-0",
|
|
76
|
+
"@deepseek-ai/dsh-credentials": ">=0.1.1-rc.2 <0.2.0-0",
|
|
77
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.1-rc.2 <0.2.0-0",
|
|
78
|
+
"@deepseek-ai/dsh-invariants": ">=0.1.1-rc.2 <0.2.0-0",
|
|
79
|
+
"@deepseek-ai/dsh-llm": ">=0.1.1-rc.2 <0.2.0-0",
|
|
80
|
+
"@deepseek-ai/dsh-llm-pi-ai": ">=0.1.1-rc.2 <0.2.0-0",
|
|
81
|
+
"@deepseek-ai/dsh-settings": ">=0.1.1-rc.2 <0.2.0-0",
|
|
73
82
|
"react": ">=18.2.0"
|
|
74
83
|
},
|
|
75
84
|
"peerDependenciesMeta": {
|
|
@@ -111,12 +120,12 @@
|
|
|
111
120
|
}
|
|
112
121
|
},
|
|
113
122
|
"dependencies": {
|
|
114
|
-
"@deepseek-ai/dsh-authorization": ">=0.1.1-rc.2",
|
|
115
123
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
116
124
|
"ws": "^8.18.3"
|
|
117
125
|
},
|
|
118
126
|
"devDependencies": {
|
|
119
127
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
128
|
+
"@deepseek-ai/dsh-authorization": "0.1.1-rc.2",
|
|
120
129
|
"@deepseek-ai/dsh-client-locale": "0.1.1-rc.2",
|
|
121
130
|
"@deepseek-ai/dsh-client-runtime": "0.1.1-rc.2",
|
|
122
131
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.1-rc.2",
|
|
@@ -136,12 +145,5 @@
|
|
|
136
145
|
"tsdown": "^0.22.2",
|
|
137
146
|
"typescript": "^6.0.3",
|
|
138
147
|
"vitest": "^4.1.8"
|
|
139
|
-
},
|
|
140
|
-
"scripts": {
|
|
141
|
-
"build": "tsdown && pnpm run build:host && pnpm run build:client:types",
|
|
142
|
-
"build:host": "tsc -p tsconfig.json",
|
|
143
|
-
"build:client:types": "tsc -p tsconfig.client.json",
|
|
144
|
-
"test": "pnpm run build && vitest run",
|
|
145
|
-
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit"
|
|
146
148
|
}
|
|
147
|
-
}
|
|
149
|
+
}
|