Skill: powtac/meross (version 1.0.27)

--- name: meross description: Control Meross cloud plugs via local CLI commands. Use for discovery, state checks, and switch on/off actions. metadata: { "openclaw": { "requires": { "env": ["MEROSS_EMAIL", "MEROSS_PASSWORD"] }, "primaryEnv": "MEROSS_PASSWORD", }, } --- # Meross Skill (CLI) Use local `node dist/cli.js` only. Do not use plugin APIs. Do not invent device mappings. ## Hard Gates - Require `MEROSS_EMAIL` and `MEROSS_PASSWORD` before cloud commands. - `MEROSS_REGION` is optional. - In new/runtime-reset environments, ensure build exists: `npm install && npm run build`. - If registry metadata conflicts with runtime behavior, trust runtime behavior. - Never write credentials to `devices.json` or other files. - Before every `set-device` command, show exact `deviceId`, capability, and value to the user and get explicit confirmation. ## Device Resolution Rules - Resolve target by exact `deviceId` first. - Fallback to alias from `devices.json`. - If multiple matches or no match: stop and return ambiguity/missing-target guidance. - Only `switch` capability is valid. ## Registry Rules - Registry path: local `devices.json` in skill root. - Refresh registry with: ```bash node dist/cli.js setup-once '{}' ``` - `setup-once` rewrites device set to normalized entries: - `deviceId=plug_<normalized_uuid>` - `channel=0` - `capabilities=["switch"]` ## Command Interface ```bash node dist/cli.js <command> '<json-input>' ``` Supported commands: 1. `list-devices` 2. `get-state` 3. `set-device` 4. `discover-cloud-devices` 5. `setup-once` Core patterns: ```bash node dist/cli.js list-devices '{}' node dist/cli.js get-state '{"deviceId":"plug_abc"}' node dist/cli.js set-device '{"deviceId":"plug_abc","capability":"switch","value":"on","confirmation":{"userConfirmed":true,"deviceId":"plug_abc","capability":"switch","value":"on"}}' node dist/cli.js set-device '{"deviceId":"plug_abc","capability":"switch","value":"off","confirmation":{"userConfirmed":true,"deviceId":"plug_abc","capability":"switch","value":"off"}}' node dist/cli.js discover-cloud-devices '{}' node dist/cli.js setup-once '{}' ``` ## Delayed Actions For delayed switch commands: - Show exact `deviceId`, capability, value, and absolute user-timezone timestamp before scheduling. - Schedule only after explicit user confirmation. - Include the same `confirmation` object in the scheduled `set-device` payload. - Tell the user how to list and cancel the pending one-shot job before ending the turn. ## Error Contract - Success: JSON on `stdout` - Failure: JSON on `stderr`, non-zero exit - Relevant error codes: `DEVICE_NOT_FOUND`, `DEVICE_OFFLINE`, `AUTH_FAILED`, `MEROSS_API_ERROR`, `INVALID_INPUT`, `REGISTRY_ERROR`, `AMBIGUOUS_DEVICE`, `CONFIRMATION_REQUIRED`, `INTERNAL_ERROR`

path: README.md
content: # OpenClaw Meross Skill

Local OpenClaw skill for Meross cloud plugs (`switch`) via `meross-cloud`.

## Scope

- Controls Meross cloud devices with `switch` capability only.
- Supports: registry bootstrap, device listing, state read, switch on/off, cloud discovery.
- Uses local registry file `devices.json` in skill root.

## Prerequisites

- Node.js >= 18
- npm
- Meross cloud account

## Required Setup

Run in skill root:

```bash
npm install
npm run build
```

Set runtime environment:

```bash
export MEROSS_EMAIL='[REDACTED_SECRET]'
export MEROSS_PASSWORD='***'
export MEROSS_REGION='eu' # optional
```

Registry metadata may miss env/install hints. Treat setup above as mandatory.

## Quick Start

```bash
node dist/cli.js setup-once '{}'
node dist/cli.js list-devices '{}'
node dist/cli.js get-state '{"deviceId":"plug_abc"}'
node dist/cli.js set-device '{"deviceId":"plug_abc","capability":"switch","value":"off","confirmation":{"userConfirmed":true,"deviceId":"plug_abc","capability":"switch","value":"off"}}'
node dist/cli.js discover-cloud-devices '{}'
```

`set-device` fails unless the caller includes an explicit confirmation object that exactly matches the resolved target and requested switch value.

## `devices.json`

- Written by `setup-once`; discovered devices replace prior set.
- Contains device identifiers and aliases; keep file access controlled.
- `setup-once` writes registry data with owner-only permissions where the OS supports `chmod`.
- Never store account credentials in project files.

## CLI Contract

- Success: JSON on `stdout`
- Failure: JSON on `stderr`, exit code `1`
- Switch writes may fail with `CONFIRMATION_REQUIRED` until the exact target/action has user approval.

If source/dependency trust is unclear, use isolated runtime and test credentials.


path: _meta.json
content: ownerId: kn7e0nz92v9ckafd1sbcx7hzwd82hf5r
slug: meross
version: 1.0.27
publishedAt: 1773168032264

path: devices.json
content: {
  "_note": "REQUIRED: replace all example values before first use (deviceId should be plug_<normalized_uuid>, aliases, meross.uuid, channel).",
  "devices": [
    {
      "deviceId": "plug_REPLACE_DEVICE_ID",
      "aliases": ["REPLACE_ALIAS_1", "REPLACE_ALIAS_2"],
      "meross": {
        "uuid": "REPLACE_WITH_REAL_DEVICE_UUID",
        "channel": 0
      },
      "capabilities": ["switch"]
    }
  ]
}


path: dist/cli.js
content: "use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const logger_1 = require("./logger");
const merossClient_1 = require("./merossClient");
const registry_1 = require("./registry");
const types_1 = require("./types");
const VALID_COMMANDS = [
    'list-devices',
    'get-state',
    'set-device',
    'discover-cloud-devices',
    'setup-once'
];
const logger = (0, logger_1.createLogger)('cli', 'error');
function isCommand(value) {
    return VALID_COMMANDS.includes(value);
}
function parseJsonInput(raw) {
    try {
        return JSON.parse(raw);
    }
    catch (error) {
        throw new types_1.SkillError('INVALID_INPUT', 'Input must be valid JSON.', error);
    }
}
async function readStdinIfAvailable() {
    if (process.stdin.isTTY) {
        return undefined;
    }
    return new Promise((resolve, reject) => {
        let data = '';
        process.stdin.setEncoding('utf8');
        process.stdin.on('data', (chunk) => {
            data += chunk;
        });
        process.stdin.on('end', () => resolve(data));
        process.stdin.on('error', reject);
    });
}
function parseObjectInput(input, command) {
    if (!(0, types_1.isRecord)(input)) {
        throw new types_1.SkillError('INVALID_INPUT', `${command} payload must be a JSON object.`);
    }
    return input;
}
function parseDeviceId(input) {
    if (!(0, types_1.isRecord)(input) || typeof input.deviceId !== 'string') {
        throw new types_1.SkillError('INVALID_INPUT', "Input must contain string field 'deviceId'.");
    }
    const deviceId = (0, types_1.normalizeWhitespace)(input.deviceId);
    if (deviceId.length === 0) {
        throw new types_1.SkillError('INVALID_INPUT', "Field 'deviceId' cannot be empty.");
    }
    return deviceId;
}
function parseSwitchValue(value) {
    if (value === 'on' || value === 'off') {
        return value;
    }
    throw new types_1.SkillError('INVALID_INPUT', "Field 'value' must be 'on' or 'off'.");
}
function parseCapability(value) {
    if (value === 'switch') {
        return value;
    }
    throw new types_1.SkillError('INVALID_INPUT', "Field 'capability' must be 'switch'.");
}
function requireSwitchConfirmation(input, device, capability, value) {
    const expected = {
        userConfirmed: true,
        deviceId: device.deviceId,
        capability,
        value
    };
    if (!(0, types_1.isRecord)(input.confirmation)) {
        throw new types_1.SkillError('CONFIRMATION_REQUIRED', `set-device requires explicit user confirmation: ${JSON.stringify(expected)}.`);
    }
    if (input.confirmation.userConfirmed !== true ||
        input.confirmation.deviceId !== expected.deviceId ||
        input.confirmation.capability !== expected.capability ||
        input.confirmation.value !== expected.value) {
        throw new types_1.SkillError('CONFIRMATION_REQUIRED', `Confirmation must exactly match target/action: ${JSON.stringify(expected)}.`);
    }
}
function normalizeUuid(uuid) {
    const normalized = (0, types_1.normalizeWhitespace)(uuid).toLowerCase();
    if (!normalized) {
        throw new types_1.SkillError('MEROSS_API_ERROR', `Invalid Meross UUID '${uuid}'.`);
    }
    return normalized;
}
function uuidKey(uuid) {
    const compact = normalizeUuid(uuid).replace(/[^a-z0-9]/g, '');
    if (!compact) {
        throw new types_1.SkillError('MEROSS_API_ERROR', `Invalid Meross UUID '${uuid}'.`);
    }
    return compact;
}
function uniqueAliases(...sources) {
    const result = [];
    const seen = new Set();
    for (const source of sources) {
        for (const aliasRaw of source) {
            const alias = (0, types_1.normalizeWhitespace)(aliasRaw);
            if (!alias) {
                continue;
            }
            const key = alias.toLowerCase();
            if (seen.has(key)) {
                continue;
            }
            seen.add(key);
            result.push(alias);
        }
    }
    return result;
}
function sameDevice(a, b) {
    return JSON.stringify(a) === JSON.stringify(b);
}
async function parseInputPayload(rawArg) {
    if (rawArg && rawArg.trim().length > 0) {
        return parseJsonInput(rawArg);
    }
    const stdin = await readStdinIfAvailable();
    if (stdin && stdin.trim().length > 0) {
        return parseJsonInput(stdin);
    }
    return {};
}
function printSuccess(payload) {
    process.stdout.write(`${JSON.stringify(payload)}\n`);
}
function printErrorAndExit(error) {
    const payload = (0, types_1.toErrorPayload)(error);
    process.stderr.write(`${JSON.stringify(payload)}\n`);
    process.exit(1);
}
async function handleListDevices(client) {
    const devices = await (0, registry_1.readRegistryDevices)();
    let cloudMap = new Map();
    try {
        const cloudDevices = await client.discoverCloudDevices();
        cloudMap = new Map(cloudDevices.map((device) => [uuidKey(device.uuid), device.online]));
    }
    catch (error) {
        logger.info('Cloud discovery failed during list-devices; returning registry-only list.', {
            error: error instanceof Error ? error.message : String(error)
        });
    }
    return {
        devices: devices.map((device) => ({
            deviceId: device.deviceId,
            aliases: device.aliases,
            online: cloudMap.get(uuidKey(device.meross.uuid)) ?? false,
            capabilities: device.capabilities,
            meross: device.meross
        }))
    };
}
async function handleGetState(client, input) {
    const deviceId = parseDeviceId(input);
    const device = await (0, registry_1.getDeviceById)(deviceId);
    if (!device) {
        throw new types_1.SkillError('DEVICE_NOT_FOUND', `No device with deviceId '${deviceId}' found in registry.`);
    }
    if (!device.capabilities.includes('switch')) {
        throw new types_1.SkillError('INVALID_INPUT', `Device '${device.deviceId}' does not support switch capability.`);
    }
    const online = await client.getOnlineStatus(device.meross.uuid);
    if (!online) {
        throw new types_1.SkillError('DEVICE_OFFLINE', `Device '${device.deviceId}' is offline.`);
    }
    const state = await client.getSwitchState(device.meross.uuid, device.meross.channel);
    return {
        deviceId: device.deviceId,
        online,
        state
    };
}
async function handleSetDevice(client, input) {
    if (!(0, types_1.isRecord)(input)) {
        throw new types_1.SkillError('INVALID_INPUT', 'set-device payload must be an object.');
    }
    const deviceId = parseDeviceId(input);
    const capability = parseCapability(input.capability);
    const value = parseSwitchValue(input.value);
    const device = await (0, registry_1.getDeviceById)(deviceId);
    if (!device) {
        throw new types_1.SkillError('DEVICE_NOT_FOUND', `No device with deviceId '${deviceId}' found in registry.`);
    }
    if (!device.capabilities.includes(capability)) {
        throw new types_1.SkillError('INVALID_INPUT', `Device '${device.deviceId}' does not support capability '${capability}'.`);
    }
    requireSwitchConfirmation(input, device, capability, value);
    const online = await client.getOnlineStatus(device.meross.uuid);
    if (!online) {
        throw new types_1.SkillError('DEVICE_OFFLINE', `Device '${device.deviceId}' is offline.`);
    }
    const setResult = await client.setSwitchState(device.meross.uuid, device.meross.channel, value);
    const response = {
        ok: true,
        deviceId: device.deviceId,
        applied: {
            capability,
            value
        },
        at: new Date().toISOString(),
        verified: setResult.verified
    };
    if (!setResult.verified) {
        response.verification = setResult.verification;
    }
    return response;
}
async function handleDiscoverCloudDevices(client) {
    const devices = await client.discoverCloudDevices(true);
    return {
        devices: devices.map((device) => ({
            uuid: normalizeUuid(device.uuid),
            name: device.name,
            online: device.online
        }))
    };
}
async function handleSetupOnce(client, input) {
    parseObjectInput(input, 'setup-once');
    const [discovered, existing] = await Promise.all([
        client.discoverCloudDevices(true),
        (0, registry_1.readRegistryDevices)()
    ]);
    const existingByUuid = new Map();
    for (const device of existing) {
        existingByUuid.set(uuidKey(device.meross.uuid), device);
    }
    const counts = {
        discovered: discovered.length,
        written: 0,
        updated: 0,
        added: 0
    };
    const nextDevices = discovered.map((cloudDevice) => {
        const uuid = normalizeUuid(cloudDevice.uuid);
        const key = uuidKey(uuid);
        const existingDevice = existingByUuid.get(key);
        const nextDevice = {
            deviceId: `plug_${key}`,
            aliases: uniqueAliases(existingDevice?.aliases ?? [], cloudDevice.name ? [cloudDevice.name] : []),
            meross: {
                uuid,
                channel: 0
            },
            capabilities: ['switch']
        };
        if (!existingDevice) {
            counts.added += 1;
            return nextDevice;
        }
        if (!sameDevice(existingDevice, nextDevice)) {
            counts.updated += 1;
        }
        return nextDevice;
    });
    counts.written = nextDevices.length;
    await (0, registry_1.writeRegistryDevices)(nextDevices);
    return {
        ok: true,
        at: new Date().toISOString(),
        registryPath: (0, registry_1.getRegistryPathForDisplay)(),
        counts
    };
}
async function run() {
    const commandArg = process.argv[2];
    if (!commandArg || !isCommand(commandArg)) {
        throw new types_1.SkillError('INVALID_INPUT', `Unknown command. Use one of: ${VALID_COMMANDS.join(', ')}.`);
    }
    const payload = await parseInputPayload(process.argv[3]);
    const client = new merossClient_1.MerossClient();
    let result;
    try {
        if (commandArg === 'list-devices') {
            result = await handleListDevices(client);
        }
        else if (commandArg === 'get-state') {
            result = await handleGetState(client, payload);
        }
        else if (commandArg === 'set-device') {
            result = await handleSetDevice(client, payload);
        }
        else if (commandArg === 'discover-cloud-devices') {
            result = await handleDiscoverCloudDevices(client);
        }
        else if (commandArg === 'setup-once') {
            result = await handleSetupOnce(client, payload);
        }
        else {
            throw new types_1.SkillError('INVALID_INPUT', `Unsupported command '${commandArg}'.`);
        }
    }
    finally {
        await client.shutdown();
    }
    printSuccess(result);
}
run().catch((error) => {
    printErrorAndExit(error);
});
process.on('unhandledRejection', (error) => {
    printErrorAndExit(error);
});


path: dist/logger.js
content: "use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createLogger = createLogger;
const node_util_1 = require("node:util");
const LEVEL_ORDER = {
    error: 0,
    info: 1,
    debug: 2
};
function serializeMeta(meta) {
    if (meta === undefined) {
        return '';
    }
    return ` ${(0, node_util_1.inspect)(meta, { depth: 4, breakLength: 120 })}`;
}
function createLogger(scope, minLevel = 'error') {
    // minLevel is provided explicitly; no env lookups here.
    const log = (level, message, meta) => {
        if (LEVEL_ORDER[level] > LEVEL_ORDER[minLevel]) {
            return;
        }
        const stamp = new Date().toISOString();
        process.stderr.write(`[${stamp}] [${level}] [${scope}] ${message}${serializeMeta(meta)}\n`);
    };
    return {
        error(message, meta) {
            log('error', message, meta);
        },
        info(message, meta) {
            log('info', message, meta);
        },
        debug(message, meta) {
            log('debug', message, meta);
        }
    };
}


path: dist/merossClient.js
content: "use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MerossClient = exports.DEFAULT_REGISTRY_PATH = void 0;
const meross_cloud_1 = __importDefault(require("meross-cloud"));
const logger_1 = require("./logger");
const types_1 = require("./types");
const node_path_1 = require("node:path");
exports.DEFAULT_REGISTRY_PATH = (0, node_path_1.join)(__dirname, '..', 'devices.json');
function asNonEmptyString(value) {
    if (!value) {
        return undefined;
    }
    const trimmed = value.trim();
    return trimmed.length > 0 ? trimmed : undefined;
}
function extractErrorMessage(error) {
    if (error instanceof Error) {
        return error.message;
    }
    if (typeof error === 'string') {
        return error;
    }
    return 'Unknown error';
}
function getOnlineFromDefinition(definition) {
    return definition.onlineStatus === 1;
}
function parseOnOffFromEntry(entry) {
    if (!(0, types_1.isRecord)(entry)) {
        return undefined;
    }
    const onoff = entry.onoff;
    if (typeof onoff === 'number') {
        return onoff;
    }
    return undefined;
}
function parseSwitchFromPayload(payload, channel) {
    if (!(0, types_1.isRecord)(payload)) {
        throw new types_1.SkillError('MEROSS_API_ERROR', 'Invalid response payload for switch state.');
    }
    const root = (0, types_1.isRecord)(payload.all) ? payload.all : payload;
    const digest = (0, types_1.isRecord)(root.digest) ? root.digest : root;
    const togglex = digest.togglex;
    if (Array.isArray(togglex)) {
        const byChannel = togglex.find((entry) => (0, types_1.isRecord)(entry) && entry.channel === channel);
        const exact = parseOnOffFromEntry(byChannel);
        if (exact !== undefined) {
            return exact === 1 ? 'on' : 'off';
        }
        const first = parseOnOffFromEntry(togglex[0]);
        if (first !== undefined) {
            return first === 1 ? 'on' : 'off';
        }
    }
    const singleToggleX = parseOnOffFromEntry(togglex);
    if (singleToggleX !== undefined) {
        return singleToggleX === 1 ? 'on' : 'off';
    }
    const toggle = parseOnOffFromEntry(digest.toggle);
    if (toggle !== undefined) {
        return toggle === 1 ? 'on' : 'off';
    }
    throw new types_1.SkillError('MEROSS_API_ERROR', 'No switch state found in Meross response payload.');
}
function getRawMessageNamespace(message) {
    if (!(0, types_1.isRecord)(message)) {
        return undefined;
    }
    const raw = message;
    if (!(0, types_1.isRecord)(raw.header) || typeof raw.header.namespace !== 'string') {
        return undefined;
    }
    return raw.header.namespace;
}
function getRawMessagePayload(message) {
    if (!(0, types_1.isRecord)(message)) {
        return message;
    }
    if (Object.prototype.hasOwnProperty.call(message, 'payload')) {
        return message.payload;
    }
    return message;
}
class MerossClient {
    constructor(logger = (0, logger_1.createLogger)('meross-client', MerossClient.DEFAULT_LOG_LEVEL)) {
        this.cloud = null;
        this.connectPromise = null;
        this.connected = false;
        this.shuttingDown = false;
        this.definitions = new Map();
        this.discoveryCache = null;
        this.deviceLocks = new Map();
        this.logger = logger;
        this.cacheTtlMs = MerossClient.DEFAULT_CACHE_TTL_MS;
        this.timeoutMs = MerossClient.DEFAULT_TIMEOUT_MS;
        this.region = asNonEmptyString(process.env.MEROSS_REGION);
    }
    getCloudOptions() {
        const email = asNonEmptyString(process.env.MEROSS_EMAIL);
        const [REDACTED_SECRET]);
        if (!email || !password) {
            throw new types_1.SkillError('AUTH_FAILED', 'Missing Meross credentials. Set MEROSS_EMAIL and MEROSS_PASSWORD.');
        }
        return {
            email,
            password,
            timeout: this.timeoutMs,
            logger: (message) => this.logger.debug(String(message))
        };
    }
    async shutdown() {
        if (!this.cloud) {
            return;
        }
        const toClose = this.cloud;
        this.shuttingDown = true;
        this.cloud = null;
        this.connected = false;
        this.discoveryCache = null;
        this.definitions.clear();
        try {
            if (typeof toClose.disconnectAll === 'function') {
                // Force close to avoid long-lived MQTT handles keeping the CLI process alive.
                toClose.disconnectAll(true);
            }
            await Promise.race([
                new Promise((resolve) => {
                    try {
                        toClose.logout(() => resolve());
                    }
                    catch {
                        resolve();
                    }
                }),
                new Promise((resolve) => {
                    setTimeout(resolve, MerossClient.SHUTDOWN_TIMEOUT_MS);
                })
            ]);
        }
        finally {
            this.shuttingDown = false;
        }
    }
    isExpectedDisconnectError(error) {
        const message = extractErrorMessage(error).toLowerCase();
        return (message.includes('client disconnecting') ||
            message.includes('client disconnected') ||
            message.includes('connection closed'));
    }
    createCloudInstance() {
        const cloud = new meross_cloud_1.default(this.getCloudOptions());
        if (this.region) {
            this.logger.debug('MEROSS_REGION configured (library decides final region via API redirect).', {
                region: this.region
            });
        }
        cloud.on('deviceInitialized', (_deviceId, definition) => {
            this.definitions.set(definition.uuid, definition);
        });
        cloud.on('error', (error, deviceId) => {
            if (this.isExpectedDisconnectError(error)) {
                this.logger.debug('Ignoring expected Meross disconnect error.', {
                    deviceId,
                    error: String(error)
                });
                return;
            }
            this.logger.error('Meross runtime error', { deviceId, error: String(error) });
        });
        return cloud;
    }
    withTimeout(promise, timeoutMs, operation) {
        return new Promise((resolve, reject) => {
            const timer = setTimeout(() => {
                reject(new types_1.SkillError('MEROSS_API_ERROR', `${operation} timed out after ${timeoutMs}ms.`));
            }, timeoutMs);
            promise
                .then((value) => {
                clearTimeout(timer);
                resolve(value);
            })
                .catch((error) => {
                clearTimeout(timer);
                reject(error);
            });
        });
    }
    async ensureConnected(forceReconnect = false) {
        if (forceReconnect) {
            this.connected = false;
            this.cloud = null;
            this.definitions.clear();
            this.discoveryCache = null;
        }
        if (this.connected && this.cloud) {
            return;
        }
        if (this.connectPromise) {
            return this.connectPromise;
        }
        this.connectPromise = (async () => {
            if (!this.cloud) {
                this.cloud = this.createCloudInstance();
            }
            await this.withTimeout(new Promise((resolve, reject) => {
                this.cloud?.connect((error) => {
                    if (error) {
                        reject(error);
                        return;
                    }
                    resolve();
                });
            }), this.timeoutMs * 3, 'Meross connect');
            this.connected = true;
            this.discoveryCache = null;
        })();
        try {
            await this.connectPromise;
        }
        finally {
            this.connectPromise = null;
        }
    }
    isAuthError(error) {
        const message = extractErrorMessage(error).toLowerCase();
        return (message.includes('token') ||
            message.includes('auth') ||
            message.includes('email missing') ||
            message.includes('password missing') ||
            message.includes('login'));
    }
    mapMerossError(error, fallbackMessage) {
        if (error instanceof types_1.SkillError) {
            return error;
        }
        const message = extractErrorMessage(error);
        if (message.toLowerCase().includes('no data connection')) {
            return new types_1.SkillError('DEVICE_OFFLINE', 'Device is offline or not reachable.', error);
        }
        if (this.isAuthError(error)) {
            return new types_1.SkillError('AUTH_FAILED', `Meross authentication failed: ${message}`, error);
        }
        return new types_1.SkillError('MEROSS_API_ERROR', `${fallbackMessage}: ${message}`, error);
    }
    async withAuthRetry(operation) {
        try {
            return await operation();
        }
        catch (error) {
            if (!this.isAuthError(error)) {
                throw error;
            }
            this.logger.info('Auth error detected, reconnecting once.');
            await this.ensureConnected(true);
            return operation();
        }
    }
    async runWithDeviceLock(uuid, operation) {
        const previous = this.deviceLocks.get(uuid) ?? Promise.resolve();
        const next = previous.catch(() => undefined).then(operation);
        this.deviceLocks.set(uuid, next);
        try {
            return await next;
        }
        finally {
            if (this.deviceLocks.get(uuid) === next) {
                this.deviceLocks.delete(uuid);
            }
        }
    }
    getCloudDevice(uuid) {
        if (!this.cloud) {
            throw new types_1.SkillError('INTERNAL_ERROR', 'Meross cloud connection is not initialized.');
        }
        const device = this.cloud.getDevice(uuid);
        if (!device) {
            throw new types_1.SkillError('DEVICE_NOT_FOUND', `Meross cloud device '${uuid}' was not found.`);
        }
        return device;
    }
    async dispatchSwitchCommand(uuid, channel, value) {
        await this.ensureConnected();
        const device = this.getCloudDevice(uuid);
        const onoff = value === 'on';
        try {
            // Do not provide callback: meross-cloud then does not await MQTT ACK.
            device.controlToggleX(channel, onoff);
            return;
        }
        catch (error) {
            if (channel !== 0) {
                throw error;
            }
        }
        device.controlToggle(onoff);
    }
    async sleep(delayMs) {
        await new Promise((resolve) => {
            setTimeout(resolve, delayMs);
        });
    }
    async deviceCall(uuid, operationName, call, timeoutMs = this.timeoutMs * 2, rawFallbackNamespace) {
        await this.ensureConnected();
        const device = this.getCloudDevice(uuid);
        const trackingDevice = device;
        return new Promise((resolve, reject) => {
            let settled = false;
            let messageId;
            const cleanupPendingAck = () => {
                if (!messageId || !trackingDevice.waitingMessageIds) {
                    return;
                }
                const pending = trackingDevice.waitingMessageIds[messageId];
                if (!pending) {
                    return;
                }
                if (pending.timeout) {
                    clearTimeout(pending.timeout);
                }
                delete trackingDevice.waitingMessageIds[messageId];
            };
            const cleanupRawListener = () => {
                if (!rawFallbackNamespace) {
                    return;
                }
                device.removeListener('rawData', onRawData);
            };
            const settleResolve = (value) => {
                if (settled) {
                    return;
                }
                settled = true;
                clearTimeout(timeout);
                cleanupPendingAck();
                cleanupRawListener();
                resolve(value);
            };
            const settleReject = (error) => {
                if (settled) {
                    return;
                }
                settled = true;
                clearTimeout(timeout);
                cleanupPendingAck();
                cleanupRawListener();
                reject(error);
            };
            const onRawData = (rawMessage) => {
                if (!rawFallbackNamespace || settled) {
                    return;
                }
                const namespace = getRawMessageNamespace(rawMessage);
                if (namespace !== rawFallbackNamespace) {
                    return;
                }
                settleResolve(getRawMessagePayload(rawMessage));
            };
            const timeout = setTimeout(() => {
                settleReject(new types_1.SkillError('MEROSS_API_ERROR', `${operationName} timed out after ${timeoutMs}ms.`));
            }, timeoutMs);
            if (rawFallbackNamespace) {
                device.on('rawData', onRawData);
            }
            try {
                const returnedMessageId = call(device, (error, data) => {
                    if (error) {
                        settleReject(error);
                        return;
                    }
                    settleResolve(data);
                });
                if (typeof returnedMessageId === 'string') {
                    messageId = returnedMessageId;
                }
            }
            catch (error) {
                settleReject(error);
            }
        });
    }
    async readSwitchStateOnce(uuid, channel, timeoutMs = this.timeoutMs * 2) {
        const readAttempts = [
            {
                operationName: `getSystemAllData(${uuid})#warmup`,
                rawFallbackNamespace: 'Appliance.System.All',
                call: (device, callback) => device.getSystemAllData(callback)
            },
            {
                operationName: `getSystemAllData(${uuid})#retry`,
                rawFallbackNamespace: 'Appliance.System.All',
                call: (device, callback) => device.getSystemAllData(callback)
            },
            {
                operationName: `getControlToggleX(${uuid},channel=${channel})`,
                rawFallbackNamespace: 'Appliance.Control.ToggleX',
                call: (device, callback) => device.publishMessage('GET', 'Appliance.Control.ToggleX', {
                    togglex: [{ channel }]
                }, callback)
            },
            {
                operationName: `getControlToggleX(${uuid})`,
                rawFallbackNamespace: 'Appliance.Control.ToggleX',
                call: (device, callback) => device.publishMessage('GET', 'Appliance.Control.ToggleX', {}, callback)
            }
        ];
        if (channel === 0) {
            readAttempts.push({
                operationName: `getControlToggle(${uuid})`,
                rawFallbackNamespace: 'Appliance.Control.Toggle',
                call: (device, callback) => device.publishMessage('GET', 'Appliance.Control.Toggle', {}, callback)
            });
        }
        const deadline = Date.now() + timeoutMs;
        let lastError;
        for (const attempt of readAttempts) {
            const remainingMs = deadline - Date.now();
            if (remainingMs < MerossClient.MIN_STATE_READ_ATTEMPT_TIMEOUT_MS) {
                break;
            }
            const attemptTimeoutMs = Math.max(MerossClient.MIN_STATE_READ_ATTEMPT_TIMEOUT_MS, Math.min(remainingMs, MerossClient.MAX_STATE_READ_ATTEMPT_TIMEOUT_MS));
            try {
                const payload = await this.deviceCall(uuid, attempt.operationName, attempt.call, attemptTimeoutMs, attempt.rawFallbackNamespace);
                return {
                    switch: parseSwitchFromPayload(payload, channel),
                    lastUpdated: new Date().toISOString()
                };
            }
            catch (error) {
                lastError = error;
            }
        }
        if (lastError) {
            throw lastError;
        }
        throw new types_1.SkillError('MEROSS_API_ERROR', `Failed to read switch state for '${uuid}' within ${timeoutMs}ms.`);
    }
    async verifySwitchState(uuid, channel, expected) {
        let lastObserved;
        let lastError;
        for (let attempt = 1; attempt <= MerossClient.SET_VERIFY_ATTEMPTS; attempt += 1) {
            try {
                const state = await this.withAuthRetry(() => this.readSwitchStateOnce(uuid, channel, MerossClient.SET_VERIFY_READ_TIMEOUT_MS));
                lastObserved = state.switch;
                if (state.switch === expected) {
                    return {
                        verified: true,
                        verification: {
                            attempts: attempt,
                            observed: state.switch
                        }
                    };
                }
            }
            catch (error) {
                lastError = error;
            }
            if (attempt < MerossClient.SET_VERIFY_ATTEMPTS) {
                await this.sleep(MerossClient.SET_VERIFY_DELAY_MS);
            }
        }
        return {
            verified: false,
            verification: {
                attempts: MerossClient.SET_VERIFY_ATTEMPTS,
                observed: lastObserved,
                error: lastError ? extractErrorMessage(lastError) : undefined
            }
        };
    }
    collectDefinitions() {
        if (this.definitions.size > 0) {
            return Array.from(this.definitions.values());
        }
        if (!this.cloud) {
            return [];
        }
        const runtime = this.cloud;
        const fromRuntime = [];
        if (!runtime.devices) {
            return fromRuntime;
        }
        for (const value of Object.values(runtime.devices)) {
            if (value.dev) {
                fromRuntime.push(value.dev);
            }
        }
        return fromRuntime;
    }
    async discoverCloudDevices(forceRefresh = false) {
        return this.withAuthRetry(async () => {
            if (!forceRefresh && this.discoveryCache && this.discoveryCache.expiresAt > Date.now()) {
                return this.discoveryCache.devices;
            }
            await this.ensureConnected();
            const devices = this.collectDefinitions().map((definition) => ({
                uuid: definition.uuid,
                name: definition.devName || definition.uuid,
                online: getOnlineFromDefinition(definition)
            }));
            devices.sort((a, b) => a.name.localeCompare(b.name));
            this.discoveryCache = {
                expiresAt: Date.now() + this.cacheTtlMs,
                devices
            };
            return devices;
        }).catch((error) => {
            throw this.mapMerossError(error, 'Failed to discover cloud devices');
        });
    }
    async getOnlineStatus(uuid) {
        const devices = await this.discoverCloudDevices();
        const cloudDevice = devices.find((device) => device.uuid === uuid);
        if (!cloudDevice) {
            throw new types_1.SkillError('DEVICE_NOT_FOUND', `Meross cloud device '${uuid}' was not found.`);
        }
        return cloudDevice.online;
    }
    async getSwitchState(uuid, channel) {
        return this.runWithDeviceLock(uuid, async () => {
            try {
                return await this.withAuthRetry(() => this.readSwitchStateOnce(uuid, channel));
            }
            catch (error) {
                throw this.mapMerossError(error, `Failed to read switch state for '${uuid}'`);
            }
        });
    }
    async setSwitchState(uuid, channel, value) {
        return this.runWithDeviceLock(uuid, async () => {
            try {
                await this.withAuthRetry(() => this.dispatchSwitchCommand(uuid, channel, value));
                return await this.verifySwitchState(uuid, channel, value);
            }
            catch (error) {
                throw this.mapMerossError(error, `Failed to set switch state for '${uuid}'`);
            }
        });
    }
}
exports.MerossClient = MerossClient;
MerossClient.DEFAULT_CACHE_TTL_MS = 30 * 1000;
MerossClient.DEFAULT_TIMEOUT_MS = 10000;
MerossClient.DEFAULT_LOG_LEVEL = 'error';
MerossClient.SHUTDOWN_TIMEOUT_MS = 2000;
MerossClient.SET_VERIFY_ATTEMPTS = 3;
MerossClient.SET_VERIFY_DELAY_MS = 400;
MerossClient.SET_VERIFY_READ_TIMEOUT_MS = 2500;
MerossClient.MIN_STATE_READ_ATTEMPT_TIMEOUT_MS = 800;
MerossClient.MAX_STATE_READ_ATTEMPT_TIMEOUT_MS = 3500;


path: dist/registry.js
content: "use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeAlias = normalizeAlias;
exports.findDevicesByAlias = findDevicesByAlias;
exports.resolveDeviceByAlias = resolveDeviceByAlias;
exports.readRegistryDevices = readRegistryDevices;
exports.getDeviceById = getDeviceById;
exports.writeRegistryDevices = writeRegistryDevices;
exports.getRegistryPathForDisplay = getRegistryPathForDisplay;
const promises_1 = require("node:fs/promises");
const node_path_1 = require("node:path");
const types_1 = require("./types");
const merossClient_1 = require("./merossClient");
function uniqueStrings(values) {
    const result = [];
    const seen = new Set();
    for (const raw of values) {
        const clean = (0, types_1.normalizeWhitespace)(raw);
        if (clean.length === 0) {
            continue;
        }
        const key = clean.toLowerCase();
        if (seen.has(key)) {
            continue;
        }
        seen.add(key);
        result.push(clean);
    }
    return result;
}
function normalizeCapabilities(capabilities) {
    if (!Array.isArray(capabilities)) {
        return ['switch'];
    }
    const filtered = capabilities
        .map((value) => String(value).trim().toLowerCase())
        .filter((value) => value === 'switch');
    return filtered.length > 0 ? ['switch'] : ['switch'];
}
function sanitizeDevice(raw) {
    if (!(0, types_1.isRecord)(raw)) {
        throw new types_1.SkillError('REGISTRY_ERROR', 'Registry contains an invalid device entry.');
    }
    const deviceIdRaw = raw.deviceId;
    if (typeof deviceIdRaw !== 'string' || (0, types_1.normalizeWhitespace)(deviceIdRaw).length === 0) {
        throw new types_1.SkillError('REGISTRY_ERROR', 'Registry device is missing a valid deviceId.');
    }
    const deviceId = (0, types_1.normalizeWhitespace)(deviceIdRaw);
    const aliasesRaw = Array.isArray(raw.aliases) ? raw.aliases.map((value) => String(value)) : [];
    const aliases = uniqueStrings(aliasesRaw);
    if (!(0, types_1.isRecord)(raw.meross)) {
        throw new types_1.SkillError('REGISTRY_ERROR', `Registry device '${deviceId}' is missing meross binding.`);
    }
    const uuidRaw = raw.meross.uuid;
    const channelRaw = raw.meross.channel;
    if (typeof uuidRaw !== 'string' || (0, types_1.normalizeWhitespace)(uuidRaw).length === 0) {
        throw new types_1.SkillError('REGISTRY_ERROR', `Registry device '${deviceId}' has invalid meross.uuid.`);
    }
    const channelNumber = typeof channelRaw === 'number' ? channelRaw : Number(channelRaw);
    if (!Number.isInteger(channelNumber) || channelNumber < 0) {
        throw new types_1.SkillError('REGISTRY_ERROR', `Registry device '${deviceId}' has invalid meross.channel.`);
    }
    return {
        deviceId,
        aliases,
        meross: {
            uuid: (0, types_1.normalizeWhitespace)(uuidRaw),
            channel: channelNumber
        },
        capabilities: normalizeCapabilities(raw.capabilities)
    };
}
function sanitizeRegistry(raw) {
    if (!(0, types_1.isRecord)(raw)) {
        throw new types_1.SkillError('REGISTRY_ERROR', 'Registry root must be an object.');
    }
    const rawDevices = raw.devices;
    if (!Array.isArray(rawDevices)) {
        return { devices: [] };
    }
    const devices = rawDevices.map((device) => sanitizeDevice(device));
    const seenDeviceIds = new Set();
    for (const device of devices) {
        const key = device.deviceId.toLowerCase();
        if (seenDeviceIds.has(key)) {
            throw new types_1.SkillError('REGISTRY_ERROR', `Duplicate deviceId '${device.deviceId}' in registry.`);
        }
        seenDeviceIds.add(key);
    }
    return { devices };
}
async function ensureRegistryFile(path) {
    await (0, promises_1.mkdir)((0, node_path_1.dirname)(path), { recursive: true });
    try {
        await (0, promises_1.readFile)(path, 'utf8');
    }
    catch {
        await (0, promises_1.writeFile)(path, JSON.stringify({ devices: [] }, null, 2), { encoding: 'utf8', mode: 0o600 });
    }
    try {
        await (0, promises_1.chmod)(path, 0o600);
    }
    catch {
        // Best-effort only; chmod is not reliable on every filesystem.
    }
}
async function writeRegistry(path, data) {
    const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`;
    const json = `${JSON.stringify(data, null, 2)}\n`;
    await (0, promises_1.writeFile)(tmpPath, json, { encoding: 'utf8', mode: 0o600 });
    await (0, promises_1.rename)(tmpPath, path);
    try {
        await (0, promises_1.chmod)(path, 0o600);
    }
    catch {
        // Best-effort only; chmod is not reliable on every filesystem.
    }
}
function normalizeAlias(alias) {
    return (0, types_1.normalizeWhitespace)(alias).toLowerCase();
}
function findDevicesByAlias(devices, alias) {
    const normalized = normalizeAlias(alias);
    if (!normalized) {
        return [];
    }
    return devices.filter((device) => {
        return device.aliases.some((deviceAlias) => normalizeAlias(deviceAlias) === normalized);
    });
}
function resolveDeviceByAlias(devices, aliasOrId, allowUniqueFuzzy = false) {
    const token = (0, types_1.normalizeWhitespace)(aliasOrId);
    if (token.length === 0) {
        return undefined;
    }
    const direct = devices.find((device) => device.deviceId.toLowerCase() === token.toLowerCase());
    if (direct) {
        return direct;
    }
    const exactAliasMatches = findDevicesByAlias(devices, token);
    if (exactAliasMatches.length === 1) {
        return exactAliasMatches[0];
    }
    if (exactAliasMatches.length > 1) {
        throw new types_1.SkillError('AMBIGUOUS_DEVICE', `Alias '${token}' matches multiple devices.`);
    }
    if (!allowUniqueFuzzy) {
        return undefined;
    }
    const normalizedToken = normalizeAlias(token);
    const fuzzyMatches = devices.filter((device) => device.aliases.some((alias) => normalizeAlias(alias).includes(normalizedToken)));
    if (fuzzyMatches.length === 1) {
        return fuzzyMatches[0];
    }
    if (fuzzyMatches.length > 1) {
        throw new types_1.SkillError('AMBIGUOUS_DEVICE', `Alias '${token}' fuzzy-matches multiple devices.`);
    }
    return undefined;
}
async function readRegistryDevices() {
    const registryPath = merossClient_1.DEFAULT_REGISTRY_PATH;
    try {
        await ensureRegistryFile(registryPath);
        const raw = await (0, promises_1.readFile)(registryPath, 'utf8');
        const parsed = JSON.parse(raw);
        const registry = sanitizeRegistry(parsed);
        return registry.devices;
    }
    catch (error) {
        if (error instanceof types_1.SkillError) {
            throw error;
        }
        throw new types_1.SkillError('REGISTRY_ERROR', `Failed to read registry '${registryPath}'.`, error);
    }
}
async function getDeviceById(deviceId) {
    const normalized = (0, types_1.normalizeWhitespace)(deviceId);
    const devices = await readRegistryDevices();
    return devices.find((device) => device.deviceId.toLowerCase() === normalized.toLowerCase());
}
async function writeRegistryDevices(devices) {
    const registryPath = merossClient_1.DEFAULT_REGISTRY_PATH;
    try {
        await ensureRegistryFile(registryPath);
        const next = sanitizeRegistry({ devices });
        next.devices.sort((a, b) => a.deviceId.localeCompare(b.deviceId));
        await writeRegistry(registryPath, next);
    }
    catch (error) {
        if (error instanceof types_1.SkillError) {
            throw error;
        }
        throw new types_1.SkillError('REGISTRY_ERROR', `Failed to write registry '${registryPath}'.`, error);
    }
}
function getRegistryPathForDisplay() {
    return merossClient_1.DEFAULT_REGISTRY_PATH;
}


path: dist/types.js
content: "use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SkillError = void 0;
exports.isRecord = isRecord;
exports.normalizeWhitespace = normalizeWhitespace;
exports.toErrorPayload = toErrorPayload;
class SkillError extends Error {
    constructor(code, message, cause = undefined) {
        super(message);
        this.code = code;
        this.cause = cause;
        this.name = 'SkillError';
    }
}
exports.SkillError = SkillError;
function isRecord(value) {
    return typeof value === 'object' && value !== null;
}
function normalizeWhitespace(value) {
    return value.trim().replace(/\s+/g, ' ');
}
function toErrorPayload(error) {
    if (error instanceof SkillError) {
        return {
            ok: false,
            error: {
                code: error.code,
                message: error.message
            }
        };
    }
    if (error instanceof Error) {
        return {
            ok: false,
            error: {
                code: 'INTERNAL_ERROR',
                message: error.message
            }
        };
    }
    return {
        ok: false,
        error: {
            code: 'INTERNAL_ERROR',
            message: 'Unknown internal error.'
        }
    };
}


path: npm-shrinkwrap.json
content: {
  "name": "openclaw-skill-meross",
  "version": "1.0.27",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "openclaw-skill-meross",
      "version": "1.0.27",
      "license": "MIT-0",
      "dependencies": {
        "meross-cloud": "3.1.2"
      },
      "devDependencies": {
        "@types/node": "22.14.0",
        "typescript": "5.8.2"
      },
      "engines": {
        "node": ">=18"
      }
    },
    "node_modules/@babel/runtime": {
      "version": "7.29.2",
      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=6.9.0"
      }
    },
    "node_modules/@types/node": {
      "version": "22.14.0",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "undici-types": "~6.21.0"
      }
    },
    "node_modules/@types/readable-stream": {
      "version": "4.0.23",
      "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.23.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/@types/ws": {
      "version": "8.18.1",
      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/abort-controller": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "event-target-shim": "^5.0.0"
      },
      "engines": {
        "node": ">=6.5"
      }
    },
    "node_modules/ajv": {
      "version": "6.15.0",
      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "fast-deep-equal": "^3.1.1",
        "fast-json-stable-stringify": "^2.0.0",
        "json-schema-traverse": "^0.4.1",
        "uri-js": "^4.2.2"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/epoberezkin"
      }
    },
    "node_modules/asn1": {
      "version": "0.2.6",
      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "safer-buffer": "~2.1.0"
      }
    },
    "node_modules/assert-plus": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=0.8"
      }
    },
    "node_modules/asynckit": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/aws-sign2": {
      "version": "0.7.0",
      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "engines": {
        "node": "*"
      }
    },
    "node_modules/aws4": {
      "version": "1.13.2",
      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/base64-js": {
      "version": "1.5.1",
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/bcrypt-pbkdf": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause",
      "dependencies": {
        "tweetnacl": "^0.14.3"
      }
    },
    "node_modules/bl": {
      "version": "6.1.6",
      "resolved": "https://registry.npmjs.org/bl/-/bl-6.1.6.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/readable-stream": "^4.0.0",
        "buffer": "^6.0.3",
        "inherits": "^2.0.4",
        "readable-stream": "^4.2.0"
      }
    },
    "node_modules/broker-factory": {
      "version": "3.1.14",
      "resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.14.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.29.2",
        "fast-unique-numbers": "^9.0.27",
        "tslib": "^2.8.1",
        "worker-factory": "^7.0.49"
      }
    },
    "node_modules/buffer": {
      "version": "6.0.3",
      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT",
      "dependencies": {
        "base64-js": "^1.3.1",
        "ieee754": "^1.2.1"
      }
    },
    "node_modules/buffer-from": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/call-bind-apply-helpers": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/call-bound": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.2",
        "get-intrinsic": "^1.3.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/caseless": {
      "version": "0.12.0",
      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0"
    },
    "node_modules/combined-stream": {
      "version": "1.0.8",
      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "delayed-stream": "~1.0.0"
      },
      "engines": {
        "node": ">= 0.8"
      }
    },
    "node_modules/commist": {
      "version": "3.2.0",
      "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/concat-stream": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "engines": [
        "node >= 6.0"
      ],
      "license": "MIT",
      "dependencies": {
        "buffer-from": "^1.0.0",
        "inherits": "^2.0.3",
        "readable-stream": "^3.0.2",
        "typedarray": "^0.0.6"
      }
    },
    "node_modules/concat-stream/node_modules/readable-stream": {
      "version": "3.6.2",
      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "inherits": "^2.0.3",
        "string_decoder": "^1.1.1",
        "util-deprecate": "^1.0.1"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/core-util-is": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/dashdash": {
      "version": "1.14.1",
      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "assert-plus": "^1.0.0"
      },
      "engines": {
        "node": ">=0.10"
      }
    },
    "node_modules/debug": {
      "version": "4.4.3",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ms": "^2.1.3"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/delayed-stream": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/dunder-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.1",
        "es-errors": "^1.3.0",
        "gopd": "^1.2.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/ecc-jsbn": {
      "version": "0.1.2",
      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "jsbn": "~0.1.0",
        "safer-buffer": "^2.1.0"
      }
    },
    "node_modules/es-define-property": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-errors": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-object-atoms": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-set-tostringtag": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.6",
        "has-tostringtag": "^1.0.2",
        "hasown": "^2.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/event-target-shim": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/events": {
      "version": "3.3.0",
      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=0.8.x"
      }
    },
    "node_modules/extend": {
      "version": "3.0.2",
      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/extsprintf": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "engines": [
        "node >=0.6.0"
      ],
      "license": "MIT"
    },
    "node_modules/fast-deep-equal": {
      "version": "3.1.3",
      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/fast-json-stable-stringify": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/fast-unique-numbers": {
      "version": "9.0.27",
      "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.27.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.29.2",
        "tslib": "^2.8.1"
      },
      "engines": {
        "node": ">=18.2.0"
      }
    },
    "node_modules/forever-agent": {
      "version": "0.6.1",
      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "engines": {
        "node": "*"
      }
    },
    "node_modules/form-data": {
      "version": "2.5.5",
      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "asynckit": "^0.4.0",
        "combined-stream": "^1.0.8",
        "es-set-tostringtag": "^2.1.0",
        "hasown": "^2.0.2",
        "mime-types": "^2.1.35",
        "safe-buffer": "^5.2.1"
      },
      "engines": {
        "node": ">= 0.12"
      }
    },
    "node_modules/function-bind": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-intrinsic": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bind-apply-helpers": "^1.0.2",
        "es-define-property": "^1.0.1",
        "es-errors": "^1.3.0",
        "es-object-atoms": "^1.1.1",
        "function-bind": "^1.1.2",
        "get-proto": "^1.0.1",
        "gopd": "^1.2.0",
        "has-symbols": "^1.1.0",
        "hasown": "^2.0.2",
        "math-intrinsics": "^1.1.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "dunder-proto": "^1.0.1",
        "es-object-atoms": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/getpass": {
      "version": "0.1.7",
      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "assert-plus": "^1.0.0"
      }
    },
    "node_modules/gopd": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/har-schema": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/har-validator": {
      "version": "5.1.5",
      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
      "integrity": [REDACTED_SECRET],
      "deprecated": "this library is no longer supported",
      "license": "MIT",
      "dependencies": {
        "ajv": "^6.12.3",
        "har-schema": "^2.0.0"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/has-symbols": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-tostringtag": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "has-symbols": "^1.0.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/hasown": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "function-bind": "^1.1.2"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/help-me": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/http-signature": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "assert-plus": "^1.0.0",
        "jsprim": "^1.2.2",
        "sshpk": "^1.7.0"
      },
      "engines": {
        "node": ">=0.8",
        "npm": ">=1.3.7"
      }
    },
    "node_modules/ieee754": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "BSD-3-Clause"
    },
    "node_modules/inherits": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/ip-address": {
      "version": "10.2.0",
      "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 12"
      }
    },
    "node_modules/is-typedarray": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/isstream": {
      "version": "0.1.2",
      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/js-sdsl": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/js-sdsl"
      }
    },
    "node_modules/jsbn": {
      "version": "0.1.1",
      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/json-schema": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "(AFL-2.1 OR BSD-3-Clause)"
    },
    "node_modules/json-schema-traverse": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/json-stringify-safe": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/jsprim": {
      "version": "1.4.2",
      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "assert-plus": "1.0.0",
        "extsprintf": "1.3.0",
        "json-schema": "0.4.0",
        "verror": "1.10.0"
      },
      "engines": {
        "node": ">=0.6.0"
      }
    },
    "node_modules/lru-cache": {
      "version": "10.4.3",
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC"
    },
    "node_modules/math-intrinsics": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/meross-cloud": {
      "version": "3.1.2",
      "resolved": "https://registry.npmjs.org/meross-cloud/-/meross-cloud-3.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "mqtt": "^5.3.4",
        "request": "^2.88.2",
        "uuid": "^9.0.1"
      },
      "engines": {
        "node": ">=16"
      }
    },
    "node_modules/mime-db": {
      "version": "1.52.0",
      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/mime-types": {
      "version": "2.1.35",
      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "mime-db": "1.52.0"
      },
      "engines": {
        "node": ">= 0.6"
      }
    },
    "node_modules/minimist": {
      "version": "1.2.8",
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/mqtt": {
      "version": "5.15.1",
      "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.15.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@types/readable-stream": "^4.0.21",
        "@types/ws": "^8.18.1",
        "commist": "^3.2.0",
        "concat-stream": "^2.0.0",
        "debug": "^4.4.1",
        "help-me": "^5.0.0",
        "lru-cache": "^10.4.3",
        "minimist": "^1.2.8",
        "mqtt-packet": "^9.0.2",
        "number-allocator": "^1.0.14",
        "readable-stream": "^4.7.0",
        "rfdc": "^1.4.1",
        "socks": "^2.8.6",
        "split2": "^4.2.0",
        "worker-timers": "^8.0.23",
        "ws": "^8.18.3"
      },
      "bin": {
        "mqtt": "build/bin/mqtt.js",
        "mqtt_pub": "build/bin/pub.js",
        "mqtt_sub": "build/bin/sub.js"
      },
      "engines": {
        "node": ">=16.0.0"
      }
    },
    "node_modules/mqtt-packet": {
      "version": "9.0.2",
      "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "bl": "^6.0.8",
        "debug": "^4.3.4",
        "process-nextick-args": "^2.0.1"
      }
    },
    "node_modules/ms": {
      "version": "2.1.3",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/number-allocator": {
      "version": "1.0.14",
      "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "debug": "^4.3.1",
        "js-sdsl": "4.3.0"
      }
    },
    "node_modules/oauth-sign": {
      "version": "0.9.0",
      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "engines": {
        "node": "*"
      }
    },
    "node_modules/object-inspect": {
      "version": "1.13.4",
      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/performance-now": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/process": {
      "version": "0.11.10",
      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 0.6.0"
      }
    },
    "node_modules/process-nextick-args": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/psl": {
      "version": "1.15.0",
      "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "punycode": "^2.3.1"
      },
      "funding": {
        "url": "https://github.com/sponsors/lupomontero"
      }
    },
    "node_modules/punycode": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/qs": {
      "version": "6.15.1",
      "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause",
      "dependencies": {
        "side-channel": "^1.1.0"
      },
      "engines": {
        "node": ">=0.6"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/querystringify": {
      "version": "2.2.0",
      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/readable-stream": {
      "version": "4.7.0",
      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "abort-controller": "^3.0.0",
        "buffer": "^6.0.3",
        "events": "^3.3.0",
        "process": "^0.11.10",
        "string_decoder": "^1.3.0"
      },
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      }
    },
    "node_modules/request": {
      "version": "2.88.2",
      "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
      "integrity": [REDACTED_SECRET],
      "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
      "license": "Apache-2.0",
      "dependencies": {
        "aws-sign2": "~0.7.0",
        "aws4": "^1.8.0",
        "caseless": "~0.12.0",
        "combined-stream": "~1.0.6",
        "extend": "~3.0.2",
        "forever-agent": "~0.6.1",
        "form-data": "~2.3.2",
        "har-validator": "~5.1.3",
        "http-signature": "~1.2.0",
        "is-typedarray": "~1.0.0",
        "isstream": "~0.1.2",
        "json-stringify-safe": "~5.0.1",
        "mime-types": "~2.1.19",
        "oauth-sign": "~0.9.0",
        "performance-now": "^2.1.0",
        "qs": "~6.5.2",
        "safe-buffer": "^5.1.2",
        "tough-cookie": "~2.5.0",
        "tunnel-agent": "^0.6.0",
        "uuid": "^3.3.2"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/request/node_modules/uuid": {
      "version": "3.4.0",
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
      "integrity": [REDACTED_SECRET],
      "deprecated": "uuid@10 and below is no longer supported.  For ESM codebases, update to uuid@latest.  For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).",
      "license": "MIT",
      "bin": {
        "uuid": "bin/uuid"
      }
    },
    "node_modules/requires-port": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/rfdc": {
      "version": "1.4.1",
      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/safe-buffer": {
      "version": "5.2.1",
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
      "integrity": [REDACTED_SECRET],
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "license": "MIT"
    },
    "node_modules/safer-buffer": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/side-channel": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "object-inspect": "^1.13.3",
        "side-channel-list": "^1.0.0",
        "side-channel-map": "^1.0.1",
        "side-channel-weakmap": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-list": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "es-errors": "^1.3.0",
        "object-inspect": "^1.13.4"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-map": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.5",
        "object-inspect": "^1.13.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel-weakmap": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "call-bound": "^1.0.2",
        "es-errors": "^1.3.0",
        "get-intrinsic": "^1.2.5",
        "object-inspect": "^1.13.3",
        "side-channel-map": "^1.0.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/smart-buffer": {
      "version": "4.2.0",
      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 6.0.0",
        "npm": ">= 3.0.0"
      }
    },
    "node_modules/socks": {
      "version": "2.8.8",
      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.8.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "ip-address": "^10.1.1",
        "smart-buffer": "^4.2.0"
      },
      "engines": {
        "node": ">= 10.0.0",
        "npm": ">= 3.0.0"
      }
    },
    "node_modules/split2": {
      "version": "4.2.0",
      "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "ISC",
      "engines": {
        "node": ">= 10.x"
      }
    },
    "node_modules/sshpk": {
      "version": "1.18.0",
      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "asn1": "~0.2.3",
        "assert-plus": "^1.0.0",
        "bcrypt-pbkdf": "^1.0.0",
        "dashdash": "^1.12.0",
        "ecc-jsbn": "~0.1.1",
        "getpass": "^0.1.1",
        "jsbn": "~0.1.0",
        "safer-buffer": "^2.0.2",
        "tweetnacl": "~0.14.0"
      },
      "bin": {
        "sshpk-conv": "bin/sshpk-conv",
        "sshpk-sign": "bin/sshpk-sign",
        "sshpk-verify": "bin/sshpk-verify"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/string_decoder": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "safe-buffer": "~5.2.0"
      }
    },
    "node_modules/tough-cookie": {
      "version": "4.1.4",
      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-3-Clause",
      "dependencies": {
        "psl": "^1.1.33",
        "punycode": "^2.1.1",
        "universalify": "^0.2.0",
        "url-parse": "^1.5.3"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/tslib": {
      "version": "2.8.1",
      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "0BSD"
    },
    "node_modules/tunnel-agent": {
      "version": "0.6.0",
      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Apache-2.0",
      "dependencies": {
        "safe-buffer": "^5.0.1"
      },
      "engines": {
        "node": "*"
      }
    },
    "node_modules/tweetnacl": {
      "version": "0.14.5",
      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "Unlicense"
    },
    "node_modules/typedarray": {
      "version": "0.0.6",
      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/typescript": {
      "version": "5.8.2",
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
      "integrity": [REDACTED_SECRET],
      "dev": true,
      "license": "Apache-2.0",
      "bin": {
        "tsc": "bin/tsc",
        "tsserver": "bin/tsserver"
      },
      "engines": {
        "node": ">=14.17"
      }
    },
    "node_modules/undici-types": {
      "version": "6.21.0",
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/universalify": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">= 4.0.0"
      }
    },
    "node_modules/uri-js": {
      "version": "4.4.1",
      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "BSD-2-Clause",
      "dependencies": {
        "punycode": "^2.1.0"
      }
    },
    "node_modules/url-parse": {
      "version": "1.5.10",
      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "querystringify": "^2.1.1",
        "requires-port": "^1.0.0"
      }
    },
    "node_modules/util-deprecate": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT"
    },
    "node_modules/uuid": {
      "version": "9.0.1",
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
      "integrity": [REDACTED_SECRET],
      "deprecated": "uuid@10 and below is no longer supported.  For ESM codebases, update to uuid@latest.  For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).",
      "funding": [
        "https://github.com/sponsors/broofa",
        "https://github.com/sponsors/ctavan"
      ],
      "license": "MIT",
      "bin": {
        "uuid": "dist/bin/uuid"
      }
    },
    "node_modules/verror": {
      "version": "1.10.0",
      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
      "integrity": [REDACTED_SECRET],
      "engines": [
        "node >=0.6.0"
      ],
      "license": "MIT",
      "dependencies": {
        "assert-plus": "^1.0.0",
        "core-util-is": "1.0.2",
        "extsprintf": "^1.2.0"
      }
    },
    "node_modules/worker-factory": {
      "version": "7.0.49",
      "resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.49.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.29.2",
        "fast-unique-numbers": "^9.0.27",
        "tslib": "^2.8.1"
      }
    },
    "node_modules/worker-timers": {
      "version": "8.0.31",
      "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.31.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.29.2",
        "tslib": "^2.8.1",
        "worker-timers-broker": "^8.0.16",
        "worker-timers-worker": "^9.0.14"
      }
    },
    "node_modules/worker-timers-broker": {
      "version": "8.0.16",
      "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.16.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.29.2",
        "broker-factory": "^3.1.14",
        "fast-unique-numbers": "^9.0.27",
        "tslib": "^2.8.1",
        "worker-timers-worker": "^9.0.14"
      }
    },
    "node_modules/worker-timers-worker": {
      "version": "9.0.14",
      "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.14.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.29.2",
        "tslib": "^2.8.1",
        "worker-factory": "^7.0.49"
      }
    },
    "node_modules/ws": {
      "version": "8.20.0",
      "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
      "integrity": [REDACTED_SECRET],
      "license": "MIT",
      "engines": {
        "node": ">=10.0.0"
      },
      "peerDependencies": {
        "bufferutil": "^4.0.1",
        "utf-8-validate": ">=5.0.2"
      },
      "peerDependenciesMeta": {
        "bufferutil": {
          "optional": true
        },
        "utf-8-validate": {
          "optional": true
        }
      }
    }
  }
}


path: package.json
content: {
  "name": "openclaw-skill-meross",
  "version": "1.0.27",
  "private": true,
  "description": "OpenClaw Meross smart device controller via meross-cloud",
  "license": "MIT-0",
  "type": "commonjs",
  "files": [
    "dist/",
    "README.md",
    "SKILL.md",
    "devices.json",
    "package-lock.json",
    "npm-shrinkwrap.json"
  ],
  "engines": {
    "node": ">=18"
  },
  "scripts": {
    "build": "node -e \"require('node:fs').accessSync('dist/cli.js')\"",
    "clean": "rm -rf dist",
    "prepack": "npm run build",
    "smoke:cli": "node dist/cli.js list-devices '{}'",
    "release:check": "npm run build && npm run smoke:cli && npm pack --dry-run"
  },
  "dependencies": {
    "meross-cloud": "3.1.2"
  },
  "overrides": {
    "form-data": "2.5.5",
    "qs": "6.15.1",
    "tough-cookie": "4.1.4"
  },
  "devDependencies": {
    "@types/node": "22.14.0",
    "typescript": "5.8.2"
  }
}


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal: clean | SkillSpector: clean (LOW)