@codmir/cli 1.1.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.
- package/README.md +207 -0
- package/dist/build-V6CJBXHK.js +7 -0
- package/dist/chunk-3VE47H25.js +286 -0
- package/dist/chunk-5XZIEJ3P.js +231 -0
- package/dist/chunk-BQMZNWYV.js +295 -0
- package/dist/chunk-KFQGP6VL.js +33 -0
- package/dist/context/index.js +9 -0
- package/dist/index.js +13005 -0
- package/dist/sync/index.js +7 -0
- package/package.json +95 -0
package/README.md
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# codmir
|
|
2
|
+
|
|
3
|
+
Official Codmir CLI - AI-powered autonomous agent for developers.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/codmir)
|
|
6
|
+
[](https://www.npmjs.com/package/codmir)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🤖 **AI Assistant** - Interactive AI-powered coding assistant in your terminal
|
|
11
|
+
- 🔍 **Codebase Analysis** - Understand and navigate your codebase with AI
|
|
12
|
+
- ⚡ **Intelligent Automation** - Automate repetitive development tasks
|
|
13
|
+
- 🎯 **Context-Aware** - Understands your project structure and dependencies
|
|
14
|
+
- 🔗 **Cloud Sync** - Sync tasks and context with the Codmir platform
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install globally
|
|
20
|
+
npm install -g codmir
|
|
21
|
+
|
|
22
|
+
# Or use with npx
|
|
23
|
+
npx codmir
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Login to your Codmir account
|
|
30
|
+
codmir login
|
|
31
|
+
|
|
32
|
+
# Start an interactive AI session
|
|
33
|
+
codmir
|
|
34
|
+
|
|
35
|
+
# Ask a question about your codebase
|
|
36
|
+
codmir "How is authentication implemented?"
|
|
37
|
+
|
|
38
|
+
# Analyze your project
|
|
39
|
+
codmir analyze
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Commands
|
|
43
|
+
|
|
44
|
+
### Interactive Mode
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Start interactive AI assistant
|
|
48
|
+
codmir
|
|
49
|
+
|
|
50
|
+
# You can then chat naturally:
|
|
51
|
+
# > How do I add a new API endpoint?
|
|
52
|
+
# > Explain the database schema
|
|
53
|
+
# > Help me fix this error: [paste error]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Project Commands
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Link current directory to a Codmir project
|
|
60
|
+
codmir link
|
|
61
|
+
|
|
62
|
+
# Show project status
|
|
63
|
+
codmir status
|
|
64
|
+
|
|
65
|
+
# Analyze codebase and generate insights
|
|
66
|
+
codmir analyze
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Task Commands
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Create a new task
|
|
73
|
+
codmir task create "Implement user authentication"
|
|
74
|
+
|
|
75
|
+
# List tasks
|
|
76
|
+
codmir task list
|
|
77
|
+
|
|
78
|
+
# Get task details
|
|
79
|
+
codmir task show <task-id>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Authentication
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Login to Codmir
|
|
86
|
+
codmir login
|
|
87
|
+
|
|
88
|
+
# Show current user
|
|
89
|
+
codmir whoami
|
|
90
|
+
|
|
91
|
+
# Logout
|
|
92
|
+
codmir logout
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Cloud Sync
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Sync local context to cloud
|
|
99
|
+
codmir sync
|
|
100
|
+
|
|
101
|
+
# Push local changes
|
|
102
|
+
codmir sync push
|
|
103
|
+
|
|
104
|
+
# Pull remote changes
|
|
105
|
+
codmir sync pull
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Configuration
|
|
109
|
+
|
|
110
|
+
The CLI uses the following environment variables:
|
|
111
|
+
|
|
112
|
+
| Variable | Description | Default |
|
|
113
|
+
|----------|-------------|---------|
|
|
114
|
+
| `CODMIR_API_KEY` | API key for authentication | - |
|
|
115
|
+
| `CODMIR_API_URL` | Custom API endpoint | `https://codmir.com/api` |
|
|
116
|
+
| `CODMIR_PROJECT_ID` | Default project ID | - |
|
|
117
|
+
|
|
118
|
+
You can also create a `.codmir` config file in your project root:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"projectId": "your-project-id",
|
|
123
|
+
"organization": "your-org-slug"
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Usage Examples
|
|
128
|
+
|
|
129
|
+
### Code Review
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Review staged changes
|
|
133
|
+
codmir "Review my staged changes for potential issues"
|
|
134
|
+
|
|
135
|
+
# Review a specific file
|
|
136
|
+
codmir "Review src/auth/login.ts for security issues"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Debugging Help
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Get help with an error
|
|
143
|
+
codmir "I'm getting this error: TypeError: Cannot read property 'id' of undefined"
|
|
144
|
+
|
|
145
|
+
# Explain code behavior
|
|
146
|
+
codmir "Why is this function returning null?"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Code Generation
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Generate code
|
|
153
|
+
codmir "Write a function to validate email addresses"
|
|
154
|
+
|
|
155
|
+
# Generate tests
|
|
156
|
+
codmir "Write unit tests for the UserService class"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Documentation
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Generate documentation
|
|
163
|
+
codmir "Document the API endpoints in src/routes/"
|
|
164
|
+
|
|
165
|
+
# Explain code
|
|
166
|
+
codmir "Explain how the payment flow works"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Programmatic Usage
|
|
170
|
+
|
|
171
|
+
You can also import the CLI functionality in your Node.js projects:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
import { createContext } from 'codmir/context';
|
|
175
|
+
import { syncToCloud } from 'codmir/sync';
|
|
176
|
+
|
|
177
|
+
// Create a context for the current directory
|
|
178
|
+
const context = await createContext({
|
|
179
|
+
rootDir: process.cwd(),
|
|
180
|
+
includeGitHistory: true,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Sync to cloud
|
|
184
|
+
await syncToCloud(context, {
|
|
185
|
+
projectId: 'your-project-id',
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Requirements
|
|
190
|
+
|
|
191
|
+
- Node.js >= 18.0.0
|
|
192
|
+
- npm, pnpm, or yarn
|
|
193
|
+
|
|
194
|
+
## Related Packages
|
|
195
|
+
|
|
196
|
+
- [`@codmir/sdk`](https://www.npmjs.com/package/@codmir/sdk) - TypeScript/JavaScript SDK for the Codmir API
|
|
197
|
+
- `@codmir/types` - Shared type definitions
|
|
198
|
+
|
|
199
|
+
## Support
|
|
200
|
+
|
|
201
|
+
- 📖 [Documentation](https://codmir.com/docs/cli)
|
|
202
|
+
- 🐛 [Report Issues](https://github.com/codmir-labs/platform/issues)
|
|
203
|
+
- 💬 [Discord Community](https://discord.gg/codmir)
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
// src/commands/build.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import EventSource from "eventsource";
|
|
6
|
+
var BUILD_SERVER_URL = process.env.CODMIR_BUILD_SERVER_URL || process.env.BUILD_SERVER_URL || "";
|
|
7
|
+
var BUILD_SERVER_SECRET = process.env.CODMIR_BUILD_SERVER_SECRET || process.env.BUILD_SERVER_SECRET || "";
|
|
8
|
+
function headers() {
|
|
9
|
+
const h = { "Content-Type": "application/json" };
|
|
10
|
+
if (BUILD_SERVER_SECRET) h["Authorization"] = `Bearer ${BUILD_SERVER_SECRET}`;
|
|
11
|
+
return h;
|
|
12
|
+
}
|
|
13
|
+
function getRepoUrl() {
|
|
14
|
+
try {
|
|
15
|
+
return execSync("git remote get-url origin", { encoding: "utf-8" }).trim();
|
|
16
|
+
} catch {
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function getCurrentBranch() {
|
|
21
|
+
try {
|
|
22
|
+
return execSync("git branch --show-current", { encoding: "utf-8" }).trim();
|
|
23
|
+
} catch {
|
|
24
|
+
return "main";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function getLatestCommit() {
|
|
28
|
+
try {
|
|
29
|
+
return execSync("git rev-parse HEAD", { encoding: "utf-8" }).trim();
|
|
30
|
+
} catch {
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function formatDuration(ms) {
|
|
35
|
+
const s = Math.floor(ms / 1e3);
|
|
36
|
+
if (s < 60) return `${s}s`;
|
|
37
|
+
return `${Math.floor(s / 60)}m ${s % 60}s`;
|
|
38
|
+
}
|
|
39
|
+
function phaseIcon(phase) {
|
|
40
|
+
const map = {
|
|
41
|
+
queued: "\u23F3",
|
|
42
|
+
cloning: "\u{1F4E6}",
|
|
43
|
+
installing: "\u{1F4E5}",
|
|
44
|
+
building: "\u{1F528}",
|
|
45
|
+
testing: "\u{1F9EA}",
|
|
46
|
+
linting: "\u{1F50D}",
|
|
47
|
+
uploading_artifacts: "\u2601\uFE0F",
|
|
48
|
+
collecting_artifacts: "\u{1F4C1}",
|
|
49
|
+
custom_step: "\u2699\uFE0F",
|
|
50
|
+
completed: "\u2705",
|
|
51
|
+
failed: "\u274C",
|
|
52
|
+
cancelled: "\u{1F6AB}"
|
|
53
|
+
};
|
|
54
|
+
return map[phase] || "\u2753";
|
|
55
|
+
}
|
|
56
|
+
function streamBuildLogs(buildId) {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
const url = `${BUILD_SERVER_URL}/build/${buildId}/events`;
|
|
59
|
+
const es = new EventSource(url, {
|
|
60
|
+
headers: BUILD_SERVER_SECRET ? { Authorization: `Bearer ${BUILD_SERVER_SECRET}` } : void 0
|
|
61
|
+
});
|
|
62
|
+
es.addEventListener("phase_change", (e) => {
|
|
63
|
+
const data = JSON.parse(e.data);
|
|
64
|
+
console.log(chalk.cyan(`
|
|
65
|
+
${phaseIcon(data.phase)} Phase: ${data.phase}`));
|
|
66
|
+
if (data.version) {
|
|
67
|
+
console.log(chalk.dim(` Build ${data.version.displayVersion}`));
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
es.addEventListener("log", (e) => {
|
|
71
|
+
const data = JSON.parse(e.data);
|
|
72
|
+
const prefix = data.stepName ? chalk.dim(`[${data.stepName}] `) : "";
|
|
73
|
+
if (data.stream === "stderr") {
|
|
74
|
+
console.log(chalk.red(`${prefix}${data.text}`));
|
|
75
|
+
} else if (data.stream === "system") {
|
|
76
|
+
console.log(chalk.cyan(`${prefix}${data.text}`));
|
|
77
|
+
} else {
|
|
78
|
+
console.log(`${prefix}${data.text}`);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
es.addEventListener("step_start", (e) => {
|
|
82
|
+
const data = JSON.parse(e.data);
|
|
83
|
+
console.log(chalk.yellow(`
|
|
84
|
+
\u25B6 Step: ${data.name}`));
|
|
85
|
+
});
|
|
86
|
+
es.addEventListener("step_complete", (e) => {
|
|
87
|
+
const data = JSON.parse(e.data);
|
|
88
|
+
const icon = data.status === "passed" ? "\u2705" : "\u274C";
|
|
89
|
+
console.log(chalk.dim(`${icon} Step "${data.name}" ${data.status} (${data.duration ? formatDuration(data.duration) : ""})`));
|
|
90
|
+
});
|
|
91
|
+
es.addEventListener("completed", (e) => {
|
|
92
|
+
const data = JSON.parse(e.data);
|
|
93
|
+
console.log(chalk.green(`
|
|
94
|
+
\u2705 Build completed in ${data.duration ? formatDuration(data.duration) : "unknown"}`));
|
|
95
|
+
if (data.artifactCount > 0) {
|
|
96
|
+
console.log(chalk.dim(` \u{1F4E6} ${data.artifactCount} artifacts`));
|
|
97
|
+
}
|
|
98
|
+
if (data.artifactUrls?.length > 0) {
|
|
99
|
+
console.log(chalk.dim(` \u2601\uFE0F Uploaded to R2`));
|
|
100
|
+
}
|
|
101
|
+
es.close();
|
|
102
|
+
resolve();
|
|
103
|
+
});
|
|
104
|
+
es.addEventListener("failed", (e) => {
|
|
105
|
+
const data = JSON.parse(e.data);
|
|
106
|
+
console.log(chalk.red(`
|
|
107
|
+
\u274C Build failed: ${data.error || "Unknown error"}`));
|
|
108
|
+
es.close();
|
|
109
|
+
reject(new Error(data.error || "Build failed"));
|
|
110
|
+
});
|
|
111
|
+
es.onerror = () => {
|
|
112
|
+
es.close();
|
|
113
|
+
reject(new Error("Lost connection to build server"));
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function registerBuildCommands(program) {
|
|
118
|
+
const build = program.command("build [action]").alias("bld").description("\u{1F528} Cloud compile & build via Codmir Build Server").option("-b, --branch <branch>", "Branch to build").option("-c, --commit <sha>", "Specific commit SHA").option("-r, --repo <url>", "Repository URL (auto-detected from git)").option("--cmd <command>", "Build command", "npm run build").option("--install <command>", "Install command", "npm install").option("--output <dir>", "Output directory", "dist").option("-w, --watch <id>", "Watch/stream logs from a build").option("-p, --project <id>", "Project ID").option("--workflow <id>", "Run via workflow").action(async (action, options) => {
|
|
119
|
+
if (!BUILD_SERVER_URL) {
|
|
120
|
+
console.log(chalk.red("\u274C Build server not configured."));
|
|
121
|
+
console.log(chalk.dim(" Set CODMIR_BUILD_SERVER_URL or BUILD_SERVER_URL"));
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
if (action === "list" || action === "ls") {
|
|
125
|
+
await listBuilds(options.project);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
if (action === "status") {
|
|
129
|
+
const id = process.argv[4];
|
|
130
|
+
if (!id) {
|
|
131
|
+
console.log(chalk.red("Usage: codmir build status <build-id>"));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
await showBuildStatus(id);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (action === "cancel") {
|
|
138
|
+
const id = process.argv[4];
|
|
139
|
+
if (!id) {
|
|
140
|
+
console.log(chalk.red("Usage: codmir build cancel <build-id>"));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
await cancelBuild(id);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (options.watch) {
|
|
147
|
+
console.log(chalk.cyan(`\u{1F4E1} Streaming logs for build ${options.watch}...
|
|
148
|
+
`));
|
|
149
|
+
try {
|
|
150
|
+
await streamBuildLogs(options.watch);
|
|
151
|
+
} catch (err) {
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const repoUrl = options.repo || getRepoUrl();
|
|
157
|
+
const branch = options.branch || getCurrentBranch();
|
|
158
|
+
const commitSha = options.commit || getLatestCommit();
|
|
159
|
+
if (!repoUrl) {
|
|
160
|
+
console.log(chalk.red("\u274C Cannot detect repository URL. Use --repo <url>"));
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
const spinner = ora(`Submitting build for ${chalk.bold(branch)}...`).start();
|
|
164
|
+
try {
|
|
165
|
+
const res = await fetch(`${BUILD_SERVER_URL}/build`, {
|
|
166
|
+
method: "POST",
|
|
167
|
+
headers: headers(),
|
|
168
|
+
body: JSON.stringify({
|
|
169
|
+
repoUrl,
|
|
170
|
+
branch,
|
|
171
|
+
commitSha: commitSha || void 0,
|
|
172
|
+
buildCommand: options.cmd,
|
|
173
|
+
installCommand: options.install,
|
|
174
|
+
outputDir: options.output,
|
|
175
|
+
projectId: options.project,
|
|
176
|
+
triggeredBy: "cli",
|
|
177
|
+
workflowId: options.workflow
|
|
178
|
+
})
|
|
179
|
+
});
|
|
180
|
+
if (!res.ok) {
|
|
181
|
+
const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
182
|
+
spinner.fail(`Build submission failed: ${err.error || res.statusText}`);
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
const data = await res.json();
|
|
186
|
+
spinner.succeed(`Build submitted: ${chalk.bold(data.version?.displayVersion || data.id)}`);
|
|
187
|
+
console.log(chalk.dim(` ID: ${data.id}`));
|
|
188
|
+
console.log(chalk.dim(` Build #${data.version?.buildNumber || "?"}`));
|
|
189
|
+
console.log();
|
|
190
|
+
console.log(chalk.cyan("\u{1F4E1} Streaming build logs...\n"));
|
|
191
|
+
try {
|
|
192
|
+
await streamBuildLogs(data.id);
|
|
193
|
+
} catch {
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
} catch (err) {
|
|
197
|
+
spinner.fail(`Failed to reach build server: ${err}`);
|
|
198
|
+
process.exit(1);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
async function listBuilds(projectId) {
|
|
203
|
+
const spinner = ora("Fetching builds...").start();
|
|
204
|
+
try {
|
|
205
|
+
const url = new URL(`${BUILD_SERVER_URL}/builds`);
|
|
206
|
+
url.searchParams.set("limit", "15");
|
|
207
|
+
if (projectId) url.searchParams.set("projectId", projectId);
|
|
208
|
+
const res = await fetch(url.toString(), { headers: headers() });
|
|
209
|
+
const data = await res.json();
|
|
210
|
+
spinner.stop();
|
|
211
|
+
if (!data.builds?.length) {
|
|
212
|
+
console.log(chalk.dim("No builds found."));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
console.log(chalk.bold(`
|
|
216
|
+
Builds (${data.total} total)
|
|
217
|
+
`));
|
|
218
|
+
console.log(chalk.dim(" ID Version Status Duration Triggered"));
|
|
219
|
+
console.log(chalk.dim(" \u2500".repeat(40)));
|
|
220
|
+
for (const b of data.builds) {
|
|
221
|
+
const status = b.phase === "completed" ? chalk.green("\u2705 passed") : b.phase === "failed" ? chalk.red("\u274C failed") : b.phase === "cancelled" ? chalk.dim("\u{1F6AB} cancelled") : chalk.yellow(`\u23F3 ${b.phase}`);
|
|
222
|
+
const dur = b.duration ? formatDuration(b.duration) : "\u2014";
|
|
223
|
+
const ver = b.version?.displayVersion || b.branch;
|
|
224
|
+
console.log(` ${chalk.dim(b.id)} ${chalk.bold(ver.padEnd(20))} ${status.padEnd(20)} ${dur.padStart(8)} ${b.triggeredBy}`);
|
|
225
|
+
}
|
|
226
|
+
console.log();
|
|
227
|
+
} catch (err) {
|
|
228
|
+
spinner.fail(`Failed: ${err}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async function showBuildStatus(id) {
|
|
232
|
+
const spinner = ora("Fetching build...").start();
|
|
233
|
+
try {
|
|
234
|
+
const res = await fetch(`${BUILD_SERVER_URL}/build/${id}`, { headers: headers() });
|
|
235
|
+
if (!res.ok) {
|
|
236
|
+
spinner.fail("Build not found");
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const b = await res.json();
|
|
240
|
+
spinner.stop();
|
|
241
|
+
const status = b.phase === "completed" ? chalk.green("\u2705 Completed") : b.phase === "failed" ? chalk.red("\u274C Failed") : chalk.yellow(`\u23F3 ${b.phase}`);
|
|
242
|
+
console.log();
|
|
243
|
+
console.log(chalk.bold(` Build ${b.version?.displayVersion || b.id}`));
|
|
244
|
+
console.log(chalk.dim(" \u2500".repeat(25)));
|
|
245
|
+
console.log(` Status: ${status}`);
|
|
246
|
+
console.log(` Branch: ${b.branch}`);
|
|
247
|
+
if (b.commitSha) console.log(` Commit: ${chalk.dim(b.commitSha.slice(0, 7))}`);
|
|
248
|
+
console.log(` Command: ${chalk.dim(b.buildCommand)}`);
|
|
249
|
+
console.log(` Triggered: ${b.triggeredBy}`);
|
|
250
|
+
if (b.duration) console.log(` Duration: ${formatDuration(b.duration)}`);
|
|
251
|
+
if (b.artifactCount > 0) console.log(` Artifacts: ${b.artifactCount} files`);
|
|
252
|
+
if (b.error) console.log(` Error: ${chalk.red(b.error)}`);
|
|
253
|
+
if (b.steps?.length > 0) {
|
|
254
|
+
console.log(`
|
|
255
|
+
${chalk.bold("Steps:")}`);
|
|
256
|
+
for (const step of b.steps) {
|
|
257
|
+
const icon = step.status === "passed" ? "\u2705" : step.status === "failed" ? "\u274C" : step.status === "running" ? "\u{1F504}" : "\u2B1C";
|
|
258
|
+
const dur = step.duration ? chalk.dim(` (${formatDuration(step.duration)})`) : "";
|
|
259
|
+
console.log(` ${icon} ${step.name}${dur}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
console.log();
|
|
263
|
+
} catch (err) {
|
|
264
|
+
spinner.fail(`Failed: ${err}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
async function cancelBuild(id) {
|
|
268
|
+
const spinner = ora("Cancelling build...").start();
|
|
269
|
+
try {
|
|
270
|
+
const res = await fetch(`${BUILD_SERVER_URL}/build/${id}/cancel`, {
|
|
271
|
+
method: "POST",
|
|
272
|
+
headers: headers()
|
|
273
|
+
});
|
|
274
|
+
if (!res.ok) {
|
|
275
|
+
spinner.fail("Failed to cancel");
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
spinner.succeed("Build cancelled");
|
|
279
|
+
} catch (err) {
|
|
280
|
+
spinner.fail(`Failed: ${err}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export {
|
|
285
|
+
registerBuildCommands
|
|
286
|
+
};
|