
【免费下载链接】jetbrains-cc-guiJetbrains Claude Code and Codex GUI Plugin项目地址https://gitcode.com/gh_mirrors/id/jetbrains-cc-gui点击查看免费下载导读本篇技术指南围绕 docs/codex/MULTI-PROVIDER-ARCHITECTURE.md 展开深入剖析 jetbrains-cc-guiJetBrains Claude Code and Codex GUI Plugin如何在同一 IDEA 插件内以统一抽象支撑 Claude、Codex 等多个 AI Provider。文章将带你理解“Java 层IDEA 插件— Node.js 层ai-bridge— Provider SDK/CLI”的三层桥接架构、统一权限模型的映射机制、会话 ID 抽象与事件流归一化协议并给出在仓库现有代码基础上扩展新 Provider以 Gemini 为例的完整实操步骤。读完本文你将掌握该插件多 Provider 架构的设计哲学、关键调用链以及如何诊断与排查 Provider 接入问题。架构哲学抽象、扩展性与优雅原文档以三句箴言开篇“Simplicity is the ultimate sophistication.”简单是极致的优雅、“Design is not just what it looks like and feels like. Design is how it works.”设计不止于外观更在于其运作方式。这并非装饰而是该多 Provider 架构落地的三条核心原则抽象Abstraction将不同 Provider 的差异SDK 调用方式、事件格式、权限模型隐藏在一组统一接口之后上层Java 与 WebView只感知统一概念可扩展Extensibility新增 Provider如 Gemini的改动被约束在“一个服务模块 一个权限映射 一处路由注册 一个 Java Bridge”的极小区间内优雅Elegance代码自描述、职责单一每个模块只做一件事且命名即文档。从仓库现状看这一设计已从“Claude Codex 双 Provider”演进为覆盖十类 Provider 的路由体系channel-manager.js 头部注释列出了claude、codex、grok、kimi、opencode、pi、omp、dsh、minimax、zcode共十个 provider其中仅claude/codex基于官方 SDK其余通过本地 CLI 二进制spawn 进程或持久化 app-server 接入。这一现状本身就是对“可扩展性”原则的最佳实证。三层架构总览Java Layer ↔ ai-bridge ↔ Provider SDK进程模型核心拓扑如下语义忠于原文档的架构图┌──────────────────────────────────────────────────────────────┐ │ Java 层IDEA 插件 │ │ ClaudeSDKBridge CodexSDKBridge GeminiSDKBridge(未来) │ │ - sessionId - threadId - │ │ - permissionMode - skipGitRepoCheck │ │ - attachments ✅ - attachments(已演进) │ └──────────────────────────────┬────────────────────────────────┘ ProcessBuilder stdin/stdout(JSON) │ ┌──────────────────────────────▼────────────────────────────────┐ │ Node.js 层ai-bridge │ │ channel-manager.jsRouter按 provider 分发 │ │ ├── channels/claude-channel.js → services/claude/* │ │ ├── channels/codex-channel.js → services/codex/* │ │ └── ...其余 Provider 同理 │ │ utils/permission-mapper.js统一权限 ↔ Provider 权限双向映射 │ └───────────────────────────────────────────────────────────────┘要点Java 层负责生命周期原文档明确指出sessionId/threadId由调用方Java 侧管理。对应地仓库中有五个 SDK Bridge 实现ClaudeSDKBridge.java、CodexSDKBridge.java、GrokSDKBridge.java、ZcodeSDKBridge.java以及承载公共逻辑的 BaseSDKBridge.java。Node.js 层负责协议转换统一入口channel-manager.js通过ProcessBuilder被 Java 拉起以node channel-manager.js provider command [args...]的形式接收命令消息体通过 stdin 以 JSON 传入结果与事件流通过 stdout 逐行回传。统一 JSON 协议字段conversationId会话 ID 的泛化名、permissionMode统一权限模式、message消息正文。入口与路由channel-manager.jschannel-manager.js是整个桥接的中枢其职责在源码头部注释中定义得清清楚楚单一入口、按 provider 分发、消息参数经 stdin 以 JSON 传递。关键实现细节Provider 校验与分发providerHandlers映射表channel-manager.js 中providerHandlers对象把claude→handleClaudeCommand、codex→handleCodexCommand以及system→handleSystemCommand用于getSdkStatus/checkClaudeSdk/checkCodexSdk等 SDK 可用性探测关联起来。未知 provider 会返回Invalid provider错误 JSON。stdin 读取的按 Provider 开关stdin-utils.js 为每个 Provider 预留独立的环境变量开关CODEX_USE_STDIN、GROK_USE_STDIN等仅当对应开关为true时才尝试读取 stdin JSON读取带 5 秒超时与 JSON 解析容错。stdout 刷新的正确性处理writeJsonAndExit在process.stdout.write的 flush 回调中退出避免console.log后立即process.exit截断大 JSON如getSession返回的历史记录正常路径则只设置process.exitCode让进程自然退出确保 I/O 完整落盘。从源码结构可以推断新增 Provider 的核心改动之一就是在providerHandlers注册一个 handler并在readStdinData对应的环境变量开关表中登记这两处与原文档 Step 4 “Update Router” 的意图完全一致只是仓库将其演化为独立channels/provider-channel.js文件以隔离各 Provider 的特定逻辑。统一权限模型PermissionMapper 双向映射为什么需要统一权限模型不同 Provider 的权限系统形态各异Claude简单的字符串模式default、sandbox、yoloCodex配置对象{skipGitRepoCheck: true, sandbox: workspace-write, approvalPolicy: on-request}未来 Provider如 Gemini可能又是另一套语义如安全分级。插件 UI 与 Java 层不能为每个 Provider 各写一套权限判断于是原文档给出“集中式权限映射器双向翻译”的解决方案。统一模式与 Provider 映射表原文档给出的映射表已结合当前源码扩充统一模式ClaudeCodexGemini示例DEFAULTdefaultworkspace-writeapprovalPolicy: on-requestBLOCK_MEDIUM_AND_ABOVESANDBOXsandboxread-onlyapprovalPolicy: on-requestBLOCK_ONLY_HIGHYOLOyolodanger-full-accessapprovalPolicy: neverBLOCK_NONEAUTO源码新增autoworkspace-writeapprovalPolicy: on-requestapprovalsReviewer: auto_review—当前仓库的 permission-mapper.js 在文档基础上做了两处显著演进统一模式扩充为四档UnifiedPermissionMode常量新增了AUTO原生自动审查由 Provider 自身的分类器/审查器决策审批请求并支持来自 WebView 的别名bypassPermissions归入YOLO、acceptEdits/autoEdit归入DEFAULT、plan归入SANDBOX通过normalizeUnifiedMode()统一归一化。Codex 映射细化CodexPermissionMapper.toProvider()不再只返回sandbox而是返回{skipGitRepoCheck, sandbox, approvalPolicy}三元组fromProvider()则依据sandbox取值read-only/danger-full-access/workspace-write与approvalsReviewer auto_review反向归一化。此外针对 Windows 平台沙箱为实验特性做了danger-full-access兜底并在注释中说明了 Codex CLI v0.149 移除untrusted、语义并入on-request的演进issue #1702。调用示例// Unified → Provider-Specific const mapper PermissionMapperFactory.getMapper(codex); const config mapper.toProvider(yolo); // → {skipGitRepoCheck: true, sandbox: danger-full-access, approvalPolicy: never} // Provider-Specific → Unified const unified mapper.fromProvider({sandbox: read-only}); // → sandboxPermissionMapperFactory.getMapper(provider)目前支持claude与codex对gemini会抛出 “Gemini permission mapping not yet implemented”与文档中“Gemini未来”的定位一致。单元测试 permission-mapper.test.js 覆盖了四档模式的双向映射断言含AUTO的approvalsReviewer: auto_review结构可作为扩展映射器时的回归基准。权限映射在 Codex 链路中的落地在 codex/message-service.js 的sendMessage中映射结果被组装进 Codex SDK 的threadOptionsskipGitRepoCheck→threadOptions.skipGitRepoChecksandbox→threadOptions.sandboxModeapprovalPolicy→threadOptions.approvalPolicymaxTurns固定为 200支持model、modelReasoningEffort、workingDirectory仅新线程设置恢复线程时跳过以便会话查找环境变量CODEX_SANDBOX_MODE、CODEX_APPROVAL_POLICY可对沙箱与审批策略做覆盖原生自动审查模式除外。此外buildCodexCliEnvironment()会对传给 SDK 的子进程环境做净化剥离继承的CODEX_*变量以避免污染这些细节共同保证了权限语义在“统一模式 → Provider 配置 → SDK 调用”全链路上不失真。会话 ID 抽象sessionId 与 threadId 的统一原文档指出的痛点Claude 使用sessionIdCodex 使用threadId若上层不抽象每个 Provider 的会话管理逻辑都将耦合进 UI 层。解决方案分两层Java 层使用泛化参数名如conversationId接口签名保持 Provider 无关Node.js 层各服务保留 Provider 原生命名——claude/message-service.js接收sessionId通道层将其解构后调用codex/message-service.js接收threadId见 codex-channel.js 中threadId的解构与透传。命名差异被收敛在channels/*-channel.js这一薄适配层内上层无需感知。Codex 侧对threadId的利用还体现在恢复机制上resumeThread(threadId, threadOptions)用于续聊且恢复时不重复注入workingDirectory与 AGENTS.md 指令新线程则通过startThread创建并采集AGENTS.md指令前置到消息中。最终结果 JSON 会回传state.currentThreadId供 Java 侧保存用于下次恢复。事件系统归一化统一控制台事件协议Claude 与 Codex 的事件格式差异巨大Claude{type: assistant, message: {...}}之类的会话消息结构Codex{type: item.completed, item: {type: agent_message, text: ...}}的流式 item 结构。原文档的解决方案是让每个 Provider 服务统一向 stdout 发射一组标记化事件console.log([MESSAGE_START]); console.log([CONTENT], content); console.log([CONTENT_DELTA], delta); console.log([MESSAGE_END]);仓库实现完全遵循并扩展了这一协议。以 Claude 链路为例message-sender.js 与 message-sender-anthropic.js 中实际发射[MESSAGE_START]、[CONTENT_DELTA]携带 JSON 序列化的 delta、[MESSAGE_END]Codex 侧则通过 codex-event-handler.js 的processCodexEventStream把thread.*/turn.*/item.*事件归一化为同一套[MESSAGE]/[CONTENT_DELTA]/[STREAM_START]/[STREAM_END]输出。值得注意的补充标记还包括[THREAD_ID]回传当前线程 ID文档的“Common Issues”中特别提醒此标记不可缺失[DEBUG]Node 侧诊断日志统一使用[DEBUG]前缀[SEND_ERROR]错误发生时以 JSON 结构化输出错误载荷。Java 层只需逐行解析 stdout识别这些信封标记并触发 UI 回调即可实现两种 Provider 完全一致的流式渲染体验。这也是原文档“Stream Buffering使用 BufferedReader 高效解析 stdout”建议的落点。消息流转全链路综合原文档的 Message Flow 与当前源码一次消息发送的完整调用链为用户在 IDEA 中输入消息Java 层如ClaudeSDKBridge/CodexSDKBridge构造携带消息的 stdin JSON通过ProcessBuilder拉起node channel-manager.js provider sendchannel-manager.js解析 stdin按provider分发到对应channels/provider-channel.jschannel 解构参数message、threadId/sessionId、cwd、permissionMode、model、baseUrl、apiKey、reasoningEffort等调用服务层message-service.js服务层通过PermissionMapperFactory映射权限 → 初始化 SDK动态加载见 sdk-loader.js→startThread/resumeThread→thread.runStreamed(input)事件处理器把 SDK 事件流归一化为[MESSAGE_START]/[CONTENT_DELTA]/[MESSAGE_END]等 stdout 标记Java 层逐行读取 stdout 并解析标记驱动 UI 流式更新。Codex 特有的两个补充能力一是buildCodexRunInput支持local_image附件以{type: local_image, path}数组形式传入 SDK空消息使用哨兵字符\u2063规避 CLI 拒绝空 stdin二是getMcpServerTools复用 Claude 的 mcp-status 探测逻辑mcp-status/index.js获取 MCP 工具列表其中对 Codex 配置字段http_headers、env_http_headers、bearer_token_env_var做了归一化转换。配置文件结构原文档的 File Structure 与仓库现状基本一致核心文件对照如下ai-bridge/ ├── channel-manager.js # 统一入口/路由provider 分发 ├── channels/ # 每 Provider 一个 channel 适配层 │ ├── claude-channel.js │ ├── codex-channel.js │ └── ...grok/kimi/opencode/pi/omp/dsh/minimax/zcode ├── services/ │ ├── claude/ │ │ ├── message-service.js # Claude SDK 集成 │ │ ├── session-service.js # 会话历史管理 │ │ └── attachment-service.js # 多模态支持 │ └── codex/ │ ├── message-service.js # Codex SDK 集成 │ ├── codex-event-handler.js # Codex 事件归一化 │ └── models-service.js # 模型列表发现 ├── utils/ │ ├── permission-mapper.js # 统一 ↔ Provider 权限翻译 │ ├── stdin-utils.js # JSON stdin/stdout 工具 │ └── sdk-loader.js # SDK 动态加载与状态探测 └── config/ └── api-config.js # API key/base URL/认证配置依赖方面package.json 声明了sql.js作为运行时依赖而anthropic-ai/claude-agent-sdk与openai/codex-sdk是通过插件设置页的 Dependencies 管理动态安装sdk-loader.js负责探测可用性这种“SDK 惰性加载”设计使未安装 SDK 的 Provider 不至于阻塞整个插件启动。API 配置自定义 Base URL 与 API Key原文档指出每个 Provider 均支持自定义 base URL 与 API key通过 stdin JSON 传递{ message: Hello, permissionMode: default, baseUrl: https://custom-api.example.com, // Optional apiKey: sk-... // Optional }仓库中该能力被两类路径落地Codex 侧codex/message-service.js 的sendMessage接收baseUrl/apiKey并分别写入codexOptions.baseUrl/codexOptions.apiKey同时支持reasoningEffort默认medium映射为modelReasoningEffort与serviceTier映射为 SDK 的service_tierfeatures.fast_mode。Claude 侧api-config.js 的setupApiKey()定义了严格的配置优先级——仅从~/.claude/settings.json读取忽略 shell 环境变量以保证单一事实来源依次支持ANTHROPIC_AUTH_TOKENBearer 认证→ANTHROPIC_API_KEYx-api-key 认证→ Bedrock 开关 →apiKeyHelperCLI Login 模式则走 SDK 原生 OAuth。injectStartupEnvVars()会在任何网络活动前把代理/TLS/AWS 凭据注入子进程环境解决桌面启动的 IDE 不继承 shell 环境的问题。这些细节印证了原文档“API Configuration”一节的通用约定也展示了仓库针对真实使用场景企业代理、Bedrock 认证、CLI 登录的加固。添加新 Provider 的完整实操以 Gemini 为例原文档给出了清晰的五步扩展路线以下结合仓库现状逐一展开。Step 1创建服务模块mkdir -p ai-bridge/services/gemini touch ai-bridge/services/gemini/message-service.js仓库当前的实际组织方式是在channels/下新增gemini-channel.js作为命令适配层再于services/gemini/下放置message-service.js与models-service.js。原文档的简化步骤与之一致仅多了一层 channel 适配可参考 grok-channel.js 等既有通道的写法。Step 2实现消息服务// ai-bridge/services/gemini/message-service.js import { GeminiClient } from google/generative-ai; import { GeminiPermissionMapper } from ../../utils/permission-mapper.js; export async function sendMessage(message, sessionId, cwd, permissionMode, model) { console.log([MESSAGE_START]); // 映射统一权限模式到 Gemini 语义 const config GeminiPermissionMapper.toProvider(permissionMode); // 调用 Gemini SDK示例 const client new GeminiClient(config); const response await client.generateContent(message); // 发射统一事件 console.log([CONTENT], response.text); console.log([MESSAGE_END]); console.log(JSON.stringify({success: true, sessionId})); }从现有 Codex 服务可看到更完整的工程化模板SDK 动态加载ensureCodexSdk、[DEBUG]诊断日志、[STREAM_START]/[STREAM_END]配对、错误载荷[SEND_ERROR]、以及最终{success, threadId/sessionId, result}的结果 JSON建议新 Provider 一并遵循。Step 3添加权限映射器// ai-bridge/utils/permission-mapper.js export class GeminiPermissionMapper { static toProvider(unifiedMode) { switch (unifiedMode) { case UnifiedPermissionMode.DEFAULT: return {safetySettings: BLOCK_MEDIUM_AND_ABOVE}; case UnifiedPermissionMode.SANDBOX: return {safetySettings: BLOCK_ONLY_HIGH}; case UnifiedPermissionMode.YOLO: return {safetySettings: BLOCK_NONE}; default: return {safetySettings: BLOCK_MEDIUM_AND_ABOVE}; } } }同时在PermissionMapperFactory.getMapper()的 switch 中注册case gemini否则会落入 “Gemini permission mapping not yet implemented” 的抛错分支——这是仓库源码中为新 Provider 预埋的显式占位正是新增映射器时需要替换的位置。Step 4更新路由// ai-bridge/channel-manager.js import { sendMessage as geminiSendMessage } from ./services/gemini/message-service.js; async function handleGeminiCommand(command, args, stdinData) { switch (command) { case send: await geminiSendMessage(...stdinData); break; } } // 在 providerHandlers 中注册 // gemini: handleGeminiCommand仓库建议的做法是在channels/gemini-channel.js中导出handleGeminiCommand再在channel-manager.js的providerHandlers注册同时别忘了在 stdin-utils.js 的STDIN_ENV_BY_PROVIDER中登记GEMINI_USE_STDIN开关。Step 5创建 Java Bridge// src/main/java/com/github/claudecodegui/provider/gemini/GeminiSDKBridge.java public class GeminiSDKBridge { public CompletableFutureSDKResult sendMessage(...) { // 与 CodexSDKBridge 类似 // 调用: node channel-manager.js gemini send } }可直接继承 BaseSDKBridge.java 复用进程拉起、stdout 解析、事件回调等公共逻辑仅实现 Gemini 特有的参数组装与默认值。完成以上五步后剩余的会话存储、UI 消息渲染、权限面板等均由既有架构自动承接——这正是原文档“Thats it! The architecture handles the rest automatically.” 的含义。测试与验证原文档给出的测试路径与仓库 npm scripts 完全对应package.jsoncd ai-bridge npm run test:claude # node channel-manager.js claude send npm run test:codex # node channel-manager.js codex send npm run test:sdk-status # node channel-manager.js system getSdkStatus手动验证权限映射cd ai-bridge node -e import {PermissionMapperFactory} from ./utils/permission-mapper.js; const config PermissionMapperFactory.toProvider(codex, yolo); console.log(config); // → {skipGitRepoCheck: true, sandbox: danger-full-access, approvalPolicy: never} 仓库还提供了一组可直接运行的自动化测试作为回归保障permission-mapper.test.js四档统一模式与 Claude/Codex 双向映射的结构化断言codex-event-handler.test.jsCodex 事件流归一化正确性message-service.test.js、models-service.test.mjs消息发送与模型发现逻辑。在接入新 Provider 时为gemini补一组等价测试尤其覆盖toProvider/fromProvider的边界与默认值是保证架构质量的最小成本。Provider 能力矩阵与演进状态原文档给出的能力矩阵含演进说明能力ClaudeCodexGemini未来流式输出✅✅✅会话恢复✅sessionId✅threadId✅sessionId附件/图片✅✅local_image已演进✅思维链Thinking✅✅reasoning 事件已支持⚠️IDE 上下文✅openedFiles⚠️⚠️工具/函数调用✅✅✅权限控制✅✅✅图例✅ 完整支持⚠️ 部分/手动支持❌ 不支持。对照仓库源码需要说明两处演进其一Codex 链路的 buildCodexRunInput 已支持local_image附件原文档“Attachments ❌”的标记已被源码推翻其二Codex 通过codex-event-handler.js处理 reasoning item 并输出[THINKING_HINT]提示思维链展示已可用部分场景受hide_agent_reasoning/show_raw_agent_reasoning配置影响详见 docs/codex/docs/config.md。安全注意事项原文档提出的四点安全准则在仓库中均有对应实现API Key 保护调试日志只记录hasApiKey: !!apiKey布尔值绝不输出明文codex/message-service.js 的[DEBUG]日志api-config.js 还定义了一组危险环境变量黑名单NODE_OPTIONS、LD_PRELOAD、PYTHONPATH等防止恶意项目通过 settings.json 注入代码执行。进程隔离每个 Provider 在独立的 Node.js 子进程中运行Java 层通过ProcessBuilder管理。权限前置校验Java 层在拉起子进程前校验权限模式Node 侧PermissionMapper是唯一的权限翻译入口。stdin/stdout JSON 序列化消息与参数经 JSON 传递避免命令注入readStdinData对解析失败有容错并返回null。性能优化建议进程复用高频操作为每个 Provider 考虑常驻进程/连接池仓库中的 daemon 模式与persistent-query-service即是该方向的实践流式缓冲Java 侧用BufferedReader逐行解析 stdoutNode 侧事件处理器尽量增量发射[CONTENT_DELTA]而非整体拼接超时管理stdin-utils.js的 5 秒读取超时、writeJsonAndExit的 5 秒兜底退出都是避免子进程悬挂的具体实现内存管理在finally块中清理 SDK 会话与子进程资源channel-manager.js对rewindFiles命令的强制退出即是针对 MCP 连接不释放的专项处理。常见问题排查“Provider not found”检查 provider 字符串是否与providerHandlers键精确匹配claude、codex、grok、kimi、opencode、pi、omp、dsh、minimax、zcode、system“Permission denied”核对PermissionMapperFactory在该 Provider 下的映射配置确认sandbox/approvalPolicy组合是否符合预期Codex 可借助CODEX_SANDBOX_MODE/CODEX_APPROVAL_POLICY环境变量临时覆盖验证“Thread ID not captured”确保服务在会话创建后发射console.log([THREAD_ID], threadId)Java 侧依赖该信封回传保存Codex 链路最终结果 JSON 中的threadId字段同样需要被消费Codex 无文本回复可能因任务纯信息收集、达到 200 turn 上限或仅执行命令所致服务会输出[WARNING]引导用户提出更具体的问题codex/message-service.js 的 no-response fallback调试日志Java 侧LOG.setLevel(Level.DEBUG)Node 侧统一使用[DEBUG]前缀输出同时channel-manager.js启动阶段会打印[DIAG-ENTRY]诊断块Node 版本、平台、CWD、argv、provider/command这是定位“没走到对应服务”的第一现场。未来增强方向原文档列出的五项演进方向中仓库已部分落地Provider 插件化当前十个 Provider 已证明“channels services”模式的扩展力未来可演进出 npm 包动态加载WebSocket 支持dshProvider 的 WS mux 与zcode的持久化 app-server 已是准实时通道的雏形缓存层相同查询的响应缓存可结合 lruCache 等既有工具指标采集按 Provider 统计用量、延迟、错误率WebView 侧已有 UsageStatistics 的 token 追踪面板A/B 测试同一查询路由到多个 Provider 对比结果。以上均为架构设计预留的空间是否落地取决于后续迭代计划本文仅作方向性陈述不构成现状承诺。参考资源本架构文档docs/codex/MULTI-PROVIDER-ARCHITECTURE.mdCodex 集成快速上手docs/codex/CODEX-INTEGRATION-QUICKSTART.mdCodex 详细配置docs/codex/docs/config.md路由入口实现ai-bridge/channel-manager.js权限映射实现ai-bridge/utils/permission-mapper.jsCodex 消息服务ai-bridge/services/codex/message-service.jsJava Bridge 公共基类src/main/java/com/github/claudecodegui/provider/common/BaseSDKBridge.java赞分享【免费下载链接】jetbrains-cc-guiJetbrains Claude Code and Codex GUI Plugin项目地址https://gitcode.com/gh_mirrors/id/jetbrains-cc-gui点击查看免费下载相关推荐CC GUIjetbrains-cc-gui版本演进全解读从单 CLI 桥接到多 Provider 架构的技术实践指南CC GUIjetbrains cc gui版本演进全解读从单 CLI 桥接到多 Provider 架构的技术实践指南 CC GUI原 idea clajetbrains-cc-gui 的 Opencode 集成前奏用 provider-neutral chat_event 契约统一结构化 Agent 的流式渲染jetbrains cc gui 的 Opencode 集成前奏用 provider neutral chat_event 契约统一结构化 Agent 的流式Happy Provider Envelope 重构设计以 OpenCode messageparts 模型统一多 Provider 会话协议Happy Provider Envelope 重构设计以 OpenCode messageparts 模型统一多 Provider 会话协议 本文基于 d人工智能AI AgentAI 应用移动开发CLI后端上一篇React Three Fiber性能优化终极指南10个技巧解决渲染瓶颈和兼容性问题下一篇想随时随地畅享二次元创作这个开源应用让你在手机和电脑间无缝切换创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考