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 +7 -7
- package/src/cli/cmd/tui/app.tsx +0 -13
- package/src/cli/cmd/tui/component/dialog-mimo-login.tsx +113 -129
- package/src/cli/cmd/tui/component/dialog-model.tsx +62 -77
- package/src/cli/cmd/tui/component/dialog-variant.tsx +28 -11
- package/src/cli/cmd/tui/ui/dialog-select.tsx +2 -2
- package/src/cli/logo.ts +16 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"version": "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
|
-
"
|
|
52
|
-
"
|
|
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
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
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",
|
package/src/cli/cmd/tui/app.tsx
CHANGED
|
@@ -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
|
-
<
|
|
41
|
+
<TulingAIOAuthFlow url={result.data!.url} instructions={result.data!.instructions} />
|
|
44
42
|
))
|
|
45
43
|
},
|
|
46
44
|
},
|
|
47
45
|
{
|
|
48
|
-
title:
|
|
49
|
-
value: "
|
|
50
|
-
description:
|
|
51
|
-
onSelect:
|
|
52
|
-
|
|
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:
|
|
68
|
-
value: "
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
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: "
|
|
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=
|
|
192
|
-
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
|
-
|
|
210
|
-
|
|
211
|
-
providerID: "xiaomi",
|
|
186
|
+
const { error } = await sdk.client.provider.oauth.callback({
|
|
187
|
+
providerID: "tuling-ai",
|
|
212
188
|
method: 0,
|
|
213
|
-
code: value
|
|
189
|
+
code: value,
|
|
214
190
|
})
|
|
215
|
-
if (
|
|
216
|
-
|
|
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
|
-
|
|
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
|
|
56
|
+
description: undefined, // 不显示 provider 名称
|
|
57
57
|
category,
|
|
58
|
-
disabled:
|
|
59
|
-
footer:
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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 =
|
|
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
|
-
|
|
167
|
-
|
|
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: "
|
|
14
|
-
title: "
|
|
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
|
-
|
|
21
|
-
value:
|
|
22
|
-
title:
|
|
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=
|
|
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={
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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 = "_^~,"
|