@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.
Files changed (2) hide show
  1. package/bin/0dai.js +78 -5
  2. 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 Initialize ai/ layer (via API)");
261
- console.log(" sync Update ai/ layer (via API)");
262
- console.log(" detect Show detected stack");
263
- console.log(" doctor Check health");
264
- console.log(" status Show maturity, swarm, session");
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0dai-dev/cli",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "One config layer for 5 AI agent CLIs — Claude Code, Codex, OpenCode, Gemini, Aider",
5
5
  "bin": {
6
6
  "0dai": "./bin/0dai.js"