Skip to content

Commit e879d02

Browse files
committed
fix: update browser start + stop commands
1 parent bd1e95f commit e879d02

File tree

2 files changed

+191
-9
lines changed

2 files changed

+191
-9
lines changed

source/commands/browser/start.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ export default function Start({options}: Props) {
178178
return (
179179
<Callout variant="info" title="Starting Development Environment">
180180
<Text>
181-
<Spinner type="dots" /> {status}
181+
<Spinner type="dots" /> {status + '\n'}
182182
</Text>
183183
{output && (
184184
<Text dimColor>{output.split('\n').slice(-5).join('\n')}</Text>

source/commands/browser/stop.tsx

Lines changed: 190 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,201 @@
1-
import path from 'path';
2-
import {useEffect} from 'react';
3-
import {exec} from 'child_process';
1+
import React, {useEffect, useState} from 'react';
2+
import {spawn} from 'child_process';
43
import {CONFIG_DIR, REPO_URL} from '../../utils/constants.js';
4+
import path from 'path';
5+
import zod from 'zod';
6+
import {option} from 'pastel';
7+
import Spinner from 'ink-spinner';
8+
import {Text} from 'ink';
9+
import Callout from '../../components/callout.js';
10+
11+
export const description = 'Stops the development environment';
12+
13+
export const options = zod.object({
14+
verbose: zod
15+
.string()
16+
.describe(
17+
option({
18+
description: 'Enable verbose logging',
19+
alias: 'v',
20+
}),
21+
)
22+
.optional(),
23+
docker_check: zod
24+
.string()
25+
.describe(option({description: 'Verify Docker is running', alias: 'dc'}))
26+
.optional(),
27+
force: zod
28+
.boolean()
29+
.describe(
30+
option({
31+
description: 'Force stop containers and remove orphaned containers',
32+
alias: 'f',
33+
}),
34+
)
35+
.optional(),
36+
});
37+
38+
type Props = {
39+
options: zod.infer<typeof options>;
40+
};
41+
42+
function isDockerRunning(): Promise<boolean> {
43+
return new Promise(resolve => {
44+
const isRunning = spawn('docker', ['info']);
45+
isRunning.on('close', code => {
46+
resolve(code === 0);
47+
});
48+
isRunning.on('error', () => {
49+
resolve(false);
50+
});
51+
});
52+
}
553

6-
export const description = 'Stops the development server';
54+
export default function Stop({options}: Props) {
55+
const [loading, setLoading] = useState(false);
56+
const [dockerError, setDockerError] = useState(false);
57+
const [status, setStatus] = useState('');
58+
const [output, setOutput] = useState<string>('');
59+
const [stopped, setStopped] = useState(false);
760

8-
export default function Stop() {
9-
const folderName = path.basename(REPO_URL, '.git');
1061
useEffect(() => {
1162
async function stop() {
12-
console.log('🚀 Stopping Docker Compose...');
13-
exec('docker-compose down', {
63+
setLoading(true);
64+
setStatus('Checking Docker status...');
65+
66+
const dockerRunning = await isDockerRunning();
67+
if (!dockerRunning) {
68+
setDockerError(true);
69+
setLoading(false);
70+
return;
71+
}
72+
73+
setStatus(
74+
options?.force
75+
? 'Force stopping Docker Compose...'
76+
: 'Stopping Docker Compose...',
77+
);
78+
79+
const folderName = path.basename(REPO_URL, '.git');
80+
81+
// Build docker-compose command arguments
82+
const dockerCommand = 'docker-compose';
83+
let dockerArgs: string[];
84+
85+
if (options?.force) {
86+
// Use kill for force stop (sends SIGKILL)
87+
dockerArgs = ['-f', 'docker-compose.dev.yml', 'kill'];
88+
} else {
89+
// Use down for graceful stop
90+
dockerArgs = ['-f', 'docker-compose.dev.yml', 'down'];
91+
}
92+
93+
const dockerCompose = spawn(dockerCommand, dockerArgs, {
1494
cwd: path.join(CONFIG_DIR, folderName),
95+
stdio: ['pipe', 'pipe', 'pipe'], // Capture stdout and stderr
96+
env: {
97+
...process.env,
98+
ENABLE_VERBOSE_LOGGING: options?.verbose || 'false',
99+
},
100+
});
101+
102+
// Stream stdout to output state
103+
dockerCompose.stdout?.on('data', data => {
104+
const text = data.toString();
105+
setOutput(prev => prev + text);
106+
});
107+
108+
// Stream stderr to output state
109+
dockerCompose.stderr?.on('data', data => {
110+
const text = data.toString();
111+
setOutput(prev => prev + text);
112+
});
113+
114+
dockerCompose.on('close', async code => {
115+
if (code !== 0) {
116+
setDockerError(true);
117+
setLoading(false);
118+
return;
119+
}
120+
121+
// If we used kill (force), we still need to clean up with down
122+
if (options?.force) {
123+
setStatus('Cleaning up containers...');
124+
const cleanup = spawn(
125+
'docker-compose',
126+
['-f', 'docker-compose.dev.yml', 'down'],
127+
{
128+
cwd: path.join(CONFIG_DIR, folderName),
129+
env: {
130+
...process.env,
131+
ENABLE_VERBOSE_LOGGING: options?.verbose || 'false',
132+
},
133+
},
134+
);
135+
136+
cleanup.on('close', () => {
137+
setStatus('Development environment force stopped and cleaned up');
138+
setStopped(true);
139+
setLoading(false);
140+
});
141+
142+
cleanup.on('error', () => {
143+
setStatus('Development environment force stopped (cleanup failed)');
144+
setStopped(true);
145+
setLoading(false);
146+
});
147+
} else {
148+
setStatus('Development environment stopped successfully');
149+
setStopped(true);
150+
setLoading(false);
151+
}
152+
});
153+
154+
dockerCompose.on('error', error => {
155+
console.error('Error stopping Docker Compose:', error);
156+
setDockerError(true);
157+
setLoading(false);
15158
});
16159
}
17160
stop();
18161
}, []);
162+
163+
if (dockerError) {
164+
return (
165+
<Callout variant="failed" title="Stop Failed">
166+
Docker is not running or there was an error stopping the containers.
167+
</Callout>
168+
);
169+
}
170+
171+
if (loading) {
172+
return (
173+
<Callout variant="info" title="Stopping Development Environment">
174+
<Text>
175+
<Spinner type="dots" /> {status + '\n'}
176+
</Text>
177+
{output && (
178+
<Text dimColor>{output.split('\n').slice(-5).join('\n')}</Text>
179+
)}
180+
</Callout>
181+
);
182+
}
183+
184+
if (stopped) {
185+
return (
186+
<Callout variant="success" title="Development Environment Stopped">
187+
{options?.force
188+
? 'All containers have been force stopped and cleaned up successfully.'
189+
: 'All containers have been stopped successfully.'}
190+
</Callout>
191+
);
192+
}
193+
194+
return (
195+
<Callout variant="info" title="Stopping Development Environment">
196+
<Text>
197+
<Spinner type="dots" /> {status}
198+
</Text>
199+
</Callout>
200+
);
19201
}

0 commit comments

Comments
 (0)