@pikecode/api-key-manager 1.0.39 → 1.0.43

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.
@@ -1,38 +1,7 @@
1
1
  const chalk = require('chalk');
2
2
 
3
3
  class UIHelper {
4
- // 颜色主题
5
- static colors = {
6
- primary: chalk.cyan,
7
- secondary: chalk.blue,
8
- success: chalk.green,
9
- warning: chalk.yellow,
10
- error: chalk.red,
11
- info: chalk.white,
12
- muted: chalk.gray,
13
- accent: chalk.magenta
14
- };
15
-
16
- // 图标
17
- static icons = {
18
- success: '✅',
19
- error: '❌',
20
- warning: '⚠️',
21
- info: 'ℹ️',
22
- loading: '⏳',
23
- arrow: '→',
24
- back: '🔙',
25
- home: '🏠',
26
- settings: '⚙️',
27
- add: '➕',
28
- edit: '✏️',
29
- delete: '🗑️',
30
- launch: '🚀',
31
- list: '📋',
32
- config: '🛠️',
33
- current: '🎯',
34
- search: '🔍'
35
- };
4
+ // 创建标题
36
5
 
37
6
  // 创建标题
38
7
  static createTitle(text, icon = '') {
@@ -47,36 +16,36 @@ class UIHelper {
47
16
 
48
17
  // 创建项目列表
49
18
  static createItem(label, value, isSelected = false) {
50
- const icon = isSelected ? this.icons.current : '•';
51
- const color = isSelected ? this.colors.primary : this.colors.info;
19
+ const icon = isSelected ? UIHelper.icons.current : '•';
20
+ const color = isSelected ? UIHelper.colors.primary : UIHelper.colors.info;
52
21
  return `${color(icon)} ${label}`;
53
22
  }
54
23
 
55
24
  // 创建操作按钮
56
25
  static createButton(label, action, icon = '') {
57
26
  const fullIcon = icon ? `${icon} ` : '';
58
- return `${this.colors.accent(fullIcon)}${this.colors.info(label)}`;
27
+ return `${UIHelper.colors.accent(fullIcon)}${UIHelper.colors.info(label)}`;
59
28
  }
60
29
 
61
30
  // 创建状态指示器
62
31
  static createStatus(status, label) {
63
32
  const statusConfig = {
64
- current: { icon: this.icons.current, color: this.colors.success },
65
- active: { icon: '🟢', color: this.colors.success },
66
- inactive: { icon: '⚫', color: this.colors.muted },
67
- loading: { icon: this.icons.loading, color: this.colors.warning },
68
- error: { icon: this.icons.error, color: this.colors.error }
33
+ current: { icon: UIHelper.icons.current, color: UIHelper.colors.success },
34
+ active: { icon: '🟢', color: UIHelper.colors.success },
35
+ inactive: { icon: '⚫', color: UIHelper.colors.muted },
36
+ loading: { icon: UIHelper.icons.loading, color: UIHelper.colors.warning },
37
+ error: { icon: UIHelper.icons.error, color: UIHelper.colors.error }
69
38
  };
70
39
 
71
40
  const config = statusConfig[status] || statusConfig.inactive;
72
- return `${config.color(config.icon)} ${this.colors.info(label)}`;
41
+ return `${config.color(config.icon)} ${UIHelper.colors.info(label)}`;
73
42
  }
74
43
 
75
44
  // 格式化供应商信息
76
45
  static formatProvider(provider) {
77
46
  const status = provider.current ? 'current' : 'inactive';
78
- const statusText = this.createStatus(status, provider.name);
79
- const displayName = this.colors.secondary(`(${provider.displayName})`);
47
+ const statusText = UIHelper.createStatus(status, provider.name);
48
+ const displayName = UIHelper.colors.secondary(`(${provider.displayName})`);
80
49
 
81
50
  return `${statusText} ${displayName}`;
82
51
  }
@@ -88,30 +57,30 @@ class UIHelper {
88
57
  const filled = '█'.repeat(progress);
89
58
  const emptySpace = '░'.repeat(empty);
90
59
  const percentage = Math.floor((current / total) * 100);
91
-
92
- return `${this.colors.primary(filled)}${this.colors.muted(emptySpace)} ${this.colors.info(percentage + '%')}`;
60
+
61
+ return `${UIHelper.colors.primary(filled)}${UIHelper.colors.muted(emptySpace)} ${UIHelper.colors.info(percentage + '%')}`;
93
62
  }
94
63
 
95
64
  // 创建表格
96
65
  static createTable(headers, rows) {
97
66
  const columnWidths = headers.map(header => Math.max(header.length, ...rows.map(row => String(row[headers.indexOf(header)]).length)));
98
-
67
+
99
68
  let result = '';
100
-
69
+
101
70
  // 表头
102
71
  const headerRow = headers.map((header, i) => header.padEnd(columnWidths[i])).join(' │ ');
103
- result += `${this.colors.primary(headerRow)}\n`;
104
-
72
+ result += `${UIHelper.colors.primary(headerRow)}\n`;
73
+
105
74
  // 分隔线
106
75
  const separator = columnWidths.map(width => '─'.repeat(width)).join('─┼─');
107
- result += `${this.colors.muted(separator)}\n`;
108
-
76
+ result += `${UIHelper.colors.muted(separator)}\n`;
77
+
109
78
  // 数据行
110
79
  rows.forEach(row => {
111
80
  const dataRow = row.map((cell, i) => String(cell).padEnd(columnWidths[i])).join(' │ ');
112
- result += `${this.colors.info(dataRow)}\n`;
81
+ result += `${UIHelper.colors.info(dataRow)}\n`;
113
82
  });
114
-
83
+
115
84
  return result;
116
85
  }
117
86
 
@@ -120,41 +89,41 @@ class UIHelper {
120
89
  const lines = content.split('\n');
121
90
  const maxLineLength = Math.max(...lines.map(line => line.length));
122
91
  const horizontalBorder = '─'.repeat(maxLineLength + 4);
123
-
124
- let result = `${this.colors.primary(`┌─${horizontalBorder}─┐`)}\n`;
125
- result += `${this.colors.primary('│')} ${chalk.bold.white(icon ? `${icon} ` : '')}${chalk.bold.white(title)}${' '.repeat(maxLineLength - title.length - (icon ? 2 : 0))} ${this.colors.primary('│')}\n`;
126
- result += `${this.colors.primary('├─')}${this.colors.muted(horizontalBorder)}${this.colors.primary('─┤')}\n`;
127
-
92
+
93
+ let result = `${UIHelper.colors.primary(`┌─${horizontalBorder}─┐`)}\n`;
94
+ result += `${UIHelper.colors.primary('│')} ${chalk.bold.white(icon ? `${icon} ` : '')}${chalk.bold.white(title)}${' '.repeat(maxLineLength - title.length - (icon ? 2 : 0))} ${UIHelper.colors.primary('│')}\n`;
95
+ result += `${UIHelper.colors.primary('├─')}${UIHelper.colors.muted(horizontalBorder)}${UIHelper.colors.primary('─┤')}\n`;
96
+
128
97
  lines.forEach(line => {
129
- result += `${this.colors.primary('│')} ${this.colors.info(line)}${' '.repeat(maxLineLength - line.length)} ${this.colors.primary('│')}\n`;
98
+ result += `${UIHelper.colors.primary('│')} ${UIHelper.colors.info(line)}${' '.repeat(maxLineLength - line.length)} ${UIHelper.colors.primary('│')}\n`;
130
99
  });
131
-
132
- result += `${this.colors.primary('└─')}${this.colors.muted(horizontalBorder)}${this.colors.primary('─┘')}`;
100
+
101
+ result += `${UIHelper.colors.primary('└─')}${UIHelper.colors.muted(horizontalBorder)}${UIHelper.colors.primary('─┘')}`;
133
102
  return result;
134
103
  }
135
104
 
136
105
  // 创建操作菜单
137
106
  static createMenu(title, options) {
138
- let result = `${this.createTitle(title, this.icons.list)}\n\n`;
139
-
107
+ let result = `${UIHelper.createTitle(title, UIHelper.icons.list)}\n\n`;
108
+
140
109
  options.forEach((option, index) => {
141
- const number = this.colors.muted(`[${index + 1}]`);
110
+ const number = UIHelper.colors.muted(`[${index + 1}]`);
142
111
  const icon = option.icon || '•';
143
- const description = option.description ? this.colors.muted(` - ${option.description}`) : '';
144
- result += `${number} ${this.colors.accent(icon)} ${this.colors.info(option.label)}${description}\n`;
112
+ const description = option.description ? UIHelper.colors.muted(` - ${option.description}`) : '';
113
+ result += `${number} ${UIHelper.colors.accent(icon)} ${UIHelper.colors.info(option.label)}${description}\n`;
145
114
  });
146
-
147
- result += `\n${this.colors.muted(this.createSeparator())}\n`;
148
- result += `${this.colors.warning('请选择操作 (输入数字): ')}`;
149
-
115
+
116
+ result += `\n${UIHelper.colors.muted(UIHelper.createSeparator())}\n`;
117
+ result += `${UIHelper.colors.warning('请选择操作 (输入数字): ')}`;
118
+
150
119
  return result;
151
120
  }
152
121
 
153
122
  // 创建确认对话框
154
123
  static createConfirmDialog(message, options = ['确认', '取消']) {
155
- return `${this.colors.warning(message)}\n\n` +
156
- `${this.colors.success('[Y]')} ${this.colors.info(options[0])} ` +
157
- `${this.colors.error('[N]')} ${this.colors.info(options[1])}`;
124
+ return `${UIHelper.colors.warning(message)}\n\n` +
125
+ `${UIHelper.colors.success('[Y]')} ${UIHelper.colors.info(options[0])} ` +
126
+ `${UIHelper.colors.error('[N]')} ${UIHelper.colors.info(options[1])}`;
158
127
  }
159
128
 
160
129
  // 格式化时间
@@ -162,32 +131,32 @@ class UIHelper {
162
131
  const date = new Date(dateString);
163
132
  const now = new Date();
164
133
  const diff = now - date;
165
-
134
+
166
135
  if (diff < 60000) return '刚刚';
167
136
  if (diff < 3600000) return `${Math.floor(diff / 60000)} 分钟前`;
168
137
  if (diff < 86400000) return `${Math.floor(diff / 3600000)} 小时前`;
169
138
  if (diff < 2592000000) return `${Math.floor(diff / 86400000)} 天前`;
170
-
139
+
171
140
  return date.toLocaleDateString('zh-CN');
172
141
  }
173
142
 
174
143
  // 创建搜索框
175
144
  static createSearchBox(placeholder = '搜索...') {
176
- return `${this.colors.info(this.icons.search)} ${this.colors.muted(placeholder)}`;
145
+ return `${UIHelper.colors.info(UIHelper.icons.search)} ${UIHelper.colors.muted(placeholder)}`;
177
146
  }
178
147
 
179
148
  // 创建提示框
180
149
  static createTooltip(text) {
181
- return `${this.colors.muted('💡 ' + text)}`;
150
+ return `${UIHelper.colors.muted('💡 ' + text)}`;
182
151
  }
183
152
 
184
153
  // 创建加载动画
185
154
  static createLoadingAnimation(text = '加载中...') {
186
155
  const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
187
156
  let frameIndex = 0;
188
-
157
+
189
158
  return setInterval(() => {
190
- process.stdout.write(`\r${this.colors.warning(frames[frameIndex])} ${this.colors.info(text)}`);
159
+ process.stdout.write(`\r${UIHelper.colors.warning(frames[frameIndex])} ${UIHelper.colors.info(text)}`);
191
160
  frameIndex = (frameIndex + 1) % frames.length;
192
161
  }, 100);
193
162
  }
@@ -200,12 +169,12 @@ class UIHelper {
200
169
 
201
170
  // 创建快捷键提示
202
171
  static createShortcutHint(key, action) {
203
- return `${this.colors.muted('[')}${this.colors.primary(key)}${this.colors.muted(']')} ${this.colors.info(action)}`;
172
+ return `${UIHelper.colors.muted('[')}${UIHelper.colors.primary(key)}${UIHelper.colors.muted(']')} ${UIHelper.colors.info(action)}`;
204
173
  }
205
174
 
206
175
  // 创建 ESC 键提示
207
176
  static createESCHint(action = '返回') {
208
- return `${this.colors.muted('[')}${this.colors.primary('ESC')}${this.colors.muted(']')} ${this.colors.info(action)}`;
177
+ return `${UIHelper.colors.muted('[')}${UIHelper.colors.primary('ESC')}${UIHelper.colors.muted(']')} ${UIHelper.colors.info(action)}`;
209
178
  }
210
179
 
211
180
  // 创建提示行
@@ -213,16 +182,49 @@ class UIHelper {
213
182
  if (!pairs.length) {
214
183
  return '';
215
184
  }
216
- const hints = pairs.map(([key, action]) => this.createShortcutHint(key, action));
217
- return `${this.colors.muted('提示: ')}${hints.join(this.colors.muted(' · '))}`;
185
+ const hints = pairs.map(([key, action]) => UIHelper.createShortcutHint(key, action));
186
+ return `${UIHelper.colors.muted('提示: ')}${hints.join(UIHelper.colors.muted(' · '))}`;
218
187
  }
219
188
 
220
189
  // 创建步骤指示
221
190
  static createStepIndicator(current, total, label) {
222
- const prefix = this.colors.muted(`步骤 ${current}/${total}`);
223
- const title = label ? ` ${this.colors.info(label)}` : '';
191
+ const prefix = UIHelper.colors.muted(`步骤 ${current}/${total}`);
192
+ const title = label ? ` ${UIHelper.colors.info(label)}` : '';
224
193
  return `${prefix}${title}`;
225
194
  }
226
195
  }
227
196
 
197
+ // 颜色主题
198
+ UIHelper.colors = {
199
+ primary: chalk.cyan,
200
+ secondary: chalk.blue,
201
+ success: chalk.green,
202
+ warning: chalk.yellow,
203
+ error: chalk.red,
204
+ info: chalk.white,
205
+ muted: chalk.gray,
206
+ accent: chalk.magenta
207
+ };
208
+
209
+ // 图标
210
+ UIHelper.icons = {
211
+ success: '✅',
212
+ error: '❌',
213
+ warning: '⚠️',
214
+ info: 'ℹ️',
215
+ loading: '⏳',
216
+ arrow: '→',
217
+ back: '🔙',
218
+ home: '🏠',
219
+ settings: '⚙️',
220
+ add: '➕',
221
+ edit: '✏️',
222
+ delete: '🗑️',
223
+ launch: '🚀',
224
+ list: '📋',
225
+ config: '🛠️',
226
+ current: '🎯',
227
+ search: '🔍'
228
+ };
229
+
228
230
  module.exports = { UIHelper };
@@ -1,7 +1,19 @@
1
+ /**
2
+ * Update Checker Utility
3
+ * 检查 npm 包更新
4
+ * @module utils/update-checker
5
+ */
6
+
1
7
  const chalk = require('chalk');
2
8
  const inquirer = require('inquirer');
3
9
  const spawn = require('cross-spawn');
4
10
 
11
+ /**
12
+ * 比较两个版本号
13
+ * @param {string} a - 版本号 A
14
+ * @param {string} b - 版本号 B
15
+ * @returns {number} -1 表示 a < b, 0 表示相等, 1 表示 a > b
16
+ */
5
17
  function compareVersions(a, b) {
6
18
  const pa = String(a).split('.').map(Number);
7
19
  const pb = String(b).split('.').map(Number);
@@ -15,16 +27,22 @@ function compareVersions(a, b) {
15
27
  return 0;
16
28
  }
17
29
 
30
+ /**
31
+ * 获取 npm 包的最新版本号
32
+ * @param {string} pkgName - 包名
33
+ * @param {number} [timeoutMs=4000] - 超时时间(毫秒)
34
+ * @returns {Promise<string|null>} 最新版本号,失败返回 null
35
+ */
18
36
  function getLatestVersion(pkgName, timeoutMs = 4000) {
19
- return new Promise((resolve, reject) => {
37
+ return new Promise((resolve, _reject) => {
20
38
  let done = false;
21
39
  const child = spawn('npm', ['view', pkgName, 'version', '--json'], {
22
40
  shell: process.platform === 'win32',
23
- stdio: ['ignore', 'pipe', 'ignore'],
41
+ stdio: ['ignore', 'pipe', 'ignore']
24
42
  });
25
43
 
26
44
  let out = '';
27
- child.stdout.on('data', (d) => (out += d.toString()))
45
+ child.stdout.on('data', (d) => (out += d.toString()));
28
46
 
29
47
  const t = setTimeout(() => {
30
48
  if (done) return;
@@ -86,8 +104,8 @@ async function checkForUpdates({ packageName, currentVersion }) {
86
104
  type: 'confirm',
87
105
  name: 'doUpdate',
88
106
  message: '是否立即更新并重启?',
89
- default: false,
90
- },
107
+ default: false
108
+ }
91
109
  ]);
92
110
 
93
111
  if (!doUpdate) return;
@@ -96,7 +114,7 @@ async function checkForUpdates({ packageName, currentVersion }) {
96
114
  await new Promise((resolve) => {
97
115
  const child = spawn('npm', ['i', '-g', `${packageName}@latest`], {
98
116
  shell: process.platform === 'win32',
99
- stdio: 'inherit',
117
+ stdio: 'inherit'
100
118
  });
101
119
  child.on('close', (code) => resolve(code === 0));
102
120
  }).then((ok) => {
@@ -113,7 +131,7 @@ async function checkForUpdates({ packageName, currentVersion }) {
113
131
 
114
132
  const child = spawn(restartCommand, restartArgs, {
115
133
  shell: process.platform === 'win32',
116
- stdio: 'inherit',
134
+ stdio: 'inherit'
117
135
  });
118
136
  child.on('close', (code) => {
119
137
  process.exit(code || 0);
@@ -15,8 +15,8 @@ const validator = {
15
15
 
16
16
  // 禁止使用保留名称 (Windows)
17
17
  const reserved = ['CON', 'PRN', 'AUX', 'NUL', 'COM1', 'COM2', 'COM3', 'COM4',
18
- 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2',
19
- 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'];
18
+ 'COM5', 'COM6', 'COM7', 'COM8', 'COM9', 'LPT1', 'LPT2',
19
+ 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9'];
20
20
  if (reserved.includes(name.toUpperCase())) {
21
21
  return '供应商名称不能使用系统保留名称';
22
22
  }
@@ -38,15 +38,15 @@ const validator = {
38
38
  if (displayName === null || displayName === undefined || displayName === '') {
39
39
  return null;
40
40
  }
41
-
41
+
42
42
  if (typeof displayName !== 'string') {
43
43
  return '显示名称必须是字符串';
44
44
  }
45
-
45
+
46
46
  if (displayName.length > 100) {
47
47
  return '显示名称不能超过100个字符';
48
48
  }
49
-
49
+
50
50
  return null;
51
51
  },
52
52
 
@@ -54,17 +54,17 @@ const validator = {
54
54
  if (!url || typeof url !== 'string') {
55
55
  return required ? 'URL不能为空' : null;
56
56
  }
57
-
57
+
58
58
  try {
59
59
  new URL(url);
60
60
  } catch (error) {
61
61
  return '请输入有效的URL';
62
62
  }
63
-
63
+
64
64
  if (!url.startsWith('http://') && !url.startsWith('https://')) {
65
65
  return 'URL必须以http://或https://开头';
66
66
  }
67
-
67
+
68
68
  return null;
69
69
  },
70
70
 
@@ -101,19 +101,19 @@ const validator = {
101
101
  if (!model) {
102
102
  return null;
103
103
  }
104
-
104
+
105
105
  if (typeof model !== 'string') {
106
106
  return '模型名称必须是字符串';
107
107
  }
108
-
108
+
109
109
  if (model.trim().length === 0) {
110
110
  return '模型名称不能为空字符串';
111
111
  }
112
-
112
+
113
113
  if (model.length > 100) {
114
114
  return '模型名称不能超过100个字符';
115
115
  }
116
-
116
+
117
117
  return null;
118
118
  },
119
119