@eddyskywalker/dsh-chatgpt-subscription 0.13.2 → 0.15.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +76 -8
  3. package/lib/client.js +183 -115
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +1110 -76
  6. package/lib/types/client/CodexSubscriptionSection.d.ts +1 -1
  7. package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
  8. package/lib/types/client/ProviderHubSection.d.ts.map +1 -1
  9. package/lib/types/client/api.d.ts +12 -0
  10. package/lib/types/client/api.d.ts.map +1 -1
  11. package/lib/types/client/claude/ClaudeSection.d.ts.map +1 -1
  12. package/lib/types/client/claude/locales.d.ts +2 -11
  13. package/lib/types/client/claude/locales.d.ts.map +1 -1
  14. package/lib/types/client/locales.d.ts +13 -1
  15. package/lib/types/client/locales.d.ts.map +1 -1
  16. package/lib/types/host/claude/model-catalog.d.ts +42 -20
  17. package/lib/types/host/claude/model-catalog.d.ts.map +1 -1
  18. package/lib/types/host/claude/types.d.ts +7 -2
  19. package/lib/types/host/claude/types.d.ts.map +1 -1
  20. package/lib/types/host/codex-account-pool.d.ts +129 -1
  21. package/lib/types/host/codex-account-pool.d.ts.map +1 -1
  22. package/lib/types/host/codex-adopt.d.ts +255 -0
  23. package/lib/types/host/codex-adopt.d.ts.map +1 -0
  24. package/lib/types/host/reasoning-collapse-guard/index.d.ts +166 -0
  25. package/lib/types/host/reasoning-collapse-guard/index.d.ts.map +1 -1
  26. package/lib/types/host/routes.d.ts +11 -1
  27. package/lib/types/host/routes.d.ts.map +1 -1
  28. package/lib/types/host/token-store.d.ts +26 -1
  29. package/lib/types/host/token-store.d.ts.map +1 -1
  30. package/lib/types/host/workbuddy/client.d.ts +1 -1
  31. package/lib/types/host/workbuddy/client.d.ts.map +1 -1
  32. package/lib/types/host/workbuddy/model-catalog.d.ts +77 -4
  33. package/lib/types/host/workbuddy/model-catalog.d.ts.map +1 -1
  34. package/lib/types/host/workbuddy/routes.d.ts +7 -1
  35. package/lib/types/host/workbuddy/routes.d.ts.map +1 -1
  36. package/lib/types/index.d.ts.map +1 -1
  37. package/lib/types/shared/contracts.d.ts +22 -0
  38. package/lib/types/shared/contracts.d.ts.map +1 -1
  39. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -685,6 +685,22 @@ window.__ModuleLoader__.load({
685
685
  ...body
686
686
  });
687
687
  }
688
+ /**
689
+ * Import this machine's Codex CLI sign-in, answering with the refreshed status.
690
+ *
691
+ * The body names the source rather than the URL carrying it, so the host can
692
+ * refuse a sign-in it does not import with a sentence instead of a silent
693
+ * no-op. The type is 'codex' alone on purpose: Claude Code and MiniMax Code are
694
+ * imported from their own provider settings, and a union here would invite a
695
+ * call the host always answers with a 400.
696
+ */
697
+ adoptLocalLogin(source) {
698
+ return post$2(`${ROUTE_PREFIX}/adopt`, { source });
699
+ }
700
+ /** Forget every imported snapshot. The CLIs' own files are never touched. */
701
+ disableAdoptedLocalLogins() {
702
+ return post$2(`${ROUTE_PREFIX}/adopt/disable`, {});
703
+ }
688
704
  refresh() {
689
705
  return post$2(`${ROUTE_PREFIX}/token/refresh`, {});
690
706
  }
@@ -1436,6 +1452,38 @@ window.__ModuleLoader__.load({
1436
1452
  setStatus(next);
1437
1453
  });
1438
1454
  };
1455
+ /**
1456
+ * Forget every imported snapshot: the undo for the local sign-in import below.
1457
+ *
1458
+ * ONE control for the whole pool rather than one per row, because the host's
1459
+ * route deliberately ignores an accountId and clears every imported row at once.
1460
+ * That is not an oversight to route around: the pool refuses to delete an
1461
+ * adopted credential, so a per-row control here could only ever be a button that
1462
+ * silently clears its neighbours — a worse bug than offering no button at all.
1463
+ * The Codex CLI's own file is not deleted, rewritten or moved by this; it only
1464
+ * makes this plugin forget the copy it took.
1465
+ */
1466
+ const stopImporting = async () => {
1467
+ await run("adopt-disable", async () => {
1468
+ setStatus(await apiRef.current.disableAdoptedLocalLogins());
1469
+ });
1470
+ };
1471
+ /**
1472
+ * Copy this machine's Codex CLI sign-in into the pool as a snapshot.
1473
+ *
1474
+ * The status is re-read rather than taken from the route's answer: the route
1475
+ * answers with the pool's refreshed status, which knows nothing about the
1476
+ * CLI file, so adopting from its value would flip the block to "not detected"
1477
+ * one click after the import succeeded. The file is still there — the import
1478
+ * copies it — so /status is the answer that tells the truth, and the row the
1479
+ * account just created comes back with it.
1480
+ */
1481
+ const importLocalSignIn = async () => {
1482
+ await run("adopt", async () => {
1483
+ await apiRef.current.adoptLocalLogin("codex");
1484
+ await load(true);
1485
+ });
1486
+ };
1439
1487
  const setRotationStrategy = async (strategy) => {
1440
1488
  await run("strategy", async () => {
1441
1489
  const next = await apiRef.current.accountAction("strategy", { strategy });
@@ -1472,6 +1520,7 @@ window.__ModuleLoader__.load({
1472
1520
  setBusy(null);
1473
1521
  }
1474
1522
  };
1523
+ const importedAccounts = (status?.accounts ?? []).filter((account) => account.removable === false);
1475
1524
  status?.account;
1476
1525
  const preferences = status?.preferences;
1477
1526
  const quota = status?.quota;
@@ -1515,6 +1564,21 @@ window.__ModuleLoader__.load({
1515
1564
  onRelogin: (accountId) => relogin(accountId),
1516
1565
  onSetStrategy: (strategy) => void setRotationStrategy(strategy),
1517
1566
  showQuota: true,
1567
+ renderLoginActions: () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1568
+ className: "dsha-account-add-actions",
1569
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1570
+ className: "dsha-btn dsha-btn-primary",
1571
+ disabled: busy !== null,
1572
+ onClick: () => void startLogin(),
1573
+ children: login?.active ? t("pending") : t("addAccount")
1574
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1575
+ className: "dsha-btn",
1576
+ disabled: busy !== null,
1577
+ "aria-label": t("localCodexLoginImport"),
1578
+ onClick: () => void importLocalSignIn(),
1579
+ children: busy === "adopt" ? t("localCodexLoginImporting") : t("localCodexLoginImport")
1580
+ })]
1581
+ }),
1518
1582
  renderDetails: (entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: entry.planLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
1519
1583
  t("plan"),
1520
1584
  ": ",
@@ -1548,7 +1612,21 @@ window.__ModuleLoader__.load({
1548
1612
  onClick: refreshToken,
1549
1613
  children: t("refreshToken")
1550
1614
  }) : null]
1551
- })
1615
+ }),
1616
+ importedAccounts.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1617
+ className: "dsha-muted",
1618
+ children: formatPoolLabel(t("stopImportingHint"), { count: importedAccounts.length })
1619
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1620
+ className: "dsha-actions",
1621
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1622
+ className: "dsha-btn",
1623
+ type: "button",
1624
+ disabled: busy !== null,
1625
+ "aria-label": formatPoolLabel(t("stopImportingLabel"), { count: importedAccounts.length }),
1626
+ onClick: () => void stopImporting(),
1627
+ children: busy === "adopt-disable" ? t("stopImportingBusy") : t("stopImporting")
1628
+ })
1629
+ })] }) : null
1552
1630
  ]
1553
1631
  }),
1554
1632
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
@@ -7143,9 +7221,6 @@ window.__ModuleLoader__.load({
7143
7221
  importClaudeCode: "导入本机 Claude Code 登录态",
7144
7222
  importing: "导入中...",
7145
7223
  stopImporting: "停止导入",
7146
- importHint: "读取本机 Claude Code 的登录凭据,作为只读快照加入账号池。不会修改、移动或删除 Claude Code 自己的文件,停止导入只是让本插件忘记这份快照。",
7147
- importUnavailable: "未找到可导入的本机 Claude Code 登录态。",
7148
- importSearched: "查找位置:{paths}",
7149
7224
  connection: "连接",
7150
7225
  testConnection: "测试连接",
7151
7226
  testingConnection: "测试中...",
@@ -7263,9 +7338,6 @@ window.__ModuleLoader__.load({
7263
7338
  importClaudeCode: "Import the local Claude Code sign-in",
7264
7339
  importing: "Importing...",
7265
7340
  stopImporting: "Stop importing",
7266
- importHint: "Reads the local Claude Code credential and adds it to the account pool as a read-only snapshot. Claude Code's own file is never modified, moved or deleted; stopping the import only makes this plugin forget the snapshot.",
7267
- importUnavailable: "No usable local Claude Code sign-in was found.",
7268
- importSearched: "Searched: {paths}",
7269
7341
  connection: "Connection",
7270
7342
  testConnection: "Test connection",
7271
7343
  testingConnection: "Testing...",
@@ -7919,118 +7991,102 @@ window.__ModuleLoader__.load({
7919
7991
  entry.source === "claude-code" ? t.sourceClaudeCode : t.sourceManaged
7920
7992
  ] })
7921
7993
  ] }),
7922
- children: [
7923
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7924
- className: "dsha-muted",
7925
- style: { paddingTop: 12 },
7926
- children: t.importHint
7927
- }),
7928
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7929
- className: "dsha-muted",
7930
- children: status?.claudeCodeSignInAvailable === true ? t.importClaudeCode : t.importUnavailable
7931
- }),
7932
- status?.claudeCodePaths !== void 0 && status.claudeCodePaths.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7933
- className: "dsha-muted dshcl-mono",
7934
- children: t.importSearched.replace("{paths}", status.claudeCodePaths.join(" · "))
7935
- }),
7936
- hasAdopted && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7937
- className: "dsha-actions",
7938
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7939
- className: "dsha-btn",
7940
- disabled: busy !== null,
7941
- "aria-label": t.stopImporting,
7942
- onClick: () => void stopImporting(),
7943
- children: busy === "adopt-disable" ? t.importing : t.stopImporting
7944
- })
7945
- }),
7946
- flow !== null && flow.status !== "idle" && flow.status !== "complete" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7947
- className: "dshcl-flow",
7948
- children: [
7949
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.signInSection }),
7950
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7951
- className: "dsha-muted",
7952
- children: flow?.status === "error" ? `${t.loginFailed}: ${flow.error ?? ""}` : flow?.status === "exchanging" ? t.loginExchanging : flow?.mode === "manual" ? t.loginModeManual : t.loginModeLoopback
7953
- }),
7954
- flow?.hint !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7955
- className: "dsha-muted",
7956
- children: flow.hint
7994
+ children: [hasAdopted && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7995
+ className: "dsha-actions",
7996
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7997
+ className: "dsha-btn",
7998
+ disabled: busy !== null,
7999
+ "aria-label": t.stopImporting,
8000
+ onClick: () => void stopImporting(),
8001
+ children: busy === "adopt-disable" ? t.importing : t.stopImporting
8002
+ })
8003
+ }), flow !== null && flow.status !== "idle" && flow.status !== "complete" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8004
+ className: "dshcl-flow",
8005
+ children: [
8006
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.signInSection }),
8007
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8008
+ className: "dsha-muted",
8009
+ children: flow?.status === "error" ? `${t.loginFailed}: ${flow.error ?? ""}` : flow?.status === "exchanging" ? t.loginExchanging : flow?.mode === "manual" ? t.loginModeManual : t.loginModeLoopback
8010
+ }),
8011
+ flow?.hint !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8012
+ className: "dsha-muted",
8013
+ children: flow.hint
8014
+ }),
8015
+ flow?.fallbackReason !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8016
+ className: "dsha-notice",
8017
+ children: t.loginFallbackReason.replace("{detail}", flow.fallbackReason)
8018
+ }),
8019
+ flow?.authUrl !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
8020
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8021
+ className: "dsha-label",
8022
+ children: t.authorizeUrl
7957
8023
  }),
7958
- flow?.fallbackReason !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7959
- className: "dsha-notice",
7960
- children: t.loginFallbackReason.replace("{detail}", flow.fallbackReason)
8024
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
8025
+ className: "dshcl-flow-url",
8026
+ children: flow.authUrl
7961
8027
  }),
7962
- flow?.authUrl !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
7963
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7964
- className: "dsha-label",
7965
- children: t.authorizeUrl
7966
- }),
7967
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
7968
- className: "dshcl-flow-url",
7969
- children: flow.authUrl
7970
- }),
7971
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7972
- className: "dsha-actions",
7973
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
7974
- className: "dsha-btn",
7975
- href: flow.authUrl,
7976
- target: "_blank",
7977
- rel: "noreferrer noopener",
7978
- children: t.openAuthorizeUrl
7979
- })
8028
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8029
+ className: "dsha-actions",
8030
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
8031
+ className: "dsha-btn",
8032
+ href: flow.authUrl,
8033
+ target: "_blank",
8034
+ rel: "noreferrer noopener",
8035
+ children: t.openAuthorizeUrl
7980
8036
  })
7981
- ] }),
7982
- flow?.redirectUri !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7983
- className: "dsha-row",
7984
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7985
- className: "dsha-label",
7986
- children: t.redirectUri
7987
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7988
- className: "dsha-value dshcl-mono",
7989
- children: flow.redirectUri
7990
- })]
7991
- }),
7992
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7993
- className: "dshcl-paste",
7994
- children: [
7995
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.manualPasteSection }),
7996
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7997
- className: "dsha-muted",
7998
- children: t.manualPasteHint
7999
- }),
8000
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8001
- className: "dshcl-paste-row",
8002
- children: [
8003
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8004
- type: "text",
8005
- className: "dsha-select",
8006
- "aria-label": t.manualPasteSection,
8007
- placeholder: t.manualPastePlaceholder,
8008
- value: pasteValue,
8009
- disabled: busy !== null,
8010
- onChange: (event) => setPasteValue(event.currentTarget.value),
8011
- onKeyDown: (event) => {
8012
- if (event.key === "Enter") submitPaste();
8013
- }
8014
- }),
8015
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8016
- className: "dsha-btn dsha-btn-primary",
8017
- disabled: busy !== null || pasteValue.trim() === "",
8018
- onClick: () => void submitPaste(),
8019
- children: busy === "login-input" ? t.manualPasteSubmitting : t.manualPasteSubmit
8020
- }),
8021
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8022
- className: "dsha-btn",
8023
- disabled: busy !== null,
8024
- onClick: () => void cancelLogin(),
8025
- children: t.cancelSignIn
8026
- })
8027
- ]
8028
- })
8029
- ]
8030
8037
  })
8031
- ]
8032
- })
8033
- ]
8038
+ ] }),
8039
+ flow?.redirectUri !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8040
+ className: "dsha-row",
8041
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8042
+ className: "dsha-label",
8043
+ children: t.redirectUri
8044
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8045
+ className: "dsha-value dshcl-mono",
8046
+ children: flow.redirectUri
8047
+ })]
8048
+ }),
8049
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8050
+ className: "dshcl-paste",
8051
+ children: [
8052
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.manualPasteSection }),
8053
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8054
+ className: "dsha-muted",
8055
+ children: t.manualPasteHint
8056
+ }),
8057
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8058
+ className: "dshcl-paste-row",
8059
+ children: [
8060
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8061
+ type: "text",
8062
+ className: "dsha-select",
8063
+ "aria-label": t.manualPasteSection,
8064
+ placeholder: t.manualPastePlaceholder,
8065
+ value: pasteValue,
8066
+ disabled: busy !== null,
8067
+ onChange: (event) => setPasteValue(event.currentTarget.value),
8068
+ onKeyDown: (event) => {
8069
+ if (event.key === "Enter") submitPaste();
8070
+ }
8071
+ }),
8072
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8073
+ className: "dsha-btn dsha-btn-primary",
8074
+ disabled: busy !== null || pasteValue.trim() === "",
8075
+ onClick: () => void submitPaste(),
8076
+ children: busy === "login-input" ? t.manualPasteSubmitting : t.manualPasteSubmit
8077
+ }),
8078
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8079
+ className: "dsha-btn",
8080
+ disabled: busy !== null,
8081
+ onClick: () => void cancelLogin(),
8082
+ children: t.cancelSignIn
8083
+ })
8084
+ ]
8085
+ })
8086
+ ]
8087
+ })
8088
+ ]
8089
+ })]
8034
8090
  }),
8035
8091
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
8036
8092
  className: "dsha-group",
@@ -9334,6 +9390,12 @@ window.__ModuleLoader__.load({
9334
9390
  hubSwitchOn: "启用 {name}",
9335
9391
  hubSwitchOff: "停用 {name}",
9336
9392
  hubCardLabel: "{name},{annotation}",
9393
+ localCodexLoginImport: "导入本机 Codex CLI 登录",
9394
+ localCodexLoginImporting: "导入中…",
9395
+ stopImporting: "停止导入全部本机登录",
9396
+ stopImportingLabel: "停止导入全部本机登录(当前 {count} 个)",
9397
+ stopImportingBusy: "停止导入中…",
9398
+ stopImportingHint: "停止导入只会让本插件忘记本机 CLI 登录的副本;Codex CLI 自己的登录文件不会被删除或修改。账号池不允许逐条删除借来的凭据,所以这里一次会停止全部导入。",
9337
9399
  modelChecklistCount: "已启用 {count}/{total}"
9338
9400
  },
9339
9401
  en: {
@@ -9484,6 +9546,12 @@ window.__ModuleLoader__.load({
9484
9546
  hubSwitchOn: "Enable {name}",
9485
9547
  hubSwitchOff: "Disable {name}",
9486
9548
  hubCardLabel: "{name}, {annotation}",
9549
+ localCodexLoginImport: "Import the local Codex CLI sign-in",
9550
+ localCodexLoginImporting: "Importing…",
9551
+ stopImporting: "Stop importing all local sign-ins",
9552
+ stopImportingLabel: "Stop importing all local sign-ins ({count} currently imported)",
9553
+ stopImportingBusy: "Stopping the import…",
9554
+ stopImportingHint: "Stopping the import only makes this plugin forget its copy of the local CLI sign-in; the Codex CLI own sign-in file is never deleted or changed. The account pool does not allow deleting a borrowed credential one at a time, so this stops every import at once.",
9487
9555
  modelChecklistCount: "{count}/{total} enabled"
9488
9556
  }
9489
9557
  };