diff --git a/apps/desktop/src/main/bootstrap/post-auth-identity.ts b/apps/desktop/src/main/bootstrap/post-auth-identity.ts index 85fc36f4..5e4513cc 100644 --- a/apps/desktop/src/main/bootstrap/post-auth-identity.ts +++ b/apps/desktop/src/main/bootstrap/post-auth-identity.ts @@ -59,7 +59,7 @@ export interface PostAuthDeps { */ clearBlocked(): void } - media: { + media?: { selfAvatar(options?: { force?: boolean | undefined }): Promise<{ path: string | null reason: string | null @@ -270,7 +270,7 @@ export async function applyPostAuthIdentity( deps.dataPlane.clearBlocked() await confirmIdentity(deps, channelId) - await refreshAccountProfile(deps, status) + if (deps.media !== undefined) await refreshAccountProfile(deps, status) } /** @@ -431,6 +431,7 @@ async function refreshAccountProfile( deps: PostAuthDeps, status: Extract, ): Promise { + if (deps.media === undefined) return const { media, auth, logger, toFileUrl } = deps try { /** @@ -495,5 +496,7 @@ export function scopedChannelIdFor( channelId: string, binOverride: string | null | undefined, ): string { + /** Codex 记录与 DWS 二进制来源无关,不能继承 DWS 的来源后缀。 */ + if (channelId === "codex") return channelId return scopedChannelId(channelId, sourceKeyOf(binOverride ?? undefined)) } diff --git a/apps/desktop/src/main/bootstrap/startup.ts b/apps/desktop/src/main/bootstrap/startup.ts index b2ab6a1e..8090b247 100644 --- a/apps/desktop/src/main/bootstrap/startup.ts +++ b/apps/desktop/src/main/bootstrap/startup.ts @@ -7,6 +7,7 @@ */ import { randomUUID } from "node:crypto" import { existsSync, mkdirSync, rmSync, statSync, writeFileSync } from "node:fs" +import { homedir } from "node:os" import { dirname, join } from "node:path" import Database from "better-sqlite3" import { app, powerMonitor, shell, type BrowserWindow } from "electron" @@ -29,6 +30,7 @@ import { } from "@mycontext/store" import { ChannelHost, + createCodexLocalPlugin, createDingTalkPlugin, createFeishuPlugin, createRegistry, @@ -436,7 +438,14 @@ export function bootstrapApp(mainDir: string): AppContext { : `lark-cli-${process.platform}-${process.arch === "x64" ? "x64" : process.arch}`, ), }) - const registry = createRegistry([dingtalk, feishu]) + const codex = createCodexLocalPlugin({ + recordsRoot: () => { + const configured = process.env["CODEX_HOME"]?.trim() + return configured === undefined || configured === "" ? join(homedir(), ".codex") : configured + }, + consentRoot: () => vaultPaths?.codexAuthRoot ?? "", + }) + const registry = createRegistry([dingtalk, feishu, codex]) let window: BrowserWindow | null = null /** @@ -2873,8 +2882,15 @@ export function bootstrapApp(mainDir: string): AppContext { void mounted.klServer.ensureReady().catch(() => undefined) } } + const plugin = registry.get(channelId) await applyPostAuthIdentity( - { dataPlane, media, auth, logger, toFileUrl: toLocalFileUrl }, + { + dataPlane, + auth, + logger, + toFileUrl: toLocalFileUrl, + ...(plugin.avatars === undefined ? {} : { media }), + }, status, /** * ★ 把渠道传下去 —— 不传的话身份会写到**主渠道**那张表上, diff --git a/apps/desktop/src/main/services/channel.service.ts b/apps/desktop/src/main/services/channel.service.ts index e61426e8..f3636189 100644 --- a/apps/desktop/src/main/services/channel.service.ts +++ b/apps/desktop/src/main/services/channel.service.ts @@ -68,6 +68,7 @@ export class ChannelService { descriptionKey: plugin.meta.descriptionKey, available: plugin.meta.available, stepKeys: plugin.auth.describeStepKeys(), + authModes: plugin.auth.supportedModes?.() ?? ["loopback", "device"], status, loginInProgress: this.options.host.isLoginInProgress(plugin.meta.id), /** @@ -83,6 +84,7 @@ export class ChannelService { sendAs: [...plugin.capabilities.sendAs], domains: [...plugin.capabilities.domains], isolatedCredentials: plugin.capabilities.isolatedCredentials, + avatars: plugin.avatars !== undefined, }, }) } diff --git a/apps/desktop/src/renderer/features/channels/channel-auth-panel.tsx b/apps/desktop/src/renderer/features/channels/channel-auth-panel.tsx index c38343a4..033b187d 100644 --- a/apps/desktop/src/renderer/features/channels/channel-auth-panel.tsx +++ b/apps/desktop/src/renderer/features/channels/channel-auth-panel.tsx @@ -175,7 +175,8 @@ export function ChannelAuthPanel({ channel, variant = "settings" }: ChannelAuthP selfExternalId === null ? null : (selfAvatars.data?.find((e) => e.externalId === selfExternalId)?.path ?? null) - const scopePrefix = channel.id === "feishu" ? "feishuScope" : "scope" + const scopePrefix = + channel.id === "feishu" ? "feishuScope" : channel.id === "codex" ? "codexScope" : "scope" /** * 「本机已有登录态」这句话的 i18n key —— **按渠道分**。 * @@ -190,7 +191,9 @@ export function ChannelAuthPanel({ channel, variant = "settings" }: ChannelAuthP const machineSessionKey = channel.id === "feishu" ? "onboarding.machineSessionHintFeishu" - : "onboarding.machineSessionHint" + : channel.id === "codex" + ? "onboarding.machineSessionHintCodex" + : "onboarding.machineSessionHint" /** * 渠道侧的昵称(钉钉叫花名)。 @@ -458,11 +461,13 @@ export function ChannelAuthPanel({ channel, variant = "settings" }: ChannelAuthP */} {t(accountConnected ? "actions.reauthorize" : "actions.start")} - - - + {(channel.authModes ?? ["loopback", "device"]).includes("device") ? ( + + + + ) : null} {/* ── 退出授权 / 切换账号 ────────────────────────────────── @@ -542,7 +547,7 @@ export function ChannelAuthPanel({ channel, variant = "settings" }: ChannelAuthP `useFetchSelfAvatar` —— 后者会连账号级头像一起写,那会让"在飞书点 刷新、切回钉钉看到飞书那张"(已修,见那个 hook 的说明)。 */} - {accountConnected ? ( + {accountConnected && channel.capabilities?.avatars === true ? (