omnara 0.3.1 → 0.3.2
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 +192 -133
- package/dist/cli.js.map +3 -3
- package/dist/daemon/session-pid-registry.d.ts +7 -1
- package/dist/daemon/session-runner.d.ts +0 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6204,7 +6204,7 @@ var FALLBACK_NAME = pkg.name ?? "omnara";
|
|
|
6204
6204
|
var FALLBACK_VERSION = pkg.version ?? "0.0.0";
|
|
6205
6205
|
var FALLBACK_DESCRIPTION = pkg.description ?? "Command-line interface for Omnara.";
|
|
6206
6206
|
var PACKAGE_NAME = true ? "omnara" : FALLBACK_NAME;
|
|
6207
|
-
var PACKAGE_VERSION = true ? "0.3.
|
|
6207
|
+
var PACKAGE_VERSION = true ? "0.3.2" : FALLBACK_VERSION;
|
|
6208
6208
|
var PACKAGE_DESCRIPTION = true ? "Command-line interface for Omnara." : FALLBACK_DESCRIPTION;
|
|
6209
6209
|
|
|
6210
6210
|
// src/auth/supabase-client.ts
|
|
@@ -8041,8 +8041,8 @@ import * as Sentry26 from "@sentry/node";
|
|
|
8041
8041
|
// src/daemon/daemon-launcher.ts
|
|
8042
8042
|
import { spawn as spawn2, exec as execCb } from "node:child_process";
|
|
8043
8043
|
import path12 from "node:path";
|
|
8044
|
-
import
|
|
8045
|
-
import { promisify } from "node:util";
|
|
8044
|
+
import os4 from "node:os";
|
|
8045
|
+
import { promisify as promisify2 } from "node:util";
|
|
8046
8046
|
|
|
8047
8047
|
// src/daemon/daemon-client.ts
|
|
8048
8048
|
import http2 from "node:http";
|
|
@@ -8494,9 +8494,14 @@ import chalk2 from "chalk";
|
|
|
8494
8494
|
// src/daemon/session-pid-registry.ts
|
|
8495
8495
|
import fs10 from "node:fs/promises";
|
|
8496
8496
|
import path11 from "node:path";
|
|
8497
|
+
import os3 from "node:os";
|
|
8498
|
+
import { execFile } from "node:child_process";
|
|
8499
|
+
import { promisify } from "node:util";
|
|
8497
8500
|
import * as Sentry20 from "@sentry/node";
|
|
8498
8501
|
var REGISTRY_PATH = path11.join(OMNARA_HOME_DIR, "session-processes.json");
|
|
8499
8502
|
var LOCK_PATH = `${REGISTRY_PATH}.lock`;
|
|
8503
|
+
var execFileAsync = promisify(execFile);
|
|
8504
|
+
var START_TIME_TOLERANCE_MS = 5e3;
|
|
8500
8505
|
async function acquireLock(retries = 20, delayMs = 50) {
|
|
8501
8506
|
for (let attempt = 0; attempt < retries; attempt += 1) {
|
|
8502
8507
|
try {
|
|
@@ -8519,7 +8524,24 @@ async function releaseLock(handle) {
|
|
|
8519
8524
|
async function readRegistry() {
|
|
8520
8525
|
try {
|
|
8521
8526
|
const raw = await fs10.readFile(REGISTRY_PATH, "utf8");
|
|
8522
|
-
|
|
8527
|
+
const parsed = JSON.parse(raw);
|
|
8528
|
+
const normalized = {};
|
|
8529
|
+
for (const [sessionId, value] of Object.entries(parsed)) {
|
|
8530
|
+
if (typeof value === "number") {
|
|
8531
|
+
normalized[sessionId] = {
|
|
8532
|
+
pid: value
|
|
8533
|
+
};
|
|
8534
|
+
continue;
|
|
8535
|
+
}
|
|
8536
|
+
if (value && typeof value.pid === "number") {
|
|
8537
|
+
normalized[sessionId] = {
|
|
8538
|
+
pid: value.pid,
|
|
8539
|
+
startedAt: typeof value.startedAt === "string" ? value.startedAt : void 0,
|
|
8540
|
+
command: typeof value.command === "string" ? value.command : void 0
|
|
8541
|
+
};
|
|
8542
|
+
}
|
|
8543
|
+
}
|
|
8544
|
+
return normalized;
|
|
8523
8545
|
} catch (error) {
|
|
8524
8546
|
if (error.code === "ENOENT") {
|
|
8525
8547
|
return {};
|
|
@@ -8556,9 +8578,69 @@ async function isProcessAlive3(pid) {
|
|
|
8556
8578
|
return true;
|
|
8557
8579
|
}
|
|
8558
8580
|
}
|
|
8581
|
+
async function isSessionProcessAlive(record) {
|
|
8582
|
+
const alive = await isProcessAlive3(record.pid);
|
|
8583
|
+
if (!alive) {
|
|
8584
|
+
return false;
|
|
8585
|
+
}
|
|
8586
|
+
const tokensMatch = await matchesExpectedCommand(record.pid);
|
|
8587
|
+
if (!tokensMatch) {
|
|
8588
|
+
return false;
|
|
8589
|
+
}
|
|
8590
|
+
const timeMatch = await matchesStartTime(record.pid, record.startedAt);
|
|
8591
|
+
if (record.startedAt && !timeMatch) {
|
|
8592
|
+
return false;
|
|
8593
|
+
}
|
|
8594
|
+
return true;
|
|
8595
|
+
}
|
|
8596
|
+
async function matchesExpectedCommand(pid) {
|
|
8597
|
+
if (os3.platform() === "win32") {
|
|
8598
|
+
return true;
|
|
8599
|
+
}
|
|
8600
|
+
try {
|
|
8601
|
+
const { stdout } = await execFileAsync("ps", ["-p", String(pid), "-o", "command="]);
|
|
8602
|
+
const command = stdout.trim().toLowerCase();
|
|
8603
|
+
if (!command) {
|
|
8604
|
+
return false;
|
|
8605
|
+
}
|
|
8606
|
+
if (!command.includes("omnara") || !command.includes("daemon run-session")) {
|
|
8607
|
+
return false;
|
|
8608
|
+
}
|
|
8609
|
+
return true;
|
|
8610
|
+
} catch {
|
|
8611
|
+
return false;
|
|
8612
|
+
}
|
|
8613
|
+
}
|
|
8614
|
+
async function matchesStartTime(pid, recordedStartedAt) {
|
|
8615
|
+
if (os3.platform() === "win32") {
|
|
8616
|
+
return true;
|
|
8617
|
+
}
|
|
8618
|
+
if (!recordedStartedAt) {
|
|
8619
|
+
return true;
|
|
8620
|
+
}
|
|
8621
|
+
const recordedMs = Date.parse(recordedStartedAt);
|
|
8622
|
+
if (Number.isNaN(recordedMs)) {
|
|
8623
|
+
return true;
|
|
8624
|
+
}
|
|
8625
|
+
try {
|
|
8626
|
+
const { stdout } = await execFileAsync("ps", ["-p", String(pid), "-o", "lstart="]);
|
|
8627
|
+
const psStart = stdout.trim();
|
|
8628
|
+
if (!psStart) {
|
|
8629
|
+
return true;
|
|
8630
|
+
}
|
|
8631
|
+
const psDate = new Date(psStart);
|
|
8632
|
+
if (Number.isNaN(psDate.getTime())) {
|
|
8633
|
+
return true;
|
|
8634
|
+
}
|
|
8635
|
+
const delta = Math.abs(psDate.getTime() - recordedMs);
|
|
8636
|
+
return delta <= START_TIME_TOLERANCE_MS;
|
|
8637
|
+
} catch {
|
|
8638
|
+
return true;
|
|
8639
|
+
}
|
|
8640
|
+
}
|
|
8559
8641
|
|
|
8560
8642
|
// src/daemon/daemon-launcher.ts
|
|
8561
|
-
var exec =
|
|
8643
|
+
var exec = promisify2(execCb);
|
|
8562
8644
|
var DEFAULT_WAIT_MS = 1e4;
|
|
8563
8645
|
async function ensureDaemonForSession(options = {}) {
|
|
8564
8646
|
const logger3 = options.logger ?? logger;
|
|
@@ -8598,7 +8680,7 @@ async function ensureMachineNameConfigured(configStore, logger3) {
|
|
|
8598
8680
|
process.env.OMNARA_MACHINE_NAME = config.machine.name;
|
|
8599
8681
|
return config.machine.name;
|
|
8600
8682
|
}
|
|
8601
|
-
const defaultName =
|
|
8683
|
+
const defaultName = os4.hostname();
|
|
8602
8684
|
let machineName = defaultName;
|
|
8603
8685
|
if (process.stdin.isTTY && process.stdout.isTTY) {
|
|
8604
8686
|
const answer = (await prompt(chalk2.blue(`Enter a name for this machine [${defaultName}]: `))).trim();
|
|
@@ -8732,20 +8814,19 @@ async function killSessionsByRegistry(options = {}) {
|
|
|
8732
8814
|
const logger3 = options.logger ?? logger;
|
|
8733
8815
|
try {
|
|
8734
8816
|
await withSessionRegistry(async (registry) => {
|
|
8735
|
-
const
|
|
8736
|
-
|
|
8737
|
-
if (!Number.isFinite(pid)) {
|
|
8817
|
+
for (const record of Object.values(registry)) {
|
|
8818
|
+
if (!record || !Number.isFinite(record.pid)) {
|
|
8738
8819
|
continue;
|
|
8739
8820
|
}
|
|
8740
|
-
const alive = await
|
|
8821
|
+
const alive = await isSessionProcessAlive(record);
|
|
8741
8822
|
if (!alive) {
|
|
8742
8823
|
continue;
|
|
8743
8824
|
}
|
|
8744
8825
|
try {
|
|
8745
|
-
process.kill(pid, "SIGKILL");
|
|
8746
|
-
logger3.success(`Killed session process ${pid}`);
|
|
8826
|
+
process.kill(record.pid, "SIGKILL");
|
|
8827
|
+
logger3.success(`Killed session process ${record.pid}`);
|
|
8747
8828
|
} catch (error) {
|
|
8748
|
-
logger3.warn(`Failed to kill session ${pid}: ${extractErrorMessage12(error)}`);
|
|
8829
|
+
logger3.warn(`Failed to kill session ${record.pid}: ${extractErrorMessage12(error)}`);
|
|
8749
8830
|
}
|
|
8750
8831
|
}
|
|
8751
8832
|
return [{}, void 0];
|
|
@@ -9051,7 +9132,7 @@ function extractErrorMessage13(error) {
|
|
|
9051
9132
|
|
|
9052
9133
|
// src/daemon/machine-supervisor.ts
|
|
9053
9134
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
9054
|
-
import
|
|
9135
|
+
import os5 from "node:os";
|
|
9055
9136
|
import { setTimeout as delay5 } from "node:timers/promises";
|
|
9056
9137
|
import WebSocket2 from "ws";
|
|
9057
9138
|
import * as Sentry23 from "@sentry/node";
|
|
@@ -9090,13 +9171,13 @@ async function ensureWorkspace(client, accessToken, payload) {
|
|
|
9090
9171
|
// src/daemon/session-runner.ts
|
|
9091
9172
|
import { spawn as spawn3 } from "node:child_process";
|
|
9092
9173
|
import * as Sentry22 from "@sentry/node";
|
|
9174
|
+
import fs11 from "node:fs";
|
|
9093
9175
|
import path13 from "node:path";
|
|
9094
9176
|
var SessionManager = class {
|
|
9095
9177
|
backendUrl;
|
|
9096
9178
|
frontendUrl;
|
|
9097
9179
|
directoryRegistry;
|
|
9098
9180
|
logger;
|
|
9099
|
-
runners = /* @__PURE__ */ new Map();
|
|
9100
9181
|
constructor(options) {
|
|
9101
9182
|
this.backendUrl = options.backendUrl;
|
|
9102
9183
|
this.frontendUrl = options.frontendUrl;
|
|
@@ -9104,9 +9185,6 @@ var SessionManager = class {
|
|
|
9104
9185
|
this.logger = options.logger;
|
|
9105
9186
|
}
|
|
9106
9187
|
async startSession(spec) {
|
|
9107
|
-
if (this.runners.has(spec.launchId)) {
|
|
9108
|
-
throw new Error("Session is already running on this machine");
|
|
9109
|
-
}
|
|
9110
9188
|
const entry = await this.directoryRegistry.getEntry(spec.directory);
|
|
9111
9189
|
if (!entry) {
|
|
9112
9190
|
throw new Error(`Directory ${spec.directory} is not registered on this machine`);
|
|
@@ -9118,23 +9196,15 @@ var SessionManager = class {
|
|
|
9118
9196
|
frontendUrl: this.frontendUrl,
|
|
9119
9197
|
logger: this.logger,
|
|
9120
9198
|
onExit: () => {
|
|
9121
|
-
this.runners.delete(spec.launchId);
|
|
9122
9199
|
}
|
|
9123
9200
|
});
|
|
9124
|
-
this.runners.set(spec.launchId, runner);
|
|
9125
9201
|
try {
|
|
9126
9202
|
await runner.start();
|
|
9127
9203
|
} catch (error) {
|
|
9128
|
-
this.runners.delete(spec.launchId);
|
|
9129
9204
|
Sentry22.captureException(error);
|
|
9130
9205
|
throw error;
|
|
9131
9206
|
}
|
|
9132
9207
|
}
|
|
9133
|
-
async stopAll() {
|
|
9134
|
-
const runners = Array.from(this.runners.values());
|
|
9135
|
-
this.runners.clear();
|
|
9136
|
-
await Promise.all(runners.map((runner) => runner.stop()));
|
|
9137
|
-
}
|
|
9138
9208
|
};
|
|
9139
9209
|
var SessionRunner = class {
|
|
9140
9210
|
spec;
|
|
@@ -9143,12 +9213,7 @@ var SessionRunner = class {
|
|
|
9143
9213
|
frontendUrl;
|
|
9144
9214
|
logger;
|
|
9145
9215
|
onExit;
|
|
9146
|
-
startedAt = null;
|
|
9147
9216
|
child = null;
|
|
9148
|
-
exitPromise = null;
|
|
9149
|
-
resolveExit = null;
|
|
9150
|
-
exitHandled = false;
|
|
9151
|
-
sessionLogPath = null;
|
|
9152
9217
|
constructor(options) {
|
|
9153
9218
|
this.spec = options.spec;
|
|
9154
9219
|
this.directory = options.directory;
|
|
@@ -9165,15 +9230,12 @@ var SessionRunner = class {
|
|
|
9165
9230
|
if (!entry) {
|
|
9166
9231
|
throw new Error("Unable to determine CLI entry path for session runner");
|
|
9167
9232
|
}
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
});
|
|
9171
|
-
this.sessionLogPath = await createSessionLogPath(this.spec.workspaceId, this.spec.launchId);
|
|
9172
|
-
this.logger.info(`Session ${this.spec.launchId} logs available at ${this.sessionLogPath}`);
|
|
9233
|
+
const sessionLogPath = await createSessionLogPath(this.spec.workspaceId, this.spec.launchId);
|
|
9234
|
+
this.logger.info(`Session ${this.spec.launchId} logs available at ${sessionLogPath}`);
|
|
9173
9235
|
await withSessionRegistry(async (registry) => {
|
|
9174
|
-
const
|
|
9175
|
-
if (
|
|
9176
|
-
const alive = await
|
|
9236
|
+
const existing = registry[this.spec.userSessionId];
|
|
9237
|
+
if (existing) {
|
|
9238
|
+
const alive = await isSessionProcessAlive(existing);
|
|
9177
9239
|
if (alive) {
|
|
9178
9240
|
throw new Error(`User session ${this.spec.userSessionId} is already running`);
|
|
9179
9241
|
}
|
|
@@ -9199,7 +9261,7 @@ var SessionRunner = class {
|
|
|
9199
9261
|
OMNARA_WORKSPACE_ID: this.spec.workspaceId,
|
|
9200
9262
|
OMNARA_WORKSPACE_DIR: this.directory.path,
|
|
9201
9263
|
OMNARA_USER_SESSION_ID: this.spec.userSessionId,
|
|
9202
|
-
|
|
9264
|
+
OMNARA_SESSION_LOG_PATH: sessionLogPath
|
|
9203
9265
|
};
|
|
9204
9266
|
if (this.spec.workspaceConfig) {
|
|
9205
9267
|
env.OMNARA_WORKSPACE_CONFIG = JSON.stringify(this.spec.workspaceConfig);
|
|
@@ -9210,95 +9272,58 @@ var SessionRunner = class {
|
|
|
9210
9272
|
if (this.spec.metadata) {
|
|
9211
9273
|
env.OMNARA_WORKSPACE_METADATA = JSON.stringify(this.spec.metadata);
|
|
9212
9274
|
}
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
child.once("spawn", () => {
|
|
9222
|
-
spawned = true;
|
|
9223
|
-
this.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9224
|
-
this.writeLog("INFO", `Session process started in ${this.directory.path}`);
|
|
9225
|
-
resolve();
|
|
9275
|
+
let logFd = null;
|
|
9276
|
+
try {
|
|
9277
|
+
logFd = fs11.openSync(sessionLogPath, "a");
|
|
9278
|
+
const child = spawn3(process.execPath, args, {
|
|
9279
|
+
cwd: this.directory.path,
|
|
9280
|
+
stdio: ["ignore", logFd, logFd],
|
|
9281
|
+
env,
|
|
9282
|
+
detached: true
|
|
9226
9283
|
});
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
reject(error);
|
|
9234
|
-
} else {
|
|
9235
|
-
Sentry22.captureException(error);
|
|
9236
|
-
this.handleExit(error.message, true);
|
|
9237
|
-
}
|
|
9284
|
+
fs11.closeSync(logFd);
|
|
9285
|
+
logFd = null;
|
|
9286
|
+
child.unref();
|
|
9287
|
+
await new Promise((resolve, reject) => {
|
|
9288
|
+
child.once("spawn", resolve);
|
|
9289
|
+
child.once("error", reject);
|
|
9238
9290
|
});
|
|
9239
|
-
child
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
this.
|
|
9291
|
+
this.child = child;
|
|
9292
|
+
child.once("exit", () => {
|
|
9293
|
+
this.onExit();
|
|
9294
|
+
this.child = null;
|
|
9243
9295
|
});
|
|
9244
|
-
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9296
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9297
|
+
const command = `${process.execPath} ${args.join(" ")}`;
|
|
9298
|
+
await withSessionRegistry(async (registry) => {
|
|
9299
|
+
registry[this.spec.userSessionId] = {
|
|
9300
|
+
pid: child.pid ?? -1,
|
|
9301
|
+
startedAt,
|
|
9302
|
+
command
|
|
9303
|
+
};
|
|
9304
|
+
return [registry, null];
|
|
9305
|
+
});
|
|
9306
|
+
} catch (error) {
|
|
9307
|
+
if (logFd !== null) {
|
|
9308
|
+
try {
|
|
9309
|
+
fs11.closeSync(logFd);
|
|
9310
|
+
} catch {
|
|
9311
|
+
}
|
|
9312
|
+
}
|
|
9313
|
+
Sentry22.captureException(error);
|
|
9314
|
+
this.logger.error("Failed to start session process:", error);
|
|
9315
|
+
throw error;
|
|
9316
|
+
}
|
|
9250
9317
|
}
|
|
9251
9318
|
async stop() {
|
|
9252
9319
|
if (!this.child) {
|
|
9253
|
-
await this.exitPromise;
|
|
9254
9320
|
return;
|
|
9255
9321
|
}
|
|
9256
9322
|
if (!this.child.killed) {
|
|
9257
9323
|
this.child.kill("SIGINT");
|
|
9258
9324
|
}
|
|
9259
|
-
await this.exitPromise;
|
|
9260
|
-
}
|
|
9261
|
-
handleExit(reason, failed) {
|
|
9262
|
-
if (this.exitHandled) {
|
|
9263
|
-
return;
|
|
9264
|
-
}
|
|
9265
|
-
this.exitHandled = true;
|
|
9266
|
-
if (reason) {
|
|
9267
|
-
this.writeLog(failed ? "ERROR" : "INFO", reason);
|
|
9268
|
-
}
|
|
9269
|
-
this.cleanup();
|
|
9270
|
-
this.resolveExit?.();
|
|
9271
|
-
this.onExit();
|
|
9272
|
-
}
|
|
9273
|
-
cleanup() {
|
|
9274
|
-
if (this.child) {
|
|
9275
|
-
this.child.removeAllListeners();
|
|
9276
|
-
this.child = null;
|
|
9277
|
-
}
|
|
9278
|
-
void withSessionRegistry(async (registry) => {
|
|
9279
|
-
delete registry[this.spec.userSessionId];
|
|
9280
|
-
return [registry, null];
|
|
9281
|
-
});
|
|
9282
|
-
}
|
|
9283
|
-
writeLog(level, ...args) {
|
|
9284
|
-
if (level === "ERROR") {
|
|
9285
|
-
this.logger.error(...args);
|
|
9286
|
-
} else if (level === "WARN") {
|
|
9287
|
-
this.logger.warn(...args);
|
|
9288
|
-
} else {
|
|
9289
|
-
this.logger.info(...args);
|
|
9290
|
-
}
|
|
9291
9325
|
}
|
|
9292
9326
|
};
|
|
9293
|
-
function buildExitMessage(code, signal) {
|
|
9294
|
-
if (code !== null) {
|
|
9295
|
-
return code === 0 ? null : `Process exited with code ${code}`;
|
|
9296
|
-
}
|
|
9297
|
-
if (signal) {
|
|
9298
|
-
return `Process terminated via signal ${signal}`;
|
|
9299
|
-
}
|
|
9300
|
-
return null;
|
|
9301
|
-
}
|
|
9302
9327
|
async function createSessionLogPath(workspaceId, launchId) {
|
|
9303
9328
|
await ensureOmnaraHome();
|
|
9304
9329
|
const workspaceDir = path13.join(USER_SESSION_LOG_ROOT, workspaceId);
|
|
@@ -9312,6 +9337,7 @@ async function createSessionLogPath(workspaceId, launchId) {
|
|
|
9312
9337
|
var HEARTBEAT_INTERVAL_MS = 1e4;
|
|
9313
9338
|
var RECONNECT_DELAY_MS = 2e3;
|
|
9314
9339
|
var LOGIN_WAIT_DELAY_MS2 = 3e4;
|
|
9340
|
+
var CONNECT_TIMEOUT_MS = 3e4;
|
|
9315
9341
|
var DAEMON_VERSION = PACKAGE_VERSION ?? "0.0.0";
|
|
9316
9342
|
var MachineSupervisor = class {
|
|
9317
9343
|
backendUrl;
|
|
@@ -9376,15 +9402,14 @@ var MachineSupervisor = class {
|
|
|
9376
9402
|
type: "heartbeat",
|
|
9377
9403
|
status,
|
|
9378
9404
|
metadata: {
|
|
9379
|
-
hostname:
|
|
9380
|
-
platform:
|
|
9381
|
-
architecture:
|
|
9405
|
+
hostname: os5.hostname(),
|
|
9406
|
+
platform: os5.platform(),
|
|
9407
|
+
architecture: os5.arch(),
|
|
9382
9408
|
daemon_version: DAEMON_VERSION
|
|
9383
9409
|
},
|
|
9384
9410
|
directories: directories.map((entry) => entry.path)
|
|
9385
9411
|
};
|
|
9386
9412
|
await this.sendMessage(payload);
|
|
9387
|
-
await this.sessionManager.stopAll();
|
|
9388
9413
|
await this.closeWebsocket();
|
|
9389
9414
|
if (this.loopPromise) {
|
|
9390
9415
|
await this.loopPromise;
|
|
@@ -9435,9 +9460,9 @@ var MachineSupervisor = class {
|
|
|
9435
9460
|
const payload = {
|
|
9436
9461
|
machine_id: config.machine?.id,
|
|
9437
9462
|
machine_name: machineName,
|
|
9438
|
-
hostname:
|
|
9439
|
-
platform:
|
|
9440
|
-
architecture:
|
|
9463
|
+
hostname: os5.hostname(),
|
|
9464
|
+
platform: os5.platform(),
|
|
9465
|
+
architecture: os5.arch(),
|
|
9441
9466
|
daemon_version: DAEMON_VERSION,
|
|
9442
9467
|
directories: directories.map((entry) => entry.path),
|
|
9443
9468
|
metadata: {
|
|
@@ -9494,7 +9519,38 @@ var MachineSupervisor = class {
|
|
|
9494
9519
|
}
|
|
9495
9520
|
});
|
|
9496
9521
|
this.websocket = ws;
|
|
9522
|
+
let done = false;
|
|
9523
|
+
let connectTimer = null;
|
|
9524
|
+
const finish = (error) => {
|
|
9525
|
+
if (done) return;
|
|
9526
|
+
done = true;
|
|
9527
|
+
if (connectTimer) {
|
|
9528
|
+
clearTimeout(connectTimer);
|
|
9529
|
+
connectTimer = null;
|
|
9530
|
+
}
|
|
9531
|
+
this.clearHeartbeatTimer();
|
|
9532
|
+
this.websocket = null;
|
|
9533
|
+
try {
|
|
9534
|
+
ws.removeAllListeners();
|
|
9535
|
+
if (ws.readyState === WebSocket2.OPEN || ws.readyState === WebSocket2.CONNECTING) {
|
|
9536
|
+
ws.close();
|
|
9537
|
+
}
|
|
9538
|
+
} catch {
|
|
9539
|
+
}
|
|
9540
|
+
if (error) {
|
|
9541
|
+
reject(error);
|
|
9542
|
+
} else {
|
|
9543
|
+
resolve();
|
|
9544
|
+
}
|
|
9545
|
+
};
|
|
9546
|
+
connectTimer = setTimeout(() => {
|
|
9547
|
+
finish(new Error("machine websocket connection timed out"));
|
|
9548
|
+
}, CONNECT_TIMEOUT_MS);
|
|
9497
9549
|
ws.on("open", () => {
|
|
9550
|
+
if (connectTimer) {
|
|
9551
|
+
clearTimeout(connectTimer);
|
|
9552
|
+
connectTimer = null;
|
|
9553
|
+
}
|
|
9498
9554
|
this.logger.success("\u2713 Machine daemon connected to backend");
|
|
9499
9555
|
void this.sendHeartbeat().catch((error) => {
|
|
9500
9556
|
this.logger.error("Failed to send heartbeat:", error);
|
|
@@ -9510,20 +9566,23 @@ var MachineSupervisor = class {
|
|
|
9510
9566
|
}
|
|
9511
9567
|
});
|
|
9512
9568
|
ws.on("close", (code, reason) => {
|
|
9569
|
+
if (connectTimer) {
|
|
9570
|
+
clearTimeout(connectTimer);
|
|
9571
|
+
connectTimer = null;
|
|
9572
|
+
}
|
|
9513
9573
|
this.logger.warn(
|
|
9514
9574
|
`Machine websocket closed (${code}${reason ? `: ${reason.toString()}` : ""})`
|
|
9515
9575
|
);
|
|
9516
|
-
this.clearHeartbeatTimer();
|
|
9517
|
-
this.websocket = null;
|
|
9518
9576
|
if (this.stopRequested) {
|
|
9519
|
-
|
|
9577
|
+
finish();
|
|
9520
9578
|
} else {
|
|
9521
|
-
|
|
9579
|
+
finish(new Error("machine websocket closed"));
|
|
9522
9580
|
}
|
|
9523
9581
|
});
|
|
9524
9582
|
ws.on("error", (error) => {
|
|
9525
9583
|
Sentry23.captureException(error);
|
|
9526
9584
|
this.logger.error("Machine websocket error:", error);
|
|
9585
|
+
finish(new Error("machine websocket error"));
|
|
9527
9586
|
});
|
|
9528
9587
|
});
|
|
9529
9588
|
}
|
|
@@ -9711,9 +9770,9 @@ var MachineSupervisor = class {
|
|
|
9711
9770
|
type: "heartbeat",
|
|
9712
9771
|
status: "ONLINE",
|
|
9713
9772
|
metadata: {
|
|
9714
|
-
hostname:
|
|
9715
|
-
platform:
|
|
9716
|
-
architecture:
|
|
9773
|
+
hostname: os5.hostname(),
|
|
9774
|
+
platform: os5.platform(),
|
|
9775
|
+
architecture: os5.arch(),
|
|
9717
9776
|
daemon_version: DAEMON_VERSION
|
|
9718
9777
|
},
|
|
9719
9778
|
directories: directories.map((entry) => entry.path)
|
|
@@ -9782,7 +9841,7 @@ function isUnauthorizedApiError2(error) {
|
|
|
9782
9841
|
return error instanceof ApiError && (error.status === 401 || error.status === 403);
|
|
9783
9842
|
}
|
|
9784
9843
|
function deriveMachineName() {
|
|
9785
|
-
return process.env.OMNARA_MACHINE_NAME ||
|
|
9844
|
+
return process.env.OMNARA_MACHINE_NAME || os5.hostname();
|
|
9786
9845
|
}
|
|
9787
9846
|
function decodeJson(raw) {
|
|
9788
9847
|
const text = typeof raw === "string" ? raw : raw.toString("utf8");
|
|
@@ -9902,7 +9961,7 @@ var DaemonService = class {
|
|
|
9902
9961
|
};
|
|
9903
9962
|
|
|
9904
9963
|
// src/daemon/run-daemon.ts
|
|
9905
|
-
import
|
|
9964
|
+
import fs12 from "node:fs";
|
|
9906
9965
|
import path14 from "node:path";
|
|
9907
9966
|
async function runDaemonProcess() {
|
|
9908
9967
|
await ensureOmnaraHome();
|
|
@@ -9910,7 +9969,7 @@ async function runDaemonProcess() {
|
|
|
9910
9969
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
9911
9970
|
const fileName = `${timestamp}-${process.pid}.log`;
|
|
9912
9971
|
const logPath = path14.join(DAEMON_LOG_DIR, fileName);
|
|
9913
|
-
const stream =
|
|
9972
|
+
const stream = fs12.createWriteStream(logPath, {
|
|
9914
9973
|
flags: "a",
|
|
9915
9974
|
mode: DEFAULT_FILE_MODE2
|
|
9916
9975
|
});
|