tulingcode 0.2.0 → 0.3.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "name": "tulingcode",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -48,8 +48,8 @@
48
48
  "@babel/core": "7.28.4",
49
49
  "@effect/language-service": "0.84.2",
50
50
  "@octokit/webhooks-types": "7.6.1",
51
- "@tuling-ai/script": "0.1.0",
52
- "@tuling-ai/shared": "0.1.0",
51
+ "tulingcode-script": "0.1.0",
52
+ "tulingcode-shared": "0.1.0",
53
53
  "@parcel/watcher-darwin-arm64": "2.5.1",
54
54
  "@parcel/watcher-darwin-x64": "2.5.1",
55
55
  "@parcel/watcher-linux-arm64-glibc": "2.5.1",
@@ -134,10 +134,10 @@
134
134
  "@solid-primitives/i18n": "2.2.1",
135
135
  "@solid-primitives/scheduled": "1.5.2",
136
136
  "@standard-schema/spec": "1.0.0",
137
- "@tuling-ai/plugin": "0.1.0",
138
- "@tuling-ai/script": "0.1.0",
139
- "@tuling-ai/sdk": "0.1.0",
140
- "@tuling-ai/ui": "0.1.0",
137
+ "tulingcode-plugin": "0.1.0",
138
+ "tulingcode-script": "0.1.0",
139
+ "tulingcode-sdk": "0.1.0",
140
+ "tulingcode-ui": "0.1.0",
141
141
  "@zip.js/zip.js": "2.7.62",
142
142
  "ai": "6.0.168",
143
143
  "ai-gateway-provider": "3.1.2",
@@ -765,19 +765,6 @@ function App(props: { onSnapshot?: () => Promise<string[]> }) {
765
765
  },
766
766
  category: "system",
767
767
  },
768
- {
769
- title: t("tui.command.docs.open.title"),
770
- value: "docs.open",
771
- slash: {
772
- name: "doc",
773
- aliases: ["docs"],
774
- },
775
- onSelect: () => {
776
- open("https://mimo.xiaomi.com/coder/docs").catch(() => {})
777
- dialog.clear()
778
- },
779
- category: "system",
780
- },
781
768
  {
782
769
  title: t("tui.command.app.exit.title"),
783
770
  value: "app.exit",
@@ -5,8 +5,6 @@ import { useLocal } from "@tui/context/local"
5
5
  import { useDialog } from "@tui/ui/dialog"
6
6
  import { useTheme } from "../context/theme"
7
7
  import { useLanguage } from "../context/language"
8
- import { DialogProvider as DialogProviderList } from "./dialog-provider"
9
- import { DialogSelect } from "@tui/ui/dialog-select"
10
8
  import { DialogPrompt } from "../ui/dialog-prompt"
11
9
  import { useToast } from "../ui/toast"
12
10
  import os from "os"
@@ -40,129 +38,122 @@ export function DialogMimoLogin() {
40
38
  return
41
39
  }
42
40
  dialog.replace(() => (
43
- <MimoOAuthFlow url={result.data!.url} instructions={result.data!.instructions} />
41
+ <TulingAIOAuthFlow url={result.data!.url} instructions={result.data!.instructions} />
44
42
  ))
45
43
  },
46
44
  },
47
45
  {
48
- title: t("tui.dialog.login.xiaomi"),
49
- value: "xiaomi",
50
- description: t("tui.dialog.login.xiaomi.desc"),
51
- onSelect: async () => {
52
- const result = await sdk.client.provider.oauth.authorize({
53
- providerID: "xiaomi",
54
- method: 0,
55
- })
56
- if (result.error) {
57
- toast.show({ message: t("tui.dialog.login.start_failed"), variant: "error" })
58
- dialog.clear()
59
- return
60
- }
61
- dialog.replace(() => (
62
- <MimoOAuthFlow url={result.data!.url} instructions={result.data!.instructions} />
63
- ))
46
+ title: "云端API",
47
+ value: "cloud-api",
48
+ description: "使用云端API Key",
49
+ onSelect: () => {
50
+ dialog.replace(() => <CloudAPIKeyInput />)
64
51
  },
65
52
  },
66
53
  {
67
- title: t("tui.dialog.login.import_claude"),
68
- value: "import_claude",
69
- onSelect: async () => {
70
- const claudeDir = path.join(os.homedir(), ".claude")
71
- const candidates = ["settings.json", "settings.local.json", "settings_local.json"]
54
+ title: "自定义API",
55
+ value: "custom-api",
56
+ description: "自定义API地址和Key",
57
+ onSelect: () => {
58
+ dialog.replace(() => <CustomAPIInput />)
59
+ },
60
+ },
61
+ ]}
62
+ />
63
+ )
64
+ }
72
65
 
73
- const resolve = await (async () => {
74
- const envs: Record<string, string>[] = []
75
- for (const file of candidates) {
76
- try {
77
- const content = await Bun.file(path.join(claudeDir, file)).json()
78
- if (content?.env && typeof content.env === "object") envs.push(content.env)
79
- } catch {}
80
- }
81
- return (name: string) => {
82
- for (let i = envs.length - 1; i >= 0; i--) {
83
- const v = envs[i][name]
84
- if (v && typeof v === "string") return v
85
- }
86
- return process.env[name]
87
- }
88
- })()
66
+ // 云端API Key 输入组件
67
+ function CloudAPIKeyInput() {
68
+ const dialog = useDialog()
69
+ const sdk = useSDK()
70
+ const sync = useSync()
71
+ const local = useLocal()
72
+ const toast = useToast()
89
73
 
90
- const key = resolve("ANTHROPIC_API_KEY")
91
- const rawBaseUrl = resolve("ANTHROPIC_BASE_URL")
92
- const baseUrl = rawBaseUrl
93
- ? rawBaseUrl.replace(/\/+$/, "").replace(/(?<!\/v1)$/, "/v1")
94
- : undefined
95
- // strip Claude Code context-window suffix e.g. claude-opus-4-6[1m]
96
- const preferredModel = (
97
- resolve("ANTHROPIC_DEFAULT_OPUS_MODEL") ?? resolve("ANTHROPIC_DEFAULT_SONNET_MODEL")
98
- )?.replace(/\[.*\]$/, "")
74
+ return (
75
+ <DialogPrompt
76
+ title="云端API Key"
77
+ placeholder="请输入 API Key (sk-...)"
78
+ onConfirm={async (value) => {
79
+ if (!value) return
80
+ await sdk.client.auth.set({
81
+ providerID: "cloud-api",
82
+ auth: { type: "api", key: value, metadata: { base_url: "https://ydapi.cxikeji.top" } },
83
+ })
84
+ await sdk.client.instance.dispose()
85
+ await sync.bootstrap()
86
+ const provider = sync.data.provider.find((p) => p.id === "cloud-api")
87
+ if (provider) {
88
+ local.model.set({ providerID: "cloud-api", modelID: Object.keys(provider.models)[0] }, { recent: true })
89
+ }
90
+ toast.show({ message: "云端API 连接成功", variant: "info" })
91
+ dialog.clear()
92
+ }}
93
+ />
94
+ )
95
+ }
99
96
 
100
- if (!key) {
101
- toast.show({ message: t("tui.dialog.login.import_claude.no_key"), variant: "error" })
102
- dialog.clear()
103
- return
104
- }
97
+ // 自定义API 输入组件
98
+ function CustomAPIInput() {
99
+ const dialog = useDialog()
100
+ const sdk = useSDK()
101
+ const sync = useSync()
102
+ const local = useLocal()
103
+ const toast = useToast()
104
+ const [apiUrl, setApiUrl] = createSignal("")
105
105
 
106
- await sdk.client.auth.set({
107
- providerID: "anthropic",
108
- auth: { type: "api", key },
109
- })
110
- await sdk.client.global.config.update({
111
- config: {
112
- provider: {
113
- anthropic: { options: { baseURL: baseUrl || "https://api.anthropic.com/v1" } },
114
- },
115
- },
116
- })
117
- await sdk.client.instance.dispose()
118
- await sync.bootstrap()
106
+ return (
107
+ <DialogPrompt
108
+ title="自定义API 地址"
109
+ placeholder="请输入API地址 (https://api.example.com/v1)"
110
+ onConfirm={async (value) => {
111
+ if (!value) return
112
+ setApiUrl(value)
113
+ dialog.replace(() => <CustomAPIKeyInput apiUrl={value} />)
114
+ }}
115
+ />
116
+ )
117
+ }
119
118
 
120
- const anthropic = sync.data.provider.find((p) => p.id === "anthropic")
121
- if (anthropic) {
122
- if (preferredModel && !(preferredModel in anthropic.models)) {
123
- await sdk.client.global.config.update({
124
- config: {
125
- provider: {
126
- anthropic: { models: { [preferredModel]: { name: preferredModel } } },
127
- },
128
- },
129
- })
130
- await sdk.client.instance.dispose()
131
- await sync.bootstrap()
132
- }
133
- const models = Object.keys(anthropic.models).sort()
134
- const selected = preferredModel
135
- || models.find((m) => m === "claude-opus-4-6")
136
- || models.findLast((m) => m.includes("opus"))
137
- || models.findLast((m) => m.includes("sonnet"))
138
- || models[0]
139
- if (selected) {
140
- local.model.set({ providerID: "anthropic", modelID: selected }, { recent: true })
141
- }
142
- }
143
- toast.show({ message: t("tui.dialog.login.import_claude.success"), variant: "info" })
144
- dialog.clear()
145
- },
146
- },
147
- {
148
- title: t("tui.dialog.login.other"),
149
- value: "__other__",
150
- onSelect: () => {
151
- dialog.replace(() => <DialogProviderList />)
152
- },
153
- },
154
- ]}
119
+ // 自定义API Key 输入组件
120
+ function CustomAPIKeyInput(props: { apiUrl: string }) {
121
+ const dialog = useDialog()
122
+ const sdk = useSDK()
123
+ const sync = useSync()
124
+ const local = useLocal()
125
+ const toast = useToast()
126
+
127
+ return (
128
+ <DialogPrompt
129
+ title="自定义API Key"
130
+ placeholder="请输入 API Key (sk-...)"
131
+ onConfirm={async (value) => {
132
+ if (!value) return
133
+ await sdk.client.auth.set({
134
+ providerID: "custom-api",
135
+ auth: { type: "api", key: value, metadata: { base_url: props.apiUrl } },
136
+ })
137
+ await sdk.client.instance.dispose()
138
+ await sync.bootstrap()
139
+ const provider = sync.data.provider.find((p) => p.id === "custom-api")
140
+ if (provider) {
141
+ local.model.set({ providerID: "custom-api", modelID: Object.keys(provider.models)[0] }, { recent: true })
142
+ }
143
+ toast.show({ message: "自定义API 连接成功", variant: "info" })
144
+ dialog.clear()
145
+ }}
155
146
  />
156
147
  )
157
148
  }
158
149
 
159
- function MimoOAuthFlow(props: { url: string; instructions: string }) {
150
+ // 图灵AI OAuth 流程
151
+ function TulingAIOAuthFlow(props: { url: string; instructions: string }) {
160
152
  const dialog = useDialog()
161
153
  const sdk = useSDK()
162
154
  const sync = useSync()
163
155
  const local = useLocal()
164
156
  const { theme } = useTheme()
165
- const { t } = useLanguage()
166
157
  const toast = useToast()
167
158
  const [busy, setBusy] = createSignal(false)
168
159
 
@@ -179,7 +170,7 @@ function MimoOAuthFlow(props: { url: string; instructions: string }) {
179
170
 
180
171
  onMount(async () => {
181
172
  const callbackResult = await sdk.client.provider.oauth.callback({
182
- providerID: "xiaomi",
173
+ providerID: "tuling-ai",
183
174
  method: 0,
184
175
  })
185
176
  if (callbackResult.error) return
@@ -188,37 +179,30 @@ function MimoOAuthFlow(props: { url: string; instructions: string }) {
188
179
 
189
180
  return (
190
181
  <DialogPrompt
191
- title={t("tui.dialog.login.flow.title")}
192
- placeholder={t("tui.dialog.login.flow.placeholder")}
193
- busy={busy()}
194
- busyText={t("tui.dialog.login.flow.busy")}
195
- description={
196
- <box gap={1}>
197
- <Show when={props.url}>
198
- <text fg={theme.textMuted}>{t("tui.dialog.login.flow.manual_hint")}</text>
199
- <text fg={theme.primary}>{props.url}</text>
200
- </Show>
201
- <Show when={props.instructions}>
202
- <text fg={theme.textMuted}>{props.instructions}</text>
203
- </Show>
204
- <text fg={theme.textMuted}>{t("tui.dialog.login.flow.waiting")}</text>
205
- </box>
206
- }
182
+ title="图灵AI 授权"
183
+ placeholder="Authorization code"
207
184
  onConfirm={async (value) => {
208
185
  if (!value) return
209
- setBusy(true)
210
- const { error: err } = await sdk.client.provider.oauth.callback({
211
- providerID: "xiaomi",
186
+ const { error } = await sdk.client.provider.oauth.callback({
187
+ providerID: "tuling-ai",
212
188
  method: 0,
213
- code: value.trim(),
189
+ code: value,
214
190
  })
215
- if (err) {
216
- setBusy(false)
217
- toast.show({ message: t("tui.dialog.login.flow.invalid_code"), variant: "error" })
191
+ if (!error) {
192
+ await onLoginSuccess()
218
193
  return
219
194
  }
220
- await onLoginSuccess()
195
+ toast.show({ message: "授权失败", variant: "error" })
221
196
  }}
197
+ description={() => (
198
+ <box gap={1}>
199
+ <text fg={theme.textMuted}>{props.instructions}</text>
200
+ <text fg={theme.textMuted}>Press c to copy the authorization code</text>
201
+ </box>
202
+ )}
222
203
  />
223
204
  )
224
205
  }
206
+
207
+ // 导入 DialogSelect
208
+ import { DialogSelect } from "@tui/ui/dialog-select"
@@ -53,10 +53,10 @@ export function DialogModel(props: { providerID?: string }) {
53
53
  key: item,
54
54
  value: { providerID: provider.id, modelID: model.id },
55
55
  title: model.name ?? item.modelID,
56
- description: provider.name,
56
+ description: undefined, // 不显示 provider 名称
57
57
  category,
58
- disabled: provider.id === "tulingcode" && model.id.includes("-nano"),
59
- footer: model.cost?.input === 0 && provider.id === "tulingcode" ? "Free" : undefined,
58
+ disabled: false,
59
+ footer: undefined as "Free" | undefined,
60
60
  onSelect: () => {
61
61
  onSelect(provider.id, model.id)
62
62
  },
@@ -73,73 +73,67 @@ export function DialogModel(props: { providerID?: string }) {
73
73
  "Recent",
74
74
  )
75
75
 
76
+ // 合并所有provider的模型,去重后显示(通用模型,不分provider)
77
+ const allModels = new Map<string, { providerID: string; modelID: string; name: string }>()
78
+ for (const provider of sync.data.provider.filter((p) => ["tuling-ai", "cloud-api", "custom-api"].includes(p.id))) {
79
+ for (const [modelID, info] of Object.entries(provider.models)) {
80
+ if (info.status === "deprecated") continue
81
+ if (!allModels.has(modelID)) {
82
+ allModels.set(modelID, { providerID: provider.id, modelID, name: info.name ?? modelID })
83
+ }
84
+ }
85
+ }
86
+
87
+ // 自定义排序:GPT-5.5 放在第一个
88
+ const modelOrder = ["gpt-5.5", "claude-opus-4-8", "claude-sonnet-4-6", "mimo-v2.5", "mimo-v2.5-pro", "gemini-3.1-pro-preview"]
89
+ const sortedModels = Array.from(allModels.values()).sort((a, b) => {
90
+ const aIndex = modelOrder.indexOf(a.modelID)
91
+ const bIndex = modelOrder.indexOf(b.modelID)
92
+ if (aIndex !== -1 && bIndex !== -1) return aIndex - bIndex
93
+ if (aIndex !== -1) return -1
94
+ if (bIndex !== -1) return 1
95
+ return a.name.localeCompare(b.name)
96
+ })
97
+
76
98
  const providerOptions = pipe(
77
- sync.data.provider,
78
- sortBy(
79
- (provider) => provider.id !== "tulingcode",
80
- (provider) => provider.name,
81
- ),
82
- flatMap((provider) => {
83
- const models = pipe(
84
- provider.models,
85
- entries(),
86
- filter(([_, info]) => info.status !== "deprecated"),
87
- filter(([_, info]) => (props.providerID ? info.providerID === props.providerID : true)),
88
- map(([model, info]) => ({
89
- value: { providerID: provider.id, modelID: model },
90
- title: info.name ?? model,
91
- description: favorites.some((item) => item.providerID === provider.id && item.modelID === model)
92
- ? "(Favorite)"
93
- : undefined,
94
- category: connected() ? provider.name : undefined,
95
- disabled: provider.id === "tulingcode" && model.includes("-nano"),
96
- footer: info.cost?.input === 0 && provider.id === "tulingcode" ? "Free" : undefined,
97
- onSelect() {
98
- onSelect(provider.id, model)
99
- },
100
- })),
101
- filter((x) => {
102
- if (!showSections) return true
103
- if (favorites.some((item) => item.providerID === x.value.providerID && item.modelID === x.value.modelID))
104
- return false
105
- if (recents.some((item) => item.providerID === x.value.providerID && item.modelID === x.value.modelID))
106
- return false
107
- return true
108
- }),
109
- sortBy(
110
- (x) => x.footer !== "Free",
111
- (x) => x.title,
112
- ),
113
- )
114
- if (provider.source !== "config") return models
115
- if (props.providerID && props.providerID !== provider.id) return models
116
- return [
117
- ...models,
118
- {
119
- value: { providerID: provider.id, modelID: ADD_MODEL_SENTINEL },
120
- title: "+ Add model",
121
- description: undefined,
122
- category: connected() ? provider.name : undefined,
123
- disabled: false,
124
- footer: undefined as "Free" | undefined,
125
- onSelect() {
126
- void runAddModelWizard({ dialog, sdk, sync, toast, providerID: provider.id })
127
- },
128
- },
129
- ]
99
+ sortedModels,
100
+ map((item) => ({
101
+ value: { providerID: item.providerID, modelID: item.modelID },
102
+ title: item.name,
103
+ description: "",
104
+ category: undefined,
105
+ disabled: false,
106
+ footer: undefined as "Free" | undefined,
107
+ onSelect() {
108
+ onSelect(item.providerID, item.modelID)
109
+ },
110
+ })),
111
+ filter((x) => {
112
+ if (!showSections) return true
113
+ if (favorites.some((item) => item.modelID === x.value.modelID))
114
+ return false
115
+ if (recents.some((item) => item.modelID === x.value.modelID))
116
+ return false
117
+ return true
130
118
  }),
119
+ // 添加 "+ Add model" 选项
120
+ (list) => [
121
+ ...list,
122
+ {
123
+ value: { providerID: "tuling-ai", modelID: ADD_MODEL_SENTINEL },
124
+ title: "+ Add model",
125
+ description: "",
126
+ category: undefined,
127
+ disabled: false,
128
+ footer: undefined as "Free" | undefined,
129
+ onSelect() {
130
+ void runAddModelWizard({ dialog, sdk, sync, toast, providerID: "tuling-ai" })
131
+ },
132
+ },
133
+ ],
131
134
  )
132
135
 
133
- const popularProviders = !connected()
134
- ? pipe(
135
- providers(),
136
- map((option) => ({
137
- ...option,
138
- category: "Popular providers",
139
- })),
140
- take(6),
141
- )
142
- : []
136
+ const popularProviders = [] // 移除不需要的 provider 选项
143
137
 
144
138
  if (needle) {
145
139
  return [
@@ -163,17 +157,8 @@ export function DialogModel(props: { providerID?: string }) {
163
157
 
164
158
  function onSelect(providerID: string, modelID: string) {
165
159
  local.model.set({ providerID, modelID }, { recent: true })
166
- const list = local.model.variant.list()
167
- const cur = local.model.variant.selected()
168
- if (cur === "default" || (cur && list.includes(cur))) {
169
- dialog.clear()
170
- return
171
- }
172
- if (list.length > 0) {
173
- dialog.replace(() => <DialogVariant />)
174
- return
175
- }
176
- dialog.clear()
160
+ // 总是跳转到 API 格式选择
161
+ dialog.replace(() => <DialogVariant />)
177
162
  }
178
163
 
179
164
  return (
@@ -1,4 +1,4 @@
1
- import { createMemo } from "solid-js"
1
+ import { createMemo, createSignal } from "solid-js"
2
2
  import { useLocal } from "@tui/context/local"
3
3
  import { DialogSelect } from "@tui/ui/dialog-select"
4
4
  import { useDialog } from "@tui/ui/dialog"
@@ -10,30 +10,47 @@ export function DialogVariant() {
10
10
  const options = createMemo(() => {
11
11
  return [
12
12
  {
13
- value: "default",
14
- title: "Default",
13
+ value: "skip",
14
+ title: "跳过 (使用默认格式)",
15
15
  onSelect: () => {
16
+ local.model.variant.set(undefined)
16
17
  dialog.clear()
18
+ },
19
+ },
20
+ {
21
+ value: "openai",
22
+ title: "OpenAI 格式",
23
+ description: "兼容所有 OpenAI 格式 API",
24
+ onSelect: () => {
17
25
  local.model.variant.set(undefined)
26
+ dialog.clear()
18
27
  },
19
28
  },
20
- ...local.model.variant.list().map((variant) => ({
21
- value: variant,
22
- title: variant,
29
+ {
30
+ value: "anthropic",
31
+ title: "Anthropic 格式",
32
+ description: "Claude 官方格式",
23
33
  onSelect: () => {
34
+ local.model.variant.set(undefined)
24
35
  dialog.clear()
25
- local.model.variant.set(variant)
26
36
  },
27
- })),
37
+ },
38
+ {
39
+ value: "gemini",
40
+ title: "Gemini 格式",
41
+ description: "Google Gemini 官方格式",
42
+ onSelect: () => {
43
+ local.model.variant.set(undefined)
44
+ dialog.clear()
45
+ },
46
+ },
28
47
  ]
29
48
  })
30
49
 
31
50
  return (
32
51
  <DialogSelect<string>
33
52
  options={options()}
34
- title={"Select variant"}
35
- current={local.model.variant.selected()}
36
- flat={true}
53
+ title="Select API format"
37
54
  />
38
55
  )
39
56
  }
@@ -204,7 +204,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
204
204
  if (evt.name === "home") moveTo(0)
205
205
  if (evt.name === "end") moveTo(flat().length - 1)
206
206
 
207
- if (evt.name === "return") {
207
+ if (evt.name === "return" || evt.name === "enter") {
208
208
  const option = selected()
209
209
  if (option) {
210
210
  evt.preventDefault()
@@ -351,7 +351,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
351
351
  </Show>
352
352
  <Option
353
353
  title={option.title}
354
- footer={flatten() ? (option.category ?? option.footer) : option.footer}
354
+ footer={option.footer}
355
355
  description={option.description !== category ? option.description : undefined}
356
356
  active={active()}
357
357
  current={current()}
package/src/cli/logo.ts CHANGED
@@ -2,16 +2,16 @@ export const logo = {
2
2
  left: [
3
3
  " ",
4
4
  " ",
5
- " ███╗ ███╗ ██╗ ███╗ ███╗ ██████╗ ",
6
- " ████╗ ████║ ██║ ████╗ ████║ ██╔═══██╗",
7
- " ██╔████╔██║ ██║ ██╔████╔██║ ██║ ██║",
8
- " ██║╚██╔╝██║ ██║ ██║╚██╔╝██║ ██║ ██║",
9
- " ██║ ╚═╝ ██║ ██║ ██║ ╚═╝ ██║ ╚██████╔╝",
10
- " ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ",
5
+ " ███████╗██╗ ██╗██╗ ██████╗ ███████╗",
6
+ " ╚══██╔╝██║ ██║██║ ██╔═══██╗██╔════╝",
7
+ " ██║ ██║ ██║██║ ██║ ██║███████╗",
8
+ " ██║ ██║ ██║██║ ██║ ██║╚════██║",
9
+ " ██║ ╚██████╔╝███████╗╚██████╔╝███████║",
10
+ " ╚═╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝",
11
11
  ],
12
12
  right: [
13
- " Xiaomi",
14
- " ",
13
+ "",
14
+ "",
15
15
  " ██████╗ ██████╗ ██████╗ ███████╗",
16
16
  "██╔════╝ ██╔═══██╗ ██╔══██╗ ██╔════╝",
17
17
  "██║ ██║ ██║ ██║ ██║ █████╗ ",
@@ -23,15 +23,15 @@ export const logo = {
23
23
 
24
24
  export const logoThin = {
25
25
  left: [
26
- " ",
27
- " ",
28
- "█▀▄▀█ █▀▄▀█ █▀▀█",
29
- " █ █ ▀ █ █ █",
30
- "▀ ▀ ▀ ▀▀▀▀",
26
+ " ",
27
+ " ",
28
+ "█▀▀ █▀▀█ █▀▀▄",
29
+ "█▀▀▀ █ █ █",
30
+ "▀ ▀ ▀▀▀▀ ",
31
31
  ],
32
32
  right: [
33
- " Xiaomi",
34
- " ",
33
+ " Tuling",
34
+ " ",
35
35
  " █▀▀ █▀▀█ █▀▀▄ █▀▀▀",
36
36
  " █ █ █ █ █ █▀▀ ",
37
37
  " ▀▀▀ ▀▀▀▀ ▀▀▀ ▀▀▀▀",
@@ -50,4 +50,4 @@ export const go = {
50
50
  right: [" ", "█▀▀▀", "█ __", "▀▀▀▀"],
51
51
  }
52
52
 
53
- export const marks = "_^~,"
53
+ export const marks = "_^~,"