@mearl/native-host 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,39 @@
1
+ import { type CommandRunner } from '@mearl/setup/process';
2
+ export declare const NATIVE_HOST_UPDATE_TIMEOUT_MS: number;
3
+ export type NativeHostUpdateError = 'lock-timeout' | 'network' | 'package-unavailable' | 'setup-failed' | 'timeout' | 'verification-failed' | 'unknown';
4
+ export interface NativeHostUpdateCommand {
5
+ args: string[];
6
+ }
7
+ type UpdateLockRunner = <T>(targetVersion: string, operation: () => Promise<T>) => Promise<T>;
8
+ export interface RunNativeHostUpdateOptions {
9
+ areTargetsInstalled?: (targetReleaseLine: string, environment: NodeJS.ProcessEnv) => Promise<boolean>;
10
+ environment?: NodeJS.ProcessEnv;
11
+ nodePath?: string;
12
+ packageBinDirectory?: string | null;
13
+ packageManagerCommand?: string | null;
14
+ packageRunner?: string;
15
+ platform?: NodeJS.Platform;
16
+ runner?: CommandRunner;
17
+ timeoutMs?: number;
18
+ updateLockPath?: string;
19
+ withUpdateLock?: UpdateLockRunner;
20
+ }
21
+ export interface NativeHostUpdateCoordinatorOptions {
22
+ hostVersion: string;
23
+ log: (...args: unknown[]) => void;
24
+ requestRestart: () => void | Promise<void>;
25
+ runUpdate: (targetVersion: string) => Promise<void>;
26
+ }
27
+ export declare class NativeHostUpdateFailure extends Error {
28
+ readonly updateError: NativeHostUpdateError;
29
+ constructor(updateError: NativeHostUpdateError, message: string);
30
+ }
31
+ export declare function nativeHostUpdateCommand(targetVersion: string): NativeHostUpdateCommand;
32
+ export declare function runNativeHostUpdate(targetVersion: string, options?: RunNativeHostUpdateOptions): Promise<void>;
33
+ export declare class NativeHostUpdateCoordinator {
34
+ #private;
35
+ private readonly options;
36
+ constructor(options: NativeHostUpdateCoordinatorOptions);
37
+ evaluate(extensionVersion: unknown, checkForUpdates: unknown): void;
38
+ }
39
+ export {};
package/dist/index.js CHANGED
@@ -10,20 +10,20 @@ var __export = (target, all) => {
10
10
  };
11
11
 
12
12
  // ../setup/dist/nativeHost.js
13
- import fs9 from "node:fs";
13
+ import fs11 from "node:fs";
14
14
  import os6 from "node:os";
15
- import path10 from "node:path";
15
+ import path12 from "node:path";
16
16
  import { execFileSync } from "node:child_process";
17
17
  function resolveNativeHostDirectory(options = {}) {
18
18
  const env = options.env ?? process.env;
19
19
  const home = (options.homedir ?? os6.homedir)();
20
20
  switch (options.platform ?? process.platform) {
21
21
  case "darwin":
22
- return path10.join(home, "Library/Application Support/Google/Chrome/NativeMessagingHosts");
22
+ return path12.join(home, "Library/Application Support/Google/Chrome/NativeMessagingHosts");
23
23
  case "linux":
24
- return path10.join(home, ".config/google-chrome/NativeMessagingHosts");
24
+ return path12.join(home, ".config/google-chrome/NativeMessagingHosts");
25
25
  case "win32":
26
- return path10.join(env.PROGRAMDATA || "C:\\ProgramData", "Google\\Chrome\\NativeMessagingHosts");
26
+ return path12.join(env.PROGRAMDATA || "C:\\ProgramData", "Google\\Chrome\\NativeMessagingHosts");
27
27
  default:
28
28
  throw new Error(`Unsupported platform: ${String(options.platform ?? process.platform)}`);
29
29
  }
@@ -46,20 +46,20 @@ function uninstallNativeHostArtifacts(options = {}, dependencies = {}) {
46
46
  writeLine(line);
47
47
  };
48
48
  try {
49
- const existsSync4 = dependencies.existsSync ?? fs9.existsSync;
49
+ const existsSync4 = dependencies.existsSync ?? fs11.existsSync;
50
50
  const platform = dependencies.platform ?? process.platform;
51
51
  const hostDir = dependencies.hostDir ?? resolveNativeHostDirectory({
52
52
  env: dependencies.env,
53
53
  homedir: dependencies.homedir,
54
54
  platform
55
55
  });
56
- const unlinkSync = dependencies.unlinkSync ?? fs9.unlinkSync;
56
+ const unlinkSync = dependencies.unlinkSync ?? fs11.unlinkSync;
57
57
  const unregister = dependencies.unregisterWindowsNativeHost ?? unregisterWindowsNativeHost;
58
58
  const hostName = MEARL_NATIVE_HOST_NAMES[mode];
59
59
  const launcherExtension = platform === "win32" ? "cmd" : "sh";
60
60
  const artifacts = [
61
- path10.join(hostDir, `${hostName}.json`),
62
- path10.join(hostDir, `${hostName}-launcher.${launcherExtension}`)
61
+ path12.join(hostDir, `${hostName}.json`),
62
+ path12.join(hostDir, `${hostName}-launcher.${launcherExtension}`)
63
63
  ];
64
64
  for (const artifact of artifacts) {
65
65
  if (!existsSync4(artifact))
@@ -94,17 +94,17 @@ __export(install_exports, {
94
94
  runCli: () => runCli,
95
95
  uninstallNativeHost: () => uninstallNativeHost
96
96
  });
97
- import fs10 from "node:fs";
98
- import path11 from "node:path";
97
+ import fs12 from "node:fs";
98
+ import path13 from "node:path";
99
99
  import { execFileSync as execFileSync2 } from "node:child_process";
100
100
  import { createRequire } from "node:module";
101
- import { fileURLToPath } from "node:url";
101
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
102
102
  function resolveHostDir() {
103
103
  return resolveNativeHostDirectory();
104
104
  }
105
105
  function resolveNativeHostPath() {
106
- const siblingPath = path11.join(__dirname, "index.js");
107
- if (fs10.existsSync(siblingPath)) {
106
+ const siblingPath = path13.join(__dirname, "index.js");
107
+ if (fs12.existsSync(siblingPath)) {
108
108
  return siblingPath;
109
109
  }
110
110
  try {
@@ -123,16 +123,16 @@ function registerWindowsNativeHost(hostName, manifestPath) {
123
123
  });
124
124
  }
125
125
  function createLauncherScript(hostDir, hostPath, hostName) {
126
- const nodePath = path11.resolve(process.execPath);
126
+ const nodePath = path13.resolve(process.execPath);
127
127
  if (process.platform === "win32") {
128
- const launcherPath2 = path11.join(hostDir, `${hostName}-launcher.cmd`);
128
+ const launcherPath2 = path13.join(hostDir, `${hostName}-launcher.cmd`);
129
129
  const content2 = `@echo off\r
130
130
  "${nodePath}" "${hostPath}" %*\r
131
131
  `;
132
- fs10.writeFileSync(launcherPath2, content2, "utf-8");
132
+ fs12.writeFileSync(launcherPath2, content2, "utf-8");
133
133
  return launcherPath2;
134
134
  }
135
- const launcherPath = path11.join(hostDir, `${hostName}-launcher.sh`);
135
+ const launcherPath = path13.join(hostDir, `${hostName}-launcher.sh`);
136
136
  const content = [
137
137
  "#!/bin/sh",
138
138
  `NODE_BIN=${JSON.stringify(nodePath)}`,
@@ -140,8 +140,8 @@ function createLauncherScript(hostDir, hostPath, hostName) {
140
140
  'exec "$NODE_BIN" "$HOST_SCRIPT" "$@"',
141
141
  ""
142
142
  ].join("\n");
143
- fs10.writeFileSync(launcherPath, content, "utf-8");
144
- fs10.chmodSync(launcherPath, 493);
143
+ fs12.writeFileSync(launcherPath, content, "utf-8");
144
+ fs12.chmodSync(launcherPath, 493);
145
145
  return launcherPath;
146
146
  }
147
147
  async function installNativeHost(options = {}) {
@@ -167,14 +167,14 @@ async function installNativeHost(options = {}) {
167
167
  try {
168
168
  const hostDir = resolveHostDir();
169
169
  if (skipIfExists) {
170
- const manifestPath2 = path11.join(hostDir, `${hostName}.json`);
171
- if (fs10.existsSync(manifestPath2)) {
170
+ const manifestPath2 = path13.join(hostDir, `${hostName}.json`);
171
+ if (fs12.existsSync(manifestPath2)) {
172
172
  log2(`✅ Already installed: ${manifestPath2}`);
173
173
  return true;
174
174
  }
175
175
  }
176
- if (!fs10.existsSync(hostDir)) {
177
- fs10.mkdirSync(hostDir, { recursive: true });
176
+ if (!fs12.existsSync(hostDir)) {
177
+ fs12.mkdirSync(hostDir, { recursive: true });
178
178
  log2(`✅ Created directory: ${hostDir}`);
179
179
  }
180
180
  const resolvedHostPath = resolveNativeHostPath();
@@ -188,13 +188,13 @@ async function installNativeHost(options = {}) {
188
188
  type: "stdio",
189
189
  allowed_origins: [`chrome-extension://${extensionId}/`]
190
190
  };
191
- const manifestPath = path11.join(hostDir, `${hostName}.json`);
192
- fs10.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
191
+ const manifestPath = path13.join(hostDir, `${hostName}.json`);
192
+ fs12.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
193
193
  if (process.platform === "win32") {
194
194
  registerWindowsNativeHost(hostName, manifestPath);
195
195
  log2(`✅ Windows registry key created for: ${hostName}`);
196
196
  } else {
197
- fs10.chmodSync(manifestPath, 420);
197
+ fs12.chmodSync(manifestPath, 420);
198
198
  }
199
199
  log2(`✅ Manifest installed: ${manifestPath}`);
200
200
  log2(`✅ Extension ID: ${extensionId}`);
@@ -306,19 +306,19 @@ var init_install = __esm({
306
306
  "use strict";
307
307
  init_nativeHost();
308
308
  DEFAULT_EXTENSION_ID = "aoehhjnofngknnjefamjbplchbolghkm";
309
- __filename = fileURLToPath(import.meta.url);
310
- __dirname = path11.dirname(__filename);
309
+ __filename = fileURLToPath2(import.meta.url);
310
+ __dirname = path13.dirname(__filename);
311
311
  ALL_MODES = ["skills", "mcp"];
312
312
  }
313
313
  });
314
314
 
315
315
  // src/index.ts
316
316
  import net from "node:net";
317
- import fs11 from "node:fs";
317
+ import fs13 from "node:fs";
318
318
  import http5 from "node:http";
319
319
  import os7 from "node:os";
320
- import path12 from "node:path";
321
- import { fileURLToPath as fileURLToPath2 } from "node:url";
320
+ import path14 from "node:path";
321
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
322
322
 
323
323
  // src/cdp-backend/cdp-session.ts
324
324
  import http3 from "node:http";
@@ -1166,13 +1166,13 @@ function queryTrackingEvents(buffer, options = {}) {
1166
1166
  }
1167
1167
 
1168
1168
  // ../browser-core/dist/requestSerializer.js
1169
- function parsePath(path13) {
1170
- if (path13.length > 1e3)
1169
+ function parsePath(path15) {
1170
+ if (path15.length > 1e3)
1171
1171
  throw new Error("Path too long: maximum 1000 characters allowed");
1172
1172
  const keys = [];
1173
1173
  let current = "";
1174
- for (let i = 0; i < path13.length; i++) {
1175
- const char = path13[i];
1174
+ for (let i = 0; i < path15.length; i++) {
1175
+ const char = path15[i];
1176
1176
  if (char === ".") {
1177
1177
  if (current) {
1178
1178
  keys.push(current);
@@ -1184,10 +1184,10 @@ function parsePath(path13) {
1184
1184
  current = "";
1185
1185
  }
1186
1186
  let j = i + 1;
1187
- while (j < path13.length && path13[j] !== "]")
1187
+ while (j < path15.length && path15[j] !== "]")
1188
1188
  j++;
1189
- if (j < path13.length) {
1190
- const index = parseInt(path13.substring(i + 1, j), 10);
1189
+ if (j < path15.length) {
1190
+ const index = parseInt(path15.substring(i + 1, j), 10);
1191
1191
  if (!isNaN(index)) {
1192
1192
  if (index < 0 || index > 1e5)
1193
1193
  throw new Error(`Array index out of safe range: ${index}`);
@@ -1205,8 +1205,8 @@ function parsePath(path13) {
1205
1205
  throw new Error("Path too deep: maximum 50 levels allowed");
1206
1206
  return keys;
1207
1207
  }
1208
- function getValueByPath(obj, path13) {
1209
- const keys = parsePath(path13);
1208
+ function getValueByPath(obj, path15) {
1209
+ const keys = parsePath(path15);
1210
1210
  let current = obj;
1211
1211
  for (const key of keys) {
1212
1212
  if (current === null || current === void 0)
@@ -1215,8 +1215,8 @@ function getValueByPath(obj, path13) {
1215
1215
  }
1216
1216
  return current;
1217
1217
  }
1218
- function setValueByPath(obj, path13, value) {
1219
- const keys = parsePath(path13);
1218
+ function setValueByPath(obj, path15, value) {
1219
+ const keys = parsePath(path15);
1220
1220
  let current = obj;
1221
1221
  for (let i = 0; i < keys.length - 1; i++) {
1222
1222
  const key = keys[i];
@@ -2752,19 +2752,19 @@ function installPageObserverInPage(maxBatches = 50) {
2752
2752
  }
2753
2753
  }
2754
2754
  }
2755
- const path13 = [];
2755
+ const path15 = [];
2756
2756
  let current = input;
2757
- while (current && current !== document.documentElement && path13.length < 6) {
2757
+ while (current && current !== document.documentElement && path15.length < 6) {
2758
2758
  const parent = current.parentElement;
2759
2759
  const currentTag = current.tagName.toLowerCase();
2760
2760
  if (!parent) {
2761
- path13.unshift(currentTag);
2761
+ path15.unshift(currentTag);
2762
2762
  break;
2763
2763
  }
2764
2764
  const siblings = Array.from(parent.children).filter((item) => item.tagName === current.tagName);
2765
2765
  const position = siblings.indexOf(current) + 1;
2766
- path13.unshift(siblings.length > 1 ? `${currentTag}:nth-of-type(${position})` : currentTag);
2767
- const candidate = path13.join(" > ");
2766
+ path15.unshift(siblings.length > 1 ? `${currentTag}:nth-of-type(${position})` : currentTag);
2767
+ const candidate = path15.join(" > ");
2768
2768
  if (input.isConnected) {
2769
2769
  try {
2770
2770
  if (document.querySelectorAll(candidate).length === 1)
@@ -2774,7 +2774,7 @@ function installPageObserverInPage(maxBatches = 50) {
2774
2774
  }
2775
2775
  current = parent;
2776
2776
  }
2777
- return path13.join(" > ") || void 0;
2777
+ return path15.join(" > ") || void 0;
2778
2778
  };
2779
2779
  const inferredRole = (element) => {
2780
2780
  const explicit = element.getAttribute("role");
@@ -4409,12 +4409,12 @@ function resolveGetCookieTarget(currentUrl, input) {
4409
4409
  const url2 = parseCurrentUrl(currentUrl, action);
4410
4410
  const name = validateCookieName(input?.name, action);
4411
4411
  const domain2 = resolveExplicitDomain(url2, input?.domain, action);
4412
- const path13 = validateCookiePath(input?.path, action);
4412
+ const path15 = validateCookiePath(input?.path, action);
4413
4413
  return {
4414
4414
  cookieName: name,
4415
- cookieUrl: `${url2.protocol}//${url2.hostname}${(path13 ?? url2.pathname) || "/"}`,
4415
+ cookieUrl: `${url2.protocol}//${url2.hostname}${(path15 ?? url2.pathname) || "/"}`,
4416
4416
  ...domain2 ? { domain: domain2 } : {},
4417
- ...path13 ? { path: path13 } : {}
4417
+ ...path15 ? { path: path15 } : {}
4418
4418
  };
4419
4419
  }
4420
4420
  function resolveSetCookieTarget(currentUrl, input) {
@@ -4422,7 +4422,7 @@ function resolveSetCookieTarget(currentUrl, input) {
4422
4422
  const url2 = parseCurrentUrl(currentUrl, action);
4423
4423
  const name = validateCookieName(input?.name, action);
4424
4424
  const value = validateCookieValue(input?.value);
4425
- const path13 = validateCookiePath(input?.path, action) ?? "/";
4425
+ const path15 = validateCookiePath(input?.path, action) ?? "/";
4426
4426
  if (input.reload !== void 0 && typeof input.reload !== "boolean") {
4427
4427
  throw new Error('set_cookie: "reload" must be a boolean');
4428
4428
  }
@@ -4432,9 +4432,9 @@ function resolveSetCookieTarget(currentUrl, input) {
4432
4432
  cookieName: name,
4433
4433
  cookieValue: value,
4434
4434
  ...explicitDomain ? { cookieDomain: explicitDomain.includes(".") ? `.${explicitDomain}` : explicitDomain } : {},
4435
- cookieUrl: `${url2.protocol}//${url2.hostname.toLowerCase()}${path13}`,
4435
+ cookieUrl: `${url2.protocol}//${url2.hostname.toLowerCase()}${path15}`,
4436
4436
  domain: domain2,
4437
- path: path13,
4437
+ path: path15,
4438
4438
  reload: input.reload === true
4439
4439
  };
4440
4440
  }
@@ -7612,8 +7612,8 @@ registerActions([
7612
7612
  ]);
7613
7613
 
7614
7614
  // src/cdp-backend/tdbank-handlers.ts
7615
- async function cdpFetchTdbank(session, path13, options = {}) {
7616
- const url2 = new URL(`https://tdbank.alibaba-inc.com${path13}`);
7615
+ async function cdpFetchTdbank(session, path15, options = {}) {
7616
+ const url2 = new URL(`https://tdbank.alibaba-inc.com${path15}`);
7617
7617
  for (const [key, value] of Object.entries(options.params ?? {})) {
7618
7618
  if (value !== void 0 && value !== null) {
7619
7619
  url2.searchParams.set(key, String(value));
@@ -9752,7 +9752,7 @@ import os2 from "node:os";
9752
9752
  import { randomUUID as randomUUID4 } from "node:crypto";
9753
9753
 
9754
9754
  // src/version.ts
9755
- var NATIVE_HOST_VERSION = true ? "2.3.0" : "unknown";
9755
+ var NATIVE_HOST_VERSION = true ? "2.4.0" : "unknown";
9756
9756
 
9757
9757
  // src/analytics.ts
9758
9758
  var MEASUREMENT_ID = "G-W84LJDZ6PH";
@@ -10625,6 +10625,7 @@ import path7 from "node:path";
10625
10625
  import fs5 from "node:fs";
10626
10626
  import path6 from "node:path";
10627
10627
  import { spawn as spawn4 } from "node:child_process";
10628
+ var MAX_CAPTURE_LENGTH = 1e6;
10628
10629
  function isExecutable(filePath, platform = process.platform) {
10629
10630
  try {
10630
10631
  fs5.accessSync(filePath, platform === "win32" ? fs5.constants.F_OK : fs5.constants.X_OK);
@@ -10669,12 +10670,12 @@ function resolveSpawnCommand(executable, args, platform = process.platform, comm
10669
10670
  function prependCommandPath(command, env = process.env) {
10670
10671
  if (!path6.isAbsolute(command))
10671
10672
  return env;
10672
- return prependPath(path6.dirname(command), env);
10673
+ return prependPathDirectory(path6.dirname(command), env);
10673
10674
  }
10674
10675
  function prependNodePath(env = process.env, nodeExecutable = process.execPath) {
10675
- return prependPath(path6.dirname(nodeExecutable), env);
10676
+ return prependPathDirectory(path6.dirname(nodeExecutable), env);
10676
10677
  }
10677
- function prependPath(directory, env) {
10678
+ function prependPathDirectory(directory, env = process.env) {
10678
10679
  const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
10679
10680
  const inherited = env[pathKey] || "";
10680
10681
  const entries = inherited.split(path6.delimiter).filter(Boolean);
@@ -10682,6 +10683,59 @@ function prependPath(directory, env) {
10682
10683
  return env;
10683
10684
  return { ...env, [pathKey]: [directory, ...entries].join(path6.delimiter) };
10684
10685
  }
10686
+ function findExecutable(name, options = {}) {
10687
+ const env = options.env ?? process.env;
10688
+ const platform = options.platform ?? process.platform;
10689
+ const existsSync4 = options.existsSync ?? ((candidate) => isExecutable(candidate, platform));
10690
+ const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
10691
+ const directories = [
10692
+ ...options.extraDirectories ?? [],
10693
+ ...(env[pathKey] ?? "").split(path6.delimiter).filter(Boolean)
10694
+ ];
10695
+ for (const directory of directories) {
10696
+ for (const executableName of executableNames(name, platform)) {
10697
+ const candidate = path6.join(directory, executableName);
10698
+ if (existsSync4(candidate))
10699
+ return candidate;
10700
+ }
10701
+ }
10702
+ return null;
10703
+ }
10704
+ var runCommand = (command, args, options = {}) => new Promise((resolve, reject) => {
10705
+ const capture = options.capture === true;
10706
+ const launch = resolveSpawnCommand(command, args);
10707
+ const child = spawn4(launch.command, launch.args, {
10708
+ cwd: options.cwd,
10709
+ env: options.env,
10710
+ stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit",
10711
+ windowsHide: true
10712
+ });
10713
+ let stdout = "";
10714
+ let stderr = "";
10715
+ let settled = false;
10716
+ const append = (current, chunk) => current.length >= MAX_CAPTURE_LENGTH ? current : (current + chunk.toString("utf8")).slice(0, MAX_CAPTURE_LENGTH);
10717
+ const finish = (error48, code = 1) => {
10718
+ if (settled)
10719
+ return;
10720
+ settled = true;
10721
+ if (timer)
10722
+ clearTimeout(timer);
10723
+ if (error48)
10724
+ reject(error48);
10725
+ else
10726
+ resolve({ code, stdout, stderr });
10727
+ };
10728
+ const timer = options.timeoutMs === void 0 ? void 0 : setTimeout(() => {
10729
+ child.kill("SIGTERM");
10730
+ finish(new Error(`Command timed out after ${options.timeoutMs}ms`));
10731
+ }, options.timeoutMs);
10732
+ if (capture) {
10733
+ child.stdout?.on("data", (chunk) => stdout = append(stdout, chunk));
10734
+ child.stderr?.on("data", (chunk) => stderr = append(stderr, chunk));
10735
+ }
10736
+ child.once("error", (error48) => finish(error48));
10737
+ child.once("close", (code) => finish(void 0, code ?? 1));
10738
+ });
10685
10739
 
10686
10740
  // src/agent/executable-resolver.ts
10687
10741
  function agentExecutableCandidatePaths({
@@ -12163,10 +12217,10 @@ function mergeDefs(...defs) {
12163
12217
  function cloneDef(schema) {
12164
12218
  return mergeDefs(schema._zod.def);
12165
12219
  }
12166
- function getElementAtPath(obj, path13) {
12167
- if (!path13)
12220
+ function getElementAtPath(obj, path15) {
12221
+ if (!path15)
12168
12222
  return obj;
12169
- return path13.reduce((acc, key) => acc?.[key], obj);
12223
+ return path15.reduce((acc, key) => acc?.[key], obj);
12170
12224
  }
12171
12225
  function promiseAllObject(promisesObj) {
12172
12226
  const keys = Object.keys(promisesObj);
@@ -12549,11 +12603,11 @@ function aborted(x, startIndex = 0) {
12549
12603
  }
12550
12604
  return false;
12551
12605
  }
12552
- function prefixIssues(path13, issues) {
12606
+ function prefixIssues(path15, issues) {
12553
12607
  return issues.map((iss) => {
12554
12608
  var _a2;
12555
12609
  (_a2 = iss).path ?? (_a2.path = []);
12556
- iss.path.unshift(path13);
12610
+ iss.path.unshift(path15);
12557
12611
  return iss;
12558
12612
  });
12559
12613
  }
@@ -12736,7 +12790,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
12736
12790
  }
12737
12791
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
12738
12792
  const result = { errors: [] };
12739
- const processError = (error49, path13 = []) => {
12793
+ const processError = (error49, path15 = []) => {
12740
12794
  var _a2, _b;
12741
12795
  for (const issue2 of error49.issues) {
12742
12796
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -12746,7 +12800,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
12746
12800
  } else if (issue2.code === "invalid_element") {
12747
12801
  processError({ issues: issue2.issues }, issue2.path);
12748
12802
  } else {
12749
- const fullpath = [...path13, ...issue2.path];
12803
+ const fullpath = [...path15, ...issue2.path];
12750
12804
  if (fullpath.length === 0) {
12751
12805
  result.errors.push(mapper(issue2));
12752
12806
  continue;
@@ -12778,8 +12832,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
12778
12832
  }
12779
12833
  function toDotPath(_path) {
12780
12834
  const segs = [];
12781
- const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
12782
- for (const seg of path13) {
12835
+ const path15 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
12836
+ for (const seg of path15) {
12783
12837
  if (typeof seg === "number")
12784
12838
  segs.push(`[${seg}]`);
12785
12839
  else if (typeof seg === "symbol")
@@ -24756,13 +24810,13 @@ function resolveRef(ref, ctx) {
24756
24810
  if (!ref.startsWith("#")) {
24757
24811
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
24758
24812
  }
24759
- const path13 = ref.slice(1).split("/").filter(Boolean);
24760
- if (path13.length === 0) {
24813
+ const path15 = ref.slice(1).split("/").filter(Boolean);
24814
+ if (path15.length === 0) {
24761
24815
  return ctx.rootSchema;
24762
24816
  }
24763
24817
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
24764
- if (path13[0] === defsKey) {
24765
- const key = path13[1];
24818
+ if (path15[0] === defsKey) {
24819
+ const key = path15[1];
24766
24820
  if (!key || !ctx.defs[key]) {
24767
24821
  throw new Error(`Reference not found: ${ref}`);
24768
24822
  }
@@ -29769,6 +29823,409 @@ function createExtensionRequestMessage(id, action, data, trustedInternal = false
29769
29823
  };
29770
29824
  }
29771
29825
 
29826
+ // src/host-updater.ts
29827
+ import fs10 from "node:fs";
29828
+ import path11 from "node:path";
29829
+ import { fileURLToPath } from "node:url";
29830
+
29831
+ // ../setup/dist/packageManager.js
29832
+ import fs9 from "node:fs";
29833
+ import path10 from "node:path";
29834
+ function normalizePath(filePath) {
29835
+ return filePath.replaceAll("\\", "/").replace(/\/+$/, "");
29836
+ }
29837
+ function firstExisting(candidates, existsSync4) {
29838
+ return candidates.find((candidate) => existsSync4(candidate));
29839
+ }
29840
+ function fallbackCommand(name, platform) {
29841
+ if (platform !== "win32")
29842
+ return name;
29843
+ if (name === "bun" || name === "volta")
29844
+ return `${name}.exe`;
29845
+ return `${name}.cmd`;
29846
+ }
29847
+ function resolvePackageManagerInstallation(packageRoot, packageName, options = {}) {
29848
+ const env = options.env ?? process.env;
29849
+ const platform = options.platform ?? process.platform;
29850
+ const existsSync4 = options.existsSync ?? ((candidate) => isExecutable(candidate, platform));
29851
+ const processExecPath = options.processExecPath ?? process.execPath;
29852
+ const normalizedRoot = normalizePath(path10.resolve(packageRoot));
29853
+ const lowerRoot = normalizedRoot.toLowerCase();
29854
+ const lowerPackageName = packageName.toLowerCase();
29855
+ const pnpmGlobalRoot = /\/global\/\d+\/(?:\.pnpm\/.*\/)?node_modules\//.exec(lowerRoot);
29856
+ if (pnpmGlobalRoot && lowerRoot.endsWith(`/node_modules/${lowerPackageName}`)) {
29857
+ const pnpmHome = normalizedRoot.slice(0, pnpmGlobalRoot.index);
29858
+ const command = firstExisting([
29859
+ ...executableNames("pnpm", platform).map((name) => path10.join(pnpmHome, name)),
29860
+ ...executableNames("pnpm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
29861
+ ], existsSync4) ?? fallbackCommand("pnpm", platform);
29862
+ return { manager: "pnpm", command, binDirectory: pnpmHome };
29863
+ }
29864
+ const bunMarker = `/.bun/install/global/node_modules/${lowerPackageName}`;
29865
+ if (lowerRoot.endsWith(bunMarker)) {
29866
+ const bunHome = normalizedRoot.slice(0, lowerRoot.indexOf("/.bun/"));
29867
+ const command = firstExisting(executableNames("bun", platform).map((name) => path10.join(bunHome, ".bun", "bin", name)), existsSync4) ?? fallbackCommand("bun", platform);
29868
+ return {
29869
+ manager: "bun",
29870
+ command,
29871
+ binDirectory: path10.join(bunHome, ".bun", "bin")
29872
+ };
29873
+ }
29874
+ if ((lowerRoot.includes("/.config/yarn/global/node_modules/") || lowerRoot.includes("/.yarn/global/node_modules/") || lowerRoot.includes("/yarn/global/node_modules/") || lowerRoot.includes("/yarn/data/global/node_modules/")) && lowerRoot.endsWith(`/node_modules/${lowerPackageName}`)) {
29875
+ const layout = [
29876
+ { marker: "/.config/yarn/global/", binSegments: [".yarn", "bin"] },
29877
+ { marker: "/.yarn/global/", binSegments: [".yarn", "bin"] },
29878
+ { marker: "/yarn/data/global/", binSegments: ["yarn", "bin"] },
29879
+ { marker: "/yarn/global/", binSegments: ["yarn", "bin"] }
29880
+ ].find((candidate) => lowerRoot.includes(candidate.marker));
29881
+ const prefix = normalizedRoot.slice(0, lowerRoot.indexOf(layout.marker));
29882
+ const binDirectory = path10.join(prefix, ...layout.binSegments);
29883
+ const command = firstExisting([
29884
+ ...executableNames("yarn", platform).map((name) => path10.join(binDirectory, name)),
29885
+ ...executableNames("yarn", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
29886
+ ], existsSync4) ?? findExecutable("yarn", { env, existsSync: existsSync4, platform }) ?? fallbackCommand("yarn", platform);
29887
+ return { manager: "yarn", command, binDirectory };
29888
+ }
29889
+ if (lowerRoot.includes("/.volta/tools/image/packages/") && lowerRoot.endsWith(`/lib/node_modules/${lowerPackageName}`)) {
29890
+ const voltaHome = normalizedRoot.slice(0, lowerRoot.indexOf("/.volta/"));
29891
+ const command = firstExisting(executableNames("volta", platform).map((name) => path10.join(voltaHome, ".volta", "bin", name)), existsSync4) ?? fallbackCommand("volta", platform);
29892
+ return {
29893
+ manager: "volta",
29894
+ command,
29895
+ binDirectory: path10.join(voltaHome, ".volta", "bin")
29896
+ };
29897
+ }
29898
+ const npmMarker = `/lib/node_modules/${lowerPackageName}`;
29899
+ if (lowerRoot.endsWith(npmMarker)) {
29900
+ const prefix = normalizedRoot.slice(0, lowerRoot.length - npmMarker.length);
29901
+ const command = firstExisting([
29902
+ ...executableNames("npm", platform).map((name) => path10.join(prefix, "bin", name)),
29903
+ ...executableNames("npm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
29904
+ ], existsSync4) ?? fallbackCommand("npm", platform);
29905
+ return { manager: "npm", command, binDirectory: path10.join(prefix, "bin") };
29906
+ }
29907
+ if (platform === "win32" && env.APPDATA) {
29908
+ const npmRoot = normalizePath(path10.join(env.APPDATA, "npm", "node_modules", packageName));
29909
+ if (lowerRoot === npmRoot.toLowerCase()) {
29910
+ const binDirectory = path10.join(env.APPDATA, "npm");
29911
+ const command = firstExisting([
29912
+ ...executableNames("npm", platform).map((name) => path10.join(binDirectory, name)),
29913
+ ...executableNames("npm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
29914
+ ], existsSync4) ?? fallbackCommand("npm", platform);
29915
+ return { manager: "npm", command, binDirectory };
29916
+ }
29917
+ }
29918
+ return null;
29919
+ }
29920
+
29921
+ // ../setup/dist/version.js
29922
+ var MEARL_RELEASE_VERSION_MAX_LENGTH = 64;
29923
+ var RELEASE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-beta\.(0|[1-9]\d*))?$/;
29924
+ var RELEASE_LINE_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.x$/;
29925
+ var RELEASE_COMPONENT_MAXIMUM = 65535;
29926
+ function parseComponent(value) {
29927
+ const component = Number(value);
29928
+ return Number.isSafeInteger(component) && component <= RELEASE_COMPONENT_MAXIMUM ? component : null;
29929
+ }
29930
+ function parseMearlReleaseVersion(value) {
29931
+ if (typeof value !== "string" || value.length > MEARL_RELEASE_VERSION_MAX_LENGTH)
29932
+ return null;
29933
+ const match = RELEASE_VERSION_PATTERN.exec(value);
29934
+ if (!match)
29935
+ return null;
29936
+ const major = parseComponent(match[1]);
29937
+ const minor = parseComponent(match[2]);
29938
+ const patch = parseComponent(match[3]);
29939
+ const beta = match[4] === void 0 ? void 0 : parseComponent(match[4]);
29940
+ if (major === null || minor === null || patch === null || beta === null)
29941
+ return null;
29942
+ return {
29943
+ raw: value,
29944
+ major,
29945
+ minor,
29946
+ patch,
29947
+ channel: beta === void 0 ? "stable" : "beta",
29948
+ ...beta === void 0 ? {} : { beta }
29949
+ };
29950
+ }
29951
+ function isMearlReleaseVersion(value) {
29952
+ return parseMearlReleaseVersion(value) !== null;
29953
+ }
29954
+ function parseMearlReleaseLine(value) {
29955
+ if (typeof value !== "string" || value.length > MEARL_RELEASE_VERSION_MAX_LENGTH)
29956
+ return null;
29957
+ const match = RELEASE_LINE_PATTERN.exec(value);
29958
+ if (!match)
29959
+ return null;
29960
+ const major = parseComponent(match[1]);
29961
+ const minor = parseComponent(match[2]);
29962
+ if (major === null || minor === null)
29963
+ return null;
29964
+ return { raw: value, major, minor };
29965
+ }
29966
+ function mearlReleaseLineForVersion(version2) {
29967
+ const parsed = parseMearlReleaseVersion(version2);
29968
+ if (!parsed)
29969
+ throw new Error("A valid Mearl release version is required");
29970
+ return `${parsed.major}.${parsed.minor}.x`;
29971
+ }
29972
+ function isMearlReleaseVersionInLine(version2, releaseLine) {
29973
+ const parsedVersion = parseMearlReleaseVersion(version2);
29974
+ const parsedLine = parseMearlReleaseLine(releaseLine);
29975
+ return parsedVersion !== null && parsedLine !== null && parsedVersion.major === parsedLine.major && parsedVersion.minor === parsedLine.minor;
29976
+ }
29977
+ function compareMearlReleaseLines(leftVersion, rightVersion) {
29978
+ const left = parseMearlReleaseVersion(leftVersion);
29979
+ const right = parseMearlReleaseVersion(rightVersion);
29980
+ if (!left || !right) {
29981
+ throw new Error("Mearl release-line comparison requires valid release versions");
29982
+ }
29983
+ for (const key of ["major", "minor"]) {
29984
+ if (left[key] < right[key])
29985
+ return -1;
29986
+ if (left[key] > right[key])
29987
+ return 1;
29988
+ }
29989
+ return 0;
29990
+ }
29991
+
29992
+ // src/host-updater.ts
29993
+ var NATIVE_HOST_UPDATE_TIMEOUT_MS = 5 * 6e4;
29994
+ var UPDATE_LOCK_PATH = path11.join(DAEMON_HOME, "native-host-update.lock");
29995
+ var UPDATE_LOCK_POLL_MS = 500;
29996
+ var INVALID_UPDATE_LOCK_GRACE_MS = 1e4;
29997
+ var NativeHostUpdateFailure = class extends Error {
29998
+ constructor(updateError, message) {
29999
+ super(message);
30000
+ this.updateError = updateError;
30001
+ this.name = "NativeHostUpdateFailure";
30002
+ }
30003
+ };
30004
+ function wait(delayMs) {
30005
+ return new Promise((resolve) => setTimeout(resolve, delayMs));
30006
+ }
30007
+ function readLockState(lockPath) {
30008
+ try {
30009
+ const stat2 = fs10.lstatSync(lockPath);
30010
+ if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.size > 4096) {
30011
+ return { modifiedAt: stat2.mtimeMs, owner: null };
30012
+ }
30013
+ try {
30014
+ const value = JSON.parse(fs10.readFileSync(lockPath, "utf8"));
30015
+ const owner = Number.isInteger(value.pid) && value.pid > 0 && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && value.startedAt > 0 ? { pid: value.pid, startedAt: value.startedAt } : null;
30016
+ return { modifiedAt: stat2.mtimeMs, owner };
30017
+ } catch {
30018
+ return { modifiedAt: stat2.mtimeMs, owner: null };
30019
+ }
30020
+ } catch {
30021
+ return null;
30022
+ }
30023
+ }
30024
+ async function withNativeHostUpdateLock(lockPath, targetVersion, operation) {
30025
+ fs10.mkdirSync(path11.dirname(lockPath), { recursive: true, mode: 448 });
30026
+ const startedAt = Date.now();
30027
+ const owner = `${JSON.stringify({ pid: process.pid, startedAt, targetVersion })}
30028
+ `;
30029
+ while (true) {
30030
+ try {
30031
+ const handle = fs10.openSync(lockPath, "wx", 384);
30032
+ try {
30033
+ fs10.writeFileSync(handle, owner, "utf8");
30034
+ } finally {
30035
+ fs10.closeSync(handle);
30036
+ }
30037
+ break;
30038
+ } catch (error48) {
30039
+ if (!(error48 instanceof Error) || !("code" in error48) || error48.code !== "EEXIST") throw error48;
30040
+ const existing = readLockState(lockPath);
30041
+ const staleAfter = existing?.owner ? NATIVE_HOST_UPDATE_TIMEOUT_MS : INVALID_UPDATE_LOCK_GRACE_MS;
30042
+ const referenceTime = existing?.owner?.startedAt ?? existing?.modifiedAt;
30043
+ const expired = referenceTime !== void 0 && Date.now() - referenceTime > staleAfter;
30044
+ const ownerAlive = existing?.owner ? isAlive(existing.owner.pid) : false;
30045
+ if (expired && !ownerAlive) {
30046
+ try {
30047
+ fs10.unlinkSync(lockPath);
30048
+ continue;
30049
+ } catch {
30050
+ }
30051
+ }
30052
+ if (Date.now() - startedAt > NATIVE_HOST_UPDATE_TIMEOUT_MS + 1e4) {
30053
+ throw new NativeHostUpdateFailure(
30054
+ "lock-timeout",
30055
+ "Another Mearl Native Host update did not finish in time"
30056
+ );
30057
+ }
30058
+ await wait(UPDATE_LOCK_POLL_MS);
30059
+ }
30060
+ }
30061
+ try {
30062
+ return await operation();
30063
+ } finally {
30064
+ try {
30065
+ if (fs10.readFileSync(lockPath, "utf8") === owner) fs10.unlinkSync(lockPath);
30066
+ } catch {
30067
+ }
30068
+ }
30069
+ }
30070
+ function classifyUpdateFailure(output) {
30071
+ if (/\b(?:E404|ETARGET)\b|no matching version found|404\s+not found|package.+not found/i.test(
30072
+ output
30073
+ )) {
30074
+ return "package-unavailable";
30075
+ }
30076
+ if (/\b(?:EAI_AGAIN|ECONNREFUSED|ECONNRESET|ENETUNREACH|ENOTFOUND|ERR_SOCKET_TIMEOUT)\b|fetch failed|network request/i.test(
30077
+ output
30078
+ )) {
30079
+ return "network";
30080
+ }
30081
+ return "setup-failed";
30082
+ }
30083
+ function nativeHostUpdateCommand(targetVersion) {
30084
+ if (!isMearlReleaseVersion(targetVersion)) {
30085
+ throw new Error("The Native Host update target must be a valid Mearl release");
30086
+ }
30087
+ const releaseLine = mearlReleaseLineForVersion(targetVersion);
30088
+ const packageSpec = `@mearl/setup@${releaseLine}`;
30089
+ const args = [
30090
+ "--yes",
30091
+ packageSpec,
30092
+ "update",
30093
+ "--local",
30094
+ "--yes",
30095
+ "--target-line",
30096
+ releaseLine,
30097
+ "--skip-skill"
30098
+ ];
30099
+ return {
30100
+ args
30101
+ };
30102
+ }
30103
+ function currentNativeHostPackageRoot(entryPath) {
30104
+ let current = path11.dirname(entryPath);
30105
+ for (let depth = 0; depth < 12; depth += 1) {
30106
+ try {
30107
+ const manifest = JSON.parse(fs10.readFileSync(path11.join(current, "package.json"), "utf8"));
30108
+ if (manifest.name === "@mearl/native-host") return current;
30109
+ } catch {
30110
+ }
30111
+ const parent = path11.dirname(current);
30112
+ if (parent === current) break;
30113
+ current = parent;
30114
+ }
30115
+ return null;
30116
+ }
30117
+ function currentPackageManagerInstallation(environment, nodePath, platform) {
30118
+ const packageRoot = currentNativeHostPackageRoot(fileURLToPath(import.meta.url));
30119
+ if (!packageRoot) return null;
30120
+ return resolvePackageManagerInstallation(packageRoot, "@mearl/native-host", {
30121
+ env: environment,
30122
+ platform,
30123
+ processExecPath: nodePath
30124
+ });
30125
+ }
30126
+ async function installedLocalPackagesMatch(targetReleaseLine, environment, runner) {
30127
+ const installedVersions = [];
30128
+ for (const executableName of ["mearl-native-host", "mearl"]) {
30129
+ const executable = findExecutable(executableName, { env: environment });
30130
+ if (!executable) return false;
30131
+ try {
30132
+ const result = await runner(executable, ["--version"], {
30133
+ capture: true,
30134
+ env: environment,
30135
+ timeoutMs: 5e3
30136
+ });
30137
+ const installedVersion = result.stdout.trim();
30138
+ if (result.code !== 0 || !isMearlReleaseVersionInLine(installedVersion, targetReleaseLine)) {
30139
+ return false;
30140
+ }
30141
+ installedVersions.push(installedVersion);
30142
+ } catch {
30143
+ return false;
30144
+ }
30145
+ }
30146
+ return new Set(installedVersions).size === 1;
30147
+ }
30148
+ async function runNativeHostUpdate(targetVersion, options = {}) {
30149
+ const command = nativeHostUpdateCommand(targetVersion);
30150
+ const targetReleaseLine = mearlReleaseLineForVersion(targetVersion);
30151
+ const environment = options.environment ?? process.env;
30152
+ const platform = options.platform ?? process.platform;
30153
+ const nodePath = options.nodePath ?? process.execPath;
30154
+ const currentInstallation = currentPackageManagerInstallation(environment, nodePath, platform);
30155
+ const managerCommand = options.packageManagerCommand === void 0 ? currentInstallation?.command ?? null : options.packageManagerCommand;
30156
+ const packageBinDirectory = options.packageBinDirectory === void 0 ? currentInstallation?.binDirectory ?? null : options.packageBinDirectory;
30157
+ let childEnvironment = prependNodePath(environment, nodePath);
30158
+ if (managerCommand) childEnvironment = prependCommandPath(managerCommand, childEnvironment);
30159
+ if (packageBinDirectory) {
30160
+ childEnvironment = prependPathDirectory(packageBinDirectory, childEnvironment);
30161
+ }
30162
+ const packageRunner = options.packageRunner ?? findExecutable("npx", {
30163
+ env: childEnvironment,
30164
+ extraDirectories: [path11.dirname(nodePath)],
30165
+ platform
30166
+ });
30167
+ if (!packageRunner) {
30168
+ throw new NativeHostUpdateFailure("package-unavailable", "The package runner is unavailable");
30169
+ }
30170
+ const runner = options.runner ?? runCommand;
30171
+ const areTargetsInstalled = options.areTargetsInstalled ?? ((version2, env) => installedLocalPackagesMatch(version2, env, runner));
30172
+ const withUpdateLock = options.withUpdateLock ?? ((version2, operation) => withNativeHostUpdateLock(options.updateLockPath ?? UPDATE_LOCK_PATH, version2, operation));
30173
+ await withUpdateLock(targetVersion, async () => {
30174
+ let result;
30175
+ try {
30176
+ result = await runner(packageRunner, command.args, {
30177
+ capture: true,
30178
+ env: childEnvironment,
30179
+ timeoutMs: options.timeoutMs ?? NATIVE_HOST_UPDATE_TIMEOUT_MS
30180
+ });
30181
+ } catch (error48) {
30182
+ const message = error48 instanceof Error ? error48.message : String(error48);
30183
+ const classified = classifyUpdateFailure(message);
30184
+ throw new NativeHostUpdateFailure(
30185
+ /timed out/i.test(message) ? "timeout" : classified === "setup-failed" ? "unknown" : classified,
30186
+ "The Native Host update process did not complete"
30187
+ );
30188
+ }
30189
+ if (result.code !== 0) {
30190
+ throw new NativeHostUpdateFailure(
30191
+ classifyUpdateFailure(`${result.stderr.slice(0, 8192)}
30192
+ ${result.stdout.slice(0, 8192)}`),
30193
+ "The Mearl setup release line did not complete successfully"
30194
+ );
30195
+ }
30196
+ if (!await areTargetsInstalled(targetReleaseLine, childEnvironment)) {
30197
+ throw new NativeHostUpdateFailure(
30198
+ "verification-failed",
30199
+ "The installed Native Host and client do not match the Extension release line"
30200
+ );
30201
+ }
30202
+ });
30203
+ }
30204
+ var NativeHostUpdateCoordinator = class {
30205
+ constructor(options) {
30206
+ this.options = options;
30207
+ }
30208
+ #automaticAttempted = false;
30209
+ #operation = null;
30210
+ evaluate(extensionVersion2, checkForUpdates) {
30211
+ if (checkForUpdates !== true || this.#automaticAttempted || this.#operation) return;
30212
+ if (!isMearlReleaseVersion(extensionVersion2) || !isMearlReleaseVersion(this.options.hostVersion)) {
30213
+ this.options.log("Skipped Native Host update check because a release version was invalid");
30214
+ return;
30215
+ }
30216
+ const targetVersion = extensionVersion2;
30217
+ if (compareMearlReleaseLines(this.options.hostVersion, targetVersion) >= 0) return;
30218
+ this.#automaticAttempted = true;
30219
+ const operation = this.options.runUpdate(targetVersion).then(() => this.options.requestRestart()).catch((error48) => {
30220
+ const category = error48 instanceof NativeHostUpdateFailure ? error48.updateError : "unknown";
30221
+ this.options.log(`Native Host automatic update failed (${category})`);
30222
+ }).finally(() => {
30223
+ if (this.#operation === operation) this.#operation = null;
30224
+ });
30225
+ this.#operation = operation;
30226
+ }
30227
+ };
30228
+
29772
30229
  // src/index.ts
29773
30230
  var cliArgs = process.argv.slice(2);
29774
30231
  var cliArg = cliArgs[0];
@@ -29835,11 +30292,11 @@ Examples:
29835
30292
  process.exit(0);
29836
30293
  }
29837
30294
  function socketPathFor(suffix) {
29838
- return process.platform === "win32" ? `\\\\.\\pipe\\mearl-agent${suffix}` : path12.join(os7.tmpdir(), `mearl-agent${suffix}.sock`);
30295
+ return process.platform === "win32" ? `\\\\.\\pipe\\mearl-agent${suffix}` : path14.join(os7.tmpdir(), `mearl-agent${suffix}.sock`);
29839
30296
  }
29840
30297
  var LEGACY_SOCKET_PATH = socketPathFor("");
29841
30298
  var INSTANCE_SOCKET_PATH = socketPathFor(`-${process.pid}`);
29842
- var LOG_FILE = path12.join(os7.tmpdir(), "mearl-native-host.log");
30299
+ var LOG_FILE = path14.join(os7.tmpdir(), "mearl-native-host.log");
29843
30300
  var DEFAULT_TIMEOUT_MS = 15e3;
29844
30301
  var INVENTORY_IDLE_EXIT_MS = 1e3;
29845
30302
  var MAX_SOCKET_BUFFER_SIZE = 64 * 1024 * 1024;
@@ -29938,7 +30395,7 @@ function log(...args) {
29938
30395
  const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] [NativeHost] ${args.join(" ")}
29939
30396
  `;
29940
30397
  try {
29941
- fs11.appendFileSync(LOG_FILE, msg);
30398
+ fs13.appendFileSync(LOG_FILE, msg);
29942
30399
  } catch {
29943
30400
  }
29944
30401
  }
@@ -29950,6 +30407,14 @@ function sendToExtension(message) {
29950
30407
  process.stdout.write(header);
29951
30408
  process.stdout.write(json2);
29952
30409
  }
30410
+ var nativeHostUpdateCoordinator = new NativeHostUpdateCoordinator({
30411
+ hostVersion: NATIVE_HOST_VERSION,
30412
+ log,
30413
+ runUpdate: (targetVersion) => runNativeHostUpdate(targetVersion),
30414
+ requestRestart: () => {
30415
+ restartAfterUpdate();
30416
+ }
30417
+ });
29953
30418
  var agentChatManager = null;
29954
30419
  var agentSkillManager = new AgentSkillManager();
29955
30420
  function getAgentChatManager() {
@@ -30060,6 +30525,7 @@ function handleExtensionMessage(message) {
30060
30525
  extensionVersion: extensionVersion ?? void 0
30061
30526
  });
30062
30527
  sendToExtension({ type: "pong", timestamp: Date.now(), version: NATIVE_HOST_VERSION });
30528
+ nativeHostUpdateCoordinator.evaluate(message.version, message.checkForUpdates);
30063
30529
  return;
30064
30530
  }
30065
30531
  if (message && message.type === "browser_focus") {
@@ -30343,7 +30809,7 @@ async function handleSocketLine(socket, line) {
30343
30809
  return result2.cookies ?? [];
30344
30810
  } : (domains) => cdpExportCookies(getCdpSession(), domains);
30345
30811
  const result = await launchManagedBrowser(data, {
30346
- nativeHostScript: fileURLToPath2(import.meta.url),
30812
+ nativeHostScript: fileURLToPath3(import.meta.url),
30347
30813
  prepareTdbankSso,
30348
30814
  exportCookies,
30349
30815
  log
@@ -30472,7 +30938,7 @@ function onSocketConnection(socket) {
30472
30938
  }
30473
30939
  function isPathAlive(socketPath) {
30474
30940
  return new Promise((resolve) => {
30475
- if (process.platform !== "win32" && !fs11.existsSync(socketPath)) {
30941
+ if (process.platform !== "win32" && !fs13.existsSync(socketPath)) {
30476
30942
  resolve(false);
30477
30943
  return;
30478
30944
  }
@@ -30495,9 +30961,9 @@ function isPathAlive(socketPath) {
30495
30961
  }
30496
30962
  function listenOn(socketPath) {
30497
30963
  return new Promise((resolve, reject) => {
30498
- if (process.platform !== "win32" && fs11.existsSync(socketPath)) {
30964
+ if (process.platform !== "win32" && fs13.existsSync(socketPath)) {
30499
30965
  try {
30500
- fs11.unlinkSync(socketPath);
30966
+ fs13.unlinkSync(socketPath);
30501
30967
  } catch {
30502
30968
  }
30503
30969
  }
@@ -30506,11 +30972,11 @@ function listenOn(socketPath) {
30506
30972
  server.listen(socketPath, () => {
30507
30973
  if (process.platform !== "win32") {
30508
30974
  try {
30509
- fs11.chmodSync(socketPath, 384);
30975
+ fs13.chmodSync(socketPath, 384);
30510
30976
  } catch (error48) {
30511
30977
  server.close();
30512
30978
  try {
30513
- fs11.unlinkSync(socketPath);
30979
+ fs13.unlinkSync(socketPath);
30514
30980
  } catch {
30515
30981
  }
30516
30982
  reject(error48);
@@ -30546,7 +31012,7 @@ function releaseLegacySocket() {
30546
31012
  }
30547
31013
  if (process.platform !== "win32") {
30548
31014
  try {
30549
- if (fs11.existsSync(LEGACY_SOCKET_PATH)) fs11.unlinkSync(LEGACY_SOCKET_PATH);
31015
+ if (fs13.existsSync(LEGACY_SOCKET_PATH)) fs13.unlinkSync(LEGACY_SOCKET_PATH);
30550
31016
  } catch {
30551
31017
  }
30552
31018
  }
@@ -30558,8 +31024,8 @@ async function startSocketServer() {
30558
31024
  function cleanupInstanceSocketFile() {
30559
31025
  if (process.platform === "win32") return;
30560
31026
  try {
30561
- if (fs11.existsSync(INSTANCE_SOCKET_PATH)) {
30562
- fs11.unlinkSync(INSTANCE_SOCKET_PATH);
31027
+ if (fs13.existsSync(INSTANCE_SOCKET_PATH)) {
31028
+ fs13.unlinkSync(INSTANCE_SOCKET_PATH);
30563
31029
  }
30564
31030
  } catch (error48) {
30565
31031
  log("cleanup socket file failed:", String(error48));
@@ -30586,6 +31052,11 @@ function cleanupAndExit(code) {
30586
31052
  }
30587
31053
  finish();
30588
31054
  }
31055
+ function restartAfterUpdate() {
31056
+ const forcedExit = setTimeout(() => process.exit(0), 2e3);
31057
+ forcedExit.unref();
31058
+ cleanupAndExit(0);
31059
+ }
30589
31060
  async function main() {
30590
31061
  initBrowserRegistry({ log });
30591
31062
  pruneDeadBrowsers();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mearl/native-host",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Native Messaging Host for Mearl — bridges Chrome Extension and local socket server",
5
5
  "type": "module",
6
6
  "main": "dist/install.js",
@@ -32,9 +32,9 @@
32
32
  "@types/node": "^24.9.1",
33
33
  "esbuild": "^0.25.2",
34
34
  "typescript": "^5.8.3",
35
- "@mearl/daemon-core": "2.3.0",
36
- "@mearl/browser-core": "2.3.0",
37
- "@mearl/setup": "2.3.0"
35
+ "@mearl/browser-core": "2.4.0",
36
+ "@mearl/daemon-core": "2.4.0",
37
+ "@mearl/setup": "2.4.0"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "rm -rf dist/ && node build.mjs",