omnara 1.0.5 → 1.0.6

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/bin.js +297 -241
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -8,11 +8,6 @@ var __export = (target, all) => {
8
8
  // src/bin.ts
9
9
  import { Command } from "commander";
10
10
 
11
- // src/config.ts
12
- import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
13
- import { homedir } from "node:os";
14
- import { dirname, join } from "node:path";
15
-
16
11
  // ../sdk/src/generated/sdk.gen.ts
17
12
  var sdk_gen_exports = {};
18
13
  __export(sdk_gen_exports, {
@@ -1248,7 +1243,7 @@ var zConfiguredModel = z.object({
1248
1243
  context_window_tokens: z.int(),
1249
1244
  max_output_tokens: z.int(),
1250
1245
  default_max_output_tokens: z.int().nullish(),
1251
- default_cache_retention: zModelCacheRetention,
1246
+ default_cache_retention: zModelCacheRetention.optional(),
1252
1247
  supports_tools: z.boolean(),
1253
1248
  supports_reasoning: z.boolean(),
1254
1249
  default_reasoning_effort: z.string(),
@@ -6810,12 +6805,12 @@ async function pollDeviceAuthToken(options) {
6810
6805
  }
6811
6806
  }
6812
6807
 
6813
- // src/config.ts
6808
+ // src/config-file.ts
6809
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6810
+ import { homedir } from "node:os";
6811
+ import { dirname, join } from "node:path";
6814
6812
  import * as z5 from "zod";
6815
6813
 
6816
- // src/interactive.ts
6817
- import { isCancel, select } from "@clack/prompts";
6818
-
6819
6814
  // src/output.ts
6820
6815
  import * as z4 from "zod";
6821
6816
  var zRenderValue = z4.json();
@@ -7003,54 +6998,7 @@ ${z4.prettifyError(error)}`);
7003
6998
  }
7004
6999
  }
7005
7000
 
7006
- // src/interactive.ts
7007
- function canPromptInteractively() {
7008
- return process.stdin.isTTY && process.stdout.isTTY;
7009
- }
7010
- async function selectFrom(message, choices) {
7011
- const [only] = choices;
7012
- if (choices.length === 1 && only !== void 0) {
7013
- console.log(`${message}: ${only.label} (only option)`);
7014
- return only.id;
7015
- }
7016
- const picked = await select({
7017
- message,
7018
- options: choices.map((choice) => ({ value: choice.id, label: choice.label, hint: choice.id }))
7019
- });
7020
- if (isCancel(picked)) throw new CliInputError("selection cancelled");
7021
- return picked;
7022
- }
7023
- async function promptOrgSelection(client2) {
7024
- const { data } = await sdk_gen_exports.getCurrentUser({ client: client2 });
7025
- if (data.orgs.length === 0) {
7026
- throw new CliInputError("this account has no organizations");
7027
- }
7028
- return selectFrom(
7029
- "Select an organization",
7030
- data.orgs.map((org) => ({ id: org.id, label: org.name }))
7031
- );
7032
- }
7033
- async function promptProjectSelection(client2, orgId) {
7034
- const projects = [];
7035
- let cursor;
7036
- do {
7037
- const { data } = await sdk_gen_exports.listVisibleProjects({
7038
- client: client2,
7039
- path: { orgID: orgId },
7040
- query: cursor === void 0 ? {} : { cursor }
7041
- });
7042
- projects.push(...data.data.map((project) => ({ id: project.id, label: project.name })));
7043
- cursor = data.next_cursor ?? void 0;
7044
- } while (cursor !== void 0);
7045
- if (projects.length === 0) {
7046
- throw new CliInputError(`no projects visible in organization ${orgId}`);
7047
- }
7048
- return selectFrom("Select a project", projects);
7049
- }
7050
-
7051
- // src/config.ts
7052
- var DEFAULT_API_URL = "https://api.omnara.com/v1";
7053
- var DEFAULT_ISSUER_URL = "https://app.omnara.com";
7001
+ // src/config-file.ts
7054
7002
  var zConfigFile = z5.looseObject({
7055
7003
  api_url: z5.url().optional(),
7056
7004
  issuer_url: z5.url().optional(),
@@ -7113,6 +7061,234 @@ ${z5.prettifyError(result.error)}`);
7113
7061
  chmodSync(configFilePath(), 384);
7114
7062
  return result.data;
7115
7063
  }
7064
+
7065
+ // src/device-login.ts
7066
+ import { hostname } from "node:os";
7067
+ import { intro, log, note, outro, spinner } from "@clack/prompts";
7068
+ import * as z6 from "zod";
7069
+
7070
+ // src/browser.ts
7071
+ import { spawn } from "node:child_process";
7072
+ function browserCommand(url4) {
7073
+ if (process.platform === "darwin") {
7074
+ return { command: "open", args: [url4], windowsVerbatimArguments: false };
7075
+ }
7076
+ if (process.platform === "win32") {
7077
+ return {
7078
+ command: "cmd",
7079
+ args: ["/c", "start", '""', `"${url4}"`],
7080
+ windowsVerbatimArguments: true
7081
+ };
7082
+ }
7083
+ return { command: "xdg-open", args: [url4], windowsVerbatimArguments: false };
7084
+ }
7085
+ function openInBrowser(url4, onError) {
7086
+ const { command, args, windowsVerbatimArguments } = browserCommand(url4);
7087
+ const child = spawn(command, args, { stdio: "ignore", detached: true, windowsVerbatimArguments });
7088
+ child.once("error", () => {
7089
+ onError("could not open a browser; use the URL above");
7090
+ });
7091
+ child.unref();
7092
+ }
7093
+
7094
+ // src/interactive.ts
7095
+ import { isCancel, select } from "@clack/prompts";
7096
+ function canPromptInteractively() {
7097
+ return process.stdin.isTTY && process.stdout.isTTY;
7098
+ }
7099
+ async function selectFrom(message, choices) {
7100
+ const [only] = choices;
7101
+ if (choices.length === 1 && only !== void 0) {
7102
+ console.log(`${message}: ${only.label} (only option)`);
7103
+ return only.id;
7104
+ }
7105
+ const picked = await select({
7106
+ message,
7107
+ options: choices.map((choice) => ({ value: choice.id, label: choice.label, hint: choice.id }))
7108
+ });
7109
+ if (isCancel(picked)) throw new CliInputError("selection cancelled");
7110
+ return picked;
7111
+ }
7112
+ async function promptOrgSelection(client2) {
7113
+ const { data } = await sdk_gen_exports.getCurrentUser({ client: client2 });
7114
+ if (data.orgs.length === 0) {
7115
+ throw new CliInputError("this account has no organizations");
7116
+ }
7117
+ return selectFrom(
7118
+ "Select an organization",
7119
+ data.orgs.map((org) => ({ id: org.id, label: org.name }))
7120
+ );
7121
+ }
7122
+ async function promptProjectSelection(client2, orgId) {
7123
+ const projects = [];
7124
+ let cursor;
7125
+ do {
7126
+ const { data } = await sdk_gen_exports.listVisibleProjects({
7127
+ client: client2,
7128
+ path: { orgID: orgId },
7129
+ query: cursor === void 0 ? {} : { cursor }
7130
+ });
7131
+ projects.push(...data.data.map((project) => ({ id: project.id, label: project.name })));
7132
+ cursor = data.next_cursor ?? void 0;
7133
+ } while (cursor !== void 0);
7134
+ if (projects.length === 0) {
7135
+ throw new CliInputError(`no projects visible in organization ${orgId}`);
7136
+ }
7137
+ return selectFrom("Select a project", projects);
7138
+ }
7139
+
7140
+ // src/device-login.ts
7141
+ async function isProjectVisible(client2, orgId, projectId) {
7142
+ let cursor;
7143
+ do {
7144
+ const { data } = await sdk_gen_exports.listVisibleProjects({
7145
+ client: client2,
7146
+ path: { orgID: orgId },
7147
+ query: cursor === void 0 ? {} : { cursor }
7148
+ });
7149
+ if (data.data.some((project) => project.id === projectId)) return true;
7150
+ cursor = data.next_cursor ?? void 0;
7151
+ } while (cursor !== void 0);
7152
+ return false;
7153
+ }
7154
+ function interactiveReporter(title) {
7155
+ intro(title);
7156
+ const spin = spinner();
7157
+ return {
7158
+ showCode(userCode, approvalUrl) {
7159
+ note(`Code: ${userCode}
7160
+ ${approvalUrl}`, "Confirm this code in your browser");
7161
+ },
7162
+ startWaiting() {
7163
+ spin.start("Waiting for approval in your browser");
7164
+ },
7165
+ stopWaiting(approved) {
7166
+ if (approved) {
7167
+ spin.stop("Approved");
7168
+ } else {
7169
+ spin.error("Approval failed");
7170
+ }
7171
+ },
7172
+ success(message) {
7173
+ log.success(message);
7174
+ },
7175
+ info(message) {
7176
+ log.info(message);
7177
+ },
7178
+ warn(message) {
7179
+ log.warn(message);
7180
+ },
7181
+ finish(message) {
7182
+ outro(message ?? "Done");
7183
+ }
7184
+ };
7185
+ }
7186
+ function plainReporter(title) {
7187
+ console.log(title);
7188
+ return {
7189
+ showCode(userCode, approvalUrl) {
7190
+ console.log(`Confirm this code in your browser: ${userCode}`);
7191
+ console.log(`Approval page: ${approvalUrl}`);
7192
+ },
7193
+ startWaiting() {
7194
+ console.log("Waiting for approval...");
7195
+ },
7196
+ stopWaiting(approved) {
7197
+ if (approved) console.log("Approved.");
7198
+ },
7199
+ success(message) {
7200
+ console.log(message);
7201
+ },
7202
+ info(message) {
7203
+ console.log(message);
7204
+ },
7205
+ warn(message) {
7206
+ console.error(`warning: ${message}`);
7207
+ },
7208
+ finish(message) {
7209
+ if (message !== void 0) console.log(message);
7210
+ }
7211
+ };
7212
+ }
7213
+ function createLoginReporter(title) {
7214
+ return canPromptInteractively() ? interactiveReporter(title) : plainReporter(title);
7215
+ }
7216
+ function loginTokenName(explicit, hostName) {
7217
+ const candidate = explicit ?? cliLoginTokenName(hostName);
7218
+ const result = zResourceName.safeParse(candidate);
7219
+ if (result.success) return result.data;
7220
+ if (explicit === void 0) return cliLoginTokenName();
7221
+ throw new CliInputError(`invalid token name:
7222
+ ${z6.prettifyError(result.error)}`);
7223
+ }
7224
+ async function loginWithDevice(options) {
7225
+ const { report } = options;
7226
+ updateConfigFile({});
7227
+ const start = await startDeviceAuth({
7228
+ issuerUrl: options.issuerUrl,
7229
+ clientId: OMNARA_CLI_OAUTH_CLIENT_ID,
7230
+ tokenName: loginTokenName(options.tokenName, hostname())
7231
+ });
7232
+ report.showCode(start.userCode, start.verificationUriComplete);
7233
+ if (options.browser) {
7234
+ openInBrowser(start.verificationUriComplete, (message) => {
7235
+ report.warn(message);
7236
+ });
7237
+ }
7238
+ report.startWaiting();
7239
+ let token;
7240
+ try {
7241
+ token = await pollDeviceAuthToken({
7242
+ tokenEndpoint: start.tokenEndpoint,
7243
+ clientId: start.clientId,
7244
+ deviceCode: start.deviceCode,
7245
+ intervalSeconds: start.intervalSeconds
7246
+ });
7247
+ } catch (error) {
7248
+ report.stopWaiting(false);
7249
+ throw error;
7250
+ }
7251
+ report.stopWaiting(true);
7252
+ const saved = updateConfigFile({
7253
+ token,
7254
+ api_url: options.apiUrl,
7255
+ issuer_url: options.issuerUrl
7256
+ });
7257
+ const client2 = createOmnaraClient({ baseUrl: options.apiUrl, auth: bearerToken(token) });
7258
+ let orgId = saved.org_id;
7259
+ let projectId = saved.project_id;
7260
+ let loginMessage = "Logged in";
7261
+ let validationWarning;
7262
+ try {
7263
+ const { data: me } = await sdk_gen_exports.getCurrentUser({ client: client2 });
7264
+ loginMessage = `Logged in as ${me.user.email || me.user.display_name}`;
7265
+ if (orgId !== void 0 && !me.orgs.some((org) => org.id === orgId)) {
7266
+ updateConfigFile({ org_id: void 0, project_id: void 0 });
7267
+ orgId = void 0;
7268
+ projectId = void 0;
7269
+ report.warn(
7270
+ "Cleared the saved default organization and project: this account cannot access them."
7271
+ );
7272
+ } else if (orgId !== void 0 && projectId !== void 0 && !await isProjectVisible(client2, orgId, projectId)) {
7273
+ updateConfigFile({ project_id: void 0 });
7274
+ projectId = void 0;
7275
+ report.warn("Cleared the saved default project: this account cannot access it.");
7276
+ }
7277
+ } catch (error) {
7278
+ validationWarning = `could not verify the account or saved organization and project defaults: ${error instanceof Error ? error.message : String(error)}`;
7279
+ }
7280
+ report.success(loginMessage);
7281
+ report.info(`Token saved to ${configFilePath()}`);
7282
+ if (validationWarning !== void 0) report.warn(validationWarning);
7283
+ if (process.env.OMNARA_API_KEY !== void 0) {
7284
+ report.warn("OMNARA_API_KEY is set and takes precedence over the saved token");
7285
+ }
7286
+ return { token, orgId, projectId };
7287
+ }
7288
+
7289
+ // src/config.ts
7290
+ var DEFAULT_API_URL = "https://api.omnara.com/v1";
7291
+ var DEFAULT_ISSUER_URL = "https://app.omnara.com";
7116
7292
  function resolveUrls(file, env) {
7117
7293
  return {
7118
7294
  apiUrl: env.OMNARA_API_URL ?? file.api_url ?? DEFAULT_API_URL,
@@ -7124,23 +7300,58 @@ function migrateLegacyBaseUrl(file) {
7124
7300
  if (baseUrl === void 0) return void 0;
7125
7301
  return rest;
7126
7302
  }
7303
+ function createTokenResolver(options) {
7304
+ let token = options.savedToken;
7305
+ let pending;
7306
+ return () => {
7307
+ if (token !== void 0) return Promise.resolve(token);
7308
+ if (!options.canPrompt()) {
7309
+ return Promise.reject(
7310
+ new CliInputError("not logged in: run 'omnara login' or set OMNARA_API_KEY")
7311
+ );
7312
+ }
7313
+ pending ??= options.login().then((result) => {
7314
+ token = result;
7315
+ return result;
7316
+ });
7317
+ return pending;
7318
+ };
7319
+ }
7127
7320
  function loadConfig() {
7128
7321
  const loaded = readConfigFile();
7129
7322
  const migrated = migrateLegacyBaseUrl(loaded);
7130
7323
  const file = migrated === void 0 ? loaded : updateConfigFile({ ...migrated, base_url: void 0 });
7131
7324
  const { apiUrl, issuerUrl } = resolveUrls(file, process.env);
7132
- const token = process.env.OMNARA_API_KEY ?? file.token;
7325
+ let saved = { orgId: file.org_id, projectId: file.project_id };
7326
+ const resolveToken = createTokenResolver({
7327
+ savedToken: process.env.OMNARA_API_KEY ?? file.token,
7328
+ canPrompt: canPromptInteractively,
7329
+ login: async () => {
7330
+ const report = createLoginReporter(`Not logged in yet. Log in to ${issuerUrl}`);
7331
+ const login = await loginWithDevice({ apiUrl, issuerUrl, browser: true, report });
7332
+ saved = { orgId: login.orgId, projectId: login.projectId };
7333
+ report.finish("Continuing");
7334
+ return login.token;
7335
+ }
7336
+ });
7133
7337
  const client2 = createOmnaraClient({
7134
7338
  baseUrl: apiUrl,
7135
- auth: token ? bearerToken(token) : void 0,
7339
+ auth: bearerToken(resolveToken),
7136
7340
  headers: { "User-Agent": "omnara-cli" }
7137
7341
  });
7138
7342
  return {
7139
7343
  client: client2,
7140
7344
  apiUrl,
7141
7345
  issuerUrl,
7142
- defaultOrgId: process.env.OMNARA_ORG_ID ?? file.org_id,
7143
- defaultProjectId: process.env.OMNARA_PROJECT_ID ?? file.project_id
7346
+ get defaultOrgId() {
7347
+ return process.env.OMNARA_ORG_ID ?? saved.orgId;
7348
+ },
7349
+ get defaultProjectId() {
7350
+ return process.env.OMNARA_PROJECT_ID ?? saved.projectId;
7351
+ },
7352
+ ensureLoggedIn: async () => {
7353
+ await resolveToken();
7354
+ }
7144
7355
  };
7145
7356
  }
7146
7357
  function describeValue(envName, fileValue, defaultValue) {
@@ -7185,6 +7396,7 @@ function registerConfigCommand(program2, cli) {
7185
7396
  if (!canPromptInteractively()) {
7186
7397
  throw new CliInputError("interactive selection needs a terminal");
7187
7398
  }
7399
+ await cli.ensureLoggedIn();
7188
7400
  const orgId = await promptOrgSelection(cli.client);
7189
7401
  const projectId = await promptProjectSelection(cli.client, orgId);
7190
7402
  updateConfigFile({ org_id: orgId, project_id: projectId });
@@ -7195,10 +7407,10 @@ function registerConfigCommand(program2, cli) {
7195
7407
 
7196
7408
  // src/factory.ts
7197
7409
  import { InvalidArgumentError } from "commander";
7198
- import * as z7 from "zod";
7410
+ import * as z8 from "zod";
7199
7411
 
7200
7412
  // src/flags.ts
7201
- import * as z6 from "zod";
7413
+ import * as z7 from "zod";
7202
7414
  function kebabCase(name) {
7203
7415
  return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replaceAll("_", "-").toLowerCase();
7204
7416
  }
@@ -7315,21 +7527,21 @@ function finalizeFlag(draft) {
7315
7527
  };
7316
7528
  }
7317
7529
  function deriveFlags(schema) {
7318
- const jsonSchema = z6.toJSONSchema(schema, { io: "input" });
7530
+ const jsonSchema = z7.toJSONSchema(schema, { io: "input" });
7319
7531
  const drafts = /* @__PURE__ */ new Map();
7320
7532
  collectDrafts(drafts, jsonSchema, [], false);
7321
7533
  return [...drafts.values()].map(finalizeFlag);
7322
7534
  }
7323
7535
 
7324
7536
  // src/reporter.ts
7325
- import { intro, log, note, outro, spinner } from "@clack/prompts";
7326
- function interactiveReporter(title) {
7327
- intro(title);
7328
- const spin = spinner();
7537
+ import { intro as intro2, log as log2, note as note2, outro as outro2, spinner as spinner2 } from "@clack/prompts";
7538
+ function interactiveReporter2(title) {
7539
+ intro2(title);
7540
+ const spin = spinner2();
7329
7541
  let spinning = false;
7330
7542
  return {
7331
7543
  url(label, href) {
7332
- note(href, label);
7544
+ note2(href, label);
7333
7545
  },
7334
7546
  start(message) {
7335
7547
  spin.start(message);
@@ -7346,17 +7558,17 @@ function interactiveReporter(title) {
7346
7558
  spinning = false;
7347
7559
  },
7348
7560
  warn(message) {
7349
- log.warn(message);
7561
+ log2.warn(message);
7350
7562
  },
7351
7563
  info(message) {
7352
- log.info(message);
7564
+ log2.info(message);
7353
7565
  },
7354
7566
  done() {
7355
- outro("Done");
7567
+ outro2("Done");
7356
7568
  }
7357
7569
  };
7358
7570
  }
7359
- function plainReporter() {
7571
+ function plainReporter2() {
7360
7572
  return {
7361
7573
  url(label, href) {
7362
7574
  console.log(`${label}: ${href}`);
@@ -7382,7 +7594,7 @@ function plainReporter() {
7382
7594
  };
7383
7595
  }
7384
7596
  function createFlowReporter(title) {
7385
- return canPromptInteractively() ? interactiveReporter(title) : plainReporter();
7597
+ return canPromptInteractively() ? interactiveReporter2(title) : plainReporter2();
7386
7598
  }
7387
7599
 
7388
7600
  // src/factory.ts
@@ -7496,7 +7708,7 @@ function parseWithSchema(schema, value, label) {
7496
7708
  const result = schema.safeParse(value);
7497
7709
  if (!result.success) {
7498
7710
  throw new CliInputError(`invalid ${label}:
7499
- ${z7.prettifyError(result.error)}`);
7711
+ ${z8.prettifyError(result.error)}`);
7500
7712
  }
7501
7713
  return result.data;
7502
7714
  }
@@ -7504,7 +7716,7 @@ async function callOperation(spec, input) {
7504
7716
  const result = await spec.fn(input);
7505
7717
  return result.data;
7506
7718
  }
7507
- var zBodyObject = z7.looseObject({});
7719
+ var zBodyObject = z8.looseObject({});
7508
7720
  function deepMerge(base, patch) {
7509
7721
  const merged = { ...base };
7510
7722
  for (const [key, value] of Object.entries(patch)) {
@@ -7582,6 +7794,7 @@ function registerOperation(parent, config2, spec) {
7582
7794
  command.option("--json", "print the raw JSON response");
7583
7795
  command.action(async (...args) => {
7584
7796
  await runCliAction(async () => {
7797
+ await config2.ensureLoggedIn();
7585
7798
  const options = command.opts();
7586
7799
  const input = { client: config2.client };
7587
7800
  if (spec.path) {
@@ -7621,6 +7834,7 @@ function registerFlow(parent, config2, spec) {
7621
7834
  for (const flag of bodyFlags) registerFlag(command, flag);
7622
7835
  command.action(async (...args) => {
7623
7836
  await runCliAction(async () => {
7837
+ await config2.ensureLoggedIn();
7624
7838
  const options = command.opts();
7625
7839
  await spec.execute({
7626
7840
  client: config2.client,
@@ -7641,175 +7855,17 @@ function registerGroup(program2, config2, group) {
7641
7855
  }
7642
7856
 
7643
7857
  // src/login.ts
7644
- import { hostname } from "node:os";
7645
- import { intro as intro2, log as log2, note as note2, outro as outro2, spinner as spinner2 } from "@clack/prompts";
7646
- import * as z8 from "zod";
7647
-
7648
- // src/browser.ts
7649
- import { spawn } from "node:child_process";
7650
- function browserCommand(url4) {
7651
- if (process.platform === "darwin") {
7652
- return { command: "open", args: [url4], windowsVerbatimArguments: false };
7653
- }
7654
- if (process.platform === "win32") {
7655
- return {
7656
- command: "cmd",
7657
- args: ["/c", "start", '""', `"${url4}"`],
7658
- windowsVerbatimArguments: true
7659
- };
7660
- }
7661
- return { command: "xdg-open", args: [url4], windowsVerbatimArguments: false };
7662
- }
7663
- function openInBrowser(url4, onError) {
7664
- const { command, args, windowsVerbatimArguments } = browserCommand(url4);
7665
- const child = spawn(command, args, { stdio: "ignore", detached: true, windowsVerbatimArguments });
7666
- child.once("error", () => {
7667
- onError("could not open a browser; use the URL above");
7668
- });
7669
- child.unref();
7670
- }
7671
-
7672
- // src/login.ts
7673
- async function isProjectVisible(client2, orgId, projectId) {
7674
- let cursor;
7675
- do {
7676
- const { data } = await sdk_gen_exports.listVisibleProjects({
7677
- client: client2,
7678
- path: { orgID: orgId },
7679
- query: cursor === void 0 ? {} : { cursor }
7680
- });
7681
- if (data.data.some((project) => project.id === projectId)) return true;
7682
- cursor = data.next_cursor ?? void 0;
7683
- } while (cursor !== void 0);
7684
- return false;
7685
- }
7686
- function interactiveReporter2(issuerUrl) {
7687
- intro2(`Log in to ${issuerUrl}`);
7688
- const spin = spinner2();
7689
- return {
7690
- showCode(userCode, approvalUrl) {
7691
- note2(`Code: ${userCode}
7692
- ${approvalUrl}`, "Confirm this code in your browser");
7693
- },
7694
- startWaiting() {
7695
- spin.start("Waiting for approval in your browser");
7696
- },
7697
- stopWaiting(approved) {
7698
- if (approved) {
7699
- spin.stop("Approved");
7700
- } else {
7701
- spin.error("Approval failed");
7702
- }
7703
- },
7704
- success(message) {
7705
- log2.success(message);
7706
- },
7707
- info(message) {
7708
- log2.info(message);
7709
- },
7710
- warn(message) {
7711
- log2.warn(message);
7712
- },
7713
- finish(message) {
7714
- outro2(message ?? "Done");
7715
- }
7716
- };
7717
- }
7718
- function plainReporter2() {
7719
- return {
7720
- showCode(userCode, approvalUrl) {
7721
- console.log(`Confirm this code in your browser: ${userCode}`);
7722
- console.log(`Approval page: ${approvalUrl}`);
7723
- },
7724
- startWaiting() {
7725
- console.log("Waiting for approval...");
7726
- },
7727
- stopWaiting(approved) {
7728
- if (approved) console.log("Approved.");
7729
- },
7730
- success(message) {
7731
- console.log(message);
7732
- },
7733
- info(message) {
7734
- console.log(message);
7735
- },
7736
- warn(message) {
7737
- console.error(`warning: ${message}`);
7738
- },
7739
- finish(message) {
7740
- if (message !== void 0) console.log(message);
7741
- }
7742
- };
7743
- }
7744
- function loginTokenName(explicit, hostName) {
7745
- const candidate = explicit ?? cliLoginTokenName(hostName);
7746
- const result = zResourceName.safeParse(candidate);
7747
- if (result.success) return result.data;
7748
- if (explicit === void 0) return cliLoginTokenName();
7749
- throw new CliInputError(`invalid token name:
7750
- ${z8.prettifyError(result.error)}`);
7751
- }
7752
7858
  function registerLoginCommand(program2, cli) {
7753
7859
  program2.command("login").description("Log in via the browser and save an API token").option("--no-browser", "print the approval URL instead of opening a browser").option("--token-name <name>", "name for the created API token").action(async (options) => {
7754
7860
  await runCliAction(async () => {
7755
- updateConfigFile({});
7756
- const report = canPromptInteractively() ? interactiveReporter2(cli.issuerUrl) : plainReporter2();
7757
- const start = await startDeviceAuth({
7861
+ const report = createLoginReporter(`Log in to ${cli.issuerUrl}`);
7862
+ const { orgId } = await loginWithDevice({
7863
+ apiUrl: cli.apiUrl,
7758
7864
  issuerUrl: cli.issuerUrl,
7759
- clientId: OMNARA_CLI_OAUTH_CLIENT_ID,
7760
- tokenName: loginTokenName(options.tokenName, hostname())
7865
+ browser: options.browser,
7866
+ tokenName: options.tokenName,
7867
+ report
7761
7868
  });
7762
- report.showCode(start.userCode, start.verificationUriComplete);
7763
- if (options.browser) {
7764
- openInBrowser(start.verificationUriComplete, (message) => {
7765
- report.warn(message);
7766
- });
7767
- }
7768
- report.startWaiting();
7769
- let token;
7770
- try {
7771
- token = await pollDeviceAuthToken({
7772
- tokenEndpoint: start.tokenEndpoint,
7773
- clientId: start.clientId,
7774
- deviceCode: start.deviceCode,
7775
- intervalSeconds: start.intervalSeconds
7776
- });
7777
- } catch (error) {
7778
- report.stopWaiting(false);
7779
- throw error;
7780
- }
7781
- report.stopWaiting(true);
7782
- const saved = updateConfigFile({
7783
- token,
7784
- api_url: cli.apiUrl,
7785
- issuer_url: cli.issuerUrl
7786
- });
7787
- const client2 = createOmnaraClient({ baseUrl: cli.apiUrl, auth: bearerToken(token) });
7788
- let orgId = saved.org_id;
7789
- let loginMessage = "Logged in";
7790
- let validationWarning;
7791
- try {
7792
- const { data: me } = await sdk_gen_exports.getCurrentUser({ client: client2 });
7793
- loginMessage = `Logged in as ${me.user.email || me.user.display_name}`;
7794
- if (orgId !== void 0 && !me.orgs.some((org) => org.id === orgId)) {
7795
- updateConfigFile({ org_id: void 0, project_id: void 0 });
7796
- orgId = void 0;
7797
- report.warn(
7798
- "Cleared the saved default organization and project: this account cannot access them."
7799
- );
7800
- } else if (orgId !== void 0 && saved.project_id !== void 0 && !await isProjectVisible(client2, orgId, saved.project_id)) {
7801
- updateConfigFile({ project_id: void 0 });
7802
- report.warn("Cleared the saved default project: this account cannot access it.");
7803
- }
7804
- } catch (error) {
7805
- validationWarning = `could not verify the account or saved organization and project defaults: ${error instanceof Error ? error.message : String(error)}`;
7806
- }
7807
- report.success(loginMessage);
7808
- report.info(`Token saved to ${configFilePath()}`);
7809
- if (validationWarning !== void 0) report.warn(validationWarning);
7810
- if (process.env.OMNARA_API_KEY !== void 0) {
7811
- report.warn("OMNARA_API_KEY is set and takes precedence over the saved token");
7812
- }
7813
7869
  if ((process.env.OMNARA_ORG_ID ?? orgId) === void 0) {
7814
7870
  report.finish("Run 'omnara config select' to choose a default organization and project.");
7815
7871
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnara",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Command-line interface for Omnara: launch and manage agents, organizations, integrations, and MCP servers",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://omnara.com",