omnara 0.3.2 → 0.4.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/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ const __dirname = pathShim.dirname(__filename);
7
7
  // src/cli.ts
8
8
  import path15 from "path";
9
9
  import { Command as Command4 } from "commander";
10
- import * as Sentry28 from "@sentry/node";
10
+ import * as Sentry27 from "@sentry/node";
11
11
 
12
12
  // src/commands/agent.ts
13
13
  import fs5 from "node:fs";
@@ -908,9 +908,7 @@ var CredentialsStore = class {
908
908
  async save(credentials) {
909
909
  await this.withLock(async () => {
910
910
  const payload = {
911
- accessToken: credentials.accessToken,
912
- accessTokenExpiresAt: credentials.accessTokenExpiresAt,
913
- refreshToken: credentials.refreshToken
911
+ pat: credentials.pat
914
912
  };
915
913
  await fs2.mkdir(path3.dirname(this.filePath), { recursive: true, mode: DEFAULT_DIR_MODE });
916
914
  const tempPath = `${this.filePath}.tmp`;
@@ -2494,7 +2492,7 @@ import { randomUUID as randomUUID5 } from "crypto";
2494
2492
  import EventEmitter from "events";
2495
2493
  import WebSocket from "ws";
2496
2494
  import { simpleGit as simpleGit2 } from "simple-git";
2497
- import * as Sentry13 from "@sentry/node";
2495
+ import * as Sentry12 from "@sentry/node";
2498
2496
 
2499
2497
  // ../shared-js/dist/api/base.js
2500
2498
  var ApiError = class extends Error {
@@ -6186,345 +6184,41 @@ async function registerRelaySession(client, accessToken, options) {
6186
6184
  }
6187
6185
 
6188
6186
  // src/auth/auth-provider.ts
6189
- import { setTimeout as delay3 } from "node:timers/promises";
6190
- import * as Sentry12 from "@sentry/node";
6191
-
6192
- // src/auth/credential-manager.ts
6193
- import { setTimeout as delay2 } from "node:timers/promises";
6194
- import * as Sentry8 from "@sentry/node";
6195
-
6196
- // src/auth/supabase-client.ts
6197
- import { createClient } from "@supabase/supabase-js";
6198
-
6199
- // src/package-info.ts
6200
- import { createRequire } from "node:module";
6201
- var require2 = createRequire(import.meta.url);
6202
- var pkg = require2("../package.json");
6203
- var FALLBACK_NAME = pkg.name ?? "omnara";
6204
- var FALLBACK_VERSION = pkg.version ?? "0.0.0";
6205
- var FALLBACK_DESCRIPTION = pkg.description ?? "Command-line interface for Omnara.";
6206
- var PACKAGE_NAME = true ? "omnara" : FALLBACK_NAME;
6207
- var PACKAGE_VERSION = true ? "0.3.2" : FALLBACK_VERSION;
6208
- var PACKAGE_DESCRIPTION = true ? "Command-line interface for Omnara." : FALLBACK_DESCRIPTION;
6209
-
6210
- // src/auth/supabase-client.ts
6211
- var CLIENT_INFO_HEADER = `${PACKAGE_NAME}/${PACKAGE_VERSION}`;
6212
- var singleton = null;
6213
- function getSupabaseClient(config) {
6214
- if (singleton) {
6215
- return singleton;
6216
- }
6217
- singleton = createClient(config.url, config.anonKey, {
6218
- auth: {
6219
- autoRefreshToken: false,
6220
- persistSession: false,
6221
- detectSessionInUrl: false
6222
- },
6223
- global: {
6224
- headers: {
6225
- "X-Client-Info": CLIENT_INFO_HEADER
6226
- }
6227
- }
6228
- });
6229
- return singleton;
6230
- }
6231
-
6232
- // src/auth/supabase-config.ts
6233
- var CACHE = /* @__PURE__ */ new Map();
6234
- async function getSupabaseAuthConfig(baseUrl) {
6235
- const normalized = normalizeBaseUrl2(baseUrl);
6236
- const cached = CACHE.get(normalized);
6237
- if (cached) {
6238
- return cached;
6239
- }
6240
- const client = new ApiClient({ baseUrl: normalized });
6241
- const response = await client.getJson("/api/v1/auth/config");
6242
- const config = {
6243
- url: response.supabase_url,
6244
- anonKey: response.supabase_anon_key
6245
- };
6246
- CACHE.set(normalized, config);
6247
- return config;
6248
- }
6249
- function normalizeBaseUrl2(raw) {
6250
- return raw.endsWith("/") ? raw : `${raw}/`;
6251
- }
6187
+ import * as Sentry11 from "@sentry/node";
6252
6188
 
6253
6189
  // src/auth/credential-manager.ts
6254
- var EXPIRY_BUFFER_MS = 6e4;
6255
- var AUTH_REQUEST_TIMEOUT_MS = 15e3;
6256
6190
  var AuthContextError = class extends Error {
6257
6191
  code;
6258
- status;
6259
6192
  constructor(message, code, options) {
6260
6193
  super(message, { cause: options?.cause });
6261
6194
  this.name = "AuthContextError";
6262
6195
  this.code = code;
6263
- this.status = options?.status;
6264
6196
  }
6265
6197
  };
6266
- async function ensureAuthContext(store, backendUrl, initialCredentials, options = {}) {
6198
+ async function ensureAuthContext(store, initialCredentials) {
6267
6199
  const credentials = initialCredentials ?? await store.load();
6268
- if (!credentials) {
6200
+ const rawPat = credentials?.pat;
6201
+ if (!credentials || rawPat === void 0 || rawPat === null) {
6269
6202
  throw new AuthContextError(
6270
6203
  "No credentials found. Run `omnara auth login` first.",
6271
6204
  "missing_credentials"
6272
6205
  );
6273
6206
  }
6274
- if (!credentials.refreshToken) {
6275
- throw new AuthContextError(
6276
- "Refresh token unavailable. Please run `omnara auth login`.",
6277
- "refresh_token_unavailable"
6278
- );
6279
- }
6280
- if (!credentials.accessToken) {
6281
- return await refreshWithStoredToken(
6282
- store,
6283
- credentials,
6284
- backendUrl,
6285
- "access_token_missing",
6286
- options
6287
- );
6288
- }
6289
- if (!isExpiring(credentials.accessTokenExpiresAt, EXPIRY_BUFFER_MS)) {
6290
- return { credentials, accessToken: credentials.accessToken };
6291
- }
6292
- return await refreshWithStoredToken(
6293
- store,
6294
- credentials,
6295
- backendUrl,
6296
- "access_token_expired",
6297
- options
6298
- );
6299
- }
6300
- async function refreshWithStoredToken(store, credentials, backendUrl, reasonCode, options) {
6301
- const reasonMessage = reasonCode === "access_token_missing" ? "No access token stored." : "Access token expired.";
6302
- return await store.withLock(async () => {
6303
- const latest = await store.load();
6304
- const effective = latest ?? credentials;
6305
- if (effective.accessToken && !isExpiring(effective.accessTokenExpiresAt, EXPIRY_BUFFER_MS)) {
6306
- return { credentials: effective, accessToken: effective.accessToken };
6307
- }
6308
- const refreshToken = effective.refreshToken;
6309
- if (!refreshToken) {
6310
- throw new AuthContextError(
6311
- `Cannot refresh Supabase session because no refresh token is stored. Please run \`omnara auth login\`.`,
6312
- "refresh_token_unavailable"
6313
- );
6314
- }
6315
- const session = await refreshSupabaseSession({
6316
- backendUrl,
6317
- refreshToken,
6318
- reasonMessage,
6319
- logger: options.logger
6320
- });
6321
- const updated = applySession(effective, session);
6322
- await store.save(updated);
6323
- if (!updated.accessToken) {
6324
- throw new AuthContextError(
6325
- "Supabase refresh completed without an access token.",
6326
- "refresh_failed"
6327
- );
6328
- }
6329
- return { credentials: updated, accessToken: updated.accessToken };
6330
- });
6331
- }
6332
- var MAX_REFRESH_ATTEMPTS = 3;
6333
- var REFRESH_RETRY_DELAY_MS = 500;
6334
- var INVALID_REFRESH_ERROR_CODES = /* @__PURE__ */ new Set([
6335
- "invalid_grant",
6336
- "refresh_token_not_found",
6337
- "refresh_token_already_used",
6338
- "session_not_found",
6339
- "session_expired"
6340
- ]);
6341
- var INVALID_REFRESH_ERROR_PHRASES = [
6342
- "invalid refresh token",
6343
- "refresh token not found",
6344
- "refresh_token_not_found",
6345
- "refresh token already used",
6346
- "refresh token is expired",
6347
- "session not found",
6348
- "session expired",
6349
- "invalid_grant"
6350
- ];
6351
- async function refreshSupabaseSession(options) {
6352
- const supabase = await createSupabaseClientWithRetry(
6353
- options.backendUrl,
6354
- options.reasonMessage,
6355
- options.logger
6356
- );
6357
- let attempt = 0;
6358
- let lastError = null;
6359
- while (attempt < MAX_REFRESH_ATTEMPTS) {
6360
- attempt += 1;
6361
- try {
6362
- options.logger?.debug?.(
6363
- `Refreshing Supabase session (attempt ${attempt}/${MAX_REFRESH_ATTEMPTS}).`
6364
- );
6365
- const result = await withTimeout(
6366
- supabase.auth.refreshSession({ refresh_token: options.refreshToken }),
6367
- AUTH_REQUEST_TIMEOUT_MS,
6368
- () => new AuthContextError(
6369
- `${options.reasonMessage} Supabase session refresh timed out after ${AUTH_REQUEST_TIMEOUT_MS}ms.`,
6370
- "network_error"
6371
- )
6372
- );
6373
- const { data, error } = result;
6374
- if (error || !data?.session) {
6375
- const status = typeof error?.status === "number" ? error.status : void 0;
6376
- const loginRequired = isInvalidRefreshTokenError(error);
6377
- const code = loginRequired ? "refresh_failed" : "network_error";
6378
- Sentry8.captureException(error);
6379
- throw new AuthContextError(
6380
- `${options.reasonMessage} Failed to refresh Supabase session: ${error?.message ?? "unknown error"}.`,
6381
- code,
6382
- { cause: error, status }
6383
- );
6384
- }
6385
- return data.session;
6386
- } catch (error) {
6387
- const authError = error instanceof AuthContextError ? error : new AuthContextError(
6388
- `${options.reasonMessage} Failed to refresh Supabase session: ${extractErrorMessage4(error)}.`,
6389
- "network_error",
6390
- { cause: error }
6391
- );
6392
- lastError = authError;
6393
- options.logger?.debug?.(
6394
- `Supabase refresh failed (status ${authError.status ?? "unknown"}): ${authError.message}`
6395
- );
6396
- if (authError.code === "network_error" && attempt < MAX_REFRESH_ATTEMPTS) {
6397
- options.logger?.debug?.("Retrying Supabase refresh after transient error.");
6398
- await delay2(REFRESH_RETRY_DELAY_MS * attempt);
6399
- continue;
6400
- }
6401
- Sentry8.captureException(authError);
6402
- throw authError;
6403
- }
6404
- }
6405
- throw lastError ?? new AuthContextError(
6406
- `${options.reasonMessage} Failed to refresh Supabase session after multiple attempts.`,
6407
- "network_error"
6408
- );
6409
- }
6410
- async function createSupabaseClientWithRetry(backendUrl, reasonMessage, logger3) {
6411
- let attempt = 0;
6412
- let lastError = null;
6413
- while (attempt < MAX_REFRESH_ATTEMPTS) {
6414
- attempt += 1;
6415
- try {
6416
- logger3?.debug?.(
6417
- `Loading Supabase auth configuration (attempt ${attempt}/${MAX_REFRESH_ATTEMPTS}).`
6418
- );
6419
- return await createSupabaseClient(backendUrl, reasonMessage);
6420
- } catch (error) {
6421
- const authError = error instanceof AuthContextError ? error : new AuthContextError(
6422
- `${reasonMessage} Failed to load Supabase configuration: ${extractErrorMessage4(error)}.`,
6423
- "network_error",
6424
- { cause: error }
6425
- );
6426
- lastError = authError;
6427
- if (authError.code === "network_error" && attempt < MAX_REFRESH_ATTEMPTS) {
6428
- logger3?.debug?.("Retrying Supabase auth configuration load after transient error.");
6429
- await delay2(REFRESH_RETRY_DELAY_MS * attempt);
6430
- continue;
6431
- }
6432
- throw authError;
6433
- }
6434
- }
6435
- throw lastError ?? new AuthContextError(
6436
- `${reasonMessage} Failed to load Supabase configuration after multiple attempts.`,
6437
- "network_error"
6438
- );
6439
- }
6440
- async function createSupabaseClient(backendUrl, reasonMessage) {
6441
- try {
6442
- const supabaseConfig = await withTimeout(
6443
- getSupabaseAuthConfig(backendUrl),
6444
- AUTH_REQUEST_TIMEOUT_MS,
6445
- () => new AuthContextError(
6446
- `${reasonMessage} Failed to load Supabase configuration: request timed out after ${AUTH_REQUEST_TIMEOUT_MS}ms.`,
6447
- "network_error"
6448
- )
6449
- );
6450
- return getSupabaseClient(supabaseConfig);
6451
- } catch (error) {
6452
- Sentry8.captureException(error);
6207
+ const pat = rawPat.trim();
6208
+ if (!pat) {
6453
6209
  throw new AuthContextError(
6454
- `${reasonMessage} Failed to load Supabase configuration: ${extractErrorMessage4(error)}.`,
6455
- "network_error",
6456
- { cause: error }
6210
+ "Stored credentials are invalid. Please run `omnara auth login`.",
6211
+ "invalid_credentials"
6457
6212
  );
6458
6213
  }
6459
- }
6460
- function isExpiring(expiresAtIso, bufferMs) {
6461
- if (!expiresAtIso) {
6462
- return true;
6463
- }
6464
- const timestamp = Date.parse(expiresAtIso);
6465
- if (Number.isNaN(timestamp)) {
6466
- return true;
6467
- }
6468
- return timestamp - bufferMs <= Date.now();
6469
- }
6470
- function applySession(credentials, session) {
6471
- const expiresAt = deriveAccessExpiry(session);
6472
6214
  return {
6473
- ...credentials,
6474
- accessToken: session.access_token,
6475
- accessTokenExpiresAt: expiresAt,
6476
- refreshToken: session.refresh_token ?? credentials.refreshToken
6215
+ credentials: { pat },
6216
+ pat
6477
6217
  };
6478
6218
  }
6479
- function deriveAccessExpiry(session) {
6480
- if (session.expires_at) {
6481
- return new Date(session.expires_at * 1e3).toISOString();
6482
- }
6483
- if (session.expires_in) {
6484
- return new Date(Date.now() + session.expires_in * 1e3).toISOString();
6485
- }
6486
- return void 0;
6487
- }
6488
- function extractErrorMessage4(error) {
6489
- if (error instanceof Error && error.message) {
6490
- return error.message;
6491
- }
6492
- return String(error);
6493
- }
6494
- function isInvalidRefreshTokenError(error) {
6495
- if (!error) {
6496
- return false;
6497
- }
6498
- const statusField = error.status;
6499
- const status = typeof statusField === "number" ? statusField : void 0;
6500
- const codeRaw = error.code;
6501
- const code = typeof codeRaw === "string" ? codeRaw.toLowerCase() : "";
6502
- const messageRaw = error.message;
6503
- const message = typeof messageRaw === "string" ? messageRaw.toLowerCase() : "";
6504
- if (INVALID_REFRESH_ERROR_CODES.has(code)) {
6505
- return true;
6506
- }
6507
- if ((status === 400 || status === 401) && INVALID_REFRESH_ERROR_PHRASES.some((phrase) => message.includes(phrase))) {
6508
- return true;
6509
- }
6510
- return false;
6511
- }
6512
- async function withTimeout(promise, timeoutMs, onTimeout) {
6513
- let timeoutHandle = null;
6514
- try {
6515
- const timeoutPromise = new Promise((_, reject) => {
6516
- timeoutHandle = setTimeout(() => reject(onTimeout()), timeoutMs);
6517
- });
6518
- return await Promise.race([promise, timeoutPromise]);
6519
- } finally {
6520
- if (timeoutHandle) {
6521
- clearTimeout(timeoutHandle);
6522
- }
6523
- }
6524
- }
6525
6219
 
6526
6220
  // src/auth/login-flow.ts
6527
- import * as Sentry11 from "@sentry/node";
6221
+ import * as Sentry10 from "@sentry/node";
6528
6222
 
6529
6223
  // src/utils/prompt.ts
6530
6224
  import readline from "readline/promises";
@@ -6603,7 +6297,7 @@ function base64UrlEncode(input2) {
6603
6297
  // src/auth/loopback-listener.ts
6604
6298
  import http from "http";
6605
6299
  import { randomBytes as randomBytes2 } from "crypto";
6606
- import * as Sentry9 from "@sentry/node";
6300
+ import * as Sentry8 from "@sentry/node";
6607
6301
  var CALLBACK_PATH = "/callback";
6608
6302
  var LISTEN_HOST = "127.0.0.1";
6609
6303
  var LoopbackListener = class _LoopbackListener {
@@ -6613,7 +6307,7 @@ var LoopbackListener = class _LoopbackListener {
6613
6307
  await listener.start();
6614
6308
  return listener;
6615
6309
  } catch (error) {
6616
- Sentry9.captureException(error);
6310
+ Sentry8.captureException(error);
6617
6311
  await listener.stop().catch(() => void 0);
6618
6312
  return null;
6619
6313
  }
@@ -6759,7 +6453,7 @@ function buildMessageHtml(message) {
6759
6453
 
6760
6454
  // src/utils/browser.ts
6761
6455
  import { spawn } from "child_process";
6762
- import * as Sentry10 from "@sentry/node";
6456
+ import * as Sentry9 from "@sentry/node";
6763
6457
  var buildBrowserFailureMessage = (url) => `Unable to automatically open ${url}. Please copy and paste this link into your browser.`;
6764
6458
  var escapeForPowerShell = (value) => value.replace(/'/g, "''");
6765
6459
  function tryOpenBrowser(url) {
@@ -6788,11 +6482,11 @@ function tryOpenBrowser(url) {
6788
6482
  if (process.env.DEBUG && error) {
6789
6483
  const details = error instanceof Error ? error.message : String(error);
6790
6484
  console.warn(`${baseMessage} (${details}).`);
6791
- Sentry10.captureException(error);
6485
+ Sentry9.captureException(error);
6792
6486
  return;
6793
6487
  }
6794
6488
  if (error) {
6795
- Sentry10.captureException(error);
6489
+ Sentry9.captureException(error);
6796
6490
  }
6797
6491
  console.warn(baseMessage);
6798
6492
  };
@@ -6848,9 +6542,8 @@ async function performVerificationLogin({
6848
6542
  code,
6849
6543
  codeVerifier ? { codeVerifier } : {}
6850
6544
  );
6851
- const updated = mergeCredentialsAfterExchange({
6852
- exchange
6853
- });
6545
+ const pat = await issuePatToken(client, exchange.accessToken);
6546
+ const updated = { pat };
6854
6547
  await store.save(updated);
6855
6548
  latestCredentials = updated;
6856
6549
  if (!successLogged) {
@@ -6897,7 +6590,7 @@ async function performVerificationLogin({
6897
6590
  break;
6898
6591
  }
6899
6592
  }
6900
- Sentry11.captureException(error);
6593
+ Sentry10.captureException(error);
6901
6594
  await loopback?.stop();
6902
6595
  throw error;
6903
6596
  }
@@ -6923,33 +6616,13 @@ function resolveFrontendUrl(option) {
6923
6616
  const candidate = option ?? process.env.OMNARA_FRONTEND_URL ?? DEFAULT_FRONTEND_URL;
6924
6617
  return normalizeBaseUrl(candidate);
6925
6618
  }
6926
- function mergeCredentialsAfterExchange(args) {
6927
- const now = Date.now();
6928
- const accessExpiresAt = new Date(now + args.exchange.accessTokenExpiresIn * 1e3).toISOString();
6929
- return {
6930
- accessToken: args.exchange.accessToken,
6931
- accessTokenExpiresAt: accessExpiresAt,
6932
- refreshToken: args.exchange.refreshToken
6933
- };
6934
- }
6935
- function formatDuration(ms) {
6936
- const totalSeconds = Math.round(ms / 1e3);
6937
- if (totalSeconds < 60) {
6938
- return `${totalSeconds}s`;
6939
- }
6940
- const totalMinutes = Math.round(totalSeconds / 60);
6941
- if (totalMinutes < 60) {
6942
- const seconds = totalSeconds % 60;
6943
- return seconds > 0 ? `${totalMinutes}m ${seconds}s` : `${totalMinutes}m`;
6944
- }
6945
- const totalHours = Math.floor(totalMinutes / 60);
6946
- const minutes = totalMinutes % 60;
6947
- if (totalHours < 48) {
6948
- return minutes > 0 ? `${totalHours}h ${minutes}m` : `${totalHours}h`;
6949
- }
6950
- const totalDays = Math.floor(totalHours / 24);
6951
- const hours = totalDays % 24;
6952
- return hours > 0 ? `${totalDays}d ${hours}h` : `${totalDays}d`;
6619
+ async function issuePatToken(client, accessToken) {
6620
+ const response = await client.postJson(
6621
+ "/api/v1/auth/pat",
6622
+ {},
6623
+ { accessToken }
6624
+ );
6625
+ return response.token;
6953
6626
  }
6954
6627
  function reportLoopbackError(error) {
6955
6628
  if (error instanceof ApiError) {
@@ -6958,8 +6631,8 @@ function reportLoopbackError(error) {
6958
6631
  );
6959
6632
  return;
6960
6633
  }
6961
- Sentry11.captureException(error);
6962
- console.log(`Automatic login failed: ${extractErrorMessage5(error)}`);
6634
+ Sentry10.captureException(error);
6635
+ console.log(`Automatic login failed: ${extractErrorMessage4(error)}`);
6963
6636
  }
6964
6637
  function printSessionInstructions(session) {
6965
6638
  console.log(
@@ -6968,7 +6641,7 @@ function printSessionInstructions(session) {
6968
6641
  console.log(chalk.blueBright.underline(`${session.verificationUriComplete}`));
6969
6642
  console.log(chalk.blue("\nApprove the request, then return to the CLI."));
6970
6643
  }
6971
- function extractErrorMessage5(error) {
6644
+ function extractErrorMessage4(error) {
6972
6645
  if (error instanceof Error && error.message) {
6973
6646
  return error.message;
6974
6647
  }
@@ -6991,96 +6664,57 @@ async function waitForLoopback(listener, sessionId, onCode) {
6991
6664
  reportLoopbackError(error);
6992
6665
  }
6993
6666
  } catch (error) {
6994
- Sentry11.captureException(error);
6995
- console.log(`Loopback listener error: ${extractErrorMessage5(error)}`);
6667
+ Sentry10.captureException(error);
6668
+ console.log(`Loopback listener error: ${extractErrorMessage4(error)}`);
6996
6669
  }
6997
6670
  }
6998
6671
 
6999
6672
  // src/auth/auth-provider.ts
7000
- var TOKEN_REFRESH_BUFFER_MS = 6e4;
7001
- var AUTH_RETRY_BASE_MS = 500;
7002
- var AUTH_RETRY_MAX_MS = 5e3;
7003
6673
  var AuthProvider = class {
7004
6674
  constructor(options) {
7005
6675
  this.options = options;
7006
6676
  this.backendUrl = normalizeBaseUrl(options.backendUrl);
6677
+ this.defaultInteractive = options.interactive ?? true;
7007
6678
  }
7008
- cached = null;
7009
- inflight = null;
6679
+ lastBadPat = null;
6680
+ defaultInteractive;
7010
6681
  backendUrl;
7011
- lastBadCredentials = null;
7012
6682
  async getAuthContext(options) {
7013
- const interactive = options?.interactive ?? true;
7014
- const snapshot = await this.options.store.load();
7015
- const useCache = this.cached && isAccessTokenFresh(this.cached) && credentialsEqual(this.cached.credentials, snapshot ?? null);
7016
- if (useCache && this.cached) {
7017
- return this.cached;
7018
- }
7019
- let inflight = this.inflight;
7020
- if (!inflight) {
7021
- const pending = this.loadAuthContext(interactive);
7022
- inflight = pending.finally(() => {
7023
- if (this.inflight === inflight) {
7024
- this.inflight = null;
7025
- }
7026
- });
7027
- this.inflight = inflight;
7028
- }
7029
- const auth = await inflight;
7030
- this.cached = auth;
7031
- return auth;
6683
+ const interactive = options?.interactive ?? this.defaultInteractive;
6684
+ return await this.loadAuthContext(interactive);
7032
6685
  }
7033
6686
  async getAccessToken(options) {
7034
6687
  const auth = await this.getAuthContext(options);
7035
- return auth.accessToken;
6688
+ return auth.pat;
7036
6689
  }
7037
6690
  async loadAuthContext(interactive) {
7038
- let attempt = 0;
7039
- while (true) {
7040
- attempt += 1;
7041
- const snapshot = await this.options.store.load();
7042
- if (this.lastBadCredentials && credentialsEqual(snapshot ?? null, this.lastBadCredentials)) {
7043
- throw new AuthContextError(
7044
- "Stored credentials unchanged since invalid refresh token. Please log in.",
7045
- "refresh_failed"
7046
- );
6691
+ const snapshot = await this.options.store.load();
6692
+ if (this.lastBadPat && snapshot?.pat === this.lastBadPat) {
6693
+ throw new AuthContextError(
6694
+ "Stored credentials unchanged since invalid PAT. Please log in.",
6695
+ "invalid_credentials"
6696
+ );
6697
+ }
6698
+ try {
6699
+ const context = await ensureAuthContext(this.options.store, snapshot);
6700
+ this.lastBadPat = null;
6701
+ return context;
6702
+ } catch (error) {
6703
+ const authError = error instanceof AuthContextError ? error : null;
6704
+ if (authError?.code === "invalid_credentials") {
6705
+ this.lastBadPat = snapshot?.pat ?? null;
7047
6706
  }
7048
- try {
7049
- const context = await ensureAuthContext(this.options.store, this.backendUrl, snapshot, {
7050
- logger: this.options.logger
7051
- });
7052
- this.cached = context;
7053
- this.lastBadCredentials = null;
7054
- return context;
7055
- } catch (error) {
7056
- const authError = error instanceof AuthContextError ? error : null;
7057
- if (authError?.code === "refresh_failed") {
7058
- this.lastBadCredentials = snapshot ?? null;
7059
- }
7060
- if (authError) {
7061
- Sentry12.captureException(authError);
7062
- } else {
7063
- Sentry12.captureException(error);
7064
- }
7065
- if (authError && shouldAttemptLogin(authError)) {
7066
- if (!interactive) {
7067
- throw authError;
7068
- }
7069
- await this.performLogin();
7070
- continue;
7071
- }
7072
- if (authError && !shouldRetryAuth(authError)) {
7073
- throw authError;
7074
- }
7075
- const delayMs = Math.min(
7076
- AUTH_RETRY_BASE_MS * 2 ** Math.min(attempt - 1, 6),
7077
- AUTH_RETRY_MAX_MS
7078
- );
7079
- this.options.logger?.debug?.(
7080
- `Auth transient error (${extractErrorMessage6(authError ?? error)}). Retrying in ${delayMs}ms\u2026`
7081
- );
7082
- await delay3(delayMs + Math.floor(Math.random() * 100));
6707
+ if (authError) {
6708
+ Sentry11.captureException(authError);
6709
+ } else {
6710
+ Sentry11.captureException(error);
6711
+ }
6712
+ if (!interactive) {
6713
+ throw authError ?? error;
7083
6714
  }
6715
+ await this.performLogin();
6716
+ const updated = await this.options.store.load();
6717
+ return await ensureAuthContext(this.options.store, updated);
7084
6718
  }
7085
6719
  }
7086
6720
  async performLogin() {
@@ -7093,74 +6727,10 @@ var AuthProvider = class {
7093
6727
  });
7094
6728
  }
7095
6729
  };
7096
- function isAccessTokenFresh(context) {
7097
- const expiresAt = context.credentials.accessTokenExpiresAt;
7098
- if (!expiresAt) {
7099
- return false;
7100
- }
7101
- const timestamp = Date.parse(expiresAt);
7102
- if (Number.isNaN(timestamp)) {
7103
- return false;
7104
- }
7105
- return timestamp - TOKEN_REFRESH_BUFFER_MS > Date.now();
7106
- }
7107
- function shouldAttemptLogin(error) {
7108
- if (error instanceof AuthContextError) {
7109
- return authContextErrorRequiresLogin(error);
7110
- }
7111
- return false;
7112
- }
7113
- function authContextErrorRequiresLogin(error) {
7114
- switch (error.code) {
7115
- case "missing_credentials":
7116
- case "refresh_token_unavailable":
7117
- case "refresh_failed":
7118
- return true;
7119
- default:
7120
- return false;
7121
- }
7122
- }
7123
- function shouldRetryAuth(error) {
7124
- if (error.code !== "network_error") {
7125
- return false;
7126
- }
7127
- if (typeof error.status === "number" && error.status === 429) {
7128
- return true;
7129
- }
7130
- if (isLockErrorMessage(error.message)) {
7131
- return true;
7132
- }
7133
- if (typeof error.status === "number" && error.status >= 500) {
7134
- return true;
7135
- }
7136
- if (typeof error.status !== "number") {
7137
- return true;
7138
- }
7139
- return false;
7140
- }
7141
- function credentialsEqual(a, b) {
7142
- if (!a && !b) {
7143
- return true;
7144
- }
7145
- if (!a || !b) {
7146
- return false;
7147
- }
7148
- return a.accessToken === b.accessToken && a.accessTokenExpiresAt === b.accessTokenExpiresAt && a.refreshToken === b.refreshToken;
7149
- }
7150
6730
  async function createAuthProvider(options) {
7151
6731
  const provider = new AuthProvider(options);
7152
6732
  return provider;
7153
6733
  }
7154
- function isLockErrorMessage(message) {
7155
- const lower = message.toLowerCase();
7156
- return lower.includes("credentials lock") || lower.includes("acquiring credentials lock");
7157
- }
7158
- function extractErrorMessage6(error) {
7159
- if (error instanceof Error && error.message) {
7160
- return error.message;
7161
- }
7162
- return String(error);
7163
- }
7164
6734
 
7165
6735
  // src/http/user-sessions.ts
7166
6736
  async function ensureUserSession(client, accessToken, options) {
@@ -7246,7 +6816,7 @@ var RelayBridge = class extends EventEmitter {
7246
6816
  } else {
7247
6817
  this.logger.debug("Relay bridge still waiting for credentials...");
7248
6818
  }
7249
- await delay4(LOGIN_WAIT_DELAY_MS);
6819
+ await delay2(LOGIN_WAIT_DELAY_MS);
7250
6820
  continue;
7251
6821
  }
7252
6822
  const aborted = isAbortError(error);
@@ -7256,11 +6826,11 @@ var RelayBridge = class extends EventEmitter {
7256
6826
  }
7257
6827
  break;
7258
6828
  }
7259
- Sentry13.captureException(error);
6829
+ Sentry12.captureException(error);
7260
6830
  this.logger.error(
7261
- `Relay connection failed: ${extractErrorMessage7(error)}. Retrying in ${Math.round(backoffMs / 1e3)}s.`
6831
+ `Relay connection failed: ${extractErrorMessage5(error)}. Retrying in ${Math.round(backoffMs / 1e3)}s.`
7262
6832
  );
7263
- await delay4(backoffMs);
6833
+ await delay2(backoffMs);
7264
6834
  backoffMs = Math.min(backoffMs * 2, 3e4);
7265
6835
  }
7266
6836
  }
@@ -7297,7 +6867,6 @@ var RelayBridge = class extends EventEmitter {
7297
6867
  const url = buildRelayWebsocketUrl(this.backendUrl, registration.relayWsPath);
7298
6868
  const ws = new WebSocket(url, {
7299
6869
  headers: {
7300
- authorization: `Bearer ${accessToken}`,
7301
6870
  "x-relay-token": registration.relayToken
7302
6871
  }
7303
6872
  });
@@ -7383,8 +6952,8 @@ var RelayBridge = class extends EventEmitter {
7383
6952
  target.send(serialized);
7384
6953
  return;
7385
6954
  } catch (error) {
7386
- Sentry13.captureException(error);
7387
- this.logger.error(`Failed to send relay frame: ${extractErrorMessage7(error)}`);
6955
+ Sentry12.captureException(error);
6956
+ this.logger.error(`Failed to send relay frame: ${extractErrorMessage5(error)}`);
7388
6957
  if (target === this.ws) {
7389
6958
  this.closeCurrentSocket();
7390
6959
  }
@@ -7417,7 +6986,7 @@ var RelayBridge = class extends EventEmitter {
7417
6986
  };
7418
6987
  const onError = (error) => {
7419
6988
  if (!this.stopped) {
7420
- Sentry13.captureException(error);
6989
+ Sentry12.captureException(error);
7421
6990
  this.logger.error(`Relay websocket error: ${error.message}`);
7422
6991
  }
7423
6992
  };
@@ -7448,8 +7017,8 @@ var RelayBridge = class extends EventEmitter {
7448
7017
  const text = typeof data === "string" ? data : data.toString("utf8");
7449
7018
  parsed = JSON.parse(text);
7450
7019
  } catch (error) {
7451
- Sentry13.captureException(error);
7452
- this.logger.error(`Received invalid JSON from relay: ${extractErrorMessage7(error)}`);
7020
+ Sentry12.captureException(error);
7021
+ this.logger.error(`Received invalid JSON from relay: ${extractErrorMessage5(error)}`);
7453
7022
  return;
7454
7023
  }
7455
7024
  if (this.tryHandleControlMessage(parsed)) {
@@ -7674,7 +7243,7 @@ var RelayBridge = class extends EventEmitter {
7674
7243
  diff: diff.length > 0 ? diff : null
7675
7244
  };
7676
7245
  } catch (error) {
7677
- Sentry13.captureException(error);
7246
+ Sentry12.captureException(error);
7678
7247
  this.logger.error(`Failed to get git diff for branch ${branchName}:`, error);
7679
7248
  return {
7680
7249
  type: "git_diff",
@@ -7784,8 +7353,8 @@ var RelayBridge = class extends EventEmitter {
7784
7353
  try {
7785
7354
  this.ws.send(payload);
7786
7355
  } catch (error) {
7787
- Sentry13.captureException(error);
7788
- this.logger.error(`Failed to flush relay queue: ${extractErrorMessage7(error)}`);
7356
+ Sentry12.captureException(error);
7357
+ this.logger.error(`Failed to flush relay queue: ${extractErrorMessage5(error)}`);
7789
7358
  this.pendingOutbound.unshift(payload);
7790
7359
  this.closeCurrentSocket();
7791
7360
  break;
@@ -7835,10 +7404,10 @@ function buildRelayWebsocketUrl(baseUrl, path16) {
7835
7404
  }
7836
7405
  return url.toString();
7837
7406
  }
7838
- function delay4(ms) {
7407
+ function delay2(ms) {
7839
7408
  return new Promise((resolve) => setTimeout(resolve, ms));
7840
7409
  }
7841
- function extractErrorMessage7(error) {
7410
+ function extractErrorMessage5(error) {
7842
7411
  if (error instanceof Error) {
7843
7412
  return error.message;
7844
7413
  }
@@ -7874,14 +7443,14 @@ function waitForOpen(ws) {
7874
7443
  });
7875
7444
  }
7876
7445
  function isLoginRequiredError(error) {
7877
- return error instanceof AuthContextError && (error.code === "missing_credentials" || error.code === "refresh_token_unavailable" || error.code === "refresh_failed");
7446
+ return error instanceof AuthContextError && (error.code === "missing_credentials" || error.code === "invalid_credentials");
7878
7447
  }
7879
7448
  function isUnauthorizedApiError(error) {
7880
7449
  return error instanceof ApiError && (error.status === 401 || error.status === 403);
7881
7450
  }
7882
7451
 
7883
7452
  // src/commands/agent.ts
7884
- import * as Sentry14 from "@sentry/node";
7453
+ import * as Sentry13 from "@sentry/node";
7885
7454
  async function runAgentOrchestrator(options = {}) {
7886
7455
  const log = buildOrchestratorLogger();
7887
7456
  const orchestrator = await startAgentOrchestrator();
@@ -7911,7 +7480,7 @@ async function runAgentOrchestrator(options = {}) {
7911
7480
  try {
7912
7481
  await bridge.start();
7913
7482
  } catch (error) {
7914
- Sentry14.captureException(error);
7483
+ Sentry13.captureException(error);
7915
7484
  log.error(`Relay orchestrator terminated: ${extractErrorMessage(error)}`);
7916
7485
  process.exitCode = process.exitCode || 1;
7917
7486
  } finally {
@@ -7930,7 +7499,7 @@ function createSignalHandler(onStop, log) {
7930
7499
  log.important(`
7931
7500
  Received ${signal}. Shutting down agent orchestrator...`);
7932
7501
  void onStop().catch((error) => {
7933
- Sentry14.captureException(error);
7502
+ Sentry13.captureException(error);
7934
7503
  log.error("Error while shutting down agent orchestrator:", error);
7935
7504
  });
7936
7505
  };
@@ -7963,7 +7532,7 @@ function buildOrchestratorLogger() {
7963
7532
 
7964
7533
  // src/commands/auth.ts
7965
7534
  import { Command } from "commander";
7966
- import * as Sentry15 from "@sentry/node";
7535
+ import * as Sentry14 from "@sentry/node";
7967
7536
  function buildAuthCommand() {
7968
7537
  const auth = new Command("auth").description("Authenticate the Omnara CLI.");
7969
7538
  auth.command("login").description("Authenticate via the browser-based verification flow.").action(async () => {
@@ -7976,13 +7545,13 @@ function buildAuthCommand() {
7976
7545
  store
7977
7546
  });
7978
7547
  } catch (error) {
7979
- Sentry15.captureException(error);
7548
+ Sentry14.captureException(error);
7980
7549
  if (error instanceof ApiError) {
7981
7550
  console.error(`
7982
7551
  Request failed (HTTP ${error.status}): ${error.message}`);
7983
7552
  } else {
7984
7553
  console.error(`
7985
- Login failed: ${extractErrorMessage8(error)}`);
7554
+ Login failed: ${extractErrorMessage6(error)}`);
7986
7555
  }
7987
7556
  process.exitCode = 1;
7988
7557
  }
@@ -8004,30 +7573,13 @@ Login failed: ${extractErrorMessage8(error)}`);
8004
7573
  return auth;
8005
7574
  }
8006
7575
  function printStatus(credentials) {
8007
- if (credentials.accessToken) {
8008
- const accessStatus = describeExpiry(credentials.accessTokenExpiresAt);
8009
- const refreshStatus = credentials.refreshToken ? "stored" : "missing";
8010
- console.log(
8011
- `Authentication: Supabase access token (${accessStatus}), Refresh token (${refreshStatus})`
8012
- );
7576
+ if (credentials.pat) {
7577
+ console.log("Authentication: PAT stored");
8013
7578
  return;
8014
7579
  }
8015
7580
  console.log("Authentication: Not configured");
8016
7581
  }
8017
- function describeExpiry(iso) {
8018
- if (!iso) {
8019
- return "unknown expiry";
8020
- }
8021
- const timestamp = Date.parse(iso);
8022
- if (Number.isNaN(timestamp)) {
8023
- return "invalid timestamp";
8024
- }
8025
- const diff = timestamp - Date.now();
8026
- const abs = Math.abs(diff);
8027
- const descriptor = formatDuration(abs);
8028
- return diff >= 0 ? `expires in ${descriptor}` : `expired ${descriptor} ago`;
8029
- }
8030
- function extractErrorMessage8(error) {
7582
+ function extractErrorMessage6(error) {
8031
7583
  if (error instanceof Error) {
8032
7584
  return error.message;
8033
7585
  }
@@ -8036,7 +7588,7 @@ function extractErrorMessage8(error) {
8036
7588
 
8037
7589
  // src/commands/daemon.ts
8038
7590
  import { Command as Command2 } from "commander";
8039
- import * as Sentry26 from "@sentry/node";
7591
+ import * as Sentry25 from "@sentry/node";
8040
7592
 
8041
7593
  // src/daemon/daemon-launcher.ts
8042
7594
  import { spawn as spawn2, exec as execCb } from "node:child_process";
@@ -8046,12 +7598,12 @@ import { promisify as promisify2 } from "node:util";
8046
7598
 
8047
7599
  // src/daemon/daemon-client.ts
8048
7600
  import http2 from "node:http";
8049
- import * as Sentry17 from "@sentry/node";
7601
+ import * as Sentry16 from "@sentry/node";
8050
7602
 
8051
7603
  // src/daemon/state-store.ts
8052
7604
  import fs7 from "node:fs/promises";
8053
7605
  import path8 from "node:path";
8054
- import * as Sentry16 from "@sentry/node";
7606
+ import * as Sentry15 from "@sentry/node";
8055
7607
 
8056
7608
  // src/daemon/paths.ts
8057
7609
  import fs6 from "node:fs/promises";
@@ -8095,9 +7647,9 @@ var DaemonStateStore = class {
8095
7647
  if (isFileNotFound2(error)) {
8096
7648
  return null;
8097
7649
  }
8098
- Sentry16.captureException(error);
7650
+ Sentry15.captureException(error);
8099
7651
  throw new Error(
8100
- `Failed to read daemon state from ${this.filePath}: ${extractErrorMessage9(error)}`
7652
+ `Failed to read daemon state from ${this.filePath}: ${extractErrorMessage7(error)}`
8101
7653
  );
8102
7654
  }
8103
7655
  }
@@ -8116,7 +7668,7 @@ var DaemonStateStore = class {
8116
7668
  await fs7.unlink(this.filePath);
8117
7669
  } catch (error) {
8118
7670
  if (!isFileNotFound2(error)) {
8119
- Sentry16.captureException(error);
7671
+ Sentry15.captureException(error);
8120
7672
  throw error;
8121
7673
  }
8122
7674
  }
@@ -8127,7 +7679,7 @@ function isFileNotFound2(error) {
8127
7679
  error && typeof error === "object" && "code" in error && error.code === "ENOENT"
8128
7680
  );
8129
7681
  }
8130
- function extractErrorMessage9(error) {
7682
+ function extractErrorMessage7(error) {
8131
7683
  if (error instanceof Error && error.message) {
8132
7684
  return error.message;
8133
7685
  }
@@ -8154,7 +7706,7 @@ var DaemonClient = class {
8154
7706
  await this.stateStore.clear();
8155
7707
  return null;
8156
7708
  }
8157
- Sentry17.captureException(error);
7709
+ Sentry16.captureException(error);
8158
7710
  throw error;
8159
7711
  }
8160
7712
  }
@@ -8174,7 +7726,7 @@ var DaemonClient = class {
8174
7726
  await this.stateStore.clear();
8175
7727
  return null;
8176
7728
  }
8177
- Sentry17.captureException(error);
7729
+ Sentry16.captureException(error);
8178
7730
  throw error;
8179
7731
  }
8180
7732
  }
@@ -8197,7 +7749,7 @@ var DaemonClient = class {
8197
7749
  await this.stateStore.clear();
8198
7750
  return false;
8199
7751
  }
8200
- Sentry17.captureException(error);
7752
+ Sentry16.captureException(error);
8201
7753
  throw error;
8202
7754
  }
8203
7755
  }
@@ -8221,7 +7773,7 @@ var DaemonClient = class {
8221
7773
  await this.stateStore.clear();
8222
7774
  return null;
8223
7775
  }
8224
- Sentry17.captureException(error);
7776
+ Sentry16.captureException(error);
8225
7777
  throw error;
8226
7778
  }
8227
7779
  }
@@ -8295,7 +7847,7 @@ function isProcessAlive2(pid) {
8295
7847
  if (isErrno2(error, "ESRCH")) {
8296
7848
  return false;
8297
7849
  }
8298
- Sentry17.captureException(error);
7850
+ Sentry16.captureException(error);
8299
7851
  return false;
8300
7852
  }
8301
7853
  }
@@ -8328,13 +7880,13 @@ var HttpError = class extends Error {
8328
7880
  // src/daemon/directory-registry.ts
8329
7881
  import fs9 from "node:fs/promises";
8330
7882
  import path10 from "node:path";
8331
- import * as Sentry19 from "@sentry/node";
7883
+ import * as Sentry18 from "@sentry/node";
8332
7884
 
8333
7885
  // src/daemon/config-store.ts
8334
7886
  import fs8 from "node:fs/promises";
8335
7887
  import path9 from "node:path";
8336
7888
  import { randomUUID as randomUUID6 } from "node:crypto";
8337
- import * as Sentry18 from "@sentry/node";
7889
+ import * as Sentry17 from "@sentry/node";
8338
7890
  var DEFAULT_CONFIG = {
8339
7891
  directories: [],
8340
7892
  settings: {}
@@ -8352,9 +7904,9 @@ var DaemonConfigStore = class {
8352
7904
  if (isFileNotFound3(error)) {
8353
7905
  return cloneConfig(DEFAULT_CONFIG);
8354
7906
  }
8355
- Sentry18.captureException(error);
7907
+ Sentry17.captureException(error);
8356
7908
  throw new Error(
8357
- `Failed to read daemon config from ${this.filePath}: ${extractErrorMessage10(error)}`
7909
+ `Failed to read daemon config from ${this.filePath}: ${extractErrorMessage8(error)}`
8358
7910
  );
8359
7911
  }
8360
7912
  }
@@ -8436,7 +7988,7 @@ function isFileNotFound3(error) {
8436
7988
  error && typeof error === "object" && "code" in error && error.code === "ENOENT"
8437
7989
  );
8438
7990
  }
8439
- function extractErrorMessage10(error) {
7991
+ function extractErrorMessage8(error) {
8440
7992
  if (error instanceof Error && error.message) {
8441
7993
  return error.message;
8442
7994
  }
@@ -8474,14 +8026,14 @@ var DirectoryRegistry = class {
8474
8026
  throw new Error("Path is not a directory");
8475
8027
  }
8476
8028
  } catch (error) {
8477
- Sentry19.captureException(error);
8029
+ Sentry18.captureException(error);
8478
8030
  throw new Error(
8479
- `Directory ${directoryPath} is not accessible: ${extractErrorMessage11(error)}`
8031
+ `Directory ${directoryPath} is not accessible: ${extractErrorMessage9(error)}`
8480
8032
  );
8481
8033
  }
8482
8034
  }
8483
8035
  };
8484
- function extractErrorMessage11(error) {
8036
+ function extractErrorMessage9(error) {
8485
8037
  if (error instanceof Error && error.message) {
8486
8038
  return error.message;
8487
8039
  }
@@ -8497,7 +8049,7 @@ import path11 from "node:path";
8497
8049
  import os3 from "node:os";
8498
8050
  import { execFile } from "node:child_process";
8499
8051
  import { promisify } from "node:util";
8500
- import * as Sentry20 from "@sentry/node";
8052
+ import * as Sentry19 from "@sentry/node";
8501
8053
  var REGISTRY_PATH = path11.join(OMNARA_HOME_DIR, "session-processes.json");
8502
8054
  var LOCK_PATH = `${REGISTRY_PATH}.lock`;
8503
8055
  var execFileAsync = promisify(execFile);
@@ -8509,7 +8061,7 @@ async function acquireLock(retries = 20, delayMs = 50) {
8509
8061
  return handle;
8510
8062
  } catch (error) {
8511
8063
  if (error.code !== "EEXIST") {
8512
- Sentry20.captureException(error);
8064
+ Sentry19.captureException(error);
8513
8065
  throw error;
8514
8066
  }
8515
8067
  await new Promise((resolve) => setTimeout(resolve, delayMs));
@@ -8546,7 +8098,7 @@ async function readRegistry() {
8546
8098
  if (error.code === "ENOENT") {
8547
8099
  return {};
8548
8100
  }
8549
- Sentry20.captureException(error);
8101
+ Sentry19.captureException(error);
8550
8102
  throw error;
8551
8103
  }
8552
8104
  }
@@ -8574,7 +8126,7 @@ async function isProcessAlive3(pid) {
8574
8126
  if (error.code === "ESRCH") {
8575
8127
  return false;
8576
8128
  }
8577
- Sentry20.captureException(error);
8129
+ Sentry19.captureException(error);
8578
8130
  return true;
8579
8131
  }
8580
8132
  }
@@ -8783,13 +8335,13 @@ async function killAllDaemonProcesses(options = {}) {
8783
8335
  process.kill(pid, "SIGKILL");
8784
8336
  logger3.success(`Killed process ${pid}`);
8785
8337
  } catch (error) {
8786
- logger3.warn(`Failed to kill ${pid}: ${extractErrorMessage12(error)}`);
8338
+ logger3.warn(`Failed to kill ${pid}: ${extractErrorMessage10(error)}`);
8787
8339
  }
8788
8340
  }
8789
8341
  await stateStore.clear();
8790
8342
  logger3.debug(`Cleared ${envLabel} daemon state file`);
8791
8343
  } catch (error) {
8792
- logger3.error(`Failed to kill ${envLabel} daemon processes: ${extractErrorMessage12(error)}`);
8344
+ logger3.error(`Failed to kill ${envLabel} daemon processes: ${extractErrorMessage10(error)}`);
8793
8345
  }
8794
8346
  }
8795
8347
  }
@@ -8806,7 +8358,7 @@ async function killDaemonByState(options = {}) {
8806
8358
  process.kill(state.pid, "SIGKILL");
8807
8359
  logger3.success(`Killed daemon process ${state.pid}`);
8808
8360
  } catch (error) {
8809
- logger3.warn(`Failed to kill daemon ${state.pid}: ${extractErrorMessage12(error)}`);
8361
+ logger3.warn(`Failed to kill daemon ${state.pid}: ${extractErrorMessage10(error)}`);
8810
8362
  }
8811
8363
  await stateStore.clear();
8812
8364
  }
@@ -8826,13 +8378,13 @@ async function killSessionsByRegistry(options = {}) {
8826
8378
  process.kill(record.pid, "SIGKILL");
8827
8379
  logger3.success(`Killed session process ${record.pid}`);
8828
8380
  } catch (error) {
8829
- logger3.warn(`Failed to kill session ${record.pid}: ${extractErrorMessage12(error)}`);
8381
+ logger3.warn(`Failed to kill session ${record.pid}: ${extractErrorMessage10(error)}`);
8830
8382
  }
8831
8383
  }
8832
8384
  return [{}, void 0];
8833
8385
  });
8834
8386
  } catch (error) {
8835
- logger3.warn(`Failed to kill sessions via registry: ${extractErrorMessage12(error)}`);
8387
+ logger3.warn(`Failed to kill sessions via registry: ${extractErrorMessage10(error)}`);
8836
8388
  }
8837
8389
  }
8838
8390
  async function findDaemonRelatedPids() {
@@ -8869,7 +8421,7 @@ async function registerDirectory(directoryPath, options) {
8869
8421
  options.logger.warn("Daemon was unavailable; storing directory locally.");
8870
8422
  } catch (error) {
8871
8423
  options.logger.warn(
8872
- `Failed to register ${normalized} with daemon: ${extractErrorMessage12(error)}`
8424
+ `Failed to register ${normalized} with daemon: ${extractErrorMessage10(error)}`
8873
8425
  );
8874
8426
  }
8875
8427
  const registry = new DirectoryRegistry();
@@ -8907,7 +8459,7 @@ async function waitForReady(client, options = {}) {
8907
8459
  logger3.warn("Timed out waiting for daemon readiness.");
8908
8460
  return null;
8909
8461
  }
8910
- function extractErrorMessage12(error) {
8462
+ function extractErrorMessage10(error) {
8911
8463
  if (error instanceof Error && error.message) {
8912
8464
  return error.message;
8913
8465
  }
@@ -8915,16 +8467,16 @@ function extractErrorMessage12(error) {
8915
8467
  }
8916
8468
 
8917
8469
  // src/daemon/run-daemon.ts
8918
- import * as Sentry25 from "@sentry/node";
8470
+ import * as Sentry24 from "@sentry/node";
8919
8471
 
8920
8472
  // src/daemon/daemon-service.ts
8921
- import * as Sentry24 from "@sentry/node";
8473
+ import * as Sentry23 from "@sentry/node";
8922
8474
 
8923
8475
  // src/daemon/local-control-server.ts
8924
8476
  import http3 from "node:http";
8925
8477
  import { randomBytes as randomBytes3 } from "node:crypto";
8926
8478
  import { URL as URL2 } from "node:url";
8927
- import * as Sentry21 from "@sentry/node";
8479
+ import * as Sentry20 from "@sentry/node";
8928
8480
  var MIN_PORT = 1e4;
8929
8481
  var MAX_PORT = 65535;
8930
8482
  var MAX_ATTEMPTS = 100;
@@ -8991,8 +8543,8 @@ function createRequestHandler(context) {
8991
8543
  });
8992
8544
  sendJson(res, 200, { directory: result.entry, created: result.created });
8993
8545
  } catch (error) {
8994
- Sentry21.captureException(error);
8995
- sendJson(res, 400, { error: extractErrorMessage13(error) });
8546
+ Sentry20.captureException(error);
8547
+ sendJson(res, 400, { error: extractErrorMessage11(error) });
8996
8548
  }
8997
8549
  return;
8998
8550
  }
@@ -9020,8 +8572,8 @@ function createRequestHandler(context) {
9020
8572
  });
9021
8573
  return;
9022
8574
  }
9023
- Sentry21.captureException(error);
9024
- sendJson(res, 400, { error: extractErrorMessage13(error) });
8575
+ Sentry20.captureException(error);
8576
+ sendJson(res, 400, { error: extractErrorMessage11(error) });
9025
8577
  }
9026
8578
  return;
9027
8579
  }
@@ -9029,14 +8581,14 @@ function createRequestHandler(context) {
9029
8581
  const body = await readJsonBody(req);
9030
8582
  sendJson(res, 202, { status: "stopping" });
9031
8583
  Promise.resolve().then(() => context.onStopRequested(body?.status ?? "OFFLINE")).catch((error) => {
9032
- Sentry21.captureException(error);
8584
+ Sentry20.captureException(error);
9033
8585
  context.logger?.error("Failed to stop daemon:", error);
9034
8586
  });
9035
8587
  return;
9036
8588
  }
9037
8589
  sendJson(res, 404, { error: "not_found" });
9038
8590
  } catch (error) {
9039
- Sentry21.captureException(error);
8591
+ Sentry20.captureException(error);
9040
8592
  context.logger?.error("Control server error:", error);
9041
8593
  if (!res.headersSent) {
9042
8594
  sendJson(res, 500, { error: "internal_error" });
@@ -9123,7 +8675,7 @@ function isPortInUse(error) {
9123
8675
  error && typeof error === "object" && "code" in error && error.code === "EADDRINUSE"
9124
8676
  ) || false;
9125
8677
  }
9126
- function extractErrorMessage13(error) {
8678
+ function extractErrorMessage11(error) {
9127
8679
  if (error instanceof Error && error.message) {
9128
8680
  return error.message;
9129
8681
  }
@@ -9133,9 +8685,9 @@ function extractErrorMessage13(error) {
9133
8685
  // src/daemon/machine-supervisor.ts
9134
8686
  import { randomUUID as randomUUID7 } from "node:crypto";
9135
8687
  import os5 from "node:os";
9136
- import { setTimeout as delay5 } from "node:timers/promises";
8688
+ import { setTimeout as delay3 } from "node:timers/promises";
9137
8689
  import WebSocket2 from "ws";
9138
- import * as Sentry23 from "@sentry/node";
8690
+ import * as Sentry22 from "@sentry/node";
9139
8691
 
9140
8692
  // src/http/machines.ts
9141
8693
  async function registerMachine(client, accessToken, payload) {
@@ -9170,7 +8722,7 @@ async function ensureWorkspace(client, accessToken, payload) {
9170
8722
 
9171
8723
  // src/daemon/session-runner.ts
9172
8724
  import { spawn as spawn3 } from "node:child_process";
9173
- import * as Sentry22 from "@sentry/node";
8725
+ import * as Sentry21 from "@sentry/node";
9174
8726
  import fs11 from "node:fs";
9175
8727
  import path13 from "node:path";
9176
8728
  var SessionManager = class {
@@ -9201,7 +8753,7 @@ var SessionManager = class {
9201
8753
  try {
9202
8754
  await runner.start();
9203
8755
  } catch (error) {
9204
- Sentry22.captureException(error);
8756
+ Sentry21.captureException(error);
9205
8757
  throw error;
9206
8758
  }
9207
8759
  }
@@ -9310,7 +8862,7 @@ var SessionRunner = class {
9310
8862
  } catch {
9311
8863
  }
9312
8864
  }
9313
- Sentry22.captureException(error);
8865
+ Sentry21.captureException(error);
9314
8866
  this.logger.error("Failed to start session process:", error);
9315
8867
  throw error;
9316
8868
  }
@@ -9333,6 +8885,17 @@ async function createSessionLogPath(workspaceId, launchId) {
9333
8885
  return logPath;
9334
8886
  }
9335
8887
 
8888
+ // src/package-info.ts
8889
+ import { createRequire } from "node:module";
8890
+ var require2 = createRequire(import.meta.url);
8891
+ var pkg = require2("../package.json");
8892
+ var FALLBACK_NAME = pkg.name ?? "omnara";
8893
+ var FALLBACK_VERSION = pkg.version ?? "0.0.0";
8894
+ var FALLBACK_DESCRIPTION = pkg.description ?? "Command-line interface for Omnara.";
8895
+ var PACKAGE_NAME = true ? "omnara" : FALLBACK_NAME;
8896
+ var PACKAGE_VERSION = true ? "0.4.0" : FALLBACK_VERSION;
8897
+ var PACKAGE_DESCRIPTION = true ? "Command-line interface for Omnara." : FALLBACK_DESCRIPTION;
8898
+
9336
8899
  // src/daemon/machine-supervisor.ts
9337
8900
  var HEARTBEAT_INTERVAL_MS = 1e4;
9338
8901
  var RECONNECT_DELAY_MS = 2e3;
@@ -9437,11 +9000,11 @@ var MachineSupervisor = class {
9437
9000
  } else {
9438
9001
  this.logger.debug("Machine supervisor still waiting for login\u2026");
9439
9002
  }
9440
- await delay5(LOGIN_WAIT_DELAY_MS2);
9003
+ await delay3(LOGIN_WAIT_DELAY_MS2);
9441
9004
  } else {
9442
- Sentry23.captureException(error);
9005
+ Sentry22.captureException(error);
9443
9006
  this.logger.warn(`Machine supervisor error: ${error.message}`);
9444
- await delay5(RECONNECT_DELAY_MS);
9007
+ await delay3(RECONNECT_DELAY_MS);
9445
9008
  }
9446
9009
  }
9447
9010
  }
@@ -9484,7 +9047,7 @@ var MachineSupervisor = class {
9484
9047
  });
9485
9048
  return await this.registerMachine();
9486
9049
  }
9487
- Sentry23.captureException(error);
9050
+ Sentry22.captureException(error);
9488
9051
  throw error;
9489
9052
  }
9490
9053
  const now = /* @__PURE__ */ new Date();
@@ -9561,7 +9124,7 @@ var MachineSupervisor = class {
9561
9124
  try {
9562
9125
  this.handleSocketMessage(data);
9563
9126
  } catch (error) {
9564
- Sentry23.captureException(error);
9127
+ Sentry22.captureException(error);
9565
9128
  this.logger.error("Failed to process machine message:", error);
9566
9129
  }
9567
9130
  });
@@ -9580,7 +9143,7 @@ var MachineSupervisor = class {
9580
9143
  }
9581
9144
  });
9582
9145
  ws.on("error", (error) => {
9583
- Sentry23.captureException(error);
9146
+ Sentry22.captureException(error);
9584
9147
  this.logger.error("Machine websocket error:", error);
9585
9148
  finish(new Error("machine websocket error"));
9586
9149
  });
@@ -9622,7 +9185,7 @@ var MachineSupervisor = class {
9622
9185
  });
9623
9186
  return;
9624
9187
  }
9625
- Sentry23.captureException(error);
9188
+ Sentry22.captureException(error);
9626
9189
  const messageText = error instanceof Error ? error.message : String(error);
9627
9190
  await this.sendRpcResponse(message.request_id, "error", messageText);
9628
9191
  }
@@ -9706,7 +9269,7 @@ var MachineSupervisor = class {
9706
9269
  await this.recoverMachineRegistration("workspace ensure returned 404");
9707
9270
  return await this.ensureWorkspaceWithRetry(directory, metadata, attempt + 1);
9708
9271
  }
9709
- Sentry23.captureException(error);
9272
+ Sentry22.captureException(error);
9710
9273
  throw error;
9711
9274
  }
9712
9275
  }
@@ -9745,7 +9308,7 @@ var MachineSupervisor = class {
9745
9308
  return;
9746
9309
  }
9747
9310
  }
9748
- await delay5(250);
9311
+ await delay3(250);
9749
9312
  }
9750
9313
  throw new Error("Machine has not finished registering yet. Try again in a few seconds.");
9751
9314
  }
@@ -9753,7 +9316,7 @@ var MachineSupervisor = class {
9753
9316
  this.clearHeartbeatTimer();
9754
9317
  this.heartbeatTimer = setInterval(() => {
9755
9318
  void this.sendHeartbeat().catch((error) => {
9756
- Sentry23.captureException(error);
9319
+ Sentry22.captureException(error);
9757
9320
  this.logger.error("Failed to send heartbeat:", error);
9758
9321
  });
9759
9322
  }, HEARTBEAT_INTERVAL_MS);
@@ -9835,7 +9398,7 @@ function buildMachineWebsocketUrl(baseUrl, path16) {
9835
9398
  return url.toString();
9836
9399
  }
9837
9400
  function isLoginRequiredError2(error) {
9838
- return error instanceof AuthContextError && (error.code === "missing_credentials" || error.code === "refresh_token_unavailable" || error.code === "refresh_failed");
9401
+ return error instanceof AuthContextError && (error.code === "missing_credentials" || error.code === "invalid_credentials");
9839
9402
  }
9840
9403
  function isUnauthorizedApiError2(error) {
9841
9404
  return error instanceof ApiError && (error.status === 401 || error.status === 403);
@@ -9893,7 +9456,7 @@ var DaemonService = class {
9893
9456
  this.resolveStopPromise = null;
9894
9457
  await this.machineSupervisor?.stop("OFFLINE").catch(() => void 0);
9895
9458
  await this.cleanupState();
9896
- Sentry24.captureException(error);
9459
+ Sentry23.captureException(error);
9897
9460
  throw error;
9898
9461
  }
9899
9462
  }
@@ -10018,7 +9581,7 @@ async function runDaemonProcess() {
10018
9581
  return () => {
10019
9582
  logger3.warn(`Received ${signal}. Stopping daemon...`);
10020
9583
  void service.stop().catch((error) => {
10021
- Sentry25.captureException(error);
9584
+ Sentry24.captureException(error);
10022
9585
  logger3.error("Failed to stop daemon:", error);
10023
9586
  });
10024
9587
  };
@@ -10031,7 +9594,7 @@ async function runDaemonProcess() {
10031
9594
  await service.start();
10032
9595
  await service.waitForShutdown();
10033
9596
  } catch (error) {
10034
- Sentry25.captureException(error);
9597
+ Sentry24.captureException(error);
10035
9598
  logger3.error("Daemon exited with error:", error);
10036
9599
  process.exitCode = 1;
10037
9600
  } finally {
@@ -10086,7 +9649,7 @@ function buildDaemonCommand() {
10086
9649
  try {
10087
9650
  process.chdir(options.directory);
10088
9651
  } catch (error) {
10089
- Sentry26.captureException(error);
9652
+ Sentry25.captureException(error);
10090
9653
  logger.error(
10091
9654
  `Unable to switch to directory ${options.directory}: ${error.message}`
10092
9655
  );
@@ -10104,7 +9667,7 @@ function buildDaemonCommand() {
10104
9667
  userSessionId: options.userSessionId
10105
9668
  });
10106
9669
  } catch (error) {
10107
- Sentry26.captureException(error);
9670
+ Sentry25.captureException(error);
10108
9671
  logger.error("User session exited with error:", error);
10109
9672
  process.exitCode = process.exitCode || 1;
10110
9673
  }
@@ -10139,7 +9702,7 @@ function buildKillCommand() {
10139
9702
  // src/utils/version-check.ts
10140
9703
  import chalk3 from "chalk";
10141
9704
  import { execSync } from "child_process";
10142
- import * as Sentry27 from "@sentry/node";
9705
+ import * as Sentry26 from "@sentry/node";
10143
9706
  async function fetchLatestVersion(packageName) {
10144
9707
  const controller = new AbortController();
10145
9708
  const timeout = setTimeout(() => controller.abort(), 3e3);
@@ -10233,13 +9796,13 @@ $ sudo npm install -g ${packageName}@latest`,
10233
9796
  "\n"
10234
9797
  )
10235
9798
  );
10236
- Sentry27.captureException(err);
9799
+ Sentry26.captureException(err);
10237
9800
  }
10238
9801
  } else {
10239
9802
  console.log(chalk3.grey("Omnara is up to date!\n"));
10240
9803
  }
10241
9804
  } catch (e) {
10242
- Sentry27.captureException(e);
9805
+ Sentry26.captureException(e);
10243
9806
  console.log(e);
10244
9807
  }
10245
9808
  return false;
@@ -10351,7 +9914,7 @@ async function run(argv) {
10351
9914
  try {
10352
9915
  await program.parseAsync(argv);
10353
9916
  } catch (error) {
10354
- Sentry28.captureException(error);
9917
+ Sentry27.captureException(error);
10355
9918
  program.error(error.message, { exitCode: 1 });
10356
9919
  }
10357
9920
  }
@@ -10365,7 +9928,7 @@ function isMainModule() {
10365
9928
  }
10366
9929
  if (isMainModule()) {
10367
9930
  run(process.argv).catch((error) => {
10368
- Sentry28.captureException(error);
9931
+ Sentry27.captureException(error);
10369
9932
  logger.error(error);
10370
9933
  process.exitCode = 1;
10371
9934
  });
@@ -10441,7 +10004,7 @@ ${chalk5.bold("Chat via the Omnara mobile app or web dashboard")}: ${chalk5.unde
10441
10004
  process.exitCode = 1;
10442
10005
  return;
10443
10006
  }
10444
- Sentry28.captureException(error);
10007
+ Sentry27.captureException(error);
10445
10008
  logger.warn(`Failed to prepare daemon: ${error.message}`);
10446
10009
  }
10447
10010
  }
@@ -10462,7 +10025,7 @@ async function requestDaemonLaunch(client, payload, options) {
10462
10025
  if (isRecoverableLaunchError(error)) {
10463
10026
  options.logger.debug("Daemon not ready for launch yet:", error.message);
10464
10027
  } else {
10465
- Sentry28.captureException(error);
10028
+ Sentry27.captureException(error);
10466
10029
  throw error;
10467
10030
  }
10468
10031
  }