@wu529778790/open-im 1.11.8-beta.23 → 1.11.8-beta.25

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.
@@ -217,22 +217,27 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
217
217
  const event = parseCodexEvent(line);
218
218
  if (!event)
219
219
  return;
220
- const type = event.type;
221
- log.debug(`[Codex event] type=${type}`);
222
- if (type === 'thread.started') {
223
- const threadId = event.thread_id ?? '';
220
+ // Codex CLI JSONL 格式是嵌套的:顶层 type "event_msg" / "response_item",
221
+ // 真正的子类型在 payload.type 里。旧版扁平格式也兼容。
222
+ const topType = event.type;
223
+ const payload = event.payload ?? event;
224
+ const type = payload.type ?? topType;
225
+ log.debug(`[Codex event] topType=${topType} type=${type}`);
226
+ // thread.started / session_meta → 拿 session ID
227
+ if (type === 'thread.started' || type === 'session_meta') {
228
+ const threadId = payload.thread_id ?? payload.session_id ?? event.thread_id ?? '';
224
229
  if (threadId)
225
230
  callbacks.onSessionId?.(threadId);
226
231
  return;
227
232
  }
228
233
  if (type === 'turn.failed') {
229
234
  completed = true;
230
- const err = event.error;
235
+ const err = payload.error ?? event.error;
231
236
  callbacks.onError(err?.message ?? 'Codex turn failed');
232
237
  return;
233
238
  }
234
239
  if (type === 'error') {
235
- const msg = event.message;
240
+ const msg = payload.message ?? event.message;
236
241
  if (msg?.includes('Reconnecting')) {
237
242
  return;
238
243
  }
@@ -240,12 +245,12 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
240
245
  callbacks.onError(msg ?? 'Codex stream error');
241
246
  return;
242
247
  }
243
- if (type === 'item.started' || type === 'item.updated' || type === 'item.completed') {
244
- const item = event.item;
245
- if (!item)
246
- return;
247
- const itemType = item.type;
248
- if (itemType === 'reasoning' && type === 'item.completed') {
248
+ // item 事件:payload 里可能有 item 字段,或者 payload 本身就是 item
249
+ if (topType === 'response_item' || type === 'item.started' || type === 'item.updated' || type === 'item.completed') {
250
+ const item = payload.item ?? payload;
251
+ const itemType = item.type ?? type;
252
+ if (itemType === 'reasoning') {
253
+ // Codex reasoning 可能是 encrypted_content(不可读),只在有 text 时累加
249
254
  const text = item.text;
250
255
  if (text) {
251
256
  accumulatedThinking += (accumulatedThinking ? '\n\n' : '') + text;
@@ -253,23 +258,41 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
253
258
  }
254
259
  return;
255
260
  }
261
+ // function_call(Codex 新格式:response_item.type=function_call)
262
+ if (itemType === 'function_call') {
263
+ const name = item.name ?? 'unknown';
264
+ const args = item.arguments;
265
+ const toolName = name === 'exec_command' ? 'Bash' : name === 'apply_patch' ? 'Edit' : name;
266
+ toolStats[toolName] = (toolStats[toolName] || 0) + 1;
267
+ callbacks.onToolUse?.(toolName, args ? { arguments: args } : {});
268
+ return;
269
+ }
270
+ // custom_tool_call(apply_patch 等)
271
+ if (itemType === 'custom_tool_call') {
272
+ const name = item.name ?? 'unknown';
273
+ const toolName = name === 'apply_patch' ? 'Edit' : name;
274
+ toolStats[toolName] = (toolStats[toolName] || 0) + 1;
275
+ callbacks.onToolUse?.(toolName, { input: item.input });
276
+ return;
277
+ }
278
+ // command_execution(旧格式)
256
279
  if (itemType === 'command_execution') {
257
280
  const cmd = item.command;
258
- if (cmd && type === 'item.started') {
259
- const toolName = 'Bash';
260
- toolStats[toolName] = (toolStats[toolName] || 0) + 1;
261
- callbacks.onToolUse?.(toolName, { command: cmd });
281
+ if (cmd) {
282
+ toolStats['Bash'] = (toolStats['Bash'] || 0) + 1;
283
+ callbacks.onToolUse?.('Bash', { command: cmd });
262
284
  }
263
285
  return;
264
286
  }
265
- if (itemType === 'file_change' && type === 'item.completed') {
287
+ // file_change(旧格式)
288
+ if (itemType === 'file_change') {
266
289
  const changes = item.changes;
267
- const toolName = 'Edit';
268
- toolStats[toolName] = (toolStats[toolName] || 0) + 1;
269
- callbacks.onToolUse?.(toolName, { changes });
290
+ toolStats['Edit'] = (toolStats['Edit'] || 0) + 1;
291
+ callbacks.onToolUse?.('Edit', { changes });
270
292
  return;
271
293
  }
272
- if (itemType === 'mcp_tool_call' && type === 'item.started') {
294
+ // mcp_tool_call(旧格式)
295
+ if (itemType === 'mcp_tool_call') {
273
296
  const tool = item.tool;
274
297
  const server = item.server;
275
298
  if (tool) {
@@ -279,16 +302,41 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
279
302
  }
280
303
  return;
281
304
  }
282
- if (itemType === 'agent_message' && type === 'item.completed') {
283
- const text = item.text;
305
+ // agent_message / message 最终回复文本
306
+ // Codex 新格式:event_msg.payload.type=agent_message, payload.message=文本
307
+ // response_item.payload.type=message, payload.content=[{type:output_text,text:...}]
308
+ if (itemType === 'agent_message' || itemType === 'message') {
309
+ let text;
310
+ if (itemType === 'agent_message') {
311
+ text = item.message ?? item.text;
312
+ }
313
+ else {
314
+ // message 类型,content 是数组
315
+ const content = item.content;
316
+ if (Array.isArray(content)) {
317
+ text = content
318
+ .filter((c) => c.type === 'output_text' && c.text)
319
+ .map((c) => c.text)
320
+ .join('\n');
321
+ }
322
+ }
284
323
  if (text) {
324
+ // 只累加 final_answer 或 commentary,避免重复
325
+ const phase = item.phase ?? payload.phase;
285
326
  accumulated += (accumulated ? '\n\n' : '') + text;
286
327
  callbacks.onText(accumulated);
287
328
  }
288
329
  return;
289
330
  }
290
331
  }
291
- if (type === 'turn.completed') {
332
+ // task_complete / turn.completed
333
+ if (type === 'task_complete' || type === 'turn.completed') {
334
+ // task_complete 里可能有 last_agent_message
335
+ const lastMsg = payload.last_agent_message;
336
+ if (lastMsg && !accumulated) {
337
+ accumulated = lastMsg;
338
+ callbacks.onText(accumulated);
339
+ }
292
340
  completed = true;
293
341
  callbacks.onComplete({
294
342
  success: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wu529778790/open-im",
3
- "version": "1.11.8-beta.23",
3
+ "version": "1.11.8-beta.25",
4
4
  "description": "Your AI coding assistant, in every chat app. Multi-platform IM bridge for Claude Code, Codex, and CodeBuddy.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1 @@
1
+ @import"https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap";:root{--c-bg: #fafafa;--c-surface: #ffffff;--c-surface-alt: #f5f5f5;--c-border: #e5e5e5;--c-border-foc: #a3a3a3;--c-text: #1a1a2e;--c-text-2: #525252;--c-text-3: #a3a3a3;--c-accent: #6366f1;--c-accent-h: #4f46e5;--c-accent-bg: #eef2ff;--c-accent-bdr: #c7d2fe;--c-ok: #10b981;--c-ok-bg: #ecfdf5;--c-ok-bdr: #a7f3d0;--c-warn: #f59e0b;--c-warn-bg: #fffbeb;--c-warn-bdr: #fde68a;--c-err: #ef4444;--c-err-bg: #fef2f2;--c-err-bdr: #fecaca;--shadow-xs: 0 1px 2px rgba(0,0,0,.05);--shadow-s: 0 1px 3px rgba(0,0,0,.1), 0 1px 2px rgba(0,0,0,.06);--shadow-m: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -2px rgba(0,0,0,.1);--shadow-l: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -4px rgba(0,0,0,.1);--shadow-glow: 0 0 20px rgba(99,102,241,.15);--r-s: 6px;--r-m: 8px;--r-l: 12px;--r-xl: 16px;--font-display: "Space Grotesk", -apple-system, sans-serif;--font-body: "Inter", -apple-system, sans-serif;--font-mono: "JetBrains Mono", "SF Mono", monospace;--fast: .12s ease;--norm: .2s ease;--slow: .3s ease}:root.dark{--c-bg: #0a0a0f;--c-surface: #141418;--c-surface-alt: #1e1e24;--c-border: #2a2a32;--c-border-foc: #52525e;--c-text: #f0f0f5;--c-text-2: #a0a0ae;--c-text-3: #5a5a68;--c-accent: #818cf8;--c-accent-h: #6366f1;--c-accent-bg: rgba(99,102,241,.12);--c-accent-bdr: rgba(99,102,241,.3);--c-ok-bg: rgba(16,185,129,.12);--c-ok-bdr: rgba(16,185,129,.3);--c-warn-bg: rgba(245,158,11,.12);--c-warn-bdr: rgba(245,158,11,.3);--c-err-bg: rgba(239,68,68,.12);--c-err-bdr: rgba(239,68,68,.3);--shadow-xs: 0 1px 2px rgba(0,0,0,.3);--shadow-s: 0 1px 3px rgba(0,0,0,.4), 0 1px 2px rgba(0,0,0,.3);--shadow-m: 0 4px 6px -1px rgba(0,0,0,.4), 0 2px 4px -2px rgba(0,0,0,.3);--shadow-l: 0 10px 15px -3px rgba(0,0,0,.4), 0 4px 6px -4px rgba(0,0,0,.3);--shadow-glow: 0 0 20px rgba(129,140,248,.2)}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}body{font-family:var(--font-body);font-size:14px;line-height:1.5;color:var(--c-text);background:var(--c-bg);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:focus-visible{outline:2px solid var(--c-accent);outline-offset:2px}.content{padding:32px 40px 64px;max-width:800px;width:100%;margin:0 auto}.header{position:sticky;top:0;z-index:15;background:var(--c-surface);border-bottom:1px solid var(--c-border);padding:0 40px;height:48px;display:flex;align-items:center;justify-content:space-between}.header-left{display:flex;align-items:center;gap:12px}.header-right{display:flex;align-items:center;gap:8px}.header-status{font-size:13px;font-weight:500;display:inline-flex;align-items:center;gap:6px;color:var(--c-text-2)}.header-status .dot{width:8px;height:8px;border-radius:50%;display:inline-block}.header-status .dot.running{background:var(--c-ok);box-shadow:0 0 12px var(--c-ok);animation:pulse 2s infinite}.header-status .dot.idle{background:var(--c-text-3)}.header-divider{width:1px;height:20px;background:var(--c-border);margin:0 4px}@keyframes pulse{0%,to{opacity:1}50%{opacity:.6}}.stats-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-bottom:32px}.stat-card{background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-l);padding:20px;transition:all var(--norm)}.stat-card:hover{box-shadow:var(--shadow-m);transform:translateY(-2px)}.stat-label{font-size:11px;font-weight:600;color:var(--c-text-3);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px}.stat-value{font-family:var(--font-display);font-size:32px;font-weight:700;color:var(--c-text);line-height:1;letter-spacing:-.02em}.stat-meta{font-size:12px;color:var(--c-text-3);margin-top:6px}.section{margin-bottom:40px}.section-head{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:20px;flex-wrap:wrap;gap:8px}.section-title{font-family:var(--font-display);font-size:18px;font-weight:600;color:var(--c-text);letter-spacing:-.01em}.section-desc{font-size:13px;color:var(--c-text-3)}.card{background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-l);overflow:hidden;transition:all var(--norm)}.card:hover{box-shadow:var(--shadow-s)}.card-head{padding:16px 20px;border-bottom:1px solid var(--c-border);display:flex;justify-content:space-between;align-items:center;gap:12px;cursor:pointer}.card-head:hover{background:var(--c-surface-alt)}.card-title{font-family:var(--font-display);font-size:14px;font-weight:600;color:var(--c-text)}.card-body{padding:20px}.platform-grid{display:grid;grid-template-columns:1fr;gap:16px}.platform-card{background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-l);overflow:visible;transition:all var(--norm)}.platform-card:hover{box-shadow:var(--shadow-m);border-color:var(--c-border-foc)}.platform-card.disabled{opacity:.85}.platform-card.enabled{border-color:var(--c-accent-bdr);box-shadow:0 0 0 1px var(--c-accent-bdr)}.platform-card-head{padding:16px 20px;display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer;border-radius:var(--r-l) var(--r-l) 0 0}.platform-card-head:hover{background:var(--c-surface-alt)}.platform-card-meta{display:flex;align-items:center;gap:12px;min-width:0}.platform-card-icon{width:40px;height:40px;border-radius:var(--r-m);background:var(--c-surface-alt);display:flex;align-items:center;justify-content:center;font-size:22px;line-height:1;flex-shrink:0}.platform-card-title-block{display:flex;flex-direction:column;gap:2px;min-width:0}.platform-card-name{font-family:var(--font-display);font-size:14px;font-weight:600;color:var(--c-text)}.platform-card-desc{font-size:12px;color:var(--c-text-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.platform-card-right{display:grid;grid-template-columns:minmax(104px,116px) minmax(72px,84px) 40px minmax(72px,84px);align-items:center;gap:10px;flex-shrink:0}.platform-card-control{display:flex;align-items:center;justify-content:center;min-width:0}.platform-card-control-menu{width:40px}.platform-status-badge{display:inline-flex;align-items:center;justify-content:center;width:100%;min-width:0;text-align:center;font-size:11px;font-weight:500;padding:3px 8px;border-radius:999px;border:1px solid transparent;white-space:nowrap}.platform-status-badge.on{background:var(--c-ok-bg);color:var(--c-ok);border-color:var(--c-ok-bdr)}.platform-status-badge.off{color:var(--c-text-3)}.platform-card-chevron{font-size:12px;color:var(--c-text-3);transition:transform var(--fast)}.platform-card-body{padding:16px 20px 20px;border-top:1px solid var(--c-border);border-radius:0 0 var(--r-l) var(--r-l)}.ai-command-picker{background:var(--c-surface-alt);border:1px solid var(--c-border);border-radius:var(--r-m);padding:12px 14px;display:flex;flex-direction:column;gap:6px;margin-bottom:16px}.ai-command-picker-title{font-family:var(--font-display);font-size:13px;font-weight:600;color:var(--c-text)}.ai-command-picker-hint{font-size:12px;color:var(--c-text-2)}.ai-command-picker .form-select{margin-top:2px}.platform-card-divider{border:0;border-top:1px solid var(--c-border);margin:0 0 16px}.platform-card-hint{font-size:12px;color:var(--c-text-3);line-height:1.5;margin-bottom:16px}.platform-card-help{margin-top:16px;padding:10px 14px;background:var(--c-surface-alt);border-radius:var(--r-m);font-size:12px;color:var(--c-text-2);line-height:1.6}.platform-card-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:16px}.platform-card-ai-tag{position:relative;display:inline-flex;align-items:center;justify-content:center;width:100%;min-width:0;font-size:11px;font-weight:500;padding:3px 10px;border-radius:999px;background:var(--c-surface-alt);color:var(--c-text-2);border:1px solid var(--c-border);cursor:pointer;white-space:nowrap;transition:all var(--fast)}.platform-card-ai-tag:hover{border-color:var(--c-accent-bdr);color:var(--c-text)}.platform-card-ai-dropdown{position:absolute;top:calc(100% + 4px);right:0;min-width:140px;background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-m);box-shadow:var(--shadow-m, 0 8px 24px rgba(0, 0, 0, .12));z-index:20;padding:4px}.platform-card-ai-option{display:block;width:100%;text-align:left;background:transparent;border:0;padding:6px 10px;font-size:12px;color:var(--c-text);cursor:pointer;border-radius:var(--r-s, 4px)}.platform-card-ai-option:hover{background:var(--c-surface-alt)}.platform-card-ai-option.active{color:var(--c-accent);font-weight:600}.platform-card-menu{position:relative;flex-shrink:0}.platform-card-menu-btn{width:32px;height:32px;background:transparent;border:0;padding:0;font-size:18px;line-height:1;color:var(--c-text-3);cursor:pointer;border-radius:var(--r-s, 4px);transition:all var(--fast)}.platform-card-menu-btn:hover{background:var(--c-surface-alt);color:var(--c-text)}.platform-card-menu-dropdown{position:absolute;top:calc(100% + 4px);right:0;min-width:160px;background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-m);box-shadow:var(--shadow-m, 0 8px 24px rgba(0, 0, 0, .12));z-index:20;padding:4px}.platform-card-menu-item{display:block;width:100%;text-align:left;background:transparent;border:0;padding:8px 12px;font-size:13px;color:var(--c-text);cursor:pointer;border-radius:var(--r-s, 4px)}.platform-card-menu-item:hover{background:var(--c-surface-alt)}.platform-card-menu-item.danger{color:var(--c-err, #d33)}.platform-card-menu-item.danger:hover{background:#dc353514}.platform-card-menu-item:disabled{opacity:.4;cursor:not-allowed}.platform-card-config-btn{min-width:72px}.platform-card-right .toggle{justify-content:center;width:100%}.qr-modal-overlay{position:fixed;top:0;right:0;bottom:0;left:0;background:#00000073;display:flex;align-items:center;justify-content:center;z-index:1000;padding:16px}.qr-modal{position:relative;background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-l);box-shadow:var(--shadow-l, 0 12px 40px rgba(0, 0, 0, .2));padding:28px 28px 24px;width:100%;max-width:360px;text-align:center}.qr-modal-close{position:absolute;top:8px;right:12px;background:transparent;border:0;font-size:22px;line-height:1;color:var(--c-text-3);cursor:pointer;padding:4px 8px;border-radius:var(--r-m)}.qr-modal-close:hover{background:var(--c-surface-alt);color:var(--c-text)}.qr-modal-title{font-family:var(--font-display);font-size:16px;font-weight:600;color:var(--c-text);margin-bottom:16px}.qr-modal-img-wrap{display:flex;align-items:center;justify-content:center;margin-bottom:14px}.qr-modal-img{width:220px;height:220px;border:1px solid var(--c-border);border-radius:var(--r-m)}.qr-modal-hint{font-size:13px;color:var(--c-text-2);line-height:1.5;margin-bottom:8px}.qr-modal-status{font-size:13px;color:var(--c-text-2);line-height:1.5}.qr-modal-status.muted{color:var(--c-text-3)}.qr-modal-status.ok{color:var(--c-ok);font-weight:600}.qr-modal-status.err{color:var(--c-err, var(--c-text));font-weight:500;word-break:break-word}.qr-modal-actions{display:flex;gap:8px;justify-content:center;margin-top:16px}.form-group{margin-bottom:14px}.form-group:last-child{margin-bottom:0}.form-label{display:block;font-size:12px;font-weight:500;color:var(--c-text-2);margin-bottom:5px}.form-input,.form-select,.form-textarea{width:100%;padding:8px 10px;font-family:inherit;font-size:13px;color:var(--c-text);background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-s);transition:border-color var(--fast),box-shadow var(--fast);outline:none}.form-input:focus,.form-select:focus,.form-textarea:focus{border-color:var(--c-accent);box-shadow:0 0 0 3px var(--c-accent-bg)}.form-input.mono,.form-textarea.mono{font-family:var(--font-mono);font-size:12px}.form-textarea{min-height:80px;resize:vertical}.form-hint{font-size:11px;color:var(--c-text-3);margin-top:4px;line-height:1.4}.form-hint a{color:var(--c-accent)}.form-hint code{font-family:var(--font-mono);font-size:10px;padding:1px 4px;background:var(--c-surface-alt);border-radius:3px}.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:7px 14px;font-family:var(--font-body);font-size:13px;font-weight:500;border-radius:var(--r-s);border:1px solid transparent;cursor:pointer;text-decoration:none;transition:all var(--fast);white-space:nowrap}.btn:disabled{opacity:.5;cursor:not-allowed}.btn-p{background:var(--c-accent);color:#fff}.btn-p:hover:not(:disabled){background:var(--c-accent-h);box-shadow:var(--shadow-glow)}.btn-s{background:var(--c-surface);color:var(--c-text);border-color:var(--c-border)}.btn-s:hover:not(:disabled){background:var(--c-surface-alt);border-color:var(--c-border-foc)}.btn-g{background:transparent;color:var(--c-text-2)}.btn-g:hover:not(:disabled){background:var(--c-surface-alt);color:var(--c-text)}.btn-d{background:var(--c-err-bg);color:var(--c-err);border-color:var(--c-err-bdr)}.btn-d:hover:not(:disabled){background:var(--c-err);color:#fff}.btn-w{background:var(--c-warn-bg);color:var(--c-warn);border-color:var(--c-warn-bdr)}.btn-w:hover:not(:disabled){background:var(--c-warn);color:#fff}.btn-sm{padding:5px 10px;font-size:12px}.btn-lg{padding:10px 20px;font-size:14px}.toggle{display:inline-flex;align-items:center;gap:8px;cursor:pointer;flex-shrink:0}.toggle-input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.toggle-track{position:relative;width:36px;height:20px;background:var(--c-border-foc);border-radius:999px;transition:background var(--fast);flex-shrink:0}.toggle-track:after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;background:#fff;border-radius:50%;transition:transform var(--fast);box-shadow:var(--shadow-xs)}.toggle-input:checked+.toggle-track{background:var(--c-accent);box-shadow:0 0 10px var(--c-accent)}.toggle-input:checked+.toggle-track:after{transform:translate(16px)}.tabs{display:inline-flex;gap:2px;padding:3px;background:var(--c-surface-alt);border:1px solid var(--c-border);border-radius:var(--r-m)}.tab{padding:6px 12px;font-size:12px;font-weight:500;color:var(--c-text-2);background:transparent;border:none;border-radius:var(--r-s);cursor:pointer;transition:all var(--fast)}.tab:hover{color:var(--c-text)}.tab.active{background:var(--c-surface);color:var(--c-text);box-shadow:var(--shadow-xs)}.msg{padding:10px 14px;border-radius:var(--r-m);font-size:13px;line-height:1.5}.msg-ok{background:var(--c-ok-bg);color:var(--c-ok)}.msg-err{background:var(--c-err-bg);color:var(--c-err)}.msg-w{background:var(--c-warn-bg);color:var(--c-warn)}.badge{display:inline-flex;align-items:center;padding:2px 8px;font-size:11px;font-weight:500;border-radius:999px}.badge-ok{background:var(--c-ok-bg);color:var(--c-ok)}.badge-err{background:var(--c-err-bg);color:var(--c-err)}.badge-w{background:var(--c-warn-bg);color:var(--c-warn)}.badge-info{background:var(--c-accent-bg);color:var(--c-accent)}.field-tip{font-size:11px;color:var(--c-text-3);line-height:1.45;margin-top:5px}.field-tip a{color:var(--c-accent)}.field-tip code{font-family:var(--font-mono);font-size:10px;padding:1px 4px;background:var(--c-surface-alt);border-radius:3px}.mt-4{margin-top:16px}.mt-6{margin-top:24px}.gap-2{gap:8px}.gap-3{gap:12px}.text-center{text-align:center}.mono{font-family:var(--font-mono)}.hidden{display:none!important}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.flash{margin-bottom:20px}.dark-btn{padding:4px 8px;border-radius:var(--r-s);border:1px solid var(--c-border);background:var(--c-surface);color:var(--c-text-2);cursor:pointer;font-size:14px;line-height:1;transition:all var(--fast);display:inline-flex;align-items:center;justify-content:center}.dark-btn:hover{border-color:var(--c-border-foc);color:var(--c-text)}.config-stack{display:flex;flex-direction:column;gap:16px}.config-card .card-title{font-family:var(--font-mono);font-size:13px}.config-card textarea{width:100%}.wizard-wrap{display:flex;justify-content:center;padding-top:16px}.wizard{width:100%;max-width:580px;background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-xl);box-shadow:var(--shadow-l);overflow:hidden}.wizard-bar{height:3px;background:var(--c-border)}.wizard-bar-fill{height:100%;background:var(--c-accent);transition:width .4s cubic-bezier(.4,0,.2,1)}.wizard-steps{display:flex;padding:20px 24px 0;gap:0}.wizard-step-ind{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;position:relative}.wizard-step-ind+.wizard-step-ind:before{content:"";position:absolute;top:12px;right:calc(50% + 16px);width:calc(100% - 32px);height:1px;background:var(--c-border)}.wizard-step-ind.done+.wizard-step-ind:before{background:var(--c-accent)}.wizard-step-dot{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;background:var(--c-surface-alt);color:var(--c-text-3);border:2px solid var(--c-border);position:relative;z-index:1;transition:all var(--norm)}.wizard-step-ind.active .wizard-step-dot{background:var(--c-accent);color:#fff;border-color:var(--c-accent);box-shadow:0 0 12px var(--c-accent)}.wizard-step-ind.done .wizard-step-dot{background:var(--c-ok);color:#fff;border-color:var(--c-ok)}.wizard-step-label{font-size:11px;font-weight:500;color:var(--c-text-3);white-space:nowrap}.wizard-step-ind.active .wizard-step-label{color:var(--c-accent);font-weight:600}.wizard-step-ind.done .wizard-step-label{color:var(--c-ok)}.wizard-body{padding:28px 32px;min-height:260px}.wizard-icon{font-size:36px;margin-bottom:12px}.wizard-title{font-family:var(--font-display);font-size:20px;font-weight:700;color:var(--c-text);margin-bottom:6px;letter-spacing:-.02em}.wizard-desc{font-size:13px;color:var(--c-text-2);line-height:1.6;margin-bottom:24px}.wizard-checklist{display:flex;flex-direction:column;gap:10px}.wizard-check{display:flex;align-items:center;gap:10px;font-size:13px;color:var(--c-text)}.wizard-check-num{width:24px;height:24px;border-radius:50%;background:var(--c-accent-bg);color:var(--c-accent);display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;flex-shrink:0}.wizard-chips{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:12px}.wizard-platform-card{background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-l);overflow:hidden;transition:border-color var(--fast)}.wizard-platform-card.on{border-color:var(--c-accent)}.wizard-platform-head{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;cursor:pointer;gap:8px}.wizard-platform-head:hover{background:var(--c-surface-alt)}.wizard-platform-meta{display:flex;align-items:center;gap:10px;min-width:0}.wizard-platform-icon{width:36px;height:36px;border-radius:var(--r-m);background:var(--c-surface-alt);display:flex;align-items:center;justify-content:center;font-size:20px;line-height:1;flex-shrink:0}.wizard-platform-title-block{display:flex;flex-direction:column;gap:1px;min-width:0}.wizard-platform-name{font-family:var(--font-display);font-size:14px;font-weight:600}.wizard-platform-desc{font-size:12px;color:var(--c-text-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.wizard-platform-right{display:flex;align-items:center;gap:8px;flex-shrink:0}.wizard-platform-chevron{font-size:12px;color:var(--c-text-3)}.wizard-platform-body{padding:0 16px 16px;border-top:1px solid var(--c-border)}.wizard-cred{background:var(--c-surface-alt);border:1px solid var(--c-border);border-radius:var(--r-l);padding:20px;margin-bottom:14px}.wizard-cred:last-child{margin-bottom:0}.wizard-cred-name{font-family:var(--font-display);font-size:14px;font-weight:600;margin-bottom:14px;color:var(--c-text)}.wizard-radio-group{display:flex;flex-direction:column;gap:8px}.wizard-radio{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:2px solid var(--c-border);border-radius:var(--r-m);cursor:pointer;transition:all var(--fast)}.wizard-radio:hover{border-color:var(--c-accent-bdr)}.wizard-radio.on{border-color:var(--c-accent);background:var(--c-accent-bg)}.wizard-radio input[type=radio]{margin-top:2px;accent-color:var(--c-accent)}.wizard-radio-body{display:flex;flex-direction:column;gap:2px}.wizard-radio-label{font-size:13px;font-weight:600;color:var(--c-text)}.wizard-radio-desc{font-size:12px;color:var(--c-text-3)}.wizard-review-block{margin-bottom:20px}.wizard-review-head{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--c-text-3);margin-bottom:10px}.wizard-kv{display:flex;justify-content:space-between;align-items:center;padding:7px 0;border-bottom:1px solid var(--c-border);font-size:12px}.wizard-kv span{color:var(--c-text-2)}.wizard-kv code{font-family:var(--font-mono);font-size:11px;color:var(--c-text);background:var(--c-surface-alt);padding:2px 6px;border-radius:4px}.wizard-platforms{display:flex;flex-wrap:wrap;gap:6px}.wizard-platform-pill{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--c-surface-alt);border-radius:999px;font-size:12px;font-weight:500}.wizard-platform-pill .cmd{font-size:10px;padding:1px 6px;border-radius:999px;background:var(--c-accent-bg);color:var(--c-accent);font-weight:500}.wizard-done{text-align:center;padding:20px 0}.wizard-nav{display:flex;align-items:center;padding:16px 32px 24px;gap:10px}.wizard-nav-spacer{flex:1}.wizard-pulse{animation:wiz-pulse 1.2s ease-in-out infinite}@keyframes wiz-pulse{0%,to{opacity:1}50%{opacity:.4}}.conn{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:32px}.conn-card{width:100%;max-width:420px;background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--r-xl);box-shadow:var(--shadow-l);padding:32px}.conn-logo{width:40px;height:40px;border-radius:var(--r-m);background:var(--c-accent);display:flex;align-items:center;justify-content:center;margin-bottom:20px}.conn-logo svg{width:22px;height:22px;color:#fff}.conn-title{font-family:var(--font-display);font-size:20px;font-weight:700;color:var(--c-text);margin-bottom:6px;letter-spacing:-.02em}.conn-desc{font-size:13px;color:var(--c-text-2);margin-bottom:24px;line-height:1.5}.conn-row{display:flex;gap:8px}.conn-input{flex:1;padding:8px 10px;font-family:var(--font-mono);font-size:13px;color:var(--c-text);background:var(--c-surface-alt);border:1px solid var(--c-border);border-radius:var(--r-s);outline:none;transition:border-color var(--fast)}.conn-input:focus{border-color:var(--c-accent);box-shadow:0 0 0 3px var(--c-accent-bg)}.conn-status{font-size:12px;margin-top:10px;color:var(--c-text-3)}.conn-status.ok{color:var(--c-ok)}.conn-status.err{color:var(--c-err)}@media(max-width:1024px){.stats-grid{grid-template-columns:1fr}}@media(max-width:768px){.content{padding:20px 16px 40px}.header{padding:0 16px}.header-toolbar{padding:10px 16px}.platform-grid{grid-template-columns:1fr}.platform-card-head{align-items:flex-start;flex-direction:column}.platform-card-right{width:100%;grid-template-columns:repeat(4,minmax(0,1fr))}.platform-card-control-menu,.platform-card-menu-btn{width:100%}.wizard-chips{grid-template-columns:1fr}}