@wwkit/freetoken 1.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.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/cli/helpers/args.js +48 -0
  4. package/cli/index.js +374 -0
  5. package/cli/pid-manager.js +87 -0
  6. package/client/index.html +25 -0
  7. package/client/public/favicon.svg +1 -0
  8. package/client/public/icons.svg +24 -0
  9. package/client/src/App.vue +136 -0
  10. package/client/src/assets/vite.svg +1 -0
  11. package/client/src/assets/vue.svg +1 -0
  12. package/client/src/components/ChatBox.vue +320 -0
  13. package/client/src/components/CheckList.vue +52 -0
  14. package/client/src/components/CodeBlock.vue +99 -0
  15. package/client/src/components/DetailBlock.vue +47 -0
  16. package/client/src/components/HelloWorld.vue +95 -0
  17. package/client/src/components/LangSwitch.vue +32 -0
  18. package/client/src/components/LinkList.vue +32 -0
  19. package/client/src/components/OsSwitch.vue +42 -0
  20. package/client/src/components/OsToggle.vue +15 -0
  21. package/client/src/components/PageHeader.vue +31 -0
  22. package/client/src/components/StepList.vue +92 -0
  23. package/client/src/composables/useClipboard.js +26 -0
  24. package/client/src/composables/useOs.js +22 -0
  25. package/client/src/data/docs/agent.js +1002 -0
  26. package/client/src/data/docs/auth.js +631 -0
  27. package/client/src/data/docs/builtin-tools.js +322 -0
  28. package/client/src/data/docs/chat.js +181 -0
  29. package/client/src/data/docs/index.js +9 -0
  30. package/client/src/data/docs/skills.js +396 -0
  31. package/client/src/data/docs/spec-conversion.js +1042 -0
  32. package/client/src/data/freeModels/bluesliu.js +97 -0
  33. package/client/src/data/freeModels/index.js +11 -0
  34. package/client/src/data/freeModels/nvidia.js +126 -0
  35. package/client/src/data/freeModels/openrouter.js +116 -0
  36. package/client/src/data/harness/claude.js +89 -0
  37. package/client/src/data/harness/codex.js +66 -0
  38. package/client/src/data/harness/dsh.js +86 -0
  39. package/client/src/data/harness/hermes.js +56 -0
  40. package/client/src/data/harness/index.js +22 -0
  41. package/client/src/data/harness/opencode.js +77 -0
  42. package/client/src/data/proxy/api-relay.js +53 -0
  43. package/client/src/data/proxy/builtin-proxy.js +54 -0
  44. package/client/src/data/proxy/cf-workers.js +67 -0
  45. package/client/src/data/proxy/ecs-forward.js +75 -0
  46. package/client/src/data/proxy/ecs-reverse.js +89 -0
  47. package/client/src/data/proxy/index.js +15 -0
  48. package/client/src/docs/claudecode.md +44 -0
  49. package/client/src/docs/codex.md +90 -0
  50. package/client/src/docs/hermesagent.md +42 -0
  51. package/client/src/docs/opencode.md +103 -0
  52. package/client/src/locales/en.js +436 -0
  53. package/client/src/locales/index.js +31 -0
  54. package/client/src/locales/zh-CN.js +461 -0
  55. package/client/src/main.js +16 -0
  56. package/client/src/router/index.js +76 -0
  57. package/client/src/style.css +15 -0
  58. package/client/src/views/AdminModelsView.vue +214 -0
  59. package/client/src/views/DocsView.vue +1604 -0
  60. package/client/src/views/FreeModelsView.vue +518 -0
  61. package/client/src/views/HarnessView.vue +314 -0
  62. package/client/src/views/HomeView.vue +147 -0
  63. package/client/src/views/ProxyView.vue +112 -0
  64. package/client/src/views/TokenMarketView.vue +26 -0
  65. package/client/vite.config.js +41 -0
  66. package/package.json +85 -0
  67. package/scripts/build-zip.sh +61 -0
  68. package/scripts/postinstall.js +7 -0
  69. package/server/src/config/targets.json +1 -0
  70. package/server/src/index.js +52 -0
  71. package/server/src/lib/coding-test.js +215 -0
  72. package/server/src/lib/database.js +353 -0
  73. package/server/src/lib/run-test.js +15 -0
  74. package/server/src/lib/scheduler.js +21 -0
  75. package/server/src/lib/tester.js +310 -0
  76. package/server/src/routes/admin.js +48 -0
  77. package/server/src/routes/proxy.js +64 -0
  78. package/server/src/routes/speed.js +87 -0
  79. package/src/config.js +45 -0
  80. package/src/config.json5 +27 -0
  81. package/src/index.js +10 -0
@@ -0,0 +1,1604 @@
1
+ <script setup>
2
+ import { ref, computed } from 'vue'
3
+ import { useI18n } from 'vue-i18n'
4
+ import { docsModules } from '../data/docs/index.js'
5
+ import PageHeader from '../components/PageHeader.vue'
6
+ import CodeBlock from '../components/CodeBlock.vue'
7
+ import DetailBlock from '../components/DetailBlock.vue'
8
+
9
+ const { t } = useI18n()
10
+
11
+ const chatModule = docsModules.find(m => m.id === 'chat')
12
+ const agentModule = docsModules.find(m => m.id === 'agent')
13
+ const specModule = docsModules.find(m => m.id === 'spec-conversion')
14
+ const authModule = docsModules.find(m => m.id === 'auth')
15
+ const skillsModule = docsModules.find(m => m.id === 'skills')
16
+
17
+ const activeModule = ref('chat')
18
+ const activeChatSection = ref(chatModule.sections[0].id)
19
+ const activeAgentTab = ref('tool-defs')
20
+ const activeExampleId = ref(agentModule.examples[0].id)
21
+ const activeSpecTab = ref('overview')
22
+ const activeAuthTab = ref(authModule.subModules[0].id)
23
+ const activeSkillsTab = ref(skillsModule.subModules[0].id)
24
+
25
+ // Agent tab 切换时同步示例选中
26
+ const agentTabs = computed(() => [
27
+ { id: 'tool-defs', label: t('docs.agent.toolDefs') },
28
+ ...agentModule.examples.map(ex => ({ id: ex.id, label: ex.title })),
29
+ { id: 'builtin', label: t('docs.agent.builtin') },
30
+ { id: 'summary', label: t('docs.agent.summary') },
31
+ ])
32
+
33
+ function switchAgentTab(tabId) {
34
+ activeAgentTab.value = tabId
35
+ const ex = agentModule.examples.find(e => e.id === tabId)
36
+ if (ex) {
37
+ activeExampleId.value = ex.id
38
+ }
39
+ }
40
+
41
+ // 步骤图标映射
42
+ const stepIcons = {
43
+ 'user-message': '💬',
44
+ request: '📤',
45
+ 'tool-call': '🤖',
46
+ execution: '⚙️',
47
+ 'tool-result': '📥',
48
+ 'final-response': '✅',
49
+ }
50
+
51
+ const labelTagType = {
52
+ primary: '',
53
+ info: 'info',
54
+ warning: 'warning',
55
+ success: 'success',
56
+ }
57
+ </script>
58
+
59
+ <template>
60
+ <div class="docs-page">
61
+ <PageHeader
62
+ :title="t('docs.pageTitle')"
63
+ :description="t('docs.pageDesc')"
64
+ />
65
+
66
+ <!-- 顶层模块切换:Chat | Agent -->
67
+ <el-tabs v-model="activeModule" class="module-tabs">
68
+ <el-tab-pane :label="t('docs.chat.tabLabel')" name="chat">
69
+ <!-- Chat 子模块 -->
70
+ <div v-if="activeModule === 'chat'" class="chat-section">
71
+ <div class="module-intro">
72
+ <h2>{{ chatModule.name }}</h2>
73
+ <el-tag>{{ chatModule.badge }}</el-tag>
74
+ <p class="module-tagline">{{ chatModule.tagline }}</p>
75
+ <p class="module-desc">{{ chatModule.description }}</p>
76
+ </div>
77
+
78
+ <el-tabs v-model="activeChatSection" class="sub-tabs">
79
+ <el-tab-pane
80
+ v-for="section in chatModule.sections"
81
+ :key="section.id"
82
+ :label="section.title"
83
+ :name="section.id"
84
+ >
85
+ <!-- 非流式 / 流式 -->
86
+ <template v-if="section.id === 'non-streaming' || section.id === 'streaming'">
87
+ <DetailBlock :title="t('docs.chat.request')" :description="section.description">
88
+ <CodeBlock :code="section.request" lang="json" filename="request.http" />
89
+ </DetailBlock>
90
+
91
+ <DetailBlock :title="t('docs.chat.response')" style="margin-top: 16px;">
92
+ <CodeBlock :code="section.response" lang="json" filename="response.json" />
93
+ </DetailBlock>
94
+
95
+ <DetailBlock :title="t('docs.chat.notes')" style="margin-top: 16px;">
96
+ <ul class="notes-list">
97
+ <li v-for="(note, i) in section.notes" :key="i">{{ note }}</li>
98
+ </ul>
99
+ </DetailBlock>
100
+ </template>
101
+
102
+ <!-- 核心参数 -->
103
+ <template v-else-if="section.id === 'parameters'">
104
+ <DetailBlock :title="section.title" :description="section.description">
105
+ <el-table :data="section.params" border stripe>
106
+ <el-table-column prop="name" :label="t('docs.chat.paramName')" width="140">
107
+ <template #default="scope">
108
+ <code class="param-name">{{ scope.row.name }}</code>
109
+ </template>
110
+ </el-table-column>
111
+ <el-table-column prop="type" :label="t('docs.chat.paramType')" width="120" />
112
+ <el-table-column :label="t('docs.chat.paramRequired')" width="80">
113
+ <template #default="scope">
114
+ <el-tag :type="scope.row.required ? 'danger' : 'info'" size="small">
115
+ {{ scope.row.required ? t('docs.chat.yes') : t('docs.chat.no') }}
116
+ </el-tag>
117
+ </template>
118
+ </el-table-column>
119
+ <el-table-column prop="description" :label="t('docs.chat.paramDesc')" />
120
+ </el-table>
121
+ </DetailBlock>
122
+ </template>
123
+ </el-tab-pane>
124
+ </el-tabs>
125
+ </div>
126
+ </el-tab-pane>
127
+
128
+ <el-tab-pane :label="t('docs.agent.tabLabel')" name="agent">
129
+ <!-- Agent 子模块 -->
130
+ <div v-if="activeModule === 'agent'" class="agent-section">
131
+ <div class="module-intro">
132
+ <h2>{{ agentModule.name }}</h2>
133
+ <el-tag type="warning">{{ agentModule.badge }}</el-tag>
134
+ <p class="module-tagline">{{ agentModule.tagline }}</p>
135
+ <p class="module-desc">{{ agentModule.description }}</p>
136
+ </div>
137
+
138
+ <el-tabs
139
+ v-model="activeAgentTab"
140
+ class="sub-tabs"
141
+ @tab-change="switchAgentTab"
142
+ >
143
+ <!-- 工具定义 -->
144
+ <el-tab-pane :label="t('docs.agent.toolDefs')" name="tool-defs">
145
+ <DetailBlock :title="agentModule.toolDefs.title" :description="agentModule.toolDefs.description">
146
+ <CodeBlock
147
+ :code="JSON.stringify(agentModule.toolDefs.tools, null, 2)"
148
+ lang="json"
149
+ filename="tools-definition.json"
150
+ />
151
+ </DetailBlock>
152
+ <DetailBlock :title="t('docs.chat.notes')" style="margin-top: 16px;">
153
+ <ul class="notes-list">
154
+ <li v-for="(note, i) in agentModule.toolDefs.notes" :key="i">{{ note }}</li>
155
+ </ul>
156
+ </DetailBlock>
157
+ </el-tab-pane>
158
+
159
+ <!-- 各示例 -->
160
+ <el-tab-pane
161
+ v-for="example in agentModule.examples"
162
+ :key="example.id"
163
+ :label="example.title"
164
+ :name="example.id"
165
+ >
166
+ <div class="example-header">
167
+ <p class="example-scenario">
168
+ <strong>{{ t('docs.agent.scenario') }}:</strong>{{ example.scenario }}
169
+ </p>
170
+ <p class="example-desc">{{ example.description }}</p>
171
+ </div>
172
+
173
+ <!-- Timeline 步骤 -->
174
+ <div class="flow-timeline">
175
+ <div
176
+ v-for="step in example.steps"
177
+ :key="step.step"
178
+ class="flow-step"
179
+ >
180
+ <!-- 步骤连接线 -->
181
+ <div class="step-marker">
182
+ <span class="step-icon">{{ stepIcons[step.type] || '📌' }}</span>
183
+ <span class="step-number">{{ step.step }}</span>
184
+ <div v-if="step.step < example.steps.length" class="step-line" />
185
+ </div>
186
+
187
+ <!-- 步骤内容 -->
188
+ <div class="step-body">
189
+ <div class="step-header">
190
+ <span class="step-title">{{ step.title }}</span>
191
+ <el-tag
192
+ v-if="step.label"
193
+ :type="labelTagType[step.labelType] || ''"
194
+ size="small"
195
+ >
196
+ {{ step.label }}
197
+ </el-tag>
198
+ </div>
199
+
200
+ <!-- 用户消息 -->
201
+ <div v-if="step.type === 'user-message'" class="user-bubble">
202
+ {{ step.content }}
203
+ </div>
204
+
205
+ <!-- 描述文字 -->
206
+ <p v-if="step.description" class="step-desc">{{ step.description }}</p>
207
+
208
+ <!-- 代码块 -->
209
+ <CodeBlock
210
+ v-if="step.code"
211
+ :code="step.code"
212
+ :lang="step.codeLang || 'json'"
213
+ :filename="step.type === 'request' ? 'request.http' : step.type === 'tool-call' ? 'response.json' : step.type === 'tool-result' ? 'request-with-result.http' : step.type === 'final-response' ? 'final-response.json' : ''"
214
+ />
215
+
216
+ <!-- 单工具执行 -->
217
+ <div v-if="step.type === 'execution' && step.toolName && !step.parallelTools" class="tool-exec">
218
+ <div class="tool-exec-block">
219
+ <div class="tool-exec-label">
220
+ <el-tag type="success" size="small">{{ step.toolName }}</el-tag>
221
+ <span class="tool-exec-arrow">→</span>
222
+ <span class="tool-exec-text">{{ t('docs.agent.execution') }}</span>
223
+ </div>
224
+ <div v-if="step.accumulate" class="accumulate-section">
225
+ <div class="tool-output-label">客户端拼接逻辑</div>
226
+ <CodeBlock :code="step.accumulate" lang="javascript" filename="accumulate.js" />
227
+ </div>
228
+ <CodeBlock :code="step.toolInput" lang="bash" filename="tool-input" />
229
+ <div class="tool-output-label">{{ t('docs.agent.output') }}</div>
230
+ <CodeBlock :code="step.toolOutput" lang="bash" filename="tool-output" />
231
+ </div>
232
+ </div>
233
+
234
+ <!-- 并行工具执行 -->
235
+ <div v-if="step.parallelTools" class="parallel-exec">
236
+ <div class="parallel-grid">
237
+ <div v-for="(pt, pi) in step.parallelTools" :key="pi" class="parallel-card">
238
+ <div class="parallel-card-header">
239
+ <el-tag type="success" size="small">{{ pt.toolName }}</el-tag>
240
+ </div>
241
+ <CodeBlock :code="pt.toolInput" lang="bash" :filename="`input-${pi + 1}`" />
242
+ <div class="tool-output-label">{{ t('docs.agent.output') }}</div>
243
+ <CodeBlock :code="pt.toolOutput" lang="bash" :filename="`output-${pi + 1}`" />
244
+ </div>
245
+ </div>
246
+ </div>
247
+ </div>
248
+ </div>
249
+ </div>
250
+ </el-tab-pane>
251
+
252
+ <!-- 内置工具完整描述 -->
253
+ <el-tab-pane :label="t('docs.agent.builtin')" name="builtin">
254
+ <DetailBlock
255
+ :title="t('docs.agent.builtinTitle')"
256
+ :description="t('docs.agent.builtinDesc')"
257
+ >
258
+ <el-collapse class="builtin-collapse">
259
+ <el-collapse-item
260
+ v-for="tool in agentModule.builtinTools"
261
+ :key="tool.name"
262
+ :name="tool.name"
263
+ >
264
+ <template #title>
265
+ <div class="builtin-tool-header">
266
+ <code class="builtin-tool-name">{{ tool.name }}</code>
267
+ <span class="builtin-tool-summary">{{ tool.summary }}</span>
268
+ </div>
269
+ </template>
270
+ <div class="builtin-tool-body">
271
+ <div class="builtin-section-label">{{ t('docs.agent.description') }}</div>
272
+ <pre class="builtin-desc-text">{{ tool.description }}</pre>
273
+ <div class="builtin-section-label" style="margin-top: 16px;">{{ t('docs.agent.parameters') }}</div>
274
+ <CodeBlock
275
+ :code="JSON.stringify(tool.parameters, null, 2)"
276
+ lang="json"
277
+ :filename="`${tool.name}-params.json`"
278
+ />
279
+ </div>
280
+ </el-collapse-item>
281
+ </el-collapse>
282
+ </DetailBlock>
283
+ </el-tab-pane>
284
+
285
+ <!-- 总结 -->
286
+ <el-tab-pane :label="t('docs.agent.summary')" name="summary">
287
+ <DetailBlock :title="agentModule.summary.title" :description="agentModule.summary.description">
288
+ <div class="summary-flow">
289
+ <div v-for="(item, i) in agentModule.summary.flow" :key="i" class="summary-item">
290
+ <div class="summary-phase">
291
+ <span class="summary-num">{{ i + 1 }}</span>
292
+ <strong>{{ item.phase }}</strong>
293
+ </div>
294
+ <p class="summary-detail">{{ item.detail }}</p>
295
+ </div>
296
+ </div>
297
+ </DetailBlock>
298
+ </el-tab-pane>
299
+ </el-tabs>
300
+ </div>
301
+ </el-tab-pane>
302
+
303
+ <!-- 规格转换模块 -->
304
+ <el-tab-pane :label="t('docs.spec.tabLabel')" name="spec">
305
+ <div v-if="activeModule === 'spec'" class="spec-section">
306
+ <div class="module-intro">
307
+ <h2>{{ specModule.name }}</h2>
308
+ <el-tag type="info">{{ specModule.badge }}</el-tag>
309
+ <p class="module-tagline">{{ specModule.tagline }}</p>
310
+ <p class="module-desc">{{ specModule.description }}</p>
311
+ </div>
312
+
313
+ <el-tabs v-model="activeSpecTab" class="sub-tabs">
314
+ <!-- 概览 -->
315
+ <el-tab-pane :label="t('docs.spec.overview')" name="overview">
316
+ <el-row :gutter="16">
317
+ <el-col v-for="spec in specModule.specs" :key="spec.id" :xs="24" :sm="8">
318
+ <el-card shadow="hover" class="spec-card">
319
+ <h3 class="spec-name">{{ spec.name }}</h3>
320
+ <code class="spec-endpoint">{{ spec.endpoint }}</code>
321
+ <p class="spec-desc">{{ spec.description }}</p>
322
+ <div class="spec-fields">
323
+ <div v-for="f in spec.keyFields" :key="f.field" class="spec-field">
324
+ <code class="field-name">{{ f.field }}</code>
325
+ <span class="field-type">{{ f.type }}</span>
326
+ <span class="field-note">{{ f.note }}</span>
327
+ </div>
328
+ </div>
329
+ </el-card>
330
+ </el-col>
331
+ </el-row>
332
+ </el-tab-pane>
333
+
334
+ <!-- 差异对比表 -->
335
+ <el-tab-pane :label="t('docs.spec.comparison')" name="comparison">
336
+ <DetailBlock :title="t('docs.spec.comparison')">
337
+ <el-table :data="specModule.comparisonTable" border stripe>
338
+ <el-table-column prop="aspect" :label="t('docs.spec.aspect')" width="130" fixed />
339
+ <el-table-column prop="openai" label="OpenAI Chat" min-width="200" />
340
+ <el-table-column prop="claude" label="Claude Messages" min-width="200" />
341
+ <el-table-column prop="codex" label="Codex Responses" min-width="200" />
342
+ </el-table>
343
+ </DetailBlock>
344
+ </el-tab-pane>
345
+
346
+ <!-- 请求体转换 -->
347
+ <el-tab-pane :label="specModule.requestConversion.title" name="request">
348
+ <DetailBlock :title="specModule.requestConversion.title" :description="specModule.requestConversion.description">
349
+ <el-tabs type="card">
350
+ <el-tab-pane
351
+ v-for="ex in specModule.requestConversion.examples"
352
+ :key="ex.spec"
353
+ :label="ex.label"
354
+ >
355
+ <CodeBlock :code="ex.code" lang="json" :filename="`${ex.spec}-request.http`" />
356
+ </el-tab-pane>
357
+ </el-tabs>
358
+ </DetailBlock>
359
+ <DetailBlock :title="t('docs.spec.mappings')" style="margin-top: 16px;">
360
+ <el-table :data="specModule.requestConversion.mappings" border stripe>
361
+ <el-table-column prop="from" label="OpenAI Chat" width="200" />
362
+ <el-table-column prop="to_claude" label="→ Claude" width="200" />
363
+ <el-table-column prop="to_codex" label="→ Codex" width="200" />
364
+ <el-table-column prop="note" :label="t('docs.spec.note')" />
365
+ </el-table>
366
+ </DetailBlock>
367
+ </el-tab-pane>
368
+
369
+ <!-- 响应体转换 -->
370
+ <el-tab-pane :label="specModule.responseConversion.title" name="response">
371
+ <DetailBlock :title="specModule.responseConversion.title" :description="specModule.responseConversion.description">
372
+ <el-tabs type="card">
373
+ <el-tab-pane
374
+ v-for="ex in specModule.responseConversion.examples"
375
+ :key="ex.spec"
376
+ :label="ex.label"
377
+ >
378
+ <CodeBlock :code="ex.code" lang="json" :filename="`${ex.spec}-response.json`" />
379
+ </el-tab-pane>
380
+ </el-tabs>
381
+ </DetailBlock>
382
+ <DetailBlock :title="t('docs.spec.mappings')" style="margin-top: 16px;">
383
+ <el-table :data="specModule.responseConversion.mappings" border stripe>
384
+ <el-table-column prop="from" label="OpenAI Chat" width="220" />
385
+ <el-table-column prop="to_claude" label="→ Claude" width="200" />
386
+ <el-table-column prop="to_codex" label="→ Codex" width="200" />
387
+ <el-table-column prop="note" :label="t('docs.spec.note')" />
388
+ </el-table>
389
+ </DetailBlock>
390
+ </el-tab-pane>
391
+
392
+ <!-- 流式事件转换 -->
393
+ <el-tab-pane :label="specModule.streamConversion.title" name="stream">
394
+ <DetailBlock :title="specModule.streamConversion.title" :description="specModule.streamConversion.description">
395
+ <el-table :data="specModule.streamConversion.eventMapping" border stripe>
396
+ <el-table-column prop="phase" :label="t('docs.spec.phase')" width="100" fixed />
397
+ <el-table-column label="OpenAI Chat" min-width="220">
398
+ <template #default="scope"><pre class="sse-pre">{{ scope.row.openai }}</pre></template>
399
+ </el-table-column>
400
+ <el-table-column label="Claude Messages" min-width="220">
401
+ <template #default="scope"><pre class="sse-pre">{{ scope.row.claude }}</pre></template>
402
+ </el-table-column>
403
+ <el-table-column label="Codex Responses" min-width="220">
404
+ <template #default="scope"><pre class="sse-pre">{{ scope.row.codex }}</pre></template>
405
+ </el-table-column>
406
+ </el-table>
407
+ </DetailBlock>
408
+ <DetailBlock :title="t('docs.chat.notes')" style="margin-top: 16px;">
409
+ <ul class="notes-list">
410
+ <li v-for="(note, i) in specModule.streamConversion.notes" :key="i">{{ note }}</li>
411
+ </ul>
412
+ </DetailBlock>
413
+ </el-tab-pane>
414
+
415
+ <!-- 转换架构 -->
416
+ <el-tab-pane :label="specModule.architecture.title" name="architecture">
417
+ <DetailBlock :title="specModule.architecture.title" :description="specModule.architecture.description">
418
+ <div class="summary-flow">
419
+ <div v-for="(item, i) in specModule.architecture.flow" :key="i" class="summary-item">
420
+ <div class="summary-phase">
421
+ <span class="summary-num">{{ i + 1 }}</span>
422
+ <strong>{{ item.step }}</strong>
423
+ </div>
424
+ <p class="summary-detail">{{ item.detail }}</p>
425
+ </div>
426
+ </div>
427
+ </DetailBlock>
428
+ <DetailBlock :title="t('docs.spec.configExample')" style="margin-top: 16px;">
429
+ <CodeBlock :code="specModule.architecture.configExample" lang="json" filename="base.json" />
430
+ </DetailBlock>
431
+ </el-tab-pane>
432
+
433
+ <!-- 已知问题 -->
434
+ <el-tab-pane :label="specModule.knownIssues.title" name="issues">
435
+ <DetailBlock :title="specModule.knownIssues.title" :description="specModule.knownIssues.description">
436
+ <div v-for="(issue, i) in specModule.knownIssues.issues" :key="i" class="issue-item">
437
+ <div class="issue-header">
438
+ <el-tag
439
+ :type="issue.severity === 'high' ? 'danger' : issue.severity === 'medium' ? 'warning' : 'info'"
440
+ size="small"
441
+ >
442
+ {{ issue.severity }}
443
+ </el-tag>
444
+ <span class="issue-title">{{ issue.title }}</span>
445
+ </div>
446
+ <p class="issue-detail">{{ issue.detail }}</p>
447
+ <p class="issue-location">
448
+ <strong>{{ t('docs.spec.location') }}:</strong>
449
+ <code>{{ issue.location }}</code>
450
+ </p>
451
+ <div v-if="issue.fix" class="issue-fix">
452
+ <div class="tool-output-label">{{ t('docs.spec.suggestedFix') }}</div>
453
+ <CodeBlock :code="issue.fix" lang="javascript" filename="fix.js" />
454
+ </div>
455
+ </div>
456
+ </DetailBlock>
457
+ </el-tab-pane>
458
+
459
+ <!-- 协议桥接 -->
460
+ <el-tab-pane :label="t('docs.spec.toolBridge')" name="bridge">
461
+ <DetailBlock :title="specModule.toolBridge.title" :description="specModule.toolBridge.description">
462
+ <!-- 与 bluesllm 对比表 -->
463
+ <el-table :data="specModule.toolBridge.comparison.rows" border stripe style="margin-bottom: 16px;">
464
+ <el-table-column prop="aspect" :label="t('docs.spec.aspect')" width="120" fixed />
465
+ <el-table-column prop="bluesllm" label="bluesllm translator.js" min-width="200" />
466
+ <el-table-column prop="toolBridge" label="openai-tool-bridge" min-width="200" />
467
+ </el-table>
468
+ </DetailBlock>
469
+
470
+ <!-- 桥接流程 -->
471
+ <DetailBlock :title="t('docs.spec.bridgeFlow')" style="margin-top: 16px;">
472
+ <div class="summary-flow">
473
+ <div v-for="(item, i) in specModule.toolBridge.flow" :key="i" class="summary-item">
474
+ <div class="summary-phase">
475
+ <span class="summary-num">{{ i + 1 }}</span>
476
+ <strong>{{ item.phase }}</strong>
477
+ </div>
478
+ <p class="summary-detail">{{ item.detail }}</p>
479
+ </div>
480
+ </div>
481
+ </DetailBlock>
482
+
483
+ <!-- 请求桥接 -->
484
+ <DetailBlock :title="specModule.toolBridge.requestBridge.title" :description="specModule.toolBridge.requestBridge.description" style="margin-top: 16px;">
485
+ <div v-for="(s, i) in specModule.toolBridge.requestBridge.steps" :key="i" class="bridge-step">
486
+ <div class="bridge-step-header">
487
+ <span class="summary-num">{{ i + 1 }}</span>
488
+ <strong>{{ s.step }}</strong>
489
+ </div>
490
+ <p class="step-desc">{{ s.detail }}</p>
491
+ <CodeBlock v-if="s.code" :code="s.code" lang="javascript" :filename="`step-${i + 1}.js`" />
492
+ </div>
493
+ </DetailBlock>
494
+
495
+ <!-- 响应还原 -->
496
+ <DetailBlock :title="specModule.toolBridge.responseBridge.title" :description="specModule.toolBridge.responseBridge.description" style="margin-top: 16px;">
497
+ <div v-for="(s, i) in specModule.toolBridge.responseBridge.steps" :key="i" class="bridge-step">
498
+ <div class="bridge-step-header">
499
+ <span class="summary-num">{{ i + 1 }}</span>
500
+ <strong>{{ s.step }}</strong>
501
+ </div>
502
+ <p class="step-desc">{{ s.detail }}</p>
503
+ <CodeBlock v-if="s.code" :code="s.code" lang="json" :filename="`response-step-${i + 1}.json`" />
504
+ </div>
505
+ </DetailBlock>
506
+
507
+ <!-- 伪工具调用格式 -->
508
+ <DetailBlock :title="specModule.toolBridge.pseudoFormats.title" :description="specModule.toolBridge.pseudoFormats.description" style="margin-top: 16px;">
509
+ <el-table :data="specModule.toolBridge.pseudoFormats.formats" border stripe>
510
+ <el-table-column prop="name" :label="t('docs.spec.formatName')" width="180" />
511
+ <el-table-column prop="pattern" :label="t('docs.spec.pattern')" min-width="250">
512
+ <template #default="scope"><code class="param-name">{{ scope.row.pattern }}</code></template>
513
+ </el-table-column>
514
+ <el-table-column prop="note" :label="t('docs.spec.note')" />
515
+ </el-table>
516
+ </DetailBlock>
517
+
518
+ <!-- 流式桥接 -->
519
+ <DetailBlock :title="specModule.toolBridge.streaming.title" :description="specModule.toolBridge.streaming.description" style="margin-top: 16px;">
520
+ <ul class="notes-list">
521
+ <li v-for="(note, i) in specModule.toolBridge.streaming.notes" :key="i">{{ note }}</li>
522
+ </ul>
523
+ </DetailBlock>
524
+ </el-tab-pane>
525
+
526
+ <!-- OpenCode 网关 -->
527
+ <el-tab-pane :label="t('docs.spec.gateway')" name="gateway">
528
+ <DetailBlock :title="specModule.openCodeProxy.title" :description="specModule.openCodeProxy.description">
529
+ <p class="step-desc" style="margin-top: 8px;">{{ specModule.openCodeProxy.positioning }}</p>
530
+ </DetailBlock>
531
+
532
+ <!-- 三方对比 -->
533
+ <DetailBlock :title="specModule.openCodeProxy.threeWayComparison.title" style="margin-top: 16px;">
534
+ <el-table :data="specModule.openCodeProxy.threeWayComparison.rows" border stripe>
535
+ <el-table-column prop="aspect" :label="t('docs.spec.aspect')" width="100" fixed />
536
+ <el-table-column prop="bluesllm" label="bluesllm" min-width="180" />
537
+ <el-table-column prop="toolBridge" label="openai-tool-bridge" min-width="180" />
538
+ <el-table-column prop="openCodeProxy" label="opencode-llm-proxy" min-width="180" />
539
+ </el-table>
540
+ </DetailBlock>
541
+
542
+ <!-- 架构设计 -->
543
+ <DetailBlock :title="specModule.openCodeProxy.architecture.title" :description="specModule.openCodeProxy.architecture.description" style="margin-top: 16px;">
544
+ <el-table :data="specModule.openCodeProxy.architecture.endpoints" border stripe>
545
+ <el-table-column prop="method" :label="t('docs.spec.method')" width="80" />
546
+ <el-table-column prop="path" :label="t('docs.spec.path')" min-width="280">
547
+ <template #default="scope"><code class="param-name">{{ scope.row.path }}</code></template>
548
+ </el-table-column>
549
+ <el-table-column prop="format" :label="t('docs.spec.formatLabel')" />
550
+ </el-table>
551
+ </DetailBlock>
552
+
553
+ <!-- 工作原理 -->
554
+ <DetailBlock :title="specModule.openCodeProxy.howItWorks.title" :description="specModule.openCodeProxy.howItWorks.description" style="margin-top: 16px;">
555
+ <div class="summary-flow">
556
+ <div v-for="(item, i) in specModule.openCodeProxy.howItWorks.steps" :key="i" class="summary-item">
557
+ <div class="summary-phase">
558
+ <span class="summary-num">{{ i + 1 }}</span>
559
+ <strong>{{ item.step }}</strong>
560
+ </div>
561
+ <p class="summary-detail">{{ item.detail }}</p>
562
+ </div>
563
+ </div>
564
+ </DetailBlock>
565
+
566
+ <!-- MCP 桥接 -->
567
+ <DetailBlock :title="specModule.openCodeProxy.mcpBridge.title" :description="specModule.openCodeProxy.mcpBridge.description" style="margin-top: 16px;">
568
+ <div v-for="(item, i) in specModule.openCodeProxy.mcpBridge.trick" :key="i" class="bridge-step">
569
+ <div class="bridge-step-header">
570
+ <span class="summary-num">{{ i + 1 }}</span>
571
+ <strong>{{ item.step }}</strong>
572
+ </div>
573
+ <p class="step-desc">{{ item.detail }}</p>
574
+ </div>
575
+ <div style="margin-top: 16px;">
576
+ <CodeBlock :code="specModule.openCodeProxy.mcpBridge.mcpBridgeCode" lang="javascript" filename="mcp-tool-bridge.js" />
577
+ </div>
578
+ <div style="margin-top: 16px;">
579
+ <ul class="notes-list">
580
+ <li v-for="(note, i) in specModule.openCodeProxy.mcpBridge.notes" :key="i">{{ note }}</li>
581
+ </ul>
582
+ </div>
583
+ </DetailBlock>
584
+
585
+ <!-- 关键特性 -->
586
+ <DetailBlock :title="specModule.openCodeProxy.features.title" style="margin-top: 16px;">
587
+ <el-row :gutter="12">
588
+ <el-col v-for="(f, i) in specModule.openCodeProxy.features.items" :key="i" :xs="24" :sm="12">
589
+ <div class="feature-card">
590
+ <strong class="feature-name">{{ f.name }}</strong>
591
+ <p class="feature-desc">{{ f.description }}</p>
592
+ </div>
593
+ </el-col>
594
+ </el-row>
595
+ </DetailBlock>
596
+
597
+ <!-- 兼容客户端 -->
598
+ <DetailBlock :title="specModule.openCodeProxy.clients.title" :description="specModule.openCodeProxy.clients.description" style="margin-top: 16px;">
599
+ <el-table :data="specModule.openCodeProxy.clients.items" border stripe>
600
+ <el-table-column prop="name" :label="t('docs.spec.clientName')" width="220" />
601
+ <el-table-column prop="format" :label="t('docs.spec.formatLabel')" />
602
+ <el-table-column prop="toolCalling" :label="t('docs.spec.toolCalling')" width="120">
603
+ <template #default="scope">
604
+ <el-tag :type="scope.row.toolCalling === true ? 'success' : scope.row.toolCalling === 'partial' ? 'warning' : 'info'" size="small">
605
+ {{ scope.row.toolCalling === true ? t('docs.spec.yes') : scope.row.toolCalling === 'partial' ? t('docs.spec.partial') : t('docs.spec.notPrimary') }}
606
+ </el-tag>
607
+ </template>
608
+ </el-table-column>
609
+ </el-table>
610
+ </DetailBlock>
611
+ </el-tab-pane>
612
+
613
+ <!-- DeepSeek 逆向代理 -->
614
+ <el-tab-pane :label="t('docs.spec.dsProxy')" name="ds-proxy">
615
+ <DetailBlock :title="specModule.dsFreeApi.title" :description="specModule.dsFreeApi.description">
616
+ <p class="step-desc" style="margin-top: 8px;">{{ specModule.dsFreeApi.positioning }}</p>
617
+ </DetailBlock>
618
+
619
+ <!-- 四方对比 -->
620
+ <DetailBlock :title="specModule.dsFreeApi.fourWayComparison.title" style="margin-top: 16px;">
621
+ <el-table :data="specModule.dsFreeApi.fourWayComparison.rows" border stripe>
622
+ <el-table-column prop="aspect" :label="t('docs.spec.aspect')" width="100" fixed />
623
+ <el-table-column prop="bluesllm" label="bluesllm" min-width="160" />
624
+ <el-table-column prop="toolBridge" label="tool-bridge" min-width="160" />
625
+ <el-table-column prop="openCodeProxy" label="llm-proxy" min-width="160" />
626
+ <el-table-column prop="dsFreeApi" label="ds-free-api" min-width="160" />
627
+ </el-table>
628
+ </DetailBlock>
629
+
630
+ <!-- 登录认证 -->
631
+ <DetailBlock :title="specModule.dsFreeApi.auth.title" :description="specModule.dsFreeApi.auth.description" style="margin-top: 16px;">
632
+ <div v-for="(layer, li) in specModule.dsFreeApi.auth.layers" :key="li" class="bridge-step">
633
+ <div class="bridge-step-header">
634
+ <el-tag size="small" :type="li === 0 ? 'danger' : 'primary'">{{ layer.type }}</el-tag>
635
+ <strong>{{ layer.name }}</strong>
636
+ </div>
637
+ <div v-for="(s, si) in layer.steps" :key="si" class="summary-item" style="padding: 4px 0;">
638
+ <div class="summary-phase">
639
+ <span class="summary-num">{{ s.step.split('.')[0] }}</span>
640
+ <span>{{ s.step.replace(/^\d+\.\s*/, '') }}</span>
641
+ </div>
642
+ <p class="summary-detail">{{ s.detail }}</p>
643
+ </div>
644
+ </div>
645
+ <div style="margin-top: 16px;">
646
+ <CodeBlock :code="specModule.dsFreeApi.auth.powCode" lang="javascript" filename="pow-flow.js" />
647
+ </div>
648
+ <el-alert :title="specModule.dsFreeApi.auth.wafNote" type="warning" :closable="false" style="margin-top: 12px;" />
649
+ </DetailBlock>
650
+
651
+ <!-- 协议转换分析 -->
652
+ <DetailBlock :title="specModule.dsFreeApi.protocolConversion.title" :description="specModule.dsFreeApi.protocolConversion.description" style="margin-top: 16px;">
653
+ <div v-for="(item, i) in specModule.dsFreeApi.protocolConversion.analysis" :key="i" class="bridge-step">
654
+ <div class="bridge-step-header">
655
+ <span class="summary-num">{{ i + 1 }}</span>
656
+ <strong>{{ item.aspect }}</strong>
657
+ </div>
658
+ <p class="step-desc">{{ item.detail }}</p>
659
+ <p class="step-desc" style="color: var(--el-color-primary); margin-top: 4px;">
660
+ <strong>{{ t('docs.spec.comparison') }}:</strong>{{ item.comparison }}
661
+ </p>
662
+ </div>
663
+ </DetailBlock>
664
+
665
+ <!-- Tool Calling -->
666
+ <DetailBlock :title="specModule.dsFreeApi.toolCalling.title" :description="specModule.dsFreeApi.toolCalling.description" style="margin-top: 16px;">
667
+ <div v-for="(item, i) in specModule.dsFreeApi.toolCalling.mechanism" :key="i" class="summary-item">
668
+ <div class="summary-phase">
669
+ <span class="summary-num">{{ i + 1 }}</span>
670
+ <strong>{{ item.step.replace(/^\d+\.\s*/, '') }}</strong>
671
+ </div>
672
+ <p class="summary-detail">{{ item.detail }}</p>
673
+ </div>
674
+ <p class="step-desc" style="margin-top: 12px; color: var(--el-color-primary);">
675
+ {{ specModule.dsFreeApi.toolCalling.comparison }}
676
+ </p>
677
+ </DetailBlock>
678
+
679
+ <!-- 关键特性 -->
680
+ <DetailBlock :title="specModule.dsFreeApi.features.title" style="margin-top: 16px;">
681
+ <el-row :gutter="12">
682
+ <el-col v-for="(f, i) in specModule.dsFreeApi.features.items" :key="i" :xs="24" :sm="12">
683
+ <div class="feature-card">
684
+ <strong class="feature-name">{{ f.name }}</strong>
685
+ <p class="feature-desc">{{ f.description }}</p>
686
+ </div>
687
+ </el-col>
688
+ </el-row>
689
+ </DetailBlock>
690
+ </el-tab-pane>
691
+
692
+ <!-- llmproxy 认证代理 -->
693
+ <el-tab-pane :label="t('docs.spec.llmproxy')" name="llmproxy">
694
+ <DetailBlock :title="specModule.llmproxyCodearts.title" :description="specModule.llmproxyCodearts.description">
695
+ <p class="step-desc" style="margin-top: 8px;">{{ specModule.llmproxyCodearts.positioning }}</p>
696
+ </DetailBlock>
697
+
698
+ <!-- 五方对比 -->
699
+ <DetailBlock :title="specModule.llmproxyCodearts.fiveWayComparison.title" style="margin-top: 16px;">
700
+ <el-table :data="specModule.llmproxyCodearts.fiveWayComparison.rows" border stripe>
701
+ <el-table-column prop="aspect" :label="t('docs.spec.aspect')" width="100" fixed />
702
+ <el-table-column prop="bluesllm" label="bluesllm" min-width="140" />
703
+ <el-table-column prop="toolBridge" label="tool-bridge" min-width="140" />
704
+ <el-table-column prop="openCodeProxy" label="llm-proxy" min-width="140" />
705
+ <el-table-column prop="dsFreeApi" label="ds-free-api" min-width="140" />
706
+ <el-table-column prop="llmproxy" label="llmproxy" min-width="140" />
707
+ </el-table>
708
+ </DetailBlock>
709
+
710
+ <!-- 为什么不做协议转换 -->
711
+ <DetailBlock :title="specModule.llmproxyCodearts.noConversionAnalysis.title" :description="specModule.llmproxyCodearts.noConversionAnalysis.description" style="margin-top: 16px;">
712
+ <div class="summary-flow">
713
+ <div v-for="(item, i) in specModule.llmproxyCodearts.noConversionAnalysis.flow" :key="i" class="summary-item">
714
+ <div class="summary-phase">
715
+ <span class="summary-num">{{ i + 1 }}</span>
716
+ <strong>{{ item.phase.replace(/^\d+\.\s*/, '') }}</strong>
717
+ </div>
718
+ <p class="summary-detail">{{ item.detail }}</p>
719
+ </div>
720
+ </div>
721
+ <div style="margin-top: 16px;">
722
+ <CodeBlock :code="specModule.llmproxyCodearts.noConversionAnalysis.sseGuard" lang="javascript" filename="sse-guard.js" />
723
+ </div>
724
+ </DetailBlock>
725
+
726
+ <!-- Provider 插件架构 -->
727
+ <DetailBlock :title="specModule.llmproxyCodearts.providerArchitecture.title" :description="specModule.llmproxyCodearts.providerArchitecture.description" style="margin-top: 16px;">
728
+ <CodeBlock :code="specModule.llmproxyCodearts.providerArchitecture.structure" lang="bash" filename="providers-structure.txt" />
729
+ <ul class="notes-list" style="margin-top: 12px;">
730
+ <li v-for="(note, i) in specModule.llmproxyCodearts.providerArchitecture.notes" :key="i">{{ note }}</li>
731
+ </ul>
732
+ </DetailBlock>
733
+ </el-tab-pane>
734
+
735
+ <!-- CodeArts 接口转换 -->
736
+ <el-tab-pane :label="t('docs.spec.codeartsConv')" name="codearts-conv">
737
+ <DetailBlock :title="specModule.codeartsConversion.title" :description="specModule.codeartsConversion.description">
738
+ </DetailBlock>
739
+
740
+ <!-- 上游接口规格 -->
741
+ <DetailBlock :title="specModule.codeartsConversion.upstreamSpec.title" :description="specModule.codeartsConversion.upstreamSpec.description" style="margin-top: 16px;">
742
+ <el-table :data="specModule.codeartsConversion.upstreamSpec.endpoints" border stripe style="margin-bottom: 16px;">
743
+ <el-table-column prop="name" :label="t('docs.spec.endpointName')" width="180" />
744
+ <el-table-column prop="url" :label="t('docs.spec.path')" min-width="300">
745
+ <template #default="scope"><code class="param-name">{{ scope.row.url }}</code></template>
746
+ </el-table-column>
747
+ <el-table-column prop="auth" :label="t('docs.auth.tabLabel')" />
748
+ <el-table-column prop="used" :label="t('docs.spec.used')" />
749
+ </el-table>
750
+ <p class="step-desc"><strong>{{ t('docs.spec.formatLabel') }}:</strong>{{ specModule.codeartsConversion.upstreamSpec.format }}</p>
751
+ <el-table :data="specModule.codeartsConversion.upstreamSpec.models" border stripe style="margin: 8px 0;">
752
+ <el-table-column prop="id" :label="t('docs.spec.modelId')" />
753
+ <el-table-column prop="display" :label="t('docs.spec.modelDisplay')" />
754
+ <el-table-column prop="context" :label="t('docs.spec.context')" width="100" />
755
+ </el-table>
756
+ <div class="tool-output-label">{{ t('docs.spec.requestHeaders') }}</div>
757
+ <CodeBlock :code="specModule.codeartsConversion.upstreamSpec.requestHeaders" lang="json" filename="request-headers.json" />
758
+ <div class="tool-output-label" style="margin-top: 12px;">{{ t('docs.spec.requestBody') }}</div>
759
+ <CodeBlock :code="specModule.codeartsConversion.upstreamSpec.requestBody" lang="json" filename="body-inject.json" />
760
+ </DetailBlock>
761
+
762
+ <!-- 转换流程 -->
763
+ <DetailBlock :title="specModule.codeartsConversion.conversionFlow.title" :description="specModule.codeartsConversion.conversionFlow.description" style="margin-top: 16px;">
764
+ <div class="summary-flow">
765
+ <div v-for="(item, i) in specModule.codeartsConversion.conversionFlow.steps" :key="i" class="summary-item">
766
+ <div class="summary-phase">
767
+ <span class="summary-num">{{ i + 1 }}</span>
768
+ <strong>{{ item.phase.replace(/^\d+\.\s*/, '') }}</strong>
769
+ </div>
770
+ <p class="summary-detail">{{ item.detail }}</p>
771
+ </div>
772
+ </div>
773
+ <div style="margin-top: 16px;">
774
+ <CodeBlock :code="specModule.codeartsConversion.conversionFlow.configExample" lang="json" filename="base.json" />
775
+ </div>
776
+ </DetailBlock>
777
+
778
+ <!-- 转换对 -->
779
+ <DetailBlock :title="specModule.codeartsConversion.conversionPairs.title" :description="specModule.codeartsConversion.conversionPairs.description" style="margin-top: 16px;">
780
+ <el-table :data="specModule.codeartsConversion.conversionPairs.pairs" border stripe>
781
+ <el-table-column prop="from" :label="t('docs.spec.from')" width="140" />
782
+ <el-table-column prop="to" :label="t('docs.spec.to')" width="140" />
783
+ <el-table-column prop="function" :label="t('docs.spec.function')" min-width="220">
784
+ <template #default="scope"><code class="param-name">{{ scope.row.function }}</code></template>
785
+ </el-table-column>
786
+ <el-table-column prop="note" :label="t('docs.spec.note')" />
787
+ </el-table>
788
+ </DetailBlock>
789
+
790
+ <!-- 关键字段映射 -->
791
+ <DetailBlock :title="specModule.codeartsConversion.keyMappings.title" :description="specModule.codeartsConversion.keyMappings.description" style="margin-top: 16px;">
792
+ <div class="tool-output-label">{{ t('docs.spec.requestMappings') }}</div>
793
+ <el-table :data="specModule.codeartsConversion.keyMappings.requestMappings" border stripe style="margin-bottom: 16px;">
794
+ <el-table-column prop="claudeField" label="Claude 字段" min-width="200" />
795
+ <el-table-column prop="openaiField" label="OpenAI 字段" min-width="200" />
796
+ <el-table-column prop="note" :label="t('docs.spec.note')" />
797
+ </el-table>
798
+ <div class="tool-output-label">{{ t('docs.spec.responseMappings') }}</div>
799
+ <el-table :data="specModule.codeartsConversion.keyMappings.responseMappings" border stripe>
800
+ <el-table-column prop="openaiField" label="OpenAI 字段" min-width="220" />
801
+ <el-table-column prop="claudeField" label="Claude 字段" min-width="220" />
802
+ <el-table-column prop="note" :label="t('docs.spec.note')" />
803
+ </el-table>
804
+ </DetailBlock>
805
+
806
+ <!-- 流式转换 -->
807
+ <DetailBlock :title="specModule.codeartsConversion.streamConversion.title" :description="specModule.codeartsConversion.streamConversion.description" style="margin-top: 16px;">
808
+ <div class="summary-flow">
809
+ <div v-for="(item, i) in specModule.codeartsConversion.streamConversion.flow" :key="i" class="summary-item">
810
+ <div class="summary-phase">
811
+ <span class="summary-num">{{ i + 1 }}</span>
812
+ <strong>{{ item.phase }}</strong>
813
+ </div>
814
+ <p class="summary-detail">{{ item.detail }}</p>
815
+ </div>
816
+ </div>
817
+ </DetailBlock>
818
+
819
+ <!-- bluesllm vs llmproxy -->
820
+ <DetailBlock :title="specModule.codeartsConversion.vsLlmproxy.title" :description="specModule.codeartsConversion.vsLlmproxy.description" style="margin-top: 16px;">
821
+ <el-table :data="specModule.codeartsConversion.vsLlmproxy.table" border stripe>
822
+ <el-table-column prop="aspect" :label="t('docs.spec.aspect')" width="120" fixed />
823
+ <el-table-column prop="bluesllm" label="bluesllm" min-width="220" />
824
+ <el-table-column prop="llmproxy" label="llmproxy" min-width="220" />
825
+ </el-table>
826
+ </DetailBlock>
827
+ </el-tab-pane>
828
+ </el-tabs>
829
+ </div>
830
+ </el-tab-pane>
831
+
832
+ <!-- 登录认证模块 -->
833
+ <el-tab-pane :label="t('docs.auth.tabLabel')" name="auth">
834
+ <div v-if="activeModule === 'auth'" class="auth-section">
835
+ <div class="module-intro">
836
+ <h2>{{ authModule.name }}</h2>
837
+ <el-tag type="danger">{{ authModule.badge }}</el-tag>
838
+ <p class="module-tagline">{{ authModule.tagline }}</p>
839
+ <p class="module-desc">{{ authModule.description }}</p>
840
+ </div>
841
+
842
+ <el-tabs v-model="activeAuthTab" class="sub-tabs">
843
+ <!-- DeepSeek 网页端认证 -->
844
+ <el-tab-pane
845
+ v-for="sub in authModule.subModules"
846
+ :key="sub.id"
847
+ :label="sub.name"
848
+ :name="sub.id"
849
+ >
850
+ <div class="sub-module-intro">
851
+ <h3>{{ sub.name }}</h3>
852
+ <el-tag>{{ sub.badge }}</el-tag>
853
+ <p class="module-tagline">{{ sub.tagline }}</p>
854
+ <p class="module-desc">{{ sub.description }}</p>
855
+ </div>
856
+
857
+ <!-- 认证架构 -->
858
+ <DetailBlock v-if="sub.architecture" :title="sub.architecture.title" :description="sub.architecture.description" style="margin-top: 16px;">
859
+ <el-table :data="sub.architecture.layers" border stripe style="margin-bottom: 16px;">
860
+ <el-table-column prop="name" :label="t('docs.auth.layer')" width="160" />
861
+ <el-table-column prop="file" :label="t('docs.auth.file')" width="220">
862
+ <template #default="scope"><code class="param-name">{{ scope.row.file }}</code></template>
863
+ </el-table-column>
864
+ <el-table-column prop="role" :label="t('docs.auth.role')" />
865
+ </el-table>
866
+ <CodeBlock :code="sub.architecture.codeStructure" lang="bash" filename="ds_core-structure.txt" />
867
+ </DetailBlock>
868
+
869
+ <!-- 账号池初始化(DeepSeek) -->
870
+ <DetailBlock v-if="sub.poolInit" :title="sub.poolInit.title" :description="sub.poolInit.description" style="margin-top: 16px;">
871
+ <div class="summary-flow">
872
+ <div v-for="(item, i) in sub.poolInit.steps" :key="i" class="summary-item">
873
+ <div class="summary-phase">
874
+ <span class="summary-num">{{ i + 1 }}</span>
875
+ <strong>{{ item.step }}</strong>
876
+ </div>
877
+ <p class="summary-detail">{{ item.detail }}</p>
878
+ </div>
879
+ </div>
880
+ <el-alert :title="sub.poolInit.retry" type="warning" :closable="false" style="margin-top: 12px;" />
881
+ <p class="step-desc" style="margin-top: 8px;">{{ sub.poolInit.concurrency }}</p>
882
+ </DetailBlock>
883
+
884
+ <!-- PoW 挑战求解(DeepSeek) -->
885
+ <DetailBlock v-if="sub.pow" :title="sub.pow.title" :description="sub.pow.description" style="margin-top: 16px;">
886
+ <div class="summary-flow">
887
+ <div v-for="(item, i) in sub.pow.mechanism" :key="i" class="summary-item">
888
+ <div class="summary-phase">
889
+ <span class="summary-num">{{ i + 1 }}</span>
890
+ <strong>{{ item.step.replace(/^\d+\.\s*/, '') }}</strong>
891
+ </div>
892
+ <p class="summary-detail">{{ item.detail }}</p>
893
+ </div>
894
+ </div>
895
+ <div style="margin-top: 16px;">
896
+ <CodeBlock :code="sub.pow.codeExample" lang="javascript" filename="pow-solver.rs" />
897
+ </div>
898
+ <ul class="notes-list" style="margin-top: 12px;">
899
+ <li v-for="(note, i) in sub.pow.notes" :key="i">{{ note }}</li>
900
+ </ul>
901
+ </DetailBlock>
902
+
903
+ <!-- WAF 绕过(DeepSeek) -->
904
+ <DetailBlock v-if="sub.waf" :title="sub.waf.title" :description="sub.waf.description" style="margin-top: 16px;">
905
+ <div class="summary-flow">
906
+ <div v-for="(item, i) in sub.waf.mechanism" :key="i" class="summary-item">
907
+ <div class="summary-phase">
908
+ <span class="summary-num">{{ i + 1 }}</span>
909
+ <strong>{{ item.step.replace(/^\d+\.\s*/, '') }}</strong>
910
+ </div>
911
+ <p class="summary-detail">{{ item.detail }}</p>
912
+ </div>
913
+ </div>
914
+ <div style="margin-top: 12px;">
915
+ <CodeBlock :code="sub.waf.configExample" lang="toml" filename="config.toml" />
916
+ </div>
917
+ <ul class="notes-list" style="margin-top: 12px;">
918
+ <li v-for="(note, i) in sub.waf.notes" :key="i">{{ note }}</li>
919
+ </ul>
920
+ </DetailBlock>
921
+
922
+ <!-- Session 管理(DeepSeek) -->
923
+ <DetailBlock v-if="sub.session" :title="sub.session.title" :description="sub.session.description" style="margin-top: 16px;">
924
+ <div class="summary-flow">
925
+ <div v-for="(item, i) in sub.session.lifecycle" :key="i" class="summary-item">
926
+ <div class="summary-phase">
927
+ <span class="summary-num">{{ i + 1 }}</span>
928
+ <strong>{{ item.phase.replace(/^\d+\.\s*/, '') }}</strong>
929
+ </div>
930
+ <p class="summary-detail">{{ item.detail }}</p>
931
+ </div>
932
+ </div>
933
+ <div style="margin-top: 16px;">
934
+ <CodeBlock :code="sub.session.accountGuard" lang="javascript" filename="account-guard.rs" />
935
+ </div>
936
+ <ul class="notes-list" style="margin-top: 12px;">
937
+ <li v-for="(note, i) in sub.session.notes" :key="i">{{ note }}</li>
938
+ </ul>
939
+ </DetailBlock>
940
+
941
+ <!-- 客户端认证(DeepSeek) -->
942
+ <DetailBlock v-if="sub.clientAuth" :title="sub.clientAuth.title" :description="sub.clientAuth.description" style="margin-top: 16px;">
943
+ <div v-for="(layer, li) in sub.clientAuth.layers" :key="li" class="bridge-step">
944
+ <div class="bridge-step-header">
945
+ <el-tag size="small" :type="li === 0 ? 'primary' : 'success'">{{ layer.name }}</el-tag>
946
+ </div>
947
+ <div v-for="(s, si) in layer.steps" :key="si" class="summary-item" style="padding: 4px 0;">
948
+ <div class="summary-phase">
949
+ <span class="summary-num">{{ s.step.split('.')[0] }}</span>
950
+ <span>{{ s.step.replace(/^\d+\.\s*/, '') }}</span>
951
+ </div>
952
+ <p class="summary-detail">{{ s.detail }}</p>
953
+ </div>
954
+ </div>
955
+ <ul class="notes-list" style="margin-top: 12px;">
956
+ <li v-for="(note, i) in sub.clientAuth.securityNotes" :key="i">{{ note }}</li>
957
+ </ul>
958
+ </DetailBlock>
959
+
960
+ <!-- 对比表(通用:根据列名动态渲染) -->
961
+ <DetailBlock v-if="sub.comparison" :title="sub.comparison.title" :description="sub.comparison.description" style="margin-top: 16px;">
962
+ <el-table :data="sub.comparison.table" border stripe>
963
+ <el-table-column prop="aspect" :label="t('docs.spec.aspect')" width="120" fixed />
964
+ <el-table-column v-if="sub.comparison.table[0]?.standard" prop="standard" :label="t('docs.auth.standardApi')" min-width="200" />
965
+ <el-table-column v-if="sub.comparison.table[0]?.deepseek" prop="deepseek" :label="t('docs.auth.deepseekWeb')" min-width="250" />
966
+ <el-table-column v-if="sub.comparison.table[0]?.codearts" prop="codearts" label="CodeArts OAuth" min-width="250" />
967
+ </el-table>
968
+ </DetailBlock>
969
+
970
+ <!-- OAuth 认证流程(CodeArts) -->
971
+ <DetailBlock v-if="sub.oauthFlow" :title="sub.oauthFlow.title" :description="sub.oauthFlow.description" style="margin-top: 16px;">
972
+ <div class="summary-flow">
973
+ <div v-for="(item, i) in sub.oauthFlow.steps" :key="i" class="summary-item">
974
+ <div class="summary-phase">
975
+ <span class="summary-num">{{ i + 1 }}</span>
976
+ <strong>{{ item.step.replace(/^\d+\.\s*/, '') }}</strong>
977
+ </div>
978
+ <p class="summary-detail">{{ item.detail }}</p>
979
+ </div>
980
+ </div>
981
+ <div style="margin-top: 16px;">
982
+ <CodeBlock :code="sub.oauthFlow.codeExample" lang="javascript" filename="oauth-flow.js" />
983
+ </div>
984
+ <ul class="notes-list" style="margin-top: 12px;">
985
+ <li v-for="(note, i) in sub.oauthFlow.notes" :key="i">{{ note }}</li>
986
+ </ul>
987
+ </DetailBlock>
988
+
989
+ <!-- SDK 签名(CodeArts) -->
990
+ <DetailBlock v-if="sub.sdkSign" :title="sub.sdkSign.title" :description="sub.sdkSign.description" style="margin-top: 16px;">
991
+ <div class="summary-flow">
992
+ <div v-for="(item, i) in sub.sdkSign.mechanism" :key="i" class="summary-item">
993
+ <div class="summary-phase">
994
+ <span class="summary-num">{{ i + 1 }}</span>
995
+ <strong>{{ item.step.replace(/^\d+\.\s*/, '') }}</strong>
996
+ </div>
997
+ <p class="summary-detail">{{ item.detail }}</p>
998
+ </div>
999
+ </div>
1000
+ <div style="margin-top: 16px;">
1001
+ <CodeBlock :code="sub.sdkSign.codeExample" lang="javascript" filename="sdk-sign.js" />
1002
+ </div>
1003
+ <ul class="notes-list" style="margin-top: 12px;">
1004
+ <li v-for="(note, i) in sub.sdkSign.notes" :key="i">{{ note }}</li>
1005
+ </ul>
1006
+ </DetailBlock>
1007
+
1008
+ <!-- 请求发送流程(CodeArts) -->
1009
+ <DetailBlock v-if="sub.requestFlow" :title="sub.requestFlow.title" :description="sub.requestFlow.description" style="margin-top: 16px;">
1010
+ <div class="summary-flow">
1011
+ <div v-for="(item, i) in sub.requestFlow.steps" :key="i" class="summary-item">
1012
+ <div class="summary-phase">
1013
+ <span class="summary-num">{{ i + 1 }}</span>
1014
+ <strong>{{ item.step.replace(/^\d+\.\s*/, '') }}</strong>
1015
+ </div>
1016
+ <p class="summary-detail">{{ item.detail }}</p>
1017
+ </div>
1018
+ </div>
1019
+ </DetailBlock>
1020
+ </el-tab-pane>
1021
+ </el-tabs>
1022
+ </div>
1023
+ </el-tab-pane>
1024
+
1025
+ <!-- Skills 模块 -->
1026
+ <el-tab-pane :label="t('docs.skills.tabLabel')" name="skills">
1027
+ <div v-if="activeModule === 'skills'" class="skills-section">
1028
+ <div class="module-intro">
1029
+ <h2>{{ skillsModule.name }}</h2>
1030
+ <el-tag type="success">{{ skillsModule.badge }}</el-tag>
1031
+ <p class="module-tagline">{{ skillsModule.tagline }}</p>
1032
+ <p class="module-desc">{{ skillsModule.description }}</p>
1033
+ </div>
1034
+
1035
+ <el-tabs v-model="activeSkillsTab" class="sub-tabs">
1036
+ <el-tab-pane
1037
+ v-for="sub in skillsModule.subModules"
1038
+ :key="sub.id"
1039
+ :label="sub.name"
1040
+ :name="sub.id"
1041
+ >
1042
+ <div class="sub-module-intro">
1043
+ <h3>{{ sub.name }}</h3>
1044
+ <el-tag>{{ sub.badge }}</el-tag>
1045
+ <p class="module-tagline">{{ sub.tagline }}</p>
1046
+ <p class="module-desc">{{ sub.description }}</p>
1047
+ </div>
1048
+
1049
+ <!-- 核心机制 -->
1050
+ <DetailBlock v-if="sub.coreMechanism" :title="sub.coreMechanism.title" :description="sub.coreMechanism.description" style="margin-top: 16px;">
1051
+ <div class="summary-flow">
1052
+ <div v-for="(item, i) in sub.coreMechanism.flow" :key="i" class="summary-item">
1053
+ <div class="summary-phase">
1054
+ <span class="summary-num">{{ i + 1 }}</span>
1055
+ <strong>{{ item.phase.replace(/^\d+\.\s*/, '') }}</strong>
1056
+ </div>
1057
+ <p class="summary-detail">{{ item.detail }}</p>
1058
+ </div>
1059
+ </div>
1060
+ <div style="margin-top: 16px;">
1061
+ <CodeBlock :code="sub.coreMechanism.hookCode" lang="javascript" filename="session-start-hook.js" />
1062
+ </div>
1063
+ <ul class="notes-list" style="margin-top: 12px;">
1064
+ <li v-for="(note, i) in sub.coreMechanism.notes" :key="i">{{ note }}</li>
1065
+ </ul>
1066
+ </DetailBlock>
1067
+
1068
+ <!-- 技能库 -->
1069
+ <DetailBlock v-if="sub.skillLibrary" :title="sub.skillLibrary.title" :description="sub.skillLibrary.description" style="margin-top: 16px;">
1070
+ <div v-for="(cat, ci) in sub.skillLibrary.categories" :key="ci" style="margin-bottom: 16px;">
1071
+ <h4 class="category-title">{{ cat.name }}</h4>
1072
+ <div v-for="(skill, si) in cat.skills" :key="si" class="bridge-step">
1073
+ <div class="bridge-step-header">
1074
+ <code class="param-name">{{ skill.name }}</code>
1075
+ </div>
1076
+ <p class="step-desc">{{ skill.desc }}</p>
1077
+ </div>
1078
+ </div>
1079
+ </DetailBlock>
1080
+
1081
+ <!-- 基本工作流 -->
1082
+ <DetailBlock v-if="sub.workflow" :title="sub.workflow.title" :description="sub.workflow.description" style="margin-top: 16px;">
1083
+ <div class="summary-flow">
1084
+ <div v-for="(item, i) in sub.workflow.stages" :key="i" class="summary-item">
1085
+ <div class="summary-phase">
1086
+ <span class="summary-num">{{ i + 1 }}</span>
1087
+ <strong>{{ item.step.replace(/^\d+\.\s*/, '') }}</strong>
1088
+ </div>
1089
+ <p class="summary-detail">{{ item.detail }}</p>
1090
+ </div>
1091
+ </div>
1092
+ </DetailBlock>
1093
+
1094
+ <!-- 铁律 -->
1095
+ <DetailBlock v-if="sub.ironRule" :title="sub.ironRule.title" :description="sub.ironRule.description" style="margin-top: 16px;">
1096
+ <el-alert :title="sub.ironRule.rule" type="error" :closable="false" style="margin-bottom: 16px;" />
1097
+ <el-table :data="sub.ironRule.redFlags" border stripe>
1098
+ <el-table-column prop="thought" :label="t('docs.skills.thought')" min-width="250" />
1099
+ <el-table-column prop="reality" :label="t('docs.skills.reality')" min-width="200" />
1100
+ </el-table>
1101
+ <p class="step-desc" style="margin-top: 12px;"><strong>{{ t('docs.skills.priority') }}:</strong>{{ sub.ironRule.priority }}</p>
1102
+ </DetailBlock>
1103
+
1104
+ <!-- subagent 核心设计 -->
1105
+ <DetailBlock v-if="sub.subagentDesign" :title="sub.subagentDesign.title" :description="sub.subagentDesign.description" style="margin-top: 16px;">
1106
+ <div v-for="(p, i) in sub.subagentDesign.principles" :key="i" class="bridge-step">
1107
+ <div class="bridge-step-header">
1108
+ <span class="summary-num">{{ i + 1 }}</span>
1109
+ <strong>{{ p.name }}</strong>
1110
+ </div>
1111
+ <p class="step-desc">{{ p.detail }}</p>
1112
+ </div>
1113
+ <el-alert :title="sub.subagentDesign.stopConditions" type="warning" :closable="false" style="margin-top: 12px;" />
1114
+ </DetailBlock>
1115
+
1116
+ <!-- writing-skills TDD -->
1117
+ <DetailBlock v-if="sub.writingSkills" :title="sub.writingSkills.title" :description="sub.writingSkills.description" style="margin-top: 16px;">
1118
+ <el-table :data="sub.writingSkills.tddMapping" border stripe>
1119
+ <el-table-column prop="tdd" :label="t('docs.skills.tdd')" width="180" />
1120
+ <el-table-column prop="skillCreation" :label="t('docs.skills.skillCreation')" />
1121
+ </el-table>
1122
+ </DetailBlock>
1123
+
1124
+ <!-- 多平台支持 -->
1125
+ <DetailBlock v-if="sub.platforms" :title="sub.platforms.title" :description="sub.platforms.description" style="margin-top: 16px;">
1126
+ <el-table :data="sub.platforms.items" border stripe>
1127
+ <el-table-column prop="name" :label="t('docs.skills.platform')" width="180" />
1128
+ <el-table-column prop="install" :label="t('docs.skills.install')" min-width="250" />
1129
+ <el-table-column prop="hook" :label="t('docs.skills.hookFormat')" />
1130
+ </el-table>
1131
+ </DetailBlock>
1132
+
1133
+ <!-- 哲学 -->
1134
+ <DetailBlock v-if="sub.philosophy" :title="sub.philosophy.title" style="margin-top: 16px;">
1135
+ <el-row :gutter="12">
1136
+ <el-col v-for="(p, i) in sub.philosophy.principles" :key="i" :xs="24" :sm="12">
1137
+ <div class="feature-card">
1138
+ <strong class="feature-name">{{ p.name }}</strong>
1139
+ <p class="feature-desc">{{ p.desc }}</p>
1140
+ </div>
1141
+ </el-col>
1142
+ </el-row>
1143
+ </DetailBlock>
1144
+
1145
+ <!-- Subagent: 六维度对比表 -->
1146
+ <DetailBlock v-if="sub.comparison" :title="sub.comparison.title" style="margin-top: 16px;">
1147
+ <el-table :data="sub.comparison.rows" border stripe>
1148
+ <el-table-column prop="dimension" :label="t('docs.skills.dimension')" width="140" fixed />
1149
+ <el-table-column prop="superpowers" label="Superpowers" min-width="200" />
1150
+ <el-table-column prop="claude" label="Claude Code" min-width="200" />
1151
+ <el-table-column prop="opencode" label="opencode" min-width="200" />
1152
+ <el-table-column prop="codex" label="Codex CLI" min-width="200" />
1153
+ </el-table>
1154
+ </DetailBlock>
1155
+
1156
+ <!-- Subagent: Superpowers 示例详解 -->
1157
+ <DetailBlock v-if="sub.superpowersExample" :title="sub.superpowersExample.title" :description="sub.superpowersExample.description" style="margin-top: 16px;">
1158
+ <div class="tool-output-label">{{ t('docs.skills.promptTemplate') }}</div>
1159
+ <CodeBlock :code="sub.superpowersExample.promptTemplate" lang="text" filename="implementer-prompt.md" />
1160
+ <div class="tool-output-label" style="margin-top: 12px;">{{ t('docs.skills.outputContract') }}</div>
1161
+ <CodeBlock :code="sub.superpowersExample.outputContract" lang="text" filename="output-contract.txt" />
1162
+ <div class="tool-output-label" style="margin-top: 12px;">{{ t('docs.skills.fileMechanism') }}</div>
1163
+ <CodeBlock :code="sub.superpowersExample.fileMechanism" lang="bash" filename="workspace-structure.txt" />
1164
+ <div class="tool-output-label" style="margin-top: 12px;">{{ t('docs.skills.lifecycle') }}</div>
1165
+ <CodeBlock :code="sub.superpowersExample.lifecycle" lang="text" filename="lifecycle.txt" />
1166
+ </DetailBlock>
1167
+
1168
+ <!-- Subagent: 关键差异要点 -->
1169
+ <DetailBlock v-if="sub.keyDifferences" :title="sub.keyDifferences.title" style="margin-top: 16px;">
1170
+ <div v-for="(item, i) in sub.keyDifferences.items" :key="i" class="bridge-step">
1171
+ <div class="bridge-step-header">
1172
+ <el-tag size="small">{{ item.tool }}</el-tag>
1173
+ </div>
1174
+ <p class="step-desc">{{ item.point }}</p>
1175
+ </div>
1176
+ </DetailBlock>
1177
+
1178
+ <!-- Subagent: 最佳实践 -->
1179
+ <DetailBlock v-if="sub.bestPractices" :title="sub.bestPractices.title" style="margin-top: 16px;">
1180
+ <div v-for="(item, i) in sub.bestPractices.items" :key="i" class="bridge-step">
1181
+ <div class="bridge-step-header">
1182
+ <span class="summary-num">{{ i + 1 }}</span>
1183
+ <strong>{{ item.practice }}</strong>
1184
+ </div>
1185
+ <p class="step-desc">{{ item.detail }}</p>
1186
+ </div>
1187
+ </DetailBlock>
1188
+ </el-tab-pane>
1189
+ </el-tabs>
1190
+ </div>
1191
+ </el-tab-pane>
1192
+ </el-tabs>
1193
+ </div>
1194
+ </template>
1195
+
1196
+ <style scoped>
1197
+ .module-tabs {
1198
+ margin-bottom: 24px;
1199
+ }
1200
+ .module-intro {
1201
+ margin-bottom: 24px;
1202
+ }
1203
+ .module-intro h2 {
1204
+ display: inline;
1205
+ margin: 0 12px 0 0;
1206
+ font-size: 22px;
1207
+ font-weight: 600;
1208
+ }
1209
+ .module-tagline {
1210
+ margin: 8px 0 4px;
1211
+ font-size: 14px;
1212
+ color: var(--el-text-color-secondary);
1213
+ }
1214
+ .module-desc {
1215
+ margin: 0;
1216
+ font-size: 14px;
1217
+ line-height: 1.8;
1218
+ color: var(--el-text-color-primary);
1219
+ }
1220
+ .sub-tabs {
1221
+ margin-bottom: 24px;
1222
+ }
1223
+ .notes-list {
1224
+ margin: 0;
1225
+ padding-left: 20px;
1226
+ }
1227
+ .notes-list li {
1228
+ margin: 4px 0;
1229
+ font-size: 13px;
1230
+ line-height: 1.6;
1231
+ color: var(--el-text-color-regular);
1232
+ }
1233
+ .param-name {
1234
+ font-family: ui-monospace, Consolas, monospace;
1235
+ font-size: 13px;
1236
+ color: var(--el-color-primary);
1237
+ }
1238
+
1239
+ /* ── Agent Timeline ── */
1240
+ .example-header {
1241
+ margin-bottom: 24px;
1242
+ }
1243
+ .example-scenario {
1244
+ margin: 0 0 4px;
1245
+ font-size: 14px;
1246
+ }
1247
+ .example-desc {
1248
+ margin: 0;
1249
+ font-size: 13px;
1250
+ color: var(--el-text-color-secondary);
1251
+ line-height: 1.6;
1252
+ }
1253
+ .flow-timeline {
1254
+ display: flex;
1255
+ flex-direction: column;
1256
+ }
1257
+ .flow-step {
1258
+ display: flex;
1259
+ gap: 16px;
1260
+ margin-bottom: 8px;
1261
+ }
1262
+ .step-marker {
1263
+ display: flex;
1264
+ flex-direction: column;
1265
+ align-items: center;
1266
+ flex-shrink: 0;
1267
+ }
1268
+ .step-icon {
1269
+ font-size: 20px;
1270
+ line-height: 1;
1271
+ }
1272
+ .step-number {
1273
+ width: 20px;
1274
+ height: 20px;
1275
+ border-radius: 50%;
1276
+ background: var(--el-color-primary);
1277
+ color: #fff;
1278
+ font-size: 11px;
1279
+ font-weight: 600;
1280
+ display: flex;
1281
+ align-items: center;
1282
+ justify-content: center;
1283
+ margin-top: 4px;
1284
+ }
1285
+ .step-line {
1286
+ flex: 1;
1287
+ width: 2px;
1288
+ background: var(--el-border-color);
1289
+ margin-top: 4px;
1290
+ min-height: 20px;
1291
+ }
1292
+ .step-body {
1293
+ flex: 1;
1294
+ min-width: 0;
1295
+ padding-bottom: 20px;
1296
+ }
1297
+ .step-header {
1298
+ display: flex;
1299
+ align-items: center;
1300
+ gap: 8px;
1301
+ margin-bottom: 8px;
1302
+ }
1303
+ .step-title {
1304
+ font-size: 14px;
1305
+ font-weight: 600;
1306
+ color: var(--el-text-color-primary);
1307
+ }
1308
+ .step-desc {
1309
+ margin: 0 0 8px;
1310
+ font-size: 13px;
1311
+ color: var(--el-text-color-secondary);
1312
+ line-height: 1.6;
1313
+ }
1314
+ .user-bubble {
1315
+ display: inline-block;
1316
+ padding: 8px 16px;
1317
+ background: var(--el-color-primary-light-9);
1318
+ color: var(--el-color-primary);
1319
+ border-radius: 8px;
1320
+ font-size: 14px;
1321
+ margin-bottom: 8px;
1322
+ }
1323
+
1324
+ /* ── Tool Execution ── */
1325
+ .tool-exec {
1326
+ margin-top: 8px;
1327
+ }
1328
+ .accumulate-section {
1329
+ margin-bottom: 12px;
1330
+ }
1331
+ .tool-exec-label {
1332
+ display: flex;
1333
+ align-items: center;
1334
+ gap: 8px;
1335
+ margin-bottom: 8px;
1336
+ font-size: 13px;
1337
+ color: var(--el-text-color-secondary);
1338
+ }
1339
+ .tool-exec-arrow {
1340
+ color: var(--el-text-color-placeholder);
1341
+ }
1342
+ .tool-output-label {
1343
+ margin-top: 12px;
1344
+ margin-bottom: 4px;
1345
+ font-size: 12px;
1346
+ font-weight: 600;
1347
+ color: var(--el-text-color-secondary);
1348
+ }
1349
+
1350
+ /* ── Parallel Tools ── */
1351
+ .parallel-exec {
1352
+ margin-top: 8px;
1353
+ }
1354
+ .parallel-grid {
1355
+ display: grid;
1356
+ grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
1357
+ gap: 16px;
1358
+ }
1359
+ .parallel-card {
1360
+ display: flex;
1361
+ flex-direction: column;
1362
+ }
1363
+ .parallel-card-header {
1364
+ margin-bottom: 8px;
1365
+ }
1366
+
1367
+ /* ── Summary ── */
1368
+ .summary-flow {
1369
+ display: flex;
1370
+ flex-direction: column;
1371
+ gap: 12px;
1372
+ }
1373
+ .summary-item {
1374
+ display: flex;
1375
+ align-items: flex-start;
1376
+ gap: 12px;
1377
+ }
1378
+ .summary-phase {
1379
+ display: flex;
1380
+ align-items: center;
1381
+ gap: 8px;
1382
+ flex-shrink: 0;
1383
+ min-width: 160px;
1384
+ }
1385
+ .summary-num {
1386
+ width: 24px;
1387
+ height: 24px;
1388
+ border-radius: 50%;
1389
+ background: var(--el-color-primary);
1390
+ color: #fff;
1391
+ font-size: 12px;
1392
+ font-weight: 600;
1393
+ display: flex;
1394
+ align-items: center;
1395
+ justify-content: center;
1396
+ }
1397
+ .summary-detail {
1398
+ margin: 0;
1399
+ font-size: 13px;
1400
+ color: var(--el-text-color-regular);
1401
+ line-height: 1.6;
1402
+ padding-top: 2px;
1403
+ }
1404
+
1405
+ /* ── Builtin Tools ── */
1406
+ .builtin-collapse {
1407
+ border: none;
1408
+ }
1409
+ .builtin-tool-header {
1410
+ display: flex;
1411
+ align-items: center;
1412
+ gap: 12px;
1413
+ }
1414
+ .builtin-tool-name {
1415
+ font-family: ui-monospace, Consolas, monospace;
1416
+ font-size: 14px;
1417
+ font-weight: 600;
1418
+ color: var(--el-color-primary);
1419
+ background: var(--el-color-primary-light-9);
1420
+ padding: 2px 8px;
1421
+ border-radius: 4px;
1422
+ }
1423
+ .builtin-tool-summary {
1424
+ font-size: 13px;
1425
+ color: var(--el-text-color-secondary);
1426
+ }
1427
+ .builtin-tool-body {
1428
+ padding: 8px 0 16px;
1429
+ }
1430
+ .builtin-section-label {
1431
+ font-size: 12px;
1432
+ font-weight: 600;
1433
+ color: var(--el-text-color-secondary);
1434
+ margin-bottom: 8px;
1435
+ text-transform: uppercase;
1436
+ letter-spacing: 0.5px;
1437
+ }
1438
+ .builtin-desc-text {
1439
+ margin: 0 0 8px;
1440
+ padding: 12px 16px;
1441
+ background: #1e1e1e;
1442
+ border-radius: 8px;
1443
+ overflow-x: auto;
1444
+ font-family: ui-monospace, Consolas, monospace;
1445
+ font-size: 13px;
1446
+ line-height: 1.6;
1447
+ color: #d4d4d4;
1448
+ white-space: pre-wrap;
1449
+ word-break: break-word;
1450
+ }
1451
+
1452
+ /* ── Spec Conversion ── */
1453
+ .spec-card {
1454
+ height: 100%;
1455
+ margin-bottom: 16px;
1456
+ }
1457
+ .spec-name {
1458
+ margin: 0 0 4px;
1459
+ font-size: 16px;
1460
+ font-weight: 600;
1461
+ }
1462
+ .spec-endpoint {
1463
+ font-size: 12px;
1464
+ color: var(--el-color-primary);
1465
+ background: var(--el-color-primary-light-9);
1466
+ padding: 2px 8px;
1467
+ border-radius: 4px;
1468
+ }
1469
+ .spec-desc {
1470
+ margin: 8px 0;
1471
+ font-size: 13px;
1472
+ line-height: 1.6;
1473
+ color: var(--el-text-color-secondary);
1474
+ }
1475
+ .spec-fields {
1476
+ border-top: 1px solid var(--el-border-color-lighter);
1477
+ padding-top: 8px;
1478
+ }
1479
+ .spec-field {
1480
+ display: flex;
1481
+ align-items: baseline;
1482
+ gap: 8px;
1483
+ padding: 3px 0;
1484
+ }
1485
+ .field-name {
1486
+ font-family: ui-monospace, Consolas, monospace;
1487
+ font-size: 12px;
1488
+ color: var(--el-color-primary);
1489
+ flex-shrink: 0;
1490
+ min-width: 100px;
1491
+ }
1492
+ .field-type {
1493
+ font-size: 11px;
1494
+ color: var(--el-text-color-secondary);
1495
+ flex-shrink: 0;
1496
+ min-width: 60px;
1497
+ }
1498
+ .field-note {
1499
+ font-size: 12px;
1500
+ color: var(--el-text-color-regular);
1501
+ line-height: 1.4;
1502
+ }
1503
+ .sse-pre {
1504
+ margin: 0;
1505
+ padding: 4px 8px;
1506
+ font-family: ui-monospace, Consolas, monospace;
1507
+ font-size: 11px;
1508
+ line-height: 1.5;
1509
+ white-space: pre-wrap;
1510
+ word-break: break-all;
1511
+ color: var(--el-text-color-regular);
1512
+ }
1513
+
1514
+ /* ── Known Issues ── */
1515
+ .issue-item {
1516
+ padding: 16px 0;
1517
+ border-bottom: 1px solid var(--el-border-color-lighter);
1518
+ }
1519
+ .issue-item:last-child {
1520
+ border-bottom: none;
1521
+ }
1522
+ .issue-header {
1523
+ display: flex;
1524
+ align-items: center;
1525
+ gap: 8px;
1526
+ margin-bottom: 8px;
1527
+ }
1528
+ .issue-title {
1529
+ font-size: 14px;
1530
+ font-weight: 600;
1531
+ color: var(--el-text-color-primary);
1532
+ }
1533
+ .issue-detail {
1534
+ margin: 0 0 8px;
1535
+ font-size: 13px;
1536
+ line-height: 1.6;
1537
+ color: var(--el-text-color-regular);
1538
+ }
1539
+ .issue-location {
1540
+ margin: 0 0 8px;
1541
+ font-size: 12px;
1542
+ color: var(--el-text-color-secondary);
1543
+ }
1544
+ .issue-location code {
1545
+ font-family: ui-monospace, Consolas, monospace;
1546
+ font-size: 11px;
1547
+ color: var(--el-color-danger);
1548
+ }
1549
+ .issue-fix {
1550
+ margin-top: 8px;
1551
+ }
1552
+
1553
+ /* ── Tool Bridge ── */
1554
+ .bridge-step {
1555
+ padding: 12px 0;
1556
+ border-bottom: 1px solid var(--el-border-color-lighter);
1557
+ }
1558
+ .bridge-step:last-child {
1559
+ border-bottom: none;
1560
+ }
1561
+ .bridge-step-header {
1562
+ display: flex;
1563
+ align-items: center;
1564
+ gap: 8px;
1565
+ margin-bottom: 4px;
1566
+ }
1567
+
1568
+ /* ── Feature Cards ── */
1569
+ .feature-card {
1570
+ padding: 12px 16px;
1571
+ border: 1px solid var(--el-border-color-lighter);
1572
+ border-radius: 8px;
1573
+ margin-bottom: 12px;
1574
+ }
1575
+ .feature-name {
1576
+ font-size: 14px;
1577
+ color: var(--el-color-primary);
1578
+ }
1579
+ .feature-desc {
1580
+ margin: 4px 0 0;
1581
+ font-size: 13px;
1582
+ line-height: 1.6;
1583
+ color: var(--el-text-color-regular);
1584
+ }
1585
+
1586
+ /* ── Auth Module ── */
1587
+ .sub-module-intro {
1588
+ margin-bottom: 16px;
1589
+ }
1590
+ .sub-module-intro h3 {
1591
+ display: inline;
1592
+ margin: 0 12px 0 0;
1593
+ font-size: 18px;
1594
+ font-weight: 600;
1595
+ }
1596
+ .category-title {
1597
+ margin: 0 0 8px;
1598
+ font-size: 15px;
1599
+ font-weight: 600;
1600
+ color: var(--el-color-primary);
1601
+ border-bottom: 1px solid var(--el-border-color-lighter);
1602
+ padding-bottom: 4px;
1603
+ }
1604
+ </style>