opensteer 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/chunk-4LP7QP2O.js +4336 -0
  2. package/dist/chunk-4LP7QP2O.js.map +1 -0
  3. package/dist/{chunk-656MQUSM.js → chunk-6PGXWW3X.js} +4787 -9519
  4. package/dist/chunk-6PGXWW3X.js.map +1 -0
  5. package/dist/chunk-BMPUL66S.js +1170 -0
  6. package/dist/chunk-BMPUL66S.js.map +1 -0
  7. package/dist/{chunk-OIKLSFXA.js → chunk-L4FWHBQJ.js} +4 -3
  8. package/dist/chunk-L4FWHBQJ.js.map +1 -0
  9. package/dist/chunk-Z53HNZ7Z.js +1800 -0
  10. package/dist/chunk-Z53HNZ7Z.js.map +1 -0
  11. package/dist/cli/bin.cjs +3050 -281
  12. package/dist/cli/bin.cjs.map +1 -1
  13. package/dist/cli/bin.js +124 -7
  14. package/dist/cli/bin.js.map +1 -1
  15. package/dist/index.cjs +918 -263
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +1 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +4 -2
  20. package/dist/local-view/public/assets/app.css +770 -0
  21. package/dist/local-view/public/assets/app.js +2053 -0
  22. package/dist/local-view/public/index.html +235 -0
  23. package/dist/local-view/serve-entry.cjs +7436 -0
  24. package/dist/local-view/serve-entry.cjs.map +1 -0
  25. package/dist/local-view/serve-entry.d.cts +1 -0
  26. package/dist/local-view/serve-entry.d.ts +1 -0
  27. package/dist/local-view/serve-entry.js +23 -0
  28. package/dist/local-view/serve-entry.js.map +1 -0
  29. package/dist/opensteer-KZCRP425.js +6 -0
  30. package/dist/{opensteer-LKX3233A.js.map → opensteer-KZCRP425.js.map} +1 -1
  31. package/dist/session-control-VGBFOH3Y.js +39 -0
  32. package/dist/session-control-VGBFOH3Y.js.map +1 -0
  33. package/package.json +8 -8
  34. package/skills/README.md +3 -0
  35. package/skills/opensteer/SKILL.md +229 -48
  36. package/dist/chunk-656MQUSM.js.map +0 -1
  37. package/dist/chunk-OIKLSFXA.js.map +0 -1
  38. package/dist/opensteer-LKX3233A.js +0 -4
@@ -0,0 +1,1170 @@
1
+ import { execFileSync, execFile } from 'child_process';
2
+ import { existsSync, readFileSync } from 'fs';
3
+ import { homedir } from 'os';
4
+ import path3, { join, resolve, basename } from 'path';
5
+ import { mkdir, access, readFile, writeFile, rename, open, readdir, rm } from 'fs/promises';
6
+ import { randomUUID, createHash } from 'crypto';
7
+ import { pathToFileURL } from 'url';
8
+ import { promisify } from 'util';
9
+
10
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
11
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
12
+ }) : x)(function(x) {
13
+ if (typeof require !== "undefined") return require.apply(this, arguments);
14
+ throw Error('Dynamic require of "' + x + '" is not supported');
15
+ });
16
+ ({ ...process.env});
17
+ var WINDOWS_PROGRAM_FILES = process.env.PROGRAMFILES ?? "C:\\Program Files";
18
+ var WINDOWS_PROGRAM_FILES_X86 = process.env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
19
+ var BROWSER_BRANDS = [
20
+ {
21
+ id: "chrome",
22
+ displayName: "Google Chrome",
23
+ darwin: {
24
+ executableCandidates: ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"],
25
+ userDataDir: "~/Library/Application Support/Google/Chrome",
26
+ bundleId: "com.google.Chrome",
27
+ processNames: ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"]
28
+ },
29
+ win32: {
30
+ executableCandidates: [
31
+ join(WINDOWS_PROGRAM_FILES, "Google", "Chrome", "Application", "chrome.exe"),
32
+ join(WINDOWS_PROGRAM_FILES_X86, "Google", "Chrome", "Application", "chrome.exe"),
33
+ join("~", "AppData", "Local", "Google", "Chrome", "Application", "chrome.exe")
34
+ ],
35
+ userDataDir: "~/AppData/Local/Google/Chrome/User Data",
36
+ processNames: ["/google/chrome/application/chrome.exe"]
37
+ },
38
+ linux: {
39
+ executableCandidates: [
40
+ "/usr/bin/google-chrome",
41
+ "/usr/bin/google-chrome-stable",
42
+ "/opt/google/chrome/chrome",
43
+ resolveBinaryFromPath("google-chrome"),
44
+ resolveBinaryFromPath("google-chrome-stable")
45
+ ],
46
+ userDataDir: "~/.config/google-chrome",
47
+ processNames: ["/google-chrome", "/google-chrome-stable", "/opt/google/chrome/chrome"]
48
+ }
49
+ },
50
+ {
51
+ id: "chrome-canary",
52
+ displayName: "Google Chrome Canary",
53
+ darwin: {
54
+ executableCandidates: [
55
+ "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
56
+ ],
57
+ userDataDir: "~/Library/Application Support/Google/Chrome Canary",
58
+ bundleId: "com.google.Chrome.canary",
59
+ processNames: ["/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"]
60
+ },
61
+ win32: {
62
+ executableCandidates: [
63
+ join("~", "AppData", "Local", "Google", "Chrome SxS", "Application", "chrome.exe")
64
+ ],
65
+ userDataDir: "~/AppData/Local/Google/Chrome SxS/User Data",
66
+ processNames: ["/google/chrome sxs/application/chrome.exe"]
67
+ }
68
+ },
69
+ {
70
+ id: "chromium",
71
+ displayName: "Chromium",
72
+ darwin: {
73
+ executableCandidates: ["/Applications/Chromium.app/Contents/MacOS/Chromium"],
74
+ userDataDir: "~/Library/Application Support/Chromium",
75
+ bundleId: "org.chromium.Chromium",
76
+ processNames: ["/Applications/Chromium.app/Contents/MacOS/Chromium"]
77
+ },
78
+ win32: {
79
+ executableCandidates: [
80
+ join(WINDOWS_PROGRAM_FILES, "Chromium", "Application", "chrome.exe"),
81
+ join(WINDOWS_PROGRAM_FILES_X86, "Chromium", "Application", "chrome.exe"),
82
+ join("~", "AppData", "Local", "Chromium", "Application", "chrome.exe")
83
+ ],
84
+ userDataDir: "~/AppData/Local/Chromium/User Data",
85
+ processNames: ["/chromium/application/chrome.exe"]
86
+ },
87
+ linux: {
88
+ executableCandidates: [
89
+ "/usr/bin/chromium",
90
+ "/usr/bin/chromium-browser",
91
+ resolveBinaryFromPath("chromium"),
92
+ resolveBinaryFromPath("chromium-browser")
93
+ ],
94
+ userDataDir: "~/.config/chromium",
95
+ processNames: ["/chromium", "/chromium-browser"]
96
+ }
97
+ },
98
+ {
99
+ id: "brave",
100
+ displayName: "Brave Browser",
101
+ darwin: {
102
+ executableCandidates: ["/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"],
103
+ userDataDir: "~/Library/Application Support/BraveSoftware/Brave-Browser",
104
+ bundleId: "com.brave.Browser",
105
+ processNames: ["/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"]
106
+ },
107
+ win32: {
108
+ executableCandidates: [
109
+ join(WINDOWS_PROGRAM_FILES, "BraveSoftware", "Brave-Browser", "Application", "brave.exe"),
110
+ join(
111
+ WINDOWS_PROGRAM_FILES_X86,
112
+ "BraveSoftware",
113
+ "Brave-Browser",
114
+ "Application",
115
+ "brave.exe"
116
+ ),
117
+ join("~", "AppData", "Local", "BraveSoftware", "Brave-Browser", "Application", "brave.exe")
118
+ ],
119
+ userDataDir: "~/AppData/Local/BraveSoftware/Brave-Browser/User Data",
120
+ processNames: ["/bravesoftware/brave-browser/application/brave.exe"]
121
+ },
122
+ linux: {
123
+ executableCandidates: [
124
+ "/usr/bin/brave-browser",
125
+ "/opt/brave.com/brave/brave-browser",
126
+ resolveBinaryFromPath("brave-browser")
127
+ ],
128
+ userDataDir: "~/.config/BraveSoftware/Brave-Browser",
129
+ processNames: ["/brave-browser", "/opt/brave.com/brave/brave-browser"]
130
+ }
131
+ },
132
+ {
133
+ id: "edge",
134
+ displayName: "Microsoft Edge",
135
+ darwin: {
136
+ executableCandidates: ["/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"],
137
+ userDataDir: "~/Library/Application Support/Microsoft Edge",
138
+ bundleId: "com.microsoft.edgemac",
139
+ processNames: ["/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"]
140
+ },
141
+ win32: {
142
+ executableCandidates: [
143
+ join(WINDOWS_PROGRAM_FILES, "Microsoft", "Edge", "Application", "msedge.exe"),
144
+ join(WINDOWS_PROGRAM_FILES_X86, "Microsoft", "Edge", "Application", "msedge.exe"),
145
+ join("~", "AppData", "Local", "Microsoft", "Edge", "Application", "msedge.exe")
146
+ ],
147
+ userDataDir: "~/AppData/Local/Microsoft/Edge/User Data",
148
+ processNames: ["/microsoft/edge/application/msedge.exe"]
149
+ },
150
+ linux: {
151
+ executableCandidates: [
152
+ "/usr/bin/microsoft-edge",
153
+ "/usr/bin/microsoft-edge-stable",
154
+ "/opt/microsoft/msedge/msedge",
155
+ resolveBinaryFromPath("microsoft-edge"),
156
+ resolveBinaryFromPath("microsoft-edge-stable")
157
+ ],
158
+ userDataDir: "~/.config/microsoft-edge",
159
+ processNames: ["/microsoft-edge", "/microsoft-edge-stable", "/opt/microsoft/msedge/msedge"]
160
+ }
161
+ },
162
+ {
163
+ id: "vivaldi",
164
+ displayName: "Vivaldi",
165
+ darwin: {
166
+ executableCandidates: ["/Applications/Vivaldi.app/Contents/MacOS/Vivaldi"],
167
+ userDataDir: "~/Library/Application Support/Vivaldi",
168
+ bundleId: "com.vivaldi.Vivaldi",
169
+ processNames: ["/Applications/Vivaldi.app/Contents/MacOS/Vivaldi"]
170
+ },
171
+ win32: {
172
+ executableCandidates: [
173
+ join(WINDOWS_PROGRAM_FILES, "Vivaldi", "Application", "vivaldi.exe"),
174
+ join(WINDOWS_PROGRAM_FILES_X86, "Vivaldi", "Application", "vivaldi.exe"),
175
+ join("~", "AppData", "Local", "Vivaldi", "Application", "vivaldi.exe")
176
+ ],
177
+ userDataDir: "~/AppData/Local/Vivaldi/User Data",
178
+ processNames: ["/vivaldi/application/vivaldi.exe"]
179
+ },
180
+ linux: {
181
+ executableCandidates: [
182
+ "/usr/bin/vivaldi",
183
+ "/usr/bin/vivaldi-stable",
184
+ "/opt/vivaldi/vivaldi",
185
+ resolveBinaryFromPath("vivaldi"),
186
+ resolveBinaryFromPath("vivaldi-stable")
187
+ ],
188
+ userDataDir: "~/.config/vivaldi",
189
+ processNames: ["/vivaldi", "/vivaldi-stable", "/opt/vivaldi/vivaldi"]
190
+ }
191
+ },
192
+ {
193
+ id: "helium",
194
+ displayName: "Helium",
195
+ darwin: {
196
+ executableCandidates: ["/Applications/Helium.app/Contents/MacOS/Helium"],
197
+ userDataDir: "~/Library/Application Support/net.imput.helium",
198
+ processNames: ["/Applications/Helium.app/Contents/MacOS/Helium"]
199
+ }
200
+ }
201
+ ];
202
+ function getBrowserBrand(id) {
203
+ const brand = BROWSER_BRANDS.find((candidate) => candidate.id === id);
204
+ if (!brand) {
205
+ throw new Error(`Unknown browser brand "${id}".`);
206
+ }
207
+ return brand;
208
+ }
209
+ function resolveBrandPlatformConfig(brand, platform = process.platform) {
210
+ if (platform === "darwin") {
211
+ return brand.darwin;
212
+ }
213
+ if (platform === "win32") {
214
+ return brand.win32;
215
+ }
216
+ if (platform === "linux") {
217
+ return brand.linux;
218
+ }
219
+ return void 0;
220
+ }
221
+ function detectInstalledBrowserBrands() {
222
+ const installations = [];
223
+ for (const brand of BROWSER_BRANDS) {
224
+ const platformConfig = resolveBrandPlatformConfig(brand);
225
+ if (!platformConfig) {
226
+ continue;
227
+ }
228
+ const executablePath = firstExistingPath(
229
+ resolveExecutableCandidates(platformConfig.executableCandidates)
230
+ );
231
+ if (!executablePath) {
232
+ continue;
233
+ }
234
+ installations.push({
235
+ brand,
236
+ brandId: brand.id,
237
+ displayName: brand.displayName,
238
+ executablePath,
239
+ userDataDir: resolve(expandHome(platformConfig.userDataDir))
240
+ });
241
+ }
242
+ return installations;
243
+ }
244
+ function resolveBrandUserDataDir(brand, explicitDir) {
245
+ if (explicitDir !== void 0) {
246
+ return resolve(expandHome(explicitDir));
247
+ }
248
+ const platformConfig = resolveBrandPlatformConfig(brand);
249
+ if (!platformConfig) {
250
+ throw new Error(`${brand.displayName} is not supported on ${process.platform}.`);
251
+ }
252
+ return resolve(expandHome(platformConfig.userDataDir));
253
+ }
254
+ function resolveExecutableCandidates(candidates) {
255
+ return candidates.map((candidate) => candidate ? resolve(expandHome(candidate)) : null);
256
+ }
257
+
258
+ // src/local-browser/chrome-discovery.ts
259
+ function expandHome(value) {
260
+ if (value === "~" || value.startsWith("~/")) {
261
+ return join(homedir(), value.slice(1));
262
+ }
263
+ return value;
264
+ }
265
+ function resolveChromeUserDataDir(userDataDir) {
266
+ const installation = detectLocalChromeInstallations().find(
267
+ (candidate) => existsSync(join(candidate.userDataDir, "Local State")) || candidate.executablePath !== null
268
+ );
269
+ if (!installation) {
270
+ throw new Error("Could not find a local Chrome or Chromium profile directory.");
271
+ }
272
+ return installation.userDataDir;
273
+ }
274
+ function resolveChromeExecutablePath(executablePath) {
275
+ if (executablePath !== void 0) {
276
+ const resolvedPath = resolve(expandHome(executablePath));
277
+ if (!existsSync(resolvedPath)) {
278
+ throw new Error(`Chrome executable was not found at "${resolvedPath}".`);
279
+ }
280
+ return resolvedPath;
281
+ }
282
+ for (const installation of detectLocalChromeInstallations()) {
283
+ if (installation.executablePath) {
284
+ return installation.executablePath;
285
+ }
286
+ }
287
+ throw new Error(
288
+ "Could not find a Chrome or Chromium executable. Pass browser.executablePath or --executable-path."
289
+ );
290
+ }
291
+ function detectLocalChromeInstallations() {
292
+ if (process.platform === "darwin") {
293
+ return [
294
+ {
295
+ brand: "chrome",
296
+ executablePath: firstExistingPath([
297
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
298
+ "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
299
+ ]),
300
+ userDataDir: join(homedir(), "Library", "Application Support", "Google", "Chrome")
301
+ },
302
+ {
303
+ brand: "chromium",
304
+ executablePath: firstExistingPath(["/Applications/Chromium.app/Contents/MacOS/Chromium"]),
305
+ userDataDir: join(homedir(), "Library", "Application Support", "Chromium")
306
+ }
307
+ ];
308
+ }
309
+ if (process.platform === "win32") {
310
+ const programFiles = process.env.PROGRAMFILES ?? "C:\\Program Files";
311
+ const programFilesX86 = process.env["PROGRAMFILES(X86)"] ?? "C:\\Program Files (x86)";
312
+ const localAppData = process.env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local");
313
+ return [
314
+ {
315
+ brand: "chrome",
316
+ executablePath: firstExistingPath([
317
+ join(programFiles, "Google", "Chrome", "Application", "chrome.exe"),
318
+ join(programFilesX86, "Google", "Chrome", "Application", "chrome.exe"),
319
+ join(localAppData, "Google", "Chrome", "Application", "chrome.exe")
320
+ ]),
321
+ userDataDir: join(localAppData, "Google", "Chrome", "User Data")
322
+ },
323
+ {
324
+ brand: "chromium",
325
+ executablePath: firstExistingPath([
326
+ join(programFiles, "Chromium", "Application", "chrome.exe"),
327
+ join(programFilesX86, "Chromium", "Application", "chrome.exe"),
328
+ join(localAppData, "Chromium", "Application", "chrome.exe")
329
+ ]),
330
+ userDataDir: join(localAppData, "Chromium", "User Data")
331
+ }
332
+ ];
333
+ }
334
+ return [
335
+ {
336
+ brand: "chrome",
337
+ executablePath: firstExistingPath([
338
+ "/usr/bin/google-chrome",
339
+ "/usr/bin/google-chrome-stable",
340
+ resolveBinaryFromPath("google-chrome"),
341
+ resolveBinaryFromPath("google-chrome-stable")
342
+ ]),
343
+ userDataDir: join(homedir(), ".config", "google-chrome")
344
+ },
345
+ {
346
+ brand: "chromium",
347
+ executablePath: firstExistingPath([
348
+ "/usr/bin/chromium",
349
+ "/usr/bin/chromium-browser",
350
+ resolveBinaryFromPath("chromium"),
351
+ resolveBinaryFromPath("chromium-browser")
352
+ ]),
353
+ userDataDir: join(homedir(), ".config", "chromium")
354
+ }
355
+ ];
356
+ }
357
+ function detectLocalBrowserInstallations() {
358
+ return detectInstalledBrowserBrands().map((installation) => ({
359
+ brand: installation.brandId,
360
+ executablePath: installation.executablePath,
361
+ userDataDir: installation.userDataDir
362
+ }));
363
+ }
364
+ function listLocalChromeProfiles(userDataDir = resolveChromeUserDataDir()) {
365
+ const resolvedUserDataDir = resolve(expandHome(userDataDir));
366
+ const localStatePath = join(resolvedUserDataDir, "Local State");
367
+ if (!existsSync(localStatePath)) {
368
+ return [];
369
+ }
370
+ try {
371
+ const raw = JSON.parse(readFileSync(localStatePath, "utf8"));
372
+ const infoCache = raw.profile?.info_cache;
373
+ if (!infoCache || typeof infoCache !== "object") {
374
+ return [];
375
+ }
376
+ return Object.entries(infoCache).map(([directory, info]) => {
377
+ const record = info && typeof info === "object" && !Array.isArray(info) ? info : {};
378
+ const name = typeof record.name === "string" && record.name.trim().length > 0 ? record.name.trim() : directory || basename(directory);
379
+ return {
380
+ directory,
381
+ name,
382
+ userDataDir: resolvedUserDataDir
383
+ };
384
+ }).filter((profile) => profile.directory.trim().length > 0).sort((left, right) => left.directory.localeCompare(right.directory));
385
+ } catch {
386
+ return [];
387
+ }
388
+ }
389
+ function readDevToolsActivePort(userDataDir) {
390
+ const devToolsPath = join(userDataDir, "DevToolsActivePort");
391
+ if (!existsSync(devToolsPath)) {
392
+ return null;
393
+ }
394
+ try {
395
+ const lines = readFileSync(devToolsPath, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
396
+ const port = Number.parseInt(lines[0] ?? "", 10);
397
+ if (!Number.isInteger(port) || port <= 0) {
398
+ return null;
399
+ }
400
+ return {
401
+ port,
402
+ webSocketPath: lines[1] ?? "/devtools/browser"
403
+ };
404
+ } catch {
405
+ return null;
406
+ }
407
+ }
408
+ function firstExistingPath(candidates) {
409
+ for (const candidate of candidates) {
410
+ if (candidate && existsSync(candidate)) {
411
+ return candidate;
412
+ }
413
+ }
414
+ return null;
415
+ }
416
+ function resolveBinaryFromPath(name) {
417
+ try {
418
+ const output = execFileSync("which", [name], {
419
+ encoding: "utf8",
420
+ stdio: ["ignore", "pipe", "ignore"]
421
+ }).trim();
422
+ return output.length > 0 ? output : null;
423
+ } catch {
424
+ return null;
425
+ }
426
+ }
427
+
428
+ // src/local-browser/cdp-discovery.ts
429
+ var DEFAULT_DISCOVERY_TIMEOUT_MS = 2e3;
430
+ var DISCOVERY_FALLBACK_PORT = 9222;
431
+ var OpensteerAttachAmbiguousError = class extends Error {
432
+ constructor(candidates) {
433
+ super(
434
+ "Multiple running Chromium DevTools endpoints were discovered. Specify the desired endpoint explicitly."
435
+ );
436
+ this.candidates = candidates;
437
+ this.name = "OpensteerAttachAmbiguousError";
438
+ }
439
+ code = "attach-ambiguous";
440
+ };
441
+ async function inspectCdpEndpoint(input) {
442
+ const inspected = await probeCdpEndpoint(input);
443
+ if (inspected === null) {
444
+ throw new Error(`Could not inspect CDP endpoint "${input.endpoint}".`);
445
+ }
446
+ return inspected;
447
+ }
448
+ async function discoverLocalCdpBrowsers(input = {}) {
449
+ const timeoutMs = input.timeoutMs ?? DEFAULT_DISCOVERY_TIMEOUT_MS;
450
+ const candidates = [];
451
+ for (const installation of detectLocalBrowserInstallations()) {
452
+ const activePort = readDevToolsActivePort(installation.userDataDir);
453
+ if (!activePort) {
454
+ continue;
455
+ }
456
+ const inspected = await probeCdpEndpoint({
457
+ endpoint: `http://127.0.0.1:${String(activePort.port)}`,
458
+ timeoutMs,
459
+ fallbackBrowserWebSocketPath: activePort.webSocketPath
460
+ });
461
+ if (inspected === null) {
462
+ continue;
463
+ }
464
+ candidates.push({
465
+ ...inspected,
466
+ source: "devtools-active-port",
467
+ installationBrand: installation.brand,
468
+ userDataDir: installation.userDataDir
469
+ });
470
+ }
471
+ const fallbackCandidate = await probeCdpEndpoint({
472
+ endpoint: String(DISCOVERY_FALLBACK_PORT),
473
+ timeoutMs
474
+ });
475
+ if (fallbackCandidate !== null) {
476
+ candidates.push({
477
+ ...fallbackCandidate,
478
+ source: "fallback-port"
479
+ });
480
+ }
481
+ return dedupeAndSortCandidates(candidates);
482
+ }
483
+ async function selectAttachBrowserCandidate(input = {}) {
484
+ const candidates = await discoverLocalCdpBrowsers(input);
485
+ if (candidates.length === 0) {
486
+ throw new Error(
487
+ "No running Chromium browser instance found. Enable remote debugging or specify an attach endpoint explicitly."
488
+ );
489
+ }
490
+ const highestPriority = Math.max(...candidates.map(getAttachCandidatePriority));
491
+ const winners = candidates.filter(
492
+ (candidate) => getAttachCandidatePriority(candidate) === highestPriority
493
+ );
494
+ if (winners.length === 1) {
495
+ return winners[0];
496
+ }
497
+ throw new OpensteerAttachAmbiguousError(candidates);
498
+ }
499
+ async function probeCdpEndpoint(input) {
500
+ const trimmedEndpoint = input.endpoint.trim();
501
+ if (!trimmedEndpoint) {
502
+ return null;
503
+ }
504
+ const target = normalizeProbeTarget(trimmedEndpoint);
505
+ const timeoutMs = input.timeoutMs ?? DEFAULT_DISCOVERY_TIMEOUT_MS;
506
+ const versionPayload = await fetchJson(
507
+ new URL("/json/version", target.httpUrl),
508
+ input.headers,
509
+ timeoutMs
510
+ );
511
+ if (versionPayload !== null) {
512
+ const payload = versionPayload;
513
+ if (typeof payload.webSocketDebuggerUrl === "string" && payload.webSocketDebuggerUrl.length > 0) {
514
+ return createInspectedCdpEndpoint({
515
+ browserWebSocketUrl: rewriteBrowserWebSocketHost(
516
+ payload.webSocketDebuggerUrl,
517
+ target.httpUrl
518
+ ),
519
+ httpUrl: target.httpUrl,
520
+ ...payload.Browser === void 0 ? {} : { browser: payload.Browser },
521
+ ...payload["Protocol-Version"] === void 0 ? {} : { protocolVersion: payload["Protocol-Version"] }
522
+ });
523
+ }
524
+ }
525
+ const listPayload = await fetchJson(new URL("/json/list", target.httpUrl), input.headers, timeoutMs);
526
+ if (listPayload !== null) {
527
+ const browserTarget = listPayload.find((candidate) => candidate.type === "browser") ?? listPayload.find((candidate) => typeof candidate.webSocketDebuggerUrl === "string");
528
+ if (typeof browserTarget?.webSocketDebuggerUrl === "string") {
529
+ return createInspectedCdpEndpoint({
530
+ browserWebSocketUrl: rewriteBrowserWebSocketHost(
531
+ browserTarget.webSocketDebuggerUrl,
532
+ target.httpUrl
533
+ ),
534
+ httpUrl: target.httpUrl
535
+ });
536
+ }
537
+ }
538
+ if (input.fallbackBrowserWebSocketPath !== void 0 && await isHttpEndpointReachable(target.httpUrl, timeoutMs)) {
539
+ return createInspectedCdpEndpoint({
540
+ browserWebSocketUrl: buildBrowserWebSocketUrl(
541
+ target.httpUrl,
542
+ input.fallbackBrowserWebSocketPath
543
+ ),
544
+ httpUrl: target.httpUrl
545
+ });
546
+ }
547
+ if (target.fallbackBrowserWebSocketUrl !== void 0 && await isHttpEndpointReachable(target.httpUrl, timeoutMs)) {
548
+ return createInspectedCdpEndpoint({
549
+ browserWebSocketUrl: target.fallbackBrowserWebSocketUrl,
550
+ httpUrl: target.httpUrl
551
+ });
552
+ }
553
+ return null;
554
+ }
555
+ function dedupeAndSortCandidates(candidates) {
556
+ const deduped = /* @__PURE__ */ new Map();
557
+ for (const candidate of [...candidates].sort(compareCandidates)) {
558
+ const existing = deduped.get(candidate.endpoint);
559
+ if (!existing || compareCandidates(candidate, existing) < 0) {
560
+ deduped.set(candidate.endpoint, candidate);
561
+ }
562
+ }
563
+ return [...deduped.values()].sort(compareCandidates);
564
+ }
565
+ function compareCandidates(left, right) {
566
+ return getAttachCandidatePriority(right) - getAttachCandidatePriority(left) || left.endpoint.localeCompare(right.endpoint) || (left.userDataDir ?? "").localeCompare(right.userDataDir ?? "");
567
+ }
568
+ function getAttachCandidatePriority(candidate) {
569
+ return candidate.source === "devtools-active-port" ? 2 : 1;
570
+ }
571
+ function createInspectedCdpEndpoint(input) {
572
+ const port = readPort(input.httpUrl);
573
+ return {
574
+ endpoint: input.browserWebSocketUrl,
575
+ ...input.browser === void 0 ? {} : { browser: input.browser },
576
+ ...input.protocolVersion === void 0 ? {} : { protocolVersion: input.protocolVersion },
577
+ httpUrl: input.httpUrl.toString(),
578
+ ...port === void 0 ? {} : { port }
579
+ };
580
+ }
581
+ function normalizeProbeTarget(endpoint) {
582
+ if (/^\d+$/.test(endpoint)) {
583
+ return {
584
+ httpUrl: new URL(`http://127.0.0.1:${endpoint}`)
585
+ };
586
+ }
587
+ if (endpoint.startsWith("ws://") || endpoint.startsWith("wss://")) {
588
+ const url = new URL(endpoint);
589
+ return {
590
+ fallbackBrowserWebSocketUrl: url.toString(),
591
+ httpUrl: new URL(`${url.protocol === "wss:" ? "https:" : "http:"}//${url.host}`)
592
+ };
593
+ }
594
+ try {
595
+ const url = endpoint.startsWith("http://") || endpoint.startsWith("https://") ? new URL(endpoint) : new URL(`http://${endpoint}`);
596
+ return {
597
+ httpUrl: new URL(`${url.protocol}//${url.host}`)
598
+ };
599
+ } catch {
600
+ throw new Error(`Invalid CDP endpoint "${endpoint}".`);
601
+ }
602
+ }
603
+ async function fetchJson(url, headers, timeoutMs) {
604
+ const response = await fetch(url, {
605
+ ...headers === void 0 ? {} : { headers },
606
+ signal: AbortSignal.timeout(timeoutMs)
607
+ }).catch(() => null);
608
+ if (!response?.ok) {
609
+ return null;
610
+ }
611
+ return await response.json();
612
+ }
613
+ async function isHttpEndpointReachable(url, timeoutMs) {
614
+ const response = await fetch(url, {
615
+ signal: AbortSignal.timeout(timeoutMs)
616
+ }).catch(() => null);
617
+ return response !== null;
618
+ }
619
+ function buildBrowserWebSocketUrl(httpUrl, webSocketPath) {
620
+ const protocol = httpUrl.protocol === "https:" ? "wss:" : "ws:";
621
+ return `${protocol}//${httpUrl.host}${normalizeWebSocketPath(webSocketPath)}`;
622
+ }
623
+ function normalizeWebSocketPath(path5) {
624
+ return path5.startsWith("/") ? path5 : `/${path5}`;
625
+ }
626
+ function rewriteBrowserWebSocketHost(browserWsUrl, requestedUrl) {
627
+ try {
628
+ const parsed = new URL(browserWsUrl);
629
+ parsed.protocol = requestedUrl.protocol === "https:" ? "wss:" : "ws:";
630
+ parsed.hostname = requestedUrl.hostname;
631
+ parsed.port = requestedUrl.port;
632
+ return parsed.toString();
633
+ } catch {
634
+ return browserWsUrl;
635
+ }
636
+ }
637
+ function readPort(url) {
638
+ const port = Number.parseInt(url.port, 10);
639
+ return Number.isInteger(port) && port > 0 ? port : void 0;
640
+ }
641
+
642
+ // ../runtime-core/src/json.ts
643
+ function isPlainObject(value) {
644
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
645
+ return false;
646
+ }
647
+ const prototype = Object.getPrototypeOf(value);
648
+ return prototype === Object.prototype || prototype === null;
649
+ }
650
+ function canonicalizeJsonValue(value, path5) {
651
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
652
+ return value;
653
+ }
654
+ if (typeof value === "number") {
655
+ if (!Number.isFinite(value)) {
656
+ throw new TypeError(`${path5} must be a finite JSON number`);
657
+ }
658
+ return value;
659
+ }
660
+ if (Array.isArray(value)) {
661
+ return value.map((entry, index) => canonicalizeJsonValue(entry, `${path5}[${index}]`));
662
+ }
663
+ if (!isPlainObject(value)) {
664
+ throw new TypeError(`${path5} must be a plain JSON object`);
665
+ }
666
+ const sorted = Object.keys(value).sort((left, right) => left.localeCompare(right));
667
+ const result = {};
668
+ for (const key of sorted) {
669
+ const entry = value[key];
670
+ if (entry === void 0) {
671
+ throw new TypeError(`${path5}.${key} must not be undefined`);
672
+ }
673
+ result[key] = canonicalizeJsonValue(entry, `${path5}.${key}`);
674
+ }
675
+ return result;
676
+ }
677
+ function toCanonicalJsonValue(value) {
678
+ return canonicalizeJsonValue(value, "value");
679
+ }
680
+ function canonicalJsonString(value) {
681
+ return JSON.stringify(toCanonicalJsonValue(value));
682
+ }
683
+ function stableJsonString(value) {
684
+ return `${JSON.stringify(toCanonicalJsonValue(value), null, 2)}
685
+ `;
686
+ }
687
+
688
+ // ../runtime-core/src/internal/filesystem.ts
689
+ var LOCK_RETRY_DELAYS_MS = [1, 2, 5, 10, 20, 50];
690
+ function normalizeNonEmptyString(name, value) {
691
+ const normalized = value.trim();
692
+ if (normalized.length === 0) {
693
+ throw new TypeError(`${name} must not be empty`);
694
+ }
695
+ return normalized;
696
+ }
697
+ function normalizeTimestamp(name, value) {
698
+ if (!Number.isInteger(value) || value < 0) {
699
+ throw new RangeError(`${name} must be a non-negative integer`);
700
+ }
701
+ return value;
702
+ }
703
+ function encodePathSegment(value) {
704
+ return encodeURIComponent(normalizeNonEmptyString("path segment", value));
705
+ }
706
+ function joinStoragePath(...segments) {
707
+ return segments.join("/");
708
+ }
709
+ function resolveStoragePath(rootPath, relativePath) {
710
+ if (path3.isAbsolute(relativePath)) {
711
+ throw new TypeError(`storage path ${relativePath} must be relative`);
712
+ }
713
+ const segments = relativePath.split("/");
714
+ if (segments.length === 0 || segments.some((segment) => segment.length === 0)) {
715
+ throw new TypeError(`storage path ${relativePath} is invalid`);
716
+ }
717
+ for (const segment of segments) {
718
+ if (segment === "." || segment === "..") {
719
+ throw new TypeError(`storage path ${relativePath} must not contain path traversal`);
720
+ }
721
+ }
722
+ return path3.join(rootPath, ...segments);
723
+ }
724
+ async function ensureDirectory(directoryPath) {
725
+ await mkdir(directoryPath, { recursive: true });
726
+ }
727
+ async function pathExists(targetPath) {
728
+ try {
729
+ await access(targetPath);
730
+ return true;
731
+ } catch {
732
+ return false;
733
+ }
734
+ }
735
+ async function readJsonFile(filePath) {
736
+ return JSON.parse(await readFile(filePath, "utf8"));
737
+ }
738
+ async function writeJsonFileAtomic(filePath, value) {
739
+ await writeTextFileAtomic(filePath, stableJsonString(value));
740
+ }
741
+ async function writeTextFileAtomic(filePath, value) {
742
+ await ensureDirectory(path3.dirname(filePath));
743
+ const temporaryPath = `${filePath}.${randomUUID()}.tmp`;
744
+ await writeFile(temporaryPath, value, "utf8");
745
+ await rename(temporaryPath, filePath);
746
+ }
747
+ async function writeJsonFileExclusive(filePath, value) {
748
+ await writeTextFileExclusive(filePath, stableJsonString(value));
749
+ }
750
+ async function writeTextFileExclusive(filePath, value) {
751
+ await ensureDirectory(path3.dirname(filePath));
752
+ const handle = await open(filePath, "wx");
753
+ try {
754
+ await handle.writeFile(value, "utf8");
755
+ } finally {
756
+ await handle.close();
757
+ }
758
+ }
759
+ async function writeBufferIfMissing(filePath, value) {
760
+ await ensureDirectory(path3.dirname(filePath));
761
+ try {
762
+ const handle = await open(filePath, "wx");
763
+ try {
764
+ await handle.writeFile(value);
765
+ } finally {
766
+ await handle.close();
767
+ }
768
+ } catch (error) {
769
+ if (isAlreadyExistsError(error)) {
770
+ return;
771
+ }
772
+ throw error;
773
+ }
774
+ }
775
+ async function readBinaryFile(filePath) {
776
+ return new Uint8Array(await readFile(filePath));
777
+ }
778
+ async function listJsonFiles(directoryPath) {
779
+ if (!await pathExists(directoryPath)) {
780
+ return [];
781
+ }
782
+ return (await readdir(directoryPath)).filter((entry) => entry.endsWith(".json")).sort((left, right) => left.localeCompare(right));
783
+ }
784
+ function sha256Hex(value) {
785
+ return createHash("sha256").update(value).digest("hex");
786
+ }
787
+ function filePathToUri(filePath) {
788
+ return pathToFileURL(filePath).toString();
789
+ }
790
+ function isAlreadyExistsError(error) {
791
+ return error?.code === "EEXIST";
792
+ }
793
+ async function withFilesystemLock(lockPath, task) {
794
+ await ensureDirectory(path3.dirname(lockPath));
795
+ let attempt = 0;
796
+ while (true) {
797
+ try {
798
+ await mkdir(lockPath);
799
+ break;
800
+ } catch (error) {
801
+ if (!isAlreadyExistsError(error)) {
802
+ throw error;
803
+ }
804
+ const delayMs = LOCK_RETRY_DELAYS_MS[Math.min(attempt, LOCK_RETRY_DELAYS_MS.length - 1)];
805
+ attempt += 1;
806
+ await new Promise((resolve3) => setTimeout(resolve3, delayMs));
807
+ }
808
+ }
809
+ try {
810
+ return await task();
811
+ } finally {
812
+ await rm(lockPath, { recursive: true, force: true });
813
+ }
814
+ }
815
+
816
+ // src/live-session.ts
817
+ var OPENSTEER_LIVE_SESSION_LAYOUT = "opensteer-session";
818
+ var OPENSTEER_LIVE_SESSION_VERSION = 1;
819
+ function resolveLiveSessionRecordPath(rootPath, provider) {
820
+ return path3.join(rootPath, "live", provider === "local" ? "local.json" : "cloud.json");
821
+ }
822
+ function resolveLocalSessionRecordPath(rootPath) {
823
+ return resolveLiveSessionRecordPath(rootPath, "local");
824
+ }
825
+ function resolveCloudSessionRecordPath(rootPath) {
826
+ return resolveLiveSessionRecordPath(rootPath, "cloud");
827
+ }
828
+ async function readPersistedSessionRecord(rootPath, provider) {
829
+ const sessionPath = resolveLiveSessionRecordPath(rootPath, provider);
830
+ if (!await pathExists(sessionPath)) {
831
+ return void 0;
832
+ }
833
+ const parsed = await readJsonFile(sessionPath);
834
+ if (provider === "local" && isPersistedLocalBrowserSessionRecord(parsed)) {
835
+ return parsed;
836
+ }
837
+ if (provider === "cloud" && isPersistedCloudSessionRecord(parsed)) {
838
+ return parsed;
839
+ }
840
+ return void 0;
841
+ }
842
+ async function readPersistedCloudSessionRecord(rootPath) {
843
+ const record = await readPersistedSessionRecord(rootPath, "cloud");
844
+ return record?.provider === "cloud" ? record : void 0;
845
+ }
846
+ async function readPersistedLocalBrowserSessionRecord(rootPath) {
847
+ const record = await readPersistedSessionRecord(rootPath, "local");
848
+ return record?.provider === "local" ? record : void 0;
849
+ }
850
+ async function writePersistedSessionRecord(rootPath, record) {
851
+ await writeJsonFileAtomic(resolveLiveSessionRecordPath(rootPath, record.provider), record);
852
+ }
853
+ async function clearPersistedSessionRecord(rootPath, provider) {
854
+ await rm(resolveLiveSessionRecordPath(rootPath, provider), { force: true });
855
+ }
856
+ function isPersistedCloudSessionRecord(value) {
857
+ return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "cloud" && typeof value.sessionId === "string" && value.sessionId.length > 0 && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt);
858
+ }
859
+ function isPersistedLocalBrowserSessionRecord(value) {
860
+ return value.layout === OPENSTEER_LIVE_SESSION_LAYOUT && value.version === OPENSTEER_LIVE_SESSION_VERSION && value.provider === "local" && (value.engine === "playwright" || value.engine === "abp") && 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;
861
+ }
862
+ function resolveOpensteerStateDir() {
863
+ const explicit = process.env.OPENSTEER_HOME?.trim();
864
+ if (explicit) {
865
+ return path3.resolve(explicit);
866
+ }
867
+ if (process.platform === "win32") {
868
+ return path3.join(
869
+ process.env.LOCALAPPDATA ?? path3.join(homedir(), "AppData", "Local"),
870
+ "Opensteer"
871
+ );
872
+ }
873
+ if (process.platform === "darwin") {
874
+ return path3.join(homedir(), "Library", "Application Support", "Opensteer");
875
+ }
876
+ return path3.join(
877
+ process.env.XDG_STATE_HOME ?? path3.join(homedir(), ".local", "state"),
878
+ "opensteer"
879
+ );
880
+ }
881
+ function resolveLocalViewRootDir() {
882
+ return path3.join(resolveOpensteerStateDir(), "local-view");
883
+ }
884
+ function resolveLocalViewPreferencesPath() {
885
+ return path3.join(resolveLocalViewRootDir(), "preferences.json");
886
+ }
887
+ function resolveLocalViewServiceDir() {
888
+ return path3.join(resolveLocalViewRootDir(), "service");
889
+ }
890
+ function resolveLocalViewSessionsDir() {
891
+ return path3.join(resolveLocalViewRootDir(), "sessions");
892
+ }
893
+ function resolveLocalViewServiceLockDir() {
894
+ return path3.join(resolveLocalViewServiceDir(), "startup.lock");
895
+ }
896
+ function resolveLocalViewServiceStatePath() {
897
+ return path3.join(resolveLocalViewServiceDir(), "state.json");
898
+ }
899
+
900
+ // src/local-view/session-manifest.ts
901
+ var OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT = "opensteer-local-view-session";
902
+ var OPENSTEER_LOCAL_VIEW_SESSION_VERSION = 1;
903
+ function buildLocalViewSessionId(input) {
904
+ const hash = createHash("sha256").update(`${input.rootPath}
905
+ ${String(input.pid)}
906
+ ${String(input.startedAt)}`).digest("hex");
907
+ return `local_${hash.slice(0, 24)}`;
908
+ }
909
+ function createLocalViewSessionManifest(input) {
910
+ return {
911
+ layout: OPENSTEER_LOCAL_VIEW_SESSION_LAYOUT,
912
+ version: OPENSTEER_LOCAL_VIEW_SESSION_VERSION,
913
+ sessionId: buildLocalViewSessionId({
914
+ rootPath: input.rootPath,
915
+ pid: input.live.pid,
916
+ startedAt: input.live.startedAt
917
+ }),
918
+ rootPath: input.rootPath,
919
+ ...input.workspace === void 0 ? {} : { workspace: input.workspace },
920
+ engine: input.live.engine,
921
+ ownership: input.ownership,
922
+ pid: input.live.pid,
923
+ startedAt: input.live.startedAt,
924
+ updatedAt: Date.now()
925
+ };
926
+ }
927
+ async function writeLocalViewSessionManifest(manifest) {
928
+ await ensureDirectory(resolveLocalViewSessionsDir());
929
+ await writeJsonFileAtomic(resolveLocalViewSessionManifestPath(manifest.sessionId), manifest);
930
+ }
931
+ async function deleteLocalViewSessionManifest(sessionId) {
932
+ await rm(resolveLocalViewSessionManifestPath(sessionId), { force: true }).catch(() => void 0);
933
+ }
934
+ async function readLocalViewSessionManifest(sessionId) {
935
+ const manifestPath = resolveLocalViewSessionManifestPath(sessionId);
936
+ if (!await pathExists(manifestPath)) {
937
+ return void 0;
938
+ }
939
+ const parsed = await readJsonFile(manifestPath);
940
+ return isPersistedLocalViewSessionManifest(parsed) ? parsed : void 0;
941
+ }
942
+ async function listLocalViewSessionManifests() {
943
+ const directoryPath = resolveLocalViewSessionsDir();
944
+ const fileNames = await listJsonFiles(directoryPath);
945
+ const manifests = await Promise.all(
946
+ fileNames.map(async (fileName) => {
947
+ const parsed = await readJsonFile(
948
+ path3.join(directoryPath, fileName)
949
+ ).catch(() => void 0);
950
+ return isPersistedLocalViewSessionManifest(parsed) ? parsed : void 0;
951
+ })
952
+ );
953
+ return manifests.filter((manifest) => manifest !== void 0).sort(
954
+ (left, right) => left.startedAt - right.startedAt || left.sessionId.localeCompare(right.sessionId)
955
+ );
956
+ }
957
+ function resolveLocalViewSessionManifestPath(sessionId) {
958
+ return path3.join(resolveLocalViewSessionsDir(), `${sessionId}.json`);
959
+ }
960
+ function isPersistedLocalViewSessionManifest(value) {
961
+ 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);
962
+ }
963
+ var execFileAsync = promisify(execFile);
964
+ var PROCESS_STARTED_AT_MS = Math.floor(Date.now() - process.uptime() * 1e3);
965
+ var PROCESS_START_TIME_TOLERANCE_MS = 1e3;
966
+ var PROCESS_LIST_MAX_BUFFER_BYTES2 = 16 * 1024 * 1024;
967
+ var PS_COMMAND_ENV2 = { ...process.env, LC_ALL: "C" };
968
+ var LINUX_STAT_START_TIME_FIELD_INDEX = 19;
969
+ var CURRENT_PROCESS_OWNER = {
970
+ pid: process.pid,
971
+ processStartedAtMs: PROCESS_STARTED_AT_MS
972
+ };
973
+ var linuxClockTicksPerSecondPromise = null;
974
+ function parseProcessOwner(value) {
975
+ if (!value || typeof value !== "object") {
976
+ return null;
977
+ }
978
+ const parsed = value;
979
+ const pid = Number(parsed.pid);
980
+ const processStartedAtMs = Number(parsed.processStartedAtMs);
981
+ if (!Number.isInteger(pid) || pid <= 0) {
982
+ return null;
983
+ }
984
+ if (!Number.isInteger(processStartedAtMs) || processStartedAtMs <= 0) {
985
+ return null;
986
+ }
987
+ return {
988
+ pid,
989
+ processStartedAtMs
990
+ };
991
+ }
992
+ function processOwnersEqual(left, right) {
993
+ if (!left || !right) {
994
+ return left === right;
995
+ }
996
+ return left.pid === right.pid && left.processStartedAtMs === right.processStartedAtMs;
997
+ }
998
+ async function getProcessLiveness(owner) {
999
+ if (owner.pid === process.pid && hasMatchingProcessStartTime(owner.processStartedAtMs, PROCESS_STARTED_AT_MS)) {
1000
+ return "live";
1001
+ }
1002
+ const startedAtMs = await readProcessStartedAtMs(owner.pid);
1003
+ if (typeof startedAtMs === "number") {
1004
+ return hasMatchingProcessStartTime(owner.processStartedAtMs, startedAtMs) ? "live" : "dead";
1005
+ }
1006
+ return isProcessRunning(owner.pid) ? "unknown" : "dead";
1007
+ }
1008
+ function isProcessRunning(pid) {
1009
+ try {
1010
+ process.kill(pid, 0);
1011
+ return true;
1012
+ } catch (error) {
1013
+ const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : void 0;
1014
+ return code !== "ESRCH";
1015
+ }
1016
+ }
1017
+ function hasMatchingProcessStartTime(expectedStartedAtMs, actualStartedAtMs) {
1018
+ return Math.abs(expectedStartedAtMs - actualStartedAtMs) <= PROCESS_START_TIME_TOLERANCE_MS;
1019
+ }
1020
+ async function readProcessStartedAtMs(pid) {
1021
+ if (pid <= 0) {
1022
+ return null;
1023
+ }
1024
+ if (process.platform === "linux") {
1025
+ return readLinuxProcessStartedAtMs(pid);
1026
+ }
1027
+ if (process.platform === "win32") {
1028
+ return readWindowsProcessStartedAtMs(pid);
1029
+ }
1030
+ return readPsProcessStartedAtMs(pid);
1031
+ }
1032
+ async function readLinuxProcessStartedAtMs(pid) {
1033
+ let statRaw;
1034
+ try {
1035
+ statRaw = await readFile(`/proc/${String(pid)}/stat`, "utf8");
1036
+ } catch {
1037
+ return null;
1038
+ }
1039
+ const startTicks = parseLinuxProcessStartTicks(statRaw);
1040
+ if (startTicks === null) {
1041
+ return null;
1042
+ }
1043
+ const [bootTimeMs, clockTicksPerSecond] = await Promise.all([
1044
+ readLinuxBootTimeMs(),
1045
+ readLinuxClockTicksPerSecond()
1046
+ ]);
1047
+ if (bootTimeMs === null || clockTicksPerSecond === null) {
1048
+ return null;
1049
+ }
1050
+ return Math.floor(bootTimeMs + startTicks * 1e3 / clockTicksPerSecond);
1051
+ }
1052
+ function parseLinuxProcessStartTicks(statRaw) {
1053
+ const closingParenIndex = statRaw.lastIndexOf(")");
1054
+ if (closingParenIndex === -1) {
1055
+ return null;
1056
+ }
1057
+ const fields = statRaw.slice(closingParenIndex + 2).trim().split(/\s+/);
1058
+ const startTicks = Number(fields[LINUX_STAT_START_TIME_FIELD_INDEX]);
1059
+ return Number.isFinite(startTicks) && startTicks >= 0 ? startTicks : null;
1060
+ }
1061
+ async function readLinuxBootTimeMs() {
1062
+ try {
1063
+ const statRaw = await readFile("/proc/stat", "utf8");
1064
+ const bootTimeLine = statRaw.split("\n").find((line) => line.startsWith("btime "));
1065
+ if (!bootTimeLine) {
1066
+ return null;
1067
+ }
1068
+ const bootTimeSeconds = Number.parseInt(bootTimeLine.slice("btime ".length), 10);
1069
+ return Number.isFinite(bootTimeSeconds) ? bootTimeSeconds * 1e3 : null;
1070
+ } catch {
1071
+ return null;
1072
+ }
1073
+ }
1074
+ async function readLinuxClockTicksPerSecond() {
1075
+ if (!linuxClockTicksPerSecondPromise) {
1076
+ linuxClockTicksPerSecondPromise = execFileAsync("getconf", ["CLK_TCK"], {
1077
+ encoding: "utf8",
1078
+ maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2
1079
+ }).then(({ stdout }) => {
1080
+ const value = Number.parseInt(stdout.trim(), 10);
1081
+ return Number.isFinite(value) && value > 0 ? value : null;
1082
+ }).catch(() => null);
1083
+ }
1084
+ return linuxClockTicksPerSecondPromise;
1085
+ }
1086
+ async function readWindowsProcessStartedAtMs(pid) {
1087
+ try {
1088
+ const { stdout } = await execFileAsync(
1089
+ "powershell.exe",
1090
+ [
1091
+ "-NoProfile",
1092
+ "-Command",
1093
+ `(Get-Process -Id ${String(pid)}).StartTime.ToUniversalTime().ToString("o")`
1094
+ ],
1095
+ {
1096
+ encoding: "utf8",
1097
+ maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2
1098
+ }
1099
+ );
1100
+ const isoTimestamp = stdout.trim();
1101
+ if (!isoTimestamp) {
1102
+ return null;
1103
+ }
1104
+ const startedAtMs = Date.parse(isoTimestamp);
1105
+ return Number.isFinite(startedAtMs) ? startedAtMs : null;
1106
+ } catch {
1107
+ return null;
1108
+ }
1109
+ }
1110
+ async function readPsProcessStartedAtMs(pid) {
1111
+ try {
1112
+ const { stdout } = await execFileAsync("ps", ["-o", "lstart=", "-p", String(pid)], {
1113
+ encoding: "utf8",
1114
+ env: PS_COMMAND_ENV2,
1115
+ maxBuffer: PROCESS_LIST_MAX_BUFFER_BYTES2
1116
+ });
1117
+ const startedAt = stdout.trim();
1118
+ if (!startedAt) {
1119
+ return null;
1120
+ }
1121
+ const startedAtMs = Date.parse(startedAt.replace(/\s+/g, " "));
1122
+ return Number.isFinite(startedAtMs) ? startedAtMs : null;
1123
+ } catch {
1124
+ return null;
1125
+ }
1126
+ }
1127
+ var OPENSTEER_LOCAL_VIEW_SERVICE_LAYOUT = "opensteer-local-view-service";
1128
+ var OPENSTEER_LOCAL_VIEW_SERVICE_VERSION = 3;
1129
+ async function readLocalViewServiceState() {
1130
+ const statePath = resolveLocalViewServiceStatePath();
1131
+ if (!await pathExists(statePath)) {
1132
+ return void 0;
1133
+ }
1134
+ const parsed = await readJsonFile(statePath);
1135
+ if (!isPersistedLocalViewServiceState(parsed)) {
1136
+ return void 0;
1137
+ }
1138
+ return parsed;
1139
+ }
1140
+ async function writeLocalViewServiceState(state) {
1141
+ await writeJsonFileAtomic(resolveLocalViewServiceStatePath(), state);
1142
+ }
1143
+ async function clearLocalViewServiceState(match = void 0) {
1144
+ if (match !== void 0) {
1145
+ const current = await readLocalViewServiceState();
1146
+ if (current === void 0 || current.pid !== match.pid || current.token !== match.token) {
1147
+ return;
1148
+ }
1149
+ }
1150
+ await rm(resolveLocalViewServiceStatePath(), { force: true });
1151
+ }
1152
+ async function isLocalViewServiceStateLive(state) {
1153
+ return await getLocalViewServiceStateLiveness(state) !== "dead";
1154
+ }
1155
+ async function getLocalViewServiceStateLiveness(state) {
1156
+ if (state === void 0) {
1157
+ return "dead";
1158
+ }
1159
+ return getProcessLiveness({
1160
+ pid: state.pid,
1161
+ processStartedAtMs: state.processStartedAtMs
1162
+ });
1163
+ }
1164
+ function isPersistedLocalViewServiceState(value) {
1165
+ return value?.layout === OPENSTEER_LOCAL_VIEW_SERVICE_LAYOUT && value.version === OPENSTEER_LOCAL_VIEW_SERVICE_VERSION && typeof value.pid === "number" && Number.isFinite(value.pid) && typeof value.processStartedAtMs === "number" && Number.isFinite(value.processStartedAtMs) && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && typeof value.port === "number" && Number.isFinite(value.port) && typeof value.token === "string" && value.token.length > 0 && typeof value.url === "string" && value.url.length > 0;
1166
+ }
1167
+
1168
+ export { CURRENT_PROCESS_OWNER, OPENSTEER_LOCAL_VIEW_SERVICE_LAYOUT, OPENSTEER_LOCAL_VIEW_SERVICE_VERSION, OpensteerAttachAmbiguousError, __require, buildLocalViewSessionId, canonicalJsonString, clearLocalViewServiceState, clearPersistedSessionRecord, createLocalViewSessionManifest, deleteLocalViewSessionManifest, detectInstalledBrowserBrands, discoverLocalCdpBrowsers, encodePathSegment, ensureDirectory, expandHome, filePathToUri, getBrowserBrand, getLocalViewServiceStateLiveness, getProcessLiveness, inspectCdpEndpoint, isAlreadyExistsError, isLocalViewServiceStateLive, isProcessRunning, joinStoragePath, listJsonFiles, listLocalChromeProfiles, listLocalViewSessionManifests, normalizeNonEmptyString, normalizeTimestamp, parseProcessOwner, pathExists, processOwnersEqual, readBinaryFile, readDevToolsActivePort, readJsonFile, readLocalViewServiceState, readLocalViewSessionManifest, readPersistedCloudSessionRecord, readPersistedLocalBrowserSessionRecord, readPersistedSessionRecord, resolveBrandUserDataDir, resolveChromeExecutablePath, resolveCloudSessionRecordPath, resolveLiveSessionRecordPath, resolveLocalSessionRecordPath, resolveLocalViewPreferencesPath, resolveLocalViewServiceLockDir, resolveStoragePath, selectAttachBrowserCandidate, sha256Hex, toCanonicalJsonValue, withFilesystemLock, writeBufferIfMissing, writeJsonFileAtomic, writeJsonFileExclusive, writeLocalViewServiceState, writeLocalViewSessionManifest, writePersistedSessionRecord };
1169
+ //# sourceMappingURL=chunk-BMPUL66S.js.map
1170
+ //# sourceMappingURL=chunk-BMPUL66S.js.map