@riventa/cli 1.0.0 → 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/dist/index.js +90 -39
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -91,7 +91,7 @@ async function loginCommand() {
|
|
|
91
91
|
}
|
|
92
92
|
console.log();
|
|
93
93
|
console.log(chalk2.bold(" Welcome to Riventa.Dev CLI"));
|
|
94
|
-
console.log(chalk2.gray("
|
|
94
|
+
console.log(chalk2.gray(" Connect your terminal to your Riventa account.\n"));
|
|
95
95
|
const { method } = await inquirer.prompt([
|
|
96
96
|
{
|
|
97
97
|
type: "list",
|
|
@@ -99,60 +99,108 @@ async function loginCommand() {
|
|
|
99
99
|
message: "How would you like to authenticate?",
|
|
100
100
|
choices: [
|
|
101
101
|
{
|
|
102
|
-
name: `${chalk2.cyan("Browser")} \u2014
|
|
102
|
+
name: `${chalk2.cyan("Browser")} \u2014 sign in via browser (recommended)`,
|
|
103
103
|
value: "browser"
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
|
-
name: `${chalk2.cyan("
|
|
106
|
+
name: `${chalk2.cyan("API Key")} \u2014 paste an existing API key`,
|
|
107
107
|
value: "manual"
|
|
108
108
|
}
|
|
109
109
|
]
|
|
110
110
|
}
|
|
111
111
|
]);
|
|
112
|
-
let apiKey;
|
|
113
112
|
if (method === "browser") {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
await deviceFlowLogin();
|
|
114
|
+
} else {
|
|
115
|
+
await manualLogin();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function deviceFlowLogin() {
|
|
119
|
+
const baseUrl = getBaseUrl();
|
|
120
|
+
const spinner = ora("Requesting authorization...").start();
|
|
121
|
+
try {
|
|
122
|
+
const response = await fetch(`${baseUrl}/v1/auth/device`, {
|
|
123
|
+
method: "POST",
|
|
124
|
+
headers: { "Content-Type": "application/json" }
|
|
125
|
+
});
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
throw new Error("Failed to create device code");
|
|
128
|
+
}
|
|
129
|
+
const result = await response.json();
|
|
130
|
+
const { deviceCode, userCode, verificationUrl } = result.data;
|
|
131
|
+
spinner.stop();
|
|
132
|
+
console.log();
|
|
133
|
+
console.log(chalk2.bold(" Your device code:"));
|
|
134
|
+
console.log();
|
|
135
|
+
console.log(chalk2.cyan(` ${userCode.slice(0, 4)} - ${userCode.slice(4)}`));
|
|
136
|
+
console.log();
|
|
137
|
+
console.log(chalk2.gray(` Opening ${verificationUrl}`));
|
|
138
|
+
console.log(chalk2.gray(" Enter the code above to authorize this device.\n"));
|
|
118
139
|
try {
|
|
119
|
-
await open(
|
|
140
|
+
await open(verificationUrl);
|
|
120
141
|
} catch {
|
|
121
|
-
console.log(chalk2.yellow(` Could not open browser
|
|
122
|
-
${
|
|
142
|
+
console.log(chalk2.yellow(` Could not open browser automatically.`));
|
|
143
|
+
console.log(chalk2.yellow(` Please visit: ${chalk2.white(verificationUrl)}
|
|
123
144
|
`));
|
|
124
145
|
}
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
146
|
+
const pollSpinner = ora("Waiting for authorization...").start();
|
|
147
|
+
const maxAttempts = 60;
|
|
148
|
+
let attempts = 0;
|
|
149
|
+
while (attempts < maxAttempts) {
|
|
150
|
+
await sleep(3e3);
|
|
151
|
+
attempts++;
|
|
152
|
+
try {
|
|
153
|
+
const pollResponse = await fetch(`${baseUrl}/v1/auth/device?code=${deviceCode}`);
|
|
154
|
+
const pollResult = await pollResponse.json();
|
|
155
|
+
if (pollResult.data?.status === "authorized") {
|
|
156
|
+
pollSpinner.succeed(chalk2.green("Authorized!"));
|
|
157
|
+
const { apiKey, user } = pollResult.data;
|
|
158
|
+
setConfig("apiKey", apiKey);
|
|
159
|
+
setConfig("user", user);
|
|
160
|
+
console.log();
|
|
161
|
+
console.log(chalk2.gray(" Logged in as: ") + chalk2.white(user.email));
|
|
162
|
+
if (user.name) console.log(chalk2.gray(" Name: ") + chalk2.white(user.name));
|
|
163
|
+
console.log();
|
|
164
|
+
console.log(chalk2.gray(" Get started:"));
|
|
165
|
+
console.log(chalk2.gray(" riventa init \u2014 initialize a project"));
|
|
166
|
+
console.log(chalk2.gray(" riventa projects \u2014 list your projects"));
|
|
167
|
+
console.log(chalk2.gray(" riventa review \u2014 run AI code review"));
|
|
168
|
+
console.log(chalk2.gray(" riventa --help \u2014 see all commands"));
|
|
169
|
+
console.log();
|
|
170
|
+
return;
|
|
135
171
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const answer = await inquirer.prompt([
|
|
141
|
-
{
|
|
142
|
-
type: "password",
|
|
143
|
-
name: "apiKey",
|
|
144
|
-
message: "Enter your API key:",
|
|
145
|
-
mask: "*",
|
|
146
|
-
validate: (input) => {
|
|
147
|
-
if (!input.startsWith("riv_")) return 'API key must start with "riv_"';
|
|
148
|
-
if (input.length < 20) return "API key is too short";
|
|
149
|
-
return true;
|
|
172
|
+
if (pollResult.data?.status !== "pending") {
|
|
173
|
+
pollSpinner.fail(chalk2.red("Authorization failed"));
|
|
174
|
+
console.log(chalk2.red("\n The code may have expired. Run `riventa login` to try again.\n"));
|
|
175
|
+
process.exit(1);
|
|
150
176
|
}
|
|
177
|
+
} catch {
|
|
151
178
|
}
|
|
152
|
-
|
|
153
|
-
|
|
179
|
+
}
|
|
180
|
+
pollSpinner.fail(chalk2.red("Authorization timed out"));
|
|
181
|
+
console.log(chalk2.red("\n The code expired. Run `riventa login` to try again.\n"));
|
|
182
|
+
process.exit(1);
|
|
183
|
+
} catch {
|
|
184
|
+
spinner.fail(chalk2.red("Failed to start authorization"));
|
|
185
|
+
console.log(chalk2.red("\n Could not reach Riventa servers. Check your connection.\n"));
|
|
186
|
+
process.exit(1);
|
|
154
187
|
}
|
|
155
|
-
|
|
188
|
+
}
|
|
189
|
+
async function manualLogin() {
|
|
190
|
+
const answer = await inquirer.prompt([
|
|
191
|
+
{
|
|
192
|
+
type: "password",
|
|
193
|
+
name: "apiKey",
|
|
194
|
+
message: "Enter your API key (starts with riv_):",
|
|
195
|
+
mask: "*",
|
|
196
|
+
validate: (input) => {
|
|
197
|
+
if (!input.startsWith("riv_")) return 'API key must start with "riv_"';
|
|
198
|
+
if (input.length < 20) return "API key is too short";
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
]);
|
|
203
|
+
await verifyAndSaveKey(answer.apiKey);
|
|
156
204
|
}
|
|
157
205
|
async function verifyAndSaveKey(apiKey) {
|
|
158
206
|
const spinner = ora("Verifying API key...").start();
|
|
@@ -190,6 +238,9 @@ async function verifyAndSaveKey(apiKey) {
|
|
|
190
238
|
process.exit(1);
|
|
191
239
|
}
|
|
192
240
|
}
|
|
241
|
+
function sleep(ms) {
|
|
242
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
243
|
+
}
|
|
193
244
|
|
|
194
245
|
// src/commands/init.ts
|
|
195
246
|
import chalk3 from "chalk";
|
|
@@ -1184,7 +1235,7 @@ async function healthCommand() {
|
|
|
1184
1235
|
|
|
1185
1236
|
// src/index.ts
|
|
1186
1237
|
var program = new Command();
|
|
1187
|
-
program.name("riventa").description(chalk14.cyan("Riventa.Dev CLI") + chalk14.gray(" \u2014 AI-powered DevOps automation")).version("1.
|
|
1238
|
+
program.name("riventa").description(chalk14.cyan("Riventa.Dev CLI") + chalk14.gray(" \u2014 AI-powered DevOps automation")).version("1.1.0").addHelpText("after", `
|
|
1188
1239
|
${chalk14.bold("Quick Start:")}
|
|
1189
1240
|
${chalk14.gray("$")} riventa login Authenticate with your API key
|
|
1190
1241
|
${chalk14.gray("$")} riventa init Initialize a project
|