bingocode 1.0.13 → 1.0.15

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.
@@ -8,6 +8,7 @@ import { LogoV2 } from '../components/LogoV2/LogoV2.tsx';
8
8
  import { CondensedLogo } from '../components/LogoV2/CondensedLogo.tsx';
9
9
  import fs from 'fs';
10
10
  import path from 'path';
11
+ import os from 'os';
11
12
  import { ensureSingletonLocalServer } from '../server/ensureSingletonLocalServer.ts';
12
13
  // 新增:通用 UI 元素与顶部工具栏
13
14
  import { TopBar, BottomBar, Panel, Hint, Kbd, SecondaryMenu } from '../manager/CliMenuUi.tsx';
@@ -20,7 +21,8 @@ import { useTheme } from '../components/design-system/ThemeProvider.js';
20
21
  // 配置相关(仅使用可用接口)
21
22
  import { getGlobalConfig, saveGlobalConfig } from '../utils/config.ts';
22
23
 
23
- const MARKED_FILE = path.join(process.cwd(), 'markedSessions.json');
24
+ // markedSessions 存到 ~/.claude-cli/ 固定目录,不受 cwd 影响
25
+ const MARKED_FILE = path.join(os.homedir(), '.claude-cli', 'markedSessions.json');
24
26
 
25
27
  // 固定尺寸视口(可用环境变量覆盖)
26
28
  const VIEW_W = Number(process.env.CLI_VIEW_W || 96);
@@ -182,7 +184,7 @@ export const CliMenuManager: React.FC = () => {
182
184
  (async () => {
183
185
  try {
184
186
  if (apiUrl) return;
185
- const entry = path.resolve(process.cwd(), 'src/server/index.ts');
187
+ const entry = path.resolve(import.meta.dir, '../server/index.ts');
186
188
  const handle = await ensureSingletonLocalServer({ serverEntry: entry });
187
189
  if (!mounted) { await handle.stopIfLast(); return; }
188
190
  setApiUrl(handle.baseUrl);
@@ -678,24 +680,7 @@ export const CliMenuManager: React.FC = () => {
678
680
  setSelectedHistory(null);
679
681
  setMsgsPage(0);
680
682
  } else if (item.value === '__continue') {
681
- try {
682
- const fsReq = require('fs');
683
- const pathReq = require('path');
684
- const { spawn } = require('child_process');
685
- const pkgPath = pathReq.resolve(process.cwd(), 'package.json');
686
- const pkgJson = JSON.parse(fsReq.readFileSync(pkgPath, 'utf-8'));
687
- const bins = pkgJson.bin || {};
688
- const isWin = process.platform === 'win32';
689
- let binName = isWin
690
- ? bins['claude-haha'] ? 'claude-haha' : bins['claude'] ? 'claude' : Object.keys(bins)[0]
691
- : bins['claude-linux'] ? 'claude-linux' : bins['claude'] ? 'claude' : Object.keys(bins)[0];
692
- const spawnCmd = isWin ? 'cmd' : 'sh';
693
- const spawnArgs = isWin
694
- ? ['/c', binName, '--resume', selectedHistory.id]
695
- : ['-c', `./${binName} --resume ${selectedHistory.id}`];
696
- // 静默启动继续会话
697
- resumeSession(selectedHistory.id);
698
- } catch { }
683
+ resumeSession(selectedHistory.id);
699
684
  } else if (item.value === '__delete') {
700
685
  setHistoryMenuStage('deleteConfirm');
701
686
  } else if (item.value === '__toggle_mark') {
@@ -1,93 +1,93 @@
1
- // Provider presets — loaded from providers.yaml at startup
2
- // Original work inspired by cc-switch (https://github.com/farion1231/cc-switch) by Jason Young, MIT License
3
-
4
- //@C:ID=M.PP.providerPresets;K=M;V=2.0;P=Import dependencies;D=API;M=Providers;S=ModelConfiguration
5
- import { readFileSync } from 'fs'
6
- import { fileURLToPath } from 'url'
7
- import { parse } from 'yaml'
8
- import path from 'path'
9
- import type { ApiFormat } from '../types/provider.js'
10
-
11
- //@C:ID=T.PP.ModelMapping;K=T;V=1.0;P=Define model type mappings;D=API;M=Providers;S=ModelConfiguration
12
- export type ModelMapping = {
13
- main: string
14
- haiku: string
15
- sonnet: string
16
- opus: string
17
- }
18
-
19
- //@C:ID=T.PP.ProviderField;K=T;V=1.0;P=Define per-provider field descriptor;D=API;M=Providers;S=ModelConfiguration
20
- export type ProviderField = {
21
- /** Field key: 'name' | 'apiKey' | 'baseUrl' map to top-level fields; others go into extra.<key> */
22
- key: string
23
- /** Human-readable label shown in the CLI form */
24
- label: string
25
- required?: boolean
26
- /** If true, input is masked in the terminal */
27
- secret?: boolean
28
- placeholder?: string
29
- /** Default value pre-filled in the form */
30
- default?: string
31
- }
32
-
33
- //@C:ID=T.PP.ProviderPreset;K=T;V=2.0;P=Define provider preset structure;D=API;M=Providers;S=ModelConfiguration
34
- export type ProviderPreset = {
35
- id: string
36
- name: string
37
- baseUrl: string
38
- apiFormat: ApiFormat
39
- defaultModels: ModelMapping
40
- needsApiKey: boolean
41
- websiteUrl: string
42
- /** Ordered list of fields to render when adding a new provider from this preset */
43
- fields: ProviderField[]
44
- }
45
-
46
- //@C:ID=D.PP.PROVIDER_PRESETS;K=D;V=2.0;P=Load provider presets from yaml;D=API;M=Providers;S=ModelConfiguration
47
- function loadPresetsFromYaml(): ProviderPreset[] {
48
- try {
49
- const yamlPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'providers.yaml')
50
- const raw = parse(readFileSync(yamlPath, 'utf-8')) as { presets?: ProviderPreset[] }
51
- const presets = raw?.presets
52
- if (!Array.isArray(presets) || presets.length === 0) {
53
- throw new Error('providers.yaml missing presets array')
54
- }
55
- // Ensure fields is always an array
56
- return presets.map(p => ({ ...p, fields: Array.isArray(p.fields) ? p.fields : [] }))
57
- } catch (err) {
58
- console.error('[providerPresets] Failed to load providers.yaml, falling back to defaults:', err)
59
- // Minimal fallback so the server can still start
60
- return [
61
- {
62
- id: 'official',
63
- name: 'Claude Official',
64
- baseUrl: '',
65
- apiFormat: 'anthropic',
66
- defaultModels: { main: '', haiku: '', sonnet: '', opus: '' },
67
- needsApiKey: false,
68
- websiteUrl: 'https://www.anthropic.com/claude-code',
69
- fields: [{ key: 'name', label: 'Provider 昵称', required: true }],
70
- },
71
- {
72
- id: 'custom',
73
- name: 'Custom',
74
- baseUrl: '',
75
- apiFormat: 'anthropic',
76
- defaultModels: { main: '', haiku: '', sonnet: '', opus: '' },
77
- needsApiKey: true,
78
- websiteUrl: '',
79
- fields: [
80
- { key: 'name', label: 'Provider 昵称', required: true },
81
- { key: 'baseUrl', label: 'Base URL', required: true },
82
- { key: 'apiKey', label: 'API Key', required: false, secret: true },
83
- ],
84
- },
85
- ]
86
- }
87
- }
88
-
89
- export const PROVIDER_PRESETS: ProviderPreset[] = loadPresetsFromYaml()
90
-
91
- export async function loadProviderPresets(): Promise<ProviderPreset[]> {
92
- return PROVIDER_PRESETS
93
- }
1
+ // Provider presets — loaded from providers.yaml at startup
2
+ // Original work inspired by cc-switch (https://github.com/farion1231/cc-switch) by Jason Young, MIT License
3
+
4
+ //@C:ID=M.PP.providerPresets;K=M;V=2.0;P=Import dependencies;D=API;M=Providers;S=ModelConfiguration
5
+ import { readFileSync } from 'fs'
6
+ import { fileURLToPath } from 'url'
7
+ import { parse } from 'yaml'
8
+ import path from 'path'
9
+ import type { ApiFormat } from '../types/provider.js'
10
+
11
+ //@C:ID=T.PP.ModelMapping;K=T;V=1.0;P=Define model type mappings;D=API;M=Providers;S=ModelConfiguration
12
+ export type ModelMapping = {
13
+ main: string
14
+ haiku: string
15
+ sonnet: string
16
+ opus: string
17
+ }
18
+
19
+ //@C:ID=T.PP.ProviderField;K=T;V=1.0;P=Define per-provider field descriptor;D=API;M=Providers;S=ModelConfiguration
20
+ export type ProviderField = {
21
+ /** Field key: 'name' | 'apiKey' | 'baseUrl' map to top-level fields; others go into extra.<key> */
22
+ key: string
23
+ /** Human-readable label shown in the CLI form */
24
+ label: string
25
+ required?: boolean
26
+ /** If true, input is masked in the terminal */
27
+ secret?: boolean
28
+ placeholder?: string
29
+ /** Default value pre-filled in the form */
30
+ default?: string
31
+ }
32
+
33
+ //@C:ID=T.PP.ProviderPreset;K=T;V=2.0;P=Define provider preset structure;D=API;M=Providers;S=ModelConfiguration
34
+ export type ProviderPreset = {
35
+ id: string
36
+ name: string
37
+ baseUrl: string
38
+ apiFormat: ApiFormat
39
+ defaultModels: ModelMapping
40
+ needsApiKey: boolean
41
+ websiteUrl: string
42
+ /** Ordered list of fields to render when adding a new provider from this preset */
43
+ fields: ProviderField[]
44
+ }
45
+
46
+ //@C:ID=D.PP.PROVIDER_PRESETS;K=D;V=2.0;P=Load provider presets from yaml;D=API;M=Providers;S=ModelConfiguration
47
+ function loadPresetsFromYaml(): ProviderPreset[] {
48
+ try {
49
+ const yamlPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'providers.yaml')
50
+ const raw = parse(readFileSync(yamlPath, 'utf-8')) as { presets?: ProviderPreset[] }
51
+ const presets = raw?.presets
52
+ if (!Array.isArray(presets) || presets.length === 0) {
53
+ throw new Error('providers.yaml missing presets array')
54
+ }
55
+ // Ensure fields is always an array
56
+ return presets.map(p => ({ ...p, fields: Array.isArray(p.fields) ? p.fields : [] }))
57
+ } catch (err) {
58
+ console.error('[providerPresets] Failed to load providers.yaml, falling back to defaults:', err)
59
+ // Minimal fallback so the server can still start
60
+ return [
61
+ {
62
+ id: 'official',
63
+ name: 'Claude Official',
64
+ baseUrl: '',
65
+ apiFormat: 'anthropic',
66
+ defaultModels: { main: '', haiku: '', sonnet: '', opus: '' },
67
+ needsApiKey: false,
68
+ websiteUrl: 'https://www.anthropic.com/claude-code',
69
+ fields: [{ key: 'name', label: 'Provider 昵称', required: true }],
70
+ },
71
+ {
72
+ id: 'custom',
73
+ name: 'Custom',
74
+ baseUrl: '',
75
+ apiFormat: 'anthropic',
76
+ defaultModels: { main: '', haiku: '', sonnet: '', opus: '' },
77
+ needsApiKey: true,
78
+ websiteUrl: '',
79
+ fields: [
80
+ { key: 'name', label: 'Provider 昵称', required: true },
81
+ { key: 'baseUrl', label: 'Base URL', required: true },
82
+ { key: 'apiKey', label: 'API Key', required: false, secret: true },
83
+ ],
84
+ },
85
+ ]
86
+ }
87
+ }
88
+
89
+ export const PROVIDER_PRESETS: ProviderPreset[] = loadPresetsFromYaml()
90
+
91
+ export async function loadProviderPresets(): Promise<ProviderPreset[]> {
92
+ return PROVIDER_PRESETS
93
+ }
@@ -1,145 +1,145 @@
1
- version: 2
2
-
3
- # Provider 预设配置
4
- # fields 数组声明新增时需填写的字段
5
- # key: 'name' | 'apiKey' | 'baseUrl' 直接映射到顶层字段,其余存入 extra.<key>
6
- # secret: true 时前端使用密码掩码显示
7
-
8
- presets:
9
- - id: official
10
- name: Claude Official
11
- baseUrl: ''
12
- apiFormat: anthropic
13
- needsApiKey: false
14
- websiteUrl: https://www.anthropic.com/claude-code
15
- defaultModels:
16
- main: ''
17
- haiku: ''
18
- sonnet: ''
19
- opus: ''
20
- fields:
21
- - key: name
22
- label: Provider 昵称
23
- required: true
24
- secret: false
25
- placeholder: 'e.g. Claude Official'
26
-
27
- - id: deepseek
28
- name: DeepSeek
29
- baseUrl: https://api.deepseek.com/anthropic
30
- apiFormat: anthropic
31
- needsApiKey: true
32
- websiteUrl: https://platform.deepseek.com
33
- defaultModels:
34
- main: DeepSeek-V3.2
35
- haiku: DeepSeek-V3.2
36
- sonnet: DeepSeek-V3.2
37
- opus: DeepSeek-V3.2
38
- fields:
39
- - key: name
40
- label: Provider 昵称
41
- required: true
42
- secret: false
43
- placeholder: 'e.g. My DeepSeek'
44
- - key: apiKey
45
- label: API Key
46
- required: true
47
- secret: true
48
- placeholder: 'sk-...'
49
-
50
- - id: zhipuglm
51
- name: Zhipu GLM
52
- baseUrl: https://open.bigmodel.cn/api/anthropic
53
- apiFormat: anthropic
54
- needsApiKey: true
55
- websiteUrl: https://open.bigmodel.cn
56
- defaultModels:
57
- main: glm-5
58
- haiku: glm-5
59
- sonnet: glm-5
60
- opus: glm-5
61
- fields:
62
- - key: name
63
- label: Provider 昵称
64
- required: true
65
- secret: false
66
- placeholder: 'e.g. My GLM'
67
- - key: apiKey
68
- label: API Key
69
- required: true
70
- secret: true
71
- placeholder: '智谱 API Key'
72
-
73
- - id: kimi
74
- name: Kimi
75
- baseUrl: https://api.moonshot.cn/anthropic
76
- apiFormat: anthropic
77
- needsApiKey: true
78
- websiteUrl: https://platform.moonshot.cn
79
- defaultModels:
80
- main: kimi-k2.5
81
- haiku: kimi-k2.5
82
- sonnet: kimi-k2.5
83
- opus: kimi-k2.5
84
- fields:
85
- - key: name
86
- label: Provider 昵称
87
- required: true
88
- secret: false
89
- placeholder: 'e.g. My Kimi'
90
- - key: apiKey
91
- label: API Key
92
- required: true
93
- secret: true
94
- placeholder: 'Moonshot API Key'
95
-
96
- - id: minimax
97
- name: MiniMax
98
- baseUrl: https://api.minimaxi.com/anthropic
99
- apiFormat: anthropic
100
- needsApiKey: true
101
- websiteUrl: https://platform.minimaxi.com
102
- defaultModels:
103
- main: MiniMax-M2.7
104
- haiku: MiniMax-M2.7
105
- sonnet: MiniMax-M2.7
106
- opus: MiniMax-M2.7
107
- fields:
108
- - key: name
109
- label: Provider 昵称
110
- required: true
111
- secret: false
112
- placeholder: 'e.g. My MiniMax'
113
- - key: apiKey
114
- label: API Key
115
- required: true
116
- secret: true
117
- placeholder: 'MiniMax API Key'
118
-
119
- - id: custom
120
- name: Custom
121
- baseUrl: ''
122
- apiFormat: anthropic
123
- needsApiKey: true
124
- websiteUrl: ''
125
- defaultModels:
126
- main: ''
127
- haiku: ''
128
- sonnet: ''
129
- opus: ''
130
- fields:
131
- - key: name
132
- label: Provider 昵称
133
- required: true
134
- secret: false
135
- placeholder: 'e.g. My Custom Provider'
136
- - key: baseUrl
137
- label: Base URL
138
- required: true
139
- secret: false
140
- placeholder: 'https://your-api-endpoint.com/anthropic'
141
- - key: apiKey
142
- label: API Key
143
- required: false
144
- secret: true
145
- placeholder: '(可选)API Key'
1
+ version: 2
2
+
3
+ # Provider 预设配置
4
+ # fields 数组声明新增时需填写的字段
5
+ # key: 'name' | 'apiKey' | 'baseUrl' 直接映射到顶层字段,其余存入 extra.<key>
6
+ # secret: true 时前端使用密码掩码显示
7
+
8
+ presets:
9
+ - id: official
10
+ name: Claude Official
11
+ baseUrl: ''
12
+ apiFormat: anthropic
13
+ needsApiKey: false
14
+ websiteUrl: https://www.anthropic.com/claude-code
15
+ defaultModels:
16
+ main: ''
17
+ haiku: ''
18
+ sonnet: ''
19
+ opus: ''
20
+ fields:
21
+ - key: name
22
+ label: Provider 昵称
23
+ required: true
24
+ secret: false
25
+ placeholder: 'e.g. Claude Official'
26
+
27
+ - id: deepseek
28
+ name: DeepSeek
29
+ baseUrl: https://api.deepseek.com/anthropic
30
+ apiFormat: anthropic
31
+ needsApiKey: true
32
+ websiteUrl: https://platform.deepseek.com
33
+ defaultModels:
34
+ main: DeepSeek-V3.2
35
+ haiku: DeepSeek-V3.2
36
+ sonnet: DeepSeek-V3.2
37
+ opus: DeepSeek-V3.2
38
+ fields:
39
+ - key: name
40
+ label: Provider 昵称
41
+ required: true
42
+ secret: false
43
+ placeholder: 'e.g. My DeepSeek'
44
+ - key: apiKey
45
+ label: API Key
46
+ required: true
47
+ secret: true
48
+ placeholder: 'sk-...'
49
+
50
+ - id: zhipuglm
51
+ name: Zhipu GLM
52
+ baseUrl: https://open.bigmodel.cn/api/anthropic
53
+ apiFormat: anthropic
54
+ needsApiKey: true
55
+ websiteUrl: https://open.bigmodel.cn
56
+ defaultModels:
57
+ main: glm-5
58
+ haiku: glm-5
59
+ sonnet: glm-5
60
+ opus: glm-5
61
+ fields:
62
+ - key: name
63
+ label: Provider 昵称
64
+ required: true
65
+ secret: false
66
+ placeholder: 'e.g. My GLM'
67
+ - key: apiKey
68
+ label: API Key
69
+ required: true
70
+ secret: true
71
+ placeholder: '智谱 API Key'
72
+
73
+ - id: kimi
74
+ name: Kimi
75
+ baseUrl: https://api.moonshot.cn/anthropic
76
+ apiFormat: anthropic
77
+ needsApiKey: true
78
+ websiteUrl: https://platform.moonshot.cn
79
+ defaultModels:
80
+ main: kimi-k2.5
81
+ haiku: kimi-k2.5
82
+ sonnet: kimi-k2.5
83
+ opus: kimi-k2.5
84
+ fields:
85
+ - key: name
86
+ label: Provider 昵称
87
+ required: true
88
+ secret: false
89
+ placeholder: 'e.g. My Kimi'
90
+ - key: apiKey
91
+ label: API Key
92
+ required: true
93
+ secret: true
94
+ placeholder: 'Moonshot API Key'
95
+
96
+ - id: minimax
97
+ name: MiniMax
98
+ baseUrl: https://api.minimaxi.com/anthropic
99
+ apiFormat: anthropic
100
+ needsApiKey: true
101
+ websiteUrl: https://platform.minimaxi.com
102
+ defaultModels:
103
+ main: MiniMax-M2.7
104
+ haiku: MiniMax-M2.7
105
+ sonnet: MiniMax-M2.7
106
+ opus: MiniMax-M2.7
107
+ fields:
108
+ - key: name
109
+ label: Provider 昵称
110
+ required: true
111
+ secret: false
112
+ placeholder: 'e.g. My MiniMax'
113
+ - key: apiKey
114
+ label: API Key
115
+ required: true
116
+ secret: true
117
+ placeholder: 'MiniMax API Key'
118
+
119
+ - id: custom
120
+ name: Custom
121
+ baseUrl: ''
122
+ apiFormat: openai_chat
123
+ needsApiKey: true
124
+ websiteUrl: ''
125
+ defaultModels:
126
+ main: ''
127
+ haiku: ''
128
+ sonnet: ''
129
+ opus: ''
130
+ fields:
131
+ - key: name
132
+ label: Provider 昵称
133
+ required: true
134
+ secret: false
135
+ placeholder: 'e.g. My Custom Provider'
136
+ - key: baseUrl
137
+ label: Base URL
138
+ required: true
139
+ secret: false
140
+ placeholder: 'https://your-api-endpoint.com/v1'
141
+ - key: apiKey
142
+ label: API Key
143
+ required: false
144
+ secret: true
145
+ placeholder: '(可选)API Key'