@tryghost/velo-cli 0.1.0 → 0.1.1
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/dist/index.js +86 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { Command } from "commander";
|
|
|
12
12
|
// src/commands/login.ts
|
|
13
13
|
import { createServer } from "http";
|
|
14
14
|
import { URL } from "url";
|
|
15
|
+
import { createInterface } from "readline";
|
|
15
16
|
import chalk from "chalk";
|
|
16
17
|
import open from "open";
|
|
17
18
|
import ora from "ora";
|
|
@@ -109,14 +110,76 @@ async function verifyToken(token) {
|
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
// src/commands/login.ts
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
function isHeadless() {
|
|
114
|
+
if (process.env.SSH_CLIENT || process.env.SSH_TTY) {
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
if (process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
if (process.env.container || process.env.DOCKER_CONTAINER) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
if (process.env.CI) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
function prompt(question) {
|
|
129
|
+
const rl = createInterface({
|
|
130
|
+
input: process.stdin,
|
|
131
|
+
output: process.stdout
|
|
132
|
+
});
|
|
133
|
+
return new Promise((resolve) => {
|
|
134
|
+
rl.question(question, (answer) => {
|
|
135
|
+
rl.close();
|
|
136
|
+
resolve(answer.trim());
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
async function manualLogin() {
|
|
141
|
+
const loginUrl = `${API_BASE_URL}/cli/login`;
|
|
142
|
+
console.log(chalk.blue("Velo CLI Login (Manual Mode)"));
|
|
143
|
+
console.log(chalk.gray("No browser detected. Please authenticate manually.\n"));
|
|
144
|
+
console.log(chalk.white("1. Open this URL in a browser on any device:"));
|
|
145
|
+
console.log(chalk.cyan(` ${loginUrl}
|
|
146
|
+
`));
|
|
147
|
+
console.log(chalk.white("2. Sign in with your Ghost Google account"));
|
|
148
|
+
console.log(chalk.white("3. Copy the token shown on the success page"));
|
|
149
|
+
console.log(chalk.white("4. Paste it below:\n"));
|
|
150
|
+
const token = await prompt(chalk.yellow("Token: "));
|
|
151
|
+
if (!token) {
|
|
152
|
+
console.log(chalk.red("\nNo token provided. Login cancelled."));
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
const spinner = ora("Verifying token...").start();
|
|
156
|
+
try {
|
|
157
|
+
const verification = await verifyToken(token);
|
|
158
|
+
spinner.stop();
|
|
159
|
+
if (!verification.valid) {
|
|
160
|
+
console.log(chalk.red(`
|
|
161
|
+
Invalid token: ${verification.error || "Unknown error"}`));
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
const credentials = {
|
|
165
|
+
token,
|
|
166
|
+
email: verification.email,
|
|
167
|
+
expires_at: new Date(Date.now() + 30 * 24 * 60 * 60 * 1e3).toISOString()
|
|
168
|
+
};
|
|
169
|
+
saveCredentials(credentials);
|
|
170
|
+
console.log(chalk.green(`
|
|
171
|
+
\u2713 Logged in as ${chalk.bold(credentials.email)}`));
|
|
172
|
+
console.log(chalk.gray(` Credentials saved to ~/.config/velo/credentials.json`));
|
|
173
|
+
console.log(chalk.gray(`
|
|
174
|
+
Run ${chalk.cyan("velo status")} to see CI metrics.`));
|
|
175
|
+
} catch (error) {
|
|
176
|
+
spinner.stop();
|
|
177
|
+
console.log(chalk.red(`
|
|
178
|
+
Failed to verify token: ${error.message}`));
|
|
179
|
+
process.exit(1);
|
|
119
180
|
}
|
|
181
|
+
}
|
|
182
|
+
async function browserLogin() {
|
|
120
183
|
const port = DEFAULT_CALLBACK_PORT;
|
|
121
184
|
const loginUrl = `${API_BASE_URL}/cli/login?port=${port}`;
|
|
122
185
|
console.log(chalk.blue("Velo CLI Login"));
|
|
@@ -231,6 +294,20 @@ ${error.message}`));
|
|
|
231
294
|
process.exit(1);
|
|
232
295
|
}
|
|
233
296
|
}
|
|
297
|
+
async function login(options = {}) {
|
|
298
|
+
const existing = loadCredentials();
|
|
299
|
+
if (existing) {
|
|
300
|
+
console.log(chalk.yellow(`Already logged in as ${existing.email}`));
|
|
301
|
+
console.log(chalk.gray(`Token expires: ${new Date(existing.expires_at).toLocaleDateString()}`));
|
|
302
|
+
console.log(chalk.gray(`Run ${chalk.cyan("velo logout")} to log out first.`));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (options.manual || isHeadless()) {
|
|
306
|
+
await manualLogin();
|
|
307
|
+
} else {
|
|
308
|
+
await browserLogin();
|
|
309
|
+
}
|
|
310
|
+
}
|
|
234
311
|
|
|
235
312
|
// src/commands/logout.ts
|
|
236
313
|
import chalk2 from "chalk";
|
|
@@ -371,7 +448,7 @@ async function api(endpoint, options) {
|
|
|
371
448
|
// src/index.ts
|
|
372
449
|
var program = new Command();
|
|
373
450
|
program.name("velo").description("CLI for Velo CI/CD metrics").version("0.1.0");
|
|
374
|
-
program.command("login").description("Authenticate via Ghost SSO").action(login);
|
|
451
|
+
program.command("login").description("Authenticate via Ghost SSO").option("--manual", "Use manual token entry (for headless servers)").action((options) => login({ manual: options.manual }));
|
|
375
452
|
program.command("logout").description("Clear saved credentials").action(logout);
|
|
376
453
|
program.command("status").description("Show CI health overview").option("-r, --repo <repo>", "Filter by repository (e.g., TryGhost/Ghost)").option("-d, --days <days>", "Number of days to analyze (default: 7)", "7").action((options) => {
|
|
377
454
|
status({
|
|
@@ -389,6 +466,7 @@ program.command("api <endpoint>").description("Make raw API calls").option("-m,
|
|
|
389
466
|
program.addHelpText("after", `
|
|
390
467
|
Examples:
|
|
391
468
|
$ velo login # Authenticate via browser SSO
|
|
469
|
+
$ velo login --manual # Manual token entry (headless servers)
|
|
392
470
|
$ velo status # Quick CI health check
|
|
393
471
|
$ velo status --repo TryGhost/Ghost # Status for specific repo
|
|
394
472
|
$ velo api /api/health # Check API health
|