thatgfsj-code 3.0.0 → 3.0.2
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/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +7 -0
- package/dist/app/index.js.map +1 -1
- package/dist/tui/app.d.ts.map +1 -1
- package/dist/tui/app.js +11 -44
- package/dist/tui/app.js.map +1 -1
- package/dist/tui/components/InitWizard.d.ts +18 -9
- package/dist/tui/components/InitWizard.d.ts.map +1 -1
- package/dist/tui/components/InitWizard.js +61 -33
- package/dist/tui/components/InitWizard.js.map +1 -1
- package/dist/tui/components/ModelSelector.d.ts +3 -1
- package/dist/tui/components/ModelSelector.d.ts.map +1 -1
- package/dist/tui/components/ModelSelector.js +24 -7
- package/dist/tui/components/ModelSelector.js.map +1 -1
- package/dist/tui/components/UserInput.d.ts.map +1 -1
- package/dist/tui/components/UserInput.js +20 -0
- package/dist/tui/components/UserInput.js.map +1 -1
- package/package.json +2 -1
- package/src/app/index.ts +9 -0
- package/src/tui/app.tsx +9 -56
- package/src/tui/components/InitWizard.tsx +87 -40
- package/src/tui/components/ModelSelector.tsx +27 -7
- package/src/tui/components/UserInput.tsx +20 -0
- package/tests/cache/providerCatalog.test.ts +31 -0
package/dist/app/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEjF,qBAAa,GAAG;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,UAAU,EAAE,eAAe,CAAC;IAC5B;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAS;IAE9B,OAAO;WAoBM,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC;IAyCnC;;;;;;;;;;;;OAYG;IACI,cAAc,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC,WAAW,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEjF,qBAAa,GAAG;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,mBAAmB,CAAC;IAC7B,MAAM,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,UAAU,EAAE,eAAe,CAAC;IAC5B;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAS;IAE9B,OAAO;WAoBM,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC;IAyCnC;;;;;;;;;;;;OAYG;IACI,cAAc,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,cAAc,CAAC,WAAW,EAAE,YAAY,CAAC;IA2B1F;;;;;;;;;;;;;OAaG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;CAgCnF"}
|
package/dist/app/index.js
CHANGED
|
@@ -94,6 +94,7 @@ export class App {
|
|
|
94
94
|
async *streamResponse(messages) {
|
|
95
95
|
const msgs = messages || this.session.getMessages();
|
|
96
96
|
const inner = this.llm.chatStream(msgs);
|
|
97
|
+
const debugUsage = !!process.env.GFCODE_DEBUG_USAGE;
|
|
97
98
|
let next = await inner.next();
|
|
98
99
|
while (!next.done) {
|
|
99
100
|
// Forward chunks unchanged, but capture usage into the persistent
|
|
@@ -103,6 +104,12 @@ export class App {
|
|
|
103
104
|
this.cacheStats.record(next.value.usage);
|
|
104
105
|
}
|
|
105
106
|
catch { /* best-effort */ }
|
|
107
|
+
if (debugUsage) {
|
|
108
|
+
// v3.0.0 DEBUG: dump raw usage fields to stderr so the user can
|
|
109
|
+
// confirm whether the upstream provider/relay forwards cache stats.
|
|
110
|
+
// Enable with: GFCODE_DEBUG_USAGE=1 gfcode ...
|
|
111
|
+
process.stderr.write('[debug_usage] ' + JSON.stringify(next.value.usage) + '\n');
|
|
112
|
+
}
|
|
106
113
|
}
|
|
107
114
|
yield next.value;
|
|
108
115
|
next = await inner.next();
|
package/dist/app/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/app/index.ts"],"names":[],"mappings":"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"}
|
package/dist/tui/app.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/tui/app.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAA2C,MAAM,OAAO,CAAC;AAWhE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/tui/app.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAA2C,MAAM,OAAO,CAAC;AAWhE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAM3C,UAAU,KAAK;IACb,GAAG,EAAE,GAAG,CAAC;CACV;AAkBD,wBAAgB,MAAM,CAAC,EAAE,GAAG,EAAE,EAAE,KAAK,qBAiHpC"}
|
package/dist/tui/app.js
CHANGED
|
@@ -36,8 +36,6 @@ export function TuiApp({ app }) {
|
|
|
36
36
|
const { handleCommand } = useCommands(app);
|
|
37
37
|
const [systemMessages, setSystemMessages] = useState([]);
|
|
38
38
|
const [viewMode, setViewMode] = useState('chat');
|
|
39
|
-
const [initProvider, setInitProvider] = useState('siliconflow');
|
|
40
|
-
const [initUrl, setInitUrl] = useState('');
|
|
41
39
|
const { stdout } = useStdout();
|
|
42
40
|
const terminalWidth = stdout?.columns || 80;
|
|
43
41
|
// v3.0.0: cache stats snapshot for the Header. Re-read whenever messages
|
|
@@ -51,44 +49,6 @@ export function TuiApp({ app }) {
|
|
|
51
49
|
setSystemMessages(prev => [...prev, { role: 'assistant', content }]);
|
|
52
50
|
}, []);
|
|
53
51
|
const onSubmit = useCallback(async (input) => {
|
|
54
|
-
// Init wizard - API Key input
|
|
55
|
-
if (viewMode === 'init_key') {
|
|
56
|
-
const key = input.trim();
|
|
57
|
-
if (!key) {
|
|
58
|
-
setViewMode('chat');
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
// Save and complete
|
|
62
|
-
const { App: AppClass } = await import('../app/index.js');
|
|
63
|
-
const cfg = app.config.get();
|
|
64
|
-
app.config.save({ provider: initProvider, apiKey: key, model: cfg.model || 'default' });
|
|
65
|
-
saveModelToHistory(cfg.model || 'default');
|
|
66
|
-
setViewMode('chat');
|
|
67
|
-
addMsg(`配置已更新: ${initProvider}`);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
// Init wizard - Custom URL input
|
|
71
|
-
if (viewMode === 'init_url') {
|
|
72
|
-
const url = input.trim();
|
|
73
|
-
if (!url) {
|
|
74
|
-
setViewMode('chat');
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
setInitUrl(url);
|
|
78
|
-
setViewMode('init_key');
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
// Init wizard - Custom model name
|
|
82
|
-
if (viewMode === 'init_custom_model') {
|
|
83
|
-
const model = input.trim();
|
|
84
|
-
if (model) {
|
|
85
|
-
app.config.save({ model });
|
|
86
|
-
saveModelToHistory(model);
|
|
87
|
-
addMsg(`模型已切换: ${model}`);
|
|
88
|
-
}
|
|
89
|
-
setViewMode('chat');
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
52
|
// Model selector - ignore text input
|
|
93
53
|
if (viewMode === 'model_select')
|
|
94
54
|
return;
|
|
@@ -114,19 +74,26 @@ export function TuiApp({ app }) {
|
|
|
114
74
|
return;
|
|
115
75
|
}
|
|
116
76
|
sendMessage(input);
|
|
117
|
-
}, [handleCommand, sendMessage, app, viewMode,
|
|
77
|
+
}, [handleCommand, sendMessage, app, viewMode, addMsg]);
|
|
118
78
|
const allMessages = [...systemMessages, ...messages];
|
|
119
79
|
const activeSkills = app.skills.listActive().map(s => s.id);
|
|
120
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { provider: app.config.get().provider, model: app.config.get().model, cacheHitRate: cacheSnapshot.hitRate > 0 ? cacheSnapshot.hitRate : null, cacheSavingsCNY: cacheSnapshot.estimatedSavingsCNY }), _jsx(ChatList, { messages: allMessages, streaming: streaming, streamingToolCalls: streamingToolCalls, width: terminalWidth - 4 }), _jsx(Thinking, { active: isThinking }), queuedMessage && (_jsxs(Box, { paddingLeft: 1, children: [_jsx(Text, { color: "#F59E0B", children: "\uD83D\uDCCE \u5DF2\u6392\u961F: " }), _jsx(Text, { color: "#94A3B8", children: queuedMessage })] })), viewMode === 'model_select' ? (_jsx(ModelSelector, { currentModel: app.config.get().model, onSelect: (model) => {
|
|
80
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Header, { provider: app.config.get().provider, model: app.config.get().model, cacheHitRate: cacheSnapshot.hitRate > 0 ? cacheSnapshot.hitRate : null, cacheSavingsCNY: cacheSnapshot.estimatedSavingsCNY }), _jsx(ChatList, { messages: allMessages, streaming: streaming, streamingToolCalls: streamingToolCalls, width: terminalWidth - 4 }), _jsx(Thinking, { active: isThinking }), queuedMessage && (_jsxs(Box, { paddingLeft: 1, children: [_jsx(Text, { color: "#F59E0B", children: "\uD83D\uDCCE \u5DF2\u6392\u961F: " }), _jsx(Text, { color: "#94A3B8", children: queuedMessage })] })), viewMode === 'model_select' ? (_jsx(ModelSelector, { currentModel: app.config.get().model, currentProvider: app.config.get().provider, onSelect: (model) => {
|
|
121
81
|
app.config.save({ model });
|
|
122
82
|
saveModelToHistory(model);
|
|
123
83
|
setViewMode('chat');
|
|
124
84
|
addMsg(`模型已切换: ${model}`);
|
|
125
|
-
}, onAddNew: () => setViewMode('init_wizard') })) : viewMode === 'init_wizard' ? (
|
|
85
|
+
}, onAddNew: () => setViewMode('init_wizard') })) : viewMode === 'init_wizard' ? (
|
|
86
|
+
// v3.0.1: InitWizard is now fully self-contained — it owns its own
|
|
87
|
+
// input handling via useInput + ink-text-input. No external UserInput
|
|
88
|
+
// is rendered here, and app.tsx no longer has the text-entry
|
|
89
|
+
// viewModes (init_key / init_url / init_custom_model) because they
|
|
90
|
+
// were the broken input-handling path that left users stuck on a
|
|
91
|
+
// frozen "输入 API Key" screen with no way to type.
|
|
92
|
+
_jsx(InitWizard, { onComplete: (provider, model, apiKey, baseUrl) => {
|
|
126
93
|
app.config.save({ provider, model, apiKey, baseUrl });
|
|
127
94
|
saveModelToHistory(model);
|
|
128
95
|
setViewMode('chat');
|
|
129
96
|
addMsg(`配置完成: ${provider} / ${model}`);
|
|
130
|
-
}, onCancel: () => setViewMode('chat') })) : (
|
|
97
|
+
}, onCancel: () => setViewMode('chat') })) : (_jsx(Box, { flexDirection: "column", children: _jsx(UserInput, { onSubmit: onSubmit, onCancel: cancel, disabled: false }) })), _jsx(StatusBar, { messageCount: allMessages.length, skills: activeSkills })] }));
|
|
131
98
|
}
|
|
132
99
|
//# sourceMappingURL=app.js.map
|
package/dist/tui/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/tui/app.tsx"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,OAAc,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/tui/app.tsx"],"names":[],"mappings":"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"}
|
|
@@ -6,17 +6,26 @@ interface Props {
|
|
|
6
6
|
onComplete: (provider: ProviderName, model: string, apiKey: string, baseUrl?: string) => void;
|
|
7
7
|
onCancel: () => void;
|
|
8
8
|
}
|
|
9
|
-
type InitStep = 'provider' | '
|
|
9
|
+
type InitStep = 'provider' | 'custom_url' | 'api_key' | 'model' | 'custom_model' | 'cache_strategy' | 'cache_ttl';
|
|
10
10
|
/**
|
|
11
|
-
* v3.0.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* v3.0.1: InitWizard is now fully self-contained — it manages its own
|
|
12
|
+
* step state AND its own keyboard input for text-entry steps (api_key,
|
|
13
|
+
* custom_url, custom_model). The previous version had a fatal bug:
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* The text-entry steps (`api_key`, `custom_url`, `custom_model`) only
|
|
16
|
+
* rendered a `<Text>` prompt with no actual input box. The host
|
|
17
|
+
* component (app.tsx) had its own UserInput BUT only rendered it when
|
|
18
|
+
* viewMode was NOT 'init_wizard' (see app.tsx ternary). So when the
|
|
19
|
+
* wizard's internal step advanced to 'api_key', the user could SEE the
|
|
20
|
+
* "输入 API Key: 服务商: deepseek" prompt but had NO way to type into
|
|
21
|
+
* it. Ink silently swallowed keystrokes (no useInput handler was
|
|
22
|
+
* active), and the user was stuck on a frozen screen — exactly the
|
|
23
|
+
* bug that prompted the user-reported "选择 deepseek 然后退出":
|
|
24
|
+
* pressing Ctrl+C felt like the only escape.
|
|
25
|
+
*
|
|
26
|
+
* Fix: this file now uses `useInput` and `ink-text-input` for the text
|
|
27
|
+
* steps. The SetViewMode-based input delegation in app.tsx is no longer
|
|
28
|
+
* required for the InitWizard flow.
|
|
20
29
|
*/
|
|
21
30
|
export declare function InitWizard({ onComplete, onCancel }: Props): React.JSX.Element | null;
|
|
22
31
|
export type { InitStep };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InitWizard.d.ts","sourceRoot":"","sources":["../../../src/tui/components/InitWizard.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"InitWizard.d.ts","sourceRoot":"","sources":["../../../src/tui/components/InitWizard.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAAmB,MAAM,OAAO,CAAC;AAOxC,OAAO,EAAuC,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,UAAU,KAAK;IACb,UAAU,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9F,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,KAAK,QAAQ,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,cAAc,GAAG,gBAAgB,GAAG,WAAW,CAAC;AAOlH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,KAAK,4BAwNzD;AAGD,YAAY,EAAE,QAAQ,EAAE,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -1,22 +1,32 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource react */
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { Box, Text } from 'ink';
|
|
4
|
+
import { Box, Text, useInput } from 'ink';
|
|
5
5
|
import SelectInput from 'ink-select-input';
|
|
6
|
-
import
|
|
6
|
+
import TextInput from 'ink-text-input';
|
|
7
|
+
import { writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
7
8
|
import { join } from 'path';
|
|
8
9
|
import { homedir } from 'os';
|
|
9
10
|
import { listProviders, getModelsForProvider, isCustomProvider } from '../../config/providers.js';
|
|
10
11
|
/**
|
|
11
|
-
* v3.0.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* v3.0.1: InitWizard is now fully self-contained — it manages its own
|
|
13
|
+
* step state AND its own keyboard input for text-entry steps (api_key,
|
|
14
|
+
* custom_url, custom_model). The previous version had a fatal bug:
|
|
14
15
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* The text-entry steps (`api_key`, `custom_url`, `custom_model`) only
|
|
17
|
+
* rendered a `<Text>` prompt with no actual input box. The host
|
|
18
|
+
* component (app.tsx) had its own UserInput BUT only rendered it when
|
|
19
|
+
* viewMode was NOT 'init_wizard' (see app.tsx ternary). So when the
|
|
20
|
+
* wizard's internal step advanced to 'api_key', the user could SEE the
|
|
21
|
+
* "输入 API Key: 服务商: deepseek" prompt but had NO way to type into
|
|
22
|
+
* it. Ink silently swallowed keystrokes (no useInput handler was
|
|
23
|
+
* active), and the user was stuck on a frozen screen — exactly the
|
|
24
|
+
* bug that prompted the user-reported "选择 deepseek 然后退出":
|
|
25
|
+
* pressing Ctrl+C felt like the only escape.
|
|
26
|
+
*
|
|
27
|
+
* Fix: this file now uses `useInput` and `ink-text-input` for the text
|
|
28
|
+
* steps. The SetViewMode-based input delegation in app.tsx is no longer
|
|
29
|
+
* required for the InitWizard flow.
|
|
20
30
|
*/
|
|
21
31
|
export function InitWizard({ onComplete, onCancel }) {
|
|
22
32
|
const [step, setStep] = useState('provider');
|
|
@@ -39,7 +49,6 @@ export function InitWizard({ onComplete, onCancel }) {
|
|
|
39
49
|
temperature: 0.7,
|
|
40
50
|
maxTokens: 4096,
|
|
41
51
|
contextLength: 50,
|
|
42
|
-
// v3.0.0: cache policy from wizard
|
|
43
52
|
cache: {
|
|
44
53
|
enabled: cacheChoice.enabled,
|
|
45
54
|
ttl: cacheChoice.ttl,
|
|
@@ -49,26 +58,23 @@ export function InitWizard({ onComplete, onCancel }) {
|
|
|
49
58
|
if (url)
|
|
50
59
|
config.baseUrl = url;
|
|
51
60
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
52
|
-
// Save to models history
|
|
53
|
-
const historyPath = join(dir, 'models.json');
|
|
54
|
-
let history = [];
|
|
55
|
-
if (existsSync(historyPath)) {
|
|
56
|
-
try {
|
|
57
|
-
history = JSON.parse(readFileSync(historyPath, 'utf-8'));
|
|
58
|
-
}
|
|
59
|
-
catch { }
|
|
60
|
-
}
|
|
61
|
-
if (!history.includes(model)) {
|
|
62
|
-
history.push(model);
|
|
63
|
-
writeFileSync(historyPath, JSON.stringify(history, null, 2));
|
|
64
|
-
}
|
|
65
61
|
};
|
|
62
|
+
// v3.0.1: ESC cancels the wizard from any text-entry step. This is the
|
|
63
|
+
// hook that the previous version was missing — when the user pressed
|
|
64
|
+
// ESC on the frozen "输入 API Key" screen, nothing happened because no
|
|
65
|
+
// useInput was active. Now it bails out cleanly.
|
|
66
|
+
useInput((_input, key) => {
|
|
67
|
+
if (key.escape && (step === 'api_key' || step === 'custom_url' || step === 'custom_model')) {
|
|
68
|
+
onCancel();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
66
71
|
// Step 1: Provider selection
|
|
67
72
|
if (step === 'provider') {
|
|
68
73
|
const items = providers.map(p => ({ label: p.name, value: p.key }));
|
|
69
74
|
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsx(Text, { color: "#06B6D4", bold: true, children: "\u9009\u62E9\u670D\u52A1\u5546 (\u2191\u2193 \u56DE\u8F66):" }), _jsx(SelectInput, { items: items, onSelect: (item) => {
|
|
70
|
-
|
|
71
|
-
|
|
75
|
+
const provider = item.value;
|
|
76
|
+
setSelectedProvider(provider);
|
|
77
|
+
if (isCustomProvider(provider)) {
|
|
72
78
|
setStep('custom_url');
|
|
73
79
|
}
|
|
74
80
|
else {
|
|
@@ -76,13 +82,31 @@ export function InitWizard({ onComplete, onCancel }) {
|
|
|
76
82
|
}
|
|
77
83
|
} })] }));
|
|
78
84
|
}
|
|
79
|
-
// Custom URL input
|
|
85
|
+
// Custom URL input — v3.0.1 NOW has a real TextInput
|
|
80
86
|
if (step === 'custom_url') {
|
|
81
|
-
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsx(Text, { color: "#06B6D4", bold: true, children: "\u8F93\u5165\u4E2D\u8F6C\u7AD9 URL:" }), _jsx(Text, { dimColor: true, children: "\u4F8B\u5982: https://api.example.com/v1" }), _jsx(Text, { color: "#F59E0B", children: "\uFF08\u8BF7\u76F4\u63A5\u8F93\u5165 URL \u5E76\u56DE\u8F66\uFF09" })
|
|
87
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsx(Text, { color: "#06B6D4", bold: true, children: "\u8F93\u5165\u4E2D\u8F6C\u7AD9 URL:" }), _jsx(Text, { dimColor: true, children: "\u4F8B\u5982: https://api.example.com/v1" }), _jsx(Text, { color: "#F59E0B", children: "\uFF08\u8BF7\u76F4\u63A5\u8F93\u5165 URL \u5E76\u56DE\u8F66\uFF0CESC \u53D6\u6D88\uFF09" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "#06B6D4", children: "\u276F " }), _jsx(TextInput, { value: customUrl, onChange: setCustomUrl, onSubmit: (value) => {
|
|
88
|
+
if (value.trim()) {
|
|
89
|
+
setCustomUrl(value.trim());
|
|
90
|
+
setStep('api_key');
|
|
91
|
+
}
|
|
92
|
+
} })] })] }));
|
|
82
93
|
}
|
|
83
|
-
// Step 2: API Key
|
|
94
|
+
// Step 2: API Key — v3.0.1 NOW has a real TextInput
|
|
84
95
|
if (step === 'api_key') {
|
|
85
|
-
|
|
96
|
+
const providerLabel = providers.find(p => p.key === selectedProvider)?.name || selectedProvider;
|
|
97
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsx(Text, { color: "#06B6D4", bold: true, children: "\u8F93\u5165 API Key:" }), _jsxs(Text, { dimColor: true, children: ["\u670D\u52A1\u5546: ", providerLabel] }), _jsx(Text, { color: "#F59E0B", children: "\uFF08\u8BF7\u76F4\u63A5\u8F93\u5165 Key \u5E76\u56DE\u8F66\uFF0CESC \u53D6\u6D88\uFF09" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "#06B6D4", children: "\u276F " }), _jsx(TextInput, { value: apiKey, onChange: setApiKey, onSubmit: (value) => {
|
|
98
|
+
if (value.trim()) {
|
|
99
|
+
setApiKey(value.trim());
|
|
100
|
+
if (isCustomProvider(selectedProvider)) {
|
|
101
|
+
// Custom OpenAI/Anthropic: after key, go to model
|
|
102
|
+
setStep('model');
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Standard providers: skip to model selection
|
|
106
|
+
setStep('model');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} })] })] }));
|
|
86
110
|
}
|
|
87
111
|
// Step 3: Model selection
|
|
88
112
|
if (step === 'model') {
|
|
@@ -96,14 +120,18 @@ export function InitWizard({ onComplete, onCancel }) {
|
|
|
96
120
|
}
|
|
97
121
|
else {
|
|
98
122
|
setSelectedModel(item.value);
|
|
99
|
-
// v3.0.0: prompt the user for cache strategy after model.
|
|
100
123
|
setStep('cache_strategy');
|
|
101
124
|
}
|
|
102
125
|
} })] }));
|
|
103
126
|
}
|
|
104
|
-
// Custom model name
|
|
127
|
+
// Custom model name input — v3.0.1 NOW has a real TextInput
|
|
105
128
|
if (step === 'custom_model') {
|
|
106
|
-
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsx(Text, { color: "#06B6D4", bold: true, children: "\u8F93\u5165\u6A21\u578B\u540D\u79F0:" }), _jsx(Text, { color: "#F59E0B", children: "\uFF08\u8BF7\u76F4\u63A5\u8F93\u5165\u6A21\u578B\u540D\u5E76\u56DE\u8F66\uFF09" })
|
|
129
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsx(Text, { color: "#06B6D4", bold: true, children: "\u8F93\u5165\u6A21\u578B\u540D\u79F0:" }), _jsx(Text, { color: "#F59E0B", children: "\uFF08\u8BF7\u76F4\u63A5\u8F93\u5165\u6A21\u578B\u540D\u5E76\u56DE\u8F66\uFF0CESC \u53D6\u6D88\uFF09" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "#06B6D4", children: "\u276F " }), _jsx(TextInput, { value: selectedModel, onChange: setSelectedModel, onSubmit: (value) => {
|
|
130
|
+
if (value.trim()) {
|
|
131
|
+
setSelectedModel(value.trim());
|
|
132
|
+
setStep('cache_strategy');
|
|
133
|
+
}
|
|
134
|
+
} })] })] }));
|
|
107
135
|
}
|
|
108
136
|
// v3.0.0: prompt-cache strategy step
|
|
109
137
|
if (step === 'cache_strategy') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InitWizard.js","sourceRoot":"","sources":["../../../src/tui/components/InitWizard.tsx"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,OAAc,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"InitWizard.js","sourceRoot":"","sources":["../../../src/tui/components/InitWizard.tsx"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,WAAW,MAAM,kBAAkB,CAAC;AAC3C,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAelG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAS;IACxD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAW,UAAU,CAAC,CAAC;IACvD,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAe,aAAa,CAAC,CAAC;IACtF,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC/C,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAc,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1F,MAAM,SAAS,GAAG,aAAa,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAEtD,MAAM,UAAU,GAAG,CAAC,QAAsB,EAAE,KAAa,EAAE,GAAW,EAAE,GAAY,EAAE,EAAE;QACtF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1D,MAAM,MAAM,GAAwB;YAClC,QAAQ;YACR,KAAK;YACL,MAAM,EAAE,GAAG;YACX,WAAW,EAAE,GAAG;YAChB,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,EAAE;YACjB,KAAK,EAAE;gBACL,OAAO,EAAE,WAAW,CAAC,OAAO;gBAC5B,GAAG,EAAE,WAAW,CAAC,GAAG;gBACpB,QAAQ,EAAE,MAAM;aACjB;SACF,CAAC;QACF,IAAI,GAAG;YAAE,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC;QAC9B,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC;IAEF,uEAAuE;IACvE,qEAAqE;IACrE,qEAAqE;IACrE,iDAAiD;IACjD,QAAQ,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QACvB,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,cAAc,CAAC,EAAE,CAAC;YAC3F,QAAQ,EAAE,CAAC;QACb,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,6BAA6B;IAC7B,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACpE,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,kFAAsB,EAChD,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;wBACjB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAqB,CAAC;wBAC5C,mBAAmB,CAAC,QAAQ,CAAC,CAAC;wBAC9B,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;4BAC/B,OAAO,CAAC,YAAY,CAAC,CAAC;wBACxB,CAAC;6BAAM,CAAC;4BACN,OAAO,CAAC,SAAS,CAAC,CAAC;wBACrB,CAAC;oBACH,CAAC,GACD,IACE,CACP,CAAC;IACJ,CAAC;IAED,qDAAqD;IACrD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,0DAAkB,EAC5C,KAAC,IAAI,IAAC,QAAQ,+DAAsC,EACpD,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,wGAA8B,EACnD,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,aACf,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,wBAAU,EAC/B,KAAC,SAAS,IACR,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gCAClB,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;oCACjB,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oCAC3B,OAAO,CAAC,SAAS,CAAC,CAAC;gCACrB,CAAC;4BACH,CAAC,GACD,IACE,IACF,CACP,CAAC;IACJ,CAAC;IAED,oDAAoD;IACpD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,aAAa,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,gBAAgB,CAAC,EAAE,IAAI,IAAI,gBAAgB,CAAC;QAChG,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,4CAAmB,EAC7C,MAAC,IAAI,IAAC,QAAQ,2CAAO,aAAa,IAAQ,EAC1C,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,wGAA8B,EACnD,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,aACf,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,wBAAU,EAC/B,KAAC,SAAS,IACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,EACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gCAClB,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;oCACjB,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oCACxB,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,EAAE,CAAC;wCACvC,kDAAkD;wCAClD,OAAO,CAAC,OAAO,CAAC,CAAC;oCACnB,CAAC;yCAAM,CAAC;wCACN,8CAA8C;wCAC9C,OAAO,CAAC,OAAO,CAAC,CAAC;oCACnB,CAAC;gCACH,CAAC;4BACH,CAAC,GACD,IACE,IACF,CACP,CAAC;IACJ,CAAC;IAED,0BAA0B;IAC1B,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG;YACZ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACrE,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;SAC7C,CAAC;QACF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,4EAAqB,EAC/C,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;wBACjB,IAAI,IAAI,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;4BAChC,OAAO,CAAC,cAAc,CAAC,CAAC;wBAC1B,CAAC;6BAAM,CAAC;4BACN,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;4BAC7B,OAAO,CAAC,gBAAgB,CAAC,CAAC;wBAC5B,CAAC;oBACH,CAAC,GACD,IACE,CACP,CAAC;IACJ,CAAC;IAED,4DAA4D;IAC5D,IAAI,IAAI,KAAK,cAAc,EAAE,CAAC;QAC5B,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,4DAAe,EACzC,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,qHAA4B,EACjD,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,aACf,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,wBAAU,EAC/B,KAAC,SAAS,IACR,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gCAClB,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;oCACjB,gBAAgB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oCAC/B,OAAO,CAAC,gBAAgB,CAAC,CAAC;gCAC5B,CAAC;4BACH,CAAC,GACD,IACE,IACF,CACP,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG;YACZ,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,IAAI,EAAE;YAC9C,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,EAAE;SAC3C,CAAC;QACF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,+DAA4B,EACtD,KAAC,IAAI,IAAC,QAAQ,uJAA6D,EAC3E,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;wBACjB,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;4BACxB,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;4BAC/C,OAAO,CAAC,WAAW,CAAC,CAAC;wBACvB,CAAC;6BAAM,CAAC;4BACN,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;4BAChD,UAAU,CAAC,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,IAAI,SAAS,CAAC,CAAC;4BAC5E,UAAU,CAAC,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,IAAI,SAAS,CAAC,CAAC;wBAC9E,CAAC;oBACH,CAAC,GACD,IACE,CACP,CAAC;IACJ,CAAC;IAED,qBAAqB;IACrB,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG;YACZ,EAAE,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE;YAC3C,EAAE,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE;SAC5C,CAAC;QACF,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,WAAW,EAAE,CAAC,aACxC,KAAC,IAAI,IAAC,KAAK,EAAC,SAAS,EAAC,IAAI,iCAAkB,EAC5C,KAAC,WAAW,IACV,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;wBACjB,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,KAAoB,EAAE,CAAC,CAAC,CAAC;wBAChE,UAAU,CAAC,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,IAAI,SAAS,CAAC,CAAC;wBAC5E,UAAU,CAAC,gBAAgB,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,IAAI,SAAS,CAAC,CAAC;oBAC9E,CAAC,GACD,IACE,CACP,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAID,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/** @jsxImportSource react */
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import type { ProviderName } from '../../config/types.js';
|
|
3
4
|
interface Props {
|
|
4
5
|
currentModel: string;
|
|
6
|
+
currentProvider?: ProviderName;
|
|
5
7
|
onSelect: (model: string) => void;
|
|
6
8
|
onAddNew: () => void;
|
|
7
9
|
}
|
|
8
|
-
export declare function ModelSelector({ currentModel, onSelect, onAddNew }: Props): React.JSX.Element;
|
|
10
|
+
export declare function ModelSelector({ currentModel, currentProvider, onSelect, onAddNew }: Props): React.JSX.Element;
|
|
9
11
|
export {};
|
|
10
12
|
//# sourceMappingURL=ModelSelector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelSelector.d.ts","sourceRoot":"","sources":["../../../src/tui/components/ModelSelector.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAA8B,MAAM,OAAO,CAAC;AAOnD,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"ModelSelector.d.ts","sourceRoot":"","sources":["../../../src/tui/components/ModelSelector.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAA8B,MAAM,OAAO,CAAC;AAOnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,UAAU,KAAK;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAiED,wBAAgB,aAAa,CAAC,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,KAAK,qBA0BzF"}
|
|
@@ -6,11 +6,12 @@ import SelectInput from 'ink-select-input';
|
|
|
6
6
|
import { readFileSync, existsSync } from 'fs';
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { homedir } from 'os';
|
|
9
|
-
|
|
9
|
+
import { PROVIDERS, getModelsForProvider } from '../../config/providers.js';
|
|
10
|
+
function loadSavedModels(currentProvider) {
|
|
10
11
|
const configPath = join(homedir(), '.thatgfsj', 'config.json');
|
|
11
12
|
const models = [];
|
|
12
13
|
const seen = new Set();
|
|
13
|
-
// Load from history if exists
|
|
14
|
+
// 1. Load from history if exists
|
|
14
15
|
const historyPath = join(homedir(), '.thatgfsj', 'models.json');
|
|
15
16
|
if (existsSync(historyPath)) {
|
|
16
17
|
try {
|
|
@@ -24,7 +25,7 @@ function loadSavedModels() {
|
|
|
24
25
|
}
|
|
25
26
|
catch { }
|
|
26
27
|
}
|
|
27
|
-
// Always include current model
|
|
28
|
+
// 2. Always include current model
|
|
28
29
|
if (existsSync(configPath)) {
|
|
29
30
|
try {
|
|
30
31
|
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
@@ -35,7 +36,23 @@ function loadSavedModels() {
|
|
|
35
36
|
}
|
|
36
37
|
catch { }
|
|
37
38
|
}
|
|
38
|
-
//
|
|
39
|
+
// 3. v3.0.0 bug fix: ALWAYS include the current provider's catalog of
|
|
40
|
+
// models, otherwise users on a custom relay (mimo / one-api / etc.) who
|
|
41
|
+
// only have the current model in history see a list of 1 item and can't
|
|
42
|
+
// switch to deepseek / gpt-4o / etc. without going through init wizard.
|
|
43
|
+
// This is the model_selector "选 deepseek 然后退出" bug: the list only
|
|
44
|
+
// contained the current model, so the user pressed Enter on the wrong
|
|
45
|
+
// item (or thought the list was broken), then Ctrl+C'd out.
|
|
46
|
+
if (currentProvider && PROVIDERS[currentProvider]) {
|
|
47
|
+
const catalog = getModelsForProvider(currentProvider);
|
|
48
|
+
for (const m of catalog) {
|
|
49
|
+
if (!seen.has(m.id)) {
|
|
50
|
+
seen.add(m.id);
|
|
51
|
+
models.push({ label: m.id, value: m.id });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// 4. Universal fallbacks if user is on no history and no catalog
|
|
39
56
|
if (models.length === 0) {
|
|
40
57
|
const defaults = ['deepseek-chat', 'gpt-4o', 'mimo-v2.5-pro'];
|
|
41
58
|
for (const m of defaults) {
|
|
@@ -44,14 +61,14 @@ function loadSavedModels() {
|
|
|
44
61
|
}
|
|
45
62
|
return models;
|
|
46
63
|
}
|
|
47
|
-
export function ModelSelector({ currentModel, onSelect, onAddNew }) {
|
|
64
|
+
export function ModelSelector({ currentModel, currentProvider, onSelect, onAddNew }) {
|
|
48
65
|
const [items, setItems] = useState([]);
|
|
49
66
|
useEffect(() => {
|
|
50
|
-
const saved = loadSavedModels();
|
|
67
|
+
const saved = loadSavedModels(currentProvider);
|
|
51
68
|
// Add "add new" option at the end
|
|
52
69
|
saved.push({ label: '+ 添加新模型', value: '__add_new__' });
|
|
53
70
|
setItems(saved);
|
|
54
|
-
}, []);
|
|
71
|
+
}, [currentProvider]);
|
|
55
72
|
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Text, { color: "#06B6D4", bold: true, children: ["\u5F53\u524D\u6A21\u578B: ", currentModel] }), _jsx(Text, { dimColor: true, children: "\u9009\u62E9\u6A21\u578B (\u2191\u2193 \u56DE\u8F66):" }), _jsx(SelectInput, { items: items, onSelect: (item) => {
|
|
56
73
|
if (item.value === '__add_new__') {
|
|
57
74
|
onAddNew();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelSelector.js","sourceRoot":"","sources":["../../../src/tui/components/ModelSelector.tsx"],"names":[],"mappings":";AAAA,6BAA6B;AAC7B,OAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,WAAW,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ModelSelector.js","sourceRoot":"","sources":["../../../src/tui/components/ModelSelector.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserInput.d.ts","sourceRoot":"","sources":["../../../src/tui/components/UserInput.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,UAAU,KAAK;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"UserInput.d.ts","sourceRoot":"","sources":["../../../src/tui/components/UserInput.tsx"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,OAAO,KAAmB,MAAM,OAAO,CAAC;AAIxC,UAAU,KAAK;IACb,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,KAAK,qBA2IhE"}
|
|
@@ -37,6 +37,26 @@ export function UserInput({ onSubmit, onCancel, disabled }) {
|
|
|
37
37
|
}
|
|
38
38
|
if (key.tab || key.return) {
|
|
39
39
|
const selected = filteredCommands[selectedCmd] || filteredCommands[0];
|
|
40
|
+
// v3.0.0 bug fix: previously we set `value = selected.name + ' '` and
|
|
41
|
+
// returned, which forced the user to press Enter a SECOND time to
|
|
42
|
+
// actually execute the command. For single-word commands like
|
|
43
|
+
// /模型 /新建 /压缩 /帮助 /技能 etc. that meant: "press Enter twice
|
|
44
|
+
// to switch model", which is confusing and a reproduce-and-exit
|
|
45
|
+
// vector if the user panics and Ctrl+C's in the middle.
|
|
46
|
+
//
|
|
47
|
+
// Fix: when Enter is pressed on a command-list item, EXECUTE the
|
|
48
|
+
// command directly. If the user wants to append args (e.g. /模型
|
|
49
|
+
// <name>), they can type them after the slash. Tab still writes
|
|
50
|
+
// the name into the input so the user can append text.
|
|
51
|
+
if (key.return) {
|
|
52
|
+
setSelectedCmd(0);
|
|
53
|
+
setValue('');
|
|
54
|
+
setHistory(prev => [...prev, selected.name]);
|
|
55
|
+
setHistoryIdx(-1);
|
|
56
|
+
onSubmit(selected.name);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Tab: write the name into the input so the user can append args.
|
|
40
60
|
setValue(selected.name + ' ');
|
|
41
61
|
setSelectedCmd(0);
|
|
42
62
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserInput.js","sourceRoot":"","sources":["../../../src/tui/components/UserInput.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UserInput.js","sourceRoot":"","sources":["../../../src/tui/components/UserInput.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "thatgfsj-code",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Thatgfsj Code - AI Coding Assistant with Reasonix-style prompt caching",
|
|
5
5
|
"main": "dist/cmd/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"@types/marked-terminal": "^6.1.1",
|
|
43
43
|
"@types/node": "^20.10.0",
|
|
44
44
|
"@types/react": "^19.2.17",
|
|
45
|
+
"ink-testing-library": "^4.0.0",
|
|
45
46
|
"typescript": "^5.3.0",
|
|
46
47
|
"vitest": "^4.1.10"
|
|
47
48
|
}
|
package/src/app/index.ts
CHANGED
|
@@ -116,12 +116,21 @@ export class App {
|
|
|
116
116
|
async *streamResponse(messages?: ChatMessage[]): AsyncGenerator<StreamChunk, ChatResponse> {
|
|
117
117
|
const msgs = messages || this.session.getMessages();
|
|
118
118
|
const inner = this.llm.chatStream(msgs);
|
|
119
|
+
const debugUsage = !!process.env.GFCODE_DEBUG_USAGE;
|
|
119
120
|
let next = await inner.next();
|
|
120
121
|
while (!next.done) {
|
|
121
122
|
// Forward chunks unchanged, but capture usage into the persistent
|
|
122
123
|
// cache stats store so the TUI Header / /cache command can read it.
|
|
123
124
|
if (next.value && next.value.type === 'usage') {
|
|
124
125
|
try { this.cacheStats.record(next.value.usage); } catch { /* best-effort */ }
|
|
126
|
+
if (debugUsage) {
|
|
127
|
+
// v3.0.0 DEBUG: dump raw usage fields to stderr so the user can
|
|
128
|
+
// confirm whether the upstream provider/relay forwards cache stats.
|
|
129
|
+
// Enable with: GFCODE_DEBUG_USAGE=1 gfcode ...
|
|
130
|
+
process.stderr.write(
|
|
131
|
+
'[debug_usage] ' + JSON.stringify(next.value.usage) + '\n'
|
|
132
|
+
);
|
|
133
|
+
}
|
|
125
134
|
}
|
|
126
135
|
yield next.value;
|
|
127
136
|
next = await inner.next();
|
package/src/tui/app.tsx
CHANGED
|
@@ -12,7 +12,6 @@ import { useChat } from './hooks/useChat.js';
|
|
|
12
12
|
import { useCommands } from './hooks/useCommands.js';
|
|
13
13
|
import type { App } from '../app/index.js';
|
|
14
14
|
import type { MessageData } from './components/ChatMessage.js';
|
|
15
|
-
import type { ProviderName } from '../config/types.js';
|
|
16
15
|
import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';
|
|
17
16
|
import { join } from 'path';
|
|
18
17
|
import { homedir } from 'os';
|
|
@@ -35,15 +34,13 @@ function saveModelToHistory(model: string) {
|
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
type ViewMode = 'chat' | 'model_select' | 'init_wizard'
|
|
37
|
+
type ViewMode = 'chat' | 'model_select' | 'init_wizard';
|
|
39
38
|
|
|
40
39
|
export function TuiApp({ app }: Props) {
|
|
41
40
|
const { messages, isThinking, streaming, streamingToolCalls, queuedMessage, sendMessage, cancel } = useChat(app);
|
|
42
41
|
const { handleCommand } = useCommands(app);
|
|
43
42
|
const [systemMessages, setSystemMessages] = useState<MessageData[]>([]);
|
|
44
43
|
const [viewMode, setViewMode] = useState<ViewMode>('chat');
|
|
45
|
-
const [initProvider, setInitProvider] = useState<ProviderName>('siliconflow');
|
|
46
|
-
const [initUrl, setInitUrl] = useState('');
|
|
47
44
|
const { stdout } = useStdout();
|
|
48
45
|
const terminalWidth = stdout?.columns || 80;
|
|
49
46
|
|
|
@@ -60,41 +57,6 @@ export function TuiApp({ app }: Props) {
|
|
|
60
57
|
}, []);
|
|
61
58
|
|
|
62
59
|
const onSubmit = useCallback(async (input: string) => {
|
|
63
|
-
// Init wizard - API Key input
|
|
64
|
-
if (viewMode === 'init_key') {
|
|
65
|
-
const key = input.trim();
|
|
66
|
-
if (!key) { setViewMode('chat'); return; }
|
|
67
|
-
// Save and complete
|
|
68
|
-
const { App: AppClass } = await import('../app/index.js');
|
|
69
|
-
const cfg = app.config.get();
|
|
70
|
-
app.config.save({ provider: initProvider, apiKey: key, model: cfg.model || 'default' });
|
|
71
|
-
saveModelToHistory(cfg.model || 'default');
|
|
72
|
-
setViewMode('chat');
|
|
73
|
-
addMsg(`配置已更新: ${initProvider}`);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Init wizard - Custom URL input
|
|
78
|
-
if (viewMode === 'init_url') {
|
|
79
|
-
const url = input.trim();
|
|
80
|
-
if (!url) { setViewMode('chat'); return; }
|
|
81
|
-
setInitUrl(url);
|
|
82
|
-
setViewMode('init_key');
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Init wizard - Custom model name
|
|
87
|
-
if (viewMode === 'init_custom_model') {
|
|
88
|
-
const model = input.trim();
|
|
89
|
-
if (model) {
|
|
90
|
-
app.config.save({ model });
|
|
91
|
-
saveModelToHistory(model);
|
|
92
|
-
addMsg(`模型已切换: ${model}`);
|
|
93
|
-
}
|
|
94
|
-
setViewMode('chat');
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
60
|
// Model selector - ignore text input
|
|
99
61
|
if (viewMode === 'model_select') return;
|
|
100
62
|
|
|
@@ -125,7 +87,7 @@ export function TuiApp({ app }: Props) {
|
|
|
125
87
|
}
|
|
126
88
|
|
|
127
89
|
sendMessage(input);
|
|
128
|
-
}, [handleCommand, sendMessage, app, viewMode,
|
|
90
|
+
}, [handleCommand, sendMessage, app, viewMode, addMsg]);
|
|
129
91
|
|
|
130
92
|
const allMessages = [...systemMessages, ...messages];
|
|
131
93
|
const activeSkills = app.skills.listActive().map(s => s.id);
|
|
@@ -154,6 +116,7 @@ export function TuiApp({ app }: Props) {
|
|
|
154
116
|
{viewMode === 'model_select' ? (
|
|
155
117
|
<ModelSelector
|
|
156
118
|
currentModel={app.config.get().model}
|
|
119
|
+
currentProvider={app.config.get().provider}
|
|
157
120
|
onSelect={(model) => {
|
|
158
121
|
app.config.save({ model });
|
|
159
122
|
saveModelToHistory(model);
|
|
@@ -163,6 +126,12 @@ export function TuiApp({ app }: Props) {
|
|
|
163
126
|
onAddNew={() => setViewMode('init_wizard')}
|
|
164
127
|
/>
|
|
165
128
|
) : viewMode === 'init_wizard' ? (
|
|
129
|
+
// v3.0.1: InitWizard is now fully self-contained — it owns its own
|
|
130
|
+
// input handling via useInput + ink-text-input. No external UserInput
|
|
131
|
+
// is rendered here, and app.tsx no longer has the text-entry
|
|
132
|
+
// viewModes (init_key / init_url / init_custom_model) because they
|
|
133
|
+
// were the broken input-handling path that left users stuck on a
|
|
134
|
+
// frozen "输入 API Key" screen with no way to type.
|
|
166
135
|
<InitWizard
|
|
167
136
|
onComplete={(provider, model, apiKey, baseUrl) => {
|
|
168
137
|
app.config.save({ provider, model, apiKey, baseUrl });
|
|
@@ -174,22 +143,6 @@ export function TuiApp({ app }: Props) {
|
|
|
174
143
|
/>
|
|
175
144
|
) : (
|
|
176
145
|
<Box flexDirection="column">
|
|
177
|
-
{viewMode === 'init_key' && (
|
|
178
|
-
<Box paddingLeft={1} marginBottom={0}>
|
|
179
|
-
<Text color="#06B6D4" bold>输入 API Key: </Text>
|
|
180
|
-
<Text dimColor>({initProvider})</Text>
|
|
181
|
-
</Box>
|
|
182
|
-
)}
|
|
183
|
-
{viewMode === 'init_url' && (
|
|
184
|
-
<Box paddingLeft={1} marginBottom={0}>
|
|
185
|
-
<Text color="#06B6D4" bold>输入中转站 URL: </Text>
|
|
186
|
-
</Box>
|
|
187
|
-
)}
|
|
188
|
-
{viewMode === 'init_custom_model' && (
|
|
189
|
-
<Box paddingLeft={1} marginBottom={0}>
|
|
190
|
-
<Text color="#06B6D4" bold>输入模型名称: </Text>
|
|
191
|
-
</Box>
|
|
192
|
-
)}
|
|
193
146
|
<UserInput onSubmit={onSubmit} onCancel={cancel} disabled={false} />
|
|
194
147
|
</Box>
|
|
195
148
|
)}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** @jsxImportSource react */
|
|
2
|
-
import React, { useState
|
|
3
|
-
import { Box, Text } from 'ink';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
4
|
import SelectInput from 'ink-select-input';
|
|
5
|
-
import
|
|
5
|
+
import TextInput from 'ink-text-input';
|
|
6
|
+
import { writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
6
7
|
import { join } from 'path';
|
|
7
8
|
import { homedir } from 'os';
|
|
8
9
|
import { listProviders, getModelsForProvider, isCustomProvider } from '../../config/providers.js';
|
|
@@ -13,14 +14,7 @@ interface Props {
|
|
|
13
14
|
onCancel: () => void;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
type InitStep =
|
|
17
|
-
| 'provider'
|
|
18
|
-
| 'api_key'
|
|
19
|
-
| 'model'
|
|
20
|
-
| 'custom_model'
|
|
21
|
-
| 'custom_url'
|
|
22
|
-
| 'cache_strategy'
|
|
23
|
-
| 'cache_ttl';
|
|
17
|
+
type InitStep = 'provider' | 'custom_url' | 'api_key' | 'model' | 'custom_model' | 'cache_strategy' | 'cache_ttl';
|
|
24
18
|
|
|
25
19
|
interface CacheChoice {
|
|
26
20
|
enabled: boolean;
|
|
@@ -28,15 +22,24 @@ interface CacheChoice {
|
|
|
28
22
|
}
|
|
29
23
|
|
|
30
24
|
/**
|
|
31
|
-
* v3.0.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
25
|
+
* v3.0.1: InitWizard is now fully self-contained — it manages its own
|
|
26
|
+
* step state AND its own keyboard input for text-entry steps (api_key,
|
|
27
|
+
* custom_url, custom_model). The previous version had a fatal bug:
|
|
34
28
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
29
|
+
* The text-entry steps (`api_key`, `custom_url`, `custom_model`) only
|
|
30
|
+
* rendered a `<Text>` prompt with no actual input box. The host
|
|
31
|
+
* component (app.tsx) had its own UserInput BUT only rendered it when
|
|
32
|
+
* viewMode was NOT 'init_wizard' (see app.tsx ternary). So when the
|
|
33
|
+
* wizard's internal step advanced to 'api_key', the user could SEE the
|
|
34
|
+
* "输入 API Key: 服务商: deepseek" prompt but had NO way to type into
|
|
35
|
+
* it. Ink silently swallowed keystrokes (no useInput handler was
|
|
36
|
+
* active), and the user was stuck on a frozen screen — exactly the
|
|
37
|
+
* bug that prompted the user-reported "选择 deepseek 然后退出":
|
|
38
|
+
* pressing Ctrl+C felt like the only escape.
|
|
39
|
+
*
|
|
40
|
+
* Fix: this file now uses `useInput` and `ink-text-input` for the text
|
|
41
|
+
* steps. The SetViewMode-based input delegation in app.tsx is no longer
|
|
42
|
+
* required for the InitWizard flow.
|
|
40
43
|
*/
|
|
41
44
|
export function InitWizard({ onComplete, onCancel }: Props) {
|
|
42
45
|
const [step, setStep] = useState<InitStep>('provider');
|
|
@@ -61,7 +64,6 @@ export function InitWizard({ onComplete, onCancel }: Props) {
|
|
|
61
64
|
temperature: 0.7,
|
|
62
65
|
maxTokens: 4096,
|
|
63
66
|
contextLength: 50,
|
|
64
|
-
// v3.0.0: cache policy from wizard
|
|
65
67
|
cache: {
|
|
66
68
|
enabled: cacheChoice.enabled,
|
|
67
69
|
ttl: cacheChoice.ttl,
|
|
@@ -70,18 +72,17 @@ export function InitWizard({ onComplete, onCancel }: Props) {
|
|
|
70
72
|
};
|
|
71
73
|
if (url) config.baseUrl = url;
|
|
72
74
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
75
|
+
};
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
// v3.0.1: ESC cancels the wizard from any text-entry step. This is the
|
|
78
|
+
// hook that the previous version was missing — when the user pressed
|
|
79
|
+
// ESC on the frozen "输入 API Key" screen, nothing happened because no
|
|
80
|
+
// useInput was active. Now it bails out cleanly.
|
|
81
|
+
useInput((_input, key) => {
|
|
82
|
+
if (key.escape && (step === 'api_key' || step === 'custom_url' || step === 'custom_model')) {
|
|
83
|
+
onCancel();
|
|
79
84
|
}
|
|
80
|
-
|
|
81
|
-
history.push(model);
|
|
82
|
-
writeFileSync(historyPath, JSON.stringify(history, null, 2));
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
+
});
|
|
85
86
|
|
|
86
87
|
// Step 1: Provider selection
|
|
87
88
|
if (step === 'provider') {
|
|
@@ -92,8 +93,9 @@ export function InitWizard({ onComplete, onCancel }: Props) {
|
|
|
92
93
|
<SelectInput
|
|
93
94
|
items={items}
|
|
94
95
|
onSelect={(item) => {
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
const provider = item.value as ProviderName;
|
|
97
|
+
setSelectedProvider(provider);
|
|
98
|
+
if (isCustomProvider(provider)) {
|
|
97
99
|
setStep('custom_url');
|
|
98
100
|
} else {
|
|
99
101
|
setStep('api_key');
|
|
@@ -104,24 +106,57 @@ export function InitWizard({ onComplete, onCancel }: Props) {
|
|
|
104
106
|
);
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
// Custom URL input
|
|
109
|
+
// Custom URL input — v3.0.1 NOW has a real TextInput
|
|
108
110
|
if (step === 'custom_url') {
|
|
109
111
|
return (
|
|
110
112
|
<Box flexDirection="column" paddingLeft={1}>
|
|
111
113
|
<Text color="#06B6D4" bold>输入中转站 URL:</Text>
|
|
112
114
|
<Text dimColor>例如: https://api.example.com/v1</Text>
|
|
113
|
-
<Text color="#F59E0B">(请直接输入 URL
|
|
115
|
+
<Text color="#F59E0B">(请直接输入 URL 并回车,ESC 取消)</Text>
|
|
116
|
+
<Box marginTop={1}>
|
|
117
|
+
<Text color="#06B6D4">❯ </Text>
|
|
118
|
+
<TextInput
|
|
119
|
+
value={customUrl}
|
|
120
|
+
onChange={setCustomUrl}
|
|
121
|
+
onSubmit={(value) => {
|
|
122
|
+
if (value.trim()) {
|
|
123
|
+
setCustomUrl(value.trim());
|
|
124
|
+
setStep('api_key');
|
|
125
|
+
}
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
128
|
+
</Box>
|
|
114
129
|
</Box>
|
|
115
130
|
);
|
|
116
131
|
}
|
|
117
132
|
|
|
118
|
-
// Step 2: API Key
|
|
133
|
+
// Step 2: API Key — v3.0.1 NOW has a real TextInput
|
|
119
134
|
if (step === 'api_key') {
|
|
135
|
+
const providerLabel = providers.find(p => p.key === selectedProvider)?.name || selectedProvider;
|
|
120
136
|
return (
|
|
121
137
|
<Box flexDirection="column" paddingLeft={1}>
|
|
122
138
|
<Text color="#06B6D4" bold>输入 API Key:</Text>
|
|
123
|
-
<Text dimColor>服务商: {
|
|
124
|
-
<Text color="#F59E0B">(请直接输入 Key
|
|
139
|
+
<Text dimColor>服务商: {providerLabel}</Text>
|
|
140
|
+
<Text color="#F59E0B">(请直接输入 Key 并回车,ESC 取消)</Text>
|
|
141
|
+
<Box marginTop={1}>
|
|
142
|
+
<Text color="#06B6D4">❯ </Text>
|
|
143
|
+
<TextInput
|
|
144
|
+
value={apiKey}
|
|
145
|
+
onChange={setApiKey}
|
|
146
|
+
onSubmit={(value) => {
|
|
147
|
+
if (value.trim()) {
|
|
148
|
+
setApiKey(value.trim());
|
|
149
|
+
if (isCustomProvider(selectedProvider)) {
|
|
150
|
+
// Custom OpenAI/Anthropic: after key, go to model
|
|
151
|
+
setStep('model');
|
|
152
|
+
} else {
|
|
153
|
+
// Standard providers: skip to model selection
|
|
154
|
+
setStep('model');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}}
|
|
158
|
+
/>
|
|
159
|
+
</Box>
|
|
125
160
|
</Box>
|
|
126
161
|
);
|
|
127
162
|
}
|
|
@@ -142,7 +177,6 @@ export function InitWizard({ onComplete, onCancel }: Props) {
|
|
|
142
177
|
setStep('custom_model');
|
|
143
178
|
} else {
|
|
144
179
|
setSelectedModel(item.value);
|
|
145
|
-
// v3.0.0: prompt the user for cache strategy after model.
|
|
146
180
|
setStep('cache_strategy');
|
|
147
181
|
}
|
|
148
182
|
}}
|
|
@@ -151,12 +185,25 @@ export function InitWizard({ onComplete, onCancel }: Props) {
|
|
|
151
185
|
);
|
|
152
186
|
}
|
|
153
187
|
|
|
154
|
-
// Custom model name
|
|
188
|
+
// Custom model name input — v3.0.1 NOW has a real TextInput
|
|
155
189
|
if (step === 'custom_model') {
|
|
156
190
|
return (
|
|
157
191
|
<Box flexDirection="column" paddingLeft={1}>
|
|
158
192
|
<Text color="#06B6D4" bold>输入模型名称:</Text>
|
|
159
|
-
<Text color="#F59E0B"
|
|
193
|
+
<Text color="#F59E0B">(请直接输入模型名并回车,ESC 取消)</Text>
|
|
194
|
+
<Box marginTop={1}>
|
|
195
|
+
<Text color="#06B6D4">❯ </Text>
|
|
196
|
+
<TextInput
|
|
197
|
+
value={selectedModel}
|
|
198
|
+
onChange={setSelectedModel}
|
|
199
|
+
onSubmit={(value) => {
|
|
200
|
+
if (value.trim()) {
|
|
201
|
+
setSelectedModel(value.trim());
|
|
202
|
+
setStep('cache_strategy');
|
|
203
|
+
}
|
|
204
|
+
}}
|
|
205
|
+
/>
|
|
206
|
+
</Box>
|
|
160
207
|
</Box>
|
|
161
208
|
);
|
|
162
209
|
}
|
|
@@ -5,9 +5,12 @@ import SelectInput from 'ink-select-input';
|
|
|
5
5
|
import { readFileSync, existsSync } from 'fs';
|
|
6
6
|
import { join } from 'path';
|
|
7
7
|
import { homedir } from 'os';
|
|
8
|
+
import { PROVIDERS, getModelsForProvider } from '../../config/providers.js';
|
|
9
|
+
import type { ProviderName } from '../../config/types.js';
|
|
8
10
|
|
|
9
11
|
interface Props {
|
|
10
12
|
currentModel: string;
|
|
13
|
+
currentProvider?: ProviderName;
|
|
11
14
|
onSelect: (model: string) => void;
|
|
12
15
|
onAddNew: () => void;
|
|
13
16
|
}
|
|
@@ -17,12 +20,12 @@ interface SavedModel {
|
|
|
17
20
|
value: string;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
function loadSavedModels(): SavedModel[] {
|
|
23
|
+
function loadSavedModels(currentProvider?: ProviderName): SavedModel[] {
|
|
21
24
|
const configPath = join(homedir(), '.thatgfsj', 'config.json');
|
|
22
25
|
const models: SavedModel[] = [];
|
|
23
26
|
const seen = new Set<string>();
|
|
24
27
|
|
|
25
|
-
// Load from history if exists
|
|
28
|
+
// 1. Load from history if exists
|
|
26
29
|
const historyPath = join(homedir(), '.thatgfsj', 'models.json');
|
|
27
30
|
if (existsSync(historyPath)) {
|
|
28
31
|
try {
|
|
@@ -36,7 +39,7 @@ function loadSavedModels(): SavedModel[] {
|
|
|
36
39
|
} catch {}
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
// Always include current model
|
|
42
|
+
// 2. Always include current model
|
|
40
43
|
if (existsSync(configPath)) {
|
|
41
44
|
try {
|
|
42
45
|
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
@@ -47,7 +50,24 @@ function loadSavedModels(): SavedModel[] {
|
|
|
47
50
|
} catch {}
|
|
48
51
|
}
|
|
49
52
|
|
|
50
|
-
//
|
|
53
|
+
// 3. v3.0.0 bug fix: ALWAYS include the current provider's catalog of
|
|
54
|
+
// models, otherwise users on a custom relay (mimo / one-api / etc.) who
|
|
55
|
+
// only have the current model in history see a list of 1 item and can't
|
|
56
|
+
// switch to deepseek / gpt-4o / etc. without going through init wizard.
|
|
57
|
+
// This is the model_selector "选 deepseek 然后退出" bug: the list only
|
|
58
|
+
// contained the current model, so the user pressed Enter on the wrong
|
|
59
|
+
// item (or thought the list was broken), then Ctrl+C'd out.
|
|
60
|
+
if (currentProvider && PROVIDERS[currentProvider]) {
|
|
61
|
+
const catalog = getModelsForProvider(currentProvider);
|
|
62
|
+
for (const m of catalog) {
|
|
63
|
+
if (!seen.has(m.id)) {
|
|
64
|
+
seen.add(m.id);
|
|
65
|
+
models.push({ label: m.id, value: m.id });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 4. Universal fallbacks if user is on no history and no catalog
|
|
51
71
|
if (models.length === 0) {
|
|
52
72
|
const defaults = ['deepseek-chat', 'gpt-4o', 'mimo-v2.5-pro'];
|
|
53
73
|
for (const m of defaults) {
|
|
@@ -58,15 +78,15 @@ function loadSavedModels(): SavedModel[] {
|
|
|
58
78
|
return models;
|
|
59
79
|
}
|
|
60
80
|
|
|
61
|
-
export function ModelSelector({ currentModel, onSelect, onAddNew }: Props) {
|
|
81
|
+
export function ModelSelector({ currentModel, currentProvider, onSelect, onAddNew }: Props) {
|
|
62
82
|
const [items, setItems] = useState<SavedModel[]>([]);
|
|
63
83
|
|
|
64
84
|
useEffect(() => {
|
|
65
|
-
const saved = loadSavedModels();
|
|
85
|
+
const saved = loadSavedModels(currentProvider);
|
|
66
86
|
// Add "add new" option at the end
|
|
67
87
|
saved.push({ label: '+ 添加新模型', value: '__add_new__' });
|
|
68
88
|
setItems(saved);
|
|
69
|
-
}, []);
|
|
89
|
+
}, [currentProvider]);
|
|
70
90
|
|
|
71
91
|
return (
|
|
72
92
|
<Box flexDirection="column" paddingLeft={1}>
|
|
@@ -46,6 +46,26 @@ export function UserInput({ onSubmit, onCancel, disabled }: Props) {
|
|
|
46
46
|
}
|
|
47
47
|
if (key.tab || key.return) {
|
|
48
48
|
const selected = filteredCommands[selectedCmd] || filteredCommands[0];
|
|
49
|
+
// v3.0.0 bug fix: previously we set `value = selected.name + ' '` and
|
|
50
|
+
// returned, which forced the user to press Enter a SECOND time to
|
|
51
|
+
// actually execute the command. For single-word commands like
|
|
52
|
+
// /模型 /新建 /压缩 /帮助 /技能 etc. that meant: "press Enter twice
|
|
53
|
+
// to switch model", which is confusing and a reproduce-and-exit
|
|
54
|
+
// vector if the user panics and Ctrl+C's in the middle.
|
|
55
|
+
//
|
|
56
|
+
// Fix: when Enter is pressed on a command-list item, EXECUTE the
|
|
57
|
+
// command directly. If the user wants to append args (e.g. /模型
|
|
58
|
+
// <name>), they can type them after the slash. Tab still writes
|
|
59
|
+
// the name into the input so the user can append text.
|
|
60
|
+
if (key.return) {
|
|
61
|
+
setSelectedCmd(0);
|
|
62
|
+
setValue('');
|
|
63
|
+
setHistory(prev => [...prev, selected.name]);
|
|
64
|
+
setHistoryIdx(-1);
|
|
65
|
+
onSubmit(selected.name);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Tab: write the name into the input so the user can append args.
|
|
49
69
|
setValue(selected.name + ' ');
|
|
50
70
|
setSelectedCmd(0);
|
|
51
71
|
return;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { getModelsForProvider, PROVIDERS } from '../../src/config/providers.js';
|
|
3
|
+
|
|
4
|
+
describe('ModelSelector catalog integration', () => {
|
|
5
|
+
it('deepseek provider has deepseek-chat and deepseek-reasoner', () => {
|
|
6
|
+
const models = getModelsForProvider('deepseek');
|
|
7
|
+
const ids = models.map(m => m.id);
|
|
8
|
+
expect(ids).toContain('deepseek-chat');
|
|
9
|
+
expect(ids).toContain('deepseek-reasoner');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('siliconflow provider has Qwen models', () => {
|
|
13
|
+
const models = getModelsForProvider('siliconflow');
|
|
14
|
+
const ids = models.map(m => m.id);
|
|
15
|
+
expect(ids).toContain('Qwen/Qwen2.5-7B-Instruct');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('custom_openai provider has gpt-4o fallback', () => {
|
|
19
|
+
const models = getModelsForProvider('custom_openai');
|
|
20
|
+
const ids = models.map(m => m.id);
|
|
21
|
+
expect(ids).toContain('gpt-4o');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('all known providers have a non-empty catalog', () => {
|
|
25
|
+
const knownProviders = Object.keys(PROVIDERS);
|
|
26
|
+
for (const p of knownProviders) {
|
|
27
|
+
const models = getModelsForProvider(p as any);
|
|
28
|
+
expect(models.length, `provider ${p} should have at least one model`).toBeGreaterThan(0);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|