opensteer 0.9.6 → 0.9.7
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/{chunk-BVRIPCWA.js → chunk-3OHKIPBD.js} +316 -465
- package/dist/chunk-3OHKIPBD.js.map +1 -0
- package/dist/{chunk-L4NF74KI.js → chunk-52UNH5UW.js} +5 -5
- package/dist/{chunk-L4NF74KI.js.map → chunk-52UNH5UW.js.map} +1 -1
- package/dist/{chunk-3XBQRZZC.js → chunk-PJXN7HED.js} +115 -14
- package/dist/chunk-PJXN7HED.js.map +1 -0
- package/dist/{chunk-3I3A5OLB.js → chunk-R33BXCMQ.js} +16 -7
- package/dist/chunk-R33BXCMQ.js.map +1 -0
- package/dist/{chunk-T5P2QGZ3.js → chunk-U4BUCIZ4.js} +153 -12
- package/dist/chunk-U4BUCIZ4.js.map +1 -0
- package/dist/cli/bin.cjs +663 -544
- package/dist/cli/bin.cjs.map +1 -1
- package/dist/cli/bin.js +66 -50
- package/dist/cli/bin.js.map +1 -1
- package/dist/index.cjs +584 -495
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -50
- package/dist/index.d.ts +26 -50
- package/dist/index.js +4 -4
- package/dist/local-view/public/assets/app.js +10 -1
- package/dist/local-view/serve-entry.cjs +687 -494
- package/dist/local-view/serve-entry.cjs.map +1 -1
- package/dist/local-view/serve-entry.js +2 -2
- package/dist/opensteer-CY2QUJEG.js +6 -0
- package/dist/{opensteer-UGA6YBRN.js.map → opensteer-CY2QUJEG.js.map} +1 -1
- package/dist/{session-control-U3L5H2ZI.js → session-control-FIP6ZJLH.js} +4 -4
- package/dist/{session-control-U3L5H2ZI.js.map → session-control-FIP6ZJLH.js.map} +1 -1
- package/package.json +7 -7
- package/dist/chunk-3I3A5OLB.js.map +0 -1
- package/dist/chunk-3XBQRZZC.js.map +0 -1
- package/dist/chunk-BVRIPCWA.js.map +0 -1
- package/dist/chunk-T5P2QGZ3.js.map +0 -1
- package/dist/opensteer-UGA6YBRN.js +0 -6
|
@@ -6,9 +6,9 @@ var crypto = require('crypto');
|
|
|
6
6
|
var path12 = require('path');
|
|
7
7
|
var url = require('url');
|
|
8
8
|
var child_process = require('child_process');
|
|
9
|
-
var util = require('util');
|
|
10
|
-
var os = require('os');
|
|
11
9
|
var fs = require('fs');
|
|
10
|
+
var os = require('os');
|
|
11
|
+
var util = require('util');
|
|
12
12
|
var module$1 = require('module');
|
|
13
13
|
var enginePlaywright = require('@opensteer/engine-playwright');
|
|
14
14
|
var http = require('http');
|
|
@@ -203,388 +203,174 @@ function isAlreadyExistsError(error) {
|
|
|
203
203
|
}
|
|
204
204
|
async function withFilesystemLock(lockPath, task) {
|
|
205
205
|
await ensureDirectory(path12__default.default.dirname(lockPath));
|
|
206
|
+
const ownerToken = crypto.randomUUID();
|
|
206
207
|
let attempt = 0;
|
|
207
208
|
while (true) {
|
|
208
209
|
try {
|
|
209
210
|
await promises.mkdir(lockPath);
|
|
211
|
+
const acquiredAt = Date.now();
|
|
212
|
+
await writeLockMetadata(lockPath, {
|
|
213
|
+
version: LOCK_METADATA_VERSION,
|
|
214
|
+
ownerToken,
|
|
215
|
+
pid: process.pid,
|
|
216
|
+
acquiredAt,
|
|
217
|
+
heartbeatAt: acquiredAt
|
|
218
|
+
});
|
|
210
219
|
break;
|
|
211
220
|
} catch (error) {
|
|
212
221
|
if (!isAlreadyExistsError(error)) {
|
|
213
222
|
throw error;
|
|
214
223
|
}
|
|
224
|
+
if (await tryRecoverFilesystemLock(lockPath)) {
|
|
225
|
+
attempt = 0;
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
215
228
|
const delayMs = LOCK_RETRY_DELAYS_MS[Math.min(attempt, LOCK_RETRY_DELAYS_MS.length - 1)];
|
|
216
229
|
attempt += 1;
|
|
217
230
|
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
|
|
218
231
|
}
|
|
219
232
|
}
|
|
233
|
+
const heartbeatTimer = setInterval(() => {
|
|
234
|
+
void touchLockMetadata(lockPath, ownerToken);
|
|
235
|
+
}, LOCK_HEARTBEAT_INTERVAL_MS);
|
|
236
|
+
heartbeatTimer.unref?.();
|
|
220
237
|
try {
|
|
221
238
|
return await task();
|
|
222
239
|
} finally {
|
|
223
|
-
|
|
240
|
+
clearInterval(heartbeatTimer);
|
|
241
|
+
const metadata = await readLockMetadata(lockPath);
|
|
242
|
+
if (metadata?.ownerToken === ownerToken) {
|
|
243
|
+
await promises.rm(lockPath, { recursive: true, force: true });
|
|
244
|
+
}
|
|
224
245
|
}
|
|
225
246
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
init_json();
|
|
230
|
-
LOCK_RETRY_DELAYS_MS = [1, 2, 5, 10, 20, 50];
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// src/internal/filesystem.ts
|
|
235
|
-
var init_filesystem2 = __esm({
|
|
236
|
-
"src/internal/filesystem.ts"() {
|
|
237
|
-
init_filesystem();
|
|
247
|
+
async function tryRecoverFilesystemLock(lockPath) {
|
|
248
|
+
if (!await shouldRecoverFilesystemLock(lockPath)) {
|
|
249
|
+
return false;
|
|
238
250
|
}
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
return path12__default.default.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
|
|
251
|
+
await promises.rm(lockPath, { recursive: true, force: true });
|
|
252
|
+
return true;
|
|
242
253
|
}
|
|
243
|
-
async function
|
|
244
|
-
const
|
|
245
|
-
if (
|
|
246
|
-
|
|
254
|
+
async function shouldRecoverFilesystemLock(lockPath) {
|
|
255
|
+
const metadata = await readLockMetadata(lockPath);
|
|
256
|
+
if (metadata !== void 0) {
|
|
257
|
+
if (isProcessRunning(metadata.pid)) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
return Date.now() - metadata.heartbeatAt >= LOCK_ORPHAN_GRACE_MS;
|
|
247
261
|
}
|
|
248
|
-
const
|
|
249
|
-
if (
|
|
250
|
-
return
|
|
262
|
+
const lockStat = await promises.stat(lockPath).catch(() => void 0);
|
|
263
|
+
if (lockStat === void 0) {
|
|
264
|
+
return false;
|
|
251
265
|
}
|
|
252
|
-
return
|
|
253
|
-
}
|
|
254
|
-
async function readPersistedLocalBrowserSessionRecord(rootPath) {
|
|
255
|
-
const record = await readPersistedSessionRecord(rootPath, "local");
|
|
256
|
-
return record?.provider === "local" ? record : void 0;
|
|
257
|
-
}
|
|
258
|
-
async function writePersistedSessionRecord(rootPath, record) {
|
|
259
|
-
await writeJsonFileAtomic(resolveLiveSessionRecordPath(rootPath, record.provider), record);
|
|
260
|
-
}
|
|
261
|
-
async function clearPersistedSessionRecord(rootPath, provider) {
|
|
262
|
-
await promises.rm(resolveLiveSessionRecordPath(rootPath, provider), { force: true });
|
|
266
|
+
return Date.now() - lockStat.mtimeMs >= LOCK_METADATALESS_STALE_MS;
|
|
263
267
|
}
|
|
264
|
-
function
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
var init_live_session = __esm({
|
|
269
|
-
"src/live-session.ts"() {
|
|
270
|
-
init_filesystem2();
|
|
271
|
-
OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
|
|
272
|
-
OPENSTEER_LIVE_SESSION_VERSION = 1;
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
function parseProcessOwner(value) {
|
|
276
|
-
if (!value || typeof value !== "object") {
|
|
277
|
-
return null;
|
|
278
|
-
}
|
|
279
|
-
const parsed = value;
|
|
280
|
-
const pid = Number(parsed.pid);
|
|
281
|
-
const processStartedAtMs = Number(parsed.processStartedAtMs);
|
|
282
|
-
if (!Number.isInteger(pid) || pid <= 0) {
|
|
283
|
-
return null;
|
|
268
|
+
async function readLockMetadata(lockPath) {
|
|
269
|
+
const metadataPath = path12__default.default.join(lockPath, LOCK_METADATA_FILENAME);
|
|
270
|
+
if (!await pathExists(metadataPath)) {
|
|
271
|
+
return void 0;
|
|
284
272
|
}
|
|
285
|
-
|
|
286
|
-
|
|
273
|
+
try {
|
|
274
|
+
const parsed = await readJsonFile(metadataPath);
|
|
275
|
+
const pid = parsed.pid;
|
|
276
|
+
const acquiredAt = parsed.acquiredAt;
|
|
277
|
+
const heartbeatAt = parsed.heartbeatAt;
|
|
278
|
+
if (parsed.version !== LOCK_METADATA_VERSION || typeof parsed.ownerToken !== "string" || parsed.ownerToken.length === 0 || typeof pid !== "number" || !Number.isInteger(pid) || pid <= 0 || typeof acquiredAt !== "number" || !Number.isFinite(acquiredAt) || typeof heartbeatAt !== "number" || !Number.isFinite(heartbeatAt)) {
|
|
279
|
+
return void 0;
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
version: LOCK_METADATA_VERSION,
|
|
283
|
+
ownerToken: parsed.ownerToken,
|
|
284
|
+
pid,
|
|
285
|
+
acquiredAt,
|
|
286
|
+
heartbeatAt
|
|
287
|
+
};
|
|
288
|
+
} catch {
|
|
289
|
+
return void 0;
|
|
287
290
|
}
|
|
288
|
-
return {
|
|
289
|
-
pid,
|
|
290
|
-
processStartedAtMs
|
|
291
|
-
};
|
|
292
291
|
}
|
|
293
|
-
function
|
|
294
|
-
|
|
295
|
-
|
|
292
|
+
async function writeLockMetadata(lockPath, metadata) {
|
|
293
|
+
try {
|
|
294
|
+
await writeJsonFileAtomic(path12__default.default.join(lockPath, LOCK_METADATA_FILENAME), metadata);
|
|
295
|
+
} catch (error) {
|
|
296
|
+
await promises.rm(lockPath, { recursive: true, force: true }).catch(() => void 0);
|
|
297
|
+
throw error;
|
|
296
298
|
}
|
|
297
|
-
return left.pid === right.pid && left.processStartedAtMs === right.processStartedAtMs;
|
|
298
299
|
}
|
|
299
|
-
async function
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const startedAtMs = await readProcessStartedAtMs(owner.pid);
|
|
304
|
-
if (typeof startedAtMs === "number") {
|
|
305
|
-
return hasMatchingProcessStartTime(owner.processStartedAtMs, startedAtMs) ? "live" : "dead";
|
|
300
|
+
async function touchLockMetadata(lockPath, ownerToken) {
|
|
301
|
+
const metadata = await readLockMetadata(lockPath);
|
|
302
|
+
if (metadata === void 0 || metadata.ownerToken !== ownerToken) {
|
|
303
|
+
return;
|
|
306
304
|
}
|
|
307
|
-
|
|
305
|
+
await writeJsonFileAtomic(path12__default.default.join(lockPath, LOCK_METADATA_FILENAME), {
|
|
306
|
+
...metadata,
|
|
307
|
+
heartbeatAt: Date.now()
|
|
308
|
+
}).catch(() => void 0);
|
|
308
309
|
}
|
|
309
310
|
function isProcessRunning(pid) {
|
|
311
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
310
314
|
try {
|
|
311
315
|
process.kill(pid, 0);
|
|
312
316
|
return true;
|
|
313
317
|
} catch (error) {
|
|
314
|
-
|
|
315
|
-
return code !== "ESRCH";
|
|
318
|
+
return error?.code === "EPERM";
|
|
316
319
|
}
|
|
317
320
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (process.platform === "win32") {
|
|
329
|
-
return readWindowsProcessStartedAtMs(pid);
|
|
321
|
+
var LOCK_RETRY_DELAYS_MS, LOCK_METADATA_FILENAME, LOCK_METADATA_VERSION, LOCK_HEARTBEAT_INTERVAL_MS, LOCK_ORPHAN_GRACE_MS, LOCK_METADATALESS_STALE_MS;
|
|
322
|
+
var init_filesystem = __esm({
|
|
323
|
+
"../runtime-core/src/internal/filesystem.ts"() {
|
|
324
|
+
init_json();
|
|
325
|
+
LOCK_RETRY_DELAYS_MS = [1, 2, 5, 10, 20, 50];
|
|
326
|
+
LOCK_METADATA_FILENAME = "owner.json";
|
|
327
|
+
LOCK_METADATA_VERSION = 1;
|
|
328
|
+
LOCK_HEARTBEAT_INTERVAL_MS = 1e3;
|
|
329
|
+
LOCK_ORPHAN_GRACE_MS = 2e3;
|
|
330
|
+
LOCK_METADATALESS_STALE_MS = 3e4;
|
|
330
331
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
} catch {
|
|
338
|
-
return null;
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// src/internal/filesystem.ts
|
|
335
|
+
var init_filesystem2 = __esm({
|
|
336
|
+
"src/internal/filesystem.ts"() {
|
|
337
|
+
init_filesystem();
|
|
339
338
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
339
|
+
});
|
|
340
|
+
function resolveBrandPlatformConfig(brand, platform = process.platform) {
|
|
341
|
+
if (platform === "darwin") {
|
|
342
|
+
return brand.darwin;
|
|
343
343
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
readLinuxClockTicksPerSecond()
|
|
347
|
-
]);
|
|
348
|
-
if (bootTimeMs === null || clockTicksPerSecond === null) {
|
|
349
|
-
return null;
|
|
344
|
+
if (platform === "win32") {
|
|
345
|
+
return brand.win32;
|
|
350
346
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
function parseLinuxProcessStartTicks(statRaw) {
|
|
354
|
-
const closingParenIndex = statRaw.lastIndexOf(")");
|
|
355
|
-
if (closingParenIndex === -1) {
|
|
356
|
-
return null;
|
|
347
|
+
if (platform === "linux") {
|
|
348
|
+
return brand.linux;
|
|
357
349
|
}
|
|
358
|
-
|
|
359
|
-
const startTicks = Number(fields[LINUX_STAT_START_TIME_FIELD_INDEX]);
|
|
360
|
-
return Number.isFinite(startTicks) && startTicks >= 0 ? startTicks : null;
|
|
350
|
+
return void 0;
|
|
361
351
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const
|
|
366
|
-
if (!
|
|
367
|
-
|
|
352
|
+
function detectInstalledBrowserBrands() {
|
|
353
|
+
const installations = [];
|
|
354
|
+
for (const brand of BROWSER_BRANDS) {
|
|
355
|
+
const platformConfig = resolveBrandPlatformConfig(brand);
|
|
356
|
+
if (!platformConfig) {
|
|
357
|
+
continue;
|
|
368
358
|
}
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
} catch {
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
async function readLinuxClockTicksPerSecond() {
|
|
376
|
-
if (!linuxClockTicksPerSecondPromise) {
|
|
377
|
-
linuxClockTicksPerSecondPromise = execFileAsync("getconf", ["CLK_TCK"], {
|
|
378
|
-
encoding: "utf8",
|
|
379
|
-
maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES
|
|
380
|
-
}).then(({ stdout }) => {
|
|
381
|
-
const value = Number.parseInt(stdout.trim(), 10);
|
|
382
|
-
return Number.isFinite(value) && value > 0 ? value : null;
|
|
383
|
-
}).catch(() => null);
|
|
384
|
-
}
|
|
385
|
-
return linuxClockTicksPerSecondPromise;
|
|
386
|
-
}
|
|
387
|
-
async function readWindowsProcessStartedAtMs(pid) {
|
|
388
|
-
try {
|
|
389
|
-
const { stdout } = await execFileAsync(
|
|
390
|
-
"powershell.exe",
|
|
391
|
-
[
|
|
392
|
-
"-NoProfile",
|
|
393
|
-
"-Command",
|
|
394
|
-
`(Get-Process -Id ${String(pid)}).StartTime.ToUniversalTime().ToString("o")`
|
|
395
|
-
],
|
|
396
|
-
{
|
|
397
|
-
encoding: "utf8",
|
|
398
|
-
maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES
|
|
399
|
-
}
|
|
359
|
+
const executablePath = firstExistingPath(
|
|
360
|
+
resolveExecutableCandidates(platformConfig.executableCandidates)
|
|
400
361
|
);
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
return null;
|
|
362
|
+
if (!executablePath) {
|
|
363
|
+
continue;
|
|
404
364
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
async function readPsProcessStartedAtMs(pid) {
|
|
412
|
-
try {
|
|
413
|
-
const { stdout } = await execFileAsync("ps", ["-o", "lstart=", "-p", String(pid)], {
|
|
414
|
-
encoding: "utf8",
|
|
415
|
-
env: PS_COMMAND_ENV,
|
|
416
|
-
maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES
|
|
365
|
+
installations.push({
|
|
366
|
+
brand,
|
|
367
|
+
brandId: brand.id,
|
|
368
|
+
displayName: brand.displayName,
|
|
369
|
+
executablePath,
|
|
370
|
+
userDataDir: path12.resolve(expandHome(platformConfig.userDataDir))
|
|
417
371
|
});
|
|
418
|
-
const startedAt = stdout.trim();
|
|
419
|
-
if (!startedAt) {
|
|
420
|
-
return null;
|
|
421
|
-
}
|
|
422
|
-
const startedAtMs = Date.parse(startedAt.replace(/\s+/g, " "));
|
|
423
|
-
return Number.isFinite(startedAtMs) ? startedAtMs : null;
|
|
424
|
-
} catch {
|
|
425
|
-
return null;
|
|
426
372
|
}
|
|
427
|
-
|
|
428
|
-
var execFileAsync, PROCESS_STARTED_AT_MS, PROCESS_START_TIME_TOLERANCE_MS, PROCESS_LIST_MAX_BUFFER_BYTES, PS_COMMAND_ENV, LINUX_STAT_START_TIME_FIELD_INDEX, CURRENT_PROCESS_OWNER, linuxClockTicksPerSecondPromise;
|
|
429
|
-
var init_process_owner = __esm({
|
|
430
|
-
"src/local-browser/process-owner.ts"() {
|
|
431
|
-
execFileAsync = util.promisify(child_process.execFile);
|
|
432
|
-
PROCESS_STARTED_AT_MS = Math.floor(Date.now() - process.uptime() * 1e3);
|
|
433
|
-
PROCESS_START_TIME_TOLERANCE_MS = 1e3;
|
|
434
|
-
PROCESS_LIST_MAX_BUFFER_BYTES = 16 * 1024 * 1024;
|
|
435
|
-
PS_COMMAND_ENV = { ...process.env, LC_ALL: "C" };
|
|
436
|
-
LINUX_STAT_START_TIME_FIELD_INDEX = 19;
|
|
437
|
-
CURRENT_PROCESS_OWNER = {
|
|
438
|
-
pid: process.pid,
|
|
439
|
-
processStartedAtMs: PROCESS_STARTED_AT_MS
|
|
440
|
-
};
|
|
441
|
-
linuxClockTicksPerSecondPromise = null;
|
|
442
|
-
}
|
|
443
|
-
});
|
|
444
|
-
function resolveOpensteerStateDir() {
|
|
445
|
-
const explicit = process.env.OPENSTEER_HOME?.trim();
|
|
446
|
-
if (explicit) {
|
|
447
|
-
return path12__default.default.resolve(explicit);
|
|
448
|
-
}
|
|
449
|
-
if (process.platform === "win32") {
|
|
450
|
-
return path12__default.default.join(
|
|
451
|
-
process.env.LOCALAPPDATA ?? path12__default.default.join(os.homedir(), "AppData", "Local"),
|
|
452
|
-
"Opensteer"
|
|
453
|
-
);
|
|
454
|
-
}
|
|
455
|
-
if (process.platform === "darwin") {
|
|
456
|
-
return path12__default.default.join(os.homedir(), "Library", "Application Support", "Opensteer");
|
|
457
|
-
}
|
|
458
|
-
return path12__default.default.join(
|
|
459
|
-
process.env.XDG_STATE_HOME ?? path12__default.default.join(os.homedir(), ".local", "state"),
|
|
460
|
-
"opensteer"
|
|
461
|
-
);
|
|
462
|
-
}
|
|
463
|
-
function resolveLocalViewRootDir() {
|
|
464
|
-
return path12__default.default.join(resolveOpensteerStateDir(), "local-view");
|
|
465
|
-
}
|
|
466
|
-
function resolveLocalViewPreferencesPath() {
|
|
467
|
-
return path12__default.default.join(resolveLocalViewRootDir(), "preferences.json");
|
|
468
|
-
}
|
|
469
|
-
function resolveLocalViewServiceDir() {
|
|
470
|
-
return path12__default.default.join(resolveLocalViewRootDir(), "service");
|
|
471
|
-
}
|
|
472
|
-
function resolveLocalViewSessionsDir() {
|
|
473
|
-
return path12__default.default.join(resolveLocalViewRootDir(), "sessions");
|
|
474
|
-
}
|
|
475
|
-
function resolveLocalViewServiceLockDir() {
|
|
476
|
-
return path12__default.default.join(resolveLocalViewServiceDir(), "startup.lock");
|
|
477
|
-
}
|
|
478
|
-
function resolveLocalViewServiceStatePath() {
|
|
479
|
-
return path12__default.default.join(resolveLocalViewServiceDir(), "state.json");
|
|
480
|
-
}
|
|
481
|
-
var init_runtime_dir = __esm({
|
|
482
|
-
"src/local-view/runtime-dir.ts"() {
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
function buildLocalViewSessionId(input) {
|
|
486
|
-
const hash = crypto.createHash("sha256").update(`${input.rootPath}
|
|
487
|
-
${String(input.pid)}
|
|
488
|
-
${String(input.startedAt)}`).digest("hex");
|
|
489
|
-
return `local_${hash.slice(0, 24)}`;
|
|
490
|
-
}
|
|
491
|
-
function createLocalViewSessionManifest(input) {
|
|
492
|
-
return {
|
|
493
|
-
layout: OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT,
|
|
494
|
-
version: OPENSTEER_LOCAL_VIEW_SESSION_VERSION,
|
|
495
|
-
sessionId: buildLocalViewSessionId({
|
|
496
|
-
rootPath: input.rootPath,
|
|
497
|
-
pid: input.live.pid,
|
|
498
|
-
startedAt: input.live.startedAt
|
|
499
|
-
}),
|
|
500
|
-
rootPath: input.rootPath,
|
|
501
|
-
...input.workspace === void 0 ? {} : { workspace: input.workspace },
|
|
502
|
-
engine: input.live.engine,
|
|
503
|
-
ownership: input.ownership,
|
|
504
|
-
pid: input.live.pid,
|
|
505
|
-
startedAt: input.live.startedAt,
|
|
506
|
-
updatedAt: Date.now()
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
async function writeLocalViewSessionManifest(manifest) {
|
|
510
|
-
await ensureDirectory(resolveLocalViewSessionsDir());
|
|
511
|
-
await writeJsonFileAtomic(resolveLocalViewSessionManifestPath(manifest.sessionId), manifest);
|
|
512
|
-
}
|
|
513
|
-
async function deleteLocalViewSessionManifest(sessionId) {
|
|
514
|
-
await promises.rm(resolveLocalViewSessionManifestPath(sessionId), { force: true }).catch(() => void 0);
|
|
515
|
-
}
|
|
516
|
-
async function readLocalViewSessionManifest(sessionId) {
|
|
517
|
-
const manifestPath = resolveLocalViewSessionManifestPath(sessionId);
|
|
518
|
-
if (!await pathExists(manifestPath)) {
|
|
519
|
-
return void 0;
|
|
520
|
-
}
|
|
521
|
-
const parsed = await readJsonFile(manifestPath);
|
|
522
|
-
return isPersistedLocalViewSessionManifest(parsed) ? parsed : void 0;
|
|
523
|
-
}
|
|
524
|
-
async function listLocalViewSessionManifests() {
|
|
525
|
-
const directoryPath = resolveLocalViewSessionsDir();
|
|
526
|
-
const fileNames = await listJsonFiles(directoryPath);
|
|
527
|
-
const manifests = await Promise.all(
|
|
528
|
-
fileNames.map(async (fileName) => {
|
|
529
|
-
const parsed = await readJsonFile(
|
|
530
|
-
path12__default.default.join(directoryPath, fileName)
|
|
531
|
-
).catch(() => void 0);
|
|
532
|
-
return isPersistedLocalViewSessionManifest(parsed) ? parsed : void 0;
|
|
533
|
-
})
|
|
534
|
-
);
|
|
535
|
-
return manifests.filter((manifest) => manifest !== void 0).sort(
|
|
536
|
-
(left, right) => left.startedAt - right.startedAt || left.sessionId.localeCompare(right.sessionId)
|
|
537
|
-
);
|
|
538
|
-
}
|
|
539
|
-
function resolveLocalViewSessionManifestPath(sessionId) {
|
|
540
|
-
return path12__default.default.join(resolveLocalViewSessionsDir(), `${sessionId}.json`);
|
|
541
|
-
}
|
|
542
|
-
function isPersistedLocalViewSessionManifest(value) {
|
|
543
|
-
return value?.layout === OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT && value.version === OPENSTEER_LOCAL_VIEW_SESSION_VERSION && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.rootPath === "string" && value.rootPath.length > 0 && (value.engine === "playwright" || value.engine === "abp") && (value.ownership === "owned" || value.ownership === "attached" || value.ownership === "managed") && typeof value.pid === "number" && Number.isFinite(value.pid) && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt);
|
|
544
|
-
}
|
|
545
|
-
var OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT, OPENSTEER_LOCAL_VIEW_SESSION_VERSION;
|
|
546
|
-
var init_session_manifest = __esm({
|
|
547
|
-
"src/local-view/session-manifest.ts"() {
|
|
548
|
-
init_filesystem2();
|
|
549
|
-
init_runtime_dir();
|
|
550
|
-
OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT = "opensteer-local-view-session";
|
|
551
|
-
OPENSTEER_LOCAL_VIEW_SESSION_VERSION = 1;
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
function resolveBrandPlatformConfig(brand, platform = process.platform) {
|
|
555
|
-
if (platform === "darwin") {
|
|
556
|
-
return brand.darwin;
|
|
557
|
-
}
|
|
558
|
-
if (platform === "win32") {
|
|
559
|
-
return brand.win32;
|
|
560
|
-
}
|
|
561
|
-
if (platform === "linux") {
|
|
562
|
-
return brand.linux;
|
|
563
|
-
}
|
|
564
|
-
return void 0;
|
|
565
|
-
}
|
|
566
|
-
function detectInstalledBrowserBrands() {
|
|
567
|
-
const installations = [];
|
|
568
|
-
for (const brand of BROWSER_BRANDS) {
|
|
569
|
-
const platformConfig = resolveBrandPlatformConfig(brand);
|
|
570
|
-
if (!platformConfig) {
|
|
571
|
-
continue;
|
|
572
|
-
}
|
|
573
|
-
const executablePath = firstExistingPath(
|
|
574
|
-
resolveExecutableCandidates(platformConfig.executableCandidates)
|
|
575
|
-
);
|
|
576
|
-
if (!executablePath) {
|
|
577
|
-
continue;
|
|
578
|
-
}
|
|
579
|
-
installations.push({
|
|
580
|
-
brand,
|
|
581
|
-
brandId: brand.id,
|
|
582
|
-
displayName: brand.displayName,
|
|
583
|
-
executablePath,
|
|
584
|
-
userDataDir: path12.resolve(expandHome(platformConfig.userDataDir))
|
|
585
|
-
});
|
|
586
|
-
}
|
|
587
|
-
return installations;
|
|
373
|
+
return installations;
|
|
588
374
|
}
|
|
589
375
|
function resolveExecutableCandidates(candidates) {
|
|
590
376
|
return candidates.map((candidate) => candidate ? path12.resolve(expandHome(candidate)) : null);
|
|
@@ -1089,60 +875,417 @@ function normalizeProbeTarget(endpoint) {
|
|
|
1089
875
|
throw new Error(`Invalid CDP endpoint "${endpoint}".`);
|
|
1090
876
|
}
|
|
1091
877
|
}
|
|
1092
|
-
async function fetchJson(url, headers, timeoutMs) {
|
|
1093
|
-
const response = await fetch(url, {
|
|
1094
|
-
...headers === void 0 ? {} : { headers },
|
|
1095
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
1096
|
-
}).catch(() => null);
|
|
1097
|
-
if (!response?.ok) {
|
|
1098
|
-
return null;
|
|
878
|
+
async function fetchJson(url, headers, timeoutMs) {
|
|
879
|
+
const response = await fetch(url, {
|
|
880
|
+
...headers === void 0 ? {} : { headers },
|
|
881
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
882
|
+
}).catch(() => null);
|
|
883
|
+
if (!response?.ok) {
|
|
884
|
+
return null;
|
|
885
|
+
}
|
|
886
|
+
return await response.json();
|
|
887
|
+
}
|
|
888
|
+
async function isHttpEndpointReachable(url, timeoutMs) {
|
|
889
|
+
const response = await fetch(url, {
|
|
890
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
891
|
+
}).catch(() => null);
|
|
892
|
+
return response !== null;
|
|
893
|
+
}
|
|
894
|
+
function buildBrowserWebSocketUrl(httpUrl, webSocketPath) {
|
|
895
|
+
const protocol = httpUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
896
|
+
return `${protocol}//${httpUrl.host}${normalizeWebSocketPath(webSocketPath)}`;
|
|
897
|
+
}
|
|
898
|
+
function normalizeWebSocketPath(path15) {
|
|
899
|
+
return path15.startsWith("/") ? path15 : `/${path15}`;
|
|
900
|
+
}
|
|
901
|
+
function rewriteBrowserWebSocketHost(browserWsUrl, requestedUrl) {
|
|
902
|
+
try {
|
|
903
|
+
const parsed = new URL(browserWsUrl);
|
|
904
|
+
parsed.protocol = requestedUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
905
|
+
parsed.hostname = requestedUrl.hostname;
|
|
906
|
+
parsed.port = requestedUrl.port;
|
|
907
|
+
return parsed.toString();
|
|
908
|
+
} catch {
|
|
909
|
+
return browserWsUrl;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
function readPort(url) {
|
|
913
|
+
const port = Number.parseInt(url.port, 10);
|
|
914
|
+
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
915
|
+
}
|
|
916
|
+
var DEFAULT_DISCOVERY_TIMEOUT_MS, DISCOVERY_FALLBACK_PORT, OpensteerAttachAmbiguousError;
|
|
917
|
+
var init_cdp_discovery = __esm({
|
|
918
|
+
"src/local-browser/cdp-discovery.ts"() {
|
|
919
|
+
init_chrome_discovery();
|
|
920
|
+
DEFAULT_DISCOVERY_TIMEOUT_MS = 2e3;
|
|
921
|
+
DISCOVERY_FALLBACK_PORT = 9222;
|
|
922
|
+
OpensteerAttachAmbiguousError = class extends Error {
|
|
923
|
+
constructor(candidates) {
|
|
924
|
+
super(
|
|
925
|
+
"Multiple running Chromium DevTools endpoints were discovered. Specify the desired endpoint explicitly."
|
|
926
|
+
);
|
|
927
|
+
this.candidates = candidates;
|
|
928
|
+
this.name = "OpensteerAttachAmbiguousError";
|
|
929
|
+
}
|
|
930
|
+
code = "attach-ambiguous";
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
function resolveLiveSessionRecordPath(rootPath, provider) {
|
|
935
|
+
return path12__default.default.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
|
|
936
|
+
}
|
|
937
|
+
async function readPersistedSessionRecord(rootPath, provider) {
|
|
938
|
+
const sessionPath = resolveLiveSessionRecordPath(rootPath, provider);
|
|
939
|
+
if (!await pathExists(sessionPath)) {
|
|
940
|
+
return void 0;
|
|
941
|
+
}
|
|
942
|
+
const parsed = await readJsonFile(sessionPath);
|
|
943
|
+
if (isPersistedLocalBrowserSessionRecord(parsed)) {
|
|
944
|
+
return parsed;
|
|
945
|
+
}
|
|
946
|
+
return void 0;
|
|
947
|
+
}
|
|
948
|
+
async function readPersistedLocalBrowserSessionRecord(rootPath) {
|
|
949
|
+
const record = await readPersistedSessionRecord(rootPath, "local");
|
|
950
|
+
return record?.provider === "local" ? record : void 0;
|
|
951
|
+
}
|
|
952
|
+
async function writePersistedSessionRecord(rootPath, record) {
|
|
953
|
+
await writeJsonFileAtomic(resolveLiveSessionRecordPath(rootPath, record.provider), record);
|
|
954
|
+
}
|
|
955
|
+
async function clearPersistedSessionRecord(rootPath, provider) {
|
|
956
|
+
await promises.rm(resolveLiveSessionRecordPath(rootPath, provider), { force: true });
|
|
957
|
+
}
|
|
958
|
+
function getPersistedLocalBrowserSessionOwnership(record) {
|
|
959
|
+
return record.ownership === "attached" ? "attached" : "owned";
|
|
960
|
+
}
|
|
961
|
+
async function isAttachedLocalBrowserSessionReachable(record) {
|
|
962
|
+
if (getPersistedLocalBrowserSessionOwnership(record) !== "attached") {
|
|
963
|
+
return false;
|
|
964
|
+
}
|
|
965
|
+
if (record.engine !== "playwright" || record.endpoint === void 0) {
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
try {
|
|
969
|
+
await inspectCdpEndpoint({
|
|
970
|
+
endpoint: record.endpoint,
|
|
971
|
+
timeoutMs: 1500
|
|
972
|
+
});
|
|
973
|
+
return true;
|
|
974
|
+
} catch {
|
|
975
|
+
return false;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
function isPersistedLocalBrowserSessionRecord(value) {
|
|
979
|
+
return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "local" && (value.engine === "playwright" || value.engine === "abp") && (value.ownership === void 0 || value.ownership === "owned" || value.ownership === "attached") && typeof value.pid === "number" && Number.isFinite(value.pid) && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt) && typeof value.userDataDir === "string" && value.userDataDir.length > 0;
|
|
980
|
+
}
|
|
981
|
+
var OPENSTEER_LIVE_SESSION_LAYOUT, OPENSTEER_LIVE_SESSION_VERSION;
|
|
982
|
+
var init_live_session = __esm({
|
|
983
|
+
"src/live-session.ts"() {
|
|
984
|
+
init_filesystem2();
|
|
985
|
+
init_cdp_discovery();
|
|
986
|
+
OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
|
|
987
|
+
OPENSTEER_LIVE_SESSION_VERSION = 1;
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
function parseProcessOwner(value) {
|
|
991
|
+
if (!value || typeof value !== "object") {
|
|
992
|
+
return null;
|
|
993
|
+
}
|
|
994
|
+
const parsed = value;
|
|
995
|
+
const pid = Number(parsed.pid);
|
|
996
|
+
const processStartedAtMs = Number(parsed.processStartedAtMs);
|
|
997
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
998
|
+
return null;
|
|
999
|
+
}
|
|
1000
|
+
if (!Number.isInteger(processStartedAtMs) || processStartedAtMs <= 0) {
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
return {
|
|
1004
|
+
pid,
|
|
1005
|
+
processStartedAtMs
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
function processOwnersEqual(left, right) {
|
|
1009
|
+
if (!left || !right) {
|
|
1010
|
+
return left === right;
|
|
1011
|
+
}
|
|
1012
|
+
return left.pid === right.pid && left.processStartedAtMs === right.processStartedAtMs;
|
|
1013
|
+
}
|
|
1014
|
+
async function getProcessLiveness(owner) {
|
|
1015
|
+
if (owner.pid === process.pid && hasMatchingProcessStartTime(owner.processStartedAtMs, PROCESS_STARTED_AT_MS)) {
|
|
1016
|
+
return "live";
|
|
1017
|
+
}
|
|
1018
|
+
const startedAtMs = await readProcessStartedAtMs(owner.pid);
|
|
1019
|
+
if (typeof startedAtMs === "number") {
|
|
1020
|
+
return hasMatchingProcessStartTime(owner.processStartedAtMs, startedAtMs) ? "live" : "dead";
|
|
1021
|
+
}
|
|
1022
|
+
return isProcessRunning2(owner.pid) ? "unknown" : "dead";
|
|
1023
|
+
}
|
|
1024
|
+
function isProcessRunning2(pid) {
|
|
1025
|
+
try {
|
|
1026
|
+
process.kill(pid, 0);
|
|
1027
|
+
return true;
|
|
1028
|
+
} catch (error) {
|
|
1029
|
+
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
1030
|
+
return code !== "ESRCH";
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
function hasMatchingProcessStartTime(expectedStartedAtMs, actualStartedAtMs) {
|
|
1034
|
+
return Math.abs(expectedStartedAtMs - actualStartedAtMs) <= PROCESS_START_TIME_TOLERANCE_MS;
|
|
1035
|
+
}
|
|
1036
|
+
async function readProcessStartedAtMs(pid) {
|
|
1037
|
+
if (pid <= 0) {
|
|
1038
|
+
return null;
|
|
1039
|
+
}
|
|
1040
|
+
if (process.platform === "linux") {
|
|
1041
|
+
return readLinuxProcessStartedAtMs(pid);
|
|
1042
|
+
}
|
|
1043
|
+
if (process.platform === "win32") {
|
|
1044
|
+
return readWindowsProcessStartedAtMs(pid);
|
|
1045
|
+
}
|
|
1046
|
+
return readPsProcessStartedAtMs(pid);
|
|
1047
|
+
}
|
|
1048
|
+
async function readLinuxProcessStartedAtMs(pid) {
|
|
1049
|
+
let statRaw;
|
|
1050
|
+
try {
|
|
1051
|
+
statRaw = await promises.readFile(`/proc/${String(pid)}/stat`, "utf8");
|
|
1052
|
+
} catch {
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1055
|
+
const startTicks = parseLinuxProcessStartTicks(statRaw);
|
|
1056
|
+
if (startTicks === null) {
|
|
1057
|
+
return null;
|
|
1058
|
+
}
|
|
1059
|
+
const [bootTimeMs, clockTicksPerSecond] = await Promise.all([
|
|
1060
|
+
readLinuxBootTimeMs(),
|
|
1061
|
+
readLinuxClockTicksPerSecond()
|
|
1062
|
+
]);
|
|
1063
|
+
if (bootTimeMs === null || clockTicksPerSecond === null) {
|
|
1064
|
+
return null;
|
|
1065
|
+
}
|
|
1066
|
+
return Math.floor(bootTimeMs + startTicks * 1e3 / clockTicksPerSecond);
|
|
1067
|
+
}
|
|
1068
|
+
function parseLinuxProcessStartTicks(statRaw) {
|
|
1069
|
+
const closingParenIndex = statRaw.lastIndexOf(")");
|
|
1070
|
+
if (closingParenIndex === -1) {
|
|
1071
|
+
return null;
|
|
1072
|
+
}
|
|
1073
|
+
const fields = statRaw.slice(closingParenIndex + 2).trim().split(/\s+/);
|
|
1074
|
+
const startTicks = Number(fields[LINUX_STAT_START_TIME_FIELD_INDEX]);
|
|
1075
|
+
return Number.isFinite(startTicks) && startTicks >= 0 ? startTicks : null;
|
|
1076
|
+
}
|
|
1077
|
+
async function readLinuxBootTimeMs() {
|
|
1078
|
+
try {
|
|
1079
|
+
const statRaw = await promises.readFile("/proc/stat", "utf8");
|
|
1080
|
+
const bootTimeLine = statRaw.split("\n").find((line) => line.startsWith("btime "));
|
|
1081
|
+
if (!bootTimeLine) {
|
|
1082
|
+
return null;
|
|
1083
|
+
}
|
|
1084
|
+
const bootTimeSeconds = Number.parseInt(bootTimeLine.slice("btime ".length), 10);
|
|
1085
|
+
return Number.isFinite(bootTimeSeconds) ? bootTimeSeconds * 1e3 : null;
|
|
1086
|
+
} catch {
|
|
1087
|
+
return null;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
async function readLinuxClockTicksPerSecond() {
|
|
1091
|
+
if (!linuxClockTicksPerSecondPromise) {
|
|
1092
|
+
linuxClockTicksPerSecondPromise = execFileAsync("getconf", ["CLK_TCK"], {
|
|
1093
|
+
encoding: "utf8",
|
|
1094
|
+
maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2
|
|
1095
|
+
}).then(({ stdout }) => {
|
|
1096
|
+
const value = Number.parseInt(stdout.trim(), 10);
|
|
1097
|
+
return Number.isFinite(value) && value > 0 ? value : null;
|
|
1098
|
+
}).catch(() => null);
|
|
1099
|
+
}
|
|
1100
|
+
return linuxClockTicksPerSecondPromise;
|
|
1101
|
+
}
|
|
1102
|
+
async function readWindowsProcessStartedAtMs(pid) {
|
|
1103
|
+
try {
|
|
1104
|
+
const { stdout } = await execFileAsync(
|
|
1105
|
+
"powershell.exe",
|
|
1106
|
+
[
|
|
1107
|
+
"-NoProfile",
|
|
1108
|
+
"-Command",
|
|
1109
|
+
`(Get-Process -Id ${String(pid)}).StartTime.ToUniversalTime().ToString("o")`
|
|
1110
|
+
],
|
|
1111
|
+
{
|
|
1112
|
+
encoding: "utf8",
|
|
1113
|
+
maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2
|
|
1114
|
+
}
|
|
1115
|
+
);
|
|
1116
|
+
const isoTimestamp = stdout.trim();
|
|
1117
|
+
if (!isoTimestamp) {
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
const startedAtMs = Date.parse(isoTimestamp);
|
|
1121
|
+
return Number.isFinite(startedAtMs) ? startedAtMs : null;
|
|
1122
|
+
} catch {
|
|
1123
|
+
return null;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
async function readPsProcessStartedAtMs(pid) {
|
|
1127
|
+
try {
|
|
1128
|
+
const { stdout } = await execFileAsync("ps", ["-o", "lstart=", "-p", String(pid)], {
|
|
1129
|
+
encoding: "utf8",
|
|
1130
|
+
env: PS_COMMAND_ENV2,
|
|
1131
|
+
maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2
|
|
1132
|
+
});
|
|
1133
|
+
const startedAt = stdout.trim();
|
|
1134
|
+
if (!startedAt) {
|
|
1135
|
+
return null;
|
|
1136
|
+
}
|
|
1137
|
+
const startedAtMs = Date.parse(startedAt.replace(/\s+/g, " "));
|
|
1138
|
+
return Number.isFinite(startedAtMs) ? startedAtMs : null;
|
|
1139
|
+
} catch {
|
|
1140
|
+
return null;
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
var execFileAsync, PROCESS_STARTED_AT_MS, PROCESS_START_TIME_TOLERANCE_MS, PROCESS_LIST_MAX_BUFFER_BYTES2, PS_COMMAND_ENV2, LINUX_STAT_START_TIME_FIELD_INDEX, CURRENT_PROCESS_OWNER, linuxClockTicksPerSecondPromise;
|
|
1144
|
+
var init_process_owner = __esm({
|
|
1145
|
+
"src/local-browser/process-owner.ts"() {
|
|
1146
|
+
execFileAsync = util.promisify(child_process.execFile);
|
|
1147
|
+
PROCESS_STARTED_AT_MS = Math.floor(Date.now() - process.uptime() * 1e3);
|
|
1148
|
+
PROCESS_START_TIME_TOLERANCE_MS = 1e3;
|
|
1149
|
+
PROCESS_LIST_MAX_BUFFER_BYTES2 = 16 * 1024 * 1024;
|
|
1150
|
+
PS_COMMAND_ENV2 = { ...process.env, LC_ALL: "C" };
|
|
1151
|
+
LINUX_STAT_START_TIME_FIELD_INDEX = 19;
|
|
1152
|
+
CURRENT_PROCESS_OWNER = {
|
|
1153
|
+
pid: process.pid,
|
|
1154
|
+
processStartedAtMs: PROCESS_STARTED_AT_MS
|
|
1155
|
+
};
|
|
1156
|
+
linuxClockTicksPerSecondPromise = null;
|
|
1157
|
+
}
|
|
1158
|
+
});
|
|
1159
|
+
function resolveOpensteerStateDir() {
|
|
1160
|
+
const explicit = process.env.OPENSTEER_HOME?.trim();
|
|
1161
|
+
if (explicit) {
|
|
1162
|
+
return path12__default.default.resolve(explicit);
|
|
1163
|
+
}
|
|
1164
|
+
if (process.platform === "win32") {
|
|
1165
|
+
return path12__default.default.join(
|
|
1166
|
+
process.env.LOCALAPPDATA ?? path12__default.default.join(os.homedir(), "AppData", "Local"),
|
|
1167
|
+
"Opensteer"
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
if (process.platform === "darwin") {
|
|
1171
|
+
return path12__default.default.join(os.homedir(), "Library", "Application Support", "Opensteer");
|
|
1172
|
+
}
|
|
1173
|
+
return path12__default.default.join(
|
|
1174
|
+
process.env.XDG_STATE_HOME ?? path12__default.default.join(os.homedir(), ".local", "state"),
|
|
1175
|
+
"opensteer"
|
|
1176
|
+
);
|
|
1177
|
+
}
|
|
1178
|
+
function resolveLocalViewRootDir() {
|
|
1179
|
+
return path12__default.default.join(resolveOpensteerStateDir(), "local-view");
|
|
1180
|
+
}
|
|
1181
|
+
function resolveLocalViewPreferencesPath() {
|
|
1182
|
+
return path12__default.default.join(resolveLocalViewRootDir(), "preferences.json");
|
|
1183
|
+
}
|
|
1184
|
+
function resolveLocalViewServiceDir() {
|
|
1185
|
+
return path12__default.default.join(resolveLocalViewRootDir(), "service");
|
|
1186
|
+
}
|
|
1187
|
+
function resolveLocalViewSessionsDir() {
|
|
1188
|
+
return path12__default.default.join(resolveLocalViewRootDir(), "sessions");
|
|
1189
|
+
}
|
|
1190
|
+
function resolveLocalViewServiceLockDir() {
|
|
1191
|
+
return path12__default.default.join(resolveLocalViewServiceDir(), "startup.lock");
|
|
1192
|
+
}
|
|
1193
|
+
function resolveLocalViewServiceStatePath() {
|
|
1194
|
+
return path12__default.default.join(resolveLocalViewServiceDir(), "state.json");
|
|
1195
|
+
}
|
|
1196
|
+
var init_runtime_dir = __esm({
|
|
1197
|
+
"src/local-view/runtime-dir.ts"() {
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
1200
|
+
function buildLocalViewSessionId(input) {
|
|
1201
|
+
const ownership = input.ownership ?? "owned";
|
|
1202
|
+
const identity = ownership === "attached" ? input.endpoint ?? input.remoteDebuggingUrl ?? input.baseUrl ?? "attached" : `pid:${String(input.pid ?? 0)}`;
|
|
1203
|
+
const hash = crypto.createHash("sha256").update(`${input.rootPath}
|
|
1204
|
+
${ownership}
|
|
1205
|
+
${identity}
|
|
1206
|
+
${String(input.startedAt)}`).digest("hex");
|
|
1207
|
+
return `local_${hash.slice(0, 24)}`;
|
|
1208
|
+
}
|
|
1209
|
+
function buildLocalViewSessionIdForRecord(input) {
|
|
1210
|
+
const ownership = getPersistedLocalBrowserSessionOwnership(input.live);
|
|
1211
|
+
if (ownership === "attached") {
|
|
1212
|
+
return buildLocalViewSessionId({
|
|
1213
|
+
rootPath: input.rootPath,
|
|
1214
|
+
ownership,
|
|
1215
|
+
startedAt: input.live.startedAt,
|
|
1216
|
+
...input.live.endpoint === void 0 ? {} : { endpoint: input.live.endpoint },
|
|
1217
|
+
...input.live.baseUrl === void 0 ? {} : { baseUrl: input.live.baseUrl },
|
|
1218
|
+
...input.live.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: input.live.remoteDebuggingUrl }
|
|
1219
|
+
});
|
|
1099
1220
|
}
|
|
1100
|
-
return
|
|
1221
|
+
return buildLocalViewSessionId({
|
|
1222
|
+
rootPath: input.rootPath,
|
|
1223
|
+
ownership,
|
|
1224
|
+
startedAt: input.live.startedAt,
|
|
1225
|
+
pid: input.live.pid
|
|
1226
|
+
});
|
|
1101
1227
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1228
|
+
function createLocalViewSessionManifest(input) {
|
|
1229
|
+
return {
|
|
1230
|
+
layout: OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT,
|
|
1231
|
+
version: OPENSTEER_LOCAL_VIEW_SESSION_VERSION,
|
|
1232
|
+
sessionId: buildLocalViewSessionIdForRecord({
|
|
1233
|
+
rootPath: input.rootPath,
|
|
1234
|
+
live: input.live
|
|
1235
|
+
}),
|
|
1236
|
+
rootPath: input.rootPath,
|
|
1237
|
+
...input.workspace === void 0 ? {} : { workspace: input.workspace },
|
|
1238
|
+
engine: input.live.engine,
|
|
1239
|
+
ownership: input.ownership,
|
|
1240
|
+
pid: input.live.pid,
|
|
1241
|
+
startedAt: input.live.startedAt,
|
|
1242
|
+
updatedAt: Date.now()
|
|
1243
|
+
};
|
|
1107
1244
|
}
|
|
1108
|
-
function
|
|
1109
|
-
|
|
1110
|
-
|
|
1245
|
+
async function writeLocalViewSessionManifest(manifest) {
|
|
1246
|
+
await ensureDirectory(resolveLocalViewSessionsDir());
|
|
1247
|
+
await writeJsonFileAtomic(resolveLocalViewSessionManifestPath(manifest.sessionId), manifest);
|
|
1111
1248
|
}
|
|
1112
|
-
function
|
|
1113
|
-
|
|
1249
|
+
async function deleteLocalViewSessionManifest(sessionId) {
|
|
1250
|
+
await promises.rm(resolveLocalViewSessionManifestPath(sessionId), { force: true }).catch(() => void 0);
|
|
1114
1251
|
}
|
|
1115
|
-
function
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
parsed.hostname = requestedUrl.hostname;
|
|
1120
|
-
parsed.port = requestedUrl.port;
|
|
1121
|
-
return parsed.toString();
|
|
1122
|
-
} catch {
|
|
1123
|
-
return browserWsUrl;
|
|
1252
|
+
async function readLocalViewSessionManifest(sessionId) {
|
|
1253
|
+
const manifestPath = resolveLocalViewSessionManifestPath(sessionId);
|
|
1254
|
+
if (!await pathExists(manifestPath)) {
|
|
1255
|
+
return void 0;
|
|
1124
1256
|
}
|
|
1257
|
+
const parsed = await readJsonFile(manifestPath);
|
|
1258
|
+
return isPersistedLocalViewSessionManifest(parsed) ? parsed : void 0;
|
|
1125
1259
|
}
|
|
1126
|
-
function
|
|
1127
|
-
const
|
|
1128
|
-
|
|
1260
|
+
async function listLocalViewSessionManifests() {
|
|
1261
|
+
const directoryPath = resolveLocalViewSessionsDir();
|
|
1262
|
+
const fileNames = await listJsonFiles(directoryPath);
|
|
1263
|
+
const manifests = await Promise.all(
|
|
1264
|
+
fileNames.map(async (fileName) => {
|
|
1265
|
+
const parsed = await readJsonFile(
|
|
1266
|
+
path12__default.default.join(directoryPath, fileName)
|
|
1267
|
+
).catch(() => void 0);
|
|
1268
|
+
return isPersistedLocalViewSessionManifest(parsed) ? parsed : void 0;
|
|
1269
|
+
})
|
|
1270
|
+
);
|
|
1271
|
+
return manifests.filter((manifest) => manifest !== void 0).sort(
|
|
1272
|
+
(left, right) => left.startedAt - right.startedAt || left.sessionId.localeCompare(right.sessionId)
|
|
1273
|
+
);
|
|
1129
1274
|
}
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
code = "attach-ambiguous";
|
|
1145
|
-
};
|
|
1275
|
+
function resolveLocalViewSessionManifestPath(sessionId) {
|
|
1276
|
+
return path12__default.default.join(resolveLocalViewSessionsDir(), `${sessionId}.json`);
|
|
1277
|
+
}
|
|
1278
|
+
function isPersistedLocalViewSessionManifest(value) {
|
|
1279
|
+
return value?.layout === OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT && value.version === OPENSTEER_LOCAL_VIEW_SESSION_VERSION && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.rootPath === "string" && value.rootPath.length > 0 && (value.engine === "playwright" || value.engine === "abp") && (value.ownership === "owned" || value.ownership === "attached" || value.ownership === "managed") && typeof value.pid === "number" && Number.isFinite(value.pid) && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt);
|
|
1280
|
+
}
|
|
1281
|
+
var OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT, OPENSTEER_LOCAL_VIEW_SESSION_VERSION;
|
|
1282
|
+
var init_session_manifest = __esm({
|
|
1283
|
+
"src/local-view/session-manifest.ts"() {
|
|
1284
|
+
init_filesystem2();
|
|
1285
|
+
init_live_session();
|
|
1286
|
+
init_runtime_dir();
|
|
1287
|
+
OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT = "opensteer-local-view-session";
|
|
1288
|
+
OPENSTEER_LOCAL_VIEW_SESSION_VERSION = 1;
|
|
1146
1289
|
}
|
|
1147
1290
|
});
|
|
1148
1291
|
async function readLocalViewServiceState() {
|
|
@@ -2228,7 +2371,7 @@ var init_version = __esm({
|
|
|
2228
2371
|
"../protocol/src/version.ts"() {
|
|
2229
2372
|
init_json2();
|
|
2230
2373
|
OPENSTEER_PROTOCOL_NAME = "opensteer";
|
|
2231
|
-
OPENSTEER_PROTOCOL_COMPATIBILITY_REVISION =
|
|
2374
|
+
OPENSTEER_PROTOCOL_COMPATIBILITY_REVISION = 3;
|
|
2232
2375
|
OPENSTEER_PROTOCOL_VERSION = `0.${OPENSTEER_PROTOCOL_COMPATIBILITY_REVISION}.0`;
|
|
2233
2376
|
OPENSTEER_PROTOCOL_MEDIA_TYPE = `application/vnd.${OPENSTEER_PROTOCOL_NAME}+json;version=${OPENSTEER_PROTOCOL_VERSION}`;
|
|
2234
2377
|
OPENSTEER_PROTOCOL_REST_BASE_PATH = `/api/v${OPENSTEER_PROTOCOL_COMPATIBILITY_REVISION}`;
|
|
@@ -6252,14 +6395,14 @@ var init_interaction = __esm({
|
|
|
6252
6395
|
function defineSemanticOperationSpec(spec) {
|
|
6253
6396
|
return spec;
|
|
6254
6397
|
}
|
|
6255
|
-
var opensteerComputerAnnotationNames, opensteerExposedSemanticOperationNames, opensteerPackageRunnableSemanticOperationNames, snapshotModeSchema, viewportSchema, opensteerBrowserLaunchOptionsSchema, attachBrowserOptionsSchema, opensteerBrowserOptionsSchema, opensteerBrowserContextOptionsSchema, targetByElementSchema2, targetByPersistSchema2, targetBySelectorSchema2, opensteerTargetInputSchema,
|
|
6398
|
+
var opensteerComputerAnnotationNames, opensteerExposedSemanticOperationNames, opensteerPackageRunnableSemanticOperationNames, snapshotModeSchema, viewportSchema, opensteerBrowserLaunchOptionsSchema, attachBrowserOptionsSchema, opensteerBrowserOptionsSchema, opensteerBrowserContextOptionsSchema, targetByElementSchema2, targetByPersistSchema2, targetBySelectorSchema2, opensteerTargetInputSchema, opensteerActionResultSchema, opensteerSnapshotCounterSchema, opensteerNavigationSummarySchema, opensteerOpenInputSchema, opensteerPageListInputSchema, opensteerPageListOutputSchema, opensteerPageNewInputSchema, opensteerPageActivateInputSchema, opensteerPageCloseInputSchema, opensteerPageCloseOutputSchema, opensteerPageNewOutputSchema, opensteerPageGotoInputSchema, opensteerPageEvaluateInputSchema, opensteerPageEvaluateOutputSchema, opensteerAddInitScriptInputSchema, opensteerAddInitScriptOutputSchema, opensteerCapturedScriptSchema, opensteerCaptureScriptsInputSchema, opensteerCaptureScriptsOutputSchema, opensteerPageSnapshotInputSchema, opensteerPageSnapshotOutputSchema, opensteerComputerMouseButtonSchema, opensteerComputerKeyModifierSchema, opensteerDomClickInputSchema, opensteerDomHoverInputSchema, opensteerDomInputInputSchema, opensteerDomScrollInputSchema, opensteerExtractTemplateSchema, opensteerDomExtractInputSchema, jsonValueSchema2, opensteerDomExtractOutputSchema, opensteerSessionCloseInputSchema, opensteerSessionCloseOutputSchema, opensteerComputerAnnotationSchema, opensteerComputerClickActionSchema, opensteerComputerMoveActionSchema, opensteerComputerScrollActionSchema, opensteerComputerTypeActionSchema, opensteerComputerKeyActionSchema, opensteerComputerDragActionSchema, opensteerComputerScreenshotActionSchema, opensteerComputerWaitActionSchema, opensteerComputerActionSchema, opensteerComputerScreenshotOptionsSchema, opensteerComputerExecuteInputSchema, opensteerScreenshotSummarySchema, opensteerComputerExecuteOutputSchema, opensteerSemanticOperationSpecificationsBase, exposedSemanticOperationNameSet, opensteerSemanticOperationSpecificationsInternal, opensteerSemanticOperationSpecifications, semanticRestBasePath;
|
|
6256
6399
|
var init_semantic = __esm({
|
|
6257
6400
|
"../protocol/src/semantic.ts"() {
|
|
6258
6401
|
init_json2();
|
|
6402
|
+
init_binary_location();
|
|
6259
6403
|
init_identity();
|
|
6260
6404
|
init_geometry();
|
|
6261
6405
|
init_metadata();
|
|
6262
|
-
init_events();
|
|
6263
6406
|
init_envelopes();
|
|
6264
6407
|
init_snapshots();
|
|
6265
6408
|
init_artifacts2();
|
|
@@ -6482,39 +6625,14 @@ var init_semantic = __esm({
|
|
|
6482
6625
|
title: "OpensteerTargetInput"
|
|
6483
6626
|
}
|
|
6484
6627
|
);
|
|
6485
|
-
opensteerResolvedTargetSchema = objectSchema(
|
|
6486
|
-
{
|
|
6487
|
-
pageRef: pageRefSchema,
|
|
6488
|
-
frameRef: frameRefSchema,
|
|
6489
|
-
documentRef: documentRefSchema,
|
|
6490
|
-
documentEpoch: documentEpochSchema,
|
|
6491
|
-
nodeRef: nodeRefSchema,
|
|
6492
|
-
tagName: stringSchema(),
|
|
6493
|
-
pathHint: stringSchema(),
|
|
6494
|
-
persist: stringSchema(),
|
|
6495
|
-
selectorUsed: stringSchema()
|
|
6496
|
-
},
|
|
6497
|
-
{
|
|
6498
|
-
title: "OpensteerResolvedTarget",
|
|
6499
|
-
required: [
|
|
6500
|
-
"pageRef",
|
|
6501
|
-
"frameRef",
|
|
6502
|
-
"documentRef",
|
|
6503
|
-
"documentEpoch",
|
|
6504
|
-
"nodeRef",
|
|
6505
|
-
"tagName",
|
|
6506
|
-
"pathHint"
|
|
6507
|
-
]
|
|
6508
|
-
}
|
|
6509
|
-
);
|
|
6510
6628
|
opensteerActionResultSchema = objectSchema(
|
|
6511
6629
|
{
|
|
6512
|
-
|
|
6513
|
-
|
|
6630
|
+
tagName: stringSchema({ minLength: 1 }),
|
|
6631
|
+
persist: stringSchema({ minLength: 1 })
|
|
6514
6632
|
},
|
|
6515
6633
|
{
|
|
6516
6634
|
title: "OpensteerActionResult",
|
|
6517
|
-
required: ["
|
|
6635
|
+
required: ["tagName"]
|
|
6518
6636
|
}
|
|
6519
6637
|
);
|
|
6520
6638
|
opensteerSnapshotCounterSchema = objectSchema(
|
|
@@ -6560,16 +6678,14 @@ var init_semantic = __esm({
|
|
|
6560
6678
|
]
|
|
6561
6679
|
}
|
|
6562
6680
|
);
|
|
6563
|
-
|
|
6681
|
+
opensteerNavigationSummarySchema = objectSchema(
|
|
6564
6682
|
{
|
|
6565
|
-
sessionRef: sessionRefSchema,
|
|
6566
|
-
pageRef: pageRefSchema,
|
|
6567
6683
|
url: stringSchema(),
|
|
6568
6684
|
title: stringSchema()
|
|
6569
6685
|
},
|
|
6570
6686
|
{
|
|
6571
|
-
title: "
|
|
6572
|
-
required: ["
|
|
6687
|
+
title: "OpensteerNavigationSummary",
|
|
6688
|
+
required: ["url", "title"]
|
|
6573
6689
|
}
|
|
6574
6690
|
);
|
|
6575
6691
|
opensteerOpenInputSchema = objectSchema(
|
|
@@ -6637,6 +6753,17 @@ var init_semantic = __esm({
|
|
|
6637
6753
|
required: ["closedPageRef", "pages"]
|
|
6638
6754
|
}
|
|
6639
6755
|
);
|
|
6756
|
+
opensteerPageNewOutputSchema = objectSchema(
|
|
6757
|
+
{
|
|
6758
|
+
pageRef: pageRefSchema,
|
|
6759
|
+
url: stringSchema(),
|
|
6760
|
+
title: stringSchema()
|
|
6761
|
+
},
|
|
6762
|
+
{
|
|
6763
|
+
title: "OpensteerPageNewOutput",
|
|
6764
|
+
required: ["pageRef", "url", "title"]
|
|
6765
|
+
}
|
|
6766
|
+
);
|
|
6640
6767
|
opensteerPageGotoInputSchema = objectSchema(
|
|
6641
6768
|
{
|
|
6642
6769
|
url: stringSchema(),
|
|
@@ -7023,72 +7150,28 @@ var init_semantic = __esm({
|
|
|
7023
7150
|
required: ["action"]
|
|
7024
7151
|
}
|
|
7025
7152
|
);
|
|
7026
|
-
|
|
7027
|
-
{
|
|
7028
|
-
role: enumSchema(["point", "start", "end"]),
|
|
7029
|
-
point: pointSchema,
|
|
7030
|
-
hitTest: hitTestResultSchema,
|
|
7031
|
-
target: opensteerResolvedTargetSchema
|
|
7032
|
-
},
|
|
7033
|
-
{
|
|
7034
|
-
title: "OpensteerComputerTracePoint",
|
|
7035
|
-
required: ["role", "point"]
|
|
7036
|
-
}
|
|
7037
|
-
);
|
|
7038
|
-
opensteerComputerTraceEnrichmentSchema = objectSchema(
|
|
7039
|
-
{
|
|
7040
|
-
points: arraySchema(opensteerComputerTracePointSchema)
|
|
7041
|
-
},
|
|
7042
|
-
{
|
|
7043
|
-
title: "OpensteerComputerTraceEnrichment",
|
|
7044
|
-
required: ["points"]
|
|
7045
|
-
}
|
|
7046
|
-
);
|
|
7047
|
-
opensteerComputerExecuteTimingSchema = objectSchema(
|
|
7153
|
+
opensteerScreenshotSummarySchema = objectSchema(
|
|
7048
7154
|
{
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
title: "OpensteerComputerExecuteTiming",
|
|
7055
|
-
required: ["actionMs", "waitMs", "totalMs"]
|
|
7056
|
-
}
|
|
7057
|
-
);
|
|
7058
|
-
opensteerComputerDisplayScaleSchema = objectSchema(
|
|
7059
|
-
{
|
|
7060
|
-
x: numberSchema({ exclusiveMinimum: 0 }),
|
|
7061
|
-
y: numberSchema({ exclusiveMinimum: 0 })
|
|
7155
|
+
payload: externalBinaryLocationSchema,
|
|
7156
|
+
format: screenshotFormatSchema,
|
|
7157
|
+
size: sizeSchema,
|
|
7158
|
+
coordinateSpace: coordinateSpaceSchema,
|
|
7159
|
+
clip: rectSchema
|
|
7062
7160
|
},
|
|
7063
7161
|
{
|
|
7064
|
-
title: "
|
|
7065
|
-
required: ["
|
|
7162
|
+
title: "OpensteerScreenshotSummary",
|
|
7163
|
+
required: ["payload", "format", "size", "coordinateSpace"]
|
|
7066
7164
|
}
|
|
7067
7165
|
);
|
|
7068
7166
|
opensteerComputerExecuteOutputSchema = objectSchema(
|
|
7069
7167
|
{
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
screenshot:
|
|
7073
|
-
displayViewport: viewportMetricsSchema,
|
|
7074
|
-
nativeViewport: viewportMetricsSchema,
|
|
7075
|
-
displayScale: opensteerComputerDisplayScaleSchema,
|
|
7076
|
-
events: arraySchema(opensteerEventSchema),
|
|
7077
|
-
timing: opensteerComputerExecuteTimingSchema,
|
|
7078
|
-
trace: opensteerComputerTraceEnrichmentSchema
|
|
7168
|
+
url: stringSchema(),
|
|
7169
|
+
title: stringSchema(),
|
|
7170
|
+
screenshot: opensteerScreenshotSummarySchema
|
|
7079
7171
|
},
|
|
7080
7172
|
{
|
|
7081
7173
|
title: "OpensteerComputerExecuteOutput",
|
|
7082
|
-
required: [
|
|
7083
|
-
"action",
|
|
7084
|
-
"pageRef",
|
|
7085
|
-
"screenshot",
|
|
7086
|
-
"displayViewport",
|
|
7087
|
-
"nativeViewport",
|
|
7088
|
-
"displayScale",
|
|
7089
|
-
"events",
|
|
7090
|
-
"timing"
|
|
7091
|
-
]
|
|
7174
|
+
required: ["url", "title", "screenshot"]
|
|
7092
7175
|
}
|
|
7093
7176
|
);
|
|
7094
7177
|
opensteerSemanticOperationSpecificationsBase = [
|
|
@@ -7096,7 +7179,7 @@ var init_semantic = __esm({
|
|
|
7096
7179
|
name: "session.open",
|
|
7097
7180
|
description: "Open or resume the current Opensteer session and primary page.",
|
|
7098
7181
|
inputSchema: opensteerOpenInputSchema,
|
|
7099
|
-
outputSchema:
|
|
7182
|
+
outputSchema: opensteerNavigationSummarySchema,
|
|
7100
7183
|
requiredCapabilities: ["sessions.manage", "pages.manage"],
|
|
7101
7184
|
resolveRequiredCapabilities: (input) => input.url === void 0 ? ["sessions.manage", "pages.manage"] : ["sessions.manage", "pages.manage", "pages.navigate"]
|
|
7102
7185
|
}),
|
|
@@ -7111,7 +7194,7 @@ var init_semantic = __esm({
|
|
|
7111
7194
|
name: "page.new",
|
|
7112
7195
|
description: "Create and optionally navigate a new top-level page in the current session.",
|
|
7113
7196
|
inputSchema: opensteerPageNewInputSchema,
|
|
7114
|
-
outputSchema:
|
|
7197
|
+
outputSchema: opensteerPageNewOutputSchema,
|
|
7115
7198
|
requiredCapabilities: ["pages.manage"],
|
|
7116
7199
|
resolveRequiredCapabilities: (input) => input.url === void 0 ? ["pages.manage"] : ["pages.manage", "pages.navigate"]
|
|
7117
7200
|
}),
|
|
@@ -7119,7 +7202,7 @@ var init_semantic = __esm({
|
|
|
7119
7202
|
name: "page.activate",
|
|
7120
7203
|
description: "Activate an existing top-level page in the current session.",
|
|
7121
7204
|
inputSchema: opensteerPageActivateInputSchema,
|
|
7122
|
-
outputSchema:
|
|
7205
|
+
outputSchema: opensteerNavigationSummarySchema,
|
|
7123
7206
|
requiredCapabilities: ["pages.manage", "inspect.pages"]
|
|
7124
7207
|
}),
|
|
7125
7208
|
defineSemanticOperationSpec({
|
|
@@ -7133,7 +7216,7 @@ var init_semantic = __esm({
|
|
|
7133
7216
|
name: "page.goto",
|
|
7134
7217
|
description: "Navigate the current Opensteer page to a new URL.",
|
|
7135
7218
|
inputSchema: opensteerPageGotoInputSchema,
|
|
7136
|
-
outputSchema:
|
|
7219
|
+
outputSchema: opensteerNavigationSummarySchema,
|
|
7137
7220
|
requiredCapabilities: ["pages.navigate"]
|
|
7138
7221
|
}),
|
|
7139
7222
|
defineSemanticOperationSpec({
|
|
@@ -9800,6 +9883,7 @@ function toPersistedLocalBrowserSessionRecord(workspace, live) {
|
|
|
9800
9883
|
version: 1,
|
|
9801
9884
|
provider: "local",
|
|
9802
9885
|
...workspace === void 0 ? {} : { workspace },
|
|
9886
|
+
ownership: live.ownership,
|
|
9803
9887
|
engine: live.engine,
|
|
9804
9888
|
...live.endpoint === void 0 ? {} : { endpoint: live.endpoint },
|
|
9805
9889
|
...live.baseUrl === void 0 ? {} : { baseUrl: live.baseUrl },
|
|
@@ -9815,6 +9899,7 @@ function toPersistedLocalBrowserSessionRecord(workspace, live) {
|
|
|
9815
9899
|
function toWorkspaceLiveBrowserRecord(record) {
|
|
9816
9900
|
return {
|
|
9817
9901
|
mode: "persistent",
|
|
9902
|
+
ownership: getPersistedLocalBrowserSessionOwnership(record),
|
|
9818
9903
|
engine: record.engine,
|
|
9819
9904
|
...record.endpoint === void 0 ? {} : { endpoint: record.endpoint },
|
|
9820
9905
|
...record.baseUrl === void 0 ? {} : { baseUrl: record.baseUrl },
|
|
@@ -9841,7 +9926,12 @@ function isAttachBrowserOptions(browser) {
|
|
|
9841
9926
|
async function resolveAttachEndpoint(browser) {
|
|
9842
9927
|
const endpoint = browser?.endpoint?.trim();
|
|
9843
9928
|
if (endpoint && endpoint.length > 0) {
|
|
9844
|
-
|
|
9929
|
+
const inspected = await inspectCdpEndpoint({
|
|
9930
|
+
endpoint,
|
|
9931
|
+
...browser?.headers === void 0 ? {} : { headers: browser.headers },
|
|
9932
|
+
timeoutMs: DEFAULT_TIMEOUT_MS
|
|
9933
|
+
});
|
|
9934
|
+
return inspected.endpoint;
|
|
9845
9935
|
}
|
|
9846
9936
|
const selection = await selectAttachBrowserCandidate({
|
|
9847
9937
|
timeoutMs: DEFAULT_TIMEOUT_MS
|
|
@@ -10105,12 +10195,12 @@ async function waitForProcessExit(pid, timeoutMs) {
|
|
|
10105
10195
|
}
|
|
10106
10196
|
const deadline = Date.now() + timeoutMs;
|
|
10107
10197
|
while (Date.now() < deadline) {
|
|
10108
|
-
if (!
|
|
10198
|
+
if (!isProcessRunning2(pid)) {
|
|
10109
10199
|
return true;
|
|
10110
10200
|
}
|
|
10111
10201
|
await sleep2(50);
|
|
10112
10202
|
}
|
|
10113
|
-
return !
|
|
10203
|
+
return !isProcessRunning2(pid);
|
|
10114
10204
|
}
|
|
10115
10205
|
function resolveAbpSessionDir(workspace) {
|
|
10116
10206
|
return path12__default.default.join(workspace.livePath, "abp-session");
|
|
@@ -10267,7 +10357,7 @@ var init_browser_manager = __esm({
|
|
|
10267
10357
|
}
|
|
10268
10358
|
const liveRecord = await this.readLivePersistentBrowser(await this.ensureWorkspaceStore());
|
|
10269
10359
|
return {
|
|
10270
|
-
mode: this.mode,
|
|
10360
|
+
mode: liveRecord?.ownership === "attached" ? "attach" : this.mode,
|
|
10271
10361
|
engine: liveRecord?.engine ?? this.engineName,
|
|
10272
10362
|
...this.workspace === void 0 ? {} : { workspace: this.workspace },
|
|
10273
10363
|
live: liveRecord !== void 0
|
|
@@ -10395,6 +10485,7 @@ var init_browser_manager = __esm({
|
|
|
10395
10485
|
});
|
|
10396
10486
|
const liveRecord = {
|
|
10397
10487
|
mode: "persistent",
|
|
10488
|
+
ownership: "owned",
|
|
10398
10489
|
engine: "abp",
|
|
10399
10490
|
baseUrl: launched.baseUrl,
|
|
10400
10491
|
remoteDebuggingUrl: launched.remoteDebuggingUrl,
|
|
@@ -10481,11 +10572,78 @@ var init_browser_manager = __esm({
|
|
|
10481
10572
|
}
|
|
10482
10573
|
async createAttachEngine() {
|
|
10483
10574
|
const endpoint = await resolveAttachEndpoint(this.browserOptions);
|
|
10484
|
-
|
|
10485
|
-
|
|
10486
|
-
|
|
10487
|
-
|
|
10488
|
-
|
|
10575
|
+
if (this.workspace === void 0) {
|
|
10576
|
+
return this.createAttachedEngine({
|
|
10577
|
+
endpoint,
|
|
10578
|
+
...this.browserOptions?.headers === void 0 ? {} : { headers: this.browserOptions.headers },
|
|
10579
|
+
freshTab: this.browserOptions?.freshTab ?? true,
|
|
10580
|
+
onDispose: async () => void 0
|
|
10581
|
+
});
|
|
10582
|
+
}
|
|
10583
|
+
const workspace = await this.ensureWorkspaceStore();
|
|
10584
|
+
return workspace.lock(async () => {
|
|
10585
|
+
const live = await this.readLivePersistentBrowser(workspace);
|
|
10586
|
+
if (live) {
|
|
10587
|
+
if (live.engine !== "playwright") {
|
|
10588
|
+
throw new Error(
|
|
10589
|
+
`workspace "${this.workspace}" already has a live ${live.engine} browser. Close it before attaching a Playwright browser.`
|
|
10590
|
+
);
|
|
10591
|
+
}
|
|
10592
|
+
if (live.ownership !== "attached") {
|
|
10593
|
+
throw new Error(
|
|
10594
|
+
`workspace "${this.workspace}" already has a live Opensteer-owned browser. Close it before attaching another browser.`
|
|
10595
|
+
);
|
|
10596
|
+
}
|
|
10597
|
+
if (live.endpoint === void 0) {
|
|
10598
|
+
throw new Error("workspace live browser record is missing a DevTools endpoint.");
|
|
10599
|
+
}
|
|
10600
|
+
if (live.endpoint !== endpoint) {
|
|
10601
|
+
throw new Error(
|
|
10602
|
+
`workspace "${this.workspace}" is already attached to a different browser endpoint. Close it before reattaching.`
|
|
10603
|
+
);
|
|
10604
|
+
}
|
|
10605
|
+
await bestEffortRegisterLocalViewSession({
|
|
10606
|
+
rootPath: workspace.rootPath,
|
|
10607
|
+
...this.workspace === void 0 ? {} : { workspace: this.workspace },
|
|
10608
|
+
live: toPersistedLocalBrowserSessionRecord(this.workspace, live),
|
|
10609
|
+
ownership: "attached"
|
|
10610
|
+
});
|
|
10611
|
+
return this.createAttachedEngine({
|
|
10612
|
+
endpoint: live.endpoint,
|
|
10613
|
+
...this.browserOptions?.headers === void 0 ? {} : { headers: this.browserOptions.headers },
|
|
10614
|
+
freshTab: this.browserOptions?.freshTab ?? true,
|
|
10615
|
+
onDispose: async () => void 0
|
|
10616
|
+
});
|
|
10617
|
+
}
|
|
10618
|
+
const liveRecord = {
|
|
10619
|
+
mode: "persistent",
|
|
10620
|
+
ownership: "attached",
|
|
10621
|
+
engine: "playwright",
|
|
10622
|
+
endpoint,
|
|
10623
|
+
pid: 0,
|
|
10624
|
+
startedAt: Date.now(),
|
|
10625
|
+
userDataDir: workspace.browserUserDataDir
|
|
10626
|
+
};
|
|
10627
|
+
await this.writeLivePersistentBrowser(workspace, liveRecord);
|
|
10628
|
+
const persistedLiveRecord = toPersistedLocalBrowserSessionRecord(this.workspace, liveRecord);
|
|
10629
|
+
await bestEffortRegisterLocalViewSession({
|
|
10630
|
+
rootPath: workspace.rootPath,
|
|
10631
|
+
...this.workspace === void 0 ? {} : { workspace: this.workspace },
|
|
10632
|
+
live: persistedLiveRecord,
|
|
10633
|
+
ownership: "attached"
|
|
10634
|
+
});
|
|
10635
|
+
try {
|
|
10636
|
+
return await this.createAttachedEngine({
|
|
10637
|
+
endpoint,
|
|
10638
|
+
...this.browserOptions?.headers === void 0 ? {} : { headers: this.browserOptions.headers },
|
|
10639
|
+
freshTab: this.browserOptions?.freshTab ?? true,
|
|
10640
|
+
onDispose: async () => void 0
|
|
10641
|
+
});
|
|
10642
|
+
} catch (error) {
|
|
10643
|
+
await this.unregisterLocalViewSessionForRecord(workspace.rootPath, persistedLiveRecord);
|
|
10644
|
+
await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
|
|
10645
|
+
throw error;
|
|
10646
|
+
}
|
|
10489
10647
|
});
|
|
10490
10648
|
}
|
|
10491
10649
|
async createPersistentEngine() {
|
|
@@ -10505,7 +10663,7 @@ var init_browser_manager = __esm({
|
|
|
10505
10663
|
rootPath: workspace.rootPath,
|
|
10506
10664
|
...this.workspace === void 0 ? {} : { workspace: this.workspace },
|
|
10507
10665
|
live: toPersistedLocalBrowserSessionRecord(this.workspace, live),
|
|
10508
|
-
ownership:
|
|
10666
|
+
ownership: live.ownership
|
|
10509
10667
|
});
|
|
10510
10668
|
return this.createAttachedEngine({
|
|
10511
10669
|
endpoint: live.endpoint,
|
|
@@ -10521,6 +10679,7 @@ var init_browser_manager = __esm({
|
|
|
10521
10679
|
});
|
|
10522
10680
|
const liveRecord = {
|
|
10523
10681
|
mode: "persistent",
|
|
10682
|
+
ownership: "owned",
|
|
10524
10683
|
engine: "playwright",
|
|
10525
10684
|
endpoint: launched.endpoint,
|
|
10526
10685
|
pid: launched.pid,
|
|
@@ -10650,7 +10809,20 @@ var init_browser_manager = __esm({
|
|
|
10650
10809
|
if (live === void 0) {
|
|
10651
10810
|
return void 0;
|
|
10652
10811
|
}
|
|
10653
|
-
if (
|
|
10812
|
+
if (live.ownership === "attached") {
|
|
10813
|
+
const attachedRecord = toPersistedLocalBrowserSessionRecord(this.workspace, live);
|
|
10814
|
+
if (!await isAttachedLocalBrowserSessionReachable(attachedRecord)) {
|
|
10815
|
+
await this.unregisterLocalViewSessionForRecord(workspace.rootPath, attachedRecord);
|
|
10816
|
+
await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
|
|
10817
|
+
return void 0;
|
|
10818
|
+
}
|
|
10819
|
+
return live;
|
|
10820
|
+
}
|
|
10821
|
+
if (!isProcessRunning2(live.pid)) {
|
|
10822
|
+
await this.unregisterLocalViewSessionForRecord(
|
|
10823
|
+
workspace.rootPath,
|
|
10824
|
+
toPersistedLocalBrowserSessionRecord(this.workspace, live)
|
|
10825
|
+
);
|
|
10654
10826
|
await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
|
|
10655
10827
|
return void 0;
|
|
10656
10828
|
}
|
|
@@ -10698,6 +10870,10 @@ var init_browser_manager = __esm({
|
|
|
10698
10870
|
workspace.rootPath,
|
|
10699
10871
|
toPersistedLocalBrowserSessionRecord(this.workspace, live)
|
|
10700
10872
|
);
|
|
10873
|
+
if (live.ownership === "attached") {
|
|
10874
|
+
await clearPersistedSessionRecord(workspace.rootPath, "local").catch(() => void 0);
|
|
10875
|
+
return;
|
|
10876
|
+
}
|
|
10701
10877
|
if (live.engine === "playwright") {
|
|
10702
10878
|
if (live.endpoint !== void 0) {
|
|
10703
10879
|
await requestBrowserClose(live.endpoint).catch(() => void 0);
|
|
@@ -10726,10 +10902,18 @@ var init_browser_manager = __esm({
|
|
|
10726
10902
|
}
|
|
10727
10903
|
async unregisterLocalViewSessionForRecord(rootPath, record) {
|
|
10728
10904
|
await bestEffortUnregisterLocalViewSession(
|
|
10729
|
-
buildLocalViewSessionId({
|
|
10905
|
+
getPersistedLocalBrowserSessionOwnership(record) === "attached" ? buildLocalViewSessionId({
|
|
10730
10906
|
rootPath,
|
|
10731
|
-
|
|
10732
|
-
|
|
10907
|
+
startedAt: record.startedAt,
|
|
10908
|
+
ownership: "attached",
|
|
10909
|
+
...record.endpoint === void 0 ? {} : { endpoint: record.endpoint },
|
|
10910
|
+
...record.baseUrl === void 0 ? {} : { baseUrl: record.baseUrl },
|
|
10911
|
+
...record.remoteDebuggingUrl === void 0 ? {} : { remoteDebuggingUrl: record.remoteDebuggingUrl }
|
|
10912
|
+
}) : buildLocalViewSessionId({
|
|
10913
|
+
rootPath,
|
|
10914
|
+
startedAt: record.startedAt,
|
|
10915
|
+
ownership: "owned",
|
|
10916
|
+
pid: record.pid
|
|
10733
10917
|
})
|
|
10734
10918
|
);
|
|
10735
10919
|
}
|
|
@@ -10833,13 +11017,13 @@ async function resolveSessionSummary(manifest) {
|
|
|
10833
11017
|
return {
|
|
10834
11018
|
sessionId: manifest.sessionId,
|
|
10835
11019
|
label: manifest.workspace ?? (path12__default.default.basename(manifest.rootPath) || manifest.sessionId),
|
|
10836
|
-
status:
|
|
11020
|
+
status: getPersistedLocalBrowserSessionOwnership(record) === "attached" || isProcessRunning2(record.pid) ? "live" : "stale",
|
|
10837
11021
|
...manifest.workspace === void 0 ? {} : { workspace: manifest.workspace },
|
|
10838
11022
|
rootPath: manifest.rootPath,
|
|
10839
11023
|
engine: record.engine,
|
|
10840
11024
|
ownership: manifest.ownership,
|
|
10841
|
-
pid: record.pid,
|
|
10842
11025
|
startedAt: record.startedAt,
|
|
11026
|
+
...record.pid > 0 ? { pid: record.pid } : {},
|
|
10843
11027
|
...browserName === void 0 ? {} : { browserName }
|
|
10844
11028
|
};
|
|
10845
11029
|
}
|
|
@@ -10867,7 +11051,16 @@ async function readLiveRecord(manifest) {
|
|
|
10867
11051
|
if (!record) {
|
|
10868
11052
|
return void 0;
|
|
10869
11053
|
}
|
|
10870
|
-
if (
|
|
11054
|
+
if (buildLocalViewSessionIdForRecord({
|
|
11055
|
+
rootPath: manifest.rootPath,
|
|
11056
|
+
live: record
|
|
11057
|
+
}) !== manifest.sessionId || record.startedAt !== manifest.startedAt || record.engine !== manifest.engine || getPersistedLocalBrowserSessionOwnership(record) !== manifest.ownership) {
|
|
11058
|
+
return void 0;
|
|
11059
|
+
}
|
|
11060
|
+
if (getPersistedLocalBrowserSessionOwnership(record) === "attached") {
|
|
11061
|
+
return await isAttachedLocalBrowserSessionReachable(record) ? record : void 0;
|
|
11062
|
+
}
|
|
11063
|
+
if (record.pid !== manifest.pid || !isProcessRunning2(record.pid)) {
|
|
10871
11064
|
return void 0;
|
|
10872
11065
|
}
|
|
10873
11066
|
return record;
|