@eddyskywalker/dsh-chatgpt-subscription 0.1.0 → 0.1.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 +10 -0
- package/lib/client.js +236 -1
- package/lib/client.js.map +1 -1
- package/lib/index.js +207 -23
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/process-folding.d.ts +5 -0
- package/lib/types/client/process-folding.d.ts.map +1 -0
- package/lib/types/client/styles.d.ts.map +1 -1
- package/lib/types/host/responses-client.d.ts +4 -1
- package/lib/types/host/responses-client.d.ts.map +1 -1
- package/lib/types/host/responses-mapper.d.ts +7 -1
- package/lib/types/host/responses-mapper.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.2 - 2026-08-16
|
|
4
|
+
|
|
5
|
+
- 优化过程详情折叠(Process folding)的初始化时机与节点匹配探测逻辑。
|
|
6
|
+
- 增强客户端 DOM 观察与挂载测试用例覆盖。
|
|
7
|
+
|
|
8
|
+
## 0.1.1 - 2026-08-16
|
|
9
|
+
|
|
10
|
+
- 新增执行过程详情与思考过程的可折叠展示机制(Collapsible process detail folding)。
|
|
11
|
+
- 增强客户端与服务端 Responses 过程解析及 UI 交互。
|
|
12
|
+
|
|
3
13
|
## 0.1.0 - 2026-08-16
|
|
4
14
|
|
|
5
15
|
- 首个正式版本发布。
|
package/lib/client.js
CHANGED
|
@@ -592,6 +592,233 @@ window.__ModuleLoader__.load({
|
|
|
592
592
|
}
|
|
593
593
|
};
|
|
594
594
|
//#endregion
|
|
595
|
+
//#region src/client/process-folding.ts
|
|
596
|
+
const ROW_CLASS = "dsh-codex-process-row";
|
|
597
|
+
const GROUP_HEAD_CLASS = "dsh-codex-process-group-head";
|
|
598
|
+
const GROUP_COLLAPSED_CLASS = "dsh-codex-process-group-collapsed";
|
|
599
|
+
const GROUP_HIDDEN_CLASS = "dsh-codex-process-group-hidden";
|
|
600
|
+
const USER_TOGGLED_ATTR = "data-dsh-codex-process-user-toggled";
|
|
601
|
+
const TITLE_ATTR = "data-dsh-codex-process-title";
|
|
602
|
+
const TITLE = "Click to expand or collapse process details";
|
|
603
|
+
const DEFAULT_AUTO_COLLAPSE_MS = 2500;
|
|
604
|
+
const MAX_PROCESS_LABELS_PER_ROW = 3;
|
|
605
|
+
const MAX_SCAN_ROOTS_PER_FRAME = 80;
|
|
606
|
+
const MAX_TEXT_SAMPLE = 2e4;
|
|
607
|
+
const PROCESS_CANDIDATE_SELECTOR = "article,section,li,div,p,h1,h2,h3,h4,h5,h6,[role=\"listitem\"]";
|
|
608
|
+
const PROCESS_PREFIX_PATTERN = "(?:上下文注入|Think|Search|Code|代码|Pwsh|PowerShell|Bash|Shell|Read|Glob|Grep|Web(?:\\s+Search)?|Tool|工具|思考)";
|
|
609
|
+
const COMMAND_PATTERN = /(?:Code|代码|Pwsh|PowerShell|Bash|Shell|Read|Glob|Grep|Tool|工具)/i;
|
|
610
|
+
const SEARCH_PATTERN = /(?:Search|Web\s+Search|搜索)/i;
|
|
611
|
+
const PROCESS_PREFIX_RE = new RegExp(`^\\s*(?:[•●◦▪▫·#-]\\s*)?${PROCESS_PREFIX_PATTERN}\\s*(?:[·::-]|$)`, "i");
|
|
612
|
+
const PROCESS_LINE_RE = new RegExp(`(?:^|\\n)\\s*(?:[•●◦▪▫·#-]\\s*)?${PROCESS_PREFIX_PATTERN}\\s*(?:[·::-]|$)`, "gi");
|
|
613
|
+
function installProcessFolding(options = {}) {
|
|
614
|
+
if (typeof document === "undefined") return () => void 0;
|
|
615
|
+
if (document.body === null) {
|
|
616
|
+
let dispose = () => void 0;
|
|
617
|
+
let started = false;
|
|
618
|
+
const start = () => {
|
|
619
|
+
if (started) return;
|
|
620
|
+
started = true;
|
|
621
|
+
dispose = installProcessFolding(options);
|
|
622
|
+
};
|
|
623
|
+
document.addEventListener("DOMContentLoaded", start, { once: true });
|
|
624
|
+
return () => {
|
|
625
|
+
document.removeEventListener("DOMContentLoaded", start);
|
|
626
|
+
dispose();
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
const autoCollapseMs = options.autoCollapseMs ?? DEFAULT_AUTO_COLLAPSE_MS;
|
|
630
|
+
const groups = /* @__PURE__ */ new Map();
|
|
631
|
+
const pending = /* @__PURE__ */ new Set();
|
|
632
|
+
let frame = null;
|
|
633
|
+
const scheduleFlush = () => {
|
|
634
|
+
if (frame !== null) return;
|
|
635
|
+
frame = requestAnimationFrame(() => {
|
|
636
|
+
frame = null;
|
|
637
|
+
flush();
|
|
638
|
+
});
|
|
639
|
+
};
|
|
640
|
+
const queue = (element) => {
|
|
641
|
+
if (element === null || !element.isConnected) return;
|
|
642
|
+
pending.add(element);
|
|
643
|
+
scheduleFlush();
|
|
644
|
+
};
|
|
645
|
+
const scheduleAutoCollapse = (head) => {
|
|
646
|
+
const state = groups.get(head);
|
|
647
|
+
if (state === void 0 || head.hasAttribute(USER_TOGGLED_ATTR)) return;
|
|
648
|
+
if (state.timer !== null) clearTimeout(state.timer);
|
|
649
|
+
state.timer = setTimeout(() => {
|
|
650
|
+
state.timer = null;
|
|
651
|
+
if (head.isConnected && !head.hasAttribute(USER_TOGGLED_ATTR)) setGroupCollapsed(head, true);
|
|
652
|
+
}, autoCollapseMs);
|
|
653
|
+
};
|
|
654
|
+
const syncGroup = (rows, previous) => {
|
|
655
|
+
const head = rows[0];
|
|
656
|
+
const title = titleForProcessRows(rows);
|
|
657
|
+
const click = (event) => {
|
|
658
|
+
if (isInteractiveTarget(event.target)) return;
|
|
659
|
+
markUserToggled(head);
|
|
660
|
+
setGroupCollapsed(head, !head.classList.contains(GROUP_COLLAPSED_CLASS));
|
|
661
|
+
};
|
|
662
|
+
const keydown = (event) => {
|
|
663
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
664
|
+
event.preventDefault();
|
|
665
|
+
markUserToggled(head);
|
|
666
|
+
setGroupCollapsed(head, !head.classList.contains(GROUP_COLLAPSED_CLASS));
|
|
667
|
+
};
|
|
668
|
+
groups.set(head, {
|
|
669
|
+
rows,
|
|
670
|
+
click,
|
|
671
|
+
keydown,
|
|
672
|
+
timer: null
|
|
673
|
+
});
|
|
674
|
+
for (const row of rows) row.classList.add(ROW_CLASS);
|
|
675
|
+
head.classList.add(GROUP_HEAD_CLASS);
|
|
676
|
+
if (!head.hasAttribute("tabindex")) head.tabIndex = 0;
|
|
677
|
+
head.setAttribute("aria-expanded", String(!(previous?.collapsed ?? false)));
|
|
678
|
+
head.setAttribute(TITLE_ATTR, title);
|
|
679
|
+
head.title ||= TITLE;
|
|
680
|
+
if (previous?.userToggled === true) head.setAttribute(USER_TOGGLED_ATTR, "true");
|
|
681
|
+
head.addEventListener("click", click);
|
|
682
|
+
head.addEventListener("keydown", keydown);
|
|
683
|
+
setGroupCollapsed(head, previous?.collapsed ?? false);
|
|
684
|
+
scheduleAutoCollapse(head);
|
|
685
|
+
};
|
|
686
|
+
const rebuildParentGroups = (parent) => {
|
|
687
|
+
const previous = /* @__PURE__ */ new Map();
|
|
688
|
+
for (const [head, state] of groups) {
|
|
689
|
+
if (head.parentElement !== parent) continue;
|
|
690
|
+
previous.set(head, {
|
|
691
|
+
collapsed: head.classList.contains(GROUP_COLLAPSED_CLASS),
|
|
692
|
+
userToggled: head.hasAttribute(USER_TOGGLED_ATTR)
|
|
693
|
+
});
|
|
694
|
+
cleanupGroup(head, state);
|
|
695
|
+
groups.delete(head);
|
|
696
|
+
}
|
|
697
|
+
let rows = [];
|
|
698
|
+
const flushRows = () => {
|
|
699
|
+
if (rows.length > 0) syncGroup(rows, previous.get(rows[0]));
|
|
700
|
+
rows = [];
|
|
701
|
+
};
|
|
702
|
+
for (const child of Array.from(parent.children)) if (child instanceof HTMLElement && isProcessRow(child)) rows.push(child);
|
|
703
|
+
else flushRows();
|
|
704
|
+
flushRows();
|
|
705
|
+
};
|
|
706
|
+
const flush = () => {
|
|
707
|
+
const parents = /* @__PURE__ */ new Set();
|
|
708
|
+
let scanned = 0;
|
|
709
|
+
for (const root of Array.from(pending)) {
|
|
710
|
+
pending.delete(root);
|
|
711
|
+
if (!root.isConnected) continue;
|
|
712
|
+
for (const row of findProcessRows(root)) if (row.parentElement !== null) parents.add(row.parentElement);
|
|
713
|
+
const grouped = nearestGroupHead(root);
|
|
714
|
+
if (grouped !== null && grouped.parentElement !== null) parents.add(grouped.parentElement);
|
|
715
|
+
scanned++;
|
|
716
|
+
if (scanned >= MAX_SCAN_ROOTS_PER_FRAME && pending.size > 0) {
|
|
717
|
+
scheduleFlush();
|
|
718
|
+
break;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
for (const parent of parents) rebuildParentGroups(parent);
|
|
722
|
+
};
|
|
723
|
+
const observer = new MutationObserver((mutations) => {
|
|
724
|
+
for (const mutation of mutations) {
|
|
725
|
+
if (mutation.type === "characterData") {
|
|
726
|
+
queue(nodeElement(mutation.target)?.closest(PROCESS_CANDIDATE_SELECTOR) ?? nodeElement(mutation.target));
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
for (const node of mutation.addedNodes) queue(nodeElement(node));
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
observer.observe(document.body, {
|
|
733
|
+
childList: true,
|
|
734
|
+
characterData: true,
|
|
735
|
+
subtree: true
|
|
736
|
+
});
|
|
737
|
+
queue(document.body);
|
|
738
|
+
return () => {
|
|
739
|
+
observer.disconnect();
|
|
740
|
+
if (frame !== null) cancelAnimationFrame(frame);
|
|
741
|
+
pending.clear();
|
|
742
|
+
for (const [head, state] of groups) cleanupGroup(head, state);
|
|
743
|
+
groups.clear();
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
function cleanupGroup(head, state) {
|
|
747
|
+
if (state.timer !== null) clearTimeout(state.timer);
|
|
748
|
+
head.removeEventListener("click", state.click);
|
|
749
|
+
head.removeEventListener("keydown", state.keydown);
|
|
750
|
+
for (const row of state.rows) row.classList.remove(ROW_CLASS, GROUP_HIDDEN_CLASS);
|
|
751
|
+
head.classList.remove(GROUP_HEAD_CLASS, GROUP_COLLAPSED_CLASS);
|
|
752
|
+
head.removeAttribute("aria-expanded");
|
|
753
|
+
head.removeAttribute(USER_TOGGLED_ATTR);
|
|
754
|
+
head.removeAttribute(TITLE_ATTR);
|
|
755
|
+
if (head.title === TITLE) head.removeAttribute("title");
|
|
756
|
+
}
|
|
757
|
+
function findProcessRows(root) {
|
|
758
|
+
const rows = [];
|
|
759
|
+
if (root instanceof HTMLElement && isProcessRow(root)) rows.push(root);
|
|
760
|
+
for (const element of root.querySelectorAll(PROCESS_CANDIDATE_SELECTOR)) if (element instanceof HTMLElement && isProcessRow(element)) rows.push(element);
|
|
761
|
+
return rows;
|
|
762
|
+
}
|
|
763
|
+
function isProcessRow(element) {
|
|
764
|
+
if (element.closest(".dsh-codex-page") !== null || shouldIgnore(element)) return false;
|
|
765
|
+
const raw = (element.textContent ?? "").slice(0, MAX_TEXT_SAMPLE);
|
|
766
|
+
const normalized = raw.replace(/\s+/g, " ").trim();
|
|
767
|
+
if (!PROCESS_PREFIX_RE.test(normalized)) return false;
|
|
768
|
+
const stats = processTextStats(raw);
|
|
769
|
+
if (stats.processLabels === 0 || stats.processLabels > MAX_PROCESS_LABELS_PER_ROW) return false;
|
|
770
|
+
return !(element.children.length > 0 && stats.hasNonProcessLine);
|
|
771
|
+
}
|
|
772
|
+
function processTextStats(text) {
|
|
773
|
+
PROCESS_LINE_RE.lastIndex = 0;
|
|
774
|
+
let processLabels = 0;
|
|
775
|
+
while (PROCESS_LINE_RE.exec(text) !== null) processLabels++;
|
|
776
|
+
const hasNonProcessLine = text.split(/\r?\n/).map((line) => line.replace(/\s+/g, " ").trim()).some((line) => line !== "" && !PROCESS_PREFIX_RE.test(line));
|
|
777
|
+
return {
|
|
778
|
+
processLabels,
|
|
779
|
+
hasNonProcessLine
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
function setGroupCollapsed(head, collapsed) {
|
|
783
|
+
const state = findCurrentGroupState(head);
|
|
784
|
+
if (state === null) return;
|
|
785
|
+
head.classList.toggle(GROUP_COLLAPSED_CLASS, collapsed);
|
|
786
|
+
head.setAttribute("aria-expanded", String(!collapsed));
|
|
787
|
+
for (const row of state.rows.slice(1)) row.classList.toggle(GROUP_HIDDEN_CLASS, collapsed);
|
|
788
|
+
}
|
|
789
|
+
function findCurrentGroupState(head) {
|
|
790
|
+
const rows = [head];
|
|
791
|
+
let sibling = head.nextElementSibling;
|
|
792
|
+
while (sibling instanceof HTMLElement && isProcessRow(sibling)) {
|
|
793
|
+
rows.push(sibling);
|
|
794
|
+
sibling = sibling.nextElementSibling;
|
|
795
|
+
}
|
|
796
|
+
return rows.length > 0 ? { rows } : null;
|
|
797
|
+
}
|
|
798
|
+
function markUserToggled(head) {
|
|
799
|
+
head.setAttribute(USER_TOGGLED_ATTR, "true");
|
|
800
|
+
}
|
|
801
|
+
function nearestGroupHead(element) {
|
|
802
|
+
const decorated = element.closest(`.${GROUP_HEAD_CLASS}`);
|
|
803
|
+
return decorated instanceof HTMLElement ? decorated : null;
|
|
804
|
+
}
|
|
805
|
+
function titleForProcessRows(rows) {
|
|
806
|
+
const text = rows.map((row) => row.textContent ?? "").join("\n");
|
|
807
|
+
if (COMMAND_PATTERN.test(text)) return "运行了命令";
|
|
808
|
+
if (SEARCH_PATTERN.test(text)) return "进行了搜索";
|
|
809
|
+
return "思考过程";
|
|
810
|
+
}
|
|
811
|
+
function nodeElement(node) {
|
|
812
|
+
if (node instanceof Element) return node;
|
|
813
|
+
return node.parentElement;
|
|
814
|
+
}
|
|
815
|
+
function shouldIgnore(element) {
|
|
816
|
+
return element.closest("textarea,input,select,button,a,[contenteditable=\"true\"],script,style") !== null;
|
|
817
|
+
}
|
|
818
|
+
function isInteractiveTarget(target) {
|
|
819
|
+
return target instanceof Element && target.closest("button,a,input,textarea,select,[role=\"button\"],[contenteditable=\"true\"]") !== null;
|
|
820
|
+
}
|
|
821
|
+
//#endregion
|
|
595
822
|
//#region src/client/styles.ts
|
|
596
823
|
const STYLE_ID = "@eddyskywalker/dsh-chatgpt-subscription/main";
|
|
597
824
|
const CSS = `
|
|
@@ -636,9 +863,16 @@ window.__ModuleLoader__.load({
|
|
|
636
863
|
.dsh-codex-skeleton span{animation:dsh-codex-pulse 1.4s ease-in-out infinite;background:var(--dsw-alias-bg-layer-2);border-radius:5px;height:42px}
|
|
637
864
|
.dsh-codex-skeleton span:nth-child(2){animation-delay:.12s}.dsh-codex-skeleton span:nth-child(3){animation-delay:.24s}
|
|
638
865
|
.dsh-codex-sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0 0 0 0);white-space:nowrap}
|
|
866
|
+
.dsh-codex-process-group-head{border-radius:6px;cursor:pointer;transition:background-color .15s ease,opacity .15s ease}
|
|
867
|
+
.dsh-codex-process-group-head:hover{background:color-mix(in srgb,var(--dsw-alias-bg-layer-2,rgba(127,127,127,.18)) 72%,transparent)}
|
|
868
|
+
.dsh-codex-process-group-head:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
869
|
+
.dsh-codex-process-group-head.dsh-codex-process-group-collapsed{align-items:center!important;color:transparent!important;display:flex!important;font-size:0!important;line-height:28px!important;max-height:28px!important;min-height:28px!important;overflow:hidden!important;opacity:.78}
|
|
870
|
+
.dsh-codex-process-group-head.dsh-codex-process-group-collapsed>*{display:none!important}
|
|
871
|
+
.dsh-codex-process-group-head.dsh-codex-process-group-collapsed::before{color:var(--dsw-alias-label-secondary);content:"▸ " attr(data-dsh-codex-process-title);display:block;font-size:13px;line-height:28px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
872
|
+
.dsh-codex-process-group-hidden{display:none!important}
|
|
639
873
|
@keyframes dsh-codex-pulse{0%,100%{opacity:.55}50%{opacity:1}}
|
|
640
874
|
@media(max-width:560px){.dsh-codex-row{align-items:flex-start;flex-direction:column;gap:3px}.dsh-codex-value{text-align:left}.dsh-codex-actions{justify-content:flex-start}.dsh-codex-grouphead{align-items:flex-start;flex-direction:column;gap:0;padding:12px 0}.dsh-codex-meter-meta{align-items:flex-start;flex-direction:column;gap:2px}.dsh-codex-errorbar{align-items:flex-start;flex-direction:column}}
|
|
641
|
-
@media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}
|
|
875
|
+
@media(prefers-reduced-motion:reduce){.dsh-codex-meter>span,.dsh-codex-process-group-head{transition:none}.dsh-codex-skeleton span{animation:none}}
|
|
642
876
|
`;
|
|
643
877
|
function installStyles() {
|
|
644
878
|
if (document.querySelector(`style[data-plugin-css="${STYLE_ID}"]`) !== null) return () => void 0;
|
|
@@ -655,6 +889,7 @@ window.__ModuleLoader__.load({
|
|
|
655
889
|
function apply(ctx) {
|
|
656
890
|
ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");
|
|
657
891
|
ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
|
|
892
|
+
ctx.effect(() => installProcessFolding(), "dsh-chatgpt-subscription: process folding");
|
|
658
893
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
659
894
|
name: "settings.section",
|
|
660
895
|
id: "codex-subscription",
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../src/compat.ts","../src/client/api.ts","../src/client/CodexSubscriptionSection.tsx","../src/client/locales.ts","../src/client/styles.ts","../src/client/index.tsx"],"sourcesContent":["/**\n * Compatibility constants for the ChatGPT-backed Codex flow. The backend and\n * OAuth parameters are not a public third-party API contract, so every such\n * value is isolated here for review and rollback.\n */\nexport const CHATGPT_OAUTH_ISSUER = 'https://auth.openai.com' as const\nexport const CHATGPT_OAUTH_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann' as const\nexport const OAUTH_CALLBACK_HOST = 'localhost' as const\nexport const OAUTH_CALLBACK_PORT = 1455 as const\nexport const OAUTH_CALLBACK_PATH = '/auth/callback' as const\nexport const OAUTH_REDIRECT_URI = `http://${OAUTH_CALLBACK_HOST}:${OAUTH_CALLBACK_PORT}${OAUTH_CALLBACK_PATH}` as const\nexport const OAUTH_SCOPE = 'openid profile email offline_access' as const\nexport const OAUTH_ORIGINATOR = 'opencode' as const\nexport const OAUTH_LOGIN_TIMEOUT_MS = 5 * 60_000\nexport const TOKEN_REFRESH_MARGIN_MS = 60_000\nexport const ROUTE_PREFIX = '/api/dsh-chatgpt-subscription' as const\nexport const PLUGIN_VERSION = '0.1.0-alpha.0' as const\n\nexport const CODEX_API_BASE = 'https://chatgpt.com/backend-api/codex' as const\nexport const CODEX_RESPONSES_URL = `${CODEX_API_BASE}/responses` as const\nexport const CODEX_USAGE_URL = 'https://chatgpt.com/backend-api/wham/usage' as const\nexport const CODEX_ORIGINATOR = 'opencode' as const\nexport const QUOTA_CACHE_MS = 60_000\nexport const QUOTA_MIN_UPSTREAM_INTERVAL_MS = 15_000\n\nexport const OAUTH_AUTHORIZE_URL = `${CHATGPT_OAUTH_ISSUER}/oauth/authorize` as const\nexport const OAUTH_TOKEN_URL = `${CHATGPT_OAUTH_ISSUER}/oauth/token` as const\n","import { ROUTE_PREFIX } from '../compat.ts'\nimport type {\n ApiEnvelope,\n LoginEventDto,\n LoginStartDto,\n PluginStatusDto,\n QuotaStatusDto,\n ConnectionTestDto,\n} from '../shared/contracts.ts'\n\nexport class SubscriptionApi {\n status(): Promise<PluginStatusDto> {\n return request<PluginStatusDto>(`${ROUTE_PREFIX}/status`)\n }\n\n startLogin(): Promise<LoginStartDto> {\n return post<LoginStartDto>(`${ROUTE_PREFIX}/login/start`, {})\n }\n\n cancelLogin(loginId: string): Promise<{ cancelled: boolean }> {\n return post(`${ROUTE_PREFIX}/login/cancel`, { loginId })\n }\n\n logout(): Promise<{ authenticated: false }> {\n return post(`${ROUTE_PREFIX}/logout`, {})\n }\n\n refresh(): Promise<PluginStatusDto> {\n return post(`${ROUTE_PREFIX}/token/refresh`, {})\n }\n\n refreshQuota(): Promise<QuotaStatusDto> {\n return post(`${ROUTE_PREFIX}/quota/refresh`, {})\n }\n\n testConnection(): Promise<ConnectionTestDto> {\n return post(`${ROUTE_PREFIX}/connection/test`, {})\n }\n\n events(loginId: string): EventSource {\n return new EventSource(`${ROUTE_PREFIX}/login/events?loginId=${encodeURIComponent(loginId)}`)\n }\n}\n\nasync function post<T>(url: string, body: Record<string, unknown>): Promise<T> {\n return request<T>(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n}\n\nasync function request<T>(url: string, init?: RequestInit): Promise<T> {\n const response = await fetch(url, { ...init, credentials: 'same-origin' })\n const envelope = await response.json() as ApiEnvelope<T>\n if (!response.ok || !envelope.ok) {\n throw new Error(envelope.ok ? `Request failed (${response.status})` : envelope.error.message)\n }\n return envelope.value\n}\n\nexport function parseLoginEvent(event: MessageEvent<string>): LoginEventDto | null {\n try {\n const value = JSON.parse(event.data) as LoginEventDto\n return typeof value === 'object' && value !== null && typeof value.type === 'string' ? value : null\n } catch {\n return null\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { PluginStatusDto, QuotaBucketDto, QuotaWindowDto } from '../shared/contracts.ts'\nimport { SubscriptionApi, parseLoginEvent } from './api.ts'\nimport { NS } from './locales.ts'\n\ntype Props = PropsRuntime<'settings.section'> & PropsLocale<typeof NS>\ntype BusyAction = 'login' | 'token' | 'quota' | 'test' | 'logout' | null\ntype Translate = Props['t']\n\nconst MODELS = ['gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna', 'gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.2']\n\nexport function CodexSubscriptionSection({ t }: Props): React.JSX.Element {\n const apiRef = useRef(new SubscriptionApi())\n const eventSourceRef = useRef<EventSource | null>(null)\n const [status, setStatus] = useState<PluginStatusDto | null>(null)\n const [busy, setBusy] = useState<BusyAction>(null)\n const [error, setError] = useState<string | null>(null)\n const [authUrl, setAuthUrl] = useState<string | null>(null)\n const [popupBlocked, setPopupBlocked] = useState(false)\n const [connection, setConnection] = useState<{ latencyMs: number; checkedAt: number } | null>(null)\n\n const load = useCallback(async (quiet = false) => {\n if (!quiet) setError(null)\n try {\n const next = await apiRef.current.status()\n setStatus(next)\n if (next.error !== undefined) setError(next.error.message)\n } catch (cause) {\n if (!quiet) setError(messageOf(cause))\n }\n }, [])\n\n useEffect(() => {\n void load()\n const refreshWhenVisible = (): void => {\n if (document.visibilityState === 'visible') void load(true)\n }\n document.addEventListener('visibilitychange', refreshWhenVisible)\n const timer = window.setInterval(refreshWhenVisible, 60_000)\n return () => {\n window.clearInterval(timer)\n document.removeEventListener('visibilitychange', refreshWhenVisible)\n eventSourceRef.current?.close()\n }\n }, [load])\n\n const watchLogin = useCallback((loginId: string) => {\n eventSourceRef.current?.close()\n const source = apiRef.current.events(loginId)\n eventSourceRef.current = source\n const finish = async (message?: string): Promise<void> => {\n source.close()\n eventSourceRef.current = null\n setBusy(null)\n setAuthUrl(null)\n if (message !== undefined) setError(message)\n // Preserve the terminal OAuth error while refreshing the account DTO.\n await load(true)\n }\n source.addEventListener('completed', (event) => {\n const parsed = parseLoginEvent(event as MessageEvent<string>)\n if (parsed?.type === 'completed') void finish()\n })\n source.addEventListener('cancelled', () => void finish())\n source.addEventListener('failed', (event) => {\n const parsed = parseLoginEvent(event as MessageEvent<string>)\n void finish(parsed?.type === 'failed' ? parsed.error.message : 'ChatGPT sign-in failed.')\n })\n }, [load])\n\n useEffect(() => {\n const loginId = status?.login.active ? status.login.loginId : null\n if (loginId !== null && loginId !== undefined && eventSourceRef.current === null) watchLogin(loginId)\n }, [status?.login.active, status?.login.loginId, watchLogin])\n\n const startLogin = async (): Promise<void> => {\n setBusy('login')\n setError(null)\n setPopupBlocked(false)\n const popup = window.open('about:blank', 'dsh-chatgpt-oauth', 'popup,width=560,height=760')\n try {\n const login = await apiRef.current.startLogin()\n setAuthUrl(login.authUrl)\n if (popup === null) setPopupBlocked(true)\n else popup.location.replace(login.authUrl)\n watchLogin(login.loginId)\n await load(true)\n } catch (cause) {\n popup?.close()\n setBusy(null)\n setError(messageOf(cause))\n }\n }\n\n const cancelLogin = async (): Promise<void> => {\n const loginId = status?.login.loginId\n if (loginId === null || loginId === undefined) return\n setBusy('login')\n try {\n await apiRef.current.cancelLogin(loginId)\n eventSourceRef.current?.close()\n eventSourceRef.current = null\n setAuthUrl(null)\n await load()\n } catch (cause) {\n setError(messageOf(cause))\n } finally {\n setBusy(null)\n }\n }\n\n const refreshToken = async (): Promise<void> => run('token', async () => {\n setStatus(await apiRef.current.refresh())\n })\n\n const refreshQuota = async (): Promise<void> => run('quota', async () => {\n const quota = await apiRef.current.refreshQuota()\n setStatus((current) => current === null ? current : { ...current, quota })\n })\n\n const testConnection = async (): Promise<void> => run('test', async () => {\n const result = await apiRef.current.testConnection()\n setConnection({ latencyMs: result.latencyMs, checkedAt: result.checkedAt })\n })\n\n const logout = async (): Promise<void> => run('logout', async () => {\n await apiRef.current.logout()\n eventSourceRef.current?.close()\n eventSourceRef.current = null\n setAuthUrl(null)\n setConnection(null)\n await load()\n })\n\n const run = async (action: Exclude<BusyAction, null>, task: () => Promise<void>): Promise<void> => {\n setBusy(action)\n setError(null)\n try {\n await task()\n } catch (cause) {\n setError(messageOf(cause))\n } finally {\n setBusy(null)\n }\n }\n\n const account = status?.account\n return <section className=\"dsh-codex-page\" aria-labelledby=\"dsh-codex-title\">\n <header>\n <h2 id=\"dsh-codex-title\" className=\"dsh-codex-title\">{t('title')}</h2>\n <p className=\"dsh-codex-intro\">{t('intro')}</p>\n </header>\n\n {error !== null ? <div className=\"dsh-codex-errorbar\" role=\"alert\">\n <span>{error}</span>\n {status === null ? <Button disabled={busy !== null} onClick={() => load()}>{t('retry')}</Button> : null}\n </div> : null}\n\n {status === null && error === null ? <Skeleton label={t('loading')} /> : <>\n <Section title={t('account')}>\n <InfoRow label={status?.authenticated ? t('signedIn') : t('signedOut')} value={account?.email ?? '—'} />\n {status?.authenticated ? <>\n <InfoRow label={t('plan')} value={account?.planType ?? t('unknown')} />\n <InfoRow label={t('accountId')} value={account?.accountIdSuffix ?? '—'} />\n <InfoRow label={t('expires')} value={formatDate(account?.tokenExpiresAt)} />\n </> : null}\n <InfoRow label={t('storage')} value={t('storageValue')} />\n <p className=\"dsh-codex-notice\">{t('securityNotice')}</p>\n {status?.login.active ? <p className=\"dsh-codex-muted\" role=\"status\">{t('pending')}</p> : null}\n {popupBlocked ? <p className=\"dsh-codex-error\">{t('popupBlocked')}</p> : null}\n {authUrl !== null ? <a className=\"dsh-codex-link\" href={authUrl} target=\"_blank\" rel=\"noreferrer\">{t('continueLogin')}</a> : null}\n <div className=\"dsh-codex-actions\">\n {status?.login.active\n ? <Button disabled={busy !== null} onClick={cancelLogin}>{t('cancel')}</Button>\n : <Button primary disabled={busy !== null} onClick={startLogin}>{status?.authenticated ? t('signInAgain') : t('signIn')}</Button>}\n {status?.authenticated ? <>\n <Button disabled={busy !== null} onClick={refreshToken}>{t('refreshToken')}</Button>\n <Button disabled={busy !== null} onClick={logout}>{t('signOut')}</Button>\n </> : null}\n </div>\n </Section>\n\n <Section title={t('connection')}>\n <InfoRow label={t('provider')} value=\"Codex(ChatGPT 订阅) · codex-chatgpt\" />\n <InfoRow label={t('connectionState')} value={connection === null ? t('untested') : t('connected')} />\n {connection !== null ? <InfoRow label={t('latency')} value={`${connection.latencyMs} ms · ${formatDate(connection.checkedAt)}`} /> : null}\n <div className=\"dsh-codex-models\" aria-label={t('models')}>\n {MODELS.map((model) => <code key={model}>{model}</code>)}\n </div>\n <div className=\"dsh-codex-actions\">\n <Button disabled={!status?.authenticated || busy !== null} onClick={testConnection}>{busy === 'test' ? t('testing') : t('testConnection')}</Button>\n </div>\n </Section>\n\n <Section title={t('quota')} aside={<Button disabled={!status?.authenticated || busy !== null} onClick={refreshQuota}>{busy === 'quota' ? t('refreshing') : t('refreshQuota')}</Button>}>\n <p className=\"dsh-codex-muted\">{t('quotaIntro')}</p>\n {status?.quota.state === 'signed-out' ? <p className=\"dsh-codex-empty\">{t('quotaSignedOut')}</p> : null}\n {status?.quota.buckets.map((bucket) => <QuotaBucket key={bucket.id} bucket={bucket} t={t} />)}\n {status?.quota.state === 'empty' ? <p className=\"dsh-codex-empty\">{t('noQuota')}</p> : null}\n {status?.quota.stale ? <p className=\"dsh-codex-warning\" role=\"status\">{t('stale')}</p> : null}\n {status?.quota.error ? <p className=\"dsh-codex-error\" role=\"alert\">{status.quota.error.message}</p> : null}\n {status?.quota.fetchedAt ? <p className=\"dsh-codex-timestamp\">{t('updated')}: {formatDate(status.quota.fetchedAt)}</p> : null}\n </Section>\n </>}\n\n <span className=\"dsh-codex-sr\" aria-live=\"polite\">{busy === null ? '' : busy}</span>\n </section>\n}\n\nfunction Section({ title, aside, children }: { title: string; aside?: React.ReactNode; children: React.ReactNode }): React.JSX.Element {\n return <section className=\"dsh-codex-group\">\n <div className=\"dsh-codex-grouphead\"><h3>{title}</h3>{aside}</div>\n {children}\n </section>\n}\n\nfunction Button({ primary = false, disabled, onClick, children }: { primary?: boolean; disabled?: boolean; onClick: () => void | Promise<void>; children: React.ReactNode }): React.JSX.Element {\n return <button className={`dsh-codex-button${primary ? ' dsh-codex-button-primary' : ''}`} type=\"button\" disabled={disabled} onClick={() => void onClick()}>{children}</button>\n}\n\nfunction InfoRow({ label, value }: { label: string; value: string }): React.JSX.Element {\n return <div className=\"dsh-codex-row\"><span className=\"dsh-codex-label\">{label}</span><span className=\"dsh-codex-value\">{value}</span></div>\n}\n\nfunction QuotaBucket({ bucket, t }: { bucket: QuotaBucketDto; t: Translate }): React.JSX.Element {\n return <article className=\"dsh-codex-quota-card\">\n <div className=\"dsh-codex-quota-title\"><strong>{bucket.name}</strong>{bucket.planType ? <span>{bucket.planType}</span> : null}</div>\n {bucket.primary ? <QuotaBar label={windowLabel(bucket.primary.windowDurationMins, t)} window={bucket.primary} t={t} /> : null}\n {bucket.secondary ? <QuotaBar label={windowLabel(bucket.secondary.windowDurationMins, t)} window={bucket.secondary} t={t} /> : null}\n </article>\n}\n\nexport function QuotaBar({ label, window, t }: { label: string; window: QuotaWindowDto; t: Translate }): React.JSX.Element {\n const percent = window.usedPercent\n const level = percent >= 95 ? 'danger' : percent >= 80 ? 'warning' : 'normal'\n const remaining = Math.max(0, 100 - percent)\n return <div className=\"dsh-codex-meter-wrap\">\n <div className=\"dsh-codex-meter-label\"><span>{label}</span><strong>{formatPercent(percent)}</strong></div>\n <div className={`dsh-codex-meter dsh-codex-meter-${level}`} role=\"progressbar\" aria-label={`${label}: ${formatPercent(percent)} ${t('used')}`} aria-valuemin={0} aria-valuemax={100} aria-valuenow={percent}>\n <span style={{ width: `${percent}%` }} />\n </div>\n <div className=\"dsh-codex-meter-meta\">\n <span>{percent >= 100 ? `${t('exhausted')} · ${formatPercent(remaining)} ${t('remaining')}` : `${formatPercent(percent)} ${t('used')} · ${formatPercent(remaining)} ${t('remaining')}`}</span>\n <span>{window.resetsAt === null ? '—' : `${t('resets')}: ${formatReset(window.resetsAt)}`}</span>\n </div>\n </div>\n}\n\nfunction Skeleton({ label }: { label: string }): React.JSX.Element {\n return <div className=\"dsh-codex-skeleton\" role=\"status\" aria-label={label}><span /><span /></div>\n}\n\nexport function windowLabel(minutes: number | null, t: Translate): string {\n if (minutes === null) return t('limitWindow')\n const [value, unit]: [number, Intl.NumberFormatOptions['unit']] = minutes >= 1440 && minutes % 1440 === 0\n ? [minutes / 1440, 'day']\n : minutes >= 60 && minutes % 60 === 0\n ? [minutes / 60, 'hour']\n : [Math.round(minutes), 'minute']\n return `${new Intl.NumberFormat(undefined, { style: 'unit', unit, unitDisplay: 'long' }).format(value)} ${t('limitWindow')}`\n}\n\nfunction formatPercent(value: number): string {\n return `${new Intl.NumberFormat(undefined, { maximumFractionDigits: 1 }).format(value)}%`\n}\n\nfunction formatDate(seconds: number | undefined): string {\n if (seconds === undefined) return '—'\n return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short' }).format(seconds * 1000)\n}\n\nexport function formatReset(seconds: number): string {\n const absolute = formatDate(seconds)\n const diff = seconds * 1000 - Date.now()\n const abs = Math.abs(diff)\n const [amount, unit]: [number, Intl.RelativeTimeFormatUnit] = abs >= 86_400_000\n ? [Math.round(diff / 86_400_000), 'day']\n : abs >= 3_600_000\n ? [Math.round(diff / 3_600_000), 'hour']\n : [Math.round(diff / 60_000), 'minute']\n return `${absolute} (${new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' }).format(amount, unit)})`\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","export const NS = 'dsh-chatgpt-subscription' as const\n\nexport const zh = {\n title: 'Codex 订阅',\n intro: '使用 ChatGPT 账号登录,在 DSH 中使用订阅可用的 Codex 模型。',\n account: '账号',\n signedOut: '尚未登录',\n signedIn: '已登录',\n plan: '套餐',\n accountId: '账号 ID',\n expires: '令牌到期',\n storage: '凭据存储',\n storageValue: 'Windows DPAPI(当前用户加密)',\n securityNotice: '令牌仅保存在 Host 端的 DPAPI 加密文件中,不会进入浏览器、settings.yaml 或日志。',\n signIn: '使用 ChatGPT 登录',\n signInAgain: '重新登录',\n cancel: '取消登录',\n signOut: '注销',\n refreshToken: '刷新凭据',\n pending: '请在浏览器中完成登录。',\n popupBlocked: '浏览器拦截了登录窗口,请使用下面的链接继续。',\n continueLogin: '打开 ChatGPT 登录页',\n loading: '正在读取状态…',\n connection: '连接',\n provider: 'Provider',\n connectionState: '连接状态',\n connected: '可用',\n untested: '尚未测试',\n testConnection: '测试连接',\n testing: '测试中…',\n latency: '最近延迟',\n models: '可用模型',\n quota: '用量与限额',\n quotaIntro: '数据来自 ChatGPT Codex 用量服务。页面可见时最多每 60 秒刷新一次。',\n refreshQuota: '刷新用量',\n refreshing: '刷新中…',\n noQuota: '当前套餐未返回可显示的限额窗口。',\n quotaSignedOut: '登录后可查看订阅限额。',\n stale: '显示的是上次成功获取的数据。',\n updated: '更新时间',\n primary: '主要窗口',\n secondary: '次要窗口',\n limitWindow: '额度',\n used: '已使用',\n remaining: '剩余',\n exhausted: '额度已用尽',\n resets: '重置',\n retry: '重试',\n unknown: '未知',\n} as const\n\nexport const en: Record<keyof typeof zh, string> = {\n title: 'Codex subscription',\n intro: 'Sign in with ChatGPT to use Codex models available to your subscription in DSH.',\n account: 'Account',\n signedOut: 'Not signed in',\n signedIn: 'Signed in',\n plan: 'Plan',\n accountId: 'Account ID',\n expires: 'Token expires',\n storage: 'Credential storage',\n storageValue: 'Windows DPAPI (current-user encrypted)',\n securityNotice: 'Tokens stay in a Host-side DPAPI-encrypted file and never enter the browser, settings.yaml, or logs.',\n signIn: 'Sign in with ChatGPT',\n signInAgain: 'Sign in again',\n cancel: 'Cancel sign-in',\n signOut: 'Sign out',\n refreshToken: 'Refresh credentials',\n pending: 'Complete sign-in in your browser.',\n popupBlocked: 'The sign-in window was blocked. Use the link below to continue.',\n continueLogin: 'Open ChatGPT sign-in',\n loading: 'Reading status…',\n connection: 'Connection',\n provider: 'Provider',\n connectionState: 'Connection status',\n connected: 'Available',\n untested: 'Not tested',\n testConnection: 'Test connection',\n testing: 'Testing…',\n latency: 'Last latency',\n models: 'Available models',\n quota: 'Usage and limits',\n quotaIntro: 'Data comes from the ChatGPT Codex usage service and refreshes at most once per minute while visible.',\n refreshQuota: 'Refresh usage',\n refreshing: 'Refreshing…',\n noQuota: 'Your plan did not return any displayable limit windows.',\n quotaSignedOut: 'Sign in to view subscription limits.',\n stale: 'Showing the last successfully fetched data.',\n updated: 'Updated',\n primary: 'Primary window',\n secondary: 'Secondary window',\n limitWindow: 'limit',\n used: 'used',\n remaining: 'remaining',\n exhausted: 'Quota exhausted',\n resets: 'Resets',\n retry: 'Retry',\n unknown: 'Unknown',\n}\n\nexport type LocaleKey = keyof typeof zh\nexport const dictionaries = { zh, en }\n","const STYLE_ID = '@eddyskywalker/dsh-chatgpt-subscription/main'\n\nconst CSS = `\n.dsh-codex-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}\n.dsh-codex-page *{box-sizing:border-box}\n.dsh-codex-title{font-size:15px;font-weight:650;line-height:1.4;margin:0 0 5px}\n.dsh-codex-intro,.dsh-codex-muted{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55;margin:0}\n.dsh-codex-group{border-top:1px solid var(--dsw-alias-border-l2);min-width:0}\n.dsh-codex-grouphead{align-items:center;display:flex;gap:12px;justify-content:space-between;min-height:48px}\n.dsh-codex-grouphead h3{font-size:14px;font-weight:650;margin:0}\n.dsh-codex-row{align-items:center;border-bottom:1px solid var(--dsw-alias-border-l2);display:flex;gap:20px;justify-content:space-between;min-height:44px;padding:8px 0}\n.dsh-codex-label{color:var(--dsw-alias-label-secondary);font-size:13px;flex:0 0 auto}\n.dsh-codex-value{font-size:13px;min-width:0;overflow-wrap:anywhere;text-align:right}\n.dsh-codex-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;padding-top:12px}\n.dsh-codex-button{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:13px;line-height:1;padding:8px 13px;white-space:nowrap}\n.dsh-codex-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}\n.dsh-codex-button:focus-visible,.dsh-codex-link:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}\n.dsh-codex-button:disabled{cursor:default;opacity:.5}\n.dsh-codex-button-primary{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}\n.dsh-codex-notice{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55;margin:12px 0 0;padding:10px 12px}\n.dsh-codex-error,.dsh-codex-warning{font-size:12px;line-height:1.5;margin:8px 0 0}\n.dsh-codex-error{color:var(--dsw-alias-label-danger,#d94b4b)}\n.dsh-codex-warning{color:var(--dsw-alias-label-warning,#c77a18)}\n.dsh-codex-errorbar{align-items:center;background:color-mix(in srgb,var(--dsw-alias-label-danger,#d94b4b) 9%,transparent);border:1px solid color-mix(in srgb,var(--dsw-alias-label-danger,#d94b4b) 28%,transparent);border-radius:7px;color:var(--dsw-alias-label-danger,#d94b4b);display:flex;font-size:13px;gap:12px;justify-content:space-between;padding:10px 12px}\n.dsh-codex-link{color:var(--dsw-alias-label-link,#3278d4);display:inline-block;font-size:13px;margin-top:8px}\n.dsh-codex-models{display:flex;flex-wrap:wrap;gap:6px;padding-top:12px}\n.dsh-codex-models code{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:5px;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:4px 6px}\n.dsh-codex-quota-card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}\n.dsh-codex-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between}\n.dsh-codex-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}\n.dsh-codex-meter-wrap{margin-top:13px}\n.dsh-codex-meter-label,.dsh-codex-meter-meta{display:flex;gap:10px;justify-content:space-between}\n.dsh-codex-meter-label{font-size:12px;margin-bottom:6px}\n.dsh-codex-meter-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45;margin-top:6px}\n.dsh-codex-meter{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.15));border-radius:999px;height:7px;overflow:hidden;width:100%}\n.dsh-codex-meter>span{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:inherit;display:block;height:100%;max-width:100%;min-width:0;transition:width .25s ease}\n.dsh-codex-meter-warning>span{background:var(--dsw-alias-label-warning,#d58a24)}\n.dsh-codex-meter-danger>span{background:var(--dsw-alias-label-danger,#d94b4b)}\n.dsh-codex-empty{border:1px dashed var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;margin:12px 0 0;padding:16px;text-align:center}\n.dsh-codex-timestamp{color:var(--dsw-alias-label-tertiary);font-size:11px;margin:10px 0 0;text-align:right}\n.dsh-codex-skeleton{display:grid;gap:9px;padding-top:10px}\n.dsh-codex-skeleton span{animation:dsh-codex-pulse 1.4s ease-in-out infinite;background:var(--dsw-alias-bg-layer-2);border-radius:5px;height:42px}\n.dsh-codex-skeleton span:nth-child(2){animation-delay:.12s}.dsh-codex-skeleton span:nth-child(3){animation-delay:.24s}\n.dsh-codex-sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0 0 0 0);white-space:nowrap}\n@keyframes dsh-codex-pulse{0%,100%{opacity:.55}50%{opacity:1}}\n@media(max-width:560px){.dsh-codex-row{align-items:flex-start;flex-direction:column;gap:3px}.dsh-codex-value{text-align:left}.dsh-codex-actions{justify-content:flex-start}.dsh-codex-grouphead{align-items:flex-start;flex-direction:column;gap:0;padding:12px 0}.dsh-codex-meter-meta{align-items:flex-start;flex-direction:column;gap:2px}.dsh-codex-errorbar{align-items:flex-start;flex-direction:column}}\n@media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}\n`\n\nexport function installStyles(): () => void {\n if (document.querySelector(`style[data-plugin-css=\"${STYLE_ID}\"]`) !== null) return () => undefined\n const element = document.createElement('style')\n element.dataset.plugin = '@eddyskywalker/dsh-chatgpt-subscription'\n element.dataset.pluginCss = STYLE_ID\n element.textContent = CSS\n document.head.appendChild(element)\n return () => element.remove()\n}\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { CodexSubscriptionSection } from './CodexSubscriptionSection.tsx'\nimport { dictionaries, NS, type LocaleKey } from './locales.ts'\nimport { installStyles } from './styles.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'dsh-chatgpt-subscription': LocaleKey\n }\n}\n\nexport const inject = ['slots', 'locale']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, dictionaries), 'dsh-chatgpt-subscription: dictionaries')\n ctx.effect(() => installStyles(), 'dsh-chatgpt-subscription: styles')\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'codex-subscription',\n order: 45,\n label: 'Codex 订阅',\n locale: NS,\n }, CodexSubscriptionSection))\n}\n"],"mappings":";;;;;;;;EAeA,MAAa,eAAe;;;ECL5B,IAAa,kBAAb,MAA6B;GAC3B,SAAmC;IACjC,OAAO,QAAyB,GAAG,aAAa,QAAQ;GAC1D;GAEA,aAAqC;IACnC,OAAO,KAAoB,GAAG,aAAa,eAAe,CAAC,CAAC;GAC9D;GAEA,YAAY,SAAkD;IAC5D,OAAO,KAAK,GAAG,aAAa,gBAAgB,EAAE,QAAQ,CAAC;GACzD;GAEA,SAA4C;IAC1C,OAAO,KAAK,GAAG,aAAa,UAAU,CAAC,CAAC;GAC1C;GAEA,UAAoC;IAClC,OAAO,KAAK,GAAG,aAAa,iBAAiB,CAAC,CAAC;GACjD;GAEA,eAAwC;IACtC,OAAO,KAAK,GAAG,aAAa,iBAAiB,CAAC,CAAC;GACjD;GAEA,iBAA6C;IAC3C,OAAO,KAAK,GAAG,aAAa,mBAAmB,CAAC,CAAC;GACnD;GAEA,OAAO,SAA8B;IACnC,OAAO,IAAI,YAAY,GAAG,aAAa,wBAAwB,mBAAmB,OAAO,GAAG;GAC9F;EACF;EAEA,eAAe,KAAQ,KAAa,MAA2C;GAC7E,OAAO,QAAW,KAAK;IACrB,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM,KAAK,UAAU,IAAI;GAC3B,CAAC;EACH;EAEA,eAAe,QAAW,KAAa,MAAgC;GACrE,MAAM,WAAW,MAAM,MAAM,KAAK;IAAE,GAAG;IAAM,aAAa;GAAc,CAAC;GACzE,MAAM,WAAW,MAAM,SAAS,KAAK;GACrC,IAAI,CAAC,SAAS,MAAM,CAAC,SAAS,IAC5B,MAAM,IAAI,MAAM,SAAS,KAAK,mBAAmB,SAAS,OAAO,KAAK,SAAS,MAAM,OAAO;GAE9F,OAAO,SAAS;EAClB;EAEA,SAAgB,gBAAgB,OAAmD;GACjF,IAAI;IACF,MAAM,QAAQ,KAAK,MAAM,MAAM,IAAI;IACnC,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAO,MAAM,SAAS,WAAW,QAAQ;GACjG,QAAQ;IACN,OAAO;GACT;EACF;;;EC1DA,MAAM,SAAS;GAAC;GAAe;GAAiB;GAAgB;GAAW;GAAW;GAAgB;EAAS;EAE/G,SAAgB,yBAAyB,EAAE,KAA+B;GACxE,MAAM,UAAA,GAAA,MAAA,OAAA,CAAgB,IAAI,gBAAgB,CAAC;GAC3C,MAAM,kBAAA,GAAA,MAAA,OAAA,CAA4C,IAAI;GACtD,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAA8C,IAAI;GACjE,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAgC,IAAI;GACjD,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAoC,IAAI;GACtD,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAsC,IAAI;GAC1D,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,KAAK;GACtD,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA2E,IAAI;GAElG,MAAM,QAAA,GAAA,MAAA,YAAA,CAAmB,OAAO,QAAQ,UAAU;IAChD,IAAI,CAAC,OAAO,SAAS,IAAI;IACzB,IAAI;KACF,MAAM,OAAO,MAAM,OAAO,QAAQ,OAAO;KACzC,UAAU,IAAI;KACd,IAAI,KAAK,UAAU,KAAA,GAAW,SAAS,KAAK,MAAM,OAAO;IAC3D,SAAS,OAAO;KACd,IAAI,CAAC,OAAO,SAAS,UAAU,KAAK,CAAC;IACvC;GACF,GAAG,CAAC,CAAC;GAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,KAAU;IACV,MAAM,2BAAiC;KACrC,IAAI,SAAS,oBAAoB,WAAW,KAAU,IAAI;IAC5D;IACA,SAAS,iBAAiB,oBAAoB,kBAAkB;IAChE,MAAM,QAAQ,OAAO,YAAY,oBAAoB,GAAM;IAC3D,aAAa;KACX,OAAO,cAAc,KAAK;KAC1B,SAAS,oBAAoB,oBAAoB,kBAAkB;KACnE,eAAe,SAAS,MAAM;IAChC;GACF,GAAG,CAAC,IAAI,CAAC;GAET,MAAM,cAAA,GAAA,MAAA,YAAA,EAA0B,YAAoB;IAClD,eAAe,SAAS,MAAM;IAC9B,MAAM,SAAS,OAAO,QAAQ,OAAO,OAAO;IAC5C,eAAe,UAAU;IACzB,MAAM,SAAS,OAAO,YAAoC;KACxD,OAAO,MAAM;KACb,eAAe,UAAU;KACzB,QAAQ,IAAI;KACZ,WAAW,IAAI;KACf,IAAI,YAAY,KAAA,GAAW,SAAS,OAAO;KAE3C,MAAM,KAAK,IAAI;IACjB;IACA,OAAO,iBAAiB,cAAc,UAAU;KAE9C,IADe,gBAAgB,KACtB,CAAC,EAAE,SAAS,aAAa,OAAY;IAChD,CAAC;IACD,OAAO,iBAAiB,mBAAmB,KAAK,OAAO,CAAC;IACxD,OAAO,iBAAiB,WAAW,UAAU;KAC3C,MAAM,SAAS,gBAAgB,KAA6B;KAC5D,OAAY,QAAQ,SAAS,WAAW,OAAO,MAAM,UAAU,yBAAyB;IAC1F,CAAC;GACH,GAAG,CAAC,IAAI,CAAC;GAET,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,UAAU,QAAQ,MAAM,SAAS,OAAO,MAAM,UAAU;IAC9D,IAAI,YAAY,QAAQ,YAAY,KAAA,KAAa,eAAe,YAAY,MAAM,WAAW,OAAO;GACtG,GAAG;IAAC,QAAQ,MAAM;IAAQ,QAAQ,MAAM;IAAS;GAAU,CAAC;GAE5D,MAAM,aAAa,YAA2B;IAC5C,QAAQ,OAAO;IACf,SAAS,IAAI;IACb,gBAAgB,KAAK;IACrB,MAAM,QAAQ,OAAO,KAAK,eAAe,qBAAqB,4BAA4B;IAC1F,IAAI;KACF,MAAM,QAAQ,MAAM,OAAO,QAAQ,WAAW;KAC9C,WAAW,MAAM,OAAO;KACxB,IAAI,UAAU,MAAM,gBAAgB,IAAI;UACnC,MAAM,SAAS,QAAQ,MAAM,OAAO;KACzC,WAAW,MAAM,OAAO;KACxB,MAAM,KAAK,IAAI;IACjB,SAAS,OAAO;KACd,OAAO,MAAM;KACb,QAAQ,IAAI;KACZ,SAAS,UAAU,KAAK,CAAC;IAC3B;GACF;GAEA,MAAM,cAAc,YAA2B;IAC7C,MAAM,UAAU,QAAQ,MAAM;IAC9B,IAAI,YAAY,QAAQ,YAAY,KAAA,GAAW;IAC/C,QAAQ,OAAO;IACf,IAAI;KACF,MAAM,OAAO,QAAQ,YAAY,OAAO;KACxC,eAAe,SAAS,MAAM;KAC9B,eAAe,UAAU;KACzB,WAAW,IAAI;KACf,MAAM,KAAK;IACb,SAAS,OAAO;KACd,SAAS,UAAU,KAAK,CAAC;IAC3B,UAAU;KACR,QAAQ,IAAI;IACd;GACF;GAEA,MAAM,eAAe,YAA2B,IAAI,SAAS,YAAY;IACvE,UAAU,MAAM,OAAO,QAAQ,QAAQ,CAAC;GAC1C,CAAC;GAED,MAAM,eAAe,YAA2B,IAAI,SAAS,YAAY;IACvE,MAAM,QAAQ,MAAM,OAAO,QAAQ,aAAa;IAChD,WAAW,YAAY,YAAY,OAAO,UAAU;KAAE,GAAG;KAAS;IAAM,CAAC;GAC3E,CAAC;GAED,MAAM,iBAAiB,YAA2B,IAAI,QAAQ,YAAY;IACxE,MAAM,SAAS,MAAM,OAAO,QAAQ,eAAe;IACnD,cAAc;KAAE,WAAW,OAAO;KAAW,WAAW,OAAO;IAAU,CAAC;GAC5E,CAAC;GAED,MAAM,SAAS,YAA2B,IAAI,UAAU,YAAY;IAClE,MAAM,OAAO,QAAQ,OAAO;IAC5B,eAAe,SAAS,MAAM;IAC9B,eAAe,UAAU;IACzB,WAAW,IAAI;IACf,cAAc,IAAI;IAClB,MAAM,KAAK;GACb,CAAC;GAED,MAAM,MAAM,OAAO,QAAmC,SAA6C;IACjG,QAAQ,MAAM;IACd,SAAS,IAAI;IACb,IAAI;KACF,MAAM,KAAK;IACb,SAAS,OAAO;KACd,SAAS,UAAU,KAAK,CAAC;IAC3B,UAAU;KACR,QAAQ,IAAI;IACd;GACF;GAEA,MAAM,UAAU,QAAQ;GACxB,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAU;IAAiB,mBAAgB;cAApD;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;MAAI,IAAG;MAAkB,WAAU;gBAAmB,EAAE,OAAO;KAAM,CAAA,GACrE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAU;gBAAmB,EAAE,OAAO;KAAK,CAAA,CACxC,EAAA,CAAA;KAEP,UAAU,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;MAAqB,MAAK;gBAAzC,CAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,MAAY,CAAA,GAClB,WAAW,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAQ,UAAU,SAAS;OAAM,eAAe,KAAK;iBAAI,EAAE,OAAO;MAAU,CAAA,IAAI,IAChG;UAAI;KAER,WAAW,QAAQ,UAAU,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,OAAO,EAAE,SAAS,EAAI,CAAA,IAAI,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;MACvE,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAS,OAAO,EAAE,SAAS;iBAA3B;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,QAAQ,gBAAgB,EAAE,UAAU,IAAI,EAAE,WAAW;SAAG,OAAO,SAAS,SAAS;QAAM,CAAA;QACtG,QAAQ,gBAAgB,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;SACvB,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;UAAS,OAAO,EAAE,MAAM;UAAG,OAAO,SAAS,YAAY,EAAE,SAAS;SAAI,CAAA;SACtE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;UAAS,OAAO,EAAE,WAAW;UAAG,OAAO,SAAS,mBAAmB;SAAM,CAAA;SACzE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;UAAS,OAAO,EAAE,SAAS;UAAG,OAAO,WAAW,SAAS,cAAc;SAAI,CAAA;QAC3E,EAAA,CAAA,IAAI;QACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,EAAE,SAAS;SAAG,OAAO,EAAE,cAAc;QAAI,CAAA;QACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAoB,EAAE,gBAAgB;QAAK,CAAA;QACvD,QAAQ,MAAM,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAkB,MAAK;mBAAU,EAAE,SAAS;QAAK,CAAA,IAAI;QACzF,eAAe,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAmB,EAAE,cAAc;QAAK,CAAA,IAAI;QACxE,YAAY,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAiB,MAAM;SAAS,QAAO;SAAS,KAAI;mBAAc,EAAE,eAAe;QAAK,CAAA,IAAI;QAC7H,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAU;mBAAf,CACG,QAAQ,MAAM,SACX,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,UAAU,SAAS;UAAM,SAAS;oBAAc,EAAE,QAAQ;SAAU,CAAA,IAC5E,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,SAAA;UAAQ,UAAU,SAAS;UAAM,SAAS;oBAAa,QAAQ,gBAAgB,EAAE,aAAa,IAAI,EAAE,QAAQ;SAAU,CAAA,GACjI,QAAQ,gBAAgB,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACvB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,UAAU,SAAS;UAAM,SAAS;oBAAe,EAAE,cAAc;SAAU,CAAA,GACnF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,UAAU,SAAS;UAAM,SAAS;oBAAS,EAAE,SAAS;SAAU,CAAA,CACxE,EAAA,CAAA,IAAI,IACH;;OACE;;MAET,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAS,OAAO,EAAE,YAAY;iBAA9B;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,EAAE,UAAU;SAAG,OAAM;QAAqC,CAAA;QAC1E,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,EAAE,iBAAiB;SAAG,OAAO,eAAe,OAAO,EAAE,UAAU,IAAI,EAAE,WAAW;QAAI,CAAA;QACnG,eAAe,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,EAAE,SAAS;SAAG,OAAO,GAAG,WAAW,UAAU,QAAQ,WAAW,WAAW,SAAS;QAAM,CAAA,IAAI;QACrI,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAU;SAAmB,cAAY,EAAE,QAAQ;mBACrD,OAAO,KAAK,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAmB,MAAY,GAApB,KAAoB,CAAC;QACpD,CAAA;QACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAU;mBACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,UAAU,CAAC,QAAQ,iBAAiB,SAAS;UAAM,SAAS;oBAAiB,SAAS,SAAS,EAAE,SAAS,IAAI,EAAE,gBAAgB;SAAU,CAAA;QAC/I,CAAA;OACE;;MAET,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAS,OAAO,EAAE,OAAO;OAAG,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAQ,UAAU,CAAC,QAAQ,iBAAiB,SAAS;QAAM,SAAS;kBAAe,SAAS,UAAU,EAAE,YAAY,IAAI,EAAE,cAAc;OAAU,CAAA;iBAArL;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAmB,EAAE,YAAY;QAAK,CAAA;QAClD,QAAQ,MAAM,UAAU,eAAe,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAmB,EAAE,gBAAgB;QAAK,CAAA,IAAI;QAClG,QAAQ,MAAM,QAAQ,KAAK,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;SAAqC;SAAW;QAAI,GAAlC,OAAO,EAA2B,CAAC;QAC3F,QAAQ,MAAM,UAAU,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAmB,EAAE,SAAS;QAAK,CAAA,IAAI;QACtF,QAAQ,MAAM,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAoB,MAAK;mBAAU,EAAE,OAAO;QAAK,CAAA,IAAI;QACxF,QAAQ,MAAM,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAkB,MAAK;mBAAS,OAAO,MAAM,MAAM;QAAW,CAAA,IAAI;QACrG,QAAQ,MAAM,YAAY,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;SAAG,WAAU;mBAAb;UAAoC,EAAE,SAAS;UAAE;UAAG,WAAW,OAAO,MAAM,SAAS;SAAK;aAAI;OAClH;;KACT,EAAA,CAAA;KAEF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAU;MAAe,aAAU;gBAAU,SAAS,OAAO,KAAK;KAAW,CAAA;IAC5E;;EACX;EAEA,SAAS,QAAQ,EAAE,OAAO,OAAO,YAAsG;GACrI,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAU;cAAnB,CACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;eAAf,CAAqC,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,MAAU,CAAA,GAAE,KAAW;QAChE,QACM;;EACX;EAEA,SAAS,OAAO,EAAE,UAAU,OAAO,UAAU,SAAS,YAA0I;GAC9L,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,WAAW,mBAAmB,UAAU,8BAA8B;IAAM,MAAK;IAAmB;IAAU,eAAe,KAAK,QAAQ;IAAI;GAAiB,CAAA;EAChL;EAEA,SAAS,QAAQ,EAAE,OAAO,SAA8D;GACtF,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;cAAf,CAA+B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;eAAmB;IAAY,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;eAAmB;IAAY,CAAA,CAAM;;EAC7I;EAEA,SAAS,YAAY,EAAE,QAAQ,KAAkE;GAC/F,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAU;cAAnB;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CAAuC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,OAAO,KAAa,CAAA,GAAE,OAAO,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,OAAO,SAAe,CAAA,IAAI,IAAU;;KAClI,OAAO,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAU,OAAO,YAAY,OAAO,QAAQ,oBAAoB,CAAC;MAAG,QAAQ,OAAO;MAAY;KAAI,CAAA,IAAI;KACxH,OAAO,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAU,OAAO,YAAY,OAAO,UAAU,oBAAoB,CAAC;MAAG,QAAQ,OAAO;MAAc;KAAI,CAAA,IAAI;IACxH;;EACX;EAEA,SAAgB,SAAS,EAAE,OAAO,QAAQ,KAAiF;GACzH,MAAM,UAAU,OAAO;GACvB,MAAM,QAAQ,WAAW,KAAK,WAAW,WAAW,KAAK,YAAY;GACrE,MAAM,YAAY,KAAK,IAAI,GAAG,MAAM,OAAO;GAC3C,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;cAAf;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CAAuC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,MAAY,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,cAAc,OAAO,EAAU,CAAA,CAAM;;KACzG,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAW,mCAAmC;MAAS,MAAK;MAAc,cAAY,GAAG,MAAM,IAAI,cAAc,OAAO,EAAE,GAAG,EAAE,MAAM;MAAK,iBAAe;MAAG,iBAAe;MAAK,iBAAe;gBAClM,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,EAAI,CAAA;KACrC,CAAA;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,WAAW,MAAM,GAAG,EAAE,WAAW,EAAE,KAAK,cAAc,SAAS,EAAE,GAAG,EAAE,WAAW,MAAM,GAAG,cAAc,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,cAAc,SAAS,EAAE,GAAG,EAAE,WAAW,IAAU,CAAA,GAC7L,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,OAAO,aAAa,OAAO,MAAM,GAAG,EAAE,QAAQ,EAAE,IAAI,YAAY,OAAO,QAAQ,IAAU,CAAA,CAC7F;;IACF;;EACP;EAEA,SAAS,SAAS,EAAE,SAA+C;GACjE,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;IAAqB,MAAK;IAAS,cAAY;cAA9D,CAAqE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,CAAO,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,CAAO,CAAA,CAAM;;EACnG;EAEA,SAAgB,YAAY,SAAwB,GAAsB;GACxE,IAAI,YAAY,MAAM,OAAO,EAAE,aAAa;GAC5C,MAAM,CAAC,OAAO,QAAoD,WAAW,QAAQ,UAAU,SAAS,IACpG,CAAC,UAAU,MAAM,KAAK,IACtB,WAAW,MAAM,UAAU,OAAO,IAChC,CAAC,UAAU,IAAI,MAAM,IACrB,CAAC,KAAK,MAAM,OAAO,GAAG,QAAQ;GACpC,OAAO,GAAG,IAAI,KAAK,aAAa,KAAA,GAAW;IAAE,OAAO;IAAQ;IAAM,aAAa;GAAO,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,GAAG,EAAE,aAAa;EAC3H;EAEA,SAAS,cAAc,OAAuB;GAC5C,OAAO,GAAG,IAAI,KAAK,aAAa,KAAA,GAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE;EACzF;EAEA,SAAS,WAAW,SAAqC;GACvD,IAAI,YAAY,KAAA,GAAW,OAAO;GAClC,OAAO,IAAI,KAAK,eAAe,KAAA,GAAW;IAAE,WAAW;IAAU,WAAW;GAAQ,CAAC,CAAC,CAAC,OAAO,UAAU,GAAI;EAC9G;EAEA,SAAgB,YAAY,SAAyB;GACnD,MAAM,WAAW,WAAW,OAAO;GACnC,MAAM,OAAO,UAAU,MAAO,KAAK,IAAI;GACvC,MAAM,MAAM,KAAK,IAAI,IAAI;GACzB,MAAM,CAAC,QAAQ,QAA+C,OAAO,QACjE,CAAC,KAAK,MAAM,OAAO,KAAU,GAAG,KAAK,IACrC,OAAO,OACL,CAAC,KAAK,MAAM,OAAO,IAAS,GAAG,MAAM,IACrC,CAAC,KAAK,MAAM,OAAO,GAAM,GAAG,QAAQ;GAC1C,OAAO,GAAG,SAAS,IAAI,IAAI,KAAK,mBAAmB,KAAA,GAAW,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,OAAO,QAAQ,IAAI,EAAE;EAC1G;EAEA,SAAS,UAAU,OAAwB;GACzC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC9D;;;EC9RA,MAAa,KAAK;EAqGlB,MAAa,eAAe;GAAE;IAlG5B,OAAO;IACP,OAAO;IACP,SAAS;IACT,WAAW;IACX,UAAU;IACV,MAAM;IACN,WAAW;IACX,SAAS;IACT,SAAS;IACT,cAAc;IACd,gBAAgB;IAChB,QAAQ;IACR,aAAa;IACb,QAAQ;IACR,SAAS;IACT,cAAc;IACd,SAAS;IACT,cAAc;IACd,eAAe;IACf,SAAS;IACT,YAAY;IACZ,UAAU;IACV,iBAAiB;IACjB,WAAW;IACX,UAAU;IACV,gBAAgB;IAChB,SAAS;IACT,SAAS;IACT,QAAQ;IACR,OAAO;IACP,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,SAAS;IACT,SAAS;IACT,WAAW;IACX,aAAa;IACb,MAAM;IACN,WAAW;IACX,WAAW;IACX,QAAQ;IACR,OAAO;IACP,SAAS;GAqDmB;GAAI;IAjDhC,OAAO;IACP,OAAO;IACP,SAAS;IACT,WAAW;IACX,UAAU;IACV,MAAM;IACN,WAAW;IACX,SAAS;IACT,SAAS;IACT,cAAc;IACd,gBAAgB;IAChB,QAAQ;IACR,aAAa;IACb,QAAQ;IACR,SAAS;IACT,cAAc;IACd,SAAS;IACT,cAAc;IACd,eAAe;IACf,SAAS;IACT,YAAY;IACZ,UAAU;IACV,iBAAiB;IACjB,WAAW;IACX,UAAU;IACV,gBAAgB;IAChB,SAAS;IACT,SAAS;IACT,QAAQ;IACR,OAAO;IACP,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,SAAS;IACT,SAAS;IACT,WAAW;IACX,aAAa;IACb,MAAM;IACN,WAAW;IACX,WAAW;IACX,QAAQ;IACR,OAAO;IACP,SAAS;GAIuB;EAAG;;;ECrGrC,MAAM,WAAW;EAEjB,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+CZ,SAAgB,gBAA4B;GAC1C,IAAI,SAAS,cAAc,0BAA0B,SAAS,GAAG,MAAM,MAAM,aAAa,KAAA;GAC1F,MAAM,UAAU,SAAS,cAAc,OAAO;GAC9C,QAAQ,QAAQ,SAAS;GACzB,QAAQ,QAAQ,YAAY;GAC5B,QAAQ,cAAc;GACtB,SAAS,KAAK,YAAY,OAAO;GACjC,aAAa,QAAQ,OAAO;EAC9B;;;EC3CA,MAAa,SAAS,CAAC,SAAS,QAAQ;EAExC,SAAgB,MAAM,KAA0B;GAC9C,IAAI,aAAa,IAAI,OAAO,SAAS,IAAI,YAAY,GAAG,wCAAwC;GAChG,IAAI,aAAa,cAAc,GAAG,kCAAkC;GACpE,IAAI,MAAM,OAAO,0BAA0B,IAAI,MAAM,SAAS;IAC5D,MAAM;IACN,IAAI;IACJ,OAAO;IACP,OAAO;IACP,QAAQ;GACV,GAAG,wBAAwB,CAAC;EAC9B"}
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../src/compat.ts","../src/client/api.ts","../src/client/CodexSubscriptionSection.tsx","../src/client/locales.ts","../src/client/process-folding.ts","../src/client/styles.ts","../src/client/index.tsx"],"sourcesContent":["/**\n * Compatibility constants for the ChatGPT-backed Codex flow. The backend and\n * OAuth parameters are not a public third-party API contract, so every such\n * value is isolated here for review and rollback.\n */\nexport const CHATGPT_OAUTH_ISSUER = 'https://auth.openai.com' as const\nexport const CHATGPT_OAUTH_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann' as const\nexport const OAUTH_CALLBACK_HOST = 'localhost' as const\nexport const OAUTH_CALLBACK_PORT = 1455 as const\nexport const OAUTH_CALLBACK_PATH = '/auth/callback' as const\nexport const OAUTH_REDIRECT_URI = `http://${OAUTH_CALLBACK_HOST}:${OAUTH_CALLBACK_PORT}${OAUTH_CALLBACK_PATH}` as const\nexport const OAUTH_SCOPE = 'openid profile email offline_access' as const\nexport const OAUTH_ORIGINATOR = 'opencode' as const\nexport const OAUTH_LOGIN_TIMEOUT_MS = 5 * 60_000\nexport const TOKEN_REFRESH_MARGIN_MS = 60_000\nexport const ROUTE_PREFIX = '/api/dsh-chatgpt-subscription' as const\nexport const PLUGIN_VERSION = '0.1.0-alpha.0' as const\n\nexport const CODEX_API_BASE = 'https://chatgpt.com/backend-api/codex' as const\nexport const CODEX_RESPONSES_URL = `${CODEX_API_BASE}/responses` as const\nexport const CODEX_USAGE_URL = 'https://chatgpt.com/backend-api/wham/usage' as const\nexport const CODEX_ORIGINATOR = 'opencode' as const\nexport const QUOTA_CACHE_MS = 60_000\nexport const QUOTA_MIN_UPSTREAM_INTERVAL_MS = 15_000\n\nexport const OAUTH_AUTHORIZE_URL = `${CHATGPT_OAUTH_ISSUER}/oauth/authorize` as const\nexport const OAUTH_TOKEN_URL = `${CHATGPT_OAUTH_ISSUER}/oauth/token` as const\n","import { ROUTE_PREFIX } from '../compat.ts'\nimport type {\n ApiEnvelope,\n LoginEventDto,\n LoginStartDto,\n PluginStatusDto,\n QuotaStatusDto,\n ConnectionTestDto,\n} from '../shared/contracts.ts'\n\nexport class SubscriptionApi {\n status(): Promise<PluginStatusDto> {\n return request<PluginStatusDto>(`${ROUTE_PREFIX}/status`)\n }\n\n startLogin(): Promise<LoginStartDto> {\n return post<LoginStartDto>(`${ROUTE_PREFIX}/login/start`, {})\n }\n\n cancelLogin(loginId: string): Promise<{ cancelled: boolean }> {\n return post(`${ROUTE_PREFIX}/login/cancel`, { loginId })\n }\n\n logout(): Promise<{ authenticated: false }> {\n return post(`${ROUTE_PREFIX}/logout`, {})\n }\n\n refresh(): Promise<PluginStatusDto> {\n return post(`${ROUTE_PREFIX}/token/refresh`, {})\n }\n\n refreshQuota(): Promise<QuotaStatusDto> {\n return post(`${ROUTE_PREFIX}/quota/refresh`, {})\n }\n\n testConnection(): Promise<ConnectionTestDto> {\n return post(`${ROUTE_PREFIX}/connection/test`, {})\n }\n\n events(loginId: string): EventSource {\n return new EventSource(`${ROUTE_PREFIX}/login/events?loginId=${encodeURIComponent(loginId)}`)\n }\n}\n\nasync function post<T>(url: string, body: Record<string, unknown>): Promise<T> {\n return request<T>(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n })\n}\n\nasync function request<T>(url: string, init?: RequestInit): Promise<T> {\n const response = await fetch(url, { ...init, credentials: 'same-origin' })\n const envelope = await response.json() as ApiEnvelope<T>\n if (!response.ok || !envelope.ok) {\n throw new Error(envelope.ok ? `Request failed (${response.status})` : envelope.error.message)\n }\n return envelope.value\n}\n\nexport function parseLoginEvent(event: MessageEvent<string>): LoginEventDto | null {\n try {\n const value = JSON.parse(event.data) as LoginEventDto\n return typeof value === 'object' && value !== null && typeof value.type === 'string' ? value : null\n } catch {\n return null\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { PluginStatusDto, QuotaBucketDto, QuotaWindowDto } from '../shared/contracts.ts'\nimport { SubscriptionApi, parseLoginEvent } from './api.ts'\nimport { NS } from './locales.ts'\n\ntype Props = PropsRuntime<'settings.section'> & PropsLocale<typeof NS>\ntype BusyAction = 'login' | 'token' | 'quota' | 'test' | 'logout' | null\ntype Translate = Props['t']\n\nconst MODELS = ['gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna', 'gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.2']\n\nexport function CodexSubscriptionSection({ t }: Props): React.JSX.Element {\n const apiRef = useRef(new SubscriptionApi())\n const eventSourceRef = useRef<EventSource | null>(null)\n const [status, setStatus] = useState<PluginStatusDto | null>(null)\n const [busy, setBusy] = useState<BusyAction>(null)\n const [error, setError] = useState<string | null>(null)\n const [authUrl, setAuthUrl] = useState<string | null>(null)\n const [popupBlocked, setPopupBlocked] = useState(false)\n const [connection, setConnection] = useState<{ latencyMs: number; checkedAt: number } | null>(null)\n\n const load = useCallback(async (quiet = false) => {\n if (!quiet) setError(null)\n try {\n const next = await apiRef.current.status()\n setStatus(next)\n if (next.error !== undefined) setError(next.error.message)\n } catch (cause) {\n if (!quiet) setError(messageOf(cause))\n }\n }, [])\n\n useEffect(() => {\n void load()\n const refreshWhenVisible = (): void => {\n if (document.visibilityState === 'visible') void load(true)\n }\n document.addEventListener('visibilitychange', refreshWhenVisible)\n const timer = window.setInterval(refreshWhenVisible, 60_000)\n return () => {\n window.clearInterval(timer)\n document.removeEventListener('visibilitychange', refreshWhenVisible)\n eventSourceRef.current?.close()\n }\n }, [load])\n\n const watchLogin = useCallback((loginId: string) => {\n eventSourceRef.current?.close()\n const source = apiRef.current.events(loginId)\n eventSourceRef.current = source\n const finish = async (message?: string): Promise<void> => {\n source.close()\n eventSourceRef.current = null\n setBusy(null)\n setAuthUrl(null)\n if (message !== undefined) setError(message)\n // Preserve the terminal OAuth error while refreshing the account DTO.\n await load(true)\n }\n source.addEventListener('completed', (event) => {\n const parsed = parseLoginEvent(event as MessageEvent<string>)\n if (parsed?.type === 'completed') void finish()\n })\n source.addEventListener('cancelled', () => void finish())\n source.addEventListener('failed', (event) => {\n const parsed = parseLoginEvent(event as MessageEvent<string>)\n void finish(parsed?.type === 'failed' ? parsed.error.message : 'ChatGPT sign-in failed.')\n })\n }, [load])\n\n useEffect(() => {\n const loginId = status?.login.active ? status.login.loginId : null\n if (loginId !== null && loginId !== undefined && eventSourceRef.current === null) watchLogin(loginId)\n }, [status?.login.active, status?.login.loginId, watchLogin])\n\n const startLogin = async (): Promise<void> => {\n setBusy('login')\n setError(null)\n setPopupBlocked(false)\n const popup = window.open('about:blank', 'dsh-chatgpt-oauth', 'popup,width=560,height=760')\n try {\n const login = await apiRef.current.startLogin()\n setAuthUrl(login.authUrl)\n if (popup === null) setPopupBlocked(true)\n else popup.location.replace(login.authUrl)\n watchLogin(login.loginId)\n await load(true)\n } catch (cause) {\n popup?.close()\n setBusy(null)\n setError(messageOf(cause))\n }\n }\n\n const cancelLogin = async (): Promise<void> => {\n const loginId = status?.login.loginId\n if (loginId === null || loginId === undefined) return\n setBusy('login')\n try {\n await apiRef.current.cancelLogin(loginId)\n eventSourceRef.current?.close()\n eventSourceRef.current = null\n setAuthUrl(null)\n await load()\n } catch (cause) {\n setError(messageOf(cause))\n } finally {\n setBusy(null)\n }\n }\n\n const refreshToken = async (): Promise<void> => run('token', async () => {\n setStatus(await apiRef.current.refresh())\n })\n\n const refreshQuota = async (): Promise<void> => run('quota', async () => {\n const quota = await apiRef.current.refreshQuota()\n setStatus((current) => current === null ? current : { ...current, quota })\n })\n\n const testConnection = async (): Promise<void> => run('test', async () => {\n const result = await apiRef.current.testConnection()\n setConnection({ latencyMs: result.latencyMs, checkedAt: result.checkedAt })\n })\n\n const logout = async (): Promise<void> => run('logout', async () => {\n await apiRef.current.logout()\n eventSourceRef.current?.close()\n eventSourceRef.current = null\n setAuthUrl(null)\n setConnection(null)\n await load()\n })\n\n const run = async (action: Exclude<BusyAction, null>, task: () => Promise<void>): Promise<void> => {\n setBusy(action)\n setError(null)\n try {\n await task()\n } catch (cause) {\n setError(messageOf(cause))\n } finally {\n setBusy(null)\n }\n }\n\n const account = status?.account\n return <section className=\"dsh-codex-page\" aria-labelledby=\"dsh-codex-title\">\n <header>\n <h2 id=\"dsh-codex-title\" className=\"dsh-codex-title\">{t('title')}</h2>\n <p className=\"dsh-codex-intro\">{t('intro')}</p>\n </header>\n\n {error !== null ? <div className=\"dsh-codex-errorbar\" role=\"alert\">\n <span>{error}</span>\n {status === null ? <Button disabled={busy !== null} onClick={() => load()}>{t('retry')}</Button> : null}\n </div> : null}\n\n {status === null && error === null ? <Skeleton label={t('loading')} /> : <>\n <Section title={t('account')}>\n <InfoRow label={status?.authenticated ? t('signedIn') : t('signedOut')} value={account?.email ?? '—'} />\n {status?.authenticated ? <>\n <InfoRow label={t('plan')} value={account?.planType ?? t('unknown')} />\n <InfoRow label={t('accountId')} value={account?.accountIdSuffix ?? '—'} />\n <InfoRow label={t('expires')} value={formatDate(account?.tokenExpiresAt)} />\n </> : null}\n <InfoRow label={t('storage')} value={t('storageValue')} />\n <p className=\"dsh-codex-notice\">{t('securityNotice')}</p>\n {status?.login.active ? <p className=\"dsh-codex-muted\" role=\"status\">{t('pending')}</p> : null}\n {popupBlocked ? <p className=\"dsh-codex-error\">{t('popupBlocked')}</p> : null}\n {authUrl !== null ? <a className=\"dsh-codex-link\" href={authUrl} target=\"_blank\" rel=\"noreferrer\">{t('continueLogin')}</a> : null}\n <div className=\"dsh-codex-actions\">\n {status?.login.active\n ? <Button disabled={busy !== null} onClick={cancelLogin}>{t('cancel')}</Button>\n : <Button primary disabled={busy !== null} onClick={startLogin}>{status?.authenticated ? t('signInAgain') : t('signIn')}</Button>}\n {status?.authenticated ? <>\n <Button disabled={busy !== null} onClick={refreshToken}>{t('refreshToken')}</Button>\n <Button disabled={busy !== null} onClick={logout}>{t('signOut')}</Button>\n </> : null}\n </div>\n </Section>\n\n <Section title={t('connection')}>\n <InfoRow label={t('provider')} value=\"Codex(ChatGPT 订阅) · codex-chatgpt\" />\n <InfoRow label={t('connectionState')} value={connection === null ? t('untested') : t('connected')} />\n {connection !== null ? <InfoRow label={t('latency')} value={`${connection.latencyMs} ms · ${formatDate(connection.checkedAt)}`} /> : null}\n <div className=\"dsh-codex-models\" aria-label={t('models')}>\n {MODELS.map((model) => <code key={model}>{model}</code>)}\n </div>\n <div className=\"dsh-codex-actions\">\n <Button disabled={!status?.authenticated || busy !== null} onClick={testConnection}>{busy === 'test' ? t('testing') : t('testConnection')}</Button>\n </div>\n </Section>\n\n <Section title={t('quota')} aside={<Button disabled={!status?.authenticated || busy !== null} onClick={refreshQuota}>{busy === 'quota' ? t('refreshing') : t('refreshQuota')}</Button>}>\n <p className=\"dsh-codex-muted\">{t('quotaIntro')}</p>\n {status?.quota.state === 'signed-out' ? <p className=\"dsh-codex-empty\">{t('quotaSignedOut')}</p> : null}\n {status?.quota.buckets.map((bucket) => <QuotaBucket key={bucket.id} bucket={bucket} t={t} />)}\n {status?.quota.state === 'empty' ? <p className=\"dsh-codex-empty\">{t('noQuota')}</p> : null}\n {status?.quota.stale ? <p className=\"dsh-codex-warning\" role=\"status\">{t('stale')}</p> : null}\n {status?.quota.error ? <p className=\"dsh-codex-error\" role=\"alert\">{status.quota.error.message}</p> : null}\n {status?.quota.fetchedAt ? <p className=\"dsh-codex-timestamp\">{t('updated')}: {formatDate(status.quota.fetchedAt)}</p> : null}\n </Section>\n </>}\n\n <span className=\"dsh-codex-sr\" aria-live=\"polite\">{busy === null ? '' : busy}</span>\n </section>\n}\n\nfunction Section({ title, aside, children }: { title: string; aside?: React.ReactNode; children: React.ReactNode }): React.JSX.Element {\n return <section className=\"dsh-codex-group\">\n <div className=\"dsh-codex-grouphead\"><h3>{title}</h3>{aside}</div>\n {children}\n </section>\n}\n\nfunction Button({ primary = false, disabled, onClick, children }: { primary?: boolean; disabled?: boolean; onClick: () => void | Promise<void>; children: React.ReactNode }): React.JSX.Element {\n return <button className={`dsh-codex-button${primary ? ' dsh-codex-button-primary' : ''}`} type=\"button\" disabled={disabled} onClick={() => void onClick()}>{children}</button>\n}\n\nfunction InfoRow({ label, value }: { label: string; value: string }): React.JSX.Element {\n return <div className=\"dsh-codex-row\"><span className=\"dsh-codex-label\">{label}</span><span className=\"dsh-codex-value\">{value}</span></div>\n}\n\nfunction QuotaBucket({ bucket, t }: { bucket: QuotaBucketDto; t: Translate }): React.JSX.Element {\n return <article className=\"dsh-codex-quota-card\">\n <div className=\"dsh-codex-quota-title\"><strong>{bucket.name}</strong>{bucket.planType ? <span>{bucket.planType}</span> : null}</div>\n {bucket.primary ? <QuotaBar label={windowLabel(bucket.primary.windowDurationMins, t)} window={bucket.primary} t={t} /> : null}\n {bucket.secondary ? <QuotaBar label={windowLabel(bucket.secondary.windowDurationMins, t)} window={bucket.secondary} t={t} /> : null}\n </article>\n}\n\nexport function QuotaBar({ label, window, t }: { label: string; window: QuotaWindowDto; t: Translate }): React.JSX.Element {\n const percent = window.usedPercent\n const level = percent >= 95 ? 'danger' : percent >= 80 ? 'warning' : 'normal'\n const remaining = Math.max(0, 100 - percent)\n return <div className=\"dsh-codex-meter-wrap\">\n <div className=\"dsh-codex-meter-label\"><span>{label}</span><strong>{formatPercent(percent)}</strong></div>\n <div className={`dsh-codex-meter dsh-codex-meter-${level}`} role=\"progressbar\" aria-label={`${label}: ${formatPercent(percent)} ${t('used')}`} aria-valuemin={0} aria-valuemax={100} aria-valuenow={percent}>\n <span style={{ width: `${percent}%` }} />\n </div>\n <div className=\"dsh-codex-meter-meta\">\n <span>{percent >= 100 ? `${t('exhausted')} · ${formatPercent(remaining)} ${t('remaining')}` : `${formatPercent(percent)} ${t('used')} · ${formatPercent(remaining)} ${t('remaining')}`}</span>\n <span>{window.resetsAt === null ? '—' : `${t('resets')}: ${formatReset(window.resetsAt)}`}</span>\n </div>\n </div>\n}\n\nfunction Skeleton({ label }: { label: string }): React.JSX.Element {\n return <div className=\"dsh-codex-skeleton\" role=\"status\" aria-label={label}><span /><span /></div>\n}\n\nexport function windowLabel(minutes: number | null, t: Translate): string {\n if (minutes === null) return t('limitWindow')\n const [value, unit]: [number, Intl.NumberFormatOptions['unit']] = minutes >= 1440 && minutes % 1440 === 0\n ? [minutes / 1440, 'day']\n : minutes >= 60 && minutes % 60 === 0\n ? [minutes / 60, 'hour']\n : [Math.round(minutes), 'minute']\n return `${new Intl.NumberFormat(undefined, { style: 'unit', unit, unitDisplay: 'long' }).format(value)} ${t('limitWindow')}`\n}\n\nfunction formatPercent(value: number): string {\n return `${new Intl.NumberFormat(undefined, { maximumFractionDigits: 1 }).format(value)}%`\n}\n\nfunction formatDate(seconds: number | undefined): string {\n if (seconds === undefined) return '—'\n return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short' }).format(seconds * 1000)\n}\n\nexport function formatReset(seconds: number): string {\n const absolute = formatDate(seconds)\n const diff = seconds * 1000 - Date.now()\n const abs = Math.abs(diff)\n const [amount, unit]: [number, Intl.RelativeTimeFormatUnit] = abs >= 86_400_000\n ? [Math.round(diff / 86_400_000), 'day']\n : abs >= 3_600_000\n ? [Math.round(diff / 3_600_000), 'hour']\n : [Math.round(diff / 60_000), 'minute']\n return `${absolute} (${new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' }).format(amount, unit)})`\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","export const NS = 'dsh-chatgpt-subscription' as const\n\nexport const zh = {\n title: 'Codex 订阅',\n intro: '使用 ChatGPT 账号登录,在 DSH 中使用订阅可用的 Codex 模型。',\n account: '账号',\n signedOut: '尚未登录',\n signedIn: '已登录',\n plan: '套餐',\n accountId: '账号 ID',\n expires: '令牌到期',\n storage: '凭据存储',\n storageValue: 'Windows DPAPI(当前用户加密)',\n securityNotice: '令牌仅保存在 Host 端的 DPAPI 加密文件中,不会进入浏览器、settings.yaml 或日志。',\n signIn: '使用 ChatGPT 登录',\n signInAgain: '重新登录',\n cancel: '取消登录',\n signOut: '注销',\n refreshToken: '刷新凭据',\n pending: '请在浏览器中完成登录。',\n popupBlocked: '浏览器拦截了登录窗口,请使用下面的链接继续。',\n continueLogin: '打开 ChatGPT 登录页',\n loading: '正在读取状态…',\n connection: '连接',\n provider: 'Provider',\n connectionState: '连接状态',\n connected: '可用',\n untested: '尚未测试',\n testConnection: '测试连接',\n testing: '测试中…',\n latency: '最近延迟',\n models: '可用模型',\n quota: '用量与限额',\n quotaIntro: '数据来自 ChatGPT Codex 用量服务。页面可见时最多每 60 秒刷新一次。',\n refreshQuota: '刷新用量',\n refreshing: '刷新中…',\n noQuota: '当前套餐未返回可显示的限额窗口。',\n quotaSignedOut: '登录后可查看订阅限额。',\n stale: '显示的是上次成功获取的数据。',\n updated: '更新时间',\n primary: '主要窗口',\n secondary: '次要窗口',\n limitWindow: '额度',\n used: '已使用',\n remaining: '剩余',\n exhausted: '额度已用尽',\n resets: '重置',\n retry: '重试',\n unknown: '未知',\n} as const\n\nexport const en: Record<keyof typeof zh, string> = {\n title: 'Codex subscription',\n intro: 'Sign in with ChatGPT to use Codex models available to your subscription in DSH.',\n account: 'Account',\n signedOut: 'Not signed in',\n signedIn: 'Signed in',\n plan: 'Plan',\n accountId: 'Account ID',\n expires: 'Token expires',\n storage: 'Credential storage',\n storageValue: 'Windows DPAPI (current-user encrypted)',\n securityNotice: 'Tokens stay in a Host-side DPAPI-encrypted file and never enter the browser, settings.yaml, or logs.',\n signIn: 'Sign in with ChatGPT',\n signInAgain: 'Sign in again',\n cancel: 'Cancel sign-in',\n signOut: 'Sign out',\n refreshToken: 'Refresh credentials',\n pending: 'Complete sign-in in your browser.',\n popupBlocked: 'The sign-in window was blocked. Use the link below to continue.',\n continueLogin: 'Open ChatGPT sign-in',\n loading: 'Reading status…',\n connection: 'Connection',\n provider: 'Provider',\n connectionState: 'Connection status',\n connected: 'Available',\n untested: 'Not tested',\n testConnection: 'Test connection',\n testing: 'Testing…',\n latency: 'Last latency',\n models: 'Available models',\n quota: 'Usage and limits',\n quotaIntro: 'Data comes from the ChatGPT Codex usage service and refreshes at most once per minute while visible.',\n refreshQuota: 'Refresh usage',\n refreshing: 'Refreshing…',\n noQuota: 'Your plan did not return any displayable limit windows.',\n quotaSignedOut: 'Sign in to view subscription limits.',\n stale: 'Showing the last successfully fetched data.',\n updated: 'Updated',\n primary: 'Primary window',\n secondary: 'Secondary window',\n limitWindow: 'limit',\n used: 'used',\n remaining: 'remaining',\n exhausted: 'Quota exhausted',\n resets: 'Resets',\n retry: 'Retry',\n unknown: 'Unknown',\n}\n\nexport type LocaleKey = keyof typeof zh\nexport const dictionaries = { zh, en }\n","const ROW_CLASS = 'dsh-codex-process-row'\nconst GROUP_HEAD_CLASS = 'dsh-codex-process-group-head'\nconst GROUP_COLLAPSED_CLASS = 'dsh-codex-process-group-collapsed'\nconst GROUP_HIDDEN_CLASS = 'dsh-codex-process-group-hidden'\nconst USER_TOGGLED_ATTR = 'data-dsh-codex-process-user-toggled'\nconst TITLE_ATTR = 'data-dsh-codex-process-title'\nconst TITLE = 'Click to expand or collapse process details'\nconst DEFAULT_AUTO_COLLAPSE_MS = 2500\nconst MAX_PROCESS_LABELS_PER_ROW = 3\nconst MAX_SCAN_ROOTS_PER_FRAME = 80\nconst MAX_TEXT_SAMPLE = 20_000\nconst PROCESS_CANDIDATE_SELECTOR = 'article,section,li,div,p,h1,h2,h3,h4,h5,h6,[role=\"listitem\"]'\nconst PROCESS_PREFIX_PATTERN = '(?:上下文注入|Think|Search|Code|代码|Pwsh|PowerShell|Bash|Shell|Read|Glob|Grep|Web(?:\\\\s+Search)?|Tool|工具|思考)'\nconst COMMAND_PATTERN = /(?:Code|代码|Pwsh|PowerShell|Bash|Shell|Read|Glob|Grep|Tool|工具)/i\nconst SEARCH_PATTERN = /(?:Search|Web\\s+Search|搜索)/i\nconst PROCESS_PREFIX_RE = new RegExp(`^\\\\s*(?:[•●◦▪▫·#-]\\\\s*)?${PROCESS_PREFIX_PATTERN}\\\\s*(?:[·::-]|$)`, 'i')\nconst PROCESS_LINE_RE = new RegExp(`(?:^|\\\\n)\\\\s*(?:[•●◦▪▫·#-]\\\\s*)?${PROCESS_PREFIX_PATTERN}\\\\s*(?:[·::-]|$)`, 'gi')\n\nexport interface ProcessFoldingOptions {\n autoCollapseMs?: number\n}\n\ninterface GroupState {\n rows: HTMLElement[]\n click: (event: MouseEvent) => void\n keydown: (event: KeyboardEvent) => void\n timer: ReturnType<typeof setTimeout> | null\n}\n\ninterface PreviousGroupState {\n collapsed: boolean\n userToggled: boolean\n}\n\nexport function installProcessFolding(options: ProcessFoldingOptions = {}): () => void {\n if (typeof document === 'undefined') return () => undefined\n if (document.body === null) {\n let dispose: () => void = () => undefined\n let started = false\n const start = () => {\n if (started) return\n started = true\n dispose = installProcessFolding(options)\n }\n document.addEventListener('DOMContentLoaded', start, { once: true })\n return () => {\n document.removeEventListener('DOMContentLoaded', start)\n dispose()\n }\n }\n\n const autoCollapseMs = options.autoCollapseMs ?? DEFAULT_AUTO_COLLAPSE_MS\n const groups = new Map<HTMLElement, GroupState>()\n const pending = new Set<Element>()\n let frame: number | null = null\n\n const scheduleFlush = () => {\n if (frame !== null) return\n frame = requestAnimationFrame(() => {\n frame = null\n flush()\n })\n }\n\n const queue = (element: Element | null) => {\n if (element === null || !element.isConnected) return\n pending.add(element)\n scheduleFlush()\n }\n\n const scheduleAutoCollapse = (head: HTMLElement) => {\n const state = groups.get(head)\n if (state === undefined || head.hasAttribute(USER_TOGGLED_ATTR)) return\n if (state.timer !== null) clearTimeout(state.timer)\n state.timer = setTimeout(() => {\n state.timer = null\n if (head.isConnected && !head.hasAttribute(USER_TOGGLED_ATTR)) setGroupCollapsed(head, true)\n }, autoCollapseMs)\n }\n\n const syncGroup = (rows: HTMLElement[], previous: PreviousGroupState | undefined) => {\n const head = rows[0]\n const title = titleForProcessRows(rows)\n const click = (event: MouseEvent) => {\n if (isInteractiveTarget(event.target)) return\n markUserToggled(head)\n setGroupCollapsed(head, !head.classList.contains(GROUP_COLLAPSED_CLASS))\n }\n const keydown = (event: KeyboardEvent) => {\n if (event.key !== 'Enter' && event.key !== ' ') return\n event.preventDefault()\n markUserToggled(head)\n setGroupCollapsed(head, !head.classList.contains(GROUP_COLLAPSED_CLASS))\n }\n\n groups.set(head, { rows, click, keydown, timer: null })\n for (const row of rows) row.classList.add(ROW_CLASS)\n head.classList.add(GROUP_HEAD_CLASS)\n if (!head.hasAttribute('tabindex')) head.tabIndex = 0\n head.setAttribute('aria-expanded', String(!(previous?.collapsed ?? false)))\n head.setAttribute(TITLE_ATTR, title)\n head.title ||= TITLE\n if (previous?.userToggled === true) head.setAttribute(USER_TOGGLED_ATTR, 'true')\n head.addEventListener('click', click)\n head.addEventListener('keydown', keydown)\n setGroupCollapsed(head, previous?.collapsed ?? false)\n scheduleAutoCollapse(head)\n }\n\n const rebuildParentGroups = (parent: Element) => {\n const previous = new Map<HTMLElement, PreviousGroupState>()\n for (const [head, state] of groups) {\n if (head.parentElement !== parent) continue\n previous.set(head, {\n collapsed: head.classList.contains(GROUP_COLLAPSED_CLASS),\n userToggled: head.hasAttribute(USER_TOGGLED_ATTR),\n })\n cleanupGroup(head, state)\n groups.delete(head)\n }\n\n let rows: HTMLElement[] = []\n const flushRows = () => {\n if (rows.length > 0) syncGroup(rows, previous.get(rows[0]))\n rows = []\n }\n\n for (const child of Array.from(parent.children)) {\n if (child instanceof HTMLElement && isProcessRow(child)) {\n rows.push(child)\n } else {\n flushRows()\n }\n }\n flushRows()\n }\n\n const flush = () => {\n const parents = new Set<Element>()\n let scanned = 0\n for (const root of Array.from(pending)) {\n pending.delete(root)\n if (!root.isConnected) continue\n for (const row of findProcessRows(root)) {\n if (row.parentElement !== null) parents.add(row.parentElement)\n }\n const grouped = nearestGroupHead(root)\n if (grouped !== null && grouped.parentElement !== null) parents.add(grouped.parentElement)\n scanned++\n if (scanned >= MAX_SCAN_ROOTS_PER_FRAME && pending.size > 0) {\n scheduleFlush()\n break\n }\n }\n for (const parent of parents) rebuildParentGroups(parent)\n }\n\n const observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n if (mutation.type === 'characterData') {\n queue(nodeElement(mutation.target)?.closest(PROCESS_CANDIDATE_SELECTOR) ?? nodeElement(mutation.target))\n continue\n }\n for (const node of mutation.addedNodes) queue(nodeElement(node))\n }\n })\n observer.observe(document.body, { childList: true, characterData: true, subtree: true })\n queue(document.body)\n\n return () => {\n observer.disconnect()\n if (frame !== null) cancelAnimationFrame(frame)\n pending.clear()\n for (const [head, state] of groups) cleanupGroup(head, state)\n groups.clear()\n }\n}\n\nfunction cleanupGroup(head: HTMLElement, state: GroupState): void {\n if (state.timer !== null) clearTimeout(state.timer)\n head.removeEventListener('click', state.click)\n head.removeEventListener('keydown', state.keydown)\n for (const row of state.rows) row.classList.remove(ROW_CLASS, GROUP_HIDDEN_CLASS)\n head.classList.remove(GROUP_HEAD_CLASS, GROUP_COLLAPSED_CLASS)\n head.removeAttribute('aria-expanded')\n head.removeAttribute(USER_TOGGLED_ATTR)\n head.removeAttribute(TITLE_ATTR)\n if (head.title === TITLE) head.removeAttribute('title')\n}\n\nfunction findProcessRows(root: Element): HTMLElement[] {\n const rows: HTMLElement[] = []\n if (root instanceof HTMLElement && isProcessRow(root)) rows.push(root)\n for (const element of root.querySelectorAll(PROCESS_CANDIDATE_SELECTOR)) {\n if (element instanceof HTMLElement && isProcessRow(element)) rows.push(element)\n }\n return rows\n}\n\nfunction isProcessRow(element: HTMLElement): boolean {\n if (element.closest('.dsh-codex-page') !== null || shouldIgnore(element)) return false\n const raw = (element.textContent ?? '').slice(0, MAX_TEXT_SAMPLE)\n const normalized = raw.replace(/\\s+/g, ' ').trim()\n if (!PROCESS_PREFIX_RE.test(normalized)) return false\n const stats = processTextStats(raw)\n if (stats.processLabels === 0 || stats.processLabels > MAX_PROCESS_LABELS_PER_ROW) return false\n return !(element.children.length > 0 && stats.hasNonProcessLine)\n}\n\nfunction processTextStats(text: string): { processLabels: number; hasNonProcessLine: boolean } {\n PROCESS_LINE_RE.lastIndex = 0\n let processLabels = 0\n while (PROCESS_LINE_RE.exec(text) !== null) processLabels++\n const hasNonProcessLine = text.split(/\\r?\\n/)\n .map((line) => line.replace(/\\s+/g, ' ').trim())\n .some((line) => line !== '' && !PROCESS_PREFIX_RE.test(line))\n return { processLabels, hasNonProcessLine }\n}\n\nfunction setGroupCollapsed(head: HTMLElement, collapsed: boolean): void {\n const state = findCurrentGroupState(head)\n if (state === null) return\n head.classList.toggle(GROUP_COLLAPSED_CLASS, collapsed)\n head.setAttribute('aria-expanded', String(!collapsed))\n for (const row of state.rows.slice(1)) row.classList.toggle(GROUP_HIDDEN_CLASS, collapsed)\n}\n\nfunction findCurrentGroupState(head: HTMLElement): { rows: HTMLElement[] } | null {\n const rows: HTMLElement[] = [head]\n let sibling = head.nextElementSibling\n while (sibling instanceof HTMLElement && isProcessRow(sibling)) {\n rows.push(sibling)\n sibling = sibling.nextElementSibling\n }\n return rows.length > 0 ? { rows } : null\n}\n\nfunction markUserToggled(head: HTMLElement): void {\n head.setAttribute(USER_TOGGLED_ATTR, 'true')\n}\n\nfunction nearestGroupHead(element: Element): HTMLElement | null {\n const decorated = element.closest(`.${GROUP_HEAD_CLASS}`)\n return decorated instanceof HTMLElement ? decorated : null\n}\n\nfunction titleForProcessRows(rows: HTMLElement[]): string {\n const text = rows.map((row) => row.textContent ?? '').join('\\n')\n if (COMMAND_PATTERN.test(text)) return '运行了命令'\n if (SEARCH_PATTERN.test(text)) return '进行了搜索'\n return '思考过程'\n}\n\nfunction nodeElement(node: Node): Element | null {\n if (node instanceof Element) return node\n return node.parentElement\n}\n\nfunction shouldIgnore(element: HTMLElement): boolean {\n return element.closest('textarea,input,select,button,a,[contenteditable=\"true\"],script,style') !== null\n}\n\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n return target instanceof Element && target.closest('button,a,input,textarea,select,[role=\"button\"],[contenteditable=\"true\"]') !== null\n}\n","const STYLE_ID = '@eddyskywalker/dsh-chatgpt-subscription/main'\n\nconst CSS = `\n.dsh-codex-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}\n.dsh-codex-page *{box-sizing:border-box}\n.dsh-codex-title{font-size:15px;font-weight:650;line-height:1.4;margin:0 0 5px}\n.dsh-codex-intro,.dsh-codex-muted{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55;margin:0}\n.dsh-codex-group{border-top:1px solid var(--dsw-alias-border-l2);min-width:0}\n.dsh-codex-grouphead{align-items:center;display:flex;gap:12px;justify-content:space-between;min-height:48px}\n.dsh-codex-grouphead h3{font-size:14px;font-weight:650;margin:0}\n.dsh-codex-row{align-items:center;border-bottom:1px solid var(--dsw-alias-border-l2);display:flex;gap:20px;justify-content:space-between;min-height:44px;padding:8px 0}\n.dsh-codex-label{color:var(--dsw-alias-label-secondary);font-size:13px;flex:0 0 auto}\n.dsh-codex-value{font-size:13px;min-width:0;overflow-wrap:anywhere;text-align:right}\n.dsh-codex-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;padding-top:12px}\n.dsh-codex-button{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:13px;line-height:1;padding:8px 13px;white-space:nowrap}\n.dsh-codex-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}\n.dsh-codex-button:focus-visible,.dsh-codex-link:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}\n.dsh-codex-button:disabled{cursor:default;opacity:.5}\n.dsh-codex-button-primary{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}\n.dsh-codex-notice{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55;margin:12px 0 0;padding:10px 12px}\n.dsh-codex-error,.dsh-codex-warning{font-size:12px;line-height:1.5;margin:8px 0 0}\n.dsh-codex-error{color:var(--dsw-alias-label-danger,#d94b4b)}\n.dsh-codex-warning{color:var(--dsw-alias-label-warning,#c77a18)}\n.dsh-codex-errorbar{align-items:center;background:color-mix(in srgb,var(--dsw-alias-label-danger,#d94b4b) 9%,transparent);border:1px solid color-mix(in srgb,var(--dsw-alias-label-danger,#d94b4b) 28%,transparent);border-radius:7px;color:var(--dsw-alias-label-danger,#d94b4b);display:flex;font-size:13px;gap:12px;justify-content:space-between;padding:10px 12px}\n.dsh-codex-link{color:var(--dsw-alias-label-link,#3278d4);display:inline-block;font-size:13px;margin-top:8px}\n.dsh-codex-models{display:flex;flex-wrap:wrap;gap:6px;padding-top:12px}\n.dsh-codex-models code{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:5px;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:4px 6px}\n.dsh-codex-quota-card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}\n.dsh-codex-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between}\n.dsh-codex-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}\n.dsh-codex-meter-wrap{margin-top:13px}\n.dsh-codex-meter-label,.dsh-codex-meter-meta{display:flex;gap:10px;justify-content:space-between}\n.dsh-codex-meter-label{font-size:12px;margin-bottom:6px}\n.dsh-codex-meter-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45;margin-top:6px}\n.dsh-codex-meter{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.15));border-radius:999px;height:7px;overflow:hidden;width:100%}\n.dsh-codex-meter>span{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:inherit;display:block;height:100%;max-width:100%;min-width:0;transition:width .25s ease}\n.dsh-codex-meter-warning>span{background:var(--dsw-alias-label-warning,#d58a24)}\n.dsh-codex-meter-danger>span{background:var(--dsw-alias-label-danger,#d94b4b)}\n.dsh-codex-empty{border:1px dashed var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;margin:12px 0 0;padding:16px;text-align:center}\n.dsh-codex-timestamp{color:var(--dsw-alias-label-tertiary);font-size:11px;margin:10px 0 0;text-align:right}\n.dsh-codex-skeleton{display:grid;gap:9px;padding-top:10px}\n.dsh-codex-skeleton span{animation:dsh-codex-pulse 1.4s ease-in-out infinite;background:var(--dsw-alias-bg-layer-2);border-radius:5px;height:42px}\n.dsh-codex-skeleton span:nth-child(2){animation-delay:.12s}.dsh-codex-skeleton span:nth-child(3){animation-delay:.24s}\n.dsh-codex-sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0 0 0 0);white-space:nowrap}\n.dsh-codex-process-group-head{border-radius:6px;cursor:pointer;transition:background-color .15s ease,opacity .15s ease}\n.dsh-codex-process-group-head:hover{background:color-mix(in srgb,var(--dsw-alias-bg-layer-2,rgba(127,127,127,.18)) 72%,transparent)}\n.dsh-codex-process-group-head:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}\n.dsh-codex-process-group-head.dsh-codex-process-group-collapsed{align-items:center!important;color:transparent!important;display:flex!important;font-size:0!important;line-height:28px!important;max-height:28px!important;min-height:28px!important;overflow:hidden!important;opacity:.78}\n.dsh-codex-process-group-head.dsh-codex-process-group-collapsed>*{display:none!important}\n.dsh-codex-process-group-head.dsh-codex-process-group-collapsed::before{color:var(--dsw-alias-label-secondary);content:\"▸ \" attr(data-dsh-codex-process-title);display:block;font-size:13px;line-height:28px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsh-codex-process-group-hidden{display:none!important}\n@keyframes dsh-codex-pulse{0%,100%{opacity:.55}50%{opacity:1}}\n@media(max-width:560px){.dsh-codex-row{align-items:flex-start;flex-direction:column;gap:3px}.dsh-codex-value{text-align:left}.dsh-codex-actions{justify-content:flex-start}.dsh-codex-grouphead{align-items:flex-start;flex-direction:column;gap:0;padding:12px 0}.dsh-codex-meter-meta{align-items:flex-start;flex-direction:column;gap:2px}.dsh-codex-errorbar{align-items:flex-start;flex-direction:column}}\n@media(prefers-reduced-motion:reduce){.dsh-codex-meter>span,.dsh-codex-process-group-head{transition:none}.dsh-codex-skeleton span{animation:none}}\n`\n\nexport function installStyles(): () => void {\n if (document.querySelector(`style[data-plugin-css=\"${STYLE_ID}\"]`) !== null) return () => undefined\n const element = document.createElement('style')\n element.dataset.plugin = '@eddyskywalker/dsh-chatgpt-subscription'\n element.dataset.pluginCss = STYLE_ID\n element.textContent = CSS\n document.head.appendChild(element)\n return () => element.remove()\n}\n","import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { CodexSubscriptionSection } from './CodexSubscriptionSection.tsx'\nimport { dictionaries, NS, type LocaleKey } from './locales.ts'\nimport { installProcessFolding } from './process-folding.ts'\nimport { installStyles } from './styles.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'dsh-chatgpt-subscription': LocaleKey\n }\n}\n\nexport const inject = ['slots', 'locale']\n\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => ctx.locale.register(NS, dictionaries), 'dsh-chatgpt-subscription: dictionaries')\n ctx.effect(() => installStyles(), 'dsh-chatgpt-subscription: styles')\n ctx.effect(() => installProcessFolding(), 'dsh-chatgpt-subscription: process folding')\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'codex-subscription',\n order: 45,\n label: 'Codex 订阅',\n locale: NS,\n }, CodexSubscriptionSection))\n}\n"],"mappings":";;;;;;;;EAeA,MAAa,eAAe;;;ECL5B,IAAa,kBAAb,MAA6B;GAC3B,SAAmC;IACjC,OAAO,QAAyB,GAAG,aAAa,QAAQ;GAC1D;GAEA,aAAqC;IACnC,OAAO,KAAoB,GAAG,aAAa,eAAe,CAAC,CAAC;GAC9D;GAEA,YAAY,SAAkD;IAC5D,OAAO,KAAK,GAAG,aAAa,gBAAgB,EAAE,QAAQ,CAAC;GACzD;GAEA,SAA4C;IAC1C,OAAO,KAAK,GAAG,aAAa,UAAU,CAAC,CAAC;GAC1C;GAEA,UAAoC;IAClC,OAAO,KAAK,GAAG,aAAa,iBAAiB,CAAC,CAAC;GACjD;GAEA,eAAwC;IACtC,OAAO,KAAK,GAAG,aAAa,iBAAiB,CAAC,CAAC;GACjD;GAEA,iBAA6C;IAC3C,OAAO,KAAK,GAAG,aAAa,mBAAmB,CAAC,CAAC;GACnD;GAEA,OAAO,SAA8B;IACnC,OAAO,IAAI,YAAY,GAAG,aAAa,wBAAwB,mBAAmB,OAAO,GAAG;GAC9F;EACF;EAEA,eAAe,KAAQ,KAAa,MAA2C;GAC7E,OAAO,QAAW,KAAK;IACrB,QAAQ;IACR,SAAS,EAAE,gBAAgB,mBAAmB;IAC9C,MAAM,KAAK,UAAU,IAAI;GAC3B,CAAC;EACH;EAEA,eAAe,QAAW,KAAa,MAAgC;GACrE,MAAM,WAAW,MAAM,MAAM,KAAK;IAAE,GAAG;IAAM,aAAa;GAAc,CAAC;GACzE,MAAM,WAAW,MAAM,SAAS,KAAK;GACrC,IAAI,CAAC,SAAS,MAAM,CAAC,SAAS,IAC5B,MAAM,IAAI,MAAM,SAAS,KAAK,mBAAmB,SAAS,OAAO,KAAK,SAAS,MAAM,OAAO;GAE9F,OAAO,SAAS;EAClB;EAEA,SAAgB,gBAAgB,OAAmD;GACjF,IAAI;IACF,MAAM,QAAQ,KAAK,MAAM,MAAM,IAAI;IACnC,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAO,MAAM,SAAS,WAAW,QAAQ;GACjG,QAAQ;IACN,OAAO;GACT;EACF;;;EC1DA,MAAM,SAAS;GAAC;GAAe;GAAiB;GAAgB;GAAW;GAAW;GAAgB;EAAS;EAE/G,SAAgB,yBAAyB,EAAE,KAA+B;GACxE,MAAM,UAAA,GAAA,MAAA,OAAA,CAAgB,IAAI,gBAAgB,CAAC;GAC3C,MAAM,kBAAA,GAAA,MAAA,OAAA,CAA4C,IAAI;GACtD,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAA8C,IAAI;GACjE,MAAM,CAAC,MAAM,YAAA,GAAA,MAAA,SAAA,CAAgC,IAAI;GACjD,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAAoC,IAAI;GACtD,MAAM,CAAC,SAAS,eAAA,GAAA,MAAA,SAAA,CAAsC,IAAI;GAC1D,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA4B,KAAK;GACtD,MAAM,CAAC,YAAY,kBAAA,GAAA,MAAA,SAAA,CAA2E,IAAI;GAElG,MAAM,QAAA,GAAA,MAAA,YAAA,CAAmB,OAAO,QAAQ,UAAU;IAChD,IAAI,CAAC,OAAO,SAAS,IAAI;IACzB,IAAI;KACF,MAAM,OAAO,MAAM,OAAO,QAAQ,OAAO;KACzC,UAAU,IAAI;KACd,IAAI,KAAK,UAAU,KAAA,GAAW,SAAS,KAAK,MAAM,OAAO;IAC3D,SAAS,OAAO;KACd,IAAI,CAAC,OAAO,SAAS,UAAU,KAAK,CAAC;IACvC;GACF,GAAG,CAAC,CAAC;GAEL,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,KAAU;IACV,MAAM,2BAAiC;KACrC,IAAI,SAAS,oBAAoB,WAAW,KAAU,IAAI;IAC5D;IACA,SAAS,iBAAiB,oBAAoB,kBAAkB;IAChE,MAAM,QAAQ,OAAO,YAAY,oBAAoB,GAAM;IAC3D,aAAa;KACX,OAAO,cAAc,KAAK;KAC1B,SAAS,oBAAoB,oBAAoB,kBAAkB;KACnE,eAAe,SAAS,MAAM;IAChC;GACF,GAAG,CAAC,IAAI,CAAC;GAET,MAAM,cAAA,GAAA,MAAA,YAAA,EAA0B,YAAoB;IAClD,eAAe,SAAS,MAAM;IAC9B,MAAM,SAAS,OAAO,QAAQ,OAAO,OAAO;IAC5C,eAAe,UAAU;IACzB,MAAM,SAAS,OAAO,YAAoC;KACxD,OAAO,MAAM;KACb,eAAe,UAAU;KACzB,QAAQ,IAAI;KACZ,WAAW,IAAI;KACf,IAAI,YAAY,KAAA,GAAW,SAAS,OAAO;KAE3C,MAAM,KAAK,IAAI;IACjB;IACA,OAAO,iBAAiB,cAAc,UAAU;KAE9C,IADe,gBAAgB,KACtB,CAAC,EAAE,SAAS,aAAa,OAAY;IAChD,CAAC;IACD,OAAO,iBAAiB,mBAAmB,KAAK,OAAO,CAAC;IACxD,OAAO,iBAAiB,WAAW,UAAU;KAC3C,MAAM,SAAS,gBAAgB,KAA6B;KAC5D,OAAY,QAAQ,SAAS,WAAW,OAAO,MAAM,UAAU,yBAAyB;IAC1F,CAAC;GACH,GAAG,CAAC,IAAI,CAAC;GAET,CAAA,GAAA,MAAA,UAAA,OAAgB;IACd,MAAM,UAAU,QAAQ,MAAM,SAAS,OAAO,MAAM,UAAU;IAC9D,IAAI,YAAY,QAAQ,YAAY,KAAA,KAAa,eAAe,YAAY,MAAM,WAAW,OAAO;GACtG,GAAG;IAAC,QAAQ,MAAM;IAAQ,QAAQ,MAAM;IAAS;GAAU,CAAC;GAE5D,MAAM,aAAa,YAA2B;IAC5C,QAAQ,OAAO;IACf,SAAS,IAAI;IACb,gBAAgB,KAAK;IACrB,MAAM,QAAQ,OAAO,KAAK,eAAe,qBAAqB,4BAA4B;IAC1F,IAAI;KACF,MAAM,QAAQ,MAAM,OAAO,QAAQ,WAAW;KAC9C,WAAW,MAAM,OAAO;KACxB,IAAI,UAAU,MAAM,gBAAgB,IAAI;UACnC,MAAM,SAAS,QAAQ,MAAM,OAAO;KACzC,WAAW,MAAM,OAAO;KACxB,MAAM,KAAK,IAAI;IACjB,SAAS,OAAO;KACd,OAAO,MAAM;KACb,QAAQ,IAAI;KACZ,SAAS,UAAU,KAAK,CAAC;IAC3B;GACF;GAEA,MAAM,cAAc,YAA2B;IAC7C,MAAM,UAAU,QAAQ,MAAM;IAC9B,IAAI,YAAY,QAAQ,YAAY,KAAA,GAAW;IAC/C,QAAQ,OAAO;IACf,IAAI;KACF,MAAM,OAAO,QAAQ,YAAY,OAAO;KACxC,eAAe,SAAS,MAAM;KAC9B,eAAe,UAAU;KACzB,WAAW,IAAI;KACf,MAAM,KAAK;IACb,SAAS,OAAO;KACd,SAAS,UAAU,KAAK,CAAC;IAC3B,UAAU;KACR,QAAQ,IAAI;IACd;GACF;GAEA,MAAM,eAAe,YAA2B,IAAI,SAAS,YAAY;IACvE,UAAU,MAAM,OAAO,QAAQ,QAAQ,CAAC;GAC1C,CAAC;GAED,MAAM,eAAe,YAA2B,IAAI,SAAS,YAAY;IACvE,MAAM,QAAQ,MAAM,OAAO,QAAQ,aAAa;IAChD,WAAW,YAAY,YAAY,OAAO,UAAU;KAAE,GAAG;KAAS;IAAM,CAAC;GAC3E,CAAC;GAED,MAAM,iBAAiB,YAA2B,IAAI,QAAQ,YAAY;IACxE,MAAM,SAAS,MAAM,OAAO,QAAQ,eAAe;IACnD,cAAc;KAAE,WAAW,OAAO;KAAW,WAAW,OAAO;IAAU,CAAC;GAC5E,CAAC;GAED,MAAM,SAAS,YAA2B,IAAI,UAAU,YAAY;IAClE,MAAM,OAAO,QAAQ,OAAO;IAC5B,eAAe,SAAS,MAAM;IAC9B,eAAe,UAAU;IACzB,WAAW,IAAI;IACf,cAAc,IAAI;IAClB,MAAM,KAAK;GACb,CAAC;GAED,MAAM,MAAM,OAAO,QAAmC,SAA6C;IACjG,QAAQ,MAAM;IACd,SAAS,IAAI;IACb,IAAI;KACF,MAAM,KAAK;IACb,SAAS,OAAO;KACd,SAAS,UAAU,KAAK,CAAC;IAC3B,UAAU;KACR,QAAQ,IAAI;IACd;GACF;GAEA,MAAM,UAAU,QAAQ;GACxB,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAU;IAAiB,mBAAgB;cAApD;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;MAAI,IAAG;MAAkB,WAAU;gBAAmB,EAAE,OAAO;KAAM,CAAA,GACrE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;MAAG,WAAU;gBAAmB,EAAE,OAAO;KAAK,CAAA,CACxC,EAAA,CAAA;KAEP,UAAU,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;MAAqB,MAAK;gBAAzC,CAChB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,MAAY,CAAA,GAClB,WAAW,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAQ,UAAU,SAAS;OAAM,eAAe,KAAK;iBAAI,EAAE,OAAO;MAAU,CAAA,IAAI,IAChG;UAAI;KAER,WAAW,QAAQ,UAAU,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAU,OAAO,EAAE,SAAS,EAAI,CAAA,IAAI,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;MACvE,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAS,OAAO,EAAE,SAAS;iBAA3B;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,QAAQ,gBAAgB,EAAE,UAAU,IAAI,EAAE,WAAW;SAAG,OAAO,SAAS,SAAS;QAAM,CAAA;QACtG,QAAQ,gBAAgB,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA;SACvB,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;UAAS,OAAO,EAAE,MAAM;UAAG,OAAO,SAAS,YAAY,EAAE,SAAS;SAAI,CAAA;SACtE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;UAAS,OAAO,EAAE,WAAW;UAAG,OAAO,SAAS,mBAAmB;SAAM,CAAA;SACzE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;UAAS,OAAO,EAAE,SAAS;UAAG,OAAO,WAAW,SAAS,cAAc;SAAI,CAAA;QAC3E,EAAA,CAAA,IAAI;QACN,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,EAAE,SAAS;SAAG,OAAO,EAAE,cAAc;QAAI,CAAA;QACzD,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAoB,EAAE,gBAAgB;QAAK,CAAA;QACvD,QAAQ,MAAM,SAAS,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAkB,MAAK;mBAAU,EAAE,SAAS;QAAK,CAAA,IAAI;QACzF,eAAe,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAmB,EAAE,cAAc;QAAK,CAAA,IAAI;QACxE,YAAY,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAiB,MAAM;SAAS,QAAO;SAAS,KAAI;mBAAc,EAAE,eAAe;QAAK,CAAA,IAAI;QAC7H,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAU;mBAAf,CACG,QAAQ,MAAM,SACX,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,UAAU,SAAS;UAAM,SAAS;oBAAc,EAAE,QAAQ;SAAU,CAAA,IAC5E,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,SAAA;UAAQ,UAAU,SAAS;UAAM,SAAS;oBAAa,QAAQ,gBAAgB,EAAE,aAAa,IAAI,EAAE,QAAQ;SAAU,CAAA,GACjI,QAAQ,gBAAgB,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACvB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,UAAU,SAAS;UAAM,SAAS;oBAAe,EAAE,cAAc;SAAU,CAAA,GACnF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,UAAU,SAAS;UAAM,SAAS;oBAAS,EAAE,SAAS;SAAU,CAAA,CACxE,EAAA,CAAA,IAAI,IACH;;OACE;;MAET,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAS,OAAO,EAAE,YAAY;iBAA9B;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,EAAE,UAAU;SAAG,OAAM;QAAqC,CAAA;QAC1E,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,EAAE,iBAAiB;SAAG,OAAO,eAAe,OAAO,EAAE,UAAU,IAAI,EAAE,WAAW;QAAI,CAAA;QACnG,eAAe,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;SAAS,OAAO,EAAE,SAAS;SAAG,OAAO,GAAG,WAAW,UAAU,QAAQ,WAAW,WAAW,SAAS;QAAM,CAAA,IAAI;QACrI,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAU;SAAmB,cAAY,EAAE,QAAQ;mBACrD,OAAO,KAAK,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAmB,MAAY,GAApB,KAAoB,CAAC;QACpD,CAAA;QACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAU;mBACb,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;UAAQ,UAAU,CAAC,QAAQ,iBAAiB,SAAS;UAAM,SAAS;oBAAiB,SAAS,SAAS,EAAE,SAAS,IAAI,EAAE,gBAAgB;SAAU,CAAA;QAC/I,CAAA;OACE;;MAET,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAS,OAAO,EAAE,OAAO;OAAG,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAQ,UAAU,CAAC,QAAQ,iBAAiB,SAAS;QAAM,SAAS;kBAAe,SAAS,UAAU,EAAE,YAAY,IAAI,EAAE,cAAc;OAAU,CAAA;iBAArL;QACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAmB,EAAE,YAAY;QAAK,CAAA;QAClD,QAAQ,MAAM,UAAU,eAAe,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAmB,EAAE,gBAAgB;QAAK,CAAA,IAAI;QAClG,QAAQ,MAAM,QAAQ,KAAK,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;SAAqC;SAAW;QAAI,GAAlC,OAAO,EAA2B,CAAC;QAC3F,QAAQ,MAAM,UAAU,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;mBAAmB,EAAE,SAAS;QAAK,CAAA,IAAI;QACtF,QAAQ,MAAM,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAoB,MAAK;mBAAU,EAAE,OAAO;QAAK,CAAA,IAAI;QACxF,QAAQ,MAAM,QAAQ,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;SAAG,WAAU;SAAkB,MAAK;mBAAS,OAAO,MAAM,MAAM;QAAW,CAAA,IAAI;QACrG,QAAQ,MAAM,YAAY,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;SAAG,WAAU;mBAAb;UAAoC,EAAE,SAAS;UAAE;UAAG,WAAW,OAAO,MAAM,SAAS;SAAK;aAAI;OAClH;;KACT,EAAA,CAAA;KAEF,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAU;MAAe,aAAU;gBAAU,SAAS,OAAO,KAAK;KAAW,CAAA;IAC5E;;EACX;EAEA,SAAS,QAAQ,EAAE,OAAO,OAAO,YAAsG;GACrI,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAU;cAAnB,CACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;eAAf,CAAqC,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD,EAAA,UAAK,MAAU,CAAA,GAAE,KAAW;QAChE,QACM;;EACX;EAEA,SAAS,OAAO,EAAE,UAAU,OAAO,UAAU,SAAS,YAA0I;GAC9L,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;IAAQ,WAAW,mBAAmB,UAAU,8BAA8B;IAAM,MAAK;IAAmB;IAAU,eAAe,KAAK,QAAQ;IAAI;GAAiB,CAAA;EAChL;EAEA,SAAS,QAAQ,EAAE,OAAO,SAA8D;GACtF,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;cAAf,CAA+B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;eAAmB;IAAY,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAU;eAAmB;IAAY,CAAA,CAAM;;EAC7I;EAEA,SAAS,YAAY,EAAE,QAAQ,KAAkE;GAC/F,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,WAAD;IAAS,WAAU;cAAnB;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CAAuC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,OAAO,KAAa,CAAA,GAAE,OAAO,WAAW,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,OAAO,SAAe,CAAA,IAAI,IAAU;;KAClI,OAAO,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAU,OAAO,YAAY,OAAO,QAAQ,oBAAoB,CAAC;MAAG,QAAQ,OAAO;MAAY;KAAI,CAAA,IAAI;KACxH,OAAO,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;MAAU,OAAO,YAAY,OAAO,UAAU,oBAAoB,CAAC;MAAG,QAAQ,OAAO;MAAc;KAAI,CAAA,IAAI;IACxH;;EACX;EAEA,SAAgB,SAAS,EAAE,OAAO,QAAQ,KAAiF;GACzH,MAAM,UAAU,OAAO;GACvB,MAAM,QAAQ,WAAW,KAAK,WAAW,WAAW,KAAK,YAAY;GACrE,MAAM,YAAY,KAAK,IAAI,GAAG,MAAM,OAAO;GAC3C,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;cAAf;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CAAuC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,MAAY,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD,EAAA,UAAS,cAAc,OAAO,EAAU,CAAA,CAAM;;KACzG,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAW,mCAAmC;MAAS,MAAK;MAAc,cAAY,GAAG,MAAM,IAAI,cAAc,OAAO,EAAE,GAAG,EAAE,MAAM;MAAK,iBAAe;MAAG,iBAAe;MAAK,iBAAe;gBAClM,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,EAAI,CAAA;KACrC,CAAA;KACL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,WAAW,MAAM,GAAG,EAAE,WAAW,EAAE,KAAK,cAAc,SAAS,EAAE,GAAG,EAAE,WAAW,MAAM,GAAG,cAAc,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,cAAc,SAAS,EAAE,GAAG,EAAE,WAAW,IAAU,CAAA,GAC7L,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,OAAO,aAAa,OAAO,MAAM,GAAG,EAAE,QAAQ,EAAE,IAAI,YAAY,OAAO,QAAQ,IAAU,CAAA,CAC7F;;IACF;;EACP;EAEA,SAAS,SAAS,EAAE,SAA+C;GACjE,OAAO,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;IAAqB,MAAK;IAAS,cAAY;cAA9D,CAAqE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,CAAO,CAAA,GAAC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,CAAO,CAAA,CAAM;;EACnG;EAEA,SAAgB,YAAY,SAAwB,GAAsB;GACxE,IAAI,YAAY,MAAM,OAAO,EAAE,aAAa;GAC5C,MAAM,CAAC,OAAO,QAAoD,WAAW,QAAQ,UAAU,SAAS,IACpG,CAAC,UAAU,MAAM,KAAK,IACtB,WAAW,MAAM,UAAU,OAAO,IAChC,CAAC,UAAU,IAAI,MAAM,IACrB,CAAC,KAAK,MAAM,OAAO,GAAG,QAAQ;GACpC,OAAO,GAAG,IAAI,KAAK,aAAa,KAAA,GAAW;IAAE,OAAO;IAAQ;IAAM,aAAa;GAAO,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,GAAG,EAAE,aAAa;EAC3H;EAEA,SAAS,cAAc,OAAuB;GAC5C,OAAO,GAAG,IAAI,KAAK,aAAa,KAAA,GAAW,EAAE,uBAAuB,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE;EACzF;EAEA,SAAS,WAAW,SAAqC;GACvD,IAAI,YAAY,KAAA,GAAW,OAAO;GAClC,OAAO,IAAI,KAAK,eAAe,KAAA,GAAW;IAAE,WAAW;IAAU,WAAW;GAAQ,CAAC,CAAC,CAAC,OAAO,UAAU,GAAI;EAC9G;EAEA,SAAgB,YAAY,SAAyB;GACnD,MAAM,WAAW,WAAW,OAAO;GACnC,MAAM,OAAO,UAAU,MAAO,KAAK,IAAI;GACvC,MAAM,MAAM,KAAK,IAAI,IAAI;GACzB,MAAM,CAAC,QAAQ,QAA+C,OAAO,QACjE,CAAC,KAAK,MAAM,OAAO,KAAU,GAAG,KAAK,IACrC,OAAO,OACL,CAAC,KAAK,MAAM,OAAO,IAAS,GAAG,MAAM,IACrC,CAAC,KAAK,MAAM,OAAO,GAAM,GAAG,QAAQ;GAC1C,OAAO,GAAG,SAAS,IAAI,IAAI,KAAK,mBAAmB,KAAA,GAAW,EAAE,SAAS,OAAO,CAAC,CAAC,CAAC,OAAO,QAAQ,IAAI,EAAE;EAC1G;EAEA,SAAS,UAAU,OAAwB;GACzC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC9D;;;EC9RA,MAAa,KAAK;EAqGlB,MAAa,eAAe;GAAE;IAlG5B,OAAO;IACP,OAAO;IACP,SAAS;IACT,WAAW;IACX,UAAU;IACV,MAAM;IACN,WAAW;IACX,SAAS;IACT,SAAS;IACT,cAAc;IACd,gBAAgB;IAChB,QAAQ;IACR,aAAa;IACb,QAAQ;IACR,SAAS;IACT,cAAc;IACd,SAAS;IACT,cAAc;IACd,eAAe;IACf,SAAS;IACT,YAAY;IACZ,UAAU;IACV,iBAAiB;IACjB,WAAW;IACX,UAAU;IACV,gBAAgB;IAChB,SAAS;IACT,SAAS;IACT,QAAQ;IACR,OAAO;IACP,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,SAAS;IACT,SAAS;IACT,WAAW;IACX,aAAa;IACb,MAAM;IACN,WAAW;IACX,WAAW;IACX,QAAQ;IACR,OAAO;IACP,SAAS;GAqDmB;GAAI;IAjDhC,OAAO;IACP,OAAO;IACP,SAAS;IACT,WAAW;IACX,UAAU;IACV,MAAM;IACN,WAAW;IACX,SAAS;IACT,SAAS;IACT,cAAc;IACd,gBAAgB;IAChB,QAAQ;IACR,aAAa;IACb,QAAQ;IACR,SAAS;IACT,cAAc;IACd,SAAS;IACT,cAAc;IACd,eAAe;IACf,SAAS;IACT,YAAY;IACZ,UAAU;IACV,iBAAiB;IACjB,WAAW;IACX,UAAU;IACV,gBAAgB;IAChB,SAAS;IACT,SAAS;IACT,QAAQ;IACR,OAAO;IACP,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,SAAS;IACT,gBAAgB;IAChB,OAAO;IACP,SAAS;IACT,SAAS;IACT,WAAW;IACX,aAAa;IACb,MAAM;IACN,WAAW;IACX,WAAW;IACX,QAAQ;IACR,OAAO;IACP,SAAS;GAIuB;EAAG;;;ECrGrC,MAAM,YAAY;EAClB,MAAM,mBAAmB;EACzB,MAAM,wBAAwB;EAC9B,MAAM,qBAAqB;EAC3B,MAAM,oBAAoB;EAC1B,MAAM,aAAa;EACnB,MAAM,QAAQ;EACd,MAAM,2BAA2B;EACjC,MAAM,6BAA6B;EACnC,MAAM,2BAA2B;EACjC,MAAM,kBAAkB;EACxB,MAAM,6BAA6B;EACnC,MAAM,yBAAyB;EAC/B,MAAM,kBAAkB;EACxB,MAAM,iBAAiB;EACvB,MAAM,oBAAoB,IAAI,OAAO,2BAA2B,uBAAuB,mBAAmB,GAAG;EAC7G,MAAM,kBAAkB,IAAI,OAAO,mCAAmC,uBAAuB,mBAAmB,IAAI;EAkBpH,SAAgB,sBAAsB,UAAiC,CAAC,GAAe;GACrF,IAAI,OAAO,aAAa,aAAa,aAAa,KAAA;GAClD,IAAI,SAAS,SAAS,MAAM;IAC1B,IAAI,gBAA4B,KAAA;IAChC,IAAI,UAAU;IACd,MAAM,cAAc;KAClB,IAAI,SAAS;KACb,UAAU;KACV,UAAU,sBAAsB,OAAO;IACzC;IACA,SAAS,iBAAiB,oBAAoB,OAAO,EAAE,MAAM,KAAK,CAAC;IACnE,aAAa;KACX,SAAS,oBAAoB,oBAAoB,KAAK;KACtD,QAAQ;IACV;GACF;GAEA,MAAM,iBAAiB,QAAQ,kBAAkB;GACjD,MAAM,yBAAS,IAAI,IAA6B;GAChD,MAAM,0BAAU,IAAI,IAAa;GACjC,IAAI,QAAuB;GAE3B,MAAM,sBAAsB;IAC1B,IAAI,UAAU,MAAM;IACpB,QAAQ,4BAA4B;KAClC,QAAQ;KACR,MAAM;IACR,CAAC;GACH;GAEA,MAAM,SAAS,YAA4B;IACzC,IAAI,YAAY,QAAQ,CAAC,QAAQ,aAAa;IAC9C,QAAQ,IAAI,OAAO;IACnB,cAAc;GAChB;GAEA,MAAM,wBAAwB,SAAsB;IAClD,MAAM,QAAQ,OAAO,IAAI,IAAI;IAC7B,IAAI,UAAU,KAAA,KAAa,KAAK,aAAa,iBAAiB,GAAG;IACjE,IAAI,MAAM,UAAU,MAAM,aAAa,MAAM,KAAK;IAClD,MAAM,QAAQ,iBAAiB;KAC7B,MAAM,QAAQ;KACd,IAAI,KAAK,eAAe,CAAC,KAAK,aAAa,iBAAiB,GAAG,kBAAkB,MAAM,IAAI;IAC7F,GAAG,cAAc;GACnB;GAEA,MAAM,aAAa,MAAqB,aAA6C;IACnF,MAAM,OAAO,KAAK;IAClB,MAAM,QAAQ,oBAAoB,IAAI;IACtC,MAAM,SAAS,UAAsB;KACnC,IAAI,oBAAoB,MAAM,MAAM,GAAG;KACvC,gBAAgB,IAAI;KACpB,kBAAkB,MAAM,CAAC,KAAK,UAAU,SAAS,qBAAqB,CAAC;IACzE;IACA,MAAM,WAAW,UAAyB;KACxC,IAAI,MAAM,QAAQ,WAAW,MAAM,QAAQ,KAAK;KAChD,MAAM,eAAe;KACrB,gBAAgB,IAAI;KACpB,kBAAkB,MAAM,CAAC,KAAK,UAAU,SAAS,qBAAqB,CAAC;IACzE;IAEA,OAAO,IAAI,MAAM;KAAE;KAAM;KAAO;KAAS,OAAO;IAAK,CAAC;IACtD,KAAK,MAAM,OAAO,MAAM,IAAI,UAAU,IAAI,SAAS;IACnD,KAAK,UAAU,IAAI,gBAAgB;IACnC,IAAI,CAAC,KAAK,aAAa,UAAU,GAAG,KAAK,WAAW;IACpD,KAAK,aAAa,iBAAiB,OAAO,EAAE,UAAU,aAAa,MAAM,CAAC;IAC1E,KAAK,aAAa,YAAY,KAAK;IACnC,KAAK,UAAU;IACf,IAAI,UAAU,gBAAgB,MAAM,KAAK,aAAa,mBAAmB,MAAM;IAC/E,KAAK,iBAAiB,SAAS,KAAK;IACpC,KAAK,iBAAiB,WAAW,OAAO;IACxC,kBAAkB,MAAM,UAAU,aAAa,KAAK;IACpD,qBAAqB,IAAI;GAC3B;GAEA,MAAM,uBAAuB,WAAoB;IAC/C,MAAM,2BAAW,IAAI,IAAqC;IAC1D,KAAK,MAAM,CAAC,MAAM,UAAU,QAAQ;KAClC,IAAI,KAAK,kBAAkB,QAAQ;KACnC,SAAS,IAAI,MAAM;MACjB,WAAW,KAAK,UAAU,SAAS,qBAAqB;MACxD,aAAa,KAAK,aAAa,iBAAiB;KAClD,CAAC;KACD,aAAa,MAAM,KAAK;KACxB,OAAO,OAAO,IAAI;IACpB;IAEA,IAAI,OAAsB,CAAC;IAC3B,MAAM,kBAAkB;KACtB,IAAI,KAAK,SAAS,GAAG,UAAU,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;KAC1D,OAAO,CAAC;IACV;IAEA,KAAK,MAAM,SAAS,MAAM,KAAK,OAAO,QAAQ,GAC5C,IAAI,iBAAiB,eAAe,aAAa,KAAK,GACpD,KAAK,KAAK,KAAK;SAEf,UAAU;IAGd,UAAU;GACZ;GAEA,MAAM,cAAc;IAClB,MAAM,0BAAU,IAAI,IAAa;IACjC,IAAI,UAAU;IACd,KAAK,MAAM,QAAQ,MAAM,KAAK,OAAO,GAAG;KACtC,QAAQ,OAAO,IAAI;KACnB,IAAI,CAAC,KAAK,aAAa;KACvB,KAAK,MAAM,OAAO,gBAAgB,IAAI,GACpC,IAAI,IAAI,kBAAkB,MAAM,QAAQ,IAAI,IAAI,aAAa;KAE/D,MAAM,UAAU,iBAAiB,IAAI;KACrC,IAAI,YAAY,QAAQ,QAAQ,kBAAkB,MAAM,QAAQ,IAAI,QAAQ,aAAa;KACzF;KACA,IAAI,WAAW,4BAA4B,QAAQ,OAAO,GAAG;MAC3D,cAAc;MACd;KACF;IACF;IACA,KAAK,MAAM,UAAU,SAAS,oBAAoB,MAAM;GAC1D;GAEA,MAAM,WAAW,IAAI,kBAAkB,cAAc;IACnD,KAAK,MAAM,YAAY,WAAW;KAChC,IAAI,SAAS,SAAS,iBAAiB;MACrC,MAAM,YAAY,SAAS,MAAM,CAAC,EAAE,QAAQ,0BAA0B,KAAK,YAAY,SAAS,MAAM,CAAC;MACvG;KACF;KACA,KAAK,MAAM,QAAQ,SAAS,YAAY,MAAM,YAAY,IAAI,CAAC;IACjE;GACF,CAAC;GACD,SAAS,QAAQ,SAAS,MAAM;IAAE,WAAW;IAAM,eAAe;IAAM,SAAS;GAAK,CAAC;GACvF,MAAM,SAAS,IAAI;GAEnB,aAAa;IACX,SAAS,WAAW;IACpB,IAAI,UAAU,MAAM,qBAAqB,KAAK;IAC9C,QAAQ,MAAM;IACd,KAAK,MAAM,CAAC,MAAM,UAAU,QAAQ,aAAa,MAAM,KAAK;IAC5D,OAAO,MAAM;GACf;EACF;EAEA,SAAS,aAAa,MAAmB,OAAyB;GAChE,IAAI,MAAM,UAAU,MAAM,aAAa,MAAM,KAAK;GAClD,KAAK,oBAAoB,SAAS,MAAM,KAAK;GAC7C,KAAK,oBAAoB,WAAW,MAAM,OAAO;GACjD,KAAK,MAAM,OAAO,MAAM,MAAM,IAAI,UAAU,OAAO,WAAW,kBAAkB;GAChF,KAAK,UAAU,OAAO,kBAAkB,qBAAqB;GAC7D,KAAK,gBAAgB,eAAe;GACpC,KAAK,gBAAgB,iBAAiB;GACtC,KAAK,gBAAgB,UAAU;GAC/B,IAAI,KAAK,UAAU,OAAO,KAAK,gBAAgB,OAAO;EACxD;EAEA,SAAS,gBAAgB,MAA8B;GACrD,MAAM,OAAsB,CAAC;GAC7B,IAAI,gBAAgB,eAAe,aAAa,IAAI,GAAG,KAAK,KAAK,IAAI;GACrE,KAAK,MAAM,WAAW,KAAK,iBAAiB,0BAA0B,GACpE,IAAI,mBAAmB,eAAe,aAAa,OAAO,GAAG,KAAK,KAAK,OAAO;GAEhF,OAAO;EACT;EAEA,SAAS,aAAa,SAA+B;GACnD,IAAI,QAAQ,QAAQ,iBAAiB,MAAM,QAAQ,aAAa,OAAO,GAAG,OAAO;GACjF,MAAM,OAAO,QAAQ,eAAe,GAAA,CAAI,MAAM,GAAG,eAAe;GAChE,MAAM,aAAa,IAAI,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK;GACjD,IAAI,CAAC,kBAAkB,KAAK,UAAU,GAAG,OAAO;GAChD,MAAM,QAAQ,iBAAiB,GAAG;GAClC,IAAI,MAAM,kBAAkB,KAAK,MAAM,gBAAgB,4BAA4B,OAAO;GAC1F,OAAO,EAAE,QAAQ,SAAS,SAAS,KAAK,MAAM;EAChD;EAEA,SAAS,iBAAiB,MAAqE;GAC7F,gBAAgB,YAAY;GAC5B,IAAI,gBAAgB;GACpB,OAAO,gBAAgB,KAAK,IAAI,MAAM,MAAM;GAC5C,MAAM,oBAAoB,KAAK,MAAM,OAAO,CAAC,CAC1C,KAAK,SAAS,KAAK,QAAQ,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAC/C,MAAM,SAAS,SAAS,MAAM,CAAC,kBAAkB,KAAK,IAAI,CAAC;GAC9D,OAAO;IAAE;IAAe;GAAkB;EAC5C;EAEA,SAAS,kBAAkB,MAAmB,WAA0B;GACtE,MAAM,QAAQ,sBAAsB,IAAI;GACxC,IAAI,UAAU,MAAM;GACpB,KAAK,UAAU,OAAO,uBAAuB,SAAS;GACtD,KAAK,aAAa,iBAAiB,OAAO,CAAC,SAAS,CAAC;GACrD,KAAK,MAAM,OAAO,MAAM,KAAK,MAAM,CAAC,GAAG,IAAI,UAAU,OAAO,oBAAoB,SAAS;EAC3F;EAEA,SAAS,sBAAsB,MAAmD;GAChF,MAAM,OAAsB,CAAC,IAAI;GACjC,IAAI,UAAU,KAAK;GACnB,OAAO,mBAAmB,eAAe,aAAa,OAAO,GAAG;IAC9D,KAAK,KAAK,OAAO;IACjB,UAAU,QAAQ;GACpB;GACA,OAAO,KAAK,SAAS,IAAI,EAAE,KAAK,IAAI;EACtC;EAEA,SAAS,gBAAgB,MAAyB;GAChD,KAAK,aAAa,mBAAmB,MAAM;EAC7C;EAEA,SAAS,iBAAiB,SAAsC;GAC9D,MAAM,YAAY,QAAQ,QAAQ,IAAI,kBAAkB;GACxD,OAAO,qBAAqB,cAAc,YAAY;EACxD;EAEA,SAAS,oBAAoB,MAA6B;GACxD,MAAM,OAAO,KAAK,KAAK,QAAQ,IAAI,eAAe,EAAE,CAAC,CAAC,KAAK,IAAI;GAC/D,IAAI,gBAAgB,KAAK,IAAI,GAAG,OAAO;GACvC,IAAI,eAAe,KAAK,IAAI,GAAG,OAAO;GACtC,OAAO;EACT;EAEA,SAAS,YAAY,MAA4B;GAC/C,IAAI,gBAAgB,SAAS,OAAO;GACpC,OAAO,KAAK;EACd;EAEA,SAAS,aAAa,SAA+B;GACnD,OAAO,QAAQ,QAAQ,wEAAsE,MAAM;EACrG;EAEA,SAAS,oBAAoB,QAAqC;GAChE,OAAO,kBAAkB,WAAW,OAAO,QAAQ,6EAAyE,MAAM;EACpI;;;ECxQA,MAAM,WAAW;EAEjB,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsDZ,SAAgB,gBAA4B;GAC1C,IAAI,SAAS,cAAc,0BAA0B,SAAS,GAAG,MAAM,MAAM,aAAa,KAAA;GAC1F,MAAM,UAAU,SAAS,cAAc,OAAO;GAC9C,QAAQ,QAAQ,SAAS;GACzB,QAAQ,QAAQ,YAAY;GAC5B,QAAQ,cAAc;GACtB,SAAS,KAAK,YAAY,OAAO;GACjC,aAAa,QAAQ,OAAO;EAC9B;;;ECjDA,MAAa,SAAS,CAAC,SAAS,QAAQ;EAExC,SAAgB,MAAM,KAA0B;GAC9C,IAAI,aAAa,IAAI,OAAO,SAAS,IAAI,YAAY,GAAG,wCAAwC;GAChG,IAAI,aAAa,cAAc,GAAG,kCAAkC;GACpE,IAAI,aAAa,sBAAsB,GAAG,2CAA2C;GACrF,IAAI,MAAM,OAAO,0BAA0B,IAAI,MAAM,SAAS;IAC5D,MAAM;IACN,IAAI;IACJ,OAAO;IACP,OAAO;IACP,QAAQ;GACV,GAAG,wBAAwB,CAAC;EAC9B"}
|
package/lib/index.js
CHANGED
|
@@ -631,9 +631,10 @@ function hiddenSandboxControlToolNames(options) {
|
|
|
631
631
|
const retryTools = recentSandboxRetryToolNames(options.messages);
|
|
632
632
|
return new Set(options.tools?.filter((tool) => hasSandboxControls(tool.parameters) && !retryTools.has(tool.name)).map((tool) => tool.name) ?? []);
|
|
633
633
|
}
|
|
634
|
-
async function buildResponsesPayload(options, attachments) {
|
|
634
|
+
async function buildResponsesPayload(options, attachments, localRawImages = {}) {
|
|
635
635
|
const sandboxRetryTools = recentSandboxRetryToolNames(options.messages);
|
|
636
|
-
const
|
|
636
|
+
const resolveLocalRawImages = supportsImageInput(options);
|
|
637
|
+
const instructionParts = [
|
|
637
638
|
options.system?.trim(),
|
|
638
639
|
...options.messages.filter((message) => message.role === "system").map((message) => blocksToText(message.content).trim()),
|
|
639
640
|
sandboxToolInstruction(options.tools, sandboxRetryTools),
|
|
@@ -642,6 +643,11 @@ async function buildResponsesPayload(options, attachments) {
|
|
|
642
643
|
].filter((value) => Boolean(value));
|
|
643
644
|
const input = [];
|
|
644
645
|
const knownToolCalls = /* @__PURE__ */ new Map();
|
|
646
|
+
const localImageStats = {
|
|
647
|
+
attempted: 0,
|
|
648
|
+
resolved: 0,
|
|
649
|
+
failed: 0
|
|
650
|
+
};
|
|
645
651
|
for (const message of options.messages) {
|
|
646
652
|
if (message.role === "system") continue;
|
|
647
653
|
const replayItems = replayOutputItems(message);
|
|
@@ -649,7 +655,7 @@ async function buildResponsesPayload(options, attachments) {
|
|
|
649
655
|
input.push(...replayItems);
|
|
650
656
|
for (const item of replayItems) if (item.type === "function_call" && typeof item.call_id === "string") knownToolCalls.set(item.call_id, typeof item.name === "string" ? item.name : void 0);
|
|
651
657
|
if (!replayItems.some((item) => item.type === "message")) {
|
|
652
|
-
const content = await mapContent(message, attachments, options.signal);
|
|
658
|
+
const content = await mapContent(message, attachments, options.signal, localRawImages, localImageStats, resolveLocalRawImages);
|
|
653
659
|
if (content.length > 0) input.push({
|
|
654
660
|
role: message.role,
|
|
655
661
|
content
|
|
@@ -678,7 +684,7 @@ async function buildResponsesPayload(options, attachments) {
|
|
|
678
684
|
});
|
|
679
685
|
continue;
|
|
680
686
|
}
|
|
681
|
-
const content = await mapContent(message, attachments, options.signal);
|
|
687
|
+
const content = await mapContent(message, attachments, options.signal, localRawImages, localImageStats, resolveLocalRawImages);
|
|
682
688
|
if (content.length > 0) input.push({
|
|
683
689
|
role: message.role,
|
|
684
690
|
content
|
|
@@ -692,6 +698,7 @@ async function buildResponsesPayload(options, attachments) {
|
|
|
692
698
|
store: false,
|
|
693
699
|
include: ["reasoning.encrypted_content"]
|
|
694
700
|
};
|
|
701
|
+
const instructions = [...instructionParts, localRawImageInstruction(localImageStats)].filter((value) => Boolean(value));
|
|
695
702
|
if (instructions.length > 0) payload.instructions = instructions.join("\n\n");
|
|
696
703
|
if (options.tools?.length) {
|
|
697
704
|
payload.tools = options.tools.map((tool) => ({
|
|
@@ -713,6 +720,13 @@ function runCodeInstruction(tools) {
|
|
|
713
720
|
if (!tools?.some((tool) => tool.name === "run_code")) return void 0;
|
|
714
721
|
return "run_code compatibility rule: its code is parsed as strict JavaScript/TypeScript before execution. On Windows, do not embed PowerShell containing $, ${...}, backslashes, or here-strings in JavaScript template literals; String.raw does not disable ${...} interpolation. Prefer arrays of ordinary quoted strings joined with \"\\n\", escaping backslashes, or use a file-write tool for large scripts and then invoke pwsh.";
|
|
715
722
|
}
|
|
723
|
+
function localRawImageInstruction(stats) {
|
|
724
|
+
if (stats.failed === 0) return void 0;
|
|
725
|
+
return "Image attachment rule: a user message contains a markdown image link to a local/raw session URL but no structured image attachment. That link is not accessible image bytes for the provider. Do not claim to see the image; ask the user to resend it as an actual image attachment if visual inspection is required.";
|
|
726
|
+
}
|
|
727
|
+
function supportsImageInput(options) {
|
|
728
|
+
return options.provider === "codex-chatgpt" && options.model.toLowerCase().startsWith("gpt-");
|
|
729
|
+
}
|
|
716
730
|
function toolDescriptionForCodex(name, description) {
|
|
717
731
|
if (name === "run_code") return `${description}\n\nCompatibility: code is strict JavaScript/TypeScript. When composing PowerShell, avoid JavaScript template literals containing $, \${...}, Windows backslashes, or PowerShell here-strings. Prefer ordinary quoted string arrays joined with "\\n", or write a script file with a dedicated file tool before invoking pwsh.`;
|
|
718
732
|
if (isCommandTool(name)) return `${description}\n\n${commandToolCompatibilityText(name)}`;
|
|
@@ -819,10 +833,11 @@ function runCodeErrorOutput(output) {
|
|
|
819
833
|
function isRunCodeParserError(output) {
|
|
820
834
|
return /(?:Legacy octal escape is not permitted in strict mode|Unexpected token|Invalid or unexpected token|Unterminated template|Expected ['"]?\}['"]?)/i.test(output);
|
|
821
835
|
}
|
|
822
|
-
async function mapContent(message, attachments, signal) {
|
|
836
|
+
async function mapContent(message, attachments, signal, localRawImages, localImageStats, resolveLocalRawImages) {
|
|
823
837
|
const result = [];
|
|
824
|
-
for (const block of message.content) if (block.type === "text") result.push(
|
|
825
|
-
|
|
838
|
+
for (const block of message.content) if (block.type === "text") if (message.role === "user") result.push(...await mapUserText(block.text, attachments, signal, localRawImages, localImageStats, resolveLocalRawImages));
|
|
839
|
+
else result.push({
|
|
840
|
+
type: "output_text",
|
|
826
841
|
text: block.text
|
|
827
842
|
});
|
|
828
843
|
else if (block.type === "image") {
|
|
@@ -834,9 +849,128 @@ async function mapContent(message, attachments, signal) {
|
|
|
834
849
|
}
|
|
835
850
|
return result;
|
|
836
851
|
}
|
|
852
|
+
async function mapUserText(text, attachments, signal, localRawImages, localImageStats, resolveLocalRawImages) {
|
|
853
|
+
const links = markdownImageLinks(text);
|
|
854
|
+
if (links.length === 0) return [{
|
|
855
|
+
type: "input_text",
|
|
856
|
+
text
|
|
857
|
+
}];
|
|
858
|
+
if (!resolveLocalRawImages) {
|
|
859
|
+
localImageStats.failed += links.length;
|
|
860
|
+
return [{
|
|
861
|
+
type: "input_text",
|
|
862
|
+
text
|
|
863
|
+
}];
|
|
864
|
+
}
|
|
865
|
+
const result = [];
|
|
866
|
+
let cursor = 0;
|
|
867
|
+
for (const match of links) {
|
|
868
|
+
if (match.start > cursor) pushInputText(result, text.slice(cursor, match.start));
|
|
869
|
+
localImageStats.attempted++;
|
|
870
|
+
const image = await localRawImageDataUrl(match.url, localRawImages, attachments.imageLimits?.maxImageBytes, signal);
|
|
871
|
+
if (image === null) {
|
|
872
|
+
localImageStats.failed++;
|
|
873
|
+
pushInputText(result, text.slice(match.start, match.end));
|
|
874
|
+
} else {
|
|
875
|
+
localImageStats.resolved++;
|
|
876
|
+
result.push({
|
|
877
|
+
type: "input_image",
|
|
878
|
+
image_url: image
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
cursor = match.end;
|
|
882
|
+
}
|
|
883
|
+
if (cursor < text.length) pushInputText(result, text.slice(cursor));
|
|
884
|
+
return result.length > 0 ? result : [{
|
|
885
|
+
type: "input_text",
|
|
886
|
+
text
|
|
887
|
+
}];
|
|
888
|
+
}
|
|
889
|
+
function pushInputText(content, text) {
|
|
890
|
+
if (text === "") return;
|
|
891
|
+
const previous = content.at(-1);
|
|
892
|
+
if (previous?.type === "input_text" && typeof previous.text === "string") previous.text += text;
|
|
893
|
+
else content.push({
|
|
894
|
+
type: "input_text",
|
|
895
|
+
text
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
function markdownImageLinks(text) {
|
|
899
|
+
const links = [];
|
|
900
|
+
for (const match of text.matchAll(/!\[[^\]]*\]\(([^)\s]+)\)/gi)) {
|
|
901
|
+
const url = match[1];
|
|
902
|
+
if (match.index === void 0 || !isLocalRawImageReference(url)) continue;
|
|
903
|
+
links.push({
|
|
904
|
+
start: match.index,
|
|
905
|
+
end: match.index + match[0].length,
|
|
906
|
+
url
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
return links;
|
|
910
|
+
}
|
|
911
|
+
async function localRawImageDataUrl(rawUrl, options, maxBytes, signal) {
|
|
912
|
+
const url = localRawImageUrl(rawUrl, options.baseUrl);
|
|
913
|
+
if (url === null) return null;
|
|
914
|
+
let response;
|
|
915
|
+
try {
|
|
916
|
+
response = await (options.fetchFn ?? fetch)(url, {
|
|
917
|
+
signal,
|
|
918
|
+
redirect: "error"
|
|
919
|
+
});
|
|
920
|
+
} catch {
|
|
921
|
+
return null;
|
|
922
|
+
}
|
|
923
|
+
if (!response.ok) return null;
|
|
924
|
+
const contentLength = Number(response.headers.get("content-length") ?? NaN);
|
|
925
|
+
if (maxBytes !== void 0 && Number.isFinite(contentLength) && contentLength > maxBytes) return null;
|
|
926
|
+
let bytes;
|
|
927
|
+
try {
|
|
928
|
+
bytes = new Uint8Array(await response.arrayBuffer());
|
|
929
|
+
} catch {
|
|
930
|
+
return null;
|
|
931
|
+
}
|
|
932
|
+
if (maxBytes !== void 0 && bytes.byteLength > maxBytes) return null;
|
|
933
|
+
const mediaType = supportedImageMediaType(response.headers.get("content-type")) ?? sniffImageMediaType(bytes);
|
|
934
|
+
if (mediaType === null) return null;
|
|
935
|
+
return bytesToDataUrl(mediaType, bytes);
|
|
936
|
+
}
|
|
937
|
+
function localRawImageUrl(rawUrl, baseUrl) {
|
|
938
|
+
if (!isLocalRawImageReference(rawUrl)) return null;
|
|
939
|
+
try {
|
|
940
|
+
const url = rawUrl.startsWith("/") ? baseUrl === void 0 ? null : new URL(rawUrl, baseUrl) : new URL(rawUrl);
|
|
941
|
+
if (url === null || !isLoopbackHost(url.hostname)) return null;
|
|
942
|
+
return url.toString();
|
|
943
|
+
} catch {
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
function isLocalRawImageReference(url) {
|
|
948
|
+
return /(?:^|\/)raw\/sha256:[a-f0-9]{32,}/i.test(url);
|
|
949
|
+
}
|
|
950
|
+
function isLoopbackHost(hostname) {
|
|
951
|
+
return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "[::1]" || hostname === "::1";
|
|
952
|
+
}
|
|
953
|
+
function supportedImageMediaType(value) {
|
|
954
|
+
const mediaType = value?.split(";", 1)[0]?.trim().toLowerCase();
|
|
955
|
+
if (mediaType === "image/png" || mediaType === "image/jpeg" || mediaType === "image/webp" || mediaType === "image/gif") return mediaType;
|
|
956
|
+
return null;
|
|
957
|
+
}
|
|
958
|
+
function sniffImageMediaType(bytes) {
|
|
959
|
+
if (bytes.length >= 8 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71 && bytes[4] === 13 && bytes[5] === 10 && bytes[6] === 26 && bytes[7] === 10) return "image/png";
|
|
960
|
+
if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return "image/jpeg";
|
|
961
|
+
if (bytes.length >= 12 && ascii(bytes, 0, 4) === "RIFF" && ascii(bytes, 8, 12) === "WEBP") return "image/webp";
|
|
962
|
+
if (bytes.length >= 6 && (ascii(bytes, 0, 6) === "GIF87a" || ascii(bytes, 0, 6) === "GIF89a")) return "image/gif";
|
|
963
|
+
return null;
|
|
964
|
+
}
|
|
965
|
+
function ascii(bytes, start, end) {
|
|
966
|
+
return String.fromCharCode(...bytes.slice(start, end));
|
|
967
|
+
}
|
|
837
968
|
async function imageDataUrl(ref, attachments, signal) {
|
|
838
969
|
const stored = await attachments.readImage(ref, signal);
|
|
839
|
-
return
|
|
970
|
+
return bytesToDataUrl(stored.ref.mediaType, stored.data);
|
|
971
|
+
}
|
|
972
|
+
function bytesToDataUrl(mediaType, data) {
|
|
973
|
+
return `data:${mediaType};base64,${Buffer.from(data).toString("base64")}`;
|
|
840
974
|
}
|
|
841
975
|
function blocksToText(blocks) {
|
|
842
976
|
return blocks.map((block) => {
|
|
@@ -884,6 +1018,9 @@ function retryAfterMs(headers) {
|
|
|
884
1018
|
}
|
|
885
1019
|
//#endregion
|
|
886
1020
|
//#region src/host/responses-client.ts
|
|
1021
|
+
const MAX_VISIBLE_REASONING_CHARS = 12e3;
|
|
1022
|
+
const REASONING_DELTA_FLUSH_CHARS = 768;
|
|
1023
|
+
const REASONING_TRUNCATED_NOTICE = "\n\n[Reasoning summary truncated to keep the DSH web UI responsive.]";
|
|
887
1024
|
var ResponsesClient = class {
|
|
888
1025
|
oauth;
|
|
889
1026
|
attachments;
|
|
@@ -893,10 +1030,12 @@ var ResponsesClient = class {
|
|
|
893
1030
|
this.oauth = oauth;
|
|
894
1031
|
this.attachments = attachments;
|
|
895
1032
|
this.fetchFn = options.fetchFn ?? fetch;
|
|
1033
|
+
this.localRawImages = options.localRawImages ?? {};
|
|
896
1034
|
this.onGenerationFinished = options.onGenerationFinished ?? (() => void 0);
|
|
897
1035
|
}
|
|
1036
|
+
localRawImages;
|
|
898
1037
|
async *stream(options) {
|
|
899
|
-
const payload = await buildResponsesPayload(options, this.attachments);
|
|
1038
|
+
const payload = await buildResponsesPayload(options, this.attachments, this.localRawImages);
|
|
900
1039
|
const hiddenSandboxControls = hiddenSandboxControlToolNames(options);
|
|
901
1040
|
const sessionId = stableSessionId(options.sessionId);
|
|
902
1041
|
try {
|
|
@@ -948,6 +1087,8 @@ async function* parseResponsesStream(response, signal, hiddenSandboxControls = /
|
|
|
948
1087
|
let reasoningIndex = null;
|
|
949
1088
|
let text = "";
|
|
950
1089
|
let reasoning = "";
|
|
1090
|
+
let pendingReasoningDelta = "";
|
|
1091
|
+
let reasoningTruncated = false;
|
|
951
1092
|
let terminal = null;
|
|
952
1093
|
let usage = null;
|
|
953
1094
|
let replayOutput = [];
|
|
@@ -1000,12 +1141,20 @@ async function* parseResponsesStream(response, signal, hiddenSandboxControls = /
|
|
|
1000
1141
|
blockType: "reasoning"
|
|
1001
1142
|
};
|
|
1002
1143
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
text
|
|
1008
|
-
}
|
|
1144
|
+
const visibleDelta = visibleReasoningDelta(delta, reasoning.length, reasoningTruncated);
|
|
1145
|
+
reasoningTruncated ||= visibleDelta.truncated;
|
|
1146
|
+
if (visibleDelta.text !== "") {
|
|
1147
|
+
reasoning += visibleDelta.text;
|
|
1148
|
+
pendingReasoningDelta += visibleDelta.text;
|
|
1149
|
+
}
|
|
1150
|
+
if (pendingReasoningDelta.length >= REASONING_DELTA_FLUSH_CHARS) {
|
|
1151
|
+
yield {
|
|
1152
|
+
type: "reasoning-delta",
|
|
1153
|
+
index: reasoningIndex,
|
|
1154
|
+
text: pendingReasoningDelta
|
|
1155
|
+
};
|
|
1156
|
+
pendingReasoningDelta = "";
|
|
1157
|
+
}
|
|
1009
1158
|
return;
|
|
1010
1159
|
}
|
|
1011
1160
|
if (type === "response.output_item.added" || type === "response.output_item.done") {
|
|
@@ -1101,14 +1250,24 @@ async function* parseResponsesStream(response, signal, hiddenSandboxControls = /
|
|
|
1101
1250
|
}
|
|
1102
1251
|
if (signal?.aborted) throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
1103
1252
|
if (terminal === null) throw new LlmError("Codex stream ended before a terminal event.", "PROTOCOL_ERROR");
|
|
1104
|
-
if (reasoningIndex !== null)
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1253
|
+
if (reasoningIndex !== null) {
|
|
1254
|
+
if (pendingReasoningDelta !== "") {
|
|
1255
|
+
yield {
|
|
1256
|
+
type: "reasoning-delta",
|
|
1257
|
+
index: reasoningIndex,
|
|
1258
|
+
text: pendingReasoningDelta
|
|
1259
|
+
};
|
|
1260
|
+
pendingReasoningDelta = "";
|
|
1110
1261
|
}
|
|
1111
|
-
|
|
1262
|
+
yield {
|
|
1263
|
+
type: "block-end",
|
|
1264
|
+
index: reasoningIndex,
|
|
1265
|
+
block: {
|
|
1266
|
+
type: "reasoning",
|
|
1267
|
+
text: reasoning
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1112
1271
|
if (textIndex !== null) yield {
|
|
1113
1272
|
type: "block-end",
|
|
1114
1273
|
index: textIndex,
|
|
@@ -1155,6 +1314,25 @@ async function* parseResponsesStream(response, signal, hiddenSandboxControls = /
|
|
|
1155
1314
|
replayState: { outputItems: replayOutput }
|
|
1156
1315
|
};
|
|
1157
1316
|
}
|
|
1317
|
+
function visibleReasoningDelta(delta, currentVisibleChars, alreadyTruncated) {
|
|
1318
|
+
if (delta === "" || alreadyTruncated) return {
|
|
1319
|
+
text: "",
|
|
1320
|
+
truncated: alreadyTruncated
|
|
1321
|
+
};
|
|
1322
|
+
const remaining = MAX_VISIBLE_REASONING_CHARS - currentVisibleChars;
|
|
1323
|
+
if (remaining <= 0) return {
|
|
1324
|
+
text: REASONING_TRUNCATED_NOTICE,
|
|
1325
|
+
truncated: true
|
|
1326
|
+
};
|
|
1327
|
+
if (delta.length <= remaining) return {
|
|
1328
|
+
text: delta,
|
|
1329
|
+
truncated: false
|
|
1330
|
+
};
|
|
1331
|
+
return {
|
|
1332
|
+
text: `${delta.slice(0, remaining)}${REASONING_TRUNCATED_NOTICE}`,
|
|
1333
|
+
truncated: true
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1158
1336
|
function mapUsage(value) {
|
|
1159
1337
|
if (value === null) return null;
|
|
1160
1338
|
const totalInput = number(value.input_tokens) ?? 0;
|
|
@@ -1769,7 +1947,10 @@ const inject = [
|
|
|
1769
1947
|
function apply(ctx) {
|
|
1770
1948
|
const oauth = new OAuthService(new WindowsDpapiTokenStore(), { logger: ctx.logger });
|
|
1771
1949
|
const usage = new UsageService(oauth);
|
|
1772
|
-
const adapter = new CodexChatGptAdapter(new ResponsesClient(oauth, ctx.attachments, {
|
|
1950
|
+
const adapter = new CodexChatGptAdapter(new ResponsesClient(oauth, ctx.attachments, {
|
|
1951
|
+
localRawImages: { baseUrl: localWebServerBaseUrl(ctx.webServer.host, ctx.webServer.port) },
|
|
1952
|
+
onGenerationFinished: () => usage.invalidate()
|
|
1953
|
+
}));
|
|
1773
1954
|
ctx.effect(() => {
|
|
1774
1955
|
const disposeRoutes = registerRoutes(ctx, oauth, usage);
|
|
1775
1956
|
const disposeAdapter = ctx.llm.registerAdapter([PROVIDER_ID], adapter);
|
|
@@ -1780,5 +1961,8 @@ function apply(ctx) {
|
|
|
1780
1961
|
};
|
|
1781
1962
|
}, "dsh-chatgpt-subscription: adapter, routes, and lifecycle");
|
|
1782
1963
|
}
|
|
1964
|
+
function localWebServerBaseUrl(host, port) {
|
|
1965
|
+
return `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}`;
|
|
1966
|
+
}
|
|
1783
1967
|
//#endregion
|
|
1784
1968
|
export { CodexChatGptAdapter, OAuthService, ResponsesClient, UsageService, apply, inject, mapCodexUsage, parseResponsesStream };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAK3E,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAK3E,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAI/D,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,0BAA0B,EAAE,SAAS,CAAA;KACtC;CACF;AAED,eAAO,MAAM,MAAM,UAAsB,CAAA;AAEzC,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAW9C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-folding.d.ts","sourceRoot":"","sources":["../../../src/client/process-folding.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,qBAAqB;IACpC,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAcD,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,qBAA0B,GAAG,MAAM,IAAI,CA8IrF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/client/styles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/client/styles.ts"],"names":[],"mappings":"AAwDA,wBAAgB,aAAa,IAAI,MAAM,IAAI,CAQ1C"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type GenerateOptions, type StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
2
2
|
import { OAuthService } from './oauth-service.ts';
|
|
3
|
+
import { type LocalRawImageOptions } from './responses-mapper.ts';
|
|
3
4
|
import type { AttachmentStore } from '@deepseek-ai/dsh-attachment';
|
|
4
5
|
type FetchLike = typeof fetch;
|
|
5
6
|
export interface ResponsesClientOptions {
|
|
6
7
|
fetchFn?: FetchLike;
|
|
8
|
+
localRawImages?: LocalRawImageOptions;
|
|
7
9
|
onGenerationFinished?: () => void;
|
|
8
10
|
}
|
|
9
11
|
export declare class ResponsesClient {
|
|
@@ -11,7 +13,8 @@ export declare class ResponsesClient {
|
|
|
11
13
|
private readonly attachments;
|
|
12
14
|
private readonly fetchFn;
|
|
13
15
|
private readonly onGenerationFinished;
|
|
14
|
-
constructor(oauth: OAuthService, attachments: Pick<AttachmentStore, 'readImage'
|
|
16
|
+
constructor(oauth: OAuthService, attachments: Pick<AttachmentStore, 'readImage'> & Partial<Pick<AttachmentStore, 'imageLimits'>>, options?: ResponsesClientOptions);
|
|
17
|
+
private readonly localRawImages;
|
|
15
18
|
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
16
19
|
private send;
|
|
17
20
|
private request;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses-client.d.ts","sourceRoot":"","sources":["../../../src/host/responses-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,WAAW,EAEjB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"responses-client.d.ts","sourceRoot":"","sources":["../../../src/host/responses-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,WAAW,EAEjB,MAAM,sBAAsB,CAAA;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAwD,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AAEvH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAElE,KAAK,SAAS,GAAG,OAAO,KAAK,CAAA;AAK7B,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,cAAc,CAAC,EAAE,oBAAoB,CAAA;IACrC,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAA;CAClC;AAED,qBAAa,eAAe;IAKxB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAL9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAW;IACnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAY;gBAG9B,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC,EAChH,OAAO,GAAE,sBAA2B;IAOtC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAsB;IAE9C,MAAM,CAAC,OAAO,EAAE,eAAe,GAAG,aAAa,CAAC,WAAW,CAAC;YAYrD,IAAI;YAYJ,OAAO;CAsBtB;AAWD,wBAAuB,oBAAoB,CACzC,QAAQ,EAAE,QAAQ,EAClB,MAAM,CAAC,EAAE,WAAW,EACpB,qBAAqB,GAAE,WAAW,CAAC,MAAM,CAAa,GACrD,aAAa,CAAC,WAAW,CAAC,CAyN5B"}
|
|
@@ -6,6 +6,12 @@ export interface ResponsesPayload extends Record<string, unknown> {
|
|
|
6
6
|
stream: true;
|
|
7
7
|
store: false;
|
|
8
8
|
}
|
|
9
|
+
type FetchLike = typeof fetch;
|
|
10
|
+
export interface LocalRawImageOptions {
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
fetchFn?: FetchLike;
|
|
13
|
+
}
|
|
9
14
|
export declare function hiddenSandboxControlToolNames(options: GenerateOptions): Set<string>;
|
|
10
|
-
export declare function buildResponsesPayload(options: GenerateOptions, attachments: Pick<AttachmentStore, 'readImage'>): Promise<ResponsesPayload>;
|
|
15
|
+
export declare function buildResponsesPayload(options: GenerateOptions, attachments: Pick<AttachmentStore, 'readImage'> & Partial<Pick<AttachmentStore, 'imageLimits'>>, localRawImages?: LocalRawImageOptions): Promise<ResponsesPayload>;
|
|
16
|
+
export {};
|
|
11
17
|
//# sourceMappingURL=responses-mapper.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses-mapper.d.ts","sourceRoot":"","sources":["../../../src/host/responses-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"responses-mapper.d.ts","sourceRoot":"","sources":["../../../src/host/responses-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAsC,MAAM,6BAA6B,CAAA;AACtG,OAAO,KAAK,EAAgB,eAAe,EAAW,MAAM,sBAAsB,CAAA;AAElF,MAAM,WAAW,gBAAiB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC/D,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACrC,MAAM,EAAE,IAAI,CAAA;IACZ,KAAK,EAAE,KAAK,CAAA;CACb;AAED,KAAK,SAAS,GAAG,OAAO,KAAK,CAAA;AAE7B,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,SAAS,CAAA;CACpB;AAQD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,eAAe,GAAG,GAAG,CAAC,MAAM,CAAC,CAKnF;AAED,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,eAAe,EACxB,WAAW,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC,EAC/F,cAAc,GAAE,oBAAyB,GACxC,OAAO,CAAC,gBAAgB,CAAC,CA6F3B"}
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAWlD,eAAO,MAAM,MAAM,UAAsC,CAAA;AAEzD,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAWlD,eAAO,MAAM,MAAM,UAAsC,CAAA;AAEzD,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAkBxC;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAClF,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACrE,YAAY,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA"}
|