dockup-cli 1.0.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.
@@ -0,0 +1,2 @@
1
+ export declare function link(target?: string): Promise<void>;
2
+ export declare function unlink(): Promise<void>;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.link = link;
7
+ exports.unlink = unlink;
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const inquirer_1 = __importDefault(require("inquirer"));
10
+ const ora_1 = __importDefault(require("ora"));
11
+ const config_1 = require("../lib/config");
12
+ const api_1 = require("../lib/api");
13
+ async function link(target) {
14
+ if (!(0, config_1.isLoggedIn)()) {
15
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
16
+ process.exit(1);
17
+ }
18
+ const existing = (0, config_1.getProjectConfig)();
19
+ if (existing) {
20
+ console.log(chalk_1.default.yellow(`Already linked to ${existing.projectName}/${existing.serviceName}`));
21
+ const { confirm } = await inquirer_1.default.prompt([{
22
+ type: 'confirm',
23
+ name: 'confirm',
24
+ message: 'Do you want to relink to a different service?',
25
+ default: false
26
+ }]);
27
+ if (!confirm) {
28
+ return;
29
+ }
30
+ }
31
+ let projectSlug;
32
+ let serviceSlug;
33
+ let projectName;
34
+ let serviceName;
35
+ if (target) {
36
+ // Parse target: project/service
37
+ const parts = target.split('/');
38
+ if (parts.length !== 2) {
39
+ console.log(chalk_1.default.red('Invalid format. Use: dockup link <project>/<service>'));
40
+ process.exit(1);
41
+ }
42
+ [projectSlug, serviceSlug] = parts;
43
+ // Verify the service exists
44
+ const spinner = (0, ora_1.default)('Verifying service...').start();
45
+ try {
46
+ const service = await api_1.api.getServiceStatus(projectSlug, serviceSlug);
47
+ projectName = service.project?.name || projectSlug;
48
+ serviceName = service.name || serviceSlug;
49
+ spinner.succeed(`Found service: ${serviceName}`);
50
+ }
51
+ catch (error) {
52
+ spinner.fail(`Service not found: ${error.message}`);
53
+ process.exit(1);
54
+ }
55
+ }
56
+ else {
57
+ // Interactive selection
58
+ const spinner = (0, ora_1.default)('Loading projects...').start();
59
+ try {
60
+ const projects = await api_1.api.getProjects();
61
+ spinner.stop();
62
+ if (projects.length === 0) {
63
+ console.log(chalk_1.default.yellow('No projects found. Create a project first at https://app.dockup.ai'));
64
+ process.exit(1);
65
+ }
66
+ // Select project
67
+ const { selectedProject } = await inquirer_1.default.prompt([{
68
+ type: 'list',
69
+ name: 'selectedProject',
70
+ message: 'Select a project:',
71
+ choices: projects.map(p => ({
72
+ name: `${p.name} ${chalk_1.default.dim(`(${p.slug})`)}`,
73
+ value: p
74
+ }))
75
+ }]);
76
+ projectSlug = selectedProject.slug;
77
+ projectName = selectedProject.name;
78
+ // Get services for the project
79
+ spinner.start('Loading services...');
80
+ const services = await api_1.api.getServices(projectSlug);
81
+ spinner.stop();
82
+ if (services.length === 0) {
83
+ console.log(chalk_1.default.yellow('No services found in this project.'));
84
+ process.exit(1);
85
+ }
86
+ // Select service
87
+ const { selectedService } = await inquirer_1.default.prompt([{
88
+ type: 'list',
89
+ name: 'selectedService',
90
+ message: 'Select a service:',
91
+ choices: services.map(s => ({
92
+ name: `${s.name} ${chalk_1.default.dim(`(${s.slug})`)} ${s.status === 'running' ? chalk_1.default.green('●') : chalk_1.default.red('●')}`,
93
+ value: s
94
+ }))
95
+ }]);
96
+ serviceSlug = selectedService.slug;
97
+ serviceName = selectedService.name;
98
+ }
99
+ catch (error) {
100
+ spinner.fail(`Failed to load projects: ${error.message}`);
101
+ process.exit(1);
102
+ }
103
+ }
104
+ // Save config
105
+ (0, config_1.saveProjectConfig)({
106
+ projectSlug,
107
+ serviceSlug,
108
+ projectName,
109
+ serviceName
110
+ });
111
+ console.log(chalk_1.default.green(`\n✓ Linked to ${chalk_1.default.bold(projectName)}/${chalk_1.default.bold(serviceName)}`));
112
+ console.log(chalk_1.default.dim('\nYou can now run:'));
113
+ console.log(chalk_1.default.cyan(' dockup push ') + chalk_1.default.dim('- Deploy your code'));
114
+ console.log(chalk_1.default.cyan(' dockup logs ') + chalk_1.default.dim('- View live logs'));
115
+ console.log(chalk_1.default.cyan(' dockup status ') + chalk_1.default.dim('- Check service status'));
116
+ console.log();
117
+ }
118
+ async function unlink() {
119
+ const config = (0, config_1.getProjectConfig)();
120
+ if (!config) {
121
+ console.log(chalk_1.default.yellow('Not linked to any service'));
122
+ return;
123
+ }
124
+ const { confirm } = await inquirer_1.default.prompt([{
125
+ type: 'confirm',
126
+ name: 'confirm',
127
+ message: `Unlink from ${config.projectName}/${config.serviceName}?`,
128
+ default: false
129
+ }]);
130
+ if (!confirm) {
131
+ return;
132
+ }
133
+ (0, config_1.removeProjectConfig)();
134
+ console.log(chalk_1.default.green('✓ Unlinked successfully'));
135
+ }
@@ -0,0 +1,4 @@
1
+ export declare function logs(options: {
2
+ tail?: string;
3
+ follow?: boolean;
4
+ }): Promise<void>;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logs = logs;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const config_1 = require("../lib/config");
10
+ const api_1 = require("../lib/api");
11
+ async function logs(options) {
12
+ if (!(0, config_1.isLoggedIn)()) {
13
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
14
+ process.exit(1);
15
+ }
16
+ const config = (0, config_1.getProjectConfig)();
17
+ if (!config) {
18
+ console.log(chalk_1.default.red('Not linked to any service. Run `dockup link` first.'));
19
+ process.exit(1);
20
+ }
21
+ console.log(chalk_1.default.cyan(`\n Logs for ${chalk_1.default.bold(config.projectName)}/${chalk_1.default.bold(config.serviceName)}\n`));
22
+ const spinner = (0, ora_1.default)('Connecting to log stream...').start();
23
+ try {
24
+ // For now, just fetch recent logs via API
25
+ // In the future, we can add WebSocket support for real-time streaming
26
+ const service = await api_1.api.getServiceStatus(config.projectSlug, config.serviceSlug);
27
+ spinner.stop();
28
+ // Get recent deployments and their logs
29
+ const deployments = service.deployments || [];
30
+ if (deployments.length === 0) {
31
+ console.log(chalk_1.default.yellow(' No deployments found'));
32
+ return;
33
+ }
34
+ const latest = deployments[0];
35
+ console.log(chalk_1.default.dim(` Latest deployment: ${latest.id}`));
36
+ console.log(chalk_1.default.dim(` Status: ${latest.status}`));
37
+ console.log(chalk_1.default.dim(` Started: ${new Date(latest.startedAt || latest.createdAt).toLocaleString()}`));
38
+ if (latest.completedAt) {
39
+ console.log(chalk_1.default.dim(` Completed: ${new Date(latest.completedAt).toLocaleString()}`));
40
+ }
41
+ console.log(chalk_1.default.dim('\n ─────────────────────────────────────────\n'));
42
+ // If there's a build log available
43
+ if (latest.buildLog) {
44
+ const lines = latest.buildLog.split('\n');
45
+ const tailLines = parseInt(options.tail || '100', 10);
46
+ const displayLines = lines.slice(-tailLines);
47
+ for (const line of displayLines) {
48
+ // Colorize common log patterns
49
+ if (line.includes('ERROR') || line.includes('error')) {
50
+ console.log(chalk_1.default.red(` ${line}`));
51
+ }
52
+ else if (line.includes('WARN') || line.includes('warn')) {
53
+ console.log(chalk_1.default.yellow(` ${line}`));
54
+ }
55
+ else if (line.includes('SUCCESS') || line.includes('success') || line.includes('✓')) {
56
+ console.log(chalk_1.default.green(` ${line}`));
57
+ }
58
+ else if (line.startsWith('#') || line.includes('Step')) {
59
+ console.log(chalk_1.default.cyan(` ${line}`));
60
+ }
61
+ else {
62
+ console.log(chalk_1.default.dim(` ${line}`));
63
+ }
64
+ }
65
+ if (lines.length > tailLines) {
66
+ console.log(chalk_1.default.dim(`\n ... ${lines.length - tailLines} more lines (use --tail to see more)`));
67
+ }
68
+ }
69
+ else {
70
+ console.log(chalk_1.default.yellow(' No build logs available yet'));
71
+ }
72
+ console.log();
73
+ if (options.follow) {
74
+ console.log(chalk_1.default.dim(' Live log streaming coming soon...'));
75
+ console.log(chalk_1.default.dim(' Press Ctrl+C to exit\n'));
76
+ // Keep the process running for future WebSocket implementation
77
+ process.on('SIGINT', () => {
78
+ console.log(chalk_1.default.dim('\n Disconnected'));
79
+ process.exit(0);
80
+ });
81
+ // For now, just poll every 5 seconds
82
+ // setInterval(async () => {
83
+ // // Poll for new logs
84
+ // }, 5000);
85
+ }
86
+ }
87
+ catch (error) {
88
+ spinner.fail(`Failed to fetch logs: ${error.message}`);
89
+ process.exit(1);
90
+ }
91
+ }
@@ -0,0 +1,3 @@
1
+ export declare function open(options: {
2
+ dashboard?: boolean;
3
+ }): Promise<void>;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.open = open;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const open_1 = __importDefault(require("open"));
10
+ const config_1 = require("../lib/config");
11
+ const api_1 = require("../lib/api");
12
+ async function open(options) {
13
+ if (!(0, config_1.isLoggedIn)()) {
14
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
15
+ process.exit(1);
16
+ }
17
+ const config = (0, config_1.getProjectConfig)();
18
+ if (!config) {
19
+ console.log(chalk_1.default.red('Not linked to any service. Run `dockup link` first.'));
20
+ process.exit(1);
21
+ }
22
+ if (options.dashboard) {
23
+ // Open dashboard
24
+ const dashboardUrl = `${(0, config_1.getApiUrl)().replace('deploy-api', 'app')}/projects/${config.projectSlug}/services/${config.serviceSlug}`;
25
+ console.log(chalk_1.default.dim(`Opening dashboard: ${dashboardUrl}`));
26
+ await (0, open_1.default)(dashboardUrl);
27
+ return;
28
+ }
29
+ // Open live URL
30
+ const spinner = (0, ora_1.default)('Fetching service URL...').start();
31
+ try {
32
+ const service = await api_1.api.getServiceStatus(config.projectSlug, config.serviceSlug);
33
+ spinner.stop();
34
+ if (!service.domain) {
35
+ console.log(chalk_1.default.yellow('Service has no domain yet'));
36
+ process.exit(1);
37
+ }
38
+ const url = `https://${service.domain}`;
39
+ console.log(chalk_1.default.dim(`Opening: ${url}`));
40
+ await (0, open_1.default)(url);
41
+ }
42
+ catch (error) {
43
+ spinner.fail(`Failed to fetch service: ${error.message}`);
44
+ process.exit(1);
45
+ }
46
+ }
@@ -0,0 +1,2 @@
1
+ export declare function listProjects(): Promise<void>;
2
+ export declare function listServices(projectSlug?: string): Promise<void>;
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.listProjects = listProjects;
7
+ exports.listServices = listServices;
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const ora_1 = __importDefault(require("ora"));
10
+ const inquirer_1 = __importDefault(require("inquirer"));
11
+ const config_1 = require("../lib/config");
12
+ const api_1 = require("../lib/api");
13
+ async function listProjects() {
14
+ if (!(0, config_1.isLoggedIn)()) {
15
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
16
+ process.exit(1);
17
+ }
18
+ const spinner = (0, ora_1.default)('Loading projects...').start();
19
+ try {
20
+ const projects = await api_1.api.getProjects();
21
+ spinner.stop();
22
+ if (projects.length === 0) {
23
+ console.log(chalk_1.default.yellow('\n No projects found.'));
24
+ console.log(chalk_1.default.dim(' Create one at https://app.dockup.ai\n'));
25
+ return;
26
+ }
27
+ console.log(chalk_1.default.cyan('\n Your Projects:\n'));
28
+ for (const project of projects) {
29
+ const serviceCount = project.serviceCount || 0;
30
+ const dbCount = project.databaseCount || 0;
31
+ console.log(` ${chalk_1.default.bold(project.name)} ${chalk_1.default.dim(`(${project.slug})`)}`);
32
+ console.log(chalk_1.default.dim(` Services: ${serviceCount} | Databases: ${dbCount}`));
33
+ console.log();
34
+ }
35
+ console.log(chalk_1.default.dim(` Total: ${projects.length} project(s)\n`));
36
+ }
37
+ catch (error) {
38
+ spinner.fail(`Failed to load projects: ${error.message}`);
39
+ process.exit(1);
40
+ }
41
+ }
42
+ async function listServices(projectSlug) {
43
+ if (!(0, config_1.isLoggedIn)()) {
44
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
45
+ process.exit(1);
46
+ }
47
+ const spinner = (0, ora_1.default)('Loading...').start();
48
+ try {
49
+ // If no project specified, ask user to select
50
+ if (!projectSlug) {
51
+ const projects = await api_1.api.getProjects();
52
+ spinner.stop();
53
+ if (projects.length === 0) {
54
+ console.log(chalk_1.default.yellow('No projects found.'));
55
+ return;
56
+ }
57
+ const { selected } = await inquirer_1.default.prompt([{
58
+ type: 'list',
59
+ name: 'selected',
60
+ message: 'Select a project:',
61
+ choices: projects.map(p => ({
62
+ name: `${p.name} ${chalk_1.default.dim(`(${p.slug})`)}`,
63
+ value: p.slug
64
+ }))
65
+ }]);
66
+ projectSlug = selected;
67
+ spinner.start('Loading services...');
68
+ }
69
+ const services = await api_1.api.getServices(projectSlug);
70
+ spinner.stop();
71
+ if (services.length === 0) {
72
+ console.log(chalk_1.default.yellow(`\n No services in ${projectSlug}`));
73
+ return;
74
+ }
75
+ console.log(chalk_1.default.cyan(`\n Services in ${chalk_1.default.bold(projectSlug)}:\n`));
76
+ for (const service of services) {
77
+ const statusColors = {
78
+ running: chalk_1.default.green,
79
+ building: chalk_1.default.yellow,
80
+ deploying: chalk_1.default.blue,
81
+ stopped: chalk_1.default.red,
82
+ error: chalk_1.default.red,
83
+ pending: chalk_1.default.gray
84
+ };
85
+ const statusColor = statusColors[service.status] || chalk_1.default.gray;
86
+ const statusIcons = {
87
+ running: '●',
88
+ building: '◐',
89
+ deploying: '◐',
90
+ stopped: '○',
91
+ error: '✗',
92
+ pending: '○'
93
+ };
94
+ const statusIcon = statusIcons[service.status] || '?';
95
+ console.log(` ${statusColor(statusIcon)} ${chalk_1.default.bold(service.name)} ${chalk_1.default.dim(`(${service.slug})`)}`);
96
+ console.log(chalk_1.default.dim(` Status: ${service.status} | Domain: ${service.domain || 'N/A'}`));
97
+ console.log();
98
+ }
99
+ console.log(chalk_1.default.dim(` Total: ${services.length} service(s)\n`));
100
+ }
101
+ catch (error) {
102
+ spinner.fail(`Failed to load services: ${error.message}`);
103
+ process.exit(1);
104
+ }
105
+ }
@@ -0,0 +1,3 @@
1
+ export declare function push(branch?: string, options?: {
2
+ force?: boolean;
3
+ }): Promise<void>;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.push = push;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const ora_1 = __importDefault(require("ora"));
9
+ const child_process_1 = require("child_process");
10
+ const config_1 = require("../lib/config");
11
+ const api_1 = require("../lib/api");
12
+ async function push(branch, options) {
13
+ if (!(0, config_1.isLoggedIn)()) {
14
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
15
+ process.exit(1);
16
+ }
17
+ const config = (0, config_1.getProjectConfig)();
18
+ if (!config) {
19
+ console.log(chalk_1.default.red('Not linked to any service. Run `dockup link` first.'));
20
+ process.exit(1);
21
+ }
22
+ console.log(chalk_1.default.cyan(`\n Deploying to ${chalk_1.default.bold(config.projectName)}/${chalk_1.default.bold(config.serviceName)}\n`));
23
+ // Get current branch if not specified
24
+ if (!branch) {
25
+ try {
26
+ branch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
27
+ }
28
+ catch {
29
+ branch = 'main';
30
+ }
31
+ }
32
+ // Check for uncommitted changes
33
+ try {
34
+ const status = (0, child_process_1.execSync)('git status --porcelain', { encoding: 'utf-8' }).trim();
35
+ if (status) {
36
+ console.log(chalk_1.default.yellow('⚠ You have uncommitted changes:'));
37
+ console.log(chalk_1.default.dim(status.split('\n').slice(0, 5).join('\n')));
38
+ if (status.split('\n').length > 5) {
39
+ console.log(chalk_1.default.dim(` ... and ${status.split('\n').length - 5} more files`));
40
+ }
41
+ console.log();
42
+ }
43
+ }
44
+ catch {
45
+ // Not a git repo, that's fine
46
+ }
47
+ // Git push first (unless --force)
48
+ if (!options?.force) {
49
+ const gitSpinner = (0, ora_1.default)(`Pushing to origin/${branch}...`).start();
50
+ try {
51
+ (0, child_process_1.execSync)(`git push origin ${branch}`, {
52
+ encoding: 'utf-8',
53
+ stdio: ['pipe', 'pipe', 'pipe']
54
+ });
55
+ gitSpinner.succeed(`Pushed to origin/${branch}`);
56
+ }
57
+ catch (error) {
58
+ // Check if it's just "Everything up-to-date"
59
+ if (error.stderr?.includes('Everything up-to-date') || error.stdout?.includes('Everything up-to-date')) {
60
+ gitSpinner.succeed('Already up to date');
61
+ }
62
+ else {
63
+ gitSpinner.warn('Git push failed (continuing with deploy)');
64
+ console.log(chalk_1.default.dim(error.message));
65
+ }
66
+ }
67
+ }
68
+ // Trigger deployment
69
+ const deploySpinner = (0, ora_1.default)('Triggering deployment...').start();
70
+ try {
71
+ const result = await api_1.api.deploy(config.projectSlug, config.serviceSlug, { branch });
72
+ deploySpinner.succeed('Deployment started!');
73
+ console.log(chalk_1.default.dim(`\n Deployment ID: ${result.deployment?.id || 'N/A'}`));
74
+ // Poll for deployment status
75
+ console.log(chalk_1.default.cyan('\n Building...\n'));
76
+ let lastStatus = '';
77
+ let dots = 0;
78
+ const maxPolls = 120; // 2 minutes max
79
+ let polls = 0;
80
+ while (polls < maxPolls) {
81
+ polls++;
82
+ try {
83
+ const status = await api_1.api.getServiceStatus(config.projectSlug, config.serviceSlug);
84
+ const deployment = status.deployments?.[0];
85
+ if (!deployment) {
86
+ await sleep(1000);
87
+ continue;
88
+ }
89
+ const currentStatus = deployment.status;
90
+ if (currentStatus !== lastStatus) {
91
+ lastStatus = currentStatus;
92
+ if (currentStatus === 'building') {
93
+ process.stdout.write(chalk_1.default.yellow(' ⏳ Building'));
94
+ }
95
+ else if (currentStatus === 'deploying') {
96
+ process.stdout.write(chalk_1.default.blue('\n 🚀 Deploying'));
97
+ }
98
+ else if (currentStatus === 'success') {
99
+ console.log(chalk_1.default.green('\n\n ✓ Deployed successfully!\n'));
100
+ console.log(chalk_1.default.dim(' URL: ') + chalk_1.default.cyan(`https://${status.domain}`));
101
+ console.log();
102
+ return;
103
+ }
104
+ else if (currentStatus === 'failed') {
105
+ console.log(chalk_1.default.red('\n\n ✗ Deployment failed\n'));
106
+ console.log(chalk_1.default.dim(' Run `dockup logs` to see error details'));
107
+ console.log();
108
+ process.exit(1);
109
+ }
110
+ }
111
+ else {
112
+ // Show progress dots
113
+ dots++;
114
+ if (dots % 3 === 0) {
115
+ process.stdout.write('.');
116
+ }
117
+ }
118
+ await sleep(1000);
119
+ }
120
+ catch (error) {
121
+ await sleep(1000);
122
+ }
123
+ }
124
+ console.log(chalk_1.default.yellow('\n\n ⚠ Deployment is taking longer than expected'));
125
+ console.log(chalk_1.default.dim(' Run `dockup status` to check progress'));
126
+ console.log();
127
+ }
128
+ catch (error) {
129
+ deploySpinner.fail(`Deployment failed: ${error.message}`);
130
+ process.exit(1);
131
+ }
132
+ }
133
+ function sleep(ms) {
134
+ return new Promise(resolve => setTimeout(resolve, ms));
135
+ }
@@ -0,0 +1,8 @@
1
+ export declare function startService(): Promise<void>;
2
+ export declare function stopService(): Promise<void>;
3
+ export declare function restartService(): Promise<void>;
4
+ export declare function deployService(): Promise<void>;
5
+ export declare function serviceLogs(options: {
6
+ tail?: string;
7
+ follow?: boolean;
8
+ }): Promise<void>;
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startService = startService;
7
+ exports.stopService = stopService;
8
+ exports.restartService = restartService;
9
+ exports.deployService = deployService;
10
+ exports.serviceLogs = serviceLogs;
11
+ const chalk_1 = __importDefault(require("chalk"));
12
+ const ora_1 = __importDefault(require("ora"));
13
+ const config_1 = require("../lib/config");
14
+ const api_1 = require("../lib/api");
15
+ async function getServiceContext() {
16
+ const config = (0, config_1.getProjectConfig)();
17
+ if (!config) {
18
+ console.log(chalk_1.default.red('Not linked to any service. Run `dockup link` first.'));
19
+ return null;
20
+ }
21
+ return { projectSlug: config.projectSlug, serviceSlug: config.serviceSlug };
22
+ }
23
+ async function startService() {
24
+ if (!(0, config_1.isLoggedIn)()) {
25
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
26
+ process.exit(1);
27
+ }
28
+ const ctx = await getServiceContext();
29
+ if (!ctx)
30
+ process.exit(1);
31
+ const spinner = (0, ora_1.default)('Starting service...').start();
32
+ try {
33
+ await api_1.api.post(`/projects/${ctx.projectSlug}/services/${ctx.serviceSlug}/start`);
34
+ spinner.succeed('Service started!');
35
+ }
36
+ catch (error) {
37
+ spinner.fail(`Failed to start: ${error.message}`);
38
+ process.exit(1);
39
+ }
40
+ }
41
+ async function stopService() {
42
+ if (!(0, config_1.isLoggedIn)()) {
43
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
44
+ process.exit(1);
45
+ }
46
+ const ctx = await getServiceContext();
47
+ if (!ctx)
48
+ process.exit(1);
49
+ const spinner = (0, ora_1.default)('Stopping service...').start();
50
+ try {
51
+ await api_1.api.post(`/projects/${ctx.projectSlug}/services/${ctx.serviceSlug}/stop`);
52
+ spinner.succeed('Service stopped!');
53
+ }
54
+ catch (error) {
55
+ spinner.fail(`Failed to stop: ${error.message}`);
56
+ process.exit(1);
57
+ }
58
+ }
59
+ async function restartService() {
60
+ if (!(0, config_1.isLoggedIn)()) {
61
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
62
+ process.exit(1);
63
+ }
64
+ const ctx = await getServiceContext();
65
+ if (!ctx)
66
+ process.exit(1);
67
+ const spinner = (0, ora_1.default)('Restarting service...').start();
68
+ try {
69
+ await api_1.api.post(`/projects/${ctx.projectSlug}/services/${ctx.serviceSlug}/restart`);
70
+ spinner.succeed('Service restarted!');
71
+ }
72
+ catch (error) {
73
+ spinner.fail(`Failed to restart: ${error.message}`);
74
+ process.exit(1);
75
+ }
76
+ }
77
+ async function deployService() {
78
+ if (!(0, config_1.isLoggedIn)()) {
79
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
80
+ process.exit(1);
81
+ }
82
+ const ctx = await getServiceContext();
83
+ if (!ctx)
84
+ process.exit(1);
85
+ const spinner = (0, ora_1.default)('Triggering deployment...').start();
86
+ try {
87
+ const result = await api_1.api.deploy(ctx.projectSlug, ctx.serviceSlug);
88
+ spinner.succeed('Deployment started!');
89
+ console.log(chalk_1.default.dim(`\n Deployment ID: ${result.deploymentId || 'N/A'}`));
90
+ console.log(chalk_1.default.dim(' Run `dockup logs` to watch progress\n'));
91
+ }
92
+ catch (error) {
93
+ spinner.fail(`Failed to deploy: ${error.message}`);
94
+ process.exit(1);
95
+ }
96
+ }
97
+ async function serviceLogs(options) {
98
+ if (!(0, config_1.isLoggedIn)()) {
99
+ console.log(chalk_1.default.red('Not logged in. Run `dockup login` first.'));
100
+ process.exit(1);
101
+ }
102
+ const ctx = await getServiceContext();
103
+ if (!ctx)
104
+ process.exit(1);
105
+ const spinner = (0, ora_1.default)('Fetching logs...').start();
106
+ try {
107
+ const lines = parseInt(options.tail || '100', 10);
108
+ const logs = await api_1.api.get(`/projects/${ctx.projectSlug}/services/${ctx.serviceSlug}/logs?lines=${lines}`);
109
+ spinner.stop();
110
+ if (!logs.logs || logs.logs.length === 0) {
111
+ console.log(chalk_1.default.yellow('\n No logs available\n'));
112
+ return;
113
+ }
114
+ console.log(chalk_1.default.cyan('\n Service Logs:\n'));
115
+ const logLines = logs.logs.split('\n');
116
+ for (const line of logLines) {
117
+ if (line.toLowerCase().includes('error')) {
118
+ console.log(chalk_1.default.red(` ${line}`));
119
+ }
120
+ else if (line.toLowerCase().includes('warn')) {
121
+ console.log(chalk_1.default.yellow(` ${line}`));
122
+ }
123
+ else {
124
+ console.log(chalk_1.default.dim(` ${line}`));
125
+ }
126
+ }
127
+ console.log();
128
+ }
129
+ catch (error) {
130
+ spinner.fail(`Failed to fetch logs: ${error.message}`);
131
+ process.exit(1);
132
+ }
133
+ }