ai-zero-token 2.0.0 → 2.0.1

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 CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.1 - 2026-05-04
4
+
5
+ - Improved desktop sidebar navigation responsiveness by switching routes immediately and de-duplicating hash-change updates.
6
+ - Removed the generated skill documentation zip from Git tracking and ignored it for future commits.
7
+
3
8
  ## 2.0.0 - 2026-05-04
4
9
 
5
10
  - Added the Electron desktop app, with a local gateway boot path and the management UI embedded in the desktop shell.
@@ -1742,4 +1742,4 @@ Or:
1742
1742
  \`\`\`
1743
1743
  `)?`Skill.md 已复制。`:`Skill.md 复制失败。`)}function v(){Ve(`AI-Zero-Token-Skill.md`,Ut,`text/markdown;charset=utf-8`),r(`Skill.md 已下载。`)}return(0,O.jsxs)(`section`,{className:`docs-page`,children:[(0,O.jsx)(`header`,{className:`docs-page-head docs-page-head-actions`,children:(0,O.jsxs)(`div`,{className:`docs-page-actions`,children:[(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>void g(),children:[(0,O.jsx)(T,{size:16}),`复制 Skill.md`]}),(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:v,children:[(0,O.jsx)(E,{size:16}),`下载 Skill.md`]}),(0,O.jsxs)(`button`,{className:`btn-primary`,type:`button`,onClick:()=>t(`tester`),children:[(0,O.jsx)(fe,{size:16}),`打开接口测试`]})]})}),(0,O.jsxs)(`section`,{className:`docs-summary`,children:[(0,O.jsxs)(`div`,{className:`docs-summary-item`,children:[(0,O.jsx)(`span`,{children:`Base URL`}),(0,O.jsx)(`strong`,{children:o})]}),(0,O.jsxs)(`div`,{className:`docs-summary-item`,children:[(0,O.jsx)(`span`,{children:`API Key`}),(0,O.jsx)(`strong`,{children:s})]}),(0,O.jsxs)(`div`,{className:`docs-summary-item`,children:[(0,O.jsx)(`span`,{children:`启动命令`}),(0,O.jsx)(`strong`,{children:c})]}),(0,O.jsxs)(`div`,{className:`docs-summary-item`,children:[(0,O.jsx)(`span`,{children:`文档规模`}),(0,O.jsxs)(`strong`,{children:[u.lines,` 行 · `,u.headings,` 级标题 · `,u.codeBlocks,` 段代码`]})]})]}),(0,O.jsx)(`div`,{className:`docs-layout`,children:(0,O.jsxs)(`div`,{className:`docs-main`,children:[(0,O.jsxs)(`nav`,{className:`docs-tab-bar`,"aria-label":`Skill 文档视图切换`,children:[(0,O.jsx)(`button`,{className:i===`quick-start`?`is-active`:``,type:`button`,onClick:()=>a(`quick-start`),children:`快速接入`}),(0,O.jsx)(`button`,{className:i===`skill`?`is-active`:``,type:`button`,onClick:()=>a(`skill`),children:`Skill.md`}),(0,O.jsx)(`button`,{className:i===`examples`?`is-active`:``,type:`button`,onClick:()=>a(`examples`),children:`示例代码`})]}),i===`quick-start`?(0,O.jsxs)(`div`,{className:`docs-panel-grid`,children:[(0,O.jsxs)(`section`,{className:`docs-panel`,children:[(0,O.jsx)(`div`,{className:`docs-panel-head`,children:(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`三步接入`}),(0,O.jsx)(`p`,{children:`先启动本地网关,再把 Skill.md 放进你的工具或项目。`})]})}),(0,O.jsxs)(`ol`,{className:`docs-step-list`,children:[(0,O.jsxs)(`li`,{children:[(0,O.jsx)(`strong`,{children:`启动网关`}),(0,O.jsxs)(`span`,{children:[`执行 `,(0,O.jsx)(`code`,{children:c}),`,管理页默认在 `,(0,O.jsx)(`code`,{children:`http://127.0.0.1:8787`}),`。`]})]}),(0,O.jsxs)(`li`,{children:[(0,O.jsx)(`strong`,{children:`复制接入参数`}),(0,O.jsxs)(`span`,{children:[`Base URL 用 `,(0,O.jsx)(`code`,{children:o}),`,API Key 用 `,(0,O.jsx)(`code`,{children:s}),`。`]})]}),(0,O.jsxs)(`li`,{children:[(0,O.jsx)(`strong`,{children:`下载 Skill.md`}),(0,O.jsx)(`span`,{children:`把这份文档保存到你的工作流里,或直接复制给支持 Skill 的工具。`})]})]})]}),(0,O.jsxs)(`section`,{className:`docs-panel`,children:[(0,O.jsx)(`div`,{className:`docs-panel-head`,children:(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`接入模板`}),(0,O.jsx)(`p`,{children:`最少只需要这两项。`})]})}),(0,O.jsxs)(`div`,{className:`docs-mini-grid`,children:[(0,O.jsxs)(`button`,{className:`docs-mini-copy`,type:`button`,onClick:n,children:[(0,O.jsx)(`span`,{children:`Base URL`}),(0,O.jsx)(`strong`,{children:o}),(0,O.jsx)(T,{size:14})]}),(0,O.jsxs)(`button`,{className:`docs-mini-copy`,type:`button`,onClick:()=>void yt(s).then(e=>r(e?`API Key 已复制。`:`API Key 复制失败。`)),children:[(0,O.jsx)(`span`,{children:`API Key`}),(0,O.jsx)(`strong`,{children:s}),(0,O.jsx)(T,{size:14})]})]}),(0,O.jsx)(`pre`,{className:`docs-code-sample`,children:(0,O.jsx)(`code`,{children:f})})]}),(0,O.jsxs)(`section`,{className:`docs-panel docs-panel-wide`,children:[(0,O.jsx)(`div`,{className:`docs-panel-head`,children:(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`常用接口`}),(0,O.jsx)(`p`,{children:`这个 Skill 文档覆盖了模型、对话和生图三类常见用法。`})]})}),(0,O.jsx)(`div`,{className:`docs-endpoint-grid`,children:[`/v1/models`,`/v1/chat/completions`,`/v1/responses`,`/v1/images/generations`].map(e=>(0,O.jsxs)(`div`,{className:`docs-endpoint`,children:[(0,O.jsx)(`span`,{children:e}),(0,O.jsx)(oe,{size:14})]},e))})]})]}):null,i===`skill`?(0,O.jsxs)(`section`,{className:`docs-panel docs-preview-panel`,children:[(0,O.jsx)(`div`,{className:`docs-panel-head`,children:(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`Skill.md 摘要`}),(0,O.jsx)(`p`,{children:`先看关键信息,再按需展开源码。`})]})}),(0,O.jsx)(`div`,{className:`docs-skill-summary`,children:d.map(e=>(0,O.jsxs)(`article`,{className:`docs-summary-tile`,children:[(0,O.jsx)(`span`,{children:e.label}),(0,O.jsx)(`strong`,{children:e.value})]},e.label))}),(0,O.jsxs)(`details`,{className:`docs-source-fold`,children:[(0,O.jsxs)(`summary`,{children:[`查看源码`,(0,O.jsxs)(`span`,{children:[l,` 行`]})]}),(0,O.jsx)(`pre`,{className:`docs-source`,children:(0,O.jsx)(`code`,{children:Ut})})]})]}):null,i===`examples`?(0,O.jsxs)(`div`,{className:`docs-example-grid`,children:[(0,O.jsx)(Wt,{title:`OpenAI SDK`,description:`适合前端和本地脚本。`,code:p,onCopy:()=>void yt(p).then(e=>r(e?`OpenAI SDK 示例已复制。`:`复制失败。`))}),(0,O.jsx)(Wt,{title:`curl Chat Completions`,description:`最直接的接口自测方式。`,code:m,onCopy:()=>void yt(m).then(e=>r(e?`Chat Completions 示例已复制。`:`复制失败。`))}),(0,O.jsx)(Wt,{title:`Responses API`,description:`适用于新式文本生成调用。`,code:h,onCopy:()=>void yt(h).then(e=>r(e?`Responses API 示例已复制。`:`复制失败。`))}),(0,O.jsxs)(`section`,{className:`docs-panel docs-note-panel`,children:[(0,O.jsx)(`h3`,{children:`用户如何使用`}),(0,O.jsxs)(`ul`,{children:[(0,O.jsx)(`li`,{children:`在侧边栏打开“使用文档”。`}),(0,O.jsx)(`li`,{children:`先复制 Base URL 和 API Key,再下载 Skill.md。`}),(0,O.jsx)(`li`,{children:`把 Skill.md 放到你的 AI 工具、项目文档或自动化流程里。`}),(0,O.jsx)(`li`,{children:`需要验证时,直接跳到“接口测试”页面跑一条请求。`})]}),(0,O.jsxs)(`div`,{className:`docs-action-row`,children:[(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>t(`overview`),children:[(0,O.jsx)(xe,{size:16}),`回到概览`]}),(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>t(`tester`),children:[(0,O.jsx)(we,{size:16}),`去接口测试`]})]})]})]}):null]})})]})}var Kt={claude:`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eClaude%3c/title%3e%3cpath%20d='m4.7144%2015.9555%204.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608%201.5179.1032%202.2767.1578%201.6514.0972%202.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973%209.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686%201.9064%201.4754%202.4893%201.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335%206.6997%200l.9957.1336.419.3642.6192%201.4147%201.0018%202.2282%201.5543%203.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853%201.8517-.5586%202.9021-.3643%201.9429h.2125l.2429-.2429.9835-1.3053%201.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759%201.1293-.34%201.1657-1.0625%201.3478-.8804%201.1414-1.2628%201.7-.7893%201.36.0729.1093.1882-.0183%202.8535-.607%201.5421-.2794%201.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607%201.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929%201.0686%202.0035%201.8092%202.5075%202.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496%202.3436%203.5214.1214%201.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38%2017.959l-1.1414-1.9428-.1397.079-.674%207.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328%201.9672-2.1796%202.9446-1.7243%201.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889%202.386-3.0357%201.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385%204.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429%201.9064-1.3114Z'/%3e%3c/svg%3e`,chatgpt:`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eOpenAI%3c/title%3e%3cpath%20d='M22.2819%209.8211a5.9847%205.9847%200%200%200-.5157-4.9108%206.0462%206.0462%200%200%200-6.5098-2.9A6.0651%206.0651%200%200%200%204.9807%204.1818a5.9847%205.9847%200%200%200-3.9977%202.9%206.0462%206.0462%200%200%200%20.7427%207.0966%205.98%205.98%200%200%200%20.511%204.9107%206.051%206.051%200%200%200%206.5146%202.9001A5.9847%205.9847%200%200%200%2013.2599%2024a6.0557%206.0557%200%200%200%205.7718-4.2058%205.9894%205.9894%200%200%200%203.9977-2.9001%206.0557%206.0557%200%200%200-.7475-7.0729zm-9.022%2012.6081a4.4755%204.4755%200%200%201-2.8764-1.0408l.1419-.0804%204.7783-2.7582a.7948.7948%200%200%200%20.3927-.6813v-6.7369l2.02%201.1686a.071.071%200%200%201%20.038.052v5.5826a4.504%204.504%200%200%201-4.4945%204.4944zm-9.6607-4.1254a4.4708%204.4708%200%200%201-.5346-3.0137l.142.0852%204.783%202.7582a.7712.7712%200%200%200%20.7806%200l5.8428-3.3685v2.3324a.0804.0804%200%200%201-.0332.0615L9.74%2019.9502a4.4992%204.4992%200%200%201-6.1408-1.6464zM2.3408%207.8956a4.485%204.485%200%200%201%202.3655-1.9728V11.6a.7664.7664%200%200%200%20.3879.6765l5.8144%203.3543-2.0201%201.1685a.0757.0757%200%200%201-.071%200l-4.8303-2.7865A4.504%204.504%200%200%201%202.3408%207.872zm16.5963%203.8558L13.1038%208.364%2015.1192%207.2a.0757.0757%200%200%201%20.071%200l4.8303%202.7913a4.4944%204.4944%200%200%201-.6765%208.1042v-5.6772a.79.79%200%200%200-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759%200%200%200-.7854%200L9.409%209.2297V6.8974a.0662.0662%200%200%201%20.0284-.0615l4.8303-2.7866a4.4992%204.4992%200%200%201%206.6802%204.66zM8.3065%2012.863l-2.02-1.1638a.0804.0804%200%200%201-.038-.0567V6.0742a4.4992%204.4992%200%200%201%207.3757-3.4537l-.142.0805L8.704%205.459a.7948.7948%200%200%200-.3927.6813zm1.0976-2.3654l2.602-1.4998%202.6069%201.4998v2.9994l-2.5974%201.4997-2.6067-1.4997Z'/%3e%3c/svg%3e`,google:`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eGoogle%3c/title%3e%3cpath%20d='M12.48%2010.92v3.28h7.84c-.24%201.84-.853%203.187-1.787%204.133-1.147%201.147-2.933%202.4-6.053%202.4-4.827%200-8.6-3.893-8.6-8.72s3.773-8.72%208.6-8.72c2.6%200%204.507%201.027%205.907%202.347l2.307-2.307C18.747%201.44%2016.133%200%2012.48%200%205.867%200%20.307%205.387.307%2012s5.56%2012%2012.173%2012c3.573%200%206.267-1.173%208.373-3.36%202.16-2.16%202.84-5.213%202.84-7.667%200-.76-.053-1.467-.173-2.053H12.48z'/%3e%3c/svg%3e`,x:`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eX%3c/title%3e%3cpath%20d='M14.234%2010.162%2022.977%200h-2.072l-7.591%208.824L7.251%200H.258l9.168%2013.343L.258%2024H2.33l8.016-9.318L16.749%2024h6.993zm-2.837%203.299-.929-1.329L3.076%201.56h3.182l5.965%208.532.929%201.329%207.754%2011.09h-3.182z'/%3e%3c/svg%3e`,youtube:`data:image/svg+xml,%3csvg%20role='img'%20viewBox='0%200%2024%2024'%20xmlns='http://www.w3.org/2000/svg'%3e%3ctitle%3eYouTube%3c/title%3e%3cpath%20d='M23.498%206.186a3.016%203.016%200%200%200-2.122-2.136C19.505%203.545%2012%203.545%2012%203.545s-7.505%200-9.377.505A3.017%203.017%200%200%200%20.502%206.186C0%208.07%200%2012%200%2012s0%203.93.502%205.814a3.016%203.016%200%200%200%202.122%202.136c1.871.505%209.376.505%209.376.505s7.505%200%209.377-.505a3.015%203.015%200%200%200%202.122-2.136C24%2015.93%2024%2012%2024%2012s0-3.93-.502-5.814zM9.545%2015.568V8.432L15.818%2012l-6.273%203.568z'/%3e%3c/svg%3e`};function qt(e){return`tone-${e}`}function Jt(e){try{return new URL(e).hostname.replace(/^www\./i,``)}catch{return e}}function Yt(e){return/^(10|127|169\.254|172\.(1[6-9]|2\d|3[0-1])|192\.168)\./.test(e)||/^100\.(6[4-9]|[7-9]\d|1\d\d|2[0-3]\d|24[0-7])\./.test(e)||/^198\.(18|19)\./.test(e)||/^192\.0\.2\./.test(e)||/^198\.51\.100\./.test(e)||/^203\.0\.113\./.test(e)||/^fc00:/i.test(e)||/^fd00:/i.test(e)||/^fe80:/i.test(e)||/^::1$/.test(e)}function Xt(e){let t=e.match(/Electron\/([\d.]+)/i);if(t)return`Electron ${t[1]}`;let n=e.match(/Chrome\/([\d.]+)/i);if(n&&/Safari\//i.test(e))return`Chrome ${n[1].split(`.`)[0]}`;let r=e.match(/Version\/([\d.]+).*Safari\//i);if(r&&!/Chrome\//i.test(e))return`Safari ${r[1].split(`.`)[0]}`;let i=e.match(/Firefox\/([\d.]+)/i);return i?`Firefox ${i[1].split(`.`)[0]}`:e.slice(0,40)}async function Zt(){if(typeof RTCPeerConnection>`u`)return{status:`不支持`,detail:`当前环境不支持 WebRTC。`,tone:`orange`,candidates:[]};let e=new Set,t=new RTCPeerConnection({iceServers:[]}),n=!1,r=new Promise(r=>{t.onicecandidate=t=>{t.candidate?.candidate&&e.add(t.candidate.candidate),t.candidate||(n=!0,r())}});try{t.createDataChannel(`probe`);let e=await t.createOffer();await t.setLocalDescription(e),await Promise.race([r,new Promise(e=>window.setTimeout(e,2400))])}catch{}finally{t.close()}let i=[...e],a=i.some(e=>/\btyp srflx\b/.test(e)||/\btyp relay\b/.test(e)),o=i.some(e=>/\btyp host\b/.test(e));return a?{status:`疑似泄漏`,detail:`收集到 ${i.length} 个候选地址,存在公网回显风险。`,tone:`red`,candidates:i}:o||n?{status:`局域网可见`,detail:`收集到 ${i.length} 个候选地址,主要是本地网段。`,tone:`orange`,candidates:i}:{status:`未发现异常`,detail:`未收集到可识别的候选地址。`,tone:`green`,candidates:i}}async function Qt(){let[e]=await Promise.all([Zt()]);return{timezone:Intl.DateTimeFormat().resolvedOptions().timeZone||`-`,language:navigator.language||`-`,browser:Xt(navigator.userAgent||``),webrtc:e}}function $t(e){return e.length===0?`slate`:e.some(e=>Yt(e))?`orange`:`green`}function en(e){return e.length===0?`未读取`:e.some(e=>Yt(e))?`内网 / 企业 DNS`:`公网 DNS`}function tn(e){return{total:e.length,reachable:e.filter(e=>e.status===`可达`).length,limited:e.filter(e=>e.status===`受限`).length,unavailable:e.filter(e=>e.status===`不可用`).length}}function nn(e,t){if(!e||!t)return{label:`检测中`,detail:`正在采集公网出口、DNS、WebRTC 和平台可达性。`,tone:`blue`};let n=[e.platforms.some(e=>e.tone===`red`),t.webrtc.tone===`red`,!e.publicIpv4.ip],r=[e.platforms.some(e=>e.tone===`orange`),t.webrtc.tone===`orange`,$t(e.dns.servers)!==`green`,!e.publicIpv6.available];return n.some(Boolean)?{label:`风险偏高`,detail:`部分关键项存在明显异常,建议先处理网络环境。`,tone:`red`}:r.some(Boolean)?{label:`需要复核`,detail:`当前环境可用,但有几项状态不够干净。`,tone:`orange`}:{label:`环境正常`,detail:`出口、DNS、WebRTC 和常用平台状态都比较稳定。`,tone:`green`}}function rn(e){return(0,O.jsx)(`span`,{className:`network-chip ${e.tone}`,children:e.children})}function an(e){let t=e.platformKey.toLowerCase(),n=Kt[t];return(0,O.jsx)(`span`,{className:`platform-icon ${e.tone} platform-${t}`,children:n?(0,O.jsx)(`img`,{alt:``,src:n}):e.icon})}function on(e){return(0,O.jsxs)(`div`,{className:`network-metric ${qt(e.tone)}`,children:[(0,O.jsx)(`span`,{children:e.label}),(0,O.jsx)(`strong`,{children:e.value}),e.detail?(0,O.jsx)(`p`,{children:e.detail}):null]})}function sn(e){return(0,O.jsxs)(`div`,{className:`network-block ${qt(e.tone)}`,children:[(0,O.jsx)(`span`,{children:e.label}),(0,O.jsx)(`strong`,{children:e.value}),(0,O.jsx)(`p`,{children:e.detail})]})}function cn(e){return typeof e==`number`?`${e} ms`:`-`}function ln(){let[e,t]=(0,_.useState)(null),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)(!0),[o,s]=(0,_.useState)(`正在采集真实网络状态...`),[c,l]=(0,_.useState)(null);async function u(){a(!0),l(null),s(`正在采集真实网络状态...`);try{let[e,n]=await Promise.all([ze(`/_gateway/admin/network-detect`),Qt()]);t(e),r(n),s(`检测完成。`)}catch(e){l(e instanceof Error?e.message:String(e)),s(`检测失败。`)}finally{a(!1)}}(0,_.useEffect)(()=>{u().catch(()=>void 0)},[]);let d=(0,_.useMemo)(()=>e?new Intl.DateTimeFormat(`zh-CN`,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1}).format(new Date(e.checkedAt)):`--:--:--`,[e]),f=nn(e,n),p=$t(e?.dns.servers||[]),m=en(e?.dns.servers||[]),h=e?.dns.servers?.length?e.dns.servers.slice(0,2).join(` / `):`-`,g=e?.dns.detail||`尚未检测到系统 DNS。`,v=tn(e?.platforms||[]),y=e?`green`:`blue`,b=e?.publicIpv6.available?`green`:`orange`,x=f.label,ee=f.tone;return(0,O.jsxs)(`section`,{className:`network-page`,children:[(0,O.jsxs)(`div`,{className:`network-toolbar`,children:[(0,O.jsxs)(`div`,{className:`network-updated`,children:[(0,O.jsx)(le,{size:14}),(0,O.jsxs)(`span`,{children:[`最后检测 `,d]}),(0,O.jsx)(`span`,{className:`network-toolbar-status`,children:o})]}),(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>u().catch(()=>void 0),disabled:i,children:[(0,O.jsx)(ve,{size:16}),i?`检测中`:`重新检测`]})]}),c?(0,O.jsxs)(`p`,{className:`network-error`,children:[`检测失败: `,c]}):null,(0,O.jsxs)(`section`,{className:`summary-grid network-summary-grid`,children:[(0,O.jsxs)(`div`,{className:`summary-card compact-value ${qt(f.tone)}`,children:[(0,O.jsx)(`div`,{className:`summary-icon`,children:(0,O.jsx)(we,{size:14})}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`span`,{children:`总状态`}),(0,O.jsx)(`strong`,{children:f.label}),(0,O.jsx)(`p`,{children:f.detail})]})]}),(0,O.jsxs)(`div`,{className:`summary-card compact-value ${qt(y)}`,children:[(0,O.jsx)(`div`,{className:`summary-icon blue`,children:(0,O.jsx)(de,{size:14})}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`span`,{children:`IPv4`}),(0,O.jsx)(`strong`,{children:e?.publicIpv4.ip||(i?`检测中`:`未读取`)}),(0,O.jsx)(`p`,{children:e?.publicIpv4.countryName?`${e.publicIpv4.countryName} · ${e.publicIpv4.colo||`-`}`:e?.publicIpv4.source||`公网出口`})]})]}),(0,O.jsxs)(`div`,{className:`summary-card compact-value ${qt(b)}`,children:[(0,O.jsx)(`div`,{className:`summary-icon green`,children:(0,O.jsx)(de,{size:14})}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`span`,{children:`IPv6`}),(0,O.jsx)(`strong`,{children:e?.publicIpv6.available?e.publicIpv6.ip:`未检测到`}),(0,O.jsx)(`p`,{children:e?.publicIpv6.detail||`未检测到独立 IPv6 出口。`})]})]}),(0,O.jsxs)(`div`,{className:`summary-card compact-value ${qt(ee)}`,children:[(0,O.jsx)(`div`,{className:`summary-icon orange`,children:(0,O.jsx)(Te,{size:14})}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`span`,{children:`风险提示`}),(0,O.jsx)(`strong`,{children:x}),(0,O.jsx)(`p`,{children:n?`${n.webrtc.status} · ${m}`:`正在评估 WebRTC 和 DNS 状态。`})]})]})]}),(0,O.jsxs)(`section`,{className:`network-grid`,children:[(0,O.jsxs)(`div`,{className:`network-stack`,children:[(0,O.jsxs)(`section`,{className:`card network-section`,children:[(0,O.jsx)(`div`,{className:`section-head compact`,children:(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`公网 IP`}),(0,O.jsx)(`p`,{children:`真实出口和出口区域。`})]})}),(0,O.jsxs)(`div`,{className:`network-dual`,children:[(0,O.jsx)(sn,{label:`IPv4 出口`,value:e?.publicIpv4.ip||(i?`检测中`:`-`),detail:e?`${e.publicIpv4.countryName||e.publicIpv4.countryCode||`未知地区`} · ${e.publicIpv4.colo||`未知节点`} · ${cn(e.publicIpv4.elapsedMs)}`:`正在采集公网出口信息。`,tone:e?`green`:`blue`}),(0,O.jsx)(sn,{label:`IPv6 出口`,value:e?.publicIpv6.available?e.publicIpv6.ip||`-`:`未检测到`,detail:e?.publicIpv6.detail||`未检测到独立 IPv6 出口。`,tone:b})]})]}),(0,O.jsxs)(`section`,{className:`card network-section`,children:[(0,O.jsx)(`div`,{className:`section-head compact`,children:(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`DNS`}),(0,O.jsx)(`p`,{children:`系统解析器和解析路径。`})]})}),(0,O.jsxs)(`div`,{className:`network-dual network-dns-grid`,children:[(0,O.jsx)(sn,{label:`系统 DNS`,value:h,detail:g,tone:p}),(0,O.jsx)(sn,{label:`DNS 结论`,value:m,detail:e?.dns.source||`尚未获取`,tone:p})]}),e?.dns.servers.length?(0,O.jsx)(`div`,{className:`dns-chip-row`,children:e.dns.servers.map(e=>(0,O.jsx)(`span`,{className:`dns-chip ${Yt(e)?`orange`:`green`}`,children:e},e))}):null]}),(0,O.jsxs)(`section`,{className:`card network-section`,children:[(0,O.jsx)(`div`,{className:`section-head compact`,children:(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`WebRTC / 时区 / 语言`}),(0,O.jsx)(`p`,{children:`本地浏览器环境和潜在泄漏。`})]})}),(0,O.jsxs)(`div`,{className:`network-three-up`,children:[(0,O.jsx)(on,{label:`WebRTC`,value:n?.webrtc.status||(i?`检测中`:`-`),detail:n?.webrtc.detail,tone:n?.webrtc.tone||`blue`}),(0,O.jsx)(on,{label:`时区`,value:n?.timezone||`-`,detail:`与出口地区交叉校验`,tone:n?.webrtc.tone||`blue`}),(0,O.jsx)(on,{label:`语言`,value:n?.language||`-`,detail:n?.browser||`-`,tone:n?.webrtc.tone||`blue`})]})]}),(0,O.jsxs)(`section`,{className:`card network-section network-glass-panel`,children:[(0,O.jsxs)(`div`,{className:`section-head compact`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`海外平台可达性`}),(0,O.jsx)(`p`,{children:`连通性测试和原始 HTTP 结果放在同一块里看。`})]}),(0,O.jsxs)(`div`,{className:`platform-summary-strip`,children:[(0,O.jsxs)(`div`,{className:`platform-summary-chip green`,children:[(0,O.jsx)(`strong`,{children:v.reachable}),(0,O.jsx)(`span`,{children:`可达`})]}),(0,O.jsxs)(`div`,{className:`platform-summary-chip orange`,children:[(0,O.jsx)(`strong`,{children:v.limited}),(0,O.jsx)(`span`,{children:`受限`})]}),(0,O.jsxs)(`div`,{className:`platform-summary-chip red`,children:[(0,O.jsx)(`strong`,{children:v.unavailable}),(0,O.jsx)(`span`,{children:`不可用`})]}),(0,O.jsxs)(`div`,{className:`platform-summary-chip slate`,children:[(0,O.jsx)(`strong`,{children:v.total}),(0,O.jsx)(`span`,{children:`总数`})]})]})]}),(0,O.jsx)(`div`,{className:`platform-grid`,children:(e?.platforms||[]).map(e=>(0,O.jsxs)(`div`,{className:`platform-card ${e.tone}`,children:[(0,O.jsxs)(`div`,{className:`platform-card-head`,children:[(0,O.jsxs)(`div`,{className:`platform-card-left`,children:[(0,O.jsx)(an,{icon:e.label.slice(0,1),tone:e.tone,platformKey:e.key}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`strong`,{children:e.label}),(0,O.jsx)(`span`,{children:e.detail})]})]}),(0,O.jsxs)(`div`,{className:`platform-state`,children:[(0,O.jsx)(`span`,{className:`platform-state-dot ${e.tone}`}),(0,O.jsxs)(`div`,{className:`platform-state-copy ${e.tone}`,children:[(0,O.jsx)(`strong`,{children:e.status}),(0,O.jsx)(`span`,{children:e.httpStatus?`HTTP ${e.httpStatus}`:`连接结果`})]})]})]}),(0,O.jsxs)(`div`,{className:`platform-card-foot`,children:[(0,O.jsx)(`span`,{className:`platform-url-chip`,children:Jt(e.url)}),typeof e.elapsedMs==`number`?(0,O.jsxs)(`span`,{className:`platform-latency-chip`,children:[e.elapsedMs,` ms`]}):null,(0,O.jsx)(`span`,{className:`platform-detail-copy`,children:e.detail})]})]},e.key))})]})]}),(0,O.jsx)(`aside`,{className:`network-side`,children:(0,O.jsxs)(`section`,{className:`card network-section`,children:[(0,O.jsx)(`div`,{className:`section-head compact`,children:(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h3`,{children:`风险提示`}),(0,O.jsx)(`p`,{children:`把最影响使用的异常拎出来。`})]})}),(0,O.jsxs)(`div`,{className:`network-list`,children:[(0,O.jsxs)(`div`,{className:`network-list-item`,children:[(0,O.jsx)(rn,{tone:f.tone,children:f.label}),(0,O.jsx)(`p`,{children:f.detail})]}),(0,O.jsxs)(`div`,{className:`network-list-item`,children:[(0,O.jsx)(rn,{tone:n?.webrtc.tone||`blue`,children:n?.webrtc.status||`检测中`}),(0,O.jsx)(`p`,{children:n?.webrtc.detail||`正在采集 WebRTC 候选。`})]}),(0,O.jsxs)(`div`,{className:`network-list-item`,children:[(0,O.jsx)(rn,{tone:p,children:m}),(0,O.jsx)(`p`,{children:g})]})]})]})})]})]})}function un(e){let t=e.endpoint.startsWith(`/v1/images/`);function n(t){let n=t.currentTarget.files?.[0];t.currentTarget.value=``,n&&e.onImageUpload(n).catch(()=>void 0)}return(0,O.jsxs)(`section`,{className:`card tester-card`,id:`tester`,children:[(0,O.jsxs)(`div`,{className:`section-head compact`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`h2`,{children:`快速测试`}),(0,O.jsx)(`p`,{children:`页面直接调用当前网关暴露的 OpenAI 风格接口。`})]}),(0,O.jsx)(`span`,{className:`badge brand`,children:e.busy===`test`?`请求中`:`准备就绪`})]}),(0,O.jsx)(`div`,{className:`tester-tabs`,children:e.endpoints.map(t=>(0,O.jsx)(`button`,{className:`tab-btn ${e.endpoint===t.path?`is-active`:``}`,type:`button`,onClick:()=>e.onEndpoint(t.path),children:Ye[t.path]||t.path},t.path))}),(0,O.jsxs)(`div`,{className:`tester-workbench`,children:[(0,O.jsxs)(`div`,{className:`tester-pane tester-request-pane`,children:[(0,O.jsxs)(`label`,{className:`field`,children:[(0,O.jsx)(`span`,{children:`接口`}),(0,O.jsx)(`select`,{className:`control`,value:e.endpoint,onChange:t=>e.onEndpoint(t.target.value),children:e.endpoints.map(e=>(0,O.jsxs)(`option`,{value:e.path,children:[e.method,` `,e.path]},e.path))})]}),(0,O.jsxs)(`div`,{className:`tester-copy-row tester-copy-row-top`,children:[(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyRequest,children:[(0,O.jsx)(T,{size:16}),`复制请求`]}),(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyResponse,children:[(0,O.jsx)(T,{size:16}),`复制响应`]}),(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onCopyTiming,children:[(0,O.jsx)(T,{size:16}),`复制日志`]}),(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:e.onResetExample,children:[(0,O.jsx)(ye,{size:16}),`重置示例`]})]}),(0,O.jsxs)(`label`,{className:`field tester-body-field`,children:[(0,O.jsx)(`span`,{children:`请求体 JSON`}),(0,O.jsx)(`textarea`,{className:`textarea tester-textarea`,value:e.requestBody,onChange:t=>e.onRequestBody(t.target.value),disabled:e.activeEndpoint.method===`GET`,spellCheck:!1})]}),e.endpoint===`/v1/images/edits`&&(0,O.jsxs)(`div`,{className:`edit-upload-row`,children:[(0,O.jsxs)(`label`,{className:`btn-secondary upload-btn`,title:`上传图片并写入 images[0].image_url`,children:[(0,O.jsx)(Ee,{size:16}),`上传图片写入 Body`,(0,O.jsx)(`input`,{type:`file`,accept:`image/*`,onChange:n})]}),(0,O.jsx)(`span`,{children:`目标字段:images[0].image_url`})]}),(0,O.jsx)(`p`,{className:`hint`,children:t?e.capability.detail:e.activeEndpoint.description||`GET /v1/models 无需请求体。`}),(0,O.jsxs)(`div`,{className:`tester-actions-bar`,children:[(0,O.jsx)(`div`,{className:`tester-actions-group`,children:(0,O.jsx)(`div`,{className:`example-row`,children:Je.map(t=>(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>e.onEndpoint(t),disabled:!e.endpoints.some(e=>e.path===t),children:[`示例 `,Ye[t]||t]},t))})}),(0,O.jsxs)(`button`,{className:`btn-primary`,type:`button`,onClick:e.onRun,disabled:e.busy===`test`||t&&!e.config?.profile,children:[e.busy===`test`?(0,O.jsx)(ge,{className:`spin`,size:16}):(0,O.jsx)(Ae,{size:16}),`发送请求`]})]})]}),(0,O.jsxs)(`div`,{className:`tester-pane tester-response-pane`,children:[(0,O.jsxs)(`div`,{className:`tester-result-head`,children:[(0,O.jsxs)(`div`,{className:`tester-result-tabs`,children:[(0,O.jsx)(`button`,{className:`tab-btn ${e.resultTab===`response`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`response`),children:`响应 JSON`}),(0,O.jsx)(`button`,{className:`tab-btn ${e.resultTab===`timing`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`timing`),children:`耗时日志`}),(0,O.jsx)(`button`,{className:`tab-btn ${e.resultTab===`preview`?`is-active`:``}`,type:`button`,onClick:()=>e.onResultTab(`preview`),children:`图片预览`})]}),(0,O.jsx)(`p`,{className:`status-inline`,children:e.status})]}),e.resultTab===`response`&&(0,O.jsx)(`pre`,{className:`pre`,children:e.responseBody}),e.resultTab===`timing`&&(0,O.jsx)(`pre`,{className:`pre`,children:e.timingBody}),e.resultTab===`preview`&&(0,O.jsx)(`div`,{className:`preview-panel`,children:e.previewImages.length===0?(0,O.jsx)(`div`,{className:`preview-empty`,children:`图片结果会显示在这里。点击缩略图可查看大图。`}):(0,O.jsx)(`div`,{className:`preview-grid`,children:e.previewImages.map(t=>(0,O.jsxs)(`figure`,{className:`preview-card`,children:[(0,O.jsx)(`button`,{type:`button`,onClick:()=>e.onPreview({src:t.src,meta:t.meta,filename:t.filename}),children:(0,O.jsx)(`img`,{src:t.src,alt:t.meta})}),(0,O.jsx)(`figcaption`,{children:t.meta}),(0,O.jsx)(`div`,{className:`preview-actions`,children:(0,O.jsx)(`a`,{href:t.src,download:t.filename,children:`下载`})})]},t.filename))})})]})]})]})}function dn(e){let[t,n]=(0,_.useState)(`/v1/models`),[r,i]=(0,_.useState)(``),[a,o]=(0,_.useState)(`等待请求...`),[s,c]=(0,_.useState)(`等待请求...`),[l,u]=(0,_.useState)(`response`),[d,f]=(0,_.useState)([]),p=(0,_.useMemo)(()=>[...e.config?.supportedEndpoints||[]].sort(Xe),[e.config?.supportedEndpoints]),m=(0,_.useMemo)(()=>p.find(e=>e.path===t)||p[0]||{method:`GET`,path:`/v1/models`,description:``},[t,p]);(0,_.useEffect)(()=>{if(!e.config)return;let r=Je.find(t=>e.config?.supportedEndpoints.some(e=>e.path===t)),a=e.config.supportedEndpoints.some(e=>e.path===t)?t:r||`/v1/models`;n(a),i(wt(a,e.config.settings.defaultModel))},[e.config]);function h(t){n(t),i(wt(t,e.config?.settings.defaultModel||`gpt-5.4`)),f([])}function g(){h(t)}function v(){yt(r||wt(t,e.config?.settings.defaultModel||`gpt-5.4`)).then(t=>e.setStatus(t?`请求体已复制。`:`请求体复制失败。`)).catch(()=>e.setStatus(`请求体复制失败。`))}function y(){yt(a).then(t=>e.setStatus(t?`响应内容已复制。`:`响应内容复制失败。`)).catch(()=>e.setStatus(`响应内容复制失败。`))}function b(){yt(s).then(t=>e.setStatus(t?`耗时日志已复制。`:`耗时日志复制失败。`)).catch(()=>e.setStatus(`耗时日志复制失败。`))}async function x(){let t=m,n=performance.now(),i=[];e.setBusy(`test`),u(`response`),o(`请求发送中...`),c(`请求发送中...`),f([]);try{let a=null,s={method:t.method,headers:{}};if(t.method!==`GET`){let e=performance.now();a=r.trim()?JSON.parse(r):{},i.push(`解析请求体: ${Ke(performance.now()-e)}`),s.headers[`Content-Type`]=`application/json`,s.body=He(a)}let l=performance.now(),d=await fetch(t.path,s);i.push(`等待响应头: ${Ke(performance.now()-l)}`);let p=performance.now(),m=await d.text();i.push(`读取响应体: ${Ke(performance.now()-p)}`);let h=performance.now(),g=m;try{g=m?JSON.parse(m):null}catch{g=m}i.push(`解析响应体: ${Ke(performance.now()-h)}`);let _=Et(g);f(_),_.length>0&&u(`preview`),o(typeof g==`string`?g:He(Ct(g))),c([`${t.method} ${t.path}`,`HTTP 状态: ${d.status} ${d.statusText}`,...i].join(`
1744
1744
  `)),e.setStatus(`${d.ok?`成功`:`失败`}: HTTP ${d.status} ${t.method} ${t.path}`),e.setRequestLogs(r=>[{id:crypto.randomUUID(),time:Date.now(),method:t.method,endpoint:t.path,account:rt(e.config?.profile,e.showEmails),model:typeof a==`object`&&a&&`model`in a?String(a.model||e.config?.settings.defaultModel||`-`):e.config?.settings.defaultModel||`-`,statusCode:d.status,durationMs:performance.now()-n,source:`管理台`},...r].slice(0,20)),e.config?.profile&&e.refreshConfig({silent:!0}).catch(()=>void 0)}catch(n){let r=vt(n);o(r),c([`${t.method} ${t.path}(失败)`,...i,`错误: ${r}`].join(`
1745
- `)),e.setStatus(`请求失败。`)}finally{e.setBusy(null)}}async function ee(t){if(!t.type.startsWith(`image/`)){e.setStatus(`请选择图片文件。`);return}try{i(St(r,await xt(t),e.config?.settings.defaultModel||`gpt-image-2`)),e.setStatus(`已将 ${t.name} 转成 base64 data URL,并写入请求体 images[0].image_url(${qe(t.size)})。`)}catch(t){e.setStatus(`图片写入失败: ${vt(t)}`)}}return(0,O.jsx)(un,{config:e.config,endpoints:p,activeEndpoint:m,endpoint:t,requestBody:r,responseBody:a,timingBody:s,resultTab:l,status:e.status,busy:e.busy,previewImages:d,capability:e.capability,onEndpoint:h,onRequestBody:i,onResultTab:u,onRun:x,onResetExample:g,onCopyRequest:v,onCopyResponse:y,onCopyTiming:b,onPreview:e.setPreviewImage,onImageUpload:ee})}var fn=`https://github.com/fchangjun/AI-Zero-Token/releases`;function pn(e){return(0,O.jsxs)(`section`,{className:`launch-page`,children:[(0,O.jsxs)(`div`,{className:`launch-copy`,children:[(0,O.jsxs)(`div`,{className:`launch-identity`,children:[(0,O.jsx)(`div`,{className:`launch-app-icon`,children:(0,O.jsx)(`img`,{src:y,alt:``})}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`span`,{className:`badge brand`,children:`Desktop Gateway`}),(0,O.jsx)(`h2`,{children:`AI Zero Token`}),(0,O.jsx)(`p`,{children:`本地 OpenAI 兼容网关、账号池和接口测试工作台。`})]})]}),(0,O.jsxs)(`div`,{className:`launch-metrics`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(De,{size:18}),(0,O.jsx)(`span`,{children:`账号池`}),(0,O.jsx)(`strong`,{children:e.config?.status.profileCount||0})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(xe,{size:18}),(0,O.jsx)(`span`,{children:`网关`}),(0,O.jsx)(`strong`,{children:e.config?.status.loggedIn?`运行中`:`待登录`})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(ae,{size:18}),(0,O.jsx)(`span`,{children:`模型`}),(0,O.jsx)(`strong`,{children:e.config?.settings.defaultModel||`-`})]})]}),(0,O.jsxs)(`div`,{className:`launch-actions`,children:[(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>e.onRoute(`accounts`),children:[(0,O.jsx)(De,{size:16}),`管理账号`]}),(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>e.onRoute(`tester`),children:[(0,O.jsx)(Ae,{size:16}),`测试接口`]}),(0,O.jsxs)(`a`,{className:`btn-secondary`,href:fn,target:`_blank`,rel:`noreferrer`,children:[(0,O.jsx)(E,{size:16}),`桌面版下载`]}),(0,O.jsxs)(`a`,{className:`btn-secondary`,href:fn,target:`_blank`,rel:`noreferrer`,title:`桌面版安装包发布后会放在这里`,children:[(0,O.jsx)(fe,{size:16}),`发布页`]})]}),(0,O.jsx)(`p`,{className:`launch-download-note`,children:`当前还没有公开安装包时,这里会先打开 GitHub Releases 发布页。`}),(0,O.jsxs)(`div`,{className:`launch-status`,children:[(0,O.jsx)(j,{label:`当前账号`,value:rt(e.activeProfile,e.showEmails)}),(0,O.jsx)(j,{label:`服务状态`,value:e.config?.status.loggedIn?`已登录并运行`:`等待登录`}),(0,O.jsx)(j,{label:`Base URL`,value:e.config?.baseUrl||`http://127.0.0.1:8787/v1`,code:!0}),(0,O.jsx)(j,{label:`同步消息`,value:e.status})]})]}),(0,O.jsx)(`div`,{className:`launch-visual`,children:(0,O.jsxs)(`div`,{className:`launch-visual-stage`,children:[(0,O.jsx)(`img`,{className:`launch-visual-mark`,src:y,alt:`AI Zero Token 图标`}),(0,O.jsx)(`img`,{className:`launch-visual-dashboard`,src:e.visualSrc||`data:image/svg+xml,%3csvg%20width='920'%20height='600'%20viewBox='0%200%20920%20600'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20width='920'%20height='600'%20rx='36'%20fill='%23F8FAFC'/%3e%3crect%20x='56'%20y='54'%20width='808'%20height='492'%20rx='24'%20fill='%23FFFFFF'%20stroke='%23D8E0EA'/%3e%3crect%20x='56'%20y='54'%20width='190'%20height='492'%20rx='24'%20fill='%23111827'/%3e%3cpath%20d='M246%2054h594c13.255%200%2024%2010.745%2024%2024v40H246V54Z'%20fill='%23F8FAFC'/%3e%3ccircle%20cx='88'%20cy='86'%20r='7'%20fill='%23EF4444'/%3e%3ccircle%20cx='112'%20cy='86'%20r='7'%20fill='%23F59E0B'/%3e%3ccircle%20cx='136'%20cy='86'%20r='7'%20fill='%2322C55E'/%3e%3crect%20x='86'%20y='148'%20width='108'%20height='14'%20rx='7'%20fill='%23E5E7EB'%20fill-opacity='.75'/%3e%3crect%20x='86'%20y='194'%20width='128'%20height='34'%20rx='10'%20fill='%232563EB'/%3e%3crect%20x='86'%20y='244'%20width='112'%20height='34'%20rx='10'%20fill='%231F2937'/%3e%3crect%20x='86'%20y='294'%20width='124'%20height='34'%20rx='10'%20fill='%231F2937'/%3e%3crect%20x='86'%20y='344'%20width='98'%20height='34'%20rx='10'%20fill='%231F2937'/%3e%3crect%20x='278'%20y='150'%20width='250'%20height='96'%20rx='18'%20fill='%23EFF6FF'%20stroke='%23BFDBFE'/%3e%3crect%20x='558'%20y='150'%20width='250'%20height='96'%20rx='18'%20fill='%23F0FDF4'%20stroke='%23BBF7D0'/%3e%3crect%20x='278'%20y='280'%20width='530'%20height='210'%20rx='18'%20fill='%23FFFFFF'%20stroke='%23D8E0EA'/%3e%3cpath%20d='M318%20430c43-68%2089-70%20137-8%2039%2049%2081%2037%20126-36%2038-62%2081-79%20129-21'%20stroke='%232563EB'%20stroke-width='8'%20stroke-linecap='round'/%3e%3cpath%20d='M318%20386c42-35%2083-33%20123%206%2045%2045%2092%2040%20141-16%2038-43%2080-49%20126-18'%20stroke='%2322C55E'%20stroke-width='8'%20stroke-linecap='round'/%3e%3crect%20x='318'%20y='316'%20width='118'%20height='13'%20rx='6.5'%20fill='%23111827'/%3e%3crect%20x='318'%20y='342'%20width='194'%20height='10'%20rx='5'%20fill='%23CBD5E1'/%3e%3crect%20x='596'%20y='182'%20width='80'%20height='12'%20rx='6'%20fill='%23111827'/%3e%3crect%20x='596'%20y='207'%20width='150'%20height='10'%20rx='5'%20fill='%2386EFAC'/%3e%3crect%20x='316'%20y='182'%20width='80'%20height='12'%20rx='6'%20fill='%23111827'/%3e%3crect%20x='316'%20y='207'%20width='150'%20height='10'%20rx='5'%20fill='%2393C5FD'/%3e%3ccircle%20cx='776'%20cy='198'%20r='16'%20fill='%2322C55E'/%3e%3cpath%20d='M768%20198l6%206%2011-13'%20stroke='%23FFFFFF'%20stroke-width='5'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M478%20186l15%2020-15%2020-15-20%2015-20Z'%20fill='%232563EB'/%3e%3c/svg%3e`,alt:`AI Zero Token 桌面端启动页配图`})]})})]})}function mn(e){return{defaultModel:e.settings.defaultModel,proxyEnabled:e.settings.networkProxy.enabled,proxyUrl:e.settings.networkProxy.url,proxyNoProxy:e.settings.networkProxy.noProxy||`localhost,127.0.0.1,::1`,autoSwitchEnabled:e.settings.autoSwitch.enabled}}function hn(e){let[t,n]=(0,_.useState)({defaultModel:``,proxyEnabled:!1,proxyUrl:``,proxyNoProxy:`localhost,127.0.0.1,::1`,autoSwitchEnabled:!1}),[r,i]=(0,_.useState)(!1);(0,_.useEffect)(()=>{!e.config||r||n(mn(e.config))},[e.config,r]);function a(e){n(t=>({...t,...e})),i(!0)}async function o(){e.setBusy(`settings`);try{let n=await ze(`/_gateway/admin/settings`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:He({defaultModel:t.defaultModel,networkProxy:{enabled:t.proxyEnabled,url:t.proxyUrl,noProxy:t.proxyNoProxy},autoSwitch:{enabled:t.autoSwitchEnabled}})});e.setConfig(n),i(!1),e.setStatus(`设置已保存。`)}catch(t){e.setStatus(vt(t))}finally{e.setBusy(null)}}async function s(){e.setBusy(`proxy`);try{let n=await ze(`/_gateway/admin/settings/proxy-test`,{method:`POST`,headers:{"Content-Type":`application/json`},body:He({networkProxy:{enabled:t.proxyEnabled,url:t.proxyUrl,noProxy:t.proxyNoProxy}})});e.setStatus(`代理测试通过: HTTP ${n.status},耗时 ${n.elapsedMs} ms。`)}catch(t){e.setStatus(`代理测试失败: ${vt(t)}`)}finally{e.setBusy(null)}}async function c(){e.setBusy(`models`);try{await ze(`/_gateway/models/refresh`,{method:`POST`}),await e.refreshConfig({silent:!0}),e.setStatus(`Codex 模型列表已同步。`)}catch(t){e.setStatus(vt(t))}finally{e.setBusy(null)}}return(0,O.jsxs)(`section`,{className:`settings-page`,children:[(0,O.jsxs)(`div`,{className:`settings-page-head`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsxs)(`div`,{className:`settings-page-kicker`,children:[(0,O.jsx)(Se,{size:14}),`系统设置`]}),(0,O.jsx)(`h2`,{children:`本地网关和运行策略`}),(0,O.jsx)(`p`,{children:`设置会保存到本地状态目录,CLI、桌面端和本地服务共享。`})]}),(0,O.jsxs)(`div`,{className:`settings-page-actions`,children:[(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:c,disabled:e.busy===`models`,children:[e.busy===`models`?(0,O.jsx)(ge,{className:`spin`,size:16}):(0,O.jsx)(ve,{size:16}),`同步 Codex 模型`]}),(0,O.jsx)(`button`,{className:`btn-primary`,type:`button`,onClick:o,disabled:e.busy===`settings`||!r,children:`保存设置`})]})]}),(0,O.jsxs)(`div`,{className:`settings-grid`,children:[(0,O.jsxs)(`section`,{className:`settings-section`,children:[(0,O.jsx)(`h4`,{children:`模型`}),(0,O.jsxs)(`label`,{className:`field`,children:[(0,O.jsx)(`span`,{children:`默认文本模型`}),(0,O.jsx)(`select`,{className:`control`,value:t.defaultModel,onChange:e=>a({defaultModel:e.target.value}),children:(e.config?.models||[]).map(e=>(0,O.jsx)(`option`,{value:e.id,children:e.id},e.id))})]}),(0,O.jsxs)(`p`,{className:`hint`,children:[`模型列表来源:`,e.config?.modelCatalog.source||`-`,`,共 `,e.config?.modelCatalog.modelCount||0,` 个。`]})]}),(0,O.jsxs)(`section`,{className:`settings-section`,children:[(0,O.jsx)(`h4`,{children:`上游代理`}),(0,O.jsxs)(`label`,{className:`switch-line`,children:[(0,O.jsx)(`input`,{type:`checkbox`,checked:t.proxyEnabled,onChange:e=>a({proxyEnabled:e.target.checked})}),(0,O.jsx)(`span`,{children:`启用 OAuth、模型刷新和接口转发代理`})]}),(0,O.jsxs)(`label`,{className:`field`,children:[(0,O.jsx)(`span`,{children:`代理地址`}),(0,O.jsx)(`input`,{className:`input`,value:t.proxyUrl,onChange:e=>a({proxyUrl:e.target.value}),placeholder:`http://127.0.0.1:7890`})]}),(0,O.jsxs)(`label`,{className:`field`,children:[(0,O.jsx)(`span`,{children:`No Proxy`}),(0,O.jsx)(`input`,{className:`input`,value:t.proxyNoProxy,onChange:e=>a({proxyNoProxy:e.target.value})})]}),(0,O.jsx)(`button`,{className:`btn-secondary`,type:`button`,onClick:s,disabled:e.busy===`proxy`,children:`测试代理`})]}),(0,O.jsxs)(`section`,{className:`settings-section`,children:[(0,O.jsx)(`h4`,{children:`账号自动切换`}),(0,O.jsxs)(`label`,{className:`switch-line`,children:[(0,O.jsx)(`input`,{type:`checkbox`,checked:t.autoSwitchEnabled,onChange:e=>a({autoSwitchEnabled:e.target.checked})}),(0,O.jsx)(`span`,{children:`当前 API 账号额度耗尽后自动切换到下一个仍有额度的账号`})]}),(0,O.jsx)(`p`,{className:`hint`,children:e.status})]}),(0,O.jsxs)(`section`,{className:`settings-section`,children:[(0,O.jsx)(`h4`,{children:`显示`}),(0,O.jsxs)(`label`,{className:`switch-line`,children:[(0,O.jsx)(`input`,{type:`checkbox`,checked:e.showEmails,onChange:t=>e.setShowEmails(t.target.checked)}),(0,O.jsx)(`span`,{children:`脱敏模式`})]}),(0,O.jsx)(`p`,{className:`hint`,children:`开启后账号邮箱将以脱敏形式展示。`})]})]})]})}function gn({workspace:e}){let{activeRoute:t,busy:n,config:r,refreshConfig:i}=e;return t===`launch`?(0,O.jsx)(pn,{config:r,visualSrc:Ot,status:e.status,showEmails:e.showEmails,activeProfile:e.activeProfile,onRoute:e.goRoute}):t===`overview`?(0,O.jsx)(Ht,{config:r,activeProfile:e.activeProfile,codexProfile:e.codexProfile,codexAccountId:e.codexAccountId,codexEmail:r?.codex?.email,showEmails:e.showEmails,requestLogs:e.requestLogs}):t===`docs`?(0,O.jsx)(Gt,{config:r,onRoute:e.goRoute,copyBaseUrl:e.copyBaseUrl,setStatus:e.setStatus}):t===`accounts`?(0,O.jsx)(Mt,{config:r,showEmails:e.showEmails,busy:n,activeProfile:e.activeProfile,codexAccountId:e.codexAccountId,setAccountModalOpen:e.setAccountModalOpen,setBusy:e.setBusy,setConfig:e.setConfig,setStatus:e.setStatus,refreshConfig:i,logout:e.logout}):t===`tester`?(0,O.jsx)(dn,{config:r,status:e.status,busy:n,showEmails:e.showEmails,capability:e.capability,setBusy:e.setBusy,setStatus:e.setStatus,setRequestLogs:e.setRequestLogs,refreshConfig:i,setPreviewImage:e.setPreviewImage}):t===`network`?(0,O.jsx)(ln,{}):t===`settings`?(0,O.jsx)(hn,{showEmails:e.showEmails,setShowEmails:e.setShowEmails,config:r,busy:n,status:e.status,setBusy:e.setBusy,setConfig:e.setConfig,setStatus:e.setStatus,refreshConfig:i}):(0,O.jsx)(Pt,{logs:e.requestLogs})}function _n({workspace:e}){return(0,O.jsxs)(`div`,{className:`app-shell`,children:[(0,O.jsx)(Ne,{workspace:e}),(0,O.jsxs)(`main`,{className:`main`,children:[(0,O.jsx)(Pe,{workspace:e}),(0,O.jsx)(gn,{workspace:e})]}),(0,O.jsx)(A,{workspace:e})]})}function vn(e){return{login:(0,_.useCallback)(async()=>{e.setBusy(`login`),e.setStatus(`正在打开 OAuth 登录...`);try{let t=await ze(`/_gateway/admin/login`,{method:`POST`});e.setConfig(t),e.setAccountModalOpen(!1),e.setStatus(`登录完成,账号状态已同步。`)}catch(t){e.setStatus(vt(t))}finally{e.setBusy(null)}},[e]),logout:(0,_.useCallback)(async()=>{if(window.confirm(`确认清空本地保存的所有账号?`)){e.setBusy(`logout`),e.setStatus(`正在清空账号...`);try{let t=await ze(`/_gateway/admin/logout`,{method:`POST`});e.setConfig(t),e.setRequestLogs([]),e.setStatus(`账号已清空。`)}catch(t){e.setStatus(vt(t))}finally{e.setBusy(null)}}},[e]),goRoute:(0,_.useCallback)(t=>{e.setActiveRoute(t),window.location.hash=t},[e]),copyBaseUrl:(0,_.useCallback)(()=>{let t=e.config?.baseUrl||`http://127.0.0.1:8787/v1`;navigator.clipboard.writeText(t).then(()=>e.setStatus(`Base URL 已复制。`),()=>e.setStatus(t))},[e])}}var yn=[{id:`launch`,label:`启动页`,icon:me},{id:`overview`,label:`概览`,icon:he},{id:`accounts`,label:`账号管理`,icon:De},{id:`tester`,label:`接口测试`,icon:we},{id:`docs`,label:`使用文档`,icon:se},{id:`network`,label:`网络检测`,icon:Oe},{id:`logs`,label:`请求日志`,icon:D},{id:`settings`,label:`系统设置`,icon:Ce}];function bn(){let e=window.location.hash.replace(/^#\/?/,``);return yn.some(t=>t.id===e)?e:`overview`}function xn(e){let t=e.config?.profile||null,n=_t(t),r=e.config?.codex?.accountId,i=(0,_.useMemo)(()=>e.config?.profiles.find(e=>r&&e.accountId===r)||null,[r,e.config?.profiles]);return{routes:yn,activeRouteMeta:yn.find(t=>t.id===e.activeRoute)||yn[0],pageDescriptions:{launch:`面向桌面端的启动入口,聚合服务状态、快捷操作和产品视觉。`,overview:t?`当前账号为 ${rt(t,e.showEmails)},套餐 ${Qe(t)},可查看网关状态和运行摘要。`:`还没有激活账号。你可以新增账号、导入账号 JSON,或先查看本地 API 信息。`,accounts:`账号池、额度、套餐、Codex 应用状态集中管理,适合横向比较多个账号。`,tester:`独立接口测试工作区,支持 Chat、Responses、Models 和 gpt-image-2 图片接口。`,docs:`查看 AI-Zero-Token Skill.md,复制 Base URL、下载文档,并按步骤接入本地网关。`,network:`单页总览 IPv4、IPv6、DNS、WebRTC、常用平台和版本状态。`,logs:`查看本页快速测试产生的最近请求,包含接口、模型、状态和耗时。`,settings:`调整本地网关、默认模型、代理和自动切换策略的桌面设置页。`},activeProfile:t,codexProfile:i,codexAccountId:r,capability:n,isLoading:e.busy===`initial`&&!e.config}}var Sn=300*1e3,Cn=15*1e3;function wn(){let[e,t]=(0,_.useState)(null),[n,r]=(0,_.useState)(`initial`),[i,a]=(0,_.useState)(`正在读取本地网关状态...`),[o,s]=(0,_.useState)(!1),[c,l]=(0,_.useState)(!1),[u,d]=(0,_.useState)(!1),[f,p]=(0,_.useState)(null),[m,h]=(0,_.useState)(()=>bn()),[g,v]=(0,_.useState)([]),y=(0,_.useCallback)(async e=>{e?.silent||r(e?.runtime?`runtime-refresh`:`refresh`);try{let n=await ze(e?.runtime?`/_gateway/admin/runtime-refresh`:`/_gateway/admin/config`,e?.runtime?{method:`POST`}:void 0);t(n);let r=n.quotaSync;return a(e?.runtime&&r?`状态和额度已刷新:${r.synced}/${r.total} 个账号成功${r.failed?`,${r.failed} 个失败`:``}${r.skipped?`,${r.skipped} 个登录失效已跳过`:``}。`:e?.runtime?`状态和额度已刷新。`:`网关状态已同步。`),n}catch(e){throw a(vt(e)),e}finally{e?.silent||r(null)}},[]);return(0,_.useEffect)(()=>{y().catch(()=>void 0);let e=window.setInterval(()=>{y({silent:!0}).catch(()=>void 0)},6e4);return()=>window.clearInterval(e)},[y]),(0,_.useEffect)(()=>{let e=()=>h(bn());return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),(0,_.useEffect)(()=>{let e=window.setInterval(()=>{document.hidden||y({runtime:!0,silent:!0}).catch(()=>void 0)},Sn);return()=>window.clearInterval(e)},[y]),(0,_.useEffect)(()=>{let t=window.setInterval(()=>{!document.hidden&&e?.settings.autoSwitch.enabled&&y({silent:!0}).catch(()=>void 0)},Cn);return()=>window.clearInterval(t)},[e?.settings.autoSwitch.enabled,y]),(0,_.useEffect)(()=>{let e=e=>{e.key===`Escape`&&(p(null),d(!1),l(!1))};return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[]),(0,_.useEffect)(()=>{e&&g.length===0&&v(Tt(e,o))},[e,g.length,o]),{config:e,setConfig:t,busy:n,setBusy:r,status:i,setStatus:a,showEmails:o,setShowEmails:s,accountModalOpen:c,setAccountModalOpen:l,contactOpen:u,setContactOpen:d,previewImage:f,setPreviewImage:p,activeRoute:m,setActiveRoute:h,requestLogs:g,setRequestLogs:v,refreshConfig:y}}function Tn(){let e=wn(),t=xn({config:e.config,busy:e.busy,activeRoute:e.activeRoute,showEmails:e.showEmails}),n=vn(e);return{...e,...t,...n}}function En(){return(0,O.jsx)(_n,{workspace:Tn()})}(0,v.createRoot)(document.getElementById(`root`)).render((0,O.jsx)(_.StrictMode,{children:(0,O.jsx)(En,{})}));
1745
+ `)),e.setStatus(`请求失败。`)}finally{e.setBusy(null)}}async function ee(t){if(!t.type.startsWith(`image/`)){e.setStatus(`请选择图片文件。`);return}try{i(St(r,await xt(t),e.config?.settings.defaultModel||`gpt-image-2`)),e.setStatus(`已将 ${t.name} 转成 base64 data URL,并写入请求体 images[0].image_url(${qe(t.size)})。`)}catch(t){e.setStatus(`图片写入失败: ${vt(t)}`)}}return(0,O.jsx)(un,{config:e.config,endpoints:p,activeEndpoint:m,endpoint:t,requestBody:r,responseBody:a,timingBody:s,resultTab:l,status:e.status,busy:e.busy,previewImages:d,capability:e.capability,onEndpoint:h,onRequestBody:i,onResultTab:u,onRun:x,onResetExample:g,onCopyRequest:v,onCopyResponse:y,onCopyTiming:b,onPreview:e.setPreviewImage,onImageUpload:ee})}var fn=`https://github.com/fchangjun/AI-Zero-Token/releases`;function pn(e){return(0,O.jsxs)(`section`,{className:`launch-page`,children:[(0,O.jsxs)(`div`,{className:`launch-copy`,children:[(0,O.jsxs)(`div`,{className:`launch-identity`,children:[(0,O.jsx)(`div`,{className:`launch-app-icon`,children:(0,O.jsx)(`img`,{src:y,alt:``})}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`span`,{className:`badge brand`,children:`Desktop Gateway`}),(0,O.jsx)(`h2`,{children:`AI Zero Token`}),(0,O.jsx)(`p`,{children:`本地 OpenAI 兼容网关、账号池和接口测试工作台。`})]})]}),(0,O.jsxs)(`div`,{className:`launch-metrics`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsx)(De,{size:18}),(0,O.jsx)(`span`,{children:`账号池`}),(0,O.jsx)(`strong`,{children:e.config?.status.profileCount||0})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(xe,{size:18}),(0,O.jsx)(`span`,{children:`网关`}),(0,O.jsx)(`strong`,{children:e.config?.status.loggedIn?`运行中`:`待登录`})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(ae,{size:18}),(0,O.jsx)(`span`,{children:`模型`}),(0,O.jsx)(`strong`,{children:e.config?.settings.defaultModel||`-`})]})]}),(0,O.jsxs)(`div`,{className:`launch-actions`,children:[(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>e.onRoute(`accounts`),children:[(0,O.jsx)(De,{size:16}),`管理账号`]}),(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:()=>e.onRoute(`tester`),children:[(0,O.jsx)(Ae,{size:16}),`测试接口`]}),(0,O.jsxs)(`a`,{className:`btn-secondary`,href:fn,target:`_blank`,rel:`noreferrer`,children:[(0,O.jsx)(E,{size:16}),`桌面版下载`]}),(0,O.jsxs)(`a`,{className:`btn-secondary`,href:fn,target:`_blank`,rel:`noreferrer`,title:`桌面版安装包发布后会放在这里`,children:[(0,O.jsx)(fe,{size:16}),`发布页`]})]}),(0,O.jsx)(`p`,{className:`launch-download-note`,children:`当前还没有公开安装包时,这里会先打开 GitHub Releases 发布页。`}),(0,O.jsxs)(`div`,{className:`launch-status`,children:[(0,O.jsx)(j,{label:`当前账号`,value:rt(e.activeProfile,e.showEmails)}),(0,O.jsx)(j,{label:`服务状态`,value:e.config?.status.loggedIn?`已登录并运行`:`等待登录`}),(0,O.jsx)(j,{label:`Base URL`,value:e.config?.baseUrl||`http://127.0.0.1:8787/v1`,code:!0}),(0,O.jsx)(j,{label:`同步消息`,value:e.status})]})]}),(0,O.jsx)(`div`,{className:`launch-visual`,children:(0,O.jsxs)(`div`,{className:`launch-visual-stage`,children:[(0,O.jsx)(`img`,{className:`launch-visual-mark`,src:y,alt:`AI Zero Token 图标`}),(0,O.jsx)(`img`,{className:`launch-visual-dashboard`,src:e.visualSrc||`data:image/svg+xml,%3csvg%20width='920'%20height='600'%20viewBox='0%200%20920%20600'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20width='920'%20height='600'%20rx='36'%20fill='%23F8FAFC'/%3e%3crect%20x='56'%20y='54'%20width='808'%20height='492'%20rx='24'%20fill='%23FFFFFF'%20stroke='%23D8E0EA'/%3e%3crect%20x='56'%20y='54'%20width='190'%20height='492'%20rx='24'%20fill='%23111827'/%3e%3cpath%20d='M246%2054h594c13.255%200%2024%2010.745%2024%2024v40H246V54Z'%20fill='%23F8FAFC'/%3e%3ccircle%20cx='88'%20cy='86'%20r='7'%20fill='%23EF4444'/%3e%3ccircle%20cx='112'%20cy='86'%20r='7'%20fill='%23F59E0B'/%3e%3ccircle%20cx='136'%20cy='86'%20r='7'%20fill='%2322C55E'/%3e%3crect%20x='86'%20y='148'%20width='108'%20height='14'%20rx='7'%20fill='%23E5E7EB'%20fill-opacity='.75'/%3e%3crect%20x='86'%20y='194'%20width='128'%20height='34'%20rx='10'%20fill='%232563EB'/%3e%3crect%20x='86'%20y='244'%20width='112'%20height='34'%20rx='10'%20fill='%231F2937'/%3e%3crect%20x='86'%20y='294'%20width='124'%20height='34'%20rx='10'%20fill='%231F2937'/%3e%3crect%20x='86'%20y='344'%20width='98'%20height='34'%20rx='10'%20fill='%231F2937'/%3e%3crect%20x='278'%20y='150'%20width='250'%20height='96'%20rx='18'%20fill='%23EFF6FF'%20stroke='%23BFDBFE'/%3e%3crect%20x='558'%20y='150'%20width='250'%20height='96'%20rx='18'%20fill='%23F0FDF4'%20stroke='%23BBF7D0'/%3e%3crect%20x='278'%20y='280'%20width='530'%20height='210'%20rx='18'%20fill='%23FFFFFF'%20stroke='%23D8E0EA'/%3e%3cpath%20d='M318%20430c43-68%2089-70%20137-8%2039%2049%2081%2037%20126-36%2038-62%2081-79%20129-21'%20stroke='%232563EB'%20stroke-width='8'%20stroke-linecap='round'/%3e%3cpath%20d='M318%20386c42-35%2083-33%20123%206%2045%2045%2092%2040%20141-16%2038-43%2080-49%20126-18'%20stroke='%2322C55E'%20stroke-width='8'%20stroke-linecap='round'/%3e%3crect%20x='318'%20y='316'%20width='118'%20height='13'%20rx='6.5'%20fill='%23111827'/%3e%3crect%20x='318'%20y='342'%20width='194'%20height='10'%20rx='5'%20fill='%23CBD5E1'/%3e%3crect%20x='596'%20y='182'%20width='80'%20height='12'%20rx='6'%20fill='%23111827'/%3e%3crect%20x='596'%20y='207'%20width='150'%20height='10'%20rx='5'%20fill='%2386EFAC'/%3e%3crect%20x='316'%20y='182'%20width='80'%20height='12'%20rx='6'%20fill='%23111827'/%3e%3crect%20x='316'%20y='207'%20width='150'%20height='10'%20rx='5'%20fill='%2393C5FD'/%3e%3ccircle%20cx='776'%20cy='198'%20r='16'%20fill='%2322C55E'/%3e%3cpath%20d='M768%20198l6%206%2011-13'%20stroke='%23FFFFFF'%20stroke-width='5'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M478%20186l15%2020-15%2020-15-20%2015-20Z'%20fill='%232563EB'/%3e%3c/svg%3e`,alt:`AI Zero Token 桌面端启动页配图`})]})})]})}function mn(e){return{defaultModel:e.settings.defaultModel,proxyEnabled:e.settings.networkProxy.enabled,proxyUrl:e.settings.networkProxy.url,proxyNoProxy:e.settings.networkProxy.noProxy||`localhost,127.0.0.1,::1`,autoSwitchEnabled:e.settings.autoSwitch.enabled}}function hn(e){let[t,n]=(0,_.useState)({defaultModel:``,proxyEnabled:!1,proxyUrl:``,proxyNoProxy:`localhost,127.0.0.1,::1`,autoSwitchEnabled:!1}),[r,i]=(0,_.useState)(!1);(0,_.useEffect)(()=>{!e.config||r||n(mn(e.config))},[e.config,r]);function a(e){n(t=>({...t,...e})),i(!0)}async function o(){e.setBusy(`settings`);try{let n=await ze(`/_gateway/admin/settings`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:He({defaultModel:t.defaultModel,networkProxy:{enabled:t.proxyEnabled,url:t.proxyUrl,noProxy:t.proxyNoProxy},autoSwitch:{enabled:t.autoSwitchEnabled}})});e.setConfig(n),i(!1),e.setStatus(`设置已保存。`)}catch(t){e.setStatus(vt(t))}finally{e.setBusy(null)}}async function s(){e.setBusy(`proxy`);try{let n=await ze(`/_gateway/admin/settings/proxy-test`,{method:`POST`,headers:{"Content-Type":`application/json`},body:He({networkProxy:{enabled:t.proxyEnabled,url:t.proxyUrl,noProxy:t.proxyNoProxy}})});e.setStatus(`代理测试通过: HTTP ${n.status},耗时 ${n.elapsedMs} ms。`)}catch(t){e.setStatus(`代理测试失败: ${vt(t)}`)}finally{e.setBusy(null)}}async function c(){e.setBusy(`models`);try{await ze(`/_gateway/models/refresh`,{method:`POST`}),await e.refreshConfig({silent:!0}),e.setStatus(`Codex 模型列表已同步。`)}catch(t){e.setStatus(vt(t))}finally{e.setBusy(null)}}return(0,O.jsxs)(`section`,{className:`settings-page`,children:[(0,O.jsxs)(`div`,{className:`settings-page-head`,children:[(0,O.jsxs)(`div`,{children:[(0,O.jsxs)(`div`,{className:`settings-page-kicker`,children:[(0,O.jsx)(Se,{size:14}),`系统设置`]}),(0,O.jsx)(`h2`,{children:`本地网关和运行策略`}),(0,O.jsx)(`p`,{children:`设置会保存到本地状态目录,CLI、桌面端和本地服务共享。`})]}),(0,O.jsxs)(`div`,{className:`settings-page-actions`,children:[(0,O.jsxs)(`button`,{className:`btn-secondary`,type:`button`,onClick:c,disabled:e.busy===`models`,children:[e.busy===`models`?(0,O.jsx)(ge,{className:`spin`,size:16}):(0,O.jsx)(ve,{size:16}),`同步 Codex 模型`]}),(0,O.jsx)(`button`,{className:`btn-primary`,type:`button`,onClick:o,disabled:e.busy===`settings`||!r,children:`保存设置`})]})]}),(0,O.jsxs)(`div`,{className:`settings-grid`,children:[(0,O.jsxs)(`section`,{className:`settings-section`,children:[(0,O.jsx)(`h4`,{children:`模型`}),(0,O.jsxs)(`label`,{className:`field`,children:[(0,O.jsx)(`span`,{children:`默认文本模型`}),(0,O.jsx)(`select`,{className:`control`,value:t.defaultModel,onChange:e=>a({defaultModel:e.target.value}),children:(e.config?.models||[]).map(e=>(0,O.jsx)(`option`,{value:e.id,children:e.id},e.id))})]}),(0,O.jsxs)(`p`,{className:`hint`,children:[`模型列表来源:`,e.config?.modelCatalog.source||`-`,`,共 `,e.config?.modelCatalog.modelCount||0,` 个。`]})]}),(0,O.jsxs)(`section`,{className:`settings-section`,children:[(0,O.jsx)(`h4`,{children:`上游代理`}),(0,O.jsxs)(`label`,{className:`switch-line`,children:[(0,O.jsx)(`input`,{type:`checkbox`,checked:t.proxyEnabled,onChange:e=>a({proxyEnabled:e.target.checked})}),(0,O.jsx)(`span`,{children:`启用 OAuth、模型刷新和接口转发代理`})]}),(0,O.jsxs)(`label`,{className:`field`,children:[(0,O.jsx)(`span`,{children:`代理地址`}),(0,O.jsx)(`input`,{className:`input`,value:t.proxyUrl,onChange:e=>a({proxyUrl:e.target.value}),placeholder:`http://127.0.0.1:7890`})]}),(0,O.jsxs)(`label`,{className:`field`,children:[(0,O.jsx)(`span`,{children:`No Proxy`}),(0,O.jsx)(`input`,{className:`input`,value:t.proxyNoProxy,onChange:e=>a({proxyNoProxy:e.target.value})})]}),(0,O.jsx)(`button`,{className:`btn-secondary`,type:`button`,onClick:s,disabled:e.busy===`proxy`,children:`测试代理`})]}),(0,O.jsxs)(`section`,{className:`settings-section`,children:[(0,O.jsx)(`h4`,{children:`账号自动切换`}),(0,O.jsxs)(`label`,{className:`switch-line`,children:[(0,O.jsx)(`input`,{type:`checkbox`,checked:t.autoSwitchEnabled,onChange:e=>a({autoSwitchEnabled:e.target.checked})}),(0,O.jsx)(`span`,{children:`当前 API 账号额度耗尽后自动切换到下一个仍有额度的账号`})]}),(0,O.jsx)(`p`,{className:`hint`,children:e.status})]}),(0,O.jsxs)(`section`,{className:`settings-section`,children:[(0,O.jsx)(`h4`,{children:`显示`}),(0,O.jsxs)(`label`,{className:`switch-line`,children:[(0,O.jsx)(`input`,{type:`checkbox`,checked:e.showEmails,onChange:t=>e.setShowEmails(t.target.checked)}),(0,O.jsx)(`span`,{children:`脱敏模式`})]}),(0,O.jsx)(`p`,{className:`hint`,children:`开启后账号邮箱将以脱敏形式展示。`})]})]})]})}function gn({workspace:e}){let{activeRoute:t,busy:n,config:r,refreshConfig:i}=e;return t===`launch`?(0,O.jsx)(pn,{config:r,visualSrc:Ot,status:e.status,showEmails:e.showEmails,activeProfile:e.activeProfile,onRoute:e.goRoute}):t===`overview`?(0,O.jsx)(Ht,{config:r,activeProfile:e.activeProfile,codexProfile:e.codexProfile,codexAccountId:e.codexAccountId,codexEmail:r?.codex?.email,showEmails:e.showEmails,requestLogs:e.requestLogs}):t===`docs`?(0,O.jsx)(Gt,{config:r,onRoute:e.goRoute,copyBaseUrl:e.copyBaseUrl,setStatus:e.setStatus}):t===`accounts`?(0,O.jsx)(Mt,{config:r,showEmails:e.showEmails,busy:n,activeProfile:e.activeProfile,codexAccountId:e.codexAccountId,setAccountModalOpen:e.setAccountModalOpen,setBusy:e.setBusy,setConfig:e.setConfig,setStatus:e.setStatus,refreshConfig:i,logout:e.logout}):t===`tester`?(0,O.jsx)(dn,{config:r,status:e.status,busy:n,showEmails:e.showEmails,capability:e.capability,setBusy:e.setBusy,setStatus:e.setStatus,setRequestLogs:e.setRequestLogs,refreshConfig:i,setPreviewImage:e.setPreviewImage}):t===`network`?(0,O.jsx)(ln,{}):t===`settings`?(0,O.jsx)(hn,{showEmails:e.showEmails,setShowEmails:e.setShowEmails,config:r,busy:n,status:e.status,setBusy:e.setBusy,setConfig:e.setConfig,setStatus:e.setStatus,refreshConfig:i}):(0,O.jsx)(Pt,{logs:e.requestLogs})}function _n({workspace:e}){return(0,O.jsxs)(`div`,{className:`app-shell`,children:[(0,O.jsx)(Ne,{workspace:e}),(0,O.jsxs)(`main`,{className:`main`,children:[(0,O.jsx)(Pe,{workspace:e}),(0,O.jsx)(gn,{workspace:e})]}),(0,O.jsx)(A,{workspace:e})]})}function vn(e){return{login:(0,_.useCallback)(async()=>{e.setBusy(`login`),e.setStatus(`正在打开 OAuth 登录...`);try{let t=await ze(`/_gateway/admin/login`,{method:`POST`});e.setConfig(t),e.setAccountModalOpen(!1),e.setStatus(`登录完成,账号状态已同步。`)}catch(t){e.setStatus(vt(t))}finally{e.setBusy(null)}},[e]),logout:(0,_.useCallback)(async()=>{if(window.confirm(`确认清空本地保存的所有账号?`)){e.setBusy(`logout`),e.setStatus(`正在清空账号...`);try{let t=await ze(`/_gateway/admin/logout`,{method:`POST`});e.setConfig(t),e.setRequestLogs([]),e.setStatus(`账号已清空。`)}catch(t){e.setStatus(vt(t))}finally{e.setBusy(null)}}},[e]),goRoute:(0,_.useCallback)(t=>{let n=`#${t}`;e.setActiveRoute(t),window.location.hash!==n&&(window.location.hash=t)},[e]),copyBaseUrl:(0,_.useCallback)(()=>{let t=e.config?.baseUrl||`http://127.0.0.1:8787/v1`;navigator.clipboard.writeText(t).then(()=>e.setStatus(`Base URL 已复制。`),()=>e.setStatus(t))},[e])}}var yn=[{id:`launch`,label:`启动页`,icon:me},{id:`overview`,label:`概览`,icon:he},{id:`accounts`,label:`账号管理`,icon:De},{id:`tester`,label:`接口测试`,icon:we},{id:`docs`,label:`使用文档`,icon:se},{id:`network`,label:`网络检测`,icon:Oe},{id:`logs`,label:`请求日志`,icon:D},{id:`settings`,label:`系统设置`,icon:Ce}];function bn(){let e=window.location.hash.replace(/^#\/?/,``);return yn.some(t=>t.id===e)?e:`overview`}function xn(e){let t=e.config?.profile||null,n=_t(t),r=e.config?.codex?.accountId,i=(0,_.useMemo)(()=>e.config?.profiles.find(e=>r&&e.accountId===r)||null,[r,e.config?.profiles]);return{routes:yn,activeRouteMeta:yn.find(t=>t.id===e.activeRoute)||yn[0],pageDescriptions:{launch:`面向桌面端的启动入口,聚合服务状态、快捷操作和产品视觉。`,overview:t?`当前账号为 ${rt(t,e.showEmails)},套餐 ${Qe(t)},可查看网关状态和运行摘要。`:`还没有激活账号。你可以新增账号、导入账号 JSON,或先查看本地 API 信息。`,accounts:`账号池、额度、套餐、Codex 应用状态集中管理,适合横向比较多个账号。`,tester:`独立接口测试工作区,支持 Chat、Responses、Models 和 gpt-image-2 图片接口。`,docs:`查看 AI-Zero-Token Skill.md,复制 Base URL、下载文档,并按步骤接入本地网关。`,network:`单页总览 IPv4、IPv6、DNS、WebRTC、常用平台和版本状态。`,logs:`查看本页快速测试产生的最近请求,包含接口、模型、状态和耗时。`,settings:`调整本地网关、默认模型、代理和自动切换策略的桌面设置页。`},activeProfile:t,codexProfile:i,codexAccountId:r,capability:n,isLoading:e.busy===`initial`&&!e.config}}var Sn=300*1e3,Cn=15*1e3;function wn(){let[e,t]=(0,_.useState)(null),[n,r]=(0,_.useState)(`initial`),[i,a]=(0,_.useState)(`正在读取本地网关状态...`),[o,s]=(0,_.useState)(!1),[c,l]=(0,_.useState)(!1),[u,d]=(0,_.useState)(!1),[f,p]=(0,_.useState)(null),[m,h]=(0,_.useState)(()=>bn()),[g,v]=(0,_.useState)([]),y=(0,_.useCallback)(async e=>{e?.silent||r(e?.runtime?`runtime-refresh`:`refresh`);try{let n=await ze(e?.runtime?`/_gateway/admin/runtime-refresh`:`/_gateway/admin/config`,e?.runtime?{method:`POST`}:void 0);t(n);let r=n.quotaSync;return a(e?.runtime&&r?`状态和额度已刷新:${r.synced}/${r.total} 个账号成功${r.failed?`,${r.failed} 个失败`:``}${r.skipped?`,${r.skipped} 个登录失效已跳过`:``}。`:e?.runtime?`状态和额度已刷新。`:`网关状态已同步。`),n}catch(e){throw a(vt(e)),e}finally{e?.silent||r(null)}},[]);return(0,_.useEffect)(()=>{y().catch(()=>void 0);let e=window.setInterval(()=>{y({silent:!0}).catch(()=>void 0)},6e4);return()=>window.clearInterval(e)},[y]),(0,_.useEffect)(()=>{let e=()=>{let e=bn();h(t=>t===e?t:e)};return window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[]),(0,_.useEffect)(()=>{let e=window.setInterval(()=>{document.hidden||y({runtime:!0,silent:!0}).catch(()=>void 0)},Sn);return()=>window.clearInterval(e)},[y]),(0,_.useEffect)(()=>{let t=window.setInterval(()=>{!document.hidden&&e?.settings.autoSwitch.enabled&&y({silent:!0}).catch(()=>void 0)},Cn);return()=>window.clearInterval(t)},[e?.settings.autoSwitch.enabled,y]),(0,_.useEffect)(()=>{let e=e=>{e.key===`Escape`&&(p(null),d(!1),l(!1))};return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[]),(0,_.useEffect)(()=>{e&&g.length===0&&v(Tt(e,o))},[e,g.length,o]),{config:e,setConfig:t,busy:n,setBusy:r,status:i,setStatus:a,showEmails:o,setShowEmails:s,accountModalOpen:c,setAccountModalOpen:l,contactOpen:u,setContactOpen:d,previewImage:f,setPreviewImage:p,activeRoute:m,setActiveRoute:h,requestLogs:g,setRequestLogs:v,refreshConfig:y}}function Tn(){let e=wn(),t=xn({config:e.config,busy:e.busy,activeRoute:e.activeRoute,showEmails:e.showEmails}),n=vn(e);return{...e,...t,...n}}function En(){return(0,O.jsx)(_n,{workspace:Tn()})}(0,v.createRoot)(document.getElementById(`root`)).render((0,O.jsx)(_.StrictMode,{children:(0,O.jsx)(En,{})}));
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" type="image/svg+xml" href="/assets/app-mark-Gd2QnHMO.svg" />
7
7
  <title>AI Zero Token</title>
8
- <script type="module" crossorigin src="/assets/index-CCywUil_.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-DZMegNPs.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-DNzR8XR7.css">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-zero-token",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Local-first OpenAI-compatible AI CLI and gateway with Codex OAuth, multi-account management, and gpt-image-2 image generation/editing.",
5
5
  "license": "MIT",
6
6
  "author": "AI Zero Token Contributors",