dsh-opendesign-corouter 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,7 +32,7 @@ dsh plugin --profile web add dsh-opendesign-corouter
32
32
  也可打开 [Actions → CI](https://github.com/KouzakiUmi/dsh-opendesign-corouter/actions/workflows/ci.yml),从成功构建下载 **`dsh-opendesign-corouter-build`** artifact。登录 GitHub 后解压 ZIP,取得 `.tgz` 与 `.sha256`,再安装本地包:
33
33
 
34
34
  ```console
35
- dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.5.tgz
35
+ dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.6.tgz
36
36
  ```
37
37
 
38
38
  `web` 只是示例,请替换为目标 Profile。Desktop 使用桌面安装器提供的 `dsh` 入口;独立公共 CLI 不能代管保留的 `desktop` Profile。安装后的启用与重载按目标 DSH 的管理流程进行。
@@ -40,7 +40,7 @@ dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.5.tgz
40
40
  ### 2. 配置连接
41
41
 
42
42
  1. 打开 **设置 → OpenDesign CoRouter → 连接与登录**。
43
- 2. 点击 **开始设备授权**,再用 **在新窗口打开授权页** 显示官方页面,核对授权码并确认;也可复制链接到你自己的常用浏览器,或单独配置工作空间 API Key / 沿用 `COROUTER_API_KEY`。
43
+ 2. 点击 **开始设备授权**,取得授权码后自动打开临时 Chrome 官方授权页,核对并确认;打开失败可用 **在新窗口打开授权页** 重试,也可复制链接到常用浏览器,或单独配置工作空间 API Key / 沿用 `COROUTER_API_KEY`。
44
44
  3. 返回设置页等待保存成功。额度默认优先读取桌面登录态;要明确使用设备授权的账号,可关闭桌面优先。
45
45
  4. 回到模型选择器,选择 **OpenDesign CoRouter · 套餐赠送** 或 **OpenDesign CoRouter · 付费模型**。
46
46
 
@@ -52,8 +52,8 @@ dsh plugin --profile web add /absolute/path/to/dsh-opendesign-corouter-0.1.5.tgz
52
52
 
53
53
  | Provider | 模型数 | 用途 |
54
54
  | --- | ---: | --- |
55
- | `opendesign-corouter-plan` | 12 | 官网 Design Plan 套餐赠送模型 |
56
- | `opendesign-corouter-paid` | 21 | 其余公开对话模型 |
55
+ | `opendesign-corouter-plan` | 13 | Core / Design Plan 附赠通道,含预检确认覆盖的 MiniMax M3.1 Flash |
56
+ | `opendesign-corouter-paid` | 25 | Plan 套餐模型及其他钱包付费模型 |
57
57
 
58
58
  上表为内置目录。模型页可从 OpenAI `/models` 端口刷新,逐个启用或停用模型,并配置温度、top-p、默认输出上限、上下文预算及思考深度。停用同时影响模型选择器和直接调用;参数会保存并应用到实际请求。媒体生成接口不在对话目录中,未知能力不按名称猜测。
59
59
 
package/lib/catalog.d.ts CHANGED
@@ -16,16 +16,17 @@
16
16
  * 分组语义(重要):`plan`/`paid` 是**本插件本地目录分类**,用于把“套餐赠送通道”与
17
17
  * “其余付费通道”拆成两个 Provider,不是上游强制计费契约。最终可用性、扣哪个额度池、
18
18
  * 是否先扣 Design Plan 额度再用套餐模型/钱包额度,全部由服务端按账号套餐决定。
19
- * `paid` 21 款里只有 8 款出现在官网套餐可抵扣名单,其余 13 款同样可经钱包/按量付费调用,
20
- * 因此 `paid` 收录 21 款而不是 13 款。
19
+ * 2026-10-27 官方 GET /v1/models 实测补齐五个 ID,现为 plan 13 + paid 25。
20
+ * 同日桌面 Vela 按模型 billing preflight:M3.1 Flash 的 modelCovered=true /
21
+ * funding=coding_plan,新增于附赠通道;其余四项为 false / wallet,归付费通道。
22
+ * 此分类以当次工作区证据为依据,不保证其他账号或未来套餐权益。
23
+ * 新增项证据及名称来源见 docs/client-evidence.md;不从型号名推断能力。
21
24
  *
22
- * 未收录(证据不足,不猜测):
23
- * - 套餐模型组中尚未公开精确 ID 的 `Muse Spark 1.3`、`Gemini 4 Argon`:
24
- * 前者详情页没有 `data-model`/模型 ID,后者在模型目录里没有详情页。
25
+ * 未收录:
25
26
  * - 媒体模型 `GPT Image 2`、`Nano Banana 2`、`Seedream 5 Lite / Pro`:
26
27
  * 走 `/api/v1/media/*`,不应出现在对话模型列表里,避免选中后 chat 请求必败。
27
28
  *
28
- * `paid` 21 款的能力字段一律缺省:既没有官网数值,也没有可信默认表,
29
+ * `paid` 25 款及新增 M3.1 Flash 的能力字段一律缺省:没有可核实的能力数值,
29
30
  * 不按名称推断图像能力,也不给未知项填 `['text']` 谎称不支持图像。
30
31
  */
31
32
  export interface CatalogModel {
@@ -38,8 +39,8 @@ export interface CatalogModel {
38
39
  reasoningEfforts?: readonly string[];
39
40
  }
40
41
  /**
41
- * 顺序按供应商分组(与官网模型目录导航一致);`plan` 为 Design Plan 额度覆盖的 12 款,
42
- * 其余 21 款公开对话模型归 `paid`。
42
+ * `plan` 为官网 12 款 Core / Design Plan 模型,加预检确认覆盖的 M3.1 Flash;
43
+ * 其余 25 项归 `paid`(Plan / 钱包付费通道)。
43
44
  */
44
45
  export declare const MODELS: readonly CatalogModel[];
45
46
  export declare function modelsFor(group: 'plan' | 'paid'): readonly CatalogModel[];
package/lib/client.js CHANGED
@@ -19927,22 +19927,29 @@ function record2(value) {
19927
19927
  }
19928
19928
 
19929
19929
  // src/device-auth.ts
19930
- function validateActivationUrl(value, userCode) {
19930
+ function validateActivationUrl(value, userCode, deviceId) {
19931
19931
  if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
19932
19932
  try {
19933
19933
  const url2 = new URL(value);
19934
19934
  if (url2.origin !== "https://open-design.ai" || url2.pathname !== "/cloud/cli/activate" || url2.username || url2.password || url2.hash) return null;
19935
19935
  const entries = [...url2.searchParams];
19936
- if (entries.length > 1) return null;
19937
- if (entries.length) {
19936
+ if (entries.length === 2) {
19937
+ if (entries.some(([key]) => key !== "deviceId" && key !== "userCode")) return null;
19938
+ const id = url2.searchParams.get("deviceId");
19939
+ const code = url2.searchParams.get("userCode");
19940
+ if (!validDeviceId(id) || !validUserCode(code) || deviceId !== void 0 && id !== deviceId || userCode !== void 0 && code !== userCode) return null;
19941
+ } else if (entries.length === 1) {
19938
19942
  const entry = entries[0];
19939
19943
  if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
19940
- }
19944
+ } else if (entries.length > 2) return null;
19941
19945
  return url2.href;
19942
19946
  } catch {
19943
19947
  return null;
19944
19948
  }
19945
19949
  }
19950
+ function validDeviceId(value) {
19951
+ return typeof value === "string" && /^[a-z0-9_-]{1,200}$/iu.test(value);
19952
+ }
19946
19953
  function validUserCode(value) {
19947
19954
  return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
19948
19955
  }
@@ -21154,6 +21161,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21154
21161
  const [activationNotice, setActivationNotice] = React.useState(null);
21155
21162
  const activationJob = React.useRef(null);
21156
21163
  const activationToken = React.useRef(0);
21164
+ const autoOpenPending = React.useRef(false);
21157
21165
  React.useEffect(() => () => {
21158
21166
  actionVersion.current += 1;
21159
21167
  }, []);
@@ -21172,6 +21180,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21172
21180
  if (status === void 0 || busy || keyBusy) return;
21173
21181
  const version2 = ++actionVersion.current;
21174
21182
  setBusy(true);
21183
+ autoOpenPending.current = true;
21175
21184
  setNotice({ kind: "status", text: "\u6B63\u5728\u7533\u8BF7\u8BBE\u5907\u6388\u6743\u2026" });
21176
21185
  try {
21177
21186
  const next = await caller("startLogin", { expectedRevision: status.revision });
@@ -21180,6 +21189,7 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21180
21189
  setActivationNotice(null);
21181
21190
  await (next.state === "success" ? refreshAfterLogin() : loadStatus());
21182
21191
  } catch {
21192
+ autoOpenPending.current = false;
21183
21193
  if (mounted.current && version2 === actionVersion.current) setNotice({ kind: "error", text: "\u65E0\u6CD5\u542F\u52A8\u767B\u5F55\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002" });
21184
21194
  } finally {
21185
21195
  if (mounted.current && version2 === actionVersion.current) setBusy(false);
@@ -21240,6 +21250,15 @@ function Connection({ status, formSnapshot, setFormField, pendingField, caller,
21240
21250
  if (mounted.current && activationToken.current === token) setOpening(false);
21241
21251
  }
21242
21252
  };
21253
+ React.useEffect(() => {
21254
+ if (!autoOpenPending.current || busy || keyBusy) return;
21255
+ if (state === "waiting") {
21256
+ autoOpenPending.current = false;
21257
+ void openActivation();
21258
+ } else if (state === "error" || state === "cancelled" || state === "success") {
21259
+ autoOpenPending.current = false;
21260
+ }
21261
+ }, [state, login?.jobId, busy, keyBusy]);
21243
21262
  const desktopChecked = formSnapshot.value?.useDesktopCredential ?? status?.config.useDesktopCredential ?? true;
21244
21263
  return h(
21245
21264
  React.Fragment,
@@ -3,7 +3,7 @@ export interface DeviceTokens {
3
3
  runtimeKey: string;
4
4
  }
5
5
  export declare const DEVICE_AUTH_ENDPOINT = "https://amr-api.open-design.ai/api/v1/cli/device-authorizations";
6
- export declare const DEVICE_AUTH_PLUGIN_VERSION = "0.1.5";
6
+ export declare const DEVICE_AUTH_PLUGIN_VERSION = "0.1.6";
7
7
  export declare const DEVICE_REQUEST_TIMEOUT_MS = 20000;
8
8
  /** One bounded launch step of the temporary activation window. */
9
9
  export declare const DEVICE_OPEN_TIMEOUT_MS = 30000;
@@ -14,8 +14,8 @@ export declare class DeviceAuthError extends Error {
14
14
  readonly code: string;
15
15
  constructor(code: string);
16
16
  }
17
- /** Strict public-link allowlist: only an optional, single, non-secret code is allowed. */
18
- export declare function validateActivationUrl(value: unknown, userCode?: string): string | null;
17
+ /** Strict public-link allowlist: a legacy code or the public deviceId/userCode pair. */
18
+ export declare function validateActivationUrl(value: unknown, userCode?: string, deviceId?: string): string | null;
19
19
  export interface DeviceAuthorization {
20
20
  deviceId: string;
21
21
  deviceSecret: string;
@@ -8,22 +8,29 @@ function record(value) {
8
8
  }
9
9
 
10
10
  // src/device-auth.ts
11
- function validateActivationUrl(value, userCode) {
11
+ function validateActivationUrl(value, userCode, deviceId) {
12
12
  if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
13
13
  try {
14
14
  const url = new URL(value);
15
15
  if (url.origin !== "https://open-design.ai" || url.pathname !== "/cloud/cli/activate" || url.username || url.password || url.hash) return null;
16
16
  const entries = [...url.searchParams];
17
- if (entries.length > 1) return null;
18
- if (entries.length) {
17
+ if (entries.length === 2) {
18
+ if (entries.some(([key]) => key !== "deviceId" && key !== "userCode")) return null;
19
+ const id = url.searchParams.get("deviceId");
20
+ const code = url.searchParams.get("userCode");
21
+ if (!validDeviceId(id) || !validUserCode(code) || deviceId !== void 0 && id !== deviceId || userCode !== void 0 && code !== userCode) return null;
22
+ } else if (entries.length === 1) {
19
23
  const entry = entries[0];
20
24
  if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
21
- }
25
+ } else if (entries.length > 2) return null;
22
26
  return url.href;
23
27
  } catch {
24
28
  return null;
25
29
  }
26
30
  }
31
+ function validDeviceId(value) {
32
+ return typeof value === "string" && /^[a-z0-9_-]{1,200}$/iu.test(value);
33
+ }
27
34
  function validUserCode(value) {
28
35
  return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
29
36
  }
@@ -8,22 +8,29 @@ function record(value) {
8
8
  }
9
9
 
10
10
  // src/device-auth.ts
11
- function validateActivationUrl(value, userCode) {
11
+ function validateActivationUrl(value, userCode, deviceId) {
12
12
  if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
13
13
  try {
14
14
  const url = new URL(value);
15
15
  if (url.origin !== "https://open-design.ai" || url.pathname !== "/cloud/cli/activate" || url.username || url.password || url.hash) return null;
16
16
  const entries = [...url.searchParams];
17
- if (entries.length > 1) return null;
18
- if (entries.length) {
17
+ if (entries.length === 2) {
18
+ if (entries.some(([key]) => key !== "deviceId" && key !== "userCode")) return null;
19
+ const id = url.searchParams.get("deviceId");
20
+ const code = url.searchParams.get("userCode");
21
+ if (!validDeviceId(id) || !validUserCode(code) || deviceId !== void 0 && id !== deviceId || userCode !== void 0 && code !== userCode) return null;
22
+ } else if (entries.length === 1) {
19
23
  const entry = entries[0];
20
24
  if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
21
- }
25
+ } else if (entries.length > 2) return null;
22
26
  return url.href;
23
27
  } catch {
24
28
  return null;
25
29
  }
26
30
  }
31
+ function validDeviceId(value) {
32
+ return typeof value === "string" && /^[a-z0-9_-]{1,200}$/iu.test(value);
33
+ }
27
34
  function validUserCode(value) {
28
35
  return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
29
36
  }
package/lib/index.js CHANGED
@@ -159,7 +159,7 @@ var MODELS = [
159
159
  reasoningEfforts: EFFORTS_LOW_HIGH
160
160
  },
161
161
  { id: "glm-5.2", name: "GLM-5.2", group: "paid" },
162
- // ── Moonshot(2) ───────────────────────────────────────────
162
+ // ── Moonshot(3) ───────────────────────────────────────────
163
163
  {
164
164
  id: "kimi-k2.7-code",
165
165
  name: "Kimi K2.7 Code",
@@ -170,7 +170,9 @@ var MODELS = [
170
170
  reasoningEfforts: EFFORTS_STD
171
171
  },
172
172
  { id: "kimi-k3", name: "Kimi K3", group: "paid" },
173
- // ── Google(2) ─────────────────────────────────────────────
173
+ { id: "kimi-k3.1-pro", name: "Kimi K3.1 Pro", group: "paid" },
174
+ // ── Google(3) ─────────────────────────────────────────────
175
+ { id: "gemini-4-argon", name: "Gemini 4 Argon", group: "paid" },
174
176
  { id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", group: "paid" },
175
177
  { id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", group: "paid" },
176
178
  // ── xAI(3) ────────────────────────────────────────────────
@@ -207,7 +209,11 @@ var MODELS = [
207
209
  reasoningEfforts: EFFORTS_STD
208
210
  },
209
211
  // ── Alibaba(1) ────────────────────────────────────────────
210
- { id: "qwen3.7-max", name: "Qwen3.7 Max", group: "paid" }
212
+ { id: "qwen3.7-max", name: "Qwen3.7 Max", group: "paid" },
213
+ // Official API additions; display labels for undocumented entries are local formatting.
214
+ { id: "minimax-m3.1-flash", name: "MiniMax M3.1 Flash", group: "plan" },
215
+ { id: "muse-spark-1.3", name: "Muse Spark 1.3", group: "paid" },
216
+ { id: "muse-wonder", name: "Muse Wonder", group: "paid" }
211
217
  ];
212
218
  var BY_ID = new Map(MODELS.map((model) => [model.id, model]));
213
219
  function findModel(id) {
@@ -2194,7 +2200,7 @@ import { randomUUID } from "node:crypto";
2194
2200
 
2195
2201
  // src/device-auth.ts
2196
2202
  var DEVICE_AUTH_ENDPOINT = "https://amr-api.open-design.ai/api/v1/cli/device-authorizations";
2197
- var DEVICE_AUTH_PLUGIN_VERSION = "0.1.5";
2203
+ var DEVICE_AUTH_PLUGIN_VERSION = "0.1.6";
2198
2204
  var DEVICE_REQUEST_TIMEOUT_MS = 2e4;
2199
2205
  var DEVICE_RESPONSE_MAX_BYTES = 65536;
2200
2206
  var DEVICE_POLL_MIN_MS = 1e3;
@@ -2206,17 +2212,21 @@ var DeviceAuthError = class extends Error {
2206
2212
  }
2207
2213
  code;
2208
2214
  };
2209
- function validateActivationUrl(value, userCode) {
2215
+ function validateActivationUrl(value, userCode, deviceId) {
2210
2216
  if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
2211
2217
  try {
2212
2218
  const url = new URL(value);
2213
2219
  if (url.origin !== "https://open-design.ai" || url.pathname !== "/cloud/cli/activate" || url.username || url.password || url.hash) return null;
2214
2220
  const entries = [...url.searchParams];
2215
- if (entries.length > 1) return null;
2216
- if (entries.length) {
2221
+ if (entries.length === 2) {
2222
+ if (entries.some(([key]) => key !== "deviceId" && key !== "userCode")) return null;
2223
+ const id = url.searchParams.get("deviceId");
2224
+ const code = url.searchParams.get("userCode");
2225
+ if (!validDeviceId(id) || !validUserCode(code) || deviceId !== void 0 && id !== deviceId || userCode !== void 0 && code !== userCode) return null;
2226
+ } else if (entries.length === 1) {
2217
2227
  const entry = entries[0];
2218
2228
  if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
2219
- }
2229
+ } else if (entries.length > 2) return null;
2220
2230
  return url.href;
2221
2231
  } catch {
2222
2232
  return null;
@@ -2225,6 +2235,9 @@ function validateActivationUrl(value, userCode) {
2225
2235
  function object(value) {
2226
2236
  return value !== null && typeof value === "object" && !Array.isArray(value);
2227
2237
  }
2238
+ function validDeviceId(value) {
2239
+ return typeof value === "string" && /^[a-z0-9_-]{1,200}$/iu.test(value);
2240
+ }
2228
2241
  function validUserCode(value) {
2229
2242
  return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
2230
2243
  }
@@ -2232,8 +2245,8 @@ function secret(value) {
2232
2245
  return typeof value === "string" && value.length > 0 && value.length <= 8192 && /^[\x21-\x7e]+$/u.test(value);
2233
2246
  }
2234
2247
  function parseDeviceAuthorization(value) {
2235
- if (!object(value) || typeof value.deviceId !== "string" || !/^[a-z0-9_-]{1,200}$/iu.test(value.deviceId) || !secret(value.deviceSecret) || !validUserCode(value.userCode)) throw new DeviceAuthError("opendesign/login-response");
2236
- const activationUrl = validateActivationUrl(value.activationUrl, value.userCode);
2248
+ if (!object(value) || !validDeviceId(value.deviceId) || !secret(value.deviceSecret) || !validUserCode(value.userCode)) throw new DeviceAuthError("opendesign/login-response");
2249
+ const activationUrl = validateActivationUrl(value.activationUrl, value.userCode, value.deviceId);
2237
2250
  if (!activationUrl || value.userCode.toLowerCase().includes(value.deviceSecret.toLowerCase()) || decodeURIComponent(activationUrl).toLowerCase().includes(value.deviceSecret.toLowerCase())) throw new DeviceAuthError("opendesign/login-response");
2238
2251
  const expiresAt = typeof value.expiresAt === "string" && /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d{1,3})?(?:Z|[+-]\d\d:\d\d)$/u.test(value.expiresAt) ? Date.parse(value.expiresAt) : NaN;
2239
2252
  if (!Number.isFinite(expiresAt) || typeof value.pollIntervalSeconds !== "number" || !Number.isFinite(value.pollIntervalSeconds) || value.pollIntervalSeconds <= 0) throw new DeviceAuthError("opendesign/login-response");
@@ -2252,6 +2265,7 @@ function parseDevicePoll(value) {
2252
2265
  if (["expired", "cancelled", "canceled", "denied", "rejected", "failed", "error"].includes(state)) throw new DeviceAuthError(state === "expired" ? "opendesign/login-expired" : "opendesign/login-denied");
2253
2266
  if (value.error !== void 0 && value.error !== null && value.error !== "") throw new DeviceAuthError("opendesign/login-response");
2254
2267
  const user = object(value.user) ? value.user : {};
2268
+ if ((state === "pending" || state === "authorization_pending") && [value.controlKey, value.runtimeKey, user.controlKey, user.runtimeKey].every((key) => key === void 0 || key === null)) return { state: "pending" };
2255
2269
  const topPresent = value.controlKey !== void 0 || value.runtimeKey !== void 0;
2256
2270
  const source = topPresent ? value : user;
2257
2271
  if (source.controlKey !== void 0 || source.runtimeKey !== void 0) {