Skip to content

Commit 06030b8

Browse files
feat: suppress package manager output during update (#104)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c3544dc commit 06030b8

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

src/__tests__/update.test.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ function mockFetchNetworkError(message: string) {
5252

5353
function mockSpawnSuccess() {
5454
mockSpawn.mockReturnValue({
55+
stderr: {
56+
on: vi.fn(),
57+
},
5558
on: vi.fn((event: string, cb: (arg?: unknown) => void) => {
5659
if (event === 'close') cb(0)
5760
}),
@@ -60,6 +63,9 @@ function mockSpawnSuccess() {
6063

6164
function mockSpawnFailure(exitCode: number) {
6265
mockSpawn.mockReturnValue({
66+
stderr: {
67+
on: vi.fn(),
68+
},
6369
on: vi.fn((event: string, cb: (arg?: unknown) => void) => {
6470
if (event === 'close') cb(exitCode)
6571
}),
@@ -68,6 +74,9 @@ function mockSpawnFailure(exitCode: number) {
6874

6975
function mockSpawnPermissionError() {
7076
mockSpawn.mockReturnValue({
77+
stderr: {
78+
on: vi.fn(),
79+
},
7180
on: vi.fn((event: string, cb: (arg?: unknown) => void) => {
7281
if (event === 'error') {
7382
const err = Object.assign(new Error('EACCES'), { code: 'EACCES' })
@@ -150,7 +159,7 @@ describe('update command', () => {
150159
expect(mockSpawn).toHaveBeenCalledWith(
151160
'npm',
152161
['install', '-g', '@doist/todoist-cli@latest'],
153-
{ stdio: 'inherit' },
162+
{ stdio: 'pipe' },
154163
)
155164
expect(consoleSpy).toHaveBeenCalledWith(
156165
expect.anything(),
@@ -169,7 +178,7 @@ describe('update command', () => {
169178
expect(mockSpawn).toHaveBeenCalledWith(
170179
'pnpm',
171180
['add', '-g', '@doist/todoist-cli@latest'],
172-
{ stdio: 'inherit' },
181+
{ stdio: 'pipe' },
173182
)
174183
})
175184
})

src/commands/update.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,20 @@ function detectPackageManager(): string {
2626
return 'npm'
2727
}
2828

29-
function runInstall(pm: string): Promise<number> {
29+
function runInstall(pm: string): Promise<{ exitCode: number; stderr: string }> {
3030
const command = pm === 'pnpm' ? 'add' : 'install'
3131
return new Promise((resolve, reject) => {
3232
const child = spawn(pm, [command, '-g', `${PACKAGE_NAME}@latest`], {
33-
stdio: 'inherit',
33+
stdio: 'pipe',
34+
})
35+
36+
let stderr = ''
37+
child.stderr?.on('data', (data: Buffer) => {
38+
stderr += data.toString()
3439
})
3540

3641
child.on('error', reject)
37-
child.on('close', (code) => resolve(code ?? 1))
42+
child.on('close', (code) => resolve({ exitCode: code ?? 1, stderr }))
3843
})
3944
}
4045

@@ -68,15 +73,13 @@ export async function updateAction(options: { check?: boolean }): Promise<void>
6873
}
6974

7075
const pm = detectPackageManager()
71-
console.log(chalk.dim(`Updating to v${latestVersion}...`))
7276

77+
let result: { exitCode: number; stderr: string }
7378
try {
74-
const exitCode = await runInstall(pm)
75-
if (exitCode !== 0) {
76-
console.error(chalk.red('Error:'), `${pm} exited with code ${exitCode}`)
77-
process.exitCode = 1
78-
return
79-
}
79+
result = await withSpinner(
80+
{ text: `Updating to v${latestVersion}...`, color: 'blue' },
81+
() => runInstall(pm),
82+
)
8083
} catch (error) {
8184
if (error instanceof Error && 'code' in error && error.code === 'EACCES') {
8285
console.error(chalk.red('Error:'), 'Permission denied. Try running with sudo:')
@@ -93,6 +96,15 @@ export async function updateAction(options: { check?: boolean }): Promise<void>
9396
return
9497
}
9598

99+
if (result.exitCode !== 0) {
100+
console.error(chalk.red('Error:'), `${pm} exited with code ${result.exitCode}`)
101+
if (result.stderr) {
102+
console.error(chalk.dim(result.stderr.trim()))
103+
}
104+
process.exitCode = 1
105+
return
106+
}
107+
96108
console.log(chalk.green('✓'), `Updated to v${latestVersion}`)
97109
}
98110

0 commit comments

Comments
 (0)