@0dai-dev/cli 4.2.0 → 4.3.4

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 (48) hide show
  1. package/README.md +30 -5
  2. package/bin/0dai.js +289 -60
  3. package/lib/commands/audit.js +13 -0
  4. package/lib/commands/auth.js +341 -98
  5. package/lib/commands/boneyard.js +44 -0
  6. package/lib/commands/ci.js +329 -0
  7. package/lib/commands/compliance.js +20 -0
  8. package/lib/commands/doctor.js +20 -1
  9. package/lib/commands/experience.js +5 -1
  10. package/lib/commands/feedback.js +92 -5
  11. package/lib/commands/gh.js +506 -0
  12. package/lib/commands/graph.js +78 -10
  13. package/lib/commands/heatmap.js +17 -0
  14. package/lib/commands/import_claude_code_agents.js +367 -0
  15. package/lib/commands/init.js +440 -28
  16. package/lib/commands/loop.js +108 -0
  17. package/lib/commands/mcp.js +410 -0
  18. package/lib/commands/models.js +27 -3
  19. package/lib/commands/paste.js +114 -0
  20. package/lib/commands/play.js +173 -0
  21. package/lib/commands/provider.js +69 -0
  22. package/lib/commands/quota.js +76 -0
  23. package/lib/commands/receipt.js +53 -0
  24. package/lib/commands/report.js +29 -2
  25. package/lib/commands/run.js +44 -4
  26. package/lib/commands/runner.js +527 -0
  27. package/lib/commands/session.js +1 -7
  28. package/lib/commands/standup.js +40 -0
  29. package/lib/commands/status.js +26 -1
  30. package/lib/commands/swarm.js +97 -4
  31. package/lib/commands/tui.js +81 -13
  32. package/lib/commands/usage.js +87 -0
  33. package/lib/commands/vault.js +246 -0
  34. package/lib/onboarding.js +9 -3
  35. package/lib/shared.js +29 -14
  36. package/lib/tui/index.mjs +571 -187
  37. package/lib/utils/auth.js +1 -0
  38. package/lib/utils/canonical-counts.js +54 -0
  39. package/lib/utils/diff-preview.js +192 -0
  40. package/lib/utils/identity.js +76 -18
  41. package/lib/utils/mcp-auth.js +607 -0
  42. package/lib/utils/plan.js +37 -2
  43. package/lib/vault/cipher.js +125 -0
  44. package/lib/vault/identity.js +122 -0
  45. package/lib/vault/index.js +184 -0
  46. package/lib/vault/storage.js +84 -0
  47. package/lib/wizard.js +19 -12
  48. package/package.json +2 -2
package/lib/shared.js CHANGED
@@ -60,7 +60,7 @@ const DRIFT_TRACKED_CONFIGS = [
60
60
  ];
61
61
 
62
62
  // --- API ---
63
- function apiCall(endpoint, data) {
63
+ function apiCall(endpoint, data, options = {}) {
64
64
  return new Promise((resolve) => {
65
65
  const url = new URL(endpoint, API_URL);
66
66
  const mod = url.protocol === "https:" ? https : http;
@@ -71,11 +71,16 @@ function apiCall(endpoint, data) {
71
71
  "X-CLI-Version": VERSION,
72
72
  "X-Client-Channel": "npm",
73
73
  };
74
- try {
75
- const auth = JSON.parse(fs.readFileSync(AUTH_FILE, "utf8"));
76
- const token = auth.api_key || auth.access_token || auth.token;
77
- if (token) headers["Authorization"] = `Bearer ${token}`;
78
- } catch {}
74
+ const accessToken = options && options.accessToken ? String(options.accessToken).trim() : "";
75
+ if (accessToken) {
76
+ headers["Authorization"] = `Bearer ${accessToken}`;
77
+ } else {
78
+ try {
79
+ const auth = JSON.parse(fs.readFileSync(AUTH_FILE, "utf8"));
80
+ const token = auth.api_key || auth.access_token || auth.token;
81
+ if (token) headers["Authorization"] = `Bearer ${token}`;
82
+ } catch {}
83
+ }
79
84
  const opts = {
80
85
  hostname: url.hostname,
81
86
  port: url.port || (url.protocol === "https:" ? 443 : 80),
@@ -116,12 +121,14 @@ function updateAuthState(patch) {
116
121
  saveAuthState({ ...current, ...patch });
117
122
  }
118
123
 
119
- async function fetchAuthStatus() {
120
- const status = await apiCall("/v1/auth/status");
121
- if (status && !status.error && status.email) {
124
+ async function fetchAuthStatus(accessToken = "") {
125
+ const token = String(accessToken || "").trim();
126
+ const status = await apiCall("/v1/auth/status", null, token ? { accessToken: token } : undefined);
127
+ if (status && !status.error && status.email && !token) {
122
128
  updateAuthState({
123
129
  email: status.email, plan: status.plan || "free",
124
130
  name: status.name || "", license: status.license || {},
131
+ plan_expires_at: status.plan_expires_at || "",
125
132
  });
126
133
  }
127
134
  return status;
@@ -302,6 +309,8 @@ function mergeSettingsJson(existing, incoming) {
302
309
  function writeFiles(target, files) {
303
310
  let created = 0, updated = 0, unchanged = 0, merged = 0, skipped = 0;
304
311
  const targetResolved = path.resolve(target);
312
+ let backupDir = null;
313
+ const backupConfigs = new Set(["CLAUDE.md", "AGENTS.md"]);
305
314
  for (const [rel, content] of Object.entries(files)) {
306
315
  if (typeof rel !== "string" || !rel || path.isAbsolute(rel) || rel.split(/[/\\]/).includes("..")) {
307
316
  skipped++; continue;
@@ -314,11 +323,16 @@ function writeFiles(target, files) {
314
323
  const existing = fs.readFileSync(p, "utf8");
315
324
  if (existing === content) { unchanged++; continue; }
316
325
  if (rel.endsWith("settings.json")) { finalContent = mergeSettingsJson(existing, content); merged++; }
317
- else if (rel === "AGENTS.md") {
318
- if (existing.includes("managed: false")) { unchanged++; continue; }
319
- const backupDir = path.join(target, "ai", ".backups");
320
- fs.mkdirSync(backupDir, { recursive: true });
321
- fs.writeFileSync(path.join(backupDir, "AGENTS.md.bak"), existing, "utf8");
326
+ else if (backupConfigs.has(rel)) {
327
+ if (rel === "AGENTS.md" && existing.includes("managed: false")) { unchanged++; continue; }
328
+ if (!backupDir) {
329
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
330
+ backupDir = path.join(targetResolved, "ai", ".backups", timestamp);
331
+ fs.mkdirSync(backupDir, { recursive: true });
332
+ }
333
+ const backupPath = path.join(backupDir, rel);
334
+ fs.writeFileSync(backupPath, existing, "utf8");
335
+ log(`backed up existing ${rel} to ${backupPath}`);
322
336
  updated++;
323
337
  } else { updated++; }
324
338
  } else { created++; }
@@ -337,6 +351,7 @@ function findRepoScript(target, scriptName) {
337
351
  path.join(target, "scripts", scriptName),
338
352
  path.join(process.cwd(), "scripts", scriptName),
339
353
  path.join(__dirname, "..", "..", "..", "scripts", scriptName),
354
+ path.join(__dirname, "..", "..", "..", "..", "scripts", scriptName),
340
355
  ];
341
356
  for (const c of candidates) { if (fs.existsSync(c)) return c; }
342
357
  return null;