@0dai-dev/cli 1.2.1 → 1.3.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/bin/0dai.js +78 -5
- package/package.json +1 -1
package/bin/0dai.js
CHANGED
|
@@ -239,6 +239,67 @@ function cmdStatus(target) {
|
|
|
239
239
|
} catch {}
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
async function cmdAuthLogin() {
|
|
243
|
+
// Step 1: request device code
|
|
244
|
+
const result = await apiCall("/v1/auth/device", { client_id: "cli" });
|
|
245
|
+
if (result.error) { console.error(`[0dai] error: ${result.error}`); process.exit(1); }
|
|
246
|
+
|
|
247
|
+
console.log(`[0dai] Open this URL in your browser:\n`);
|
|
248
|
+
console.log(` ${result.verification_uri}\n`);
|
|
249
|
+
console.log(`[0dai] Enter code: ${result.user_code}\n`);
|
|
250
|
+
console.log("[0dai] Waiting for authorization...");
|
|
251
|
+
|
|
252
|
+
// Step 2: poll for token
|
|
253
|
+
const interval = (result.interval || 5) * 1000;
|
|
254
|
+
const deadline = Date.now() + (result.expires_in || 600) * 1000;
|
|
255
|
+
|
|
256
|
+
while (Date.now() < deadline) {
|
|
257
|
+
await new Promise(r => setTimeout(r, interval));
|
|
258
|
+
const poll = await apiCall("/v1/auth/token", { device_code: result.device_code });
|
|
259
|
+
if (poll.access_token) {
|
|
260
|
+
// Save token
|
|
261
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
262
|
+
fs.writeFileSync(AUTH_FILE, JSON.stringify({
|
|
263
|
+
access_token: poll.access_token,
|
|
264
|
+
email: poll.email,
|
|
265
|
+
plan: poll.plan || "free",
|
|
266
|
+
authenticated_at: new Date().toISOString(),
|
|
267
|
+
expires_at: poll.expires_at,
|
|
268
|
+
}, null, 2) + "\n", { mode: 0o600 });
|
|
269
|
+
console.log(`[0dai] Logged in as ${poll.email} (${poll.plan} plan)`);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (poll.error && poll.error !== "authorization_pending") {
|
|
273
|
+
console.error(`[0dai] ${poll.error}`);
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
276
|
+
process.stdout.write(".");
|
|
277
|
+
}
|
|
278
|
+
console.error("\n[0dai] Authorization timed out. Try again.");
|
|
279
|
+
process.exit(1);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function cmdAuthLogout() {
|
|
283
|
+
try { fs.unlinkSync(AUTH_FILE); } catch {}
|
|
284
|
+
console.log("[0dai] Logged out");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function cmdAuthStatus() {
|
|
288
|
+
try {
|
|
289
|
+
const auth = JSON.parse(fs.readFileSync(AUTH_FILE, "utf8"));
|
|
290
|
+
console.log(`[0dai] ${auth.email} (${auth.plan} plan)`);
|
|
291
|
+
// Get usage from API
|
|
292
|
+
const status = await apiCall("/v1/auth/status");
|
|
293
|
+
if (status.usage_today) {
|
|
294
|
+
console.log(" Usage today:");
|
|
295
|
+
for (const [k, v] of Object.entries(status.usage_today))
|
|
296
|
+
console.log(` ${k}: ${v} / ${status.limits[k]}`);
|
|
297
|
+
}
|
|
298
|
+
} catch {
|
|
299
|
+
console.log("[0dai] Not logged in. Run: 0dai auth login");
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
242
303
|
async function main() {
|
|
243
304
|
const args = process.argv.slice(2);
|
|
244
305
|
let target = process.cwd();
|
|
@@ -246,6 +307,7 @@ async function main() {
|
|
|
246
307
|
if (ti >= 0 && args[ti + 1]) { target = path.resolve(args[ti + 1]); args.splice(ti, 2); }
|
|
247
308
|
|
|
248
309
|
const cmd = args[0] || "help";
|
|
310
|
+
const sub = args[1] || "";
|
|
249
311
|
|
|
250
312
|
switch (cmd) {
|
|
251
313
|
case "init": await cmdInit(target); break;
|
|
@@ -253,15 +315,26 @@ async function main() {
|
|
|
253
315
|
case "detect": await cmdDetect(target); break;
|
|
254
316
|
case "doctor": cmdDoctor(target); break;
|
|
255
317
|
case "status": cmdStatus(target); break;
|
|
318
|
+
case "auth":
|
|
319
|
+
if (sub === "login") await cmdAuthLogin();
|
|
320
|
+
else if (sub === "logout") cmdAuthLogout();
|
|
321
|
+
else if (sub === "status") await cmdAuthStatus();
|
|
322
|
+
else {
|
|
323
|
+
console.log("Usage: 0dai auth [login|logout|status]");
|
|
324
|
+
}
|
|
325
|
+
break;
|
|
256
326
|
case "--version": console.log(`0dai ${VERSION}`); break;
|
|
257
327
|
case "help": case "--help": case "-h":
|
|
258
328
|
console.log(`0dai v${VERSION} — One config for 5 AI agent CLIs\n`);
|
|
259
329
|
console.log("Commands:");
|
|
260
|
-
console.log(" init
|
|
261
|
-
console.log(" sync
|
|
262
|
-
console.log(" detect
|
|
263
|
-
console.log(" doctor
|
|
264
|
-
console.log(" status
|
|
330
|
+
console.log(" init Initialize ai/ layer (via API)");
|
|
331
|
+
console.log(" sync Update ai/ layer (via API)");
|
|
332
|
+
console.log(" detect Show detected stack");
|
|
333
|
+
console.log(" doctor Check health");
|
|
334
|
+
console.log(" status Show maturity, swarm, session");
|
|
335
|
+
console.log(" auth login Authenticate (device code flow)");
|
|
336
|
+
console.log(" auth logout Remove credentials");
|
|
337
|
+
console.log(" auth status Show account and usage");
|
|
265
338
|
console.log(" --version\n");
|
|
266
339
|
console.log("https://0dai.dev");
|
|
267
340
|
break;
|