@yivan-lab/pretty-please 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +390 -1
  2. package/bin/pls.tsx +1255 -123
  3. package/dist/bin/pls.js +1098 -103
  4. package/dist/package.json +4 -4
  5. package/dist/src/alias.d.ts +41 -0
  6. package/dist/src/alias.js +240 -0
  7. package/dist/src/chat-history.js +10 -1
  8. package/dist/src/components/Chat.js +54 -26
  9. package/dist/src/components/CodeColorizer.js +26 -20
  10. package/dist/src/components/CommandBox.js +19 -8
  11. package/dist/src/components/ConfirmationPrompt.js +2 -1
  12. package/dist/src/components/Duration.js +2 -1
  13. package/dist/src/components/InlineRenderer.js +2 -1
  14. package/dist/src/components/MarkdownDisplay.js +2 -1
  15. package/dist/src/components/MultiStepCommandGenerator.d.ts +3 -1
  16. package/dist/src/components/MultiStepCommandGenerator.js +20 -10
  17. package/dist/src/components/TableRenderer.js +2 -1
  18. package/dist/src/config.d.ts +33 -3
  19. package/dist/src/config.js +83 -34
  20. package/dist/src/mastra-agent.d.ts +1 -0
  21. package/dist/src/mastra-agent.js +3 -11
  22. package/dist/src/mastra-chat.d.ts +13 -6
  23. package/dist/src/mastra-chat.js +31 -31
  24. package/dist/src/multi-step.d.ts +23 -7
  25. package/dist/src/multi-step.js +45 -26
  26. package/dist/src/prompts.d.ts +30 -4
  27. package/dist/src/prompts.js +218 -70
  28. package/dist/src/remote-history.d.ts +63 -0
  29. package/dist/src/remote-history.js +315 -0
  30. package/dist/src/remote.d.ts +113 -0
  31. package/dist/src/remote.js +634 -0
  32. package/dist/src/shell-hook.d.ts +58 -0
  33. package/dist/src/shell-hook.js +295 -26
  34. package/dist/src/ui/theme.d.ts +60 -23
  35. package/dist/src/ui/theme.js +544 -22
  36. package/dist/src/upgrade.d.ts +41 -0
  37. package/dist/src/upgrade.js +348 -0
  38. package/dist/src/utils/console.d.ts +4 -0
  39. package/dist/src/utils/console.js +89 -17
  40. package/package.json +4 -4
  41. package/src/alias.ts +301 -0
  42. package/src/chat-history.ts +11 -1
  43. package/src/components/Chat.tsx +71 -26
  44. package/src/components/CodeColorizer.tsx +27 -19
  45. package/src/components/CommandBox.tsx +26 -8
  46. package/src/components/ConfirmationPrompt.tsx +2 -1
  47. package/src/components/Duration.tsx +2 -1
  48. package/src/components/InlineRenderer.tsx +2 -1
  49. package/src/components/MarkdownDisplay.tsx +2 -1
  50. package/src/components/MultiStepCommandGenerator.tsx +25 -11
  51. package/src/components/TableRenderer.tsx +2 -1
  52. package/src/config.ts +126 -35
  53. package/src/mastra-agent.ts +3 -12
  54. package/src/mastra-chat.ts +40 -34
  55. package/src/multi-step.ts +62 -30
  56. package/src/prompts.ts +236 -78
  57. package/src/remote-history.ts +390 -0
  58. package/src/remote.ts +800 -0
  59. package/src/shell-hook.ts +339 -26
  60. package/src/ui/theme.ts +632 -23
  61. package/src/upgrade.ts +397 -0
  62. package/src/utils/console.ts +99 -17
package/src/upgrade.ts ADDED
@@ -0,0 +1,397 @@
1
+ /**
2
+ * 版本升级模块
3
+ */
4
+ import fs from 'fs'
5
+ import os from 'os'
6
+ import path from 'path'
7
+ import https from 'https'
8
+ import http from 'http'
9
+ import { execSync, spawn } from 'child_process'
10
+ import chalk from 'chalk'
11
+ import * as console2 from './utils/console.js'
12
+ import { getCurrentTheme } from './ui/theme.js'
13
+
14
+ // 获取主题颜色
15
+ function getColors() {
16
+ const theme = getCurrentTheme()
17
+ return {
18
+ primary: theme.primary,
19
+ success: theme.success,
20
+ }
21
+ }
22
+
23
+ const REPO = 'IvanLark/pretty-please'
24
+ const UPDATE_CHECK_FILE = path.join(os.homedir(), '.please', 'update-check.json')
25
+ const CHECK_INTERVAL = 24 * 60 * 60 * 1000 // 24 小时
26
+
27
+ interface UpdateCheckCache {
28
+ lastCheck: number
29
+ latestVersion: string | null
30
+ }
31
+
32
+ /**
33
+ * 获取最新版本(通过重定向,避免 API 限制)
34
+ * 优先使用 curl(支持代理),fallback 到 https 模块
35
+ */
36
+ export async function getLatestVersion(): Promise<string | null> {
37
+ // 先尝试用 curl(支持环境变量代理)
38
+ try {
39
+ const result = execSync(
40
+ `curl -fsSI "https://github.com/${REPO}/releases/latest" 2>/dev/null | grep -i "^location:" | head -1`,
41
+ { timeout: 10000, encoding: 'utf-8' }
42
+ )
43
+ const match = result.match(/\/tag\/([^\s\r\n]+)/)
44
+ if (match) {
45
+ return match[1].trim()
46
+ }
47
+ } catch {
48
+ // curl 失败,尝试 https 模块
49
+ }
50
+
51
+ // fallback: 使用 https 模块
52
+ return new Promise((resolve) => {
53
+ const req = https.request(
54
+ `https://github.com/${REPO}/releases/latest`,
55
+ { method: 'HEAD' },
56
+ (res) => {
57
+ const location = res.headers.location
58
+ if (location) {
59
+ const match = location.match(/\/tag\/([^/]+)$/)
60
+ if (match) {
61
+ resolve(match[1])
62
+ return
63
+ }
64
+ }
65
+ resolve(null)
66
+ }
67
+ )
68
+ req.on('error', () => resolve(null))
69
+ req.setTimeout(5000, () => {
70
+ req.destroy()
71
+ resolve(null)
72
+ })
73
+ req.end()
74
+ })
75
+ }
76
+
77
+ /**
78
+ * 比较版本号
79
+ * @returns 1 if v1 > v2, -1 if v1 < v2, 0 if equal
80
+ */
81
+ export function compareVersions(v1: string, v2: string): number {
82
+ const normalize = (v: string) => v.replace(/^v/, '').split('.').map(Number)
83
+ const parts1 = normalize(v1)
84
+ const parts2 = normalize(v2)
85
+
86
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
87
+ const p1 = parts1[i] || 0
88
+ const p2 = parts2[i] || 0
89
+ if (p1 > p2) return 1
90
+ if (p1 < p2) return -1
91
+ }
92
+ return 0
93
+ }
94
+
95
+ /**
96
+ * 检测当前平台
97
+ */
98
+ export function detectPlatform(): { os: string; arch: string; artifact: string } | null {
99
+ const platform = os.platform()
100
+ const arch = os.arch()
101
+
102
+ if (platform === 'darwin') {
103
+ if (arch === 'arm64') {
104
+ return { os: 'darwin', arch: 'arm64', artifact: 'pls-darwin-arm64' }
105
+ } else if (arch === 'x64') {
106
+ return { os: 'darwin', arch: 'x64', artifact: 'pls-darwin-x64' }
107
+ }
108
+ } else if (platform === 'linux') {
109
+ if (arch === 'arm64') {
110
+ return { os: 'linux', arch: 'arm64', artifact: 'pls-linux-arm64' }
111
+ } else if (arch === 'x64') {
112
+ return { os: 'linux', arch: 'x64', artifact: 'pls-linux-x64' }
113
+ }
114
+ } else if (platform === 'win32') {
115
+ if (arch === 'x64') {
116
+ return { os: 'windows', arch: 'x64', artifact: 'pls-windows-x64.exe' }
117
+ }
118
+ }
119
+
120
+ return null
121
+ }
122
+
123
+ /**
124
+ * 获取当前可执行文件路径
125
+ */
126
+ export function getCurrentExecutablePath(): string {
127
+ return process.execPath
128
+ }
129
+
130
+ /**
131
+ * 读取更新检查缓存
132
+ */
133
+ function readUpdateCache(): UpdateCheckCache | null {
134
+ try {
135
+ if (fs.existsSync(UPDATE_CHECK_FILE)) {
136
+ const data = fs.readFileSync(UPDATE_CHECK_FILE, 'utf-8')
137
+ return JSON.parse(data)
138
+ }
139
+ } catch {
140
+ // 忽略错误
141
+ }
142
+ return null
143
+ }
144
+
145
+ /**
146
+ * 写入更新检查缓存
147
+ */
148
+ function writeUpdateCache(cache: UpdateCheckCache): void {
149
+ try {
150
+ const dir = path.dirname(UPDATE_CHECK_FILE)
151
+ if (!fs.existsSync(dir)) {
152
+ fs.mkdirSync(dir, { recursive: true })
153
+ }
154
+ fs.writeFileSync(UPDATE_CHECK_FILE, JSON.stringify(cache, null, 2))
155
+ } catch {
156
+ // 忽略错误
157
+ }
158
+ }
159
+
160
+ /**
161
+ * 检查是否有新版本(带缓存)
162
+ */
163
+ export async function checkForUpdates(
164
+ currentVersion: string,
165
+ force = false
166
+ ): Promise<{ hasUpdate: boolean; latestVersion: string | null }> {
167
+ const cache = readUpdateCache()
168
+ const now = Date.now()
169
+
170
+ // 如果不是强制检查,且缓存有效,使用缓存
171
+ if (!force && cache && now - cache.lastCheck < CHECK_INTERVAL) {
172
+ if (cache.latestVersion) {
173
+ const hasUpdate = compareVersions(cache.latestVersion, currentVersion) > 0
174
+ return { hasUpdate, latestVersion: cache.latestVersion }
175
+ }
176
+ return { hasUpdate: false, latestVersion: null }
177
+ }
178
+
179
+ // 获取最新版本
180
+ const latestVersion = await getLatestVersion()
181
+
182
+ // 更新缓存
183
+ writeUpdateCache({ lastCheck: now, latestVersion })
184
+
185
+ if (latestVersion) {
186
+ const hasUpdate = compareVersions(latestVersion, currentVersion) > 0
187
+ return { hasUpdate, latestVersion }
188
+ }
189
+
190
+ return { hasUpdate: false, latestVersion: null }
191
+ }
192
+
193
+ /**
194
+ * 显示更新提示
195
+ */
196
+ export function showUpdateNotice(currentVersion: string, latestVersion: string): void {
197
+ const colors = getColors()
198
+ // 使用简洁的单行提示,避免复杂的对齐问题
199
+ console.log('')
200
+ console2.warning(`发现新版本: ${currentVersion} → ${chalk.hex(colors.success)(latestVersion)},运行 ${chalk.hex(colors.primary)('pls upgrade')} 更新`)
201
+ }
202
+
203
+ /**
204
+ * 下载文件(使用 curl,支持代理)
205
+ */
206
+ function downloadFile(url: string, dest: string, onProgress?: (percent: number) => void): Promise<void> {
207
+ return new Promise((resolve, reject) => {
208
+ // 使用 curl 下载,支持代理和进度显示
209
+ const args = ['-fSL', '--progress-bar', '-o', dest, url]
210
+ const curl = spawn('curl', args, { stdio: ['ignore', 'pipe', 'pipe'] })
211
+
212
+ let lastPercent = 0
213
+
214
+ // curl 进度输出在 stderr
215
+ curl.stderr?.on('data', (data: Buffer) => {
216
+ const str = data.toString()
217
+ // 解析 curl 进度条输出,格式如: "### 6.2%"
218
+ const match = str.match(/(\d+\.?\d*)%/)
219
+ if (match && onProgress) {
220
+ const percent = Math.round(parseFloat(match[1]))
221
+ if (percent > lastPercent) {
222
+ lastPercent = percent
223
+ onProgress(percent)
224
+ }
225
+ }
226
+ })
227
+
228
+ curl.on('close', (code) => {
229
+ if (code === 0) {
230
+ resolve()
231
+ } else {
232
+ reject(new Error(`curl 退出码: ${code}`))
233
+ }
234
+ })
235
+
236
+ curl.on('error', (err) => {
237
+ reject(err)
238
+ })
239
+ })
240
+ }
241
+
242
+ /**
243
+ * 检测是否是 Bun 编译的二进制
244
+ */
245
+ export function isBunBinary(): boolean {
246
+ const execPath = process.execPath.toLowerCase()
247
+ // npm/node 运行时,execPath 会包含 node
248
+ // tsx 开发时,execPath 会包含 node 或 tsx
249
+ // Bun 编译的二进制,execPath 就是程序自己的路径
250
+ return !execPath.includes('node') && !execPath.includes('bun')
251
+ }
252
+
253
+ /**
254
+ * 执行升级
255
+ */
256
+ export async function performUpgrade(currentVersion: string): Promise<boolean> {
257
+ console.log('')
258
+ console2.title('🚀 Pretty-Please 升级')
259
+ console2.muted('━'.repeat(40))
260
+
261
+ // 检测平台
262
+ console2.info('检测系统平台...')
263
+ const platform = detectPlatform()
264
+ if (!platform) {
265
+ console2.error('不支持的平台')
266
+ return false
267
+ }
268
+ console2.success(`平台: ${platform.os} ${platform.arch}`)
269
+
270
+ // 获取最新版本
271
+ console2.info('获取最新版本...')
272
+ const latestVersion = await getLatestVersion()
273
+ if (!latestVersion) {
274
+ console2.error('无法获取最新版本')
275
+ return false
276
+ }
277
+
278
+ // 比较版本
279
+ if (compareVersions(latestVersion, currentVersion) <= 0) {
280
+ console2.success(`当前已是最新版本 (${currentVersion})`)
281
+ console.log('')
282
+ return true
283
+ }
284
+
285
+ console2.success(`发现新版本: ${currentVersion} → ${latestVersion}`)
286
+
287
+ // 检查安装方式
288
+ if (!isBunBinary()) {
289
+ // 如果是通过 npm/node 运行的,提示使用 npm 更新
290
+ console.log('')
291
+ console2.warning('检测到你是通过 npm 安装的,请使用以下命令更新:')
292
+ console.log('')
293
+ console.log(chalk.hex(getColors().primary)(' npm update -g @yivan-lab/pretty-please'))
294
+ console.log('')
295
+ return false
296
+ }
297
+
298
+ // 获取当前可执行文件路径
299
+ const execPath = getCurrentExecutablePath()
300
+ console2.info(`当前程序: ${execPath}`)
301
+
302
+ // 下载新版本
303
+ const downloadUrl = `https://github.com/${REPO}/releases/download/${latestVersion}/${platform.artifact}`
304
+ const tempFile = path.join(os.tmpdir(), `pls-upgrade-${Date.now()}`)
305
+
306
+ console2.info('下载中...')
307
+
308
+ try {
309
+ let lastPercent = 0
310
+ await downloadFile(downloadUrl, tempFile, (percent) => {
311
+ if (percent - lastPercent >= 10 || percent === 100) {
312
+ process.stdout.write(`\r${chalk.hex(getCurrentTheme().primary)('[INFO]')} 下载中... ${percent}%`)
313
+ lastPercent = percent
314
+ }
315
+ })
316
+ console.log('') // 换行
317
+ console2.success('下载完成')
318
+ } catch (err: any) {
319
+ console2.error(`下载失败: ${err.message}`)
320
+ return false
321
+ }
322
+
323
+ // 替换当前程序
324
+ console2.info('安装新版本...')
325
+
326
+ try {
327
+ // 设置可执行权限
328
+ fs.chmodSync(tempFile, 0o755)
329
+
330
+ // 备份旧版本
331
+ const backupPath = `${execPath}.backup`
332
+ if (fs.existsSync(backupPath)) {
333
+ fs.unlinkSync(backupPath)
334
+ }
335
+
336
+ // Windows 需要特殊处理
337
+ if (platform.os === 'windows') {
338
+ // Windows 上无法替换正在运行的程序,创建一个批处理脚本
339
+ const batchScript = `@echo off
340
+ timeout /t 1 /nobreak >nul
341
+ move /y "${execPath}" "${backupPath}" >nul
342
+ move /y "${tempFile}" "${execPath}" >nul
343
+ del "${backupPath}" >nul 2>&1
344
+ echo.
345
+ echo 升级完成! ${currentVersion} → ${latestVersion}
346
+ echo.
347
+ pause
348
+ `
349
+ const batchPath = path.join(os.tmpdir(), 'pls-upgrade.bat')
350
+ fs.writeFileSync(batchPath, batchScript)
351
+
352
+ console.log('')
353
+ console2.warning('Windows 上需要额外步骤完成升级:')
354
+ console.log('')
355
+ console.log(chalk.hex(getColors().primary)(` 请运行: ${batchPath}`))
356
+ console.log('')
357
+ return true
358
+ }
359
+
360
+ // Unix 系统:直接替换
361
+ fs.renameSync(execPath, backupPath)
362
+ fs.renameSync(tempFile, execPath)
363
+
364
+ // 删除备份
365
+ try {
366
+ fs.unlinkSync(backupPath)
367
+ } catch {
368
+ // 忽略删除备份失败
369
+ }
370
+
371
+ console2.muted('━'.repeat(40))
372
+ console2.success(`升级成功: ${currentVersion} → ${latestVersion}`)
373
+ console.log('')
374
+
375
+ return true
376
+ } catch (err: any) {
377
+ console2.error(`安装失败: ${err.message}`)
378
+
379
+ // 尝试清理
380
+ try {
381
+ if (fs.existsSync(tempFile)) {
382
+ fs.unlinkSync(tempFile)
383
+ }
384
+ } catch {}
385
+
386
+ // 如果是权限问题,提示使用 sudo
387
+ if (err.code === 'EACCES' || err.code === 'EPERM') {
388
+ console.log('')
389
+ console2.warning('权限不足,请尝试使用 sudo:')
390
+ console.log('')
391
+ console.log(chalk.hex(getColors().primary)(' sudo pls upgrade'))
392
+ console.log('')
393
+ }
394
+
395
+ return false
396
+ }
397
+ }
@@ -1,21 +1,25 @@
1
1
  import chalk from 'chalk'
2
+ import { getCurrentTheme } from '../ui/theme.js'
2
3
 
3
4
  /**
4
5
  * 原生控制台输出工具函数
5
6
  * 用于不需要 Ink 的场景,避免清屏和性能问题
6
7
  */
7
8
 
8
- // 主题色
9
- const colors = {
10
- primary: '#00D9FF',
11
- secondary: '#A78BFA',
12
- accent: '#F472B6',
13
- success: '#10B981',
14
- error: '#EF4444',
15
- warning: '#F59E0B',
16
- info: '#3B82F6',
17
- muted: '#6B7280',
18
- } as const
9
+ // 获取当前主题颜色
10
+ function getColors() {
11
+ const theme = getCurrentTheme()
12
+ return {
13
+ primary: theme.primary,
14
+ secondary: theme.secondary,
15
+ accent: theme.accent,
16
+ success: theme.success,
17
+ error: theme.error,
18
+ warning: theme.warning,
19
+ info: theme.info,
20
+ muted: theme.text.muted,
21
+ }
22
+ }
19
23
 
20
24
  /**
21
25
  * 计算字符串的显示宽度(中文占2个宽度)
@@ -32,23 +36,95 @@ export function getDisplayWidth(str: string): number {
32
36
  return width
33
37
  }
34
38
 
39
+ /**
40
+ * 将长文本按指定宽度自动换行(智能分词)
41
+ */
42
+ export function wrapText(text: string, maxWidth: number): string[] {
43
+ if (getDisplayWidth(text) <= maxWidth) {
44
+ return [text]
45
+ }
46
+
47
+ const lines: string[] = []
48
+ const words = text.split(' ')
49
+ let currentLine = ''
50
+
51
+ for (const word of words) {
52
+ const testLine = currentLine ? `${currentLine} ${word}` : word
53
+ const testWidth = getDisplayWidth(testLine)
54
+
55
+ if (testWidth <= maxWidth) {
56
+ currentLine = testLine
57
+ } else {
58
+ // 如果当前行有内容,先保存
59
+ if (currentLine) {
60
+ lines.push(currentLine)
61
+ currentLine = word
62
+ } else {
63
+ // 单个单词太长,强制拆分
64
+ let remaining = word
65
+ while (remaining.length > 0) {
66
+ let chunk = ''
67
+ for (const char of remaining) {
68
+ if (getDisplayWidth(chunk + char) <= maxWidth) {
69
+ chunk += char
70
+ } else {
71
+ break
72
+ }
73
+ }
74
+ if (chunk.length === 0) {
75
+ // 防止死循环,至少取一个字符
76
+ chunk = remaining[0]
77
+ }
78
+ lines.push(chunk)
79
+ remaining = remaining.slice(chunk.length)
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ // 添加最后一行
86
+ if (currentLine) {
87
+ lines.push(currentLine)
88
+ }
89
+
90
+ return lines
91
+ }
92
+
35
93
  /**
36
94
  * 绘制命令框(原生版本)
37
95
  */
38
96
  export function drawCommandBox(command: string, title: string = '生成命令'): void {
39
- const lines = command.split('\n')
97
+ const colors = getColors()
98
+
99
+ // 获取终端宽度,限制最大宽度
100
+ const termWidth = process.stdout.columns || 80
40
101
  const titleWidth = getDisplayWidth(title)
41
- const maxContentWidth = Math.max(...lines.map((l) => getDisplayWidth(l)))
42
- const boxWidth = Math.max(maxContentWidth + 4, titleWidth + 6, 20)
102
+
103
+ // 计算最大内容宽度(终端宽度 - 边框和内边距)
104
+ const maxContentWidth = termWidth - 6 // 减去 '│ ' 和 ' │' 以及一些余量
105
+
106
+ // 处理命令换行
107
+ const originalLines = command.split('\n')
108
+ const wrappedLines: string[] = []
109
+ for (const line of originalLines) {
110
+ wrappedLines.push(...wrapText(line, maxContentWidth))
111
+ }
112
+
113
+ // 计算实际使用的宽度
114
+ const actualMaxWidth = Math.max(
115
+ ...wrappedLines.map((l) => getDisplayWidth(l)),
116
+ titleWidth
117
+ )
118
+ const boxWidth = Math.min(actualMaxWidth + 4, termWidth - 2)
43
119
 
44
120
  const topPadding = boxWidth - titleWidth - 5
45
- const topBorder = '┌─ ' + title + ' ' + '─'.repeat(topPadding) + '┐'
121
+ const topBorder = '┌─ ' + title + ' ' + '─'.repeat(Math.max(0, topPadding)) + '┐'
46
122
  const bottomBorder = '└' + '─'.repeat(boxWidth - 2) + '┘'
47
123
 
48
124
  console.log(chalk.hex(colors.warning)(topBorder))
49
- for (const line of lines) {
125
+ for (const line of wrappedLines) {
50
126
  const lineWidth = getDisplayWidth(line)
51
- const padding = ' '.repeat(boxWidth - lineWidth - 4)
127
+ const padding = ' '.repeat(Math.max(0, boxWidth - lineWidth - 4))
52
128
  console.log(
53
129
  chalk.hex(colors.warning)('│ ') + chalk.hex(colors.primary)(line) + padding + chalk.hex(colors.warning)(' │')
54
130
  )
@@ -82,6 +158,7 @@ export function printSeparator(text: string = '输出', length: number = 38): vo
82
158
  * 输出成功消息
83
159
  */
84
160
  export function success(message: string): void {
161
+ const colors = getColors()
85
162
  console.log(chalk.hex(colors.success)('✓ ' + message))
86
163
  }
87
164
 
@@ -89,6 +166,7 @@ export function success(message: string): void {
89
166
  * 输出错误消息
90
167
  */
91
168
  export function error(message: string): void {
169
+ const colors = getColors()
92
170
  console.log(chalk.hex(colors.error)('✗ ' + message))
93
171
  }
94
172
 
@@ -96,6 +174,7 @@ export function error(message: string): void {
96
174
  * 输出警告消息
97
175
  */
98
176
  export function warning(message: string): void {
177
+ const colors = getColors()
99
178
  console.log(chalk.hex(colors.warning)('⚠️ ' + message))
100
179
  }
101
180
 
@@ -103,6 +182,7 @@ export function warning(message: string): void {
103
182
  * 输出信息消息
104
183
  */
105
184
  export function info(message: string): void {
185
+ const colors = getColors()
106
186
  console.log(chalk.hex(colors.info)(message))
107
187
  }
108
188
 
@@ -110,6 +190,7 @@ export function info(message: string): void {
110
190
  * 输出灰色文本
111
191
  */
112
192
  export function muted(message: string): void {
193
+ const colors = getColors()
113
194
  console.log(chalk.hex(colors.muted)(message))
114
195
  }
115
196
 
@@ -124,5 +205,6 @@ export function title(message: string): void {
124
205
  * 输出主色文本
125
206
  */
126
207
  export function primary(message: string): void {
208
+ const colors = getColors()
127
209
  console.log(chalk.hex(colors.primary)(message))
128
210
  }