Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 未发布

- 面板凭据:选择 Claude Code 官方登录时直接打开槽终端,已有 OAuth 授权链接不再挡住 CC 登录路径。(#622)
- Responses WebSocket:入站 `response.interrupt`(Codex steer)本地中止在飞 hop 并回 `response.interrupt.accepted`;取消走既有 handleProtocol 终态记账,不再报 `unsupported Responses WebSocket message type` 或网关 `incomplete_response`。上游 interrupt 转发对齐 CPR 后置。(#616)
- Fable `7d_oi`:reset 已过(含秒级时间戳)不再永久判 rejected;`fableWindowResetAt` / weekly split 用 `parseResetMs`;过期清理纳入 `unified['7d_oi']`,且 `elapsedExtraResetMs` 纳入 `7d_oi` 后会在窗口过期时触发 usage probe;无 reset 时仍按 rejected 处理。(#601)
- OpenAI 槽:从 OAuth `id_token` 读取 `chatgpt_subscription_active_until`(含 epoch 秒/毫秒归一化为 ISO),刷新时新 token 带 claim 则覆盖到期日、不带则保留旧值;账号页只读展示「订阅到期(以凭证为准)」,缺失显示「—」。`plan_type` 缺失时用 id_token 的 `chatgpt_plan_type` 兜底展示;wham 写入的套餐类型优先。(#609)
Expand Down
66 changes: 32 additions & 34 deletions web/src/features/vm/credential-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,37 @@ function ClaudeCredentialPanel({
{importCred.isPending ? '换票中…' : '导入'}
</Button>
</div>
) : activeMethod === 'cc' ? (
<div className='space-y-2'>
<Hint>
打开槽终端并自动执行 claude auth
login。链接在终端里复制,授权码直接粘进终端,不经过面板。需要容器已运行且
cli-node 已安装。
</Hint>
<Button size='sm' onClick={() => setLoginOpen(true)}>
打开官方登录终端
</Button>
<Dialog open={loginOpen} onOpenChange={setLoginOpen}>
<DialogContent className='flex h-[70vh] max-w-4xl flex-col'>
<DialogHeader>
<DialogTitle>官方登录</DialogTitle>
<DialogDescription>
终端会执行 claude auth
login。复制里面的链接,授权码粘回这个终端。
</DialogDescription>
</DialogHeader>
<div className='min-h-0 flex-1'>
{loginOpen ? (
<WsTerminal
ticketPath={`/api/panel/vms/${encodeURIComponent(vmId)}/shell-ticket`}
socketPath={`/api/panel/vms/${encodeURIComponent(vmId)}/shell`}
officialLogin
/>
) : null}
</div>
</DialogContent>
</Dialog>
</div>
) : linkReady ? (
<div className='space-y-2'>
<div className='flex flex-wrap items-center gap-2'>
Expand Down Expand Up @@ -477,42 +508,9 @@ function ClaudeCredentialPanel({
<Hint>
{kind === 'setup-token'
? `申请完整 OAuth 权限,换票后采集身份。浏览器须走 ${proxyHint || '同一槽出口'},授权码须含 # 后半段。以 Setup Token 模式运行,不跑官方初装。`
: activeMethod === 'cc'
? `槽内 cli-node 执行官方 claude auth login。链接、PKCE 和换票都由官方 CLI 完成,浏览器须走 ${proxyHint || '同一槽出口'}。需要容器已运行且 cli-node 已安装。`
: `浏览器须走 ${proxyHint || '同一槽出口'},授权码须含 # 后半段。换票后采集身份。`}
: `浏览器须走 ${proxyHint || '同一槽出口'},授权码须含 # 后半段。换票后采集身份。`}
</Hint>
</div>
) : activeMethod === 'cc' ? (
<div className='space-y-2'>
<Hint>
打开槽终端并自动执行 claude auth
login。链接在终端里复制,授权码直接粘进终端,不经过面板。需要容器已运行且
cli-node 已安装。
</Hint>
<Button size='sm' onClick={() => setLoginOpen(true)}>
打开官方登录终端
</Button>
<Dialog open={loginOpen} onOpenChange={setLoginOpen}>
<DialogContent className='flex h-[70vh] max-w-4xl flex-col'>
<DialogHeader>
<DialogTitle>官方登录</DialogTitle>
<DialogDescription>
终端会执行 claude auth
login。复制里面的链接,授权码粘回这个终端。
</DialogDescription>
</DialogHeader>
<div className='min-h-0 flex-1'>
{loginOpen ? (
<WsTerminal
ticketPath={`/api/panel/vms/${encodeURIComponent(vmId)}/shell-ticket`}
socketPath={`/api/panel/vms/${encodeURIComponent(vmId)}/shell`}
officialLogin
/>
) : null}
</div>
</DialogContent>
</Dialog>
</div>
) : (
<div className='space-y-2'>
<Hint>
Expand Down
Loading