@mearl/native-host 2.2.1 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/process-env.d.ts +2 -6
- package/dist/agent/skill-manager.d.ts +4 -8
- package/dist/index.js +302 -192
- package/dist/install.d.ts +18 -0
- package/dist/install.js +110 -40
- package/package.json +4 -3
package/dist/install.d.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* import { installNativeHost } from '@mearl/native-host';
|
|
17
17
|
* await installNativeHost(); // installs both
|
|
18
18
|
*/
|
|
19
|
+
import fs from 'node:fs';
|
|
19
20
|
export type IntegrationMode = 'skills' | 'mcp';
|
|
20
21
|
export interface InstallOptions {
|
|
21
22
|
/**
|
|
@@ -31,6 +32,23 @@ export interface InstallOptions {
|
|
|
31
32
|
/** Skip installation if the manifest file already exists. Defaults to `false`. */
|
|
32
33
|
skipIfExists?: boolean;
|
|
33
34
|
}
|
|
35
|
+
export interface UninstallOptions {
|
|
36
|
+
/** Integration manifest to remove. Defaults to both Skills and MCP. */
|
|
37
|
+
mode?: IntegrationMode | 'both';
|
|
38
|
+
/** Suppress console output when `true`. */
|
|
39
|
+
silent?: boolean;
|
|
40
|
+
}
|
|
41
|
+
export interface UninstallDependencies {
|
|
42
|
+
env?: NodeJS.ProcessEnv;
|
|
43
|
+
existsSync?: typeof fs.existsSync;
|
|
44
|
+
homedir?: () => string;
|
|
45
|
+
hostDir?: string;
|
|
46
|
+
platform?: NodeJS.Platform;
|
|
47
|
+
unlinkSync?: typeof fs.unlinkSync;
|
|
48
|
+
unregisterWindowsNativeHost?: (hostName: string) => void;
|
|
49
|
+
writeLine?: (line: string) => void;
|
|
50
|
+
}
|
|
34
51
|
export declare function resolveHostDir(): string;
|
|
35
52
|
export declare function installNativeHost(options?: InstallOptions): Promise<boolean>;
|
|
53
|
+
export declare function uninstallNativeHost(options?: UninstallOptions, dependencies?: UninstallDependencies): Promise<boolean>;
|
|
36
54
|
export declare function runCli(argv: string[]): Promise<void>;
|
package/dist/install.js
CHANGED
|
@@ -1,39 +1,92 @@
|
|
|
1
1
|
// src/install.ts
|
|
2
|
+
import fs2 from "node:fs";
|
|
3
|
+
import path2 from "node:path";
|
|
4
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
// ../setup/dist/nativeHost.js
|
|
2
9
|
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
10
|
import os from "node:os";
|
|
11
|
+
import path from "node:path";
|
|
5
12
|
import { execFileSync } from "node:child_process";
|
|
6
|
-
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
var DEFAULT_EXTENSION_ID = "aoehhjnofngknnjefamjbplchbolghkm";
|
|
9
|
-
var HOST_NAME_BY_MODE = {
|
|
13
|
+
var MEARL_NATIVE_HOST_NAMES = {
|
|
10
14
|
skills: "com.alibaba.mearl.skills",
|
|
11
15
|
mcp: "com.alibaba.mearl.mcp"
|
|
12
16
|
};
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
switch (process.platform) {
|
|
17
|
+
function resolveNativeHostDirectory(options = {}) {
|
|
18
|
+
const env = options.env ?? process.env;
|
|
19
|
+
const home = (options.homedir ?? os.homedir)();
|
|
20
|
+
switch (options.platform ?? process.platform) {
|
|
18
21
|
case "darwin":
|
|
19
|
-
return path.join(
|
|
20
|
-
os.homedir(),
|
|
21
|
-
"Library/Application Support/Google/Chrome/NativeMessagingHosts"
|
|
22
|
-
);
|
|
22
|
+
return path.join(home, "Library/Application Support/Google/Chrome/NativeMessagingHosts");
|
|
23
23
|
case "linux":
|
|
24
|
-
return path.join(
|
|
24
|
+
return path.join(home, ".config/google-chrome/NativeMessagingHosts");
|
|
25
25
|
case "win32":
|
|
26
|
-
return path.join(
|
|
27
|
-
process.env.PROGRAMDATA || "C:\\ProgramData",
|
|
28
|
-
"Google\\Chrome\\NativeMessagingHosts"
|
|
29
|
-
);
|
|
26
|
+
return path.join(env.PROGRAMDATA || "C:\\ProgramData", "Google\\Chrome\\NativeMessagingHosts");
|
|
30
27
|
default:
|
|
31
|
-
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
28
|
+
throw new Error(`Unsupported platform: ${String(options.platform ?? process.platform)}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function unregisterWindowsNativeHost(hostName) {
|
|
32
|
+
const registryKey = `HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\${hostName}`;
|
|
33
|
+
try {
|
|
34
|
+
execFileSync("reg", ["delete", registryKey, "/f"], { stdio: "pipe" });
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function uninstallNativeHostArtifacts(options = {}, dependencies = {}) {
|
|
39
|
+
const { mode = "both", silent = false } = options;
|
|
40
|
+
if (mode === "both") {
|
|
41
|
+
return ["skills", "mcp"].map((integrationMode) => uninstallNativeHostArtifacts({ ...options, mode: integrationMode }, dependencies)).every(Boolean);
|
|
32
42
|
}
|
|
43
|
+
const writeLine = dependencies.writeLine ?? ((line) => console.error(line));
|
|
44
|
+
const log = (line) => {
|
|
45
|
+
if (!silent)
|
|
46
|
+
writeLine(line);
|
|
47
|
+
};
|
|
48
|
+
try {
|
|
49
|
+
const existsSync = dependencies.existsSync ?? fs.existsSync;
|
|
50
|
+
const platform = dependencies.platform ?? process.platform;
|
|
51
|
+
const hostDir = dependencies.hostDir ?? resolveNativeHostDirectory({
|
|
52
|
+
env: dependencies.env,
|
|
53
|
+
homedir: dependencies.homedir,
|
|
54
|
+
platform
|
|
55
|
+
});
|
|
56
|
+
const unlinkSync = dependencies.unlinkSync ?? fs.unlinkSync;
|
|
57
|
+
const unregister = dependencies.unregisterWindowsNativeHost ?? unregisterWindowsNativeHost;
|
|
58
|
+
const hostName = MEARL_NATIVE_HOST_NAMES[mode];
|
|
59
|
+
const launcherExtension = platform === "win32" ? "cmd" : "sh";
|
|
60
|
+
const artifacts = [
|
|
61
|
+
path.join(hostDir, `${hostName}.json`),
|
|
62
|
+
path.join(hostDir, `${hostName}-launcher.${launcherExtension}`)
|
|
63
|
+
];
|
|
64
|
+
for (const artifact of artifacts) {
|
|
65
|
+
if (!existsSync(artifact))
|
|
66
|
+
continue;
|
|
67
|
+
unlinkSync(artifact);
|
|
68
|
+
log(`✅ Removed: ${artifact}`);
|
|
69
|
+
}
|
|
70
|
+
if (platform === "win32")
|
|
71
|
+
unregister(hostName);
|
|
72
|
+
return true;
|
|
73
|
+
} catch (error) {
|
|
74
|
+
log(`❌ Uninstall failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/install.ts
|
|
80
|
+
var DEFAULT_EXTENSION_ID = "aoehhjnofngknnjefamjbplchbolghkm";
|
|
81
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
82
|
+
var __dirname = path2.dirname(__filename);
|
|
83
|
+
var ALL_MODES = ["skills", "mcp"];
|
|
84
|
+
function resolveHostDir() {
|
|
85
|
+
return resolveNativeHostDirectory();
|
|
33
86
|
}
|
|
34
87
|
function resolveNativeHostPath() {
|
|
35
|
-
const siblingPath =
|
|
36
|
-
if (
|
|
88
|
+
const siblingPath = path2.join(__dirname, "index.js");
|
|
89
|
+
if (fs2.existsSync(siblingPath)) {
|
|
37
90
|
return siblingPath;
|
|
38
91
|
}
|
|
39
92
|
try {
|
|
@@ -47,21 +100,21 @@ function resolveNativeHostPath() {
|
|
|
47
100
|
}
|
|
48
101
|
function registerWindowsNativeHost(hostName, manifestPath) {
|
|
49
102
|
const regKey = `HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\${hostName}`;
|
|
50
|
-
|
|
103
|
+
execFileSync2("reg", ["add", regKey, "/ve", "/t", "REG_SZ", "/d", manifestPath, "/f"], {
|
|
51
104
|
stdio: "pipe"
|
|
52
105
|
});
|
|
53
106
|
}
|
|
54
107
|
function createLauncherScript(hostDir, hostPath, hostName) {
|
|
55
|
-
const nodePath =
|
|
108
|
+
const nodePath = path2.resolve(process.execPath);
|
|
56
109
|
if (process.platform === "win32") {
|
|
57
|
-
const launcherPath2 =
|
|
110
|
+
const launcherPath2 = path2.join(hostDir, `${hostName}-launcher.cmd`);
|
|
58
111
|
const content2 = `@echo off\r
|
|
59
112
|
"${nodePath}" "${hostPath}" %*\r
|
|
60
113
|
`;
|
|
61
|
-
|
|
114
|
+
fs2.writeFileSync(launcherPath2, content2, "utf-8");
|
|
62
115
|
return launcherPath2;
|
|
63
116
|
}
|
|
64
|
-
const launcherPath =
|
|
117
|
+
const launcherPath = path2.join(hostDir, `${hostName}-launcher.sh`);
|
|
65
118
|
const content = [
|
|
66
119
|
"#!/bin/sh",
|
|
67
120
|
`NODE_BIN=${JSON.stringify(nodePath)}`,
|
|
@@ -69,8 +122,8 @@ function createLauncherScript(hostDir, hostPath, hostName) {
|
|
|
69
122
|
'exec "$NODE_BIN" "$HOST_SCRIPT" "$@"',
|
|
70
123
|
""
|
|
71
124
|
].join("\n");
|
|
72
|
-
|
|
73
|
-
|
|
125
|
+
fs2.writeFileSync(launcherPath, content, "utf-8");
|
|
126
|
+
fs2.chmodSync(launcherPath, 493);
|
|
74
127
|
return launcherPath;
|
|
75
128
|
}
|
|
76
129
|
async function installNativeHost(options = {}) {
|
|
@@ -86,7 +139,7 @@ async function installNativeHost(options = {}) {
|
|
|
86
139
|
);
|
|
87
140
|
return results.every(Boolean);
|
|
88
141
|
}
|
|
89
|
-
const hostName =
|
|
142
|
+
const hostName = MEARL_NATIVE_HOST_NAMES[mode];
|
|
90
143
|
if (!hostName) {
|
|
91
144
|
throw new Error(`Unknown mode: ${mode}. Expected 'skills' or 'mcp'.`);
|
|
92
145
|
}
|
|
@@ -96,14 +149,14 @@ async function installNativeHost(options = {}) {
|
|
|
96
149
|
try {
|
|
97
150
|
const hostDir = resolveHostDir();
|
|
98
151
|
if (skipIfExists) {
|
|
99
|
-
const manifestPath2 =
|
|
100
|
-
if (
|
|
152
|
+
const manifestPath2 = path2.join(hostDir, `${hostName}.json`);
|
|
153
|
+
if (fs2.existsSync(manifestPath2)) {
|
|
101
154
|
log(`✅ Already installed: ${manifestPath2}`);
|
|
102
155
|
return true;
|
|
103
156
|
}
|
|
104
157
|
}
|
|
105
|
-
if (!
|
|
106
|
-
|
|
158
|
+
if (!fs2.existsSync(hostDir)) {
|
|
159
|
+
fs2.mkdirSync(hostDir, { recursive: true });
|
|
107
160
|
log(`✅ Created directory: ${hostDir}`);
|
|
108
161
|
}
|
|
109
162
|
const resolvedHostPath = resolveNativeHostPath();
|
|
@@ -117,13 +170,13 @@ async function installNativeHost(options = {}) {
|
|
|
117
170
|
type: "stdio",
|
|
118
171
|
allowed_origins: [`chrome-extension://${extensionId}/`]
|
|
119
172
|
};
|
|
120
|
-
const manifestPath =
|
|
121
|
-
|
|
173
|
+
const manifestPath = path2.join(hostDir, `${hostName}.json`);
|
|
174
|
+
fs2.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
122
175
|
if (process.platform === "win32") {
|
|
123
176
|
registerWindowsNativeHost(hostName, manifestPath);
|
|
124
177
|
log(`✅ Windows registry key created for: ${hostName}`);
|
|
125
178
|
} else {
|
|
126
|
-
|
|
179
|
+
fs2.chmodSync(manifestPath, 420);
|
|
127
180
|
}
|
|
128
181
|
log(`✅ Manifest installed: ${manifestPath}`);
|
|
129
182
|
log(`✅ Extension ID: ${extensionId}`);
|
|
@@ -137,14 +190,18 @@ async function installNativeHost(options = {}) {
|
|
|
137
190
|
return false;
|
|
138
191
|
}
|
|
139
192
|
}
|
|
193
|
+
async function uninstallNativeHost(options = {}, dependencies = {}) {
|
|
194
|
+
return uninstallNativeHostArtifacts(options, dependencies);
|
|
195
|
+
}
|
|
140
196
|
function parseCliArgs(argv) {
|
|
141
197
|
let mode = "both";
|
|
142
198
|
let extensionId;
|
|
143
199
|
let skipIfExists = false;
|
|
200
|
+
let uninstall = false;
|
|
144
201
|
for (let i = 0; i < argv.length; i += 1) {
|
|
145
202
|
const arg = argv[i];
|
|
146
203
|
if (arg === "--help" || arg === "-h") {
|
|
147
|
-
return { showHelp: true, mode, skipIfExists };
|
|
204
|
+
return { showHelp: true, uninstall, mode, skipIfExists };
|
|
148
205
|
}
|
|
149
206
|
if (arg === "--mode" || arg.startsWith("--mode=")) {
|
|
150
207
|
const value = arg.includes("=") ? arg.slice("--mode=".length) : argv[++i];
|
|
@@ -163,24 +220,31 @@ function parseCliArgs(argv) {
|
|
|
163
220
|
skipIfExists = true;
|
|
164
221
|
continue;
|
|
165
222
|
}
|
|
223
|
+
if (arg === "--uninstall") {
|
|
224
|
+
uninstall = true;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
166
227
|
if (arg === "--init") {
|
|
167
228
|
continue;
|
|
168
229
|
}
|
|
169
230
|
}
|
|
170
|
-
return { showHelp: false, mode, extensionId, skipIfExists };
|
|
231
|
+
return { showHelp: false, uninstall, mode, extensionId, skipIfExists };
|
|
171
232
|
}
|
|
172
233
|
function printHelp() {
|
|
173
234
|
console.error(`Usage:
|
|
174
235
|
mearl-native-host --init [options]
|
|
236
|
+
mearl-native-host --uninstall [options]
|
|
175
237
|
|
|
176
238
|
Options:
|
|
177
239
|
--mode <skills|mcp|both> Integration mode (default: both — installs both hosts)
|
|
178
240
|
--extension-id <id> Chrome extension ID (default: ${DEFAULT_EXTENSION_ID})
|
|
241
|
+
--uninstall Remove the selected Native Messaging manifests
|
|
179
242
|
-h, --help Show this help message
|
|
180
243
|
|
|
181
244
|
Examples:
|
|
182
245
|
mearl-native-host --init
|
|
183
246
|
mearl-native-host --init --mode mcp
|
|
247
|
+
mearl-native-host --uninstall --mode skills
|
|
184
248
|
mearl-native-host --init --extension-id abcdefghijklmnopqrstuvwxyzabcdef`);
|
|
185
249
|
}
|
|
186
250
|
async function runCli(argv) {
|
|
@@ -194,6 +258,11 @@ async function runCli(argv) {
|
|
|
194
258
|
console.error(" Must be a 32-character lowercase string (see chrome://extensions/)");
|
|
195
259
|
process.exit(1);
|
|
196
260
|
}
|
|
261
|
+
if (parsed.uninstall) {
|
|
262
|
+
const success2 = await uninstallNativeHost({ mode: parsed.mode });
|
|
263
|
+
if (success2) console.error("\n✅ Uninstall complete!\n");
|
|
264
|
+
process.exit(success2 ? 0 : 1);
|
|
265
|
+
}
|
|
197
266
|
const success = await installNativeHost({
|
|
198
267
|
mode: parsed.mode,
|
|
199
268
|
extensionId: parsed.extensionId,
|
|
@@ -216,5 +285,6 @@ Verify:
|
|
|
216
285
|
export {
|
|
217
286
|
installNativeHost,
|
|
218
287
|
resolveHostDir,
|
|
219
|
-
runCli
|
|
288
|
+
runCli,
|
|
289
|
+
uninstallNativeHost
|
|
220
290
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mearl/native-host",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
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,8 +32,9 @@
|
|
|
32
32
|
"@types/node": "^24.9.1",
|
|
33
33
|
"esbuild": "^0.25.2",
|
|
34
34
|
"typescript": "^5.8.3",
|
|
35
|
-
"@mearl/browser-core": "2.2.
|
|
36
|
-
"@mearl/daemon-core": "2.2.
|
|
35
|
+
"@mearl/browser-core": "2.2.2",
|
|
36
|
+
"@mearl/daemon-core": "2.2.2",
|
|
37
|
+
"@mearl/setup": "2.2.2"
|
|
37
38
|
},
|
|
38
39
|
"scripts": {
|
|
39
40
|
"build": "rm -rf dist/ && node build.mjs",
|