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/auth/auth-provider.d.ts +2 -3
- package/dist/auth/credential-manager.d.ts +3 -9
- package/dist/auth/credentials-store.d.ts +1 -0
- package/dist/auth/ensure-cli-credentials.d.ts +0 -5
- package/dist/auth/login-flow.d.ts +0 -4
- package/dist/cli.js +169 -606
- package/dist/cli.js.map +4 -4
- package/package.json +1 -2
- package/dist/auth/supabase-client.d.ts +0 -3
- package/dist/auth/supabase-config.d.ts +0 -5
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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,
|
|
6198
|
+
async function ensureAuthContext(store, initialCredentials) {
|
|
6267
6199
|
const credentials = initialCredentials ?? await store.load();
|
|
6268
|
-
|
|
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
|
-
|
|
6275
|
-
|
|
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
|
-
|
|
6455
|
-
"
|
|
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
|
-
|
|
6474
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
6485
|
+
Sentry9.captureException(error);
|
|
6792
6486
|
return;
|
|
6793
6487
|
}
|
|
6794
6488
|
if (error) {
|
|
6795
|
-
|
|
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
|
|
6852
|
-
|
|
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
|
-
|
|
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
|
|
6927
|
-
const
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
accessToken
|
|
6931
|
-
|
|
6932
|
-
|
|
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
|
-
|
|
6962
|
-
console.log(`Automatic login failed: ${
|
|
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
|
|
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
|
-
|
|
6995
|
-
console.log(`Loopback listener 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
|
-
|
|
7009
|
-
|
|
6679
|
+
lastBadPat = null;
|
|
6680
|
+
defaultInteractive;
|
|
7010
6681
|
backendUrl;
|
|
7011
|
-
lastBadCredentials = null;
|
|
7012
6682
|
async getAuthContext(options) {
|
|
7013
|
-
const interactive = options?.interactive ??
|
|
7014
|
-
|
|
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.
|
|
6688
|
+
return auth.pat;
|
|
7036
6689
|
}
|
|
7037
6690
|
async loadAuthContext(interactive) {
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
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
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
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
|
|
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
|
-
|
|
6829
|
+
Sentry12.captureException(error);
|
|
7260
6830
|
this.logger.error(
|
|
7261
|
-
`Relay connection failed: ${
|
|
6831
|
+
`Relay connection failed: ${extractErrorMessage5(error)}. Retrying in ${Math.round(backoffMs / 1e3)}s.`
|
|
7262
6832
|
);
|
|
7263
|
-
await
|
|
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
|
-
|
|
7387
|
-
this.logger.error(`Failed to send relay frame: ${
|
|
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
|
-
|
|
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
|
-
|
|
7452
|
-
this.logger.error(`Received invalid JSON from relay: ${
|
|
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
|
-
|
|
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
|
-
|
|
7788
|
-
this.logger.error(`Failed to flush relay queue: ${
|
|
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
|
|
7407
|
+
function delay2(ms) {
|
|
7839
7408
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7840
7409
|
}
|
|
7841
|
-
function
|
|
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 === "
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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: ${
|
|
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.
|
|
8008
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
7650
|
+
Sentry15.captureException(error);
|
|
8099
7651
|
throw new Error(
|
|
8100
|
-
`Failed to read daemon state from ${this.filePath}: ${
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
7907
|
+
Sentry17.captureException(error);
|
|
8356
7908
|
throw new Error(
|
|
8357
|
-
`Failed to read daemon config from ${this.filePath}: ${
|
|
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
|
|
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
|
-
|
|
8029
|
+
Sentry18.captureException(error);
|
|
8478
8030
|
throw new Error(
|
|
8479
|
-
`Directory ${directoryPath} is not accessible: ${
|
|
8031
|
+
`Directory ${directoryPath} is not accessible: ${extractErrorMessage9(error)}`
|
|
8480
8032
|
);
|
|
8481
8033
|
}
|
|
8482
8034
|
}
|
|
8483
8035
|
};
|
|
8484
|
-
function
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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}: ${
|
|
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: ${
|
|
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}: ${
|
|
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}: ${
|
|
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: ${
|
|
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: ${
|
|
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
|
|
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
|
|
8470
|
+
import * as Sentry24 from "@sentry/node";
|
|
8919
8471
|
|
|
8920
8472
|
// src/daemon/daemon-service.ts
|
|
8921
|
-
import * as
|
|
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
|
|
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
|
-
|
|
8995
|
-
sendJson(res, 400, { 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
|
-
|
|
9024
|
-
sendJson(res, 400, { 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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
8688
|
+
import { setTimeout as delay3 } from "node:timers/promises";
|
|
9137
8689
|
import WebSocket2 from "ws";
|
|
9138
|
-
import * as
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
9003
|
+
await delay3(LOGIN_WAIT_DELAY_MS2);
|
|
9441
9004
|
} else {
|
|
9442
|
-
|
|
9005
|
+
Sentry22.captureException(error);
|
|
9443
9006
|
this.logger.warn(`Machine supervisor error: ${error.message}`);
|
|
9444
|
-
await
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 === "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
10028
|
+
Sentry27.captureException(error);
|
|
10466
10029
|
throw error;
|
|
10467
10030
|
}
|
|
10468
10031
|
}
|