@openma/cli 0.1.0-beta.3 → 0.1.0-beta.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 (2) hide show
  1. package/dist/index.js +101 -25
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12,12 +12,39 @@ function credentialsPath() {
12
12
  const base = xdg && xdg.length > 0 ? xdg : join(homedir(), ".config");
13
13
  return join(base, "oma", "credentials.json");
14
14
  }
15
+ function migrateV1ToV2(v1) {
16
+ return {
17
+ version: 2,
18
+ base_url: v1.base_url,
19
+ user: v1.user,
20
+ active_tenant_id: v1.tenant.id,
21
+ tenants: {
22
+ [v1.tenant.id]: {
23
+ name: v1.tenant.name,
24
+ role: v1.tenants.find((t) => t.id === v1.tenant.id)?.role ?? "owner",
25
+ token: v1.token,
26
+ key_id: v1.key_id,
27
+ created_at: v1.created_at
28
+ }
29
+ }
30
+ };
31
+ }
15
32
  function readCredentials() {
16
33
  const path = credentialsPath();
17
34
  try {
18
35
  if (!existsSync(path)) return null;
19
36
  const raw = readFileSync(path, "utf8");
20
- return JSON.parse(raw);
37
+ const parsed = JSON.parse(raw);
38
+ if (parsed.version === 2) return parsed;
39
+ if (parsed.version === 1) {
40
+ const v2 = migrateV1ToV2(parsed);
41
+ try {
42
+ writeCredentials(v2);
43
+ } catch {
44
+ }
45
+ return v2;
46
+ }
47
+ return null;
21
48
  } catch {
22
49
  return null;
23
50
  }
@@ -40,6 +67,7 @@ function clearCredentials() {
40
67
  function loadConfig() {
41
68
  const envBase = process.env.OMA_BASE_URL;
42
69
  const envKey = process.env.OMA_API_KEY;
70
+ const envTenant = process.env.OMA_TENANT_ID;
43
71
  const stored = readCredentials();
44
72
  if (envKey) {
45
73
  return {
@@ -50,9 +78,15 @@ function loadConfig() {
50
78
  };
51
79
  }
52
80
  if (stored) {
81
+ const activeId = envTenant || stored.active_tenant_id;
82
+ const profile = stored.tenants[activeId];
83
+ if (!profile) {
84
+ console.error(`Error: tenant ${activeId} not in credentials. Run: oma auth tenant ls`);
85
+ process.exit(1);
86
+ }
53
87
  return {
54
88
  baseUrl: envBase || stored.base_url,
55
- apiKey: stored.token,
89
+ apiKey: profile.token,
56
90
  json: false,
57
91
  source: "stored"
58
92
  };
@@ -65,12 +99,17 @@ function loadConfig() {
65
99
  function loadConfigOptional() {
66
100
  const envBase = process.env.OMA_BASE_URL;
67
101
  const envKey = process.env.OMA_API_KEY;
102
+ const envTenant = process.env.OMA_TENANT_ID;
68
103
  const stored = readCredentials();
69
104
  if (envKey) {
70
105
  return { baseUrl: envBase || stored?.base_url || "https://openma.dev", apiKey: envKey, json: false, source: "env" };
71
106
  }
72
107
  if (stored) {
73
- return { baseUrl: envBase || stored.base_url, apiKey: stored.token, json: false, source: "stored" };
108
+ const activeId = envTenant || stored.active_tenant_id;
109
+ const profile = stored.tenants[activeId];
110
+ if (profile) {
111
+ return { baseUrl: envBase || stored.base_url, apiKey: profile.token, json: false, source: "stored" };
112
+ }
74
113
  }
75
114
  return { baseUrl: envBase || "https://openma.dev", apiKey: "", json: false, source: "missing" };
76
115
  }
@@ -195,21 +234,35 @@ async function authLogin(baseUrl, requestedTenant) {
195
234
  });
196
235
  const tempConfig = { baseUrl, apiKey: result.token, json: false, source: "stored" };
197
236
  const me = await apiFetch(tempConfig, "/v1/me");
198
- writeCredentials({
199
- version: 1,
237
+ const existing = readCredentials();
238
+ const role = me.tenants.find((t) => t.id === me.tenant.id)?.role ?? "owner";
239
+ const updated = {
240
+ version: 2,
200
241
  base_url: baseUrl,
201
242
  user: me.user ?? { id: result.user, email: "", name: null },
202
- tenant: me.tenant,
203
- tenants: me.tenants,
204
- token: result.token,
205
- key_id: result.key_id,
206
- created_at: (/* @__PURE__ */ new Date()).toISOString()
207
- });
243
+ active_tenant_id: me.tenant.id,
244
+ tenants: {
245
+ ...existing && existing.user.id === (me.user?.id ?? result.user) ? existing.tenants : {},
246
+ [me.tenant.id]: {
247
+ name: me.tenant.name,
248
+ role,
249
+ token: result.token,
250
+ key_id: result.key_id,
251
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
252
+ }
253
+ }
254
+ };
255
+ writeCredentials(updated);
208
256
  console.log(`\u2713 Signed in as ${me.user?.email ?? me.user?.id}`);
209
257
  console.log(` Tenant : ${displayTenantName(me.tenant)} (${me.tenant.id})`);
210
258
  console.log(` Stored : ${credentialsPath()}`);
211
- if (me.tenants.length > 1) {
212
- console.log(` ${me.tenants.length} tenants available \u2014 switch with: oma auth tenant use <id>`);
259
+ const knownCount = Object.keys(updated.tenants).length;
260
+ const totalAvailable = me.tenants.length;
261
+ if (totalAvailable > knownCount) {
262
+ const missing = totalAvailable - knownCount;
263
+ console.log(` ${missing} more tenant${missing === 1 ? "" : "s"} available \u2014 add with: oma auth login --tenant <id>`);
264
+ } else if (knownCount > 1) {
265
+ console.log(` ${knownCount} tenants stored \u2014 switch with: oma auth tenant use <id>`);
213
266
  }
214
267
  }
215
268
  function displayTenantName(t) {
@@ -238,12 +291,13 @@ var commands = [
238
291
  {
239
292
  group: "Auth",
240
293
  match: ["auth", "login"],
241
- usage: "oma auth login [--base-url <url>]",
242
- desc: "Open browser to authenticate; stores ~/.config/oma/credentials.json",
294
+ usage: "oma auth login [--base-url <url>] [--tenant <id>]",
295
+ desc: "Open browser to authenticate; --tenant pre-picks a workspace",
243
296
  http: "POST /v1/me/cli-tokens (browser handoff via /cli/login)",
244
297
  async run(_config, args) {
245
298
  const baseUrl = (flag(args, "--base-url") ?? process.env.OMA_BASE_URL ?? "https://openma.dev").replace(/\/+$/, "");
246
- await authLogin(baseUrl);
299
+ const tenant = flag(args, "--tenant");
300
+ await authLogin(baseUrl, tenant);
247
301
  }
248
302
  },
249
303
  {
@@ -261,7 +315,7 @@ var commands = [
261
315
  group: "Auth",
262
316
  match: ["whoami"],
263
317
  usage: "oma whoami",
264
- desc: "Show current user, tenant, and base URL",
318
+ desc: "Show current user, active tenant, and base URL",
265
319
  http: "GET /v1/me",
266
320
  async run(config) {
267
321
  try {
@@ -273,9 +327,12 @@ var commands = [
273
327
  console.log(`Base URL : ${config.baseUrl}`);
274
328
  console.log(`Source : ${config.source === "env" ? "OMA_API_KEY env var" : "stored credentials"}`);
275
329
  console.log(`User : ${me.user?.email ?? me.user?.id ?? "(unknown \u2014 legacy key without user_id)"}`);
276
- console.log(`Tenant : ${displayTenantName(me.tenant)} (${me.tenant.id})`);
277
330
  if (me.tenants.length > 1) {
278
- console.log(`Available: ${me.tenants.map((t) => t.id).join(", ")}`);
331
+ console.log(`Tenant : ${displayTenantName(me.tenant)} (${me.tenant.id})`);
332
+ const others = me.tenants.filter((t) => t.id !== me.tenant.id);
333
+ if (others.length) {
334
+ console.log(`Available: ${others.map((t) => t.id).join(", ")} \u2014 switch with: oma auth tenant use <id>`);
335
+ }
279
336
  }
280
337
  } catch (err) {
281
338
  console.error(`whoami failed: ${err.message}`);
@@ -299,8 +356,20 @@ var commands = [
299
356
  return;
300
357
  }
301
358
  const stored = readCredentials();
302
- const current = stored?.tenant.id;
303
- table([["", "ID", "NAME", "ROLE"], ...data.map((t) => [t.id === current ? "*" : " ", t.id, t.name || "\u2014", t.role])]);
359
+ const active = stored?.active_tenant_id;
360
+ table([
361
+ ["", "ID", "NAME", "ROLE", "TOKEN"],
362
+ ...data.map((t) => [
363
+ t.id === active ? "*" : " ",
364
+ t.id,
365
+ t.name || "\u2014",
366
+ t.role,
367
+ stored?.tenants[t.id] ? "stored" : "\u2014"
368
+ ])
369
+ ]);
370
+ console.log(`
371
+ * = active. "stored" = local token cached. To switch active: oma auth tenant use <id>`);
372
+ console.log(`To add a tenant the CLI hasn't seen yet: oma auth login --tenant <id>`);
304
373
  }
305
374
  },
306
375
  {
@@ -308,9 +377,9 @@ var commands = [
308
377
  match: ["auth", "tenant", "use"],
309
378
  needsArg: true,
310
379
  usage: "oma auth tenant use <tenant-id>",
311
- desc: "Switch active tenant (mints a new CLI token for that tenant)",
312
- http: "POST /v1/me/cli-tokens {tenant_id}",
313
- async run(config, args) {
380
+ desc: "Switch active tenant; if not yet authenticated for it, opens browser to mint",
381
+ http: "(local file update \u2014 or POST /v1/me/cli-tokens via browser if no cached token)",
382
+ async run(_config, args) {
314
383
  const tenantId = args[0];
315
384
  if (!tenantId) {
316
385
  console.error("Usage: oma auth tenant use <tenant-id>");
@@ -321,7 +390,14 @@ var commands = [
321
390
  console.error("No stored credentials. Run: oma auth login");
322
391
  process.exit(1);
323
392
  }
324
- console.log(`Switching to tenant ${tenantId} \u2014 opening browser to confirm\u2026`);
393
+ if (stored.tenants[tenantId]) {
394
+ const updated = { ...stored, active_tenant_id: tenantId };
395
+ writeCredentials(updated);
396
+ const profile = stored.tenants[tenantId];
397
+ console.log(`\u2713 Active tenant: ${profile.name || tenantId} (${tenantId})`);
398
+ return;
399
+ }
400
+ console.log(`No cached token for ${tenantId}. Opening browser to authorize\u2026`);
325
401
  await authLogin(stored.base_url, tenantId);
326
402
  }
327
403
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openma/cli",
3
- "version": "0.1.0-beta.3",
3
+ "version": "0.1.0-beta.4",
4
4
  "description": "CLI for the openma managed agents platform",
5
5
  "type": "module",
6
6
  "bin": {