@mearl/native-host
Advanced tools
@@ -1,6 +0,2 @@ | ||
| export interface AgentSpawnCommand { | ||
| command: string; | ||
| args: string[]; | ||
| } | ||
| export declare function agentSpawnCommand(executable: string, args: string[], platform?: NodeJS.Platform, commandInterpreter?: string | undefined): AgentSpawnCommand; | ||
| export declare function createAgentChildEnv(sourceEnv?: NodeJS.ProcessEnv, nodeExecutable?: string): NodeJS.ProcessEnv; | ||
| export { prependNodePath as createAgentChildEnv, resolveSpawnCommand as agentSpawnCommand, } from '@mearl/setup/process'; | ||
| export type { SpawnCommand as AgentSpawnCommand } from '@mearl/setup/process'; |
| import type { AgentSkillCheckUpdatesResult, AgentSkillCheckUpdatesOptions, AgentSkillCliStatus, AgentSkillInstallOptions, AgentSkillMutationOptions, AgentSkillMutationResult, AgentSkillScope, AgentSkillUpdate } from '@mearl/browser-core'; | ||
| interface SkillCliOutput { | ||
| stdout: string; | ||
| stderr: string; | ||
| } | ||
| export type SkillCliRunner = (executable: string, args: string[], cwd?: string) => Promise<SkillCliOutput>; | ||
| import { resolveAliSkillsExecutable, type AliSkillsCliRunner } from '@mearl/setup/ali-skills'; | ||
| export type SkillCliRunner = AliSkillsCliRunner; | ||
| export { resolveAliSkillsExecutable }; | ||
| export declare const runSkillCli: SkillCliRunner; | ||
| export interface AgentSkillManagerOptions { | ||
@@ -11,4 +10,2 @@ resolveExecutable?: () => string | null; | ||
| } | ||
| export declare function resolveAliSkillsExecutable(): string | null; | ||
| export declare const runSkillCli: SkillCliRunner; | ||
| export declare function parseSkillUpdates(stdout: string, scope: AgentSkillScope): AgentSkillUpdate[]; | ||
@@ -26,2 +23,1 @@ export declare class AgentSkillManager { | ||
| } | ||
| export {}; |
+18
-0
@@ -19,2 +19,3 @@ /** | ||
| */ | ||
| import fs from 'node:fs'; | ||
| export type IntegrationMode = 'skills' | 'mcp'; | ||
@@ -35,4 +36,21 @@ export interface InstallOptions { | ||
| } | ||
| export interface UninstallOptions { | ||
| /** Integration manifest to remove. Defaults to both Skills and MCP. */ | ||
| mode?: IntegrationMode | 'both'; | ||
| /** Suppress console output when `true`. */ | ||
| silent?: boolean; | ||
| } | ||
| export interface UninstallDependencies { | ||
| env?: NodeJS.ProcessEnv; | ||
| existsSync?: typeof fs.existsSync; | ||
| homedir?: () => string; | ||
| hostDir?: string; | ||
| platform?: NodeJS.Platform; | ||
| unlinkSync?: typeof fs.unlinkSync; | ||
| unregisterWindowsNativeHost?: (hostName: string) => void; | ||
| writeLine?: (line: string) => void; | ||
| } | ||
| export declare function resolveHostDir(): string; | ||
| export declare function installNativeHost(options?: InstallOptions): Promise<boolean>; | ||
| export declare function uninstallNativeHost(options?: UninstallOptions, dependencies?: UninstallDependencies): Promise<boolean>; | ||
| export declare function runCli(argv: string[]): Promise<void>; |
+110
-40
| // src/install.ts | ||
| import fs2 from "node:fs"; | ||
| import path2 from "node:path"; | ||
| import { execFileSync as execFileSync2 } from "node:child_process"; | ||
| import { createRequire } from "node:module"; | ||
| import { fileURLToPath } from "node:url"; | ||
| // ../setup/dist/nativeHost.js | ||
| import fs from "node:fs"; | ||
| import os from "node:os"; | ||
| import path from "node:path"; | ||
| import os from "node:os"; | ||
| import { execFileSync } from "node:child_process"; | ||
| import { createRequire } from "node:module"; | ||
| import { fileURLToPath } from "node:url"; | ||
| var DEFAULT_EXTENSION_ID = "aoehhjnofngknnjefamjbplchbolghkm"; | ||
| var HOST_NAME_BY_MODE = { | ||
| var MEARL_NATIVE_HOST_NAMES = { | ||
| skills: "com.alibaba.mearl.skills", | ||
| mcp: "com.alibaba.mearl.mcp" | ||
| }; | ||
| var __filename = fileURLToPath(import.meta.url); | ||
| var __dirname = path.dirname(__filename); | ||
| var ALL_MODES = ["skills", "mcp"]; | ||
| function resolveHostDir() { | ||
| switch (process.platform) { | ||
| function resolveNativeHostDirectory(options = {}) { | ||
| const env = options.env ?? process.env; | ||
| const home = (options.homedir ?? os.homedir)(); | ||
| switch (options.platform ?? process.platform) { | ||
| case "darwin": | ||
| return path.join( | ||
| os.homedir(), | ||
| "Library/Application Support/Google/Chrome/NativeMessagingHosts" | ||
| ); | ||
| return path.join(home, "Library/Application Support/Google/Chrome/NativeMessagingHosts"); | ||
| case "linux": | ||
| return path.join(os.homedir(), ".config/google-chrome/NativeMessagingHosts"); | ||
| return path.join(home, ".config/google-chrome/NativeMessagingHosts"); | ||
| case "win32": | ||
| return path.join( | ||
| process.env.PROGRAMDATA || "C:\\ProgramData", | ||
| "Google\\Chrome\\NativeMessagingHosts" | ||
| ); | ||
| return path.join(env.PROGRAMDATA || "C:\\ProgramData", "Google\\Chrome\\NativeMessagingHosts"); | ||
| default: | ||
| throw new Error(`Unsupported platform: ${process.platform}`); | ||
| throw new Error(`Unsupported platform: ${String(options.platform ?? process.platform)}`); | ||
| } | ||
| } | ||
| function unregisterWindowsNativeHost(hostName) { | ||
| const registryKey = `HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\${hostName}`; | ||
| try { | ||
| execFileSync("reg", ["delete", registryKey, "/f"], { stdio: "pipe" }); | ||
| } catch { | ||
| } | ||
| } | ||
| function uninstallNativeHostArtifacts(options = {}, dependencies = {}) { | ||
| const { mode = "both", silent = false } = options; | ||
| if (mode === "both") { | ||
| return ["skills", "mcp"].map((integrationMode) => uninstallNativeHostArtifacts({ ...options, mode: integrationMode }, dependencies)).every(Boolean); | ||
| } | ||
| const writeLine = dependencies.writeLine ?? ((line) => console.error(line)); | ||
| const log = (line) => { | ||
| if (!silent) | ||
| writeLine(line); | ||
| }; | ||
| try { | ||
| const existsSync = dependencies.existsSync ?? fs.existsSync; | ||
| const platform = dependencies.platform ?? process.platform; | ||
| const hostDir = dependencies.hostDir ?? resolveNativeHostDirectory({ | ||
| env: dependencies.env, | ||
| homedir: dependencies.homedir, | ||
| platform | ||
| }); | ||
| const unlinkSync = dependencies.unlinkSync ?? fs.unlinkSync; | ||
| const unregister = dependencies.unregisterWindowsNativeHost ?? unregisterWindowsNativeHost; | ||
| const hostName = MEARL_NATIVE_HOST_NAMES[mode]; | ||
| const launcherExtension = platform === "win32" ? "cmd" : "sh"; | ||
| const artifacts = [ | ||
| path.join(hostDir, `${hostName}.json`), | ||
| path.join(hostDir, `${hostName}-launcher.${launcherExtension}`) | ||
| ]; | ||
| for (const artifact of artifacts) { | ||
| if (!existsSync(artifact)) | ||
| continue; | ||
| unlinkSync(artifact); | ||
| log(`✅ Removed: ${artifact}`); | ||
| } | ||
| if (platform === "win32") | ||
| unregister(hostName); | ||
| return true; | ||
| } catch (error) { | ||
| log(`❌ Uninstall failed: ${error instanceof Error ? error.message : String(error)}`); | ||
| return false; | ||
| } | ||
| } | ||
| // src/install.ts | ||
| var DEFAULT_EXTENSION_ID = "aoehhjnofngknnjefamjbplchbolghkm"; | ||
| var __filename = fileURLToPath(import.meta.url); | ||
| var __dirname = path2.dirname(__filename); | ||
| var ALL_MODES = ["skills", "mcp"]; | ||
| function resolveHostDir() { | ||
| return resolveNativeHostDirectory(); | ||
| } | ||
| function resolveNativeHostPath() { | ||
| const siblingPath = path.join(__dirname, "index.js"); | ||
| if (fs.existsSync(siblingPath)) { | ||
| const siblingPath = path2.join(__dirname, "index.js"); | ||
| if (fs2.existsSync(siblingPath)) { | ||
| return siblingPath; | ||
@@ -50,3 +103,3 @@ } | ||
| const regKey = `HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\${hostName}`; | ||
| execFileSync("reg", ["add", regKey, "/ve", "/t", "REG_SZ", "/d", manifestPath, "/f"], { | ||
| execFileSync2("reg", ["add", regKey, "/ve", "/t", "REG_SZ", "/d", manifestPath, "/f"], { | ||
| stdio: "pipe" | ||
@@ -56,12 +109,12 @@ }); | ||
| function createLauncherScript(hostDir, hostPath, hostName) { | ||
| const nodePath = path.resolve(process.execPath); | ||
| const nodePath = path2.resolve(process.execPath); | ||
| if (process.platform === "win32") { | ||
| const launcherPath2 = path.join(hostDir, `${hostName}-launcher.cmd`); | ||
| const launcherPath2 = path2.join(hostDir, `${hostName}-launcher.cmd`); | ||
| const content2 = `@echo off\r | ||
| "${nodePath}" "${hostPath}" %*\r | ||
| `; | ||
| fs.writeFileSync(launcherPath2, content2, "utf-8"); | ||
| fs2.writeFileSync(launcherPath2, content2, "utf-8"); | ||
| return launcherPath2; | ||
| } | ||
| const launcherPath = path.join(hostDir, `${hostName}-launcher.sh`); | ||
| const launcherPath = path2.join(hostDir, `${hostName}-launcher.sh`); | ||
| const content = [ | ||
@@ -74,4 +127,4 @@ "#!/bin/sh", | ||
| ].join("\n"); | ||
| fs.writeFileSync(launcherPath, content, "utf-8"); | ||
| fs.chmodSync(launcherPath, 493); | ||
| fs2.writeFileSync(launcherPath, content, "utf-8"); | ||
| fs2.chmodSync(launcherPath, 493); | ||
| return launcherPath; | ||
@@ -92,3 +145,3 @@ } | ||
| } | ||
| const hostName = HOST_NAME_BY_MODE[mode]; | ||
| const hostName = MEARL_NATIVE_HOST_NAMES[mode]; | ||
| if (!hostName) { | ||
@@ -103,4 +156,4 @@ throw new Error(`Unknown mode: ${mode}. Expected 'skills' or 'mcp'.`); | ||
| if (skipIfExists) { | ||
| const manifestPath2 = path.join(hostDir, `${hostName}.json`); | ||
| if (fs.existsSync(manifestPath2)) { | ||
| const manifestPath2 = path2.join(hostDir, `${hostName}.json`); | ||
| if (fs2.existsSync(manifestPath2)) { | ||
| log(`✅ Already installed: ${manifestPath2}`); | ||
@@ -110,4 +163,4 @@ return true; | ||
| } | ||
| if (!fs.existsSync(hostDir)) { | ||
| fs.mkdirSync(hostDir, { recursive: true }); | ||
| if (!fs2.existsSync(hostDir)) { | ||
| fs2.mkdirSync(hostDir, { recursive: true }); | ||
| log(`✅ Created directory: ${hostDir}`); | ||
@@ -126,4 +179,4 @@ } | ||
| }; | ||
| const manifestPath = path.join(hostDir, `${hostName}.json`); | ||
| fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); | ||
| const manifestPath = path2.join(hostDir, `${hostName}.json`); | ||
| fs2.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2)); | ||
| if (process.platform === "win32") { | ||
@@ -133,3 +186,3 @@ registerWindowsNativeHost(hostName, manifestPath); | ||
| } else { | ||
| fs.chmodSync(manifestPath, 420); | ||
| fs2.chmodSync(manifestPath, 420); | ||
| } | ||
@@ -148,2 +201,5 @@ log(`✅ Manifest installed: ${manifestPath}`); | ||
| } | ||
| async function uninstallNativeHost(options = {}, dependencies = {}) { | ||
| return uninstallNativeHostArtifacts(options, dependencies); | ||
| } | ||
| function parseCliArgs(argv) { | ||
@@ -153,6 +209,7 @@ let mode = "both"; | ||
| let skipIfExists = false; | ||
| let uninstall = false; | ||
| for (let i = 0; i < argv.length; i += 1) { | ||
| const arg = argv[i]; | ||
| if (arg === "--help" || arg === "-h") { | ||
| return { showHelp: true, mode, skipIfExists }; | ||
| return { showHelp: true, uninstall, mode, skipIfExists }; | ||
| } | ||
@@ -176,2 +233,6 @@ if (arg === "--mode" || arg.startsWith("--mode=")) { | ||
| } | ||
| if (arg === "--uninstall") { | ||
| uninstall = true; | ||
| continue; | ||
| } | ||
| if (arg === "--init") { | ||
@@ -181,3 +242,3 @@ continue; | ||
| } | ||
| return { showHelp: false, mode, extensionId, skipIfExists }; | ||
| return { showHelp: false, uninstall, mode, extensionId, skipIfExists }; | ||
| } | ||
@@ -187,2 +248,3 @@ function printHelp() { | ||
| mearl-native-host --init [options] | ||
| mearl-native-host --uninstall [options] | ||
@@ -192,2 +254,3 @@ Options: | ||
| --extension-id <id> Chrome extension ID (default: ${DEFAULT_EXTENSION_ID}) | ||
| --uninstall Remove the selected Native Messaging manifests | ||
| -h, --help Show this help message | ||
@@ -198,2 +261,3 @@ | ||
| mearl-native-host --init --mode mcp | ||
| mearl-native-host --uninstall --mode skills | ||
| mearl-native-host --init --extension-id abcdefghijklmnopqrstuvwxyzabcdef`); | ||
@@ -212,2 +276,7 @@ } | ||
| } | ||
| if (parsed.uninstall) { | ||
| const success2 = await uninstallNativeHost({ mode: parsed.mode }); | ||
| if (success2) console.error("\n✅ Uninstall complete!\n"); | ||
| process.exit(success2 ? 0 : 1); | ||
| } | ||
| const success = await installNativeHost({ | ||
@@ -235,3 +304,4 @@ mode: parsed.mode, | ||
| resolveHostDir, | ||
| runCli | ||
| runCli, | ||
| uninstallNativeHost | ||
| }; |
+4
-3
| { | ||
| "name": "@mearl/native-host", | ||
| "version": "2.2.1", | ||
| "version": "2.2.2", | ||
| "description": "Native Messaging Host for Mearl — bridges Chrome Extension and local socket server", | ||
@@ -35,4 +35,5 @@ "type": "module", | ||
| "typescript": "^5.8.3", | ||
| "@mearl/browser-core": "2.2.1", | ||
| "@mearl/daemon-core": "2.2.1" | ||
| "@mearl/browser-core": "2.2.2", | ||
| "@mearl/daemon-core": "2.2.2", | ||
| "@mearl/setup": "2.2.2" | ||
| }, | ||
@@ -39,0 +40,0 @@ "scripts": { |
Sorry, the diff of this file is too big to display
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Network access
Supply chain riskThis module accesses the network.
Found 4 instances
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 10 instances
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
1116428
0.7%31433
0.6%8
-81.4%2
-88.89%7
16.67%