@yoooclaw/phone-notifications 1.10.0 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/host.ts","../src/env.ts","../src/auth/credentials.ts","../src/recording/transcript-document.ts","../src/recording/whisper-local.ts","../src/recording/asr.ts","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js","../src/index.ts","../src/logger.ts","../src/version.ts","../src/light/repeat.ts","../src/cli/helpers.ts","../src/light/validators.ts","../src/light-rules/storage.ts","../src/monitor/fetch-gen.ts","../src/light-rules/gateway.ts","../src/light-rules/evaluator-job.ts","../src/light-rules/migration.ts","../src/light-rules/registry.ts","../src/plugin/auto-update.ts","../src/update/channel.ts","../src/update/checker.ts","../src/update/executor.ts","../src/update/index.ts","../src/plugin/cli.ts","../src/cli/auth.ts","../src/cli/ntf-search.ts","../src/cli/ntf-stats.ts","../src/cli/ntf-sync.ts","../src/cli/ntf-monitor.ts","../src/cli/light-send.ts","../src/light/sender.ts","../src/light/protocol.ts","../src/cli/light-setup-tools.ts","../src/cli/tunnel-status.ts","../src/cli/ntf-storage-path.ts","../src/cli/log-search.ts","../src/cli/env.ts","../src/cli/doctor.ts","../src/cli/doctor/check-dangerous-flags.ts","../src/cli/doctor/check-trusted-proxy.ts","../src/cli/doctor/check-state-dir-perms.ts","../src/cli/doctor/check-tool-policy.ts","../src/cli/doctor/check-credentials.ts","../src/cli/doctor/check-tunnel.ts","../src/cli/doctor/check-node-version.ts","../src/cli/doctor/check-plugin-version.ts","../src/cli/doctor/checkers.ts","../src/cli/rec-list.ts","../src/cli/rec-status.ts","../src/cli/rec-storage-path.ts","../src/cli/rec-setup.ts","../src/cli/index.ts","../src/plugin/light-control.ts","../src/plugin/lifecycle.ts","../src/notification/app-name-map.ts","../src/notification/storage.ts","../src/recording/storage.ts","../src/recording/state-machine.ts","../src/recording/index.ts","../src/recording/downloader.ts","../src/recording/handler.ts","../src/tunnel/service.ts","../src/tunnel/relay-client.ts","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs","../src/tunnel/proxy.ts","../src/tunnel/utils.ts","../src/tunnel/device-identity.ts","../src/tunnel/http-proxy.ts","../src/tunnel/ws-proxy.ts","../src/plugin/shared.ts","../src/plugin/notifications.ts","../src/plugin/recordings.ts","../src/plugin/runtime-mode.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport type HostKind = \"openclaw\" | \"qclaw\";\n\ninterface QClawMeta {\n stateDir?: string;\n configPath?: string;\n}\n\nfunction trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction homeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"/tmp\";\n}\n\nfunction expandUserPath(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n if (value === \"~\") {\n return homeDir();\n }\n if (value.startsWith(\"~/\")) {\n return join(homeDir(), value.slice(2));\n }\n return value;\n}\n\nfunction detectHostKindFromPath(value: string | undefined): HostKind | undefined {\n if (!value) {\n return undefined;\n }\n const normalized = value.replace(/\\\\/g, \"/\").toLowerCase();\n if (\n normalized.endsWith(\"/.qclaw\") ||\n normalized.includes(\"/.qclaw/\") ||\n normalized.endsWith(\"/.qclow\") ||\n normalized.includes(\"/.qclow/\")\n ) {\n return \"qclaw\";\n }\n if (\n normalized.endsWith(\"/.openclaw\") ||\n normalized.includes(\"/.openclaw/\")\n ) {\n return \"openclaw\";\n }\n return undefined;\n}\n\nfunction candidateMetaPaths(): string[] {\n const home = homeDir();\n return [\n join(home, \".qclaw\", \"qclaw.json\"),\n join(home, \".qclow\", \"qclaw.json\"),\n ];\n}\n\nfunction loadQClawMeta(): QClawMeta | undefined {\n for (const metaPath of candidateMetaPaths()) {\n if (!existsSync(metaPath)) {\n continue;\n }\n try {\n const parsed = JSON.parse(readFileSync(metaPath, \"utf-8\")) as QClawMeta;\n return {\n stateDir: expandUserPath(trimToUndefined(parsed?.stateDir)),\n configPath: expandUserPath(trimToUndefined(parsed?.configPath)),\n };\n } catch {\n // ignore invalid metadata and keep trying\n }\n }\n return undefined;\n}\n\nfunction resolveStateDirFromEnv(): string | undefined {\n return expandUserPath(\n trimToUndefined(process.env.OPENCLAW_STATE_DIR) ??\n trimToUndefined(process.env.QCLAW_STATE_DIR) ??\n trimToUndefined(process.env.OPENCLAW_ROOT) ??\n trimToUndefined(process.env.OPENCLAW_HOME) ??\n trimToUndefined(process.env.QCLAW_HOME),\n );\n}\n\nfunction resolveConfigPathFromEnv(): string | undefined {\n return expandUserPath(\n trimToUndefined(process.env.OPENCLAW_CONFIG_PATH) ??\n trimToUndefined(process.env.QCLAW_CONFIG_PATH),\n );\n}\n\nfunction hasOpenClawMarkers(): boolean {\n const baseDir = join(homeDir(), \".openclaw\");\n return [\n join(baseDir, \"openclaw.json\"),\n join(baseDir, \"credentials.json\"),\n join(baseDir, \"extensions\"),\n ].some((candidate) => existsSync(candidate));\n}\n\nexport function detectHostKind(): HostKind {\n if (\n trimToUndefined(process.env.QCLAW_STATE_DIR) ||\n trimToUndefined(process.env.QCLAW_CONFIG_PATH) ||\n trimToUndefined(process.env.QCLAW_HOME)\n ) {\n return \"qclaw\";\n }\n\n const pathHintKind =\n detectHostKindFromPath(resolveStateDirFromEnv()) ??\n detectHostKindFromPath(resolveConfigPathFromEnv());\n if (pathHintKind) {\n return pathHintKind;\n }\n\n if (hasOpenClawMarkers()) {\n return \"openclaw\";\n }\n\n if (loadQClawMeta()) {\n return \"qclaw\";\n }\n\n return \"openclaw\";\n}\n\nexport function resolveStateDir(): string {\n const envDir = resolveStateDirFromEnv();\n if (envDir) {\n return envDir;\n }\n\n if (hasOpenClawMarkers()) {\n return join(homeDir(), \".openclaw\");\n }\n\n const meta = loadQClawMeta();\n if (meta?.stateDir) {\n return meta.stateDir;\n }\n if (meta?.configPath) {\n return dirname(meta.configPath);\n }\n\n return join(homeDir(), \".openclaw\");\n}\n\nexport function resolveConfigPath(stateDir = resolveStateDir()): string {\n const envConfigPath = resolveConfigPathFromEnv();\n if (envConfigPath) {\n return envConfigPath;\n }\n\n const meta = loadQClawMeta();\n if (\n meta?.configPath &&\n (!meta.stateDir || !stateDir || meta.stateDir === stateDir)\n ) {\n return meta.configPath;\n }\n\n return join(stateDir, \"openclaw.json\");\n}\n\nexport function resolveStateFile(filename: string): string {\n return join(resolveStateDir(), filename);\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { resolveStateFile } from \"./host.js\";\n\nexport type EnvName = \"development\" | \"production\";\n\ninterface EnvUrls {\n lightApiUrl: string;\n appNameMapUrl: string;\n relayTunnelUrl: string;\n modelProxyLongRecordingSubmitTaskUrl: string;\n modelProxyLongRecordingQueryTaskResultBaseUrl: string;\n}\n\nconst ENV_CONFIG: Record<EnvName, EnvUrls> = {\n development: {\n lightApiUrl: \"https://openclaw-service-dev.yoooclaw.com/api/message/tob/sendMessage\",\n relayTunnelUrl: \"wss://openclaw-service-dev.yoooclaw.com/message/messages/ws/plugin\",\n appNameMapUrl:\n \"https://openclaw-service-dev.yoooclaw.com/api/application-config/app-package/config-all\",\n modelProxyLongRecordingSubmitTaskUrl:\n \"https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/submit-task\",\n modelProxyLongRecordingQueryTaskResultBaseUrl:\n \"https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/query-task-result\",\n },\n production: {\n lightApiUrl: \"https://openclaw-service.yoootek.com/api/message/tob/sendMessage\",\n relayTunnelUrl: \"wss://openclaw-service.yoootek.com/message/messages/ws/plugin\",\n appNameMapUrl:\n \"https://openclaw-service.yoootek.com/api/application-config/app-package/config-all\",\n modelProxyLongRecordingSubmitTaskUrl:\n \"https://openclaw-service.yoootek.com/api/model-proxy/long-recording/submit-task\",\n modelProxyLongRecordingQueryTaskResultBaseUrl:\n \"https://openclaw-service.yoootek.com/api/model-proxy/long-recording/query-task-result\",\n },\n};\n\nconst VALID_ENVS: ReadonlySet<string> = new Set(Object.keys(ENV_CONFIG));\n\nfunction envFilePath(): string {\n return resolveStateFile(\"env.json\");\n}\n\n/** 读取当前环境名称,默认 production */\nexport function loadEnvName(): EnvName {\n const filePath = envFilePath();\n if (!existsSync(filePath)) return \"production\";\n try {\n const data = JSON.parse(readFileSync(filePath, \"utf-8\")) as { env?: string };\n if (data.env && VALID_ENVS.has(data.env)) return data.env as EnvName;\n } catch {\n // ignore\n }\n return \"production\";\n}\n\n/** 持久化当前环境 */\nexport function saveEnvName(env: EnvName): void {\n if (!VALID_ENVS.has(env)) {\n throw new Error(`无效的环境名称: ${env},可选值: ${[...VALID_ENVS].join(\", \")}`);\n }\n const filePath = envFilePath();\n mkdirSync(dirname(filePath), { recursive: true, mode: 0o700 });\n writeFileSync(filePath, JSON.stringify({ env }, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\n/** 获取当前环境的 URL 配置 */\nexport function getEnvUrls(env?: EnvName): EnvUrls {\n return ENV_CONFIG[env ?? loadEnvName()];\n}\n\n/** 获取所有可用环境名称 */\nexport function getAvailableEnvs(): EnvName[] {\n return Object.keys(ENV_CONFIG) as EnvName[];\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n watch,\n} from \"node:fs\";\nimport { dirname, basename } from \"node:path\";\nimport { resolveStateFile } from \"../host.js\";\n\ninterface Credentials {\n /**\n * 推荐:API Key 明文(例如 ock_xxx)\n */\n apiKey?: string;\n /**\n * 兼容旧字段:历史上这里存的是 token;现在等价于 apiKey\n */\n token?: string;\n}\n\nexport function credentialsPath(): string {\n return resolveStateFile(\"credentials.json\");\n}\n\nexport function readCredentials(): Credentials {\n const path = credentialsPath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nexport function writeCredentials(creds: Credentials): void {\n const path = credentialsPath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n writeFileSync(path, JSON.stringify(creds, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function loadApiKey(): string | undefined {\n const creds = readCredentials();\n return creds.apiKey ?? creds.token;\n}\n\nexport function requireApiKey(): string {\n const apiKey = loadApiKey();\n if (!apiKey) {\n throw new Error(\n `API Key 未设置,请先写入 ${credentialsPath()},或通过宿主 CLI 执行 ntf auth set-api-key <apiKey>`,\n );\n }\n return apiKey;\n}\n\n// ---- Backward-compatible exports (旧代码仍可编译;语义等价于 apiKey) ----\nexport function loadToken(): string | undefined {\n return loadApiKey();\n}\n\nexport function requireToken(): string {\n return requireApiKey();\n}\n\n/** 监听 credentials 文件变化(如 set-token 后)触发 callback;返回取消监听的函数 */\nexport function watchCredentials(onChange: () => void): () => void {\n const path = credentialsPath();\n const dir = dirname(path);\n const filename = basename(path);\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n const delayMs = 200;\n\n const listener = (_event: string, changedName: string | null) => {\n if (!changedName || (changedName !== filename && !changedName.endsWith(filename))) return;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n onChange();\n }, delayMs);\n };\n\n let watcher: ReturnType<typeof watch> | null = null;\n try {\n watcher = watch(dir, { persistent: false }, listener);\n } catch {\n // 目录可能不存在\n }\n\n return () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher?.close();\n };\n}\n","export const TRANSCRIPT_DOCUMENT_SCHEMA_VERSION = 1;\n\nexport interface TranscriptDocumentSource {\n provider: string;\n taskId?: string;\n requestId?: string;\n status?: string;\n}\n\nexport interface TranscriptDocumentSegment {\n text: string;\n startMs?: number;\n endMs?: number;\n speakerId?: number;\n}\n\nexport interface TranscriptDocumentContentItem {\n content: string;\n speakerId?: number;\n startTime?: number;\n endTime?: number;\n}\n\nexport interface TranscriptDocumentNormalized {\n title?: string;\n category?: string;\n summary?: string;\n text: string;\n segments: TranscriptDocumentSegment[];\n}\n\nexport interface TranscriptDocument {\n schemaVersion: number;\n recordingId: string;\n generatedAt: string;\n source: TranscriptDocumentSource;\n normalized: TranscriptDocumentNormalized;\n raw?: unknown;\n}\n\nexport function buildTranscriptDataFilename(recordingId: string): string {\n return `${recordingId}.json`;\n}\n\nexport function buildTranscriptDocument(params: {\n recordingId: string;\n generatedAt?: string;\n source: TranscriptDocumentSource;\n title?: string;\n category?: string;\n summary?: string;\n text?: string;\n segments?: TranscriptDocumentSegment[];\n raw?: unknown;\n}): TranscriptDocument {\n const segments = normalizeSegments(params.segments);\n const text = normalizeOptionalText(params.text) ?? joinSegmentsText(segments) ?? \"\";\n\n return {\n schemaVersion: TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n recordingId: params.recordingId,\n generatedAt: params.generatedAt ?? new Date().toISOString(),\n source: {\n provider: params.source.provider,\n taskId: normalizeOptionalText(params.source.taskId),\n requestId: normalizeOptionalText(params.source.requestId),\n status: normalizeOptionalText(params.source.status),\n },\n normalized: {\n title: normalizeOptionalText(params.title),\n category: normalizeOptionalText(params.category),\n summary: normalizeOptionalText(params.summary),\n text,\n segments,\n },\n raw: params.raw,\n };\n}\n\nexport function parseTranscriptDocument(\n value: string | unknown,\n): TranscriptDocument | undefined {\n const parsed = typeof value === \"string\"\n ? parseJson(value)\n : value;\n\n if (!parsed || typeof parsed !== \"object\") {\n return undefined;\n }\n\n const doc = parsed as Record<string, unknown>;\n const recordingId = normalizeOptionalText(doc.recordingId);\n const generatedAt = normalizeOptionalText(doc.generatedAt);\n const source = normalizeSource(doc.source);\n const normalized = normalizeDocumentBody(doc.normalized);\n\n if (!recordingId || !generatedAt || !source || !normalized) {\n return undefined;\n }\n\n return {\n schemaVersion:\n typeof doc.schemaVersion === \"number\"\n ? doc.schemaVersion\n : TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n recordingId,\n generatedAt,\n source,\n normalized,\n raw: doc.raw,\n };\n}\n\nexport function extractTranscriptTextFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizeOptionalText(doc.normalized.text)\n ?? joinSegmentsText(doc.normalized.segments);\n}\n\nexport function extractTranscriptSummaryFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizeOptionalText(doc.normalized.summary);\n}\n\nexport function extractTranscriptTitleFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizeOptionalText(doc.normalized.title);\n}\n\nexport function extractSourceTextListFromDocument(\n doc: TranscriptDocument | undefined,\n): TranscriptDocumentContentItem[] | undefined {\n if (!doc) return undefined;\n\n const fromNormalized = doc.normalized.segments\n .map((segment) => ({\n content: segment.text,\n speakerId: segment.speakerId,\n startTime: segment.startMs,\n endTime: segment.endMs,\n }))\n .filter((segment) => normalizeOptionalText(segment.content));\n\n if (fromNormalized.length > 0) {\n return fromNormalized;\n }\n\n const rawList = extractRawSourceTextList(doc.raw);\n if (rawList.length > 0) {\n return rawList;\n }\n\n const normalizedText = normalizeOptionalText(doc.normalized.text);\n return normalizedText\n ? [{ content: normalizedText }]\n : undefined;\n}\n\nfunction parseJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeSource(value: unknown): TranscriptDocumentSource | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const source = value as Record<string, unknown>;\n const provider = normalizeOptionalText(source.provider);\n if (!provider) {\n return undefined;\n }\n\n return {\n provider,\n taskId: normalizeOptionalText(source.taskId),\n requestId: normalizeOptionalText(source.requestId),\n status: normalizeOptionalText(source.status),\n };\n}\n\nfunction normalizeDocumentBody(\n value: unknown,\n): TranscriptDocumentNormalized | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const normalized = value as Record<string, unknown>;\n const segments = normalizeSegments(normalized.segments);\n const text = normalizeOptionalText(normalized.text) ?? joinSegmentsText(segments);\n if (!text) {\n return undefined;\n }\n\n return {\n title: normalizeOptionalText(normalized.title),\n category: normalizeOptionalText(normalized.category),\n summary: normalizeOptionalText(normalized.summary),\n text,\n segments,\n };\n}\n\nfunction normalizeSegments(value: unknown): TranscriptDocumentSegment[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .map((item) => normalizeSegment(item))\n .filter((item): item is TranscriptDocumentSegment => !!item);\n}\n\nfunction normalizeSegment(value: unknown): TranscriptDocumentSegment | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const segment = value as Record<string, unknown>;\n const text = normalizeOptionalText(segment.text);\n if (!text) {\n return undefined;\n }\n\n return {\n text,\n startMs: normalizeOptionalNumber(segment.startMs),\n endMs: normalizeOptionalNumber(segment.endMs),\n speakerId: normalizeOptionalInteger(segment.speakerId),\n };\n}\n\nfunction joinSegmentsText(\n segments: TranscriptDocumentSegment[],\n): string | undefined {\n const parts = segments\n .map((segment) => normalizeOptionalText(segment.text))\n .filter((segment): segment is string => !!segment);\n\n if (parts.length === 0) {\n return undefined;\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nfunction extractRawSourceTextList(raw: unknown): TranscriptDocumentContentItem[] {\n if (!raw || typeof raw !== \"object\") {\n return [];\n }\n\n const recordResult = (raw as { recordResult?: unknown }).recordResult;\n if (!recordResult || typeof recordResult !== \"object\") {\n return [];\n }\n\n const sourceTextList = (recordResult as { sourceTextList?: unknown }).sourceTextList;\n if (!Array.isArray(sourceTextList)) {\n return [];\n }\n\n return sourceTextList\n .flatMap((item) => {\n if (!item || typeof item !== \"object\") {\n return [];\n }\n\n const value = item as Record<string, unknown>;\n const content = normalizeOptionalText(value.content);\n if (!content) {\n return [];\n }\n\n return [{\n content,\n speakerId: normalizeOptionalInteger(value.speakerId),\n startTime: normalizeOptionalNumber(value.startTime),\n endTime: normalizeOptionalNumber(value.endTime),\n }];\n });\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim()\n ? value.trim()\n : undefined;\n}\n\nfunction normalizeOptionalNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined;\n}\n\nfunction normalizeOptionalInteger(value: unknown): number | undefined {\n return Number.isInteger(value)\n ? Number(value)\n : undefined;\n}\n","/**\n * 本地 Whisper 转写模块(arc-long-recording §6.4)\n *\n * 插件内置 Whisper 推理能力:\n * 1. 自动检测运行环境与硬件配置(§6.4.1)\n * 2. 选择最优推理后端(§6.4.2)\n * 3. 根据可用内存自动选择模型规格(§6.4.3)\n * 4. 首次使用时下载模型文件(§6.4.5)\n * 5. 通过 whisper.cpp CLI 执行本地离线转写\n */\n\nimport { execSync, execFileSync, spawnSync, type SpawnSyncReturns } from \"node:child_process\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n statSync,\n createWriteStream,\n unlinkSync,\n copyFileSync,\n openSync,\n readSync,\n closeSync,\n} from \"node:fs\";\nimport { join, dirname, basename } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport { platform, arch, totalmem, cpus, freemem } from \"node:os\";\nimport type {\n WhisperLocalConfig,\n WhisperModelSize,\n WhisperModelSource,\n WhisperBackend,\n WhisperEnvironmentInfo,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { TranscriptionResult, TranscriptSegment } from \"./asr.js\";\n\n// ─── Constants ───\n\nconst WHISPER_MODELS_DIR = \"whisper-models\";\nconst WHISPER_BIN_DIR = \"whisper-bin\";\n\n/** Hugging Face GGML 模型下载 URL 模板(海外) */\nconst HF_MODEL_URL_TEMPLATE =\n \"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-{model}.bin\";\n\n/** 国内 ModelScope 镜像 URL 模板(lihuoo/whisper.cpp-asr-model-collection) */\nconst MODELSCOPE_MODEL_URL_TEMPLATE =\n \"https://modelscope.cn/models/lihuoo/whisper.cpp-asr-model-collection/resolve/master/{model}.bin\";\n\n/** 连通性探测超时(ms) */\nconst PROBE_TIMEOUT_MS = 5_000;\n\n/** 模型规格 → 文件名映射 */\nconst MODEL_FILENAMES: Record<WhisperModelSize, string> = {\n tiny: \"ggml-tiny.bin\",\n base: \"ggml-base.bin\",\n small: \"ggml-small.bin\",\n medium: \"ggml-medium.bin\",\n \"large-v3\": \"ggml-large-v3.bin\",\n};\n\n/** 模型规格 → 推理内存需求 GB(§6.4.3) */\nconst MODEL_MEMORY_REQUIREMENTS: Record<WhisperModelSize, number> = {\n tiny: 1,\n base: 1.5,\n small: 3,\n medium: 6,\n \"large-v3\": 11,\n};\n\n/** 模型规格 → 磁盘占用(字节,近似值) */\nconst MODEL_DISK_SIZES: Record<WhisperModelSize, number> = {\n tiny: 75 * 1024 * 1024,\n base: 140 * 1024 * 1024,\n small: 460 * 1024 * 1024,\n medium: 1500 * 1024 * 1024,\n \"large-v3\": 3000 * 1024 * 1024,\n};\n\n/** whisper.cpp JSON 输出格式 */\ninterface WhisperCppJsonOutput {\n transcription?: Array<{\n timestamps?: { from: string; to: string };\n offsets?: { from: number; to: number };\n text: string;\n }>;\n}\n\n// ─── Public API ───\n\n/**\n * 检测运行环境与硬件配置(§6.4.1)\n *\n * 检测操作系统、CPU 架构、GPU、可用内存,\n * 推荐最优推理后端与模型规格。\n */\nexport function detectEnvironment(logger: Logger): WhisperEnvironmentInfo {\n const os = platform() as \"darwin\" | \"linux\" | \"win32\";\n const cpuArch = arch() as \"arm64\" | \"x64\";\n const isAppleSilicon = os === \"darwin\" && cpuArch === \"arm64\";\n const hasCuda = detectCuda(logger);\n\n // 推荐后端(§6.4.2)\n let recommendedBackend: WhisperBackend;\n if (isAppleSilicon) {\n recommendedBackend = \"coreml\";\n } else if (hasCuda) {\n recommendedBackend = \"cuda\";\n } else {\n recommendedBackend = \"cpu\";\n }\n\n // 可用内存\n const availableMemoryGB = getAvailableMemoryGB(recommendedBackend, logger);\n const physicalCores = getPhysicalCoreCount();\n\n // 推荐模型\n const recommendedModel = selectModelByMemory(availableMemoryGB, isAppleSilicon);\n\n const info: WhisperEnvironmentInfo = {\n os,\n arch: cpuArch,\n isAppleSilicon,\n hasCuda,\n recommendedBackend,\n availableMemoryGB: Math.round(availableMemoryGB * 10) / 10,\n recommendedModel,\n physicalCores,\n };\n\n logger.info(\n `[whisper-local] 环境检测完成: os=${os}, arch=${cpuArch}, ` +\n `appleSilicon=${isAppleSilicon}, cuda=${hasCuda}, ` +\n `backend=${recommendedBackend}, memory=${info.availableMemoryGB}GB, ` +\n `model=${recommendedModel}, cores=${physicalCores}`,\n );\n\n return info;\n}\n\n/**\n * 根据可用内存自动选择模型规格(§6.4.3)\n *\n * 策略:优先匹配可用内存最大能承载的模型(向下取最近档位)。\n * Apple Silicon CoreML 后端内存效率更高,同档位需求降低 ~30%。\n */\nexport function selectModelByMemory(\n availableGB: number,\n isAppleSilicon: boolean = false,\n): WhisperModelSize {\n // Apple Silicon CoreML 内存效率提升约 30%\n const effectiveGB = isAppleSilicon ? availableGB / 0.7 : availableGB;\n\n if (effectiveGB >= 12) return \"large-v3\";\n if (effectiveGB >= 8) return \"medium\";\n if (effectiveGB >= 6) return \"small\";\n if (effectiveGB >= 4) return \"base\";\n return \"tiny\";\n}\n\n/**\n * 解析模型存储目录\n */\nexport function resolveModelsDir(dataDir: string): string {\n const dir = join(dataDir, WHISPER_MODELS_DIR);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * 解析 whisper.cpp 二进制目录\n */\nexport function resolveBinDir(dataDir: string): string {\n const dir = join(dataDir, WHISPER_BIN_DIR);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * 检查模型文件是否已下载(§6.4.5)\n */\nexport function isModelDownloaded(modelsDir: string, modelSize: WhisperModelSize): boolean {\n const modelPath = join(modelsDir, MODEL_FILENAMES[modelSize]);\n if (!existsSync(modelPath)) return false;\n\n // 简单校验:文件大小至少为预期大小的 80%(防止下载不完整)\n try {\n const stat = statSync(modelPath);\n const expectedSize = MODEL_DISK_SIZES[modelSize];\n return stat.size >= expectedSize * 0.8;\n } catch {\n return false;\n }\n}\n\n/**\n * 下载 Whisper 模型文件(§6.4.5)\n *\n * 下载源选择策略:\n * - modelMirrorUrl 存在 → 使用自定义 URL\n * - modelSource = \"huggingface\" → 直接使用 Hugging Face\n * - modelSource = \"domestic\" → 直接使用国内镜像(ModelScope)\n * - modelSource = \"auto\"(默认)→ 先探测 Hugging Face 连通性(5s 超时),\n * 可达则用 HF,不可达则回退国内镜像\n */\nexport async function downloadModel(\n modelsDir: string,\n modelSize: WhisperModelSize,\n logger: Logger,\n modelSource?: WhisperModelSource,\n mirrorUrl?: string,\n): Promise<{ ok: boolean; modelPath: string; error?: string }> {\n const filename = MODEL_FILENAMES[modelSize];\n const modelPath = join(modelsDir, filename);\n\n // 已存在且完整 → 跳过\n if (isModelDownloaded(modelsDir, modelSize)) {\n logger.info(`[whisper-local] 模型已存在,跳过下载: ${filename}`);\n return { ok: true, modelPath };\n }\n\n // 解析下载 URL\n const url = await resolveModelUrl(modelSize, modelSource, mirrorUrl, logger);\n\n logger.info(\n `[whisper-local] 开始下载模型: ${modelSize} (${formatBytes(MODEL_DISK_SIZES[modelSize])})`,\n );\n logger.info(`[whisper-local] 下载 URL: ${url}`);\n\n const result = await downloadFromUrl(url, modelPath, logger);\n\n // auto 模式且 HF 失败 → 尝试国内镜像回退\n if (\n !result.ok &&\n !mirrorUrl &&\n (modelSource === \"auto\" || !modelSource) &&\n url.includes(\"huggingface.co\")\n ) {\n const fallbackUrl = MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n logger.info(\n `[whisper-local] Hugging Face 下载失败,回退至国内镜像(ModelScope): ${fallbackUrl}`,\n );\n return downloadFromUrl(fallbackUrl, modelPath, logger);\n }\n\n return result;\n}\n\n/**\n * 解析模型下载 URL\n */\nasync function resolveModelUrl(\n modelSize: WhisperModelSize,\n modelSource: WhisperModelSource | undefined,\n mirrorUrl: string | undefined,\n logger: Logger,\n): Promise<string> {\n // 自定义 URL 优先级最高\n if (mirrorUrl) {\n return `${mirrorUrl.replace(/\\/$/, \"\")}/${MODEL_FILENAMES[modelSize]}`;\n }\n\n const source = modelSource ?? \"auto\";\n\n switch (source) {\n case \"huggingface\":\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n case \"domestic\":\n return MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n case \"auto\": {\n // 探测 Hugging Face 连通性\n const hfReachable = await probeUrl(\"https://huggingface.co\", logger);\n if (hfReachable) {\n logger.info(\"[whisper-local] Hugging Face 可达,使用海外源\");\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n logger.info(\"[whisper-local] Hugging Face 不可达,使用国内镜像(ModelScope)\");\n return MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n default:\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n}\n\n/**\n * 探测 URL 连通性(HEAD 请求,短超时)\n */\nasync function probeUrl(url: string, logger: Logger): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: \"HEAD\",\n signal: controller.signal,\n });\n return res.ok || res.status === 301 || res.status === 302;\n } finally {\n clearTimeout(timer);\n }\n } catch (err: any) {\n logger.info(\n `[whisper-local] 连通性探测失败: ${url} (${err?.name ?? err?.message ?? \"unknown\"})`,\n );\n return false;\n }\n}\n\n/**\n * 从指定 URL 下载模型文件至本地\n */\nasync function downloadFromUrl(\n url: string,\n modelPath: string,\n logger: Logger,\n): Promise<{ ok: boolean; modelPath: string; error?: string }> {\n const tmpPath = `${modelPath}.downloading`;\n\n try {\n mkdirSync(dirname(modelPath), { recursive: true });\n\n const controller = new AbortController();\n // 模型下载超时:30 分钟(large-v3 约 3GB)\n const timer = setTimeout(() => controller.abort(), 30 * 60 * 1000);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n\n if (!res.ok) {\n return {\n ok: false,\n modelPath,\n error: `模型下载失败: HTTP ${res.status} ${res.statusText}`,\n };\n }\n\n if (!res.body) {\n return { ok: false, modelPath, error: \"模型下载失败: 响应体为空\" };\n }\n\n const contentLength = Number(res.headers.get(\"content-length\") ?? 0);\n const writeStream = createWriteStream(tmpPath);\n const readable = Readable.fromWeb(res.body as any);\n\n // 下载进度日志\n let downloaded = 0;\n let lastLogPercent = 0;\n readable.on(\"data\", (chunk: Buffer) => {\n downloaded += chunk.length;\n if (contentLength > 0) {\n const percent = Math.floor((downloaded / contentLength) * 100);\n if (percent >= lastLogPercent + 10) {\n logger.info(\n `[whisper-local] 下载进度: ${percent}% (${formatBytes(downloaded)} / ${formatBytes(contentLength)})`,\n );\n lastLogPercent = percent;\n }\n }\n });\n\n await pipeline(readable, writeStream);\n } finally {\n clearTimeout(timer);\n }\n\n // 重命名为正式文件\n const { renameSync } = await import(\"node:fs\");\n renameSync(tmpPath, modelPath);\n\n const fileSize = statSync(modelPath).size;\n logger.info(\n `[whisper-local] 模型下载完成: ${basename(modelPath)} (${formatBytes(fileSize)})`,\n );\n\n return { ok: true, modelPath };\n } catch (err: any) {\n // 清理临时文件\n try {\n if (existsSync(tmpPath)) unlinkSync(tmpPath);\n } catch { /* ignore */ }\n\n const msg = err?.name === \"AbortError\"\n ? \"模型下载超时(30 分钟)\"\n : (err?.message ?? String(err));\n logger.error(`[whisper-local] 模型下载失败: ${msg}`);\n return { ok: false, modelPath, error: msg };\n }\n}\n\n/**\n * 查找 whisper.cpp CLI 二进制文件\n *\n * 按以下优先级查找:\n * 1. 插件数据目录下的 whisper-bin/\n * 2. 系统 PATH 中的 whisper-cli / whisper-cpp / whisper\n */\nexport function findWhisperBinary(dataDir: string, logger: Logger): string | null {\n // 1. 检查插件 bin 目录\n const binDir = resolveBinDir(dataDir);\n const binNames = platform() === \"win32\"\n ? [\"whisper-cli.exe\", \"whisper.exe\", \"main.exe\"]\n : [\"whisper-cli\", \"whisper\", \"main\"];\n\n for (const name of binNames) {\n const binPath = join(binDir, name);\n if (existsSync(binPath)) {\n logger.info(`[whisper-local] 找到本地二进制: ${binPath}`);\n return binPath;\n }\n }\n\n // 2. 检查系统 PATH\n const pathNames = platform() === \"win32\"\n ? [\"whisper-cli\", \"whisper-cpp\", \"whisper\"]\n : [\"whisper-cli\", \"whisper-cpp\", \"whisper\"];\n\n for (const name of pathNames) {\n try {\n const cmd = platform() === \"win32\" ? \"where\" : \"which\";\n const result = execSync(`${cmd} ${name}`, { encoding: \"utf-8\", stdio: \"pipe\" }).trim();\n if (result) {\n logger.info(`[whisper-local] 找到系统 PATH 二进制: ${result}`);\n return result.split(\"\\n\")[0].trim();\n }\n } catch {\n // not found, continue\n }\n }\n\n logger.warn(\"[whisper-local] 未找到 whisper.cpp 二进制文件\");\n return null;\n}\n\n/**\n * 使用本地 Whisper 执行转写(§6.4)\n *\n * @param audioFilePath 本地音频文件绝对路径\n * @param localConfig 本地 Whisper 配置\n * @param dataDir 插件数据目录(存放模型和二进制)\n * @param logger 日志\n */\nexport async function transcribeWithWhisperLocal(\n audioFilePath: string,\n localConfig: WhisperLocalConfig,\n dataDir: string,\n logger: Logger,\n): Promise<TranscriptionResult> {\n // 1. 检测环境\n const env = detectEnvironment(logger);\n\n // 2. 确定后端、模型、线程数\n const backend = localConfig.backend ?? env.recommendedBackend;\n const modelSize = localConfig.model ?? env.recommendedModel;\n const threads = localConfig.threads ?? env.physicalCores;\n const language = localConfig.language ?? \"auto\";\n const translate = localConfig.translate ?? false;\n\n logger.info(\n `[whisper-local] 转写参数: backend=${backend}, model=${modelSize}, ` +\n `threads=${threads}, language=${language}, translate=${translate}`,\n );\n\n // 3. 查找 whisper.cpp 二进制\n const whisperBin = findWhisperBinary(dataDir, logger);\n if (!whisperBin) {\n return {\n ok: false,\n error:\n \"未找到 whisper.cpp 二进制文件。请安装 whisper.cpp 并确保 whisper-cli 在 PATH 中,\" +\n `或将二进制文件放入 ${resolveBinDir(dataDir)}`,\n };\n }\n\n // 4. 确保模型已下载\n const modelsDir = resolveModelsDir(dataDir);\n if (!isModelDownloaded(modelsDir, modelSize)) {\n logger.info(`[whisper-local] 模型 ${modelSize} 未下载,开始下载...`);\n const downloadResult = await downloadModel(\n modelsDir,\n modelSize,\n logger,\n localConfig.modelSource,\n localConfig.modelMirrorUrl,\n );\n if (!downloadResult.ok) {\n return { ok: false, error: `模型下载失败: ${downloadResult.error}` };\n }\n }\n\n const modelPath = join(modelsDir, MODEL_FILENAMES[modelSize]);\n\n // 5. 音频格式转换(whisper.cpp 仅支持 16kHz mono WAV)\n // 通过 magic bytes 判断真实格式,不依赖扩展名\n let inputPath = audioFilePath;\n let tmpWavPath: string | null = null;\n\n const actualFmt = detectAudioFormat(audioFilePath);\n if (actualFmt !== \".wav\") {\n tmpWavPath = audioFilePath.replace(/\\.[^.]+$/, \".whisper.wav\");\n logger.info(\n `[whisper-local] 转换音频格式: ${audioFilePath} (${actualFmt ?? \"未知\"}) → WAV (16kHz mono)`,\n );\n\n const convertResult = convertToWav(audioFilePath, tmpWavPath, actualFmt, logger);\n if (!convertResult.ok) {\n return { ok: false, error: convertResult.error! };\n }\n inputPath = tmpWavPath;\n }\n\n // 6. 构建 whisper.cpp CLI 参数\n const args = buildWhisperArgs({\n audioFilePath: inputPath,\n modelPath,\n language,\n translate,\n threads,\n backend,\n });\n\n logger.info(`[whisper-local] 执行: ${whisperBin} ${args.join(\" \")}`);\n\n // 7. 执行转写\n try {\n const startMs = Date.now();\n let result: SpawnSyncReturns<string>;\n\n try {\n result = spawnSync(whisperBin, args, {\n encoding: \"utf-8\" as const,\n timeout: 60 * 60 * 1000, // 1 小时超时(5 小时录音)\n maxBuffer: 100 * 1024 * 1024, // 100MB stdout buffer\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n } catch (err: any) {\n cleanupTmpWav(tmpWavPath);\n return { ok: false, error: `whisper.cpp 执行失败: ${err?.message ?? err}` };\n }\n\n if (result.status !== 0) {\n cleanupTmpWav(tmpWavPath);\n const stderr = result.stderr?.slice(0, 500) ?? \"\";\n return {\n ok: false,\n error: `whisper.cpp 退出码 ${result.status}: ${stderr}`,\n };\n }\n\n const elapsed = Date.now() - startMs;\n logger.info(`[whisper-local] 转写耗时: ${Math.round(elapsed / 1000)}s`);\n\n // 8. 读取 JSON 输出文件(--output-json 将结果写入 {inputPath}.json)\n const jsonPath = inputPath + \".json\";\n let jsonContent: string;\n\n if (existsSync(jsonPath)) {\n jsonContent = readFileSync(jsonPath, \"utf-8\");\n // 清理 JSON 文件\n try { unlinkSync(jsonPath); } catch { /* ignore */ }\n } else {\n // 回退:尝试解析 stdout(部分 whisper.cpp 版本可能输出到 stdout)\n jsonContent = result.stdout;\n }\n\n cleanupTmpWav(tmpWavPath);\n\n return parseWhisperOutput(jsonContent, logger);\n } catch (err: any) {\n cleanupTmpWav(tmpWavPath);\n return { ok: false, error: `whisper.cpp 转写异常: ${err?.message ?? err}` };\n }\n}\n\n/**\n * 获取本地 Whisper 状态信息(供 App 查询环境检测结果)\n */\nexport function getWhisperLocalStatus(\n dataDir: string,\n logger: Logger,\n): {\n environment: WhisperEnvironmentInfo;\n binaryFound: boolean;\n binaryPath: string | null;\n downloadedModels: WhisperModelSize[];\n} {\n const env = detectEnvironment(logger);\n const binaryPath = findWhisperBinary(dataDir, logger);\n const modelsDir = resolveModelsDir(dataDir);\n\n const allModels: WhisperModelSize[] = [\"tiny\", \"base\", \"small\", \"medium\", \"large-v3\"];\n const downloadedModels = allModels.filter((m) => isModelDownloaded(modelsDir, m));\n\n return {\n environment: env,\n binaryFound: binaryPath !== null,\n binaryPath,\n downloadedModels,\n };\n}\n\n// ─── Internal Helpers ───\n\n/**\n * 检测 CUDA 是否可用(§6.4.1)\n */\nfunction detectCuda(logger: Logger): boolean {\n try {\n // 尝试运行 nvidia-smi\n execSync(\"nvidia-smi\", { encoding: \"utf-8\", stdio: \"pipe\", timeout: 5000 });\n logger.info(\"[whisper-local] 检测到 NVIDIA GPU (nvidia-smi)\");\n return true;\n } catch {\n // nvidia-smi 不存在或执行失败\n }\n\n // 检查 CUDA runtime 库\n if (platform() === \"linux\") {\n try {\n const ldconfig = execSync(\"ldconfig -p 2>/dev/null | grep libcudart\", {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n timeout: 5000,\n });\n if (ldconfig.includes(\"libcudart\")) {\n logger.info(\"[whisper-local] 检测到 CUDA runtime (ldconfig)\");\n return true;\n }\n } catch { /* ignore */ }\n }\n\n return false;\n}\n\n/**\n * 获取可用内存(GB)\n *\n * CUDA 后端使用 VRAM,其余使用系统 RAM。\n */\nfunction getAvailableMemoryGB(backend: WhisperBackend, logger: Logger): number {\n if (backend === \"cuda\") {\n // 尝试获取 GPU VRAM\n try {\n const output = execSync(\n \"nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits\",\n { encoding: \"utf-8\", stdio: \"pipe\", timeout: 5000 },\n );\n const freeVramMB = parseInt(output.trim().split(\"\\n\")[0], 10);\n if (!Number.isNaN(freeVramMB) && freeVramMB > 0) {\n return freeVramMB / 1024;\n }\n } catch {\n logger.warn(\"[whisper-local] 无法获取 GPU VRAM,使用系统 RAM 代替\");\n }\n }\n\n // 使用系统可用内存(取 total 的 80% 和 free 的较大值作为可用估计)\n const totalGB = totalmem() / (1024 * 1024 * 1024);\n const freeGB = freemem() / (1024 * 1024 * 1024);\n return Math.max(freeGB, totalGB * 0.6);\n}\n\n/**\n * 获取物理 CPU 核心数\n */\nfunction getPhysicalCoreCount(): number {\n const cpuList = cpus();\n if (cpuList.length === 0) return 4; // fallback\n\n // 简单估算:逻辑核 / 2(假设超线程)\n // macOS ARM 无超线程,直接使用逻辑核数\n if (platform() === \"darwin\" && arch() === \"arm64\") {\n // Apple Silicon: P-cores only (exclude E-cores for inference)\n // 简化处理:使用总核数\n return cpuList.length;\n }\n\n return Math.max(1, Math.floor(cpuList.length / 2));\n}\n\n/**\n * 通过文件头 magic bytes 检测音频的真实格式\n * @returns 正确的文件扩展名(如 .aiff, .wav, .m4a),或 null\n */\nfunction detectAudioFormat(filePath: string): string | null {\n try {\n const fd = openSync(filePath, \"r\");\n const buf = Buffer.alloc(12);\n readSync(fd, buf, 0, 12, 0);\n closeSync(fd);\n\n const header = buf.toString(\"ascii\", 0, 4);\n const header8 = buf.toString(\"ascii\", 0, 8);\n\n // RIFF....WAVE = WAV\n if (header === \"RIFF\" && buf.toString(\"ascii\", 8, 12) === \"WAVE\") return \".wav\";\n // FORM....AIFF / FORM....AIFC = AIFF\n if (header === \"FORM\") {\n const sub = buf.toString(\"ascii\", 8, 12);\n if (sub === \"AIFF\" || sub === \"AIFC\") return \".aiff\";\n }\n // ftyp = MP4/M4A/AAC container\n if (buf.toString(\"ascii\", 4, 8) === \"ftyp\") return \".m4a\";\n // ID3 or 0xFF 0xFB = MP3\n if (header.startsWith(\"ID3\") || (buf[0] === 0xff && (buf[1] & 0xe0) === 0xe0)) return \".mp3\";\n // OggS = Ogg (Vorbis/Opus)\n if (header === \"OggS\") return \".ogg\";\n // fLaC = FLAC\n if (header === \"fLaC\") return \".flac\";\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * 将音频文件转换为 whisper.cpp 所需的 16kHz mono WAV 格式\n *\n * 转换链(按优先级):\n * 1. ffmpeg — 支持全格式,含 OGG/Opus\n * 2. opusdec — 专用于 OGG/Opus(来自 brew install opus-tools)\n * 3. afconvert — macOS 内置,支持 AIFF/M4A/AAC;需正确文件扩展名\n *\n * @param actualFmt detectAudioFormat 检测到的真实格式(如 \".ogg\", \".aiff\"),可为 null\n */\nfunction convertToWav(\n inputPath: string,\n outputPath: string,\n actualFmt: string | null,\n logger: Logger,\n): { ok: boolean; error?: string } {\n // 尝试 ffmpeg(可自动检测格式,不依赖扩展名)\n try {\n const ffmpegResult = spawnSync(\"ffmpeg\", [\n \"-y\", \"-i\", inputPath,\n \"-ar\", \"16000\", \"-ac\", \"1\", \"-c:a\", \"pcm_s16le\",\n outputPath,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n if (ffmpegResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] ffmpeg 转换完成: ${outputPath}`);\n return { ok: true };\n }\n } catch {\n // ffmpeg 不可用,继续尝试其他方式\n }\n\n // 2. opusdec — 专用于 OGG/Opus(ffmpeg 不可用时)\n if (actualFmt === \".ogg\") {\n try {\n const opusResult = spawnSync(\n \"opusdec\",\n [\"--rate\", \"16000\", \"--mono\", inputPath, outputPath],\n { encoding: \"utf-8\", timeout: 120_000, stdio: [\"pipe\", \"pipe\", \"pipe\"] },\n );\n if (opusResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] opusdec 转换完成: ${outputPath}`);\n return { ok: true };\n }\n } catch { /* opusdec 不可用,继续 */ }\n }\n\n // 3. macOS afconvert — 支持 AIFF/M4A/AAC,不支持 OGG\n if (process.platform === \"darwin\" && actualFmt !== \".ogg\") {\n // afconvert 依赖扩展名判断输入格式,先确保扩展名正确\n let actualInputPath = inputPath;\n let tmpCopy: string | null = null;\n const detectedExt = actualFmt;\n\n if (detectedExt && !inputPath.endsWith(detectedExt)) {\n // 扩展名不匹配,创建带正确扩展名的临时副本\n tmpCopy = inputPath + \".detected\" + detectedExt;\n try {\n copyFileSync(inputPath, tmpCopy);\n actualInputPath = tmpCopy;\n logger.info(\n `[whisper-local] 检测到实际格式 ${detectedExt},临时重命名`,\n );\n } catch {\n tmpCopy = null;\n }\n }\n\n try {\n const afResult = spawnSync(\"afconvert\", [\n \"-f\", \"WAVE\", \"-d\", \"LEI16@16000\", \"-c\", \"1\",\n actualInputPath, outputPath,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n // 清理临时副本\n if (tmpCopy && existsSync(tmpCopy)) {\n try { unlinkSync(tmpCopy); } catch { /* ignore */ }\n }\n\n if (afResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] afconvert 转换完成: ${outputPath}`);\n return { ok: true };\n }\n\n const stderr = afResult.stderr?.slice(0, 200) ?? \"\";\n return { ok: false, error: `afconvert 转换失败 (exit ${afResult.status}): ${stderr}` };\n } catch (err: any) {\n // 清理临时副本\n if (tmpCopy && existsSync(tmpCopy)) {\n try { unlinkSync(tmpCopy); } catch { /* ignore */ }\n }\n return { ok: false, error: `afconvert 不可用: ${err?.message}` };\n }\n }\n\n const fmtHint = actualFmt === \".ogg\"\n ? \"OGG/Opus 格式需要 ffmpeg 或 opus-tools(brew install opus-tools)\"\n : \"请安装 ffmpeg(brew install ffmpeg)或确保音频文件为 WAV 格式\";\n return { ok: false, error: `无法将音频转换为 WAV 格式。${fmtHint}` };\n}\n\n/** 清理临时 WAV 文件 */\nfunction cleanupTmpWav(path: string | null): void {\n if (path && existsSync(path)) {\n try { unlinkSync(path); } catch { /* ignore */ }\n }\n}\n\n/**\n * 构建 whisper.cpp CLI 参数\n */\nfunction buildWhisperArgs(params: {\n audioFilePath: string;\n modelPath: string;\n language: string;\n translate: boolean;\n threads: number;\n backend: WhisperBackend;\n}): string[] {\n const args: string[] = [\n \"--model\", params.modelPath,\n \"--file\", params.audioFilePath,\n \"--output-json\", // JSON 格式输出到 {audioFilePath}.json\n \"--no-prints\", // 抑制模型信息输出\n \"--threads\", String(params.threads),\n ];\n\n // 语言\n if (params.language && params.language !== \"auto\") {\n args.push(\"--language\", params.language);\n } else {\n args.push(\"--language\", \"auto\");\n }\n\n // 翻译为英文\n if (params.translate) {\n args.push(\"--translate\");\n }\n\n return args;\n}\n\n/**\n * 解析 whisper.cpp JSON 输出\n */\nfunction parseWhisperOutput(\n stdout: string,\n logger: Logger,\n): TranscriptionResult {\n if (!stdout || !stdout.trim()) {\n return { ok: false, error: \"whisper.cpp 无输出\" };\n }\n\n try {\n const data = JSON.parse(stdout.trim()) as WhisperCppJsonOutput;\n\n if (!data.transcription || !Array.isArray(data.transcription)) {\n // 可能是纯文本输出\n return {\n ok: true,\n text: stdout.trim(),\n segments: [],\n };\n }\n\n const segments: TranscriptSegment[] = [];\n const textParts: string[] = [];\n\n for (const item of data.transcription) {\n const text = item.text?.trim() ?? \"\";\n if (!text) continue;\n\n textParts.push(text);\n\n const startMs = item.offsets?.from ?? parseTimestamp(item.timestamps?.from);\n const endMs = item.offsets?.to ?? parseTimestamp(item.timestamps?.to);\n\n segments.push({\n start_ms: startMs,\n end_ms: endMs,\n text,\n });\n }\n\n const fullText = textParts.join(\" \");\n\n logger.info(\n `[whisper-local] 转写完成: ${fullText.length} 字, ${segments.length} 段`,\n );\n\n return {\n ok: true,\n text: fullText,\n segments,\n };\n } catch (err: any) {\n logger.warn(`[whisper-local] JSON 解析失败,尝试纯文本: ${err?.message}`);\n\n // Fallback: 将 stdout 视为纯文本\n return {\n ok: true,\n text: stdout.trim(),\n segments: [],\n };\n }\n}\n\n/**\n * 解析 whisper.cpp 时间戳字符串 \"HH:MM:SS,mmm\" → 毫秒\n */\nfunction parseTimestamp(ts?: string): number {\n if (!ts) return 0;\n // \"00:00:05,000\" or \"00:00:05.000\"\n const match = ts.match(/^(\\d+):(\\d+):(\\d+)[,.](\\d+)$/);\n if (!match) return 0;\n const [, h, m, s, ms] = match;\n return (\n parseInt(h, 10) * 3600000 +\n parseInt(m, 10) * 60000 +\n parseInt(s, 10) * 1000 +\n parseInt(ms, 10)\n );\n}\n\n/**\n * 格式化字节数\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;\n}\n","/**\n * ASR 转写调度器(§6 / §7)\n *\n * 按 arc-long-recording §6.2 定义的两层配置结构调度 ASR:\n * - mode = \"api\":YoooClaw 托管云端 ASR(经 model-proxy 长录音接口调用)\n * - mode = \"local\":本地 Whisper 转写(§6.4,内置 whisper.cpp 推理)\n * - mode = \"yoooclaw\":YoooClaw 自建 ASR(P2,预留接口)\n *\n * 转写流程:\n * 1. 读取录音 OSS URL 与本地文件\n * 2. 调用云端 model-proxy 或本地 Whisper 获取转写文本\n * 3. 将关键点以 [关键点 MM:SS] 内嵌转写文本\n * 4. 自动生成摘要标题(≤ 10 字)\n * 5. 写入 /recordings/transcripts/日期_时间_摘要.md\n */\n\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type {\n AsrConfig,\n AsrApiConfig,\n RecordingMarker,\n RecordingAsrInitResult,\n RecordingTranscriptItem,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport { requireApiKey, loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport {\n buildTranscriptDataFilename,\n buildTranscriptDocument,\n extractSourceTextListFromDocument,\n} from \"./transcript-document.js\";\n\nconst DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS = 2000;\nconst DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS = 150;\nconst LONG_RECORDING_RUNNING_STATUSES = new Set([\"PENDING\", \"RUNNING\", \"SUSPENDED\"]);\nconst LONG_RECORDING_TERMINAL_FAILURE_STATUSES = new Set([\"FAILED\", \"CANCELED\", \"UNKNOWN\"]);\n\n// ─── Types ───\n\nexport interface TranscriptionResult {\n ok: boolean;\n /** 转写全文 */\n text?: string;\n /** 带时间戳的分段(如 ASR 支持) */\n segments?: TranscriptSegment[];\n /** 自动生成的摘要标题 */\n summary?: string;\n /** 给客户端展示的摘要文本 */\n summaryText?: string;\n /** 分类信息(如会议纪要、采访) */\n category?: string;\n /** 转写来源信息 */\n sourceInfo?: {\n provider: string;\n taskId?: string;\n requestId?: string;\n status?: string;\n };\n /** Provider 原始响应,供后续兼容字段演进 */\n rawResponse?: unknown;\n /** 错误信息 */\n error?: string;\n}\n\nexport interface TranscriptSegment {\n /** 开始时间(毫秒) */\n start_ms: number;\n /** 结束时间(毫秒) */\n end_ms: number;\n /** 文本内容 */\n text: string;\n /** 说话人 ID(如云端 ASR 返回) */\n speaker_id?: number;\n}\n\ninterface ModelProxyLongRecordingSubmitRequest {\n audioOssUrl: string;\n language?: string;\n enableNormalization?: boolean;\n}\n\ninterface ModelProxyLongRecordingResult {\n sourceText?: string | null;\n sourceTextList?: ModelProxyLongRecordingSourceTextItem[] | null;\n summaryResult?: string | null;\n category?: string | null;\n title?: string | null;\n}\n\ninterface ModelProxyLongRecordingSourceTextItem {\n content?: string | null;\n speakerId?: number | null;\n startTime?: number | null;\n}\n\ninterface ModelProxyLongRecordingStatusResponse {\n taskId?: string;\n status?: string;\n requestId?: string;\n errorMessage?: string | null;\n recordResult?: ModelProxyLongRecordingResult | null;\n}\n\ninterface ResponseEnvelope<T> {\n success?: boolean;\n code?: number | string;\n message?: string | null;\n e?: unknown;\n data?: T | null;\n}\n\n// ─── Public API ───\n\n/**\n * 判断 ASR 是否已配置\n */\nexport function isAsrConfigured(config?: AsrConfig): boolean {\n return !!config && !validateAsrConfig(config);\n}\n\n/**\n * 校验客户端下发的 ASR 配置。\n * 返回 undefined 表示配置可用;返回字符串表示错误原因。\n */\nexport function validateAsrConfig(config?: AsrConfig): string | undefined {\n if (!config?.mode) {\n return \"asr.mode is required\";\n }\n\n switch (config.mode) {\n case \"local\":\n case \"api\":\n return undefined;\n case \"yoooclaw\":\n return \"YoooClaw ASR 尚未实现(P2)\";\n default:\n return `未知的 ASR mode: ${(config as { mode: string }).mode}`;\n }\n}\n\n/**\n * 显式初始化 ASR 能力。\n * - mode=api:校验插件本地 API Key 是否存在,并返回最终使用的 model-proxy submit-task endpoint\n * - mode=local:按配置预下载模型,并返回本地环境状态\n */\nexport async function initializeAsr(\n config: AsrConfig,\n dataDir: string,\n logger: Logger,\n): Promise<RecordingAsrInitResult> {\n const validationError = validateAsrConfig(config);\n if (validationError) {\n return {\n ok: false,\n mode: config.mode,\n error: validationError,\n };\n }\n\n switch (config.mode) {\n case \"api\": {\n const endpoint = resolveModelProxyLongRecordingSubmitEndpoint(config.api);\n const keyConfigured = hasText(config.api?.apiKey) || hasText(loadApiKey());\n\n if (!keyConfigured) {\n return {\n ok: false,\n mode: \"api\",\n provider: \"model-proxy\",\n endpoint,\n language: config.api?.language ?? \"auto\",\n keyConfigured: false,\n error:\n \"API Key 未设置,请在本次 asr.api.apiKey 中传入,或先写入 credentials.json / 执行 ntf auth set-api-key <apiKey>\",\n };\n }\n\n return {\n ok: true,\n mode: \"api\",\n provider: \"model-proxy\",\n endpoint,\n language: config.api?.language ?? \"auto\",\n keyConfigured: true,\n };\n }\n case \"local\": {\n const localConfig = config.local ?? {};\n const {\n getWhisperLocalStatus,\n downloadModel,\n resolveModelsDir,\n } = await import(\"./whisper-local.js\");\n\n const initialStatus = getWhisperLocalStatus(dataDir, logger);\n const requestedModel = localConfig.model ?? initialStatus.environment.recommendedModel;\n\n const modelsDir = resolveModelsDir(dataDir);\n const downloadResult = await downloadModel(\n modelsDir,\n requestedModel,\n logger,\n localConfig.modelSource,\n localConfig.modelMirrorUrl,\n );\n if (!downloadResult.ok) {\n return {\n ok: false,\n mode: \"local\",\n model: requestedModel,\n localStatus: {\n ...initialStatus,\n requestedModel,\n },\n error: `模型下载失败: ${downloadResult.error}`,\n };\n }\n\n const finalStatus = getWhisperLocalStatus(dataDir, logger);\n if (!finalStatus.binaryFound) {\n return {\n ok: false,\n mode: \"local\",\n model: requestedModel,\n localStatus: {\n ...finalStatus,\n requestedModel,\n },\n error:\n \"模型已就绪,但未找到 whisper.cpp 二进制文件。请安装 whisper.cpp 并确保 whisper-cli 在 PATH 中。\",\n };\n }\n\n return {\n ok: true,\n mode: \"local\",\n model: requestedModel,\n language: localConfig.language ?? \"auto\",\n localStatus: {\n ...finalStatus,\n requestedModel,\n },\n };\n }\n case \"yoooclaw\":\n return {\n ok: false,\n mode: \"yoooclaw\",\n error: \"YoooClaw ASR 尚未实现(P2)\",\n };\n default:\n return {\n ok: false,\n mode: config.mode,\n error: `未知的 ASR mode: ${config.mode}`,\n };\n }\n}\n\n/**\n * 执行 ASR 转写\n *\n * @param audioFilePath 本地音频文件绝对路径\n * @param config ASR 配置(两层结构:mode + api/local)\n * @param logger 日志\n * @param options 额外上下文(云端 ASR 需要 OSS URL)\n */\nexport async function transcribeAudio(\n audioFilePath: string,\n config: AsrConfig,\n logger: Logger,\n options: {\n audioOssUrl?: string;\n } = {},\n): Promise<TranscriptionResult> {\n if (!existsSync(audioFilePath)) {\n return { ok: false, error: `音频文件不存在: ${audioFilePath}` };\n }\n\n logger.info(\n `[asr] 开始转写: mode=${config.mode}, file=${audioFilePath}`,\n );\n\n try {\n switch (config.mode) {\n case \"api\":\n return await transcribeWithModelProxy(\n options.audioOssUrl,\n config.api,\n logger,\n );\n case \"local\":\n return await transcribeWithWhisperLocal(audioFilePath, config, logger);\n case \"yoooclaw\":\n return { ok: false, error: \"YoooClaw ASR 尚未实现(P2)\" };\n default:\n return {\n ok: false,\n error: `未知的 ASR mode: ${config.mode}`,\n };\n }\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n logger.error(`[asr] 转写异常: ${msg}`);\n return { ok: false, error: msg };\n }\n}\n\n/**\n * 将转写结果与关键点标记合并,生成最终 Markdown 转写文本\n *\n * @param result 转写结果\n * @param markers 关键点列表\n * @param recordingName 录音名称\n * @param durationSec 录音总时长(秒)\n * @param createdAt 录音创建时间\n */\nexport function buildTranscriptMarkdown(\n result: TranscriptionResult,\n markers: RecordingMarker[],\n recordingName: string,\n durationSec: number,\n createdAt: string,\n): string {\n const summary = result.summary ?? recordingName.slice(0, 10);\n const lines: string[] = [];\n\n // 元数据头\n lines.push(`# ${summary}`);\n lines.push(\"\");\n lines.push(`> 录音名称:${recordingName}`);\n lines.push(`> 时长:${formatDuration(durationSec)}`);\n lines.push(`> 创建时间:${createdAt}`);\n if (markers.length > 0) {\n lines.push(`> 关键点数:${markers.length}`);\n }\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n\n if (result.segments && result.segments.length > 0) {\n // 有分段的转写文本:在合适的位置插入关键点标记\n const sortedMarkers = [...markers].sort(\n (a, b) => a.timestamp_ms - b.timestamp_ms,\n );\n let markerIdx = 0;\n\n for (const seg of result.segments) {\n // 在当前段之前插入所有对应的关键点\n while (\n markerIdx < sortedMarkers.length &&\n sortedMarkers[markerIdx].timestamp_ms <= seg.start_ms\n ) {\n const m = sortedMarkers[markerIdx];\n lines.push(\n `**[关键点 ${formatTimestamp(m.timestamp_ms)}]**`,\n );\n lines.push(\"\");\n markerIdx++;\n }\n\n const segmentText = formatTranscriptSegmentText(seg);\n if (segmentText) {\n lines.push(segmentText);\n lines.push(\"\");\n }\n }\n\n // 追加剩余关键点\n while (markerIdx < sortedMarkers.length) {\n const m = sortedMarkers[markerIdx];\n lines.push(\n `**[关键点 ${formatTimestamp(m.timestamp_ms)}]**`,\n );\n lines.push(\"\");\n markerIdx++;\n }\n } else if (result.text) {\n // 纯文本转写:在文本头部集中列出关键点\n if (markers.length > 0) {\n lines.push(\"### 关键点\");\n lines.push(\"\");\n for (const m of markers) {\n lines.push(`- **[关键点 ${formatTimestamp(m.timestamp_ms)}]**`);\n }\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n lines.push(result.text);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * 从转写文本中提取摘要标题(≤ 10 字)\n */\nexport function extractSummary(text: string): string {\n // 取第一句话,截断到 10 字\n const firstLine = text.split(/[。!?\\n]/).find((s) => s.trim().length > 0);\n if (!firstLine) return \"录音转写\";\n const trimmed = firstLine.trim();\n return trimmed.length <= 10 ? trimmed : trimmed.slice(0, 10);\n}\n\n/**\n * 完整的转写工作流:转写 → 生成 Markdown → 写入文件\n */\nexport async function runTranscriptionWorkflow(params: {\n audioFilePath: string;\n audioOssUrl?: string;\n config: AsrConfig;\n markers: RecordingMarker[];\n recordingName: string;\n durationSec: number;\n createdAt: string;\n transcriptsDir: string;\n transcriptDataDir: string;\n summariesDir: string;\n recordingId: string;\n logger: Logger;\n}): Promise<{\n ok: boolean;\n transcriptFilename?: string;\n transcriptDataFilename?: string;\n summaryFilename?: string;\n transcript?: RecordingTranscriptItem[];\n summary?: string;\n title?: string;\n error?: string;\n}> {\n const {\n audioFilePath,\n audioOssUrl,\n config,\n markers,\n recordingName,\n durationSec,\n createdAt,\n transcriptsDir,\n transcriptDataDir,\n summariesDir,\n recordingId,\n logger,\n } = params;\n\n // 1. ASR 转写\n const result = await transcribeAudio(audioFilePath, config, logger, {\n audioOssUrl,\n });\n if (!result.ok) {\n return { ok: false, error: result.error };\n }\n\n // 2. 提取摘要\n const title = normalizeOptionalText(result.summary)\n ? normalizeOptionalText(result.summary)!\n : extractSummary(result.text ?? \"\");\n const summary = normalizeOptionalText(result.summaryText)\n ? normalizeOptionalText(result.summaryText)!\n : extractTranscriptSummary(result.text ?? \"\");\n result.summary = title;\n const transcriptData = buildTranscriptDocument({\n recordingId,\n generatedAt: new Date().toISOString(),\n source: result.sourceInfo ?? {\n provider: config.mode === \"api\" ? \"model-proxy\" : config.mode,\n },\n title,\n category: result.category,\n summary,\n text: result.text,\n segments: (result.segments ?? []).map((segment) => ({\n text: segment.text,\n startMs: segment.start_ms,\n endMs: segment.end_ms,\n speakerId: segment.speaker_id,\n })),\n raw: result.rawResponse,\n });\n\n // 3. 生成 Markdown\n const markdown = buildTranscriptMarkdown(\n result,\n markers,\n recordingName,\n durationSec,\n createdAt,\n );\n\n // 4. 写入文件\n const transcriptDataFilename = buildTranscriptDataFilename(recordingId);\n const transcriptDataPath = join(transcriptDataDir, transcriptDataFilename);\n writeFileSync(\n transcriptDataPath,\n JSON.stringify(transcriptData, null, 2),\n \"utf-8\",\n );\n logger.info(`[asr] 转写 JSON 已写入: ${transcriptDataPath}`);\n\n const safeSummary = title\n .replace(/[/\\\\:*?\"<>|]/g, \"\")\n .trim()\n .slice(0, 20);\n const filename = safeSummary\n ? `${recordingId}_${safeSummary}.md`\n : `${recordingId}.md`;\n const filePath = join(transcriptsDir, filename);\n writeFileSync(filePath, markdown, \"utf-8\");\n logger.info(`[asr] 转写文本已写入: ${filePath}`);\n\n const summaryFilename = `${recordingId}.md`;\n const summaryFilePath = join(summariesDir, summaryFilename);\n writeFileSync(summaryFilePath, summary, \"utf-8\");\n logger.info(`[asr] 摘要文本已写入: ${summaryFilePath}`);\n\n return {\n ok: true,\n transcriptFilename: filename,\n transcriptDataFilename,\n summaryFilename,\n transcript: extractSourceTextListFromDocument(transcriptData),\n summary,\n title,\n };\n}\n\n// ─── ASR Provider Implementations ───\n\n/**\n * 通过 model-proxy 的长录音接口执行云端转写。\n */\nasync function transcribeWithModelProxy(\n audioOssUrl: string | undefined,\n apiConfig: AsrApiConfig | undefined,\n logger: Logger,\n): Promise<TranscriptionResult> {\n const normalizedAudioOssUrl = normalizeOptionalText(audioOssUrl);\n if (!normalizedAudioOssUrl) {\n return { ok: false, error: \"API 模式缺少 audioOssUrl,无法调用 model-proxy\" };\n }\n\n const apiKey = resolveModelProxyApiKey(apiConfig);\n const submitEndpoint = resolveModelProxyLongRecordingSubmitEndpoint(apiConfig);\n const submitBody = buildLongRecordingSubmitRequest(normalizedAudioOssUrl, apiConfig);\n\n logger.info(\n `[asr-submit] 提交长录音任务: endpoint=${submitEndpoint}, body=${stringifyForLog(submitBody) ?? \"{}\"}`,\n );\n\n const res = await fetch(submitEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key-Id\": apiKey,\n },\n body: JSON.stringify(submitBody),\n });\n\n if (!res.ok) {\n const errText = await res.text();\n logger.error(\n `[asr-submit-response] 提交长录音任务失败: status=${res.status}, body=${errText.slice(0, 500)}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR error: ${res.status} ${errText.slice(0, 200)}`,\n };\n }\n\n const raw = (await res.json()) as\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n logger.info(\n `[asr-submit-response] 提交长录音任务响应: ${stringifyForLog(raw) ?? \"{}\"}`,\n );\n const submitEnvelopeError = buildModelProxyEnvelopeError(raw);\n if (submitEnvelopeError) {\n logger.error(\n `[asr-submit-response] 提交长录音任务失败: ${submitEnvelopeError}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR 提交失败: ${submitEnvelopeError}`,\n };\n }\n\n const data = unwrapResponse(raw);\n const taskId = normalizeOptionalText(data?.taskId);\n const requestId = normalizeOptionalText(data?.requestId);\n const status = normalizeLongRecordingStatus(data?.status);\n\n if (!taskId) {\n return {\n ok: false,\n error: \"Model Proxy ASR 响应缺少 taskId\",\n };\n }\n\n logger.info(\n `[asr] Model Proxy 长录音任务已提交: taskId=${taskId}, status=${status ?? \"UNKNOWN\"}, requestId=${requestId ?? \"n/a\"}`,\n );\n\n if (status && LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {\n return {\n ok: false,\n error: buildLongRecordingStatusError(data, status),\n };\n }\n\n return await pollLongRecordingTaskResult({\n apiKey,\n taskId,\n initialRequestId: requestId,\n apiConfig,\n logger,\n });\n}\n\n/**\n * 本地 Whisper 转写(§6.4 — 内置 whisper.cpp 推理)\n */\nasync function transcribeWithWhisperLocal(\n audioFilePath: string,\n config: AsrConfig,\n logger: Logger,\n): Promise<TranscriptionResult> {\n const { transcribeWithWhisperLocal: runLocal } = await import(\"./whisper-local.js\");\n\n // 解析插件数据目录(与模型/二进制存放位置)\n // 优先使用环境变量指定的目录,否则使用音频文件所在目录的上两级(recordings 的父目录)\n const dataDir =\n process.env.OPENCLAW_STATE_DIR ??\n process.env.QCLAW_STATE_DIR ??\n join(audioFilePath, \"..\", \"..\", \"..\");\n\n const localConfig = config.local ?? {};\n\n const result = await runLocal(\n audioFilePath,\n localConfig,\n dataDir,\n logger,\n );\n\n if (result.ok && result.text) {\n const { extractSummary: extract } = await import(\"./asr.js\");\n result.summary = extract(result.text);\n result.sourceInfo = {\n provider: \"whisper-local\",\n status: \"SUCCEEDED\",\n };\n }\n\n return result;\n}\n\n// ─── Helpers ───\n\nfunction resolveModelProxyLongRecordingSubmitEndpoint(apiConfig?: AsrApiConfig): string {\n return apiConfig?.endpoint?.trim() || getEnvUrls().modelProxyLongRecordingSubmitTaskUrl;\n}\n\nfunction resolveModelProxyApiKey(apiConfig?: AsrApiConfig): string {\n const requestApiKey = normalizeOptionalText(apiConfig?.apiKey);\n return normalizeApiKeyHeaderValue(requestApiKey ?? requireApiKey());\n}\n\nfunction resolveModelProxyLongRecordingQueryTaskResultBaseUrl(\n apiConfig?: AsrApiConfig,\n): string {\n const customEndpoint = apiConfig?.endpoint?.trim();\n if (customEndpoint) {\n return deriveLongRecordingQueryTaskResultBaseUrl(customEndpoint);\n }\n return getEnvUrls().modelProxyLongRecordingQueryTaskResultBaseUrl;\n}\n\nfunction deriveLongRecordingQueryTaskResultBaseUrl(endpoint: string): string {\n const trimmed = endpoint.replace(/\\/+$/, \"\");\n if (trimmed.endsWith(\"/submit-task\")) {\n return `${trimmed.slice(0, -\"/submit-task\".length)}/query-task-result`;\n }\n return trimmed;\n}\n\nfunction buildLongRecordingSubmitRequest(\n audioOssUrl: string,\n apiConfig?: AsrApiConfig,\n): ModelProxyLongRecordingSubmitRequest {\n const body: ModelProxyLongRecordingSubmitRequest = {\n audioOssUrl,\n };\n\n if (apiConfig?.language?.trim()) {\n body.language = apiConfig.language.trim();\n }\n if (typeof apiConfig?.enableNormalization === \"boolean\") {\n body.enableNormalization = apiConfig.enableNormalization;\n }\n\n return body;\n}\n\nasync function pollLongRecordingTaskResult(params: {\n apiKey: string;\n taskId: string;\n initialRequestId?: string;\n apiConfig?: AsrApiConfig;\n logger: Logger;\n}): Promise<TranscriptionResult> {\n const {\n apiKey,\n taskId,\n initialRequestId,\n apiConfig,\n logger,\n } = params;\n const queryBaseUrl = resolveModelProxyLongRecordingQueryTaskResultBaseUrl(apiConfig);\n let lastStatus: string | undefined;\n\n for (let attempt = 1; attempt <= DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS; attempt++) {\n const queryUrl = `${queryBaseUrl}/${encodeURIComponent(taskId)}`;\n const res = await fetch(queryUrl, {\n method: \"GET\",\n headers: {\n \"X-Api-Key-Id\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errText = await res.text();\n logger.error(\n `[asr-query-response] 长录音任务查询失败: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 500)}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR query error: ${res.status} ${errText.slice(0, 200)}`,\n };\n }\n\n const raw = (await res.json()) as\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n const queryEnvelopeError = buildModelProxyEnvelopeError(raw);\n if (queryEnvelopeError) {\n logger.error(\n `[asr-query-response] 长录音任务查询失败: taskId=${taskId}, attempt=${attempt}, ${queryEnvelopeError}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR 查询失败: ${queryEnvelopeError}`,\n };\n }\n\n const data = unwrapResponse(raw);\n const status = normalizeLongRecordingStatus(data?.status) ?? \"UNKNOWN\";\n const requestId = normalizeOptionalText(data?.requestId) ?? initialRequestId;\n\n if (status !== lastStatus) {\n logger.info(\n `[asr-query-response] 长录音任务查询响应: taskId=${taskId}, attempt=${attempt}, body=${stringifyForLog(raw) ?? \"{}\"}`,\n );\n logger.info(\n `[asr] Model Proxy 长录音任务状态: taskId=${taskId}, status=${status}, attempt=${attempt}, requestId=${requestId ?? \"n/a\"}`,\n );\n lastStatus = status;\n }\n\n if (status === \"SUCCEEDED\") {\n return buildLongRecordingSuccessResult(taskId, requestId, data, logger);\n }\n\n if (LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {\n return {\n ok: false,\n error: buildLongRecordingStatusError(data, status),\n };\n }\n\n if (!LONG_RECORDING_RUNNING_STATUSES.has(status)) {\n return {\n ok: false,\n error: `Model Proxy ASR 返回未知任务状态: ${status}`,\n };\n }\n\n if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {\n await sleep(DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS);\n }\n }\n\n return {\n ok: false,\n error:\n `Model Proxy ASR 轮询超时: taskId=${taskId}, waited=${DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS * DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS}ms`,\n };\n}\n\nfunction buildLongRecordingSuccessResult(\n taskId: string,\n requestId: string | undefined,\n data: ModelProxyLongRecordingStatusResponse | undefined,\n logger: Logger,\n): TranscriptionResult {\n const sourceTextList = normalizeLongRecordingSourceTextList(\n data?.recordResult?.sourceTextList,\n );\n const listResult = extractLongRecordingTextFromList(sourceTextList);\n const sourceText = normalizeOptionalText(data?.recordResult?.sourceText);\n const summaryText = normalizeOptionalText(data?.recordResult?.summaryResult);\n const title = normalizeOptionalText(data?.recordResult?.title);\n const category = normalizeOptionalText(data?.recordResult?.category);\n const text = listResult.text ?? sourceText ?? summaryText;\n\n if (!text) {\n return {\n ok: false,\n error: \"Model Proxy ASR 任务已完成,但未返回 sourceTextList、sourceText 或 summaryResult\",\n };\n }\n\n if (!listResult.text && !sourceText && summaryText) {\n logger.warn(\n `[asr] Model Proxy 长录音结果缺少 sourceTextList/sourceText,已回退使用 summaryResult 作为转写文本: taskId=${taskId}`,\n );\n }\n\n logger.info(\n `[asr] Model Proxy 长录音转写完成: taskId=${taskId}, requestId=${requestId ?? \"n/a\"}, chars=${text.length}`,\n );\n\n return {\n ok: true,\n text,\n segments: listResult.segments,\n summary: title ?? extractSummary(text),\n summaryText: summaryText ?? extractTranscriptSummary(text),\n category,\n sourceInfo: {\n provider: \"model-proxy\",\n taskId,\n requestId,\n status: \"SUCCEEDED\",\n },\n rawResponse: data,\n };\n}\n\nfunction buildLongRecordingStatusError(\n data: ModelProxyLongRecordingStatusResponse | undefined,\n status: string,\n): string {\n const errorMessage = normalizeOptionalText(data?.errorMessage);\n return errorMessage\n ? `Model Proxy ASR ${status}: ${errorMessage}`\n : `Model Proxy ASR ${status}`;\n}\n\nfunction buildModelProxyEnvelopeError(\n payload:\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>,\n): string | undefined {\n if (!payload || typeof payload !== \"object\" || !(\"data\" in payload)) {\n return undefined;\n }\n\n const envelope = payload as ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n const explicitFailure = envelope.success === false;\n const message = normalizeOptionalText(envelope.message);\n if (!explicitFailure && (!message || envelope.data)) {\n return undefined;\n }\n\n const code = normalizeOptionalCode(envelope.code);\n if (code && message) {\n return `${code} ${message}`;\n }\n return message ?? code ?? \"response envelope indicates failure\";\n}\n\nfunction unwrapResponse(\n payload:\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>,\n): ModelProxyLongRecordingStatusResponse | undefined {\n if (\n payload &&\n typeof payload === \"object\" &&\n \"data\" in payload &&\n payload.data &&\n typeof payload.data === \"object\"\n ) {\n return payload.data;\n }\n\n return payload as ModelProxyLongRecordingStatusResponse;\n}\n\nfunction normalizeApiKeyHeaderValue(apiKey: string): string {\n return apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n}\n\nfunction normalizeLongRecordingStatus(status: unknown): string | undefined {\n return typeof status === \"string\" && status.trim()\n ? status.trim().toUpperCase()\n : undefined;\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim()\n ? value.trim()\n : undefined;\n}\n\nfunction normalizeOptionalCode(value: unknown): string | undefined {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value);\n }\n return undefined;\n}\n\nfunction normalizeOptionalInteger(value: unknown): number | undefined {\n return Number.isInteger(value)\n ? Number(value)\n : undefined;\n}\n\nfunction normalizeOptionalNonNegativeNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0\n ? value\n : undefined;\n}\n\nfunction normalizeLongRecordingSourceTextList(\n value: unknown,\n): Array<{\n content: string;\n speakerId?: number;\n startTime?: number;\n}> {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .flatMap((item) => {\n if (!item || typeof item !== \"object\") {\n return [];\n }\n\n const record = item as Record<string, unknown>;\n const content = normalizeOptionalText(record.content);\n if (!content) {\n return [];\n }\n\n return [{\n content,\n speakerId: normalizeOptionalInteger(record.speakerId),\n startTime: normalizeOptionalNonNegativeNumber(record.startTime),\n }];\n });\n}\n\nfunction extractLongRecordingTextFromList(\n items: Array<{\n content: string;\n speakerId?: number;\n startTime?: number;\n }>,\n): {\n text?: string;\n segments: TranscriptSegment[];\n} {\n if (items.length === 0) {\n return {\n segments: [],\n };\n }\n\n const segments = items.map((item, index) => {\n const startMs = item.startTime ?? 0;\n const nextStart = items[index + 1]?.startTime;\n\n return {\n start_ms: startMs,\n end_ms: nextStart ?? startMs,\n text: item.content,\n speaker_id: item.speakerId,\n };\n });\n\n return {\n text: items.map((item) => item.content).join(\"\\n\\n\"),\n segments,\n };\n}\n\nfunction stringifyForLog(value: unknown, maxLength = 500): string | undefined {\n if (value == null) {\n return undefined;\n }\n\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed ? trimmed.slice(0, maxLength) : undefined;\n }\n\n try {\n const serialized = JSON.stringify(value);\n return serialized ? serialized.slice(0, maxLength) : undefined;\n } catch {\n return String(value).slice(0, maxLength);\n }\n}\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction extractTranscriptSummary(text: string): string {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (!normalized) {\n return \"\";\n }\n\n const sentence = normalized\n .split(/[。!?!?]/)\n .map((part) => part.trim())\n .find((part) => part.length > 0);\n\n const candidate = sentence || normalized;\n return candidate.length <= 120\n ? candidate\n : `${candidate.slice(0, 117).trimEnd()}...`;\n}\n\n/** 毫秒 → \"MM:SS\" */\nfunction formatTimestamp(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`;\n}\n\n/** 秒 → \"HH:MM:SS\" 或 \"MM:SS\" */\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) {\n return `${h}:${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n }\n return `${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n}\n\nfunction hasText(value: unknown): boolean {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction formatTranscriptSegmentText(segment: TranscriptSegment): string {\n const text = segment.text.trim();\n if (!text) {\n return text;\n }\n\n if (typeof segment.speaker_id === \"number\") {\n return `说话人${segment.speaker_id}:${text}`;\n }\n\n return text;\n}\n","'use strict';\n\nconst BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];\nconst hasBlob = typeof Blob !== 'undefined';\n\nif (hasBlob) BINARY_TYPES.push('blob');\n\nmodule.exports = {\n BINARY_TYPES,\n CLOSE_TIMEOUT: 30000,\n EMPTY_BUFFER: Buffer.alloc(0),\n GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',\n hasBlob,\n kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),\n kListener: Symbol('kListener'),\n kStatusCode: Symbol('status-code'),\n kWebSocket: Symbol('websocket'),\n NOOP: () => {}\n};\n","'use strict';\n\nconst { EMPTY_BUFFER } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\n\n/**\n * Merges an array of buffers into a new buffer.\n *\n * @param {Buffer[]} list The array of buffers to concat\n * @param {Number} totalLength The total length of buffers in the list\n * @return {Buffer} The resulting buffer\n * @public\n */\nfunction concat(list, totalLength) {\n if (list.length === 0) return EMPTY_BUFFER;\n if (list.length === 1) return list[0];\n\n const target = Buffer.allocUnsafe(totalLength);\n let offset = 0;\n\n for (let i = 0; i < list.length; i++) {\n const buf = list[i];\n target.set(buf, offset);\n offset += buf.length;\n }\n\n if (offset < totalLength) {\n return new FastBuffer(target.buffer, target.byteOffset, offset);\n }\n\n return target;\n}\n\n/**\n * Masks a buffer using the given mask.\n *\n * @param {Buffer} source The buffer to mask\n * @param {Buffer} mask The mask to use\n * @param {Buffer} output The buffer where to store the result\n * @param {Number} offset The offset at which to start writing\n * @param {Number} length The number of bytes to mask.\n * @public\n */\nfunction _mask(source, mask, output, offset, length) {\n for (let i = 0; i < length; i++) {\n output[offset + i] = source[i] ^ mask[i & 3];\n }\n}\n\n/**\n * Unmasks a buffer using the given mask.\n *\n * @param {Buffer} buffer The buffer to unmask\n * @param {Buffer} mask The mask to use\n * @public\n */\nfunction _unmask(buffer, mask) {\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] ^= mask[i & 3];\n }\n}\n\n/**\n * Converts a buffer to an `ArrayBuffer`.\n *\n * @param {Buffer} buf The buffer to convert\n * @return {ArrayBuffer} Converted buffer\n * @public\n */\nfunction toArrayBuffer(buf) {\n if (buf.length === buf.buffer.byteLength) {\n return buf.buffer;\n }\n\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);\n}\n\n/**\n * Converts `data` to a `Buffer`.\n *\n * @param {*} data The data to convert\n * @return {Buffer} The buffer\n * @throws {TypeError}\n * @public\n */\nfunction toBuffer(data) {\n toBuffer.readOnly = true;\n\n if (Buffer.isBuffer(data)) return data;\n\n let buf;\n\n if (data instanceof ArrayBuffer) {\n buf = new FastBuffer(data);\n } else if (ArrayBuffer.isView(data)) {\n buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);\n } else {\n buf = Buffer.from(data);\n toBuffer.readOnly = false;\n }\n\n return buf;\n}\n\nmodule.exports = {\n concat,\n mask: _mask,\n toArrayBuffer,\n toBuffer,\n unmask: _unmask\n};\n\n/* istanbul ignore else */\nif (!process.env.WS_NO_BUFFER_UTIL) {\n try {\n const bufferUtil = require('bufferutil');\n\n module.exports.mask = function (source, mask, output, offset, length) {\n if (length < 48) _mask(source, mask, output, offset, length);\n else bufferUtil.mask(source, mask, output, offset, length);\n };\n\n module.exports.unmask = function (buffer, mask) {\n if (buffer.length < 32) _unmask(buffer, mask);\n else bufferUtil.unmask(buffer, mask);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst kDone = Symbol('kDone');\nconst kRun = Symbol('kRun');\n\n/**\n * A very simple job queue with adjustable concurrency. Adapted from\n * https://github.com/STRML/async-limiter\n */\nclass Limiter {\n /**\n * Creates a new `Limiter`.\n *\n * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed\n * to run concurrently\n */\n constructor(concurrency) {\n this[kDone] = () => {\n this.pending--;\n this[kRun]();\n };\n this.concurrency = concurrency || Infinity;\n this.jobs = [];\n this.pending = 0;\n }\n\n /**\n * Adds a job to the queue.\n *\n * @param {Function} job The job to run\n * @public\n */\n add(job) {\n this.jobs.push(job);\n this[kRun]();\n }\n\n /**\n * Removes a job from the queue and runs it if possible.\n *\n * @private\n */\n [kRun]() {\n if (this.pending === this.concurrency) return;\n\n if (this.jobs.length) {\n const job = this.jobs.shift();\n\n this.pending++;\n job(this[kDone]);\n }\n }\n}\n\nmodule.exports = Limiter;\n","'use strict';\n\nconst zlib = require('zlib');\n\nconst bufferUtil = require('./buffer-util');\nconst Limiter = require('./limiter');\nconst { kStatusCode } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\nconst TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);\nconst kPerMessageDeflate = Symbol('permessage-deflate');\nconst kTotalLength = Symbol('total-length');\nconst kCallback = Symbol('callback');\nconst kBuffers = Symbol('buffers');\nconst kError = Symbol('error');\n\n//\n// We limit zlib concurrency, which prevents severe memory fragmentation\n// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913\n// and https://github.com/websockets/ws/issues/1202\n//\n// Intentionally global; it's the global thread pool that's an issue.\n//\nlet zlibLimiter;\n\n/**\n * permessage-deflate implementation.\n */\nclass PerMessageDeflate {\n /**\n * Creates a PerMessageDeflate instance.\n *\n * @param {Object} [options] Configuration options\n * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support\n * for, or request, a custom client window size\n * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/\n * acknowledge disabling of client context takeover\n * @param {Number} [options.concurrencyLimit=10] The number of concurrent\n * calls to zlib\n * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the\n * use of a custom server window size\n * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept\n * disabling of server context takeover\n * @param {Number} [options.threshold=1024] Size (in bytes) below which\n * messages should not be compressed if context takeover is disabled\n * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on\n * deflate\n * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on\n * inflate\n * @param {Boolean} [isServer=false] Create the instance in either server or\n * client mode\n * @param {Number} [maxPayload=0] The maximum allowed message length\n */\n constructor(options, isServer, maxPayload) {\n this._maxPayload = maxPayload | 0;\n this._options = options || {};\n this._threshold =\n this._options.threshold !== undefined ? this._options.threshold : 1024;\n this._isServer = !!isServer;\n this._deflate = null;\n this._inflate = null;\n\n this.params = null;\n\n if (!zlibLimiter) {\n const concurrency =\n this._options.concurrencyLimit !== undefined\n ? this._options.concurrencyLimit\n : 10;\n zlibLimiter = new Limiter(concurrency);\n }\n }\n\n /**\n * @type {String}\n */\n static get extensionName() {\n return 'permessage-deflate';\n }\n\n /**\n * Create an extension negotiation offer.\n *\n * @return {Object} Extension parameters\n * @public\n */\n offer() {\n const params = {};\n\n if (this._options.serverNoContextTakeover) {\n params.server_no_context_takeover = true;\n }\n if (this._options.clientNoContextTakeover) {\n params.client_no_context_takeover = true;\n }\n if (this._options.serverMaxWindowBits) {\n params.server_max_window_bits = this._options.serverMaxWindowBits;\n }\n if (this._options.clientMaxWindowBits) {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n } else if (this._options.clientMaxWindowBits == null) {\n params.client_max_window_bits = true;\n }\n\n return params;\n }\n\n /**\n * Accept an extension negotiation offer/response.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Object} Accepted configuration\n * @public\n */\n accept(configurations) {\n configurations = this.normalizeParams(configurations);\n\n this.params = this._isServer\n ? this.acceptAsServer(configurations)\n : this.acceptAsClient(configurations);\n\n return this.params;\n }\n\n /**\n * Releases all resources used by the extension.\n *\n * @public\n */\n cleanup() {\n if (this._inflate) {\n this._inflate.close();\n this._inflate = null;\n }\n\n if (this._deflate) {\n const callback = this._deflate[kCallback];\n\n this._deflate.close();\n this._deflate = null;\n\n if (callback) {\n callback(\n new Error(\n 'The deflate stream was closed while data was being processed'\n )\n );\n }\n }\n }\n\n /**\n * Accept an extension negotiation offer.\n *\n * @param {Array} offers The extension negotiation offers\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsServer(offers) {\n const opts = this._options;\n const accepted = offers.find((params) => {\n if (\n (opts.serverNoContextTakeover === false &&\n params.server_no_context_takeover) ||\n (params.server_max_window_bits &&\n (opts.serverMaxWindowBits === false ||\n (typeof opts.serverMaxWindowBits === 'number' &&\n opts.serverMaxWindowBits > params.server_max_window_bits))) ||\n (typeof opts.clientMaxWindowBits === 'number' &&\n !params.client_max_window_bits)\n ) {\n return false;\n }\n\n return true;\n });\n\n if (!accepted) {\n throw new Error('None of the extension offers can be accepted');\n }\n\n if (opts.serverNoContextTakeover) {\n accepted.server_no_context_takeover = true;\n }\n if (opts.clientNoContextTakeover) {\n accepted.client_no_context_takeover = true;\n }\n if (typeof opts.serverMaxWindowBits === 'number') {\n accepted.server_max_window_bits = opts.serverMaxWindowBits;\n }\n if (typeof opts.clientMaxWindowBits === 'number') {\n accepted.client_max_window_bits = opts.clientMaxWindowBits;\n } else if (\n accepted.client_max_window_bits === true ||\n opts.clientMaxWindowBits === false\n ) {\n delete accepted.client_max_window_bits;\n }\n\n return accepted;\n }\n\n /**\n * Accept the extension negotiation response.\n *\n * @param {Array} response The extension negotiation response\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsClient(response) {\n const params = response[0];\n\n if (\n this._options.clientNoContextTakeover === false &&\n params.client_no_context_takeover\n ) {\n throw new Error('Unexpected parameter \"client_no_context_takeover\"');\n }\n\n if (!params.client_max_window_bits) {\n if (typeof this._options.clientMaxWindowBits === 'number') {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n }\n } else if (\n this._options.clientMaxWindowBits === false ||\n (typeof this._options.clientMaxWindowBits === 'number' &&\n params.client_max_window_bits > this._options.clientMaxWindowBits)\n ) {\n throw new Error(\n 'Unexpected or invalid parameter \"client_max_window_bits\"'\n );\n }\n\n return params;\n }\n\n /**\n * Normalize parameters.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Array} The offers/response with normalized parameters\n * @private\n */\n normalizeParams(configurations) {\n configurations.forEach((params) => {\n Object.keys(params).forEach((key) => {\n let value = params[key];\n\n if (value.length > 1) {\n throw new Error(`Parameter \"${key}\" must have only a single value`);\n }\n\n value = value[0];\n\n if (key === 'client_max_window_bits') {\n if (value !== true) {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (!this._isServer) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else if (key === 'server_max_window_bits') {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (\n key === 'client_no_context_takeover' ||\n key === 'server_no_context_takeover'\n ) {\n if (value !== true) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else {\n throw new Error(`Unknown parameter \"${key}\"`);\n }\n\n params[key] = value;\n });\n });\n\n return configurations;\n }\n\n /**\n * Decompress data. Concurrency limited.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n decompress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._decompress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Compress data. Concurrency limited.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n compress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._compress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Decompress data.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _decompress(data, fin, callback) {\n const endpoint = this._isServer ? 'client' : 'server';\n\n if (!this._inflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._inflate = zlib.createInflateRaw({\n ...this._options.zlibInflateOptions,\n windowBits\n });\n this._inflate[kPerMessageDeflate] = this;\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n this._inflate.on('error', inflateOnError);\n this._inflate.on('data', inflateOnData);\n }\n\n this._inflate[kCallback] = callback;\n\n this._inflate.write(data);\n if (fin) this._inflate.write(TRAILER);\n\n this._inflate.flush(() => {\n const err = this._inflate[kError];\n\n if (err) {\n this._inflate.close();\n this._inflate = null;\n callback(err);\n return;\n }\n\n const data = bufferUtil.concat(\n this._inflate[kBuffers],\n this._inflate[kTotalLength]\n );\n\n if (this._inflate._readableState.endEmitted) {\n this._inflate.close();\n this._inflate = null;\n } else {\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._inflate.reset();\n }\n }\n\n callback(null, data);\n });\n }\n\n /**\n * Compress data.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _compress(data, fin, callback) {\n const endpoint = this._isServer ? 'server' : 'client';\n\n if (!this._deflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._deflate = zlib.createDeflateRaw({\n ...this._options.zlibDeflateOptions,\n windowBits\n });\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n this._deflate.on('data', deflateOnData);\n }\n\n this._deflate[kCallback] = callback;\n\n this._deflate.write(data);\n this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {\n if (!this._deflate) {\n //\n // The deflate stream was closed while data was being processed.\n //\n return;\n }\n\n let data = bufferUtil.concat(\n this._deflate[kBuffers],\n this._deflate[kTotalLength]\n );\n\n if (fin) {\n data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);\n }\n\n //\n // Ensure that the callback will not be called again in\n // `PerMessageDeflate#cleanup()`.\n //\n this._deflate[kCallback] = null;\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._deflate.reset();\n }\n\n callback(null, data);\n });\n }\n}\n\nmodule.exports = PerMessageDeflate;\n\n/**\n * The listener of the `zlib.DeflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction deflateOnData(chunk) {\n this[kBuffers].push(chunk);\n this[kTotalLength] += chunk.length;\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction inflateOnData(chunk) {\n this[kTotalLength] += chunk.length;\n\n if (\n this[kPerMessageDeflate]._maxPayload < 1 ||\n this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload\n ) {\n this[kBuffers].push(chunk);\n return;\n }\n\n this[kError] = new RangeError('Max payload size exceeded');\n this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';\n this[kError][kStatusCode] = 1009;\n this.removeListener('data', inflateOnData);\n\n //\n // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the\n // fact that in Node.js versions prior to 13.10.0, the callback for\n // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing\n // `zlib.reset()` ensures that either the callback is invoked or an error is\n // emitted.\n //\n this.reset();\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'error'` event.\n *\n * @param {Error} err The emitted error\n * @private\n */\nfunction inflateOnError(err) {\n //\n // There is no need to call `Zlib#close()` as the handle is automatically\n // closed when an error is emitted.\n //\n this[kPerMessageDeflate]._inflate = null;\n\n if (this[kError]) {\n this[kCallback](this[kError]);\n return;\n }\n\n err[kStatusCode] = 1007;\n this[kCallback](err);\n}\n","'use strict';\n\nconst { isUtf8 } = require('buffer');\n\nconst { hasBlob } = require('./constants');\n\n//\n// Allowed token characters:\n//\n// '!', '#', '$', '%', '&', ''', '*', '+', '-',\n// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'\n//\n// tokenChars[32] === 0 // ' '\n// tokenChars[33] === 1 // '!'\n// tokenChars[34] === 0 // '\"'\n// ...\n//\n// prettier-ignore\nconst tokenChars = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31\n 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63\n 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127\n];\n\n/**\n * Checks if a status code is allowed in a close frame.\n *\n * @param {Number} code The status code\n * @return {Boolean} `true` if the status code is valid, else `false`\n * @public\n */\nfunction isValidStatusCode(code) {\n return (\n (code >= 1000 &&\n code <= 1014 &&\n code !== 1004 &&\n code !== 1005 &&\n code !== 1006) ||\n (code >= 3000 && code <= 4999)\n );\n}\n\n/**\n * Checks if a given buffer contains only correct UTF-8.\n * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by\n * Markus Kuhn.\n *\n * @param {Buffer} buf The buffer to check\n * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`\n * @public\n */\nfunction _isValidUTF8(buf) {\n const len = buf.length;\n let i = 0;\n\n while (i < len) {\n if ((buf[i] & 0x80) === 0) {\n // 0xxxxxxx\n i++;\n } else if ((buf[i] & 0xe0) === 0xc0) {\n // 110xxxxx 10xxxxxx\n if (\n i + 1 === len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i] & 0xfe) === 0xc0 // Overlong\n ) {\n return false;\n }\n\n i += 2;\n } else if ((buf[i] & 0xf0) === 0xe0) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n if (\n i + 2 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong\n (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)\n ) {\n return false;\n }\n\n i += 3;\n } else if ((buf[i] & 0xf8) === 0xf0) {\n // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n if (\n i + 3 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i + 3] & 0xc0) !== 0x80 ||\n (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong\n (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||\n buf[i] > 0xf4 // > U+10FFFF\n ) {\n return false;\n }\n\n i += 4;\n } else {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Determines whether a value is a `Blob`.\n *\n * @param {*} value The value to be tested\n * @return {Boolean} `true` if `value` is a `Blob`, else `false`\n * @private\n */\nfunction isBlob(value) {\n return (\n hasBlob &&\n typeof value === 'object' &&\n typeof value.arrayBuffer === 'function' &&\n typeof value.type === 'string' &&\n typeof value.stream === 'function' &&\n (value[Symbol.toStringTag] === 'Blob' ||\n value[Symbol.toStringTag] === 'File')\n );\n}\n\nmodule.exports = {\n isBlob,\n isValidStatusCode,\n isValidUTF8: _isValidUTF8,\n tokenChars\n};\n\nif (isUtf8) {\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);\n };\n} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {\n try {\n const isValidUTF8 = require('utf-8-validate');\n\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst { Writable } = require('stream');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst {\n BINARY_TYPES,\n EMPTY_BUFFER,\n kStatusCode,\n kWebSocket\n} = require('./constants');\nconst { concat, toArrayBuffer, unmask } = require('./buffer-util');\nconst { isValidStatusCode, isValidUTF8 } = require('./validation');\n\nconst FastBuffer = Buffer[Symbol.species];\n\nconst GET_INFO = 0;\nconst GET_PAYLOAD_LENGTH_16 = 1;\nconst GET_PAYLOAD_LENGTH_64 = 2;\nconst GET_MASK = 3;\nconst GET_DATA = 4;\nconst INFLATING = 5;\nconst DEFER_EVENT = 6;\n\n/**\n * HyBi Receiver implementation.\n *\n * @extends Writable\n */\nclass Receiver extends Writable {\n /**\n * Creates a Receiver instance.\n *\n * @param {Object} [options] Options object\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {String} [options.binaryType=nodebuffer] The type for binary data\n * @param {Object} [options.extensions] An object containing the negotiated\n * extensions\n * @param {Boolean} [options.isServer=false] Specifies whether to operate in\n * client or server mode\n * @param {Number} [options.maxPayload=0] The maximum allowed message length\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n */\n constructor(options = {}) {\n super();\n\n this._allowSynchronousEvents =\n options.allowSynchronousEvents !== undefined\n ? options.allowSynchronousEvents\n : true;\n this._binaryType = options.binaryType || BINARY_TYPES[0];\n this._extensions = options.extensions || {};\n this._isServer = !!options.isServer;\n this._maxPayload = options.maxPayload | 0;\n this._skipUTF8Validation = !!options.skipUTF8Validation;\n this[kWebSocket] = undefined;\n\n this._bufferedBytes = 0;\n this._buffers = [];\n\n this._compressed = false;\n this._payloadLength = 0;\n this._mask = undefined;\n this._fragmented = 0;\n this._masked = false;\n this._fin = false;\n this._opcode = 0;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragments = [];\n\n this._errored = false;\n this._loop = false;\n this._state = GET_INFO;\n }\n\n /**\n * Implements `Writable.prototype._write()`.\n *\n * @param {Buffer} chunk The chunk of data to write\n * @param {String} encoding The character encoding of `chunk`\n * @param {Function} cb Callback\n * @private\n */\n _write(chunk, encoding, cb) {\n if (this._opcode === 0x08 && this._state == GET_INFO) return cb();\n\n this._bufferedBytes += chunk.length;\n this._buffers.push(chunk);\n this.startLoop(cb);\n }\n\n /**\n * Consumes `n` bytes from the buffered data.\n *\n * @param {Number} n The number of bytes to consume\n * @return {Buffer} The consumed bytes\n * @private\n */\n consume(n) {\n this._bufferedBytes -= n;\n\n if (n === this._buffers[0].length) return this._buffers.shift();\n\n if (n < this._buffers[0].length) {\n const buf = this._buffers[0];\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n\n return new FastBuffer(buf.buffer, buf.byteOffset, n);\n }\n\n const dst = Buffer.allocUnsafe(n);\n\n do {\n const buf = this._buffers[0];\n const offset = dst.length - n;\n\n if (n >= buf.length) {\n dst.set(this._buffers.shift(), offset);\n } else {\n dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n }\n\n n -= buf.length;\n } while (n > 0);\n\n return dst;\n }\n\n /**\n * Starts the parsing loop.\n *\n * @param {Function} cb Callback\n * @private\n */\n startLoop(cb) {\n this._loop = true;\n\n do {\n switch (this._state) {\n case GET_INFO:\n this.getInfo(cb);\n break;\n case GET_PAYLOAD_LENGTH_16:\n this.getPayloadLength16(cb);\n break;\n case GET_PAYLOAD_LENGTH_64:\n this.getPayloadLength64(cb);\n break;\n case GET_MASK:\n this.getMask();\n break;\n case GET_DATA:\n this.getData(cb);\n break;\n case INFLATING:\n case DEFER_EVENT:\n this._loop = false;\n return;\n }\n } while (this._loop);\n\n if (!this._errored) cb();\n }\n\n /**\n * Reads the first two bytes of a frame.\n *\n * @param {Function} cb Callback\n * @private\n */\n getInfo(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(2);\n\n if ((buf[0] & 0x30) !== 0x00) {\n const error = this.createError(\n RangeError,\n 'RSV2 and RSV3 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_2_3'\n );\n\n cb(error);\n return;\n }\n\n const compressed = (buf[0] & 0x40) === 0x40;\n\n if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n this._fin = (buf[0] & 0x80) === 0x80;\n this._opcode = buf[0] & 0x0f;\n this._payloadLength = buf[1] & 0x7f;\n\n if (this._opcode === 0x00) {\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fragmented) {\n const error = this.createError(\n RangeError,\n 'invalid opcode 0',\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._opcode = this._fragmented;\n } else if (this._opcode === 0x01 || this._opcode === 0x02) {\n if (this._fragmented) {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._compressed = compressed;\n } else if (this._opcode > 0x07 && this._opcode < 0x0b) {\n if (!this._fin) {\n const error = this.createError(\n RangeError,\n 'FIN must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_FIN'\n );\n\n cb(error);\n return;\n }\n\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (\n this._payloadLength > 0x7d ||\n (this._opcode === 0x08 && this._payloadLength === 1)\n ) {\n const error = this.createError(\n RangeError,\n `invalid payload length ${this._payloadLength}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n } else {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fin && !this._fragmented) this._fragmented = this._opcode;\n this._masked = (buf[1] & 0x80) === 0x80;\n\n if (this._isServer) {\n if (!this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n } else if (this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n\n if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;\n else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;\n else this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+16).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength16(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n this._payloadLength = this.consume(2).readUInt16BE(0);\n this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+64).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength64(cb) {\n if (this._bufferedBytes < 8) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(8);\n const num = buf.readUInt32BE(0);\n\n //\n // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned\n // if payload length is greater than this number.\n //\n if (num > Math.pow(2, 53 - 32) - 1) {\n const error = this.createError(\n RangeError,\n 'Unsupported WebSocket frame: payload length > 2^53 - 1',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);\n this.haveLength(cb);\n }\n\n /**\n * Payload length has been read.\n *\n * @param {Function} cb Callback\n * @private\n */\n haveLength(cb) {\n if (this._payloadLength && this._opcode < 0x08) {\n this._totalPayloadLength += this._payloadLength;\n if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n }\n\n if (this._masked) this._state = GET_MASK;\n else this._state = GET_DATA;\n }\n\n /**\n * Reads mask bytes.\n *\n * @private\n */\n getMask() {\n if (this._bufferedBytes < 4) {\n this._loop = false;\n return;\n }\n\n this._mask = this.consume(4);\n this._state = GET_DATA;\n }\n\n /**\n * Reads data bytes.\n *\n * @param {Function} cb Callback\n * @private\n */\n getData(cb) {\n let data = EMPTY_BUFFER;\n\n if (this._payloadLength) {\n if (this._bufferedBytes < this._payloadLength) {\n this._loop = false;\n return;\n }\n\n data = this.consume(this._payloadLength);\n\n if (\n this._masked &&\n (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0\n ) {\n unmask(data, this._mask);\n }\n }\n\n if (this._opcode > 0x07) {\n this.controlMessage(data, cb);\n return;\n }\n\n if (this._compressed) {\n this._state = INFLATING;\n this.decompress(data, cb);\n return;\n }\n\n if (data.length) {\n //\n // This message is not compressed so its length is the sum of the payload\n // length of all fragments.\n //\n this._messageLength = this._totalPayloadLength;\n this._fragments.push(data);\n }\n\n this.dataMessage(cb);\n }\n\n /**\n * Decompresses data.\n *\n * @param {Buffer} data Compressed data\n * @param {Function} cb Callback\n * @private\n */\n decompress(data, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n perMessageDeflate.decompress(data, this._fin, (err, buf) => {\n if (err) return cb(err);\n\n if (buf.length) {\n this._messageLength += buf.length;\n if (this._messageLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._fragments.push(buf);\n }\n\n this.dataMessage(cb);\n if (this._state === GET_INFO) this.startLoop(cb);\n });\n }\n\n /**\n * Handles a data message.\n *\n * @param {Function} cb Callback\n * @private\n */\n dataMessage(cb) {\n if (!this._fin) {\n this._state = GET_INFO;\n return;\n }\n\n const messageLength = this._messageLength;\n const fragments = this._fragments;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragmented = 0;\n this._fragments = [];\n\n if (this._opcode === 2) {\n let data;\n\n if (this._binaryType === 'nodebuffer') {\n data = concat(fragments, messageLength);\n } else if (this._binaryType === 'arraybuffer') {\n data = toArrayBuffer(concat(fragments, messageLength));\n } else if (this._binaryType === 'blob') {\n data = new Blob(fragments);\n } else {\n data = fragments;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit('message', data, true);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', data, true);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n } else {\n const buf = concat(fragments, messageLength);\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n if (this._state === INFLATING || this._allowSynchronousEvents) {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n }\n\n /**\n * Handles a control message.\n *\n * @param {Buffer} data Data to handle\n * @return {(Error|RangeError|undefined)} A possible error\n * @private\n */\n controlMessage(data, cb) {\n if (this._opcode === 0x08) {\n if (data.length === 0) {\n this._loop = false;\n this.emit('conclude', 1005, EMPTY_BUFFER);\n this.end();\n } else {\n const code = data.readUInt16BE(0);\n\n if (!isValidStatusCode(code)) {\n const error = this.createError(\n RangeError,\n `invalid status code ${code}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CLOSE_CODE'\n );\n\n cb(error);\n return;\n }\n\n const buf = new FastBuffer(\n data.buffer,\n data.byteOffset + 2,\n data.length - 2\n );\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n this._loop = false;\n this.emit('conclude', code, buf);\n this.end();\n }\n\n this._state = GET_INFO;\n return;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n\n /**\n * Builds an error object.\n *\n * @param {function(new:Error|RangeError)} ErrorCtor The error constructor\n * @param {String} message The error message\n * @param {Boolean} prefix Specifies whether or not to add a default prefix to\n * `message`\n * @param {Number} statusCode The status code\n * @param {String} errorCode The exposed error code\n * @return {(Error|RangeError)} The error\n * @private\n */\n createError(ErrorCtor, message, prefix, statusCode, errorCode) {\n this._loop = false;\n this._errored = true;\n\n const err = new ErrorCtor(\n prefix ? `Invalid WebSocket frame: ${message}` : message\n );\n\n Error.captureStackTrace(err, this.createError);\n err.code = errorCode;\n err[kStatusCode] = statusCode;\n return err;\n }\n}\n\nmodule.exports = Receiver;\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex\" }] */\n\n'use strict';\n\nconst { Duplex } = require('stream');\nconst { randomFillSync } = require('crypto');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants');\nconst { isBlob, isValidStatusCode } = require('./validation');\nconst { mask: applyMask, toBuffer } = require('./buffer-util');\n\nconst kByteLength = Symbol('kByteLength');\nconst maskBuffer = Buffer.alloc(4);\nconst RANDOM_POOL_SIZE = 8 * 1024;\nlet randomPool;\nlet randomPoolPointer = RANDOM_POOL_SIZE;\n\nconst DEFAULT = 0;\nconst DEFLATING = 1;\nconst GET_BLOB_DATA = 2;\n\n/**\n * HyBi Sender implementation.\n */\nclass Sender {\n /**\n * Creates a Sender instance.\n *\n * @param {Duplex} socket The connection socket\n * @param {Object} [extensions] An object containing the negotiated extensions\n * @param {Function} [generateMask] The function used to generate the masking\n * key\n */\n constructor(socket, extensions, generateMask) {\n this._extensions = extensions || {};\n\n if (generateMask) {\n this._generateMask = generateMask;\n this._maskBuffer = Buffer.alloc(4);\n }\n\n this._socket = socket;\n\n this._firstFragment = true;\n this._compress = false;\n\n this._bufferedBytes = 0;\n this._queue = [];\n this._state = DEFAULT;\n this.onerror = NOOP;\n this[kWebSocket] = undefined;\n }\n\n /**\n * Frames a piece of data according to the HyBi WebSocket protocol.\n *\n * @param {(Buffer|String)} data The data to frame\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @return {(Buffer|String)[]} The framed data\n * @public\n */\n static frame(data, options) {\n let mask;\n let merge = false;\n let offset = 2;\n let skipMasking = false;\n\n if (options.mask) {\n mask = options.maskBuffer || maskBuffer;\n\n if (options.generateMask) {\n options.generateMask(mask);\n } else {\n if (randomPoolPointer === RANDOM_POOL_SIZE) {\n /* istanbul ignore else */\n if (randomPool === undefined) {\n //\n // This is lazily initialized because server-sent frames must not\n // be masked so it may never be used.\n //\n randomPool = Buffer.alloc(RANDOM_POOL_SIZE);\n }\n\n randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);\n randomPoolPointer = 0;\n }\n\n mask[0] = randomPool[randomPoolPointer++];\n mask[1] = randomPool[randomPoolPointer++];\n mask[2] = randomPool[randomPoolPointer++];\n mask[3] = randomPool[randomPoolPointer++];\n }\n\n skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;\n offset = 6;\n }\n\n let dataLength;\n\n if (typeof data === 'string') {\n if (\n (!options.mask || skipMasking) &&\n options[kByteLength] !== undefined\n ) {\n dataLength = options[kByteLength];\n } else {\n data = Buffer.from(data);\n dataLength = data.length;\n }\n } else {\n dataLength = data.length;\n merge = options.mask && options.readOnly && !skipMasking;\n }\n\n let payloadLength = dataLength;\n\n if (dataLength >= 65536) {\n offset += 8;\n payloadLength = 127;\n } else if (dataLength > 125) {\n offset += 2;\n payloadLength = 126;\n }\n\n const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);\n\n target[0] = options.fin ? options.opcode | 0x80 : options.opcode;\n if (options.rsv1) target[0] |= 0x40;\n\n target[1] = payloadLength;\n\n if (payloadLength === 126) {\n target.writeUInt16BE(dataLength, 2);\n } else if (payloadLength === 127) {\n target[2] = target[3] = 0;\n target.writeUIntBE(dataLength, 4, 6);\n }\n\n if (!options.mask) return [target, data];\n\n target[1] |= 0x80;\n target[offset - 4] = mask[0];\n target[offset - 3] = mask[1];\n target[offset - 2] = mask[2];\n target[offset - 1] = mask[3];\n\n if (skipMasking) return [target, data];\n\n if (merge) {\n applyMask(data, mask, target, offset, dataLength);\n return [target];\n }\n\n applyMask(data, mask, data, 0, dataLength);\n return [target, data];\n }\n\n /**\n * Sends a close message to the other peer.\n *\n * @param {Number} [code] The status code component of the body\n * @param {(String|Buffer)} [data] The message component of the body\n * @param {Boolean} [mask=false] Specifies whether or not to mask the message\n * @param {Function} [cb] Callback\n * @public\n */\n close(code, data, mask, cb) {\n let buf;\n\n if (code === undefined) {\n buf = EMPTY_BUFFER;\n } else if (typeof code !== 'number' || !isValidStatusCode(code)) {\n throw new TypeError('First argument must be a valid error code number');\n } else if (data === undefined || !data.length) {\n buf = Buffer.allocUnsafe(2);\n buf.writeUInt16BE(code, 0);\n } else {\n const length = Buffer.byteLength(data);\n\n if (length > 123) {\n throw new RangeError('The message must not be greater than 123 bytes');\n }\n\n buf = Buffer.allocUnsafe(2 + length);\n buf.writeUInt16BE(code, 0);\n\n if (typeof data === 'string') {\n buf.write(data, 2);\n } else {\n buf.set(data, 2);\n }\n }\n\n const options = {\n [kByteLength]: buf.length,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x08,\n readOnly: false,\n rsv1: false\n };\n\n if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, buf, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(buf, options), cb);\n }\n }\n\n /**\n * Sends a ping message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n ping(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x09,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a pong message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n pong(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x0a,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a data message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Object} options Options object\n * @param {Boolean} [options.binary=false] Specifies whether `data` is binary\n * or text\n * @param {Boolean} [options.compress=false] Specifies whether or not to\n * compress `data`\n * @param {Boolean} [options.fin=false] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Function} [cb] Callback\n * @public\n */\n send(data, options, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n let opcode = options.binary ? 2 : 1;\n let rsv1 = options.compress;\n\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (this._firstFragment) {\n this._firstFragment = false;\n if (\n rsv1 &&\n perMessageDeflate &&\n perMessageDeflate.params[\n perMessageDeflate._isServer\n ? 'server_no_context_takeover'\n : 'client_no_context_takeover'\n ]\n ) {\n rsv1 = byteLength >= perMessageDeflate._threshold;\n }\n this._compress = rsv1;\n } else {\n rsv1 = false;\n opcode = 0;\n }\n\n if (options.fin) this._firstFragment = true;\n\n const opts = {\n [kByteLength]: byteLength,\n fin: options.fin,\n generateMask: this._generateMask,\n mask: options.mask,\n maskBuffer: this._maskBuffer,\n opcode,\n readOnly,\n rsv1\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, this._compress, opts, cb]);\n } else {\n this.getBlobData(data, this._compress, opts, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, this._compress, opts, cb]);\n } else {\n this.dispatch(data, this._compress, opts, cb);\n }\n }\n\n /**\n * Gets the contents of a blob as binary data.\n *\n * @param {Blob} blob The blob\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * the data\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n getBlobData(blob, compress, options, cb) {\n this._bufferedBytes += options[kByteLength];\n this._state = GET_BLOB_DATA;\n\n blob\n .arrayBuffer()\n .then((arrayBuffer) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while the blob was being read'\n );\n\n //\n // `callCallbacks` is called in the next tick to ensure that errors\n // that might be thrown in the callbacks behave like errors thrown\n // outside the promise chain.\n //\n process.nextTick(callCallbacks, this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n const data = toBuffer(arrayBuffer);\n\n if (!compress) {\n this._state = DEFAULT;\n this.sendFrame(Sender.frame(data, options), cb);\n this.dequeue();\n } else {\n this.dispatch(data, compress, options, cb);\n }\n })\n .catch((err) => {\n //\n // `onError` is called in the next tick for the same reason that\n // `callCallbacks` above is.\n //\n process.nextTick(onError, this, err, cb);\n });\n }\n\n /**\n * Dispatches a message.\n *\n * @param {(Buffer|String)} data The message to send\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * `data`\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n dispatch(data, compress, options, cb) {\n if (!compress) {\n this.sendFrame(Sender.frame(data, options), cb);\n return;\n }\n\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n this._bufferedBytes += options[kByteLength];\n this._state = DEFLATING;\n perMessageDeflate.compress(data, options.fin, (_, buf) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while data was being compressed'\n );\n\n callCallbacks(this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n this._state = DEFAULT;\n options.readOnly = false;\n this.sendFrame(Sender.frame(buf, options), cb);\n this.dequeue();\n });\n }\n\n /**\n * Executes queued send operations.\n *\n * @private\n */\n dequeue() {\n while (this._state === DEFAULT && this._queue.length) {\n const params = this._queue.shift();\n\n this._bufferedBytes -= params[3][kByteLength];\n Reflect.apply(params[0], this, params.slice(1));\n }\n }\n\n /**\n * Enqueues a send operation.\n *\n * @param {Array} params Send operation parameters.\n * @private\n */\n enqueue(params) {\n this._bufferedBytes += params[3][kByteLength];\n this._queue.push(params);\n }\n\n /**\n * Sends a frame.\n *\n * @param {(Buffer | String)[]} list The frame to send\n * @param {Function} [cb] Callback\n * @private\n */\n sendFrame(list, cb) {\n if (list.length === 2) {\n this._socket.cork();\n this._socket.write(list[0]);\n this._socket.write(list[1], cb);\n this._socket.uncork();\n } else {\n this._socket.write(list[0], cb);\n }\n }\n}\n\nmodule.exports = Sender;\n\n/**\n * Calls queued callbacks with an error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error to call the callbacks with\n * @param {Function} [cb] The first callback\n * @private\n */\nfunction callCallbacks(sender, err, cb) {\n if (typeof cb === 'function') cb(err);\n\n for (let i = 0; i < sender._queue.length; i++) {\n const params = sender._queue[i];\n const callback = params[params.length - 1];\n\n if (typeof callback === 'function') callback(err);\n }\n}\n\n/**\n * Handles a `Sender` error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error\n * @param {Function} [cb] The first pending callback\n * @private\n */\nfunction onError(sender, err, cb) {\n callCallbacks(sender, err, cb);\n sender.onerror(err);\n}\n","'use strict';\n\nconst { kForOnEventAttribute, kListener } = require('./constants');\n\nconst kCode = Symbol('kCode');\nconst kData = Symbol('kData');\nconst kError = Symbol('kError');\nconst kMessage = Symbol('kMessage');\nconst kReason = Symbol('kReason');\nconst kTarget = Symbol('kTarget');\nconst kType = Symbol('kType');\nconst kWasClean = Symbol('kWasClean');\n\n/**\n * Class representing an event.\n */\nclass Event {\n /**\n * Create a new `Event`.\n *\n * @param {String} type The name of the event\n * @throws {TypeError} If the `type` argument is not specified\n */\n constructor(type) {\n this[kTarget] = null;\n this[kType] = type;\n }\n\n /**\n * @type {*}\n */\n get target() {\n return this[kTarget];\n }\n\n /**\n * @type {String}\n */\n get type() {\n return this[kType];\n }\n}\n\nObject.defineProperty(Event.prototype, 'target', { enumerable: true });\nObject.defineProperty(Event.prototype, 'type', { enumerable: true });\n\n/**\n * Class representing a close event.\n *\n * @extends Event\n */\nclass CloseEvent extends Event {\n /**\n * Create a new `CloseEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {Number} [options.code=0] The status code explaining why the\n * connection was closed\n * @param {String} [options.reason=''] A human-readable string explaining why\n * the connection was closed\n * @param {Boolean} [options.wasClean=false] Indicates whether or not the\n * connection was cleanly closed\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kCode] = options.code === undefined ? 0 : options.code;\n this[kReason] = options.reason === undefined ? '' : options.reason;\n this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;\n }\n\n /**\n * @type {Number}\n */\n get code() {\n return this[kCode];\n }\n\n /**\n * @type {String}\n */\n get reason() {\n return this[kReason];\n }\n\n /**\n * @type {Boolean}\n */\n get wasClean() {\n return this[kWasClean];\n }\n}\n\nObject.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });\n\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent extends Event {\n /**\n * Create a new `ErrorEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.error=null] The error that generated this event\n * @param {String} [options.message=''] The error message\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kError] = options.error === undefined ? null : options.error;\n this[kMessage] = options.message === undefined ? '' : options.message;\n }\n\n /**\n * @type {*}\n */\n get error() {\n return this[kError];\n }\n\n /**\n * @type {String}\n */\n get message() {\n return this[kMessage];\n }\n}\n\nObject.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });\n\n/**\n * Class representing a message event.\n *\n * @extends Event\n */\nclass MessageEvent extends Event {\n /**\n * Create a new `MessageEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.data=null] The message content\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kData] = options.data === undefined ? null : options.data;\n }\n\n /**\n * @type {*}\n */\n get data() {\n return this[kData];\n }\n}\n\nObject.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });\n\n/**\n * This provides methods for emulating the `EventTarget` interface. It's not\n * meant to be used directly.\n *\n * @mixin\n */\nconst EventTarget = {\n /**\n * Register an event listener.\n *\n * @param {String} type A string representing the event type to listen for\n * @param {(Function|Object)} handler The listener to add\n * @param {Object} [options] An options object specifies characteristics about\n * the event listener\n * @param {Boolean} [options.once=false] A `Boolean` indicating that the\n * listener should be invoked at most once after being added. If `true`,\n * the listener would be automatically removed when invoked.\n * @public\n */\n addEventListener(type, handler, options = {}) {\n for (const listener of this.listeners(type)) {\n if (\n !options[kForOnEventAttribute] &&\n listener[kListener] === handler &&\n !listener[kForOnEventAttribute]\n ) {\n return;\n }\n }\n\n let wrapper;\n\n if (type === 'message') {\n wrapper = function onMessage(data, isBinary) {\n const event = new MessageEvent('message', {\n data: isBinary ? data : data.toString()\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'close') {\n wrapper = function onClose(code, message) {\n const event = new CloseEvent('close', {\n code,\n reason: message.toString(),\n wasClean: this._closeFrameReceived && this._closeFrameSent\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'error') {\n wrapper = function onError(error) {\n const event = new ErrorEvent('error', {\n error,\n message: error.message\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'open') {\n wrapper = function onOpen() {\n const event = new Event('open');\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else {\n return;\n }\n\n wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];\n wrapper[kListener] = handler;\n\n if (options.once) {\n this.once(type, wrapper);\n } else {\n this.on(type, wrapper);\n }\n },\n\n /**\n * Remove an event listener.\n *\n * @param {String} type A string representing the event type to remove\n * @param {(Function|Object)} handler The listener to remove\n * @public\n */\n removeEventListener(type, handler) {\n for (const listener of this.listeners(type)) {\n if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {\n this.removeListener(type, listener);\n break;\n }\n }\n }\n};\n\nmodule.exports = {\n CloseEvent,\n ErrorEvent,\n Event,\n EventTarget,\n MessageEvent\n};\n\n/**\n * Call an event listener\n *\n * @param {(Function|Object)} listener The listener to call\n * @param {*} thisArg The value to use as `this`` when calling the listener\n * @param {Event} event The event to pass to the listener\n * @private\n */\nfunction callListener(listener, thisArg, event) {\n if (typeof listener === 'object' && listener.handleEvent) {\n listener.handleEvent.call(listener, event);\n } else {\n listener.call(thisArg, event);\n }\n}\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Adds an offer to the map of extension offers or a parameter to the map of\n * parameters.\n *\n * @param {Object} dest The map of extension offers or parameters\n * @param {String} name The extension or parameter name\n * @param {(Object|Boolean|String)} elem The extension parameters or the\n * parameter value\n * @private\n */\nfunction push(dest, name, elem) {\n if (dest[name] === undefined) dest[name] = [elem];\n else dest[name].push(elem);\n}\n\n/**\n * Parses the `Sec-WebSocket-Extensions` header into an object.\n *\n * @param {String} header The field value of the header\n * @return {Object} The parsed object\n * @public\n */\nfunction parse(header) {\n const offers = Object.create(null);\n let params = Object.create(null);\n let mustUnescape = false;\n let isEscaping = false;\n let inQuotes = false;\n let extensionName;\n let paramName;\n let start = -1;\n let code = -1;\n let end = -1;\n let i = 0;\n\n for (; i < header.length; i++) {\n code = header.charCodeAt(i);\n\n if (extensionName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n const name = header.slice(start, end);\n if (code === 0x2c) {\n push(offers, name, params);\n params = Object.create(null);\n } else {\n extensionName = name;\n }\n\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (paramName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x20 || code === 0x09) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n push(params, header.slice(start, end), true);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n start = end = -1;\n } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {\n paramName = header.slice(start, i);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else {\n //\n // The value of a quoted-string after unescaping must conform to the\n // token ABNF, so only token characters are valid.\n // Ref: https://tools.ietf.org/html/rfc6455#section-9.1\n //\n if (isEscaping) {\n if (tokenChars[code] !== 1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n if (start === -1) start = i;\n else if (!mustUnescape) mustUnescape = true;\n isEscaping = false;\n } else if (inQuotes) {\n if (tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x22 /* '\"' */ && start !== -1) {\n inQuotes = false;\n end = i;\n } else if (code === 0x5c /* '\\' */) {\n isEscaping = true;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {\n inQuotes = true;\n } else if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (start !== -1 && (code === 0x20 || code === 0x09)) {\n if (end === -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n let value = header.slice(start, end);\n if (mustUnescape) {\n value = value.replace(/\\\\/g, '');\n mustUnescape = false;\n }\n push(params, paramName, value);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n paramName = undefined;\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n }\n\n if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n if (end === -1) end = i;\n const token = header.slice(start, end);\n if (extensionName === undefined) {\n push(offers, token, params);\n } else {\n if (paramName === undefined) {\n push(params, token, true);\n } else if (mustUnescape) {\n push(params, paramName, token.replace(/\\\\/g, ''));\n } else {\n push(params, paramName, token);\n }\n push(offers, extensionName, params);\n }\n\n return offers;\n}\n\n/**\n * Builds the `Sec-WebSocket-Extensions` header field value.\n *\n * @param {Object} extensions The map of extensions and parameters to format\n * @return {String} A string representing the given object\n * @public\n */\nfunction format(extensions) {\n return Object.keys(extensions)\n .map((extension) => {\n let configurations = extensions[extension];\n if (!Array.isArray(configurations)) configurations = [configurations];\n return configurations\n .map((params) => {\n return [extension]\n .concat(\n Object.keys(params).map((k) => {\n let values = params[k];\n if (!Array.isArray(values)) values = [values];\n return values\n .map((v) => (v === true ? k : `${k}=${v}`))\n .join('; ');\n })\n )\n .join('; ');\n })\n .join(', ');\n })\n .join(', ');\n}\n\nmodule.exports = { format, parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex|Readable$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst https = require('https');\nconst http = require('http');\nconst net = require('net');\nconst tls = require('tls');\nconst { randomBytes, createHash } = require('crypto');\nconst { Duplex, Readable } = require('stream');\nconst { URL } = require('url');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst Receiver = require('./receiver');\nconst Sender = require('./sender');\nconst { isBlob } = require('./validation');\n\nconst {\n BINARY_TYPES,\n CLOSE_TIMEOUT,\n EMPTY_BUFFER,\n GUID,\n kForOnEventAttribute,\n kListener,\n kStatusCode,\n kWebSocket,\n NOOP\n} = require('./constants');\nconst {\n EventTarget: { addEventListener, removeEventListener }\n} = require('./event-target');\nconst { format, parse } = require('./extension');\nconst { toBuffer } = require('./buffer-util');\n\nconst kAborted = Symbol('kAborted');\nconst protocolVersions = [8, 13];\nconst readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];\nconst subprotocolRegex = /^[!#$%&'*+\\-.0-9A-Z^_`|a-z~]+$/;\n\n/**\n * Class representing a WebSocket.\n *\n * @extends EventEmitter\n */\nclass WebSocket extends EventEmitter {\n /**\n * Create a new `WebSocket`.\n *\n * @param {(String|URL)} address The URL to which to connect\n * @param {(String|String[])} [protocols] The subprotocols\n * @param {Object} [options] Connection options\n */\n constructor(address, protocols, options) {\n super();\n\n this._binaryType = BINARY_TYPES[0];\n this._closeCode = 1006;\n this._closeFrameReceived = false;\n this._closeFrameSent = false;\n this._closeMessage = EMPTY_BUFFER;\n this._closeTimer = null;\n this._errorEmitted = false;\n this._extensions = {};\n this._paused = false;\n this._protocol = '';\n this._readyState = WebSocket.CONNECTING;\n this._receiver = null;\n this._sender = null;\n this._socket = null;\n\n if (address !== null) {\n this._bufferedAmount = 0;\n this._isServer = false;\n this._redirects = 0;\n\n if (protocols === undefined) {\n protocols = [];\n } else if (!Array.isArray(protocols)) {\n if (typeof protocols === 'object' && protocols !== null) {\n options = protocols;\n protocols = [];\n } else {\n protocols = [protocols];\n }\n }\n\n initAsClient(this, address, protocols, options);\n } else {\n this._autoPong = options.autoPong;\n this._closeTimeout = options.closeTimeout;\n this._isServer = true;\n }\n }\n\n /**\n * For historical reasons, the custom \"nodebuffer\" type is used by the default\n * instead of \"blob\".\n *\n * @type {String}\n */\n get binaryType() {\n return this._binaryType;\n }\n\n set binaryType(type) {\n if (!BINARY_TYPES.includes(type)) return;\n\n this._binaryType = type;\n\n //\n // Allow to change `binaryType` on the fly.\n //\n if (this._receiver) this._receiver._binaryType = type;\n }\n\n /**\n * @type {Number}\n */\n get bufferedAmount() {\n if (!this._socket) return this._bufferedAmount;\n\n return this._socket._writableState.length + this._sender._bufferedBytes;\n }\n\n /**\n * @type {String}\n */\n get extensions() {\n return Object.keys(this._extensions).join();\n }\n\n /**\n * @type {Boolean}\n */\n get isPaused() {\n return this._paused;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onclose() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onerror() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onopen() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onmessage() {\n return null;\n }\n\n /**\n * @type {String}\n */\n get protocol() {\n return this._protocol;\n }\n\n /**\n * @type {Number}\n */\n get readyState() {\n return this._readyState;\n }\n\n /**\n * @type {String}\n */\n get url() {\n return this._url;\n }\n\n /**\n * Set up the socket and the internal resources.\n *\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Object} options Options object\n * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.maxPayload=0] The maximum allowed message size\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\n setSocket(socket, head, options) {\n const receiver = new Receiver({\n allowSynchronousEvents: options.allowSynchronousEvents,\n binaryType: this.binaryType,\n extensions: this._extensions,\n isServer: this._isServer,\n maxPayload: options.maxPayload,\n skipUTF8Validation: options.skipUTF8Validation\n });\n\n const sender = new Sender(socket, this._extensions, options.generateMask);\n\n this._receiver = receiver;\n this._sender = sender;\n this._socket = socket;\n\n receiver[kWebSocket] = this;\n sender[kWebSocket] = this;\n socket[kWebSocket] = this;\n\n receiver.on('conclude', receiverOnConclude);\n receiver.on('drain', receiverOnDrain);\n receiver.on('error', receiverOnError);\n receiver.on('message', receiverOnMessage);\n receiver.on('ping', receiverOnPing);\n receiver.on('pong', receiverOnPong);\n\n sender.onerror = senderOnError;\n\n //\n // These methods may not be available if `socket` is just a `Duplex`.\n //\n if (socket.setTimeout) socket.setTimeout(0);\n if (socket.setNoDelay) socket.setNoDelay();\n\n if (head.length > 0) socket.unshift(head);\n\n socket.on('close', socketOnClose);\n socket.on('data', socketOnData);\n socket.on('end', socketOnEnd);\n socket.on('error', socketOnError);\n\n this._readyState = WebSocket.OPEN;\n this.emit('open');\n }\n\n /**\n * Emit the `'close'` event.\n *\n * @private\n */\n emitClose() {\n if (!this._socket) {\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n return;\n }\n\n if (this._extensions[PerMessageDeflate.extensionName]) {\n this._extensions[PerMessageDeflate.extensionName].cleanup();\n }\n\n this._receiver.removeAllListeners();\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n }\n\n /**\n * Start a closing handshake.\n *\n * +----------+ +-----------+ +----------+\n * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -\n * | +----------+ +-----------+ +----------+ |\n * +----------+ +-----------+ |\n * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING\n * +----------+ +-----------+ |\n * | | | +---+ |\n * +------------------------+-->|fin| - - - -\n * | +---+ | +---+\n * - - - - -|fin|<---------------------+\n * +---+\n *\n * @param {Number} [code] Status code explaining why the connection is closing\n * @param {(String|Buffer)} [data] The reason why the connection is\n * closing\n * @public\n */\n close(code, data) {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this.readyState === WebSocket.CLOSING) {\n if (\n this._closeFrameSent &&\n (this._closeFrameReceived || this._receiver._writableState.errorEmitted)\n ) {\n this._socket.end();\n }\n\n return;\n }\n\n this._readyState = WebSocket.CLOSING;\n this._sender.close(code, data, !this._isServer, (err) => {\n //\n // This error is handled by the `'error'` listener on the socket. We only\n // want to know if the close frame has been sent here.\n //\n if (err) return;\n\n this._closeFrameSent = true;\n\n if (\n this._closeFrameReceived ||\n this._receiver._writableState.errorEmitted\n ) {\n this._socket.end();\n }\n });\n\n setCloseTimer(this);\n }\n\n /**\n * Pause the socket.\n *\n * @public\n */\n pause() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = true;\n this._socket.pause();\n }\n\n /**\n * Send a ping.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the ping is sent\n * @public\n */\n ping(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.ping(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Send a pong.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the pong is sent\n * @public\n */\n pong(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.pong(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Resume the socket.\n *\n * @public\n */\n resume() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = false;\n if (!this._receiver._writableState.needDrain) this._socket.resume();\n }\n\n /**\n * Send a data message.\n *\n * @param {*} data The message to send\n * @param {Object} [options] Options object\n * @param {Boolean} [options.binary] Specifies whether `data` is binary or\n * text\n * @param {Boolean} [options.compress] Specifies whether or not to compress\n * `data`\n * @param {Boolean} [options.fin=true] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when data is written out\n * @public\n */\n send(data, options, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof options === 'function') {\n cb = options;\n options = {};\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n const opts = {\n binary: typeof data !== 'string',\n mask: !this._isServer,\n compress: true,\n fin: true,\n ...options\n };\n\n if (!this._extensions[PerMessageDeflate.extensionName]) {\n opts.compress = false;\n }\n\n this._sender.send(data || EMPTY_BUFFER, opts, cb);\n }\n\n /**\n * Forcibly close the connection.\n *\n * @public\n */\n terminate() {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this._socket) {\n this._readyState = WebSocket.CLOSING;\n this._socket.destroy();\n }\n }\n}\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n[\n 'binaryType',\n 'bufferedAmount',\n 'extensions',\n 'isPaused',\n 'protocol',\n 'readyState',\n 'url'\n].forEach((property) => {\n Object.defineProperty(WebSocket.prototype, property, { enumerable: true });\n});\n\n//\n// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.\n// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface\n//\n['open', 'error', 'close', 'message'].forEach((method) => {\n Object.defineProperty(WebSocket.prototype, `on${method}`, {\n enumerable: true,\n get() {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) return listener[kListener];\n }\n\n return null;\n },\n set(handler) {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) {\n this.removeListener(method, listener);\n break;\n }\n }\n\n if (typeof handler !== 'function') return;\n\n this.addEventListener(method, handler, {\n [kForOnEventAttribute]: true\n });\n }\n });\n});\n\nWebSocket.prototype.addEventListener = addEventListener;\nWebSocket.prototype.removeEventListener = removeEventListener;\n\nmodule.exports = WebSocket;\n\n/**\n * Initialize a WebSocket client.\n *\n * @param {WebSocket} websocket The client to initialize\n * @param {(String|URL)} address The URL to which to connect\n * @param {Array} protocols The subprotocols\n * @param {Object} [options] Connection options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any\n * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple\n * times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait\n * for the closing handshake to finish after `websocket.close()` is called\n * @param {Function} [options.finishRequest] A function which can be used to\n * customize the headers of each http request before it is sent\n * @param {Boolean} [options.followRedirects=false] Whether or not to follow\n * redirects\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the\n * handshake request\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Number} [options.maxRedirects=10] The maximum number of redirects\n * allowed\n * @param {String} [options.origin] Value of the `Origin` or\n * `Sec-WebSocket-Origin` header\n * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable\n * permessage-deflate\n * @param {Number} [options.protocolVersion=13] Value of the\n * `Sec-WebSocket-Version` header\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\nfunction initAsClient(websocket, address, protocols, options) {\n const opts = {\n allowSynchronousEvents: true,\n autoPong: true,\n closeTimeout: CLOSE_TIMEOUT,\n protocolVersion: protocolVersions[1],\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: true,\n followRedirects: false,\n maxRedirects: 10,\n ...options,\n socketPath: undefined,\n hostname: undefined,\n protocol: undefined,\n timeout: undefined,\n method: 'GET',\n host: undefined,\n path: undefined,\n port: undefined\n };\n\n websocket._autoPong = opts.autoPong;\n websocket._closeTimeout = opts.closeTimeout;\n\n if (!protocolVersions.includes(opts.protocolVersion)) {\n throw new RangeError(\n `Unsupported protocol version: ${opts.protocolVersion} ` +\n `(supported versions: ${protocolVersions.join(', ')})`\n );\n }\n\n let parsedUrl;\n\n if (address instanceof URL) {\n parsedUrl = address;\n } else {\n try {\n parsedUrl = new URL(address);\n } catch (e) {\n throw new SyntaxError(`Invalid URL: ${address}`);\n }\n }\n\n if (parsedUrl.protocol === 'http:') {\n parsedUrl.protocol = 'ws:';\n } else if (parsedUrl.protocol === 'https:') {\n parsedUrl.protocol = 'wss:';\n }\n\n websocket._url = parsedUrl.href;\n\n const isSecure = parsedUrl.protocol === 'wss:';\n const isIpcUrl = parsedUrl.protocol === 'ws+unix:';\n let invalidUrlMessage;\n\n if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {\n invalidUrlMessage =\n 'The URL\\'s protocol must be one of \"ws:\", \"wss:\", ' +\n '\"http:\", \"https:\", or \"ws+unix:\"';\n } else if (isIpcUrl && !parsedUrl.pathname) {\n invalidUrlMessage = \"The URL's pathname is empty\";\n } else if (parsedUrl.hash) {\n invalidUrlMessage = 'The URL contains a fragment identifier';\n }\n\n if (invalidUrlMessage) {\n const err = new SyntaxError(invalidUrlMessage);\n\n if (websocket._redirects === 0) {\n throw err;\n } else {\n emitErrorAndClose(websocket, err);\n return;\n }\n }\n\n const defaultPort = isSecure ? 443 : 80;\n const key = randomBytes(16).toString('base64');\n const request = isSecure ? https.request : http.request;\n const protocolSet = new Set();\n let perMessageDeflate;\n\n opts.createConnection =\n opts.createConnection || (isSecure ? tlsConnect : netConnect);\n opts.defaultPort = opts.defaultPort || defaultPort;\n opts.port = parsedUrl.port || defaultPort;\n opts.host = parsedUrl.hostname.startsWith('[')\n ? parsedUrl.hostname.slice(1, -1)\n : parsedUrl.hostname;\n opts.headers = {\n ...opts.headers,\n 'Sec-WebSocket-Version': opts.protocolVersion,\n 'Sec-WebSocket-Key': key,\n Connection: 'Upgrade',\n Upgrade: 'websocket'\n };\n opts.path = parsedUrl.pathname + parsedUrl.search;\n opts.timeout = opts.handshakeTimeout;\n\n if (opts.perMessageDeflate) {\n perMessageDeflate = new PerMessageDeflate(\n opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},\n false,\n opts.maxPayload\n );\n opts.headers['Sec-WebSocket-Extensions'] = format({\n [PerMessageDeflate.extensionName]: perMessageDeflate.offer()\n });\n }\n if (protocols.length) {\n for (const protocol of protocols) {\n if (\n typeof protocol !== 'string' ||\n !subprotocolRegex.test(protocol) ||\n protocolSet.has(protocol)\n ) {\n throw new SyntaxError(\n 'An invalid or duplicated subprotocol was specified'\n );\n }\n\n protocolSet.add(protocol);\n }\n\n opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');\n }\n if (opts.origin) {\n if (opts.protocolVersion < 13) {\n opts.headers['Sec-WebSocket-Origin'] = opts.origin;\n } else {\n opts.headers.Origin = opts.origin;\n }\n }\n if (parsedUrl.username || parsedUrl.password) {\n opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;\n }\n\n if (isIpcUrl) {\n const parts = opts.path.split(':');\n\n opts.socketPath = parts[0];\n opts.path = parts[1];\n }\n\n let req;\n\n if (opts.followRedirects) {\n if (websocket._redirects === 0) {\n websocket._originalIpc = isIpcUrl;\n websocket._originalSecure = isSecure;\n websocket._originalHostOrSocketPath = isIpcUrl\n ? opts.socketPath\n : parsedUrl.host;\n\n const headers = options && options.headers;\n\n //\n // Shallow copy the user provided options so that headers can be changed\n // without mutating the original object.\n //\n options = { ...options, headers: {} };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n options.headers[key.toLowerCase()] = value;\n }\n }\n } else if (websocket.listenerCount('redirect') === 0) {\n const isSameHost = isIpcUrl\n ? websocket._originalIpc\n ? opts.socketPath === websocket._originalHostOrSocketPath\n : false\n : websocket._originalIpc\n ? false\n : parsedUrl.host === websocket._originalHostOrSocketPath;\n\n if (!isSameHost || (websocket._originalSecure && !isSecure)) {\n //\n // Match curl 7.77.0 behavior and drop the following headers. These\n // headers are also dropped when following a redirect to a subdomain.\n //\n delete opts.headers.authorization;\n delete opts.headers.cookie;\n\n if (!isSameHost) delete opts.headers.host;\n\n opts.auth = undefined;\n }\n }\n\n //\n // Match curl 7.77.0 behavior and make the first `Authorization` header win.\n // If the `Authorization` header is set, then there is nothing to do as it\n // will take precedence.\n //\n if (opts.auth && !options.headers.authorization) {\n options.headers.authorization =\n 'Basic ' + Buffer.from(opts.auth).toString('base64');\n }\n\n req = websocket._req = request(opts);\n\n if (websocket._redirects) {\n //\n // Unlike what is done for the `'upgrade'` event, no early exit is\n // triggered here if the user calls `websocket.close()` or\n // `websocket.terminate()` from a listener of the `'redirect'` event. This\n // is because the user can also call `request.destroy()` with an error\n // before calling `websocket.close()` or `websocket.terminate()` and this\n // would result in an error being emitted on the `request` object with no\n // `'error'` event listeners attached.\n //\n websocket.emit('redirect', websocket.url, req);\n }\n } else {\n req = websocket._req = request(opts);\n }\n\n if (opts.timeout) {\n req.on('timeout', () => {\n abortHandshake(websocket, req, 'Opening handshake has timed out');\n });\n }\n\n req.on('error', (err) => {\n if (req === null || req[kAborted]) return;\n\n req = websocket._req = null;\n emitErrorAndClose(websocket, err);\n });\n\n req.on('response', (res) => {\n const location = res.headers.location;\n const statusCode = res.statusCode;\n\n if (\n location &&\n opts.followRedirects &&\n statusCode >= 300 &&\n statusCode < 400\n ) {\n if (++websocket._redirects > opts.maxRedirects) {\n abortHandshake(websocket, req, 'Maximum redirects exceeded');\n return;\n }\n\n req.abort();\n\n let addr;\n\n try {\n addr = new URL(location, address);\n } catch (e) {\n const err = new SyntaxError(`Invalid URL: ${location}`);\n emitErrorAndClose(websocket, err);\n return;\n }\n\n initAsClient(websocket, addr, protocols, options);\n } else if (!websocket.emit('unexpected-response', req, res)) {\n abortHandshake(\n websocket,\n req,\n `Unexpected server response: ${res.statusCode}`\n );\n }\n });\n\n req.on('upgrade', (res, socket, head) => {\n websocket.emit('upgrade', res);\n\n //\n // The user may have closed the connection from a listener of the\n // `'upgrade'` event.\n //\n if (websocket.readyState !== WebSocket.CONNECTING) return;\n\n req = websocket._req = null;\n\n const upgrade = res.headers.upgrade;\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n abortHandshake(websocket, socket, 'Invalid Upgrade header');\n return;\n }\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n if (res.headers['sec-websocket-accept'] !== digest) {\n abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');\n return;\n }\n\n const serverProt = res.headers['sec-websocket-protocol'];\n let protError;\n\n if (serverProt !== undefined) {\n if (!protocolSet.size) {\n protError = 'Server sent a subprotocol but none was requested';\n } else if (!protocolSet.has(serverProt)) {\n protError = 'Server sent an invalid subprotocol';\n }\n } else if (protocolSet.size) {\n protError = 'Server sent no subprotocol';\n }\n\n if (protError) {\n abortHandshake(websocket, socket, protError);\n return;\n }\n\n if (serverProt) websocket._protocol = serverProt;\n\n const secWebSocketExtensions = res.headers['sec-websocket-extensions'];\n\n if (secWebSocketExtensions !== undefined) {\n if (!perMessageDeflate) {\n const message =\n 'Server sent a Sec-WebSocket-Extensions header but no extension ' +\n 'was requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n let extensions;\n\n try {\n extensions = parse(secWebSocketExtensions);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n const extensionNames = Object.keys(extensions);\n\n if (\n extensionNames.length !== 1 ||\n extensionNames[0] !== PerMessageDeflate.extensionName\n ) {\n const message = 'Server indicated an extension that was not requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n try {\n perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n websocket._extensions[PerMessageDeflate.extensionName] =\n perMessageDeflate;\n }\n\n websocket.setSocket(socket, head, {\n allowSynchronousEvents: opts.allowSynchronousEvents,\n generateMask: opts.generateMask,\n maxPayload: opts.maxPayload,\n skipUTF8Validation: opts.skipUTF8Validation\n });\n });\n\n if (opts.finishRequest) {\n opts.finishRequest(req, websocket);\n } else {\n req.end();\n }\n}\n\n/**\n * Emit the `'error'` and `'close'` events.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {Error} The error to emit\n * @private\n */\nfunction emitErrorAndClose(websocket, err) {\n websocket._readyState = WebSocket.CLOSING;\n //\n // The following assignment is practically useless and is done only for\n // consistency.\n //\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n websocket.emitClose();\n}\n\n/**\n * Create a `net.Socket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {net.Socket} The newly created socket used to start the connection\n * @private\n */\nfunction netConnect(options) {\n options.path = options.socketPath;\n return net.connect(options);\n}\n\n/**\n * Create a `tls.TLSSocket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {tls.TLSSocket} The newly created socket used to start the connection\n * @private\n */\nfunction tlsConnect(options) {\n options.path = undefined;\n\n if (!options.servername && options.servername !== '') {\n options.servername = net.isIP(options.host) ? '' : options.host;\n }\n\n return tls.connect(options);\n}\n\n/**\n * Abort the handshake and emit an error.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to\n * abort or the socket to destroy\n * @param {String} message The error message\n * @private\n */\nfunction abortHandshake(websocket, stream, message) {\n websocket._readyState = WebSocket.CLOSING;\n\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshake);\n\n if (stream.setHeader) {\n stream[kAborted] = true;\n stream.abort();\n\n if (stream.socket && !stream.socket.destroyed) {\n //\n // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if\n // called after the request completed. See\n // https://github.com/websockets/ws/issues/1869.\n //\n stream.socket.destroy();\n }\n\n process.nextTick(emitErrorAndClose, websocket, err);\n } else {\n stream.destroy(err);\n stream.once('error', websocket.emit.bind(websocket, 'error'));\n stream.once('close', websocket.emitClose.bind(websocket));\n }\n}\n\n/**\n * Handle cases where the `ping()`, `pong()`, or `send()` methods are called\n * when the `readyState` attribute is `CLOSING` or `CLOSED`.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {*} [data] The data to send\n * @param {Function} [cb] Callback\n * @private\n */\nfunction sendAfterClose(websocket, data, cb) {\n if (data) {\n const length = isBlob(data) ? data.size : toBuffer(data).length;\n\n //\n // The `_bufferedAmount` property is used only when the peer is a client and\n // the opening handshake fails. Under these circumstances, in fact, the\n // `setSocket()` method is not called, so the `_socket` and `_sender`\n // properties are set to `null`.\n //\n if (websocket._socket) websocket._sender._bufferedBytes += length;\n else websocket._bufferedAmount += length;\n }\n\n if (cb) {\n const err = new Error(\n `WebSocket is not open: readyState ${websocket.readyState} ` +\n `(${readyStates[websocket.readyState]})`\n );\n process.nextTick(cb, err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'conclude'` event.\n *\n * @param {Number} code The status code\n * @param {Buffer} reason The reason for closing\n * @private\n */\nfunction receiverOnConclude(code, reason) {\n const websocket = this[kWebSocket];\n\n websocket._closeFrameReceived = true;\n websocket._closeMessage = reason;\n websocket._closeCode = code;\n\n if (websocket._socket[kWebSocket] === undefined) return;\n\n websocket._socket.removeListener('data', socketOnData);\n process.nextTick(resume, websocket._socket);\n\n if (code === 1005) websocket.close();\n else websocket.close(code, reason);\n}\n\n/**\n * The listener of the `Receiver` `'drain'` event.\n *\n * @private\n */\nfunction receiverOnDrain() {\n const websocket = this[kWebSocket];\n\n if (!websocket.isPaused) websocket._socket.resume();\n}\n\n/**\n * The listener of the `Receiver` `'error'` event.\n *\n * @param {(RangeError|Error)} err The emitted error\n * @private\n */\nfunction receiverOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket._socket[kWebSocket] !== undefined) {\n websocket._socket.removeListener('data', socketOnData);\n\n //\n // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See\n // https://github.com/websockets/ws/issues/1940.\n //\n process.nextTick(resume, websocket._socket);\n\n websocket.close(err[kStatusCode]);\n }\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'finish'` event.\n *\n * @private\n */\nfunction receiverOnFinish() {\n this[kWebSocket].emitClose();\n}\n\n/**\n * The listener of the `Receiver` `'message'` event.\n *\n * @param {Buffer|ArrayBuffer|Buffer[])} data The message\n * @param {Boolean} isBinary Specifies whether the message is binary or not\n * @private\n */\nfunction receiverOnMessage(data, isBinary) {\n this[kWebSocket].emit('message', data, isBinary);\n}\n\n/**\n * The listener of the `Receiver` `'ping'` event.\n *\n * @param {Buffer} data The data included in the ping frame\n * @private\n */\nfunction receiverOnPing(data) {\n const websocket = this[kWebSocket];\n\n if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);\n websocket.emit('ping', data);\n}\n\n/**\n * The listener of the `Receiver` `'pong'` event.\n *\n * @param {Buffer} data The data included in the pong frame\n * @private\n */\nfunction receiverOnPong(data) {\n this[kWebSocket].emit('pong', data);\n}\n\n/**\n * Resume a readable stream\n *\n * @param {Readable} stream The readable stream\n * @private\n */\nfunction resume(stream) {\n stream.resume();\n}\n\n/**\n * The `Sender` error event handler.\n *\n * @param {Error} The error\n * @private\n */\nfunction senderOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket.readyState === WebSocket.CLOSED) return;\n if (websocket.readyState === WebSocket.OPEN) {\n websocket._readyState = WebSocket.CLOSING;\n setCloseTimer(websocket);\n }\n\n //\n // `socket.end()` is used instead of `socket.destroy()` to allow the other\n // peer to finish sending queued data. There is no need to set a timer here\n // because `CLOSING` means that it is already set or not needed.\n //\n this._socket.end();\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * Set a timer to destroy the underlying raw socket of a WebSocket.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @private\n */\nfunction setCloseTimer(websocket) {\n websocket._closeTimer = setTimeout(\n websocket._socket.destroy.bind(websocket._socket),\n websocket._closeTimeout\n );\n}\n\n/**\n * The listener of the socket `'close'` event.\n *\n * @private\n */\nfunction socketOnClose() {\n const websocket = this[kWebSocket];\n\n this.removeListener('close', socketOnClose);\n this.removeListener('data', socketOnData);\n this.removeListener('end', socketOnEnd);\n\n websocket._readyState = WebSocket.CLOSING;\n\n //\n // The close frame might not have been received or the `'end'` event emitted,\n // for example, if the socket was destroyed due to an error. Ensure that the\n // `receiver` stream is closed after writing any remaining buffered data to\n // it. If the readable side of the socket is in flowing mode then there is no\n // buffered data as everything has been already written. If instead, the\n // socket is paused, any possible buffered data will be read as a single\n // chunk.\n //\n if (\n !this._readableState.endEmitted &&\n !websocket._closeFrameReceived &&\n !websocket._receiver._writableState.errorEmitted &&\n this._readableState.length !== 0\n ) {\n const chunk = this.read(this._readableState.length);\n\n websocket._receiver.write(chunk);\n }\n\n websocket._receiver.end();\n\n this[kWebSocket] = undefined;\n\n clearTimeout(websocket._closeTimer);\n\n if (\n websocket._receiver._writableState.finished ||\n websocket._receiver._writableState.errorEmitted\n ) {\n websocket.emitClose();\n } else {\n websocket._receiver.on('error', receiverOnFinish);\n websocket._receiver.on('finish', receiverOnFinish);\n }\n}\n\n/**\n * The listener of the socket `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction socketOnData(chunk) {\n if (!this[kWebSocket]._receiver.write(chunk)) {\n this.pause();\n }\n}\n\n/**\n * The listener of the socket `'end'` event.\n *\n * @private\n */\nfunction socketOnEnd() {\n const websocket = this[kWebSocket];\n\n websocket._readyState = WebSocket.CLOSING;\n websocket._receiver.end();\n this.end();\n}\n\n/**\n * The listener of the socket `'error'` event.\n *\n * @private\n */\nfunction socketOnError() {\n const websocket = this[kWebSocket];\n\n this.removeListener('error', socketOnError);\n this.on('error', NOOP);\n\n if (websocket) {\n websocket._readyState = WebSocket.CLOSING;\n this.destroy();\n }\n}\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^WebSocket$\" }] */\n'use strict';\n\nconst WebSocket = require('./websocket');\nconst { Duplex } = require('stream');\n\n/**\n * Emits the `'close'` event on a stream.\n *\n * @param {Duplex} stream The stream.\n * @private\n */\nfunction emitClose(stream) {\n stream.emit('close');\n}\n\n/**\n * The listener of the `'end'` event.\n *\n * @private\n */\nfunction duplexOnEnd() {\n if (!this.destroyed && this._writableState.finished) {\n this.destroy();\n }\n}\n\n/**\n * The listener of the `'error'` event.\n *\n * @param {Error} err The error\n * @private\n */\nfunction duplexOnError(err) {\n this.removeListener('error', duplexOnError);\n this.destroy();\n if (this.listenerCount('error') === 0) {\n // Do not suppress the throwing behavior.\n this.emit('error', err);\n }\n}\n\n/**\n * Wraps a `WebSocket` in a duplex stream.\n *\n * @param {WebSocket} ws The `WebSocket` to wrap\n * @param {Object} [options] The options for the `Duplex` constructor\n * @return {Duplex} The duplex stream\n * @public\n */\nfunction createWebSocketStream(ws, options) {\n let terminateOnDestroy = true;\n\n const duplex = new Duplex({\n ...options,\n autoDestroy: false,\n emitClose: false,\n objectMode: false,\n writableObjectMode: false\n });\n\n ws.on('message', function message(msg, isBinary) {\n const data =\n !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;\n\n if (!duplex.push(data)) ws.pause();\n });\n\n ws.once('error', function error(err) {\n if (duplex.destroyed) return;\n\n // Prevent `ws.terminate()` from being called by `duplex._destroy()`.\n //\n // - If the `'error'` event is emitted before the `'open'` event, then\n // `ws.terminate()` is a noop as no socket is assigned.\n // - Otherwise, the error is re-emitted by the listener of the `'error'`\n // event of the `Receiver` object. The listener already closes the\n // connection by calling `ws.close()`. This allows a close frame to be\n // sent to the other peer. If `ws.terminate()` is called right after this,\n // then the close frame might not be sent.\n terminateOnDestroy = false;\n duplex.destroy(err);\n });\n\n ws.once('close', function close() {\n if (duplex.destroyed) return;\n\n duplex.push(null);\n });\n\n duplex._destroy = function (err, callback) {\n if (ws.readyState === ws.CLOSED) {\n callback(err);\n process.nextTick(emitClose, duplex);\n return;\n }\n\n let called = false;\n\n ws.once('error', function error(err) {\n called = true;\n callback(err);\n });\n\n ws.once('close', function close() {\n if (!called) callback(err);\n process.nextTick(emitClose, duplex);\n });\n\n if (terminateOnDestroy) ws.terminate();\n };\n\n duplex._final = function (callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._final(callback);\n });\n return;\n }\n\n // If the value of the `_socket` property is `null` it means that `ws` is a\n // client websocket and the handshake failed. In fact, when this happens, a\n // socket is never assigned to the websocket. Wait for the `'error'` event\n // that will be emitted by the websocket.\n if (ws._socket === null) return;\n\n if (ws._socket._writableState.finished) {\n callback();\n if (duplex._readableState.endEmitted) duplex.destroy();\n } else {\n ws._socket.once('finish', function finish() {\n // `duplex` is not destroyed here because the `'end'` event will be\n // emitted on `duplex` after this `'finish'` event. The EOF signaling\n // `null` chunk is, in fact, pushed when the websocket emits `'close'`.\n callback();\n });\n ws.close();\n }\n };\n\n duplex._read = function () {\n if (ws.isPaused) ws.resume();\n };\n\n duplex._write = function (chunk, encoding, callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._write(chunk, encoding, callback);\n });\n return;\n }\n\n ws.send(chunk, callback);\n };\n\n duplex.on('end', duplexOnEnd);\n duplex.on('error', duplexOnError);\n return duplex;\n}\n\nmodule.exports = createWebSocketStream;\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.\n *\n * @param {String} header The field value of the header\n * @return {Set} The subprotocol names\n * @public\n */\nfunction parse(header) {\n const protocols = new Set();\n let start = -1;\n let end = -1;\n let i = 0;\n\n for (i; i < header.length; i++) {\n const code = header.charCodeAt(i);\n\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n\n const protocol = header.slice(start, end);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n\n if (start === -1 || end !== -1) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n const protocol = header.slice(start, i);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n return protocols;\n}\n\nmodule.exports = { parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst http = require('http');\nconst { Duplex } = require('stream');\nconst { createHash } = require('crypto');\n\nconst extension = require('./extension');\nconst PerMessageDeflate = require('./permessage-deflate');\nconst subprotocol = require('./subprotocol');\nconst WebSocket = require('./websocket');\nconst { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');\n\nconst keyRegex = /^[+/0-9A-Za-z]{22}==$/;\n\nconst RUNNING = 0;\nconst CLOSING = 1;\nconst CLOSED = 2;\n\n/**\n * Class representing a WebSocket server.\n *\n * @extends EventEmitter\n */\nclass WebSocketServer extends EventEmitter {\n /**\n * Create a `WebSocketServer` instance.\n *\n * @param {Object} options Configuration options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.backlog=511] The maximum length of the queue of\n * pending connections\n * @param {Boolean} [options.clientTracking=true] Specifies whether or not to\n * track clients\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to\n * wait for the closing handshake to finish after `websocket.close()` is\n * called\n * @param {Function} [options.handleProtocols] A hook to handle protocols\n * @param {String} [options.host] The hostname where to bind the server\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Boolean} [options.noServer=false] Enable no server mode\n * @param {String} [options.path] Accept only connections matching this path\n * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable\n * permessage-deflate\n * @param {Number} [options.port] The port where to bind the server\n * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S\n * server to use\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @param {Function} [options.verifyClient] A hook to reject connections\n * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`\n * class to use. It must be the `WebSocket` class or class that extends it\n * @param {Function} [callback] A listener for the `listening` event\n */\n constructor(options, callback) {\n super();\n\n options = {\n allowSynchronousEvents: true,\n autoPong: true,\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: false,\n handleProtocols: null,\n clientTracking: true,\n closeTimeout: CLOSE_TIMEOUT,\n verifyClient: null,\n noServer: false,\n backlog: null, // use default (511 as implemented in net.js)\n server: null,\n host: null,\n path: null,\n port: null,\n WebSocket,\n ...options\n };\n\n if (\n (options.port == null && !options.server && !options.noServer) ||\n (options.port != null && (options.server || options.noServer)) ||\n (options.server && options.noServer)\n ) {\n throw new TypeError(\n 'One and only one of the \"port\", \"server\", or \"noServer\" options ' +\n 'must be specified'\n );\n }\n\n if (options.port != null) {\n this._server = http.createServer((req, res) => {\n const body = http.STATUS_CODES[426];\n\n res.writeHead(426, {\n 'Content-Length': body.length,\n 'Content-Type': 'text/plain'\n });\n res.end(body);\n });\n this._server.listen(\n options.port,\n options.host,\n options.backlog,\n callback\n );\n } else if (options.server) {\n this._server = options.server;\n }\n\n if (this._server) {\n const emitConnection = this.emit.bind(this, 'connection');\n\n this._removeListeners = addListeners(this._server, {\n listening: this.emit.bind(this, 'listening'),\n error: this.emit.bind(this, 'error'),\n upgrade: (req, socket, head) => {\n this.handleUpgrade(req, socket, head, emitConnection);\n }\n });\n }\n\n if (options.perMessageDeflate === true) options.perMessageDeflate = {};\n if (options.clientTracking) {\n this.clients = new Set();\n this._shouldEmitClose = false;\n }\n\n this.options = options;\n this._state = RUNNING;\n }\n\n /**\n * Returns the bound address, the address family name, and port of the server\n * as reported by the operating system if listening on an IP socket.\n * If the server is listening on a pipe or UNIX domain socket, the name is\n * returned as a string.\n *\n * @return {(Object|String|null)} The address of the server\n * @public\n */\n address() {\n if (this.options.noServer) {\n throw new Error('The server is operating in \"noServer\" mode');\n }\n\n if (!this._server) return null;\n return this._server.address();\n }\n\n /**\n * Stop the server from accepting new connections and emit the `'close'` event\n * when all existing connections are closed.\n *\n * @param {Function} [cb] A one-time listener for the `'close'` event\n * @public\n */\n close(cb) {\n if (this._state === CLOSED) {\n if (cb) {\n this.once('close', () => {\n cb(new Error('The server is not running'));\n });\n }\n\n process.nextTick(emitClose, this);\n return;\n }\n\n if (cb) this.once('close', cb);\n\n if (this._state === CLOSING) return;\n this._state = CLOSING;\n\n if (this.options.noServer || this.options.server) {\n if (this._server) {\n this._removeListeners();\n this._removeListeners = this._server = null;\n }\n\n if (this.clients) {\n if (!this.clients.size) {\n process.nextTick(emitClose, this);\n } else {\n this._shouldEmitClose = true;\n }\n } else {\n process.nextTick(emitClose, this);\n }\n } else {\n const server = this._server;\n\n this._removeListeners();\n this._removeListeners = this._server = null;\n\n //\n // The HTTP/S server was created internally. Close it, and rely on its\n // `'close'` event.\n //\n server.close(() => {\n emitClose(this);\n });\n }\n }\n\n /**\n * See if a given request should be handled by this server instance.\n *\n * @param {http.IncomingMessage} req Request object to inspect\n * @return {Boolean} `true` if the request is valid, else `false`\n * @public\n */\n shouldHandle(req) {\n if (this.options.path) {\n const index = req.url.indexOf('?');\n const pathname = index !== -1 ? req.url.slice(0, index) : req.url;\n\n if (pathname !== this.options.path) return false;\n }\n\n return true;\n }\n\n /**\n * Handle a HTTP Upgrade request.\n *\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @public\n */\n handleUpgrade(req, socket, head, cb) {\n socket.on('error', socketOnError);\n\n const key = req.headers['sec-websocket-key'];\n const upgrade = req.headers.upgrade;\n const version = +req.headers['sec-websocket-version'];\n\n if (req.method !== 'GET') {\n const message = 'Invalid HTTP method';\n abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);\n return;\n }\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n const message = 'Invalid Upgrade header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (key === undefined || !keyRegex.test(key)) {\n const message = 'Missing or invalid Sec-WebSocket-Key header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (version !== 13 && version !== 8) {\n const message = 'Missing or invalid Sec-WebSocket-Version header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {\n 'Sec-WebSocket-Version': '13, 8'\n });\n return;\n }\n\n if (!this.shouldHandle(req)) {\n abortHandshake(socket, 400);\n return;\n }\n\n const secWebSocketProtocol = req.headers['sec-websocket-protocol'];\n let protocols = new Set();\n\n if (secWebSocketProtocol !== undefined) {\n try {\n protocols = subprotocol.parse(secWebSocketProtocol);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Protocol header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n const secWebSocketExtensions = req.headers['sec-websocket-extensions'];\n const extensions = {};\n\n if (\n this.options.perMessageDeflate &&\n secWebSocketExtensions !== undefined\n ) {\n const perMessageDeflate = new PerMessageDeflate(\n this.options.perMessageDeflate,\n true,\n this.options.maxPayload\n );\n\n try {\n const offers = extension.parse(secWebSocketExtensions);\n\n if (offers[PerMessageDeflate.extensionName]) {\n perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);\n extensions[PerMessageDeflate.extensionName] = perMessageDeflate;\n }\n } catch (err) {\n const message =\n 'Invalid or unacceptable Sec-WebSocket-Extensions header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n //\n // Optionally call external client verification handler.\n //\n if (this.options.verifyClient) {\n const info = {\n origin:\n req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],\n secure: !!(req.socket.authorized || req.socket.encrypted),\n req\n };\n\n if (this.options.verifyClient.length === 2) {\n this.options.verifyClient(info, (verified, code, message, headers) => {\n if (!verified) {\n return abortHandshake(socket, code || 401, message, headers);\n }\n\n this.completeUpgrade(\n extensions,\n key,\n protocols,\n req,\n socket,\n head,\n cb\n );\n });\n return;\n }\n\n if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);\n }\n\n this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);\n }\n\n /**\n * Upgrade the connection to WebSocket.\n *\n * @param {Object} extensions The accepted extensions\n * @param {String} key The value of the `Sec-WebSocket-Key` header\n * @param {Set} protocols The subprotocols\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @throws {Error} If called more than once with the same socket\n * @private\n */\n completeUpgrade(extensions, key, protocols, req, socket, head, cb) {\n //\n // Destroy the socket if the client has already sent a FIN packet.\n //\n if (!socket.readable || !socket.writable) return socket.destroy();\n\n if (socket[kWebSocket]) {\n throw new Error(\n 'server.handleUpgrade() was called more than once with the same ' +\n 'socket, possibly due to a misconfiguration'\n );\n }\n\n if (this._state > RUNNING) return abortHandshake(socket, 503);\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${digest}`\n ];\n\n const ws = new this.options.WebSocket(null, undefined, this.options);\n\n if (protocols.size) {\n //\n // Optionally call external protocol selection handler.\n //\n const protocol = this.options.handleProtocols\n ? this.options.handleProtocols(protocols, req)\n : protocols.values().next().value;\n\n if (protocol) {\n headers.push(`Sec-WebSocket-Protocol: ${protocol}`);\n ws._protocol = protocol;\n }\n }\n\n if (extensions[PerMessageDeflate.extensionName]) {\n const params = extensions[PerMessageDeflate.extensionName].params;\n const value = extension.format({\n [PerMessageDeflate.extensionName]: [params]\n });\n headers.push(`Sec-WebSocket-Extensions: ${value}`);\n ws._extensions = extensions;\n }\n\n //\n // Allow external modification/inspection of handshake headers.\n //\n this.emit('headers', headers, req);\n\n socket.write(headers.concat('\\r\\n').join('\\r\\n'));\n socket.removeListener('error', socketOnError);\n\n ws.setSocket(socket, head, {\n allowSynchronousEvents: this.options.allowSynchronousEvents,\n maxPayload: this.options.maxPayload,\n skipUTF8Validation: this.options.skipUTF8Validation\n });\n\n if (this.clients) {\n this.clients.add(ws);\n ws.on('close', () => {\n this.clients.delete(ws);\n\n if (this._shouldEmitClose && !this.clients.size) {\n process.nextTick(emitClose, this);\n }\n });\n }\n\n cb(ws, req);\n }\n}\n\nmodule.exports = WebSocketServer;\n\n/**\n * Add event listeners on an `EventEmitter` using a map of <event, listener>\n * pairs.\n *\n * @param {EventEmitter} server The event emitter\n * @param {Object.<String, Function>} map The listeners to add\n * @return {Function} A function that will remove the added listeners when\n * called\n * @private\n */\nfunction addListeners(server, map) {\n for (const event of Object.keys(map)) server.on(event, map[event]);\n\n return function removeListeners() {\n for (const event of Object.keys(map)) {\n server.removeListener(event, map[event]);\n }\n };\n}\n\n/**\n * Emit a `'close'` event on an `EventEmitter`.\n *\n * @param {EventEmitter} server The event emitter\n * @private\n */\nfunction emitClose(server) {\n server._state = CLOSED;\n server.emit('close');\n}\n\n/**\n * Handle socket errors.\n *\n * @private\n */\nfunction socketOnError() {\n this.destroy();\n}\n\n/**\n * Close the connection when preconditions are not fulfilled.\n *\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} [message] The HTTP response body\n * @param {Object} [headers] Additional HTTP response headers\n * @private\n */\nfunction abortHandshake(socket, code, message, headers) {\n //\n // The socket is writable unless the user destroyed or ended it before calling\n // `server.handleUpgrade()` or in the `verifyClient` function, which is a user\n // error. Handling this does not make much sense as the worst that can happen\n // is that some of the data written by the user might be discarded due to the\n // call to `socket.end()` below, which triggers an `'error'` event that in\n // turn causes the socket to be destroyed.\n //\n message = message || http.STATUS_CODES[code];\n headers = {\n Connection: 'close',\n 'Content-Type': 'text/html',\n 'Content-Length': Buffer.byteLength(message),\n ...headers\n };\n\n socket.once('finish', socket.destroy);\n\n socket.end(\n `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\\r\\n` +\n Object.keys(headers)\n .map((h) => `${h}: ${headers[h]}`)\n .join('\\r\\n') +\n '\\r\\n\\r\\n' +\n message\n );\n}\n\n/**\n * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least\n * one listener for it, otherwise call `abortHandshake()`.\n *\n * @param {WebSocketServer} server The WebSocket server\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} message The HTTP response body\n * @param {Object} [headers] The HTTP response headers\n * @private\n */\nfunction abortHandshakeOrEmitwsClientError(\n server,\n req,\n socket,\n code,\n message,\n headers\n) {\n if (server.listenerCount('wsClientError')) {\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);\n\n server.emit('wsClientError', err, socket, req);\n } else {\n abortHandshake(socket, code, message, headers);\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"./logger.js\";\nimport {\n createVersionAwareLogger,\n PluginFileLogger as PluginLogger,\n} from \"./logger.js\";\nimport {\n RecordingStorage,\n type RecordingStatusEvent,\n} from \"./recording/index.js\";\nimport type { NotificationStorage } from \"./notification/storage.js\";\nimport { registerLightRulesGateway } from \"./light-rules/gateway.js\";\nimport { LightRulesEvaluatorJob } from \"./light-rules/evaluator-job.js\";\nimport { migrateLegacyLightRuleTasks } from \"./light-rules/migration.js\";\nimport { LightRuleRegistry } from \"./light-rules/registry.js\";\nimport { registerAutoUpdateLifecycle } from \"./plugin/auto-update.js\";\nimport { registerPluginCli } from \"./plugin/cli.js\";\nimport { registerLightControlTool } from \"./plugin/light-control.js\";\nimport {\n registerRelayTunnelLifecycle,\n registerStorageLifecycle,\n} from \"./plugin/lifecycle.js\";\nimport { registerNotificationInterfaces } from \"./plugin/notifications.js\";\nimport { registerRecordingInterfaces } from \"./plugin/recordings.js\";\nimport { isPluginCliInvocation } from \"./plugin/runtime-mode.js\";\nimport type { GatewayHandler } from \"./plugin/shared.js\";\nimport type { PluginConfig, RawNotification } from \"./types.js\";\nimport type { BroadcastFn } from \"./update/types.js\";\n\nexport default {\n id: \"phone-notifications\",\n name: \"Phone Notifications & Light Control\",\n\n register(api: OpenClawPluginApi) {\n const config = (api.pluginConfig ?? {}) as PluginConfig;\n const ignoredApps = new Set(config.ignoredApps ?? []);\n\n let storage: NotificationStorage | null = null;\n let recordingStorage: RecordingStorage | null = null;\n let broadcastFn: BroadcastFn | null = null;\n let autoUpdateLifecycle: ReturnType<typeof registerAutoUpdateLifecycle> | null = null;\n\n const openclawDir = api.runtime.state.resolveStateDir();\n const logger: Logger = openclawDir\n ? new PluginLogger(api.logger, openclawDir)\n : createVersionAwareLogger(api.logger);\n\n const lightRuleCtx: { workspaceDir?: string; stateDir?: string } = {\n stateDir: openclawDir,\n };\n const asrDataDir =\n openclawDir ??\n process.env.OPENCLAW_STATE_DIR ??\n process.env.QCLAW_STATE_DIR ??\n process.cwd();\n\n if (isPluginCliInvocation()) {\n registerPluginCli(api, {\n logger,\n openclawDir,\n });\n logger.info(\n \"检测到插件 CLI 命令执行上下文,仅注册 CLI,跳过后台服务以避免影响 Relay tunnel 常驻连接\",\n );\n return;\n }\n\n function cacheBroadcast(broadcast: BroadcastFn | undefined): void {\n if (!broadcast) {\n return;\n }\n\n const changed = broadcastFn !== broadcast;\n broadcastFn = broadcast;\n if (changed) {\n autoUpdateLifecycle?.notifyBroadcastReady();\n }\n }\n\n function registerGatewayMethodWithBroadcastCapture(\n method: string,\n handler: GatewayHandler,\n ): void {\n api.registerGatewayMethod(method, (opts) => {\n cacheBroadcast(opts.context?.broadcast);\n return handler(opts);\n });\n }\n\n function filterNotifications(items: RawNotification[]): RawNotification[] {\n return items.filter((notification) => !ignoredApps.has(notification.app));\n }\n\n function notifyRecordingStatus(event: RecordingStatusEvent): void {\n if (!broadcastFn) {\n logger.warn(\n `[recording.status] broadcast 不可用,跳过状态事件: ${event.recordingId} -> ${event.transfer_status}`,\n );\n return;\n }\n\n broadcastFn(\"recording.status\", event);\n }\n\n const lightRuleRegistry = new LightRuleRegistry(lightRuleCtx);\n const lightRulesEvaluatorJob = new LightRulesEvaluatorJob({ logger, registry: lightRuleRegistry });\n\n registerStorageLifecycle({\n api,\n config,\n logger,\n lightRuleCtx,\n setStorage(nextStorage) {\n storage = nextStorage;\n },\n setRecordingStorage(nextRecordingStorage) {\n recordingStorage = nextRecordingStorage;\n },\n onStorageReady() {\n // storage service start 完成后 lightRuleCtx 才被回填到真实的 workspaceDir,\n // 此时运行迁移(清理旧版 fetch.py / README.md)并重新扫盘加载已有规则。\n migrateLegacyLightRuleTasks(lightRuleCtx, logger);\n lightRuleRegistry.reload();\n },\n });\n\n const tunnelService = registerRelayTunnelLifecycle({\n api,\n config,\n logger,\n openclawDir,\n });\n\n registerNotificationInterfaces({\n api,\n logger,\n getStorage: () => storage,\n filterNotifications,\n registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,\n tunnelService,\n onAfterIngest: (insertedCount, cron) => {\n void lightRulesEvaluatorJob.triggerIfNeeded(cron, insertedCount);\n },\n });\n\n registerLightControlTool(api, logger);\n\n registerRecordingInterfaces({\n api,\n logger,\n asrDataDir,\n getRecordingStorage: () => recordingStorage,\n notifyRecordingStatus,\n registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,\n shouldBroadcastStatusOnHttp: () => !!broadcastFn,\n tunnelService,\n });\n\n registerLightRulesGateway(api, lightRuleRegistry, logger, cacheBroadcast);\n logger.info(\n \"Gateway 灯效规则方法已注册: lightrules.list / lightrules.create / lightrules.update / lightrules.delete\",\n );\n\n autoUpdateLifecycle = registerAutoUpdateLifecycle({\n api,\n config,\n logger,\n getBroadcastFn: () => broadcastFn,\n cacheBroadcast,\n tunnelService,\n });\n\n registerPluginCli(api, {\n logger,\n openclawDir,\n });\n },\n};\n","import { appendFileSync, mkdirSync, readdirSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { PLUGIN_VERSION } from \"./version.js\";\n\nexport interface Logger {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n}\n\nconst DEFAULT_LOG_RETENTION_DAYS = 30;\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nexport interface PluginFileLoggerOptions {\n version?: string;\n retentionDays?: number;\n}\n\nexport function isBetaPluginVersion(version = PLUGIN_VERSION): boolean {\n return /\\bbeta\\b/i.test(version);\n}\n\nexport function createVersionAwareLogger(\n upstream: Logger,\n options: Pick<PluginFileLoggerOptions, \"version\"> = {},\n): Logger {\n if (isBetaPluginVersion(options.version ?? PLUGIN_VERSION)) {\n return upstream;\n }\n\n return {\n info() {\n // 正式版静默 INFO,保留 WARN/ERROR。\n },\n warn(msg: string) {\n upstream.warn(msg);\n },\n error(msg: string) {\n upstream.error(msg);\n },\n };\n}\n\n/**\n * 插件级文件 Logger。\n * 在调用原始 api.logger 的同时,把日志追加写入\n * `<stateDir>/plugins/phone-notifications/logs/YYYY-MM-DD.log`。\n * beta 版本保留 INFO;正式版只记录 WARN 及以上。\n */\nexport class PluginFileLogger implements Logger {\n private readonly logsDir: string;\n private readonly infoEnabled: boolean;\n private readonly retentionDays: number;\n private lastPruneDateKey: string | null = null;\n\n constructor(\n private readonly upstream: Logger,\n stateDir: string,\n options: PluginFileLoggerOptions = {},\n ) {\n this.logsDir = join(stateDir, \"plugins\", \"phone-notifications\", \"logs\");\n this.infoEnabled = isBetaPluginVersion(options.version ?? PLUGIN_VERSION);\n this.retentionDays =\n Number.isFinite(options.retentionDays) && (options.retentionDays ?? 0) > 0\n ? options.retentionDays!\n : DEFAULT_LOG_RETENTION_DAYS;\n\n mkdirSync(this.logsDir, { recursive: true });\n const now = new Date();\n this.pruneExpiredLogs(now);\n this.lastPruneDateKey = formatDate(now);\n }\n\n info(msg: string): void {\n this.prepareLogDate(new Date());\n if (!this.infoEnabled) {\n return;\n }\n this.upstream.info(msg);\n this.append(\"INFO\", msg);\n }\n\n warn(msg: string): void {\n this.upstream.warn(msg);\n this.append(\"WARN\", msg);\n }\n\n error(msg: string): void {\n this.upstream.error(msg);\n this.append(\"ERROR\", msg);\n }\n\n private append(level: string, msg: string): void {\n const now = new Date();\n const dateKey = this.prepareLogDate(now);\n const time = formatLocalTimestamp(now);\n const line = `${time} [${level}] ${msg}\\n`;\n try {\n appendFileSync(join(this.logsDir, `${dateKey}.log`), line);\n } catch {\n // 写文件失败不影响主流程\n }\n }\n\n private prepareLogDate(now: Date): string {\n const dateKey = formatDate(now);\n if (this.lastPruneDateKey !== dateKey) {\n this.pruneExpiredLogs(now);\n this.lastPruneDateKey = dateKey;\n }\n return dateKey;\n }\n\n private pruneExpiredLogs(now: Date): void {\n const cutoffMs = now.getTime() - this.retentionDays * DAY_MS;\n const cutoffDate = formatDate(new Date(cutoffMs));\n\n try {\n for (const entry of readdirSync(this.logsDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.log$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.logsDir, entry.name), { force: true });\n }\n }\n } catch {\n // 清理失败不影响主流程\n }\n }\n}\n\nfunction formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\nexport function formatLocalTimestamp(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n const hh = String(d.getHours()).padStart(2, \"0\");\n const mm = String(d.getMinutes()).padStart(2, \"0\");\n const ss = String(d.getSeconds()).padStart(2, \"0\");\n const ms = String(d.getMilliseconds()).padStart(3, \"0\");\n\n const offsetMinutes = -d.getTimezoneOffset();\n const sign = offsetMinutes >= 0 ? \"+\" : \"-\";\n const absOffsetMinutes = Math.abs(offsetMinutes);\n const offsetHours = String(Math.floor(absOffsetMinutes / 60)).padStart(2, \"0\");\n const offsetMins = String(absOffsetMinutes % 60).padStart(2, \"0\");\n\n return `${y}-${m}-${day}T${hh}:${mm}:${ss}.${ms}${sign}${offsetHours}:${offsetMins}`;\n}\n","import { readFileSync } from \"node:fs\";\n\ndeclare const __PLUGIN_VERSION__: string | undefined;\n\ninterface PackageJson {\n version?: string;\n}\n\nfunction readBuildInjectedVersion(): string | undefined {\n if (typeof __PLUGIN_VERSION__ !== \"string\") {\n return undefined;\n }\n\n const version = __PLUGIN_VERSION__.trim();\n return version || undefined;\n}\n\nfunction readPluginVersionFromPackageJson(): string | undefined {\n try {\n const packageJsonUrl = new URL(\"../package.json\", import.meta.url);\n const packageJson = JSON.parse(\n readFileSync(packageJsonUrl, \"utf-8\"),\n ) as PackageJson;\n const version = packageJson.version?.trim();\n return version || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport const PLUGIN_VERSION =\n readBuildInjectedVersion() ??\n readPluginVersionFromPackageJson() ??\n \"unknown\";\n","export interface RepeatConfig {\n repeat?: boolean;\n repeat_times?: number;\n}\n\nexport type RepeatArgument = RepeatConfig | boolean | number | undefined;\n\nexport function normalizeRepeatTimes(input?: RepeatArgument): number {\n if (typeof input === \"boolean\") {\n return input ? 0 : 1;\n }\n\n if (typeof input === \"number\") {\n return validateRepeatTimes(input);\n }\n\n if (!input) {\n return 1;\n }\n\n if (input.repeat_times !== undefined) {\n return validateRepeatTimes(input.repeat_times);\n }\n\n if (input.repeat !== undefined) {\n return input.repeat ? 0 : 1;\n }\n\n return 1;\n}\n\nexport function assertAncsRepeatTimes(repeatTimes: number): void {\n if (repeatTimes !== 0 && repeatTimes !== 1) {\n throw new Error(\n \"当前 ANCS 路径仅支持 repeat_times=0(无限循环)或 1(播放一轮);N>=2 需非 ANCS 路径\",\n );\n }\n}\n\nfunction validateRepeatTimes(value: number): number {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(\"repeat_times 必须是 >=0 的整数\");\n }\n\n return value;\n}\n","import { existsSync, readFileSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { StoredNotification } from \"../notification/storage.js\";\n\n/**\n * Minimal Commander.js Command interface.\n * The real `Command` instance comes from the openclaw runtime at registration time;\n * we only declare the subset we use so that `commander` need not be a direct dep.\n */\nexport interface CliCommand {\n command(nameAndArgs: string): CliCommand;\n description(str: string): CliCommand;\n version(str: string, flags?: string, description?: string): CliCommand;\n option(flags: string, description: string, defaultValue?: string): CliCommand;\n requiredOption(flags: string, description: string): CliCommand;\n action(fn: (...args: any[]) => void | Promise<void>): CliCommand;\n}\n\nexport interface CliContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\n/** Resolve the notifications storage directory (stateDir → workspace fallback) */\nexport function resolveNotificationsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"notifications\",\n );\n if (existsSync(dir)) return dir;\n }\n if (ctx.workspaceDir) {\n const dir = join(ctx.workspaceDir, \"notifications\");\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** List available date keys (YYYY-MM-DD) sorted descending */\nexport function listDateKeys(dir: string): string[] {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.json$/;\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Read notifications for a specific date */\nexport function readDateFile(\n dir: string,\n dateKey: string,\n): StoredNotification[] {\n const filePath = join(dir, `${dateKey}.json`);\n if (!existsSync(filePath)) return [];\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n return [];\n }\n}\n\n/** Format today as YYYY-MM-DD */\nexport function today(): string {\n return formatDate(new Date());\n}\n\n/** Format a Date as YYYY-MM-DD */\nexport function formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\n/** Get date N days ago as YYYY-MM-DD */\nexport function daysAgo(n: number): string {\n const d = new Date();\n d.setDate(d.getDate() - n);\n return formatDate(d);\n}\n\n/** Filter date keys to a [from, to] range (inclusive) */\nexport function filterDateRange(\n keys: string[],\n from: string,\n to: string,\n): string[] {\n return keys.filter((k) => k >= from && k <= to);\n}\n\n/** Parse an ISO 8601 timestamp and exit with a CLI error on invalid input */\nexport function parseIsoTime(\n value: string,\n optionName: \"--from\" | \"--to\",\n): number {\n const isoPattern =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,3})?)?(Z|[+-]\\d{2}:\\d{2})$/;\n if (!isoPattern.test(value)) {\n exitError(\n \"INVALID_TIME\",\n `${optionName} 必须是 ISO 8601 时间,例如 2026-03-01T09:00:00+08:00`,\n );\n }\n\n const ts = Date.parse(value);\n if (Number.isNaN(ts)) {\n exitError(\n \"INVALID_TIME\",\n `${optionName} 不是合法时间,例如 2026-03-01T09:00:00+08:00`,\n );\n }\n return ts;\n}\n\n/** Sort notifications by timestamp descending (newest first) */\nexport function sortNotificationsByTimestampDesc(\n items: StoredNotification[],\n): StoredNotification[] {\n return items.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));\n}\n\n/** Async version of listDateKeys */\nexport async function listDateKeysAsync(dir: string): Promise<string[]> {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.json$/;\n const keys: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Async version of readDateFile */\nexport async function readDateFileAsync(\n dir: string,\n dateKey: string,\n): Promise<StoredNotification[]> {\n const filePath = join(dir, `${dateKey}.json`);\n if (!existsSync(filePath)) return [];\n try {\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content);\n } catch {\n return [];\n }\n}\n\n/** Write progress message to stderr (visible to caller, won't pollute JSON stdout) */\nexport function progress(message: string): void {\n process.stderr.write(message + \"\\n\");\n}\n\n/** Print JSON result to stdout */\nexport function output(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\n/** Print error JSON and exit with code 1 */\nexport function exitError(code: string, message: string): never {\n output({ ok: false, error: { code, message } });\n process.exit(1);\n}\n\n/** Resolve the recordings storage directory (stateDir → workspace fallback) */\nexport function resolveRecordingsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"recordings\",\n );\n if (existsSync(dir)) return dir;\n }\n if (ctx.workspaceDir) {\n const dir = join(ctx.workspaceDir, \"recordings\");\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** Recording index entry (mirrors RecordingIndexEntry from storage.ts) */\nexport interface CliRecordingEntry {\n id: string;\n metadata: {\n name: string;\n duration_sec: number;\n file_size_bytes: number;\n created_at: string;\n transfer_status: string;\n [key: string]: unknown;\n };\n status: string;\n audioFile?: string;\n srtFile?: string;\n transcriptDataFile?: string;\n transcriptFile?: string;\n summaryFile?: string;\n title?: string;\n ingestedAt: string;\n updatedAt: string;\n}\n\n/** Resolve the asr-config.json path; creates parent dirs if needed */\nexport function resolveAsrConfigPath(ctx: CliContext): string {\n let base: string;\n if (ctx.stateDir) {\n base = join(ctx.stateDir, \"plugins\", \"phone-notifications\", \"recordings\");\n } else if (ctx.workspaceDir) {\n base = join(ctx.workspaceDir, \"recordings\");\n } else {\n exitError(\n \"STORAGE_UNAVAILABLE\",\n \"无法确定录音存储目录:stateDir 和 workspaceDir 均未设置\",\n );\n }\n mkdirSync(base, { recursive: true });\n return join(base, \"asr-config.json\");\n}\n\n/** Mask an API key, keeping first 4 and last 4 chars */\nexport function maskApiKey(key: string): string {\n if (key.length <= 8) return \"***\";\n return `${key.slice(0, 4)}***${key.slice(-4)}`;\n}\n\n/** Read recording index.json */\nexport function readRecordingIndex(\n dir: string,\n): CliRecordingEntry[] {\n const indexPath = join(dir, \"index.json\");\n if (!existsSync(indexPath)) return [];\n try {\n const raw = JSON.parse(readFileSync(indexPath, \"utf-8\"));\n return Array.isArray(raw?.recordings) ? raw.recordings : [];\n } catch {\n return [];\n }\n}\n","import type { LightPixelFramePixel, LightSegment } from \"../types.js\";\nimport { output, exitError } from \"../cli/helpers.js\";\n\nexport const VALID_MODES = [\n \"wave\",\n \"breath\",\n \"strobe\",\n \"steady\",\n \"wave_rainbow\",\n \"pixel_frame\",\n] as const;\nexport const MAX_SEGMENTS = 12;\n\nexport interface ValidationError {\n field: string;\n message: string;\n}\n\nexport type ValidationResult =\n | { valid: true; segments: LightSegment[] }\n | { valid: false; errors: ValidationError[] };\n\nexport function validateSegments(segments: unknown): ValidationResult {\n if (!Array.isArray(segments)) {\n return { valid: false, errors: [{ field: \"segments\", message: \"必须是数组\" }] };\n }\n if (segments.length === 0) {\n return { valid: false, errors: [{ field: \"segments\", message: \"不能为空\" }] };\n }\n if (segments.length > MAX_SEGMENTS) {\n return {\n valid: false,\n errors: [{ field: \"segments\", message: `最多 ${MAX_SEGMENTS} 段` }],\n };\n }\n\n const errors: ValidationError[] = [];\n for (let i = 0; i < segments.length; i++) {\n validateSegment(segments[i], `segments[${i}]`, errors);\n }\n\n if (errors.length > 0) return { valid: false, errors };\n return { valid: true, segments: segments as LightSegment[] };\n}\n\n/**\n * 解析 JSON 字符串并校验 segments,失败时直接 exitError。\n * 适用于 CLI action 中的统一入口。\n */\nexport function parseAndValidateSegments(json: string): LightSegment[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n exitError(\"VALIDATION_FAILED\", \"segments 必须是合法的 JSON\");\n }\n\n const result = validateSegments(parsed);\n if (!result.valid) {\n output({ ok: false, error: { code: \"VALIDATION_FAILED\", details: result.errors } });\n process.exit(1);\n }\n\n return result.segments;\n}\n\nfunction validateSegment(seg: unknown, prefix: string, errors: ValidationError[]): void {\n if (!isRecord(seg)) {\n errors.push({ field: prefix, message: \"必须是对象\" });\n return;\n }\n\n const mode = seg.mode;\n if (!VALID_MODES.includes(mode as (typeof VALID_MODES)[number])) {\n errors.push({\n field: `${prefix}.mode`,\n message: `不支持的模式 '${String(mode)}',可选:${VALID_MODES.join(\"/\")}`,\n });\n }\n\n validateNonNegativeNumber(seg.duration_s, `${prefix}.duration_s`, errors, \"必须是 ≥0 的数字(0 表示无限时长)\");\n\n switch (mode) {\n case \"wave\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n break;\n case \"wave_rainbow\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n type RgbLike = Parameters<typeof hasNonZeroRgb>[0];\n if (!hasNonZeroRgb(seg.color as RgbLike) && !hasNonZeroRgb(seg.background as RgbLike)) {\n errors.push({\n field: prefix,\n message: \"wave_rainbow 至少需要一组非零颜色锚点(color 或 background)\",\n });\n }\n break;\n case \"breath\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalBreathTiming(seg.breath_timing, `${prefix}.breath_timing`, errors);\n break;\n case \"strobe\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n break;\n case \"steady\":\n validateForegroundSegment(seg, prefix, errors);\n break;\n case \"pixel_frame\":\n validatePixelFrame(seg.pixels, `${prefix}.pixels`, errors);\n break;\n default:\n validateOptionalNonNegativeNumber(seg.brightness, `${prefix}.brightness`, errors);\n validateOptionalColor(seg.color, `${prefix}.color`, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBreathTiming(seg.breath_timing, `${prefix}.breath_timing`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n }\n}\n\nfunction validateForegroundSegment(\n seg: Record<string, unknown>,\n prefix: string,\n errors: ValidationError[],\n): void {\n validateNumberInRange(\n seg.brightness,\n `${prefix}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n validateColor(seg.color, `${prefix}.color`, errors);\n\n if (seg.mode !== \"steady\" && seg.brightness === 0) {\n errors.push({\n field: `${prefix}.brightness`,\n message: \"brightness=0 仅 steady 模式允许;其它模式会在固件侧被过滤\",\n });\n }\n}\n\nfunction validatePixelFrame(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (!Array.isArray(value)) {\n errors.push({ field, message: \"pixel_frame 必须提供 pixels 数组(1–7 项)\" });\n return;\n }\n\n if (value.length < 1 || value.length > 7) {\n errors.push({ field, message: \"pixels 必须为 1–7 项\" });\n }\n\n const seen = new Set<number>();\n for (let i = 0; i < value.length; i++) {\n const pixel = value[i];\n const prefix = `${field}[${i}]`;\n if (!isRecord(pixel)) {\n errors.push({ field: prefix, message: \"必须是对象\" });\n continue;\n }\n\n const idx = pixel.index;\n if (!Number.isInteger(idx) || (idx as number) < 0 || (idx as number) > 6) {\n errors.push({ field: `${prefix}.index`, message: \"index 必须是 0–6 的整数\" });\n } else if (seen.has(idx as number)) {\n errors.push({ field: `${prefix}.index`, message: `index=${idx} 重复` });\n } else {\n seen.add(idx as number);\n }\n\n validateNumberInRange(\n pixel.brightness,\n `${prefix}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n validateColor(pixel.color, `${prefix}.color`, errors);\n }\n}\n\nfunction validateOptionalBreathTiming(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须是对象\" });\n return;\n }\n\n validatePositiveNumber(\n value.rise_ms,\n `${field}.rise_ms`,\n errors,\n \"rise_ms 必须是 >0 的数字(不支持 0ms)\",\n );\n validateNonNegativeNumber(\n value.hold_ms,\n `${field}.hold_ms`,\n errors,\n \"hold_ms 必须是 ≥0 的数字\",\n );\n validatePositiveNumber(\n value.fall_ms,\n `${field}.fall_ms`,\n errors,\n \"fall_ms 必须是 >0 的数字(不支持 0ms)\",\n );\n validateNonNegativeNumber(\n value.off_ms,\n `${field}.off_ms`,\n errors,\n \"off_ms 必须是 ≥0 的数字\",\n );\n}\n\nfunction validateOptionalBackground(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须包含 r/g/b/brightness 数值\" });\n return;\n }\n\n validateColor(value, field, errors);\n validateNumberInRange(\n value.brightness,\n `${field}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n}\n\nfunction validateOptionalColor(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n validateColor(value, field, errors);\n}\n\nfunction validateColor(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须包含 r/g/b 数值\" });\n return;\n }\n\n validateNumberInRange(value.r, `${field}.r`, errors, 0, 255, \"必须是 0–255 的数字\");\n validateNumberInRange(value.g, `${field}.g`, errors, 0, 255, \"必须是 0–255 的数字\");\n validateNumberInRange(value.b, `${field}.b`, errors, 0, 255, \"必须是 0–255 的数字\");\n}\n\nfunction validateOptionalDirection(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (value !== \"ltr\" && value !== \"rtl\") {\n errors.push({ field, message: \"direction 必须是 ltr 或 rtl\" });\n }\n}\n\nfunction validateOptionalWindow(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (value !== 1 && value !== 2 && value !== 3) {\n errors.push({ field, message: \"window 仅支持 1/2/3\" });\n }\n}\n\nfunction validateOptionalNonNegativeNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n validateNonNegativeNumber(value, field, errors, \"必须是 ≥0 的数字\");\n}\n\nfunction validatePositiveNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n message: string,\n): void {\n if (value === undefined) return;\n if (!isFiniteNumber(value) || value <= 0) {\n errors.push({ field, message });\n }\n}\n\nfunction validateNonNegativeNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n message: string,\n): void {\n if (!isFiniteNumber(value) || value < 0) {\n errors.push({ field, message });\n }\n}\n\nfunction validateNumberInRange(\n value: unknown,\n field: string,\n errors: ValidationError[],\n min: number,\n max: number,\n message: string,\n): void {\n if (!isFiniteNumber(value) || value < min || value > max) {\n errors.push({ field, message });\n }\n}\n\nfunction hasNonZeroRgb(\n value: Pick<LightPixelFramePixel[\"color\"], \"r\" | \"g\" | \"b\"> | { r?: unknown; g?: unknown; b?: unknown } | undefined,\n): boolean {\n if (!value) return false;\n return [value.r, value.g, value.b].some((channel) => isFiniteNumber(channel) && channel > 0);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { LightSegment } from \"../types.js\";\nimport type { LightRuleMeta } from \"./types.js\";\nimport { generateFetchPy } from \"../monitor/fetch-gen.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\n\nconst LEGACY_DEFAULT_CRON_SCHEDULE = \"*/5 * * * *\";\n\n/**\n * 兼容窗口工具:读 / 写灯效规则的 deprecated 字段(matchRules / cronSchedule)。\n *\n * 这两个字段在 prd-lightrules-event-driven-refactor 中已被标记为 deprecated,\n * 但在 M6 客户端全部升级前必须继续接受旧客户端的入参、继续生成 cron 调度信息,\n * 否则老 App 会失去灯效能力。所有\"读 deprecated 字段\"的逻辑统一从这里走,\n * 把 SonarLint S1874(typescript:S1874 \"use of deprecated symbol\")警告\n * 收敛到本段,避免散落各处。\n *\n * 等 M6 过渡期结束删除兼容字段时,只需要删掉本段 + 调用方的 helper 调用即可。\n */\n\n/* eslint-disable @typescript-eslint/no-deprecated */\ntype LegacyMatchRulesShape = { appName?: string; senderKeywords?: string[] };\n\nfunction legacyReadMatchRules(input: {\n matchRules?: LegacyMatchRulesShape;\n}): LegacyMatchRulesShape {\n return input.matchRules ?? {};\n}\n\nfunction legacyReadCronSchedule(input: { cronSchedule?: string }): string {\n return input.cronSchedule ?? LEGACY_DEFAULT_CRON_SCHEDULE;\n}\n\nfunction legacyHasMatchRules(input: { matchRules?: LegacyMatchRulesShape }): boolean {\n return input.matchRules !== undefined;\n}\n\nfunction legacyHasCronSchedule(input: { cronSchedule?: string }): boolean {\n return input.cronSchedule !== undefined;\n}\n\nfunction legacyAssignMatchRules(\n meta: LightRuleMeta,\n matchRules: LegacyMatchRulesShape,\n): void {\n meta.matchRules = matchRules;\n}\n\nfunction legacyAssignCronSchedule(meta: LightRuleMeta, cronSchedule: string): void {\n meta.cronSchedule = cronSchedule;\n}\n\nfunction legacyReadMetaMatchRules(meta: LightRuleMeta): LegacyMatchRulesShape {\n return meta.matchRules ?? {};\n}\n\nfunction legacyReadMetaCronSchedule(meta: LightRuleMeta): string | undefined {\n return meta.cronSchedule;\n}\n/* eslint-enable @typescript-eslint/no-deprecated */\n\nexport interface LightRuleStorageContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\nfunction resolveBaseDir(ctx: LightRuleStorageContext): string {\n if (ctx.workspaceDir) return ctx.workspaceDir;\n\n if (ctx.stateDir) {\n const inferredWorkspaceDir = join(ctx.stateDir, \"workspace\");\n if (existsSync(inferredWorkspaceDir)) return inferredWorkspaceDir;\n return ctx.stateDir;\n }\n\n throw new Error(\"workspaceDir and stateDir both unavailable\");\n}\n\nfunction tasksDir(ctx: LightRuleStorageContext): string {\n return join(resolveBaseDir(ctx), \"tasks\");\n}\n\nfunction normalizeLightRuleLookupName(name: string): string {\n return name.trim().replace(/\\.json$/i, \"\");\n}\n\nfunction resolveLightRuleTask(\n ctx: LightRuleStorageContext,\n name: string,\n): { taskDir: string; meta: LightRuleMeta } | null {\n const dir = tasksDir(ctx);\n const normalizedName = normalizeLightRuleLookupName(name);\n if (!normalizedName) return null;\n\n const directTaskDir = join(dir, normalizedName);\n const directMeta = readMeta(directTaskDir);\n if (directMeta) {\n return {\n taskDir: directTaskDir,\n meta: directMeta,\n };\n }\n\n if (!existsSync(dir)) return null;\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n\n const taskDir = join(dir, entry.name);\n const meta = readMeta(taskDir);\n if (meta?.name === normalizedName) {\n return {\n taskDir,\n meta,\n };\n }\n }\n\n return null;\n}\n\nfunction readMeta(taskDir: string): LightRuleMeta | null {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(metaPath, \"utf-8\"));\n if (raw.type !== \"light-rule\") return null;\n if (!raw.createdAt) {\n raw.createdAt = statSync(metaPath).birthtime.toISOString();\n }\n const repeatTimes = normalizeRepeatTimes({\n repeat: raw.repeat,\n repeat_times: raw.repeat_times,\n });\n assertAncsRepeatTimes(repeatTimes);\n return {\n ...raw,\n repeat_times: repeatTimes,\n } as LightRuleMeta;\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(taskDir: string, meta: LightRuleMeta): void {\n writeFileSync(join(taskDir, \"meta.json\"), JSON.stringify(meta, null, 2), \"utf-8\");\n}\n\nfunction generateLightRuleReadme(\n name: string,\n description: string,\n segments: LightSegment[],\n repeatTimes: number,\n): string {\n const segmentsJson = JSON.stringify(segments, null, 2);\n return `# ${name}\n\n## 监控目标\n\n${description}\n\n## 触发后如何处理\n\n当任务脚本输出匹配结果时:\n\n1. 将输出按\"每行一个 JSON 对象\"解析\n2. 这些是候选通知,不代表已经命中\n3. 根据监控目标判断是否真正命中\n\n**命中后执行灯效**:调用 light_control 工具,传入以下灯效参数:\n\n\\`\\`\\`json\n${segmentsJson}\n\\`\\`\\`\n\nrepeat_times: ${repeatTimes}\nreason: \"${description}\"\n\n只执行灯效,不主动发送通知摘要或回复用户。\n`;\n}\n\nexport function listLightRules(ctx: LightRuleStorageContext): LightRuleMeta[] {\n const dir = tasksDir(ctx);\n if (!existsSync(dir)) return [];\n\n const rules: LightRuleMeta[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const meta = readMeta(join(dir, entry.name));\n if (meta) rules.push(meta);\n }\n return rules;\n}\n\nexport function getLightRule(\n ctx: LightRuleStorageContext,\n name: string,\n): LightRuleMeta | null {\n return resolveLightRuleTask(ctx, name)?.meta ?? null;\n}\n\nexport function createLightRule(\n ctx: LightRuleStorageContext,\n params: {\n name: string;\n description: string;\n segments: LightSegment[];\n repeat_times?: number;\n repeat?: boolean;\n /** @deprecated 旧客户端兼容字段;缺省时回退到默认 cron schedule */\n matchRules?: { appName?: string; senderKeywords?: string[] };\n /** @deprecated 旧客户端兼容字段;缺省时回退到 LEGACY_DEFAULT_CRON_SCHEDULE */\n cronSchedule?: string;\n },\n): { meta: LightRuleMeta; cronHint: unknown } {\n const dir = tasksDir(ctx);\n const taskDir = join(dir, params.name);\n\n if (existsSync(taskDir)) {\n throw new LightRuleError(\"ALREADY_EXISTS\", `灯效规则 '${params.name}' 已存在`);\n }\n\n mkdirSync(taskDir, { recursive: true });\n\n const repeatTimes = normalizeRepeatTimes({\n repeat: params.repeat,\n repeat_times: params.repeat_times,\n });\n assertAncsRepeatTimes(repeatTimes);\n\n const effectiveMatchRules = legacyReadMatchRules(params);\n const effectiveCronSchedule = legacyReadCronSchedule(params);\n\n const meta: LightRuleMeta = {\n name: params.name,\n type: \"light-rule\",\n description: params.description,\n segments: params.segments,\n repeat_times: repeatTimes,\n enabled: true,\n createdAt: new Date().toISOString(),\n };\n legacyAssignMatchRules(meta, effectiveMatchRules);\n legacyAssignCronSchedule(meta, effectiveCronSchedule);\n\n writeMeta(taskDir, meta);\n\n writeFileSync(\n join(taskDir, \"fetch.py\"),\n generateFetchPy(params.name, effectiveMatchRules as Record<string, unknown>),\n \"utf-8\",\n );\n\n writeFileSync(\n join(taskDir, \"README.md\"),\n generateLightRuleReadme(params.name, params.description, params.segments, repeatTimes),\n \"utf-8\",\n );\n\n return {\n meta,\n cronHint: {\n action: \"add\",\n job: {\n name: `notif-${params.name}`,\n schedule: effectiveCronSchedule,\n sessionTarget: \"isolated\",\n message:\n `手机通知已由独立服务实时捕获到 notifications/ 目录的 JSON 文件中。\\n` +\n `执行:python3 tasks/${params.name}/fetch.py --notifications-dir notifications\\n` +\n `- NO_CHANGE 或 NO_MATCH → 不回复,直接结束。\\n` +\n `- 有输出 → 读 tasks/${params.name}/README.md 了解如何处理数据并通知用户。`,\n },\n },\n };\n}\n\nexport function updateLightRule(\n ctx: LightRuleStorageContext,\n params: {\n name: string;\n description?: string;\n segments?: LightSegment[];\n repeat_times?: number;\n repeat?: boolean;\n enabled?: boolean;\n /** @deprecated 旧客户端兼容字段 */\n matchRules?: { appName?: string; senderKeywords?: string[] };\n /** @deprecated 旧客户端兼容字段 */\n cronSchedule?: string;\n },\n): { meta: LightRuleMeta; cronHint?: unknown } {\n const resolved = resolveLightRuleTask(ctx, params.name);\n const taskDir = resolved?.taskDir;\n const meta = resolved?.meta;\n\n if (!taskDir || !meta) {\n throw new LightRuleError(\"NOT_FOUND\", `灯效规则 '${params.name}' 不存在`);\n }\n\n let regenerateFetch = false;\n let regenerateReadme = false;\n\n if (params.description !== undefined) {\n meta.description = params.description;\n regenerateReadme = true;\n }\n if (legacyHasMatchRules(params)) {\n legacyAssignMatchRules(meta, legacyReadMatchRules(params));\n regenerateFetch = true;\n }\n if (params.segments !== undefined) {\n meta.segments = params.segments;\n regenerateReadme = true;\n }\n if (params.repeat !== undefined || params.repeat_times !== undefined) {\n meta.repeat_times = normalizeRepeatTimes({\n repeat: params.repeat,\n repeat_times: params.repeat_times,\n });\n assertAncsRepeatTimes(meta.repeat_times);\n regenerateReadme = true;\n }\n if (legacyHasCronSchedule(params)) {\n legacyAssignCronSchedule(meta, legacyReadCronSchedule(params));\n }\n if (params.enabled !== undefined) {\n meta.enabled = params.enabled;\n }\n\n meta.updatedAt = new Date().toISOString();\n writeMeta(taskDir, meta);\n\n if (regenerateFetch) {\n writeFileSync(\n join(taskDir, \"fetch.py\"),\n generateFetchPy(meta.name, legacyReadMetaMatchRules(meta) as Record<string, unknown>),\n \"utf-8\",\n );\n }\n\n if (regenerateReadme) {\n writeFileSync(\n join(taskDir, \"README.md\"),\n generateLightRuleReadme(meta.name, meta.description, meta.segments, meta.repeat_times),\n \"utf-8\",\n );\n }\n\n const cronHint = legacyHasCronSchedule(params)\n ? {\n action: \"update\",\n job: {\n name: `notif-${meta.name}`,\n schedule: legacyReadMetaCronSchedule(meta),\n },\n }\n : undefined;\n\n return { meta, cronHint };\n}\n\nexport function deleteLightRule(\n ctx: LightRuleStorageContext,\n name: string,\n): { name: string; cronHint: unknown } {\n const resolved = resolveLightRuleTask(ctx, name);\n const taskDir = resolved?.taskDir;\n const meta = resolved?.meta;\n\n if (!taskDir || !meta) {\n throw new LightRuleError(\"NOT_FOUND\", `灯效规则 '${name}' 不存在`);\n }\n\n rmSync(taskDir, { recursive: true, force: true });\n\n return {\n name: meta.name,\n cronHint: {\n action: \"remove\",\n name: `notif-${meta.name}`,\n },\n };\n}\n\nexport class LightRuleError extends Error {\n constructor(\n public code: string,\n message: string,\n ) {\n super(message);\n this.name = \"LightRuleError\";\n }\n}\n","/**\n * 共享的 fetch.py 生成逻辑,供 ntf-monitor CLI 和 light-rules gateway 复用。\n */\nexport function generateFetchPy(\n name: string,\n matchRules: Record<string, unknown>,\n): string {\n const appName = typeof matchRules.appName === \"string\" ? matchRules.appName : \"\";\n const senderKeywords = stringArray(matchRules.senderKeywords);\n const contentKeywords = stringArray(matchRules.contentKeywords);\n\n return `#!/usr/bin/env python3\n\"\"\"Auto-generated fetch script for monitor task: ${name}\"\"\"\nimport json, sys, os\nfrom pathlib import Path\n\ndef matches(notification: dict) -> bool:\n app = str(notification.get(\"appName\", \"\") or \"\")\n title = str(notification.get(\"title\", \"\") or \"\")\n content = str(notification.get(\"content\", \"\") or \"\")\n body = str(notification.get(\"body\", \"\") or \"\")\n\n app_name = ${pyLiteral(appName)}\n if app_name and app != app_name:\n return False\n\n sender_keywords = ${pyLiteral(senderKeywords)}\n sender_haystack = f\"{title}\\\\n{content}\\\\n{body}\"\n if sender_keywords and not any(keyword in sender_haystack for keyword in sender_keywords):\n return False\n\n content_keywords = ${pyLiteral(contentKeywords)}\n content_haystack = f\"{content}\\\\n{body}\"\n if content_keywords and not any(keyword in content_haystack for keyword in content_keywords):\n return False\n\n return True\n\ndef main():\n import argparse\n parser = argparse.ArgumentParser()\n parser.add_argument(\"--notifications-dir\", required=True)\n args = parser.parse_args()\n\n checkpoint_path = Path(__file__).parent / \"checkpoint.json\"\n checkpoint = {}\n if checkpoint_path.exists():\n checkpoint = json.loads(checkpoint_path.read_text())\n\n ntf_dir = Path(args.notifications_dir)\n matched = []\n new_checkpoint = dict(checkpoint)\n\n for f in sorted(ntf_dir.glob(\"*.json\")):\n date_key = f.stem\n items = json.loads(f.read_text())\n last_idx = checkpoint.get(date_key, {}).get(\"lastIndex\", -1)\n for i, item in enumerate(items):\n if i <= last_idx:\n continue\n if matches(item):\n matched.append(item)\n new_checkpoint[date_key] = {\"lastIndex\": len(items) - 1}\n\n checkpoint_path.write_text(json.dumps(new_checkpoint, indent=2))\n\n if not matched:\n print(\"NO_MATCH\")\n return\n\n for m in matched:\n print(json.dumps(m, ensure_ascii=False))\n\nif __name__ == \"__main__\":\n main()\n`;\n}\n\nfunction stringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === \"string\" && item.length > 0);\n}\n\nfunction pyLiteral(value: string | string[]): string {\n return JSON.stringify(value);\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { validateSegments } from \"../light/validators.js\";\nimport type { LightSegment } from \"../types.js\";\nimport type { BroadcastFn } from \"../update/types.js\";\nimport type {\n LightRuleCreateParams,\n LightRuleUpdateParams,\n LightRuleDeleteParams,\n} from \"./types.js\";\nimport { LightRuleError } from \"./storage.js\";\nimport type { LightRuleRegistry } from \"./registry.js\";\n\nconst DEFAULT_CRON_SCHEDULE = \"*/5 * * * *\";\n\nfunction resolveRuleIdentifier(params: unknown): string | undefined {\n if (!params || typeof params !== \"object\") return undefined;\n\n const raw = params as Record<string, unknown>;\n const candidates = [raw.name, raw.id, raw.ruleId, raw.ruleName];\n for (const candidate of candidates) {\n if (typeof candidate !== \"string\") continue;\n const normalized = candidate.trim().replace(/\\.json$/i, \"\");\n if (normalized) return normalized;\n }\n\n return undefined;\n}\n\nexport function registerLightRulesGateway(\n api: OpenClawPluginApi,\n registry: LightRuleRegistry,\n logger: Pick<Logger, \"info\" | \"warn\">,\n rememberBroadcast?: (broadcast: BroadcastFn | undefined) => void,\n): void {\n type GatewayHandler = Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1];\n\n const registerGatewayMethodWithBroadcastCapture = (\n method: string,\n handler: GatewayHandler,\n ): void => {\n api.registerGatewayMethod(method, (opts) => {\n rememberBroadcast?.(opts.context?.broadcast);\n return handler(opts);\n });\n };\n\n // lightrules.list\n registerGatewayMethodWithBroadcastCapture(\"lightrules.list\", async ({ respond }) => {\n try {\n const rules = registry.list().map((rule) => ({\n ...rule,\n id: rule.name,\n }));\n respond(true, { ok: true, rules });\n } catch (err: any) {\n logger.warn(`lightrules.list failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n });\n\n // lightrules.create\n registerGatewayMethodWithBroadcastCapture(\"lightrules.create\", async ({ params, respond }) => {\n const { name, description, matchRules, segments, repeat, repeat_times, cronSchedule } =\n params as unknown as LightRuleCreateParams;\n\n if (!name || typeof name !== \"string\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"name is required\" });\n return;\n }\n if (!description || typeof description !== \"string\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"description is required\" });\n return;\n }\n if (!matchRules || typeof matchRules !== \"object\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"matchRules is required\" });\n return;\n }\n\n const validation = validateSegments(segments);\n if (!validation.valid) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: JSON.stringify(validation.errors),\n });\n return;\n }\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (err: any) {\n respond(false, null, { code: \"VALIDATION_FAILED\", message: err?.message ?? \"Unknown error\" });\n return;\n }\n\n try {\n const result = await registry.create({\n name,\n description,\n matchRules,\n segments: validation.segments,\n repeat_times: repeatTimes,\n cronSchedule: cronSchedule || DEFAULT_CRON_SCHEDULE,\n });\n logger.info(`Light rule created: ${name}`);\n respond(true, { ok: true, name, cronHint: result.cronHint });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`lightrules.create failed: ${err?.message}`);\n respond(false, null, { code: \"INTERNAL_ERROR\", message: err?.message ?? \"Unknown error\" });\n }\n }\n });\n\n // lightrules.update\n registerGatewayMethodWithBroadcastCapture(\"lightrules.update\", async ({ params, respond }) => {\n const {\n description,\n matchRules,\n segments,\n repeat,\n repeat_times,\n cronSchedule,\n enabled,\n } = params as unknown as LightRuleUpdateParams;\n const name = resolveRuleIdentifier(params);\n\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required (or provide id/ruleId/ruleName)\",\n });\n return;\n }\n\n let validatedSegments: LightSegment[] | undefined;\n if (segments !== undefined) {\n const validation = validateSegments(segments);\n if (!validation.valid) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: JSON.stringify(validation.errors),\n });\n return;\n }\n validatedSegments = validation.segments;\n }\n\n let repeatTimes: number | undefined;\n if (repeat !== undefined || repeat_times !== undefined) {\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (err: any) {\n respond(false, null, { code: \"VALIDATION_FAILED\", message: err?.message ?? \"Unknown error\" });\n return;\n }\n }\n\n try {\n const result = await registry.update({\n name,\n description,\n matchRules,\n segments: validatedSegments,\n repeat_times: repeatTimes,\n cronSchedule,\n enabled,\n });\n logger.info(`Light rule updated: ${name}`);\n respond(true, {\n ok: true,\n id: result.meta.name,\n name: result.meta.name,\n updated: true,\n rule: result.meta,\n cronHint: result.cronHint,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`lightrules.update failed: ${err?.message}`);\n respond(false, null, { code: \"INTERNAL_ERROR\", message: err?.message ?? \"Unknown error\" });\n }\n }\n });\n\n // lightrules.delete\n registerGatewayMethodWithBroadcastCapture(\"lightrules.delete\", async ({ params, respond }) => {\n const name = resolveRuleIdentifier(params as unknown as LightRuleDeleteParams);\n\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required (or provide id/ruleId/ruleName)\",\n });\n return;\n }\n\n try {\n const result = await registry.delete(name);\n logger.info(`Light rule deleted: ${result.name}`);\n respond(true, {\n ok: true,\n id: result.name,\n name: result.name,\n deleted: true,\n cronHint: result.cronHint,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`lightrules.delete failed: ${err?.message}`);\n respond(false, null, { code: \"INTERNAL_ERROR\", message: err?.message ?? \"Unknown error\" });\n }\n }\n });\n}\n","/**\n * LightRulesEvaluatorJob — 管理 `light-rules-evaluator` cron job 的生命周期\n *\n * 职责:\n * 1. 在首次 `notifications.push` 到达时按需创建 `light-rules-evaluator` cron job\n * 2. 通知落盘后(若有新增且存在 enabled 规则),调用 `cron.enqueueRun` force-trigger 评估\n *\n * 设计约束:\n * - 本类**不**做规则匹配,匹配由 cron job 内的隔离 Agent session 完成\n * - `triggerIfNeeded` 是 fire-and-forget:成功入队后立即返回,不等待 job 执行\n * - job 存在性检查只走内存(`cron.getJob`),避免频繁 I/O\n *\n * 见 prd-lightrules-event-driven-refactor.md §宿主依赖 / §触发流程\n */\n\nimport type { Logger } from \"../logger.js\";\nimport type { LightRuleRegistry } from \"./registry.js\";\n\nexport const EVALUATOR_JOB_ID = \"light-rules-evaluator\";\n\n/**\n * 兜底定时调度:设为每年 1 月 1 日 0 点(几乎不触发)。\n * 实际驱动完全依赖 `enqueueRun(\"force\")`,schedule 仅作为 cron job 结构的必填字段。\n */\nconst FALLBACK_CRON_EXPR = \"0 0 1 1 *\";\n\nconst EVALUATOR_JOB_MESSAGE = `灯效规则评估任务。\n\n执行步骤:\n1. 读取 tasks/light-rules-evaluator/checkpoint.json(记录上次处理进度)\n2. 扫描 notifications/ 目录,获取 checkpoint 之后的新通知\n3. 扫描 tasks/ 目录,读取所有 type=light-rule 且 enabled=true 的 meta.json\n4. 对每条新通知,逐一判断是否命中每条规则的 description(语义匹配)\n5. 命中时:以该规则的 segments 和 repeat_times 调用 light_control 工具\n6. 更新 checkpoint.json,记录已处理到的最新通知位置\n7. 若无新通知或无 enabled 规则:输出 NO_CHANGE,直接结束`;\n\n/**\n * 最小结构接口,匹配 SDK CronService 中我们实际用到的方法。\n * 避免直接导入 SDK 内部类型,降低耦合。\n */\nexport interface CronServiceLike {\n getJob(id: string): unknown;\n add(input: {\n id: string;\n name: string;\n description?: string;\n enabled: boolean;\n schedule: { kind: \"cron\"; expr: string };\n sessionTarget: string;\n wakeMode: string;\n payload: { kind: \"agentTurn\"; message: string };\n }): Promise<unknown>;\n enqueueRun(\n id: string,\n mode?: \"due\" | \"force\",\n ): Promise<\n | { ok: true; enqueued: true; runId: string }\n | { ok: true; ran: false; reason: string }\n | { ok: false }\n | Record<string, unknown>\n >;\n}\n\nexport class LightRulesEvaluatorJob {\n private readonly logger: Pick<Logger, \"info\" | \"warn\">;\n private readonly registry: LightRuleRegistry;\n\n /**\n * 记录本进程生命周期内 job 是否已确认存在。\n * 仅在 `ensureJobExists` 成功后置 true,避免每次 push 都做检查。\n */\n private jobEnsured = false;\n /**\n * 首次创建 job 时的并发保护。\n * 避免冷启动瞬间多条通知并发到达时重复调用 `cron.add`。\n */\n private ensureJobPromise: Promise<void> | null = null;\n\n constructor(deps: { logger: Pick<Logger, \"info\" | \"warn\">; registry: LightRuleRegistry }) {\n this.logger = deps.logger;\n this.registry = deps.registry;\n }\n\n /**\n * 通知落盘后调用。若有新增通知且存在 enabled 规则,则 force-trigger 评估 job。\n *\n * @param cron 来自 gateway context 的 CronService 实例\n * @param insertedCount 本次 ingest 新落盘的通知条数(StoredNotification 去重后)\n */\n async triggerIfNeeded(cron: CronServiceLike, insertedCount: number): Promise<void> {\n if (insertedCount === 0) return;\n if (this.registry.getEnabled().length === 0) return;\n\n try {\n await this.ensureJobExists(cron);\n } catch (err: any) {\n this.logger.warn(`light-rules-evaluator: job ensure failed: ${err?.message ?? err}`);\n return;\n }\n\n try {\n const result = await cron.enqueueRun(EVALUATOR_JOB_ID, \"force\");\n if (!result.ok) {\n this.logger.warn(\"light-rules-evaluator: enqueueRun returned ok=false\");\n return;\n }\n if (\"enqueued\" in result && result.enqueued) {\n this.logger.info(`light-rules-evaluator: enqueued runId=${(result as any).runId}`);\n } else if (\"reason\" in result) {\n // already-running 或 not-due:当前运行中的 job 会处理到这批通知\n this.logger.info(`light-rules-evaluator: enqueueRun skipped (${result.reason})`);\n }\n } catch (err: any) {\n this.logger.warn(`light-rules-evaluator: enqueueRun failed: ${err?.message ?? err}`);\n }\n }\n\n /**\n * 按需创建 `light-rules-evaluator` job。\n * 若 job 已存在(内存缓存或 cron store),直接返回;否则调用 `cron.add`。\n */\n private async ensureJobExists(cron: CronServiceLike): Promise<void> {\n if (this.jobEnsured) return;\n if (!this.ensureJobPromise) {\n this.ensureJobPromise = this.createJobIfNeeded(cron).finally(() => {\n this.ensureJobPromise = null;\n });\n }\n await this.ensureJobPromise;\n }\n\n private async createJobIfNeeded(cron: CronServiceLike): Promise<void> {\n if (cron.getJob(EVALUATOR_JOB_ID)) {\n this.jobEnsured = true;\n return;\n }\n\n try {\n await cron.add({\n id: EVALUATOR_JOB_ID,\n name: \"灯效规则评估\",\n description:\n \"事件驱动:通知到达时评估所有 enabled 灯效规则,命中则调用 light_control 触发灯效\",\n enabled: true,\n schedule: { kind: \"cron\", expr: FALLBACK_CRON_EXPR },\n sessionTarget: \"isolated\",\n wakeMode: \"now\",\n payload: {\n kind: \"agentTurn\",\n message: EVALUATOR_JOB_MESSAGE,\n },\n });\n this.logger.info(\"light-rules-evaluator: job created\");\n } catch (err) {\n // 兜底处理:如果别的调用路径几乎同时创建成功,这里把它视为“已存在”。\n if (!cron.getJob(EVALUATOR_JOB_ID)) {\n throw err;\n }\n }\n\n this.jobEnsured = true;\n }\n}\n","/**\n * 旧版 light-rule task 目录迁移\n *\n * 目标:让存量 cron 路径平滑过渡到事件驱动架构,同时清理不再需要的辅助文件。\n *\n * 对每个 tasks/<name>/meta.json 中 type === \"light-rule\" 的目录:\n * 1. 把 matchRules 字段的内容合并进 description,再从 meta.json 删除该字段\n * 2. 替换 fetch.py 为只打印 NO_MATCH 的占位脚本(让旧 cron job 自动失效)\n * 3. 删除 README.md 和 checkpoint.json(新架构不再使用这两个文件)\n *\n * 安全设计:\n * - 不修改 type !== \"light-rule\" 的目录(普通 monitor 任务不受影响)\n * - 所有 I/O 错误只写 warn 日志,不抛出(不影响主链路启动)\n * - fetch.py 替换前先检查内容是否已经是 NO_MATCH 占位脚本,避免重复写\n *\n * 见 prd-lightrules-event-driven-refactor.md §迁移策略\n */\n\nimport {\n existsSync,\n readdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Logger } from \"../logger.js\";\nimport type { LightRuleStorageContext } from \"./storage.js\";\n\n/**\n * 替换旧版 fetch.py 的占位脚本。\n * 旧 cron job 运行后看到 NO_MATCH 就会自动退出,不再触发灯效。\n */\nconst NO_MATCH_FETCH_PY = `#!/usr/bin/env python3\n# 此文件由迁移工具生成。\n# 灯效规则已迁移至事件驱动架构,此 cron job 不再执行实际工作。\nprint(\"NO_MATCH\")\n`;\n\nfunction normalizeScriptText(text: string): string {\n return text.replace(/\\r\\n/g, \"\\n\").trim();\n}\n\n/**\n * 从 LightRuleStorageContext 解析 tasks 目录路径(与 storage.ts 逻辑一致)。\n */\nfunction resolveTasksDir(ctx: LightRuleStorageContext): string | null {\n if (ctx.workspaceDir) return join(ctx.workspaceDir, \"tasks\");\n\n if (ctx.stateDir) {\n const inferredWorkspaceDir = join(ctx.stateDir, \"workspace\");\n if (existsSync(inferredWorkspaceDir)) return join(inferredWorkspaceDir, \"tasks\");\n return join(ctx.stateDir, \"tasks\");\n }\n\n return null;\n}\n\n/**\n * 迁移入口。在插件 storage service start 完成后(lightRuleCtx 已回填)调用一次。\n */\nexport function migrateLegacyLightRuleTasks(\n ctx: LightRuleStorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n const tasksDir = resolveTasksDir(ctx);\n if (!tasksDir || !existsSync(tasksDir)) return;\n\n try {\n for (const entry of readdirSync(tasksDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n migrateTaskDir(join(tasksDir, String(entry.name)), logger);\n }\n } catch (err: any) {\n logger.warn(`migration: failed to read tasks dir: ${err?.message}`);\n }\n}\n\nfunction migrateTaskDir(taskDir: string, logger: Pick<Logger, \"info\" | \"warn\">): void {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return;\n\n let meta: Record<string, unknown>;\n try {\n meta = JSON.parse(readFileSync(metaPath, \"utf-8\"));\n } catch {\n return;\n }\n\n if (meta.type !== \"light-rule\") return;\n\n const name = typeof meta.name === \"string\" ? meta.name : taskDir;\n\n // ── 1. 把 matchRules 合并进 description ──────────────────────────────────\n mergeMatchRulesIntoDescription(meta, name, metaPath, logger);\n\n // ── 2. 替换 fetch.py 为 NO_MATCH 占位脚本 ────────────────────────────────\n replaceFetchPy(taskDir, name, logger);\n\n // ── 3. 删除 README.md 和 checkpoint.json ─────────────────────────────────\n for (const filename of [\"README.md\", \"checkpoint.json\"]) {\n removeFile(join(taskDir, filename), name, filename, logger);\n }\n}\n\nfunction mergeMatchRulesIntoDescription(\n meta: Record<string, unknown>,\n name: string,\n metaPath: string,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n const matchRules = meta.matchRules;\n if (!matchRules || typeof matchRules !== \"object\") return;\n\n const rules = matchRules as {\n appName?: string;\n senderKeywords?: string[];\n contentKeywords?: string[];\n };\n\n const parts: string[] = [];\n if (rules.appName) parts.push(`app=${rules.appName}`);\n if (rules.senderKeywords?.length) {\n parts.push(`发件人关键词=${rules.senderKeywords.join(\"、\")}`);\n }\n if (rules.contentKeywords?.length) {\n parts.push(`内容关键词=${rules.contentKeywords.join(\"、\")}`);\n }\n\n if (parts.length > 0) {\n const existing = typeof meta.description === \"string\" ? meta.description.trim() : \"\";\n meta.description = existing\n ? `${existing}。匹配规则:${parts.join(\",\")}`\n : `匹配规则:${parts.join(\",\")}`;\n }\n\n delete meta.matchRules;\n\n try {\n writeFileSync(metaPath, JSON.stringify(meta, null, 2), \"utf-8\");\n logger.info(`migration: merged matchRules into description for light rule: ${name}`);\n } catch (err: any) {\n logger.warn(`migration: failed to update meta.json for ${name}: ${err?.message}`);\n }\n}\n\nfunction replaceFetchPy(\n taskDir: string,\n name: string,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n const fetchPyPath = join(taskDir, \"fetch.py\");\n if (!existsSync(fetchPyPath)) return;\n\n try {\n const existing = readFileSync(fetchPyPath, \"utf-8\");\n if (normalizeScriptText(existing) === normalizeScriptText(NO_MATCH_FETCH_PY)) {\n return;\n }\n writeFileSync(fetchPyPath, NO_MATCH_FETCH_PY, \"utf-8\");\n logger.info(`migration: replaced fetch.py with NO_MATCH placeholder for ${name}`);\n } catch (err: any) {\n logger.warn(`migration: failed to replace fetch.py for ${name}: ${err?.message}`);\n }\n}\n\nfunction removeFile(\n filePath: string,\n ruleName: string,\n filename: string,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n if (!existsSync(filePath)) return;\n try {\n rmSync(filePath);\n logger.info(`migration: removed ${filename} for light rule: ${ruleName}`);\n } catch (err: any) {\n logger.warn(`migration: failed to remove ${filename} for ${ruleName}: ${err?.message}`);\n }\n}\n","/**\n * LightRuleRegistry —— 灯效规则的内存索引 + CRUD 包装\n *\n * 角色定位:\n * - 在事件驱动重构方案下,每条通知到达时都需要拿到\"当前 enabled 的全部规则\"\n * 用来拼装 Agent 的 system prompt。如果每次都扫盘 N 个 meta.json,\n * 5 秒延迟预算会被磨穿,所以引入这个常驻内存的 index。\n * - 同时它是 storage.ts 的 CRUD 包装:所有 create/update/delete 都会先落盘、\n * 再更新内存 Map,保证两者一致。\n *\n * 本类**不**做规则匹配 —— 匹配交给 Agent。registry 只负责\"有哪些规则\"和\n * \"按需拼装 prompt\"。\n *\n * 写路径用一个 promise 链做串行化(最朴素的 mutex),保证并发 CRUD\n * 不会出现\"内存和磁盘交错\"的状态。\n *\n * 见 prd-lightrules-event-driven-refactor.md §数据模型 / §触发流程\n */\n\nimport {\n createLightRule,\n deleteLightRule,\n listLightRules,\n updateLightRule,\n type LightRuleStorageContext,\n} from \"./storage.js\";\nimport type { LightRuleMeta } from \"./types.js\";\n\nexport { LightRuleError } from \"./storage.js\";\n\ntype CreateParams = Parameters<typeof createLightRule>[1];\ntype UpdateParams = Parameters<typeof updateLightRule>[1];\ntype CreateResult = ReturnType<typeof createLightRule>;\ntype UpdateResult = ReturnType<typeof updateLightRule>;\ntype DeleteResult = ReturnType<typeof deleteLightRule>;\n\nexport class LightRuleRegistry {\n private readonly ctx: LightRuleStorageContext;\n /** name → meta 的内存索引;落盘成功后才更新 */\n private readonly index = new Map<string, LightRuleMeta>();\n /** 写路径串行化锁:每次 mutate 都 chain 在前一次之后 */\n private writeChain: Promise<unknown> = Promise.resolve();\n\n constructor(ctx: LightRuleStorageContext) {\n this.ctx = ctx;\n this.reload();\n }\n\n /**\n * 从磁盘重新加载全部规则到内存。仅在构造时和外部显式触发时使用。\n * 正常 CRUD 路径不应该调用本方法 —— 通过 create/update/delete 增量维护即可。\n */\n reload(): void {\n this.index.clear();\n for (const meta of listLightRules(this.ctx)) {\n this.index.set(meta.name, meta);\n }\n }\n\n /** 全部规则(包含 disabled),调用方不要改返回值。 */\n list(): LightRuleMeta[] {\n return Array.from(this.index.values());\n }\n\n /** 仅 enabled 的规则。事件驱动评估链路使用。 */\n getEnabled(): LightRuleMeta[] {\n return this.list().filter((rule) => rule.enabled);\n }\n\n /** 按名字精确查找;不存在返回 null。 */\n get(name: string): LightRuleMeta | null {\n return this.index.get(name) ?? null;\n }\n\n /**\n * 创建规则。落盘成功后再写入内存索引。\n * 失败时 storage 抛 LightRuleError,内存索引保持不变。\n */\n async create(params: CreateParams): Promise<CreateResult> {\n return this.runExclusive(() => {\n const result = createLightRule(this.ctx, params);\n this.index.set(result.meta.name, result.meta);\n return result;\n });\n }\n\n /**\n * 更新规则。落盘成功后再刷新内存条目。\n */\n async update(params: UpdateParams): Promise<UpdateResult> {\n return this.runExclusive(() => {\n const result = updateLightRule(this.ctx, params);\n this.index.set(result.meta.name, result.meta);\n return result;\n });\n }\n\n /**\n * 删除规则。落盘成功后再从内存索引移除。\n */\n async delete(name: string): Promise<DeleteResult> {\n return this.runExclusive(() => {\n const result = deleteLightRule(this.ctx, name);\n this.index.delete(result.name);\n return result;\n });\n }\n\n /**\n * 拼装 Agent 评估用的 system prompt。\n *\n * 当前实现是一个最小可用骨架:列出全部 enabled 规则的 name + description。\n * M3 接入真实 Agent 链路时,会按 prd-lightrules-event-driven-refactor.md §Prompt 拼装\n * 的模板补齐\"任务说明 / 输出约束\"等段落。\n *\n * 现在先把方法签名冻结,避免后续散落在多个调用点。\n */\n buildSystemPrompt(): string {\n const enabled = this.getEnabled();\n if (enabled.length === 0) {\n return \"当前没有启用任何灯效规则。\";\n }\n\n const lines: string[] = [\n '你是一个判断\"通知 → 灯效规则\"是否命中的助手。',\n \"\",\n \"下面是用户当前启用的全部灯效规则(按创建时间倒序):\",\n \"\",\n ];\n\n const sorted = [...enabled].sort((a, b) =>\n (b.createdAt ?? \"\").localeCompare(a.createdAt ?? \"\"),\n );\n\n sorted.forEach((rule, idx) => {\n lines.push(\n `[${idx + 1}] name: ${rule.name}`,\n ` description: ${rule.description}`,\n \"\",\n );\n });\n\n lines.push(\n '任务:根据用户接下来发给你的\"通知\"内容,判断哪些规则被命中。',\n \"- 命中 0 条:不调用任何工具,直接结束。\",\n \"- 命中 1 条或多条:对每一条命中的规则调用一次 trigger_light(rule_name)。\",\n \"- 不要回复任何自由文本;判定结果**只**通过 tool calling 表达。\",\n '- 拿不准的时候倾向于\"不触发\",避免骚扰用户。',\n );\n\n return lines.join(\"\\n\");\n }\n\n /**\n * 把一段同步操作排队进 write chain,保证 mutate 串行执行。\n *\n * 用 promise 链做 mutex 是最简单的方案:每次 runExclusive 都把\n * `writeChain` 推进一步。即使前一个任务失败,链也会继续往下走,\n * 后续任务不会被永久阻塞。\n */\n private runExclusive<T>(fn: () => T): Promise<T> {\n const next = this.writeChain.then(\n () => fn(),\n () => fn(),\n );\n // 不让链上的失败传播下去(已在 then 的 onRejected 回调里吸收)\n this.writeChain = next.catch(() => undefined);\n return next;\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { loadEnvName } from \"../env.js\";\nimport type { Logger } from \"../logger.js\";\nimport { createTunnelService } from \"../tunnel/service.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { resolveUpdateChannel } from \"../update/channel.js\";\nimport { registerAutoUpdate } from \"../update/index.js\";\nimport type { BroadcastFn } from \"../update/types.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\n\ninterface AutoUpdateDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n getBroadcastFn: () => BroadcastFn | null;\n cacheBroadcast: (broadcast: BroadcastFn | undefined) => void;\n tunnelService: ReturnType<typeof createTunnelService> | null;\n}\n\nexport function registerAutoUpdateLifecycle(\n deps: AutoUpdateDeps,\n): ReturnType<typeof registerAutoUpdate> {\n const {\n api,\n config,\n logger,\n getBroadcastFn,\n cacheBroadcast,\n tunnelService,\n } = deps;\n\n const autoUpdateConfig = {\n ...config.autoUpdate,\n channel: resolveUpdateChannel({\n configuredChannel: config.autoUpdate?.channel,\n currentVersion: PLUGIN_VERSION,\n envName: loadEnvName(),\n }),\n };\n\n const autoUpdateLifecycle = registerAutoUpdate(\n api,\n logger,\n autoUpdateConfig,\n getBroadcastFn,\n cacheBroadcast,\n tunnelService\n ? {\n notifyUpdateAvailable: (update) => tunnelService.notifyUpdateAvailable(update),\n clearPendingUpdate: () => tunnelService.clearPendingUpdate(),\n }\n : undefined,\n );\n\n api.registerService({\n id: \"update-checker\",\n start() {\n autoUpdateLifecycle.start();\n },\n stop() {\n autoUpdateLifecycle.stop();\n },\n });\n\n logger.info(\"自动更新检查服务已注册\");\n return autoUpdateLifecycle;\n}\n","import type { EnvName } from \"../env.js\";\nimport type { AutoUpdateConfig } from \"./types.js\";\n\n/**\n * 解析自动更新频道。\n *\n * 默认规则:\n * - 用户显式配置时,以配置为准\n * - 当前安装的是预发布版时,默认持续跟踪 beta\n * - 否则开发环境走 beta,生产环境走 latest\n */\nexport function resolveUpdateChannel(params: {\n configuredChannel?: AutoUpdateConfig[\"channel\"];\n currentVersion: string;\n envName: EnvName;\n}): \"latest\" | \"beta\" {\n if (params.configuredChannel) {\n return params.configuredChannel;\n }\n\n if (params.currentVersion.includes(\"-\")) {\n return \"beta\";\n }\n\n return params.envName === \"development\" ? \"beta\" : \"latest\";\n}\n","import { PLUGIN_VERSION } from \"../version.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { UpdateInfo } from \"./types.js\";\n\nconst CDN_BASE_URL = \"https://cdn.yoootek.com/openclaw-plugin\";\nconst NPM_BASE_URL =\n \"https://registry.npmjs.org/@yoooclaw/phone-notifications\";\nconst FETCH_TIMEOUT_MS = 5_000;\n\nexport class UpdateChecker {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private notifiedVersion: string | null = null;\n\n constructor(\n private readonly logger: Logger,\n private readonly onUpdateFound: (info: UpdateInfo) => void,\n private readonly intervalMs: number,\n private readonly channel: \"latest\" | \"beta\",\n ) {}\n\n start(): void {\n // 首次延迟 1 分钟,避免影响插件启动\n this.timer = setTimeout(() => {\n void this.check();\n this.timer = setInterval(() => void this.check(), this.intervalMs);\n }, 60_000);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n async check(): Promise<void> {\n const latest = await this.fetchLatestVersion();\n if (!latest || latest === PLUGIN_VERSION) return;\n if (latest === this.notifiedVersion) return;\n\n // 当前版本为预发布且 channel 不是 beta 时,不提示\n if (PLUGIN_VERSION.includes(\"-\") && this.channel !== \"beta\") return;\n\n this.notifiedVersion = latest;\n this.logger.info(`发现新版本: ${PLUGIN_VERSION} → ${latest}`);\n this.onUpdateFound({ current: PLUGIN_VERSION, latest });\n }\n\n private async fetchLatestVersion(): Promise<string | null> {\n const tag = this.channel === \"beta\" ? \"beta\" : \"latest\";\n\n // 优先 CDN(轻量 plain text)\n try {\n const res = await fetch(`${CDN_BASE_URL}/${tag}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (res.ok) {\n const text = (await res.text()).trim();\n if (text) return text;\n }\n } catch {\n // CDN 不可达,回退 npm\n }\n\n // 回退 npm registry\n try {\n const res = await fetch(`${NPM_BASE_URL}/${tag}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (res.ok) {\n const data = (await res.json()) as { version?: string };\n return data.version ?? null;\n }\n } catch {\n this.logger.info(\"版本检查失败(CDN + npm 均不可达),跳过\");\n }\n\n return null;\n }\n}\n","import type { Logger } from \"../logger.js\";\n\nconst VERSION_PATTERN = /^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?$/;\n\nexport interface UpdateResult {\n success: boolean;\n message: string;\n}\n\n/**\n * 执行插件更新命令。\n * 对话通道的 tool 和网关通道的 gateway method 共用此函数。\n *\n * @param version 目标版本号,需通过正则校验防止命令注入\n * @param runCommand Host 提供的 runCommandWithTimeout\n */\nexport async function executeUpdate(\n version: string,\n runCommand: (\n argv: string[],\n opts: { timeoutMs: number },\n ) => Promise<{ code: number | null; stdout: string; stderr: string }>,\n logger: Logger,\n): Promise<UpdateResult> {\n if (!VERSION_PATTERN.test(version)) {\n return { success: false, message: `非法版本号: ${version}` };\n }\n\n const argv = [\n \"openclaw\",\n \"extension\",\n \"install\",\n `@yoooclaw/phone-notifications@${version}`,\n ];\n logger.info(`执行更新: ${argv.join(\" \")}`);\n\n try {\n const result = await runCommand(argv, { timeoutMs: 120_000 });\n\n if (result.code === 0) {\n const msg = `已更新到 ${version},请重启 gateway 生效`;\n logger.info(msg);\n return { success: true, message: msg };\n }\n\n const errMsg = `更新失败 (exit ${result.code}): ${result.stderr || result.stdout}`;\n logger.error(errMsg);\n return { success: false, message: errMsg };\n } catch (err) {\n const errMsg = `更新命令执行异常: ${String(err)}`;\n logger.error(errMsg);\n return { success: false, message: errMsg };\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport type {\n AutoUpdateConfig,\n BroadcastFn,\n ExternalUpdateNotifier,\n UpdateInfo,\n} from \"./types.js\";\nimport { UpdateChecker } from \"./checker.js\";\nimport { executeUpdate } from \"./executor.js\";\n\n/**\n * 注册插件自动更新能力:\n * - 定时版本检查(UpdateChecker)\n * - 对话通道:before_prompt_build hook + plugin-update tool\n * - 网关通道:broadcast 推送 + plugin.update gateway method\n *\n * 返回 start/stop 供 registerService 管理生命周期。\n */\nexport function registerAutoUpdate(\n api: OpenClawPluginApi,\n logger: Logger,\n config: AutoUpdateConfig,\n getBroadcast: () => BroadcastFn | null,\n rememberBroadcast?: (broadcast: BroadcastFn | undefined) => void,\n externalUpdateNotifier?: ExternalUpdateNotifier,\n): {\n start: () => void;\n stop: () => void;\n notifyBroadcastReady: () => void;\n} {\n if (config.enabled === false) {\n logger.info(\"自动更新已禁用 (autoUpdate.enabled = false)\");\n return { start() {}, stop() {}, notifyBroadcastReady() {} };\n }\n\n let pendingUpdate: UpdateInfo | null = null;\n let pendingGatewayUpdate: UpdateInfo | null = null;\n\n function tryBroadcastUpdate(update: UpdateInfo): boolean {\n const broadcast = getBroadcast();\n if (!broadcast) return false;\n\n broadcast(\"plugin.updateAvailable\", {\n pluginId: \"phone-notifications\",\n current: update.current,\n latest: update.latest,\n });\n pendingGatewayUpdate = null;\n return true;\n }\n\n // ── 对话通道:hook 注入 system prompt ──\n\n api.on(\"before_prompt_build\", () => {\n if (!pendingUpdate) return;\n return {\n appendSystemContext:\n `[系统通知] phone-notifications 插件有新版本 ${pendingUpdate.latest} 可用` +\n `(当前版本 ${pendingUpdate.current})。\\n` +\n `请用自然语言在合适时机告知用户,若用户同意更新,` +\n `调用 plugin-update tool 并传入 version 参数。` +\n `若用户拒绝,不再重复提醒。`,\n };\n });\n\n // ── 对话通道:plugin-update tool ──\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n api.registerTool({\n name: \"plugin-update\",\n label: \"Plugin Update\",\n description:\n \"将 phone-notifications 插件更新到指定版本。\" +\n \"仅在用户明确同意更新后调用。更新完成后需重启 gateway 生效。\",\n parameters: {\n type: \"object\",\n required: [\"version\"],\n additionalProperties: false,\n properties: {\n version: {\n type: \"string\",\n description: \"目标版本号,如 1.11.0\",\n },\n },\n },\n async execute(_toolCallId: string, params: unknown) {\n const { version } = params as { version: string };\n const result = await executeUpdate(\n version,\n api.runtime.system.runCommandWithTimeout,\n logger,\n );\n if (result.success) {\n pendingUpdate = null;\n externalUpdateNotifier?.clearPendingUpdate();\n }\n return {\n content: [{ type: \"text\" as const, text: result.message }],\n details: result,\n };\n },\n } as any);\n\n // ── 网关通道:plugin.update gateway method ──\n\n api.registerGatewayMethod(\"plugin.update\", async ({ params, respond, context }) => {\n rememberBroadcast?.(context?.broadcast);\n\n const version = (params as { version?: string }).version;\n if (!version) {\n respond(false, undefined, {\n code: \"MISSING_VERSION\",\n message: \"version is required\",\n });\n return;\n }\n const result = await executeUpdate(\n version,\n api.runtime.system.runCommandWithTimeout,\n logger,\n );\n if (result.success) {\n pendingUpdate = null;\n externalUpdateNotifier?.clearPendingUpdate();\n }\n if (result.success) {\n respond(true, { message: result.message });\n } else {\n respond(false, undefined, {\n code: \"UPDATE_FAILED\",\n message: result.message,\n });\n }\n });\n\n // ── 版本检查器 ──\n\n const intervalMs = (config.checkIntervalHours ?? 4) * 3_600_000;\n const channel = config.channel ?? \"latest\";\n\n logger.info(\n `自动更新已启用: channel=${channel}, checkIntervalHours=${config.checkIntervalHours ?? 4}`,\n );\n\n const checker = new UpdateChecker(\n logger,\n (update) => {\n pendingUpdate = update;\n\n const broadcasted = tryBroadcastUpdate(update);\n if (!broadcasted) pendingGatewayUpdate = update;\n if (!broadcasted) {\n externalUpdateNotifier?.notifyUpdateAvailable(update);\n }\n\n logger.info(\n `已通知更新 ${update.current} → ${update.latest}` +\n (broadcasted\n ? \"(对话 + 网关)\"\n : \"(对话通道已生效,等待下次 gateway 请求时补发客户端事件)\"),\n );\n },\n intervalMs,\n channel,\n );\n\n return {\n start: () => checker.start(),\n stop: () => checker.stop(),\n notifyBroadcastReady() {\n const update = pendingGatewayUpdate;\n if (!update) return;\n if (!tryBroadcastUpdate(update)) return;\n logger.info(`已补发插件更新事件 ${update.current} → ${update.latest}`);\n },\n };\n}\n","import { basename, dirname } from \"node:path\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { registerAllCli } from \"../cli/index.js\";\nimport type { Logger } from \"../logger.js\";\n\nfunction inferOpenClawRootDir(workspaceDir?: string): string | undefined {\n if (!workspaceDir) {\n return undefined;\n }\n\n if (basename(workspaceDir) !== \"workspace\") {\n return undefined;\n }\n\n return dirname(workspaceDir);\n}\n\nexport function registerPluginCli(\n api: OpenClawPluginApi,\n params: {\n logger: Logger;\n openclawDir?: string;\n },\n): void {\n const { logger, openclawDir } = params;\n\n const registerAlias = (command: \"ntf\" | \"phone-notifications\"): void => {\n api.registerCli(\n (ctx) => {\n const effectiveStateDir = openclawDir ?? inferOpenClawRootDir(ctx.workspaceDir);\n registerAllCli(\n ctx.program,\n {\n stateDir: effectiveStateDir,\n workspaceDir: ctx.workspaceDir,\n },\n command,\n );\n },\n { commands: [command] },\n );\n };\n\n registerAlias(\"ntf\");\n registerAlias(\"phone-notifications\");\n logger.info(\"CLI 命令已注册: ntf, phone-notifications\");\n}\n","import { existsSync, rmSync } from \"node:fs\";\nimport type { CliCommand } from \"./helpers.js\";\nimport { output } from \"./helpers.js\";\nimport {\n credentialsPath,\n readCredentials,\n writeCredentials,\n} from \"../auth/credentials.js\";\n\nexport function registerAuthCli(program: CliCommand): void {\n const auth = program\n .command(\"auth\")\n .description(\"用户认证管理\");\n\n auth\n .command(\"set-api-key <apiKey>\")\n .description(\"设置用户 API Key(持久化到本地配置)\")\n .action((apiKey: string) => {\n writeCredentials({ ...readCredentials(), apiKey, token: undefined });\n output({\n ok: true,\n apiKey: apiKey.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n });\n\n // 兼容旧命令:set-token <token>,现在等价于 set-api-key\n auth\n .command(\"set-token <token>\")\n .description(\"(兼容)设置用户 API Key(旧命令名)\")\n .action((token: string) => {\n writeCredentials({ ...readCredentials(), apiKey: token, token: undefined });\n output({\n ok: true,\n apiKey: token.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n });\n\n auth\n .command(\"show\")\n .description(\"查看当前认证状态\")\n .action(() => {\n const creds = readCredentials();\n const apiKey = creds.apiKey ?? creds.token;\n if (apiKey) {\n output({\n ok: true,\n hasApiKey: true,\n apiKey: apiKey.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n } else {\n output({ ok: true, hasApiKey: false });\n }\n });\n\n auth\n .command(\"clear\")\n .description(\"清除已保存的认证信息\")\n .action(() => {\n const path = credentialsPath();\n if (existsSync(path)) {\n const creds = readCredentials();\n delete creds.apiKey;\n delete creds.token;\n if (Object.keys(creds).length === 0) {\n rmSync(path, { force: true });\n } else {\n writeCredentials(creds);\n }\n }\n output({ ok: true, cleared: true });\n });\n}\n","import type { StoredNotification } from \"../notification/storage.js\";\nimport {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeysAsync,\n readDateFileAsync,\n parseIsoTime,\n sortNotificationsByTimestampDesc,\n output,\n exitError,\n progress,\n} from \"./helpers.js\";\n\nfunction filterItem(\n item: StoredNotification,\n opts: { app?: string; sender?: string; keyword?: string },\n): boolean {\n if (opts.app && item.appName !== opts.app) return false;\n if (opts.sender && !item.title.includes(opts.sender)) return false;\n if (\n opts.keyword &&\n !item.title.includes(opts.keyword) &&\n !item.content.includes(opts.keyword)\n ) {\n return false;\n }\n return true;\n}\n\nexport function registerNtfSearch(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"search\")\n .description(\"查询通知(按时间/应用/发送人/关键词筛选)\")\n .option(\"--from <time>\", \"开始时间 ISO 8601,例如 2026-03-01T09:00:00+08:00\")\n .option(\"--to <time>\", \"结束时间 ISO 8601,例如 2026-03-01T18:00:00+08:00\")\n .option(\"--app <name>\", \"按应用名过滤\")\n .option(\"--sender <name>\", \"按发送人过滤\")\n .option(\"--keyword <text>\", \"在标题和内容中搜索关键词\")\n .option(\"--limit <n>\", \"最大返回条数\", \"100\")\n .action(\n async (opts: {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n keyword?: string;\n limit: string;\n }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n progress(\"正在搜索通知...\");\n\n const limit = parseInt(opts.limit, 10) || 100;\n if (limit <= 0) {\n exitError(\"INVALID_LIMIT\", \"--limit 必须是大于 0 的整数\");\n }\n\n const hasFrom = typeof opts.from === \"string\" && opts.from.length > 0;\n const hasTo = typeof opts.to === \"string\" && opts.to.length > 0;\n const fromTs = hasFrom ? parseIsoTime(opts.from!, \"--from\") : null;\n const toTs = hasTo ? parseIsoTime(opts.to!, \"--to\") : null;\n\n if (fromTs !== null && toTs !== null && fromTs > toTs) {\n exitError(\"INVALID_TIME_RANGE\", \"--from 不能晚于 --to\");\n }\n\n const keys = await listDateKeysAsync(dir);\n const results: StoredNotification[] = [];\n\n if (fromTs !== null || toTs !== null) {\n const fromDateKey = hasFrom ? opts.from!.slice(0, 10) : null;\n const toDateKey = hasTo ? opts.to!.slice(0, 10) : null;\n\n for (const dateKey of keys) {\n if (fromDateKey && dateKey < fromDateKey) continue;\n if (toDateKey && dateKey > toDateKey) continue;\n\n const items = await readDateFileAsync(dir, dateKey);\n for (const item of items) {\n if (!filterItem(item, opts)) continue;\n\n const itemTs = Date.parse(item.timestamp);\n if (Number.isNaN(itemTs)) continue;\n if (fromTs !== null && itemTs < fromTs) continue;\n if (toTs !== null && itemTs > toTs) continue;\n results.push(item);\n }\n }\n } else {\n for (const dateKey of keys) {\n const items = await readDateFileAsync(dir, dateKey);\n for (const item of items) {\n if (!filterItem(item, opts)) continue;\n if (Number.isNaN(Date.parse(item.timestamp))) continue;\n results.push(item);\n }\n }\n }\n\n const notifications = sortNotificationsByTimestampDesc(results).slice(\n 0,\n limit,\n );\n\n output({\n ok: true,\n total: notifications.length,\n notifications,\n });\n },\n );\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeys,\n readDateFile,\n filterDateRange,\n today,\n daysAgo,\n output,\n exitError,\n} from \"./helpers.js\";\n\ntype Dimension = \"date\" | \"app\" | \"sender\" | \"hour\" | \"all\";\n\nexport function registerNtfStats(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"stats\")\n .description(\"通知统计分析(按日期/应用/发送人/时段聚合)\")\n .option(\"--from <date>\", \"开始日期 YYYY-MM-DD\", daysAgo(7))\n .option(\"--to <date>\", \"结束日期 YYYY-MM-DD\", today())\n .option(\"--app <name>\", \"只统计指定应用\")\n .option(\"--dim <dimension>\", \"统计维度:date/app/sender/hour/all\", \"all\")\n .action(\n (opts: { from: string; to: string; app?: string; dim: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const dim = opts.dim as Dimension;\n const keys = filterDateRange(listDateKeys(dir), opts.from, opts.to);\n\n const byDate: Record<string, number> = {};\n const byApp: Record<string, number> = {};\n const bySender: Record<string, number> = {};\n const byHour: Record<string, number> = {};\n let total = 0;\n\n for (const dateKey of keys) {\n const items = readDateFile(dir, dateKey);\n let dateCount = 0;\n for (const item of items) {\n if (opts.app && item.appName !== opts.app) continue;\n total++;\n dateCount++;\n\n byApp[item.appName] = (byApp[item.appName] || 0) + 1;\n\n if (item.title) {\n bySender[item.title] = (bySender[item.title] || 0) + 1;\n }\n\n const hourMatch = /T(\\d{2}):/.exec(item.timestamp);\n if (hourMatch) {\n const h = hourMatch[1];\n byHour[h] = (byHour[h] || 0) + 1;\n }\n }\n byDate[dateKey] = dateCount;\n }\n\n const result: Record<string, unknown> = {\n ok: true,\n range: { from: opts.from, to: opts.to },\n total,\n };\n\n if (dim === \"date\" || dim === \"all\") {\n result.byDate = byDate;\n }\n if (dim === \"app\" || dim === \"all\") {\n result.byApp = byApp;\n }\n if (dim === \"sender\" || dim === \"all\") {\n // Sort by count descending, return top 20\n const sorted = Object.entries(bySender)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 20)\n .map(([sender, count]) => ({ sender, count }));\n result.bySender = sorted;\n }\n if (dim === \"hour\" || dim === \"all\") {\n result.byHour = byHour;\n }\n\n output(result);\n },\n );\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeys,\n readDateFile,\n output,\n exitError,\n} from \"./helpers.js\";\n\ninterface CheckpointData {\n [dateKey: string]: { lastIndex: number };\n}\n\nconst SYNC_FETCH_LIMIT = 300;\n\nfunction checkpointPath(dir: string): string {\n return join(dir, \".checkpoint.json\");\n}\n\nfunction readCheckpoint(dir: string): CheckpointData {\n const p = checkpointPath(dir);\n if (!existsSync(p)) return {};\n try {\n return JSON.parse(readFileSync(p, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nfunction writeCheckpoint(dir: string, data: CheckpointData): void {\n writeFileSync(checkpointPath(dir), JSON.stringify(data, null, 2), \"utf-8\");\n}\n\nexport function registerNtfSync(ntf: CliCommand, ctx: CliContext): void {\n const sync = ntf.command(\"sync\").description(\"同步通知到记忆系统\");\n\n sync\n .command(\"scan\")\n .description(\"扫描未处理的通知,返回待同步摘要\")\n .action(() => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const checkpoint = readCheckpoint(dir);\n const keys = listDateKeys(dir); // descending\n const pending: { date: string; count: number; startIndex: number }[] = [];\n let totalPending = 0;\n\n for (const dateKey of keys) {\n const items = readDateFile(dir, dateKey);\n const lastIndex = checkpoint[dateKey]?.lastIndex ?? -1;\n const unprocessed = items.length - (lastIndex + 1);\n if (unprocessed > 0) {\n pending.push({\n date: dateKey,\n count: unprocessed,\n startIndex: lastIndex + 1,\n });\n totalPending += unprocessed;\n }\n }\n\n output({ ok: true, pending, totalPending });\n });\n\n sync\n .command(\"fetch\")\n .description(\"获取指定日期的未处理通知详情\")\n .requiredOption(\"--date <date>\", \"目标日期 YYYY-MM-DD\")\n .action((opts: { date: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const items = readDateFile(dir, opts.date);\n if (items.length === 0) {\n exitError(\"NO_DATA\", `日期 ${opts.date} 无通知数据`);\n }\n\n const checkpoint = readCheckpoint(dir);\n const lastIndex = checkpoint[opts.date]?.lastIndex ?? -1;\n const startIndex = lastIndex + 1;\n const unprocessed = items.slice(startIndex);\n const notifications = unprocessed.slice(0, SYNC_FETCH_LIMIT);\n const endIndex =\n notifications.length > 0 ? startIndex + notifications.length - 1 : lastIndex;\n const hasMore = unprocessed.length > notifications.length;\n\n if (unprocessed.length === 0) {\n output({\n ok: true,\n date: opts.date,\n startIndex,\n endIndex,\n nextStartIndex: null,\n limit: SYNC_FETCH_LIMIT,\n returned: 0,\n totalUnprocessed: 0,\n hasMore: false,\n notifications: [],\n });\n return;\n }\n\n output({\n ok: true,\n date: opts.date,\n startIndex,\n endIndex,\n nextStartIndex: hasMore ? endIndex + 1 : null,\n limit: SYNC_FETCH_LIMIT,\n returned: notifications.length,\n totalUnprocessed: unprocessed.length,\n hasMore,\n notifications,\n });\n });\n\n sync\n .command(\"commit\")\n .description(\"标记指定日期当前批次处理完成,更新 checkpoint\")\n .requiredOption(\"--date <date>\", \"目标日期 YYYY-MM-DD\")\n .action((opts: { date: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const items = readDateFile(dir, opts.date);\n if (items.length === 0) {\n exitError(\"NO_DATA\", `日期 ${opts.date} 无通知数据`);\n }\n\n const checkpoint = readCheckpoint(dir);\n const lastIndex = checkpoint[opts.date]?.lastIndex ?? -1;\n const committedIndex = Math.min(items.length - 1, lastIndex + SYNC_FETCH_LIMIT);\n const hasMore = committedIndex < items.length - 1;\n checkpoint[opts.date] = { lastIndex: committedIndex };\n writeCheckpoint(dir, checkpoint);\n\n output({\n ok: true,\n date: opts.date,\n committedIndex,\n limit: SYNC_FETCH_LIMIT,\n hasMore,\n nextStartIndex: hasMore ? committedIndex + 1 : null,\n });\n });\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type CliCommand, type CliContext, output, exitError } from \"./helpers.js\";\nimport { generateFetchPy } from \"../monitor/fetch-gen.js\";\n\ninterface MonitorMeta {\n name: string;\n type?: \"monitor\" | \"light-rule\";\n description: string;\n matchRules: Record<string, unknown>;\n cronSchedule: string;\n enabled: boolean;\n createdAt: string;\n updatedAt?: string;\n}\n\nfunction tasksDir(ctx: CliContext): string {\n const base = ctx.workspaceDir || ctx.stateDir;\n if (!base) throw new Error(\"workspaceDir and stateDir both unavailable\");\n return join(base, \"tasks\");\n}\n\nfunction readMeta(taskDir: string): MonitorMeta | null {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return null;\n try {\n return JSON.parse(readFileSync(metaPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(taskDir: string, meta: MonitorMeta): void {\n writeFileSync(join(taskDir, \"meta.json\"), JSON.stringify(meta, null, 2), \"utf-8\");\n}\n\nfunction generateReadme(name: string, description: string): string {\n return `# Monitor Task: ${name}\n\n## 描述\n${description}\n\n## 处理指南\n当 fetch.py 输出匹配的通知时,请:\n1. 阅读匹配到的通知内容\n2. 根据任务描述判断是否需要通知用户\n3. 如需通知用户,使用 message 工具发送摘要\n`;\n}\n\nexport function registerNtfMonitor(ntf: CliCommand, ctx: CliContext): void {\n const monitor = ntf.command(\"monitor\").description(\"通知监控任务管理\");\n\n monitor\n .command(\"list\")\n .description(\"列出所有监控任务\")\n .action(() => {\n const dir = tasksDir(ctx);\n if (!existsSync(dir)) {\n output({ ok: true, tasks: [] });\n return;\n }\n\n const tasks: MonitorMeta[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const meta = readMeta(join(dir, entry.name));\n if (meta) tasks.push(meta);\n }\n\n output({ ok: true, tasks });\n });\n\n monitor\n .command(\"show <name>\")\n .description(\"查看监控任务详情\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n const checkpointPath = join(taskDir, \"checkpoint.json\");\n let checkpoint = {};\n if (existsSync(checkpointPath)) {\n try {\n checkpoint = JSON.parse(readFileSync(checkpointPath, \"utf-8\"));\n } catch {\n // ignore\n }\n }\n\n output({\n ok: true,\n ...meta,\n matchScript: `tasks/${name}/fetch.py`,\n readme: `tasks/${name}/README.md`,\n checkpoint,\n });\n });\n\n monitor\n .command(\"create <name>\")\n .description(\"创建监控任务\")\n .requiredOption(\"--description <text>\", \"任务描述\")\n .requiredOption(\"--match-rules <json>\", \"匹配规则 JSON\")\n .requiredOption(\"--schedule <cron>\", \"cron 表达式\")\n .action(\n (\n name: string,\n opts: {\n description: string;\n matchRules: string;\n schedule: string;\n },\n ) => {\n const dir = tasksDir(ctx);\n const taskDir = join(dir, name);\n\n if (existsSync(taskDir)) {\n exitError(\"ALREADY_EXISTS\", `监控任务 '${name}' 已存在`);\n }\n\n let matchRules: Record<string, unknown>;\n try {\n matchRules = JSON.parse(opts.matchRules);\n } catch {\n exitError(\n \"VALIDATION_FAILED\",\n \"match-rules 必须是合法的 JSON\",\n );\n }\n\n mkdirSync(taskDir, { recursive: true });\n\n const meta: MonitorMeta = {\n name,\n description: opts.description,\n matchRules,\n cronSchedule: opts.schedule,\n enabled: true,\n createdAt: new Date().toISOString(),\n };\n writeMeta(taskDir, meta);\n writeFileSync(\n join(taskDir, \"fetch.py\"),\n generateFetchPy(name, matchRules),\n \"utf-8\",\n );\n writeFileSync(\n join(taskDir, \"README.md\"),\n generateReadme(name, opts.description),\n \"utf-8\",\n );\n\n output({\n ok: true,\n name,\n created: {\n script: `tasks/${name}/fetch.py`,\n readme: `tasks/${name}/README.md`,\n cronJob: `notif-${name}`,\n },\n cronHint: {\n action: \"add\",\n job: {\n name: `notif-${name}`,\n schedule: opts.schedule,\n sessionTarget: \"isolated\",\n message: `手机通知已由独立服务实时捕获到 notifications/ 目录的 JSON 文件中。\\n执行:python3 tasks/${name}/fetch.py --notifications-dir notifications\\n- NO_CHANGE 或 NO_MATCH → 不回复,直接结束。\\n- 有输出 → 读 tasks/${name}/README.md 了解如何处理数据并通知用户。`,\n },\n },\n });\n },\n );\n\n monitor\n .command(\"delete <name>\")\n .description(\"删除监控任务\")\n .option(\"--yes\", \"跳过确认\")\n .action((name: string, opts: { yes?: boolean }) => {\n const taskDir = join(tasksDir(ctx), name);\n if (!existsSync(taskDir)) {\n exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n }\n\n if (!opts.yes) {\n output({\n ok: false,\n error: {\n code: \"CONFIRMATION_REQUIRED\",\n message: `确认删除监控任务 '${name}'?添加 --yes 跳过确认`,\n },\n });\n process.exit(1);\n }\n\n rmSync(taskDir, { recursive: true, force: true });\n output({\n ok: true,\n name,\n deleted: true,\n cronHint: {\n action: \"remove\",\n name: `notif-${name}`,\n },\n });\n });\n\n monitor\n .command(\"enable <name>\")\n .description(\"启用监控任务\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n meta.enabled = true;\n writeMeta(taskDir, meta);\n output({ ok: true, name, enabled: true });\n });\n\n monitor\n .command(\"disable <name>\")\n .description(\"暂停监控任务\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n meta.enabled = false;\n writeMeta(taskDir, meta);\n output({ ok: true, name, enabled: false });\n });\n}\n","import { type CliCommand, output, exitError } from \"./helpers.js\";\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport { parseAndValidateSegments } from \"../light/validators.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\n\nexport function registerLightSend(light: CliCommand): void {\n light\n .command(\"send\")\n .description(\"发送灯效指令到硬件设备\")\n .requiredOption(\"--segments <json>\", \"灯效参数 JSON\")\n .option(\"--repeat\", \"无限循环播放(默认仅播放一轮)\")\n .option(\"--repeat-times <n>\", \"整条组合重复次数:0=无限,1=一轮;当前 ANCS 路径不支持 >=2\")\n .action(async (opts: { segments: string; repeat?: boolean; repeatTimes?: string }) => {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (e: any) {\n exitError(\"AUTH_REQUIRED\", e.message);\n }\n\n const segments = parseAndValidateSegments(opts.segments);\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({\n repeat: opts.repeat,\n repeat_times: opts.repeatTimes === undefined ? undefined : Number(opts.repeatTimes),\n });\n assertAncsRepeatTimes(repeatTimes);\n } catch (e: any) {\n exitError(\"VALIDATION_FAILED\", e.message);\n }\n\n const result = await sendLightEffect(\n apiKey,\n segments,\n undefined,\n { repeat_times: repeatTimes },\n );\n\n if (!result.ok) {\n exitError(\"HTTP_ERROR\", `请求失败: ${result.status} ${result.error}`);\n }\n\n output({ ok: true, bizUniqueId: result.bizUniqueId, response: result.response });\n });\n}\n","import { randomUUID } from \"node:crypto\";\nimport { buildLightEffectApnsBody } from \"./protocol.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport type { LightSegment } from \"../types.js\";\nimport type { RepeatArgument } from \"./repeat.js\";\n\nexport interface SendLightResult {\n ok: boolean;\n bizUniqueId?: string;\n response?: unknown;\n status?: number;\n error?: string;\n}\n\nexport async function sendLightEffect(\n apiKey: string,\n segments: LightSegment[],\n logger?: { info: (msg: string) => void; warn: (msg: string) => void },\n repeatInput?: RepeatArgument,\n reason?: string,\n): Promise<SendLightResult> {\n const apiUrl = getEnvUrls().lightApiUrl;\n const appKey = process.env.LIGHT_APP_KEY;\n const templateId = process.env.LIGHT_TEMPLATE_ID;\n\n logger?.info(\n `Light sender: apiUrl=${apiUrl ?? \"UNSET\"}, appKey=${appKey ? appKey.substring(0, 8) + \"…\" : \"UNSET\"}, templateId=${templateId ?? \"UNSET\"}, apiKey=${apiKey ? apiKey.substring(0, 20) + \"…\" : \"EMPTY\"}, segments=${JSON.stringify(segments)}`,\n );\n\n if (!apiUrl || !appKey || !templateId) {\n return {\n ok: false,\n error:\n \"灯效 API 未配置,请设置环境变量 LIGHT_API_URL / LIGHT_APP_KEY / LIGHT_TEMPLATE_ID\",\n };\n }\n\n let bizContent: string;\n try {\n bizContent = buildLightEffectApnsBody(segments, repeatInput);\n } catch (error: any) {\n return { ok: false, error: error?.message ?? String(error) };\n }\n const bizUniqueId = randomUUID();\n\n const requestBody = {\n appKey,\n bizMap: { noticeType: \"APP_NOTIFICATION_IMPORTANT\", reason },\n bizUniqueId,\n paramsMap: { bizContent },\n pushType: \"SPECIFY_PUSH\",\n templateId,\n };\n\n logger?.info(\n `Light sender: POST ${apiUrl}, bizUniqueId=${bizUniqueId}, body=${JSON.stringify(requestBody).substring(0, 500)}`,\n );\n\n const res = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key-Id\": apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey,\n },\n body: JSON.stringify(requestBody),\n });\n\n const resBody = await res.text();\n if (!res.ok) {\n logger?.warn(\n `Light sender: FAILED ${res.status}, url=${apiUrl}, resBody=${resBody.substring(0, 500)}`,\n );\n return { ok: false, status: res.status, error: resBody };\n }\n\n logger?.info(`Light sender: OK bizUniqueId=${bizUniqueId}, resBody=${resBody.substring(0, 200)}`);\n return { ok: true, bizUniqueId, response: JSON.parse(resBody) };\n}\n","import type { LightSegment } from \"../types.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes, type RepeatArgument } from \"./repeat.js\";\nimport { validateSegments } from \"./validators.js\";\n\nexport const MAX_LIGHT_SEGMENTS = 12;\n\nconst PROTOCOL_DIGITS = [\n \"\\u0080\",\n \"\\u0081\",\n \"\\u0082\",\n \"\\u0083\",\n \"\\u0084\",\n \"\\u0091\",\n \"\\u0092\",\n \"\\u0093\",\n \"\\u0094\",\n \"\\u0095\",\n \"\\u0096\",\n \"\\u0097\",\n] as const;\n\n/** \\u009A = play once, \\u009B = infinite loop */\nconst LED_SEPARATOR_ONCE = \"\\u009A\";\nconst LED_SEPARATOR_LOOP = \"\\u009B\";\n\n/** v0–v10 mapped by index; duration_s=0 is special-cased to v11 (infinite) */\nconst DURATION_STEPS_S = [0.5, 1, 2, 3, 5, 6, 8, 16, 24, 32, 48] as const;\n/** v0–v10 mapped by index; removed 400ms, added 50ms */\nconst INTERVAL_STEPS_MS = [50, 100, 200, 300, 500, 600, 800, 1600, 2400, 3200, 4800] as const;\nconst BREATH_STEPS_MS = [1040, 1560, 2080, 2600, 3100, 4160] as const;\nconst BRIGHTNESS_STEPS = [32, 64, 96, 128, 192, 255] as const;\nconst COLOR_STEPS = [0, 32, 64, 128, 192, 255] as const;\nconst BACKGROUND_BRIGHTNESS_STEPS = [0, 32, 64, 96, 128, 192, 255] as const;\nconst MULTI_CHANNEL_COLOR_COEFFICIENTS = { r: 1, g: 0.25, b: 0.25 } as const;\nconst PURE_WHITE_COLOR_COEFFICIENTS = { r: 1, g: 0.35, b: 0.35 } as const;\n\nconst MODE_TO_INDEX: Record<LightSegment[\"mode\"], number> = {\n wave: 0,\n breath: 1,\n strobe: 2,\n steady: 3,\n wave_rainbow: 4,\n pixel_frame: 5,\n};\n\nexport function buildLightEffectApnsBody(\n segments: LightSegment[],\n repeatInput?: RepeatArgument,\n): string {\n assertSegmentCount(segments);\n assertSegmentsValid(segments);\n\n const repeatTimes = normalizeRepeatTimes(repeatInput);\n assertAncsRepeatTimes(repeatTimes);\n\n const visibleText = summarizeSegments(segments);\n const separator = repeatTimes === 0 ? LED_SEPARATOR_LOOP : LED_SEPARATOR_ONCE;\n const payload = segments.map((segment) => encodeSegment(segment)).join(\"\");\n return `${visibleText}${separator}${payload}`;\n}\n\nfunction assertSegmentCount(segments: LightSegment[]): void {\n if (segments.length < 1 || segments.length > MAX_LIGHT_SEGMENTS) {\n throw new Error(`light_control supports 1-${MAX_LIGHT_SEGMENTS} segments`);\n }\n}\n\nfunction summarizeSegments(segments: LightSegment[]): string {\n const modeDesc = segments.map((segment) => segment.mode).join(\"+\");\n return `Effect: ${modeDesc} (${segments.length} segment${segments.length > 1 ? \"s\" : \"\"})`;\n}\n\nfunction assertSegmentsValid(segments: LightSegment[]): void {\n const validation = validateSegments(segments);\n if (!validation.valid) {\n throw new Error(\n validation.errors.map((error) => `${error.field}: ${error.message}`).join(\"; \"),\n );\n }\n}\n\nfunction encodeSegment(segment: LightSegment): string {\n const common = [\n MODE_TO_INDEX[segment.mode],\n quantizeDuration(segment.duration_s),\n ];\n\n let values: number[];\n switch (segment.mode) {\n case \"wave\":\n case \"wave_rainbow\":\n const color = normalizeProtocolColor(segment.color);\n const background = normalizeProtocolColor(segment.background);\n values = [\n ...common,\n quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(color.r, COLOR_STEPS),\n quantize(color.g, COLOR_STEPS),\n quantize(color.b, COLOR_STEPS),\n segment.direction === \"rtl\" ? 1 : 0,\n quantizeWindow(segment.window ?? 2),\n quantize(background.r, COLOR_STEPS),\n quantize(background.g, COLOR_STEPS),\n quantize(background.b, COLOR_STEPS),\n quantize(segment.background?.brightness ?? 0, BACKGROUND_BRIGHTNESS_STEPS),\n ];\n break;\n case \"breath\":\n const breathColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantizeBreathRiseFall(segment.breath_timing?.rise_ms),\n quantizeBreathHoldOff(segment.breath_timing?.hold_ms),\n quantizeBreathRiseFall(segment.breath_timing?.fall_ms),\n quantizeBreathHoldOff(segment.breath_timing?.off_ms),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(breathColor.r, COLOR_STEPS),\n quantize(breathColor.g, COLOR_STEPS),\n quantize(breathColor.b, COLOR_STEPS),\n ];\n break;\n case \"strobe\":\n const strobeColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(strobeColor.r, COLOR_STEPS),\n quantize(strobeColor.g, COLOR_STEPS),\n quantize(strobeColor.b, COLOR_STEPS),\n ];\n break;\n case \"steady\":\n const steadyColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(steadyColor.r, COLOR_STEPS),\n quantize(steadyColor.g, COLOR_STEPS),\n quantize(steadyColor.b, COLOR_STEPS),\n ];\n break;\n case \"pixel_frame\":\n values = encodePixelFrameValues(common, segment);\n break;\n }\n\n return values.map((value) => PROTOCOL_DIGITS[value]).join(\"\");\n}\n\nfunction encodePixelFrameValues(common: number[], segment: LightSegment): number[] {\n const pixels = segment.pixels ?? [];\n return [\n ...common,\n pixels.length - 1,\n ...pixels.flatMap((pixel) => {\n const color = normalizeProtocolColor(pixel.color);\n return [\n pixel.index,\n quantize(color.r, COLOR_STEPS),\n quantize(color.g, COLOR_STEPS),\n quantize(color.b, COLOR_STEPS),\n quantizeBrightnessValue(pixel.brightness),\n ];\n }),\n ];\n}\n\nexport function normalizeProtocolColor(\n color:\n | Pick<NonNullable<LightSegment[\"color\"]>, \"r\" | \"g\" | \"b\">\n | Pick<NonNullable<LightSegment[\"background\"]>, \"r\" | \"g\" | \"b\">\n | undefined,\n): { r: number; g: number; b: number } {\n const normalized = {\n r: color?.r ?? 0,\n g: color?.g ?? 0,\n b: color?.b ?? 0,\n };\n\n if (isPureWhiteProtocolColor(normalized)) {\n return applyProtocolColorCoefficients(normalized, PURE_WHITE_COLOR_COEFFICIENTS);\n }\n\n if (countActiveProtocolColorChannels(normalized) <= 1) {\n return normalized;\n }\n\n return applyProtocolColorCoefficients(normalized, MULTI_CHANNEL_COLOR_COEFFICIENTS);\n}\n\nfunction countActiveProtocolColorChannels(color: { r: number; g: number; b: number }): number {\n return Number(color.r > 0) + Number(color.g > 0) + Number(color.b > 0);\n}\n\nfunction isPureWhiteProtocolColor(color: { r: number; g: number; b: number }): boolean {\n return color.r === 255 && color.g === 255 && color.b === 255;\n}\n\nfunction applyProtocolColorCoefficients(\n color: { r: number; g: number; b: number },\n coefficients: { r: number; g: number; b: number },\n): { r: number; g: number; b: number } {\n return {\n r: scaleProtocolColorChannel(color.r, coefficients.r),\n g: scaleProtocolColorChannel(color.g, coefficients.g),\n b: scaleProtocolColorChannel(color.b, coefficients.b),\n };\n}\n\nfunction scaleProtocolColorChannel(value: number, coefficient: number): number {\n return Math.max(0, Math.min(255, Math.round(value * coefficient)));\n}\n\nfunction quantize(value: number, steps: readonly number[]): number {\n let bestIndex = 0;\n let bestDistance = Number.POSITIVE_INFINITY;\n\n for (const [index, step] of steps.entries()) {\n const distance = Math.abs(value - step);\n if (distance < bestDistance) {\n bestIndex = index;\n bestDistance = distance;\n }\n }\n\n return bestIndex;\n}\n\n/** duration_s=0 maps to v11 (infinite); otherwise quantize to DURATION_STEPS_S */\nfunction quantizeDuration(duration_s: number): number {\n if (duration_s === 0) return 11;\n return quantize(duration_s, DURATION_STEPS_S);\n}\n\n/**\n * brightness=0 maps to v11 (explicit off / pixel-off).\n * Otherwise quantize to BRIGHTNESS_STEPS (v0–v5).\n */\nfunction quantizeBrightnessValue(brightness: number): number {\n if (brightness === 0) return 11;\n return quantize(brightness, BRIGHTNESS_STEPS);\n}\n\nfunction quantizeBreathRiseFall(value: number | undefined): number {\n return quantize(value ?? 1040, BREATH_STEPS_MS);\n}\n\nfunction quantizeBreathHoldOff(value: number | undefined): number {\n if (value === 0) {\n return 5;\n }\n\n return quantize(value ?? 1040, BREATH_STEPS_MS.slice(0, 5));\n}\n\nfunction quantizeWindow(value: 1 | 2 | 3): number {\n return value - 1;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { type CliCommand, output, exitError } from \"./helpers.js\";\n\ntype JsonObject = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is JsonObject {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction ensureArray(obj: JsonObject, key: string): unknown[] {\n const current = obj[key];\n if (Array.isArray(current)) return current;\n const next: unknown[] = [];\n obj[key] = next;\n return next;\n}\n\nfunction resolveConfigPath(): string {\n const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();\n if (fromEnv) return fromEnv;\n return join(homedir(), \".openclaw\", \"openclaw.json\");\n}\n\nfunction upsertLightControlAlsoAllow(cfg: JsonObject): {\n globalChanged: boolean;\n mainAgentChanged: boolean;\n} {\n if (!isObject(cfg.tools)) cfg.tools = {};\n const toolsAlsoAllow = ensureArray(cfg.tools as JsonObject, \"alsoAllow\");\n const hasGlobal = toolsAlsoAllow.includes(\"light_control\");\n if (!hasGlobal) toolsAlsoAllow.push(\"light_control\");\n\n if (!isObject(cfg.agents)) cfg.agents = {};\n const agents = cfg.agents as JsonObject;\n const list = ensureArray(agents, \"list\");\n let mainAgent = list.find(\n (item) => isObject(item) && item.id === \"main\",\n ) as JsonObject | undefined;\n if (!mainAgent) {\n mainAgent = { id: \"main\" };\n list.push(mainAgent);\n }\n if (!isObject(mainAgent.tools)) mainAgent.tools = {};\n const mainAlsoAllow = ensureArray(mainAgent.tools as JsonObject, \"alsoAllow\");\n const hasMain = mainAlsoAllow.includes(\"light_control\");\n if (!hasMain) mainAlsoAllow.push(\"light_control\");\n\n return {\n globalChanged: !hasGlobal,\n mainAgentChanged: !hasMain,\n };\n}\n\nexport function registerLightSetupTools(light: CliCommand): void {\n light\n .command(\"setup\")\n .description(\"自动放行 light_control(写入 tools.alsoAllow 与 agents.main.tools.alsoAllow)\")\n .action(() => {\n const configPath = resolveConfigPath();\n if (!existsSync(configPath)) {\n exitError(\"CONFIG_NOT_FOUND\", `未找到配置文件: ${configPath}`);\n }\n\n let cfg: JsonObject = {};\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (isObject(parsed)) cfg = parsed;\n } catch (err: any) {\n exitError(\"CONFIG_INVALID\", `读取/解析配置失败: ${err?.message ?? String(err)}`);\n }\n\n const result = upsertLightControlAlsoAllow(cfg);\n try {\n mkdirSync(dirname(configPath), { recursive: true });\n writeFileSync(configPath, JSON.stringify(cfg, null, 2) + \"\\n\", \"utf-8\");\n } catch (err: any) {\n exitError(\"WRITE_FAILED\", `写入配置失败: ${err?.message ?? String(err)}`);\n }\n\n output({\n ok: true,\n configPath,\n changed: result.globalChanged || result.mainAgentChanged,\n updates: {\n toolsAlsoAllow: result.globalChanged ? \"added\" : \"already_exists\",\n mainAgentAlsoAllow: result.mainAgentChanged ? \"added\" : \"already_exists\",\n },\n next: \"请执行: openclaw gateway restart\",\n });\n });\n}\n\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport { output, exitError } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport type { TunnelStatusInfo } from \"../tunnel/relay-client.js\";\n\n/** 状态文件相对于 stateDir 的路径 */\nconst STATUS_REL_PATH = join(\"plugins\", \"phone-notifications\", \"tunnel-status.json\");\n\n/** 读取 RelayClient 写入的状态文件 */\nfunction readTunnelStatus(ctx: CliContext): TunnelStatusInfo | null {\n if (!ctx.stateDir) return null;\n const filePath = join(ctx.stateDir, STATUS_REL_PATH);\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\")) as TunnelStatusInfo;\n } catch {\n return null;\n }\n}\n\nfunction formatMessage(status: TunnelStatusInfo): string {\n switch (status.state) {\n case \"connected\":\n return `隧道已连接(自 ${status.since})`;\n case \"connecting\":\n return `隧道正在连接(自 ${status.since},第 ${status.reconnectAttempt} 次重连)`;\n case \"disconnected\":\n return `隧道已断开(自 ${status.since})${status.lastDisconnectReason ? `,原因: ${status.lastDisconnectReason}` : \"\"},等待重连(第 ${status.reconnectAttempt} 次)`;\n case \"stopped\":\n return `隧道服务已停止(自 ${status.since})`;\n default:\n return `未知状态: ${status.state}`;\n }\n}\n\nexport function registerTunnelStatus(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"tunnel-status\")\n .description(\"检查 Relay Tunnel 隧道连接状态(读取运行中服务的状态文件,不影响已有连接)\")\n .action(async () => {\n const tunnelUrl = getEnvUrls().relayTunnelUrl;\n const apiKey = loadApiKey();\n\n if (!tunnelUrl) {\n exitError(\n \"TUNNEL_NOT_CONFIGURED\",\n \"RELAY_TUNNEL_URL 未配置,隧道功能未启用。请在构建时设置 RELAY_TUNNEL_URL 环境变量。\",\n );\n }\n\n if (!apiKey) {\n exitError(\n \"TOKEN_MISSING\",\n \"API Key 未设置,隧道无法连接。请执行 openclaw ntf auth set-api-key <apiKey>\",\n );\n }\n\n const status = readTunnelStatus(ctx);\n\n if (!status) {\n exitError(\n \"STATUS_NOT_FOUND\",\n \"未找到隧道状态文件,隧道服务可能尚未启动过。请确认 openclaw 主进程正在运行。\",\n );\n }\n\n const ok = status.state === \"connected\";\n output({\n ok,\n tunnelUrl,\n connection: {\n state: status.state,\n since: status.since,\n reconnectAttempt: status.reconnectAttempt,\n lastDisconnectReason: status.lastDisconnectReason,\n },\n message: formatMessage(status),\n });\n\n if (!ok) process.exit(1);\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerNtfStoragePath(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"storage-path\")\n .description(\"查询通知存储路径\")\n .action(() => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n output({ ok: true, path: dir });\n });\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type CliCommand,\n type CliContext,\n filterDateRange,\n today,\n daysAgo,\n output,\n exitError,\n} from \"./helpers.js\";\n\n/** Resolve the plugin logs directory from stateDir */\nfunction resolveLogsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"logs\",\n );\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** List available log date keys (YYYY-MM-DD) sorted descending */\nfunction listLogDateKeys(dir: string): string[] {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.log$/;\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Read log lines from a date file, optionally filtering by keyword */\nfunction collectLogLines(\n dir: string,\n dateKey: string,\n keyword: string | undefined,\n limit: number,\n collected: string[],\n): void {\n const filePath = join(dir, `${dateKey}.log`);\n if (!existsSync(filePath)) return;\n\n const content = readFileSync(filePath, \"utf-8\");\n const lowerKeyword = keyword?.toLowerCase();\n\n for (const line of content.split(\"\\n\")) {\n if (collected.length >= limit) return;\n if (!line) continue;\n if (lowerKeyword && !line.toLowerCase().includes(lowerKeyword)) continue;\n collected.push(`[${dateKey}] ${line}`);\n }\n}\n\nexport function registerLogSearch(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"log\")\n .description(\"查看/搜索插件日志\")\n .option(\"--keyword <text>\", \"按关键词过滤日志\")\n .option(\"--from <date>\", \"开始日期 YYYY-MM-DD\", daysAgo(7))\n .option(\"--to <date>\", \"结束日期 YYYY-MM-DD\", today())\n .option(\"--limit <n>\", \"最大返回条数\", \"50\")\n .action(\n (opts: {\n keyword?: string;\n from: string;\n to: string;\n limit: string;\n }) => {\n const dir = resolveLogsDir(ctx);\n if (!dir) exitError(\"LOGS_UNAVAILABLE\", \"日志目录不可用\");\n\n const keys = filterDateRange(listLogDateKeys(dir), opts.from, opts.to);\n const limit = parseInt(opts.limit, 10) || 50;\n const results: string[] = [];\n\n for (const dateKey of keys) {\n if (results.length >= limit) break;\n collectLogLines(dir, dateKey, opts.keyword, limit, results);\n }\n\n output({\n ok: true,\n keyword: opts.keyword ?? null,\n total: results.length,\n lines: results,\n });\n },\n );\n}\n","import { loadEnvName, saveEnvName, getEnvUrls, getAvailableEnvs } from \"../env.js\";\nimport { output, exitError } from \"./helpers.js\";\nimport type { CliCommand } from \"./helpers.js\";\n\nexport function registerEnvCli(ntf: CliCommand): void {\n const env = ntf.command(\"env\").description(\"环境管理(切换 development / production)\");\n\n env\n .command(\"show\")\n .description(\"显示当前环境及对应的接口地址\")\n .action(() => {\n const current = loadEnvName();\n const urls = getEnvUrls(current);\n output({\n ok: true,\n env: current,\n lightApiUrl: urls.lightApiUrl,\n relayTunnelUrl: urls.relayTunnelUrl,\n availableEnvs: getAvailableEnvs(),\n });\n });\n\n env\n .command(\"switch <env>\")\n .description(\"切换环境(development / production)\")\n .action((envName: string) => {\n const available = getAvailableEnvs();\n if (!available.includes(envName as any)) {\n exitError(\n \"INVALID_ENV\",\n `无效的环境名称: ${envName},可选值: ${available.join(\", \")}`,\n );\n }\n saveEnvName(envName as any);\n const urls = getEnvUrls(envName as any);\n output({\n ok: true,\n message: `已切换到 ${envName} 环境`,\n env: envName,\n lightApiUrl: urls.lightApiUrl,\n relayTunnelUrl: urls.relayTunnelUrl,\n });\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport { resolveConfigPath, resolveStateDir } from \"../host.js\";\nimport { output } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport type { CheckResult, JsonObject, Severity } from \"./doctor/types.js\";\nimport { allCheckers } from \"./doctor/checkers.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nfunction readConfig(configPath: string): JsonObject {\n if (!existsSync(configPath)) return {};\n try {\n const parsed = JSON.parse(readFileSync(configPath, \"utf-8\"));\n return isObject(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction severityIcon(s: Severity): string {\n switch (s) {\n case \"critical\":\n return \"\\x1b[31m[CRITICAL]\\x1b[0m\";\n case \"warn\":\n return \"\\x1b[33m[WARN]\\x1b[0m\";\n case \"info\":\n return \"\\x1b[36m[INFO]\\x1b[0m\";\n }\n}\n\nfunction severityOrder(s: Severity): number {\n switch (s) {\n case \"critical\":\n return 0;\n case \"warn\":\n return 1;\n case \"info\":\n return 2;\n }\n}\n\nfunction confirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === \"y\");\n });\n });\n}\n\nasync function runDoctor(ctx: CliContext, json: boolean, fix?: boolean): Promise<void> {\n const stateDir = ctx.stateDir ?? resolveStateDir();\n const configPath = resolveConfigPath(stateDir);\n const cfg = readConfig(configPath);\n\n const checkCtx = { cfg, configPath, stateDir };\n\n // 执行所有 checker\n const issues: CheckResult[] = [];\n for (const checker of allCheckers) {\n const result = await checker(checkCtx);\n if (result) issues.push(result);\n }\n\n // 按严重级别排序\n issues.sort((a, b) => severityOrder(a.severity) - severityOrder(b.severity));\n\n // 统计\n const summary = { critical: 0, warn: 0, info: 0 };\n for (const issue of issues) {\n summary[issue.severity]++;\n }\n\n // --json 模式\n if (json) {\n output({\n ok: issues.length === 0,\n summary,\n checks: issues.map((i) => ({\n id: i.id,\n severity: i.severity,\n title: i.title,\n detail: i.detail,\n autoFixable: i.fix !== null,\n fixDescription: i.fixDescription,\n })),\n });\n if (issues.length > 0) process.exit(1);\n return;\n }\n\n // 人类可读输出\n const log = console.error; // stderr,不污染 stdout\n log(\"\\n\\x1b[1m🔍 正在检查环境...\\x1b[0m\\n\");\n\n if (issues.length === 0) {\n log(\"\\x1b[32m✅ 所有检查通过,未发现问题。\\x1b[0m\\n\");\n output({ ok: true, summary });\n return;\n }\n\n for (const issue of issues) {\n log(`${severityIcon(issue.severity)} ${issue.title}`);\n log(` ↳ ${issue.detail}`);\n log(` ↳ 修复: ${issue.fixDescription}`);\n log();\n }\n\n log(\n `检测完成: \\x1b[31m${summary.critical} critical\\x1b[0m · ` +\n `\\x1b[33m${summary.warn} warn\\x1b[0m · ` +\n `\\x1b[36m${summary.info} info\\x1b[0m\\n`,\n );\n\n // 找出可自动修复的\n const fixable = issues.filter((i) => i.fix !== null);\n\n if (fixable.length === 0) {\n log(\"以上问题均需手动修复,请参考上方提示。\\n\");\n output({ ok: false, summary });\n process.exit(1);\n return;\n }\n\n log(`发现 ${fixable.length} 个可自动修复的问题:`);\n for (const issue of fixable) {\n log(` • ${issue.title} → ${issue.fixDescription}`);\n }\n log();\n\n const yes = fix === true || await confirm(\"是否执行自动修复?[y/N]: \");\n if (!yes) {\n log(\"\\n已取消。\\n\");\n output({ ok: false, summary, fixed: 0 });\n process.exit(1);\n return;\n }\n\n log();\n let fixed = 0;\n for (const issue of fixable) {\n try {\n await issue.fix!();\n log(`\\x1b[32m✅\\x1b[0m ${issue.title} → ${issue.fixDescription}`);\n fixed++;\n } catch (err: any) {\n log(\n `\\x1b[31m❌\\x1b[0m ${issue.title} 修复失败: ${err?.message ?? String(err)}`,\n );\n }\n }\n\n const manualCount = issues.length - fixable.length;\n if (manualCount > 0) {\n log(`\\n⚠️ 还有 ${manualCount} 个问题需要手动处理,请参考上方提示。`);\n }\n\n log(`\\n修复完成 (${fixed}/${fixable.length})。建议执行: openclaw gateway restart\\n`);\n output({ ok: fixed === fixable.length && manualCount === 0, summary, fixed });\n if (fixed < fixable.length || manualCount > 0) process.exit(1);\n}\n\nexport function registerDoctor(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"doctor\")\n .description(\"自检环境配置,检测安全风险和常见问题\")\n .option(\"--json\", \"以 JSON 格式输出结果(供脚本调用)\")\n .option(\"--fix\", \"自动修复可修复的问题(跳过确认提示)\")\n .action((opts: { json?: boolean; fix?: boolean }) => {\n return runDoctor(ctx, opts.json === true, opts.fix);\n });\n}\n","import { readFileSync, writeFileSync, copyFileSync } from \"node:fs\";\nimport type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkDangerousFlags: Checker = ({ cfg, configPath }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const controlUi = gateway.controlUi;\n if (!isObject(controlUi)) return null;\n\n if (controlUi.dangerouslyDisableDeviceAuth !== true) return null;\n\n return {\n id: \"dangerous-flags\",\n severity: \"critical\",\n title: \"gateway.controlUi.dangerouslyDisableDeviceAuth 已启用\",\n detail: \"这会关闭 Control UI 的设备身份验证,任何人都可以访问控制面板。\",\n fixDescription: \"设为 false\",\n fix: () => {\n const raw = readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(raw) as JsonObject;\n const gw = config.gateway as JsonObject;\n const cui = gw.controlUi as JsonObject;\n cui.dangerouslyDisableDeviceAuth = false;\n copyFileSync(configPath, configPath + \".bak\");\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n },\n };\n};\n","import type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkTrustedProxy: Checker = ({ cfg }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const auth = gateway.auth;\n if (!isObject(auth)) return null;\n\n if (auth.mode !== \"trusted-proxy\") return null;\n\n return {\n id: \"trusted-proxy\",\n severity: \"critical\",\n title: \"gateway.auth.mode 为 trusted-proxy\",\n detail:\n \"认证委托给了反向代理。请确保: (1) 代理终止 TLS 并认证用户; \" +\n \"(2) gateway.trustedProxies 仅限代理 IP; \" +\n \"(3) 防火墙阻止直接访问 Gateway 端口。\",\n fixDescription: \"此项需手动检查代理配置,无法自动修复\",\n fix: null,\n };\n};\n\nexport const checkTrustedProxyAllowUsers: Checker = ({ cfg }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const auth = gateway.auth;\n if (!isObject(auth)) return null;\n\n if (auth.mode !== \"trusted-proxy\") return null;\n\n const tp = auth.trustedProxy;\n if (!isObject(tp)) return warnEmpty();\n\n const allowUsers = tp.allowUsers;\n if (!Array.isArray(allowUsers) || allowUsers.length === 0) return warnEmpty();\n\n return null;\n};\n\nfunction warnEmpty() {\n return {\n id: \"trusted-proxy-allow-users\",\n severity: \"warn\" as const,\n title: \"trusted-proxy 模式下 allowUsers 为空\",\n detail: \"任何通过代理认证的用户都可以访问 Gateway。\",\n fixDescription:\n '请编辑 openclaw.json,在 gateway.auth.trustedProxy.allowUsers 中添加允许的用户邮箱,例如 [\"nick@example.com\"]',\n fix: null,\n };\n}\n","import { statSync, chmodSync } from \"node:fs\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkStateDirPerms: Checker = ({ stateDir }) => {\n let mode: number;\n try {\n mode = statSync(stateDir).mode;\n } catch {\n return null;\n }\n\n // 检查 group 和 other 是否有任何权限\n const otherBits = mode & 0o077;\n if (otherBits === 0) return null;\n\n const modeStr = \"0\" + (mode & 0o777).toString(8);\n\n return {\n id: \"state-dir-perms\",\n severity: \"warn\",\n title: `状态目录权限过于宽松 (${stateDir} mode=${modeStr})`,\n detail: \"其他用户可以读取该目录下的凭证和配置文件。\",\n fixDescription: \"chmod 700 \" + stateDir,\n fix: () => {\n chmodSync(stateDir, 0o700);\n },\n };\n};\n","import type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkToolPolicy: Checker = ({ cfg }) => {\n const agents = cfg.agents;\n if (!isObject(agents)) return null;\n\n const list = agents.list;\n if (!Array.isArray(list)) return null;\n\n const permissiveAgents: string[] = [];\n\n for (const agent of list) {\n if (!isObject(agent)) continue;\n const id = String(agent.id ?? \"unknown\");\n\n // 如果 agent 没有设置 toolPolicy / profile,则视为使用 default(宽松)\n const tools = agent.tools;\n if (!isObject(tools)) {\n permissiveAgents.push(id);\n continue;\n }\n\n const profile = tools.profile;\n if (!profile || profile === \"default\") {\n permissiveAgents.push(id);\n }\n }\n\n if (permissiveAgents.length === 0) return null;\n\n return {\n id: \"tool-policy\",\n severity: \"warn\",\n title: \"扩展插件 tool policy 宽松\",\n detail: `以下 agent 使用了 default 策略: ${permissiveAgents.join(\", \")}。插件工具可能被未授权调用。`,\n fixDescription:\n \"建议为处理不可信输入的 agent 使用 minimal 或 coding profile,或配置明确的 tool allowlist。\",\n fix: null,\n };\n};\n","import { loadApiKey } from \"../../auth/credentials.js\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkCredentials: Checker = () => {\n const apiKey = loadApiKey();\n if (apiKey) return null;\n\n return {\n id: \"credentials\",\n severity: \"critical\",\n title: \"API Key 未配置\",\n detail:\n \"未在 credentials.json 中找到 apiKey,隧道和推送等功能无法正常工作。\",\n fixDescription:\n \"请执行: openclaw ntf auth set-api-key <your-api-key>\",\n fix: null,\n };\n};\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { TunnelStatusInfo } from \"../../tunnel/relay-client.js\";\nimport type { Checker } from \"./types.js\";\n\nconst STATUS_REL_PATH = join(\n \"plugins\",\n \"phone-notifications\",\n \"tunnel-status.json\",\n);\n\nexport const checkTunnel: Checker = ({ stateDir }) => {\n const filePath = join(stateDir, STATUS_REL_PATH);\n\n if (!existsSync(filePath)) {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态文件不存在\",\n detail: \"隧道服务可能尚未启动过,或状态文件已被删除。\",\n fixDescription: \"请确认 openclaw 主进程正在运行\",\n fix: null,\n };\n }\n\n let status: TunnelStatusInfo;\n try {\n status = JSON.parse(readFileSync(filePath, \"utf-8\")) as TunnelStatusInfo;\n } catch {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态文件解析失败\",\n detail: \"文件内容损坏或格式不正确。\",\n fixDescription: \"请重启 openclaw 主进程\",\n fix: null,\n };\n }\n\n if (status.state === \"connected\") return null;\n\n const reasonSuffix = status.lastDisconnectReason\n ? `,原因: ${status.lastDisconnectReason}`\n : \"\";\n\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: `隧道未连接 (state=${status.state})`,\n detail: `隧道自 ${status.since} 处于 ${status.state} 状态${reasonSuffix},重连次数: ${status.reconnectAttempt}`,\n fixDescription: \"请检查网络连接或重启 openclaw 主进程\",\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\n\nconst MIN_MAJOR = 22;\nconst MIN_MINOR = 12;\n\nexport const checkNodeVersion: Checker = () => {\n const version = process.versions.node;\n const [major, minor] = version.split(\".\").map(Number);\n\n if (major > MIN_MAJOR || (major === MIN_MAJOR && minor >= MIN_MINOR)) {\n return null;\n }\n\n return {\n id: \"node-version\",\n severity: \"warn\",\n title: `Node.js 版本过低 (v${version})`,\n detail: `要求 >= ${MIN_MAJOR}.${MIN_MINOR}.0,当前为 v${version}。`,\n fixDescription: `请升级 Node.js 到 ${MIN_MAJOR}.${MIN_MINOR}.0 或更高版本`,\n fix: null,\n };\n};\n","import { loadEnvName } from \"../../env.js\";\nimport { resolveUpdateChannel } from \"../../update/channel.js\";\nimport { PLUGIN_VERSION } from \"../../version.js\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkPluginVersion: Checker = async () => {\n const channel = resolveUpdateChannel({\n currentVersion: PLUGIN_VERSION,\n envName: loadEnvName(),\n });\n\n let latest: string;\n try {\n const res = await fetch(\n `https://registry.npmjs.org/@yoooclaw/phone-notifications/${channel}`,\n { signal: AbortSignal.timeout(5000) },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { version?: string };\n latest = data.version ?? \"\";\n } catch {\n // 网络不可用时跳过\n return null;\n }\n\n if (!latest || latest === PLUGIN_VERSION) return null;\n\n return {\n id: \"plugin-version\",\n severity: \"info\",\n title: `插件版本可更新 (当前 ${PLUGIN_VERSION} → 最新 ${latest})`,\n detail: \"有新版本可用,建议更新以获取最新功能和修复。\",\n fixDescription: `请执行: openclaw extension install @yoooclaw/phone-notifications@${latest}`,\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\nimport { checkDangerousFlags } from \"./check-dangerous-flags.js\";\nimport { checkTrustedProxy, checkTrustedProxyAllowUsers } from \"./check-trusted-proxy.js\";\nimport { checkStateDirPerms } from \"./check-state-dir-perms.js\";\nimport { checkToolPolicy } from \"./check-tool-policy.js\";\nimport { checkCredentials } from \"./check-credentials.js\";\nimport { checkTunnel } from \"./check-tunnel.js\";\nimport { checkNodeVersion } from \"./check-node-version.js\";\nimport { checkPluginVersion } from \"./check-plugin-version.js\";\n\n/** 所有 checker,按优先级排列 */\nexport const allCheckers: Checker[] = [\n // critical\n checkDangerousFlags,\n checkTrustedProxy,\n checkCredentials,\n // warn\n checkTrustedProxyAllowUsers,\n checkStateDirPerms,\n checkToolPolicy,\n checkTunnel,\n // info\n checkNodeVersion,\n checkPluginVersion,\n];\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n readRecordingIndex,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecList(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"list\")\n .description(\"列出所有录音(可按状态过滤)\")\n .option(\"--status <status>\", \"按传输状态过滤(如 synced, transcribed)\")\n .action((opts: { status?: string }) => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n\n let recordings = readRecordingIndex(dir);\n\n if (opts.status) {\n recordings = recordings.filter((r) => r.status === opts.status);\n }\n\n const items = recordings.map((r) => ({\n id: r.id,\n name: r.metadata.name,\n duration_sec: r.metadata.duration_sec,\n status: r.status,\n file_size_bytes: r.metadata.file_size_bytes,\n has_audio: !!r.audioFile,\n has_transcript: !!r.transcriptFile,\n created_at: r.metadata.created_at,\n updated_at: r.updatedAt,\n }));\n\n output({ ok: true, total: items.length, recordings: items });\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n readRecordingIndex,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecStatus(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"status <id>\")\n .description(\"查看单条录音详情\")\n .action((id: string) => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n\n const recordings = readRecordingIndex(dir);\n const entry = recordings.find((r) => r.id === id);\n\n if (!entry) {\n exitError(\"NOT_FOUND\", `录音不存在: ${id}`);\n }\n\n output({\n ok: true,\n recording: {\n id: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n status: entry.status,\n created_at: entry.metadata.created_at,\n location: entry.metadata.location ?? null,\n markers: entry.metadata.markers ?? [],\n audioFile: entry.audioFile ?? null,\n srtFile: entry.srtFile ?? null,\n transcriptDataFile: entry.transcriptDataFile ?? null,\n transcriptFile: entry.transcriptFile ?? null,\n summaryFile: entry.summaryFile ?? null,\n title: entry.title ?? null,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n },\n });\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecStoragePath(\n rec: CliCommand,\n ctx: CliContext,\n): void {\n rec\n .command(\"storage-path\")\n .description(\"查询录音存储路径\")\n .action(() => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n output({ ok: true, path: dir });\n });\n}\n","import { createInterface } from \"node:readline\";\nimport { writeFileSync, existsSync, readFileSync } from \"node:fs\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport { resolveAsrConfigPath, output } from \"./helpers.js\";\nimport type { AsrConfig, WhisperModelSize, WhisperBackend, WhisperModelSource } from \"../types.js\";\n\n// ─── Prompt helpers ───\n\ntype Rl = ReturnType<typeof createInterface>;\n\nfunction ask(rl: Rl, question: string): Promise<string> {\n return new Promise((resolve) => rl.question(question, resolve));\n}\n\n/**\n * Ask for a single choice from a numbered list.\n * Writes the list and prompt to stderr; returns the 0-based index of the chosen item.\n */\nasync function askChoice(\n rl: Rl,\n prompt: string,\n choices: readonly string[],\n defaultIdx = 0,\n): Promise<number> {\n choices.forEach((c, i) => {\n const marker = i === defaultIdx ? \"●\" : \"○\";\n process.stderr.write(` ${marker} ${i + 1}. ${c}\\n`);\n });\n while (true) {\n const ans = (await ask(rl, `${prompt} [1-${choices.length},默认 ${defaultIdx + 1}]: `)).trim();\n if (!ans) return defaultIdx;\n const n = parseInt(ans, 10);\n if (!isNaN(n) && n >= 1 && n <= choices.length) return n - 1;\n process.stderr.write(` 请输入 1-${choices.length} 之间的数字\\n`);\n }\n}\n\n/** Ask for a value; returns undefined if user presses Enter with no input. */\nasync function askOptional(rl: Rl, prompt: string): Promise<string | undefined> {\n const ans = (await ask(rl, `${prompt} [可选,直接回车跳过]: `)).trim();\n return ans || undefined;\n}\n\n// ─── Mode-specific setup flows ───\n\nasync function setupApi(rl: Rl): Promise<AsrConfig> {\n process.stderr.write(\"\\n─── 云端 ASR(model-proxy)配置 ───\\n\\n\");\n process.stderr.write(\"说明:不再填写第三方 API Key,插件会复用当前账号的 API Key 调用 model-proxy 长录音接口。\\n\\n\");\n\n const endpoint = await askOptional(rl, \"自定义 model-proxy submit-task 端点 URL\");\n const language = await askOptional(rl, \"语言提示(如 zh / en)\");\n const enableNormalizationInput = await askOptional(rl, \"启用文本规范化 ITN?(y/N)\");\n const normalized = enableNormalizationInput?.trim().toLowerCase();\n const enableNormalization =\n normalized === \"y\" || normalized === \"yes\" || normalized === \"true\";\n\n return {\n mode: \"api\",\n api: {\n ...(endpoint ? { endpoint } : {}),\n ...(language ? { language } : {}),\n ...(enableNormalizationInput ? { enableNormalization } : {}),\n },\n };\n}\n\nasync function setupLocal(rl: Rl): Promise<AsrConfig> {\n process.stderr.write(\"\\n─── 本地 Whisper 转写配置 ───\\n\\n\");\n\n process.stderr.write(\"模型大小:\\n\");\n const modelChoices = [\n \"自动选择(根据可用内存推荐)\",\n \"tiny\",\n \"base\",\n \"small\",\n \"medium\",\n \"large-v3\",\n ] as const;\n const modelIdx = await askChoice(rl, \"选择模型\", modelChoices);\n const model: WhisperModelSize | undefined =\n modelIdx === 0 ? undefined : (modelChoices[modelIdx] as WhisperModelSize);\n\n const language = await askOptional(rl, \"语言提示(如 zh / en,留空自动检测)\");\n\n process.stderr.write(\"\\n推理后端:\\n\");\n const backendChoices = [\n \"自动选择(根据运行环境推荐)\",\n \"coreml(Apple Silicon 推荐)\",\n \"cuda(NVIDIA GPU)\",\n \"cpu\",\n ] as const;\n const backendIdx = await askChoice(rl, \"选择后端\", backendChoices);\n const backend: WhisperBackend | undefined =\n backendIdx === 0 ? undefined : ([\"coreml\", \"cuda\", \"cpu\"] as const)[backendIdx - 1];\n\n process.stderr.write(\"\\n模型下载源:\\n\");\n const sourceChoices = [\n \"auto(自动探测,优先 HuggingFace,失败回退国内镜像)\",\n \"huggingface(海外直连)\",\n \"domestic(国内镜像)\",\n ] as const;\n const sourceIdx = await askChoice(rl, \"选择下载源\", sourceChoices);\n const modelSource: WhisperModelSource = ([\"auto\", \"huggingface\", \"domestic\"] as const)[sourceIdx];\n\n const modelMirrorUrl = await askOptional(rl, \"自定义模型下载地址(覆盖下载源)\");\n\n return {\n mode: \"local\",\n local: {\n ...(model ? { model } : {}),\n ...(language ? { language } : {}),\n ...(backend ? { backend } : {}),\n modelSource,\n ...(modelMirrorUrl ? { modelMirrorUrl } : {}),\n },\n };\n}\n\n// ─── Command registration ───\n\nexport function registerRecSetup(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"setup\")\n .description(\"交互式配置 ASR 转写参数,保存到本地配置文件\")\n .action(async () => {\n const configPath = resolveAsrConfigPath(ctx);\n\n // Show existing config hint if present\n if (existsSync(configPath)) {\n try {\n const existing = JSON.parse(readFileSync(configPath, \"utf-8\")) as AsrConfig & { updatedAt?: string };\n process.stderr.write(`当前已有配置:mode = ${existing.mode}`);\n if (existing.updatedAt) process.stderr.write(`,更新于 ${existing.updatedAt}`);\n process.stderr.write(\"\\n\");\n } catch {\n // ignore parse errors\n }\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stderr, terminal: true });\n\n try {\n process.stderr.write(\"\\n转写模式:\\n\");\n const modeIdx = await askChoice(rl, \"选择模式\", [\"api(云端 model-proxy 长录音)\", \"local(本地 Whisper)\"]);\n\n const config: AsrConfig = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);\n const stored = { ...config, updatedAt: new Date().toISOString() };\n\n writeFileSync(configPath, JSON.stringify(stored, null, 2), \"utf-8\");\n process.stderr.write(`\\n✓ 配置已保存到 ${configPath}\\n\\n`);\n\n output({ ok: true, ...stored });\n } finally {\n rl.close();\n }\n });\n}\n","import type { CliCommand, CliContext } from \"./helpers.js\";\nimport { registerAuthCli } from \"./auth.js\";\nimport { registerNtfSearch } from \"./ntf-search.js\";\nimport { registerNtfStats } from \"./ntf-stats.js\";\nimport { registerNtfSync } from \"./ntf-sync.js\";\nimport { registerNtfMonitor } from \"./ntf-monitor.js\";\nimport { registerLightSend } from \"./light-send.js\";\nimport { registerLightSetupTools } from \"./light-setup-tools.js\";\nimport { registerTunnelStatus } from \"./tunnel-status.js\";\nimport { registerNtfStoragePath } from \"./ntf-storage-path.js\";\nimport { registerLogSearch } from \"./log-search.js\";\nimport { registerEnvCli } from \"./env.js\";\nimport { registerDoctor } from \"./doctor.js\";\nimport { registerRecList } from \"./rec-list.js\";\nimport { registerRecStatus } from \"./rec-status.js\";\nimport { registerRecStoragePath } from \"./rec-storage-path.js\";\nimport { registerRecSetup } from \"./rec-setup.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\n\nexport function registerAllCli(\n program: CliCommand,\n ctx: CliContext,\n rootCommandName = \"ntf\",\n): void {\n const ntf = program\n .command(rootCommandName)\n .description(\"手机通知数据管理\")\n .version(PLUGIN_VERSION, \"-v, --version\", \"显示插件版本\");\n\n // openclaw ntf auth ...\n registerAuthCli(ntf);\n\n // openclaw ntf search / stats / sync / monitor ...\n registerNtfSearch(ntf, ctx);\n registerNtfStats(ntf, ctx);\n registerNtfSync(ntf, ctx);\n registerNtfMonitor(ntf, ctx);\n\n // openclaw ntf light send / setup-tools ...\n const light = ntf.command(\"light\").description(\"灯效管理\");\n registerLightSend(light);\n registerLightSetupTools(light);\n\n // openclaw ntf storage-path\n registerNtfStoragePath(ntf, ctx);\n\n // openclaw ntf log <keyword>\n registerLogSearch(ntf, ctx);\n\n // openclaw ntf tunnel-status\n registerTunnelStatus(ntf, ctx);\n\n // openclaw ntf env show / switch\n registerEnvCli(ntf);\n\n // openclaw ntf doctor\n registerDoctor(ntf, ctx);\n\n // openclaw ntf rec list / status / storage-path / setup\n const rec = ntf.command(\"rec\").description(\"录音管理\");\n registerRecList(rec, ctx);\n registerRecStatus(rec, ctx);\n registerRecStoragePath(rec, ctx);\n registerRecSetup(rec, ctx);\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport type { Logger } from \"../logger.js\";\nimport { MAX_LIGHT_SEGMENTS } from \"../light/protocol.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport { validateSegments } from \"../light/validators.js\";\nimport type { LightControlInput } from \"../types.js\";\n\nconst lightControlParameters = {\n type: \"object\",\n required: [\"segments\", \"reason\"],\n additionalProperties: false,\n properties: {\n segments: {\n type: \"array\",\n description: \"灯效段序列,1–12 段,按顺序播放\",\n minItems: 1,\n maxItems: MAX_LIGHT_SEGMENTS,\n items: {\n type: \"object\",\n required: [\"mode\", \"duration_s\"],\n additionalProperties: false,\n properties: {\n mode: {\n type: \"string\",\n enum: [\"wave\", \"breath\", \"strobe\", \"steady\", \"wave_rainbow\", \"pixel_frame\"],\n description:\n \"灯效模式:wave 波浪 / breath 呼吸 / strobe 频闪 / steady 常亮 / wave_rainbow 流光 / pixel_frame 逐组像素帧\",\n },\n duration_s: {\n type: \"number\",\n minimum: 0,\n description:\n \"本段持续时长(秒),0 表示无限时长。推荐离散值:0.5/1/2/3/5/6/8/16/24/32/48,建议单段 ≤8s 省电\",\n },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description:\n \"前景亮度 0–255。非 pixel_frame 模式必填;brightness=0 仅 steady 模式有效(显式灭灯)\",\n },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n description:\n \"前景色 RGB。非 pixel_frame 模式必填;wave_rainbow 下作为第一颜色锚点,至少 color/background 其一非零\",\n },\n interval_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"步进间隔(ms),wave/strobe/wave_rainbow 有效,默认 200。量化档位:50/100/200/300/500/600/800/1600/2400/3200/4800\",\n },\n direction: {\n type: \"string\",\n enum: [\"ltr\", \"rtl\"],\n description: \"波浪/流光方向,wave/wave_rainbow 有效,默认 ltr\",\n },\n window: {\n type: \"number\",\n enum: [1, 2, 3],\n description:\n \"wave:窗口灯数,默认 2;wave_rainbow:调色板平移步幅(速度)\",\n },\n breath_timing: {\n type: \"object\",\n additionalProperties: false,\n properties: {\n rise_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"上升时间(ms),量化到 1040/1560/2080/2600/3100/4160\",\n },\n hold_ms: {\n type: \"number\",\n minimum: 0,\n description: \"保持最高亮度时间(ms),支持 0ms\",\n },\n fall_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"下降时间(ms),量化到 1040/1560/2080/2600/3100/4160\",\n },\n off_ms: {\n type: \"number\",\n minimum: 0,\n description: \"熄灭时间(ms),支持 0ms\",\n },\n },\n description:\n \"呼吸四段时间,仅 breath 有效;rise/fall 量化档位:1040/1560/2080/2600/3100/4160,hold/off 额外支持 0ms\",\n },\n background: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\", \"brightness\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description: \"底色亮度,量化档位:0/32/64/96/128/192/255\",\n },\n },\n description:\n \"底色 RGB + 亮度,wave 有效为底色层;wave_rainbow 有效为第二颜色锚点(与前景色插值生成多色调色板)\",\n },\n pixels: {\n type: \"array\",\n minItems: 1,\n maxItems: 7,\n items: {\n type: \"object\",\n required: [\"index\", \"color\", \"brightness\"],\n additionalProperties: false,\n properties: {\n index: {\n type: \"number\",\n minimum: 0,\n maximum: 6,\n description: \"LED 组索引,0–6\",\n },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n description: \"该像素的 RGB\",\n },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description: \"该像素亮度 0–255;0 会编码为像素熄灭\",\n },\n },\n },\n description:\n \"仅 pixel_frame 有效:播放前先清 7 组,再按此列表写入 (Idx,R,G,B,Br)\",\n },\n },\n },\n },\n reason: {\n type: \"string\",\n description:\n \"结合对话上下文,简要说明为什么要亮灯(例如:用户心情低落想要温暖氛围、庆祝生日、提醒喝水等)。\" +\n \"这个字段帮助记录每次亮灯的意图和动机。\",\n },\n repeat: {\n type: \"boolean\",\n description:\n \"兼容旧参数。true = 无限循环,false/不填 = 一轮;若同时提供 repeat_times,则以后者为准\",\n },\n repeat_times: {\n type: \"number\",\n minimum: 0,\n description:\n \"整条组合重复次数:0 = 无限循环,1 = 播放一轮。当前 ANCS 路径不支持 N>=2\",\n },\n },\n} as const;\n\nexport function registerLightControlTool(\n api: OpenClawPluginApi,\n logger: Logger,\n): void {\n api.registerTool({\n name: \"light_control\",\n label: \"Light Control\",\n description:\n \"控制硬件灯效,支持 1–12 段顺序灯效,每段独立参数(6 种模式:波浪/呼吸/频闪/常亮/流光/逐组像素帧)。\" +\n \"Tool 内部自动量化为嵌入式协议定义的离散档位,并按模式精简为变长 ANCS 控制序列,通过 HTTP 接口下发灯效指令。\" +\n '当用户说\"开灯\"、\"换个灯效\"、\"把灯调成红色\"、\"营造氛围\"等与灯光控制相关的表达时调用。',\n parameters: lightControlParameters,\n async execute(_toolCallId: string, params: unknown) {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (e: any) {\n return {\n content: [{ type: \"text\" as const, text: e.message }],\n details: { ok: false, error: { code: \"AUTH_REQUIRED\", message: e.message } },\n };\n }\n\n const { segments, reason, repeat, repeat_times } = params as LightControlInput;\n const validation = validateSegments(segments);\n if (!validation.valid) {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(validation.errors) }],\n details: {\n ok: false,\n error: { code: \"VALIDATION_FAILED\", details: validation.errors },\n },\n };\n }\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (error: any) {\n return {\n content: [{ type: \"text\" as const, text: error?.message ?? String(error) }],\n details: {\n ok: false,\n error: { code: \"VALIDATION_FAILED\", message: error?.message ?? String(error) },\n },\n };\n }\n\n logger.info(`Light control reason: ${reason}`);\n const result = await sendLightEffect(\n apiKey,\n validation.segments,\n logger,\n { repeat_times: repeatTimes },\n reason,\n );\n\n if (!result.ok) {\n logger.warn(\n `Light control HTTP request failed: ${result.status} ${result.error}`,\n );\n } else {\n logger.info(`Light control sent, bizUniqueId=${result.bizUniqueId}`);\n }\n\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\n details: result,\n };\n },\n } as any);\n}\n","import { readFileSync } from \"node:fs\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { resolveConfigPath } from \"../host.js\";\nimport type { Logger } from \"../logger.js\";\nimport { createAppNameMapProvider } from \"../notification/app-name-map.js\";\nimport {\n NotificationStorage,\n resolveNotificationStorageDir,\n} from \"../notification/storage.js\";\nimport {\n RecordingStorage,\n resolveRecordingStorageDir,\n} from \"../recording/index.js\";\nimport {\n createTunnelService,\n type RelayTunnelService,\n} from \"../tunnel/service.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport { trimToUndefined } from \"./shared.js\";\n\ninterface LightRuleContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\ninterface StorageLifecycleDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n lightRuleCtx: LightRuleContext;\n setStorage: (storage: NotificationStorage | null) => void;\n setRecordingStorage: (storage: RecordingStorage | null) => void;\n /**\n * 在 storage service 完成 start 之后触发,此时 lightRuleCtx 已被回填。\n * 用于让 LightRuleRegistry 等下游组件在拿到真实 workspaceDir 后重新加载状态。\n */\n onStorageReady?: () => void;\n}\n\nexport function registerStorageLifecycle(\n deps: StorageLifecycleDeps,\n): void {\n const {\n api,\n config,\n logger,\n lightRuleCtx,\n setStorage,\n setRecordingStorage,\n onStorageReady,\n } = deps;\n\n let storage: NotificationStorage | null = null;\n let recordingStorage: RecordingStorage | null = null;\n let appNameMapProvider: ReturnType<typeof createAppNameMapProvider> | null = null;\n\n api.registerService({\n id: \"notification-storage\",\n async start(ctx) {\n const storageDir = resolveNotificationStorageDir(ctx, logger);\n\n appNameMapProvider = createAppNameMapProvider({\n stateDir: ctx.stateDir,\n logger,\n });\n await appNameMapProvider.start();\n\n const resolveDisplayName = appNameMapProvider.resolveDisplayName.bind(appNameMapProvider);\n storage = new NotificationStorage(storageDir, config, logger, resolveDisplayName);\n await storage.init();\n setStorage(storage);\n logger.info(`通知存储服务已启动: ${storageDir}`);\n\n const recDir = resolveRecordingStorageDir(ctx, logger);\n recordingStorage = new RecordingStorage(recDir, logger);\n await recordingStorage.init();\n setRecordingStorage(recordingStorage);\n logger.info(`录音存储服务已启动: ${recDir}`);\n\n lightRuleCtx.workspaceDir = ctx.workspaceDir;\n if (ctx.stateDir) {\n lightRuleCtx.stateDir = ctx.stateDir;\n }\n\n onStorageReady?.();\n },\n async stop() {\n await storage?.close();\n storage = null;\n setStorage(null);\n\n await recordingStorage?.close();\n recordingStorage = null;\n setRecordingStorage(null);\n\n appNameMapProvider?.stop();\n appNameMapProvider = null;\n logger.info(\"通知/录音存储服务已停止\");\n },\n });\n}\n\nfunction readHostGatewayConfig(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}) {\n const configPath = params.stateDir\n ? resolveConfigPath(params.stateDir)\n : undefined;\n\n let configData: any;\n\n if (configPath) {\n try {\n configData = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch (err: any) {\n if (err?.code !== \"ENOENT\") {\n params.logger.warn(\n `Relay tunnel: 无法读取 gateway 鉴权配置 (${configPath})`,\n );\n }\n }\n }\n\n return configData;\n}\n\nfunction resolveLocalGatewayAuth(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}): {\n gatewayAuthMode?: \"token\" | \"password\";\n gatewayToken?: string;\n gatewayPassword?: string;\n} {\n const envGatewayToken =\n trimToUndefined(process.env.OPENCLAW_GATEWAY_TOKEN) ??\n trimToUndefined(process.env.QCLAW_GATEWAY_TOKEN);\n const envGatewayPassword =\n trimToUndefined(process.env.OPENCLAW_GATEWAY_PASSWORD) ??\n trimToUndefined(process.env.QCLAW_GATEWAY_PASSWORD);\n\n const configData = readHostGatewayConfig(params);\n let configGatewayAuthMode: \"token\" | \"password\" | undefined;\n const rawGatewayAuthMode = trimToUndefined(configData?.gateway?.auth?.mode);\n if (rawGatewayAuthMode === \"token\" || rawGatewayAuthMode === \"password\") {\n configGatewayAuthMode = rawGatewayAuthMode;\n }\n const configGatewayToken = trimToUndefined(configData?.gateway?.auth?.token);\n const configGatewayPassword = trimToUndefined(configData?.gateway?.auth?.password);\n\n return {\n gatewayAuthMode: configGatewayAuthMode,\n gatewayToken: envGatewayToken ?? configGatewayToken,\n gatewayPassword: envGatewayPassword ?? configGatewayPassword,\n };\n}\n\nfunction resolveExclusiveTunnelHint(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}): string | undefined {\n const configData = readHostGatewayConfig(params);\n const tailscaleMode = trimToUndefined(configData?.gateway?.tailscale?.mode);\n if (tailscaleMode) {\n return `gateway.tailscale.mode=${tailscaleMode}`;\n }\n\n return undefined;\n}\n\ninterface RelayTunnelDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n openclawDir?: string;\n}\n\nexport function registerRelayTunnelLifecycle(\n deps: RelayTunnelDeps,\n): RelayTunnelService | null {\n const {\n api,\n config,\n logger,\n openclawDir,\n } = deps;\n\n const tunnelUrl = getEnvUrls().relayTunnelUrl;\n if (!tunnelUrl) {\n return null;\n }\n\n const exclusiveTunnelHint = resolveExclusiveTunnelHint({\n stateDir: openclawDir,\n logger,\n });\n if (exclusiveTunnelHint) {\n logger.info(\n `Relay tunnel: detected ${exclusiveTunnelHint} in host gateway config, skipping relay startup to keep ingress mutually exclusive`,\n );\n return null;\n }\n\n const gatewayPort =\n process.env.OPENCLAW_GATEWAY_PORT ??\n process.env.QCLAW_GATEWAY_PORT ??\n \"18789\";\n const { gatewayAuthMode, gatewayToken, gatewayPassword } =\n resolveLocalGatewayAuth({\n stateDir: openclawDir,\n logger,\n });\n\n const tunnelService = createTunnelService({\n tunnelUrl,\n heartbeatSec: config.relay?.heartbeatSec,\n reconnectBackoffMs: config.relay?.reconnectBackoffMs,\n gatewayBaseUrl: `http://localhost:${gatewayPort}`,\n gatewayAuthMode,\n gatewayToken,\n gatewayPassword,\n logger,\n });\n\n api.registerService(tunnelService);\n logger.info(\"Relay tunnel 服务已注册\");\n return tunnelService;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadApiKey, watchCredentials } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\n\nconst PLUGIN_STATE_DIR = \"phone-notifications\";\nconst CACHE_FILE = \"app-name-map.json\";\n\n/** 包名→应用名映射 API 地址(默认随环境变化;可用 APP_NAME_MAP_URL 覆盖;需鉴权) */\nconst BUILTIN_APP_NAME_MAP_URL = getEnvUrls().appNameMapUrl;\nconst APP_NAME_MAP_URL =\n (typeof process.env.APP_NAME_MAP_URL === \"string\" && process.env.APP_NAME_MAP_URL.trim()\n ? process.env.APP_NAME_MAP_URL.trim()\n : undefined) ?? BUILTIN_APP_NAME_MAP_URL;\n/** 映射刷新间隔(小时) */\nconst APP_NAME_MAP_REFRESH_HOURS = 12;\n\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\nfunction isRecordOfStrings(v: unknown): v is Record<string, string> {\n if (v === null || typeof v !== \"object\") return false;\n for (const val of Object.values(v)) if (typeof val !== \"string\") return false;\n return true;\n}\n\n/** API 返回的单项 */\ninterface AppPackageItem {\n appName: string;\n packageName: string;\n iconUrl?: string | null;\n platform?: string | null;\n jumpUrl?: string | null;\n urlParams?: string | null;\n description?: string | null;\n}\n\n/** API 响应格式 */\ninterface AppNameMapApiResponse {\n success?: boolean;\n code?: string;\n message?: string;\n data?: AppPackageItem[];\n}\n\nfunction isAppNameMapApiResponse(v: unknown): v is AppNameMapApiResponse {\n if (v === null || typeof v !== \"object\") return false;\n const o = v as Record<string, unknown>;\n return Array.isArray(o.data) && o.data.every(\n (item: unknown) =>\n item !== null &&\n typeof item === \"object\" &&\n typeof (item as AppPackageItem).packageName === \"string\" &&\n typeof (item as AppPackageItem).appName === \"string\"\n );\n}\n\nfunction getCachePath(stateDir: string): string {\n return join(stateDir, \"plugins\", PLUGIN_STATE_DIR, CACHE_FILE);\n}\n\nexport interface AppNameMapProvider {\n /** 解析包名为显示名(未命中时拉取一次再返回,保证当前落库即有值) */\n resolveDisplayName(packageName: string): Promise<string>;\n start(): Promise<void>;\n stop(): void;\n}\n\nexport function createAppNameMapProvider(opts: {\n stateDir: string;\n logger: Logger;\n}): AppNameMapProvider {\n const { stateDir, logger } = opts;\n const url = APP_NAME_MAP_URL;\n const refreshHours = APP_NAME_MAP_REFRESH_HOURS;\n\n const map = new Map<string, string>();\n let refreshTimer: ReturnType<typeof setInterval> | null = null;\n let stopWatching: (() => void) | null = null;\n let inFlightFetch: Promise<void> | null = null;\n\n function loadFromDisk(): void {\n const path = getCachePath(stateDir);\n if (!existsSync(path)) return;\n try {\n const raw = JSON.parse(readFileSync(path, \"utf-8\"));\n if (!isRecordOfStrings(raw)) return;\n map.clear();\n for (const [k, v] of Object.entries(raw)) map.set(k, v);\n logger.info(`[app-name-map] loaded ${map.size} entries from cache: ${path}`);\n } catch {\n /* ignore */\n }\n }\n\n async function fetchFromServer(): Promise<void> {\n const apiKey = loadApiKey();\n if (!url) {\n logger.warn(\"[app-name-map] APP_NAME_MAP_URL is empty, skip refresh\");\n return;\n }\n if (!apiKey) {\n logger.info(\"[app-name-map] api key missing, skip refresh\");\n return;\n }\n\n const rawApiKey = apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Api-Key-Id\": rawApiKey },\n body: JSON.stringify({\n platform: \"\"\n })\n });\n if (!res.ok) {\n logger.warn(`[app-name-map] refresh failed: HTTP ${res.status} ${res.statusText}`);\n return;\n }\n const body = await res.json() as unknown;\n if (!isAppNameMapApiResponse(body) || !body.success || !body.data?.length) {\n logger.warn(\"[app-name-map] refresh failed: unexpected response shape or empty data\");\n return;\n }\n map.clear();\n for (const item of body.data) {\n if (item.packageName && item.appName) map.set(item.packageName, item.appName);\n }\n if (map.size === 0) {\n logger.warn(\"[app-name-map] refresh succeeded but got 0 entries\");\n return;\n }\n const dir = join(stateDir, \"plugins\", PLUGIN_STATE_DIR);\n\n mkdirSync(dir, { recursive: true });\n const cachePath = getCachePath(stateDir);\n writeFileSync(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), \"utf-8\");\n logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n logger.warn(`[app-name-map] refresh error: ${message}`);\n }\n }\n\n async function ensureOneFetch(): Promise<void> {\n if (inFlightFetch) return inFlightFetch;\n inFlightFetch = fetchFromServer().finally(() => {\n inFlightFetch = null;\n });\n return inFlightFetch;\n }\n\n return {\n async resolveDisplayName(packageName: string): Promise<string> {\n // 临时策略:仅使用内存/磁盘中已有的映射,缺少时不主动触发拉取\n if (map.has(packageName)) return map.get(packageName)!;\n return packageName;\n // 如需在缺少应用名时触发一次拉取再返回,可恢复为:\n // if (!url || !loadApiKey()) return packageName;\n // await ensureOneFetch();\n // return map.get(packageName) ?? packageName;\n },\n\n async start(): Promise<void> {\n loadFromDisk();\n await fetchFromServer();\n\n if (!url) return;\n\n if (refreshHours > 0) {\n const ms = refreshHours * 60 * 60 * 1000;\n refreshTimer = setInterval(() => fetchFromServer().catch(() => { }), ms);\n }\n stopWatching = watchCredentials(() => fetchFromServer().catch(() => { }));\n },\n\n stop(): void {\n stopWatching?.();\n stopWatching = null;\n if (refreshTimer) {\n clearInterval(refreshTimer);\n refreshTimer = null;\n }\n map.clear();\n },\n };\n}\n","import {\n accessSync,\n mkdirSync,\n appendFileSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n existsSync,\n rmSync,\n constants,\n} from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport type { PluginConfig, RawNotification } from \"../types.js\";\n\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\nexport interface StorageContext {\n stateDir: string;\n workspaceDir?: string;\n}\n\n/** Stored notification entry (JSON format, append-only) */\nexport interface StoredNotification {\n /** 包名 */\n appName: string;\n /** 应用显示名(由映射补全),缺省时与 appName 一致 */\n appDisplayName?: string;\n title: string;\n content: string;\n /** ISO 8601 with timezone, e.g. \"2026-03-02T08:30:00+08:00\" */\n timestamp: string;\n}\n\nconst NOTIFICATION_DIR_NAME = \"notifications\";\nconst ID_INDEX_DIR_NAME = \".ids\";\nconst CONTENT_KEY_INDEX_DIR_NAME = \".keys\";\n\nexport interface NotificationIngestResult {\n received: number;\n ingested: number;\n dedupedById: number;\n dedupedByContent: number;\n invalid: number;\n /**\n * 本次 ingest 实际新写入的条目(去重 / 非法之后的产物)。\n * 用于后续事件驱动链路(如 light-rule agent 评估)拿到本次新增的通知列表,\n * 不需要重新读盘。\n */\n inserted: StoredNotification[];\n}\n\ntype WriteOutcome =\n | { kind: \"ingested\"; entry: StoredNotification }\n | { kind: \"dedupedById\" }\n | { kind: \"dedupedByContent\" }\n | { kind: \"invalid\" };\n\nexport function getStateFallbackNotificationDir(stateDir: string): string {\n return join(stateDir, \"plugins\", \"phone-notifications\", NOTIFICATION_DIR_NAME);\n}\n\nfunction ensureWritableDirectory(dir: string): boolean {\n try {\n mkdirSync(dir, { recursive: true });\n accessSync(dir, constants.R_OK | constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function resolveNotificationStorageDir(\n ctx: StorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): string {\n // 优先使用 stateDir(插件私有稳定路径),避免通知随 workspace 切换而分散\n const stateNotifDir = getStateFallbackNotificationDir(ctx.stateDir);\n\n if (ensureWritableDirectory(stateNotifDir)) {\n logger.info(`通知将写入 stateDir 路径: ${stateNotifDir}`);\n return stateNotifDir;\n }\n\n // stateDir 不可用时回退到 workspaceDir\n if (ctx.workspaceDir) {\n const workspaceDir = join(ctx.workspaceDir, NOTIFICATION_DIR_NAME);\n if (ensureWritableDirectory(workspaceDir)) {\n logger.warn(\n `stateDir 不可用,通知已回退到 workspace 路径: ${workspaceDir}`,\n );\n return workspaceDir;\n }\n }\n\n throw new Error(`通知存储目录不可用: ${stateNotifDir}`);\n}\n\n/** 包名 → 应用显示名(异步,未命中时内部可拉取后返回);不提供则落库仅用 appName */\nexport type ResolveDisplayName = (packageName: string) => Promise<string>;\n\nexport class NotificationStorage {\n private dir: string;\n private idIndexDir: string;\n private contentKeyIndexDir: string;\n private idCache = new Map<string, Set<string>>();\n private contentKeyCache = new Map<string, Set<string>>();\n private dateWriteChains = new Map<string, Promise<void>>();\n private resolveDisplayName: ResolveDisplayName | undefined;\n\n constructor(\n dir: string,\n private config: PluginConfig,\n private logger: Logger,\n resolveDisplayName?: ResolveDisplayName,\n ) {\n this.dir = dir;\n this.idIndexDir = join(dir, ID_INDEX_DIR_NAME);\n this.contentKeyIndexDir = join(dir, CONTENT_KEY_INDEX_DIR_NAME);\n this.resolveDisplayName = resolveDisplayName;\n }\n\n async init() {\n mkdirSync(this.dir, { recursive: true });\n mkdirSync(this.idIndexDir, { recursive: true });\n rmSync(this.contentKeyIndexDir, { recursive: true, force: true });\n mkdirSync(this.contentKeyIndexDir, { recursive: true });\n }\n\n async ingest(items: RawNotification[]): Promise<NotificationIngestResult> {\n const result: NotificationIngestResult = {\n received: items.length,\n ingested: 0,\n dedupedById: 0,\n dedupedByContent: 0,\n invalid: 0,\n inserted: [],\n };\n\n for (const n of items) {\n const outcome = await this.writeNotification(n);\n switch (outcome.kind) {\n case \"ingested\":\n result.ingested += 1;\n result.inserted.push(outcome.entry);\n break;\n case \"dedupedById\":\n result.dedupedById += 1;\n break;\n case \"dedupedByContent\":\n result.dedupedByContent += 1;\n break;\n case \"invalid\":\n result.invalid += 1;\n break;\n }\n }\n this.prune();\n return result;\n }\n\n private async writeNotification(n: RawNotification): Promise<WriteOutcome> {\n const ts = new Date(n.timestamp);\n if (Number.isNaN(ts.getTime())) {\n this.logger.warn(`忽略非法 timestamp 的通知: ${n.id}`);\n return { kind: \"invalid\" };\n }\n\n const dateKey = this.formatDate(ts);\n const filePath = join(this.dir, `${dateKey}.json`);\n const normalizedId = typeof n.id === \"string\" ? n.id.trim() : \"\";\n const entry = this.buildStoredNotification(n);\n\n return this.withDateWriteLock(dateKey, async () => {\n if (normalizedId && this.hasNotificationId(dateKey, normalizedId)) {\n return { kind: \"dedupedById\" };\n }\n\n if (this.hasNotificationContentKey(dateKey, filePath, entry)) {\n return { kind: \"dedupedByContent\" };\n }\n\n const appDisplayName = this.resolveDisplayName\n ? await this.resolveDisplayName(entry.appName)\n : entry.appName;\n\n const storedEntry: StoredNotification = {\n ...entry,\n appDisplayName,\n };\n\n const arr = this.readStoredNotifications(filePath);\n arr.push(storedEntry);\n writeFileSync(filePath, JSON.stringify(arr, null, 2), \"utf-8\");\n\n if (normalizedId) {\n this.recordNotificationId(dateKey, normalizedId);\n }\n this.recordNotificationContentKey(dateKey, filePath, storedEntry);\n return { kind: \"ingested\", entry: storedEntry };\n });\n }\n\n private buildStoredNotification(n: RawNotification): StoredNotification {\n return {\n appName: typeof n.app === \"string\" && n.app ? n.app : \"Unknown\",\n title: typeof n.title === \"string\" ? n.title : \"\",\n content: this.buildContent(n),\n timestamp: n.timestamp,\n };\n }\n\n private buildContent(n: RawNotification): string {\n const body = n.body?.trim();\n if (body) {\n return body;\n }\n\n const fallback: string[] = [];\n if (n.category) {\n fallback.push(`category:${n.category}`);\n }\n\n if (n.metadata && Object.keys(n.metadata).length > 0) {\n fallback.push(`metadata:${JSON.stringify(n.metadata)}`);\n }\n\n return fallback.join(\" ; \") || \"-\";\n }\n\n private formatDate(d: Date): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n }\n\n private getIdIndexPath(dateKey: string): string {\n return join(this.idIndexDir, `${dateKey}.ids`);\n }\n\n private getIdSet(dateKey: string): Set<string> {\n const cached = this.idCache.get(dateKey);\n if (cached) {\n return cached;\n }\n\n const idPath = this.getIdIndexPath(dateKey);\n const ids = new Set<string>();\n if (existsSync(idPath)) {\n const lines = readFileSync(idPath, \"utf-8\").split(/\\r?\\n/);\n for (const line of lines) {\n const id = line.trim();\n if (id) {\n ids.add(id);\n }\n }\n }\n\n this.idCache.set(dateKey, ids);\n return ids;\n }\n\n private hasNotificationId(dateKey: string, id: string): boolean {\n return this.getIdSet(dateKey).has(id);\n }\n\n private getContentKeyIndexPath(dateKey: string): string {\n return join(this.contentKeyIndexDir, `${dateKey}.keys`);\n }\n\n private getContentKeySet(dateKey: string, filePath: string): Set<string> {\n const cached = this.contentKeyCache.get(dateKey);\n if (cached) {\n return cached;\n }\n\n const keyPath = this.getContentKeyIndexPath(dateKey);\n const keys = new Set<string>();\n\n if (existsSync(filePath)) {\n for (const item of this.readStoredNotifications(filePath)) {\n keys.add(this.buildNotificationContentKey(item));\n }\n }\n\n if (keys.size > 0) {\n writeFileSync(keyPath, `${Array.from(keys).join(\"\\n\")}\\n`, \"utf-8\");\n } else if (existsSync(keyPath)) {\n rmSync(keyPath, { force: true });\n }\n\n this.contentKeyCache.set(dateKey, keys);\n return keys;\n }\n\n private hasNotificationContentKey(\n dateKey: string,\n filePath: string,\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ): boolean {\n return this.getContentKeySet(dateKey, filePath).has(\n this.buildNotificationContentKey(entry),\n );\n }\n\n private recordNotificationId(dateKey: string, id: string) {\n const ids = this.getIdSet(dateKey);\n if (ids.has(id)) {\n return;\n }\n\n appendFileSync(this.getIdIndexPath(dateKey), `${id}\\n`, \"utf-8\");\n ids.add(id);\n }\n\n private recordNotificationContentKey(\n dateKey: string,\n filePath: string,\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ) {\n const keys = this.getContentKeySet(dateKey, filePath);\n const key = this.buildNotificationContentKey(entry);\n\n if (keys.has(key)) {\n return;\n }\n\n appendFileSync(this.getContentKeyIndexPath(dateKey), `${key}\\n`, \"utf-8\");\n keys.add(key);\n }\n\n private buildNotificationContentKey(\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ): string {\n return createHash(\"sha256\")\n .update(entry.appName)\n .update(\"\\x1f\")\n .update(entry.title)\n .update(\"\\x1f\")\n .update(entry.content)\n .update(\"\\x1f\")\n .update(entry.timestamp)\n .digest(\"hex\");\n }\n\n private readStoredNotifications(filePath: string): StoredNotification[] {\n if (!existsSync(filePath)) {\n return [];\n }\n\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf-8\"));\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n\n private async withDateWriteLock<T>(\n dateKey: string,\n task: () => Promise<T>,\n ): Promise<T> {\n const previous = this.dateWriteChains.get(dateKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const chain = previous.then(() => current);\n this.dateWriteChains.set(dateKey, chain);\n\n await previous;\n try {\n return await task();\n } finally {\n release();\n if (this.dateWriteChains.get(dateKey) === chain) {\n this.dateWriteChains.delete(dateKey);\n }\n }\n }\n\n private prune() {\n const retentionDays = this.config.retentionDays;\n if (retentionDays === undefined) {\n return;\n }\n\n const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;\n const cutoffDate = this.formatDate(new Date(cutoffMs));\n\n this.pruneDataFiles(cutoffDate);\n this.pruneIdIndex(cutoffDate);\n this.pruneContentKeyIndex(cutoffDate);\n }\n\n /** Remove expired .json, legacy .md files, and legacy date directories */\n private pruneDataFiles(cutoffDate: string) {\n const dateFilePattern = /^(\\d{4}-\\d{2}-\\d{2})\\.(json|md)$/;\n const dateDirPattern = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n try {\n for (const entry of readdirSync(this.dir, { withFileTypes: true })) {\n if (entry.isFile()) {\n const match = dateFilePattern.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.dir, entry.name), { force: true });\n }\n } else if (entry.isDirectory() && dateDirPattern.test(entry.name) && entry.name < cutoffDate) {\n rmSync(join(this.dir, entry.name), { recursive: true, force: true });\n }\n }\n } catch {\n // ignore\n }\n }\n\n /** Remove expired .ids index files */\n private pruneIdIndex(cutoffDate: string) {\n try {\n for (const entry of readdirSync(this.idIndexDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.ids$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.idIndexDir, entry.name), { force: true });\n this.idCache.delete(match[1]);\n }\n }\n } catch {\n // ignore\n }\n }\n\n private pruneContentKeyIndex(cutoffDate: string) {\n try {\n for (const entry of readdirSync(this.contentKeyIndexDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.keys$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.contentKeyIndexDir, entry.name), { force: true });\n this.contentKeyCache.delete(match[1]);\n }\n }\n } catch {\n // ignore\n }\n }\n\n async close() {\n this.idCache.clear();\n this.contentKeyCache.clear();\n this.dateWriteChains.clear();\n }\n}\n","/**\n * 录音本地存储管理(§5.2)\n *\n * 目录结构:\n * <storageDir>/recordings/\n * ├── audio/ # 原始音频 + 打点文件\n * │ ├── 2026-03-23_14-32.ogg\n * │ └── 2026-03-23_14-32.srt\n * ├── transcript-data/ # 转写 JSON(主存储)\n * │ └── 2026-03-23_14-32.json\n * ├── transcripts/ # 转写文本\n * │ └── 2026-03-23_14-32_与王总沟通产品方向.md\n * ├── summaries/ # 转写摘要\n * │ └── 2026-03-23_14-32.md\n * └── index.json # 元数据索引\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport type {\n RecordingMetadata,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport { transition } from \"./state-machine.js\";\nimport type { Logger } from \"../logger.js\";\nimport {\n buildTranscriptDataFilename as buildTranscriptDataJsonFilename,\n buildTranscriptDocument,\n extractTranscriptSummaryFromDocument,\n extractTranscriptTextFromDocument,\n extractTranscriptTitleFromDocument,\n parseTranscriptDocument,\n} from \"./transcript-document.js\";\n\n/**\n * 从 OSS URL 中提取音频文件扩展名(含点号,如 \".ogg\")\n * 默认返回 \".ogg\"(小硬件录音为 Opus/OGG 格式)\n */\nfunction extractAudioExt(ossUrl: string): string {\n try {\n const pathname = new URL(ossUrl).pathname;\n const m = pathname.match(/(\\.[a-z0-9]+)(?:\\?|$)/i);\n if (m) return m[1].toLowerCase();\n } catch {\n const m = ossUrl.match(/(\\.[a-z0-9]+)(?:\\?|$)/i);\n if (m) return m[1].toLowerCase();\n }\n return \".ogg\"; // 硬件默认录音格式(Opus/OGG)\n}\n\n// ─── Types ───\n\n/** 持久化到 index.json 的单条录音记录 */\nexport interface RecordingIndexEntry {\n /** 录音 ID,基于文件名(如 \"2026-03-23_14-32\") */\n id: string;\n /** 原始元数据 */\n metadata: RecordingMetadata;\n /** 当前插件侧状态 */\n status: RecordingTransferStatus;\n /** 本地音频文件相对路径 */\n audioFile?: string;\n /** 本地打点文件相对路径 */\n srtFile?: string;\n /** 本地转写文件相对路径 */\n transcriptFile?: string;\n /** 本地转写 JSON 文件相对路径 */\n transcriptDataFile?: string;\n /** 本地摘要文件相对路径 */\n summaryFile?: string;\n /** 转写标题 */\n title?: string;\n /** 入库时间 ISO 8601 */\n ingestedAt: string;\n /** 最后更新时间 ISO 8601 */\n updatedAt: string;\n}\n\n/** 录音存储索引(整个 index.json) */\ninterface RecordingIndex {\n recordings: RecordingIndexEntry[];\n}\n\nexport interface RecordingStorageContext {\n stateDir: string;\n workspaceDir?: string;\n}\n\n// ─── Constants ───\n\nconst RECORDINGS_DIR = \"recordings\";\nconst AUDIO_DIR = \"audio\";\nconst TRANSCRIPT_DATA_DIR = \"transcript-data\";\nconst TRANSCRIPTS_DIR = \"transcripts\";\nconst SUMMARIES_DIR = \"summaries\";\nconst INDEX_FILE = \"index.json\";\n\nfunction stripMarkdownFence(markdown: string): string {\n return markdown.replace(/\\r\\n/g, \"\\n\");\n}\n\nfunction deriveTitleFromTranscriptPath(\n transcriptFile: string | undefined,\n recordingId: string,\n): string | undefined {\n if (!transcriptFile) return undefined;\n const name = basename(transcriptFile, \".md\");\n const prefix = `${recordingId}_`;\n if (name.startsWith(prefix)) {\n const derived = name.slice(prefix.length).trim();\n return derived || undefined;\n }\n return undefined;\n}\n\nfunction extractTranscriptContent(markdown: string): string {\n const normalized = stripMarkdownFence(markdown);\n const firstDivider = normalized.indexOf(\"\\n---\\n\");\n let body = firstDivider >= 0\n ? normalized.slice(firstDivider + \"\\n---\\n\".length)\n : normalized;\n\n if (body.startsWith(\"\\n\")) {\n body = body.slice(1);\n }\n\n if (body.startsWith(\"### 关键点\")) {\n const secondDivider = body.indexOf(\"\\n---\\n\");\n if (secondDivider >= 0) {\n body = body.slice(secondDivider + \"\\n---\\n\".length);\n if (body.startsWith(\"\\n\")) {\n body = body.slice(1);\n }\n }\n }\n\n const lines = body\n .split(\"\\n\")\n .filter((line) => !/^\\*\\*\\[关键点 .+\\]\\*\\*$/.test(line.trim()))\n .filter((line) => !/^- \\*\\*\\[关键点 .+\\]\\*\\*$/.test(line.trim()));\n\n return lines.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trim();\n}\n\n// ─── Public Functions ───\n\n/**\n * 解析录音存储根目录(复用通知同级的 stateDir 路径)\n */\nexport function resolveRecordingStorageDir(\n ctx: RecordingStorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): string {\n const stateRecDir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n RECORDINGS_DIR,\n );\n\n try {\n mkdirSync(stateRecDir, { recursive: true });\n logger.info(`录音将写入 stateDir 路径: ${stateRecDir}`);\n return stateRecDir;\n } catch {\n // fallback\n }\n\n if (ctx.workspaceDir) {\n const wsRecDir = join(ctx.workspaceDir, RECORDINGS_DIR);\n try {\n mkdirSync(wsRecDir, { recursive: true });\n logger.warn(`stateDir 不可用,录音已回退到 workspace 路径: ${wsRecDir}`);\n return wsRecDir;\n } catch {\n // fallthrough\n }\n }\n\n throw new Error(`录音存储目录不可用: ${stateRecDir}`);\n}\n\n// ─── RecordingStorage Class ───\n\nexport class RecordingStorage {\n private readonly dir: string;\n private readonly audioDir: string;\n private readonly transcriptDataDir: string;\n private readonly transcriptsDir: string;\n private readonly summariesDir: string;\n private readonly indexPath: string;\n private index: RecordingIndex = { recordings: [] };\n\n constructor(\n dir: string,\n private readonly logger: Logger,\n ) {\n this.dir = dir;\n this.audioDir = join(dir, AUDIO_DIR);\n this.transcriptDataDir = join(dir, TRANSCRIPT_DATA_DIR);\n this.transcriptsDir = join(dir, TRANSCRIPTS_DIR);\n this.summariesDir = join(dir, SUMMARIES_DIR);\n this.indexPath = join(dir, INDEX_FILE);\n }\n\n /** 初始化目录结构并加载索引 */\n async init(): Promise<void> {\n mkdirSync(this.audioDir, { recursive: true });\n mkdirSync(this.transcriptDataDir, { recursive: true });\n mkdirSync(this.transcriptsDir, { recursive: true });\n mkdirSync(this.summariesDir, { recursive: true });\n this.loadIndex();\n this.logger.info(\n `录音存储已初始化: ${this.dir}(共 ${this.index.recordings.length} 条记录)`,\n );\n }\n\n /** 获取音频目录路径 */\n getAudioDir(): string {\n return this.audioDir;\n }\n\n /** 获取转写 JSON 目录路径 */\n getTranscriptDataDir(): string {\n return this.transcriptDataDir;\n }\n\n /** 获取转写目录路径 */\n getTranscriptsDir(): string {\n return this.transcriptsDir;\n }\n\n /** 获取摘要目录路径 */\n getSummariesDir(): string {\n return this.summariesDir;\n }\n\n // ─── 录音入库 ───\n\n /**\n * 收到 recordings.sync 后,将元数据写入索引。\n * 如果同 ID 录音已存在则更新,否则新建。\n * 返回录音 ID。\n */\n ingest(recordingId: string, metadata: RecordingMetadata): string {\n const id = recordingId;\n const existing = this.findById(id);\n\n if (existing) {\n const sameAudioUrl = existing.metadata.oss_audio_url === metadata.oss_audio_url;\n const canPreserveSyncState =\n sameAudioUrl && !!existing.audioFile && existing.status !== \"syncing_openclaw\";\n\n if (canPreserveSyncState) {\n existing.metadata = metadata;\n existing.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(\n `录音元数据已更新: ${id}(同音频,保留状态 ${existing.status})`,\n );\n return id;\n }\n\n // 更新已有记录(覆盖上传/本地文件缺失场景)\n if (existing.transcriptDataFile) {\n rmSync(join(this.dir, existing.transcriptDataFile), { force: true });\n }\n if (existing.transcriptFile) {\n rmSync(join(this.dir, existing.transcriptFile), { force: true });\n }\n if (existing.summaryFile) {\n rmSync(join(this.dir, existing.summaryFile), { force: true });\n }\n existing.metadata = metadata;\n existing.status = \"syncing_openclaw\";\n existing.transcriptDataFile = undefined;\n existing.transcriptFile = undefined;\n existing.summaryFile = undefined;\n existing.title = undefined;\n existing.updatedAt = new Date().toISOString();\n this.logger.info(`录音元数据已更新: ${id}`);\n } else {\n const entry: RecordingIndexEntry = {\n id,\n metadata,\n status: \"syncing_openclaw\",\n ingestedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n this.index.recordings.push(entry);\n this.logger.info(`录音元数据已入库: ${id}`);\n }\n\n this.saveIndex();\n return id;\n }\n\n // ─── 状态管理 ───\n\n /**\n * 更新录音传输状态(严格状态机校验)\n */\n updateStatus(\n recordingId: string,\n newStatus: RecordingTransferStatus,\n ): RecordingIndexEntry {\n const entry = this.findById(recordingId);\n if (!entry) {\n throw new Error(`录音不存在: ${recordingId}`);\n }\n\n const validatedStatus = transition(entry.status, newStatus);\n entry.status = validatedStatus;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音状态更新: ${recordingId} → ${newStatus}`);\n return entry;\n }\n\n /**\n * 记录本地音频文件已下载\n */\n setAudioFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.audioFile = `${AUDIO_DIR}/${filename}`;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录本地打点文件已下载\n */\n setSrtFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.srtFile = `${AUDIO_DIR}/${filename}`;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写 JSON 文件路径\n */\n setTranscriptDataFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;\n if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {\n rmSync(join(this.dir, entry.transcriptDataFile), { force: true });\n }\n entry.transcriptDataFile = nextTranscriptDataFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写文件路径\n */\n setTranscriptFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;\n if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {\n rmSync(join(this.dir, entry.transcriptFile), { force: true });\n }\n entry.transcriptFile = nextTranscriptFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录摘要文件路径\n */\n setSummaryFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;\n if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {\n rmSync(join(this.dir, entry.summaryFile), { force: true });\n }\n entry.summaryFile = nextSummaryFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写标题\n */\n setTitle(recordingId: string, title?: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.title = title?.trim() || undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 读取摘要文本\n */\n readSummary(recordingId: string): string | undefined {\n const entry = this.findById(recordingId);\n if (!entry) return undefined;\n\n if (entry.summaryFile) {\n const summary = this.readRelativeTextFile(entry.summaryFile);\n if (summary?.trim()) {\n return summary.trim();\n }\n }\n\n const transcriptDoc = entry.transcriptDataFile\n ? this.readRelativeTranscriptDocument(entry.transcriptDataFile)\n : undefined;\n return extractTranscriptSummaryFromDocument(transcriptDoc);\n }\n\n /**\n * 优先从 transcript JSON 中读取正文,旧数据回退读取 Markdown。\n */\n readTranscript(recordingId: string): string | undefined {\n const entry = this.findById(recordingId);\n if (!entry) return undefined;\n\n if (entry.transcriptDataFile) {\n const transcriptDoc = this.readRelativeTranscriptDocument(entry.transcriptDataFile);\n const transcriptFromJson = extractTranscriptTextFromDocument(transcriptDoc);\n if (transcriptFromJson) {\n return transcriptFromJson;\n }\n }\n\n if (!entry.transcriptFile) return undefined;\n const markdown = this.readRelativeTextFile(entry.transcriptFile);\n if (!markdown) return undefined;\n const transcript = extractTranscriptContent(markdown);\n return transcript || undefined;\n }\n\n /**\n * 读取结构化 transcript JSON。\n */\n readTranscriptDocument(recordingId: string) {\n const entry = this.findById(recordingId);\n if (!entry?.transcriptDataFile) {\n return undefined;\n }\n return this.readRelativeTranscriptDocument(entry.transcriptDataFile);\n }\n\n // ─── 查询 ───\n\n findById(id: string): RecordingIndexEntry | undefined {\n return this.index.recordings.find((r) => r.id === id);\n }\n\n listAll(): RecordingIndexEntry[] {\n return [...this.index.recordings].sort(\n (a, b) => b.metadata.created_at.localeCompare(a.metadata.created_at),\n );\n }\n\n listByStatus(status: RecordingTransferStatus): RecordingIndexEntry[] {\n return this.listAll().filter((r) => r.status === status);\n }\n\n rename(recordingId: string, name: string): RecordingIndexEntry {\n const entry = this.findById(recordingId);\n if (!entry) {\n throw new Error(`录音不存在: ${recordingId}`);\n }\n\n entry.metadata = {\n ...entry.metadata,\n name,\n };\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音名称已更新: ${recordingId} → ${name}`);\n return entry;\n }\n\n // ─── 删除 ───\n\n /**\n * 删除录音及其本地文件(约束 R-4 安全删除)\n *\n * @param opts.localOnly 仅删除本地文件(音频/打点/转写),保留索引条目。\n * App 端\"仅删除本地\"时使用此模式,插件侧保留元数据记录。\n * 默认 false — 完整删除(文件 + 索引)。\n */\n delete(\n recordingId: string,\n opts?: { localOnly?: boolean },\n ): boolean {\n const entry = this.findById(recordingId);\n if (!entry) return false;\n\n // 删除本地文件\n if (entry.audioFile) {\n const audioPath = join(this.dir, entry.audioFile);\n rmSync(audioPath, { force: true });\n }\n if (entry.srtFile) {\n const srtPath = join(this.dir, entry.srtFile);\n rmSync(srtPath, { force: true });\n }\n if (entry.transcriptDataFile) {\n const transcriptDataPath = join(this.dir, entry.transcriptDataFile);\n rmSync(transcriptDataPath, { force: true });\n }\n if (entry.transcriptFile) {\n const transcriptPath = join(this.dir, entry.transcriptFile);\n rmSync(transcriptPath, { force: true });\n }\n if (entry.summaryFile) {\n const summaryPath = join(this.dir, entry.summaryFile);\n rmSync(summaryPath, { force: true });\n }\n\n if (opts?.localOnly) {\n // 保留索引条目,清除文件引用\n entry.audioFile = undefined;\n entry.srtFile = undefined;\n entry.transcriptDataFile = undefined;\n entry.transcriptFile = undefined;\n entry.summaryFile = undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音本地文件已删除(保留索引): ${recordingId}`);\n } else {\n // 从索引中移除\n this.index.recordings = this.index.recordings.filter(\n (r) => r.id !== recordingId,\n );\n this.saveIndex();\n this.logger.info(`录音已完整删除: ${recordingId}`);\n }\n return true;\n }\n\n // ─── Helpers ───\n\n /**\n * 生成音频文件名。扩展名从 OSS URL 中提取,未提供时默认 .ogg(硬件录音格式)\n */\n buildAudioFilename(recordingId: string, ossUrl?: string): string {\n const ext = ossUrl ? extractAudioExt(ossUrl) : \".ogg\";\n return `${recordingId}${ext}`;\n }\n\n /**\n * 生成打点文件名\n */\n buildSrtFilename(recordingId: string): string {\n return `${recordingId}.srt`;\n }\n\n /**\n * 生成转写 JSON 文件名\n */\n buildTranscriptDataFilename(recordingId: string): string {\n return buildTranscriptDataJsonFilename(recordingId);\n }\n\n /**\n * 生成转写文件名\n * @param summary 摘要标题(≤ 10 字)\n */\n buildTranscriptFilename(recordingId: string, summary: string): string {\n // 清理文件名中的非法字符\n const safeSummary = summary\n .replace(/[/\\\\:*?\"<>|]/g, \"\")\n .trim()\n .slice(0, 20);\n return safeSummary\n ? `${recordingId}_${safeSummary}.md`\n : `${recordingId}.md`;\n }\n\n /**\n * 生成摘要文件名\n */\n buildSummaryFilename(recordingId: string): string {\n return `${recordingId}.md`;\n }\n\n /**\n * 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名\n */\n getAudioFilePath(recordingId: string, ossUrl?: string): string {\n return join(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));\n }\n\n /**\n * 获取打点文件的绝对路径\n */\n getSrtFilePath(recordingId: string): string {\n return join(this.audioDir, this.buildSrtFilename(recordingId));\n }\n\n /**\n * 获取转写 JSON 文件的绝对路径\n */\n getTranscriptDataFilePath(recordingId: string): string {\n return join(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));\n }\n\n /**\n * 获取摘要文件的绝对路径\n */\n getSummaryFilePath(recordingId: string): string {\n return join(this.summariesDir, this.buildSummaryFilename(recordingId));\n }\n\n // ─── Persistence ───\n\n private loadIndex(): void {\n if (!existsSync(this.indexPath)) {\n this.index = { recordings: [] };\n return;\n }\n try {\n const raw = JSON.parse(readFileSync(this.indexPath, \"utf-8\"));\n if (raw && Array.isArray(raw.recordings)) {\n let needsRewrite = false;\n const normalized = raw.recordings\n .filter((entry: unknown) => entry && typeof entry === \"object\")\n .map((entry: any) => {\n const compacted: RecordingIndexEntry = {\n id: entry.id,\n metadata: entry.metadata,\n status: entry.status,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n };\n if (typeof entry.audioFile === \"string\") compacted.audioFile = entry.audioFile;\n if (typeof entry.srtFile === \"string\") compacted.srtFile = entry.srtFile;\n if (typeof entry.transcriptFile === \"string\") {\n compacted.transcriptFile = entry.transcriptFile;\n }\n let transcriptDoc = typeof entry.transcriptDataFile === \"string\"\n ? this.readRelativeTranscriptDocument(entry.transcriptDataFile)\n : undefined;\n if (typeof entry.transcriptDataFile === \"string\" && transcriptDoc) {\n compacted.transcriptDataFile = entry.transcriptDataFile;\n } else {\n const legacyTranscriptText = typeof entry.transcript === \"string\" && entry.transcript.trim()\n ? entry.transcript.trim()\n : compacted.transcriptFile\n ? extractTranscriptContent(\n this.readRelativeTextFile(compacted.transcriptFile) ?? \"\",\n ) || undefined\n : undefined;\n const legacyTitle = typeof entry.title === \"string\" && entry.title.trim()\n ? entry.title.trim()\n : deriveTitleFromTranscriptPath(compacted.transcriptFile, compacted.id);\n const legacySummary = typeof entry.summary === \"string\" && entry.summary.trim()\n ? entry.summary.trim()\n : undefined;\n\n if (legacyTranscriptText) {\n transcriptDoc = buildTranscriptDocument({\n recordingId: compacted.id,\n generatedAt: compacted.updatedAt,\n source: {\n provider: \"legacy-markdown\",\n },\n title: legacyTitle,\n summary: legacySummary,\n text: legacyTranscriptText,\n segments: [],\n });\n const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);\n writeFileSync(\n join(this.transcriptDataDir, transcriptDataFilename),\n JSON.stringify(transcriptDoc, null, 2),\n \"utf-8\",\n );\n compacted.transcriptDataFile = `${TRANSCRIPT_DATA_DIR}/${transcriptDataFilename}`;\n needsRewrite = true;\n }\n }\n\n if (typeof entry.summaryFile === \"string\") {\n compacted.summaryFile = entry.summaryFile;\n } else if (typeof entry.summary === \"string\" && entry.summary.trim()) {\n const summaryFilename = this.buildSummaryFilename(entry.id);\n writeFileSync(\n join(this.summariesDir, summaryFilename),\n entry.summary.trim(),\n \"utf-8\",\n );\n compacted.summaryFile = `${SUMMARIES_DIR}/${summaryFilename}`;\n needsRewrite = true;\n } else {\n const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);\n if (summaryFromDocument) {\n const summaryFilename = this.buildSummaryFilename(entry.id);\n writeFileSync(\n join(this.summariesDir, summaryFilename),\n summaryFromDocument,\n \"utf-8\",\n );\n compacted.summaryFile = `${SUMMARIES_DIR}/${summaryFilename}`;\n needsRewrite = true;\n }\n }\n if (typeof entry.title === \"string\" && entry.title.trim()) {\n compacted.title = entry.title.trim();\n } else {\n const titleFromDocument = extractTranscriptTitleFromDocument(transcriptDoc);\n const derivedTitle = titleFromDocument ?? deriveTitleFromTranscriptPath(\n compacted.transcriptFile,\n compacted.id,\n );\n if (derivedTitle) {\n compacted.title = derivedTitle;\n needsRewrite = true;\n }\n }\n return compacted;\n });\n const hadLargeFields = raw.recordings.some(\n (entry: any) => entry && typeof entry === \"object\" && (\"transcript\" in entry || \"summary\" in entry),\n );\n this.index = { recordings: normalized };\n if (hadLargeFields || needsRewrite) {\n this.saveIndex();\n }\n } else {\n this.index = { recordings: [] };\n }\n } catch {\n this.logger.warn(`录音索引文件损坏,已重建: ${this.indexPath}`);\n this.index = { recordings: [] };\n }\n }\n\n private readRelativeTextFile(relativePath: string): string | undefined {\n try {\n return readFileSync(join(this.dir, relativePath), \"utf-8\");\n } catch {\n return undefined;\n }\n }\n\n private readRelativeTranscriptDocument(relativePath: string) {\n const raw = this.readRelativeTextFile(relativePath);\n if (!raw) {\n return undefined;\n }\n return parseTranscriptDocument(raw);\n }\n\n private saveIndex(): void {\n writeFileSync(\n this.indexPath,\n JSON.stringify(this.index, null, 2),\n \"utf-8\",\n );\n }\n\n async close(): Promise<void> {\n // 当前无需额外清理\n }\n}\n","/**\n * 录音传输状态机(约束 R-3)\n *\n * 状态流转严格不可跳跃:\n * receiving_failed → receiving\n * receiving → pending_oss_upload\n * pending_oss_upload → uploading_oss\n * uploading_oss → oss_uploaded\n * oss_uploaded → syncing_openclaw\n * syncing_openclaw → synced\n * synced → transcribing(仅当已配置 ASR)\n * transcribing → transcribed | transcribe_failed\n * transcribe_failed → transcribing\n * transcribed → transcribing(手动强制重新转写)\n */\n\nimport type { RecordingTransferStatus } from \"../types.js\";\n\n/** 合法的状态转换表:from → Set<to> */\nconst VALID_TRANSITIONS: ReadonlyMap<\n RecordingTransferStatus,\n ReadonlySet<RecordingTransferStatus>\n> = new Map<RecordingTransferStatus, ReadonlySet<RecordingTransferStatus>>([\n [\"receiving_failed\", new Set([\"receiving\"])],\n [\"receiving\", new Set([\"pending_oss_upload\"])],\n [\"pending_oss_upload\", new Set([\"uploading_oss\"])],\n [\"uploading_oss\", new Set([\"oss_uploaded\"])],\n [\"oss_uploaded\", new Set([\"syncing_openclaw\"])],\n [\"syncing_openclaw\", new Set([\"synced\"])],\n [\"synced\", new Set([\"transcribing\"])],\n [\"transcribing\", new Set([\"transcribed\", \"transcribe_failed\"])],\n [\"transcribe_failed\", new Set([\"transcribing\"])],\n [\"transcribed\", new Set([\"transcribing\"])],\n]);\n\n/** 插件侧关注的状态:从 syncing_openclaw 开始 */\nexport type PluginSideStatus = Extract<\n RecordingTransferStatus,\n \"syncing_openclaw\" | \"synced\" | \"transcribing\" | \"transcribe_failed\" | \"transcribed\"\n>;\n\n/**\n * 校验状态转换是否合法\n */\nexport function isValidTransition(\n from: RecordingTransferStatus,\n to: RecordingTransferStatus,\n): boolean {\n const allowed = VALID_TRANSITIONS.get(from);\n return allowed ? allowed.has(to) : false;\n}\n\n/**\n * 尝试执行状态转换,非法转换抛出 Error\n */\nexport function transition(\n from: RecordingTransferStatus,\n to: RecordingTransferStatus,\n): RecordingTransferStatus {\n if (!isValidTransition(from, to)) {\n throw new TransitionError(from, to);\n }\n return to;\n}\n\n/**\n * 状态是否为终态(没有后续合法转换)\n */\nexport function isTerminalStatus(status: RecordingTransferStatus): boolean {\n const allowed = VALID_TRANSITIONS.get(status);\n return !allowed || allowed.size === 0;\n}\n\n/**\n * 状态是否允许触发 ASR 转写\n */\nexport function canStartTranscription(status: RecordingTransferStatus): boolean {\n return (\n status === \"synced\"\n || status === \"transcribe_failed\"\n || status === \"transcribed\"\n );\n}\n\n/**\n * 获取当前状态的所有合法后续状态\n */\nexport function getNextStatuses(\n status: RecordingTransferStatus,\n): RecordingTransferStatus[] {\n const allowed = VALID_TRANSITIONS.get(status);\n return allowed ? [...allowed] : [];\n}\n\nexport class TransitionError extends Error {\n constructor(\n public readonly from: RecordingTransferStatus,\n public readonly to: RecordingTransferStatus,\n ) {\n super(`非法状态转换: ${from} → ${to}`);\n this.name = \"TransitionError\";\n }\n}\n","export {\n RecordingStorage,\n resolveRecordingStorageDir,\n type RecordingIndexEntry,\n type RecordingStorageContext,\n} from \"./storage.js\";\n\nexport {\n TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n buildTranscriptDataFilename,\n buildTranscriptDocument,\n parseTranscriptDocument,\n extractTranscriptTextFromDocument,\n extractTranscriptSummaryFromDocument,\n extractTranscriptTitleFromDocument,\n extractSourceTextListFromDocument,\n type TranscriptDocument,\n type TranscriptDocumentContentItem,\n type TranscriptDocumentNormalized,\n type TranscriptDocumentSegment,\n type TranscriptDocumentSource,\n} from \"./transcript-document.js\";\n\nexport {\n isValidTransition,\n transition,\n isTerminalStatus,\n canStartTranscription,\n getNextStatuses,\n TransitionError,\n} from \"./state-machine.js\";\n\nexport {\n downloadFile,\n downloadRecordingFiles,\n type DownloadResult,\n type DownloadOptions,\n} from \"./downloader.js\";\n\nexport {\n isAsrConfigured,\n validateAsrConfig,\n initializeAsr,\n transcribeAudio,\n buildTranscriptMarkdown,\n extractSummary,\n runTranscriptionWorkflow,\n type TranscriptionResult,\n type TranscriptSegment,\n} from \"./asr.js\";\n\nexport {\n detectEnvironment,\n selectModelByMemory,\n isModelDownloaded,\n downloadModel,\n findWhisperBinary,\n transcribeWithWhisperLocal,\n getWhisperLocalStatus,\n} from \"./whisper-local.js\";\n\nexport {\n handleRecordingSync,\n triggerTranscription,\n type RecordingStatusEvent,\n type RecordingSyncOptions,\n} from \"./handler.js\";\n","/**\n * OSS 文件下载器(约束 R-6)\n *\n * 从 OSS URL 下载原始音频(mp3)和打点文件(srt)到本地。\n * 支持重试、超时控制、下载进度日志。\n */\n\nimport { createWriteStream, existsSync, mkdirSync, statSync, unlinkSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport type { Logger } from \"../logger.js\";\n\n// ─── Types ───\n\nexport interface DownloadOptions {\n /** 下载超时(毫秒),默认 5 分钟 */\n timeoutMs?: number;\n /** 最大重试次数,默认 3 */\n maxRetries?: number;\n /** 重试间隔基数(毫秒),默认 2000 */\n retryBackoffMs?: number;\n}\n\nexport interface DownloadResult {\n ok: boolean;\n /** 下载的文件大小(字节) */\n sizeBytes?: number;\n /** 耗时(毫秒) */\n elapsedMs?: number;\n /** 错误信息 */\n error?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 分钟(最大 ~56MB 文件)\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_BACKOFF_MS = 2000;\n\n// ─── Public API ───\n\n/**\n * 从 URL 下载文件到本地路径\n */\nexport async function downloadFile(\n url: string,\n destPath: string,\n logger: Logger,\n options?: DownloadOptions,\n): Promise<DownloadResult> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;\n\n mkdirSync(dirname(destPath), { recursive: true });\n\n let lastError: string | undefined;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n const startMs = Date.now();\n try {\n logger.info(\n `[downloader] 开始下载 (attempt ${attempt}/${maxRetries}): ${url}`,\n );\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} ${res.statusText}`);\n }\n\n if (!res.body) {\n throw new Error(\"响应体为空\");\n }\n\n // 写入文件\n const writeStream = createWriteStream(destPath);\n const readable = Readable.fromWeb(res.body as any);\n await pipeline(readable, writeStream);\n\n const elapsed = Date.now() - startMs;\n const fileSize = existsSync(destPath)\n ? statSync(destPath).size\n : 0;\n\n logger.info(\n `[downloader] 下载完成: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`,\n );\n\n return { ok: true, sizeBytes: fileSize, elapsedMs: elapsed };\n } finally {\n clearTimeout(timer);\n }\n } catch (err: any) {\n lastError = err?.message ?? String(err);\n\n // 清理可能写了一半的文件\n try {\n if (existsSync(destPath)) unlinkSync(destPath);\n } catch {\n // ignore\n }\n\n const isAbort = err?.name === \"AbortError\";\n logger.warn(\n `[downloader] 下载失败 (attempt ${attempt}/${maxRetries}): ${isAbort ? \"超时\" : lastError}`,\n );\n\n if (attempt < maxRetries) {\n const delay = retryBackoffMs * Math.pow(2, attempt - 1);\n logger.info(`[downloader] ${delay}ms 后重试...`);\n await sleep(delay);\n }\n }\n }\n\n return { ok: false, error: lastError ?? \"下载失败\" };\n}\n\n/**\n * 下载录音的音频文件和打点文件\n */\nexport async function downloadRecordingFiles(\n ossAudioUrl: string,\n ossSrtUrl: string | undefined,\n audioDestPath: string,\n srtDestPath: string,\n logger: Logger,\n options?: DownloadOptions,\n): Promise<{\n audio: DownloadResult;\n srt: DownloadResult | null;\n}> {\n // 下载音频(必须)\n const audio = await downloadFile(ossAudioUrl, audioDestPath, logger, options);\n\n // 下载打点文件(可选)\n let srt: DownloadResult | null = null;\n if (ossSrtUrl) {\n srt = await downloadFile(ossSrtUrl, srtDestPath, logger, options);\n if (!srt.ok) {\n // 打点文件下载失败不阻断主流程,仅警告\n logger.warn(`[downloader] 打点文件下载失败(非致命): ${srt.error}`);\n }\n }\n\n return { audio, srt };\n}\n\n// ─── Helpers ───\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * 录音同步处理器(§2 阶段 4–5)\n *\n * 统一处理 recordings.sync 请求:\n * 1. 元数据入库\n * 2. 从 OSS 下载音频 + 打点文件\n * 3. 更新状态 → synced\n * 4. 如已配置 ASR → 自动触发转写\n */\n\nimport type {\n RecordingMetadata,\n RecordingSyncResult,\n AsrConfig,\n RecordingTranscriptItem,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport { RecordingStorage } from \"./storage.js\";\nimport { downloadRecordingFiles } from \"./downloader.js\";\nimport { isAsrConfigured, runTranscriptionWorkflow } from \"./asr.js\";\nimport { canStartTranscription } from \"./state-machine.js\";\n\nexport interface RecordingStatusEvent {\n recordingId: string;\n transfer_status: RecordingTransferStatus;\n audioFile?: string;\n srtFile?: string;\n transcriptDataFile?: string;\n transcriptFile?: string;\n transcript?: RecordingTranscriptItem[];\n summary?: string;\n title: string;\n updatedAt: string;\n error?: string;\n}\n\nexport interface RecordingSyncOptions {\n notifyStatus?: (event: RecordingStatusEvent) => void;\n}\n\nfunction emitRecordingStatus(\n recordingId: string,\n storage: RecordingStorage,\n logger: Logger,\n notifyStatus?: RecordingSyncOptions[\"notifyStatus\"],\n error?: string,\n extras?: Pick<RecordingStatusEvent, \"transcript\" | \"summary\" | \"title\">,\n): void {\n if (!notifyStatus) {\n return;\n }\n\n const entry = storage.findById(recordingId);\n if (!entry) {\n return;\n }\n\n const title = extras?.title?.trim()\n || entry.title?.trim()\n || entry.metadata.name?.trim()\n || entry.id;\n\n try {\n notifyStatus({\n recordingId: entry.id,\n transfer_status: entry.status,\n audioFile: entry.audioFile,\n srtFile: entry.srtFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n transcript: extras?.transcript,\n summary: extras?.summary,\n title,\n updatedAt: entry.updatedAt,\n error,\n });\n } catch (err: any) {\n logger.error(\n `[recording-status] 状态事件发送失败: ${recordingId}, ${err?.message ?? err}`,\n );\n }\n}\n\nasync function runRecordingSyncInBackground(\n metadata: RecordingMetadata,\n recordingId: string,\n storage: RecordingStorage,\n asrConfig: AsrConfig | undefined,\n logger: Logger,\n options: RecordingSyncOptions,\n): Promise<void> {\n const audioDestPath = storage.getAudioFilePath(\n recordingId,\n metadata.oss_audio_url,\n );\n const srtDestPath = storage.getSrtFilePath(recordingId);\n\n logger.info(\n `[recording-sync] 开始下载录音文件: ${recordingId}, audio=${metadata.oss_audio_url}`,\n );\n\n const downloadResult = await downloadRecordingFiles(\n metadata.oss_audio_url,\n metadata.oss_srt_url,\n audioDestPath,\n srtDestPath,\n logger,\n );\n\n if (!downloadResult.audio.ok) {\n const error = `音频下载失败: ${downloadResult.audio.error}`;\n logger.error(`[recording-sync] ${error}: ${recordingId}`);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n return;\n }\n\n storage.setAudioFile(\n recordingId,\n storage.buildAudioFilename(recordingId, metadata.oss_audio_url),\n );\n if (downloadResult.srt?.ok) {\n storage.setSrtFile(recordingId, storage.buildSrtFilename(recordingId));\n }\n\n storage.updateStatus(recordingId, \"synced\");\n logger.info(`[recording-sync] 录音已同步: ${recordingId}`);\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n if (isAsrConfigured(asrConfig) && canStartTranscription(\"synced\")) {\n await triggerTranscription(\n recordingId,\n storage,\n asrConfig!,\n logger,\n options,\n );\n }\n}\n\n/**\n * 处理 recordings.sync 请求的核心逻辑\n */\nexport async function handleRecordingSync(\n recordingId: string,\n metadata: RecordingMetadata,\n storage: RecordingStorage,\n asrConfig: AsrConfig | undefined,\n logger: Logger,\n options: RecordingSyncOptions = {},\n): Promise<RecordingSyncResult> {\n const existing = storage.findById(recordingId);\n const shouldDownloadAndSync =\n !existing\n || existing.metadata.oss_audio_url !== metadata.oss_audio_url\n || !existing.audioFile\n || existing.status === \"syncing_openclaw\";\n\n storage.ingest(recordingId, metadata);\n if (shouldDownloadAndSync) {\n runRecordingSyncInBackground(\n metadata,\n recordingId,\n storage,\n asrConfig,\n logger,\n options,\n ).catch((err) => {\n const error = `录音同步失败: ${err?.message ?? err}`;\n logger.error(`[recording-sync] ${error}: ${recordingId}`);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n });\n } else {\n logger.info(\n `[recording-sync] 录音已存在且音频未变化,跳过重复下载: ${recordingId}`,\n );\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n const current = storage.findById(recordingId);\n if (current?.status === \"synced\" && isAsrConfigured(asrConfig)) {\n triggerTranscription(\n recordingId,\n storage,\n asrConfig!,\n logger,\n options,\n ).catch((err) => {\n logger.error(\n `[asr-trigger] 转写触发失败: ${recordingId}, ${err?.message ?? err}`,\n );\n });\n }\n }\n\n return {\n ok: true,\n recordingId,\n transfer_status:\n storage.findById(recordingId)?.status ?? \"syncing_openclaw\",\n };\n}\n\n/**\n * 触发 ASR 转写(可从 sync handler 自动触发或手动重试调用)\n */\nexport async function triggerTranscription(\n recordingId: string,\n storage: RecordingStorage,\n asrConfig: AsrConfig,\n logger: Logger,\n options: RecordingSyncOptions = {},\n): Promise<void> {\n const entry = storage.findById(recordingId);\n if (!entry) {\n logger.warn(`[asr-trigger] 录音不存在: ${recordingId}`);\n return;\n }\n\n if (!canStartTranscription(entry.status)) {\n logger.warn(\n `[asr-trigger] 当前状态不允许转写: ${recordingId} (status=${entry.status})`,\n );\n return;\n }\n\n // 状态 → transcribing\n storage.updateStatus(recordingId, \"transcribing\");\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n const audioFilePath = storage.getAudioFilePath(recordingId);\n\n const result = await runTranscriptionWorkflow({\n audioFilePath,\n audioOssUrl: entry.metadata.oss_audio_url,\n config: asrConfig,\n markers: entry.metadata.markers ?? [],\n recordingName: entry.metadata.name,\n durationSec: entry.metadata.duration_sec,\n createdAt: entry.metadata.created_at,\n transcriptDataDir: storage.getTranscriptDataDir(),\n transcriptsDir: storage.getTranscriptsDir(),\n summariesDir: storage.getSummariesDir(),\n recordingId,\n logger,\n });\n\n if (result.ok && result.transcriptFilename) {\n if (result.transcriptDataFilename) {\n storage.setTranscriptDataFile(recordingId, result.transcriptDataFilename);\n }\n storage.setTranscriptFile(recordingId, result.transcriptFilename);\n if (result.summaryFilename) {\n storage.setSummaryFile(recordingId, result.summaryFilename);\n }\n storage.setTitle(recordingId, result.title);\n storage.updateStatus(recordingId, \"transcribed\");\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n undefined,\n {\n transcript: result.transcript ?? [],\n summary: result.summary,\n title: result.title ?? \"\",\n },\n );\n logger.info(\n `[asr-trigger] 转写完成: ${recordingId}, summary=\"${result.summary}\"`,\n );\n } else {\n storage.updateStatus(recordingId, \"transcribe_failed\");\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n result.error,\n );\n logger.error(\n `[asr-trigger] 转写失败: ${recordingId}, error=${result.error}`,\n );\n }\n}\n","import {\n closeSync,\n mkdirSync,\n openSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { loadApiKey } from \"../auth/credentials.js\";\nimport { RelayClient } from \"./relay-client.js\";\nimport { TunnelProxy } from \"./proxy.js\";\nimport type { UpdateInfo } from \"../update/types.js\";\n\nconst DEFAULT_HEARTBEAT_SEC = 10;\nconst DEFAULT_RECONNECT_BACKOFF_MS = 2000;\n\ninterface TunnelServiceOptions {\n /** Relay Server WebSocket 地址(构建时从 RELAY_TUNNEL_URL 注入) */\n tunnelUrl: string;\n gatewayBaseUrl: string;\n /** Gateway 鉴权模式 */\n gatewayAuthMode?: \"token\" | \"password\";\n /** Gateway 鉴权 token */\n gatewayToken?: string;\n /** Gateway 鉴权密码 */\n gatewayPassword?: string;\n /** 心跳间隔(秒),默认 10 */\n heartbeatSec?: number;\n /** 重连基础退避时间(毫秒),默认 2000 */\n reconnectBackoffMs?: number;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport interface RelayTunnelService {\n id: string;\n start(ctx: { stateDir: string }): Promise<void>;\n stop(): Promise<void>;\n notifyUpdateAvailable(update: UpdateInfo): void;\n clearPendingUpdate(): void;\n deactivateForExternalTunnel(reason: string): Promise<void>;\n}\n\n/**\n * 隧道服务:组装 RelayClient + TunnelProxy,作为 registerService 的入口。\n */\nexport function createTunnelService(\n opts: TunnelServiceOptions,\n): RelayTunnelService {\n let client: RelayClient | null = null;\n let proxy: TunnelProxy | null = null;\n let abortController: AbortController | null = null;\n let lockFilePath: string | null = null;\n let lockFd: number | null = null;\n let pendingPluginUpdate: UpdateInfo | null = null;\n let suppressedByExternalTunnel = false;\n\n function emitPendingPluginUpdate(reason: string): void {\n const update = pendingPluginUpdate;\n if (!update || !client?.isConnected()) return;\n\n const frame = JSON.stringify({\n type: \"event\",\n event: \"plugin.updateAvailable\",\n payload: {\n pluginId: \"phone-notifications\",\n current: update.current,\n latest: update.latest,\n },\n });\n opts.logger.info(\n `Relay tunnel: sending plugin.updateAvailable ${update.current} → ${update.latest} (${reason})`,\n );\n client.sendRaw(frame);\n }\n\n function isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n if (pid === process.pid) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err: any) {\n return err?.code === \"EPERM\";\n }\n }\n\n function readLockOwner(filePath: string): number | null {\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf-8\")) as {\n pid?: unknown;\n };\n return typeof parsed.pid === \"number\" ? parsed.pid : null;\n } catch {\n return null;\n }\n }\n\n function releaseLock(): void {\n const filePath = lockFilePath;\n const fd = lockFd;\n lockFilePath = null;\n lockFd = null;\n\n if (fd !== null) {\n try {\n closeSync(fd);\n } catch {\n // ignore\n }\n }\n if (filePath) {\n try {\n unlinkSync(filePath);\n } catch {\n // ignore\n }\n }\n }\n\n function acquireLock(filePath: string): boolean {\n mkdirSync(dirname(filePath), { recursive: true });\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n const fd = openSync(filePath, \"wx\", 0o600);\n writeFileSync(\n fd,\n JSON.stringify({\n pid: process.pid,\n startedAt: new Date().toISOString(),\n tunnelUrl: opts.tunnelUrl,\n }) + \"\\n\",\n );\n lockFilePath = filePath;\n lockFd = fd;\n return true;\n } catch (err: any) {\n if (err?.code !== \"EEXIST\") {\n opts.logger.error(\n `Relay tunnel: failed to acquire local lock ${filePath}: ${String(err)}`,\n );\n return false;\n }\n\n const ownerPid = readLockOwner(filePath);\n if (ownerPid && !isProcessAlive(ownerPid)) {\n opts.logger.warn(\n `Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`,\n );\n try {\n unlinkSync(filePath);\n } catch {\n // ignore, retry below will fail if lock is still present\n }\n continue;\n }\n\n opts.logger.warn(\n `Relay tunnel: another local process already owns the tunnel lock${ownerPid ? ` (pid=${ownerPid})` : \"\"}; skipping connection to avoid duplicate token sessions`,\n );\n return false;\n }\n }\n\n return false;\n }\n\n async function shutdownRuntime(reason: string): Promise<void> {\n await client?.stop(reason);\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n releaseLock();\n proxy?.cleanup();\n proxy = null;\n client = null;\n }\n\n return {\n id: \"relay-tunnel\",\n\n async start(ctx: { stateDir: string }) {\n if (suppressedByExternalTunnel) {\n opts.logger.info(\n \"Relay tunnel: external tunnel currently owns ingress; skipping relay startup\",\n );\n return;\n }\n\n // 先清理上一轮连接,防止 start() 被重复调用时产生多个 RelayClient 互踢\n if (abortController) {\n opts.logger.info(\"Relay tunnel: aborting previous connection before restart\");\n await shutdownRuntime(\"service restarting\");\n }\n\n const apiKey = loadApiKey();\n if (!apiKey) {\n opts.logger.warn(\n \"Relay tunnel: apiKey 未设置,跳过隧道连接。请执行 openclaw ntf auth set-api-key <apiKey>\",\n );\n return;\n }\n\n const { logger } = opts;\n const baseStateDir = join(ctx.stateDir, \"plugins\", \"phone-notifications\");\n logger.info(\n `Relay tunnel: starting (pid=${process.pid}, url=${opts.tunnelUrl}, heartbeat=${opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC}s, backoff=${opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS}ms, gateway=${opts.gatewayBaseUrl}, hasGatewayToken=${!!opts.gatewayToken}, hasGatewayPwd=${!!opts.gatewayPassword})`,\n );\n const statusFilePath = join(baseStateDir, \"tunnel-status.json\");\n const lockPath = join(baseStateDir, \"relay-tunnel.lock\");\n\n if (!acquireLock(lockPath)) {\n return;\n }\n\n try {\n client = new RelayClient({\n tunnelUrl: opts.tunnelUrl,\n apiKey,\n heartbeatSec: opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC,\n reconnectBackoffMs: opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS,\n statusFilePath,\n logger,\n });\n\n proxy = new TunnelProxy({\n stateDir: baseStateDir,\n hostStateDir: ctx.stateDir,\n gatewayBaseUrl: opts.gatewayBaseUrl,\n gatewayAuthMode: opts.gatewayAuthMode,\n gatewayToken: opts.gatewayToken,\n gatewayPassword: opts.gatewayPassword,\n client,\n logger,\n });\n\n client.onInbound((frame) => proxy!.handleFrame(frame));\n client.onConnected(() => {\n emitPendingPluginUpdate(\"relay connected\");\n });\n\n abortController = new AbortController();\n // 非阻塞启动,connectWithAutoReconnect 内部会保持运行\n client.connectWithAutoReconnect(abortController.signal).catch((err) => {\n releaseLock();\n logger.error(`Relay tunnel: unexpected error: ${err}`);\n });\n\n logger.info(\"Relay tunnel 服务已启动\");\n } catch (err) {\n releaseLock();\n throw err;\n }\n },\n\n async stop() {\n suppressedByExternalTunnel = false;\n await shutdownRuntime(\"service stopping\");\n opts.logger.info(\"Relay tunnel 服务已停止\");\n },\n\n async deactivateForExternalTunnel(reason: string) {\n if (suppressedByExternalTunnel && !client && !proxy && !abortController) {\n return;\n }\n\n suppressedByExternalTunnel = true;\n opts.logger.info(\n `Relay tunnel: external tunnel claimed ingress (${reason}), shutting down relay connection`,\n );\n await shutdownRuntime(\"external tunnel active\");\n },\n\n notifyUpdateAvailable(update: UpdateInfo) {\n pendingPluginUpdate = update;\n emitPendingPluginUpdate(\"update detected\");\n },\n\n clearPendingUpdate() {\n pendingPluginUpdate = null;\n },\n };\n}\n","import { writeFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport WebSocket from \"ws\";\nimport type { InboundFrame, OutboundFrame } from \"./types.js\";\n\nfunction previewText(text: string, max = 500): string {\n return text.length <= max ? text : `${text.substring(0, max)}…`;\n}\n\nfunction maskSecret(value: string): string {\n if (!value) return \"empty\";\n if (value.length <= 8) {\n return `${value.slice(0, 2)}…${value.slice(-2)}`;\n }\n return `${value.slice(0, 4)}…${value.slice(-4)}`;\n}\n\n/** 持久化到磁盘的隧道连接状态 */\nexport interface TunnelStatusInfo {\n /** 当前连接状态 */\n state: \"connected\" | \"disconnected\" | \"connecting\" | \"stopped\";\n /** 状态变更时间 ISO */\n since: string;\n /** 累计重连次数 */\n reconnectAttempt: number;\n /** 上次断开原因(仅 disconnected 时有值) */\n lastDisconnectReason?: string;\n}\n\nexport interface RelayClientOptions {\n tunnelUrl: string;\n apiKey: string;\n heartbeatSec: number;\n reconnectBackoffMs: number;\n /** 状态文件路径,设置后会在连接状态变更时写入 */\n statusFilePath?: string;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport type InboundHandler = (frame: InboundFrame) => void | Promise<void>;\nexport type ConnectedHandler = () => void | Promise<void>;\n\n/**\n * Relay WebSocket 客户端。\n * 负责建连、token 认证、心跳保活、断线指数退避重连。\n */\nexport class RelayClient {\n private ws: WebSocket | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private handlers: InboundHandler[] = [];\n private connectedHandlers: ConnectedHandler[] = [];\n private aborted = false;\n private lastInboundAt = 0;\n private stopPromise: Promise<void> | null = null;\n\n constructor(private readonly opts: RelayClientOptions) {}\n\n /** 写连接状态到磁盘 */\n private writeStatus(\n state: TunnelStatusInfo[\"state\"],\n lastDisconnectReason?: string,\n ): void {\n if (!this.opts.statusFilePath) return;\n const info: TunnelStatusInfo = {\n state,\n since: new Date().toISOString(),\n reconnectAttempt: this.reconnectAttempt,\n lastDisconnectReason,\n };\n try {\n mkdirSync(dirname(this.opts.statusFilePath), { recursive: true });\n writeFileSync(this.opts.statusFilePath, JSON.stringify(info, null, 2));\n } catch {\n // 写状态文件失败不影响主流程\n }\n }\n\n /** 注册入站帧处理函数 */\n onInbound(handler: InboundHandler): void {\n this.handlers.push(handler);\n }\n\n /** 注册连接成功后的回调 */\n onConnected(handler: ConnectedHandler): void {\n this.connectedHandlers.push(handler);\n }\n\n /** 当前是否已连上 Relay */\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n /** 优雅停止客户端,优先发送 close 帧,超时后再强制 terminate */\n async stop(reason = \"client stopping\"): Promise<void> {\n if (this.stopPromise) {\n return this.stopPromise;\n }\n\n this.aborted = true;\n this.writeStatus(\"stopped\");\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const ws = this.ws;\n this.ws = null;\n if (!ws) {\n return;\n }\n\n this.opts.logger.info(\n `Relay tunnel: stopping client (readyState=${ws.readyState}, reason=${reason})`,\n );\n\n if (\n ws.readyState === WebSocket.CLOSED ||\n ws.readyState === WebSocket.CLOSING\n ) {\n return;\n }\n\n if (ws.readyState !== WebSocket.OPEN) {\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n return;\n }\n\n this.stopPromise = new Promise<void>((resolve) => {\n let finished = false;\n let fallbackTimer: ReturnType<typeof setTimeout> | null = null;\n\n const finish = () => {\n if (finished) return;\n finished = true;\n if (fallbackTimer) {\n clearTimeout(fallbackTimer);\n fallbackTimer = null;\n }\n ws.off(\"close\", handleClose);\n ws.off(\"error\", handleError);\n this.stopPromise = null;\n resolve();\n };\n\n const handleClose = () => finish();\n const handleError = () => finish();\n\n ws.once(\"close\", handleClose);\n ws.once(\"error\", handleError);\n\n fallbackTimer = setTimeout(() => {\n this.opts.logger.warn(\n \"Relay tunnel: graceful close timed out, forcing terminate\",\n );\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n finish();\n }, 1500);\n\n try {\n ws.close(1000, reason);\n } catch {\n finish();\n }\n });\n\n await this.stopPromise;\n }\n\n /** 发送出站帧 */\n send(frame: OutboundFrame): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n const payload = JSON.stringify(frame);\n this.opts.logger.info(\n `Relay tunnel: ▶ send frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"} (${payload.length} chars)`,\n );\n this.ws.send(payload);\n } else {\n this.opts.logger.warn(\n `Relay tunnel: ▶ send skipped, ws not open (readyState=${this.ws?.readyState ?? \"null\"}), frame type=${frame.type}`,\n );\n }\n }\n\n /** 原样透传文本到 Relay(用于 Gateway WS 响应直接回传) */\n sendRaw(text: string): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.opts.logger.info(\n `Relay tunnel: ▶ sendRaw (${text.length} chars): ${text.length <= 500 ? text : text.substring(0, 500) + \"…\"}`,\n );\n this.ws.send(text);\n } else {\n this.opts.logger.warn(\n `Relay tunnel: ▶ sendRaw skipped, ws not open (readyState=${this.ws?.readyState ?? \"null\"})`,\n );\n }\n }\n\n /** 启动连接,带自动重连,直到 abortSignal 触发 */\n async connectWithAutoReconnect(abortSignal?: AbortSignal): Promise<void> {\n if (abortSignal) {\n abortSignal.addEventListener(\n \"abort\",\n () => {\n void this.stop();\n },\n { once: true },\n );\n }\n\n await this.connect();\n\n // 保持运行直到 abort\n return new Promise<void>((resolve) => {\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", () => resolve(), { once: true });\n }\n });\n }\n\n private async connect(): Promise<void> {\n if (this.aborted) return;\n\n // 确保旧连接和定时器都被清理,防止重复连接\n this.cleanup(true);\n\n const rawApiKey = this.opts.apiKey.startsWith(\"Bearer \")\n ? this.opts.apiKey.slice(\"Bearer \".length)\n : this.opts.apiKey;\n\n this.opts.logger.info(\n `Relay tunnel: connecting to ${this.opts.tunnelUrl} (attempt=${this.reconnectAttempt}, heartbeat=${this.opts.heartbeatSec}s, apiKey=${maskSecret(rawApiKey)})`,\n );\n this.writeStatus(\"connecting\");\n\n return new Promise<void>((resolve) => {\n let settled = false;\n const settle = () => {\n if (!settled) {\n settled = true;\n resolve();\n }\n };\n\n const wsUrl = new URL(this.opts.tunnelUrl);\n // 推荐使用 query 传 apiKey;暂时用 token 代替 apiKey 明文\n if (!wsUrl.searchParams.get(\"apiKey\")) {\n wsUrl.searchParams.set(\"apiKey\", rawApiKey);\n }\n\n const ws = new WebSocket(wsUrl.toString(), {\n headers: {\n \"X-Api-Key-Id\": rawApiKey,\n },\n });\n // 将握手中的 socket 也记为当前连接,确保首连失败/握手前断开也能触发重连。\n this.ws = ws;\n\n ws.on(\"open\", () => {\n if (this.aborted || this.ws !== ws) {\n this.opts.logger.warn(\n `Relay tunnel: open fired but aborted=${this.aborted}, stale=${this.ws !== ws}, closing`,\n );\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n settle();\n return;\n }\n this.reconnectAttempt = 0;\n this.lastInboundAt = Date.now();\n this.startHeartbeat();\n this.opts.logger.info(\"Relay tunnel: ✔ connected, heartbeat started\");\n this.writeStatus(\"connected\");\n this.emitConnected();\n settle();\n });\n\n ws.on(\"pong\", () => {\n if (this.ws === ws) {\n this.opts.logger.info(\"Relay tunnel: ← pong received\");\n this.markInboundActivity();\n }\n });\n\n ws.on(\"message\", (data: WebSocket.RawData) => {\n if (this.ws !== ws) {\n return;\n }\n this.handleMessage(data);\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n const reasonStr = reason.toString();\n const lastInboundAgoMs = this.lastInboundAt\n ? Date.now() - this.lastInboundAt\n : null;\n const isCurrentSocket = this.ws === ws;\n const logMessage =\n `Relay tunnel: disconnected (code=${code}, reason=${previewText(reasonStr, 200)}, lastInboundAgoMs=${lastInboundAgoMs ?? \"N/A\"}, reconnectAttempt=${this.reconnectAttempt})`;\n if (this.aborted || !isCurrentSocket) {\n this.opts.logger.info(logMessage);\n } else {\n this.opts.logger.warn(logMessage);\n }\n if (isCurrentSocket) {\n this.stopHeartbeat();\n this.ws = null;\n this.writeStatus(\"disconnected\", `code=${code}, reason=${reasonStr}`);\n this.scheduleReconnect();\n }\n settle();\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.error(\n `Relay tunnel: WebSocket error: ${err.message} (readyState=${ws.readyState}, reconnectAttempt=${this.reconnectAttempt}, url=${wsUrl.toString()})`,\n );\n // 握手阶段的错误也要尽快结束本次 connect(),重连仍统一由 close 事件触发。\n settle();\n });\n });\n }\n\n private emitConnected(): void {\n for (const handler of this.connectedHandlers) {\n Promise.resolve(handler()).catch((err) => {\n this.opts.logger.warn(\n `Relay tunnel: onConnected handler failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n }\n\n private handleMessage(data: WebSocket.RawData): void {\n const text =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString()\n : String(data);\n\n this.markInboundActivity();\n\n // 应用层心跳 pong 直接消费,不走帧解析\n if (text === \"pong\") {\n return;\n }\n\n this.opts.logger.info(\n `Relay tunnel: ★ received message (${text.length} chars): ${previewText(text)}`,\n );\n\n let frame: InboundFrame;\n try {\n frame = JSON.parse(text) as InboundFrame;\n } catch {\n this.opts.logger.warn(\n `Relay tunnel: received invalid frame, ignoring (preview=${previewText(text, 200)})`,\n );\n return;\n }\n\n this.opts.logger.info(`Relay tunnel: parsed frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"}`);\n\n for (const handler of this.handlers) {\n try {\n const result = handler(frame);\n if (result instanceof Promise) {\n result.catch((err) => {\n this.opts.logger.error(`Relay tunnel: handler error: ${err}`);\n });\n }\n } catch (err) {\n this.opts.logger.error(`Relay tunnel: handler error: ${err}`);\n }\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n const intervalMs = this.opts.heartbeatSec * 1000;\n this.sendHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n this.sendHeartbeat();\n }, intervalMs);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private getHeartbeatTimeoutMs(): number {\n return this.opts.heartbeatSec * 3 * 1000;\n }\n\n private sendHeartbeat(): void {\n if (this.ws?.readyState !== WebSocket.OPEN) {\n return;\n }\n\n const idleMs = Date.now() - this.lastInboundAt;\n const timeoutMs = this.getHeartbeatTimeoutMs();\n if (idleMs >= timeoutMs) {\n this.opts.logger.warn(\n `Relay tunnel: heartbeat timeout, no inbound activity for ${idleMs}ms (threshold=${timeoutMs}ms)`,\n );\n try {\n this.ws.terminate();\n } catch {\n // ignore, close/error path will handle reconnect\n }\n return;\n }\n\n this.opts.logger.info('Relay tunnel: → heartbeat \"ping\"');\n try {\n this.ws.send(\"ping\");\n } catch {\n // ignore, close/error path will handle reconnect\n }\n try {\n this.ws.ping();\n } catch {\n // ignore, close/error path will handle reconnect\n }\n }\n\n private markInboundActivity(): void {\n this.lastInboundAt = Date.now();\n }\n\n private cleanup(force = false): void {\n this.opts.logger.info(\n `Relay tunnel: cleanup (ws=${this.ws ? \"open\" : \"null\"}, heartbeat=${!!this.heartbeatTimer}, reconnect=${!!this.reconnectTimer})`,\n );\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n try {\n if (force) {\n this.ws.terminate();\n } else {\n this.ws.close();\n }\n } catch {\n // ignore\n }\n this.ws = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.aborted) return;\n\n // 取消已有的重连定时器,防止重复 connect\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const baseMs = this.opts.reconnectBackoffMs;\n const delayMs = Math.min(\n baseMs * Math.pow(2, this.reconnectAttempt),\n 60_000,\n );\n this.reconnectAttempt++;\n\n this.opts.logger.info(\n `Relay tunnel: reconnecting in ${delayMs}ms (attempt ${this.reconnectAttempt})`,\n );\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n if (!this.aborted) {\n this.connect().catch((err) => {\n this.opts.logger.error(`Relay tunnel: reconnect failed: ${err}`);\n });\n }\n }, delayMs);\n }\n}\n","import createWebSocketStream from './lib/stream.js';\nimport Receiver from './lib/receiver.js';\nimport Sender from './lib/sender.js';\nimport WebSocket from './lib/websocket.js';\nimport WebSocketServer from './lib/websocket-server.js';\n\nexport { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };\nexport default WebSocket;\n","import { randomUUID } from \"node:crypto\";\nimport WebSocket from \"ws\";\nimport type { RelayClient } from \"./relay-client.js\";\nimport type { ReqFrame, InboundFrame } from \"./types.js\";\nimport { previewText } from \"./utils.js\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\nimport {\n type DeviceIdentity,\n resolveClientStateDir,\n loadOrCreateDeviceIdentity,\n loadDeviceAuthToken,\n storeDeviceAuthToken,\n clearDeviceAuthToken,\n buildDeviceAuthPayload,\n signDevicePayload,\n publicKeyRawBase64UrlFromPem,\n} from \"./device-identity.js\";\nimport { handleHttpRequest } from \"./http-proxy.js\";\nimport { WsProxy } from \"./ws-proxy.js\";\n\n// ─── Types ───\n\ninterface ProxyOptions {\n stateDir?: string;\n hostStateDir?: string;\n gatewayBaseUrl: string;\n /** Gateway 鉴权模式 */\n gatewayAuthMode?: \"token\" | \"password\";\n /** Gateway 鉴权 token,代理请求到本地 gateway 时使用 */\n gatewayToken?: string;\n /** Gateway 鉴权密码,代理请求到本地 gateway 时使用 */\n gatewayPassword?: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nconst MAX_AUTO_PAIRING_APPROVALS = 3;\ntype ApproveDevicePairingFn = (\n requestId: string,\n hostStateDir?: string,\n) => Promise<unknown>;\n\nlet approveDevicePairingPromise: Promise<ApproveDevicePairingFn | null> | null =\n null;\nlet approveDevicePairingWarned = false;\n\nfunction formatErrorMessage(err: unknown): string {\n if (err instanceof Error && err.message) return err.message;\n return String(err);\n}\n\nasync function loadApproveDevicePairing(\n logger: ProxyOptions[\"logger\"],\n): Promise<ApproveDevicePairingFn | null> {\n if (!approveDevicePairingPromise) {\n approveDevicePairingPromise = import(\"openclaw/plugin-sdk/device-bootstrap\")\n .then((mod) =>\n typeof mod.approveDevicePairing === \"function\"\n ? (mod.approveDevicePairing as ApproveDevicePairingFn)\n : null,\n )\n .catch((err: unknown) => {\n if (!approveDevicePairingWarned) {\n approveDevicePairingWarned = true;\n logger.warn(\n `TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK (${formatErrorMessage(err)})`,\n );\n }\n return null;\n });\n }\n\n const approveDevicePairing = await approveDevicePairingPromise;\n if (!approveDevicePairing && !approveDevicePairingWarned) {\n approveDevicePairingWarned = true;\n logger.warn(\n \"TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK\",\n );\n }\n return approveDevicePairing;\n}\n\n/**\n * 透明代理:接收 Relay 转发的请求帧,代理到本地 gateway,回传响应帧。\n * 支持 HTTP 请求代理和 WebSocket 连接代理。\n */\nexport class TunnelProxy {\n /** 到本地 Gateway 的持久 RPC WebSocket 连接 */\n private gatewayWs: WebSocket | null = null;\n private gatewayWsConnecting = false;\n /** 握手是否已完成(收到 hello-ok) */\n private gatewayWsReady = false;\n /** 收到本地自动配对成功后,在 close 回调里触发重连 */\n private gatewayWsReconnectRequested = false;\n /** 防止配对失败时无限重连 */\n private gatewayWsAutoPairingApprovals = 0;\n /** 等待 Gateway WS 握手完成后发送的帧队列 */\n private gatewayWsPending: string[] = [];\n\n /** 设备身份,用于 Gateway connect 握手 */\n private deviceIdentity: DeviceIdentity;\n\n private readonly stateDir: string;\n private readonly hostStateDir: string;\n private readonly wsProxy: WsProxy;\n\n constructor(private readonly opts: ProxyOptions) {\n this.stateDir = resolveClientStateDir(opts.stateDir);\n this.hostStateDir = opts.hostStateDir ?? resolveHostStateDir();\n this.deviceIdentity = loadOrCreateDeviceIdentity(this.stateDir);\n opts.logger.info(\n `TunnelProxy: loaded device identity (deviceId=${this.deviceIdentity.deviceId})`,\n );\n this.wsProxy = new WsProxy({\n gatewayBaseUrl: opts.gatewayBaseUrl,\n client: opts.client,\n logger: opts.logger,\n });\n }\n\n // ─── Frame dispatcher ───\n\n /** 处理从 Relay 收到的入站帧 */\n async handleFrame(frame: InboundFrame): Promise<void> {\n this.opts.logger.info(\n `TunnelProxy: handling frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"}`,\n );\n switch (frame.type) {\n case \"request\":\n await handleHttpRequest(this.opts, frame);\n break;\n case \"req\":\n this.handleReqFrame(frame);\n break;\n case \"ws_open\":\n this.wsProxy.handleWsOpen(frame);\n break;\n case \"ws_data\":\n this.wsProxy.handleWsData(frame);\n break;\n case \"ws_close\":\n this.wsProxy.handleWsClose(frame);\n break;\n default:\n this.opts.logger.warn(\n `TunnelProxy: unknown frame type=\"${(frame as any).type}\", id=${\"id\" in frame ? (frame as any).id : \"N/A\"}, forwarding raw to gateway`,\n );\n // 未知帧类型也尝试通过 RPC WS 转发,避免静默丢弃\n this.forwardRawToGateway(JSON.stringify(frame));\n break;\n }\n }\n\n /** 清理所有代理的 WebSocket 连接 */\n cleanup(): void {\n this.opts.logger.info(\n `TunnelProxy: cleanup, closing ${this.wsProxy.activeCount} active WS connections, gatewayWs=${!!this.gatewayWs}`,\n );\n this.wsProxy.cleanup();\n\n if (this.gatewayWs) {\n try {\n this.gatewayWs.close();\n } catch {\n // ignore\n }\n this.gatewayWs = null;\n }\n this.gatewayWsReady = false;\n this.gatewayWsConnecting = false;\n this.gatewayWsReconnectRequested = false;\n this.gatewayWsAutoPairingApprovals = 0;\n this.gatewayWsPending = [];\n }\n\n // ─── Gateway RPC WebSocket ───\n\n private pushGatewayPending(payload: string, reason: string): void {\n this.gatewayWsPending.push(payload);\n this.opts.logger.info(\n `TunnelProxy: gateway WS pending queue size=${this.gatewayWsPending.length} (${reason})`,\n );\n }\n\n /** 将未知帧原样转发到 Gateway WS */\n private forwardRawToGateway(payload: string): void {\n this.ensureGatewayWs();\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN) {\n this.gatewayWs.send(payload);\n } else {\n this.pushGatewayPending(payload, \"raw frame queued before gateway WS ready\");\n }\n }\n\n /** 处理 Relay 转发的 Gateway RPC 请求帧,原样通过 WebSocket 发给本地 Gateway */\n private handleReqFrame(frame: ReqFrame): void {\n const payload = JSON.stringify(frame);\n this.opts.logger.info(\n `TunnelProxy: req id=${frame.id} method=${frame.method} → gateway WS (${payload.length} chars)`,\n );\n\n this.ensureGatewayWs();\n\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN) {\n this.gatewayWs.send(payload);\n } else {\n this.opts.logger.info(\n `TunnelProxy: req id=${frame.id} queued, gateway WS not ready yet`,\n );\n this.pushGatewayPending(\n payload,\n `req id=${frame.id} queued before gateway WS handshake`,\n );\n }\n }\n\n // ─── Gateway connect auth helpers ───\n\n private resolveGatewayConnectAuth():\n | { token?: string; password?: string }\n | undefined {\n const token = this.opts.gatewayToken?.trim() || undefined;\n const password = this.opts.gatewayPassword?.trim() || undefined;\n if (!token && !password) return undefined;\n return { token, password };\n }\n\n private loadStoredDeviceToken(role: string): string | undefined {\n return (\n loadDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role,\n })?.token ?? undefined\n );\n }\n\n private buildGatewayConnectAuth(role: string): {\n auth?: { token?: string; deviceToken?: string; password?: string };\n authToken?: string;\n authPassword?: string;\n deviceToken?: string;\n } {\n const explicitAuth = this.resolveGatewayConnectAuth();\n const authPassword = explicitAuth?.password?.trim() || undefined;\n const explicitGatewayToken = explicitAuth?.token?.trim() || undefined;\n const deviceToken = explicitGatewayToken\n ? undefined\n : this.loadStoredDeviceToken(role);\n const authToken = explicitGatewayToken ?? deviceToken;\n const auth =\n authToken || authPassword || deviceToken\n ? { token: authToken, deviceToken, password: authPassword }\n : undefined;\n return { auth, authToken, authPassword, deviceToken };\n }\n\n private storeIssuedDeviceToken(params: {\n fallbackRole: string;\n fallbackScopes: string[];\n authInfo: any;\n }): void {\n const token = params.authInfo?.deviceToken;\n if (typeof token !== \"string\" || !token.trim()) return;\n const role =\n typeof params.authInfo?.role === \"string\" && params.authInfo.role.trim()\n ? params.authInfo.role.trim()\n : params.fallbackRole;\n const scopes = Array.isArray(params.authInfo?.scopes)\n ? params.authInfo.scopes.filter(\n (scope: unknown): scope is string =>\n typeof scope === \"string\" && !!scope.trim(),\n )\n : params.fallbackScopes;\n storeDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role,\n token: token.trim(),\n scopes,\n });\n }\n\n private maybeClearStoredDeviceTokenOnMismatch(code: number, reason: string): void {\n const explicitAuth = this.resolveGatewayConnectAuth();\n if (explicitAuth?.token || explicitAuth?.password) return;\n if (code !== 1008 || !reason.toLowerCase().includes(\"device token mismatch\")) return;\n clearDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role: \"operator\",\n });\n this.opts.logger.warn(\n `TunnelProxy: cleared stale stored device token after gateway mismatch (deviceId=${this.deviceIdentity.deviceId})`,\n );\n }\n\n private async maybeAutoApproveGatewayPairing(frame: any): Promise<boolean> {\n const errorCode =\n typeof frame?.error?.code === \"string\" ? frame.error.code : undefined;\n const detailsCode =\n typeof frame?.error?.details?.code === \"string\"\n ? frame.error.details.code\n : undefined;\n if (errorCode !== \"NOT_PAIRED\" && detailsCode !== \"PAIRING_REQUIRED\") {\n return false;\n }\n\n const requestId =\n typeof frame?.error?.details?.requestId === \"string\"\n ? frame.error.details.requestId.trim()\n : \"\";\n const reason =\n typeof frame?.error?.details?.reason === \"string\"\n ? frame.error.details.reason.trim()\n : \"\";\n\n if (!requestId) {\n this.opts.logger.warn(\n \"TunnelProxy: gateway pairing required but requestId missing; unable to auto-approve\",\n );\n return false;\n }\n\n if (\n reason &&\n reason !== \"not-paired\" &&\n reason !== \"scope-upgrade\"\n ) {\n this.opts.logger.warn(\n `TunnelProxy: gateway pairing required with unsupported reason=${reason}; skipping auto-approve`,\n );\n return false;\n }\n\n if (this.gatewayWsAutoPairingApprovals >= MAX_AUTO_PAIRING_APPROVALS) {\n this.opts.logger.warn(\n `TunnelProxy: reached auto-pairing retry limit (${MAX_AUTO_PAIRING_APPROVALS}); requestId=${requestId}`,\n );\n return false;\n }\n\n try {\n const approveDevicePairing = await loadApproveDevicePairing(this.opts.logger);\n if (!approveDevicePairing) {\n return false;\n }\n const approved = await approveDevicePairing(requestId, this.hostStateDir);\n if (!approved) {\n this.opts.logger.warn(\n `TunnelProxy: gateway pairing request ${requestId} not found in host state ${this.hostStateDir}`,\n );\n return false;\n }\n this.gatewayWsAutoPairingApprovals += 1;\n this.gatewayWsReconnectRequested = true;\n this.opts.logger.info(\n `TunnelProxy: auto-approved local gateway pairing request ${requestId} (reason=${reason || \"not-paired\"}, hostStateDir=${this.hostStateDir}, approval=${this.gatewayWsAutoPairingApprovals}/${MAX_AUTO_PAIRING_APPROVALS})`,\n );\n return true;\n } catch (err: any) {\n this.opts.logger.warn(\n `TunnelProxy: failed to auto-approve gateway pairing request ${requestId}: ${err?.message ?? String(err)}`,\n );\n return false;\n }\n }\n\n // ─── Gateway RPC WebSocket lifecycle ───\n\n /** 确保到本地 Gateway 的 RPC WebSocket 已连接且握手完成 */\n private ensureGatewayWs(): void {\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN)\n return;\n if (this.gatewayWsConnecting) return;\n\n this.gatewayWsConnecting = true;\n this.gatewayWsReady = false;\n const wsUrl = this.opts.gatewayBaseUrl.replace(/^http/, \"ws\");\n\n this.opts.logger.info(\n `TunnelProxy: RPC WS connecting to gateway ${wsUrl} (pending=${this.gatewayWsPending.length})`,\n );\n\n const ws = new WebSocket(wsUrl);\n\n ws.on(\"open\", () => {\n this.gatewayWs = ws;\n this.opts.logger.info(\n `TunnelProxy: RPC WS tcp connected, waiting for connect.challenge (pending=${this.gatewayWsPending.length})`,\n );\n });\n\n ws.on(\"message\", async (data: WebSocket.RawData) => {\n let text: string;\n if (typeof data === \"string\") {\n text = data;\n } else if (Buffer.isBuffer(data)) {\n text = data.toString();\n } else {\n text = Buffer.from(data as ArrayBuffer).toString();\n }\n\n const preview = text.length <= 500 ? text : text.substring(0, 500) + \"…\";\n this.opts.logger.info(\n `TunnelProxy: RPC WS ← gateway (${text.length} chars): ${preview}`,\n );\n\n let frame: any;\n try {\n frame = JSON.parse(text);\n } catch {\n this.opts.logger.warn(\n \"TunnelProxy: RPC WS received non-JSON, ignoring\",\n );\n return;\n }\n\n // 1) 收到 connect.challenge → 回复 connect 请求(带设备身份签名)\n if (frame.type === \"event\" && frame.event === \"connect.challenge\") {\n this.handleConnectChallenge(ws, frame);\n return;\n }\n\n // 2) 收到 connect 的 hello-ok 响应 → 握手完成,flush 待发帧\n if (\n frame.type === \"res\" &&\n frame.ok === true &&\n frame.payload?.type === \"hello-ok\"\n ) {\n this.storeIssuedDeviceToken({\n fallbackRole: \"operator\",\n fallbackScopes: [\"operator.admin\"],\n authInfo: frame.payload?.auth,\n });\n this.gatewayWsAutoPairingApprovals = 0;\n this.gatewayWsReconnectRequested = false;\n this.gatewayWsReady = true;\n this.gatewayWsConnecting = false;\n this.opts.logger.info(\n `TunnelProxy: RPC WS handshake done (hello-ok), flushing ${this.gatewayWsPending.length} pending frames`,\n );\n for (const pending of this.gatewayWsPending) {\n ws.send(pending);\n }\n this.gatewayWsPending = [];\n return;\n }\n\n // 3) 收到 connect 失败响应 → 关闭连接\n if (frame.type === \"res\" && frame.ok === false && !this.gatewayWsReady) {\n const autoApproved = await this.maybeAutoApproveGatewayPairing(frame);\n if (autoApproved) {\n const wsAlreadyClosed =\n ws.readyState === WebSocket.CLOSING ||\n ws.readyState === WebSocket.CLOSED ||\n this.gatewayWs !== ws;\n this.opts.logger.info(\n `TunnelProxy: RPC WS handshake requested local pairing approval, reconnecting${wsAlreadyClosed ? \" immediately\" : \" after close\"} (pending=${this.gatewayWsPending.length})`,\n );\n if (wsAlreadyClosed) {\n this.gatewayWsReconnectRequested = false;\n this.ensureGatewayWs();\n return;\n }\n ws.close(1000, \"pairing approved, reconnecting\");\n return;\n }\n this.opts.logger.error(\n `TunnelProxy: RPC WS handshake failed (pending=${this.gatewayWsPending.length}): ${previewText(JSON.stringify(frame.error), 500)}`,\n );\n ws.close();\n return;\n }\n\n // 4) 握手后的普通消息 → 透传回 Relay\n this.opts.client.sendRaw(text);\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n const wasReady = this.gatewayWsReady;\n const pendingCount = this.gatewayWsPending.length;\n const reasonText = reason.toString();\n const shouldReconnect =\n this.gatewayWsReconnectRequested && pendingCount > 0;\n this.opts.logger.info(\n `TunnelProxy: RPC WS closed by gateway (code=${code}, reason=${reasonText}, ready=${wasReady}, pending=${pendingCount}, activeWs=${this.wsProxy.activeCount})`,\n );\n if (this.gatewayWs === ws) {\n this.gatewayWs = null;\n this.gatewayWsReady = false;\n }\n this.gatewayWsConnecting = false;\n this.maybeClearStoredDeviceTokenOnMismatch(code, reasonText);\n if (shouldReconnect) {\n this.gatewayWsReconnectRequested = false;\n this.opts.logger.info(\n `TunnelProxy: retrying RPC WS after local pairing approval (pending=${this.gatewayWsPending.length})`,\n );\n queueMicrotask(() => this.ensureGatewayWs());\n }\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.warn(\n `TunnelProxy: RPC WS error: ${err.message} (ready=${this.gatewayWsReady}, pending=${this.gatewayWsPending.length}, activeWs=${this.wsProxy.activeCount})`,\n );\n this.gatewayWsConnecting = false;\n if (this.gatewayWs === ws) {\n this.gatewayWs = null;\n this.gatewayWsReady = false;\n }\n });\n }\n\n private handleConnectChallenge(ws: WebSocket, frame: any): void {\n const challengeNonce: string = frame.payload?.nonce ?? \"\";\n const connectRequestId = `tunnel-connect-${randomUUID()}`;\n const role = \"operator\";\n const scopes = [\"operator.admin\"];\n const gatewayConnectAuth = this.buildGatewayConnectAuth(role);\n this.opts.logger.info(\n `TunnelProxy: received connect.challenge (nonce=${challengeNonce}, connectReqId=${connectRequestId}, hasToken=${!!gatewayConnectAuth.authToken}, hasPassword=${!!gatewayConnectAuth.authPassword}, hasDeviceToken=${!!gatewayConnectAuth.deviceToken}), sending connect request with device identity`,\n );\n\n const signedAtMs = Date.now();\n const clientId = \"gateway-client\";\n const clientMode = \"backend\";\n\n const authPayload = buildDeviceAuthPayload({\n deviceId: this.deviceIdentity.deviceId,\n clientId,\n clientMode,\n role,\n scopes,\n signedAtMs,\n token: gatewayConnectAuth.authToken ?? null,\n nonce: challengeNonce,\n });\n const signature = signDevicePayload(\n this.deviceIdentity.privateKeyPem,\n authPayload,\n );\n\n const connectReq = {\n type: \"req\",\n id: connectRequestId,\n method: \"connect\",\n params: {\n minProtocol: 3,\n maxProtocol: 3,\n client: {\n id: clientId,\n version: \"1.0.0\",\n platform: process.platform,\n mode: clientMode,\n },\n role,\n scopes,\n ...(gatewayConnectAuth.auth ? { auth: gatewayConnectAuth.auth } : {}),\n device: {\n id: this.deviceIdentity.deviceId,\n publicKey: publicKeyRawBase64UrlFromPem(\n this.deviceIdentity.publicKeyPem,\n ),\n signature,\n signedAt: signedAtMs,\n nonce: challengeNonce,\n },\n },\n };\n ws.send(JSON.stringify(connectReq));\n }\n}\n","export function previewText(text: string | undefined, max = 200): string {\n if (!text) return \"\";\n return text.length <= max ? text : `${text.substring(0, max)}…`;\n}\n\nexport function findHeaderValue(\n headers: Record<string, string> | undefined,\n key: string,\n): string | undefined {\n if (!headers) return undefined;\n const lowerKey = key.toLowerCase();\n for (const [headerKey, headerValue] of Object.entries(headers)) {\n if (headerKey.toLowerCase() === lowerKey) {\n return headerValue;\n }\n }\n return undefined;\n}\n\nexport function summarizeRequestHeaders(headers: Record<string, string> | undefined): string {\n const contentType = findHeaderValue(headers, \"content-type\");\n const requestId = findHeaderValue(headers, \"x-request-id\");\n const parts: string[] = [];\n if (contentType) {\n parts.push(`contentType=${contentType}`);\n }\n if (requestId) {\n parts.push(`xRequestId=${previewText(requestId, 120)}`);\n }\n return parts.length ? `, ${parts.join(\", \")}` : \"\";\n}\n","import crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\n\n// ─── Types ───\n\nexport interface DeviceIdentity {\n deviceId: string;\n publicKeyPem: string;\n privateKeyPem: string;\n}\n\nexport interface DeviceAuthEntry {\n token: string;\n role: string;\n scopes: string[];\n updatedAtMs: number;\n}\n\ninterface DeviceAuthStore {\n version: 1;\n deviceId: string;\n tokens: Record<string, DeviceAuthEntry>;\n}\n\n// ─── Crypto helpers ───\n\nconst ED25519_SPKI_PREFIX = Buffer.from(\"302a300506032b6570032100\", \"hex\");\n\nexport function base64UrlEncode(buf: Buffer): string {\n return buf\n .toString(\"base64\")\n .replaceAll(\"+\", \"-\")\n .replaceAll(\"/\", \"_\")\n .replace(/=+$/g, \"\");\n}\n\nexport function derivePublicKeyRaw(publicKeyPem: string): Buffer {\n const spki = crypto.createPublicKey(publicKeyPem).export({\n type: \"spki\",\n format: \"der\",\n });\n if (\n spki.length === ED25519_SPKI_PREFIX.length + 32 &&\n spki.subarray(0, ED25519_SPKI_PREFIX.length).equals(ED25519_SPKI_PREFIX)\n )\n return spki.subarray(ED25519_SPKI_PREFIX.length);\n return spki;\n}\n\nexport function fingerprintPublicKey(publicKeyPem: string): string {\n const raw = derivePublicKeyRaw(publicKeyPem);\n return crypto.createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\nexport function publicKeyRawBase64UrlFromPem(publicKeyPem: string): string {\n return base64UrlEncode(derivePublicKeyRaw(publicKeyPem));\n}\n\nexport function signDevicePayload(privateKeyPem: string, payload: string): string {\n const key = crypto.createPrivateKey(privateKeyPem);\n return base64UrlEncode(crypto.sign(null, Buffer.from(payload, \"utf8\"), key));\n}\n\nexport function buildDeviceAuthPayload(params: {\n deviceId: string;\n clientId: string;\n clientMode: string;\n role: string;\n scopes: string[];\n signedAtMs: number;\n token: string | null;\n nonce: string;\n}): string {\n const scopes = params.scopes.join(\",\");\n const token = params.token ?? \"\";\n return [\n \"v2\",\n params.deviceId,\n params.clientId,\n params.clientMode,\n params.role,\n scopes,\n String(params.signedAtMs),\n token,\n params.nonce,\n ].join(\"|\");\n}\n\n// ─── File I/O helpers ───\n\nexport function resolveClientStateDir(stateDir: string | undefined): string {\n return stateDir ?? resolveHostStateDir();\n}\n\nfunction ensureDir(filePath: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n}\n\nfunction resolveIdentityPath(stateDir: string): string {\n return path.join(stateDir, \"identity\", \"device.json\");\n}\n\nfunction normalizeDeviceAuthRole(role: string): string {\n return role.trim();\n}\n\nfunction normalizeDeviceAuthScopes(scopes: string[]): string[] {\n const out = new Set<string>();\n for (const scope of scopes) {\n const trimmed = scope.trim();\n if (trimmed) {\n out.add(trimmed);\n }\n }\n return [...out].sort();\n}\n\nfunction resolveDeviceAuthPath(stateDir: string): string {\n return path.join(stateDir, \"identity\", \"device-auth.json\");\n}\n\nfunction readDeviceAuthStore(filePath: string): DeviceAuthStore | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed?.version !== 1 || typeof parsed.deviceId !== \"string\") return null;\n if (!parsed.tokens || typeof parsed.tokens !== \"object\") return null;\n return parsed as DeviceAuthStore;\n } catch {\n return null;\n }\n}\n\nfunction writeDeviceAuthStore(filePath: string, store: DeviceAuthStore): void {\n ensureDir(filePath);\n fs.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}\\n`, {\n mode: 0o600,\n });\n try {\n fs.chmodSync(filePath, 0o600);\n } catch {\n // ignore chmod errors on unsupported filesystems\n }\n}\n\n// ─── Token CRUD ───\n\nexport function loadDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n}): DeviceAuthEntry | null {\n const store = readDeviceAuthStore(resolveDeviceAuthPath(params.stateDir));\n if (!store || store.deviceId !== params.deviceId) return null;\n const entry = store.tokens[normalizeDeviceAuthRole(params.role)];\n if (!entry || typeof entry.token !== \"string\") return null;\n return entry;\n}\n\nexport function storeDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n token: string;\n scopes: string[];\n}): DeviceAuthEntry {\n const filePath = resolveDeviceAuthPath(params.stateDir);\n const existing = readDeviceAuthStore(filePath);\n const role = normalizeDeviceAuthRole(params.role);\n const next: DeviceAuthStore = {\n version: 1,\n deviceId: params.deviceId,\n tokens:\n existing && existing.deviceId === params.deviceId && existing.tokens\n ? { ...existing.tokens }\n : {},\n };\n const entry: DeviceAuthEntry = {\n token: params.token,\n role,\n scopes: normalizeDeviceAuthScopes(params.scopes),\n updatedAtMs: Date.now(),\n };\n next.tokens[role] = entry;\n writeDeviceAuthStore(filePath, next);\n return entry;\n}\n\nexport function clearDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n}): void {\n const filePath = resolveDeviceAuthPath(params.stateDir);\n const store = readDeviceAuthStore(filePath);\n if (!store || store.deviceId !== params.deviceId) return;\n const role = normalizeDeviceAuthRole(params.role);\n if (!store.tokens[role]) return;\n const next: DeviceAuthStore = {\n version: 1,\n deviceId: store.deviceId,\n tokens: { ...store.tokens },\n };\n delete next.tokens[role];\n writeDeviceAuthStore(filePath, next);\n}\n\n// ─── Identity lifecycle ───\n\nexport function loadOrCreateDeviceIdentity(stateDir: string): DeviceIdentity {\n const filePath = resolveIdentityPath(stateDir);\n try {\n if (fs.existsSync(filePath)) {\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n if (\n parsed?.version === 1 &&\n typeof parsed.deviceId === \"string\" &&\n typeof parsed.publicKeyPem === \"string\" &&\n typeof parsed.privateKeyPem === \"string\"\n ) {\n const derivedId = fingerprintPublicKey(parsed.publicKeyPem);\n return {\n deviceId: derivedId,\n publicKeyPem: parsed.publicKeyPem,\n privateKeyPem: parsed.privateKeyPem,\n };\n }\n }\n } catch {\n // fall through to generate\n }\n // Generate new identity\n const { publicKey, privateKey } = crypto.generateKeyPairSync(\"ed25519\");\n const publicKeyPem = publicKey\n .export({ type: \"spki\", format: \"pem\" })\n .toString();\n const privateKeyPem = privateKey\n .export({ type: \"pkcs8\", format: \"pem\" })\n .toString();\n const identity: DeviceIdentity = {\n deviceId: fingerprintPublicKey(publicKeyPem),\n publicKeyPem,\n privateKeyPem,\n };\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n const stored = {\n version: 1,\n ...identity,\n createdAtMs: Date.now(),\n };\n ensureDir(filePath);\n fs.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}\\n`, {\n mode: 0o600,\n });\n return identity;\n}\n","import type { RelayClient } from \"./relay-client.js\";\nimport type { RequestFrame } from \"./types.js\";\nimport { previewText, summarizeRequestHeaders } from \"./utils.js\";\n\nexport const RELAY_INTERNAL_HTTP_HEADER = \"x-openclaw-relay-internal\";\n\nexport interface HttpProxyOptions {\n gatewayBaseUrl: string;\n gatewayAuthMode?: \"token\" | \"password\";\n gatewayToken?: string;\n gatewayPassword?: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\n// ─── 路径映射 ───\n\nconst PATH_MAP: Record<string, string> = {\n \"/api/message/messageBridge/send\": \"/notifications\",\n};\n\nexport function mapPath(p: string): string {\n return PATH_MAP[p] ?? p;\n}\n\n// ─── Auth helpers ───\n\nfunction resolveGatewayConnectAuth(opts: HttpProxyOptions):\n | { token?: string; password?: string }\n | undefined {\n const token = opts.gatewayToken?.trim() || undefined;\n const password = opts.gatewayPassword?.trim() || undefined;\n if (!token && !password) return undefined;\n return { token, password };\n}\n\nexport function buildLocalGatewayAuthAttempts(\n opts: HttpProxyOptions,\n baseHeaders: Record<string, string>,\n): Array<{ label: string; headers: Record<string, string> }> {\n const auth = resolveGatewayConnectAuth(opts);\n const attempts: Array<{ label: string; headers: Record<string, string> }> = [];\n const seen = new Set<string>();\n const authMode = opts.gatewayAuthMode;\n\n const addAttempt = (kind: \"token\" | \"password\", secret?: string): void => {\n if (!secret) return;\n\n const dedupeKey = `${kind}:${secret}`;\n if (seen.has(dedupeKey)) return;\n seen.add(dedupeKey);\n\n const headers = { ...baseHeaders };\n headers.authorization = `Bearer ${secret}`;\n\n if (kind === \"password\") {\n headers[\"x-openclaw-password\"] = secret;\n } else {\n delete headers[\"x-openclaw-password\"];\n }\n\n attempts.push({\n label: kind === \"token\" ? \"gateway-token\" : \"gateway-password\",\n headers,\n });\n };\n\n if (authMode === \"password\") {\n addAttempt(\"password\", auth?.password);\n addAttempt(\"token\", auth?.token);\n } else {\n addAttempt(\"token\", auth?.token);\n addAttempt(\"password\", auth?.password);\n }\n\n if (attempts.length === 0) {\n attempts.push({\n label: \"no-auth\",\n headers: { ...baseHeaders },\n });\n }\n\n return attempts;\n}\n\n// ─── HTTP request proxy ───\n\nexport async function handleHttpRequest(\n opts: HttpProxyOptions,\n frame: RequestFrame,\n): Promise<void> {\n const mappedPath = mapPath(frame.path);\n const url = new URL(mappedPath, opts.gatewayBaseUrl);\n const startedAtMs = Date.now();\n\n // 代理到本地 gateway 时,替换外部鉴权头为本地 gateway token/password。\n const localHeaders: Record<string, string> = {};\n for (const [k, v] of Object.entries(frame.headers ?? {})) {\n const lower = k.toLowerCase();\n if (lower !== \"authorization\" && lower !== \"x-openclaw-password\") {\n localHeaders[k] = v;\n }\n }\n localHeaders[RELAY_INTERNAL_HTTP_HEADER] = \"1\";\n\n const authAttempts = buildLocalGatewayAuthAttempts(opts, localHeaders);\n opts.logger.info(\n `TunnelProxy: HTTP id=${frame.id} ${frame.method} ${frame.path} → ${url.toString()}${summarizeRequestHeaders(frame.headers)}, authAttempts=${authAttempts.map((a) => a.label).join(\" -> \")}, body=${previewText(frame.body)}`,\n );\n\n try {\n for (let attemptIndex = 0; attemptIndex < authAttempts.length; attemptIndex++) {\n const attempt = authAttempts[attemptIndex];\n opts.logger.info(\n `TunnelProxy: HTTP id=${frame.id} attempt ${attemptIndex + 1}/${authAttempts.length} auth=${attempt.label}`,\n );\n const res = await fetch(url.toString(), {\n method: frame.method,\n headers: attempt.headers,\n body:\n frame.method !== \"GET\" && frame.method !== \"HEAD\"\n ? frame.body\n : undefined,\n });\n\n const hasFallback = attemptIndex < authAttempts.length - 1;\n if (res.status === 401 && hasFallback) {\n const body = await res.text();\n opts.logger.warn(\n `TunnelProxy: HTTP id=${frame.id} local gateway auth via ${attempt.label} returned 401 after ${Date.now() - startedAtMs}ms, retrying next credential${body ? `, body=${previewText(body)}` : \"\"}`,\n );\n continue;\n }\n\n await sendHttpResponse(opts, {\n frameId: frame.id,\n method: frame.method,\n path: mappedPath,\n authLabel: attempt.label,\n startedAtMs,\n res,\n });\n return;\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n opts.logger.error(\n `TunnelProxy: HTTP id=${frame.id} ${frame.method} ${mappedPath} failed after ${Date.now() - startedAtMs}ms: ${message}`,\n );\n opts.client.send({\n type: \"proxy_error\",\n id: frame.id,\n status: 502,\n message: `gateway unreachable: ${message}`,\n });\n }\n}\n\n// ─── Response helpers ───\n\nasync function sendHttpResponse(\n opts: HttpProxyOptions,\n params: {\n frameId: string;\n method: string;\n path: string;\n authLabel: string;\n startedAtMs: number;\n res: Response;\n },\n): Promise<void> {\n const { frameId, method, path, authLabel, startedAtMs, res } = params;\n const contentType = res.headers.get(\"content-type\") ?? \"\";\n const isStreaming = contentType.includes(\"text/event-stream\");\n const elapsedMs = Date.now() - startedAtMs;\n\n opts.logger.info(\n `TunnelProxy: HTTP id=${frameId} ${method} ${path} <= ${res.status} (${elapsedMs}ms, auth=${authLabel}, content-type=${contentType}, streaming=${isStreaming})`,\n );\n\n if (isStreaming && res.body) {\n await streamResponse(opts, frameId, res, startedAtMs);\n return;\n }\n\n const body = await res.text();\n opts.logger.info(\n `TunnelProxy: HTTP id=${frameId} response body=${previewText(body)}`,\n );\n const headers: Record<string, string> = {};\n res.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n opts.client.send({\n type: \"proxy_response\",\n id: frameId,\n status: res.status,\n headers,\n body,\n });\n}\n\nasync function streamResponse(\n opts: HttpProxyOptions,\n requestId: string,\n res: Response,\n startedAtMs: number,\n): Promise<void> {\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let chunkCount = 0;\n\n opts.logger.info(`TunnelProxy: stream start id=${requestId}`);\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n chunkCount++;\n const chunk = decoder.decode(value, { stream: true });\n opts.logger.info(\n `TunnelProxy: stream delta id=${requestId} chunk#${chunkCount} (${chunk.length} chars)`,\n );\n opts.client.send({\n type: \"stream\",\n id: requestId,\n state: \"delta\",\n data: chunk,\n });\n }\n\n opts.logger.info(\n `TunnelProxy: stream end id=${requestId}, total chunks=${chunkCount}, totalElapsedMs=${Date.now() - startedAtMs}`,\n );\n opts.client.send({\n type: \"stream\",\n id: requestId,\n state: \"end\",\n data: \"\",\n });\n } catch (err) {\n opts.logger.error(\n `TunnelProxy: stream error id=${requestId} after ${chunkCount} chunks and ${Date.now() - startedAtMs}ms: ${err instanceof Error ? err.message : String(err)}`,\n );\n opts.client.send({\n type: \"proxy_error\",\n id: requestId,\n status: 502,\n message: `stream error: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n}\n","import WebSocket from \"ws\";\nimport type { RelayClient } from \"./relay-client.js\";\nimport type { WsOpenFrame, WsDataFrame, WsCloseFrame } from \"./types.js\";\nimport { mapPath } from \"./http-proxy.js\";\n\nexport interface WsProxyOptions {\n gatewayBaseUrl: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport class WsProxy {\n /** 活跃的 WebSocket 代理连接,按帧 id 索引 */\n private connections = new Map<string, WebSocket>();\n\n constructor(private readonly opts: WsProxyOptions) {}\n\n get activeCount(): number {\n return this.connections.size;\n }\n\n cleanup(): void {\n for (const [id, ws] of this.connections) {\n this.opts.logger.info(`WsProxy: closing WS id=${id}`);\n try {\n ws.close();\n } catch {\n // ignore\n }\n }\n this.connections.clear();\n }\n\n handleWsOpen(frame: WsOpenFrame): void {\n const wsUrl =\n this.opts.gatewayBaseUrl.replace(/^http/, \"ws\") +\n mapPath(frame.path);\n this.opts.logger.info(\n `TunnelProxy: WS open id=${frame.id}, path=${frame.path} → ${wsUrl}`,\n );\n\n try {\n const ws = new WebSocket(wsUrl, {\n headers: frame.headers,\n });\n\n ws.on(\"open\", () => {\n this.connections.set(frame.id, ws);\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} connected to gateway, active=${this.connections.size}`,\n );\n this.opts.client.send({\n type: \"ws_opened\",\n id: frame.id,\n });\n });\n\n ws.on(\"message\", (data: WebSocket.RawData) => {\n const text =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString()\n : String(data);\n\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} ← gateway data (${text.length} chars): ${text.substring(0, 200)}`,\n );\n this.opts.client.send({\n type: \"ws_data\",\n id: frame.id,\n data: text,\n });\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n this.connections.delete(frame.id);\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} closed by gateway (code=${code}, reason=${reason.toString()}), active=${this.connections.size}`,\n );\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code,\n reason: reason.toString(),\n });\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} error: ${err.message}, active=${this.connections.size}`,\n );\n this.connections.delete(frame.id);\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code: 1011,\n reason: err.message,\n });\n });\n } catch (err) {\n this.opts.logger.error(\n `TunnelProxy: WS id=${frame.id} failed to connect: ${err instanceof Error ? err.message : String(err)}`,\n );\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code: 1011,\n reason: `failed to connect: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n handleWsData(frame: WsDataFrame): void {\n const ws = this.connections.get(frame.id);\n if (ws?.readyState === WebSocket.OPEN) {\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} → gateway data (${frame.data.length} chars): ${frame.data.substring(0, 200)}`,\n );\n ws.send(frame.data);\n } else {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} data dropped, ws not open (exists=${!!ws}, readyState=${ws?.readyState ?? \"N/A\"})`,\n );\n }\n }\n\n handleWsClose(frame: WsCloseFrame): void {\n const ws = this.connections.get(frame.id);\n if (ws) {\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} close requested by relay (code=${frame.code ?? 1000}, reason=${frame.reason ?? \"\"})`,\n );\n this.connections.delete(frame.id);\n try {\n ws.close(frame.code ?? 1000, frame.reason ?? \"\");\n } catch {\n // ignore\n }\n } else {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} close requested but connection not found`,\n );\n }\n }\n}\n","import type { IncomingMessage } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\n\nexport type GatewayHandler = Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1];\n\nexport type GatewayMethodRegistrar = (\n method: string,\n handler: GatewayHandler,\n) => void;\n\nexport function readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString()));\n req.on(\"error\", reject);\n });\n}\n\nexport function trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport type { CronServiceLike } from \"../light-rules/evaluator-job.js\";\nimport {\n type NotificationIngestResult,\n NotificationStorage,\n} from \"../notification/storage.js\";\nimport { RELAY_INTERNAL_HTTP_HEADER } from \"../tunnel/http-proxy.js\";\nimport type { RelayTunnelService } from \"../tunnel/service.js\";\nimport type {\n HttpNotificationBody,\n NotificationPushParams,\n RawNotification,\n} from \"../types.js\";\nimport {\n readBody,\n type GatewayMethodRegistrar,\n} from \"./shared.js\";\n\nfunction createEmptyIngestResult(): NotificationIngestResult {\n return {\n received: 0,\n ingested: 0,\n dedupedById: 0,\n dedupedByContent: 0,\n invalid: 0,\n inserted: [],\n };\n}\n\nfunction isRelayInternalHttpRequest(req: IncomingMessage): boolean {\n const header = req.headers?.[RELAY_INTERNAL_HTTP_HEADER];\n if (Array.isArray(header)) {\n return header.includes(\"1\");\n }\n return header === \"1\";\n}\n\n/**\n * 将 ingest 内部结果转成对外响应:丢弃 `inserted` 字段,\n * 它只供插件内部下游链路(如 light-rule agent 评估)使用,\n * 不应该出现在 gateway / HTTP 响应里。\n */\nfunction toIngestResponse(\n result: NotificationIngestResult,\n): Omit<NotificationIngestResult, \"inserted\"> {\n const { inserted: _inserted, ...rest } = result;\n return rest;\n}\n\ninterface NotificationInterfaceDeps {\n api: OpenClawPluginApi;\n logger: Logger;\n getStorage: () => NotificationStorage | null;\n filterNotifications: (items: RawNotification[]) => RawNotification[];\n registerGatewayMethod: GatewayMethodRegistrar;\n tunnelService?: RelayTunnelService | null;\n /**\n * 通知落盘后的钩子,用于触发灯效规则评估。\n * 仅 gateway 路径(notifications.push)触发;HTTP 路径因无 context 而跳过。\n */\n onAfterIngest?: (insertedCount: number, cron: CronServiceLike) => void;\n}\n\nexport function registerNotificationInterfaces(\n deps: NotificationInterfaceDeps,\n): void {\n const {\n api,\n logger,\n getStorage,\n filterNotifications,\n registerGatewayMethod,\n tunnelService,\n onAfterIngest,\n } = deps;\n\n registerGatewayMethod(\n \"notifications.push\",\n async ({ params, respond, context }) => {\n const storage = getStorage();\n if (!storage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Storage service not ready\",\n });\n return;\n }\n\n const { items } = params as unknown as NotificationPushParams;\n if (!Array.isArray(items)) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"items must be an array\",\n });\n return;\n }\n\n const filtered = filterNotifications(items);\n const result = filtered.length\n ? await storage.ingest(filtered)\n : createEmptyIngestResult();\n\n // 主响应先返回,不阻塞灯效评估\n respond(true, toIngestResponse(result));\n\n // 落盘后异步 force-trigger 灯效评估 job(fire-and-forget)\n if (result.inserted.length > 0 && onAfterIngest && context?.cron) {\n void Promise.resolve()\n .then(() => onAfterIngest(result.inserted.length, context.cron as CronServiceLike))\n .catch((err) => logger.warn(`onAfterIngest failed: ${err?.message ?? err}`));\n }\n },\n );\n\n api.registerHttpRoute({\n path: \"/notifications\",\n auth: \"gateway\",\n async handler(req: IncomingMessage, res: ServerResponse) {\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Method Not Allowed\" }));\n return;\n }\n\n if (!isRelayInternalHttpRequest(req)) {\n await tunnelService?.deactivateForExternalTunnel(\"POST /notifications\");\n }\n\n const storage = getStorage();\n if (!storage) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Service Not Ready\" }));\n return;\n }\n\n let body: HttpNotificationBody;\n try {\n const raw = await readBody(req);\n body = JSON.parse(raw);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Invalid JSON\" }));\n return;\n }\n\n if (!Array.isArray(body.notifications)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"notifications must be an array\",\n }),\n );\n return;\n }\n\n const filtered = filterNotifications(body.notifications);\n const result = filtered.length\n ? await storage.ingest(filtered)\n : createEmptyIngestResult();\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, ...toIngestResponse(result) }));\n },\n });\n\n logger.info(\"Gateway 通知方法已注册: notifications.push\");\n logger.info(\"HTTP 通知端点已注册: POST /notifications\");\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport {\n RecordingStorage,\n canStartTranscription,\n extractSourceTextListFromDocument,\n extractTranscriptTitleFromDocument,\n handleRecordingSync,\n initializeAsr,\n triggerTranscription,\n type RecordingIndexEntry,\n type RecordingStatusEvent,\n validateAsrConfig,\n} from \"../recording/index.js\";\nimport { RELAY_INTERNAL_HTTP_HEADER } from \"../tunnel/http-proxy.js\";\nimport type { RelayTunnelService } from \"../tunnel/service.js\";\nimport type {\n HttpRecordingBody,\n RecordingAsrInitParams,\n RecordingDetail,\n RecordingListItem,\n RecordingListParams,\n RecordingRenameParams,\n RecordingRetranscribeParams,\n RecordingStatusParams,\n RecordingSyncParams,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport {\n readBody,\n trimToUndefined,\n type GatewayMethodRegistrar,\n} from \"./shared.js\";\n\nconst RECORDING_TRANSFER_STATUSES = new Set<RecordingTransferStatus>([\n \"receiving_failed\",\n \"receiving\",\n \"pending_oss_upload\",\n \"uploading_oss\",\n \"oss_uploaded\",\n \"syncing_openclaw\",\n \"synced\",\n \"transcribing\",\n \"transcribe_failed\",\n \"transcribed\",\n]);\n\nfunction isRecordingTransferStatus(\n value: string,\n): value is RecordingTransferStatus {\n return RECORDING_TRANSFER_STATUSES.has(value as RecordingTransferStatus);\n}\n\nfunction buildRecordingListItem(entry: RecordingIndexEntry): RecordingListItem {\n return {\n recordingId: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n created_at: entry.metadata.created_at,\n transfer_status: entry.status,\n marker_count: entry.metadata.markers?.length ?? 0,\n has_audio: !!entry.audioFile,\n has_srt: !!entry.srtFile,\n has_transcript: !!entry.transcriptFile,\n audioFile: entry.audioFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n updatedAt: entry.updatedAt,\n };\n}\n\nfunction isRelayInternalHttpRequest(req: IncomingMessage): boolean {\n const header = req.headers?.[RELAY_INTERNAL_HTTP_HEADER];\n if (Array.isArray(header)) {\n return header.includes(\"1\");\n }\n return header === \"1\";\n}\n\nfunction buildRecordingDetail(\n entry: RecordingIndexEntry,\n extras?: Partial<Pick<\n RecordingDetail,\n \"summary\" | \"title\" | \"transcript\" | \"transcriptData\"\n >>,\n): RecordingDetail {\n const title = entry.title?.trim()\n || extras?.title?.trim()\n || entry.metadata.name?.trim()\n || entry.id;\n\n return {\n recordingId: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n created_at: entry.metadata.created_at,\n location: entry.metadata.location,\n oss_audio_url: entry.metadata.oss_audio_url,\n oss_srt_url: entry.metadata.oss_srt_url,\n markers: entry.metadata.markers ?? [],\n transfer_status: entry.status,\n audioFile: entry.audioFile,\n srtFile: entry.srtFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n summaryFile: entry.summaryFile,\n title,\n summary: extras?.summary,\n transcript: extras?.transcript,\n transcriptData: extras?.transcriptData,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n };\n}\n\ninterface RecordingInterfaceDeps {\n api: OpenClawPluginApi;\n logger: Logger;\n asrDataDir: string;\n getRecordingStorage: () => RecordingStorage | null;\n notifyRecordingStatus: (event: RecordingStatusEvent) => void;\n registerGatewayMethod: GatewayMethodRegistrar;\n shouldBroadcastStatusOnHttp: () => boolean;\n tunnelService?: RelayTunnelService | null;\n}\n\nexport function registerRecordingInterfaces(\n deps: RecordingInterfaceDeps,\n): void {\n const {\n api,\n logger,\n asrDataDir,\n getRecordingStorage,\n notifyRecordingStatus,\n registerGatewayMethod,\n shouldBroadcastStatusOnHttp,\n tunnelService,\n } = deps;\n\n registerGatewayMethod(\"recordings.sync\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const {\n recordingId: rawRecordingId,\n recording,\n asr,\n } = params as unknown as RecordingSyncParams;\n const recordingId = trimToUndefined(rawRecordingId);\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n if (!recording || !recording.oss_audio_url || !recording.created_at) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recording with oss_audio_url and created_at is required\",\n });\n return;\n }\n\n const asrError = asr ? validateAsrConfig(asr) : undefined;\n if (asrError) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: asrError,\n });\n return;\n }\n\n const result = await handleRecordingSync(\n recordingId,\n recording,\n recordingStorage,\n asr,\n logger,\n { notifyStatus: notifyRecordingStatus },\n );\n respond(\n result.ok,\n result,\n result.ok\n ? undefined\n : {\n code: \"SYNC_FAILED\",\n message: result.error ?? \"Unknown error\",\n },\n );\n });\n\n registerGatewayMethod(\"recordings.list\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const rawStatus = trimToUndefined(\n (params as RecordingListParams | undefined)?.status,\n );\n if (rawStatus && !isRecordingTransferStatus(rawStatus)) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: `invalid recording status: ${rawStatus}`,\n });\n return;\n }\n\n const status = rawStatus as RecordingTransferStatus | undefined;\n const entries = status\n ? recordingStorage.listByStatus(status)\n : recordingStorage.listAll();\n\n respond(true, {\n total: entries.length,\n recordings: entries.map(buildRecordingListItem),\n });\n });\n\n registerGatewayMethod(\"recordings.status\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId } = params as unknown as RecordingStatusParams;\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n respond(\n true,\n (() => {\n const transcriptDocument =\n recordingStorage.readTranscriptDocument(recordingId);\n\n return buildRecordingDetail(entry, {\n summary: recordingStorage.readSummary(recordingId),\n title: extractTranscriptTitleFromDocument(transcriptDocument),\n transcript: extractSourceTextListFromDocument(transcriptDocument),\n transcriptData: transcriptDocument,\n });\n })(),\n );\n });\n\n registerGatewayMethod(\"recordings.rename\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId: rawRecordingId, name: rawName } =\n params as unknown as RecordingRenameParams;\n const recordingId = trimToUndefined(rawRecordingId);\n const name = trimToUndefined(rawName);\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required\",\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n const updated = recordingStorage.rename(recordingId, name);\n respond(true, buildRecordingDetail(updated));\n });\n\n registerGatewayMethod(\"recordings.delete\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId, deleteRemote } = params as {\n recordingId: string;\n deleteRemote?: boolean;\n };\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n if (deleteRemote) {\n const deleted = recordingStorage.delete(recordingId);\n respond(\n deleted,\n { ok: deleted, recordingId, deletedRemote: true },\n deleted\n ? undefined\n : {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n },\n );\n return;\n }\n\n const deleted = recordingStorage.delete(recordingId, {\n localOnly: true,\n });\n respond(\n deleted,\n { ok: deleted, recordingId, deletedRemote: false },\n deleted\n ? undefined\n : {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n },\n );\n });\n\n registerGatewayMethod(\n \"recordings.retranscribe\",\n async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId, asr } =\n params as unknown as RecordingRetranscribeParams;\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n const asrError = validateAsrConfig(asr);\n if (asrError) {\n respond(false, null, {\n code: \"ASR_NOT_CONFIGURED\",\n message: asrError,\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n if (!canStartTranscription(entry.status)) {\n respond(false, null, {\n code: \"INVALID_STATE\",\n message: `Recording status does not allow retranscribe: ${entry.status}`,\n });\n return;\n }\n\n triggerTranscription(recordingId, recordingStorage, asr, logger, {\n notifyStatus: notifyRecordingStatus,\n }).catch((err) => {\n logger.error(\n `[recordings.retranscribe] 重试转写失败: ${recordingId}, ${err?.message ?? err}`,\n );\n });\n\n respond(true, { ok: true, recordingId, message: \"转写已重新触发\" });\n },\n );\n\n registerGatewayMethod(\"recordings.asr.init\", async ({ params, respond }) => {\n const { asr } = params as unknown as RecordingAsrInitParams;\n const asrError = validateAsrConfig(asr);\n if (asrError) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: asrError,\n });\n return;\n }\n\n const result = await initializeAsr(asr, asrDataDir, logger);\n respond(\n result.ok,\n result,\n result.ok\n ? undefined\n : {\n code: \"ASR_INIT_FAILED\",\n message: result.error ?? \"ASR init failed\",\n },\n );\n });\n\n api.registerHttpRoute({\n path: \"/recordings\",\n auth: \"gateway\",\n async handler(req: IncomingMessage, res: ServerResponse) {\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Method Not Allowed\" }));\n return;\n }\n\n if (!isRelayInternalHttpRequest(req)) {\n await tunnelService?.deactivateForExternalTunnel(\"POST /recordings\");\n }\n\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Service Not Ready\" }));\n return;\n }\n\n let body: HttpRecordingBody;\n try {\n const raw = await readBody(req);\n body = JSON.parse(raw);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Invalid JSON\" }));\n return;\n }\n\n const recordingId = trimToUndefined(body.recordingId);\n if (!recordingId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"recordingId is required\",\n }),\n );\n return;\n }\n\n if (!body.recording || !body.recording.oss_audio_url) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"recording with oss_audio_url is required\",\n }),\n );\n return;\n }\n\n const asrError = body.asr ? validateAsrConfig(body.asr) : undefined;\n if (asrError) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: asrError }));\n return;\n }\n\n const result = await handleRecordingSync(\n recordingId,\n body.recording,\n recordingStorage,\n body.asr,\n logger,\n shouldBroadcastStatusOnHttp()\n ? { notifyStatus: notifyRecordingStatus }\n : undefined,\n );\n\n res.writeHead(result.ok ? 200 : 500, {\n \"Content-Type\": \"application/json\",\n });\n res.end(JSON.stringify(result));\n },\n } as any);\n\n logger.info(\n \"Gateway 录音方法已注册: recordings.sync / recordings.list / recordings.status / recordings.rename / recordings.delete / recordings.retranscribe / recordings.asr.init\",\n );\n logger.info(\"HTTP 录音端点已注册: POST /recordings\");\n}\n","const PLUGIN_CLI_COMMANDS = new Set([\"ntf\", \"phone-notifications\"]);\nconst GLOBAL_OPTIONS_WITH_VALUE = [\n \"--container\",\n \"--log-level\",\n \"--profile\",\n] as const;\nconst GLOBAL_OPTIONS_WITH_VALUE_SET = new Set<string>(GLOBAL_OPTIONS_WITH_VALUE);\n\nfunction resolvePrimaryCommand(argv = process.argv): string | undefined {\n const args = argv.slice(2);\n\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (!arg || arg === \"--\") {\n return undefined;\n }\n\n if (GLOBAL_OPTIONS_WITH_VALUE_SET.has(arg)) {\n index++;\n continue;\n }\n\n if (\n GLOBAL_OPTIONS_WITH_VALUE.some((option) => arg.startsWith(`${option}=`))\n ) {\n continue;\n }\n\n if (arg.startsWith(\"-\")) {\n continue;\n }\n\n return arg;\n }\n\n return undefined;\n}\n\nexport function isPluginCliInvocation(argv = process.argv): boolean {\n const primaryCommand = resolvePrimaryCommand(argv);\n return primaryCommand ? PLUGIN_CLI_COMMANDS.has(primaryCommand) : false;\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","import_node_fs","import_node_path","path","import_node_fs","import_node_path","formatBytes","output","path","import_node_fs","import_node_path","import_promises","import_node_stream","import_node_os","getWhisperLocalStatus","downloadModel","resolveModelsDir","transcribeWithWhisperLocal","normalizeOptionalText","sleep","normalizeOptionalInteger","import_node_fs","import_node_path","exports","module","exports","module","output","exports","module","exports","module","data","exports","module","exports","module","Receiver","exports","module","Sender","exports","module","exports","module","exports","module","createHash","Readable","URL","Receiver","Sender","WebSocket","key","exports","module","WebSocket","createWebSocketStream","err","exports","module","protocol","exports","module","createHash","WebSocket","WebSocketServer","import_node_fs","import_node_fs","import_node_path","formatDate","import_node_fs","import_node_path","import_node_fs","import_node_path","tasksDir","import_node_path","import_node_fs","path","import_node_fs","import_node_path","import_node_fs","import_node_path","tasksDir","readMeta","writeMeta","checkpointPath","import_node_fs","import_node_path","resolveConfigPath","import_node_fs","import_node_path","import_node_fs","import_node_path","import_node_fs","import_node_fs","isObject","isObject","import_node_fs","isObject","import_node_fs","import_node_path","STATUS_REL_PATH","isObject","import_node_readline","import_node_fs","import_node_fs","import_node_fs","import_node_path","path","import_node_fs","import_node_crypto","import_node_path","import_node_fs","import_node_path","import_node_fs","import_node_path","import_promises","import_node_fs","import_node_path","import_node_fs","import_node_path","import_sender","WebSocket","import_node_crypto","previewText","import_node_crypto","import_node_fs","import_node_path","crypto","fs","path","previewText","path","previewText","trimToUndefined","trimToUndefined","isRelayInternalHttpRequest","trimToUndefined","deleted"]}
1
+ {"version":3,"sources":["../src/host.ts","../src/auth/credentials.ts","../src/env.ts","../src/recording/transcript-document.ts","../src/recording/whisper-local.ts","../src/recording/asr.ts","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js","../src/index.ts","../src/logger.ts","../src/version.ts","../src/notification/storage.ts","../src/light/repeat.ts","../src/cli/helpers.ts","../src/light/validators.ts","../src/light-rules/storage.ts","../src/monitor/fetch-gen.ts","../src/light-rules/gateway.ts","../src/light-rules/evaluator-job.ts","../src/light-rules/migration.ts","../src/light-rules/registry.ts","../src/plugin/auto-update.ts","../src/update/channel.ts","../src/update/checker.ts","../src/update/executor.ts","../src/update/index.ts","../src/plugin/cli.ts","../src/cli/auth.ts","../src/cli/ntf-search.ts","../src/cli/ntf-stats.ts","../src/cli/ntf-sync.ts","../src/cli/ntf-monitor.ts","../src/cli/light-send.ts","../src/light/sender.ts","../src/light/protocol.ts","../src/cli/light-setup-tools.ts","../src/cli/tunnel-status.ts","../src/cli/ntf-storage-path.ts","../src/cli/log-search.ts","../src/cli/env.ts","../src/cli/doctor.ts","../src/cli/doctor/check-dangerous-flags.ts","../src/cli/doctor/check-trusted-proxy.ts","../src/cli/doctor/check-state-dir-perms.ts","../src/cli/doctor/check-tool-policy.ts","../src/cli/doctor/check-credentials.ts","../src/cli/doctor/check-tunnel.ts","../src/cli/doctor/check-node-version.ts","../src/cli/doctor/check-plugin-version.ts","../src/cli/doctor/checkers.ts","../src/cli/rec-list.ts","../src/cli/rec-status.ts","../src/cli/rec-storage-path.ts","../src/cli/rec-setup.ts","../src/cli/update.ts","../src/cli/index.ts","../src/plugin/light-control.ts","../src/plugin/lifecycle.ts","../src/notification/app-name-map.ts","../src/recording/storage.ts","../src/recording/state-machine.ts","../src/recording/index.ts","../src/recording/downloader.ts","../src/recording/handler.ts","../src/tunnel/service.ts","../src/tunnel/relay-client.ts","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs","../src/tunnel/proxy.ts","../src/tunnel/utils.ts","../src/tunnel/device-identity.ts","../src/tunnel/http-proxy.ts","../src/tunnel/ws-proxy.ts","../src/plugin/shared.ts","../src/plugin/notifications.ts","../src/plugin/recordings.ts","../src/plugin/runtime-mode.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\nexport type HostKind = \"openclaw\" | \"qclaw\";\n\ninterface QClawMeta {\n stateDir?: string;\n configPath?: string;\n}\n\nfunction trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction homeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"/tmp\";\n}\n\nfunction expandUserPath(value: string | undefined): string | undefined {\n if (!value) {\n return undefined;\n }\n if (value === \"~\") {\n return homeDir();\n }\n if (value.startsWith(\"~/\")) {\n return join(homeDir(), value.slice(2));\n }\n return value;\n}\n\nfunction detectHostKindFromPath(value: string | undefined): HostKind | undefined {\n if (!value) {\n return undefined;\n }\n const normalized = value.replace(/\\\\/g, \"/\").toLowerCase();\n if (\n normalized.endsWith(\"/.qclaw\") ||\n normalized.includes(\"/.qclaw/\") ||\n normalized.endsWith(\"/.qclow\") ||\n normalized.includes(\"/.qclow/\")\n ) {\n return \"qclaw\";\n }\n if (\n normalized.endsWith(\"/.openclaw\") ||\n normalized.includes(\"/.openclaw/\")\n ) {\n return \"openclaw\";\n }\n return undefined;\n}\n\nfunction candidateMetaPaths(): string[] {\n const home = homeDir();\n return [\n join(home, \".qclaw\", \"qclaw.json\"),\n join(home, \".qclow\", \"qclaw.json\"),\n ];\n}\n\nfunction loadQClawMeta(): QClawMeta | undefined {\n for (const metaPath of candidateMetaPaths()) {\n if (!existsSync(metaPath)) {\n continue;\n }\n try {\n const parsed = JSON.parse(readFileSync(metaPath, \"utf-8\")) as QClawMeta;\n return {\n stateDir: expandUserPath(trimToUndefined(parsed?.stateDir)),\n configPath: expandUserPath(trimToUndefined(parsed?.configPath)),\n };\n } catch {\n // ignore invalid metadata and keep trying\n }\n }\n return undefined;\n}\n\nfunction resolveStateDirFromEnv(): string | undefined {\n return expandUserPath(\n trimToUndefined(process.env.OPENCLAW_STATE_DIR) ??\n trimToUndefined(process.env.QCLAW_STATE_DIR) ??\n trimToUndefined(process.env.OPENCLAW_ROOT) ??\n trimToUndefined(process.env.OPENCLAW_HOME) ??\n trimToUndefined(process.env.QCLAW_HOME),\n );\n}\n\nfunction resolveConfigPathFromEnv(): string | undefined {\n return expandUserPath(\n trimToUndefined(process.env.OPENCLAW_CONFIG_PATH) ??\n trimToUndefined(process.env.QCLAW_CONFIG_PATH),\n );\n}\n\nfunction hasOpenClawMarkers(): boolean {\n const baseDir = join(homeDir(), \".openclaw\");\n return [\n join(baseDir, \"openclaw.json\"),\n join(baseDir, \"credentials.json\"),\n join(baseDir, \"extensions\"),\n ].some((candidate) => existsSync(candidate));\n}\n\nexport function detectHostKind(): HostKind {\n if (\n trimToUndefined(process.env.QCLAW_STATE_DIR) ||\n trimToUndefined(process.env.QCLAW_CONFIG_PATH) ||\n trimToUndefined(process.env.QCLAW_HOME)\n ) {\n return \"qclaw\";\n }\n\n const pathHintKind =\n detectHostKindFromPath(resolveStateDirFromEnv()) ??\n detectHostKindFromPath(resolveConfigPathFromEnv());\n if (pathHintKind) {\n return pathHintKind;\n }\n\n if (hasOpenClawMarkers()) {\n return \"openclaw\";\n }\n\n if (loadQClawMeta()) {\n return \"qclaw\";\n }\n\n return \"openclaw\";\n}\n\nexport function resolveStateDir(): string {\n const envDir = resolveStateDirFromEnv();\n if (envDir) {\n return envDir;\n }\n\n if (hasOpenClawMarkers()) {\n return join(homeDir(), \".openclaw\");\n }\n\n const meta = loadQClawMeta();\n if (meta?.stateDir) {\n return meta.stateDir;\n }\n if (meta?.configPath) {\n return dirname(meta.configPath);\n }\n\n return join(homeDir(), \".openclaw\");\n}\n\nexport function resolveConfigPath(stateDir = resolveStateDir()): string {\n const envConfigPath = resolveConfigPathFromEnv();\n if (envConfigPath) {\n return envConfigPath;\n }\n\n const meta = loadQClawMeta();\n if (\n meta?.configPath &&\n (!meta.stateDir || !stateDir || meta.stateDir === stateDir)\n ) {\n return meta.configPath;\n }\n\n return join(stateDir, \"openclaw.json\");\n}\n\nexport function resolveStateFile(filename: string): string {\n return join(resolveStateDir(), filename);\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n watch,\n} from \"node:fs\";\nimport { dirname, basename } from \"node:path\";\nimport { resolveStateFile } from \"../host.js\";\n\ninterface Credentials {\n /**\n * 推荐:API Key 明文(例如 ock_xxx)\n */\n apiKey?: string;\n /**\n * 兼容旧字段:历史上这里存的是 token;现在等价于 apiKey\n */\n token?: string;\n /**\n * 当前环境(development / production),由 ntf env switch 写入\n */\n env?: string;\n}\n\nexport function credentialsPath(): string {\n return resolveStateFile(\"credentials.json\");\n}\n\nexport function readCredentials(): Credentials {\n const path = credentialsPath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nexport function writeCredentials(creds: Credentials): void {\n const path = credentialsPath();\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 });\n writeFileSync(path, JSON.stringify(creds, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function loadApiKey(): string | undefined {\n const creds = readCredentials();\n return creds.apiKey ?? creds.token;\n}\n\nexport function requireApiKey(): string {\n const apiKey = loadApiKey();\n if (!apiKey) {\n throw new Error(\n `API Key 未设置,请先写入 ${credentialsPath()},或通过宿主 CLI 执行 ntf auth set-api-key <apiKey>`,\n );\n }\n return apiKey;\n}\n\n// ---- Backward-compatible exports (旧代码仍可编译;语义等价于 apiKey) ----\nexport function loadToken(): string | undefined {\n return loadApiKey();\n}\n\nexport function requireToken(): string {\n return requireApiKey();\n}\n\n/** 监听 credentials 文件变化(如 set-token 后)触发 callback;返回取消监听的函数 */\nexport function watchCredentials(onChange: () => void): () => void {\n const path = credentialsPath();\n const dir = dirname(path);\n const filename = basename(path);\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n const delayMs = 200;\n\n const listener = (_event: string, changedName: string | null) => {\n if (!changedName || (changedName !== filename && !changedName.endsWith(filename))) return;\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n onChange();\n }, delayMs);\n };\n\n let watcher: ReturnType<typeof watch> | null = null;\n try {\n watcher = watch(dir, { persistent: false }, listener);\n } catch {\n // 目录可能不存在\n }\n\n return () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n watcher?.close();\n };\n}\n","import { readCredentials, writeCredentials } from \"./auth/credentials.js\";\n\nexport type EnvName = \"development\" | \"production\";\n\ninterface EnvUrls {\n lightApiUrl: string;\n appNameMapUrl: string;\n relayTunnelUrl: string;\n modelProxyLongRecordingSubmitTaskUrl: string;\n modelProxyLongRecordingQueryTaskResultBaseUrl: string;\n}\n\nconst ENV_CONFIG: Record<EnvName, EnvUrls> = {\n development: {\n lightApiUrl:\n \"https://openclaw-service-dev.yoooclaw.com/api/message/tob/sendMessage\",\n relayTunnelUrl:\n \"wss://openclaw-service-dev.yoooclaw.com/message/messages/ws/plugin\",\n appNameMapUrl:\n \"https://openclaw-service-dev.yoooclaw.com/api/application-config/app-package/config-all\",\n modelProxyLongRecordingSubmitTaskUrl:\n \"https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/submit-task\",\n modelProxyLongRecordingQueryTaskResultBaseUrl:\n \"https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/query-task-result\",\n },\n production: {\n lightApiUrl:\n \"https://openclaw-service.yoootek.com/api/message/tob/sendMessage\",\n relayTunnelUrl:\n \"wss://openclaw-service.yoootek.com/message/messages/ws/plugin\",\n appNameMapUrl:\n \"https://openclaw-service.yoootek.com/api/application-config/app-package/config-all\",\n modelProxyLongRecordingSubmitTaskUrl:\n \"https://openclaw-service.yoootek.com/api/model-proxy/long-recording/submit-task\",\n modelProxyLongRecordingQueryTaskResultBaseUrl:\n \"https://openclaw-service.yoootek.com/api/model-proxy/long-recording/query-task-result\",\n },\n};\n\nconst VALID_ENVS: ReadonlySet<string> = new Set(Object.keys(ENV_CONFIG));\n\n/** 读取当前环境名称。优先级:OPENCLAW_ENV 环境变量 > credentials.json > 默认 production */\nexport function loadEnvName(): EnvName {\n const fromEnvVar = process.env.OPENCLAW_ENV?.trim();\n if (fromEnvVar && VALID_ENVS.has(fromEnvVar)) return fromEnvVar as EnvName;\n\n const { env } = readCredentials();\n if (env && VALID_ENVS.has(env)) return env as EnvName;\n\n return \"production\";\n}\n\n/** 持久化当前环境到 credentials.json */\nexport function saveEnvName(env: EnvName): void {\n if (!VALID_ENVS.has(env)) {\n throw new Error(\n `无效的环境名称: ${env},可选值: ${[...VALID_ENVS].join(\", \")}`,\n );\n }\n writeCredentials({ ...readCredentials(), env });\n}\n\n/** 获取当前环境的 URL 配置 */\nexport function getEnvUrls(env?: EnvName): EnvUrls {\n return ENV_CONFIG[env ?? loadEnvName()];\n}\n\n/** 获取所有可用环境名称 */\nexport function getAvailableEnvs(): EnvName[] {\n return Object.keys(ENV_CONFIG) as EnvName[];\n}\n","export const TRANSCRIPT_DOCUMENT_SCHEMA_VERSION = 1;\n\nexport interface TranscriptDocumentSource {\n provider: string;\n taskId?: string;\n requestId?: string;\n status?: string;\n}\n\nexport interface TranscriptDocumentSegment {\n text: string;\n startMs?: number;\n endMs?: number;\n speakerId?: number;\n}\n\nexport interface TranscriptDocumentContentItem {\n content: string;\n speakerId?: number;\n startTime?: number;\n endTime?: number;\n}\n\nexport interface TranscriptDocumentNormalized {\n title?: string;\n category?: string;\n summary?: string;\n text: string;\n segments: TranscriptDocumentSegment[];\n}\n\nexport interface TranscriptDocument {\n schemaVersion: number;\n recordingId: string;\n generatedAt: string;\n source: TranscriptDocumentSource;\n normalized: TranscriptDocumentNormalized;\n raw?: unknown;\n}\n\nexport function buildTranscriptDataFilename(recordingId: string): string {\n return `${recordingId}.json`;\n}\n\nexport function buildTranscriptDocument(params: {\n recordingId: string;\n generatedAt?: string;\n source: TranscriptDocumentSource;\n title?: string;\n category?: string;\n summary?: string;\n text?: string;\n segments?: TranscriptDocumentSegment[];\n raw?: unknown;\n}): TranscriptDocument {\n const segments = normalizeSegments(params.segments);\n const text = normalizeOptionalText(params.text) ?? joinSegmentsText(segments) ?? \"\";\n\n return {\n schemaVersion: TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n recordingId: params.recordingId,\n generatedAt: params.generatedAt ?? new Date().toISOString(),\n source: {\n provider: params.source.provider,\n taskId: normalizeOptionalText(params.source.taskId),\n requestId: normalizeOptionalText(params.source.requestId),\n status: normalizeOptionalText(params.source.status),\n },\n normalized: {\n title: normalizeOptionalText(params.title),\n category: normalizeOptionalText(params.category),\n summary: normalizeOptionalText(params.summary),\n text,\n segments,\n },\n raw: params.raw,\n };\n}\n\nexport function parseTranscriptDocument(\n value: string | unknown,\n): TranscriptDocument | undefined {\n const parsed = typeof value === \"string\"\n ? parseJson(value)\n : value;\n\n if (!parsed || typeof parsed !== \"object\") {\n return undefined;\n }\n\n const doc = parsed as Record<string, unknown>;\n const recordingId = normalizeOptionalText(doc.recordingId);\n const generatedAt = normalizeOptionalText(doc.generatedAt);\n const source = normalizeSource(doc.source);\n const normalized = normalizeDocumentBody(doc.normalized);\n\n if (!recordingId || !generatedAt || !source || !normalized) {\n return undefined;\n }\n\n return {\n schemaVersion:\n typeof doc.schemaVersion === \"number\"\n ? doc.schemaVersion\n : TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n recordingId,\n generatedAt,\n source,\n normalized,\n raw: doc.raw,\n };\n}\n\nexport function extractTranscriptTextFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizeOptionalText(doc.normalized.text)\n ?? joinSegmentsText(doc.normalized.segments);\n}\n\nexport function extractTranscriptSummaryFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizeOptionalText(doc.normalized.summary);\n}\n\nexport function extractTranscriptTitleFromDocument(\n doc: TranscriptDocument | undefined,\n): string | undefined {\n if (!doc) return undefined;\n return normalizeOptionalText(doc.normalized.title);\n}\n\nexport function extractSourceTextListFromDocument(\n doc: TranscriptDocument | undefined,\n): TranscriptDocumentContentItem[] | undefined {\n if (!doc) return undefined;\n\n const fromNormalized = doc.normalized.segments\n .map((segment) => ({\n content: segment.text,\n speakerId: segment.speakerId,\n startTime: segment.startMs,\n endTime: segment.endMs,\n }))\n .filter((segment) => normalizeOptionalText(segment.content));\n\n if (fromNormalized.length > 0) {\n return fromNormalized;\n }\n\n const rawList = extractRawSourceTextList(doc.raw);\n if (rawList.length > 0) {\n return rawList;\n }\n\n const normalizedText = normalizeOptionalText(doc.normalized.text);\n return normalizedText\n ? [{ content: normalizedText }]\n : undefined;\n}\n\nfunction parseJson(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeSource(value: unknown): TranscriptDocumentSource | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const source = value as Record<string, unknown>;\n const provider = normalizeOptionalText(source.provider);\n if (!provider) {\n return undefined;\n }\n\n return {\n provider,\n taskId: normalizeOptionalText(source.taskId),\n requestId: normalizeOptionalText(source.requestId),\n status: normalizeOptionalText(source.status),\n };\n}\n\nfunction normalizeDocumentBody(\n value: unknown,\n): TranscriptDocumentNormalized | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const normalized = value as Record<string, unknown>;\n const segments = normalizeSegments(normalized.segments);\n const text = normalizeOptionalText(normalized.text) ?? joinSegmentsText(segments);\n if (!text) {\n return undefined;\n }\n\n return {\n title: normalizeOptionalText(normalized.title),\n category: normalizeOptionalText(normalized.category),\n summary: normalizeOptionalText(normalized.summary),\n text,\n segments,\n };\n}\n\nfunction normalizeSegments(value: unknown): TranscriptDocumentSegment[] {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .map((item) => normalizeSegment(item))\n .filter((item): item is TranscriptDocumentSegment => !!item);\n}\n\nfunction normalizeSegment(value: unknown): TranscriptDocumentSegment | undefined {\n if (!value || typeof value !== \"object\") {\n return undefined;\n }\n\n const segment = value as Record<string, unknown>;\n const text = normalizeOptionalText(segment.text);\n if (!text) {\n return undefined;\n }\n\n return {\n text,\n startMs: normalizeOptionalNumber(segment.startMs),\n endMs: normalizeOptionalNumber(segment.endMs),\n speakerId: normalizeOptionalInteger(segment.speakerId),\n };\n}\n\nfunction joinSegmentsText(\n segments: TranscriptDocumentSegment[],\n): string | undefined {\n const parts = segments\n .map((segment) => normalizeOptionalText(segment.text))\n .filter((segment): segment is string => !!segment);\n\n if (parts.length === 0) {\n return undefined;\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nfunction extractRawSourceTextList(raw: unknown): TranscriptDocumentContentItem[] {\n if (!raw || typeof raw !== \"object\") {\n return [];\n }\n\n const recordResult = (raw as { recordResult?: unknown }).recordResult;\n if (!recordResult || typeof recordResult !== \"object\") {\n return [];\n }\n\n const sourceTextList = (recordResult as { sourceTextList?: unknown }).sourceTextList;\n if (!Array.isArray(sourceTextList)) {\n return [];\n }\n\n return sourceTextList\n .flatMap((item) => {\n if (!item || typeof item !== \"object\") {\n return [];\n }\n\n const value = item as Record<string, unknown>;\n const content = normalizeOptionalText(value.content);\n if (!content) {\n return [];\n }\n\n return [{\n content,\n speakerId: normalizeOptionalInteger(value.speakerId),\n startTime: normalizeOptionalNumber(value.startTime),\n endTime: normalizeOptionalNumber(value.endTime),\n }];\n });\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim()\n ? value.trim()\n : undefined;\n}\n\nfunction normalizeOptionalNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined;\n}\n\nfunction normalizeOptionalInteger(value: unknown): number | undefined {\n return Number.isInteger(value)\n ? Number(value)\n : undefined;\n}\n","/**\n * 本地 Whisper 转写模块(arc-long-recording §6.4)\n *\n * 插件内置 Whisper 推理能力:\n * 1. 自动检测运行环境与硬件配置(§6.4.1)\n * 2. 选择最优推理后端(§6.4.2)\n * 3. 根据可用内存自动选择模型规格(§6.4.3)\n * 4. 首次使用时下载模型文件(§6.4.5)\n * 5. 通过 whisper.cpp CLI 执行本地离线转写\n */\n\nimport { execSync, execFileSync, spawnSync, type SpawnSyncReturns } from \"node:child_process\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n statSync,\n createWriteStream,\n unlinkSync,\n copyFileSync,\n openSync,\n readSync,\n closeSync,\n} from \"node:fs\";\nimport { join, dirname, basename } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport { platform, arch, totalmem, cpus, freemem } from \"node:os\";\nimport type {\n WhisperLocalConfig,\n WhisperModelSize,\n WhisperModelSource,\n WhisperBackend,\n WhisperEnvironmentInfo,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { TranscriptionResult, TranscriptSegment } from \"./asr.js\";\n\n// ─── Constants ───\n\nconst WHISPER_MODELS_DIR = \"whisper-models\";\nconst WHISPER_BIN_DIR = \"whisper-bin\";\n\n/** Hugging Face GGML 模型下载 URL 模板(海外) */\nconst HF_MODEL_URL_TEMPLATE =\n \"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-{model}.bin\";\n\n/** 国内 ModelScope 镜像 URL 模板(lihuoo/whisper.cpp-asr-model-collection) */\nconst MODELSCOPE_MODEL_URL_TEMPLATE =\n \"https://modelscope.cn/models/lihuoo/whisper.cpp-asr-model-collection/resolve/master/{model}.bin\";\n\n/** 连通性探测超时(ms) */\nconst PROBE_TIMEOUT_MS = 5_000;\n\n/** 模型规格 → 文件名映射 */\nconst MODEL_FILENAMES: Record<WhisperModelSize, string> = {\n tiny: \"ggml-tiny.bin\",\n base: \"ggml-base.bin\",\n small: \"ggml-small.bin\",\n medium: \"ggml-medium.bin\",\n \"large-v3\": \"ggml-large-v3.bin\",\n};\n\n/** 模型规格 → 推理内存需求 GB(§6.4.3) */\nconst MODEL_MEMORY_REQUIREMENTS: Record<WhisperModelSize, number> = {\n tiny: 1,\n base: 1.5,\n small: 3,\n medium: 6,\n \"large-v3\": 11,\n};\n\n/** 模型规格 → 磁盘占用(字节,近似值) */\nconst MODEL_DISK_SIZES: Record<WhisperModelSize, number> = {\n tiny: 75 * 1024 * 1024,\n base: 140 * 1024 * 1024,\n small: 460 * 1024 * 1024,\n medium: 1500 * 1024 * 1024,\n \"large-v3\": 3000 * 1024 * 1024,\n};\n\n/** whisper.cpp JSON 输出格式 */\ninterface WhisperCppJsonOutput {\n transcription?: Array<{\n timestamps?: { from: string; to: string };\n offsets?: { from: number; to: number };\n text: string;\n }>;\n}\n\n// ─── Public API ───\n\n/**\n * 检测运行环境与硬件配置(§6.4.1)\n *\n * 检测操作系统、CPU 架构、GPU、可用内存,\n * 推荐最优推理后端与模型规格。\n */\nexport function detectEnvironment(logger: Logger): WhisperEnvironmentInfo {\n const os = platform() as \"darwin\" | \"linux\" | \"win32\";\n const cpuArch = arch() as \"arm64\" | \"x64\";\n const isAppleSilicon = os === \"darwin\" && cpuArch === \"arm64\";\n const hasCuda = detectCuda(logger);\n\n // 推荐后端(§6.4.2)\n let recommendedBackend: WhisperBackend;\n if (isAppleSilicon) {\n recommendedBackend = \"coreml\";\n } else if (hasCuda) {\n recommendedBackend = \"cuda\";\n } else {\n recommendedBackend = \"cpu\";\n }\n\n // 可用内存\n const availableMemoryGB = getAvailableMemoryGB(recommendedBackend, logger);\n const physicalCores = getPhysicalCoreCount();\n\n // 推荐模型\n const recommendedModel = selectModelByMemory(availableMemoryGB, isAppleSilicon);\n\n const info: WhisperEnvironmentInfo = {\n os,\n arch: cpuArch,\n isAppleSilicon,\n hasCuda,\n recommendedBackend,\n availableMemoryGB: Math.round(availableMemoryGB * 10) / 10,\n recommendedModel,\n physicalCores,\n };\n\n logger.info(\n `[whisper-local] 环境检测完成: os=${os}, arch=${cpuArch}, ` +\n `appleSilicon=${isAppleSilicon}, cuda=${hasCuda}, ` +\n `backend=${recommendedBackend}, memory=${info.availableMemoryGB}GB, ` +\n `model=${recommendedModel}, cores=${physicalCores}`,\n );\n\n return info;\n}\n\n/**\n * 根据可用内存自动选择模型规格(§6.4.3)\n *\n * 策略:优先匹配可用内存最大能承载的模型(向下取最近档位)。\n * Apple Silicon CoreML 后端内存效率更高,同档位需求降低 ~30%。\n */\nexport function selectModelByMemory(\n availableGB: number,\n isAppleSilicon: boolean = false,\n): WhisperModelSize {\n // Apple Silicon CoreML 内存效率提升约 30%\n const effectiveGB = isAppleSilicon ? availableGB / 0.7 : availableGB;\n\n if (effectiveGB >= 12) return \"large-v3\";\n if (effectiveGB >= 8) return \"medium\";\n if (effectiveGB >= 6) return \"small\";\n if (effectiveGB >= 4) return \"base\";\n return \"tiny\";\n}\n\n/**\n * 解析模型存储目录\n */\nexport function resolveModelsDir(dataDir: string): string {\n const dir = join(dataDir, WHISPER_MODELS_DIR);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * 解析 whisper.cpp 二进制目录\n */\nexport function resolveBinDir(dataDir: string): string {\n const dir = join(dataDir, WHISPER_BIN_DIR);\n mkdirSync(dir, { recursive: true });\n return dir;\n}\n\n/**\n * 检查模型文件是否已下载(§6.4.5)\n */\nexport function isModelDownloaded(modelsDir: string, modelSize: WhisperModelSize): boolean {\n const modelPath = join(modelsDir, MODEL_FILENAMES[modelSize]);\n if (!existsSync(modelPath)) return false;\n\n // 简单校验:文件大小至少为预期大小的 80%(防止下载不完整)\n try {\n const stat = statSync(modelPath);\n const expectedSize = MODEL_DISK_SIZES[modelSize];\n return stat.size >= expectedSize * 0.8;\n } catch {\n return false;\n }\n}\n\n/**\n * 下载 Whisper 模型文件(§6.4.5)\n *\n * 下载源选择策略:\n * - modelMirrorUrl 存在 → 使用自定义 URL\n * - modelSource = \"huggingface\" → 直接使用 Hugging Face\n * - modelSource = \"domestic\" → 直接使用国内镜像(ModelScope)\n * - modelSource = \"auto\"(默认)→ 先探测 Hugging Face 连通性(5s 超时),\n * 可达则用 HF,不可达则回退国内镜像\n */\nexport async function downloadModel(\n modelsDir: string,\n modelSize: WhisperModelSize,\n logger: Logger,\n modelSource?: WhisperModelSource,\n mirrorUrl?: string,\n): Promise<{ ok: boolean; modelPath: string; error?: string }> {\n const filename = MODEL_FILENAMES[modelSize];\n const modelPath = join(modelsDir, filename);\n\n // 已存在且完整 → 跳过\n if (isModelDownloaded(modelsDir, modelSize)) {\n logger.info(`[whisper-local] 模型已存在,跳过下载: ${filename}`);\n return { ok: true, modelPath };\n }\n\n // 解析下载 URL\n const url = await resolveModelUrl(modelSize, modelSource, mirrorUrl, logger);\n\n logger.info(\n `[whisper-local] 开始下载模型: ${modelSize} (${formatBytes(MODEL_DISK_SIZES[modelSize])})`,\n );\n logger.info(`[whisper-local] 下载 URL: ${url}`);\n\n const result = await downloadFromUrl(url, modelPath, logger);\n\n // auto 模式且 HF 失败 → 尝试国内镜像回退\n if (\n !result.ok &&\n !mirrorUrl &&\n (modelSource === \"auto\" || !modelSource) &&\n url.includes(\"huggingface.co\")\n ) {\n const fallbackUrl = MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n logger.info(\n `[whisper-local] Hugging Face 下载失败,回退至国内镜像(ModelScope): ${fallbackUrl}`,\n );\n return downloadFromUrl(fallbackUrl, modelPath, logger);\n }\n\n return result;\n}\n\n/**\n * 解析模型下载 URL\n */\nasync function resolveModelUrl(\n modelSize: WhisperModelSize,\n modelSource: WhisperModelSource | undefined,\n mirrorUrl: string | undefined,\n logger: Logger,\n): Promise<string> {\n // 自定义 URL 优先级最高\n if (mirrorUrl) {\n return `${mirrorUrl.replace(/\\/$/, \"\")}/${MODEL_FILENAMES[modelSize]}`;\n }\n\n const source = modelSource ?? \"auto\";\n\n switch (source) {\n case \"huggingface\":\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n case \"domestic\":\n return MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n case \"auto\": {\n // 探测 Hugging Face 连通性\n const hfReachable = await probeUrl(\"https://huggingface.co\", logger);\n if (hfReachable) {\n logger.info(\"[whisper-local] Hugging Face 可达,使用海外源\");\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n logger.info(\"[whisper-local] Hugging Face 不可达,使用国内镜像(ModelScope)\");\n return MODELSCOPE_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n default:\n return HF_MODEL_URL_TEMPLATE.replace(\"{model}\", modelSize);\n }\n}\n\n/**\n * 探测 URL 连通性(HEAD 请求,短超时)\n */\nasync function probeUrl(url: string, logger: Logger): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: \"HEAD\",\n signal: controller.signal,\n });\n return res.ok || res.status === 301 || res.status === 302;\n } finally {\n clearTimeout(timer);\n }\n } catch (err: any) {\n logger.info(\n `[whisper-local] 连通性探测失败: ${url} (${err?.name ?? err?.message ?? \"unknown\"})`,\n );\n return false;\n }\n}\n\n/**\n * 从指定 URL 下载模型文件至本地\n */\nasync function downloadFromUrl(\n url: string,\n modelPath: string,\n logger: Logger,\n): Promise<{ ok: boolean; modelPath: string; error?: string }> {\n const tmpPath = `${modelPath}.downloading`;\n\n try {\n mkdirSync(dirname(modelPath), { recursive: true });\n\n const controller = new AbortController();\n // 模型下载超时:30 分钟(large-v3 约 3GB)\n const timer = setTimeout(() => controller.abort(), 30 * 60 * 1000);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n\n if (!res.ok) {\n return {\n ok: false,\n modelPath,\n error: `模型下载失败: HTTP ${res.status} ${res.statusText}`,\n };\n }\n\n if (!res.body) {\n return { ok: false, modelPath, error: \"模型下载失败: 响应体为空\" };\n }\n\n const contentLength = Number(res.headers.get(\"content-length\") ?? 0);\n const writeStream = createWriteStream(tmpPath);\n const readable = Readable.fromWeb(res.body as any);\n\n // 下载进度日志\n let downloaded = 0;\n let lastLogPercent = 0;\n readable.on(\"data\", (chunk: Buffer) => {\n downloaded += chunk.length;\n if (contentLength > 0) {\n const percent = Math.floor((downloaded / contentLength) * 100);\n if (percent >= lastLogPercent + 10) {\n logger.info(\n `[whisper-local] 下载进度: ${percent}% (${formatBytes(downloaded)} / ${formatBytes(contentLength)})`,\n );\n lastLogPercent = percent;\n }\n }\n });\n\n await pipeline(readable, writeStream);\n } finally {\n clearTimeout(timer);\n }\n\n // 重命名为正式文件\n const { renameSync } = await import(\"node:fs\");\n renameSync(tmpPath, modelPath);\n\n const fileSize = statSync(modelPath).size;\n logger.info(\n `[whisper-local] 模型下载完成: ${basename(modelPath)} (${formatBytes(fileSize)})`,\n );\n\n return { ok: true, modelPath };\n } catch (err: any) {\n // 清理临时文件\n try {\n if (existsSync(tmpPath)) unlinkSync(tmpPath);\n } catch { /* ignore */ }\n\n const msg = err?.name === \"AbortError\"\n ? \"模型下载超时(30 分钟)\"\n : (err?.message ?? String(err));\n logger.error(`[whisper-local] 模型下载失败: ${msg}`);\n return { ok: false, modelPath, error: msg };\n }\n}\n\n/**\n * 查找 whisper.cpp CLI 二进制文件\n *\n * 按以下优先级查找:\n * 1. 插件数据目录下的 whisper-bin/\n * 2. 系统 PATH 中的 whisper-cli / whisper-cpp / whisper\n */\nexport function findWhisperBinary(dataDir: string, logger: Logger): string | null {\n // 1. 检查插件 bin 目录\n const binDir = resolveBinDir(dataDir);\n const binNames = platform() === \"win32\"\n ? [\"whisper-cli.exe\", \"whisper.exe\", \"main.exe\"]\n : [\"whisper-cli\", \"whisper\", \"main\"];\n\n for (const name of binNames) {\n const binPath = join(binDir, name);\n if (existsSync(binPath)) {\n logger.info(`[whisper-local] 找到本地二进制: ${binPath}`);\n return binPath;\n }\n }\n\n // 2. 检查系统 PATH\n const pathNames = platform() === \"win32\"\n ? [\"whisper-cli\", \"whisper-cpp\", \"whisper\"]\n : [\"whisper-cli\", \"whisper-cpp\", \"whisper\"];\n\n for (const name of pathNames) {\n try {\n const cmd = platform() === \"win32\" ? \"where\" : \"which\";\n const result = execSync(`${cmd} ${name}`, { encoding: \"utf-8\", stdio: \"pipe\" }).trim();\n if (result) {\n logger.info(`[whisper-local] 找到系统 PATH 二进制: ${result}`);\n return result.split(\"\\n\")[0].trim();\n }\n } catch {\n // not found, continue\n }\n }\n\n logger.warn(\"[whisper-local] 未找到 whisper.cpp 二进制文件\");\n return null;\n}\n\n/**\n * 使用本地 Whisper 执行转写(§6.4)\n *\n * @param audioFilePath 本地音频文件绝对路径\n * @param localConfig 本地 Whisper 配置\n * @param dataDir 插件数据目录(存放模型和二进制)\n * @param logger 日志\n */\nexport async function transcribeWithWhisperLocal(\n audioFilePath: string,\n localConfig: WhisperLocalConfig,\n dataDir: string,\n logger: Logger,\n): Promise<TranscriptionResult> {\n // 1. 检测环境\n const env = detectEnvironment(logger);\n\n // 2. 确定后端、模型、线程数\n const backend = localConfig.backend ?? env.recommendedBackend;\n const modelSize = localConfig.model ?? env.recommendedModel;\n const threads = localConfig.threads ?? env.physicalCores;\n const language = localConfig.language ?? \"auto\";\n const translate = localConfig.translate ?? false;\n\n logger.info(\n `[whisper-local] 转写参数: backend=${backend}, model=${modelSize}, ` +\n `threads=${threads}, language=${language}, translate=${translate}`,\n );\n\n // 3. 查找 whisper.cpp 二进制\n const whisperBin = findWhisperBinary(dataDir, logger);\n if (!whisperBin) {\n return {\n ok: false,\n error:\n \"未找到 whisper.cpp 二进制文件。请安装 whisper.cpp 并确保 whisper-cli 在 PATH 中,\" +\n `或将二进制文件放入 ${resolveBinDir(dataDir)}`,\n };\n }\n\n // 4. 确保模型已下载\n const modelsDir = resolveModelsDir(dataDir);\n if (!isModelDownloaded(modelsDir, modelSize)) {\n logger.info(`[whisper-local] 模型 ${modelSize} 未下载,开始下载...`);\n const downloadResult = await downloadModel(\n modelsDir,\n modelSize,\n logger,\n localConfig.modelSource,\n localConfig.modelMirrorUrl,\n );\n if (!downloadResult.ok) {\n return { ok: false, error: `模型下载失败: ${downloadResult.error}` };\n }\n }\n\n const modelPath = join(modelsDir, MODEL_FILENAMES[modelSize]);\n\n // 5. 音频格式转换(whisper.cpp 仅支持 16kHz mono WAV)\n // 通过 magic bytes 判断真实格式,不依赖扩展名\n let inputPath = audioFilePath;\n let tmpWavPath: string | null = null;\n\n const actualFmt = detectAudioFormat(audioFilePath);\n if (actualFmt !== \".wav\") {\n tmpWavPath = audioFilePath.replace(/\\.[^.]+$/, \".whisper.wav\");\n logger.info(\n `[whisper-local] 转换音频格式: ${audioFilePath} (${actualFmt ?? \"未知\"}) → WAV (16kHz mono)`,\n );\n\n const convertResult = convertToWav(audioFilePath, tmpWavPath, actualFmt, logger);\n if (!convertResult.ok) {\n return { ok: false, error: convertResult.error! };\n }\n inputPath = tmpWavPath;\n }\n\n // 6. 构建 whisper.cpp CLI 参数\n const args = buildWhisperArgs({\n audioFilePath: inputPath,\n modelPath,\n language,\n translate,\n threads,\n backend,\n });\n\n logger.info(`[whisper-local] 执行: ${whisperBin} ${args.join(\" \")}`);\n\n // 7. 执行转写\n try {\n const startMs = Date.now();\n let result: SpawnSyncReturns<string>;\n\n try {\n result = spawnSync(whisperBin, args, {\n encoding: \"utf-8\" as const,\n timeout: 60 * 60 * 1000, // 1 小时超时(5 小时录音)\n maxBuffer: 100 * 1024 * 1024, // 100MB stdout buffer\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n } catch (err: any) {\n cleanupTmpWav(tmpWavPath);\n return { ok: false, error: `whisper.cpp 执行失败: ${err?.message ?? err}` };\n }\n\n if (result.status !== 0) {\n cleanupTmpWav(tmpWavPath);\n const stderr = result.stderr?.slice(0, 500) ?? \"\";\n return {\n ok: false,\n error: `whisper.cpp 退出码 ${result.status}: ${stderr}`,\n };\n }\n\n const elapsed = Date.now() - startMs;\n logger.info(`[whisper-local] 转写耗时: ${Math.round(elapsed / 1000)}s`);\n\n // 8. 读取 JSON 输出文件(--output-json 将结果写入 {inputPath}.json)\n const jsonPath = inputPath + \".json\";\n let jsonContent: string;\n\n if (existsSync(jsonPath)) {\n jsonContent = readFileSync(jsonPath, \"utf-8\");\n // 清理 JSON 文件\n try { unlinkSync(jsonPath); } catch { /* ignore */ }\n } else {\n // 回退:尝试解析 stdout(部分 whisper.cpp 版本可能输出到 stdout)\n jsonContent = result.stdout;\n }\n\n cleanupTmpWav(tmpWavPath);\n\n return parseWhisperOutput(jsonContent, logger);\n } catch (err: any) {\n cleanupTmpWav(tmpWavPath);\n return { ok: false, error: `whisper.cpp 转写异常: ${err?.message ?? err}` };\n }\n}\n\n/**\n * 获取本地 Whisper 状态信息(供 App 查询环境检测结果)\n */\nexport function getWhisperLocalStatus(\n dataDir: string,\n logger: Logger,\n): {\n environment: WhisperEnvironmentInfo;\n binaryFound: boolean;\n binaryPath: string | null;\n downloadedModels: WhisperModelSize[];\n} {\n const env = detectEnvironment(logger);\n const binaryPath = findWhisperBinary(dataDir, logger);\n const modelsDir = resolveModelsDir(dataDir);\n\n const allModels: WhisperModelSize[] = [\"tiny\", \"base\", \"small\", \"medium\", \"large-v3\"];\n const downloadedModels = allModels.filter((m) => isModelDownloaded(modelsDir, m));\n\n return {\n environment: env,\n binaryFound: binaryPath !== null,\n binaryPath,\n downloadedModels,\n };\n}\n\n// ─── Internal Helpers ───\n\n/**\n * 检测 CUDA 是否可用(§6.4.1)\n */\nfunction detectCuda(logger: Logger): boolean {\n try {\n // 尝试运行 nvidia-smi\n execSync(\"nvidia-smi\", { encoding: \"utf-8\", stdio: \"pipe\", timeout: 5000 });\n logger.info(\"[whisper-local] 检测到 NVIDIA GPU (nvidia-smi)\");\n return true;\n } catch {\n // nvidia-smi 不存在或执行失败\n }\n\n // 检查 CUDA runtime 库\n if (platform() === \"linux\") {\n try {\n const ldconfig = execSync(\"ldconfig -p 2>/dev/null | grep libcudart\", {\n encoding: \"utf-8\",\n stdio: \"pipe\",\n timeout: 5000,\n });\n if (ldconfig.includes(\"libcudart\")) {\n logger.info(\"[whisper-local] 检测到 CUDA runtime (ldconfig)\");\n return true;\n }\n } catch { /* ignore */ }\n }\n\n return false;\n}\n\n/**\n * 获取可用内存(GB)\n *\n * CUDA 后端使用 VRAM,其余使用系统 RAM。\n */\nfunction getAvailableMemoryGB(backend: WhisperBackend, logger: Logger): number {\n if (backend === \"cuda\") {\n // 尝试获取 GPU VRAM\n try {\n const output = execSync(\n \"nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits\",\n { encoding: \"utf-8\", stdio: \"pipe\", timeout: 5000 },\n );\n const freeVramMB = parseInt(output.trim().split(\"\\n\")[0], 10);\n if (!Number.isNaN(freeVramMB) && freeVramMB > 0) {\n return freeVramMB / 1024;\n }\n } catch {\n logger.warn(\"[whisper-local] 无法获取 GPU VRAM,使用系统 RAM 代替\");\n }\n }\n\n // 使用系统可用内存(取 total 的 80% 和 free 的较大值作为可用估计)\n const totalGB = totalmem() / (1024 * 1024 * 1024);\n const freeGB = freemem() / (1024 * 1024 * 1024);\n return Math.max(freeGB, totalGB * 0.6);\n}\n\n/**\n * 获取物理 CPU 核心数\n */\nfunction getPhysicalCoreCount(): number {\n const cpuList = cpus();\n if (cpuList.length === 0) return 4; // fallback\n\n // 简单估算:逻辑核 / 2(假设超线程)\n // macOS ARM 无超线程,直接使用逻辑核数\n if (platform() === \"darwin\" && arch() === \"arm64\") {\n // Apple Silicon: P-cores only (exclude E-cores for inference)\n // 简化处理:使用总核数\n return cpuList.length;\n }\n\n return Math.max(1, Math.floor(cpuList.length / 2));\n}\n\n/**\n * 通过文件头 magic bytes 检测音频的真实格式\n * @returns 正确的文件扩展名(如 .aiff, .wav, .m4a),或 null\n */\nfunction detectAudioFormat(filePath: string): string | null {\n try {\n const fd = openSync(filePath, \"r\");\n const buf = Buffer.alloc(12);\n readSync(fd, buf, 0, 12, 0);\n closeSync(fd);\n\n const header = buf.toString(\"ascii\", 0, 4);\n const header8 = buf.toString(\"ascii\", 0, 8);\n\n // RIFF....WAVE = WAV\n if (header === \"RIFF\" && buf.toString(\"ascii\", 8, 12) === \"WAVE\") return \".wav\";\n // FORM....AIFF / FORM....AIFC = AIFF\n if (header === \"FORM\") {\n const sub = buf.toString(\"ascii\", 8, 12);\n if (sub === \"AIFF\" || sub === \"AIFC\") return \".aiff\";\n }\n // ftyp = MP4/M4A/AAC container\n if (buf.toString(\"ascii\", 4, 8) === \"ftyp\") return \".m4a\";\n // ID3 or 0xFF 0xFB = MP3\n if (header.startsWith(\"ID3\") || (buf[0] === 0xff && (buf[1] & 0xe0) === 0xe0)) return \".mp3\";\n // OggS = Ogg (Vorbis/Opus)\n if (header === \"OggS\") return \".ogg\";\n // fLaC = FLAC\n if (header === \"fLaC\") return \".flac\";\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * 将音频文件转换为 whisper.cpp 所需的 16kHz mono WAV 格式\n *\n * 转换链(按优先级):\n * 1. ffmpeg — 支持全格式,含 OGG/Opus\n * 2. opusdec — 专用于 OGG/Opus(来自 brew install opus-tools)\n * 3. afconvert — macOS 内置,支持 AIFF/M4A/AAC;需正确文件扩展名\n *\n * @param actualFmt detectAudioFormat 检测到的真实格式(如 \".ogg\", \".aiff\"),可为 null\n */\nfunction convertToWav(\n inputPath: string,\n outputPath: string,\n actualFmt: string | null,\n logger: Logger,\n): { ok: boolean; error?: string } {\n // 尝试 ffmpeg(可自动检测格式,不依赖扩展名)\n try {\n const ffmpegResult = spawnSync(\"ffmpeg\", [\n \"-y\", \"-i\", inputPath,\n \"-ar\", \"16000\", \"-ac\", \"1\", \"-c:a\", \"pcm_s16le\",\n outputPath,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n if (ffmpegResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] ffmpeg 转换完成: ${outputPath}`);\n return { ok: true };\n }\n } catch {\n // ffmpeg 不可用,继续尝试其他方式\n }\n\n // 2. opusdec — 专用于 OGG/Opus(ffmpeg 不可用时)\n if (actualFmt === \".ogg\") {\n try {\n const opusResult = spawnSync(\n \"opusdec\",\n [\"--rate\", \"16000\", \"--mono\", inputPath, outputPath],\n { encoding: \"utf-8\", timeout: 120_000, stdio: [\"pipe\", \"pipe\", \"pipe\"] },\n );\n if (opusResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] opusdec 转换完成: ${outputPath}`);\n return { ok: true };\n }\n } catch { /* opusdec 不可用,继续 */ }\n }\n\n // 3. macOS afconvert — 支持 AIFF/M4A/AAC,不支持 OGG\n if (process.platform === \"darwin\" && actualFmt !== \".ogg\") {\n // afconvert 依赖扩展名判断输入格式,先确保扩展名正确\n let actualInputPath = inputPath;\n let tmpCopy: string | null = null;\n const detectedExt = actualFmt;\n\n if (detectedExt && !inputPath.endsWith(detectedExt)) {\n // 扩展名不匹配,创建带正确扩展名的临时副本\n tmpCopy = inputPath + \".detected\" + detectedExt;\n try {\n copyFileSync(inputPath, tmpCopy);\n actualInputPath = tmpCopy;\n logger.info(\n `[whisper-local] 检测到实际格式 ${detectedExt},临时重命名`,\n );\n } catch {\n tmpCopy = null;\n }\n }\n\n try {\n const afResult = spawnSync(\"afconvert\", [\n \"-f\", \"WAVE\", \"-d\", \"LEI16@16000\", \"-c\", \"1\",\n actualInputPath, outputPath,\n ], {\n encoding: \"utf-8\",\n timeout: 120_000,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n // 清理临时副本\n if (tmpCopy && existsSync(tmpCopy)) {\n try { unlinkSync(tmpCopy); } catch { /* ignore */ }\n }\n\n if (afResult.status === 0 && existsSync(outputPath)) {\n logger.info(`[whisper-local] afconvert 转换完成: ${outputPath}`);\n return { ok: true };\n }\n\n const stderr = afResult.stderr?.slice(0, 200) ?? \"\";\n return { ok: false, error: `afconvert 转换失败 (exit ${afResult.status}): ${stderr}` };\n } catch (err: any) {\n // 清理临时副本\n if (tmpCopy && existsSync(tmpCopy)) {\n try { unlinkSync(tmpCopy); } catch { /* ignore */ }\n }\n return { ok: false, error: `afconvert 不可用: ${err?.message}` };\n }\n }\n\n const fmtHint = actualFmt === \".ogg\"\n ? \"OGG/Opus 格式需要 ffmpeg 或 opus-tools(brew install opus-tools)\"\n : \"请安装 ffmpeg(brew install ffmpeg)或确保音频文件为 WAV 格式\";\n return { ok: false, error: `无法将音频转换为 WAV 格式。${fmtHint}` };\n}\n\n/** 清理临时 WAV 文件 */\nfunction cleanupTmpWav(path: string | null): void {\n if (path && existsSync(path)) {\n try { unlinkSync(path); } catch { /* ignore */ }\n }\n}\n\n/**\n * 构建 whisper.cpp CLI 参数\n */\nfunction buildWhisperArgs(params: {\n audioFilePath: string;\n modelPath: string;\n language: string;\n translate: boolean;\n threads: number;\n backend: WhisperBackend;\n}): string[] {\n const args: string[] = [\n \"--model\", params.modelPath,\n \"--file\", params.audioFilePath,\n \"--output-json\", // JSON 格式输出到 {audioFilePath}.json\n \"--no-prints\", // 抑制模型信息输出\n \"--threads\", String(params.threads),\n ];\n\n // 语言\n if (params.language && params.language !== \"auto\") {\n args.push(\"--language\", params.language);\n } else {\n args.push(\"--language\", \"auto\");\n }\n\n // 翻译为英文\n if (params.translate) {\n args.push(\"--translate\");\n }\n\n return args;\n}\n\n/**\n * 解析 whisper.cpp JSON 输出\n */\nfunction parseWhisperOutput(\n stdout: string,\n logger: Logger,\n): TranscriptionResult {\n if (!stdout || !stdout.trim()) {\n return { ok: false, error: \"whisper.cpp 无输出\" };\n }\n\n try {\n const data = JSON.parse(stdout.trim()) as WhisperCppJsonOutput;\n\n if (!data.transcription || !Array.isArray(data.transcription)) {\n // 可能是纯文本输出\n return {\n ok: true,\n text: stdout.trim(),\n segments: [],\n };\n }\n\n const segments: TranscriptSegment[] = [];\n const textParts: string[] = [];\n\n for (const item of data.transcription) {\n const text = item.text?.trim() ?? \"\";\n if (!text) continue;\n\n textParts.push(text);\n\n const startMs = item.offsets?.from ?? parseTimestamp(item.timestamps?.from);\n const endMs = item.offsets?.to ?? parseTimestamp(item.timestamps?.to);\n\n segments.push({\n start_ms: startMs,\n end_ms: endMs,\n text,\n });\n }\n\n const fullText = textParts.join(\" \");\n\n logger.info(\n `[whisper-local] 转写完成: ${fullText.length} 字, ${segments.length} 段`,\n );\n\n return {\n ok: true,\n text: fullText,\n segments,\n };\n } catch (err: any) {\n logger.warn(`[whisper-local] JSON 解析失败,尝试纯文本: ${err?.message}`);\n\n // Fallback: 将 stdout 视为纯文本\n return {\n ok: true,\n text: stdout.trim(),\n segments: [],\n };\n }\n}\n\n/**\n * 解析 whisper.cpp 时间戳字符串 \"HH:MM:SS,mmm\" → 毫秒\n */\nfunction parseTimestamp(ts?: string): number {\n if (!ts) return 0;\n // \"00:00:05,000\" or \"00:00:05.000\"\n const match = ts.match(/^(\\d+):(\\d+):(\\d+)[,.](\\d+)$/);\n if (!match) return 0;\n const [, h, m, s, ms] = match;\n return (\n parseInt(h, 10) * 3600000 +\n parseInt(m, 10) * 60000 +\n parseInt(s, 10) * 1000 +\n parseInt(ms, 10)\n );\n}\n\n/**\n * 格式化字节数\n */\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;\n}\n","/**\n * ASR 转写调度器(§6 / §7)\n *\n * 按 arc-long-recording §6.2 定义的两层配置结构调度 ASR:\n * - mode = \"api\":YoooClaw 托管云端 ASR(经 model-proxy 长录音接口调用)\n * - mode = \"local\":本地 Whisper 转写(§6.4,内置 whisper.cpp 推理)\n * - mode = \"yoooclaw\":YoooClaw 自建 ASR(P2,预留接口)\n *\n * 转写流程:\n * 1. 读取录音 OSS URL 与本地文件\n * 2. 调用云端 model-proxy 或本地 Whisper 获取转写文本\n * 3. 将关键点以 [关键点 MM:SS] 内嵌转写文本\n * 4. 自动生成摘要标题(≤ 10 字)\n * 5. 写入 /recordings/transcripts/日期_时间_摘要.md\n */\n\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type {\n AsrConfig,\n AsrApiConfig,\n RecordingMarker,\n RecordingAsrInitResult,\n RecordingTranscriptItem,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport { requireApiKey, loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport {\n buildTranscriptDataFilename,\n buildTranscriptDocument,\n extractSourceTextListFromDocument,\n} from \"./transcript-document.js\";\n\nconst DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS = 2000;\nconst DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS = 150;\nconst LONG_RECORDING_RUNNING_STATUSES = new Set([\"PENDING\", \"RUNNING\", \"SUSPENDED\"]);\nconst LONG_RECORDING_TERMINAL_FAILURE_STATUSES = new Set([\"FAILED\", \"CANCELED\", \"UNKNOWN\"]);\n\n// ─── Types ───\n\nexport interface TranscriptionResult {\n ok: boolean;\n /** 转写全文 */\n text?: string;\n /** 带时间戳的分段(如 ASR 支持) */\n segments?: TranscriptSegment[];\n /** 自动生成的摘要标题 */\n summary?: string;\n /** 给客户端展示的摘要文本 */\n summaryText?: string;\n /** 分类信息(如会议纪要、采访) */\n category?: string;\n /** 转写来源信息 */\n sourceInfo?: {\n provider: string;\n taskId?: string;\n requestId?: string;\n status?: string;\n };\n /** Provider 原始响应,供后续兼容字段演进 */\n rawResponse?: unknown;\n /** 错误信息 */\n error?: string;\n}\n\nexport interface TranscriptSegment {\n /** 开始时间(毫秒) */\n start_ms: number;\n /** 结束时间(毫秒) */\n end_ms: number;\n /** 文本内容 */\n text: string;\n /** 说话人 ID(如云端 ASR 返回) */\n speaker_id?: number;\n}\n\ninterface ModelProxyLongRecordingSubmitRequest {\n audioOssUrl: string;\n language?: string;\n enableNormalization?: boolean;\n}\n\ninterface ModelProxyLongRecordingResult {\n sourceText?: string | null;\n sourceTextList?: ModelProxyLongRecordingSourceTextItem[] | null;\n summaryResult?: string | null;\n category?: string | null;\n title?: string | null;\n}\n\ninterface ModelProxyLongRecordingSourceTextItem {\n content?: string | null;\n speakerId?: number | null;\n startTime?: number | null;\n}\n\ninterface ModelProxyLongRecordingStatusResponse {\n taskId?: string;\n status?: string;\n requestId?: string;\n errorMessage?: string | null;\n recordResult?: ModelProxyLongRecordingResult | null;\n}\n\ninterface ResponseEnvelope<T> {\n success?: boolean;\n code?: number | string;\n message?: string | null;\n e?: unknown;\n data?: T | null;\n}\n\n// ─── Public API ───\n\n/**\n * 判断 ASR 是否已配置\n */\nexport function isAsrConfigured(config?: AsrConfig): boolean {\n return !!config && !validateAsrConfig(config);\n}\n\n/**\n * 校验客户端下发的 ASR 配置。\n * 返回 undefined 表示配置可用;返回字符串表示错误原因。\n */\nexport function validateAsrConfig(config?: AsrConfig): string | undefined {\n if (!config?.mode) {\n return \"asr.mode is required\";\n }\n\n switch (config.mode) {\n case \"local\":\n case \"api\":\n return undefined;\n case \"yoooclaw\":\n return \"YoooClaw ASR 尚未实现(P2)\";\n default:\n return `未知的 ASR mode: ${(config as { mode: string }).mode}`;\n }\n}\n\n/**\n * 显式初始化 ASR 能力。\n * - mode=api:校验插件本地 API Key 是否存在,并返回最终使用的 model-proxy submit-task endpoint\n * - mode=local:按配置预下载模型,并返回本地环境状态\n */\nexport async function initializeAsr(\n config: AsrConfig,\n dataDir: string,\n logger: Logger,\n): Promise<RecordingAsrInitResult> {\n const validationError = validateAsrConfig(config);\n if (validationError) {\n return {\n ok: false,\n mode: config.mode,\n error: validationError,\n };\n }\n\n switch (config.mode) {\n case \"api\": {\n const endpoint = resolveModelProxyLongRecordingSubmitEndpoint(config.api);\n const keyConfigured = hasText(config.api?.apiKey) || hasText(loadApiKey());\n\n if (!keyConfigured) {\n return {\n ok: false,\n mode: \"api\",\n provider: \"model-proxy\",\n endpoint,\n language: config.api?.language ?? \"auto\",\n keyConfigured: false,\n error:\n \"API Key 未设置,请在本次 asr.api.apiKey 中传入,或先写入 credentials.json / 执行 ntf auth set-api-key <apiKey>\",\n };\n }\n\n return {\n ok: true,\n mode: \"api\",\n provider: \"model-proxy\",\n endpoint,\n language: config.api?.language ?? \"auto\",\n keyConfigured: true,\n };\n }\n case \"local\": {\n const localConfig = config.local ?? {};\n const {\n getWhisperLocalStatus,\n downloadModel,\n resolveModelsDir,\n } = await import(\"./whisper-local.js\");\n\n const initialStatus = getWhisperLocalStatus(dataDir, logger);\n const requestedModel = localConfig.model ?? initialStatus.environment.recommendedModel;\n\n const modelsDir = resolveModelsDir(dataDir);\n const downloadResult = await downloadModel(\n modelsDir,\n requestedModel,\n logger,\n localConfig.modelSource,\n localConfig.modelMirrorUrl,\n );\n if (!downloadResult.ok) {\n return {\n ok: false,\n mode: \"local\",\n model: requestedModel,\n localStatus: {\n ...initialStatus,\n requestedModel,\n },\n error: `模型下载失败: ${downloadResult.error}`,\n };\n }\n\n const finalStatus = getWhisperLocalStatus(dataDir, logger);\n if (!finalStatus.binaryFound) {\n return {\n ok: false,\n mode: \"local\",\n model: requestedModel,\n localStatus: {\n ...finalStatus,\n requestedModel,\n },\n error:\n \"模型已就绪,但未找到 whisper.cpp 二进制文件。请安装 whisper.cpp 并确保 whisper-cli 在 PATH 中。\",\n };\n }\n\n return {\n ok: true,\n mode: \"local\",\n model: requestedModel,\n language: localConfig.language ?? \"auto\",\n localStatus: {\n ...finalStatus,\n requestedModel,\n },\n };\n }\n case \"yoooclaw\":\n return {\n ok: false,\n mode: \"yoooclaw\",\n error: \"YoooClaw ASR 尚未实现(P2)\",\n };\n default:\n return {\n ok: false,\n mode: config.mode,\n error: `未知的 ASR mode: ${config.mode}`,\n };\n }\n}\n\n/**\n * 执行 ASR 转写\n *\n * @param audioFilePath 本地音频文件绝对路径\n * @param config ASR 配置(两层结构:mode + api/local)\n * @param logger 日志\n * @param options 额外上下文(云端 ASR 需要 OSS URL)\n */\nexport async function transcribeAudio(\n audioFilePath: string,\n config: AsrConfig,\n logger: Logger,\n options: {\n audioOssUrl?: string;\n } = {},\n): Promise<TranscriptionResult> {\n if (!existsSync(audioFilePath)) {\n return { ok: false, error: `音频文件不存在: ${audioFilePath}` };\n }\n\n logger.info(\n `[asr] 开始转写: mode=${config.mode}, file=${audioFilePath}`,\n );\n\n try {\n switch (config.mode) {\n case \"api\":\n return await transcribeWithModelProxy(\n options.audioOssUrl,\n config.api,\n logger,\n );\n case \"local\":\n return await transcribeWithWhisperLocal(audioFilePath, config, logger);\n case \"yoooclaw\":\n return { ok: false, error: \"YoooClaw ASR 尚未实现(P2)\" };\n default:\n return {\n ok: false,\n error: `未知的 ASR mode: ${config.mode}`,\n };\n }\n } catch (err: any) {\n const msg = err?.message ?? String(err);\n logger.error(`[asr] 转写异常: ${msg}`);\n return { ok: false, error: msg };\n }\n}\n\n/**\n * 将转写结果与关键点标记合并,生成最终 Markdown 转写文本\n *\n * @param result 转写结果\n * @param markers 关键点列表\n * @param recordingName 录音名称\n * @param durationSec 录音总时长(秒)\n * @param createdAt 录音创建时间\n */\nexport function buildTranscriptMarkdown(\n result: TranscriptionResult,\n markers: RecordingMarker[],\n recordingName: string,\n durationSec: number,\n createdAt: string,\n): string {\n const summary = result.summary ?? recordingName.slice(0, 10);\n const lines: string[] = [];\n\n // 元数据头\n lines.push(`# ${summary}`);\n lines.push(\"\");\n lines.push(`> 录音名称:${recordingName}`);\n lines.push(`> 时长:${formatDuration(durationSec)}`);\n lines.push(`> 创建时间:${createdAt}`);\n if (markers.length > 0) {\n lines.push(`> 关键点数:${markers.length}`);\n }\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n\n if (result.segments && result.segments.length > 0) {\n // 有分段的转写文本:在合适的位置插入关键点标记\n const sortedMarkers = [...markers].sort(\n (a, b) => a.timestamp_ms - b.timestamp_ms,\n );\n let markerIdx = 0;\n\n for (const seg of result.segments) {\n // 在当前段之前插入所有对应的关键点\n while (\n markerIdx < sortedMarkers.length &&\n sortedMarkers[markerIdx].timestamp_ms <= seg.start_ms\n ) {\n const m = sortedMarkers[markerIdx];\n lines.push(\n `**[关键点 ${formatTimestamp(m.timestamp_ms)}]**`,\n );\n lines.push(\"\");\n markerIdx++;\n }\n\n const segmentText = formatTranscriptSegmentText(seg);\n if (segmentText) {\n lines.push(segmentText);\n lines.push(\"\");\n }\n }\n\n // 追加剩余关键点\n while (markerIdx < sortedMarkers.length) {\n const m = sortedMarkers[markerIdx];\n lines.push(\n `**[关键点 ${formatTimestamp(m.timestamp_ms)}]**`,\n );\n lines.push(\"\");\n markerIdx++;\n }\n } else if (result.text) {\n // 纯文本转写:在文本头部集中列出关键点\n if (markers.length > 0) {\n lines.push(\"### 关键点\");\n lines.push(\"\");\n for (const m of markers) {\n lines.push(`- **[关键点 ${formatTimestamp(m.timestamp_ms)}]**`);\n }\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n lines.push(result.text);\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * 从转写文本中提取摘要标题(≤ 10 字)\n */\nexport function extractSummary(text: string): string {\n // 取第一句话,截断到 10 字\n const firstLine = text.split(/[。!?\\n]/).find((s) => s.trim().length > 0);\n if (!firstLine) return \"录音转写\";\n const trimmed = firstLine.trim();\n return trimmed.length <= 10 ? trimmed : trimmed.slice(0, 10);\n}\n\n/**\n * 完整的转写工作流:转写 → 生成 Markdown → 写入文件\n */\nexport async function runTranscriptionWorkflow(params: {\n audioFilePath: string;\n audioOssUrl?: string;\n config: AsrConfig;\n markers: RecordingMarker[];\n recordingName: string;\n durationSec: number;\n createdAt: string;\n transcriptsDir: string;\n transcriptDataDir: string;\n summariesDir: string;\n recordingId: string;\n logger: Logger;\n}): Promise<{\n ok: boolean;\n transcriptFilename?: string;\n transcriptDataFilename?: string;\n summaryFilename?: string;\n transcript?: RecordingTranscriptItem[];\n summary?: string;\n title?: string;\n error?: string;\n}> {\n const {\n audioFilePath,\n audioOssUrl,\n config,\n markers,\n recordingName,\n durationSec,\n createdAt,\n transcriptsDir,\n transcriptDataDir,\n summariesDir,\n recordingId,\n logger,\n } = params;\n\n // 1. ASR 转写\n const result = await transcribeAudio(audioFilePath, config, logger, {\n audioOssUrl,\n });\n if (!result.ok) {\n return { ok: false, error: result.error };\n }\n\n // 2. 提取摘要\n const title = normalizeOptionalText(result.summary)\n ? normalizeOptionalText(result.summary)!\n : extractSummary(result.text ?? \"\");\n const summary = normalizeOptionalText(result.summaryText)\n ? normalizeOptionalText(result.summaryText)!\n : extractTranscriptSummary(result.text ?? \"\");\n result.summary = title;\n const transcriptData = buildTranscriptDocument({\n recordingId,\n generatedAt: new Date().toISOString(),\n source: result.sourceInfo ?? {\n provider: config.mode === \"api\" ? \"model-proxy\" : config.mode,\n },\n title,\n category: result.category,\n summary,\n text: result.text,\n segments: (result.segments ?? []).map((segment) => ({\n text: segment.text,\n startMs: segment.start_ms,\n endMs: segment.end_ms,\n speakerId: segment.speaker_id,\n })),\n raw: result.rawResponse,\n });\n\n // 3. 生成 Markdown\n const markdown = buildTranscriptMarkdown(\n result,\n markers,\n recordingName,\n durationSec,\n createdAt,\n );\n\n // 4. 写入文件\n const transcriptDataFilename = buildTranscriptDataFilename(recordingId);\n const transcriptDataPath = join(transcriptDataDir, transcriptDataFilename);\n writeFileSync(\n transcriptDataPath,\n JSON.stringify(transcriptData, null, 2),\n \"utf-8\",\n );\n logger.info(`[asr] 转写 JSON 已写入: ${transcriptDataPath}`);\n\n const safeSummary = title\n .replace(/[/\\\\:*?\"<>|]/g, \"\")\n .trim()\n .slice(0, 20);\n const filename = safeSummary\n ? `${recordingId}_${safeSummary}.md`\n : `${recordingId}.md`;\n const filePath = join(transcriptsDir, filename);\n writeFileSync(filePath, markdown, \"utf-8\");\n logger.info(`[asr] 转写文本已写入: ${filePath}`);\n\n const summaryFilename = `${recordingId}.md`;\n const summaryFilePath = join(summariesDir, summaryFilename);\n writeFileSync(summaryFilePath, summary, \"utf-8\");\n logger.info(`[asr] 摘要文本已写入: ${summaryFilePath}`);\n\n return {\n ok: true,\n transcriptFilename: filename,\n transcriptDataFilename,\n summaryFilename,\n transcript: extractSourceTextListFromDocument(transcriptData),\n summary,\n title,\n };\n}\n\n// ─── ASR Provider Implementations ───\n\n/**\n * 通过 model-proxy 的长录音接口执行云端转写。\n */\nasync function transcribeWithModelProxy(\n audioOssUrl: string | undefined,\n apiConfig: AsrApiConfig | undefined,\n logger: Logger,\n): Promise<TranscriptionResult> {\n const normalizedAudioOssUrl = normalizeOptionalText(audioOssUrl);\n if (!normalizedAudioOssUrl) {\n return { ok: false, error: \"API 模式缺少 audioOssUrl,无法调用 model-proxy\" };\n }\n\n const apiKey = resolveModelProxyApiKey(apiConfig);\n const submitEndpoint = resolveModelProxyLongRecordingSubmitEndpoint(apiConfig);\n const submitBody = buildLongRecordingSubmitRequest(normalizedAudioOssUrl, apiConfig);\n\n logger.info(\n `[asr-submit] 提交长录音任务: endpoint=${submitEndpoint}, body=${stringifyForLog(submitBody) ?? \"{}\"}`,\n );\n\n const res = await fetch(submitEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key-Id\": apiKey,\n },\n body: JSON.stringify(submitBody),\n });\n\n if (!res.ok) {\n const errText = await res.text();\n logger.error(\n `[asr-submit-response] 提交长录音任务失败: status=${res.status}, body=${errText.slice(0, 500)}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR error: ${res.status} ${errText.slice(0, 200)}`,\n };\n }\n\n const raw = (await res.json()) as\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n logger.info(\n `[asr-submit-response] 提交长录音任务响应: ${stringifyForLog(raw) ?? \"{}\"}`,\n );\n const submitEnvelopeError = buildModelProxyEnvelopeError(raw);\n if (submitEnvelopeError) {\n logger.error(\n `[asr-submit-response] 提交长录音任务失败: ${submitEnvelopeError}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR 提交失败: ${submitEnvelopeError}`,\n };\n }\n\n const data = unwrapResponse(raw);\n const taskId = normalizeOptionalText(data?.taskId);\n const requestId = normalizeOptionalText(data?.requestId);\n const status = normalizeLongRecordingStatus(data?.status);\n\n if (!taskId) {\n return {\n ok: false,\n error: \"Model Proxy ASR 响应缺少 taskId\",\n };\n }\n\n logger.info(\n `[asr] Model Proxy 长录音任务已提交: taskId=${taskId}, status=${status ?? \"UNKNOWN\"}, requestId=${requestId ?? \"n/a\"}`,\n );\n\n if (status && LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {\n return {\n ok: false,\n error: buildLongRecordingStatusError(data, status),\n };\n }\n\n return await pollLongRecordingTaskResult({\n apiKey,\n taskId,\n initialRequestId: requestId,\n apiConfig,\n logger,\n });\n}\n\n/**\n * 本地 Whisper 转写(§6.4 — 内置 whisper.cpp 推理)\n */\nasync function transcribeWithWhisperLocal(\n audioFilePath: string,\n config: AsrConfig,\n logger: Logger,\n): Promise<TranscriptionResult> {\n const { transcribeWithWhisperLocal: runLocal } = await import(\"./whisper-local.js\");\n\n // 解析插件数据目录(与模型/二进制存放位置)\n // 优先使用环境变量指定的目录,否则使用音频文件所在目录的上两级(recordings 的父目录)\n const dataDir =\n process.env.OPENCLAW_STATE_DIR ??\n process.env.QCLAW_STATE_DIR ??\n join(audioFilePath, \"..\", \"..\", \"..\");\n\n const localConfig = config.local ?? {};\n\n const result = await runLocal(\n audioFilePath,\n localConfig,\n dataDir,\n logger,\n );\n\n if (result.ok && result.text) {\n const { extractSummary: extract } = await import(\"./asr.js\");\n result.summary = extract(result.text);\n result.sourceInfo = {\n provider: \"whisper-local\",\n status: \"SUCCEEDED\",\n };\n }\n\n return result;\n}\n\n// ─── Helpers ───\n\nfunction resolveModelProxyLongRecordingSubmitEndpoint(apiConfig?: AsrApiConfig): string {\n return apiConfig?.endpoint?.trim() || getEnvUrls().modelProxyLongRecordingSubmitTaskUrl;\n}\n\nfunction resolveModelProxyApiKey(apiConfig?: AsrApiConfig): string {\n const requestApiKey = normalizeOptionalText(apiConfig?.apiKey);\n return normalizeApiKeyHeaderValue(requestApiKey ?? requireApiKey());\n}\n\nfunction resolveModelProxyLongRecordingQueryTaskResultBaseUrl(\n apiConfig?: AsrApiConfig,\n): string {\n const customEndpoint = apiConfig?.endpoint?.trim();\n if (customEndpoint) {\n return deriveLongRecordingQueryTaskResultBaseUrl(customEndpoint);\n }\n return getEnvUrls().modelProxyLongRecordingQueryTaskResultBaseUrl;\n}\n\nfunction deriveLongRecordingQueryTaskResultBaseUrl(endpoint: string): string {\n const trimmed = endpoint.replace(/\\/+$/, \"\");\n if (trimmed.endsWith(\"/submit-task\")) {\n return `${trimmed.slice(0, -\"/submit-task\".length)}/query-task-result`;\n }\n return trimmed;\n}\n\nfunction buildLongRecordingSubmitRequest(\n audioOssUrl: string,\n apiConfig?: AsrApiConfig,\n): ModelProxyLongRecordingSubmitRequest {\n const body: ModelProxyLongRecordingSubmitRequest = {\n audioOssUrl,\n };\n\n if (apiConfig?.language?.trim()) {\n body.language = apiConfig.language.trim();\n }\n if (typeof apiConfig?.enableNormalization === \"boolean\") {\n body.enableNormalization = apiConfig.enableNormalization;\n }\n\n return body;\n}\n\nasync function pollLongRecordingTaskResult(params: {\n apiKey: string;\n taskId: string;\n initialRequestId?: string;\n apiConfig?: AsrApiConfig;\n logger: Logger;\n}): Promise<TranscriptionResult> {\n const {\n apiKey,\n taskId,\n initialRequestId,\n apiConfig,\n logger,\n } = params;\n const queryBaseUrl = resolveModelProxyLongRecordingQueryTaskResultBaseUrl(apiConfig);\n let lastStatus: string | undefined;\n\n for (let attempt = 1; attempt <= DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS; attempt++) {\n const queryUrl = `${queryBaseUrl}/${encodeURIComponent(taskId)}`;\n const res = await fetch(queryUrl, {\n method: \"GET\",\n headers: {\n \"X-Api-Key-Id\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errText = await res.text();\n logger.error(\n `[asr-query-response] 长录音任务查询失败: taskId=${taskId}, attempt=${attempt}, status=${res.status}, body=${errText.slice(0, 500)}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR query error: ${res.status} ${errText.slice(0, 200)}`,\n };\n }\n\n const raw = (await res.json()) as\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n const queryEnvelopeError = buildModelProxyEnvelopeError(raw);\n if (queryEnvelopeError) {\n logger.error(\n `[asr-query-response] 长录音任务查询失败: taskId=${taskId}, attempt=${attempt}, ${queryEnvelopeError}`,\n );\n return {\n ok: false,\n error: `Model Proxy ASR 查询失败: ${queryEnvelopeError}`,\n };\n }\n\n const data = unwrapResponse(raw);\n const status = normalizeLongRecordingStatus(data?.status) ?? \"UNKNOWN\";\n const requestId = normalizeOptionalText(data?.requestId) ?? initialRequestId;\n\n if (status !== lastStatus) {\n logger.info(\n `[asr-query-response] 长录音任务查询响应: taskId=${taskId}, attempt=${attempt}, body=${stringifyForLog(raw) ?? \"{}\"}`,\n );\n logger.info(\n `[asr] Model Proxy 长录音任务状态: taskId=${taskId}, status=${status}, attempt=${attempt}, requestId=${requestId ?? \"n/a\"}`,\n );\n lastStatus = status;\n }\n\n if (status === \"SUCCEEDED\") {\n return buildLongRecordingSuccessResult(taskId, requestId, data, logger);\n }\n\n if (LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {\n return {\n ok: false,\n error: buildLongRecordingStatusError(data, status),\n };\n }\n\n if (!LONG_RECORDING_RUNNING_STATUSES.has(status)) {\n return {\n ok: false,\n error: `Model Proxy ASR 返回未知任务状态: ${status}`,\n };\n }\n\n if (attempt < DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS) {\n await sleep(DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS);\n }\n }\n\n return {\n ok: false,\n error:\n `Model Proxy ASR 轮询超时: taskId=${taskId}, waited=${DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS * DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS}ms`,\n };\n}\n\nfunction buildLongRecordingSuccessResult(\n taskId: string,\n requestId: string | undefined,\n data: ModelProxyLongRecordingStatusResponse | undefined,\n logger: Logger,\n): TranscriptionResult {\n const sourceTextList = normalizeLongRecordingSourceTextList(\n data?.recordResult?.sourceTextList,\n );\n const listResult = extractLongRecordingTextFromList(sourceTextList);\n const sourceText = normalizeOptionalText(data?.recordResult?.sourceText);\n const summaryText = normalizeOptionalText(data?.recordResult?.summaryResult);\n const title = normalizeOptionalText(data?.recordResult?.title);\n const category = normalizeOptionalText(data?.recordResult?.category);\n const text = listResult.text ?? sourceText ?? summaryText;\n\n if (!text) {\n return {\n ok: false,\n error: \"Model Proxy ASR 任务已完成,但未返回 sourceTextList、sourceText 或 summaryResult\",\n };\n }\n\n if (!listResult.text && !sourceText && summaryText) {\n logger.warn(\n `[asr] Model Proxy 长录音结果缺少 sourceTextList/sourceText,已回退使用 summaryResult 作为转写文本: taskId=${taskId}`,\n );\n }\n\n logger.info(\n `[asr] Model Proxy 长录音转写完成: taskId=${taskId}, requestId=${requestId ?? \"n/a\"}, chars=${text.length}`,\n );\n\n return {\n ok: true,\n text,\n segments: listResult.segments,\n summary: title ?? extractSummary(text),\n summaryText: summaryText ?? extractTranscriptSummary(text),\n category,\n sourceInfo: {\n provider: \"model-proxy\",\n taskId,\n requestId,\n status: \"SUCCEEDED\",\n },\n rawResponse: data,\n };\n}\n\nfunction buildLongRecordingStatusError(\n data: ModelProxyLongRecordingStatusResponse | undefined,\n status: string,\n): string {\n const errorMessage = normalizeOptionalText(data?.errorMessage);\n return errorMessage\n ? `Model Proxy ASR ${status}: ${errorMessage}`\n : `Model Proxy ASR ${status}`;\n}\n\nfunction buildModelProxyEnvelopeError(\n payload:\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>,\n): string | undefined {\n if (!payload || typeof payload !== \"object\" || !(\"data\" in payload)) {\n return undefined;\n }\n\n const envelope = payload as ResponseEnvelope<ModelProxyLongRecordingStatusResponse>;\n const explicitFailure = envelope.success === false;\n const message = normalizeOptionalText(envelope.message);\n if (!explicitFailure && (!message || envelope.data)) {\n return undefined;\n }\n\n const code = normalizeOptionalCode(envelope.code);\n if (code && message) {\n return `${code} ${message}`;\n }\n return message ?? code ?? \"response envelope indicates failure\";\n}\n\nfunction unwrapResponse(\n payload:\n | ModelProxyLongRecordingStatusResponse\n | ResponseEnvelope<ModelProxyLongRecordingStatusResponse>,\n): ModelProxyLongRecordingStatusResponse | undefined {\n if (\n payload &&\n typeof payload === \"object\" &&\n \"data\" in payload &&\n payload.data &&\n typeof payload.data === \"object\"\n ) {\n return payload.data;\n }\n\n return payload as ModelProxyLongRecordingStatusResponse;\n}\n\nfunction normalizeApiKeyHeaderValue(apiKey: string): string {\n return apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n}\n\nfunction normalizeLongRecordingStatus(status: unknown): string | undefined {\n return typeof status === \"string\" && status.trim()\n ? status.trim().toUpperCase()\n : undefined;\n}\n\nfunction normalizeOptionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim()\n ? value.trim()\n : undefined;\n}\n\nfunction normalizeOptionalCode(value: unknown): string | undefined {\n if (typeof value === \"string\" && value.trim()) {\n return value.trim();\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value);\n }\n return undefined;\n}\n\nfunction normalizeOptionalInteger(value: unknown): number | undefined {\n return Number.isInteger(value)\n ? Number(value)\n : undefined;\n}\n\nfunction normalizeOptionalNonNegativeNumber(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0\n ? value\n : undefined;\n}\n\nfunction normalizeLongRecordingSourceTextList(\n value: unknown,\n): Array<{\n content: string;\n speakerId?: number;\n startTime?: number;\n}> {\n if (!Array.isArray(value)) {\n return [];\n }\n\n return value\n .flatMap((item) => {\n if (!item || typeof item !== \"object\") {\n return [];\n }\n\n const record = item as Record<string, unknown>;\n const content = normalizeOptionalText(record.content);\n if (!content) {\n return [];\n }\n\n return [{\n content,\n speakerId: normalizeOptionalInteger(record.speakerId),\n startTime: normalizeOptionalNonNegativeNumber(record.startTime),\n }];\n });\n}\n\nfunction extractLongRecordingTextFromList(\n items: Array<{\n content: string;\n speakerId?: number;\n startTime?: number;\n }>,\n): {\n text?: string;\n segments: TranscriptSegment[];\n} {\n if (items.length === 0) {\n return {\n segments: [],\n };\n }\n\n const segments = items.map((item, index) => {\n const startMs = item.startTime ?? 0;\n const nextStart = items[index + 1]?.startTime;\n\n return {\n start_ms: startMs,\n end_ms: nextStart ?? startMs,\n text: item.content,\n speaker_id: item.speakerId,\n };\n });\n\n return {\n text: items.map((item) => item.content).join(\"\\n\\n\"),\n segments,\n };\n}\n\nfunction stringifyForLog(value: unknown, maxLength = 500): string | undefined {\n if (value == null) {\n return undefined;\n }\n\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed ? trimmed.slice(0, maxLength) : undefined;\n }\n\n try {\n const serialized = JSON.stringify(value);\n return serialized ? serialized.slice(0, maxLength) : undefined;\n } catch {\n return String(value).slice(0, maxLength);\n }\n}\n\nasync function sleep(ms: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction extractTranscriptSummary(text: string): string {\n const normalized = text.replace(/\\s+/g, \" \").trim();\n if (!normalized) {\n return \"\";\n }\n\n const sentence = normalized\n .split(/[。!?!?]/)\n .map((part) => part.trim())\n .find((part) => part.length > 0);\n\n const candidate = sentence || normalized;\n return candidate.length <= 120\n ? candidate\n : `${candidate.slice(0, 117).trimEnd()}...`;\n}\n\n/** 毫秒 → \"MM:SS\" */\nfunction formatTimestamp(ms: number): string {\n const totalSeconds = Math.floor(ms / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n return `${String(minutes).padStart(2, \"0\")}:${String(seconds).padStart(2, \"0\")}`;\n}\n\n/** 秒 → \"HH:MM:SS\" 或 \"MM:SS\" */\nfunction formatDuration(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = Math.floor(seconds % 60);\n if (h > 0) {\n return `${h}:${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n }\n return `${String(m).padStart(2, \"0\")}:${String(s).padStart(2, \"0\")}`;\n}\n\nfunction hasText(value: unknown): boolean {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n\nfunction formatTranscriptSegmentText(segment: TranscriptSegment): string {\n const text = segment.text.trim();\n if (!text) {\n return text;\n }\n\n if (typeof segment.speaker_id === \"number\") {\n return `说话人${segment.speaker_id}:${text}`;\n }\n\n return text;\n}\n","'use strict';\n\nconst BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];\nconst hasBlob = typeof Blob !== 'undefined';\n\nif (hasBlob) BINARY_TYPES.push('blob');\n\nmodule.exports = {\n BINARY_TYPES,\n CLOSE_TIMEOUT: 30000,\n EMPTY_BUFFER: Buffer.alloc(0),\n GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',\n hasBlob,\n kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),\n kListener: Symbol('kListener'),\n kStatusCode: Symbol('status-code'),\n kWebSocket: Symbol('websocket'),\n NOOP: () => {}\n};\n","'use strict';\n\nconst { EMPTY_BUFFER } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\n\n/**\n * Merges an array of buffers into a new buffer.\n *\n * @param {Buffer[]} list The array of buffers to concat\n * @param {Number} totalLength The total length of buffers in the list\n * @return {Buffer} The resulting buffer\n * @public\n */\nfunction concat(list, totalLength) {\n if (list.length === 0) return EMPTY_BUFFER;\n if (list.length === 1) return list[0];\n\n const target = Buffer.allocUnsafe(totalLength);\n let offset = 0;\n\n for (let i = 0; i < list.length; i++) {\n const buf = list[i];\n target.set(buf, offset);\n offset += buf.length;\n }\n\n if (offset < totalLength) {\n return new FastBuffer(target.buffer, target.byteOffset, offset);\n }\n\n return target;\n}\n\n/**\n * Masks a buffer using the given mask.\n *\n * @param {Buffer} source The buffer to mask\n * @param {Buffer} mask The mask to use\n * @param {Buffer} output The buffer where to store the result\n * @param {Number} offset The offset at which to start writing\n * @param {Number} length The number of bytes to mask.\n * @public\n */\nfunction _mask(source, mask, output, offset, length) {\n for (let i = 0; i < length; i++) {\n output[offset + i] = source[i] ^ mask[i & 3];\n }\n}\n\n/**\n * Unmasks a buffer using the given mask.\n *\n * @param {Buffer} buffer The buffer to unmask\n * @param {Buffer} mask The mask to use\n * @public\n */\nfunction _unmask(buffer, mask) {\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] ^= mask[i & 3];\n }\n}\n\n/**\n * Converts a buffer to an `ArrayBuffer`.\n *\n * @param {Buffer} buf The buffer to convert\n * @return {ArrayBuffer} Converted buffer\n * @public\n */\nfunction toArrayBuffer(buf) {\n if (buf.length === buf.buffer.byteLength) {\n return buf.buffer;\n }\n\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);\n}\n\n/**\n * Converts `data` to a `Buffer`.\n *\n * @param {*} data The data to convert\n * @return {Buffer} The buffer\n * @throws {TypeError}\n * @public\n */\nfunction toBuffer(data) {\n toBuffer.readOnly = true;\n\n if (Buffer.isBuffer(data)) return data;\n\n let buf;\n\n if (data instanceof ArrayBuffer) {\n buf = new FastBuffer(data);\n } else if (ArrayBuffer.isView(data)) {\n buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);\n } else {\n buf = Buffer.from(data);\n toBuffer.readOnly = false;\n }\n\n return buf;\n}\n\nmodule.exports = {\n concat,\n mask: _mask,\n toArrayBuffer,\n toBuffer,\n unmask: _unmask\n};\n\n/* istanbul ignore else */\nif (!process.env.WS_NO_BUFFER_UTIL) {\n try {\n const bufferUtil = require('bufferutil');\n\n module.exports.mask = function (source, mask, output, offset, length) {\n if (length < 48) _mask(source, mask, output, offset, length);\n else bufferUtil.mask(source, mask, output, offset, length);\n };\n\n module.exports.unmask = function (buffer, mask) {\n if (buffer.length < 32) _unmask(buffer, mask);\n else bufferUtil.unmask(buffer, mask);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst kDone = Symbol('kDone');\nconst kRun = Symbol('kRun');\n\n/**\n * A very simple job queue with adjustable concurrency. Adapted from\n * https://github.com/STRML/async-limiter\n */\nclass Limiter {\n /**\n * Creates a new `Limiter`.\n *\n * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed\n * to run concurrently\n */\n constructor(concurrency) {\n this[kDone] = () => {\n this.pending--;\n this[kRun]();\n };\n this.concurrency = concurrency || Infinity;\n this.jobs = [];\n this.pending = 0;\n }\n\n /**\n * Adds a job to the queue.\n *\n * @param {Function} job The job to run\n * @public\n */\n add(job) {\n this.jobs.push(job);\n this[kRun]();\n }\n\n /**\n * Removes a job from the queue and runs it if possible.\n *\n * @private\n */\n [kRun]() {\n if (this.pending === this.concurrency) return;\n\n if (this.jobs.length) {\n const job = this.jobs.shift();\n\n this.pending++;\n job(this[kDone]);\n }\n }\n}\n\nmodule.exports = Limiter;\n","'use strict';\n\nconst zlib = require('zlib');\n\nconst bufferUtil = require('./buffer-util');\nconst Limiter = require('./limiter');\nconst { kStatusCode } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\nconst TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);\nconst kPerMessageDeflate = Symbol('permessage-deflate');\nconst kTotalLength = Symbol('total-length');\nconst kCallback = Symbol('callback');\nconst kBuffers = Symbol('buffers');\nconst kError = Symbol('error');\n\n//\n// We limit zlib concurrency, which prevents severe memory fragmentation\n// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913\n// and https://github.com/websockets/ws/issues/1202\n//\n// Intentionally global; it's the global thread pool that's an issue.\n//\nlet zlibLimiter;\n\n/**\n * permessage-deflate implementation.\n */\nclass PerMessageDeflate {\n /**\n * Creates a PerMessageDeflate instance.\n *\n * @param {Object} [options] Configuration options\n * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support\n * for, or request, a custom client window size\n * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/\n * acknowledge disabling of client context takeover\n * @param {Number} [options.concurrencyLimit=10] The number of concurrent\n * calls to zlib\n * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the\n * use of a custom server window size\n * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept\n * disabling of server context takeover\n * @param {Number} [options.threshold=1024] Size (in bytes) below which\n * messages should not be compressed if context takeover is disabled\n * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on\n * deflate\n * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on\n * inflate\n * @param {Boolean} [isServer=false] Create the instance in either server or\n * client mode\n * @param {Number} [maxPayload=0] The maximum allowed message length\n */\n constructor(options, isServer, maxPayload) {\n this._maxPayload = maxPayload | 0;\n this._options = options || {};\n this._threshold =\n this._options.threshold !== undefined ? this._options.threshold : 1024;\n this._isServer = !!isServer;\n this._deflate = null;\n this._inflate = null;\n\n this.params = null;\n\n if (!zlibLimiter) {\n const concurrency =\n this._options.concurrencyLimit !== undefined\n ? this._options.concurrencyLimit\n : 10;\n zlibLimiter = new Limiter(concurrency);\n }\n }\n\n /**\n * @type {String}\n */\n static get extensionName() {\n return 'permessage-deflate';\n }\n\n /**\n * Create an extension negotiation offer.\n *\n * @return {Object} Extension parameters\n * @public\n */\n offer() {\n const params = {};\n\n if (this._options.serverNoContextTakeover) {\n params.server_no_context_takeover = true;\n }\n if (this._options.clientNoContextTakeover) {\n params.client_no_context_takeover = true;\n }\n if (this._options.serverMaxWindowBits) {\n params.server_max_window_bits = this._options.serverMaxWindowBits;\n }\n if (this._options.clientMaxWindowBits) {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n } else if (this._options.clientMaxWindowBits == null) {\n params.client_max_window_bits = true;\n }\n\n return params;\n }\n\n /**\n * Accept an extension negotiation offer/response.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Object} Accepted configuration\n * @public\n */\n accept(configurations) {\n configurations = this.normalizeParams(configurations);\n\n this.params = this._isServer\n ? this.acceptAsServer(configurations)\n : this.acceptAsClient(configurations);\n\n return this.params;\n }\n\n /**\n * Releases all resources used by the extension.\n *\n * @public\n */\n cleanup() {\n if (this._inflate) {\n this._inflate.close();\n this._inflate = null;\n }\n\n if (this._deflate) {\n const callback = this._deflate[kCallback];\n\n this._deflate.close();\n this._deflate = null;\n\n if (callback) {\n callback(\n new Error(\n 'The deflate stream was closed while data was being processed'\n )\n );\n }\n }\n }\n\n /**\n * Accept an extension negotiation offer.\n *\n * @param {Array} offers The extension negotiation offers\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsServer(offers) {\n const opts = this._options;\n const accepted = offers.find((params) => {\n if (\n (opts.serverNoContextTakeover === false &&\n params.server_no_context_takeover) ||\n (params.server_max_window_bits &&\n (opts.serverMaxWindowBits === false ||\n (typeof opts.serverMaxWindowBits === 'number' &&\n opts.serverMaxWindowBits > params.server_max_window_bits))) ||\n (typeof opts.clientMaxWindowBits === 'number' &&\n !params.client_max_window_bits)\n ) {\n return false;\n }\n\n return true;\n });\n\n if (!accepted) {\n throw new Error('None of the extension offers can be accepted');\n }\n\n if (opts.serverNoContextTakeover) {\n accepted.server_no_context_takeover = true;\n }\n if (opts.clientNoContextTakeover) {\n accepted.client_no_context_takeover = true;\n }\n if (typeof opts.serverMaxWindowBits === 'number') {\n accepted.server_max_window_bits = opts.serverMaxWindowBits;\n }\n if (typeof opts.clientMaxWindowBits === 'number') {\n accepted.client_max_window_bits = opts.clientMaxWindowBits;\n } else if (\n accepted.client_max_window_bits === true ||\n opts.clientMaxWindowBits === false\n ) {\n delete accepted.client_max_window_bits;\n }\n\n return accepted;\n }\n\n /**\n * Accept the extension negotiation response.\n *\n * @param {Array} response The extension negotiation response\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsClient(response) {\n const params = response[0];\n\n if (\n this._options.clientNoContextTakeover === false &&\n params.client_no_context_takeover\n ) {\n throw new Error('Unexpected parameter \"client_no_context_takeover\"');\n }\n\n if (!params.client_max_window_bits) {\n if (typeof this._options.clientMaxWindowBits === 'number') {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n }\n } else if (\n this._options.clientMaxWindowBits === false ||\n (typeof this._options.clientMaxWindowBits === 'number' &&\n params.client_max_window_bits > this._options.clientMaxWindowBits)\n ) {\n throw new Error(\n 'Unexpected or invalid parameter \"client_max_window_bits\"'\n );\n }\n\n return params;\n }\n\n /**\n * Normalize parameters.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Array} The offers/response with normalized parameters\n * @private\n */\n normalizeParams(configurations) {\n configurations.forEach((params) => {\n Object.keys(params).forEach((key) => {\n let value = params[key];\n\n if (value.length > 1) {\n throw new Error(`Parameter \"${key}\" must have only a single value`);\n }\n\n value = value[0];\n\n if (key === 'client_max_window_bits') {\n if (value !== true) {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (!this._isServer) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else if (key === 'server_max_window_bits') {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (\n key === 'client_no_context_takeover' ||\n key === 'server_no_context_takeover'\n ) {\n if (value !== true) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else {\n throw new Error(`Unknown parameter \"${key}\"`);\n }\n\n params[key] = value;\n });\n });\n\n return configurations;\n }\n\n /**\n * Decompress data. Concurrency limited.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n decompress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._decompress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Compress data. Concurrency limited.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n compress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._compress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Decompress data.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _decompress(data, fin, callback) {\n const endpoint = this._isServer ? 'client' : 'server';\n\n if (!this._inflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._inflate = zlib.createInflateRaw({\n ...this._options.zlibInflateOptions,\n windowBits\n });\n this._inflate[kPerMessageDeflate] = this;\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n this._inflate.on('error', inflateOnError);\n this._inflate.on('data', inflateOnData);\n }\n\n this._inflate[kCallback] = callback;\n\n this._inflate.write(data);\n if (fin) this._inflate.write(TRAILER);\n\n this._inflate.flush(() => {\n const err = this._inflate[kError];\n\n if (err) {\n this._inflate.close();\n this._inflate = null;\n callback(err);\n return;\n }\n\n const data = bufferUtil.concat(\n this._inflate[kBuffers],\n this._inflate[kTotalLength]\n );\n\n if (this._inflate._readableState.endEmitted) {\n this._inflate.close();\n this._inflate = null;\n } else {\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._inflate.reset();\n }\n }\n\n callback(null, data);\n });\n }\n\n /**\n * Compress data.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _compress(data, fin, callback) {\n const endpoint = this._isServer ? 'server' : 'client';\n\n if (!this._deflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._deflate = zlib.createDeflateRaw({\n ...this._options.zlibDeflateOptions,\n windowBits\n });\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n this._deflate.on('data', deflateOnData);\n }\n\n this._deflate[kCallback] = callback;\n\n this._deflate.write(data);\n this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {\n if (!this._deflate) {\n //\n // The deflate stream was closed while data was being processed.\n //\n return;\n }\n\n let data = bufferUtil.concat(\n this._deflate[kBuffers],\n this._deflate[kTotalLength]\n );\n\n if (fin) {\n data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);\n }\n\n //\n // Ensure that the callback will not be called again in\n // `PerMessageDeflate#cleanup()`.\n //\n this._deflate[kCallback] = null;\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._deflate.reset();\n }\n\n callback(null, data);\n });\n }\n}\n\nmodule.exports = PerMessageDeflate;\n\n/**\n * The listener of the `zlib.DeflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction deflateOnData(chunk) {\n this[kBuffers].push(chunk);\n this[kTotalLength] += chunk.length;\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction inflateOnData(chunk) {\n this[kTotalLength] += chunk.length;\n\n if (\n this[kPerMessageDeflate]._maxPayload < 1 ||\n this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload\n ) {\n this[kBuffers].push(chunk);\n return;\n }\n\n this[kError] = new RangeError('Max payload size exceeded');\n this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';\n this[kError][kStatusCode] = 1009;\n this.removeListener('data', inflateOnData);\n\n //\n // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the\n // fact that in Node.js versions prior to 13.10.0, the callback for\n // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing\n // `zlib.reset()` ensures that either the callback is invoked or an error is\n // emitted.\n //\n this.reset();\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'error'` event.\n *\n * @param {Error} err The emitted error\n * @private\n */\nfunction inflateOnError(err) {\n //\n // There is no need to call `Zlib#close()` as the handle is automatically\n // closed when an error is emitted.\n //\n this[kPerMessageDeflate]._inflate = null;\n\n if (this[kError]) {\n this[kCallback](this[kError]);\n return;\n }\n\n err[kStatusCode] = 1007;\n this[kCallback](err);\n}\n","'use strict';\n\nconst { isUtf8 } = require('buffer');\n\nconst { hasBlob } = require('./constants');\n\n//\n// Allowed token characters:\n//\n// '!', '#', '$', '%', '&', ''', '*', '+', '-',\n// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'\n//\n// tokenChars[32] === 0 // ' '\n// tokenChars[33] === 1 // '!'\n// tokenChars[34] === 0 // '\"'\n// ...\n//\n// prettier-ignore\nconst tokenChars = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31\n 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63\n 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127\n];\n\n/**\n * Checks if a status code is allowed in a close frame.\n *\n * @param {Number} code The status code\n * @return {Boolean} `true` if the status code is valid, else `false`\n * @public\n */\nfunction isValidStatusCode(code) {\n return (\n (code >= 1000 &&\n code <= 1014 &&\n code !== 1004 &&\n code !== 1005 &&\n code !== 1006) ||\n (code >= 3000 && code <= 4999)\n );\n}\n\n/**\n * Checks if a given buffer contains only correct UTF-8.\n * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by\n * Markus Kuhn.\n *\n * @param {Buffer} buf The buffer to check\n * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`\n * @public\n */\nfunction _isValidUTF8(buf) {\n const len = buf.length;\n let i = 0;\n\n while (i < len) {\n if ((buf[i] & 0x80) === 0) {\n // 0xxxxxxx\n i++;\n } else if ((buf[i] & 0xe0) === 0xc0) {\n // 110xxxxx 10xxxxxx\n if (\n i + 1 === len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i] & 0xfe) === 0xc0 // Overlong\n ) {\n return false;\n }\n\n i += 2;\n } else if ((buf[i] & 0xf0) === 0xe0) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n if (\n i + 2 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong\n (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)\n ) {\n return false;\n }\n\n i += 3;\n } else if ((buf[i] & 0xf8) === 0xf0) {\n // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n if (\n i + 3 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i + 3] & 0xc0) !== 0x80 ||\n (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong\n (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||\n buf[i] > 0xf4 // > U+10FFFF\n ) {\n return false;\n }\n\n i += 4;\n } else {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Determines whether a value is a `Blob`.\n *\n * @param {*} value The value to be tested\n * @return {Boolean} `true` if `value` is a `Blob`, else `false`\n * @private\n */\nfunction isBlob(value) {\n return (\n hasBlob &&\n typeof value === 'object' &&\n typeof value.arrayBuffer === 'function' &&\n typeof value.type === 'string' &&\n typeof value.stream === 'function' &&\n (value[Symbol.toStringTag] === 'Blob' ||\n value[Symbol.toStringTag] === 'File')\n );\n}\n\nmodule.exports = {\n isBlob,\n isValidStatusCode,\n isValidUTF8: _isValidUTF8,\n tokenChars\n};\n\nif (isUtf8) {\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);\n };\n} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {\n try {\n const isValidUTF8 = require('utf-8-validate');\n\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst { Writable } = require('stream');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst {\n BINARY_TYPES,\n EMPTY_BUFFER,\n kStatusCode,\n kWebSocket\n} = require('./constants');\nconst { concat, toArrayBuffer, unmask } = require('./buffer-util');\nconst { isValidStatusCode, isValidUTF8 } = require('./validation');\n\nconst FastBuffer = Buffer[Symbol.species];\n\nconst GET_INFO = 0;\nconst GET_PAYLOAD_LENGTH_16 = 1;\nconst GET_PAYLOAD_LENGTH_64 = 2;\nconst GET_MASK = 3;\nconst GET_DATA = 4;\nconst INFLATING = 5;\nconst DEFER_EVENT = 6;\n\n/**\n * HyBi Receiver implementation.\n *\n * @extends Writable\n */\nclass Receiver extends Writable {\n /**\n * Creates a Receiver instance.\n *\n * @param {Object} [options] Options object\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {String} [options.binaryType=nodebuffer] The type for binary data\n * @param {Object} [options.extensions] An object containing the negotiated\n * extensions\n * @param {Boolean} [options.isServer=false] Specifies whether to operate in\n * client or server mode\n * @param {Number} [options.maxPayload=0] The maximum allowed message length\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n */\n constructor(options = {}) {\n super();\n\n this._allowSynchronousEvents =\n options.allowSynchronousEvents !== undefined\n ? options.allowSynchronousEvents\n : true;\n this._binaryType = options.binaryType || BINARY_TYPES[0];\n this._extensions = options.extensions || {};\n this._isServer = !!options.isServer;\n this._maxPayload = options.maxPayload | 0;\n this._skipUTF8Validation = !!options.skipUTF8Validation;\n this[kWebSocket] = undefined;\n\n this._bufferedBytes = 0;\n this._buffers = [];\n\n this._compressed = false;\n this._payloadLength = 0;\n this._mask = undefined;\n this._fragmented = 0;\n this._masked = false;\n this._fin = false;\n this._opcode = 0;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragments = [];\n\n this._errored = false;\n this._loop = false;\n this._state = GET_INFO;\n }\n\n /**\n * Implements `Writable.prototype._write()`.\n *\n * @param {Buffer} chunk The chunk of data to write\n * @param {String} encoding The character encoding of `chunk`\n * @param {Function} cb Callback\n * @private\n */\n _write(chunk, encoding, cb) {\n if (this._opcode === 0x08 && this._state == GET_INFO) return cb();\n\n this._bufferedBytes += chunk.length;\n this._buffers.push(chunk);\n this.startLoop(cb);\n }\n\n /**\n * Consumes `n` bytes from the buffered data.\n *\n * @param {Number} n The number of bytes to consume\n * @return {Buffer} The consumed bytes\n * @private\n */\n consume(n) {\n this._bufferedBytes -= n;\n\n if (n === this._buffers[0].length) return this._buffers.shift();\n\n if (n < this._buffers[0].length) {\n const buf = this._buffers[0];\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n\n return new FastBuffer(buf.buffer, buf.byteOffset, n);\n }\n\n const dst = Buffer.allocUnsafe(n);\n\n do {\n const buf = this._buffers[0];\n const offset = dst.length - n;\n\n if (n >= buf.length) {\n dst.set(this._buffers.shift(), offset);\n } else {\n dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n }\n\n n -= buf.length;\n } while (n > 0);\n\n return dst;\n }\n\n /**\n * Starts the parsing loop.\n *\n * @param {Function} cb Callback\n * @private\n */\n startLoop(cb) {\n this._loop = true;\n\n do {\n switch (this._state) {\n case GET_INFO:\n this.getInfo(cb);\n break;\n case GET_PAYLOAD_LENGTH_16:\n this.getPayloadLength16(cb);\n break;\n case GET_PAYLOAD_LENGTH_64:\n this.getPayloadLength64(cb);\n break;\n case GET_MASK:\n this.getMask();\n break;\n case GET_DATA:\n this.getData(cb);\n break;\n case INFLATING:\n case DEFER_EVENT:\n this._loop = false;\n return;\n }\n } while (this._loop);\n\n if (!this._errored) cb();\n }\n\n /**\n * Reads the first two bytes of a frame.\n *\n * @param {Function} cb Callback\n * @private\n */\n getInfo(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(2);\n\n if ((buf[0] & 0x30) !== 0x00) {\n const error = this.createError(\n RangeError,\n 'RSV2 and RSV3 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_2_3'\n );\n\n cb(error);\n return;\n }\n\n const compressed = (buf[0] & 0x40) === 0x40;\n\n if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n this._fin = (buf[0] & 0x80) === 0x80;\n this._opcode = buf[0] & 0x0f;\n this._payloadLength = buf[1] & 0x7f;\n\n if (this._opcode === 0x00) {\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fragmented) {\n const error = this.createError(\n RangeError,\n 'invalid opcode 0',\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._opcode = this._fragmented;\n } else if (this._opcode === 0x01 || this._opcode === 0x02) {\n if (this._fragmented) {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._compressed = compressed;\n } else if (this._opcode > 0x07 && this._opcode < 0x0b) {\n if (!this._fin) {\n const error = this.createError(\n RangeError,\n 'FIN must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_FIN'\n );\n\n cb(error);\n return;\n }\n\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (\n this._payloadLength > 0x7d ||\n (this._opcode === 0x08 && this._payloadLength === 1)\n ) {\n const error = this.createError(\n RangeError,\n `invalid payload length ${this._payloadLength}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n } else {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fin && !this._fragmented) this._fragmented = this._opcode;\n this._masked = (buf[1] & 0x80) === 0x80;\n\n if (this._isServer) {\n if (!this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n } else if (this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n\n if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;\n else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;\n else this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+16).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength16(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n this._payloadLength = this.consume(2).readUInt16BE(0);\n this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+64).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength64(cb) {\n if (this._bufferedBytes < 8) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(8);\n const num = buf.readUInt32BE(0);\n\n //\n // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned\n // if payload length is greater than this number.\n //\n if (num > Math.pow(2, 53 - 32) - 1) {\n const error = this.createError(\n RangeError,\n 'Unsupported WebSocket frame: payload length > 2^53 - 1',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);\n this.haveLength(cb);\n }\n\n /**\n * Payload length has been read.\n *\n * @param {Function} cb Callback\n * @private\n */\n haveLength(cb) {\n if (this._payloadLength && this._opcode < 0x08) {\n this._totalPayloadLength += this._payloadLength;\n if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n }\n\n if (this._masked) this._state = GET_MASK;\n else this._state = GET_DATA;\n }\n\n /**\n * Reads mask bytes.\n *\n * @private\n */\n getMask() {\n if (this._bufferedBytes < 4) {\n this._loop = false;\n return;\n }\n\n this._mask = this.consume(4);\n this._state = GET_DATA;\n }\n\n /**\n * Reads data bytes.\n *\n * @param {Function} cb Callback\n * @private\n */\n getData(cb) {\n let data = EMPTY_BUFFER;\n\n if (this._payloadLength) {\n if (this._bufferedBytes < this._payloadLength) {\n this._loop = false;\n return;\n }\n\n data = this.consume(this._payloadLength);\n\n if (\n this._masked &&\n (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0\n ) {\n unmask(data, this._mask);\n }\n }\n\n if (this._opcode > 0x07) {\n this.controlMessage(data, cb);\n return;\n }\n\n if (this._compressed) {\n this._state = INFLATING;\n this.decompress(data, cb);\n return;\n }\n\n if (data.length) {\n //\n // This message is not compressed so its length is the sum of the payload\n // length of all fragments.\n //\n this._messageLength = this._totalPayloadLength;\n this._fragments.push(data);\n }\n\n this.dataMessage(cb);\n }\n\n /**\n * Decompresses data.\n *\n * @param {Buffer} data Compressed data\n * @param {Function} cb Callback\n * @private\n */\n decompress(data, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n perMessageDeflate.decompress(data, this._fin, (err, buf) => {\n if (err) return cb(err);\n\n if (buf.length) {\n this._messageLength += buf.length;\n if (this._messageLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._fragments.push(buf);\n }\n\n this.dataMessage(cb);\n if (this._state === GET_INFO) this.startLoop(cb);\n });\n }\n\n /**\n * Handles a data message.\n *\n * @param {Function} cb Callback\n * @private\n */\n dataMessage(cb) {\n if (!this._fin) {\n this._state = GET_INFO;\n return;\n }\n\n const messageLength = this._messageLength;\n const fragments = this._fragments;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragmented = 0;\n this._fragments = [];\n\n if (this._opcode === 2) {\n let data;\n\n if (this._binaryType === 'nodebuffer') {\n data = concat(fragments, messageLength);\n } else if (this._binaryType === 'arraybuffer') {\n data = toArrayBuffer(concat(fragments, messageLength));\n } else if (this._binaryType === 'blob') {\n data = new Blob(fragments);\n } else {\n data = fragments;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit('message', data, true);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', data, true);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n } else {\n const buf = concat(fragments, messageLength);\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n if (this._state === INFLATING || this._allowSynchronousEvents) {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n }\n\n /**\n * Handles a control message.\n *\n * @param {Buffer} data Data to handle\n * @return {(Error|RangeError|undefined)} A possible error\n * @private\n */\n controlMessage(data, cb) {\n if (this._opcode === 0x08) {\n if (data.length === 0) {\n this._loop = false;\n this.emit('conclude', 1005, EMPTY_BUFFER);\n this.end();\n } else {\n const code = data.readUInt16BE(0);\n\n if (!isValidStatusCode(code)) {\n const error = this.createError(\n RangeError,\n `invalid status code ${code}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CLOSE_CODE'\n );\n\n cb(error);\n return;\n }\n\n const buf = new FastBuffer(\n data.buffer,\n data.byteOffset + 2,\n data.length - 2\n );\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n this._loop = false;\n this.emit('conclude', code, buf);\n this.end();\n }\n\n this._state = GET_INFO;\n return;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n\n /**\n * Builds an error object.\n *\n * @param {function(new:Error|RangeError)} ErrorCtor The error constructor\n * @param {String} message The error message\n * @param {Boolean} prefix Specifies whether or not to add a default prefix to\n * `message`\n * @param {Number} statusCode The status code\n * @param {String} errorCode The exposed error code\n * @return {(Error|RangeError)} The error\n * @private\n */\n createError(ErrorCtor, message, prefix, statusCode, errorCode) {\n this._loop = false;\n this._errored = true;\n\n const err = new ErrorCtor(\n prefix ? `Invalid WebSocket frame: ${message}` : message\n );\n\n Error.captureStackTrace(err, this.createError);\n err.code = errorCode;\n err[kStatusCode] = statusCode;\n return err;\n }\n}\n\nmodule.exports = Receiver;\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex\" }] */\n\n'use strict';\n\nconst { Duplex } = require('stream');\nconst { randomFillSync } = require('crypto');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants');\nconst { isBlob, isValidStatusCode } = require('./validation');\nconst { mask: applyMask, toBuffer } = require('./buffer-util');\n\nconst kByteLength = Symbol('kByteLength');\nconst maskBuffer = Buffer.alloc(4);\nconst RANDOM_POOL_SIZE = 8 * 1024;\nlet randomPool;\nlet randomPoolPointer = RANDOM_POOL_SIZE;\n\nconst DEFAULT = 0;\nconst DEFLATING = 1;\nconst GET_BLOB_DATA = 2;\n\n/**\n * HyBi Sender implementation.\n */\nclass Sender {\n /**\n * Creates a Sender instance.\n *\n * @param {Duplex} socket The connection socket\n * @param {Object} [extensions] An object containing the negotiated extensions\n * @param {Function} [generateMask] The function used to generate the masking\n * key\n */\n constructor(socket, extensions, generateMask) {\n this._extensions = extensions || {};\n\n if (generateMask) {\n this._generateMask = generateMask;\n this._maskBuffer = Buffer.alloc(4);\n }\n\n this._socket = socket;\n\n this._firstFragment = true;\n this._compress = false;\n\n this._bufferedBytes = 0;\n this._queue = [];\n this._state = DEFAULT;\n this.onerror = NOOP;\n this[kWebSocket] = undefined;\n }\n\n /**\n * Frames a piece of data according to the HyBi WebSocket protocol.\n *\n * @param {(Buffer|String)} data The data to frame\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @return {(Buffer|String)[]} The framed data\n * @public\n */\n static frame(data, options) {\n let mask;\n let merge = false;\n let offset = 2;\n let skipMasking = false;\n\n if (options.mask) {\n mask = options.maskBuffer || maskBuffer;\n\n if (options.generateMask) {\n options.generateMask(mask);\n } else {\n if (randomPoolPointer === RANDOM_POOL_SIZE) {\n /* istanbul ignore else */\n if (randomPool === undefined) {\n //\n // This is lazily initialized because server-sent frames must not\n // be masked so it may never be used.\n //\n randomPool = Buffer.alloc(RANDOM_POOL_SIZE);\n }\n\n randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);\n randomPoolPointer = 0;\n }\n\n mask[0] = randomPool[randomPoolPointer++];\n mask[1] = randomPool[randomPoolPointer++];\n mask[2] = randomPool[randomPoolPointer++];\n mask[3] = randomPool[randomPoolPointer++];\n }\n\n skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;\n offset = 6;\n }\n\n let dataLength;\n\n if (typeof data === 'string') {\n if (\n (!options.mask || skipMasking) &&\n options[kByteLength] !== undefined\n ) {\n dataLength = options[kByteLength];\n } else {\n data = Buffer.from(data);\n dataLength = data.length;\n }\n } else {\n dataLength = data.length;\n merge = options.mask && options.readOnly && !skipMasking;\n }\n\n let payloadLength = dataLength;\n\n if (dataLength >= 65536) {\n offset += 8;\n payloadLength = 127;\n } else if (dataLength > 125) {\n offset += 2;\n payloadLength = 126;\n }\n\n const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);\n\n target[0] = options.fin ? options.opcode | 0x80 : options.opcode;\n if (options.rsv1) target[0] |= 0x40;\n\n target[1] = payloadLength;\n\n if (payloadLength === 126) {\n target.writeUInt16BE(dataLength, 2);\n } else if (payloadLength === 127) {\n target[2] = target[3] = 0;\n target.writeUIntBE(dataLength, 4, 6);\n }\n\n if (!options.mask) return [target, data];\n\n target[1] |= 0x80;\n target[offset - 4] = mask[0];\n target[offset - 3] = mask[1];\n target[offset - 2] = mask[2];\n target[offset - 1] = mask[3];\n\n if (skipMasking) return [target, data];\n\n if (merge) {\n applyMask(data, mask, target, offset, dataLength);\n return [target];\n }\n\n applyMask(data, mask, data, 0, dataLength);\n return [target, data];\n }\n\n /**\n * Sends a close message to the other peer.\n *\n * @param {Number} [code] The status code component of the body\n * @param {(String|Buffer)} [data] The message component of the body\n * @param {Boolean} [mask=false] Specifies whether or not to mask the message\n * @param {Function} [cb] Callback\n * @public\n */\n close(code, data, mask, cb) {\n let buf;\n\n if (code === undefined) {\n buf = EMPTY_BUFFER;\n } else if (typeof code !== 'number' || !isValidStatusCode(code)) {\n throw new TypeError('First argument must be a valid error code number');\n } else if (data === undefined || !data.length) {\n buf = Buffer.allocUnsafe(2);\n buf.writeUInt16BE(code, 0);\n } else {\n const length = Buffer.byteLength(data);\n\n if (length > 123) {\n throw new RangeError('The message must not be greater than 123 bytes');\n }\n\n buf = Buffer.allocUnsafe(2 + length);\n buf.writeUInt16BE(code, 0);\n\n if (typeof data === 'string') {\n buf.write(data, 2);\n } else {\n buf.set(data, 2);\n }\n }\n\n const options = {\n [kByteLength]: buf.length,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x08,\n readOnly: false,\n rsv1: false\n };\n\n if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, buf, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(buf, options), cb);\n }\n }\n\n /**\n * Sends a ping message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n ping(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x09,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a pong message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n pong(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x0a,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a data message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Object} options Options object\n * @param {Boolean} [options.binary=false] Specifies whether `data` is binary\n * or text\n * @param {Boolean} [options.compress=false] Specifies whether or not to\n * compress `data`\n * @param {Boolean} [options.fin=false] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Function} [cb] Callback\n * @public\n */\n send(data, options, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n let opcode = options.binary ? 2 : 1;\n let rsv1 = options.compress;\n\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (this._firstFragment) {\n this._firstFragment = false;\n if (\n rsv1 &&\n perMessageDeflate &&\n perMessageDeflate.params[\n perMessageDeflate._isServer\n ? 'server_no_context_takeover'\n : 'client_no_context_takeover'\n ]\n ) {\n rsv1 = byteLength >= perMessageDeflate._threshold;\n }\n this._compress = rsv1;\n } else {\n rsv1 = false;\n opcode = 0;\n }\n\n if (options.fin) this._firstFragment = true;\n\n const opts = {\n [kByteLength]: byteLength,\n fin: options.fin,\n generateMask: this._generateMask,\n mask: options.mask,\n maskBuffer: this._maskBuffer,\n opcode,\n readOnly,\n rsv1\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, this._compress, opts, cb]);\n } else {\n this.getBlobData(data, this._compress, opts, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, this._compress, opts, cb]);\n } else {\n this.dispatch(data, this._compress, opts, cb);\n }\n }\n\n /**\n * Gets the contents of a blob as binary data.\n *\n * @param {Blob} blob The blob\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * the data\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n getBlobData(blob, compress, options, cb) {\n this._bufferedBytes += options[kByteLength];\n this._state = GET_BLOB_DATA;\n\n blob\n .arrayBuffer()\n .then((arrayBuffer) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while the blob was being read'\n );\n\n //\n // `callCallbacks` is called in the next tick to ensure that errors\n // that might be thrown in the callbacks behave like errors thrown\n // outside the promise chain.\n //\n process.nextTick(callCallbacks, this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n const data = toBuffer(arrayBuffer);\n\n if (!compress) {\n this._state = DEFAULT;\n this.sendFrame(Sender.frame(data, options), cb);\n this.dequeue();\n } else {\n this.dispatch(data, compress, options, cb);\n }\n })\n .catch((err) => {\n //\n // `onError` is called in the next tick for the same reason that\n // `callCallbacks` above is.\n //\n process.nextTick(onError, this, err, cb);\n });\n }\n\n /**\n * Dispatches a message.\n *\n * @param {(Buffer|String)} data The message to send\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * `data`\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n dispatch(data, compress, options, cb) {\n if (!compress) {\n this.sendFrame(Sender.frame(data, options), cb);\n return;\n }\n\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n this._bufferedBytes += options[kByteLength];\n this._state = DEFLATING;\n perMessageDeflate.compress(data, options.fin, (_, buf) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while data was being compressed'\n );\n\n callCallbacks(this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n this._state = DEFAULT;\n options.readOnly = false;\n this.sendFrame(Sender.frame(buf, options), cb);\n this.dequeue();\n });\n }\n\n /**\n * Executes queued send operations.\n *\n * @private\n */\n dequeue() {\n while (this._state === DEFAULT && this._queue.length) {\n const params = this._queue.shift();\n\n this._bufferedBytes -= params[3][kByteLength];\n Reflect.apply(params[0], this, params.slice(1));\n }\n }\n\n /**\n * Enqueues a send operation.\n *\n * @param {Array} params Send operation parameters.\n * @private\n */\n enqueue(params) {\n this._bufferedBytes += params[3][kByteLength];\n this._queue.push(params);\n }\n\n /**\n * Sends a frame.\n *\n * @param {(Buffer | String)[]} list The frame to send\n * @param {Function} [cb] Callback\n * @private\n */\n sendFrame(list, cb) {\n if (list.length === 2) {\n this._socket.cork();\n this._socket.write(list[0]);\n this._socket.write(list[1], cb);\n this._socket.uncork();\n } else {\n this._socket.write(list[0], cb);\n }\n }\n}\n\nmodule.exports = Sender;\n\n/**\n * Calls queued callbacks with an error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error to call the callbacks with\n * @param {Function} [cb] The first callback\n * @private\n */\nfunction callCallbacks(sender, err, cb) {\n if (typeof cb === 'function') cb(err);\n\n for (let i = 0; i < sender._queue.length; i++) {\n const params = sender._queue[i];\n const callback = params[params.length - 1];\n\n if (typeof callback === 'function') callback(err);\n }\n}\n\n/**\n * Handles a `Sender` error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error\n * @param {Function} [cb] The first pending callback\n * @private\n */\nfunction onError(sender, err, cb) {\n callCallbacks(sender, err, cb);\n sender.onerror(err);\n}\n","'use strict';\n\nconst { kForOnEventAttribute, kListener } = require('./constants');\n\nconst kCode = Symbol('kCode');\nconst kData = Symbol('kData');\nconst kError = Symbol('kError');\nconst kMessage = Symbol('kMessage');\nconst kReason = Symbol('kReason');\nconst kTarget = Symbol('kTarget');\nconst kType = Symbol('kType');\nconst kWasClean = Symbol('kWasClean');\n\n/**\n * Class representing an event.\n */\nclass Event {\n /**\n * Create a new `Event`.\n *\n * @param {String} type The name of the event\n * @throws {TypeError} If the `type` argument is not specified\n */\n constructor(type) {\n this[kTarget] = null;\n this[kType] = type;\n }\n\n /**\n * @type {*}\n */\n get target() {\n return this[kTarget];\n }\n\n /**\n * @type {String}\n */\n get type() {\n return this[kType];\n }\n}\n\nObject.defineProperty(Event.prototype, 'target', { enumerable: true });\nObject.defineProperty(Event.prototype, 'type', { enumerable: true });\n\n/**\n * Class representing a close event.\n *\n * @extends Event\n */\nclass CloseEvent extends Event {\n /**\n * Create a new `CloseEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {Number} [options.code=0] The status code explaining why the\n * connection was closed\n * @param {String} [options.reason=''] A human-readable string explaining why\n * the connection was closed\n * @param {Boolean} [options.wasClean=false] Indicates whether or not the\n * connection was cleanly closed\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kCode] = options.code === undefined ? 0 : options.code;\n this[kReason] = options.reason === undefined ? '' : options.reason;\n this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;\n }\n\n /**\n * @type {Number}\n */\n get code() {\n return this[kCode];\n }\n\n /**\n * @type {String}\n */\n get reason() {\n return this[kReason];\n }\n\n /**\n * @type {Boolean}\n */\n get wasClean() {\n return this[kWasClean];\n }\n}\n\nObject.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });\n\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent extends Event {\n /**\n * Create a new `ErrorEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.error=null] The error that generated this event\n * @param {String} [options.message=''] The error message\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kError] = options.error === undefined ? null : options.error;\n this[kMessage] = options.message === undefined ? '' : options.message;\n }\n\n /**\n * @type {*}\n */\n get error() {\n return this[kError];\n }\n\n /**\n * @type {String}\n */\n get message() {\n return this[kMessage];\n }\n}\n\nObject.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });\n\n/**\n * Class representing a message event.\n *\n * @extends Event\n */\nclass MessageEvent extends Event {\n /**\n * Create a new `MessageEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.data=null] The message content\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kData] = options.data === undefined ? null : options.data;\n }\n\n /**\n * @type {*}\n */\n get data() {\n return this[kData];\n }\n}\n\nObject.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });\n\n/**\n * This provides methods for emulating the `EventTarget` interface. It's not\n * meant to be used directly.\n *\n * @mixin\n */\nconst EventTarget = {\n /**\n * Register an event listener.\n *\n * @param {String} type A string representing the event type to listen for\n * @param {(Function|Object)} handler The listener to add\n * @param {Object} [options] An options object specifies characteristics about\n * the event listener\n * @param {Boolean} [options.once=false] A `Boolean` indicating that the\n * listener should be invoked at most once after being added. If `true`,\n * the listener would be automatically removed when invoked.\n * @public\n */\n addEventListener(type, handler, options = {}) {\n for (const listener of this.listeners(type)) {\n if (\n !options[kForOnEventAttribute] &&\n listener[kListener] === handler &&\n !listener[kForOnEventAttribute]\n ) {\n return;\n }\n }\n\n let wrapper;\n\n if (type === 'message') {\n wrapper = function onMessage(data, isBinary) {\n const event = new MessageEvent('message', {\n data: isBinary ? data : data.toString()\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'close') {\n wrapper = function onClose(code, message) {\n const event = new CloseEvent('close', {\n code,\n reason: message.toString(),\n wasClean: this._closeFrameReceived && this._closeFrameSent\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'error') {\n wrapper = function onError(error) {\n const event = new ErrorEvent('error', {\n error,\n message: error.message\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'open') {\n wrapper = function onOpen() {\n const event = new Event('open');\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else {\n return;\n }\n\n wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];\n wrapper[kListener] = handler;\n\n if (options.once) {\n this.once(type, wrapper);\n } else {\n this.on(type, wrapper);\n }\n },\n\n /**\n * Remove an event listener.\n *\n * @param {String} type A string representing the event type to remove\n * @param {(Function|Object)} handler The listener to remove\n * @public\n */\n removeEventListener(type, handler) {\n for (const listener of this.listeners(type)) {\n if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {\n this.removeListener(type, listener);\n break;\n }\n }\n }\n};\n\nmodule.exports = {\n CloseEvent,\n ErrorEvent,\n Event,\n EventTarget,\n MessageEvent\n};\n\n/**\n * Call an event listener\n *\n * @param {(Function|Object)} listener The listener to call\n * @param {*} thisArg The value to use as `this`` when calling the listener\n * @param {Event} event The event to pass to the listener\n * @private\n */\nfunction callListener(listener, thisArg, event) {\n if (typeof listener === 'object' && listener.handleEvent) {\n listener.handleEvent.call(listener, event);\n } else {\n listener.call(thisArg, event);\n }\n}\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Adds an offer to the map of extension offers or a parameter to the map of\n * parameters.\n *\n * @param {Object} dest The map of extension offers or parameters\n * @param {String} name The extension or parameter name\n * @param {(Object|Boolean|String)} elem The extension parameters or the\n * parameter value\n * @private\n */\nfunction push(dest, name, elem) {\n if (dest[name] === undefined) dest[name] = [elem];\n else dest[name].push(elem);\n}\n\n/**\n * Parses the `Sec-WebSocket-Extensions` header into an object.\n *\n * @param {String} header The field value of the header\n * @return {Object} The parsed object\n * @public\n */\nfunction parse(header) {\n const offers = Object.create(null);\n let params = Object.create(null);\n let mustUnescape = false;\n let isEscaping = false;\n let inQuotes = false;\n let extensionName;\n let paramName;\n let start = -1;\n let code = -1;\n let end = -1;\n let i = 0;\n\n for (; i < header.length; i++) {\n code = header.charCodeAt(i);\n\n if (extensionName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n const name = header.slice(start, end);\n if (code === 0x2c) {\n push(offers, name, params);\n params = Object.create(null);\n } else {\n extensionName = name;\n }\n\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (paramName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x20 || code === 0x09) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n push(params, header.slice(start, end), true);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n start = end = -1;\n } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {\n paramName = header.slice(start, i);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else {\n //\n // The value of a quoted-string after unescaping must conform to the\n // token ABNF, so only token characters are valid.\n // Ref: https://tools.ietf.org/html/rfc6455#section-9.1\n //\n if (isEscaping) {\n if (tokenChars[code] !== 1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n if (start === -1) start = i;\n else if (!mustUnescape) mustUnescape = true;\n isEscaping = false;\n } else if (inQuotes) {\n if (tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x22 /* '\"' */ && start !== -1) {\n inQuotes = false;\n end = i;\n } else if (code === 0x5c /* '\\' */) {\n isEscaping = true;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {\n inQuotes = true;\n } else if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (start !== -1 && (code === 0x20 || code === 0x09)) {\n if (end === -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n let value = header.slice(start, end);\n if (mustUnescape) {\n value = value.replace(/\\\\/g, '');\n mustUnescape = false;\n }\n push(params, paramName, value);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n paramName = undefined;\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n }\n\n if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n if (end === -1) end = i;\n const token = header.slice(start, end);\n if (extensionName === undefined) {\n push(offers, token, params);\n } else {\n if (paramName === undefined) {\n push(params, token, true);\n } else if (mustUnescape) {\n push(params, paramName, token.replace(/\\\\/g, ''));\n } else {\n push(params, paramName, token);\n }\n push(offers, extensionName, params);\n }\n\n return offers;\n}\n\n/**\n * Builds the `Sec-WebSocket-Extensions` header field value.\n *\n * @param {Object} extensions The map of extensions and parameters to format\n * @return {String} A string representing the given object\n * @public\n */\nfunction format(extensions) {\n return Object.keys(extensions)\n .map((extension) => {\n let configurations = extensions[extension];\n if (!Array.isArray(configurations)) configurations = [configurations];\n return configurations\n .map((params) => {\n return [extension]\n .concat(\n Object.keys(params).map((k) => {\n let values = params[k];\n if (!Array.isArray(values)) values = [values];\n return values\n .map((v) => (v === true ? k : `${k}=${v}`))\n .join('; ');\n })\n )\n .join('; ');\n })\n .join(', ');\n })\n .join(', ');\n}\n\nmodule.exports = { format, parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex|Readable$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst https = require('https');\nconst http = require('http');\nconst net = require('net');\nconst tls = require('tls');\nconst { randomBytes, createHash } = require('crypto');\nconst { Duplex, Readable } = require('stream');\nconst { URL } = require('url');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst Receiver = require('./receiver');\nconst Sender = require('./sender');\nconst { isBlob } = require('./validation');\n\nconst {\n BINARY_TYPES,\n CLOSE_TIMEOUT,\n EMPTY_BUFFER,\n GUID,\n kForOnEventAttribute,\n kListener,\n kStatusCode,\n kWebSocket,\n NOOP\n} = require('./constants');\nconst {\n EventTarget: { addEventListener, removeEventListener }\n} = require('./event-target');\nconst { format, parse } = require('./extension');\nconst { toBuffer } = require('./buffer-util');\n\nconst kAborted = Symbol('kAborted');\nconst protocolVersions = [8, 13];\nconst readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];\nconst subprotocolRegex = /^[!#$%&'*+\\-.0-9A-Z^_`|a-z~]+$/;\n\n/**\n * Class representing a WebSocket.\n *\n * @extends EventEmitter\n */\nclass WebSocket extends EventEmitter {\n /**\n * Create a new `WebSocket`.\n *\n * @param {(String|URL)} address The URL to which to connect\n * @param {(String|String[])} [protocols] The subprotocols\n * @param {Object} [options] Connection options\n */\n constructor(address, protocols, options) {\n super();\n\n this._binaryType = BINARY_TYPES[0];\n this._closeCode = 1006;\n this._closeFrameReceived = false;\n this._closeFrameSent = false;\n this._closeMessage = EMPTY_BUFFER;\n this._closeTimer = null;\n this._errorEmitted = false;\n this._extensions = {};\n this._paused = false;\n this._protocol = '';\n this._readyState = WebSocket.CONNECTING;\n this._receiver = null;\n this._sender = null;\n this._socket = null;\n\n if (address !== null) {\n this._bufferedAmount = 0;\n this._isServer = false;\n this._redirects = 0;\n\n if (protocols === undefined) {\n protocols = [];\n } else if (!Array.isArray(protocols)) {\n if (typeof protocols === 'object' && protocols !== null) {\n options = protocols;\n protocols = [];\n } else {\n protocols = [protocols];\n }\n }\n\n initAsClient(this, address, protocols, options);\n } else {\n this._autoPong = options.autoPong;\n this._closeTimeout = options.closeTimeout;\n this._isServer = true;\n }\n }\n\n /**\n * For historical reasons, the custom \"nodebuffer\" type is used by the default\n * instead of \"blob\".\n *\n * @type {String}\n */\n get binaryType() {\n return this._binaryType;\n }\n\n set binaryType(type) {\n if (!BINARY_TYPES.includes(type)) return;\n\n this._binaryType = type;\n\n //\n // Allow to change `binaryType` on the fly.\n //\n if (this._receiver) this._receiver._binaryType = type;\n }\n\n /**\n * @type {Number}\n */\n get bufferedAmount() {\n if (!this._socket) return this._bufferedAmount;\n\n return this._socket._writableState.length + this._sender._bufferedBytes;\n }\n\n /**\n * @type {String}\n */\n get extensions() {\n return Object.keys(this._extensions).join();\n }\n\n /**\n * @type {Boolean}\n */\n get isPaused() {\n return this._paused;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onclose() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onerror() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onopen() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onmessage() {\n return null;\n }\n\n /**\n * @type {String}\n */\n get protocol() {\n return this._protocol;\n }\n\n /**\n * @type {Number}\n */\n get readyState() {\n return this._readyState;\n }\n\n /**\n * @type {String}\n */\n get url() {\n return this._url;\n }\n\n /**\n * Set up the socket and the internal resources.\n *\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Object} options Options object\n * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.maxPayload=0] The maximum allowed message size\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\n setSocket(socket, head, options) {\n const receiver = new Receiver({\n allowSynchronousEvents: options.allowSynchronousEvents,\n binaryType: this.binaryType,\n extensions: this._extensions,\n isServer: this._isServer,\n maxPayload: options.maxPayload,\n skipUTF8Validation: options.skipUTF8Validation\n });\n\n const sender = new Sender(socket, this._extensions, options.generateMask);\n\n this._receiver = receiver;\n this._sender = sender;\n this._socket = socket;\n\n receiver[kWebSocket] = this;\n sender[kWebSocket] = this;\n socket[kWebSocket] = this;\n\n receiver.on('conclude', receiverOnConclude);\n receiver.on('drain', receiverOnDrain);\n receiver.on('error', receiverOnError);\n receiver.on('message', receiverOnMessage);\n receiver.on('ping', receiverOnPing);\n receiver.on('pong', receiverOnPong);\n\n sender.onerror = senderOnError;\n\n //\n // These methods may not be available if `socket` is just a `Duplex`.\n //\n if (socket.setTimeout) socket.setTimeout(0);\n if (socket.setNoDelay) socket.setNoDelay();\n\n if (head.length > 0) socket.unshift(head);\n\n socket.on('close', socketOnClose);\n socket.on('data', socketOnData);\n socket.on('end', socketOnEnd);\n socket.on('error', socketOnError);\n\n this._readyState = WebSocket.OPEN;\n this.emit('open');\n }\n\n /**\n * Emit the `'close'` event.\n *\n * @private\n */\n emitClose() {\n if (!this._socket) {\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n return;\n }\n\n if (this._extensions[PerMessageDeflate.extensionName]) {\n this._extensions[PerMessageDeflate.extensionName].cleanup();\n }\n\n this._receiver.removeAllListeners();\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n }\n\n /**\n * Start a closing handshake.\n *\n * +----------+ +-----------+ +----------+\n * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -\n * | +----------+ +-----------+ +----------+ |\n * +----------+ +-----------+ |\n * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING\n * +----------+ +-----------+ |\n * | | | +---+ |\n * +------------------------+-->|fin| - - - -\n * | +---+ | +---+\n * - - - - -|fin|<---------------------+\n * +---+\n *\n * @param {Number} [code] Status code explaining why the connection is closing\n * @param {(String|Buffer)} [data] The reason why the connection is\n * closing\n * @public\n */\n close(code, data) {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this.readyState === WebSocket.CLOSING) {\n if (\n this._closeFrameSent &&\n (this._closeFrameReceived || this._receiver._writableState.errorEmitted)\n ) {\n this._socket.end();\n }\n\n return;\n }\n\n this._readyState = WebSocket.CLOSING;\n this._sender.close(code, data, !this._isServer, (err) => {\n //\n // This error is handled by the `'error'` listener on the socket. We only\n // want to know if the close frame has been sent here.\n //\n if (err) return;\n\n this._closeFrameSent = true;\n\n if (\n this._closeFrameReceived ||\n this._receiver._writableState.errorEmitted\n ) {\n this._socket.end();\n }\n });\n\n setCloseTimer(this);\n }\n\n /**\n * Pause the socket.\n *\n * @public\n */\n pause() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = true;\n this._socket.pause();\n }\n\n /**\n * Send a ping.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the ping is sent\n * @public\n */\n ping(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.ping(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Send a pong.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the pong is sent\n * @public\n */\n pong(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.pong(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Resume the socket.\n *\n * @public\n */\n resume() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = false;\n if (!this._receiver._writableState.needDrain) this._socket.resume();\n }\n\n /**\n * Send a data message.\n *\n * @param {*} data The message to send\n * @param {Object} [options] Options object\n * @param {Boolean} [options.binary] Specifies whether `data` is binary or\n * text\n * @param {Boolean} [options.compress] Specifies whether or not to compress\n * `data`\n * @param {Boolean} [options.fin=true] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when data is written out\n * @public\n */\n send(data, options, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof options === 'function') {\n cb = options;\n options = {};\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n const opts = {\n binary: typeof data !== 'string',\n mask: !this._isServer,\n compress: true,\n fin: true,\n ...options\n };\n\n if (!this._extensions[PerMessageDeflate.extensionName]) {\n opts.compress = false;\n }\n\n this._sender.send(data || EMPTY_BUFFER, opts, cb);\n }\n\n /**\n * Forcibly close the connection.\n *\n * @public\n */\n terminate() {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this._socket) {\n this._readyState = WebSocket.CLOSING;\n this._socket.destroy();\n }\n }\n}\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n[\n 'binaryType',\n 'bufferedAmount',\n 'extensions',\n 'isPaused',\n 'protocol',\n 'readyState',\n 'url'\n].forEach((property) => {\n Object.defineProperty(WebSocket.prototype, property, { enumerable: true });\n});\n\n//\n// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.\n// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface\n//\n['open', 'error', 'close', 'message'].forEach((method) => {\n Object.defineProperty(WebSocket.prototype, `on${method}`, {\n enumerable: true,\n get() {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) return listener[kListener];\n }\n\n return null;\n },\n set(handler) {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) {\n this.removeListener(method, listener);\n break;\n }\n }\n\n if (typeof handler !== 'function') return;\n\n this.addEventListener(method, handler, {\n [kForOnEventAttribute]: true\n });\n }\n });\n});\n\nWebSocket.prototype.addEventListener = addEventListener;\nWebSocket.prototype.removeEventListener = removeEventListener;\n\nmodule.exports = WebSocket;\n\n/**\n * Initialize a WebSocket client.\n *\n * @param {WebSocket} websocket The client to initialize\n * @param {(String|URL)} address The URL to which to connect\n * @param {Array} protocols The subprotocols\n * @param {Object} [options] Connection options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any\n * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple\n * times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait\n * for the closing handshake to finish after `websocket.close()` is called\n * @param {Function} [options.finishRequest] A function which can be used to\n * customize the headers of each http request before it is sent\n * @param {Boolean} [options.followRedirects=false] Whether or not to follow\n * redirects\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the\n * handshake request\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Number} [options.maxRedirects=10] The maximum number of redirects\n * allowed\n * @param {String} [options.origin] Value of the `Origin` or\n * `Sec-WebSocket-Origin` header\n * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable\n * permessage-deflate\n * @param {Number} [options.protocolVersion=13] Value of the\n * `Sec-WebSocket-Version` header\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\nfunction initAsClient(websocket, address, protocols, options) {\n const opts = {\n allowSynchronousEvents: true,\n autoPong: true,\n closeTimeout: CLOSE_TIMEOUT,\n protocolVersion: protocolVersions[1],\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: true,\n followRedirects: false,\n maxRedirects: 10,\n ...options,\n socketPath: undefined,\n hostname: undefined,\n protocol: undefined,\n timeout: undefined,\n method: 'GET',\n host: undefined,\n path: undefined,\n port: undefined\n };\n\n websocket._autoPong = opts.autoPong;\n websocket._closeTimeout = opts.closeTimeout;\n\n if (!protocolVersions.includes(opts.protocolVersion)) {\n throw new RangeError(\n `Unsupported protocol version: ${opts.protocolVersion} ` +\n `(supported versions: ${protocolVersions.join(', ')})`\n );\n }\n\n let parsedUrl;\n\n if (address instanceof URL) {\n parsedUrl = address;\n } else {\n try {\n parsedUrl = new URL(address);\n } catch (e) {\n throw new SyntaxError(`Invalid URL: ${address}`);\n }\n }\n\n if (parsedUrl.protocol === 'http:') {\n parsedUrl.protocol = 'ws:';\n } else if (parsedUrl.protocol === 'https:') {\n parsedUrl.protocol = 'wss:';\n }\n\n websocket._url = parsedUrl.href;\n\n const isSecure = parsedUrl.protocol === 'wss:';\n const isIpcUrl = parsedUrl.protocol === 'ws+unix:';\n let invalidUrlMessage;\n\n if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {\n invalidUrlMessage =\n 'The URL\\'s protocol must be one of \"ws:\", \"wss:\", ' +\n '\"http:\", \"https:\", or \"ws+unix:\"';\n } else if (isIpcUrl && !parsedUrl.pathname) {\n invalidUrlMessage = \"The URL's pathname is empty\";\n } else if (parsedUrl.hash) {\n invalidUrlMessage = 'The URL contains a fragment identifier';\n }\n\n if (invalidUrlMessage) {\n const err = new SyntaxError(invalidUrlMessage);\n\n if (websocket._redirects === 0) {\n throw err;\n } else {\n emitErrorAndClose(websocket, err);\n return;\n }\n }\n\n const defaultPort = isSecure ? 443 : 80;\n const key = randomBytes(16).toString('base64');\n const request = isSecure ? https.request : http.request;\n const protocolSet = new Set();\n let perMessageDeflate;\n\n opts.createConnection =\n opts.createConnection || (isSecure ? tlsConnect : netConnect);\n opts.defaultPort = opts.defaultPort || defaultPort;\n opts.port = parsedUrl.port || defaultPort;\n opts.host = parsedUrl.hostname.startsWith('[')\n ? parsedUrl.hostname.slice(1, -1)\n : parsedUrl.hostname;\n opts.headers = {\n ...opts.headers,\n 'Sec-WebSocket-Version': opts.protocolVersion,\n 'Sec-WebSocket-Key': key,\n Connection: 'Upgrade',\n Upgrade: 'websocket'\n };\n opts.path = parsedUrl.pathname + parsedUrl.search;\n opts.timeout = opts.handshakeTimeout;\n\n if (opts.perMessageDeflate) {\n perMessageDeflate = new PerMessageDeflate(\n opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},\n false,\n opts.maxPayload\n );\n opts.headers['Sec-WebSocket-Extensions'] = format({\n [PerMessageDeflate.extensionName]: perMessageDeflate.offer()\n });\n }\n if (protocols.length) {\n for (const protocol of protocols) {\n if (\n typeof protocol !== 'string' ||\n !subprotocolRegex.test(protocol) ||\n protocolSet.has(protocol)\n ) {\n throw new SyntaxError(\n 'An invalid or duplicated subprotocol was specified'\n );\n }\n\n protocolSet.add(protocol);\n }\n\n opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');\n }\n if (opts.origin) {\n if (opts.protocolVersion < 13) {\n opts.headers['Sec-WebSocket-Origin'] = opts.origin;\n } else {\n opts.headers.Origin = opts.origin;\n }\n }\n if (parsedUrl.username || parsedUrl.password) {\n opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;\n }\n\n if (isIpcUrl) {\n const parts = opts.path.split(':');\n\n opts.socketPath = parts[0];\n opts.path = parts[1];\n }\n\n let req;\n\n if (opts.followRedirects) {\n if (websocket._redirects === 0) {\n websocket._originalIpc = isIpcUrl;\n websocket._originalSecure = isSecure;\n websocket._originalHostOrSocketPath = isIpcUrl\n ? opts.socketPath\n : parsedUrl.host;\n\n const headers = options && options.headers;\n\n //\n // Shallow copy the user provided options so that headers can be changed\n // without mutating the original object.\n //\n options = { ...options, headers: {} };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n options.headers[key.toLowerCase()] = value;\n }\n }\n } else if (websocket.listenerCount('redirect') === 0) {\n const isSameHost = isIpcUrl\n ? websocket._originalIpc\n ? opts.socketPath === websocket._originalHostOrSocketPath\n : false\n : websocket._originalIpc\n ? false\n : parsedUrl.host === websocket._originalHostOrSocketPath;\n\n if (!isSameHost || (websocket._originalSecure && !isSecure)) {\n //\n // Match curl 7.77.0 behavior and drop the following headers. These\n // headers are also dropped when following a redirect to a subdomain.\n //\n delete opts.headers.authorization;\n delete opts.headers.cookie;\n\n if (!isSameHost) delete opts.headers.host;\n\n opts.auth = undefined;\n }\n }\n\n //\n // Match curl 7.77.0 behavior and make the first `Authorization` header win.\n // If the `Authorization` header is set, then there is nothing to do as it\n // will take precedence.\n //\n if (opts.auth && !options.headers.authorization) {\n options.headers.authorization =\n 'Basic ' + Buffer.from(opts.auth).toString('base64');\n }\n\n req = websocket._req = request(opts);\n\n if (websocket._redirects) {\n //\n // Unlike what is done for the `'upgrade'` event, no early exit is\n // triggered here if the user calls `websocket.close()` or\n // `websocket.terminate()` from a listener of the `'redirect'` event. This\n // is because the user can also call `request.destroy()` with an error\n // before calling `websocket.close()` or `websocket.terminate()` and this\n // would result in an error being emitted on the `request` object with no\n // `'error'` event listeners attached.\n //\n websocket.emit('redirect', websocket.url, req);\n }\n } else {\n req = websocket._req = request(opts);\n }\n\n if (opts.timeout) {\n req.on('timeout', () => {\n abortHandshake(websocket, req, 'Opening handshake has timed out');\n });\n }\n\n req.on('error', (err) => {\n if (req === null || req[kAborted]) return;\n\n req = websocket._req = null;\n emitErrorAndClose(websocket, err);\n });\n\n req.on('response', (res) => {\n const location = res.headers.location;\n const statusCode = res.statusCode;\n\n if (\n location &&\n opts.followRedirects &&\n statusCode >= 300 &&\n statusCode < 400\n ) {\n if (++websocket._redirects > opts.maxRedirects) {\n abortHandshake(websocket, req, 'Maximum redirects exceeded');\n return;\n }\n\n req.abort();\n\n let addr;\n\n try {\n addr = new URL(location, address);\n } catch (e) {\n const err = new SyntaxError(`Invalid URL: ${location}`);\n emitErrorAndClose(websocket, err);\n return;\n }\n\n initAsClient(websocket, addr, protocols, options);\n } else if (!websocket.emit('unexpected-response', req, res)) {\n abortHandshake(\n websocket,\n req,\n `Unexpected server response: ${res.statusCode}`\n );\n }\n });\n\n req.on('upgrade', (res, socket, head) => {\n websocket.emit('upgrade', res);\n\n //\n // The user may have closed the connection from a listener of the\n // `'upgrade'` event.\n //\n if (websocket.readyState !== WebSocket.CONNECTING) return;\n\n req = websocket._req = null;\n\n const upgrade = res.headers.upgrade;\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n abortHandshake(websocket, socket, 'Invalid Upgrade header');\n return;\n }\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n if (res.headers['sec-websocket-accept'] !== digest) {\n abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');\n return;\n }\n\n const serverProt = res.headers['sec-websocket-protocol'];\n let protError;\n\n if (serverProt !== undefined) {\n if (!protocolSet.size) {\n protError = 'Server sent a subprotocol but none was requested';\n } else if (!protocolSet.has(serverProt)) {\n protError = 'Server sent an invalid subprotocol';\n }\n } else if (protocolSet.size) {\n protError = 'Server sent no subprotocol';\n }\n\n if (protError) {\n abortHandshake(websocket, socket, protError);\n return;\n }\n\n if (serverProt) websocket._protocol = serverProt;\n\n const secWebSocketExtensions = res.headers['sec-websocket-extensions'];\n\n if (secWebSocketExtensions !== undefined) {\n if (!perMessageDeflate) {\n const message =\n 'Server sent a Sec-WebSocket-Extensions header but no extension ' +\n 'was requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n let extensions;\n\n try {\n extensions = parse(secWebSocketExtensions);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n const extensionNames = Object.keys(extensions);\n\n if (\n extensionNames.length !== 1 ||\n extensionNames[0] !== PerMessageDeflate.extensionName\n ) {\n const message = 'Server indicated an extension that was not requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n try {\n perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n websocket._extensions[PerMessageDeflate.extensionName] =\n perMessageDeflate;\n }\n\n websocket.setSocket(socket, head, {\n allowSynchronousEvents: opts.allowSynchronousEvents,\n generateMask: opts.generateMask,\n maxPayload: opts.maxPayload,\n skipUTF8Validation: opts.skipUTF8Validation\n });\n });\n\n if (opts.finishRequest) {\n opts.finishRequest(req, websocket);\n } else {\n req.end();\n }\n}\n\n/**\n * Emit the `'error'` and `'close'` events.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {Error} The error to emit\n * @private\n */\nfunction emitErrorAndClose(websocket, err) {\n websocket._readyState = WebSocket.CLOSING;\n //\n // The following assignment is practically useless and is done only for\n // consistency.\n //\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n websocket.emitClose();\n}\n\n/**\n * Create a `net.Socket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {net.Socket} The newly created socket used to start the connection\n * @private\n */\nfunction netConnect(options) {\n options.path = options.socketPath;\n return net.connect(options);\n}\n\n/**\n * Create a `tls.TLSSocket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {tls.TLSSocket} The newly created socket used to start the connection\n * @private\n */\nfunction tlsConnect(options) {\n options.path = undefined;\n\n if (!options.servername && options.servername !== '') {\n options.servername = net.isIP(options.host) ? '' : options.host;\n }\n\n return tls.connect(options);\n}\n\n/**\n * Abort the handshake and emit an error.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to\n * abort or the socket to destroy\n * @param {String} message The error message\n * @private\n */\nfunction abortHandshake(websocket, stream, message) {\n websocket._readyState = WebSocket.CLOSING;\n\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshake);\n\n if (stream.setHeader) {\n stream[kAborted] = true;\n stream.abort();\n\n if (stream.socket && !stream.socket.destroyed) {\n //\n // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if\n // called after the request completed. See\n // https://github.com/websockets/ws/issues/1869.\n //\n stream.socket.destroy();\n }\n\n process.nextTick(emitErrorAndClose, websocket, err);\n } else {\n stream.destroy(err);\n stream.once('error', websocket.emit.bind(websocket, 'error'));\n stream.once('close', websocket.emitClose.bind(websocket));\n }\n}\n\n/**\n * Handle cases where the `ping()`, `pong()`, or `send()` methods are called\n * when the `readyState` attribute is `CLOSING` or `CLOSED`.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {*} [data] The data to send\n * @param {Function} [cb] Callback\n * @private\n */\nfunction sendAfterClose(websocket, data, cb) {\n if (data) {\n const length = isBlob(data) ? data.size : toBuffer(data).length;\n\n //\n // The `_bufferedAmount` property is used only when the peer is a client and\n // the opening handshake fails. Under these circumstances, in fact, the\n // `setSocket()` method is not called, so the `_socket` and `_sender`\n // properties are set to `null`.\n //\n if (websocket._socket) websocket._sender._bufferedBytes += length;\n else websocket._bufferedAmount += length;\n }\n\n if (cb) {\n const err = new Error(\n `WebSocket is not open: readyState ${websocket.readyState} ` +\n `(${readyStates[websocket.readyState]})`\n );\n process.nextTick(cb, err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'conclude'` event.\n *\n * @param {Number} code The status code\n * @param {Buffer} reason The reason for closing\n * @private\n */\nfunction receiverOnConclude(code, reason) {\n const websocket = this[kWebSocket];\n\n websocket._closeFrameReceived = true;\n websocket._closeMessage = reason;\n websocket._closeCode = code;\n\n if (websocket._socket[kWebSocket] === undefined) return;\n\n websocket._socket.removeListener('data', socketOnData);\n process.nextTick(resume, websocket._socket);\n\n if (code === 1005) websocket.close();\n else websocket.close(code, reason);\n}\n\n/**\n * The listener of the `Receiver` `'drain'` event.\n *\n * @private\n */\nfunction receiverOnDrain() {\n const websocket = this[kWebSocket];\n\n if (!websocket.isPaused) websocket._socket.resume();\n}\n\n/**\n * The listener of the `Receiver` `'error'` event.\n *\n * @param {(RangeError|Error)} err The emitted error\n * @private\n */\nfunction receiverOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket._socket[kWebSocket] !== undefined) {\n websocket._socket.removeListener('data', socketOnData);\n\n //\n // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See\n // https://github.com/websockets/ws/issues/1940.\n //\n process.nextTick(resume, websocket._socket);\n\n websocket.close(err[kStatusCode]);\n }\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'finish'` event.\n *\n * @private\n */\nfunction receiverOnFinish() {\n this[kWebSocket].emitClose();\n}\n\n/**\n * The listener of the `Receiver` `'message'` event.\n *\n * @param {Buffer|ArrayBuffer|Buffer[])} data The message\n * @param {Boolean} isBinary Specifies whether the message is binary or not\n * @private\n */\nfunction receiverOnMessage(data, isBinary) {\n this[kWebSocket].emit('message', data, isBinary);\n}\n\n/**\n * The listener of the `Receiver` `'ping'` event.\n *\n * @param {Buffer} data The data included in the ping frame\n * @private\n */\nfunction receiverOnPing(data) {\n const websocket = this[kWebSocket];\n\n if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);\n websocket.emit('ping', data);\n}\n\n/**\n * The listener of the `Receiver` `'pong'` event.\n *\n * @param {Buffer} data The data included in the pong frame\n * @private\n */\nfunction receiverOnPong(data) {\n this[kWebSocket].emit('pong', data);\n}\n\n/**\n * Resume a readable stream\n *\n * @param {Readable} stream The readable stream\n * @private\n */\nfunction resume(stream) {\n stream.resume();\n}\n\n/**\n * The `Sender` error event handler.\n *\n * @param {Error} The error\n * @private\n */\nfunction senderOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket.readyState === WebSocket.CLOSED) return;\n if (websocket.readyState === WebSocket.OPEN) {\n websocket._readyState = WebSocket.CLOSING;\n setCloseTimer(websocket);\n }\n\n //\n // `socket.end()` is used instead of `socket.destroy()` to allow the other\n // peer to finish sending queued data. There is no need to set a timer here\n // because `CLOSING` means that it is already set or not needed.\n //\n this._socket.end();\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * Set a timer to destroy the underlying raw socket of a WebSocket.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @private\n */\nfunction setCloseTimer(websocket) {\n websocket._closeTimer = setTimeout(\n websocket._socket.destroy.bind(websocket._socket),\n websocket._closeTimeout\n );\n}\n\n/**\n * The listener of the socket `'close'` event.\n *\n * @private\n */\nfunction socketOnClose() {\n const websocket = this[kWebSocket];\n\n this.removeListener('close', socketOnClose);\n this.removeListener('data', socketOnData);\n this.removeListener('end', socketOnEnd);\n\n websocket._readyState = WebSocket.CLOSING;\n\n //\n // The close frame might not have been received or the `'end'` event emitted,\n // for example, if the socket was destroyed due to an error. Ensure that the\n // `receiver` stream is closed after writing any remaining buffered data to\n // it. If the readable side of the socket is in flowing mode then there is no\n // buffered data as everything has been already written. If instead, the\n // socket is paused, any possible buffered data will be read as a single\n // chunk.\n //\n if (\n !this._readableState.endEmitted &&\n !websocket._closeFrameReceived &&\n !websocket._receiver._writableState.errorEmitted &&\n this._readableState.length !== 0\n ) {\n const chunk = this.read(this._readableState.length);\n\n websocket._receiver.write(chunk);\n }\n\n websocket._receiver.end();\n\n this[kWebSocket] = undefined;\n\n clearTimeout(websocket._closeTimer);\n\n if (\n websocket._receiver._writableState.finished ||\n websocket._receiver._writableState.errorEmitted\n ) {\n websocket.emitClose();\n } else {\n websocket._receiver.on('error', receiverOnFinish);\n websocket._receiver.on('finish', receiverOnFinish);\n }\n}\n\n/**\n * The listener of the socket `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction socketOnData(chunk) {\n if (!this[kWebSocket]._receiver.write(chunk)) {\n this.pause();\n }\n}\n\n/**\n * The listener of the socket `'end'` event.\n *\n * @private\n */\nfunction socketOnEnd() {\n const websocket = this[kWebSocket];\n\n websocket._readyState = WebSocket.CLOSING;\n websocket._receiver.end();\n this.end();\n}\n\n/**\n * The listener of the socket `'error'` event.\n *\n * @private\n */\nfunction socketOnError() {\n const websocket = this[kWebSocket];\n\n this.removeListener('error', socketOnError);\n this.on('error', NOOP);\n\n if (websocket) {\n websocket._readyState = WebSocket.CLOSING;\n this.destroy();\n }\n}\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^WebSocket$\" }] */\n'use strict';\n\nconst WebSocket = require('./websocket');\nconst { Duplex } = require('stream');\n\n/**\n * Emits the `'close'` event on a stream.\n *\n * @param {Duplex} stream The stream.\n * @private\n */\nfunction emitClose(stream) {\n stream.emit('close');\n}\n\n/**\n * The listener of the `'end'` event.\n *\n * @private\n */\nfunction duplexOnEnd() {\n if (!this.destroyed && this._writableState.finished) {\n this.destroy();\n }\n}\n\n/**\n * The listener of the `'error'` event.\n *\n * @param {Error} err The error\n * @private\n */\nfunction duplexOnError(err) {\n this.removeListener('error', duplexOnError);\n this.destroy();\n if (this.listenerCount('error') === 0) {\n // Do not suppress the throwing behavior.\n this.emit('error', err);\n }\n}\n\n/**\n * Wraps a `WebSocket` in a duplex stream.\n *\n * @param {WebSocket} ws The `WebSocket` to wrap\n * @param {Object} [options] The options for the `Duplex` constructor\n * @return {Duplex} The duplex stream\n * @public\n */\nfunction createWebSocketStream(ws, options) {\n let terminateOnDestroy = true;\n\n const duplex = new Duplex({\n ...options,\n autoDestroy: false,\n emitClose: false,\n objectMode: false,\n writableObjectMode: false\n });\n\n ws.on('message', function message(msg, isBinary) {\n const data =\n !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;\n\n if (!duplex.push(data)) ws.pause();\n });\n\n ws.once('error', function error(err) {\n if (duplex.destroyed) return;\n\n // Prevent `ws.terminate()` from being called by `duplex._destroy()`.\n //\n // - If the `'error'` event is emitted before the `'open'` event, then\n // `ws.terminate()` is a noop as no socket is assigned.\n // - Otherwise, the error is re-emitted by the listener of the `'error'`\n // event of the `Receiver` object. The listener already closes the\n // connection by calling `ws.close()`. This allows a close frame to be\n // sent to the other peer. If `ws.terminate()` is called right after this,\n // then the close frame might not be sent.\n terminateOnDestroy = false;\n duplex.destroy(err);\n });\n\n ws.once('close', function close() {\n if (duplex.destroyed) return;\n\n duplex.push(null);\n });\n\n duplex._destroy = function (err, callback) {\n if (ws.readyState === ws.CLOSED) {\n callback(err);\n process.nextTick(emitClose, duplex);\n return;\n }\n\n let called = false;\n\n ws.once('error', function error(err) {\n called = true;\n callback(err);\n });\n\n ws.once('close', function close() {\n if (!called) callback(err);\n process.nextTick(emitClose, duplex);\n });\n\n if (terminateOnDestroy) ws.terminate();\n };\n\n duplex._final = function (callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._final(callback);\n });\n return;\n }\n\n // If the value of the `_socket` property is `null` it means that `ws` is a\n // client websocket and the handshake failed. In fact, when this happens, a\n // socket is never assigned to the websocket. Wait for the `'error'` event\n // that will be emitted by the websocket.\n if (ws._socket === null) return;\n\n if (ws._socket._writableState.finished) {\n callback();\n if (duplex._readableState.endEmitted) duplex.destroy();\n } else {\n ws._socket.once('finish', function finish() {\n // `duplex` is not destroyed here because the `'end'` event will be\n // emitted on `duplex` after this `'finish'` event. The EOF signaling\n // `null` chunk is, in fact, pushed when the websocket emits `'close'`.\n callback();\n });\n ws.close();\n }\n };\n\n duplex._read = function () {\n if (ws.isPaused) ws.resume();\n };\n\n duplex._write = function (chunk, encoding, callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._write(chunk, encoding, callback);\n });\n return;\n }\n\n ws.send(chunk, callback);\n };\n\n duplex.on('end', duplexOnEnd);\n duplex.on('error', duplexOnError);\n return duplex;\n}\n\nmodule.exports = createWebSocketStream;\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.\n *\n * @param {String} header The field value of the header\n * @return {Set} The subprotocol names\n * @public\n */\nfunction parse(header) {\n const protocols = new Set();\n let start = -1;\n let end = -1;\n let i = 0;\n\n for (i; i < header.length; i++) {\n const code = header.charCodeAt(i);\n\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n\n const protocol = header.slice(start, end);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n\n if (start === -1 || end !== -1) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n const protocol = header.slice(start, i);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n return protocols;\n}\n\nmodule.exports = { parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst http = require('http');\nconst { Duplex } = require('stream');\nconst { createHash } = require('crypto');\n\nconst extension = require('./extension');\nconst PerMessageDeflate = require('./permessage-deflate');\nconst subprotocol = require('./subprotocol');\nconst WebSocket = require('./websocket');\nconst { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');\n\nconst keyRegex = /^[+/0-9A-Za-z]{22}==$/;\n\nconst RUNNING = 0;\nconst CLOSING = 1;\nconst CLOSED = 2;\n\n/**\n * Class representing a WebSocket server.\n *\n * @extends EventEmitter\n */\nclass WebSocketServer extends EventEmitter {\n /**\n * Create a `WebSocketServer` instance.\n *\n * @param {Object} options Configuration options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.backlog=511] The maximum length of the queue of\n * pending connections\n * @param {Boolean} [options.clientTracking=true] Specifies whether or not to\n * track clients\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to\n * wait for the closing handshake to finish after `websocket.close()` is\n * called\n * @param {Function} [options.handleProtocols] A hook to handle protocols\n * @param {String} [options.host] The hostname where to bind the server\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Boolean} [options.noServer=false] Enable no server mode\n * @param {String} [options.path] Accept only connections matching this path\n * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable\n * permessage-deflate\n * @param {Number} [options.port] The port where to bind the server\n * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S\n * server to use\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @param {Function} [options.verifyClient] A hook to reject connections\n * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`\n * class to use. It must be the `WebSocket` class or class that extends it\n * @param {Function} [callback] A listener for the `listening` event\n */\n constructor(options, callback) {\n super();\n\n options = {\n allowSynchronousEvents: true,\n autoPong: true,\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: false,\n handleProtocols: null,\n clientTracking: true,\n closeTimeout: CLOSE_TIMEOUT,\n verifyClient: null,\n noServer: false,\n backlog: null, // use default (511 as implemented in net.js)\n server: null,\n host: null,\n path: null,\n port: null,\n WebSocket,\n ...options\n };\n\n if (\n (options.port == null && !options.server && !options.noServer) ||\n (options.port != null && (options.server || options.noServer)) ||\n (options.server && options.noServer)\n ) {\n throw new TypeError(\n 'One and only one of the \"port\", \"server\", or \"noServer\" options ' +\n 'must be specified'\n );\n }\n\n if (options.port != null) {\n this._server = http.createServer((req, res) => {\n const body = http.STATUS_CODES[426];\n\n res.writeHead(426, {\n 'Content-Length': body.length,\n 'Content-Type': 'text/plain'\n });\n res.end(body);\n });\n this._server.listen(\n options.port,\n options.host,\n options.backlog,\n callback\n );\n } else if (options.server) {\n this._server = options.server;\n }\n\n if (this._server) {\n const emitConnection = this.emit.bind(this, 'connection');\n\n this._removeListeners = addListeners(this._server, {\n listening: this.emit.bind(this, 'listening'),\n error: this.emit.bind(this, 'error'),\n upgrade: (req, socket, head) => {\n this.handleUpgrade(req, socket, head, emitConnection);\n }\n });\n }\n\n if (options.perMessageDeflate === true) options.perMessageDeflate = {};\n if (options.clientTracking) {\n this.clients = new Set();\n this._shouldEmitClose = false;\n }\n\n this.options = options;\n this._state = RUNNING;\n }\n\n /**\n * Returns the bound address, the address family name, and port of the server\n * as reported by the operating system if listening on an IP socket.\n * If the server is listening on a pipe or UNIX domain socket, the name is\n * returned as a string.\n *\n * @return {(Object|String|null)} The address of the server\n * @public\n */\n address() {\n if (this.options.noServer) {\n throw new Error('The server is operating in \"noServer\" mode');\n }\n\n if (!this._server) return null;\n return this._server.address();\n }\n\n /**\n * Stop the server from accepting new connections and emit the `'close'` event\n * when all existing connections are closed.\n *\n * @param {Function} [cb] A one-time listener for the `'close'` event\n * @public\n */\n close(cb) {\n if (this._state === CLOSED) {\n if (cb) {\n this.once('close', () => {\n cb(new Error('The server is not running'));\n });\n }\n\n process.nextTick(emitClose, this);\n return;\n }\n\n if (cb) this.once('close', cb);\n\n if (this._state === CLOSING) return;\n this._state = CLOSING;\n\n if (this.options.noServer || this.options.server) {\n if (this._server) {\n this._removeListeners();\n this._removeListeners = this._server = null;\n }\n\n if (this.clients) {\n if (!this.clients.size) {\n process.nextTick(emitClose, this);\n } else {\n this._shouldEmitClose = true;\n }\n } else {\n process.nextTick(emitClose, this);\n }\n } else {\n const server = this._server;\n\n this._removeListeners();\n this._removeListeners = this._server = null;\n\n //\n // The HTTP/S server was created internally. Close it, and rely on its\n // `'close'` event.\n //\n server.close(() => {\n emitClose(this);\n });\n }\n }\n\n /**\n * See if a given request should be handled by this server instance.\n *\n * @param {http.IncomingMessage} req Request object to inspect\n * @return {Boolean} `true` if the request is valid, else `false`\n * @public\n */\n shouldHandle(req) {\n if (this.options.path) {\n const index = req.url.indexOf('?');\n const pathname = index !== -1 ? req.url.slice(0, index) : req.url;\n\n if (pathname !== this.options.path) return false;\n }\n\n return true;\n }\n\n /**\n * Handle a HTTP Upgrade request.\n *\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @public\n */\n handleUpgrade(req, socket, head, cb) {\n socket.on('error', socketOnError);\n\n const key = req.headers['sec-websocket-key'];\n const upgrade = req.headers.upgrade;\n const version = +req.headers['sec-websocket-version'];\n\n if (req.method !== 'GET') {\n const message = 'Invalid HTTP method';\n abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);\n return;\n }\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n const message = 'Invalid Upgrade header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (key === undefined || !keyRegex.test(key)) {\n const message = 'Missing or invalid Sec-WebSocket-Key header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (version !== 13 && version !== 8) {\n const message = 'Missing or invalid Sec-WebSocket-Version header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {\n 'Sec-WebSocket-Version': '13, 8'\n });\n return;\n }\n\n if (!this.shouldHandle(req)) {\n abortHandshake(socket, 400);\n return;\n }\n\n const secWebSocketProtocol = req.headers['sec-websocket-protocol'];\n let protocols = new Set();\n\n if (secWebSocketProtocol !== undefined) {\n try {\n protocols = subprotocol.parse(secWebSocketProtocol);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Protocol header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n const secWebSocketExtensions = req.headers['sec-websocket-extensions'];\n const extensions = {};\n\n if (\n this.options.perMessageDeflate &&\n secWebSocketExtensions !== undefined\n ) {\n const perMessageDeflate = new PerMessageDeflate(\n this.options.perMessageDeflate,\n true,\n this.options.maxPayload\n );\n\n try {\n const offers = extension.parse(secWebSocketExtensions);\n\n if (offers[PerMessageDeflate.extensionName]) {\n perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);\n extensions[PerMessageDeflate.extensionName] = perMessageDeflate;\n }\n } catch (err) {\n const message =\n 'Invalid or unacceptable Sec-WebSocket-Extensions header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n //\n // Optionally call external client verification handler.\n //\n if (this.options.verifyClient) {\n const info = {\n origin:\n req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],\n secure: !!(req.socket.authorized || req.socket.encrypted),\n req\n };\n\n if (this.options.verifyClient.length === 2) {\n this.options.verifyClient(info, (verified, code, message, headers) => {\n if (!verified) {\n return abortHandshake(socket, code || 401, message, headers);\n }\n\n this.completeUpgrade(\n extensions,\n key,\n protocols,\n req,\n socket,\n head,\n cb\n );\n });\n return;\n }\n\n if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);\n }\n\n this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);\n }\n\n /**\n * Upgrade the connection to WebSocket.\n *\n * @param {Object} extensions The accepted extensions\n * @param {String} key The value of the `Sec-WebSocket-Key` header\n * @param {Set} protocols The subprotocols\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @throws {Error} If called more than once with the same socket\n * @private\n */\n completeUpgrade(extensions, key, protocols, req, socket, head, cb) {\n //\n // Destroy the socket if the client has already sent a FIN packet.\n //\n if (!socket.readable || !socket.writable) return socket.destroy();\n\n if (socket[kWebSocket]) {\n throw new Error(\n 'server.handleUpgrade() was called more than once with the same ' +\n 'socket, possibly due to a misconfiguration'\n );\n }\n\n if (this._state > RUNNING) return abortHandshake(socket, 503);\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${digest}`\n ];\n\n const ws = new this.options.WebSocket(null, undefined, this.options);\n\n if (protocols.size) {\n //\n // Optionally call external protocol selection handler.\n //\n const protocol = this.options.handleProtocols\n ? this.options.handleProtocols(protocols, req)\n : protocols.values().next().value;\n\n if (protocol) {\n headers.push(`Sec-WebSocket-Protocol: ${protocol}`);\n ws._protocol = protocol;\n }\n }\n\n if (extensions[PerMessageDeflate.extensionName]) {\n const params = extensions[PerMessageDeflate.extensionName].params;\n const value = extension.format({\n [PerMessageDeflate.extensionName]: [params]\n });\n headers.push(`Sec-WebSocket-Extensions: ${value}`);\n ws._extensions = extensions;\n }\n\n //\n // Allow external modification/inspection of handshake headers.\n //\n this.emit('headers', headers, req);\n\n socket.write(headers.concat('\\r\\n').join('\\r\\n'));\n socket.removeListener('error', socketOnError);\n\n ws.setSocket(socket, head, {\n allowSynchronousEvents: this.options.allowSynchronousEvents,\n maxPayload: this.options.maxPayload,\n skipUTF8Validation: this.options.skipUTF8Validation\n });\n\n if (this.clients) {\n this.clients.add(ws);\n ws.on('close', () => {\n this.clients.delete(ws);\n\n if (this._shouldEmitClose && !this.clients.size) {\n process.nextTick(emitClose, this);\n }\n });\n }\n\n cb(ws, req);\n }\n}\n\nmodule.exports = WebSocketServer;\n\n/**\n * Add event listeners on an `EventEmitter` using a map of <event, listener>\n * pairs.\n *\n * @param {EventEmitter} server The event emitter\n * @param {Object.<String, Function>} map The listeners to add\n * @return {Function} A function that will remove the added listeners when\n * called\n * @private\n */\nfunction addListeners(server, map) {\n for (const event of Object.keys(map)) server.on(event, map[event]);\n\n return function removeListeners() {\n for (const event of Object.keys(map)) {\n server.removeListener(event, map[event]);\n }\n };\n}\n\n/**\n * Emit a `'close'` event on an `EventEmitter`.\n *\n * @param {EventEmitter} server The event emitter\n * @private\n */\nfunction emitClose(server) {\n server._state = CLOSED;\n server.emit('close');\n}\n\n/**\n * Handle socket errors.\n *\n * @private\n */\nfunction socketOnError() {\n this.destroy();\n}\n\n/**\n * Close the connection when preconditions are not fulfilled.\n *\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} [message] The HTTP response body\n * @param {Object} [headers] Additional HTTP response headers\n * @private\n */\nfunction abortHandshake(socket, code, message, headers) {\n //\n // The socket is writable unless the user destroyed or ended it before calling\n // `server.handleUpgrade()` or in the `verifyClient` function, which is a user\n // error. Handling this does not make much sense as the worst that can happen\n // is that some of the data written by the user might be discarded due to the\n // call to `socket.end()` below, which triggers an `'error'` event that in\n // turn causes the socket to be destroyed.\n //\n message = message || http.STATUS_CODES[code];\n headers = {\n Connection: 'close',\n 'Content-Type': 'text/html',\n 'Content-Length': Buffer.byteLength(message),\n ...headers\n };\n\n socket.once('finish', socket.destroy);\n\n socket.end(\n `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\\r\\n` +\n Object.keys(headers)\n .map((h) => `${h}: ${headers[h]}`)\n .join('\\r\\n') +\n '\\r\\n\\r\\n' +\n message\n );\n}\n\n/**\n * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least\n * one listener for it, otherwise call `abortHandshake()`.\n *\n * @param {WebSocketServer} server The WebSocket server\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} message The HTTP response body\n * @param {Object} [headers] The HTTP response headers\n * @private\n */\nfunction abortHandshakeOrEmitwsClientError(\n server,\n req,\n socket,\n code,\n message,\n headers\n) {\n if (server.listenerCount('wsClientError')) {\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);\n\n server.emit('wsClientError', err, socket, req);\n } else {\n abortHandshake(socket, code, message, headers);\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"./logger.js\";\nimport {\n createVersionAwareLogger,\n PluginFileLogger as PluginLogger,\n} from \"./logger.js\";\nimport {\n RecordingStorage,\n type RecordingStatusEvent,\n} from \"./recording/index.js\";\nimport type { NotificationStorage } from \"./notification/storage.js\";\nimport { getStateFallbackNotificationDir } from \"./notification/storage.js\";\nimport { registerLightRulesGateway } from \"./light-rules/gateway.js\";\nimport {\n LightRulesEvaluatorJob,\n type CronServiceLike,\n} from \"./light-rules/evaluator-job.js\";\nimport { migrateLegacyLightRuleTasks } from \"./light-rules/migration.js\";\nimport { LightRuleRegistry } from \"./light-rules/registry.js\";\nimport { registerAutoUpdateLifecycle } from \"./plugin/auto-update.js\";\nimport { registerPluginCli } from \"./plugin/cli.js\";\nimport { registerLightControlTool } from \"./plugin/light-control.js\";\nimport {\n registerRelayTunnelLifecycle,\n registerStorageLifecycle,\n} from \"./plugin/lifecycle.js\";\nimport { registerNotificationInterfaces } from \"./plugin/notifications.js\";\nimport { registerRecordingInterfaces } from \"./plugin/recordings.js\";\nimport { isPluginCliInvocation } from \"./plugin/runtime-mode.js\";\nimport type { GatewayHandler } from \"./plugin/shared.js\";\nimport type { PluginConfig, RawNotification } from \"./types.js\";\nimport type { BroadcastFn } from \"./update/types.js\";\n\nexport default {\n id: \"phone-notifications\",\n name: \"Phone Notifications & Light Control\",\n\n register(api: OpenClawPluginApi) {\n const config = (api.pluginConfig ?? {}) as PluginConfig;\n const ignoredApps = new Set(config.ignoredApps ?? []);\n\n let storage: NotificationStorage | null = null;\n let recordingStorage: RecordingStorage | null = null;\n let broadcastFn: BroadcastFn | null = null;\n let cronService: CronServiceLike | null = null;\n let autoUpdateLifecycle: ReturnType<typeof registerAutoUpdateLifecycle> | null = null;\n\n const openclawDir = api.runtime.state.resolveStateDir();\n const logger: Logger = openclawDir\n ? new PluginLogger(api.logger, openclawDir)\n : createVersionAwareLogger(api.logger);\n\n const lightRuleCtx: { workspaceDir?: string; stateDir?: string } = {\n stateDir: openclawDir,\n };\n const asrDataDir =\n openclawDir ??\n process.env.OPENCLAW_STATE_DIR ??\n process.env.QCLAW_STATE_DIR ??\n process.cwd();\n\n if (isPluginCliInvocation()) {\n registerPluginCli(api, {\n logger,\n openclawDir,\n });\n logger.info(\n \"检测到插件 CLI 命令执行上下文,仅注册 CLI,跳过后台服务以避免影响 Relay tunnel 常驻连接\",\n );\n return;\n }\n\n function cacheBroadcast(broadcast: BroadcastFn | undefined): void {\n if (!broadcast) {\n return;\n }\n\n const changed = broadcastFn !== broadcast;\n broadcastFn = broadcast;\n if (changed) {\n autoUpdateLifecycle?.notifyBroadcastReady();\n }\n }\n\n function registerGatewayMethodWithBroadcastCapture(\n method: string,\n handler: GatewayHandler,\n ): void {\n api.registerGatewayMethod(method, (opts) => {\n cacheBroadcast(opts.context?.broadcast);\n if (opts.context?.cron) {\n cronService = opts.context.cron as CronServiceLike;\n }\n return handler(opts);\n });\n }\n\n function filterNotifications(items: RawNotification[]): RawNotification[] {\n return items.filter((notification) => !ignoredApps.has(notification.app));\n }\n\n function notifyRecordingStatus(event: RecordingStatusEvent): void {\n if (!broadcastFn) {\n logger.warn(\n `[recording.status] broadcast 不可用,跳过状态事件: ${event.recordingId} -> ${event.transfer_status}`,\n );\n return;\n }\n\n broadcastFn(\"recording.status\", event);\n }\n\n const lightRuleRegistry = new LightRuleRegistry(lightRuleCtx);\n const lightRulesEvaluatorJob = new LightRulesEvaluatorJob({\n logger,\n registry: lightRuleRegistry,\n subagentRunner: api.runtime.subagent,\n getNotificationsDir: () =>\n openclawDir ? getStateFallbackNotificationDir(openclawDir) : undefined,\n });\n\n registerStorageLifecycle({\n api,\n config,\n logger,\n lightRuleCtx,\n setStorage(nextStorage) {\n storage = nextStorage;\n },\n setRecordingStorage(nextRecordingStorage) {\n recordingStorage = nextRecordingStorage;\n },\n onStorageReady() {\n // storage service start 完成后 lightRuleCtx 才被回填到真实的 workspaceDir,\n // 此时运行迁移(清理旧版 fetch.py / README.md)并重新扫盘加载已有规则。\n migrateLegacyLightRuleTasks(lightRuleCtx, logger);\n lightRuleRegistry.reload();\n },\n });\n\n const tunnelService = registerRelayTunnelLifecycle({\n api,\n config,\n logger,\n openclawDir,\n });\n\n registerNotificationInterfaces({\n api,\n logger,\n getStorage: () => storage,\n filterNotifications,\n registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,\n tunnelService,\n onAfterIngest: (insertedCount, cron) => {\n void lightRulesEvaluatorJob.triggerIfNeeded(cron, insertedCount);\n },\n getCronForHttpIngest: () => cronService,\n });\n\n registerLightControlTool(api, logger);\n\n registerRecordingInterfaces({\n api,\n logger,\n asrDataDir,\n getRecordingStorage: () => recordingStorage,\n notifyRecordingStatus,\n registerGatewayMethod: registerGatewayMethodWithBroadcastCapture,\n shouldBroadcastStatusOnHttp: () => !!broadcastFn,\n tunnelService,\n });\n\n registerLightRulesGateway(api, lightRuleRegistry, logger, cacheBroadcast);\n logger.info(\n \"Gateway 灯效规则方法已注册: lightrules.list / lightrules.create / lightrules.update / lightrules.delete\",\n );\n\n autoUpdateLifecycle = registerAutoUpdateLifecycle({\n api,\n config,\n logger,\n getBroadcastFn: () => broadcastFn,\n cacheBroadcast,\n tunnelService,\n });\n\n registerPluginCli(api, {\n logger,\n openclawDir,\n });\n },\n};\n","import { appendFileSync, mkdirSync, readdirSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { PLUGIN_VERSION } from \"./version.js\";\n\nexport interface Logger {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n}\n\nconst DEFAULT_LOG_RETENTION_DAYS = 30;\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nexport interface PluginFileLoggerOptions {\n version?: string;\n retentionDays?: number;\n}\n\nexport function isBetaPluginVersion(version = PLUGIN_VERSION): boolean {\n return /\\bbeta\\b/i.test(version);\n}\n\nexport function createVersionAwareLogger(\n upstream: Logger,\n options: Pick<PluginFileLoggerOptions, \"version\"> = {},\n): Logger {\n if (isBetaPluginVersion(options.version ?? PLUGIN_VERSION)) {\n return upstream;\n }\n\n return {\n info() {\n // 正式版静默 INFO,保留 WARN/ERROR。\n },\n warn(msg: string) {\n upstream.warn(msg);\n },\n error(msg: string) {\n upstream.error(msg);\n },\n };\n}\n\n/**\n * 插件级文件 Logger。\n * 在调用原始 api.logger 的同时,把日志追加写入\n * `<stateDir>/plugins/phone-notifications/logs/YYYY-MM-DD.log`。\n * beta 版本保留 INFO;正式版只记录 WARN 及以上。\n */\nexport class PluginFileLogger implements Logger {\n private readonly logsDir: string;\n private readonly infoEnabled: boolean;\n private readonly retentionDays: number;\n private lastPruneDateKey: string | null = null;\n\n constructor(\n private readonly upstream: Logger,\n stateDir: string,\n options: PluginFileLoggerOptions = {},\n ) {\n this.logsDir = join(stateDir, \"plugins\", \"phone-notifications\", \"logs\");\n this.infoEnabled = isBetaPluginVersion(options.version ?? PLUGIN_VERSION);\n this.retentionDays =\n Number.isFinite(options.retentionDays) && (options.retentionDays ?? 0) > 0\n ? options.retentionDays!\n : DEFAULT_LOG_RETENTION_DAYS;\n\n mkdirSync(this.logsDir, { recursive: true });\n const now = new Date();\n this.pruneExpiredLogs(now);\n this.lastPruneDateKey = formatDate(now);\n }\n\n info(msg: string): void {\n this.prepareLogDate(new Date());\n if (!this.infoEnabled) {\n return;\n }\n this.upstream.info(msg);\n this.append(\"INFO\", msg);\n }\n\n warn(msg: string): void {\n this.upstream.warn(msg);\n this.append(\"WARN\", msg);\n }\n\n error(msg: string): void {\n this.upstream.error(msg);\n this.append(\"ERROR\", msg);\n }\n\n private append(level: string, msg: string): void {\n const now = new Date();\n const dateKey = this.prepareLogDate(now);\n const time = formatLocalTimestamp(now);\n const line = `${time} [${level}] ${msg}\\n`;\n try {\n appendFileSync(join(this.logsDir, `${dateKey}.log`), line);\n } catch {\n // 写文件失败不影响主流程\n }\n }\n\n private prepareLogDate(now: Date): string {\n const dateKey = formatDate(now);\n if (this.lastPruneDateKey !== dateKey) {\n this.pruneExpiredLogs(now);\n this.lastPruneDateKey = dateKey;\n }\n return dateKey;\n }\n\n private pruneExpiredLogs(now: Date): void {\n const cutoffMs = now.getTime() - this.retentionDays * DAY_MS;\n const cutoffDate = formatDate(new Date(cutoffMs));\n\n try {\n for (const entry of readdirSync(this.logsDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.log$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.logsDir, entry.name), { force: true });\n }\n }\n } catch {\n // 清理失败不影响主流程\n }\n }\n}\n\nfunction formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\nexport function formatLocalTimestamp(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n const hh = String(d.getHours()).padStart(2, \"0\");\n const mm = String(d.getMinutes()).padStart(2, \"0\");\n const ss = String(d.getSeconds()).padStart(2, \"0\");\n const ms = String(d.getMilliseconds()).padStart(3, \"0\");\n\n const offsetMinutes = -d.getTimezoneOffset();\n const sign = offsetMinutes >= 0 ? \"+\" : \"-\";\n const absOffsetMinutes = Math.abs(offsetMinutes);\n const offsetHours = String(Math.floor(absOffsetMinutes / 60)).padStart(2, \"0\");\n const offsetMins = String(absOffsetMinutes % 60).padStart(2, \"0\");\n\n return `${y}-${m}-${day}T${hh}:${mm}:${ss}.${ms}${sign}${offsetHours}:${offsetMins}`;\n}\n","import { readFileSync } from \"node:fs\";\n\ndeclare const __PLUGIN_VERSION__: string | undefined;\n\ninterface PackageJson {\n version?: string;\n}\n\nfunction readBuildInjectedVersion(): string | undefined {\n if (typeof __PLUGIN_VERSION__ !== \"string\") {\n return undefined;\n }\n\n const version = __PLUGIN_VERSION__.trim();\n return version || undefined;\n}\n\nfunction readPluginVersionFromPackageJson(): string | undefined {\n try {\n const packageJsonUrl = new URL(\"../package.json\", import.meta.url);\n const packageJson = JSON.parse(\n readFileSync(packageJsonUrl, \"utf-8\"),\n ) as PackageJson;\n const version = packageJson.version?.trim();\n return version || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport const PLUGIN_VERSION =\n readBuildInjectedVersion() ??\n readPluginVersionFromPackageJson() ??\n \"unknown\";\n","import {\n accessSync,\n mkdirSync,\n appendFileSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n existsSync,\n rmSync,\n constants,\n} from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport type { PluginConfig, RawNotification } from \"../types.js\";\n\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\nexport interface StorageContext {\n stateDir: string;\n workspaceDir?: string;\n}\n\n/** Stored notification entry (JSON format, append-only) */\nexport interface StoredNotification {\n /** 包名 */\n appName: string;\n /** 应用显示名(由映射补全),缺省时与 appName 一致 */\n appDisplayName?: string;\n title: string;\n content: string;\n /** ISO 8601 with timezone, e.g. \"2026-03-02T08:30:00+08:00\" */\n timestamp: string;\n}\n\nconst NOTIFICATION_DIR_NAME = \"notifications\";\nconst ID_INDEX_DIR_NAME = \".ids\";\nconst CONTENT_KEY_INDEX_DIR_NAME = \".keys\";\n\nexport interface NotificationIngestResult {\n received: number;\n ingested: number;\n dedupedById: number;\n dedupedByContent: number;\n invalid: number;\n /**\n * 本次 ingest 实际新写入的条目(去重 / 非法之后的产物)。\n * 用于后续事件驱动链路(如 light-rule agent 评估)拿到本次新增的通知列表,\n * 不需要重新读盘。\n */\n inserted: StoredNotification[];\n}\n\ntype WriteOutcome =\n | { kind: \"ingested\"; entry: StoredNotification }\n | { kind: \"dedupedById\" }\n | { kind: \"dedupedByContent\" }\n | { kind: \"invalid\" };\n\nexport function getStateFallbackNotificationDir(stateDir: string): string {\n return join(stateDir, \"plugins\", \"phone-notifications\", NOTIFICATION_DIR_NAME);\n}\n\nfunction ensureWritableDirectory(dir: string): boolean {\n try {\n mkdirSync(dir, { recursive: true });\n accessSync(dir, constants.R_OK | constants.W_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function resolveNotificationStorageDir(\n ctx: StorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): string {\n // 优先使用 stateDir(插件私有稳定路径),避免通知随 workspace 切换而分散\n const stateNotifDir = getStateFallbackNotificationDir(ctx.stateDir);\n\n if (ensureWritableDirectory(stateNotifDir)) {\n logger.info(`通知将写入 stateDir 路径: ${stateNotifDir}`);\n return stateNotifDir;\n }\n\n // stateDir 不可用时回退到 workspaceDir\n if (ctx.workspaceDir) {\n const workspaceDir = join(ctx.workspaceDir, NOTIFICATION_DIR_NAME);\n if (ensureWritableDirectory(workspaceDir)) {\n logger.warn(\n `stateDir 不可用,通知已回退到 workspace 路径: ${workspaceDir}`,\n );\n return workspaceDir;\n }\n }\n\n throw new Error(`通知存储目录不可用: ${stateNotifDir}`);\n}\n\n/** 包名 → 应用显示名(异步,未命中时内部可拉取后返回);不提供则落库仅用 appName */\nexport type ResolveDisplayName = (packageName: string) => Promise<string>;\n\nexport class NotificationStorage {\n private dir: string;\n private idIndexDir: string;\n private contentKeyIndexDir: string;\n private idCache = new Map<string, Set<string>>();\n private contentKeyCache = new Map<string, Set<string>>();\n private dateWriteChains = new Map<string, Promise<void>>();\n private resolveDisplayName: ResolveDisplayName | undefined;\n\n constructor(\n dir: string,\n private config: PluginConfig,\n private logger: Logger,\n resolveDisplayName?: ResolveDisplayName,\n ) {\n this.dir = dir;\n this.idIndexDir = join(dir, ID_INDEX_DIR_NAME);\n this.contentKeyIndexDir = join(dir, CONTENT_KEY_INDEX_DIR_NAME);\n this.resolveDisplayName = resolveDisplayName;\n }\n\n async init() {\n mkdirSync(this.dir, { recursive: true });\n mkdirSync(this.idIndexDir, { recursive: true });\n rmSync(this.contentKeyIndexDir, { recursive: true, force: true });\n mkdirSync(this.contentKeyIndexDir, { recursive: true });\n }\n\n async ingest(items: RawNotification[]): Promise<NotificationIngestResult> {\n const result: NotificationIngestResult = {\n received: items.length,\n ingested: 0,\n dedupedById: 0,\n dedupedByContent: 0,\n invalid: 0,\n inserted: [],\n };\n\n for (const n of items) {\n const outcome = await this.writeNotification(n);\n switch (outcome.kind) {\n case \"ingested\":\n result.ingested += 1;\n result.inserted.push(outcome.entry);\n break;\n case \"dedupedById\":\n result.dedupedById += 1;\n break;\n case \"dedupedByContent\":\n result.dedupedByContent += 1;\n break;\n case \"invalid\":\n result.invalid += 1;\n break;\n }\n }\n this.prune();\n return result;\n }\n\n private async writeNotification(n: RawNotification): Promise<WriteOutcome> {\n const ts = new Date(n.timestamp);\n if (Number.isNaN(ts.getTime())) {\n this.logger.warn(`忽略非法 timestamp 的通知: ${n.id}`);\n return { kind: \"invalid\" };\n }\n\n const dateKey = this.formatDate(ts);\n const filePath = join(this.dir, `${dateKey}.json`);\n const normalizedId = typeof n.id === \"string\" ? n.id.trim() : \"\";\n const entry = this.buildStoredNotification(n);\n\n return this.withDateWriteLock(dateKey, async () => {\n if (normalizedId && this.hasNotificationId(dateKey, normalizedId)) {\n return { kind: \"dedupedById\" };\n }\n\n if (this.hasNotificationContentKey(dateKey, filePath, entry)) {\n return { kind: \"dedupedByContent\" };\n }\n\n const appDisplayName = this.resolveDisplayName\n ? await this.resolveDisplayName(entry.appName)\n : entry.appName;\n\n const storedEntry: StoredNotification = {\n ...entry,\n appDisplayName,\n };\n\n const arr = this.readStoredNotifications(filePath);\n arr.push(storedEntry);\n writeFileSync(filePath, JSON.stringify(arr, null, 2), \"utf-8\");\n\n if (normalizedId) {\n this.recordNotificationId(dateKey, normalizedId);\n }\n this.recordNotificationContentKey(dateKey, filePath, storedEntry);\n return { kind: \"ingested\", entry: storedEntry };\n });\n }\n\n private buildStoredNotification(n: RawNotification): StoredNotification {\n return {\n appName: typeof n.app === \"string\" && n.app ? n.app : \"Unknown\",\n title: typeof n.title === \"string\" ? n.title : \"\",\n content: this.buildContent(n),\n timestamp: n.timestamp,\n };\n }\n\n private buildContent(n: RawNotification): string {\n const body = n.body?.trim();\n if (body) {\n return body;\n }\n\n const fallback: string[] = [];\n if (n.category) {\n fallback.push(`category:${n.category}`);\n }\n\n if (n.metadata && Object.keys(n.metadata).length > 0) {\n fallback.push(`metadata:${JSON.stringify(n.metadata)}`);\n }\n\n return fallback.join(\" ; \") || \"-\";\n }\n\n private formatDate(d: Date): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n }\n\n private getIdIndexPath(dateKey: string): string {\n return join(this.idIndexDir, `${dateKey}.ids`);\n }\n\n private getIdSet(dateKey: string): Set<string> {\n const cached = this.idCache.get(dateKey);\n if (cached) {\n return cached;\n }\n\n const idPath = this.getIdIndexPath(dateKey);\n const ids = new Set<string>();\n if (existsSync(idPath)) {\n const lines = readFileSync(idPath, \"utf-8\").split(/\\r?\\n/);\n for (const line of lines) {\n const id = line.trim();\n if (id) {\n ids.add(id);\n }\n }\n }\n\n this.idCache.set(dateKey, ids);\n return ids;\n }\n\n private hasNotificationId(dateKey: string, id: string): boolean {\n return this.getIdSet(dateKey).has(id);\n }\n\n private getContentKeyIndexPath(dateKey: string): string {\n return join(this.contentKeyIndexDir, `${dateKey}.keys`);\n }\n\n private getContentKeySet(dateKey: string, filePath: string): Set<string> {\n const cached = this.contentKeyCache.get(dateKey);\n if (cached) {\n return cached;\n }\n\n const keyPath = this.getContentKeyIndexPath(dateKey);\n const keys = new Set<string>();\n\n if (existsSync(filePath)) {\n for (const item of this.readStoredNotifications(filePath)) {\n keys.add(this.buildNotificationContentKey(item));\n }\n }\n\n if (keys.size > 0) {\n writeFileSync(keyPath, `${Array.from(keys).join(\"\\n\")}\\n`, \"utf-8\");\n } else if (existsSync(keyPath)) {\n rmSync(keyPath, { force: true });\n }\n\n this.contentKeyCache.set(dateKey, keys);\n return keys;\n }\n\n private hasNotificationContentKey(\n dateKey: string,\n filePath: string,\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ): boolean {\n return this.getContentKeySet(dateKey, filePath).has(\n this.buildNotificationContentKey(entry),\n );\n }\n\n private recordNotificationId(dateKey: string, id: string) {\n const ids = this.getIdSet(dateKey);\n if (ids.has(id)) {\n return;\n }\n\n appendFileSync(this.getIdIndexPath(dateKey), `${id}\\n`, \"utf-8\");\n ids.add(id);\n }\n\n private recordNotificationContentKey(\n dateKey: string,\n filePath: string,\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ) {\n const keys = this.getContentKeySet(dateKey, filePath);\n const key = this.buildNotificationContentKey(entry);\n\n if (keys.has(key)) {\n return;\n }\n\n appendFileSync(this.getContentKeyIndexPath(dateKey), `${key}\\n`, \"utf-8\");\n keys.add(key);\n }\n\n private buildNotificationContentKey(\n entry: Pick<StoredNotification, \"appName\" | \"title\" | \"content\" | \"timestamp\">,\n ): string {\n return createHash(\"sha256\")\n .update(entry.appName)\n .update(\"\\x1f\")\n .update(entry.title)\n .update(\"\\x1f\")\n .update(entry.content)\n .update(\"\\x1f\")\n .update(entry.timestamp)\n .digest(\"hex\");\n }\n\n private readStoredNotifications(filePath: string): StoredNotification[] {\n if (!existsSync(filePath)) {\n return [];\n }\n\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf-8\"));\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n }\n\n private async withDateWriteLock<T>(\n dateKey: string,\n task: () => Promise<T>,\n ): Promise<T> {\n const previous = this.dateWriteChains.get(dateKey) ?? Promise.resolve();\n let release!: () => void;\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n const chain = previous.then(() => current);\n this.dateWriteChains.set(dateKey, chain);\n\n await previous;\n try {\n return await task();\n } finally {\n release();\n if (this.dateWriteChains.get(dateKey) === chain) {\n this.dateWriteChains.delete(dateKey);\n }\n }\n }\n\n private prune() {\n const retentionDays = this.config.retentionDays;\n if (retentionDays === undefined) {\n return;\n }\n\n const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1000;\n const cutoffDate = this.formatDate(new Date(cutoffMs));\n\n this.pruneDataFiles(cutoffDate);\n this.pruneIdIndex(cutoffDate);\n this.pruneContentKeyIndex(cutoffDate);\n }\n\n /** Remove expired .json, legacy .md files, and legacy date directories */\n private pruneDataFiles(cutoffDate: string) {\n const dateFilePattern = /^(\\d{4}-\\d{2}-\\d{2})\\.(json|md)$/;\n const dateDirPattern = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n try {\n for (const entry of readdirSync(this.dir, { withFileTypes: true })) {\n if (entry.isFile()) {\n const match = dateFilePattern.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.dir, entry.name), { force: true });\n }\n } else if (entry.isDirectory() && dateDirPattern.test(entry.name) && entry.name < cutoffDate) {\n rmSync(join(this.dir, entry.name), { recursive: true, force: true });\n }\n }\n } catch {\n // ignore\n }\n }\n\n /** Remove expired .ids index files */\n private pruneIdIndex(cutoffDate: string) {\n try {\n for (const entry of readdirSync(this.idIndexDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.ids$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.idIndexDir, entry.name), { force: true });\n this.idCache.delete(match[1]);\n }\n }\n } catch {\n // ignore\n }\n }\n\n private pruneContentKeyIndex(cutoffDate: string) {\n try {\n for (const entry of readdirSync(this.contentKeyIndexDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = /^(\\d{4}-\\d{2}-\\d{2})\\.keys$/.exec(entry.name);\n if (match && match[1] < cutoffDate) {\n rmSync(join(this.contentKeyIndexDir, entry.name), { force: true });\n this.contentKeyCache.delete(match[1]);\n }\n }\n } catch {\n // ignore\n }\n }\n\n async close() {\n this.idCache.clear();\n this.contentKeyCache.clear();\n this.dateWriteChains.clear();\n }\n}\n","export interface RepeatConfig {\n repeat?: boolean;\n repeat_times?: number;\n}\n\nexport type RepeatArgument = RepeatConfig | boolean | number | undefined;\n\nexport function normalizeRepeatTimes(input?: RepeatArgument): number {\n if (typeof input === \"boolean\") {\n return input ? 0 : 1;\n }\n\n if (typeof input === \"number\") {\n return validateRepeatTimes(input);\n }\n\n if (!input) {\n return 1;\n }\n\n if (input.repeat_times !== undefined) {\n return validateRepeatTimes(input.repeat_times);\n }\n\n if (input.repeat !== undefined) {\n return input.repeat ? 0 : 1;\n }\n\n return 1;\n}\n\nexport function assertAncsRepeatTimes(repeatTimes: number): void {\n if (repeatTimes !== 0 && repeatTimes !== 1) {\n throw new Error(\n \"当前 ANCS 路径仅支持 repeat_times=0(无限循环)或 1(播放一轮);N>=2 需非 ANCS 路径\",\n );\n }\n}\n\nfunction validateRepeatTimes(value: number): number {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(\"repeat_times 必须是 >=0 的整数\");\n }\n\n return value;\n}\n","import { existsSync, readFileSync, readdirSync, mkdirSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { StoredNotification } from \"../notification/storage.js\";\n\n/**\n * Minimal Commander.js Command interface.\n * The real `Command` instance comes from the openclaw runtime at registration time;\n * we only declare the subset we use so that `commander` need not be a direct dep.\n */\nexport interface CliCommand {\n command(nameAndArgs: string): CliCommand;\n description(str: string): CliCommand;\n version(str: string, flags?: string, description?: string): CliCommand;\n option(flags: string, description: string, defaultValue?: string): CliCommand;\n requiredOption(flags: string, description: string): CliCommand;\n action(fn: (...args: any[]) => void | Promise<void>): CliCommand;\n}\n\nexport interface CliContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\n/** Resolve the notifications storage directory (stateDir → workspace fallback) */\nexport function resolveNotificationsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"notifications\",\n );\n if (existsSync(dir)) return dir;\n }\n if (ctx.workspaceDir) {\n const dir = join(ctx.workspaceDir, \"notifications\");\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** List available date keys (YYYY-MM-DD) sorted descending */\nexport function listDateKeys(dir: string): string[] {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.json$/;\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Read notifications for a specific date */\nexport function readDateFile(\n dir: string,\n dateKey: string,\n): StoredNotification[] {\n const filePath = join(dir, `${dateKey}.json`);\n if (!existsSync(filePath)) return [];\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\"));\n } catch {\n return [];\n }\n}\n\n/** Format today as YYYY-MM-DD */\nexport function today(): string {\n return formatDate(new Date());\n}\n\n/** Format a Date as YYYY-MM-DD */\nexport function formatDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\n/** Get date N days ago as YYYY-MM-DD */\nexport function daysAgo(n: number): string {\n const d = new Date();\n d.setDate(d.getDate() - n);\n return formatDate(d);\n}\n\n/** Filter date keys to a [from, to] range (inclusive) */\nexport function filterDateRange(\n keys: string[],\n from: string,\n to: string,\n): string[] {\n return keys.filter((k) => k >= from && k <= to);\n}\n\n/** Parse an ISO 8601 timestamp and exit with a CLI error on invalid input */\nexport function parseIsoTime(\n value: string,\n optionName: \"--from\" | \"--to\",\n): number {\n const isoPattern =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,3})?)?(Z|[+-]\\d{2}:\\d{2})$/;\n if (!isoPattern.test(value)) {\n exitError(\n \"INVALID_TIME\",\n `${optionName} 必须是 ISO 8601 时间,例如 2026-03-01T09:00:00+08:00`,\n );\n }\n\n const ts = Date.parse(value);\n if (Number.isNaN(ts)) {\n exitError(\n \"INVALID_TIME\",\n `${optionName} 不是合法时间,例如 2026-03-01T09:00:00+08:00`,\n );\n }\n return ts;\n}\n\n/** Sort notifications by timestamp descending (newest first) */\nexport function sortNotificationsByTimestampDesc(\n items: StoredNotification[],\n): StoredNotification[] {\n return items.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp));\n}\n\n/** Async version of listDateKeys */\nexport async function listDateKeysAsync(dir: string): Promise<string[]> {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.json$/;\n const keys: string[] = [];\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Async version of readDateFile */\nexport async function readDateFileAsync(\n dir: string,\n dateKey: string,\n): Promise<StoredNotification[]> {\n const filePath = join(dir, `${dateKey}.json`);\n if (!existsSync(filePath)) return [];\n try {\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content);\n } catch {\n return [];\n }\n}\n\n/** Write progress message to stderr (visible to caller, won't pollute JSON stdout) */\nexport function progress(message: string): void {\n process.stderr.write(message + \"\\n\");\n}\n\n/** Print JSON result to stdout */\nexport function output(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\n/** Print error JSON and exit with code 1 */\nexport function exitError(code: string, message: string): never {\n output({ ok: false, error: { code, message } });\n process.exit(1);\n}\n\n/** Resolve the recordings storage directory (stateDir → workspace fallback) */\nexport function resolveRecordingsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"recordings\",\n );\n if (existsSync(dir)) return dir;\n }\n if (ctx.workspaceDir) {\n const dir = join(ctx.workspaceDir, \"recordings\");\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** Recording index entry (mirrors RecordingIndexEntry from storage.ts) */\nexport interface CliRecordingEntry {\n id: string;\n metadata: {\n name: string;\n duration_sec: number;\n file_size_bytes: number;\n created_at: string;\n transfer_status: string;\n [key: string]: unknown;\n };\n status: string;\n audioFile?: string;\n srtFile?: string;\n transcriptDataFile?: string;\n transcriptFile?: string;\n summaryFile?: string;\n title?: string;\n ingestedAt: string;\n updatedAt: string;\n}\n\n/** Resolve the asr-config.json path; creates parent dirs if needed */\nexport function resolveAsrConfigPath(ctx: CliContext): string {\n let base: string;\n if (ctx.stateDir) {\n base = join(ctx.stateDir, \"plugins\", \"phone-notifications\", \"recordings\");\n } else if (ctx.workspaceDir) {\n base = join(ctx.workspaceDir, \"recordings\");\n } else {\n exitError(\n \"STORAGE_UNAVAILABLE\",\n \"无法确定录音存储目录:stateDir 和 workspaceDir 均未设置\",\n );\n }\n mkdirSync(base, { recursive: true });\n return join(base, \"asr-config.json\");\n}\n\n/** Mask an API key, keeping first 4 and last 4 chars */\nexport function maskApiKey(key: string): string {\n if (key.length <= 8) return \"***\";\n return `${key.slice(0, 4)}***${key.slice(-4)}`;\n}\n\n/** Read recording index.json */\nexport function readRecordingIndex(\n dir: string,\n): CliRecordingEntry[] {\n const indexPath = join(dir, \"index.json\");\n if (!existsSync(indexPath)) return [];\n try {\n const raw = JSON.parse(readFileSync(indexPath, \"utf-8\"));\n return Array.isArray(raw?.recordings) ? raw.recordings : [];\n } catch {\n return [];\n }\n}\n","import type { LightPixelFramePixel, LightSegment } from \"../types.js\";\nimport { output, exitError } from \"../cli/helpers.js\";\n\nexport const VALID_MODES = [\n \"wave\",\n \"breath\",\n \"strobe\",\n \"steady\",\n \"wave_rainbow\",\n \"pixel_frame\",\n] as const;\nexport const MAX_SEGMENTS = 12;\n\nexport interface ValidationError {\n field: string;\n message: string;\n}\n\nexport type ValidationResult =\n | { valid: true; segments: LightSegment[] }\n | { valid: false; errors: ValidationError[] };\n\nexport function validateSegments(segments: unknown): ValidationResult {\n if (!Array.isArray(segments)) {\n return { valid: false, errors: [{ field: \"segments\", message: \"必须是数组\" }] };\n }\n if (segments.length === 0) {\n return { valid: false, errors: [{ field: \"segments\", message: \"不能为空\" }] };\n }\n if (segments.length > MAX_SEGMENTS) {\n return {\n valid: false,\n errors: [{ field: \"segments\", message: `最多 ${MAX_SEGMENTS} 段` }],\n };\n }\n\n const errors: ValidationError[] = [];\n for (let i = 0; i < segments.length; i++) {\n validateSegment(segments[i], `segments[${i}]`, errors);\n }\n\n if (errors.length > 0) return { valid: false, errors };\n return { valid: true, segments: segments as LightSegment[] };\n}\n\n/**\n * 解析 JSON 字符串并校验 segments,失败时直接 exitError。\n * 适用于 CLI action 中的统一入口。\n */\nexport function parseAndValidateSegments(json: string): LightSegment[] {\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n exitError(\"VALIDATION_FAILED\", \"segments 必须是合法的 JSON\");\n }\n\n const result = validateSegments(parsed);\n if (!result.valid) {\n output({ ok: false, error: { code: \"VALIDATION_FAILED\", details: result.errors } });\n process.exit(1);\n }\n\n return result.segments;\n}\n\nfunction validateSegment(seg: unknown, prefix: string, errors: ValidationError[]): void {\n if (!isRecord(seg)) {\n errors.push({ field: prefix, message: \"必须是对象\" });\n return;\n }\n\n const mode = seg.mode;\n if (!VALID_MODES.includes(mode as (typeof VALID_MODES)[number])) {\n errors.push({\n field: `${prefix}.mode`,\n message: `不支持的模式 '${String(mode)}',可选:${VALID_MODES.join(\"/\")}`,\n });\n }\n\n validateNonNegativeNumber(seg.duration_s, `${prefix}.duration_s`, errors, \"必须是 ≥0 的数字(0 表示无限时长)\");\n\n switch (mode) {\n case \"wave\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n break;\n case \"wave_rainbow\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n type RgbLike = Parameters<typeof hasNonZeroRgb>[0];\n if (!hasNonZeroRgb(seg.color as RgbLike) && !hasNonZeroRgb(seg.background as RgbLike)) {\n errors.push({\n field: prefix,\n message: \"wave_rainbow 至少需要一组非零颜色锚点(color 或 background)\",\n });\n }\n break;\n case \"breath\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalBreathTiming(seg.breath_timing, `${prefix}.breath_timing`, errors);\n break;\n case \"strobe\":\n validateForegroundSegment(seg, prefix, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n break;\n case \"steady\":\n validateForegroundSegment(seg, prefix, errors);\n break;\n case \"pixel_frame\":\n validatePixelFrame(seg.pixels, `${prefix}.pixels`, errors);\n break;\n default:\n validateOptionalNonNegativeNumber(seg.brightness, `${prefix}.brightness`, errors);\n validateOptionalColor(seg.color, `${prefix}.color`, errors);\n validateOptionalNonNegativeNumber(seg.interval_ms, `${prefix}.interval_ms`, errors);\n validateOptionalDirection(seg.direction, `${prefix}.direction`, errors);\n validateOptionalWindow(seg.window, `${prefix}.window`, errors);\n validateOptionalBreathTiming(seg.breath_timing, `${prefix}.breath_timing`, errors);\n validateOptionalBackground(seg.background, `${prefix}.background`, errors);\n }\n}\n\nfunction validateForegroundSegment(\n seg: Record<string, unknown>,\n prefix: string,\n errors: ValidationError[],\n): void {\n validateNumberInRange(\n seg.brightness,\n `${prefix}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n validateColor(seg.color, `${prefix}.color`, errors);\n\n if (seg.mode !== \"steady\" && seg.brightness === 0) {\n errors.push({\n field: `${prefix}.brightness`,\n message: \"brightness=0 仅 steady 模式允许;其它模式会在固件侧被过滤\",\n });\n }\n}\n\nfunction validatePixelFrame(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (!Array.isArray(value)) {\n errors.push({ field, message: \"pixel_frame 必须提供 pixels 数组(1–7 项)\" });\n return;\n }\n\n if (value.length < 1 || value.length > 7) {\n errors.push({ field, message: \"pixels 必须为 1–7 项\" });\n }\n\n const seen = new Set<number>();\n for (let i = 0; i < value.length; i++) {\n const pixel = value[i];\n const prefix = `${field}[${i}]`;\n if (!isRecord(pixel)) {\n errors.push({ field: prefix, message: \"必须是对象\" });\n continue;\n }\n\n const idx = pixel.index;\n if (!Number.isInteger(idx) || (idx as number) < 0 || (idx as number) > 6) {\n errors.push({ field: `${prefix}.index`, message: \"index 必须是 0–6 的整数\" });\n } else if (seen.has(idx as number)) {\n errors.push({ field: `${prefix}.index`, message: `index=${idx} 重复` });\n } else {\n seen.add(idx as number);\n }\n\n validateNumberInRange(\n pixel.brightness,\n `${prefix}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n validateColor(pixel.color, `${prefix}.color`, errors);\n }\n}\n\nfunction validateOptionalBreathTiming(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须是对象\" });\n return;\n }\n\n validatePositiveNumber(\n value.rise_ms,\n `${field}.rise_ms`,\n errors,\n \"rise_ms 必须是 >0 的数字(不支持 0ms)\",\n );\n validateNonNegativeNumber(\n value.hold_ms,\n `${field}.hold_ms`,\n errors,\n \"hold_ms 必须是 ≥0 的数字\",\n );\n validatePositiveNumber(\n value.fall_ms,\n `${field}.fall_ms`,\n errors,\n \"fall_ms 必须是 >0 的数字(不支持 0ms)\",\n );\n validateNonNegativeNumber(\n value.off_ms,\n `${field}.off_ms`,\n errors,\n \"off_ms 必须是 ≥0 的数字\",\n );\n}\n\nfunction validateOptionalBackground(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须包含 r/g/b/brightness 数值\" });\n return;\n }\n\n validateColor(value, field, errors);\n validateNumberInRange(\n value.brightness,\n `${field}.brightness`,\n errors,\n 0,\n 255,\n \"必须是 0–255 的数字\",\n );\n}\n\nfunction validateOptionalColor(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n validateColor(value, field, errors);\n}\n\nfunction validateColor(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (!isRecord(value)) {\n errors.push({ field, message: \"必须包含 r/g/b 数值\" });\n return;\n }\n\n validateNumberInRange(value.r, `${field}.r`, errors, 0, 255, \"必须是 0–255 的数字\");\n validateNumberInRange(value.g, `${field}.g`, errors, 0, 255, \"必须是 0–255 的数字\");\n validateNumberInRange(value.b, `${field}.b`, errors, 0, 255, \"必须是 0–255 的数字\");\n}\n\nfunction validateOptionalDirection(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (value !== \"ltr\" && value !== \"rtl\") {\n errors.push({ field, message: \"direction 必须是 ltr 或 rtl\" });\n }\n}\n\nfunction validateOptionalWindow(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n if (value !== 1 && value !== 2 && value !== 3) {\n errors.push({ field, message: \"window 仅支持 1/2/3\" });\n }\n}\n\nfunction validateOptionalNonNegativeNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n): void {\n if (value === undefined) return;\n validateNonNegativeNumber(value, field, errors, \"必须是 ≥0 的数字\");\n}\n\nfunction validatePositiveNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n message: string,\n): void {\n if (value === undefined) return;\n if (!isFiniteNumber(value) || value <= 0) {\n errors.push({ field, message });\n }\n}\n\nfunction validateNonNegativeNumber(\n value: unknown,\n field: string,\n errors: ValidationError[],\n message: string,\n): void {\n if (!isFiniteNumber(value) || value < 0) {\n errors.push({ field, message });\n }\n}\n\nfunction validateNumberInRange(\n value: unknown,\n field: string,\n errors: ValidationError[],\n min: number,\n max: number,\n message: string,\n): void {\n if (!isFiniteNumber(value) || value < min || value > max) {\n errors.push({ field, message });\n }\n}\n\nfunction hasNonZeroRgb(\n value: Pick<LightPixelFramePixel[\"color\"], \"r\" | \"g\" | \"b\"> | { r?: unknown; g?: unknown; b?: unknown } | undefined,\n): boolean {\n if (!value) return false;\n return [value.r, value.g, value.b].some((channel) => isFiniteNumber(channel) && channel > 0);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { LightSegment } from \"../types.js\";\nimport type { LightRuleMeta } from \"./types.js\";\nimport { generateFetchPy } from \"../monitor/fetch-gen.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\n\nconst LEGACY_DEFAULT_CRON_SCHEDULE = \"*/5 * * * *\";\n\n/**\n * 兼容窗口工具:读 / 写灯效规则的 deprecated 字段(matchRules / cronSchedule)。\n *\n * 这两个字段在 prd-lightrules-event-driven-refactor 中已被标记为 deprecated,\n * 但在 M6 客户端全部升级前必须继续接受旧客户端的入参、继续生成 cron 调度信息,\n * 否则老 App 会失去灯效能力。所有\"读 deprecated 字段\"的逻辑统一从这里走,\n * 把 SonarLint S1874(typescript:S1874 \"use of deprecated symbol\")警告\n * 收敛到本段,避免散落各处。\n *\n * 等 M6 过渡期结束删除兼容字段时,只需要删掉本段 + 调用方的 helper 调用即可。\n */\n\n/* eslint-disable @typescript-eslint/no-deprecated */\ntype LegacyMatchRulesShape = { appName?: string; senderKeywords?: string[] };\n\nfunction legacyReadMatchRules(input: {\n matchRules?: LegacyMatchRulesShape;\n}): LegacyMatchRulesShape {\n return input.matchRules ?? {};\n}\n\nfunction legacyReadCronSchedule(input: { cronSchedule?: string }): string {\n return input.cronSchedule ?? LEGACY_DEFAULT_CRON_SCHEDULE;\n}\n\nfunction legacyHasMatchRules(input: { matchRules?: LegacyMatchRulesShape }): boolean {\n return input.matchRules !== undefined;\n}\n\nfunction legacyHasCronSchedule(input: { cronSchedule?: string }): boolean {\n return input.cronSchedule !== undefined;\n}\n\nfunction legacyAssignMatchRules(\n meta: LightRuleMeta,\n matchRules: LegacyMatchRulesShape,\n): void {\n meta.matchRules = matchRules;\n}\n\nfunction legacyAssignCronSchedule(meta: LightRuleMeta, cronSchedule: string): void {\n meta.cronSchedule = cronSchedule;\n}\n\nfunction legacyReadMetaMatchRules(meta: LightRuleMeta): LegacyMatchRulesShape {\n return meta.matchRules ?? {};\n}\n\nfunction legacyReadMetaCronSchedule(meta: LightRuleMeta): string | undefined {\n return meta.cronSchedule;\n}\n/* eslint-enable @typescript-eslint/no-deprecated */\n\nexport interface LightRuleStorageContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\nfunction resolveBaseDir(ctx: LightRuleStorageContext): string {\n if (ctx.workspaceDir) return ctx.workspaceDir;\n\n if (ctx.stateDir) {\n const inferredWorkspaceDir = join(ctx.stateDir, \"workspace\");\n if (existsSync(inferredWorkspaceDir)) return inferredWorkspaceDir;\n return ctx.stateDir;\n }\n\n throw new Error(\"workspaceDir and stateDir both unavailable\");\n}\n\nfunction tasksDir(ctx: LightRuleStorageContext): string {\n return join(resolveBaseDir(ctx), \"tasks\");\n}\n\nfunction normalizeLightRuleLookupName(name: string): string {\n return name.trim().replace(/\\.json$/i, \"\");\n}\n\nfunction resolveLightRuleTask(\n ctx: LightRuleStorageContext,\n name: string,\n): { taskDir: string; meta: LightRuleMeta } | null {\n const dir = tasksDir(ctx);\n const normalizedName = normalizeLightRuleLookupName(name);\n if (!normalizedName) return null;\n\n const directTaskDir = join(dir, normalizedName);\n const directMeta = readMeta(directTaskDir);\n if (directMeta) {\n return {\n taskDir: directTaskDir,\n meta: directMeta,\n };\n }\n\n if (!existsSync(dir)) return null;\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n\n const taskDir = join(dir, entry.name);\n const meta = readMeta(taskDir);\n if (meta?.name === normalizedName) {\n return {\n taskDir,\n meta,\n };\n }\n }\n\n return null;\n}\n\nfunction readMeta(taskDir: string): LightRuleMeta | null {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return null;\n try {\n const raw = JSON.parse(readFileSync(metaPath, \"utf-8\"));\n if (raw.type !== \"light-rule\") return null;\n if (!raw.createdAt) {\n raw.createdAt = statSync(metaPath).birthtime.toISOString();\n }\n const repeatTimes = normalizeRepeatTimes({\n repeat: raw.repeat,\n repeat_times: raw.repeat_times,\n });\n assertAncsRepeatTimes(repeatTimes);\n return {\n ...raw,\n repeat_times: repeatTimes,\n } as LightRuleMeta;\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(taskDir: string, meta: LightRuleMeta): void {\n writeFileSync(join(taskDir, \"meta.json\"), JSON.stringify(meta, null, 2), \"utf-8\");\n}\n\nfunction generateLightRuleReadme(\n name: string,\n description: string,\n segments: LightSegment[],\n repeatTimes: number,\n): string {\n const segmentsJson = JSON.stringify(segments, null, 2);\n return `# ${name}\n\n## 监控目标\n\n${description}\n\n## 触发后如何处理\n\n当任务脚本输出匹配结果时:\n\n1. 将输出按\"每行一个 JSON 对象\"解析\n2. 这些是候选通知,不代表已经命中\n3. 根据监控目标判断是否真正命中\n\n**命中后执行灯效**:调用 light_control 工具,传入以下灯效参数:\n\n\\`\\`\\`json\n${segmentsJson}\n\\`\\`\\`\n\nrepeat_times: ${repeatTimes}\nreason: \"${description}\"\n\n只执行灯效,不主动发送通知摘要或回复用户。\n`;\n}\n\nexport function listLightRules(ctx: LightRuleStorageContext): LightRuleMeta[] {\n const dir = tasksDir(ctx);\n if (!existsSync(dir)) return [];\n\n const rules: LightRuleMeta[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const meta = readMeta(join(dir, entry.name));\n if (meta) rules.push(meta);\n }\n return rules;\n}\n\nexport function getLightRule(\n ctx: LightRuleStorageContext,\n name: string,\n): LightRuleMeta | null {\n return resolveLightRuleTask(ctx, name)?.meta ?? null;\n}\n\nexport function createLightRule(\n ctx: LightRuleStorageContext,\n params: {\n name: string;\n description: string;\n segments: LightSegment[];\n repeat_times?: number;\n repeat?: boolean;\n /** @deprecated 旧客户端兼容字段;缺省时回退到默认 cron schedule */\n matchRules?: { appName?: string; senderKeywords?: string[] };\n /** @deprecated 旧客户端兼容字段;缺省时回退到 LEGACY_DEFAULT_CRON_SCHEDULE */\n cronSchedule?: string;\n },\n): { meta: LightRuleMeta; cronHint: unknown } {\n const dir = tasksDir(ctx);\n const taskDir = join(dir, params.name);\n\n if (existsSync(taskDir)) {\n throw new LightRuleError(\"ALREADY_EXISTS\", `灯效规则 '${params.name}' 已存在`);\n }\n\n mkdirSync(taskDir, { recursive: true });\n\n const repeatTimes = normalizeRepeatTimes({\n repeat: params.repeat,\n repeat_times: params.repeat_times,\n });\n assertAncsRepeatTimes(repeatTimes);\n\n const effectiveMatchRules = legacyReadMatchRules(params);\n const effectiveCronSchedule = legacyReadCronSchedule(params);\n\n const meta: LightRuleMeta = {\n name: params.name,\n type: \"light-rule\",\n description: params.description,\n segments: params.segments,\n repeat_times: repeatTimes,\n enabled: true,\n createdAt: new Date().toISOString(),\n };\n legacyAssignMatchRules(meta, effectiveMatchRules);\n legacyAssignCronSchedule(meta, effectiveCronSchedule);\n\n writeMeta(taskDir, meta);\n\n writeFileSync(\n join(taskDir, \"fetch.py\"),\n generateFetchPy(params.name, effectiveMatchRules as Record<string, unknown>),\n \"utf-8\",\n );\n\n writeFileSync(\n join(taskDir, \"README.md\"),\n generateLightRuleReadme(params.name, params.description, params.segments, repeatTimes),\n \"utf-8\",\n );\n\n return {\n meta,\n cronHint: {\n action: \"add\",\n job: {\n name: `notif-${params.name}`,\n schedule: effectiveCronSchedule,\n sessionTarget: \"isolated\",\n message:\n `手机通知已由独立服务实时捕获到 notifications/ 目录的 JSON 文件中。\\n` +\n `执行:python3 tasks/${params.name}/fetch.py --notifications-dir notifications\\n` +\n `- NO_CHANGE 或 NO_MATCH → 不回复,直接结束。\\n` +\n `- 有输出 → 读 tasks/${params.name}/README.md 了解如何处理数据并通知用户。`,\n },\n },\n };\n}\n\nexport function updateLightRule(\n ctx: LightRuleStorageContext,\n params: {\n name: string;\n description?: string;\n segments?: LightSegment[];\n repeat_times?: number;\n repeat?: boolean;\n enabled?: boolean;\n /** @deprecated 旧客户端兼容字段 */\n matchRules?: { appName?: string; senderKeywords?: string[] };\n /** @deprecated 旧客户端兼容字段 */\n cronSchedule?: string;\n },\n): { meta: LightRuleMeta; cronHint?: unknown } {\n const resolved = resolveLightRuleTask(ctx, params.name);\n const taskDir = resolved?.taskDir;\n const meta = resolved?.meta;\n\n if (!taskDir || !meta) {\n throw new LightRuleError(\"NOT_FOUND\", `灯效规则 '${params.name}' 不存在`);\n }\n\n let regenerateFetch = false;\n let regenerateReadme = false;\n\n if (params.description !== undefined) {\n meta.description = params.description;\n regenerateReadme = true;\n }\n if (legacyHasMatchRules(params)) {\n legacyAssignMatchRules(meta, legacyReadMatchRules(params));\n regenerateFetch = true;\n }\n if (params.segments !== undefined) {\n meta.segments = params.segments;\n regenerateReadme = true;\n }\n if (params.repeat !== undefined || params.repeat_times !== undefined) {\n meta.repeat_times = normalizeRepeatTimes({\n repeat: params.repeat,\n repeat_times: params.repeat_times,\n });\n assertAncsRepeatTimes(meta.repeat_times);\n regenerateReadme = true;\n }\n if (legacyHasCronSchedule(params)) {\n legacyAssignCronSchedule(meta, legacyReadCronSchedule(params));\n }\n if (params.enabled !== undefined) {\n meta.enabled = params.enabled;\n }\n\n meta.updatedAt = new Date().toISOString();\n writeMeta(taskDir, meta);\n\n if (regenerateFetch) {\n writeFileSync(\n join(taskDir, \"fetch.py\"),\n generateFetchPy(meta.name, legacyReadMetaMatchRules(meta) as Record<string, unknown>),\n \"utf-8\",\n );\n }\n\n if (regenerateReadme) {\n writeFileSync(\n join(taskDir, \"README.md\"),\n generateLightRuleReadme(meta.name, meta.description, meta.segments, meta.repeat_times),\n \"utf-8\",\n );\n }\n\n const cronHint = legacyHasCronSchedule(params)\n ? {\n action: \"update\",\n job: {\n name: `notif-${meta.name}`,\n schedule: legacyReadMetaCronSchedule(meta),\n },\n }\n : undefined;\n\n return { meta, cronHint };\n}\n\nexport function deleteLightRule(\n ctx: LightRuleStorageContext,\n name: string,\n): { name: string; cronHint: unknown } {\n const resolved = resolveLightRuleTask(ctx, name);\n const taskDir = resolved?.taskDir;\n const meta = resolved?.meta;\n\n if (!taskDir || !meta) {\n throw new LightRuleError(\"NOT_FOUND\", `灯效规则 '${name}' 不存在`);\n }\n\n rmSync(taskDir, { recursive: true, force: true });\n\n return {\n name: meta.name,\n cronHint: {\n action: \"remove\",\n name: `notif-${meta.name}`,\n },\n };\n}\n\nexport class LightRuleError extends Error {\n constructor(\n public code: string,\n message: string,\n ) {\n super(message);\n this.name = \"LightRuleError\";\n }\n}\n","/**\n * 共享的 fetch.py 生成逻辑,供 ntf-monitor CLI 和 light-rules gateway 复用。\n */\nexport function generateFetchPy(\n name: string,\n matchRules: Record<string, unknown>,\n): string {\n const appName = typeof matchRules.appName === \"string\" ? matchRules.appName : \"\";\n const senderKeywords = stringArray(matchRules.senderKeywords);\n const contentKeywords = stringArray(matchRules.contentKeywords);\n\n return `#!/usr/bin/env python3\n\"\"\"Auto-generated fetch script for monitor task: ${name}\"\"\"\nimport json, sys, os\nfrom pathlib import Path\n\ndef matches(notification: dict) -> bool:\n app = str(notification.get(\"appName\", \"\") or \"\")\n title = str(notification.get(\"title\", \"\") or \"\")\n content = str(notification.get(\"content\", \"\") or \"\")\n body = str(notification.get(\"body\", \"\") or \"\")\n\n app_name = ${pyLiteral(appName)}\n if app_name and app != app_name:\n return False\n\n sender_keywords = ${pyLiteral(senderKeywords)}\n sender_haystack = f\"{title}\\\\n{content}\\\\n{body}\"\n if sender_keywords and not any(keyword in sender_haystack for keyword in sender_keywords):\n return False\n\n content_keywords = ${pyLiteral(contentKeywords)}\n content_haystack = f\"{content}\\\\n{body}\"\n if content_keywords and not any(keyword in content_haystack for keyword in content_keywords):\n return False\n\n return True\n\ndef main():\n import argparse\n parser = argparse.ArgumentParser()\n parser.add_argument(\"--notifications-dir\", required=True)\n args = parser.parse_args()\n\n checkpoint_path = Path(__file__).parent / \"checkpoint.json\"\n checkpoint = {}\n if checkpoint_path.exists():\n checkpoint = json.loads(checkpoint_path.read_text())\n\n ntf_dir = Path(args.notifications_dir)\n matched = []\n new_checkpoint = dict(checkpoint)\n\n for f in sorted(ntf_dir.glob(\"*.json\")):\n date_key = f.stem\n items = json.loads(f.read_text())\n last_idx = checkpoint.get(date_key, {}).get(\"lastIndex\", -1)\n for i, item in enumerate(items):\n if i <= last_idx:\n continue\n if matches(item):\n matched.append(item)\n new_checkpoint[date_key] = {\"lastIndex\": len(items) - 1}\n\n checkpoint_path.write_text(json.dumps(new_checkpoint, indent=2))\n\n if not matched:\n print(\"NO_MATCH\")\n return\n\n for m in matched:\n print(json.dumps(m, ensure_ascii=False))\n\nif __name__ == \"__main__\":\n main()\n`;\n}\n\nfunction stringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((item): item is string => typeof item === \"string\" && item.length > 0);\n}\n\nfunction pyLiteral(value: string | string[]): string {\n return JSON.stringify(value);\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { validateSegments } from \"../light/validators.js\";\nimport type { LightSegment } from \"../types.js\";\nimport type { BroadcastFn } from \"../update/types.js\";\nimport type {\n LightRuleCreateParams,\n LightRuleUpdateParams,\n LightRuleDeleteParams,\n} from \"./types.js\";\nimport { LightRuleError } from \"./storage.js\";\nimport type { LightRuleRegistry } from \"./registry.js\";\n\nconst DEFAULT_CRON_SCHEDULE = \"*/5 * * * *\";\n\nfunction resolveRuleIdentifier(params: unknown): string | undefined {\n if (!params || typeof params !== \"object\") return undefined;\n\n const raw = params as Record<string, unknown>;\n const candidates = [raw.name, raw.id, raw.ruleId, raw.ruleName];\n for (const candidate of candidates) {\n if (typeof candidate !== \"string\") continue;\n const normalized = candidate.trim().replace(/\\.json$/i, \"\");\n if (normalized) return normalized;\n }\n\n return undefined;\n}\n\nexport function registerLightRulesGateway(\n api: OpenClawPluginApi,\n registry: LightRuleRegistry,\n logger: Pick<Logger, \"info\" | \"warn\">,\n rememberBroadcast?: (broadcast: BroadcastFn | undefined) => void,\n): void {\n type GatewayHandler = Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1];\n\n const registerGatewayMethodWithBroadcastCapture = (\n method: string,\n handler: GatewayHandler,\n ): void => {\n api.registerGatewayMethod(method, (opts) => {\n rememberBroadcast?.(opts.context?.broadcast);\n return handler(opts);\n });\n };\n\n // lightrules.list\n registerGatewayMethodWithBroadcastCapture(\"lightrules.list\", async ({ respond }) => {\n try {\n const rules = registry.list().map((rule) => ({\n ...rule,\n id: rule.name,\n }));\n respond(true, { ok: true, rules });\n } catch (err: any) {\n logger.warn(`lightrules.list failed: ${err?.message}`);\n respond(false, null, {\n code: \"INTERNAL_ERROR\",\n message: err?.message ?? \"Unknown error\",\n });\n }\n });\n\n // lightrules.create\n registerGatewayMethodWithBroadcastCapture(\"lightrules.create\", async ({ params, respond }) => {\n const { name, description, matchRules, segments, repeat, repeat_times, cronSchedule } =\n params as unknown as LightRuleCreateParams;\n\n if (!name || typeof name !== \"string\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"name is required\" });\n return;\n }\n if (!description || typeof description !== \"string\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"description is required\" });\n return;\n }\n if (!matchRules || typeof matchRules !== \"object\") {\n respond(false, null, { code: \"INVALID_PARAMS\", message: \"matchRules is required\" });\n return;\n }\n\n const validation = validateSegments(segments);\n if (!validation.valid) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: JSON.stringify(validation.errors),\n });\n return;\n }\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (err: any) {\n respond(false, null, { code: \"VALIDATION_FAILED\", message: err?.message ?? \"Unknown error\" });\n return;\n }\n\n try {\n const result = await registry.create({\n name,\n description,\n matchRules,\n segments: validation.segments,\n repeat_times: repeatTimes,\n cronSchedule: cronSchedule || DEFAULT_CRON_SCHEDULE,\n });\n logger.info(`Light rule created: ${name}`);\n respond(true, { ok: true, name, cronHint: result.cronHint });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`lightrules.create failed: ${err?.message}`);\n respond(false, null, { code: \"INTERNAL_ERROR\", message: err?.message ?? \"Unknown error\" });\n }\n }\n });\n\n // lightrules.update\n registerGatewayMethodWithBroadcastCapture(\"lightrules.update\", async ({ params, respond }) => {\n const {\n description,\n matchRules,\n segments,\n repeat,\n repeat_times,\n cronSchedule,\n enabled,\n } = params as unknown as LightRuleUpdateParams;\n const name = resolveRuleIdentifier(params);\n\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required (or provide id/ruleId/ruleName)\",\n });\n return;\n }\n\n let validatedSegments: LightSegment[] | undefined;\n if (segments !== undefined) {\n const validation = validateSegments(segments);\n if (!validation.valid) {\n respond(false, null, {\n code: \"VALIDATION_FAILED\",\n message: JSON.stringify(validation.errors),\n });\n return;\n }\n validatedSegments = validation.segments;\n }\n\n let repeatTimes: number | undefined;\n if (repeat !== undefined || repeat_times !== undefined) {\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (err: any) {\n respond(false, null, { code: \"VALIDATION_FAILED\", message: err?.message ?? \"Unknown error\" });\n return;\n }\n }\n\n try {\n const result = await registry.update({\n name,\n description,\n matchRules,\n segments: validatedSegments,\n repeat_times: repeatTimes,\n cronSchedule,\n enabled,\n });\n logger.info(`Light rule updated: ${name}`);\n respond(true, {\n ok: true,\n id: result.meta.name,\n name: result.meta.name,\n updated: true,\n rule: result.meta,\n cronHint: result.cronHint,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`lightrules.update failed: ${err?.message}`);\n respond(false, null, { code: \"INTERNAL_ERROR\", message: err?.message ?? \"Unknown error\" });\n }\n }\n });\n\n // lightrules.delete\n registerGatewayMethodWithBroadcastCapture(\"lightrules.delete\", async ({ params, respond }) => {\n const name = resolveRuleIdentifier(params as unknown as LightRuleDeleteParams);\n\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required (or provide id/ruleId/ruleName)\",\n });\n return;\n }\n\n try {\n const result = await registry.delete(name);\n logger.info(`Light rule deleted: ${result.name}`);\n respond(true, {\n ok: true,\n id: result.name,\n name: result.name,\n deleted: true,\n cronHint: result.cronHint,\n });\n } catch (err: any) {\n if (err instanceof LightRuleError) {\n respond(false, null, { code: err.code, message: err.message });\n } else {\n logger.warn(`lightrules.delete failed: ${err?.message}`);\n respond(false, null, { code: \"INTERNAL_ERROR\", message: err?.message ?? \"Unknown error\" });\n }\n }\n });\n}\n","/**\n * LightRulesEvaluatorJob — 管理 `light-rules-evaluator` cron job 的生命周期\n *\n * 职责:\n * 1. 在首次 `notifications.push` 到达时按需创建 `light-rules-evaluator` cron job\n * 2. 通知落盘后(若有新增且存在 enabled 规则),调用 `cron.enqueueRun` force-trigger 评估\n *\n * 两条触发路径:\n * - cron 路径(gateway context 有 cron service):enqueueRun(\"force\") 入队\n * - subagent 路径(HTTP path,cron 不可用时):直接通过 subagentRunner 运行评估 session\n *\n * 设计约束:\n * - 本类**不**做规则匹配,匹配由 Agent session 完成\n * - `triggerIfNeeded` 是 fire-and-forget:成功入队/启动后立即返回,不等待 job 执行\n * - job 存在性检查只走内存(`cron.getJob`),避免频繁 I/O\n *\n * 见 prd-lightrules-event-driven-refactor.md §宿主依赖 / §触发流程\n */\n\nimport type { Logger } from \"../logger.js\";\nimport type { LightRuleRegistry } from \"./registry.js\";\n\nexport const EVALUATOR_JOB_ID = \"light-rules-evaluator\";\n\n/**\n * subagent fallback 使用的固定 session key。\n * 使用稳定 key 让同一 session 复用历史上下文;checkpoint 文件保证不重复处理通知。\n */\nconst EVALUATOR_SUBAGENT_SESSION_KEY = EVALUATOR_JOB_ID;\n\n/**\n * 兜底定时调度:设为每年 1 月 1 日 0 点(几乎不触发)。\n * 实际驱动完全依赖 `enqueueRun(\"force\")`,schedule 仅作为 cron job 结构的必填字段。\n */\nconst FALLBACK_CRON_EXPR = \"0 0 1 1 *\";\n\nfunction buildEvaluatorJobMessage(notificationsDir: string): string {\n return `灯效规则评估任务。\n\n执行步骤:\n1. 读取 tasks/light-rules-evaluator/checkpoint.json(记录上次处理进度)\n2. 扫描 ${notificationsDir} 目录,获取 checkpoint 之后的新通知\n3. 扫描 tasks/ 目录,读取所有 type=light-rule 且 enabled=true 的 meta.json\n4. 对每条新通知,逐一判断是否命中每条规则的 description(语义匹配)\n5. 命中时:以该规则的 segments 和 repeat_times 调用 light_control 工具\n6. 更新 checkpoint.json,记录已处理到的最新通知位置\n7. 若无新通知或无 enabled 规则:输出 NO_CHANGE,直接结束`;\n}\n\n/**\n * 最小结构接口,匹配 SDK CronService 中我们实际用到的方法。\n * 避免直接导入 SDK 内部类型,降低耦合。\n */\nexport interface CronServiceLike {\n getJob(id: string): unknown;\n add(input: {\n id: string;\n name: string;\n description?: string;\n enabled: boolean;\n schedule: { kind: \"cron\"; expr: string };\n sessionTarget: string;\n wakeMode: string;\n payload: { kind: \"agentTurn\"; message: string };\n }): Promise<unknown>;\n enqueueRun(\n id: string,\n mode?: \"due\" | \"force\",\n ): Promise<\n | { ok: true; enqueued: true; runId: string }\n | { ok: true; ran: false; reason: string }\n | { ok: false }\n | Record<string, unknown>\n >;\n}\n\n/**\n * 最小结构接口,匹配 SDK SubagentService 中我们实际用到的方法。\n * 当 cron service 不可用时(HTTP 路径尚无 agent session)用作 fallback。\n */\nexport interface SubagentRunner {\n run(params: { sessionKey: string; message: string; deliver?: boolean; idempotencyKey?: string }): Promise<{ runId: string }>;\n}\n\nexport class LightRulesEvaluatorJob {\n private readonly logger: Pick<Logger, \"info\" | \"warn\">;\n private readonly registry: LightRuleRegistry;\n private readonly subagentRunner?: SubagentRunner;\n private readonly getNotificationsDir: () => string | undefined;\n\n /**\n * 记录本进程生命周期内 job 是否已确认存在。\n * 仅在 `ensureJobExists` 成功后置 true,避免每次 push 都做检查。\n */\n private jobEnsured = false;\n /**\n * 首次创建 job 时的并发保护。\n * 避免冷启动瞬间多条通知并发到达时重复调用 `cron.add`。\n */\n private ensureJobPromise: Promise<void> | null = null;\n\n /**\n * subagent fallback 路径的并发保护。\n * 若评估 session 已在运行中,跳过本次触发(checkpoint 保证下次补处理)。\n */\n private subagentInFlight = false;\n\n constructor(deps: {\n logger: Pick<Logger, \"info\" | \"warn\">;\n registry: LightRuleRegistry;\n /** 可选:当 cron service 不可用时(HTTP 路径)用作 fallback */\n subagentRunner?: SubagentRunner;\n /** 返回通知存储目录的绝对路径;storage ready 后才可用 */\n getNotificationsDir?: () => string | undefined;\n }) {\n this.logger = deps.logger;\n this.registry = deps.registry;\n this.subagentRunner = deps.subagentRunner;\n this.getNotificationsDir = deps.getNotificationsDir ?? (() => undefined);\n }\n\n /**\n * 通知落盘后调用。若有新增通知且存在 enabled 规则,则触发评估。\n *\n * 两条路径:\n * - cron 不为 null:enqueueRun(\"force\") 入队(gateway context 路径,正常路径)\n * - cron 为 null:通过 subagentRunner 直接运行(HTTP Relay 路径,fallback)\n *\n * @param cron 来自 gateway context 的 CronService;HTTP 路径下为 null\n * @param insertedCount 本次 ingest 新落盘的通知条数(StoredNotification 去重后)\n */\n async triggerIfNeeded(cron: CronServiceLike | null | undefined, insertedCount: number): Promise<void> {\n if (insertedCount === 0) return;\n if (this.registry.getEnabled().length === 0) return;\n\n if (!cron) {\n await this.triggerViaSubagent();\n return;\n }\n\n try {\n await this.ensureJobExists(cron);\n } catch (err: any) {\n this.logger.warn(`light-rules-evaluator: job ensure failed: ${err?.message ?? err}`);\n return;\n }\n\n try {\n const result = await cron.enqueueRun(EVALUATOR_JOB_ID, \"force\");\n if (!result.ok) {\n this.logger.warn(\"light-rules-evaluator: enqueueRun returned ok=false\");\n return;\n }\n if (\"enqueued\" in result && result.enqueued) {\n this.logger.info(`light-rules-evaluator: enqueued runId=${(result as any).runId}`);\n } else if (\"reason\" in result) {\n // already-running 或 not-due:当前运行中的 job 会处理到这批通知\n this.logger.info(`light-rules-evaluator: enqueueRun skipped (${result.reason})`);\n }\n } catch (err: any) {\n this.logger.warn(`light-rules-evaluator: enqueueRun failed: ${err?.message ?? err}`);\n }\n }\n\n /**\n * cron service 不可用时的 fallback:直接通过 subagentRunner 运行评估 session。\n *\n * 并发保护:若上一次 subagent 运行尚未完成,本次跳过。\n * checkpoint 保证即使本次跳过,下次触发时会处理所有积压通知。\n */\n private async triggerViaSubagent(): Promise<void> {\n if (!this.subagentRunner) {\n this.logger.warn(\n \"light-rules-evaluator: cron service unavailable and no subagent fallback configured; \" +\n \"notifications ingested via HTTP will not trigger light rules until an agent session is active\",\n );\n return;\n }\n\n if (this.subagentInFlight) {\n // 上次 subagent 运行中,本次跳过;checkpoint 保证下次触发时补处理\n this.logger.info(\"light-rules-evaluator: subagent run in-flight, skipping this trigger\");\n return;\n }\n\n const notificationsDir = this.getNotificationsDir();\n if (!notificationsDir) {\n this.logger.warn(\"light-rules-evaluator: notifications dir not ready, skipping subagent trigger\");\n return;\n }\n\n this.subagentInFlight = true;\n try {\n const result = await this.subagentRunner.run({\n sessionKey: EVALUATOR_SUBAGENT_SESSION_KEY,\n message: buildEvaluatorJobMessage(notificationsDir),\n deliver: false,\n idempotencyKey: `${EVALUATOR_SUBAGENT_SESSION_KEY}-${Date.now()}`,\n });\n this.logger.info(`light-rules-evaluator: subagent triggered runId=${result.runId}`);\n } catch (err: any) {\n this.logger.warn(`light-rules-evaluator: subagent trigger failed: ${err?.message ?? err}`);\n } finally {\n this.subagentInFlight = false;\n }\n }\n\n /**\n * 按需创建 `light-rules-evaluator` job。\n * 若 job 已存在(内存缓存或 cron store),直接返回;否则调用 `cron.add`。\n */\n private async ensureJobExists(cron: CronServiceLike): Promise<void> {\n if (this.jobEnsured) return;\n if (!this.ensureJobPromise) {\n this.ensureJobPromise = this.createJobIfNeeded(cron).finally(() => {\n this.ensureJobPromise = null;\n });\n }\n await this.ensureJobPromise;\n }\n\n private async createJobIfNeeded(cron: CronServiceLike): Promise<void> {\n if (cron.getJob(EVALUATOR_JOB_ID)) {\n this.jobEnsured = true;\n return;\n }\n\n try {\n await cron.add({\n id: EVALUATOR_JOB_ID,\n name: \"灯效规则评估\",\n description:\n \"事件驱动:通知到达时评估所有 enabled 灯效规则,命中则调用 light_control 触发灯效\",\n enabled: true,\n schedule: { kind: \"cron\", expr: FALLBACK_CRON_EXPR },\n sessionTarget: \"isolated\",\n wakeMode: \"now\",\n payload: {\n kind: \"agentTurn\",\n message: buildEvaluatorJobMessage(this.getNotificationsDir() ?? \"notifications\"),\n },\n });\n this.logger.info(\"light-rules-evaluator: job created\");\n } catch (err) {\n // 兜底处理:如果别的调用路径几乎同时创建成功,这里把它视为\"已存在\"。\n if (!cron.getJob(EVALUATOR_JOB_ID)) {\n throw err;\n }\n }\n\n this.jobEnsured = true;\n }\n}\n","/**\n * 旧版 light-rule task 目录迁移\n *\n * 目标:让存量 cron 路径平滑过渡到事件驱动架构,同时清理不再需要的辅助文件。\n *\n * 对每个 tasks/<name>/meta.json 中 type === \"light-rule\" 的目录:\n * 1. 把 matchRules 字段的内容合并进 description,再从 meta.json 删除该字段\n * 2. 替换 fetch.py 为只打印 NO_MATCH 的占位脚本(让旧 cron job 自动失效)\n * 3. 删除 README.md 和 checkpoint.json(新架构不再使用这两个文件)\n *\n * 安全设计:\n * - 不修改 type !== \"light-rule\" 的目录(普通 monitor 任务不受影响)\n * - 所有 I/O 错误只写 warn 日志,不抛出(不影响主链路启动)\n * - fetch.py 替换前先检查内容是否已经是 NO_MATCH 占位脚本,避免重复写\n *\n * 见 prd-lightrules-event-driven-refactor.md §迁移策略\n */\n\nimport {\n existsSync,\n readdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Logger } from \"../logger.js\";\nimport type { LightRuleStorageContext } from \"./storage.js\";\n\n/**\n * 替换旧版 fetch.py 的占位脚本。\n * 旧 cron job 运行后看到 NO_MATCH 就会自动退出,不再触发灯效。\n */\nconst NO_MATCH_FETCH_PY = `#!/usr/bin/env python3\n# 此文件由迁移工具生成。\n# 灯效规则已迁移至事件驱动架构,此 cron job 不再执行实际工作。\nprint(\"NO_MATCH\")\n`;\n\nfunction normalizeScriptText(text: string): string {\n return text.replace(/\\r\\n/g, \"\\n\").trim();\n}\n\n/**\n * 从 LightRuleStorageContext 解析 tasks 目录路径(与 storage.ts 逻辑一致)。\n */\nfunction resolveTasksDir(ctx: LightRuleStorageContext): string | null {\n if (ctx.workspaceDir) return join(ctx.workspaceDir, \"tasks\");\n\n if (ctx.stateDir) {\n const inferredWorkspaceDir = join(ctx.stateDir, \"workspace\");\n if (existsSync(inferredWorkspaceDir)) return join(inferredWorkspaceDir, \"tasks\");\n return join(ctx.stateDir, \"tasks\");\n }\n\n return null;\n}\n\n/**\n * 迁移入口。在插件 storage service start 完成后(lightRuleCtx 已回填)调用一次。\n */\nexport function migrateLegacyLightRuleTasks(\n ctx: LightRuleStorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n const tasksDir = resolveTasksDir(ctx);\n if (!tasksDir || !existsSync(tasksDir)) return;\n\n try {\n for (const entry of readdirSync(tasksDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n migrateTaskDir(join(tasksDir, String(entry.name)), logger);\n }\n } catch (err: any) {\n logger.warn(`migration: failed to read tasks dir: ${err?.message}`);\n }\n}\n\nfunction migrateTaskDir(taskDir: string, logger: Pick<Logger, \"info\" | \"warn\">): void {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return;\n\n let meta: Record<string, unknown>;\n try {\n meta = JSON.parse(readFileSync(metaPath, \"utf-8\"));\n } catch {\n return;\n }\n\n if (meta.type !== \"light-rule\") return;\n\n const name = typeof meta.name === \"string\" ? meta.name : taskDir;\n\n // ── 1. 把 matchRules 合并进 description ──────────────────────────────────\n mergeMatchRulesIntoDescription(meta, name, metaPath, logger);\n\n // ── 2. 替换 fetch.py 为 NO_MATCH 占位脚本 ────────────────────────────────\n replaceFetchPy(taskDir, name, logger);\n\n // ── 3. 删除 README.md 和 checkpoint.json ─────────────────────────────────\n for (const filename of [\"README.md\", \"checkpoint.json\"]) {\n removeFile(join(taskDir, filename), name, filename, logger);\n }\n}\n\nfunction mergeMatchRulesIntoDescription(\n meta: Record<string, unknown>,\n name: string,\n metaPath: string,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n const matchRules = meta.matchRules;\n if (!matchRules || typeof matchRules !== \"object\") return;\n\n const rules = matchRules as {\n appName?: string;\n senderKeywords?: string[];\n contentKeywords?: string[];\n };\n\n const parts: string[] = [];\n if (rules.appName) parts.push(`app=${rules.appName}`);\n if (rules.senderKeywords?.length) {\n parts.push(`发件人关键词=${rules.senderKeywords.join(\"、\")}`);\n }\n if (rules.contentKeywords?.length) {\n parts.push(`内容关键词=${rules.contentKeywords.join(\"、\")}`);\n }\n\n if (parts.length > 0) {\n const existing = typeof meta.description === \"string\" ? meta.description.trim() : \"\";\n meta.description = existing\n ? `${existing}。匹配规则:${parts.join(\",\")}`\n : `匹配规则:${parts.join(\",\")}`;\n }\n\n delete meta.matchRules;\n\n try {\n writeFileSync(metaPath, JSON.stringify(meta, null, 2), \"utf-8\");\n logger.info(`migration: merged matchRules into description for light rule: ${name}`);\n } catch (err: any) {\n logger.warn(`migration: failed to update meta.json for ${name}: ${err?.message}`);\n }\n}\n\nfunction replaceFetchPy(\n taskDir: string,\n name: string,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n const fetchPyPath = join(taskDir, \"fetch.py\");\n if (!existsSync(fetchPyPath)) return;\n\n try {\n const existing = readFileSync(fetchPyPath, \"utf-8\");\n if (normalizeScriptText(existing) === normalizeScriptText(NO_MATCH_FETCH_PY)) {\n return;\n }\n writeFileSync(fetchPyPath, NO_MATCH_FETCH_PY, \"utf-8\");\n logger.info(`migration: replaced fetch.py with NO_MATCH placeholder for ${name}`);\n } catch (err: any) {\n logger.warn(`migration: failed to replace fetch.py for ${name}: ${err?.message}`);\n }\n}\n\nfunction removeFile(\n filePath: string,\n ruleName: string,\n filename: string,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): void {\n if (!existsSync(filePath)) return;\n try {\n rmSync(filePath);\n logger.info(`migration: removed ${filename} for light rule: ${ruleName}`);\n } catch (err: any) {\n logger.warn(`migration: failed to remove ${filename} for ${ruleName}: ${err?.message}`);\n }\n}\n","/**\n * LightRuleRegistry —— 灯效规则的内存索引 + CRUD 包装\n *\n * 角色定位:\n * - 在事件驱动重构方案下,每条通知到达时都需要拿到\"当前 enabled 的全部规则\"\n * 用来拼装 Agent 的 system prompt。如果每次都扫盘 N 个 meta.json,\n * 5 秒延迟预算会被磨穿,所以引入这个常驻内存的 index。\n * - 同时它是 storage.ts 的 CRUD 包装:所有 create/update/delete 都会先落盘、\n * 再更新内存 Map,保证两者一致。\n *\n * 本类**不**做规则匹配 —— 匹配交给 Agent。registry 只负责\"有哪些规则\"和\n * \"按需拼装 prompt\"。\n *\n * 写路径用一个 promise 链做串行化(最朴素的 mutex),保证并发 CRUD\n * 不会出现\"内存和磁盘交错\"的状态。\n *\n * 见 prd-lightrules-event-driven-refactor.md §数据模型 / §触发流程\n */\n\nimport {\n createLightRule,\n deleteLightRule,\n listLightRules,\n updateLightRule,\n type LightRuleStorageContext,\n} from \"./storage.js\";\nimport type { LightRuleMeta } from \"./types.js\";\n\nexport { LightRuleError } from \"./storage.js\";\n\ntype CreateParams = Parameters<typeof createLightRule>[1];\ntype UpdateParams = Parameters<typeof updateLightRule>[1];\ntype CreateResult = ReturnType<typeof createLightRule>;\ntype UpdateResult = ReturnType<typeof updateLightRule>;\ntype DeleteResult = ReturnType<typeof deleteLightRule>;\n\nexport class LightRuleRegistry {\n private readonly ctx: LightRuleStorageContext;\n /** name → meta 的内存索引;落盘成功后才更新 */\n private readonly index = new Map<string, LightRuleMeta>();\n /** 写路径串行化锁:每次 mutate 都 chain 在前一次之后 */\n private writeChain: Promise<unknown> = Promise.resolve();\n\n constructor(ctx: LightRuleStorageContext) {\n this.ctx = ctx;\n this.reload();\n }\n\n /**\n * 从磁盘重新加载全部规则到内存。仅在构造时和外部显式触发时使用。\n * 正常 CRUD 路径不应该调用本方法 —— 通过 create/update/delete 增量维护即可。\n */\n reload(): void {\n this.index.clear();\n for (const meta of listLightRules(this.ctx)) {\n this.index.set(meta.name, meta);\n }\n }\n\n /** 全部规则(包含 disabled),调用方不要改返回值。 */\n list(): LightRuleMeta[] {\n return Array.from(this.index.values());\n }\n\n /** 仅 enabled 的规则。事件驱动评估链路使用。 */\n getEnabled(): LightRuleMeta[] {\n return this.list().filter((rule) => rule.enabled);\n }\n\n /** 按名字精确查找;不存在返回 null。 */\n get(name: string): LightRuleMeta | null {\n return this.index.get(name) ?? null;\n }\n\n /**\n * 创建规则。落盘成功后再写入内存索引。\n * 失败时 storage 抛 LightRuleError,内存索引保持不变。\n */\n async create(params: CreateParams): Promise<CreateResult> {\n return this.runExclusive(() => {\n const result = createLightRule(this.ctx, params);\n this.index.set(result.meta.name, result.meta);\n return result;\n });\n }\n\n /**\n * 更新规则。落盘成功后再刷新内存条目。\n */\n async update(params: UpdateParams): Promise<UpdateResult> {\n return this.runExclusive(() => {\n const result = updateLightRule(this.ctx, params);\n this.index.set(result.meta.name, result.meta);\n return result;\n });\n }\n\n /**\n * 删除规则。落盘成功后再从内存索引移除。\n */\n async delete(name: string): Promise<DeleteResult> {\n return this.runExclusive(() => {\n const result = deleteLightRule(this.ctx, name);\n this.index.delete(result.name);\n return result;\n });\n }\n\n /**\n * 拼装 Agent 评估用的 system prompt。\n *\n * 当前实现是一个最小可用骨架:列出全部 enabled 规则的 name + description。\n * M3 接入真实 Agent 链路时,会按 prd-lightrules-event-driven-refactor.md §Prompt 拼装\n * 的模板补齐\"任务说明 / 输出约束\"等段落。\n *\n * 现在先把方法签名冻结,避免后续散落在多个调用点。\n */\n buildSystemPrompt(): string {\n const enabled = this.getEnabled();\n if (enabled.length === 0) {\n return \"当前没有启用任何灯效规则。\";\n }\n\n const lines: string[] = [\n '你是一个判断\"通知 → 灯效规则\"是否命中的助手。',\n \"\",\n \"下面是用户当前启用的全部灯效规则(按创建时间倒序):\",\n \"\",\n ];\n\n const sorted = [...enabled].sort((a, b) =>\n (b.createdAt ?? \"\").localeCompare(a.createdAt ?? \"\"),\n );\n\n sorted.forEach((rule, idx) => {\n lines.push(\n `[${idx + 1}] name: ${rule.name}`,\n ` description: ${rule.description}`,\n \"\",\n );\n });\n\n lines.push(\n '任务:根据用户接下来发给你的\"通知\"内容,判断哪些规则被命中。',\n \"- 命中 0 条:不调用任何工具,直接结束。\",\n \"- 命中 1 条或多条:对每一条命中的规则调用一次 trigger_light(rule_name)。\",\n \"- 不要回复任何自由文本;判定结果**只**通过 tool calling 表达。\",\n '- 拿不准的时候倾向于\"不触发\",避免骚扰用户。',\n );\n\n return lines.join(\"\\n\");\n }\n\n /**\n * 把一段同步操作排队进 write chain,保证 mutate 串行执行。\n *\n * 用 promise 链做 mutex 是最简单的方案:每次 runExclusive 都把\n * `writeChain` 推进一步。即使前一个任务失败,链也会继续往下走,\n * 后续任务不会被永久阻塞。\n */\n private runExclusive<T>(fn: () => T): Promise<T> {\n const next = this.writeChain.then(\n () => fn(),\n () => fn(),\n );\n // 不让链上的失败传播下去(已在 then 的 onRejected 回调里吸收)\n this.writeChain = next.catch(() => undefined);\n return next;\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { loadEnvName } from \"../env.js\";\nimport type { Logger } from \"../logger.js\";\nimport { createTunnelService } from \"../tunnel/service.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { resolveUpdateChannel } from \"../update/channel.js\";\nimport { registerAutoUpdate } from \"../update/index.js\";\nimport type { BroadcastFn } from \"../update/types.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\n\ninterface AutoUpdateDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n getBroadcastFn: () => BroadcastFn | null;\n cacheBroadcast: (broadcast: BroadcastFn | undefined) => void;\n tunnelService: ReturnType<typeof createTunnelService> | null;\n}\n\nexport function registerAutoUpdateLifecycle(\n deps: AutoUpdateDeps,\n): ReturnType<typeof registerAutoUpdate> {\n const {\n api,\n config,\n logger,\n getBroadcastFn,\n cacheBroadcast,\n tunnelService,\n } = deps;\n\n const autoUpdateConfig = {\n ...config.autoUpdate,\n channel: resolveUpdateChannel({\n configuredChannel: config.autoUpdate?.channel,\n currentVersion: PLUGIN_VERSION,\n envName: loadEnvName(),\n }),\n };\n\n const autoUpdateLifecycle = registerAutoUpdate(\n api,\n logger,\n autoUpdateConfig,\n getBroadcastFn,\n cacheBroadcast,\n tunnelService\n ? {\n notifyUpdateAvailable: (update) => tunnelService.notifyUpdateAvailable(update),\n clearPendingUpdate: () => tunnelService.clearPendingUpdate(),\n }\n : undefined,\n );\n\n api.registerService({\n id: \"update-checker\",\n start() {\n autoUpdateLifecycle.start();\n },\n stop() {\n autoUpdateLifecycle.stop();\n },\n });\n\n logger.info(\"自动更新检查服务已注册\");\n return autoUpdateLifecycle;\n}\n","import type { EnvName } from \"../env.js\";\nimport type { AutoUpdateConfig } from \"./types.js\";\n\n/**\n * 解析自动更新频道。\n *\n * 默认规则:\n * - 用户显式配置时,以配置为准\n * - 当前安装的是预发布版时,默认持续跟踪 beta\n * - 否则开发环境走 beta,生产环境走 latest\n */\nexport function resolveUpdateChannel(params: {\n configuredChannel?: AutoUpdateConfig[\"channel\"];\n currentVersion: string;\n envName: EnvName;\n}): \"latest\" | \"beta\" {\n if (params.configuredChannel) {\n return params.configuredChannel;\n }\n\n if (params.currentVersion.includes(\"-\")) {\n return \"beta\";\n }\n\n return params.envName === \"development\" ? \"beta\" : \"latest\";\n}\n","import { PLUGIN_VERSION } from \"../version.js\";\nimport type { Logger } from \"../logger.js\";\nimport type { UpdateInfo } from \"./types.js\";\n\nconst CDN_BASE_URL = \"https://cdn.yoootek.com/openclaw-plugin\";\nconst NPM_BASE_URL =\n \"https://registry.npmjs.org/@yoooclaw/phone-notifications\";\nconst FETCH_TIMEOUT_MS = 5_000;\n\nexport class UpdateChecker {\n private timer: ReturnType<typeof setTimeout> | null = null;\n private notifiedVersion: string | null = null;\n\n constructor(\n private readonly logger: Logger,\n private readonly onUpdateFound: (info: UpdateInfo) => void,\n private readonly intervalMs: number,\n private readonly channel: \"latest\" | \"beta\",\n ) {}\n\n start(): void {\n // 首次延迟 1 分钟,避免影响插件启动\n this.timer = setTimeout(() => {\n void this.check();\n this.timer = setInterval(() => void this.check(), this.intervalMs);\n }, 60_000);\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n\n async check(): Promise<void> {\n const latest = await this.fetchLatestVersion();\n if (!latest || latest === PLUGIN_VERSION) return;\n if (latest === this.notifiedVersion) return;\n\n // 当前版本为预发布且 channel 不是 beta 时,不提示\n if (PLUGIN_VERSION.includes(\"-\") && this.channel !== \"beta\") return;\n\n this.notifiedVersion = latest;\n this.logger.info(`发现新版本: ${PLUGIN_VERSION} → ${latest}`);\n this.onUpdateFound({ current: PLUGIN_VERSION, latest });\n }\n\n private async fetchLatestVersion(): Promise<string | null> {\n const tag = this.channel === \"beta\" ? \"beta\" : \"latest\";\n\n // 优先 CDN(轻量 plain text)\n try {\n const res = await fetch(`${CDN_BASE_URL}/${tag}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (res.ok) {\n const text = (await res.text()).trim();\n if (text) return text;\n }\n } catch {\n // CDN 不可达,回退 npm\n }\n\n // 回退 npm registry\n try {\n const res = await fetch(`${NPM_BASE_URL}/${tag}`, {\n signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n });\n if (res.ok) {\n const data = (await res.json()) as { version?: string };\n return data.version ?? null;\n }\n } catch {\n this.logger.info(\"版本检查失败(CDN + npm 均不可达),跳过\");\n }\n\n return null;\n }\n}\n","import type { Logger } from \"../logger.js\";\n\nconst VERSION_PATTERN = /^\\d+\\.\\d+\\.\\d+(-[\\w.]+)?$/;\n\nexport interface UpdateResult {\n success: boolean;\n message: string;\n}\n\n/**\n * 执行插件更新命令。\n * 对话通道的 tool 和网关通道的 gateway method 共用此函数。\n *\n * @param version 目标版本号,需通过正则校验防止命令注入\n * @param runCommand Host 提供的 runCommandWithTimeout\n */\nexport async function executeUpdate(\n version: string,\n runCommand: (\n argv: string[],\n opts: { timeoutMs: number },\n ) => Promise<{ code: number | null; stdout: string; stderr: string }>,\n logger: Logger,\n): Promise<UpdateResult> {\n if (!VERSION_PATTERN.test(version)) {\n return { success: false, message: `非法版本号: ${version}` };\n }\n\n const argv = [\n \"openclaw\",\n \"extension\",\n \"install\",\n `@yoooclaw/phone-notifications@${version}`,\n ];\n logger.info(`执行更新: ${argv.join(\" \")}`);\n\n try {\n const result = await runCommand(argv, { timeoutMs: 120_000 });\n\n if (result.code === 0) {\n const msg = `已更新到 ${version},请重启 gateway 生效`;\n logger.info(msg);\n return { success: true, message: msg };\n }\n\n const errMsg = `更新失败 (exit ${result.code}): ${result.stderr || result.stdout}`;\n logger.error(errMsg);\n return { success: false, message: errMsg };\n } catch (err) {\n const errMsg = `更新命令执行异常: ${String(err)}`;\n logger.error(errMsg);\n return { success: false, message: errMsg };\n }\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport type {\n AutoUpdateConfig,\n BroadcastFn,\n ExternalUpdateNotifier,\n UpdateInfo,\n} from \"./types.js\";\nimport { UpdateChecker } from \"./checker.js\";\nimport { executeUpdate } from \"./executor.js\";\n\n/**\n * 注册插件自动更新能力:\n * - 定时版本检查(UpdateChecker)\n * - 对话通道:before_prompt_build hook + plugin-update tool\n * - 网关通道:broadcast 推送 + plugin.update gateway method\n *\n * 返回 start/stop 供 registerService 管理生命周期。\n */\nexport function registerAutoUpdate(\n api: OpenClawPluginApi,\n logger: Logger,\n config: AutoUpdateConfig,\n getBroadcast: () => BroadcastFn | null,\n rememberBroadcast?: (broadcast: BroadcastFn | undefined) => void,\n externalUpdateNotifier?: ExternalUpdateNotifier,\n): {\n start: () => void;\n stop: () => void;\n notifyBroadcastReady: () => void;\n} {\n if (config.enabled === false) {\n logger.info(\"自动更新已禁用 (autoUpdate.enabled = false)\");\n return { start() {}, stop() {}, notifyBroadcastReady() {} };\n }\n\n let pendingUpdate: UpdateInfo | null = null;\n let pendingGatewayUpdate: UpdateInfo | null = null;\n\n function tryBroadcastUpdate(update: UpdateInfo): boolean {\n const broadcast = getBroadcast();\n if (!broadcast) return false;\n\n broadcast(\"plugin.updateAvailable\", {\n pluginId: \"phone-notifications\",\n current: update.current,\n latest: update.latest,\n });\n pendingGatewayUpdate = null;\n return true;\n }\n\n // ── 对话通道:hook 注入 system prompt ──\n\n api.on(\"before_prompt_build\", () => {\n if (!pendingUpdate) return;\n return {\n appendSystemContext:\n `[系统通知] phone-notifications 插件有新版本 ${pendingUpdate.latest} 可用` +\n `(当前版本 ${pendingUpdate.current})。\\n` +\n `请用自然语言在合适时机告知用户,若用户同意更新,` +\n `调用 plugin-update tool 并传入 version 参数。` +\n `若用户拒绝,不再重复提醒。`,\n };\n });\n\n // ── 对话通道:plugin-update tool ──\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n api.registerTool({\n name: \"plugin-update\",\n label: \"Plugin Update\",\n description:\n \"将 phone-notifications 插件更新到指定版本。\" +\n \"仅在用户明确同意更新后调用。更新完成后需重启 gateway 生效。\",\n parameters: {\n type: \"object\",\n required: [\"version\"],\n additionalProperties: false,\n properties: {\n version: {\n type: \"string\",\n description: \"目标版本号,如 1.11.0\",\n },\n },\n },\n async execute(_toolCallId: string, params: unknown) {\n const { version } = params as { version: string };\n const result = await executeUpdate(\n version,\n api.runtime.system.runCommandWithTimeout,\n logger,\n );\n if (result.success) {\n pendingUpdate = null;\n externalUpdateNotifier?.clearPendingUpdate();\n }\n return {\n content: [{ type: \"text\" as const, text: result.message }],\n details: result,\n };\n },\n } as any);\n\n // ── 网关通道:plugin.update gateway method ──\n\n api.registerGatewayMethod(\"plugin.update\", async ({ params, respond, context }) => {\n rememberBroadcast?.(context?.broadcast);\n\n const version = (params as { version?: string }).version;\n if (!version) {\n respond(false, undefined, {\n code: \"MISSING_VERSION\",\n message: \"version is required\",\n });\n return;\n }\n const result = await executeUpdate(\n version,\n api.runtime.system.runCommandWithTimeout,\n logger,\n );\n if (result.success) {\n pendingUpdate = null;\n externalUpdateNotifier?.clearPendingUpdate();\n }\n if (result.success) {\n respond(true, { message: result.message });\n } else {\n respond(false, undefined, {\n code: \"UPDATE_FAILED\",\n message: result.message,\n });\n }\n });\n\n // ── 版本检查器 ──\n\n const intervalMs = (config.checkIntervalHours ?? 4) * 3_600_000;\n const channel = config.channel ?? \"latest\";\n\n logger.info(\n `自动更新已启用: channel=${channel}, checkIntervalHours=${config.checkIntervalHours ?? 4}`,\n );\n\n const checker = new UpdateChecker(\n logger,\n (update) => {\n pendingUpdate = update;\n\n const broadcasted = tryBroadcastUpdate(update);\n if (!broadcasted) pendingGatewayUpdate = update;\n if (!broadcasted) {\n externalUpdateNotifier?.notifyUpdateAvailable(update);\n }\n\n logger.info(\n `已通知更新 ${update.current} → ${update.latest}` +\n (broadcasted\n ? \"(对话 + 网关)\"\n : \"(对话通道已生效,等待下次 gateway 请求时补发客户端事件)\"),\n );\n },\n intervalMs,\n channel,\n );\n\n return {\n start: () => checker.start(),\n stop: () => checker.stop(),\n notifyBroadcastReady() {\n const update = pendingGatewayUpdate;\n if (!update) return;\n if (!tryBroadcastUpdate(update)) return;\n logger.info(`已补发插件更新事件 ${update.current} → ${update.latest}`);\n },\n };\n}\n","import { basename, dirname } from \"node:path\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { registerAllCli } from \"../cli/index.js\";\nimport type { Logger } from \"../logger.js\";\n\nfunction inferOpenClawRootDir(workspaceDir?: string): string | undefined {\n if (!workspaceDir) {\n return undefined;\n }\n\n if (basename(workspaceDir) !== \"workspace\") {\n return undefined;\n }\n\n return dirname(workspaceDir);\n}\n\nexport function registerPluginCli(\n api: OpenClawPluginApi,\n params: {\n logger: Logger;\n openclawDir?: string;\n },\n): void {\n const { logger, openclawDir } = params;\n\n const registerAlias = (command: \"ntf\" | \"phone-notifications\"): void => {\n api.registerCli(\n (ctx) => {\n const effectiveStateDir = openclawDir ?? inferOpenClawRootDir(ctx.workspaceDir);\n registerAllCli(\n ctx.program,\n {\n stateDir: effectiveStateDir,\n workspaceDir: ctx.workspaceDir,\n },\n command,\n );\n },\n { commands: [command] },\n );\n };\n\n registerAlias(\"ntf\");\n registerAlias(\"phone-notifications\");\n logger.info(\"CLI 命令已注册: ntf, phone-notifications\");\n}\n","import { existsSync, rmSync } from \"node:fs\";\nimport type { CliCommand } from \"./helpers.js\";\nimport { output } from \"./helpers.js\";\nimport {\n credentialsPath,\n readCredentials,\n writeCredentials,\n} from \"../auth/credentials.js\";\n\nexport function registerAuthCli(program: CliCommand): void {\n const auth = program\n .command(\"auth\")\n .description(\"用户认证管理\");\n\n auth\n .command(\"set-api-key <apiKey>\")\n .description(\"设置用户 API Key(持久化到本地配置)\")\n .action((apiKey: string) => {\n writeCredentials({ ...readCredentials(), apiKey, token: undefined });\n output({\n ok: true,\n apiKey: apiKey.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n });\n\n // 兼容旧命令:set-token <token>,现在等价于 set-api-key\n auth\n .command(\"set-token <token>\")\n .description(\"(兼容)设置用户 API Key(旧命令名)\")\n .action((token: string) => {\n writeCredentials({ ...readCredentials(), apiKey: token, token: undefined });\n output({\n ok: true,\n apiKey: token.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n });\n\n auth\n .command(\"show\")\n .description(\"查看当前认证状态\")\n .action(() => {\n const creds = readCredentials();\n const apiKey = creds.apiKey ?? creds.token;\n if (apiKey) {\n output({\n ok: true,\n hasApiKey: true,\n apiKey: apiKey.slice(0, 8) + \"…\",\n storedAt: credentialsPath(),\n });\n } else {\n output({ ok: true, hasApiKey: false });\n }\n });\n\n auth\n .command(\"clear\")\n .description(\"清除已保存的认证信息\")\n .action(() => {\n const path = credentialsPath();\n if (existsSync(path)) {\n const creds = readCredentials();\n delete creds.apiKey;\n delete creds.token;\n if (Object.keys(creds).length === 0) {\n rmSync(path, { force: true });\n } else {\n writeCredentials(creds);\n }\n }\n output({ ok: true, cleared: true });\n });\n}\n","import type { StoredNotification } from \"../notification/storage.js\";\nimport {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeysAsync,\n readDateFileAsync,\n parseIsoTime,\n sortNotificationsByTimestampDesc,\n output,\n exitError,\n progress,\n} from \"./helpers.js\";\n\nfunction filterItem(\n item: StoredNotification,\n opts: { app?: string; sender?: string; keyword?: string },\n): boolean {\n if (opts.app && item.appName !== opts.app) return false;\n if (opts.sender && !item.title.includes(opts.sender)) return false;\n if (\n opts.keyword &&\n !item.title.includes(opts.keyword) &&\n !item.content.includes(opts.keyword)\n ) {\n return false;\n }\n return true;\n}\n\nexport function registerNtfSearch(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"search\")\n .description(\"查询通知(按时间/应用/发送人/关键词筛选)\")\n .option(\"--from <time>\", \"开始时间 ISO 8601,例如 2026-03-01T09:00:00+08:00\")\n .option(\"--to <time>\", \"结束时间 ISO 8601,例如 2026-03-01T18:00:00+08:00\")\n .option(\"--app <name>\", \"按应用名过滤\")\n .option(\"--sender <name>\", \"按发送人过滤\")\n .option(\"--keyword <text>\", \"在标题和内容中搜索关键词\")\n .option(\"--limit <n>\", \"最大返回条数\", \"100\")\n .action(\n async (opts: {\n from?: string;\n to?: string;\n app?: string;\n sender?: string;\n keyword?: string;\n limit: string;\n }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n progress(\"正在搜索通知...\");\n\n const limit = parseInt(opts.limit, 10) || 100;\n if (limit <= 0) {\n exitError(\"INVALID_LIMIT\", \"--limit 必须是大于 0 的整数\");\n }\n\n const hasFrom = typeof opts.from === \"string\" && opts.from.length > 0;\n const hasTo = typeof opts.to === \"string\" && opts.to.length > 0;\n const fromTs = hasFrom ? parseIsoTime(opts.from!, \"--from\") : null;\n const toTs = hasTo ? parseIsoTime(opts.to!, \"--to\") : null;\n\n if (fromTs !== null && toTs !== null && fromTs > toTs) {\n exitError(\"INVALID_TIME_RANGE\", \"--from 不能晚于 --to\");\n }\n\n const keys = await listDateKeysAsync(dir);\n const results: StoredNotification[] = [];\n\n if (fromTs !== null || toTs !== null) {\n const fromDateKey = hasFrom ? opts.from!.slice(0, 10) : null;\n const toDateKey = hasTo ? opts.to!.slice(0, 10) : null;\n\n for (const dateKey of keys) {\n if (fromDateKey && dateKey < fromDateKey) continue;\n if (toDateKey && dateKey > toDateKey) continue;\n\n const items = await readDateFileAsync(dir, dateKey);\n for (const item of items) {\n if (!filterItem(item, opts)) continue;\n\n const itemTs = Date.parse(item.timestamp);\n if (Number.isNaN(itemTs)) continue;\n if (fromTs !== null && itemTs < fromTs) continue;\n if (toTs !== null && itemTs > toTs) continue;\n results.push(item);\n }\n }\n } else {\n for (const dateKey of keys) {\n const items = await readDateFileAsync(dir, dateKey);\n for (const item of items) {\n if (!filterItem(item, opts)) continue;\n if (Number.isNaN(Date.parse(item.timestamp))) continue;\n results.push(item);\n }\n }\n }\n\n const notifications = sortNotificationsByTimestampDesc(results).slice(\n 0,\n limit,\n );\n\n output({\n ok: true,\n total: notifications.length,\n notifications,\n });\n },\n );\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeys,\n readDateFile,\n filterDateRange,\n today,\n daysAgo,\n output,\n exitError,\n} from \"./helpers.js\";\n\ntype Dimension = \"date\" | \"app\" | \"sender\" | \"hour\" | \"all\";\n\nexport function registerNtfStats(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"stats\")\n .description(\"通知统计分析(按日期/应用/发送人/时段聚合)\")\n .option(\"--from <date>\", \"开始日期 YYYY-MM-DD\", daysAgo(7))\n .option(\"--to <date>\", \"结束日期 YYYY-MM-DD\", today())\n .option(\"--app <name>\", \"只统计指定应用\")\n .option(\"--dim <dimension>\", \"统计维度:date/app/sender/hour/all\", \"all\")\n .action(\n (opts: { from: string; to: string; app?: string; dim: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const dim = opts.dim as Dimension;\n const keys = filterDateRange(listDateKeys(dir), opts.from, opts.to);\n\n const byDate: Record<string, number> = {};\n const byApp: Record<string, number> = {};\n const bySender: Record<string, number> = {};\n const byHour: Record<string, number> = {};\n let total = 0;\n\n for (const dateKey of keys) {\n const items = readDateFile(dir, dateKey);\n let dateCount = 0;\n for (const item of items) {\n if (opts.app && item.appName !== opts.app) continue;\n total++;\n dateCount++;\n\n byApp[item.appName] = (byApp[item.appName] || 0) + 1;\n\n if (item.title) {\n bySender[item.title] = (bySender[item.title] || 0) + 1;\n }\n\n const hourMatch = /T(\\d{2}):/.exec(item.timestamp);\n if (hourMatch) {\n const h = hourMatch[1];\n byHour[h] = (byHour[h] || 0) + 1;\n }\n }\n byDate[dateKey] = dateCount;\n }\n\n const result: Record<string, unknown> = {\n ok: true,\n range: { from: opts.from, to: opts.to },\n total,\n };\n\n if (dim === \"date\" || dim === \"all\") {\n result.byDate = byDate;\n }\n if (dim === \"app\" || dim === \"all\") {\n result.byApp = byApp;\n }\n if (dim === \"sender\" || dim === \"all\") {\n // Sort by count descending, return top 20\n const sorted = Object.entries(bySender)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 20)\n .map(([sender, count]) => ({ sender, count }));\n result.bySender = sorted;\n }\n if (dim === \"hour\" || dim === \"all\") {\n result.byHour = byHour;\n }\n\n output(result);\n },\n );\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n listDateKeys,\n readDateFile,\n output,\n exitError,\n} from \"./helpers.js\";\n\ninterface CheckpointData {\n [dateKey: string]: { lastIndex: number };\n}\n\nconst SYNC_FETCH_LIMIT = 300;\n\nfunction checkpointPath(dir: string): string {\n return join(dir, \".checkpoint.json\");\n}\n\nfunction readCheckpoint(dir: string): CheckpointData {\n const p = checkpointPath(dir);\n if (!existsSync(p)) return {};\n try {\n return JSON.parse(readFileSync(p, \"utf-8\"));\n } catch {\n return {};\n }\n}\n\nfunction writeCheckpoint(dir: string, data: CheckpointData): void {\n writeFileSync(checkpointPath(dir), JSON.stringify(data, null, 2), \"utf-8\");\n}\n\nexport function registerNtfSync(ntf: CliCommand, ctx: CliContext): void {\n const sync = ntf.command(\"sync\").description(\"同步通知到记忆系统\");\n\n sync\n .command(\"scan\")\n .description(\"扫描未处理的通知,返回待同步摘要\")\n .action(() => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const checkpoint = readCheckpoint(dir);\n const keys = listDateKeys(dir); // descending\n const pending: { date: string; count: number; startIndex: number }[] = [];\n let totalPending = 0;\n\n for (const dateKey of keys) {\n const items = readDateFile(dir, dateKey);\n const lastIndex = checkpoint[dateKey]?.lastIndex ?? -1;\n const unprocessed = items.length - (lastIndex + 1);\n if (unprocessed > 0) {\n pending.push({\n date: dateKey,\n count: unprocessed,\n startIndex: lastIndex + 1,\n });\n totalPending += unprocessed;\n }\n }\n\n output({ ok: true, pending, totalPending });\n });\n\n sync\n .command(\"fetch\")\n .description(\"获取指定日期的未处理通知详情\")\n .requiredOption(\"--date <date>\", \"目标日期 YYYY-MM-DD\")\n .action((opts: { date: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const items = readDateFile(dir, opts.date);\n if (items.length === 0) {\n exitError(\"NO_DATA\", `日期 ${opts.date} 无通知数据`);\n }\n\n const checkpoint = readCheckpoint(dir);\n const lastIndex = checkpoint[opts.date]?.lastIndex ?? -1;\n const startIndex = lastIndex + 1;\n const unprocessed = items.slice(startIndex);\n const notifications = unprocessed.slice(0, SYNC_FETCH_LIMIT);\n const endIndex =\n notifications.length > 0 ? startIndex + notifications.length - 1 : lastIndex;\n const hasMore = unprocessed.length > notifications.length;\n\n if (unprocessed.length === 0) {\n output({\n ok: true,\n date: opts.date,\n startIndex,\n endIndex,\n nextStartIndex: null,\n limit: SYNC_FETCH_LIMIT,\n returned: 0,\n totalUnprocessed: 0,\n hasMore: false,\n notifications: [],\n });\n return;\n }\n\n output({\n ok: true,\n date: opts.date,\n startIndex,\n endIndex,\n nextStartIndex: hasMore ? endIndex + 1 : null,\n limit: SYNC_FETCH_LIMIT,\n returned: notifications.length,\n totalUnprocessed: unprocessed.length,\n hasMore,\n notifications,\n });\n });\n\n sync\n .command(\"commit\")\n .description(\"标记指定日期当前批次处理完成,更新 checkpoint\")\n .requiredOption(\"--date <date>\", \"目标日期 YYYY-MM-DD\")\n .action((opts: { date: string }) => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n\n const items = readDateFile(dir, opts.date);\n if (items.length === 0) {\n exitError(\"NO_DATA\", `日期 ${opts.date} 无通知数据`);\n }\n\n const checkpoint = readCheckpoint(dir);\n const lastIndex = checkpoint[opts.date]?.lastIndex ?? -1;\n const committedIndex = Math.min(items.length - 1, lastIndex + SYNC_FETCH_LIMIT);\n const hasMore = committedIndex < items.length - 1;\n checkpoint[opts.date] = { lastIndex: committedIndex };\n writeCheckpoint(dir, checkpoint);\n\n output({\n ok: true,\n date: opts.date,\n committedIndex,\n limit: SYNC_FETCH_LIMIT,\n hasMore,\n nextStartIndex: hasMore ? committedIndex + 1 : null,\n });\n });\n}\n","import {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type CliCommand, type CliContext, output, exitError } from \"./helpers.js\";\nimport { generateFetchPy } from \"../monitor/fetch-gen.js\";\n\ninterface MonitorMeta {\n name: string;\n type?: \"monitor\" | \"light-rule\";\n description: string;\n matchRules: Record<string, unknown>;\n cronSchedule: string;\n enabled: boolean;\n createdAt: string;\n updatedAt?: string;\n}\n\nfunction tasksDir(ctx: CliContext): string {\n const base = ctx.workspaceDir || ctx.stateDir;\n if (!base) throw new Error(\"workspaceDir and stateDir both unavailable\");\n return join(base, \"tasks\");\n}\n\nfunction readMeta(taskDir: string): MonitorMeta | null {\n const metaPath = join(taskDir, \"meta.json\");\n if (!existsSync(metaPath)) return null;\n try {\n return JSON.parse(readFileSync(metaPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\nfunction writeMeta(taskDir: string, meta: MonitorMeta): void {\n writeFileSync(join(taskDir, \"meta.json\"), JSON.stringify(meta, null, 2), \"utf-8\");\n}\n\nfunction generateReadme(name: string, description: string): string {\n return `# Monitor Task: ${name}\n\n## 描述\n${description}\n\n## 处理指南\n当 fetch.py 输出匹配的通知时,请:\n1. 阅读匹配到的通知内容\n2. 根据任务描述判断是否需要通知用户\n3. 如需通知用户,使用 message 工具发送摘要\n`;\n}\n\nexport function registerNtfMonitor(ntf: CliCommand, ctx: CliContext): void {\n const monitor = ntf.command(\"monitor\").description(\"通知监控任务管理\");\n\n monitor\n .command(\"list\")\n .description(\"列出所有监控任务\")\n .action(() => {\n const dir = tasksDir(ctx);\n if (!existsSync(dir)) {\n output({ ok: true, tasks: [] });\n return;\n }\n\n const tasks: MonitorMeta[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const meta = readMeta(join(dir, entry.name));\n if (meta) tasks.push(meta);\n }\n\n output({ ok: true, tasks });\n });\n\n monitor\n .command(\"show <name>\")\n .description(\"查看监控任务详情\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n const checkpointPath = join(taskDir, \"checkpoint.json\");\n let checkpoint = {};\n if (existsSync(checkpointPath)) {\n try {\n checkpoint = JSON.parse(readFileSync(checkpointPath, \"utf-8\"));\n } catch {\n // ignore\n }\n }\n\n output({\n ok: true,\n ...meta,\n matchScript: `tasks/${name}/fetch.py`,\n readme: `tasks/${name}/README.md`,\n checkpoint,\n });\n });\n\n monitor\n .command(\"create <name>\")\n .description(\"创建监控任务\")\n .requiredOption(\"--description <text>\", \"任务描述\")\n .requiredOption(\"--match-rules <json>\", \"匹配规则 JSON\")\n .requiredOption(\"--schedule <cron>\", \"cron 表达式\")\n .action(\n (\n name: string,\n opts: {\n description: string;\n matchRules: string;\n schedule: string;\n },\n ) => {\n const dir = tasksDir(ctx);\n const taskDir = join(dir, name);\n\n if (existsSync(taskDir)) {\n exitError(\"ALREADY_EXISTS\", `监控任务 '${name}' 已存在`);\n }\n\n let matchRules: Record<string, unknown>;\n try {\n matchRules = JSON.parse(opts.matchRules);\n } catch {\n exitError(\n \"VALIDATION_FAILED\",\n \"match-rules 必须是合法的 JSON\",\n );\n }\n\n mkdirSync(taskDir, { recursive: true });\n\n const meta: MonitorMeta = {\n name,\n description: opts.description,\n matchRules,\n cronSchedule: opts.schedule,\n enabled: true,\n createdAt: new Date().toISOString(),\n };\n writeMeta(taskDir, meta);\n writeFileSync(\n join(taskDir, \"fetch.py\"),\n generateFetchPy(name, matchRules),\n \"utf-8\",\n );\n writeFileSync(\n join(taskDir, \"README.md\"),\n generateReadme(name, opts.description),\n \"utf-8\",\n );\n\n output({\n ok: true,\n name,\n created: {\n script: `tasks/${name}/fetch.py`,\n readme: `tasks/${name}/README.md`,\n cronJob: `notif-${name}`,\n },\n cronHint: {\n action: \"add\",\n job: {\n name: `notif-${name}`,\n schedule: opts.schedule,\n sessionTarget: \"isolated\",\n message: `手机通知已由独立服务实时捕获到 notifications/ 目录的 JSON 文件中。\\n执行:python3 tasks/${name}/fetch.py --notifications-dir notifications\\n- NO_CHANGE 或 NO_MATCH → 不回复,直接结束。\\n- 有输出 → 读 tasks/${name}/README.md 了解如何处理数据并通知用户。`,\n },\n },\n });\n },\n );\n\n monitor\n .command(\"delete <name>\")\n .description(\"删除监控任务\")\n .option(\"--yes\", \"跳过确认\")\n .action((name: string, opts: { yes?: boolean }) => {\n const taskDir = join(tasksDir(ctx), name);\n if (!existsSync(taskDir)) {\n exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n }\n\n if (!opts.yes) {\n output({\n ok: false,\n error: {\n code: \"CONFIRMATION_REQUIRED\",\n message: `确认删除监控任务 '${name}'?添加 --yes 跳过确认`,\n },\n });\n process.exit(1);\n }\n\n rmSync(taskDir, { recursive: true, force: true });\n output({\n ok: true,\n name,\n deleted: true,\n cronHint: {\n action: \"remove\",\n name: `notif-${name}`,\n },\n });\n });\n\n monitor\n .command(\"enable <name>\")\n .description(\"启用监控任务\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n meta.enabled = true;\n writeMeta(taskDir, meta);\n output({ ok: true, name, enabled: true });\n });\n\n monitor\n .command(\"disable <name>\")\n .description(\"暂停监控任务\")\n .action((name: string) => {\n const taskDir = join(tasksDir(ctx), name);\n const meta = readMeta(taskDir);\n if (!meta) exitError(\"NOT_FOUND\", `监控任务 '${name}' 不存在`);\n\n meta.enabled = false;\n writeMeta(taskDir, meta);\n output({ ok: true, name, enabled: false });\n });\n}\n","import { type CliCommand, output, exitError } from \"./helpers.js\";\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport { parseAndValidateSegments } from \"../light/validators.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\n\nexport function registerLightSend(light: CliCommand): void {\n light\n .command(\"send\")\n .description(\"发送灯效指令到硬件设备\")\n .requiredOption(\"--segments <json>\", \"灯效参数 JSON\")\n .option(\"--repeat\", \"无限循环播放(默认仅播放一轮)\")\n .option(\"--repeat-times <n>\", \"整条组合重复次数:0=无限,1=一轮;当前 ANCS 路径不支持 >=2\")\n .action(async (opts: { segments: string; repeat?: boolean; repeatTimes?: string }) => {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (e: any) {\n exitError(\"AUTH_REQUIRED\", e.message);\n }\n\n const segments = parseAndValidateSegments(opts.segments);\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({\n repeat: opts.repeat,\n repeat_times: opts.repeatTimes === undefined ? undefined : Number(opts.repeatTimes),\n });\n assertAncsRepeatTimes(repeatTimes);\n } catch (e: any) {\n exitError(\"VALIDATION_FAILED\", e.message);\n }\n\n const result = await sendLightEffect(\n apiKey,\n segments,\n undefined,\n { repeat_times: repeatTimes },\n );\n\n if (!result.ok) {\n exitError(\"HTTP_ERROR\", `请求失败: ${result.status} ${result.error}`);\n }\n\n output({ ok: true, bizUniqueId: result.bizUniqueId, response: result.response });\n });\n}\n","import { randomUUID } from \"node:crypto\";\nimport { buildLightEffectApnsBody } from \"./protocol.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport type { LightSegment } from \"../types.js\";\nimport type { RepeatArgument } from \"./repeat.js\";\n\nexport interface SendLightResult {\n ok: boolean;\n bizUniqueId?: string;\n response?: unknown;\n status?: number;\n error?: string;\n}\n\nexport async function sendLightEffect(\n apiKey: string,\n segments: LightSegment[],\n logger?: { info: (msg: string) => void; warn: (msg: string) => void },\n repeatInput?: RepeatArgument,\n reason?: string,\n): Promise<SendLightResult> {\n const apiUrl = getEnvUrls().lightApiUrl;\n const appKey = process.env.LIGHT_APP_KEY;\n const templateId = process.env.LIGHT_TEMPLATE_ID;\n\n logger?.info(\n `Light sender: apiUrl=${apiUrl ?? \"UNSET\"}, appKey=${appKey ? appKey.substring(0, 8) + \"…\" : \"UNSET\"}, templateId=${templateId ?? \"UNSET\"}, apiKey=${apiKey ? apiKey.substring(0, 20) + \"…\" : \"EMPTY\"}, segments=${JSON.stringify(segments)}`,\n );\n\n if (!apiUrl || !appKey || !templateId) {\n return {\n ok: false,\n error:\n \"灯效 API 未配置,请设置环境变量 LIGHT_API_URL / LIGHT_APP_KEY / LIGHT_TEMPLATE_ID\",\n };\n }\n\n let bizContent: string;\n try {\n bizContent = buildLightEffectApnsBody(segments, repeatInput);\n } catch (error: any) {\n return { ok: false, error: error?.message ?? String(error) };\n }\n const bizUniqueId = randomUUID();\n\n const requestBody = {\n appKey,\n bizMap: { noticeType: \"APP_NOTIFICATION_IMPORTANT\", reason },\n bizUniqueId,\n paramsMap: { bizContent },\n pushType: \"SPECIFY_PUSH\",\n templateId,\n };\n\n logger?.info(\n `Light sender: POST ${apiUrl}, bizUniqueId=${bizUniqueId}, body=${JSON.stringify(requestBody).substring(0, 500)}`,\n );\n\n const res = await fetch(apiUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Api-Key-Id\": apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey,\n },\n body: JSON.stringify(requestBody),\n });\n\n const resBody = await res.text();\n if (!res.ok) {\n logger?.warn(\n `Light sender: FAILED ${res.status}, url=${apiUrl}, resBody=${resBody.substring(0, 500)}`,\n );\n return { ok: false, status: res.status, error: resBody };\n }\n\n logger?.info(`Light sender: OK bizUniqueId=${bizUniqueId}, resBody=${resBody.substring(0, 200)}`);\n return { ok: true, bizUniqueId, response: JSON.parse(resBody) };\n}\n","import type { LightSegment } from \"../types.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes, type RepeatArgument } from \"./repeat.js\";\nimport { validateSegments } from \"./validators.js\";\n\nexport const MAX_LIGHT_SEGMENTS = 12;\n\nconst PROTOCOL_DIGITS = [\n \"\\u0080\",\n \"\\u0081\",\n \"\\u0082\",\n \"\\u0083\",\n \"\\u0084\",\n \"\\u0091\",\n \"\\u0092\",\n \"\\u0093\",\n \"\\u0094\",\n \"\\u0095\",\n \"\\u0096\",\n \"\\u0097\",\n] as const;\n\n/** \\u009A = play once, \\u009B = infinite loop */\nconst LED_SEPARATOR_ONCE = \"\\u009A\";\nconst LED_SEPARATOR_LOOP = \"\\u009B\";\n\n/** v0–v10 mapped by index; duration_s=0 is special-cased to v11 (infinite) */\nconst DURATION_STEPS_S = [0.5, 1, 2, 3, 5, 6, 8, 16, 24, 32, 48] as const;\n/** v0–v10 mapped by index; removed 400ms, added 50ms */\nconst INTERVAL_STEPS_MS = [50, 100, 200, 300, 500, 600, 800, 1600, 2400, 3200, 4800] as const;\nconst BREATH_STEPS_MS = [1040, 1560, 2080, 2600, 3100, 4160] as const;\nconst BRIGHTNESS_STEPS = [32, 64, 96, 128, 192, 255] as const;\nconst COLOR_STEPS = [0, 32, 64, 128, 192, 255] as const;\nconst BACKGROUND_BRIGHTNESS_STEPS = [0, 32, 64, 96, 128, 192, 255] as const;\nconst MULTI_CHANNEL_COLOR_COEFFICIENTS = { r: 1, g: 0.25, b: 0.25 } as const;\nconst PURE_WHITE_COLOR_COEFFICIENTS = { r: 1, g: 0.35, b: 0.35 } as const;\n\nconst MODE_TO_INDEX: Record<LightSegment[\"mode\"], number> = {\n wave: 0,\n breath: 1,\n strobe: 2,\n steady: 3,\n wave_rainbow: 4,\n pixel_frame: 5,\n};\n\nexport function buildLightEffectApnsBody(\n segments: LightSegment[],\n repeatInput?: RepeatArgument,\n): string {\n assertSegmentCount(segments);\n assertSegmentsValid(segments);\n\n const repeatTimes = normalizeRepeatTimes(repeatInput);\n assertAncsRepeatTimes(repeatTimes);\n\n const visibleText = summarizeSegments(segments);\n const separator = repeatTimes === 0 ? LED_SEPARATOR_LOOP : LED_SEPARATOR_ONCE;\n const payload = segments.map((segment) => encodeSegment(segment)).join(\"\");\n return `${visibleText}${separator}${payload}`;\n}\n\nfunction assertSegmentCount(segments: LightSegment[]): void {\n if (segments.length < 1 || segments.length > MAX_LIGHT_SEGMENTS) {\n throw new Error(`light_control supports 1-${MAX_LIGHT_SEGMENTS} segments`);\n }\n}\n\nfunction summarizeSegments(segments: LightSegment[]): string {\n const modeDesc = segments.map((segment) => segment.mode).join(\"+\");\n return `Effect: ${modeDesc} (${segments.length} segment${segments.length > 1 ? \"s\" : \"\"})`;\n}\n\nfunction assertSegmentsValid(segments: LightSegment[]): void {\n const validation = validateSegments(segments);\n if (!validation.valid) {\n throw new Error(\n validation.errors.map((error) => `${error.field}: ${error.message}`).join(\"; \"),\n );\n }\n}\n\nfunction encodeSegment(segment: LightSegment): string {\n const common = [\n MODE_TO_INDEX[segment.mode],\n quantizeDuration(segment.duration_s),\n ];\n\n let values: number[];\n switch (segment.mode) {\n case \"wave\":\n case \"wave_rainbow\":\n const color = normalizeProtocolColor(segment.color);\n const background = normalizeProtocolColor(segment.background);\n values = [\n ...common,\n quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(color.r, COLOR_STEPS),\n quantize(color.g, COLOR_STEPS),\n quantize(color.b, COLOR_STEPS),\n segment.direction === \"rtl\" ? 1 : 0,\n quantizeWindow(segment.window ?? 2),\n quantize(background.r, COLOR_STEPS),\n quantize(background.g, COLOR_STEPS),\n quantize(background.b, COLOR_STEPS),\n quantize(segment.background?.brightness ?? 0, BACKGROUND_BRIGHTNESS_STEPS),\n ];\n break;\n case \"breath\":\n const breathColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantizeBreathRiseFall(segment.breath_timing?.rise_ms),\n quantizeBreathHoldOff(segment.breath_timing?.hold_ms),\n quantizeBreathRiseFall(segment.breath_timing?.fall_ms),\n quantizeBreathHoldOff(segment.breath_timing?.off_ms),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(breathColor.r, COLOR_STEPS),\n quantize(breathColor.g, COLOR_STEPS),\n quantize(breathColor.b, COLOR_STEPS),\n ];\n break;\n case \"strobe\":\n const strobeColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(strobeColor.r, COLOR_STEPS),\n quantize(strobeColor.g, COLOR_STEPS),\n quantize(strobeColor.b, COLOR_STEPS),\n ];\n break;\n case \"steady\":\n const steadyColor = normalizeProtocolColor(segment.color);\n values = [\n ...common,\n quantizeBrightnessValue(segment.brightness ?? 0),\n quantize(steadyColor.r, COLOR_STEPS),\n quantize(steadyColor.g, COLOR_STEPS),\n quantize(steadyColor.b, COLOR_STEPS),\n ];\n break;\n case \"pixel_frame\":\n values = encodePixelFrameValues(common, segment);\n break;\n }\n\n return values.map((value) => PROTOCOL_DIGITS[value]).join(\"\");\n}\n\nfunction encodePixelFrameValues(common: number[], segment: LightSegment): number[] {\n const pixels = segment.pixels ?? [];\n return [\n ...common,\n pixels.length - 1,\n ...pixels.flatMap((pixel) => {\n const color = normalizeProtocolColor(pixel.color);\n return [\n pixel.index,\n quantize(color.r, COLOR_STEPS),\n quantize(color.g, COLOR_STEPS),\n quantize(color.b, COLOR_STEPS),\n quantizeBrightnessValue(pixel.brightness),\n ];\n }),\n ];\n}\n\nexport function normalizeProtocolColor(\n color:\n | Pick<NonNullable<LightSegment[\"color\"]>, \"r\" | \"g\" | \"b\">\n | Pick<NonNullable<LightSegment[\"background\"]>, \"r\" | \"g\" | \"b\">\n | undefined,\n): { r: number; g: number; b: number } {\n const normalized = {\n r: color?.r ?? 0,\n g: color?.g ?? 0,\n b: color?.b ?? 0,\n };\n\n if (isPureWhiteProtocolColor(normalized)) {\n return applyProtocolColorCoefficients(normalized, PURE_WHITE_COLOR_COEFFICIENTS);\n }\n\n if (countActiveProtocolColorChannels(normalized) <= 1) {\n return normalized;\n }\n\n return applyProtocolColorCoefficients(normalized, MULTI_CHANNEL_COLOR_COEFFICIENTS);\n}\n\nfunction countActiveProtocolColorChannels(color: { r: number; g: number; b: number }): number {\n return Number(color.r > 0) + Number(color.g > 0) + Number(color.b > 0);\n}\n\nfunction isPureWhiteProtocolColor(color: { r: number; g: number; b: number }): boolean {\n return color.r === 255 && color.g === 255 && color.b === 255;\n}\n\nfunction applyProtocolColorCoefficients(\n color: { r: number; g: number; b: number },\n coefficients: { r: number; g: number; b: number },\n): { r: number; g: number; b: number } {\n return {\n r: scaleProtocolColorChannel(color.r, coefficients.r),\n g: scaleProtocolColorChannel(color.g, coefficients.g),\n b: scaleProtocolColorChannel(color.b, coefficients.b),\n };\n}\n\nfunction scaleProtocolColorChannel(value: number, coefficient: number): number {\n return Math.max(0, Math.min(255, Math.round(value * coefficient)));\n}\n\nfunction quantize(value: number, steps: readonly number[]): number {\n let bestIndex = 0;\n let bestDistance = Number.POSITIVE_INFINITY;\n\n for (const [index, step] of steps.entries()) {\n const distance = Math.abs(value - step);\n if (distance < bestDistance) {\n bestIndex = index;\n bestDistance = distance;\n }\n }\n\n return bestIndex;\n}\n\n/** duration_s=0 maps to v11 (infinite); otherwise quantize to DURATION_STEPS_S */\nfunction quantizeDuration(duration_s: number): number {\n if (duration_s === 0) return 11;\n return quantize(duration_s, DURATION_STEPS_S);\n}\n\n/**\n * brightness=0 maps to v11 (explicit off / pixel-off).\n * Otherwise quantize to BRIGHTNESS_STEPS (v0–v5).\n */\nfunction quantizeBrightnessValue(brightness: number): number {\n if (brightness === 0) return 11;\n return quantize(brightness, BRIGHTNESS_STEPS);\n}\n\nfunction quantizeBreathRiseFall(value: number | undefined): number {\n return quantize(value ?? 1040, BREATH_STEPS_MS);\n}\n\nfunction quantizeBreathHoldOff(value: number | undefined): number {\n if (value === 0) {\n return 5;\n }\n\n return quantize(value ?? 1040, BREATH_STEPS_MS.slice(0, 5));\n}\n\nfunction quantizeWindow(value: 1 | 2 | 3): number {\n return value - 1;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { type CliCommand, output, exitError } from \"./helpers.js\";\n\ntype JsonObject = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is JsonObject {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction ensureArray(obj: JsonObject, key: string): unknown[] {\n const current = obj[key];\n if (Array.isArray(current)) return current;\n const next: unknown[] = [];\n obj[key] = next;\n return next;\n}\n\nfunction resolveConfigPath(): string {\n const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();\n if (fromEnv) return fromEnv;\n return join(homedir(), \".openclaw\", \"openclaw.json\");\n}\n\nfunction upsertLightControlAlsoAllow(cfg: JsonObject): {\n globalChanged: boolean;\n mainAgentChanged: boolean;\n} {\n if (!isObject(cfg.tools)) cfg.tools = {};\n const toolsAlsoAllow = ensureArray(cfg.tools as JsonObject, \"alsoAllow\");\n const hasGlobal = toolsAlsoAllow.includes(\"light_control\");\n if (!hasGlobal) toolsAlsoAllow.push(\"light_control\");\n\n if (!isObject(cfg.agents)) cfg.agents = {};\n const agents = cfg.agents as JsonObject;\n const list = ensureArray(agents, \"list\");\n let mainAgent = list.find(\n (item) => isObject(item) && item.id === \"main\",\n ) as JsonObject | undefined;\n if (!mainAgent) {\n mainAgent = { id: \"main\" };\n list.push(mainAgent);\n }\n if (!isObject(mainAgent.tools)) mainAgent.tools = {};\n const mainAlsoAllow = ensureArray(mainAgent.tools as JsonObject, \"alsoAllow\");\n const hasMain = mainAlsoAllow.includes(\"light_control\");\n if (!hasMain) mainAlsoAllow.push(\"light_control\");\n\n return {\n globalChanged: !hasGlobal,\n mainAgentChanged: !hasMain,\n };\n}\n\nexport function registerLightSetupTools(light: CliCommand): void {\n light\n .command(\"setup\")\n .description(\"自动放行 light_control(写入 tools.alsoAllow 与 agents.main.tools.alsoAllow)\")\n .action(() => {\n const configPath = resolveConfigPath();\n if (!existsSync(configPath)) {\n exitError(\"CONFIG_NOT_FOUND\", `未找到配置文件: ${configPath}`);\n }\n\n let cfg: JsonObject = {};\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (isObject(parsed)) cfg = parsed;\n } catch (err: any) {\n exitError(\"CONFIG_INVALID\", `读取/解析配置失败: ${err?.message ?? String(err)}`);\n }\n\n const result = upsertLightControlAlsoAllow(cfg);\n try {\n mkdirSync(dirname(configPath), { recursive: true });\n writeFileSync(configPath, JSON.stringify(cfg, null, 2) + \"\\n\", \"utf-8\");\n } catch (err: any) {\n exitError(\"WRITE_FAILED\", `写入配置失败: ${err?.message ?? String(err)}`);\n }\n\n output({\n ok: true,\n configPath,\n changed: result.globalChanged || result.mainAgentChanged,\n updates: {\n toolsAlsoAllow: result.globalChanged ? \"added\" : \"already_exists\",\n mainAgentAlsoAllow: result.mainAgentChanged ? \"added\" : \"already_exists\",\n },\n next: \"请执行: openclaw gateway restart\",\n });\n });\n}\n\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadApiKey } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport { output, exitError } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport type { TunnelStatusInfo } from \"../tunnel/relay-client.js\";\n\n/** 状态文件相对于 stateDir 的路径 */\nconst STATUS_REL_PATH = join(\"plugins\", \"phone-notifications\", \"tunnel-status.json\");\n\n/** 读取 RelayClient 写入的状态文件 */\nfunction readTunnelStatus(ctx: CliContext): TunnelStatusInfo | null {\n if (!ctx.stateDir) return null;\n const filePath = join(ctx.stateDir, STATUS_REL_PATH);\n if (!existsSync(filePath)) return null;\n try {\n return JSON.parse(readFileSync(filePath, \"utf-8\")) as TunnelStatusInfo;\n } catch {\n return null;\n }\n}\n\nfunction formatMessage(status: TunnelStatusInfo): string {\n switch (status.state) {\n case \"connected\":\n return `隧道已连接(自 ${status.since})`;\n case \"connecting\":\n return `隧道正在连接(自 ${status.since},第 ${status.reconnectAttempt} 次重连)`;\n case \"disconnected\":\n return `隧道已断开(自 ${status.since})${status.lastDisconnectReason ? `,原因: ${status.lastDisconnectReason}` : \"\"},等待重连(第 ${status.reconnectAttempt} 次)`;\n case \"stopped\":\n return `隧道服务已停止(自 ${status.since})`;\n default:\n return `未知状态: ${status.state}`;\n }\n}\n\nexport function registerTunnelStatus(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"tunnel-status\")\n .description(\"检查 Relay Tunnel 隧道连接状态(读取运行中服务的状态文件,不影响已有连接)\")\n .action(async () => {\n const tunnelUrl = getEnvUrls().relayTunnelUrl;\n const apiKey = loadApiKey();\n\n if (!tunnelUrl) {\n exitError(\n \"TUNNEL_NOT_CONFIGURED\",\n \"RELAY_TUNNEL_URL 未配置,隧道功能未启用。请在构建时设置 RELAY_TUNNEL_URL 环境变量。\",\n );\n }\n\n if (!apiKey) {\n exitError(\n \"TOKEN_MISSING\",\n \"API Key 未设置,隧道无法连接。请执行 openclaw ntf auth set-api-key <apiKey>\",\n );\n }\n\n const status = readTunnelStatus(ctx);\n\n if (!status) {\n exitError(\n \"STATUS_NOT_FOUND\",\n \"未找到隧道状态文件,隧道服务可能尚未启动过。请确认 openclaw 主进程正在运行。\",\n );\n }\n\n const ok = status.state === \"connected\";\n output({\n ok,\n tunnelUrl,\n connection: {\n state: status.state,\n since: status.since,\n reconnectAttempt: status.reconnectAttempt,\n lastDisconnectReason: status.lastDisconnectReason,\n },\n message: formatMessage(status),\n });\n\n if (!ok) process.exit(1);\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveNotificationsDir,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerNtfStoragePath(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"storage-path\")\n .description(\"查询通知存储路径\")\n .action(() => {\n const dir = resolveNotificationsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"通知存储目录不可用\");\n output({ ok: true, path: dir });\n });\n}\n","import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n type CliCommand,\n type CliContext,\n filterDateRange,\n today,\n daysAgo,\n output,\n exitError,\n} from \"./helpers.js\";\n\n/** Resolve the plugin logs directory from stateDir */\nfunction resolveLogsDir(ctx: CliContext): string | null {\n if (ctx.stateDir) {\n const dir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n \"logs\",\n );\n if (existsSync(dir)) return dir;\n }\n return null;\n}\n\n/** List available log date keys (YYYY-MM-DD) sorted descending */\nfunction listLogDateKeys(dir: string): string[] {\n const pattern = /^(\\d{4}-\\d{2}-\\d{2})\\.log$/;\n const keys: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const m = pattern.exec(entry.name);\n if (m) keys.push(m[1]);\n }\n return keys.sort().reverse();\n}\n\n/** Read log lines from a date file, optionally filtering by keyword */\nfunction collectLogLines(\n dir: string,\n dateKey: string,\n keyword: string | undefined,\n limit: number,\n collected: string[],\n): void {\n const filePath = join(dir, `${dateKey}.log`);\n if (!existsSync(filePath)) return;\n\n const content = readFileSync(filePath, \"utf-8\");\n const lowerKeyword = keyword?.toLowerCase();\n\n for (const line of content.split(\"\\n\")) {\n if (collected.length >= limit) return;\n if (!line) continue;\n if (lowerKeyword && !line.toLowerCase().includes(lowerKeyword)) continue;\n collected.push(`[${dateKey}] ${line}`);\n }\n}\n\nexport function registerLogSearch(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"log\")\n .description(\"查看/搜索插件日志\")\n .option(\"--keyword <text>\", \"按关键词过滤日志\")\n .option(\"--from <date>\", \"开始日期 YYYY-MM-DD\", daysAgo(7))\n .option(\"--to <date>\", \"结束日期 YYYY-MM-DD\", today())\n .option(\"--limit <n>\", \"最大返回条数\", \"50\")\n .action(\n (opts: {\n keyword?: string;\n from: string;\n to: string;\n limit: string;\n }) => {\n const dir = resolveLogsDir(ctx);\n if (!dir) exitError(\"LOGS_UNAVAILABLE\", \"日志目录不可用\");\n\n const keys = filterDateRange(listLogDateKeys(dir), opts.from, opts.to);\n const limit = parseInt(opts.limit, 10) || 50;\n const results: string[] = [];\n\n for (const dateKey of keys) {\n if (results.length >= limit) break;\n collectLogLines(dir, dateKey, opts.keyword, limit, results);\n }\n\n output({\n ok: true,\n keyword: opts.keyword ?? null,\n total: results.length,\n lines: results,\n });\n },\n );\n}\n","import { loadEnvName, saveEnvName, getEnvUrls, getAvailableEnvs } from \"../env.js\";\nimport { output, exitError } from \"./helpers.js\";\nimport type { CliCommand } from \"./helpers.js\";\n\nexport function registerEnvCli(ntf: CliCommand): void {\n const env = ntf.command(\"env\").description(\"环境管理(切换 development / production)\");\n\n env\n .command(\"show\")\n .description(\"显示当前环境及对应的接口地址\")\n .action(() => {\n const current = loadEnvName();\n const urls = getEnvUrls(current);\n output({\n ok: true,\n env: current,\n lightApiUrl: urls.lightApiUrl,\n relayTunnelUrl: urls.relayTunnelUrl,\n availableEnvs: getAvailableEnvs(),\n });\n });\n\n env\n .command(\"switch <env>\")\n .description(\"切换环境(development / production)\")\n .action((envName: string) => {\n const available = getAvailableEnvs();\n if (!available.includes(envName as any)) {\n exitError(\n \"INVALID_ENV\",\n `无效的环境名称: ${envName},可选值: ${available.join(\", \")}`,\n );\n }\n saveEnvName(envName as any);\n const urls = getEnvUrls(envName as any);\n output({\n ok: true,\n message: `已切换到 ${envName} 环境`,\n env: envName,\n lightApiUrl: urls.lightApiUrl,\n relayTunnelUrl: urls.relayTunnelUrl,\n });\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport { resolveConfigPath, resolveStateDir } from \"../host.js\";\nimport { output } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport type { CheckResult, JsonObject, Severity } from \"./doctor/types.js\";\nimport { allCheckers } from \"./doctor/checkers.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nfunction readConfig(configPath: string): JsonObject {\n if (!existsSync(configPath)) return {};\n try {\n const parsed = JSON.parse(readFileSync(configPath, \"utf-8\"));\n return isObject(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction severityIcon(s: Severity): string {\n switch (s) {\n case \"critical\":\n return \"\\x1b[31m[CRITICAL]\\x1b[0m\";\n case \"warn\":\n return \"\\x1b[33m[WARN]\\x1b[0m\";\n case \"info\":\n return \"\\x1b[36m[INFO]\\x1b[0m\";\n }\n}\n\nfunction severityOrder(s: Severity): number {\n switch (s) {\n case \"critical\":\n return 0;\n case \"warn\":\n return 1;\n case \"info\":\n return 2;\n }\n}\n\nfunction confirm(question: string): Promise<boolean> {\n const rl = createInterface({ input: process.stdin, output: process.stderr });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim().toLowerCase() === \"y\");\n });\n });\n}\n\nasync function runDoctor(ctx: CliContext, json: boolean, fix?: boolean): Promise<void> {\n const stateDir = ctx.stateDir ?? resolveStateDir();\n const configPath = resolveConfigPath(stateDir);\n const cfg = readConfig(configPath);\n\n const checkCtx = { cfg, configPath, stateDir };\n\n // 执行所有 checker\n const issues: CheckResult[] = [];\n for (const checker of allCheckers) {\n const result = await checker(checkCtx);\n if (result) issues.push(result);\n }\n\n // 按严重级别排序\n issues.sort((a, b) => severityOrder(a.severity) - severityOrder(b.severity));\n\n // 统计\n const summary = { critical: 0, warn: 0, info: 0 };\n for (const issue of issues) {\n summary[issue.severity]++;\n }\n\n // --json 模式\n if (json) {\n output({\n ok: issues.length === 0,\n summary,\n checks: issues.map((i) => ({\n id: i.id,\n severity: i.severity,\n title: i.title,\n detail: i.detail,\n autoFixable: i.fix !== null,\n fixDescription: i.fixDescription,\n })),\n });\n if (issues.length > 0) process.exit(1);\n return;\n }\n\n // 人类可读输出\n const log = console.error; // stderr,不污染 stdout\n log(\"\\n\\x1b[1m🔍 正在检查环境...\\x1b[0m\\n\");\n\n if (issues.length === 0) {\n log(\"\\x1b[32m✅ 所有检查通过,未发现问题。\\x1b[0m\\n\");\n output({ ok: true, summary });\n return;\n }\n\n for (const issue of issues) {\n log(`${severityIcon(issue.severity)} ${issue.title}`);\n log(` ↳ ${issue.detail}`);\n log(` ↳ 修复: ${issue.fixDescription}`);\n log();\n }\n\n log(\n `检测完成: \\x1b[31m${summary.critical} critical\\x1b[0m · ` +\n `\\x1b[33m${summary.warn} warn\\x1b[0m · ` +\n `\\x1b[36m${summary.info} info\\x1b[0m\\n`,\n );\n\n // 找出可自动修复的\n const fixable = issues.filter((i) => i.fix !== null);\n\n if (fixable.length === 0) {\n log(\"以上问题均需手动修复,请参考上方提示。\\n\");\n output({ ok: false, summary });\n process.exit(1);\n return;\n }\n\n log(`发现 ${fixable.length} 个可自动修复的问题:`);\n for (const issue of fixable) {\n log(` • ${issue.title} → ${issue.fixDescription}`);\n }\n log();\n\n const yes = fix === true || await confirm(\"是否执行自动修复?[y/N]: \");\n if (!yes) {\n log(\"\\n已取消。\\n\");\n output({ ok: false, summary, fixed: 0 });\n process.exit(1);\n return;\n }\n\n log();\n let fixed = 0;\n for (const issue of fixable) {\n try {\n await issue.fix!();\n log(`\\x1b[32m✅\\x1b[0m ${issue.title} → ${issue.fixDescription}`);\n fixed++;\n } catch (err: any) {\n log(\n `\\x1b[31m❌\\x1b[0m ${issue.title} 修复失败: ${err?.message ?? String(err)}`,\n );\n }\n }\n\n const manualCount = issues.length - fixable.length;\n if (manualCount > 0) {\n log(`\\n⚠️ 还有 ${manualCount} 个问题需要手动处理,请参考上方提示。`);\n }\n\n log(`\\n修复完成 (${fixed}/${fixable.length})。建议执行: openclaw gateway restart\\n`);\n output({ ok: fixed === fixable.length && manualCount === 0, summary, fixed });\n if (fixed < fixable.length || manualCount > 0) process.exit(1);\n}\n\nexport function registerDoctor(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"doctor\")\n .description(\"自检环境配置,检测安全风险和常见问题\")\n .option(\"--json\", \"以 JSON 格式输出结果(供脚本调用)\")\n .option(\"--fix\", \"自动修复可修复的问题(跳过确认提示)\")\n .action((opts: { json?: boolean; fix?: boolean }) => {\n return runDoctor(ctx, opts.json === true, opts.fix);\n });\n}\n","import { readFileSync, writeFileSync, copyFileSync } from \"node:fs\";\nimport type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkDangerousFlags: Checker = ({ cfg, configPath }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const controlUi = gateway.controlUi;\n if (!isObject(controlUi)) return null;\n\n if (controlUi.dangerouslyDisableDeviceAuth !== true) return null;\n\n return {\n id: \"dangerous-flags\",\n severity: \"critical\",\n title: \"gateway.controlUi.dangerouslyDisableDeviceAuth 已启用\",\n detail: \"这会关闭 Control UI 的设备身份验证,任何人都可以访问控制面板。\",\n fixDescription: \"设为 false\",\n fix: () => {\n const raw = readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(raw) as JsonObject;\n const gw = config.gateway as JsonObject;\n const cui = gw.controlUi as JsonObject;\n cui.dangerouslyDisableDeviceAuth = false;\n copyFileSync(configPath, configPath + \".bak\");\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n },\n };\n};\n","import type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkTrustedProxy: Checker = ({ cfg }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const auth = gateway.auth;\n if (!isObject(auth)) return null;\n\n if (auth.mode !== \"trusted-proxy\") return null;\n\n return {\n id: \"trusted-proxy\",\n severity: \"critical\",\n title: \"gateway.auth.mode 为 trusted-proxy\",\n detail:\n \"认证委托给了反向代理。请确保: (1) 代理终止 TLS 并认证用户; \" +\n \"(2) gateway.trustedProxies 仅限代理 IP; \" +\n \"(3) 防火墙阻止直接访问 Gateway 端口。\",\n fixDescription: \"此项需手动检查代理配置,无法自动修复\",\n fix: null,\n };\n};\n\nexport const checkTrustedProxyAllowUsers: Checker = ({ cfg }) => {\n const gateway = cfg.gateway;\n if (!isObject(gateway)) return null;\n\n const auth = gateway.auth;\n if (!isObject(auth)) return null;\n\n if (auth.mode !== \"trusted-proxy\") return null;\n\n const tp = auth.trustedProxy;\n if (!isObject(tp)) return warnEmpty();\n\n const allowUsers = tp.allowUsers;\n if (!Array.isArray(allowUsers) || allowUsers.length === 0) return warnEmpty();\n\n return null;\n};\n\nfunction warnEmpty() {\n return {\n id: \"trusted-proxy-allow-users\",\n severity: \"warn\" as const,\n title: \"trusted-proxy 模式下 allowUsers 为空\",\n detail: \"任何通过代理认证的用户都可以访问 Gateway。\",\n fixDescription:\n '请编辑 openclaw.json,在 gateway.auth.trustedProxy.allowUsers 中添加允许的用户邮箱,例如 [\"nick@example.com\"]',\n fix: null,\n };\n}\n","import { statSync, chmodSync } from \"node:fs\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkStateDirPerms: Checker = ({ stateDir }) => {\n let mode: number;\n try {\n mode = statSync(stateDir).mode;\n } catch {\n return null;\n }\n\n // 检查 group 和 other 是否有任何权限\n const otherBits = mode & 0o077;\n if (otherBits === 0) return null;\n\n const modeStr = \"0\" + (mode & 0o777).toString(8);\n\n return {\n id: \"state-dir-perms\",\n severity: \"warn\",\n title: `状态目录权限过于宽松 (${stateDir} mode=${modeStr})`,\n detail: \"其他用户可以读取该目录下的凭证和配置文件。\",\n fixDescription: \"chmod 700 \" + stateDir,\n fix: () => {\n chmodSync(stateDir, 0o700);\n },\n };\n};\n","import type { Checker, JsonObject } from \"./types.js\";\n\nfunction isObject(v: unknown): v is JsonObject {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\nexport const checkToolPolicy: Checker = ({ cfg }) => {\n const agents = cfg.agents;\n if (!isObject(agents)) return null;\n\n const list = agents.list;\n if (!Array.isArray(list)) return null;\n\n const permissiveAgents: string[] = [];\n\n for (const agent of list) {\n if (!isObject(agent)) continue;\n const id = String(agent.id ?? \"unknown\");\n\n // 如果 agent 没有设置 toolPolicy / profile,则视为使用 default(宽松)\n const tools = agent.tools;\n if (!isObject(tools)) {\n permissiveAgents.push(id);\n continue;\n }\n\n const profile = tools.profile;\n if (!profile || profile === \"default\") {\n permissiveAgents.push(id);\n }\n }\n\n if (permissiveAgents.length === 0) return null;\n\n return {\n id: \"tool-policy\",\n severity: \"warn\",\n title: \"扩展插件 tool policy 宽松\",\n detail: `以下 agent 使用了 default 策略: ${permissiveAgents.join(\", \")}。插件工具可能被未授权调用。`,\n fixDescription:\n \"建议为处理不可信输入的 agent 使用 minimal 或 coding profile,或配置明确的 tool allowlist。\",\n fix: null,\n };\n};\n","import { loadApiKey } from \"../../auth/credentials.js\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkCredentials: Checker = () => {\n const apiKey = loadApiKey();\n if (apiKey) return null;\n\n return {\n id: \"credentials\",\n severity: \"critical\",\n title: \"API Key 未配置\",\n detail:\n \"未在 credentials.json 中找到 apiKey,隧道和推送等功能无法正常工作。\",\n fixDescription:\n \"请执行: openclaw ntf auth set-api-key <your-api-key>\",\n fix: null,\n };\n};\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { TunnelStatusInfo } from \"../../tunnel/relay-client.js\";\nimport type { Checker } from \"./types.js\";\n\nconst STATUS_REL_PATH = join(\n \"plugins\",\n \"phone-notifications\",\n \"tunnel-status.json\",\n);\n\nexport const checkTunnel: Checker = ({ stateDir }) => {\n const filePath = join(stateDir, STATUS_REL_PATH);\n\n if (!existsSync(filePath)) {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态文件不存在\",\n detail: \"隧道服务可能尚未启动过,或状态文件已被删除。\",\n fixDescription: \"请确认 openclaw 主进程正在运行\",\n fix: null,\n };\n }\n\n let status: TunnelStatusInfo;\n try {\n status = JSON.parse(readFileSync(filePath, \"utf-8\")) as TunnelStatusInfo;\n } catch {\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: \"隧道状态文件解析失败\",\n detail: \"文件内容损坏或格式不正确。\",\n fixDescription: \"请重启 openclaw 主进程\",\n fix: null,\n };\n }\n\n if (status.state === \"connected\") return null;\n\n const reasonSuffix = status.lastDisconnectReason\n ? `,原因: ${status.lastDisconnectReason}`\n : \"\";\n\n return {\n id: \"tunnel\",\n severity: \"warn\",\n title: `隧道未连接 (state=${status.state})`,\n detail: `隧道自 ${status.since} 处于 ${status.state} 状态${reasonSuffix},重连次数: ${status.reconnectAttempt}`,\n fixDescription: \"请检查网络连接或重启 openclaw 主进程\",\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\n\nconst MIN_MAJOR = 22;\nconst MIN_MINOR = 12;\n\nexport const checkNodeVersion: Checker = () => {\n const version = process.versions.node;\n const [major, minor] = version.split(\".\").map(Number);\n\n if (major > MIN_MAJOR || (major === MIN_MAJOR && minor >= MIN_MINOR)) {\n return null;\n }\n\n return {\n id: \"node-version\",\n severity: \"warn\",\n title: `Node.js 版本过低 (v${version})`,\n detail: `要求 >= ${MIN_MAJOR}.${MIN_MINOR}.0,当前为 v${version}。`,\n fixDescription: `请升级 Node.js 到 ${MIN_MAJOR}.${MIN_MINOR}.0 或更高版本`,\n fix: null,\n };\n};\n","import { loadEnvName } from \"../../env.js\";\nimport { resolveUpdateChannel } from \"../../update/channel.js\";\nimport { PLUGIN_VERSION } from \"../../version.js\";\nimport type { Checker } from \"./types.js\";\n\nexport const checkPluginVersion: Checker = async () => {\n const channel = resolveUpdateChannel({\n currentVersion: PLUGIN_VERSION,\n envName: loadEnvName(),\n });\n\n let latest: string;\n try {\n const res = await fetch(\n `https://registry.npmjs.org/@yoooclaw/phone-notifications/${channel}`,\n { signal: AbortSignal.timeout(5000) },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { version?: string };\n latest = data.version ?? \"\";\n } catch {\n // 网络不可用时跳过\n return null;\n }\n\n if (!latest || latest === PLUGIN_VERSION) return null;\n\n return {\n id: \"plugin-version\",\n severity: \"info\",\n title: `插件版本可更新 (当前 ${PLUGIN_VERSION} → 最新 ${latest})`,\n detail: \"有新版本可用,建议更新以获取最新功能和修复。\",\n fixDescription: `请执行: openclaw extension install @yoooclaw/phone-notifications@${latest}`,\n fix: null,\n };\n};\n","import type { Checker } from \"./types.js\";\nimport { checkDangerousFlags } from \"./check-dangerous-flags.js\";\nimport { checkTrustedProxy, checkTrustedProxyAllowUsers } from \"./check-trusted-proxy.js\";\nimport { checkStateDirPerms } from \"./check-state-dir-perms.js\";\nimport { checkToolPolicy } from \"./check-tool-policy.js\";\nimport { checkCredentials } from \"./check-credentials.js\";\nimport { checkTunnel } from \"./check-tunnel.js\";\nimport { checkNodeVersion } from \"./check-node-version.js\";\nimport { checkPluginVersion } from \"./check-plugin-version.js\";\n\n/** 所有 checker,按优先级排列 */\nexport const allCheckers: Checker[] = [\n // critical\n checkDangerousFlags,\n checkTrustedProxy,\n checkCredentials,\n // warn\n checkTrustedProxyAllowUsers,\n checkStateDirPerms,\n checkToolPolicy,\n checkTunnel,\n // info\n checkNodeVersion,\n checkPluginVersion,\n];\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n readRecordingIndex,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecList(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"list\")\n .description(\"列出所有录音(可按状态过滤)\")\n .option(\"--status <status>\", \"按传输状态过滤(如 synced, transcribed)\")\n .action((opts: { status?: string }) => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n\n let recordings = readRecordingIndex(dir);\n\n if (opts.status) {\n recordings = recordings.filter((r) => r.status === opts.status);\n }\n\n const items = recordings.map((r) => ({\n id: r.id,\n name: r.metadata.name,\n duration_sec: r.metadata.duration_sec,\n status: r.status,\n file_size_bytes: r.metadata.file_size_bytes,\n has_audio: !!r.audioFile,\n has_transcript: !!r.transcriptFile,\n created_at: r.metadata.created_at,\n updated_at: r.updatedAt,\n }));\n\n output({ ok: true, total: items.length, recordings: items });\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n readRecordingIndex,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecStatus(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"status <id>\")\n .description(\"查看单条录音详情\")\n .action((id: string) => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n\n const recordings = readRecordingIndex(dir);\n const entry = recordings.find((r) => r.id === id);\n\n if (!entry) {\n exitError(\"NOT_FOUND\", `录音不存在: ${id}`);\n }\n\n output({\n ok: true,\n recording: {\n id: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n status: entry.status,\n created_at: entry.metadata.created_at,\n location: entry.metadata.location ?? null,\n markers: entry.metadata.markers ?? [],\n audioFile: entry.audioFile ?? null,\n srtFile: entry.srtFile ?? null,\n transcriptDataFile: entry.transcriptDataFile ?? null,\n transcriptFile: entry.transcriptFile ?? null,\n summaryFile: entry.summaryFile ?? null,\n title: entry.title ?? null,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n },\n });\n });\n}\n","import {\n type CliCommand,\n type CliContext,\n resolveRecordingsDir,\n output,\n exitError,\n} from \"./helpers.js\";\n\nexport function registerRecStoragePath(\n rec: CliCommand,\n ctx: CliContext,\n): void {\n rec\n .command(\"storage-path\")\n .description(\"查询录音存储路径\")\n .action(() => {\n const dir = resolveRecordingsDir(ctx);\n if (!dir) exitError(\"STORAGE_UNAVAILABLE\", \"录音存储目录不可用\");\n output({ ok: true, path: dir });\n });\n}\n","import { createInterface } from \"node:readline\";\nimport { writeFileSync, existsSync, readFileSync } from \"node:fs\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\nimport { resolveAsrConfigPath, output } from \"./helpers.js\";\nimport type { AsrConfig, WhisperModelSize, WhisperBackend, WhisperModelSource } from \"../types.js\";\n\n// ─── Prompt helpers ───\n\ntype Rl = ReturnType<typeof createInterface>;\n\nfunction ask(rl: Rl, question: string): Promise<string> {\n return new Promise((resolve) => rl.question(question, resolve));\n}\n\n/**\n * Ask for a single choice from a numbered list.\n * Writes the list and prompt to stderr; returns the 0-based index of the chosen item.\n */\nasync function askChoice(\n rl: Rl,\n prompt: string,\n choices: readonly string[],\n defaultIdx = 0,\n): Promise<number> {\n choices.forEach((c, i) => {\n const marker = i === defaultIdx ? \"●\" : \"○\";\n process.stderr.write(` ${marker} ${i + 1}. ${c}\\n`);\n });\n while (true) {\n const ans = (await ask(rl, `${prompt} [1-${choices.length},默认 ${defaultIdx + 1}]: `)).trim();\n if (!ans) return defaultIdx;\n const n = parseInt(ans, 10);\n if (!isNaN(n) && n >= 1 && n <= choices.length) return n - 1;\n process.stderr.write(` 请输入 1-${choices.length} 之间的数字\\n`);\n }\n}\n\n/** Ask for a value; returns undefined if user presses Enter with no input. */\nasync function askOptional(rl: Rl, prompt: string): Promise<string | undefined> {\n const ans = (await ask(rl, `${prompt} [可选,直接回车跳过]: `)).trim();\n return ans || undefined;\n}\n\n// ─── Mode-specific setup flows ───\n\nasync function setupApi(rl: Rl): Promise<AsrConfig> {\n process.stderr.write(\"\\n─── 云端 ASR(model-proxy)配置 ───\\n\\n\");\n process.stderr.write(\"说明:不再填写第三方 API Key,插件会复用当前账号的 API Key 调用 model-proxy 长录音接口。\\n\\n\");\n\n const endpoint = await askOptional(rl, \"自定义 model-proxy submit-task 端点 URL\");\n const language = await askOptional(rl, \"语言提示(如 zh / en)\");\n const enableNormalizationInput = await askOptional(rl, \"启用文本规范化 ITN?(y/N)\");\n const normalized = enableNormalizationInput?.trim().toLowerCase();\n const enableNormalization =\n normalized === \"y\" || normalized === \"yes\" || normalized === \"true\";\n\n return {\n mode: \"api\",\n api: {\n ...(endpoint ? { endpoint } : {}),\n ...(language ? { language } : {}),\n ...(enableNormalizationInput ? { enableNormalization } : {}),\n },\n };\n}\n\nasync function setupLocal(rl: Rl): Promise<AsrConfig> {\n process.stderr.write(\"\\n─── 本地 Whisper 转写配置 ───\\n\\n\");\n\n process.stderr.write(\"模型大小:\\n\");\n const modelChoices = [\n \"自动选择(根据可用内存推荐)\",\n \"tiny\",\n \"base\",\n \"small\",\n \"medium\",\n \"large-v3\",\n ] as const;\n const modelIdx = await askChoice(rl, \"选择模型\", modelChoices);\n const model: WhisperModelSize | undefined =\n modelIdx === 0 ? undefined : (modelChoices[modelIdx] as WhisperModelSize);\n\n const language = await askOptional(rl, \"语言提示(如 zh / en,留空自动检测)\");\n\n process.stderr.write(\"\\n推理后端:\\n\");\n const backendChoices = [\n \"自动选择(根据运行环境推荐)\",\n \"coreml(Apple Silicon 推荐)\",\n \"cuda(NVIDIA GPU)\",\n \"cpu\",\n ] as const;\n const backendIdx = await askChoice(rl, \"选择后端\", backendChoices);\n const backend: WhisperBackend | undefined =\n backendIdx === 0 ? undefined : ([\"coreml\", \"cuda\", \"cpu\"] as const)[backendIdx - 1];\n\n process.stderr.write(\"\\n模型下载源:\\n\");\n const sourceChoices = [\n \"auto(自动探测,优先 HuggingFace,失败回退国内镜像)\",\n \"huggingface(海外直连)\",\n \"domestic(国内镜像)\",\n ] as const;\n const sourceIdx = await askChoice(rl, \"选择下载源\", sourceChoices);\n const modelSource: WhisperModelSource = ([\"auto\", \"huggingface\", \"domestic\"] as const)[sourceIdx];\n\n const modelMirrorUrl = await askOptional(rl, \"自定义模型下载地址(覆盖下载源)\");\n\n return {\n mode: \"local\",\n local: {\n ...(model ? { model } : {}),\n ...(language ? { language } : {}),\n ...(backend ? { backend } : {}),\n modelSource,\n ...(modelMirrorUrl ? { modelMirrorUrl } : {}),\n },\n };\n}\n\n// ─── Command registration ───\n\nexport function registerRecSetup(rec: CliCommand, ctx: CliContext): void {\n rec\n .command(\"setup\")\n .description(\"交互式配置 ASR 转写参数,保存到本地配置文件\")\n .action(async () => {\n const configPath = resolveAsrConfigPath(ctx);\n\n // Show existing config hint if present\n if (existsSync(configPath)) {\n try {\n const existing = JSON.parse(readFileSync(configPath, \"utf-8\")) as AsrConfig & { updatedAt?: string };\n process.stderr.write(`当前已有配置:mode = ${existing.mode}`);\n if (existing.updatedAt) process.stderr.write(`,更新于 ${existing.updatedAt}`);\n process.stderr.write(\"\\n\");\n } catch {\n // ignore parse errors\n }\n }\n\n const rl = createInterface({ input: process.stdin, output: process.stderr, terminal: true });\n\n try {\n process.stderr.write(\"\\n转写模式:\\n\");\n const modeIdx = await askChoice(rl, \"选择模式\", [\"api(云端 model-proxy 长录音)\", \"local(本地 Whisper)\"]);\n\n const config: AsrConfig = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);\n const stored = { ...config, updatedAt: new Date().toISOString() };\n\n writeFileSync(configPath, JSON.stringify(stored, null, 2), \"utf-8\");\n process.stderr.write(`\\n✓ 配置已保存到 ${configPath}\\n\\n`);\n\n output({ ok: true, ...stored });\n } finally {\n rl.close();\n }\n });\n}\n","import { spawnSync } from \"node:child_process\";\nimport { writeFileSync, unlinkSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport os from \"node:os\";\nimport { resolveStateDir } from \"../host.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\nimport { output } from \"./helpers.js\";\nimport type { CliCommand, CliContext } from \"./helpers.js\";\n\nconst BASE_URL = \"https://cdn.yoootek.com/openclaw-plugin\";\n\nasync function fetchText(url: string): Promise<string> {\n const res = await fetch(url, { signal: AbortSignal.timeout(30_000) });\n if (!res.ok) {\n throw new Error(`请求失败: ${url} (HTTP ${res.status})`);\n }\n return res.text();\n}\n\nasync function runUpdate(\n ctx: CliContext,\n opts: { json?: boolean; force?: boolean; beta?: boolean },\n): Promise<void> {\n const json = opts.json === true;\n const force = opts.force === true;\n const beta = opts.beta === true;\n const channel = beta ? \"beta\" : \"latest\";\n const log = (msg: string) => {\n if (!json) process.stderr.write(`${msg}\\n`);\n };\n\n log(`检查${beta ? \" beta\" : \"\"}最新版本 ...`);\n\n let latest: string;\n try {\n latest = (await fetchText(`${BASE_URL}/${channel}`)).trim();\n } catch (err: any) {\n const msg = `无法获取最新版本: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"FETCH_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n const current = PLUGIN_VERSION;\n\n if (!force && current === latest) {\n log(`\\x1b[32m已是最新${beta ? \" beta\" : \"\"}版本 v${current}\\x1b[0m`);\n output({ ok: true, current, latest, channel, updated: false });\n return;\n }\n\n if (force) {\n log(`\\x1b[36m强制更新: v${current} → v${latest}\\x1b[0m`);\n } else {\n log(`\\x1b[36m发现新版本: v${current} → v${latest},开始更新 ...\\x1b[0m`);\n }\n\n // 下载 install-core.mjs\n log(\"下载安装脚本 ...\");\n let installScript: string;\n try {\n installScript = await fetchText(`${BASE_URL}/install-core.mjs`);\n } catch (err: any) {\n const msg = `下载安装脚本失败: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"DOWNLOAD_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n // 写入临时文件\n const tmpScript = join(os.tmpdir(), `openclaw-install-${Date.now()}.mjs`);\n try {\n writeFileSync(tmpScript, installScript, \"utf-8\");\n } catch (err: any) {\n const msg = `写入临时文件失败: ${err?.message ?? String(err)}`;\n if (json) {\n output({ ok: false, error: { code: \"WRITE_FAILED\", message: msg } });\n process.exit(1);\n }\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n process.exit(1);\n }\n\n const stateDir = ctx.stateDir ?? resolveStateDir();\n\n // 执行安装脚本(同步,保证日志有序输出)\n const result = spawnSync(\n process.execPath,\n [tmpScript, \"--version\", latest, \"--state-dir\", stateDir],\n { stdio: \"inherit\" },\n );\n\n try {\n unlinkSync(tmpScript);\n } catch {\n // 清理失败不影响结果\n }\n\n if (result.error) {\n const msg = `安装脚本执行失败: ${result.error.message}`;\n if (json) {\n output({ ok: false, error: { code: \"SPAWN_FAILED\", message: msg } });\n } else {\n process.stderr.write(`\\x1b[31m[update] ERROR:\\x1b[0m ${msg}\\n`);\n }\n process.exit(1);\n }\n\n if (result.status !== 0) {\n if (json) {\n output({\n ok: false,\n error: {\n code: \"INSTALL_FAILED\",\n message: `安装脚本退出码: ${result.status}`,\n },\n });\n }\n process.exit(result.status ?? 1);\n }\n\n if (json) {\n output({ ok: true, current, latest, channel, updated: true });\n }\n}\n\nexport function registerUpdate(ntf: CliCommand, ctx: CliContext): void {\n ntf\n .command(\"update\")\n .description(\"检查并更新插件到最新版本,更新后自动重启\")\n .option(\"--json\", \"以 JSON 格式输出结果(供脚本调用)\")\n .option(\"--force\", \"强制重新安装当前最新版本,即使版本号相同\")\n .option(\"--beta\", \"安装最新 beta 版本\")\n .action((opts: { json?: boolean; force?: boolean; beta?: boolean }) => {\n return runUpdate(ctx, opts);\n });\n}\n","import type { CliCommand, CliContext } from \"./helpers.js\";\nimport { registerAuthCli } from \"./auth.js\";\nimport { registerNtfSearch } from \"./ntf-search.js\";\nimport { registerNtfStats } from \"./ntf-stats.js\";\nimport { registerNtfSync } from \"./ntf-sync.js\";\nimport { registerNtfMonitor } from \"./ntf-monitor.js\";\nimport { registerLightSend } from \"./light-send.js\";\nimport { registerLightSetupTools } from \"./light-setup-tools.js\";\nimport { registerTunnelStatus } from \"./tunnel-status.js\";\nimport { registerNtfStoragePath } from \"./ntf-storage-path.js\";\nimport { registerLogSearch } from \"./log-search.js\";\nimport { registerEnvCli } from \"./env.js\";\nimport { registerDoctor } from \"./doctor.js\";\nimport { registerRecList } from \"./rec-list.js\";\nimport { registerRecStatus } from \"./rec-status.js\";\nimport { registerRecStoragePath } from \"./rec-storage-path.js\";\nimport { registerRecSetup } from \"./rec-setup.js\";\nimport { registerUpdate } from \"./update.js\";\nimport { PLUGIN_VERSION } from \"../version.js\";\n\nexport function registerAllCli(\n program: CliCommand,\n ctx: CliContext,\n rootCommandName = \"ntf\",\n): void {\n const ntf = program\n .command(rootCommandName)\n .description(\"手机通知数据管理\")\n .version(PLUGIN_VERSION, \"-v, --version\", \"显示插件版本\");\n\n // openclaw ntf auth ...\n registerAuthCli(ntf);\n\n // openclaw ntf search / stats / sync / monitor ...\n registerNtfSearch(ntf, ctx);\n registerNtfStats(ntf, ctx);\n registerNtfSync(ntf, ctx);\n registerNtfMonitor(ntf, ctx);\n\n // openclaw ntf light send / setup-tools ...\n const light = ntf.command(\"light\").description(\"灯效管理\");\n registerLightSend(light);\n registerLightSetupTools(light);\n\n // openclaw ntf storage-path\n registerNtfStoragePath(ntf, ctx);\n\n // openclaw ntf log <keyword>\n registerLogSearch(ntf, ctx);\n\n // openclaw ntf tunnel-status\n registerTunnelStatus(ntf, ctx);\n\n // openclaw ntf env show / switch\n registerEnvCli(ntf);\n\n // openclaw ntf doctor\n registerDoctor(ntf, ctx);\n\n // openclaw ntf rec list / status / storage-path / setup\n const rec = ntf.command(\"rec\").description(\"录音管理\");\n registerRecList(rec, ctx);\n registerRecStatus(rec, ctx);\n registerRecStoragePath(rec, ctx);\n registerRecSetup(rec, ctx);\n\n // openclaw ntf update\n registerUpdate(ntf, ctx);\n}\n","import type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { requireApiKey } from \"../auth/credentials.js\";\nimport type { Logger } from \"../logger.js\";\nimport { MAX_LIGHT_SEGMENTS } from \"../light/protocol.js\";\nimport { assertAncsRepeatTimes, normalizeRepeatTimes } from \"../light/repeat.js\";\nimport { sendLightEffect } from \"../light/sender.js\";\nimport { validateSegments } from \"../light/validators.js\";\nimport type { LightControlInput } from \"../types.js\";\n\nconst lightControlParameters = {\n type: \"object\",\n required: [\"segments\", \"reason\"],\n additionalProperties: false,\n properties: {\n segments: {\n type: \"array\",\n description: \"灯效段序列,1–12 段,按顺序播放\",\n minItems: 1,\n maxItems: MAX_LIGHT_SEGMENTS,\n items: {\n type: \"object\",\n required: [\"mode\", \"duration_s\"],\n additionalProperties: false,\n properties: {\n mode: {\n type: \"string\",\n enum: [\"wave\", \"breath\", \"strobe\", \"steady\", \"wave_rainbow\", \"pixel_frame\"],\n description:\n \"灯效模式:wave 波浪 / breath 呼吸 / strobe 频闪 / steady 常亮 / wave_rainbow 流光 / pixel_frame 逐组像素帧\",\n },\n duration_s: {\n type: \"number\",\n minimum: 0,\n description:\n \"本段持续时长(秒),0 表示无限时长。推荐离散值:0.5/1/2/3/5/6/8/16/24/32/48,建议单段 ≤8s 省电\",\n },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description:\n \"前景亮度 0–255。非 pixel_frame 模式必填;brightness=0 仅 steady 模式有效(显式灭灯)\",\n },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n description:\n \"前景色 RGB。非 pixel_frame 模式必填;wave_rainbow 下作为第一颜色锚点,至少 color/background 其一非零\",\n },\n interval_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"步进间隔(ms),wave/strobe/wave_rainbow 有效,默认 200。量化档位:50/100/200/300/500/600/800/1600/2400/3200/4800\",\n },\n direction: {\n type: \"string\",\n enum: [\"ltr\", \"rtl\"],\n description: \"波浪/流光方向,wave/wave_rainbow 有效,默认 ltr\",\n },\n window: {\n type: \"number\",\n enum: [1, 2, 3],\n description:\n \"wave:窗口灯数,默认 2;wave_rainbow:调色板平移步幅(速度)\",\n },\n breath_timing: {\n type: \"object\",\n additionalProperties: false,\n properties: {\n rise_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"上升时间(ms),量化到 1040/1560/2080/2600/3100/4160\",\n },\n hold_ms: {\n type: \"number\",\n minimum: 0,\n description: \"保持最高亮度时间(ms),支持 0ms\",\n },\n fall_ms: {\n type: \"number\",\n minimum: 0,\n description:\n \"下降时间(ms),量化到 1040/1560/2080/2600/3100/4160\",\n },\n off_ms: {\n type: \"number\",\n minimum: 0,\n description: \"熄灭时间(ms),支持 0ms\",\n },\n },\n description:\n \"呼吸四段时间,仅 breath 有效;rise/fall 量化档位:1040/1560/2080/2600/3100/4160,hold/off 额外支持 0ms\",\n },\n background: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\", \"brightness\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description: \"底色亮度,量化档位:0/32/64/96/128/192/255\",\n },\n },\n description:\n \"底色 RGB + 亮度,wave 有效为底色层;wave_rainbow 有效为第二颜色锚点(与前景色插值生成多色调色板)\",\n },\n pixels: {\n type: \"array\",\n minItems: 1,\n maxItems: 7,\n items: {\n type: \"object\",\n required: [\"index\", \"color\", \"brightness\"],\n additionalProperties: false,\n properties: {\n index: {\n type: \"number\",\n minimum: 0,\n maximum: 6,\n description: \"LED 组索引,0–6\",\n },\n color: {\n type: \"object\",\n required: [\"r\", \"g\", \"b\"],\n additionalProperties: false,\n properties: {\n r: { type: \"number\", minimum: 0, maximum: 255 },\n g: { type: \"number\", minimum: 0, maximum: 255 },\n b: { type: \"number\", minimum: 0, maximum: 255 },\n },\n description: \"该像素的 RGB\",\n },\n brightness: {\n type: \"number\",\n minimum: 0,\n maximum: 255,\n description: \"该像素亮度 0–255;0 会编码为像素熄灭\",\n },\n },\n },\n description:\n \"仅 pixel_frame 有效:播放前先清 7 组,再按此列表写入 (Idx,R,G,B,Br)\",\n },\n },\n },\n },\n reason: {\n type: \"string\",\n description:\n \"结合对话上下文,简要说明为什么要亮灯(例如:用户心情低落想要温暖氛围、庆祝生日、提醒喝水等)。\" +\n \"这个字段帮助记录每次亮灯的意图和动机。\",\n },\n repeat: {\n type: \"boolean\",\n description:\n \"兼容旧参数。true = 无限循环,false/不填 = 一轮;若同时提供 repeat_times,则以后者为准\",\n },\n repeat_times: {\n type: \"number\",\n minimum: 0,\n description:\n \"整条组合重复次数:0 = 无限循环,1 = 播放一轮。当前 ANCS 路径不支持 N>=2\",\n },\n },\n} as const;\n\nexport function registerLightControlTool(\n api: OpenClawPluginApi,\n logger: Logger,\n): void {\n api.registerTool({\n name: \"light_control\",\n label: \"Light Control\",\n description:\n \"控制硬件灯效,支持 1–12 段顺序灯效,每段独立参数(6 种模式:波浪/呼吸/频闪/常亮/流光/逐组像素帧)。\" +\n \"Tool 内部自动量化为嵌入式协议定义的离散档位,并按模式精简为变长 ANCS 控制序列,通过 HTTP 接口下发灯效指令。\" +\n '当用户说\"开灯\"、\"换个灯效\"、\"把灯调成红色\"、\"营造氛围\"等与灯光控制相关的表达时调用。',\n parameters: lightControlParameters,\n async execute(_toolCallId: string, params: unknown) {\n let apiKey: string;\n try {\n apiKey = requireApiKey();\n } catch (e: any) {\n return {\n content: [{ type: \"text\" as const, text: e.message }],\n details: { ok: false, error: { code: \"AUTH_REQUIRED\", message: e.message } },\n };\n }\n\n const { segments, reason, repeat, repeat_times } = params as LightControlInput;\n const validation = validateSegments(segments);\n if (!validation.valid) {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(validation.errors) }],\n details: {\n ok: false,\n error: { code: \"VALIDATION_FAILED\", details: validation.errors },\n },\n };\n }\n\n let repeatTimes: number;\n try {\n repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });\n assertAncsRepeatTimes(repeatTimes);\n } catch (error: any) {\n return {\n content: [{ type: \"text\" as const, text: error?.message ?? String(error) }],\n details: {\n ok: false,\n error: { code: \"VALIDATION_FAILED\", message: error?.message ?? String(error) },\n },\n };\n }\n\n logger.info(`Light control reason: ${reason}`);\n const result = await sendLightEffect(\n apiKey,\n validation.segments,\n logger,\n { repeat_times: repeatTimes },\n reason,\n );\n\n if (!result.ok) {\n logger.warn(\n `Light control HTTP request failed: ${result.status} ${result.error}`,\n );\n } else {\n logger.info(`Light control sent, bizUniqueId=${result.bizUniqueId}`);\n }\n\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result) }],\n details: result,\n };\n },\n } as any);\n}\n","import { readFileSync } from \"node:fs\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport { resolveConfigPath } from \"../host.js\";\nimport type { Logger } from \"../logger.js\";\nimport { createAppNameMapProvider } from \"../notification/app-name-map.js\";\nimport {\n NotificationStorage,\n resolveNotificationStorageDir,\n} from \"../notification/storage.js\";\nimport {\n RecordingStorage,\n resolveRecordingStorageDir,\n} from \"../recording/index.js\";\nimport {\n createTunnelService,\n type RelayTunnelService,\n} from \"../tunnel/service.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { getEnvUrls } from \"../env.js\";\nimport { trimToUndefined } from \"./shared.js\";\n\ninterface LightRuleContext {\n workspaceDir?: string;\n stateDir?: string;\n}\n\ninterface StorageLifecycleDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n lightRuleCtx: LightRuleContext;\n setStorage: (storage: NotificationStorage | null) => void;\n setRecordingStorage: (storage: RecordingStorage | null) => void;\n /**\n * 在 storage service 完成 start 之后触发,此时 lightRuleCtx 已被回填。\n * 用于让 LightRuleRegistry 等下游组件在拿到真实 workspaceDir 后重新加载状态。\n */\n onStorageReady?: () => void;\n}\n\nexport function registerStorageLifecycle(\n deps: StorageLifecycleDeps,\n): void {\n const {\n api,\n config,\n logger,\n lightRuleCtx,\n setStorage,\n setRecordingStorage,\n onStorageReady,\n } = deps;\n\n let storage: NotificationStorage | null = null;\n let recordingStorage: RecordingStorage | null = null;\n let appNameMapProvider: ReturnType<typeof createAppNameMapProvider> | null = null;\n\n api.registerService({\n id: \"notification-storage\",\n async start(ctx) {\n const storageDir = resolveNotificationStorageDir(ctx, logger);\n\n appNameMapProvider = createAppNameMapProvider({\n stateDir: ctx.stateDir,\n logger,\n });\n await appNameMapProvider.start();\n\n const resolveDisplayName = appNameMapProvider.resolveDisplayName.bind(appNameMapProvider);\n storage = new NotificationStorage(storageDir, config, logger, resolveDisplayName);\n await storage.init();\n setStorage(storage);\n logger.info(`通知存储服务已启动: ${storageDir}`);\n\n const recDir = resolveRecordingStorageDir(ctx, logger);\n recordingStorage = new RecordingStorage(recDir, logger);\n await recordingStorage.init();\n setRecordingStorage(recordingStorage);\n logger.info(`录音存储服务已启动: ${recDir}`);\n\n lightRuleCtx.workspaceDir = ctx.workspaceDir;\n if (ctx.stateDir) {\n lightRuleCtx.stateDir = ctx.stateDir;\n }\n\n onStorageReady?.();\n },\n async stop() {\n await storage?.close();\n storage = null;\n setStorage(null);\n\n await recordingStorage?.close();\n recordingStorage = null;\n setRecordingStorage(null);\n\n appNameMapProvider?.stop();\n appNameMapProvider = null;\n logger.info(\"通知/录音存储服务已停止\");\n },\n });\n}\n\nfunction readHostGatewayConfig(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}) {\n const configPath = params.stateDir\n ? resolveConfigPath(params.stateDir)\n : undefined;\n\n let configData: any;\n\n if (configPath) {\n try {\n configData = JSON.parse(readFileSync(configPath, \"utf-8\"));\n } catch (err: any) {\n if (err?.code !== \"ENOENT\") {\n params.logger.warn(\n `Relay tunnel: 无法读取 gateway 鉴权配置 (${configPath})`,\n );\n }\n }\n }\n\n return configData;\n}\n\nfunction resolveLocalGatewayAuth(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}): {\n gatewayAuthMode?: \"token\" | \"password\";\n gatewayToken?: string;\n gatewayPassword?: string;\n} {\n const envGatewayToken =\n trimToUndefined(process.env.OPENCLAW_GATEWAY_TOKEN) ??\n trimToUndefined(process.env.QCLAW_GATEWAY_TOKEN);\n const envGatewayPassword =\n trimToUndefined(process.env.OPENCLAW_GATEWAY_PASSWORD) ??\n trimToUndefined(process.env.QCLAW_GATEWAY_PASSWORD);\n\n const configData = readHostGatewayConfig(params);\n let configGatewayAuthMode: \"token\" | \"password\" | undefined;\n const rawGatewayAuthMode = trimToUndefined(configData?.gateway?.auth?.mode);\n if (rawGatewayAuthMode === \"token\" || rawGatewayAuthMode === \"password\") {\n configGatewayAuthMode = rawGatewayAuthMode;\n }\n const configGatewayToken = trimToUndefined(configData?.gateway?.auth?.token);\n const configGatewayPassword = trimToUndefined(configData?.gateway?.auth?.password);\n\n return {\n gatewayAuthMode: configGatewayAuthMode,\n gatewayToken: envGatewayToken ?? configGatewayToken,\n gatewayPassword: envGatewayPassword ?? configGatewayPassword,\n };\n}\n\nfunction resolveExclusiveTunnelHint(params: {\n stateDir?: string;\n logger: Pick<Logger, \"warn\">;\n}): string | undefined {\n const configData = readHostGatewayConfig(params);\n const tailscaleMode = trimToUndefined(configData?.gateway?.tailscale?.mode);\n if (tailscaleMode) {\n return `gateway.tailscale.mode=${tailscaleMode}`;\n }\n\n return undefined;\n}\n\ninterface RelayTunnelDeps {\n api: OpenClawPluginApi;\n config: PluginConfig;\n logger: Logger;\n openclawDir?: string;\n}\n\nexport function registerRelayTunnelLifecycle(\n deps: RelayTunnelDeps,\n): RelayTunnelService | null {\n const {\n api,\n config,\n logger,\n openclawDir,\n } = deps;\n\n const tunnelUrl = getEnvUrls().relayTunnelUrl;\n if (!tunnelUrl) {\n return null;\n }\n\n const exclusiveTunnelHint = resolveExclusiveTunnelHint({\n stateDir: openclawDir,\n logger,\n });\n if (exclusiveTunnelHint) {\n logger.info(\n `Relay tunnel: detected ${exclusiveTunnelHint} in host gateway config, skipping relay startup to keep ingress mutually exclusive`,\n );\n return null;\n }\n\n const gatewayPort =\n process.env.OPENCLAW_GATEWAY_PORT ??\n process.env.QCLAW_GATEWAY_PORT ??\n \"18789\";\n const { gatewayAuthMode, gatewayToken, gatewayPassword } =\n resolveLocalGatewayAuth({\n stateDir: openclawDir,\n logger,\n });\n\n const tunnelService = createTunnelService({\n tunnelUrl,\n heartbeatSec: config.relay?.heartbeatSec,\n reconnectBackoffMs: config.relay?.reconnectBackoffMs,\n gatewayBaseUrl: `http://localhost:${gatewayPort}`,\n gatewayAuthMode,\n gatewayToken,\n gatewayPassword,\n logger,\n });\n\n api.registerService(tunnelService);\n logger.info(\"Relay tunnel 服务已注册\");\n return tunnelService;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { loadApiKey, watchCredentials } from \"../auth/credentials.js\";\nimport { getEnvUrls } from \"../env.js\";\n\nconst PLUGIN_STATE_DIR = \"phone-notifications\";\nconst CACHE_FILE = \"app-name-map.json\";\n\n/** 包名→应用名映射 API 地址(默认随环境变化;可用 APP_NAME_MAP_URL 覆盖;需鉴权) */\nconst BUILTIN_APP_NAME_MAP_URL = getEnvUrls().appNameMapUrl;\nconst APP_NAME_MAP_URL =\n (typeof process.env.APP_NAME_MAP_URL === \"string\" && process.env.APP_NAME_MAP_URL.trim()\n ? process.env.APP_NAME_MAP_URL.trim()\n : undefined) ?? BUILTIN_APP_NAME_MAP_URL;\n/** 映射刷新间隔(小时) */\nconst APP_NAME_MAP_REFRESH_HOURS = 12;\n\ninterface Logger {\n info: (message: string) => void;\n warn: (message: string) => void;\n}\n\nfunction isRecordOfStrings(v: unknown): v is Record<string, string> {\n if (v === null || typeof v !== \"object\") return false;\n for (const val of Object.values(v)) if (typeof val !== \"string\") return false;\n return true;\n}\n\n/** API 返回的单项 */\ninterface AppPackageItem {\n appName: string;\n packageName: string;\n iconUrl?: string | null;\n platform?: string | null;\n jumpUrl?: string | null;\n urlParams?: string | null;\n description?: string | null;\n}\n\n/** API 响应格式 */\ninterface AppNameMapApiResponse {\n success?: boolean;\n code?: string;\n message?: string;\n data?: AppPackageItem[];\n}\n\nfunction isAppNameMapApiResponse(v: unknown): v is AppNameMapApiResponse {\n if (v === null || typeof v !== \"object\") return false;\n const o = v as Record<string, unknown>;\n return Array.isArray(o.data) && o.data.every(\n (item: unknown) =>\n item !== null &&\n typeof item === \"object\" &&\n typeof (item as AppPackageItem).packageName === \"string\" &&\n typeof (item as AppPackageItem).appName === \"string\"\n );\n}\n\nfunction getCachePath(stateDir: string): string {\n return join(stateDir, \"plugins\", PLUGIN_STATE_DIR, CACHE_FILE);\n}\n\nexport interface AppNameMapProvider {\n /** 解析包名为显示名(未命中时拉取一次再返回,保证当前落库即有值) */\n resolveDisplayName(packageName: string): Promise<string>;\n start(): Promise<void>;\n stop(): void;\n}\n\nexport function createAppNameMapProvider(opts: {\n stateDir: string;\n logger: Logger;\n}): AppNameMapProvider {\n const { stateDir, logger } = opts;\n const url = APP_NAME_MAP_URL;\n const refreshHours = APP_NAME_MAP_REFRESH_HOURS;\n\n const map = new Map<string, string>();\n let refreshTimer: ReturnType<typeof setInterval> | null = null;\n let stopWatching: (() => void) | null = null;\n let inFlightFetch: Promise<void> | null = null;\n\n function loadFromDisk(): void {\n const path = getCachePath(stateDir);\n if (!existsSync(path)) return;\n try {\n const raw = JSON.parse(readFileSync(path, \"utf-8\"));\n if (!isRecordOfStrings(raw)) return;\n map.clear();\n for (const [k, v] of Object.entries(raw)) map.set(k, v);\n logger.info(`[app-name-map] loaded ${map.size} entries from cache: ${path}`);\n } catch {\n /* ignore */\n }\n }\n\n async function fetchFromServer(): Promise<void> {\n const apiKey = loadApiKey();\n if (!url) {\n logger.warn(\"[app-name-map] APP_NAME_MAP_URL is empty, skip refresh\");\n return;\n }\n if (!apiKey) {\n logger.info(\"[app-name-map] api key missing, skip refresh\");\n return;\n }\n\n const rawApiKey = apiKey.startsWith(\"Bearer \")\n ? apiKey.slice(\"Bearer \".length)\n : apiKey;\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Api-Key-Id\": rawApiKey },\n body: JSON.stringify({\n platform: \"\"\n })\n });\n if (!res.ok) {\n logger.warn(`[app-name-map] refresh failed: HTTP ${res.status} ${res.statusText}`);\n return;\n }\n const body = await res.json() as unknown;\n if (!isAppNameMapApiResponse(body) || !body.success || !body.data?.length) {\n logger.warn(\"[app-name-map] refresh failed: unexpected response shape or empty data\");\n return;\n }\n map.clear();\n for (const item of body.data) {\n if (item.packageName && item.appName) map.set(item.packageName, item.appName);\n }\n if (map.size === 0) {\n logger.warn(\"[app-name-map] refresh succeeded but got 0 entries\");\n return;\n }\n const dir = join(stateDir, \"plugins\", PLUGIN_STATE_DIR);\n\n mkdirSync(dir, { recursive: true });\n const cachePath = getCachePath(stateDir);\n writeFileSync(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), \"utf-8\");\n logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);\n } catch (e) {\n const message = e instanceof Error ? e.message : String(e);\n logger.warn(`[app-name-map] refresh error: ${message}`);\n }\n }\n\n async function ensureOneFetch(): Promise<void> {\n if (inFlightFetch) return inFlightFetch;\n inFlightFetch = fetchFromServer().finally(() => {\n inFlightFetch = null;\n });\n return inFlightFetch;\n }\n\n return {\n async resolveDisplayName(packageName: string): Promise<string> {\n // 临时策略:仅使用内存/磁盘中已有的映射,缺少时不主动触发拉取\n if (map.has(packageName)) return map.get(packageName)!;\n return packageName;\n // 如需在缺少应用名时触发一次拉取再返回,可恢复为:\n // if (!url || !loadApiKey()) return packageName;\n // await ensureOneFetch();\n // return map.get(packageName) ?? packageName;\n },\n\n async start(): Promise<void> {\n loadFromDisk();\n await fetchFromServer();\n\n if (!url) return;\n\n if (refreshHours > 0) {\n const ms = refreshHours * 60 * 60 * 1000;\n refreshTimer = setInterval(() => fetchFromServer().catch(() => { }), ms);\n }\n stopWatching = watchCredentials(() => fetchFromServer().catch(() => { }));\n },\n\n stop(): void {\n stopWatching?.();\n stopWatching = null;\n if (refreshTimer) {\n clearInterval(refreshTimer);\n refreshTimer = null;\n }\n map.clear();\n },\n };\n}\n","/**\n * 录音本地存储管理(§5.2)\n *\n * 目录结构:\n * <storageDir>/recordings/\n * ├── audio/ # 原始音频 + 打点文件\n * │ ├── 2026-03-23_14-32.ogg\n * │ └── 2026-03-23_14-32.srt\n * ├── transcript-data/ # 转写 JSON(主存储)\n * │ └── 2026-03-23_14-32.json\n * ├── transcripts/ # 转写文本\n * │ └── 2026-03-23_14-32_与王总沟通产品方向.md\n * ├── summaries/ # 转写摘要\n * │ └── 2026-03-23_14-32.md\n * └── index.json # 元数据索引\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n rmSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport { join, basename } from \"node:path\";\nimport type {\n RecordingMetadata,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport { transition } from \"./state-machine.js\";\nimport type { Logger } from \"../logger.js\";\nimport {\n buildTranscriptDataFilename as buildTranscriptDataJsonFilename,\n buildTranscriptDocument,\n extractTranscriptSummaryFromDocument,\n extractTranscriptTextFromDocument,\n extractTranscriptTitleFromDocument,\n parseTranscriptDocument,\n} from \"./transcript-document.js\";\n\n/**\n * 从 OSS URL 中提取音频文件扩展名(含点号,如 \".ogg\")\n * 默认返回 \".ogg\"(小硬件录音为 Opus/OGG 格式)\n */\nfunction extractAudioExt(ossUrl: string): string {\n try {\n const pathname = new URL(ossUrl).pathname;\n const m = pathname.match(/(\\.[a-z0-9]+)(?:\\?|$)/i);\n if (m) return m[1].toLowerCase();\n } catch {\n const m = ossUrl.match(/(\\.[a-z0-9]+)(?:\\?|$)/i);\n if (m) return m[1].toLowerCase();\n }\n return \".ogg\"; // 硬件默认录音格式(Opus/OGG)\n}\n\n// ─── Types ───\n\n/** 持久化到 index.json 的单条录音记录 */\nexport interface RecordingIndexEntry {\n /** 录音 ID,基于文件名(如 \"2026-03-23_14-32\") */\n id: string;\n /** 原始元数据 */\n metadata: RecordingMetadata;\n /** 当前插件侧状态 */\n status: RecordingTransferStatus;\n /** 本地音频文件相对路径 */\n audioFile?: string;\n /** 本地打点文件相对路径 */\n srtFile?: string;\n /** 本地转写文件相对路径 */\n transcriptFile?: string;\n /** 本地转写 JSON 文件相对路径 */\n transcriptDataFile?: string;\n /** 本地摘要文件相对路径 */\n summaryFile?: string;\n /** 转写标题 */\n title?: string;\n /** 入库时间 ISO 8601 */\n ingestedAt: string;\n /** 最后更新时间 ISO 8601 */\n updatedAt: string;\n}\n\n/** 录音存储索引(整个 index.json) */\ninterface RecordingIndex {\n recordings: RecordingIndexEntry[];\n}\n\nexport interface RecordingStorageContext {\n stateDir: string;\n workspaceDir?: string;\n}\n\n// ─── Constants ───\n\nconst RECORDINGS_DIR = \"recordings\";\nconst AUDIO_DIR = \"audio\";\nconst TRANSCRIPT_DATA_DIR = \"transcript-data\";\nconst TRANSCRIPTS_DIR = \"transcripts\";\nconst SUMMARIES_DIR = \"summaries\";\nconst INDEX_FILE = \"index.json\";\n\nfunction stripMarkdownFence(markdown: string): string {\n return markdown.replace(/\\r\\n/g, \"\\n\");\n}\n\nfunction deriveTitleFromTranscriptPath(\n transcriptFile: string | undefined,\n recordingId: string,\n): string | undefined {\n if (!transcriptFile) return undefined;\n const name = basename(transcriptFile, \".md\");\n const prefix = `${recordingId}_`;\n if (name.startsWith(prefix)) {\n const derived = name.slice(prefix.length).trim();\n return derived || undefined;\n }\n return undefined;\n}\n\nfunction extractTranscriptContent(markdown: string): string {\n const normalized = stripMarkdownFence(markdown);\n const firstDivider = normalized.indexOf(\"\\n---\\n\");\n let body = firstDivider >= 0\n ? normalized.slice(firstDivider + \"\\n---\\n\".length)\n : normalized;\n\n if (body.startsWith(\"\\n\")) {\n body = body.slice(1);\n }\n\n if (body.startsWith(\"### 关键点\")) {\n const secondDivider = body.indexOf(\"\\n---\\n\");\n if (secondDivider >= 0) {\n body = body.slice(secondDivider + \"\\n---\\n\".length);\n if (body.startsWith(\"\\n\")) {\n body = body.slice(1);\n }\n }\n }\n\n const lines = body\n .split(\"\\n\")\n .filter((line) => !/^\\*\\*\\[关键点 .+\\]\\*\\*$/.test(line.trim()))\n .filter((line) => !/^- \\*\\*\\[关键点 .+\\]\\*\\*$/.test(line.trim()));\n\n return lines.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").trim();\n}\n\n// ─── Public Functions ───\n\n/**\n * 解析录音存储根目录(复用通知同级的 stateDir 路径)\n */\nexport function resolveRecordingStorageDir(\n ctx: RecordingStorageContext,\n logger: Pick<Logger, \"info\" | \"warn\">,\n): string {\n const stateRecDir = join(\n ctx.stateDir,\n \"plugins\",\n \"phone-notifications\",\n RECORDINGS_DIR,\n );\n\n try {\n mkdirSync(stateRecDir, { recursive: true });\n logger.info(`录音将写入 stateDir 路径: ${stateRecDir}`);\n return stateRecDir;\n } catch {\n // fallback\n }\n\n if (ctx.workspaceDir) {\n const wsRecDir = join(ctx.workspaceDir, RECORDINGS_DIR);\n try {\n mkdirSync(wsRecDir, { recursive: true });\n logger.warn(`stateDir 不可用,录音已回退到 workspace 路径: ${wsRecDir}`);\n return wsRecDir;\n } catch {\n // fallthrough\n }\n }\n\n throw new Error(`录音存储目录不可用: ${stateRecDir}`);\n}\n\n// ─── RecordingStorage Class ───\n\nexport class RecordingStorage {\n private readonly dir: string;\n private readonly audioDir: string;\n private readonly transcriptDataDir: string;\n private readonly transcriptsDir: string;\n private readonly summariesDir: string;\n private readonly indexPath: string;\n private index: RecordingIndex = { recordings: [] };\n\n constructor(\n dir: string,\n private readonly logger: Logger,\n ) {\n this.dir = dir;\n this.audioDir = join(dir, AUDIO_DIR);\n this.transcriptDataDir = join(dir, TRANSCRIPT_DATA_DIR);\n this.transcriptsDir = join(dir, TRANSCRIPTS_DIR);\n this.summariesDir = join(dir, SUMMARIES_DIR);\n this.indexPath = join(dir, INDEX_FILE);\n }\n\n /** 初始化目录结构并加载索引 */\n async init(): Promise<void> {\n mkdirSync(this.audioDir, { recursive: true });\n mkdirSync(this.transcriptDataDir, { recursive: true });\n mkdirSync(this.transcriptsDir, { recursive: true });\n mkdirSync(this.summariesDir, { recursive: true });\n this.loadIndex();\n this.logger.info(\n `录音存储已初始化: ${this.dir}(共 ${this.index.recordings.length} 条记录)`,\n );\n }\n\n /** 获取音频目录路径 */\n getAudioDir(): string {\n return this.audioDir;\n }\n\n /** 获取转写 JSON 目录路径 */\n getTranscriptDataDir(): string {\n return this.transcriptDataDir;\n }\n\n /** 获取转写目录路径 */\n getTranscriptsDir(): string {\n return this.transcriptsDir;\n }\n\n /** 获取摘要目录路径 */\n getSummariesDir(): string {\n return this.summariesDir;\n }\n\n // ─── 录音入库 ───\n\n /**\n * 收到 recordings.sync 后,将元数据写入索引。\n * 如果同 ID 录音已存在则更新,否则新建。\n * 返回录音 ID。\n */\n ingest(recordingId: string, metadata: RecordingMetadata): string {\n const id = recordingId;\n const existing = this.findById(id);\n\n if (existing) {\n const sameAudioUrl = existing.metadata.oss_audio_url === metadata.oss_audio_url;\n const canPreserveSyncState =\n sameAudioUrl && !!existing.audioFile && existing.status !== \"syncing_openclaw\";\n\n if (canPreserveSyncState) {\n existing.metadata = metadata;\n existing.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(\n `录音元数据已更新: ${id}(同音频,保留状态 ${existing.status})`,\n );\n return id;\n }\n\n // 更新已有记录(覆盖上传/本地文件缺失场景)\n if (existing.transcriptDataFile) {\n rmSync(join(this.dir, existing.transcriptDataFile), { force: true });\n }\n if (existing.transcriptFile) {\n rmSync(join(this.dir, existing.transcriptFile), { force: true });\n }\n if (existing.summaryFile) {\n rmSync(join(this.dir, existing.summaryFile), { force: true });\n }\n existing.metadata = metadata;\n existing.status = \"syncing_openclaw\";\n existing.transcriptDataFile = undefined;\n existing.transcriptFile = undefined;\n existing.summaryFile = undefined;\n existing.title = undefined;\n existing.updatedAt = new Date().toISOString();\n this.logger.info(`录音元数据已更新: ${id}`);\n } else {\n const entry: RecordingIndexEntry = {\n id,\n metadata,\n status: \"syncing_openclaw\",\n ingestedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n this.index.recordings.push(entry);\n this.logger.info(`录音元数据已入库: ${id}`);\n }\n\n this.saveIndex();\n return id;\n }\n\n // ─── 状态管理 ───\n\n /**\n * 更新录音传输状态(严格状态机校验)\n */\n updateStatus(\n recordingId: string,\n newStatus: RecordingTransferStatus,\n ): RecordingIndexEntry {\n const entry = this.findById(recordingId);\n if (!entry) {\n throw new Error(`录音不存在: ${recordingId}`);\n }\n\n const validatedStatus = transition(entry.status, newStatus);\n entry.status = validatedStatus;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音状态更新: ${recordingId} → ${newStatus}`);\n return entry;\n }\n\n /**\n * 记录本地音频文件已下载\n */\n setAudioFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.audioFile = `${AUDIO_DIR}/${filename}`;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录本地打点文件已下载\n */\n setSrtFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.srtFile = `${AUDIO_DIR}/${filename}`;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写 JSON 文件路径\n */\n setTranscriptDataFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;\n if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {\n rmSync(join(this.dir, entry.transcriptDataFile), { force: true });\n }\n entry.transcriptDataFile = nextTranscriptDataFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写文件路径\n */\n setTranscriptFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;\n if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {\n rmSync(join(this.dir, entry.transcriptFile), { force: true });\n }\n entry.transcriptFile = nextTranscriptFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录摘要文件路径\n */\n setSummaryFile(recordingId: string, filename: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;\n if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {\n rmSync(join(this.dir, entry.summaryFile), { force: true });\n }\n entry.summaryFile = nextSummaryFile;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 记录转写标题\n */\n setTitle(recordingId: string, title?: string): void {\n const entry = this.findById(recordingId);\n if (!entry) return;\n entry.title = title?.trim() || undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n }\n\n /**\n * 读取摘要文本\n */\n readSummary(recordingId: string): string | undefined {\n const entry = this.findById(recordingId);\n if (!entry) return undefined;\n\n if (entry.summaryFile) {\n const summary = this.readRelativeTextFile(entry.summaryFile);\n if (summary?.trim()) {\n return summary.trim();\n }\n }\n\n const transcriptDoc = entry.transcriptDataFile\n ? this.readRelativeTranscriptDocument(entry.transcriptDataFile)\n : undefined;\n return extractTranscriptSummaryFromDocument(transcriptDoc);\n }\n\n /**\n * 优先从 transcript JSON 中读取正文,旧数据回退读取 Markdown。\n */\n readTranscript(recordingId: string): string | undefined {\n const entry = this.findById(recordingId);\n if (!entry) return undefined;\n\n if (entry.transcriptDataFile) {\n const transcriptDoc = this.readRelativeTranscriptDocument(entry.transcriptDataFile);\n const transcriptFromJson = extractTranscriptTextFromDocument(transcriptDoc);\n if (transcriptFromJson) {\n return transcriptFromJson;\n }\n }\n\n if (!entry.transcriptFile) return undefined;\n const markdown = this.readRelativeTextFile(entry.transcriptFile);\n if (!markdown) return undefined;\n const transcript = extractTranscriptContent(markdown);\n return transcript || undefined;\n }\n\n /**\n * 读取结构化 transcript JSON。\n */\n readTranscriptDocument(recordingId: string) {\n const entry = this.findById(recordingId);\n if (!entry?.transcriptDataFile) {\n return undefined;\n }\n return this.readRelativeTranscriptDocument(entry.transcriptDataFile);\n }\n\n // ─── 查询 ───\n\n findById(id: string): RecordingIndexEntry | undefined {\n return this.index.recordings.find((r) => r.id === id);\n }\n\n listAll(): RecordingIndexEntry[] {\n return [...this.index.recordings].sort(\n (a, b) => b.metadata.created_at.localeCompare(a.metadata.created_at),\n );\n }\n\n listByStatus(status: RecordingTransferStatus): RecordingIndexEntry[] {\n return this.listAll().filter((r) => r.status === status);\n }\n\n rename(recordingId: string, name: string): RecordingIndexEntry {\n const entry = this.findById(recordingId);\n if (!entry) {\n throw new Error(`录音不存在: ${recordingId}`);\n }\n\n entry.metadata = {\n ...entry.metadata,\n name,\n };\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音名称已更新: ${recordingId} → ${name}`);\n return entry;\n }\n\n // ─── 删除 ───\n\n /**\n * 删除录音及其本地文件(约束 R-4 安全删除)\n *\n * @param opts.localOnly 仅删除本地文件(音频/打点/转写),保留索引条目。\n * App 端\"仅删除本地\"时使用此模式,插件侧保留元数据记录。\n * 默认 false — 完整删除(文件 + 索引)。\n */\n delete(\n recordingId: string,\n opts?: { localOnly?: boolean },\n ): boolean {\n const entry = this.findById(recordingId);\n if (!entry) return false;\n\n // 删除本地文件\n if (entry.audioFile) {\n const audioPath = join(this.dir, entry.audioFile);\n rmSync(audioPath, { force: true });\n }\n if (entry.srtFile) {\n const srtPath = join(this.dir, entry.srtFile);\n rmSync(srtPath, { force: true });\n }\n if (entry.transcriptDataFile) {\n const transcriptDataPath = join(this.dir, entry.transcriptDataFile);\n rmSync(transcriptDataPath, { force: true });\n }\n if (entry.transcriptFile) {\n const transcriptPath = join(this.dir, entry.transcriptFile);\n rmSync(transcriptPath, { force: true });\n }\n if (entry.summaryFile) {\n const summaryPath = join(this.dir, entry.summaryFile);\n rmSync(summaryPath, { force: true });\n }\n\n if (opts?.localOnly) {\n // 保留索引条目,清除文件引用\n entry.audioFile = undefined;\n entry.srtFile = undefined;\n entry.transcriptDataFile = undefined;\n entry.transcriptFile = undefined;\n entry.summaryFile = undefined;\n entry.updatedAt = new Date().toISOString();\n this.saveIndex();\n this.logger.info(`录音本地文件已删除(保留索引): ${recordingId}`);\n } else {\n // 从索引中移除\n this.index.recordings = this.index.recordings.filter(\n (r) => r.id !== recordingId,\n );\n this.saveIndex();\n this.logger.info(`录音已完整删除: ${recordingId}`);\n }\n return true;\n }\n\n // ─── Helpers ───\n\n /**\n * 生成音频文件名。扩展名从 OSS URL 中提取,未提供时默认 .ogg(硬件录音格式)\n */\n buildAudioFilename(recordingId: string, ossUrl?: string): string {\n const ext = ossUrl ? extractAudioExt(ossUrl) : \".ogg\";\n return `${recordingId}${ext}`;\n }\n\n /**\n * 生成打点文件名\n */\n buildSrtFilename(recordingId: string): string {\n return `${recordingId}.srt`;\n }\n\n /**\n * 生成转写 JSON 文件名\n */\n buildTranscriptDataFilename(recordingId: string): string {\n return buildTranscriptDataJsonFilename(recordingId);\n }\n\n /**\n * 生成转写文件名\n * @param summary 摘要标题(≤ 10 字)\n */\n buildTranscriptFilename(recordingId: string, summary: string): string {\n // 清理文件名中的非法字符\n const safeSummary = summary\n .replace(/[/\\\\:*?\"<>|]/g, \"\")\n .trim()\n .slice(0, 20);\n return safeSummary\n ? `${recordingId}_${safeSummary}.md`\n : `${recordingId}.md`;\n }\n\n /**\n * 生成摘要文件名\n */\n buildSummaryFilename(recordingId: string): string {\n return `${recordingId}.md`;\n }\n\n /**\n * 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名\n */\n getAudioFilePath(recordingId: string, ossUrl?: string): string {\n return join(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));\n }\n\n /**\n * 获取打点文件的绝对路径\n */\n getSrtFilePath(recordingId: string): string {\n return join(this.audioDir, this.buildSrtFilename(recordingId));\n }\n\n /**\n * 获取转写 JSON 文件的绝对路径\n */\n getTranscriptDataFilePath(recordingId: string): string {\n return join(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));\n }\n\n /**\n * 获取摘要文件的绝对路径\n */\n getSummaryFilePath(recordingId: string): string {\n return join(this.summariesDir, this.buildSummaryFilename(recordingId));\n }\n\n // ─── Persistence ───\n\n private loadIndex(): void {\n if (!existsSync(this.indexPath)) {\n this.index = { recordings: [] };\n return;\n }\n try {\n const raw = JSON.parse(readFileSync(this.indexPath, \"utf-8\"));\n if (raw && Array.isArray(raw.recordings)) {\n let needsRewrite = false;\n const normalized = raw.recordings\n .filter((entry: unknown) => entry && typeof entry === \"object\")\n .map((entry: any) => {\n const compacted: RecordingIndexEntry = {\n id: entry.id,\n metadata: entry.metadata,\n status: entry.status,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n };\n if (typeof entry.audioFile === \"string\") compacted.audioFile = entry.audioFile;\n if (typeof entry.srtFile === \"string\") compacted.srtFile = entry.srtFile;\n if (typeof entry.transcriptFile === \"string\") {\n compacted.transcriptFile = entry.transcriptFile;\n }\n let transcriptDoc = typeof entry.transcriptDataFile === \"string\"\n ? this.readRelativeTranscriptDocument(entry.transcriptDataFile)\n : undefined;\n if (typeof entry.transcriptDataFile === \"string\" && transcriptDoc) {\n compacted.transcriptDataFile = entry.transcriptDataFile;\n } else {\n const legacyTranscriptText = typeof entry.transcript === \"string\" && entry.transcript.trim()\n ? entry.transcript.trim()\n : compacted.transcriptFile\n ? extractTranscriptContent(\n this.readRelativeTextFile(compacted.transcriptFile) ?? \"\",\n ) || undefined\n : undefined;\n const legacyTitle = typeof entry.title === \"string\" && entry.title.trim()\n ? entry.title.trim()\n : deriveTitleFromTranscriptPath(compacted.transcriptFile, compacted.id);\n const legacySummary = typeof entry.summary === \"string\" && entry.summary.trim()\n ? entry.summary.trim()\n : undefined;\n\n if (legacyTranscriptText) {\n transcriptDoc = buildTranscriptDocument({\n recordingId: compacted.id,\n generatedAt: compacted.updatedAt,\n source: {\n provider: \"legacy-markdown\",\n },\n title: legacyTitle,\n summary: legacySummary,\n text: legacyTranscriptText,\n segments: [],\n });\n const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);\n writeFileSync(\n join(this.transcriptDataDir, transcriptDataFilename),\n JSON.stringify(transcriptDoc, null, 2),\n \"utf-8\",\n );\n compacted.transcriptDataFile = `${TRANSCRIPT_DATA_DIR}/${transcriptDataFilename}`;\n needsRewrite = true;\n }\n }\n\n if (typeof entry.summaryFile === \"string\") {\n compacted.summaryFile = entry.summaryFile;\n } else if (typeof entry.summary === \"string\" && entry.summary.trim()) {\n const summaryFilename = this.buildSummaryFilename(entry.id);\n writeFileSync(\n join(this.summariesDir, summaryFilename),\n entry.summary.trim(),\n \"utf-8\",\n );\n compacted.summaryFile = `${SUMMARIES_DIR}/${summaryFilename}`;\n needsRewrite = true;\n } else {\n const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);\n if (summaryFromDocument) {\n const summaryFilename = this.buildSummaryFilename(entry.id);\n writeFileSync(\n join(this.summariesDir, summaryFilename),\n summaryFromDocument,\n \"utf-8\",\n );\n compacted.summaryFile = `${SUMMARIES_DIR}/${summaryFilename}`;\n needsRewrite = true;\n }\n }\n if (typeof entry.title === \"string\" && entry.title.trim()) {\n compacted.title = entry.title.trim();\n } else {\n const titleFromDocument = extractTranscriptTitleFromDocument(transcriptDoc);\n const derivedTitle = titleFromDocument ?? deriveTitleFromTranscriptPath(\n compacted.transcriptFile,\n compacted.id,\n );\n if (derivedTitle) {\n compacted.title = derivedTitle;\n needsRewrite = true;\n }\n }\n return compacted;\n });\n const hadLargeFields = raw.recordings.some(\n (entry: any) => entry && typeof entry === \"object\" && (\"transcript\" in entry || \"summary\" in entry),\n );\n this.index = { recordings: normalized };\n if (hadLargeFields || needsRewrite) {\n this.saveIndex();\n }\n } else {\n this.index = { recordings: [] };\n }\n } catch {\n this.logger.warn(`录音索引文件损坏,已重建: ${this.indexPath}`);\n this.index = { recordings: [] };\n }\n }\n\n private readRelativeTextFile(relativePath: string): string | undefined {\n try {\n return readFileSync(join(this.dir, relativePath), \"utf-8\");\n } catch {\n return undefined;\n }\n }\n\n private readRelativeTranscriptDocument(relativePath: string) {\n const raw = this.readRelativeTextFile(relativePath);\n if (!raw) {\n return undefined;\n }\n return parseTranscriptDocument(raw);\n }\n\n private saveIndex(): void {\n writeFileSync(\n this.indexPath,\n JSON.stringify(this.index, null, 2),\n \"utf-8\",\n );\n }\n\n async close(): Promise<void> {\n // 当前无需额外清理\n }\n}\n","/**\n * 录音传输状态机(约束 R-3)\n *\n * 状态流转严格不可跳跃:\n * receiving_failed → receiving\n * receiving → pending_oss_upload\n * pending_oss_upload → uploading_oss\n * uploading_oss → oss_uploaded\n * oss_uploaded → syncing_openclaw\n * syncing_openclaw → synced\n * synced → transcribing(仅当已配置 ASR)\n * transcribing → transcribed | transcribe_failed\n * transcribe_failed → transcribing\n * transcribed → transcribing(手动强制重新转写)\n */\n\nimport type { RecordingTransferStatus } from \"../types.js\";\n\n/** 合法的状态转换表:from → Set<to> */\nconst VALID_TRANSITIONS: ReadonlyMap<\n RecordingTransferStatus,\n ReadonlySet<RecordingTransferStatus>\n> = new Map<RecordingTransferStatus, ReadonlySet<RecordingTransferStatus>>([\n [\"receiving_failed\", new Set([\"receiving\"])],\n [\"receiving\", new Set([\"pending_oss_upload\"])],\n [\"pending_oss_upload\", new Set([\"uploading_oss\"])],\n [\"uploading_oss\", new Set([\"oss_uploaded\"])],\n [\"oss_uploaded\", new Set([\"syncing_openclaw\"])],\n [\"syncing_openclaw\", new Set([\"synced\"])],\n [\"synced\", new Set([\"transcribing\"])],\n [\"transcribing\", new Set([\"transcribed\", \"transcribe_failed\"])],\n [\"transcribe_failed\", new Set([\"transcribing\"])],\n [\"transcribed\", new Set([\"transcribing\"])],\n]);\n\n/** 插件侧关注的状态:从 syncing_openclaw 开始 */\nexport type PluginSideStatus = Extract<\n RecordingTransferStatus,\n \"syncing_openclaw\" | \"synced\" | \"transcribing\" | \"transcribe_failed\" | \"transcribed\"\n>;\n\n/**\n * 校验状态转换是否合法\n */\nexport function isValidTransition(\n from: RecordingTransferStatus,\n to: RecordingTransferStatus,\n): boolean {\n const allowed = VALID_TRANSITIONS.get(from);\n return allowed ? allowed.has(to) : false;\n}\n\n/**\n * 尝试执行状态转换,非法转换抛出 Error\n */\nexport function transition(\n from: RecordingTransferStatus,\n to: RecordingTransferStatus,\n): RecordingTransferStatus {\n if (!isValidTransition(from, to)) {\n throw new TransitionError(from, to);\n }\n return to;\n}\n\n/**\n * 状态是否为终态(没有后续合法转换)\n */\nexport function isTerminalStatus(status: RecordingTransferStatus): boolean {\n const allowed = VALID_TRANSITIONS.get(status);\n return !allowed || allowed.size === 0;\n}\n\n/**\n * 状态是否允许触发 ASR 转写\n */\nexport function canStartTranscription(status: RecordingTransferStatus): boolean {\n return (\n status === \"synced\"\n || status === \"transcribe_failed\"\n || status === \"transcribed\"\n );\n}\n\n/**\n * 获取当前状态的所有合法后续状态\n */\nexport function getNextStatuses(\n status: RecordingTransferStatus,\n): RecordingTransferStatus[] {\n const allowed = VALID_TRANSITIONS.get(status);\n return allowed ? [...allowed] : [];\n}\n\nexport class TransitionError extends Error {\n constructor(\n public readonly from: RecordingTransferStatus,\n public readonly to: RecordingTransferStatus,\n ) {\n super(`非法状态转换: ${from} → ${to}`);\n this.name = \"TransitionError\";\n }\n}\n","export {\n RecordingStorage,\n resolveRecordingStorageDir,\n type RecordingIndexEntry,\n type RecordingStorageContext,\n} from \"./storage.js\";\n\nexport {\n TRANSCRIPT_DOCUMENT_SCHEMA_VERSION,\n buildTranscriptDataFilename,\n buildTranscriptDocument,\n parseTranscriptDocument,\n extractTranscriptTextFromDocument,\n extractTranscriptSummaryFromDocument,\n extractTranscriptTitleFromDocument,\n extractSourceTextListFromDocument,\n type TranscriptDocument,\n type TranscriptDocumentContentItem,\n type TranscriptDocumentNormalized,\n type TranscriptDocumentSegment,\n type TranscriptDocumentSource,\n} from \"./transcript-document.js\";\n\nexport {\n isValidTransition,\n transition,\n isTerminalStatus,\n canStartTranscription,\n getNextStatuses,\n TransitionError,\n} from \"./state-machine.js\";\n\nexport {\n downloadFile,\n downloadRecordingFiles,\n type DownloadResult,\n type DownloadOptions,\n} from \"./downloader.js\";\n\nexport {\n isAsrConfigured,\n validateAsrConfig,\n initializeAsr,\n transcribeAudio,\n buildTranscriptMarkdown,\n extractSummary,\n runTranscriptionWorkflow,\n type TranscriptionResult,\n type TranscriptSegment,\n} from \"./asr.js\";\n\nexport {\n detectEnvironment,\n selectModelByMemory,\n isModelDownloaded,\n downloadModel,\n findWhisperBinary,\n transcribeWithWhisperLocal,\n getWhisperLocalStatus,\n} from \"./whisper-local.js\";\n\nexport {\n handleRecordingSync,\n triggerTranscription,\n type RecordingStatusEvent,\n type RecordingSyncOptions,\n} from \"./handler.js\";\n","/**\n * OSS 文件下载器(约束 R-6)\n *\n * 从 OSS URL 下载原始音频(mp3)和打点文件(srt)到本地。\n * 支持重试、超时控制、下载进度日志。\n */\n\nimport { createWriteStream, existsSync, mkdirSync, statSync, unlinkSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { Readable } from \"node:stream\";\nimport type { Logger } from \"../logger.js\";\n\n// ─── Types ───\n\nexport interface DownloadOptions {\n /** 下载超时(毫秒),默认 5 分钟 */\n timeoutMs?: number;\n /** 最大重试次数,默认 3 */\n maxRetries?: number;\n /** 重试间隔基数(毫秒),默认 2000 */\n retryBackoffMs?: number;\n}\n\nexport interface DownloadResult {\n ok: boolean;\n /** 下载的文件大小(字节) */\n sizeBytes?: number;\n /** 耗时(毫秒) */\n elapsedMs?: number;\n /** 错误信息 */\n error?: string;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60 * 1000; // 5 分钟(最大 ~56MB 文件)\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_RETRY_BACKOFF_MS = 2000;\n\n// ─── Public API ───\n\n/**\n * 从 URL 下载文件到本地路径\n */\nexport async function downloadFile(\n url: string,\n destPath: string,\n logger: Logger,\n options?: DownloadOptions,\n): Promise<DownloadResult> {\n const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;\n const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;\n\n mkdirSync(dirname(destPath), { recursive: true });\n\n let lastError: string | undefined;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n const startMs = Date.now();\n try {\n logger.info(\n `[downloader] 开始下载 (attempt ${attempt}/${maxRetries}): ${url}`,\n );\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const res = await fetch(url, { signal: controller.signal });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status} ${res.statusText}`);\n }\n\n if (!res.body) {\n throw new Error(\"响应体为空\");\n }\n\n // 写入文件\n const writeStream = createWriteStream(destPath);\n const readable = Readable.fromWeb(res.body as any);\n await pipeline(readable, writeStream);\n\n const elapsed = Date.now() - startMs;\n const fileSize = existsSync(destPath)\n ? statSync(destPath).size\n : 0;\n\n logger.info(\n `[downloader] 下载完成: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`,\n );\n\n return { ok: true, sizeBytes: fileSize, elapsedMs: elapsed };\n } finally {\n clearTimeout(timer);\n }\n } catch (err: any) {\n lastError = err?.message ?? String(err);\n\n // 清理可能写了一半的文件\n try {\n if (existsSync(destPath)) unlinkSync(destPath);\n } catch {\n // ignore\n }\n\n const isAbort = err?.name === \"AbortError\";\n logger.warn(\n `[downloader] 下载失败 (attempt ${attempt}/${maxRetries}): ${isAbort ? \"超时\" : lastError}`,\n );\n\n if (attempt < maxRetries) {\n const delay = retryBackoffMs * Math.pow(2, attempt - 1);\n logger.info(`[downloader] ${delay}ms 后重试...`);\n await sleep(delay);\n }\n }\n }\n\n return { ok: false, error: lastError ?? \"下载失败\" };\n}\n\n/**\n * 下载录音的音频文件和打点文件\n */\nexport async function downloadRecordingFiles(\n ossAudioUrl: string,\n ossSrtUrl: string | undefined,\n audioDestPath: string,\n srtDestPath: string,\n logger: Logger,\n options?: DownloadOptions,\n): Promise<{\n audio: DownloadResult;\n srt: DownloadResult | null;\n}> {\n // 下载音频(必须)\n const audio = await downloadFile(ossAudioUrl, audioDestPath, logger, options);\n\n // 下载打点文件(可选)\n let srt: DownloadResult | null = null;\n if (ossSrtUrl) {\n srt = await downloadFile(ossSrtUrl, srtDestPath, logger, options);\n if (!srt.ok) {\n // 打点文件下载失败不阻断主流程,仅警告\n logger.warn(`[downloader] 打点文件下载失败(非致命): ${srt.error}`);\n }\n }\n\n return { audio, srt };\n}\n\n// ─── Helpers ───\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes}B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","/**\n * 录音同步处理器(§2 阶段 4–5)\n *\n * 统一处理 recordings.sync 请求:\n * 1. 元数据入库\n * 2. 从 OSS 下载音频 + 打点文件\n * 3. 更新状态 → synced\n * 4. 如已配置 ASR → 自动触发转写\n */\n\nimport type {\n RecordingMetadata,\n RecordingSyncResult,\n AsrConfig,\n RecordingTranscriptItem,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport type { Logger } from \"../logger.js\";\nimport { RecordingStorage } from \"./storage.js\";\nimport { downloadRecordingFiles } from \"./downloader.js\";\nimport { isAsrConfigured, runTranscriptionWorkflow } from \"./asr.js\";\nimport { canStartTranscription } from \"./state-machine.js\";\n\nexport interface RecordingStatusEvent {\n recordingId: string;\n transfer_status: RecordingTransferStatus;\n audioFile?: string;\n srtFile?: string;\n transcriptDataFile?: string;\n transcriptFile?: string;\n transcript?: RecordingTranscriptItem[];\n summary?: string;\n title: string;\n updatedAt: string;\n error?: string;\n}\n\nexport interface RecordingSyncOptions {\n notifyStatus?: (event: RecordingStatusEvent) => void;\n}\n\nfunction emitRecordingStatus(\n recordingId: string,\n storage: RecordingStorage,\n logger: Logger,\n notifyStatus?: RecordingSyncOptions[\"notifyStatus\"],\n error?: string,\n extras?: Pick<RecordingStatusEvent, \"transcript\" | \"summary\" | \"title\">,\n): void {\n if (!notifyStatus) {\n return;\n }\n\n const entry = storage.findById(recordingId);\n if (!entry) {\n return;\n }\n\n const title = extras?.title?.trim()\n || entry.title?.trim()\n || entry.metadata.name?.trim()\n || entry.id;\n\n try {\n notifyStatus({\n recordingId: entry.id,\n transfer_status: entry.status,\n audioFile: entry.audioFile,\n srtFile: entry.srtFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n transcript: extras?.transcript,\n summary: extras?.summary,\n title,\n updatedAt: entry.updatedAt,\n error,\n });\n } catch (err: any) {\n logger.error(\n `[recording-status] 状态事件发送失败: ${recordingId}, ${err?.message ?? err}`,\n );\n }\n}\n\nasync function runRecordingSyncInBackground(\n metadata: RecordingMetadata,\n recordingId: string,\n storage: RecordingStorage,\n asrConfig: AsrConfig | undefined,\n logger: Logger,\n options: RecordingSyncOptions,\n): Promise<void> {\n const audioDestPath = storage.getAudioFilePath(\n recordingId,\n metadata.oss_audio_url,\n );\n const srtDestPath = storage.getSrtFilePath(recordingId);\n\n logger.info(\n `[recording-sync] 开始下载录音文件: ${recordingId}, audio=${metadata.oss_audio_url}`,\n );\n\n const downloadResult = await downloadRecordingFiles(\n metadata.oss_audio_url,\n metadata.oss_srt_url,\n audioDestPath,\n srtDestPath,\n logger,\n );\n\n if (!downloadResult.audio.ok) {\n const error = `音频下载失败: ${downloadResult.audio.error}`;\n logger.error(`[recording-sync] ${error}: ${recordingId}`);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n return;\n }\n\n storage.setAudioFile(\n recordingId,\n storage.buildAudioFilename(recordingId, metadata.oss_audio_url),\n );\n if (downloadResult.srt?.ok) {\n storage.setSrtFile(recordingId, storage.buildSrtFilename(recordingId));\n }\n\n storage.updateStatus(recordingId, \"synced\");\n logger.info(`[recording-sync] 录音已同步: ${recordingId}`);\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n if (isAsrConfigured(asrConfig) && canStartTranscription(\"synced\")) {\n await triggerTranscription(\n recordingId,\n storage,\n asrConfig!,\n logger,\n options,\n );\n }\n}\n\n/**\n * 处理 recordings.sync 请求的核心逻辑\n */\nexport async function handleRecordingSync(\n recordingId: string,\n metadata: RecordingMetadata,\n storage: RecordingStorage,\n asrConfig: AsrConfig | undefined,\n logger: Logger,\n options: RecordingSyncOptions = {},\n): Promise<RecordingSyncResult> {\n const existing = storage.findById(recordingId);\n const shouldDownloadAndSync =\n !existing\n || existing.metadata.oss_audio_url !== metadata.oss_audio_url\n || !existing.audioFile\n || existing.status === \"syncing_openclaw\";\n\n storage.ingest(recordingId, metadata);\n if (shouldDownloadAndSync) {\n runRecordingSyncInBackground(\n metadata,\n recordingId,\n storage,\n asrConfig,\n logger,\n options,\n ).catch((err) => {\n const error = `录音同步失败: ${err?.message ?? err}`;\n logger.error(`[recording-sync] ${error}: ${recordingId}`);\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n error,\n );\n });\n } else {\n logger.info(\n `[recording-sync] 录音已存在且音频未变化,跳过重复下载: ${recordingId}`,\n );\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n const current = storage.findById(recordingId);\n if (current?.status === \"synced\" && isAsrConfigured(asrConfig)) {\n triggerTranscription(\n recordingId,\n storage,\n asrConfig!,\n logger,\n options,\n ).catch((err) => {\n logger.error(\n `[asr-trigger] 转写触发失败: ${recordingId}, ${err?.message ?? err}`,\n );\n });\n }\n }\n\n return {\n ok: true,\n recordingId,\n transfer_status:\n storage.findById(recordingId)?.status ?? \"syncing_openclaw\",\n };\n}\n\n/**\n * 触发 ASR 转写(可从 sync handler 自动触发或手动重试调用)\n */\nexport async function triggerTranscription(\n recordingId: string,\n storage: RecordingStorage,\n asrConfig: AsrConfig,\n logger: Logger,\n options: RecordingSyncOptions = {},\n): Promise<void> {\n const entry = storage.findById(recordingId);\n if (!entry) {\n logger.warn(`[asr-trigger] 录音不存在: ${recordingId}`);\n return;\n }\n\n if (!canStartTranscription(entry.status)) {\n logger.warn(\n `[asr-trigger] 当前状态不允许转写: ${recordingId} (status=${entry.status})`,\n );\n return;\n }\n\n // 状态 → transcribing\n storage.updateStatus(recordingId, \"transcribing\");\n emitRecordingStatus(recordingId, storage, logger, options.notifyStatus);\n\n const audioFilePath = storage.getAudioFilePath(recordingId);\n\n const result = await runTranscriptionWorkflow({\n audioFilePath,\n audioOssUrl: entry.metadata.oss_audio_url,\n config: asrConfig,\n markers: entry.metadata.markers ?? [],\n recordingName: entry.metadata.name,\n durationSec: entry.metadata.duration_sec,\n createdAt: entry.metadata.created_at,\n transcriptDataDir: storage.getTranscriptDataDir(),\n transcriptsDir: storage.getTranscriptsDir(),\n summariesDir: storage.getSummariesDir(),\n recordingId,\n logger,\n });\n\n if (result.ok && result.transcriptFilename) {\n if (result.transcriptDataFilename) {\n storage.setTranscriptDataFile(recordingId, result.transcriptDataFilename);\n }\n storage.setTranscriptFile(recordingId, result.transcriptFilename);\n if (result.summaryFilename) {\n storage.setSummaryFile(recordingId, result.summaryFilename);\n }\n storage.setTitle(recordingId, result.title);\n storage.updateStatus(recordingId, \"transcribed\");\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n undefined,\n {\n transcript: result.transcript ?? [],\n summary: result.summary,\n title: result.title ?? \"\",\n },\n );\n logger.info(\n `[asr-trigger] 转写完成: ${recordingId}, summary=\"${result.summary}\"`,\n );\n } else {\n storage.updateStatus(recordingId, \"transcribe_failed\");\n emitRecordingStatus(\n recordingId,\n storage,\n logger,\n options.notifyStatus,\n result.error,\n );\n logger.error(\n `[asr-trigger] 转写失败: ${recordingId}, error=${result.error}`,\n );\n }\n}\n","import {\n closeSync,\n mkdirSync,\n openSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { loadApiKey } from \"../auth/credentials.js\";\nimport { RelayClient } from \"./relay-client.js\";\nimport { TunnelProxy } from \"./proxy.js\";\nimport type { UpdateInfo } from \"../update/types.js\";\n\nconst DEFAULT_HEARTBEAT_SEC = 10;\nconst DEFAULT_RECONNECT_BACKOFF_MS = 2000;\n\ninterface TunnelServiceOptions {\n /** Relay Server WebSocket 地址(构建时从 RELAY_TUNNEL_URL 注入) */\n tunnelUrl: string;\n gatewayBaseUrl: string;\n /** Gateway 鉴权模式 */\n gatewayAuthMode?: \"token\" | \"password\";\n /** Gateway 鉴权 token */\n gatewayToken?: string;\n /** Gateway 鉴权密码 */\n gatewayPassword?: string;\n /** 心跳间隔(秒),默认 10 */\n heartbeatSec?: number;\n /** 重连基础退避时间(毫秒),默认 2000 */\n reconnectBackoffMs?: number;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport interface RelayTunnelService {\n id: string;\n start(ctx: { stateDir: string }): Promise<void>;\n stop(): Promise<void>;\n notifyUpdateAvailable(update: UpdateInfo): void;\n clearPendingUpdate(): void;\n deactivateForExternalTunnel(reason: string): Promise<void>;\n}\n\n/**\n * 隧道服务:组装 RelayClient + TunnelProxy,作为 registerService 的入口。\n */\nexport function createTunnelService(\n opts: TunnelServiceOptions,\n): RelayTunnelService {\n let client: RelayClient | null = null;\n let proxy: TunnelProxy | null = null;\n let abortController: AbortController | null = null;\n let lockFilePath: string | null = null;\n let lockFd: number | null = null;\n let pendingPluginUpdate: UpdateInfo | null = null;\n let suppressedByExternalTunnel = false;\n\n function emitPendingPluginUpdate(reason: string): void {\n const update = pendingPluginUpdate;\n if (!update || !client?.isConnected()) return;\n\n const frame = JSON.stringify({\n type: \"event\",\n event: \"plugin.updateAvailable\",\n payload: {\n pluginId: \"phone-notifications\",\n current: update.current,\n latest: update.latest,\n },\n });\n opts.logger.info(\n `Relay tunnel: sending plugin.updateAvailable ${update.current} → ${update.latest} (${reason})`,\n );\n client.sendRaw(frame);\n }\n\n function isProcessAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n if (pid === process.pid) return true;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err: any) {\n return err?.code === \"EPERM\";\n }\n }\n\n function readLockOwner(filePath: string): number | null {\n try {\n const parsed = JSON.parse(readFileSync(filePath, \"utf-8\")) as {\n pid?: unknown;\n };\n return typeof parsed.pid === \"number\" ? parsed.pid : null;\n } catch {\n return null;\n }\n }\n\n function releaseLock(): void {\n const filePath = lockFilePath;\n const fd = lockFd;\n lockFilePath = null;\n lockFd = null;\n\n if (fd !== null) {\n try {\n closeSync(fd);\n } catch {\n // ignore\n }\n }\n if (filePath) {\n try {\n unlinkSync(filePath);\n } catch {\n // ignore\n }\n }\n }\n\n function acquireLock(filePath: string): boolean {\n mkdirSync(dirname(filePath), { recursive: true });\n\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n const fd = openSync(filePath, \"wx\", 0o600);\n writeFileSync(\n fd,\n JSON.stringify({\n pid: process.pid,\n startedAt: new Date().toISOString(),\n tunnelUrl: opts.tunnelUrl,\n }) + \"\\n\",\n );\n lockFilePath = filePath;\n lockFd = fd;\n return true;\n } catch (err: any) {\n if (err?.code !== \"EEXIST\") {\n opts.logger.error(\n `Relay tunnel: failed to acquire local lock ${filePath}: ${String(err)}`,\n );\n return false;\n }\n\n const ownerPid = readLockOwner(filePath);\n if (ownerPid && !isProcessAlive(ownerPid)) {\n opts.logger.warn(\n `Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`,\n );\n try {\n unlinkSync(filePath);\n } catch {\n // ignore, retry below will fail if lock is still present\n }\n continue;\n }\n\n opts.logger.warn(\n `Relay tunnel: another local process already owns the tunnel lock${ownerPid ? ` (pid=${ownerPid})` : \"\"}; skipping connection to avoid duplicate token sessions`,\n );\n return false;\n }\n }\n\n return false;\n }\n\n async function shutdownRuntime(reason: string): Promise<void> {\n await client?.stop(reason);\n if (abortController) {\n abortController.abort();\n abortController = null;\n }\n releaseLock();\n proxy?.cleanup();\n proxy = null;\n client = null;\n }\n\n return {\n id: \"relay-tunnel\",\n\n async start(ctx: { stateDir: string }) {\n if (suppressedByExternalTunnel) {\n opts.logger.info(\n \"Relay tunnel: external tunnel currently owns ingress; skipping relay startup\",\n );\n return;\n }\n\n // 先清理上一轮连接,防止 start() 被重复调用时产生多个 RelayClient 互踢\n if (abortController) {\n opts.logger.info(\"Relay tunnel: aborting previous connection before restart\");\n await shutdownRuntime(\"service restarting\");\n }\n\n const apiKey = loadApiKey();\n if (!apiKey) {\n opts.logger.warn(\n \"Relay tunnel: apiKey 未设置,跳过隧道连接。请执行 openclaw ntf auth set-api-key <apiKey>\",\n );\n return;\n }\n\n const { logger } = opts;\n const baseStateDir = join(ctx.stateDir, \"plugins\", \"phone-notifications\");\n logger.info(\n `Relay tunnel: starting (pid=${process.pid}, url=${opts.tunnelUrl}, heartbeat=${opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC}s, backoff=${opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS}ms, gateway=${opts.gatewayBaseUrl}, hasGatewayToken=${!!opts.gatewayToken}, hasGatewayPwd=${!!opts.gatewayPassword})`,\n );\n const statusFilePath = join(baseStateDir, \"tunnel-status.json\");\n const lockPath = join(baseStateDir, \"relay-tunnel.lock\");\n\n if (!acquireLock(lockPath)) {\n return;\n }\n\n try {\n client = new RelayClient({\n tunnelUrl: opts.tunnelUrl,\n apiKey,\n heartbeatSec: opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC,\n reconnectBackoffMs: opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS,\n statusFilePath,\n logger,\n });\n\n proxy = new TunnelProxy({\n stateDir: baseStateDir,\n hostStateDir: ctx.stateDir,\n gatewayBaseUrl: opts.gatewayBaseUrl,\n gatewayAuthMode: opts.gatewayAuthMode,\n gatewayToken: opts.gatewayToken,\n gatewayPassword: opts.gatewayPassword,\n client,\n logger,\n });\n\n client.onInbound((frame) => proxy!.handleFrame(frame));\n client.onConnected(() => {\n emitPendingPluginUpdate(\"relay connected\");\n });\n\n abortController = new AbortController();\n // 非阻塞启动,connectWithAutoReconnect 内部会保持运行\n client.connectWithAutoReconnect(abortController.signal).catch((err) => {\n releaseLock();\n logger.error(`Relay tunnel: unexpected error: ${err}`);\n });\n\n logger.info(\"Relay tunnel 服务已启动\");\n } catch (err) {\n releaseLock();\n throw err;\n }\n },\n\n async stop() {\n suppressedByExternalTunnel = false;\n await shutdownRuntime(\"service stopping\");\n opts.logger.info(\"Relay tunnel 服务已停止\");\n },\n\n async deactivateForExternalTunnel(reason: string) {\n if (suppressedByExternalTunnel && !client && !proxy && !abortController) {\n return;\n }\n\n suppressedByExternalTunnel = true;\n opts.logger.info(\n `Relay tunnel: external tunnel claimed ingress (${reason}), shutting down relay connection`,\n );\n await shutdownRuntime(\"external tunnel active\");\n },\n\n notifyUpdateAvailable(update: UpdateInfo) {\n pendingPluginUpdate = update;\n emitPendingPluginUpdate(\"update detected\");\n },\n\n clearPendingUpdate() {\n pendingPluginUpdate = null;\n },\n };\n}\n","import { writeFileSync, mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport WebSocket from \"ws\";\nimport type { InboundFrame, OutboundFrame } from \"./types.js\";\n\nfunction previewText(text: string, max = 500): string {\n return text.length <= max ? text : `${text.substring(0, max)}…`;\n}\n\nfunction maskSecret(value: string): string {\n if (!value) return \"empty\";\n if (value.length <= 8) {\n return `${value.slice(0, 2)}…${value.slice(-2)}`;\n }\n return `${value.slice(0, 4)}…${value.slice(-4)}`;\n}\n\n/** 持久化到磁盘的隧道连接状态 */\nexport interface TunnelStatusInfo {\n /** 当前连接状态 */\n state: \"connected\" | \"disconnected\" | \"connecting\" | \"stopped\";\n /** 状态变更时间 ISO */\n since: string;\n /** 累计重连次数 */\n reconnectAttempt: number;\n /** 上次断开原因(仅 disconnected 时有值) */\n lastDisconnectReason?: string;\n}\n\nexport interface RelayClientOptions {\n tunnelUrl: string;\n apiKey: string;\n heartbeatSec: number;\n reconnectBackoffMs: number;\n /** 状态文件路径,设置后会在连接状态变更时写入 */\n statusFilePath?: string;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport type InboundHandler = (frame: InboundFrame) => void | Promise<void>;\nexport type ConnectedHandler = () => void | Promise<void>;\n\n/**\n * Relay WebSocket 客户端。\n * 负责建连、token 认证、心跳保活、断线指数退避重连。\n */\nexport class RelayClient {\n private ws: WebSocket | null = null;\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private handlers: InboundHandler[] = [];\n private connectedHandlers: ConnectedHandler[] = [];\n private aborted = false;\n private lastInboundAt = 0;\n private stopPromise: Promise<void> | null = null;\n\n constructor(private readonly opts: RelayClientOptions) {}\n\n /** 写连接状态到磁盘 */\n private writeStatus(\n state: TunnelStatusInfo[\"state\"],\n lastDisconnectReason?: string,\n ): void {\n if (!this.opts.statusFilePath) return;\n const info: TunnelStatusInfo = {\n state,\n since: new Date().toISOString(),\n reconnectAttempt: this.reconnectAttempt,\n lastDisconnectReason,\n };\n try {\n mkdirSync(dirname(this.opts.statusFilePath), { recursive: true });\n writeFileSync(this.opts.statusFilePath, JSON.stringify(info, null, 2));\n } catch {\n // 写状态文件失败不影响主流程\n }\n }\n\n /** 注册入站帧处理函数 */\n onInbound(handler: InboundHandler): void {\n this.handlers.push(handler);\n }\n\n /** 注册连接成功后的回调 */\n onConnected(handler: ConnectedHandler): void {\n this.connectedHandlers.push(handler);\n }\n\n /** 当前是否已连上 Relay */\n isConnected(): boolean {\n return this.ws?.readyState === WebSocket.OPEN;\n }\n\n /** 优雅停止客户端,优先发送 close 帧,超时后再强制 terminate */\n async stop(reason = \"client stopping\"): Promise<void> {\n if (this.stopPromise) {\n return this.stopPromise;\n }\n\n this.aborted = true;\n this.writeStatus(\"stopped\");\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const ws = this.ws;\n this.ws = null;\n if (!ws) {\n return;\n }\n\n this.opts.logger.info(\n `Relay tunnel: stopping client (readyState=${ws.readyState}, reason=${reason})`,\n );\n\n if (\n ws.readyState === WebSocket.CLOSED ||\n ws.readyState === WebSocket.CLOSING\n ) {\n return;\n }\n\n if (ws.readyState !== WebSocket.OPEN) {\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n return;\n }\n\n this.stopPromise = new Promise<void>((resolve) => {\n let finished = false;\n let fallbackTimer: ReturnType<typeof setTimeout> | null = null;\n\n const finish = () => {\n if (finished) return;\n finished = true;\n if (fallbackTimer) {\n clearTimeout(fallbackTimer);\n fallbackTimer = null;\n }\n ws.off(\"close\", handleClose);\n ws.off(\"error\", handleError);\n this.stopPromise = null;\n resolve();\n };\n\n const handleClose = () => finish();\n const handleError = () => finish();\n\n ws.once(\"close\", handleClose);\n ws.once(\"error\", handleError);\n\n fallbackTimer = setTimeout(() => {\n this.opts.logger.warn(\n \"Relay tunnel: graceful close timed out, forcing terminate\",\n );\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n finish();\n }, 1500);\n\n try {\n ws.close(1000, reason);\n } catch {\n finish();\n }\n });\n\n await this.stopPromise;\n }\n\n /** 发送出站帧 */\n send(frame: OutboundFrame): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n const payload = JSON.stringify(frame);\n this.opts.logger.info(\n `Relay tunnel: ▶ send frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"} (${payload.length} chars)`,\n );\n this.ws.send(payload);\n } else {\n this.opts.logger.warn(\n `Relay tunnel: ▶ send skipped, ws not open (readyState=${this.ws?.readyState ?? \"null\"}), frame type=${frame.type}`,\n );\n }\n }\n\n /** 原样透传文本到 Relay(用于 Gateway WS 响应直接回传) */\n sendRaw(text: string): void {\n if (this.ws?.readyState === WebSocket.OPEN) {\n this.opts.logger.info(\n `Relay tunnel: ▶ sendRaw (${text.length} chars): ${text.length <= 500 ? text : text.substring(0, 500) + \"…\"}`,\n );\n this.ws.send(text);\n } else {\n this.opts.logger.warn(\n `Relay tunnel: ▶ sendRaw skipped, ws not open (readyState=${this.ws?.readyState ?? \"null\"})`,\n );\n }\n }\n\n /** 启动连接,带自动重连,直到 abortSignal 触发 */\n async connectWithAutoReconnect(abortSignal?: AbortSignal): Promise<void> {\n if (abortSignal) {\n abortSignal.addEventListener(\n \"abort\",\n () => {\n void this.stop();\n },\n { once: true },\n );\n }\n\n await this.connect();\n\n // 保持运行直到 abort\n return new Promise<void>((resolve) => {\n if (abortSignal) {\n abortSignal.addEventListener(\"abort\", () => resolve(), { once: true });\n }\n });\n }\n\n private async connect(): Promise<void> {\n if (this.aborted) return;\n\n // 确保旧连接和定时器都被清理,防止重复连接\n this.cleanup(true);\n\n const rawApiKey = this.opts.apiKey.startsWith(\"Bearer \")\n ? this.opts.apiKey.slice(\"Bearer \".length)\n : this.opts.apiKey;\n\n this.opts.logger.info(\n `Relay tunnel: connecting to ${this.opts.tunnelUrl} (attempt=${this.reconnectAttempt}, heartbeat=${this.opts.heartbeatSec}s, apiKey=${maskSecret(rawApiKey)})`,\n );\n this.writeStatus(\"connecting\");\n\n return new Promise<void>((resolve) => {\n let settled = false;\n const settle = () => {\n if (!settled) {\n settled = true;\n resolve();\n }\n };\n\n const wsUrl = new URL(this.opts.tunnelUrl);\n // 推荐使用 query 传 apiKey;暂时用 token 代替 apiKey 明文\n if (!wsUrl.searchParams.get(\"apiKey\")) {\n wsUrl.searchParams.set(\"apiKey\", rawApiKey);\n }\n\n const ws = new WebSocket(wsUrl.toString(), {\n headers: {\n \"X-Api-Key-Id\": rawApiKey,\n },\n });\n // 将握手中的 socket 也记为当前连接,确保首连失败/握手前断开也能触发重连。\n this.ws = ws;\n\n ws.on(\"open\", () => {\n if (this.aborted || this.ws !== ws) {\n this.opts.logger.warn(\n `Relay tunnel: open fired but aborted=${this.aborted}, stale=${this.ws !== ws}, closing`,\n );\n try {\n ws.terminate();\n } catch {\n // ignore\n }\n settle();\n return;\n }\n this.reconnectAttempt = 0;\n this.lastInboundAt = Date.now();\n this.startHeartbeat();\n this.opts.logger.info(\"Relay tunnel: ✔ connected, heartbeat started\");\n this.writeStatus(\"connected\");\n this.emitConnected();\n settle();\n });\n\n ws.on(\"pong\", () => {\n if (this.ws === ws) {\n this.opts.logger.info(\"Relay tunnel: ← pong received\");\n this.markInboundActivity();\n }\n });\n\n ws.on(\"message\", (data: WebSocket.RawData) => {\n if (this.ws !== ws) {\n return;\n }\n this.handleMessage(data);\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n const reasonStr = reason.toString();\n const lastInboundAgoMs = this.lastInboundAt\n ? Date.now() - this.lastInboundAt\n : null;\n const isCurrentSocket = this.ws === ws;\n const logMessage =\n `Relay tunnel: disconnected (code=${code}, reason=${previewText(reasonStr, 200)}, lastInboundAgoMs=${lastInboundAgoMs ?? \"N/A\"}, reconnectAttempt=${this.reconnectAttempt})`;\n if (this.aborted || !isCurrentSocket) {\n this.opts.logger.info(logMessage);\n } else {\n this.opts.logger.warn(logMessage);\n }\n if (isCurrentSocket) {\n this.stopHeartbeat();\n this.ws = null;\n this.writeStatus(\"disconnected\", `code=${code}, reason=${reasonStr}`);\n this.scheduleReconnect();\n }\n settle();\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.error(\n `Relay tunnel: WebSocket error: ${err.message} (readyState=${ws.readyState}, reconnectAttempt=${this.reconnectAttempt}, url=${wsUrl.toString()})`,\n );\n // 握手阶段的错误也要尽快结束本次 connect(),重连仍统一由 close 事件触发。\n settle();\n });\n });\n }\n\n private emitConnected(): void {\n for (const handler of this.connectedHandlers) {\n Promise.resolve(handler()).catch((err) => {\n this.opts.logger.warn(\n `Relay tunnel: onConnected handler failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n }\n\n private handleMessage(data: WebSocket.RawData): void {\n const text =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString()\n : String(data);\n\n this.markInboundActivity();\n\n // 应用层心跳 pong 直接消费,不走帧解析\n if (text === \"pong\") {\n return;\n }\n\n this.opts.logger.info(\n `Relay tunnel: ★ received message (${text.length} chars): ${previewText(text)}`,\n );\n\n let frame: InboundFrame;\n try {\n frame = JSON.parse(text) as InboundFrame;\n } catch {\n this.opts.logger.warn(\n `Relay tunnel: received invalid frame, ignoring (preview=${previewText(text, 200)})`,\n );\n return;\n }\n\n this.opts.logger.info(`Relay tunnel: parsed frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"}`);\n\n for (const handler of this.handlers) {\n try {\n const result = handler(frame);\n if (result instanceof Promise) {\n result.catch((err) => {\n this.opts.logger.error(`Relay tunnel: handler error: ${err}`);\n });\n }\n } catch (err) {\n this.opts.logger.error(`Relay tunnel: handler error: ${err}`);\n }\n }\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n const intervalMs = this.opts.heartbeatSec * 1000;\n this.sendHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n this.sendHeartbeat();\n }, intervalMs);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n private getHeartbeatTimeoutMs(): number {\n return this.opts.heartbeatSec * 3 * 1000;\n }\n\n private sendHeartbeat(): void {\n if (this.ws?.readyState !== WebSocket.OPEN) {\n return;\n }\n\n const idleMs = Date.now() - this.lastInboundAt;\n const timeoutMs = this.getHeartbeatTimeoutMs();\n if (idleMs >= timeoutMs) {\n this.opts.logger.warn(\n `Relay tunnel: heartbeat timeout, no inbound activity for ${idleMs}ms (threshold=${timeoutMs}ms)`,\n );\n try {\n this.ws.terminate();\n } catch {\n // ignore, close/error path will handle reconnect\n }\n return;\n }\n\n this.opts.logger.info('Relay tunnel: → heartbeat \"ping\"');\n try {\n this.ws.send(\"ping\");\n } catch {\n // ignore, close/error path will handle reconnect\n }\n try {\n this.ws.ping();\n } catch {\n // ignore, close/error path will handle reconnect\n }\n }\n\n private markInboundActivity(): void {\n this.lastInboundAt = Date.now();\n }\n\n private cleanup(force = false): void {\n this.opts.logger.info(\n `Relay tunnel: cleanup (ws=${this.ws ? \"open\" : \"null\"}, heartbeat=${!!this.heartbeatTimer}, reconnect=${!!this.reconnectTimer})`,\n );\n this.stopHeartbeat();\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n if (this.ws) {\n try {\n if (force) {\n this.ws.terminate();\n } else {\n this.ws.close();\n }\n } catch {\n // ignore\n }\n this.ws = null;\n }\n }\n\n private scheduleReconnect(): void {\n if (this.aborted) return;\n\n // 取消已有的重连定时器,防止重复 connect\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n const baseMs = this.opts.reconnectBackoffMs;\n const delayMs = Math.min(\n baseMs * Math.pow(2, this.reconnectAttempt),\n 60_000,\n );\n this.reconnectAttempt++;\n\n this.opts.logger.info(\n `Relay tunnel: reconnecting in ${delayMs}ms (attempt ${this.reconnectAttempt})`,\n );\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n if (!this.aborted) {\n this.connect().catch((err) => {\n this.opts.logger.error(`Relay tunnel: reconnect failed: ${err}`);\n });\n }\n }, delayMs);\n }\n}\n","import createWebSocketStream from './lib/stream.js';\nimport Receiver from './lib/receiver.js';\nimport Sender from './lib/sender.js';\nimport WebSocket from './lib/websocket.js';\nimport WebSocketServer from './lib/websocket-server.js';\n\nexport { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };\nexport default WebSocket;\n","import { randomUUID } from \"node:crypto\";\nimport WebSocket from \"ws\";\nimport type { RelayClient } from \"./relay-client.js\";\nimport type { ReqFrame, InboundFrame } from \"./types.js\";\nimport { previewText } from \"./utils.js\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\nimport {\n type DeviceIdentity,\n resolveClientStateDir,\n loadOrCreateDeviceIdentity,\n loadDeviceAuthToken,\n storeDeviceAuthToken,\n clearDeviceAuthToken,\n buildDeviceAuthPayload,\n signDevicePayload,\n publicKeyRawBase64UrlFromPem,\n} from \"./device-identity.js\";\nimport { handleHttpRequest } from \"./http-proxy.js\";\nimport { WsProxy } from \"./ws-proxy.js\";\n\n// ─── Types ───\n\ninterface ProxyOptions {\n stateDir?: string;\n hostStateDir?: string;\n gatewayBaseUrl: string;\n /** Gateway 鉴权模式 */\n gatewayAuthMode?: \"token\" | \"password\";\n /** Gateway 鉴权 token,代理请求到本地 gateway 时使用 */\n gatewayToken?: string;\n /** Gateway 鉴权密码,代理请求到本地 gateway 时使用 */\n gatewayPassword?: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nconst MAX_AUTO_PAIRING_APPROVALS = 3;\ntype ApproveDevicePairingFn = (\n requestId: string,\n hostStateDir?: string,\n) => Promise<unknown>;\n\nlet approveDevicePairingPromise: Promise<ApproveDevicePairingFn | null> | null =\n null;\nlet approveDevicePairingWarned = false;\n\nfunction formatErrorMessage(err: unknown): string {\n if (err instanceof Error && err.message) return err.message;\n return String(err);\n}\n\nasync function loadApproveDevicePairing(\n logger: ProxyOptions[\"logger\"],\n): Promise<ApproveDevicePairingFn | null> {\n if (!approveDevicePairingPromise) {\n approveDevicePairingPromise = import(\"openclaw/plugin-sdk/device-bootstrap\")\n .then((mod) =>\n typeof mod.approveDevicePairing === \"function\"\n ? (mod.approveDevicePairing as ApproveDevicePairingFn)\n : null,\n )\n .catch((err: unknown) => {\n if (!approveDevicePairingWarned) {\n approveDevicePairingWarned = true;\n logger.warn(\n `TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK (${formatErrorMessage(err)})`,\n );\n }\n return null;\n });\n }\n\n const approveDevicePairing = await approveDevicePairingPromise;\n if (!approveDevicePairing && !approveDevicePairingWarned) {\n approveDevicePairingWarned = true;\n logger.warn(\n \"TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK\",\n );\n }\n return approveDevicePairing;\n}\n\n/**\n * 透明代理:接收 Relay 转发的请求帧,代理到本地 gateway,回传响应帧。\n * 支持 HTTP 请求代理和 WebSocket 连接代理。\n */\nexport class TunnelProxy {\n /** 到本地 Gateway 的持久 RPC WebSocket 连接 */\n private gatewayWs: WebSocket | null = null;\n private gatewayWsConnecting = false;\n /** 握手是否已完成(收到 hello-ok) */\n private gatewayWsReady = false;\n /** 收到本地自动配对成功后,在 close 回调里触发重连 */\n private gatewayWsReconnectRequested = false;\n /** 防止配对失败时无限重连 */\n private gatewayWsAutoPairingApprovals = 0;\n /** 等待 Gateway WS 握手完成后发送的帧队列 */\n private gatewayWsPending: string[] = [];\n\n /** 设备身份,用于 Gateway connect 握手 */\n private deviceIdentity: DeviceIdentity;\n\n private readonly stateDir: string;\n private readonly hostStateDir: string;\n private readonly wsProxy: WsProxy;\n\n constructor(private readonly opts: ProxyOptions) {\n this.stateDir = resolveClientStateDir(opts.stateDir);\n this.hostStateDir = opts.hostStateDir ?? resolveHostStateDir();\n this.deviceIdentity = loadOrCreateDeviceIdentity(this.stateDir);\n opts.logger.info(\n `TunnelProxy: loaded device identity (deviceId=${this.deviceIdentity.deviceId})`,\n );\n this.wsProxy = new WsProxy({\n gatewayBaseUrl: opts.gatewayBaseUrl,\n client: opts.client,\n logger: opts.logger,\n });\n }\n\n // ─── Frame dispatcher ───\n\n /** 处理从 Relay 收到的入站帧 */\n async handleFrame(frame: InboundFrame): Promise<void> {\n this.opts.logger.info(\n `TunnelProxy: handling frame type=${frame.type}, id=${\"id\" in frame ? frame.id : \"N/A\"}`,\n );\n switch (frame.type) {\n case \"request\":\n await handleHttpRequest(this.opts, frame);\n break;\n case \"req\":\n this.handleReqFrame(frame);\n break;\n case \"ws_open\":\n this.wsProxy.handleWsOpen(frame);\n break;\n case \"ws_data\":\n this.wsProxy.handleWsData(frame);\n break;\n case \"ws_close\":\n this.wsProxy.handleWsClose(frame);\n break;\n default:\n this.opts.logger.warn(\n `TunnelProxy: unknown frame type=\"${(frame as any).type}\", id=${\"id\" in frame ? (frame as any).id : \"N/A\"}, forwarding raw to gateway`,\n );\n // 未知帧类型也尝试通过 RPC WS 转发,避免静默丢弃\n this.forwardRawToGateway(JSON.stringify(frame));\n break;\n }\n }\n\n /** 清理所有代理的 WebSocket 连接 */\n cleanup(): void {\n this.opts.logger.info(\n `TunnelProxy: cleanup, closing ${this.wsProxy.activeCount} active WS connections, gatewayWs=${!!this.gatewayWs}`,\n );\n this.wsProxy.cleanup();\n\n if (this.gatewayWs) {\n try {\n this.gatewayWs.close();\n } catch {\n // ignore\n }\n this.gatewayWs = null;\n }\n this.gatewayWsReady = false;\n this.gatewayWsConnecting = false;\n this.gatewayWsReconnectRequested = false;\n this.gatewayWsAutoPairingApprovals = 0;\n this.gatewayWsPending = [];\n }\n\n // ─── Gateway RPC WebSocket ───\n\n private pushGatewayPending(payload: string, reason: string): void {\n this.gatewayWsPending.push(payload);\n this.opts.logger.info(\n `TunnelProxy: gateway WS pending queue size=${this.gatewayWsPending.length} (${reason})`,\n );\n }\n\n /** 将未知帧原样转发到 Gateway WS */\n private forwardRawToGateway(payload: string): void {\n this.ensureGatewayWs();\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN) {\n this.gatewayWs.send(payload);\n } else {\n this.pushGatewayPending(payload, \"raw frame queued before gateway WS ready\");\n }\n }\n\n /** 处理 Relay 转发的 Gateway RPC 请求帧,原样通过 WebSocket 发给本地 Gateway */\n private handleReqFrame(frame: ReqFrame): void {\n const payload = JSON.stringify(frame);\n this.opts.logger.info(\n `TunnelProxy: req id=${frame.id} method=${frame.method} → gateway WS (${payload.length} chars)`,\n );\n\n this.ensureGatewayWs();\n\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN) {\n this.gatewayWs.send(payload);\n } else {\n this.opts.logger.info(\n `TunnelProxy: req id=${frame.id} queued, gateway WS not ready yet`,\n );\n this.pushGatewayPending(\n payload,\n `req id=${frame.id} queued before gateway WS handshake`,\n );\n }\n }\n\n // ─── Gateway connect auth helpers ───\n\n private resolveGatewayConnectAuth():\n | { token?: string; password?: string }\n | undefined {\n const token = this.opts.gatewayToken?.trim() || undefined;\n const password = this.opts.gatewayPassword?.trim() || undefined;\n if (!token && !password) return undefined;\n return { token, password };\n }\n\n private loadStoredDeviceToken(role: string): string | undefined {\n return (\n loadDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role,\n })?.token ?? undefined\n );\n }\n\n private buildGatewayConnectAuth(role: string): {\n auth?: { token?: string; deviceToken?: string; password?: string };\n authToken?: string;\n authPassword?: string;\n deviceToken?: string;\n } {\n const explicitAuth = this.resolveGatewayConnectAuth();\n const authPassword = explicitAuth?.password?.trim() || undefined;\n const explicitGatewayToken = explicitAuth?.token?.trim() || undefined;\n const deviceToken = explicitGatewayToken\n ? undefined\n : this.loadStoredDeviceToken(role);\n const authToken = explicitGatewayToken ?? deviceToken;\n const auth =\n authToken || authPassword || deviceToken\n ? { token: authToken, deviceToken, password: authPassword }\n : undefined;\n return { auth, authToken, authPassword, deviceToken };\n }\n\n private storeIssuedDeviceToken(params: {\n fallbackRole: string;\n fallbackScopes: string[];\n authInfo: any;\n }): void {\n const token = params.authInfo?.deviceToken;\n if (typeof token !== \"string\" || !token.trim()) return;\n const role =\n typeof params.authInfo?.role === \"string\" && params.authInfo.role.trim()\n ? params.authInfo.role.trim()\n : params.fallbackRole;\n const scopes = Array.isArray(params.authInfo?.scopes)\n ? params.authInfo.scopes.filter(\n (scope: unknown): scope is string =>\n typeof scope === \"string\" && !!scope.trim(),\n )\n : params.fallbackScopes;\n storeDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role,\n token: token.trim(),\n scopes,\n });\n }\n\n private maybeClearStoredDeviceTokenOnMismatch(code: number, reason: string): void {\n const explicitAuth = this.resolveGatewayConnectAuth();\n if (explicitAuth?.token || explicitAuth?.password) return;\n if (code !== 1008 || !reason.toLowerCase().includes(\"device token mismatch\")) return;\n clearDeviceAuthToken({\n stateDir: this.stateDir,\n deviceId: this.deviceIdentity.deviceId,\n role: \"operator\",\n });\n this.opts.logger.warn(\n `TunnelProxy: cleared stale stored device token after gateway mismatch (deviceId=${this.deviceIdentity.deviceId})`,\n );\n }\n\n private async maybeAutoApproveGatewayPairing(frame: any): Promise<boolean> {\n const errorCode =\n typeof frame?.error?.code === \"string\" ? frame.error.code : undefined;\n const detailsCode =\n typeof frame?.error?.details?.code === \"string\"\n ? frame.error.details.code\n : undefined;\n if (errorCode !== \"NOT_PAIRED\" && detailsCode !== \"PAIRING_REQUIRED\") {\n return false;\n }\n\n const requestId =\n typeof frame?.error?.details?.requestId === \"string\"\n ? frame.error.details.requestId.trim()\n : \"\";\n const reason =\n typeof frame?.error?.details?.reason === \"string\"\n ? frame.error.details.reason.trim()\n : \"\";\n\n if (!requestId) {\n this.opts.logger.warn(\n \"TunnelProxy: gateway pairing required but requestId missing; unable to auto-approve\",\n );\n return false;\n }\n\n if (\n reason &&\n reason !== \"not-paired\" &&\n reason !== \"scope-upgrade\"\n ) {\n this.opts.logger.warn(\n `TunnelProxy: gateway pairing required with unsupported reason=${reason}; skipping auto-approve`,\n );\n return false;\n }\n\n if (this.gatewayWsAutoPairingApprovals >= MAX_AUTO_PAIRING_APPROVALS) {\n this.opts.logger.warn(\n `TunnelProxy: reached auto-pairing retry limit (${MAX_AUTO_PAIRING_APPROVALS}); requestId=${requestId}`,\n );\n return false;\n }\n\n try {\n const approveDevicePairing = await loadApproveDevicePairing(this.opts.logger);\n if (!approveDevicePairing) {\n return false;\n }\n const approved = await approveDevicePairing(requestId, this.hostStateDir);\n if (!approved) {\n this.opts.logger.warn(\n `TunnelProxy: gateway pairing request ${requestId} not found in host state ${this.hostStateDir}`,\n );\n return false;\n }\n this.gatewayWsAutoPairingApprovals += 1;\n this.gatewayWsReconnectRequested = true;\n this.opts.logger.info(\n `TunnelProxy: auto-approved local gateway pairing request ${requestId} (reason=${reason || \"not-paired\"}, hostStateDir=${this.hostStateDir}, approval=${this.gatewayWsAutoPairingApprovals}/${MAX_AUTO_PAIRING_APPROVALS})`,\n );\n return true;\n } catch (err: any) {\n this.opts.logger.warn(\n `TunnelProxy: failed to auto-approve gateway pairing request ${requestId}: ${err?.message ?? String(err)}`,\n );\n return false;\n }\n }\n\n // ─── Gateway RPC WebSocket lifecycle ───\n\n /** 确保到本地 Gateway 的 RPC WebSocket 已连接且握手完成 */\n private ensureGatewayWs(): void {\n if (this.gatewayWsReady && this.gatewayWs?.readyState === WebSocket.OPEN)\n return;\n if (this.gatewayWsConnecting) return;\n\n this.gatewayWsConnecting = true;\n this.gatewayWsReady = false;\n const wsUrl = this.opts.gatewayBaseUrl.replace(/^http/, \"ws\");\n\n this.opts.logger.info(\n `TunnelProxy: RPC WS connecting to gateway ${wsUrl} (pending=${this.gatewayWsPending.length})`,\n );\n\n const ws = new WebSocket(wsUrl);\n\n ws.on(\"open\", () => {\n this.gatewayWs = ws;\n this.opts.logger.info(\n `TunnelProxy: RPC WS tcp connected, waiting for connect.challenge (pending=${this.gatewayWsPending.length})`,\n );\n });\n\n ws.on(\"message\", async (data: WebSocket.RawData) => {\n let text: string;\n if (typeof data === \"string\") {\n text = data;\n } else if (Buffer.isBuffer(data)) {\n text = data.toString();\n } else {\n text = Buffer.from(data as ArrayBuffer).toString();\n }\n\n const preview = text.length <= 500 ? text : text.substring(0, 500) + \"…\";\n this.opts.logger.info(\n `TunnelProxy: RPC WS ← gateway (${text.length} chars): ${preview}`,\n );\n\n let frame: any;\n try {\n frame = JSON.parse(text);\n } catch {\n this.opts.logger.warn(\n \"TunnelProxy: RPC WS received non-JSON, ignoring\",\n );\n return;\n }\n\n // 1) 收到 connect.challenge → 回复 connect 请求(带设备身份签名)\n if (frame.type === \"event\" && frame.event === \"connect.challenge\") {\n this.handleConnectChallenge(ws, frame);\n return;\n }\n\n // 2) 收到 connect 的 hello-ok 响应 → 握手完成,flush 待发帧\n if (\n frame.type === \"res\" &&\n frame.ok === true &&\n frame.payload?.type === \"hello-ok\"\n ) {\n this.storeIssuedDeviceToken({\n fallbackRole: \"operator\",\n fallbackScopes: [\"operator.admin\"],\n authInfo: frame.payload?.auth,\n });\n this.gatewayWsAutoPairingApprovals = 0;\n this.gatewayWsReconnectRequested = false;\n this.gatewayWsReady = true;\n this.gatewayWsConnecting = false;\n this.opts.logger.info(\n `TunnelProxy: RPC WS handshake done (hello-ok), flushing ${this.gatewayWsPending.length} pending frames`,\n );\n for (const pending of this.gatewayWsPending) {\n ws.send(pending);\n }\n this.gatewayWsPending = [];\n return;\n }\n\n // 3) 收到 connect 失败响应 → 关闭连接\n if (frame.type === \"res\" && frame.ok === false && !this.gatewayWsReady) {\n const autoApproved = await this.maybeAutoApproveGatewayPairing(frame);\n if (autoApproved) {\n const wsAlreadyClosed =\n ws.readyState === WebSocket.CLOSING ||\n ws.readyState === WebSocket.CLOSED ||\n this.gatewayWs !== ws;\n this.opts.logger.info(\n `TunnelProxy: RPC WS handshake requested local pairing approval, reconnecting${wsAlreadyClosed ? \" immediately\" : \" after close\"} (pending=${this.gatewayWsPending.length})`,\n );\n if (wsAlreadyClosed) {\n this.gatewayWsReconnectRequested = false;\n this.ensureGatewayWs();\n return;\n }\n ws.close(1000, \"pairing approved, reconnecting\");\n return;\n }\n this.opts.logger.error(\n `TunnelProxy: RPC WS handshake failed (pending=${this.gatewayWsPending.length}): ${previewText(JSON.stringify(frame.error), 500)}`,\n );\n ws.close();\n return;\n }\n\n // 4) 握手后的普通消息 → 透传回 Relay\n this.opts.client.sendRaw(text);\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n const wasReady = this.gatewayWsReady;\n const pendingCount = this.gatewayWsPending.length;\n const reasonText = reason.toString();\n const shouldReconnect =\n this.gatewayWsReconnectRequested && pendingCount > 0;\n this.opts.logger.info(\n `TunnelProxy: RPC WS closed by gateway (code=${code}, reason=${reasonText}, ready=${wasReady}, pending=${pendingCount}, activeWs=${this.wsProxy.activeCount})`,\n );\n if (this.gatewayWs === ws) {\n this.gatewayWs = null;\n this.gatewayWsReady = false;\n }\n this.gatewayWsConnecting = false;\n this.maybeClearStoredDeviceTokenOnMismatch(code, reasonText);\n if (shouldReconnect) {\n this.gatewayWsReconnectRequested = false;\n this.opts.logger.info(\n `TunnelProxy: retrying RPC WS after local pairing approval (pending=${this.gatewayWsPending.length})`,\n );\n queueMicrotask(() => this.ensureGatewayWs());\n }\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.warn(\n `TunnelProxy: RPC WS error: ${err.message} (ready=${this.gatewayWsReady}, pending=${this.gatewayWsPending.length}, activeWs=${this.wsProxy.activeCount})`,\n );\n this.gatewayWsConnecting = false;\n if (this.gatewayWs === ws) {\n this.gatewayWs = null;\n this.gatewayWsReady = false;\n }\n });\n }\n\n private handleConnectChallenge(ws: WebSocket, frame: any): void {\n const challengeNonce: string = frame.payload?.nonce ?? \"\";\n const connectRequestId = `tunnel-connect-${randomUUID()}`;\n const role = \"operator\";\n const scopes = [\"operator.admin\"];\n const gatewayConnectAuth = this.buildGatewayConnectAuth(role);\n this.opts.logger.info(\n `TunnelProxy: received connect.challenge (nonce=${challengeNonce}, connectReqId=${connectRequestId}, hasToken=${!!gatewayConnectAuth.authToken}, hasPassword=${!!gatewayConnectAuth.authPassword}, hasDeviceToken=${!!gatewayConnectAuth.deviceToken}), sending connect request with device identity`,\n );\n\n const signedAtMs = Date.now();\n const clientId = \"gateway-client\";\n const clientMode = \"backend\";\n\n const authPayload = buildDeviceAuthPayload({\n deviceId: this.deviceIdentity.deviceId,\n clientId,\n clientMode,\n role,\n scopes,\n signedAtMs,\n token: gatewayConnectAuth.authToken ?? null,\n nonce: challengeNonce,\n });\n const signature = signDevicePayload(\n this.deviceIdentity.privateKeyPem,\n authPayload,\n );\n\n const connectReq = {\n type: \"req\",\n id: connectRequestId,\n method: \"connect\",\n params: {\n minProtocol: 3,\n maxProtocol: 3,\n client: {\n id: clientId,\n version: \"1.0.0\",\n platform: process.platform,\n mode: clientMode,\n },\n role,\n scopes,\n ...(gatewayConnectAuth.auth ? { auth: gatewayConnectAuth.auth } : {}),\n device: {\n id: this.deviceIdentity.deviceId,\n publicKey: publicKeyRawBase64UrlFromPem(\n this.deviceIdentity.publicKeyPem,\n ),\n signature,\n signedAt: signedAtMs,\n nonce: challengeNonce,\n },\n },\n };\n ws.send(JSON.stringify(connectReq));\n }\n}\n","export function previewText(text: string | undefined, max = 200): string {\n if (!text) return \"\";\n return text.length <= max ? text : `${text.substring(0, max)}…`;\n}\n\nexport function findHeaderValue(\n headers: Record<string, string> | undefined,\n key: string,\n): string | undefined {\n if (!headers) return undefined;\n const lowerKey = key.toLowerCase();\n for (const [headerKey, headerValue] of Object.entries(headers)) {\n if (headerKey.toLowerCase() === lowerKey) {\n return headerValue;\n }\n }\n return undefined;\n}\n\nexport function summarizeRequestHeaders(headers: Record<string, string> | undefined): string {\n const contentType = findHeaderValue(headers, \"content-type\");\n const requestId = findHeaderValue(headers, \"x-request-id\");\n const parts: string[] = [];\n if (contentType) {\n parts.push(`contentType=${contentType}`);\n }\n if (requestId) {\n parts.push(`xRequestId=${previewText(requestId, 120)}`);\n }\n return parts.length ? `, ${parts.join(\", \")}` : \"\";\n}\n","import crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { resolveStateDir as resolveHostStateDir } from \"../host.js\";\n\n// ─── Types ───\n\nexport interface DeviceIdentity {\n deviceId: string;\n publicKeyPem: string;\n privateKeyPem: string;\n}\n\nexport interface DeviceAuthEntry {\n token: string;\n role: string;\n scopes: string[];\n updatedAtMs: number;\n}\n\ninterface DeviceAuthStore {\n version: 1;\n deviceId: string;\n tokens: Record<string, DeviceAuthEntry>;\n}\n\n// ─── Crypto helpers ───\n\nconst ED25519_SPKI_PREFIX = Buffer.from(\"302a300506032b6570032100\", \"hex\");\n\nexport function base64UrlEncode(buf: Buffer): string {\n return buf\n .toString(\"base64\")\n .replaceAll(\"+\", \"-\")\n .replaceAll(\"/\", \"_\")\n .replace(/=+$/g, \"\");\n}\n\nexport function derivePublicKeyRaw(publicKeyPem: string): Buffer {\n const spki = crypto.createPublicKey(publicKeyPem).export({\n type: \"spki\",\n format: \"der\",\n });\n if (\n spki.length === ED25519_SPKI_PREFIX.length + 32 &&\n spki.subarray(0, ED25519_SPKI_PREFIX.length).equals(ED25519_SPKI_PREFIX)\n )\n return spki.subarray(ED25519_SPKI_PREFIX.length);\n return spki;\n}\n\nexport function fingerprintPublicKey(publicKeyPem: string): string {\n const raw = derivePublicKeyRaw(publicKeyPem);\n return crypto.createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\nexport function publicKeyRawBase64UrlFromPem(publicKeyPem: string): string {\n return base64UrlEncode(derivePublicKeyRaw(publicKeyPem));\n}\n\nexport function signDevicePayload(privateKeyPem: string, payload: string): string {\n const key = crypto.createPrivateKey(privateKeyPem);\n return base64UrlEncode(crypto.sign(null, Buffer.from(payload, \"utf8\"), key));\n}\n\nexport function buildDeviceAuthPayload(params: {\n deviceId: string;\n clientId: string;\n clientMode: string;\n role: string;\n scopes: string[];\n signedAtMs: number;\n token: string | null;\n nonce: string;\n}): string {\n const scopes = params.scopes.join(\",\");\n const token = params.token ?? \"\";\n return [\n \"v2\",\n params.deviceId,\n params.clientId,\n params.clientMode,\n params.role,\n scopes,\n String(params.signedAtMs),\n token,\n params.nonce,\n ].join(\"|\");\n}\n\n// ─── File I/O helpers ───\n\nexport function resolveClientStateDir(stateDir: string | undefined): string {\n return stateDir ?? resolveHostStateDir();\n}\n\nfunction ensureDir(filePath: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n}\n\nfunction resolveIdentityPath(stateDir: string): string {\n return path.join(stateDir, \"identity\", \"device.json\");\n}\n\nfunction normalizeDeviceAuthRole(role: string): string {\n return role.trim();\n}\n\nfunction normalizeDeviceAuthScopes(scopes: string[]): string[] {\n const out = new Set<string>();\n for (const scope of scopes) {\n const trimmed = scope.trim();\n if (trimmed) {\n out.add(trimmed);\n }\n }\n return [...out].sort();\n}\n\nfunction resolveDeviceAuthPath(stateDir: string): string {\n return path.join(stateDir, \"identity\", \"device-auth.json\");\n}\n\nfunction readDeviceAuthStore(filePath: string): DeviceAuthStore | null {\n try {\n if (!fs.existsSync(filePath)) return null;\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed?.version !== 1 || typeof parsed.deviceId !== \"string\") return null;\n if (!parsed.tokens || typeof parsed.tokens !== \"object\") return null;\n return parsed as DeviceAuthStore;\n } catch {\n return null;\n }\n}\n\nfunction writeDeviceAuthStore(filePath: string, store: DeviceAuthStore): void {\n ensureDir(filePath);\n fs.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}\\n`, {\n mode: 0o600,\n });\n try {\n fs.chmodSync(filePath, 0o600);\n } catch {\n // ignore chmod errors on unsupported filesystems\n }\n}\n\n// ─── Token CRUD ───\n\nexport function loadDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n}): DeviceAuthEntry | null {\n const store = readDeviceAuthStore(resolveDeviceAuthPath(params.stateDir));\n if (!store || store.deviceId !== params.deviceId) return null;\n const entry = store.tokens[normalizeDeviceAuthRole(params.role)];\n if (!entry || typeof entry.token !== \"string\") return null;\n return entry;\n}\n\nexport function storeDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n token: string;\n scopes: string[];\n}): DeviceAuthEntry {\n const filePath = resolveDeviceAuthPath(params.stateDir);\n const existing = readDeviceAuthStore(filePath);\n const role = normalizeDeviceAuthRole(params.role);\n const next: DeviceAuthStore = {\n version: 1,\n deviceId: params.deviceId,\n tokens:\n existing && existing.deviceId === params.deviceId && existing.tokens\n ? { ...existing.tokens }\n : {},\n };\n const entry: DeviceAuthEntry = {\n token: params.token,\n role,\n scopes: normalizeDeviceAuthScopes(params.scopes),\n updatedAtMs: Date.now(),\n };\n next.tokens[role] = entry;\n writeDeviceAuthStore(filePath, next);\n return entry;\n}\n\nexport function clearDeviceAuthToken(params: {\n stateDir: string;\n deviceId: string;\n role: string;\n}): void {\n const filePath = resolveDeviceAuthPath(params.stateDir);\n const store = readDeviceAuthStore(filePath);\n if (!store || store.deviceId !== params.deviceId) return;\n const role = normalizeDeviceAuthRole(params.role);\n if (!store.tokens[role]) return;\n const next: DeviceAuthStore = {\n version: 1,\n deviceId: store.deviceId,\n tokens: { ...store.tokens },\n };\n delete next.tokens[role];\n writeDeviceAuthStore(filePath, next);\n}\n\n// ─── Identity lifecycle ───\n\nexport function loadOrCreateDeviceIdentity(stateDir: string): DeviceIdentity {\n const filePath = resolveIdentityPath(stateDir);\n try {\n if (fs.existsSync(filePath)) {\n const raw = fs.readFileSync(filePath, \"utf8\");\n const parsed = JSON.parse(raw);\n if (\n parsed?.version === 1 &&\n typeof parsed.deviceId === \"string\" &&\n typeof parsed.publicKeyPem === \"string\" &&\n typeof parsed.privateKeyPem === \"string\"\n ) {\n const derivedId = fingerprintPublicKey(parsed.publicKeyPem);\n return {\n deviceId: derivedId,\n publicKeyPem: parsed.publicKeyPem,\n privateKeyPem: parsed.privateKeyPem,\n };\n }\n }\n } catch {\n // fall through to generate\n }\n // Generate new identity\n const { publicKey, privateKey } = crypto.generateKeyPairSync(\"ed25519\");\n const publicKeyPem = publicKey\n .export({ type: \"spki\", format: \"pem\" })\n .toString();\n const privateKeyPem = privateKey\n .export({ type: \"pkcs8\", format: \"pem\" })\n .toString();\n const identity: DeviceIdentity = {\n deviceId: fingerprintPublicKey(publicKeyPem),\n publicKeyPem,\n privateKeyPem,\n };\n fs.mkdirSync(path.dirname(filePath), { recursive: true });\n const stored = {\n version: 1,\n ...identity,\n createdAtMs: Date.now(),\n };\n ensureDir(filePath);\n fs.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}\\n`, {\n mode: 0o600,\n });\n return identity;\n}\n","import type { RelayClient } from \"./relay-client.js\";\nimport type { RequestFrame } from \"./types.js\";\nimport { previewText, summarizeRequestHeaders } from \"./utils.js\";\n\nexport const RELAY_INTERNAL_HTTP_HEADER = \"x-openclaw-relay-internal\";\n\nexport interface HttpProxyOptions {\n gatewayBaseUrl: string;\n gatewayAuthMode?: \"token\" | \"password\";\n gatewayToken?: string;\n gatewayPassword?: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\n// ─── 路径映射 ───\n\nconst PATH_MAP: Record<string, string> = {\n \"/api/message/messageBridge/send\": \"/notifications\",\n};\n\nexport function mapPath(p: string): string {\n return PATH_MAP[p] ?? p;\n}\n\n// ─── Auth helpers ───\n\nfunction resolveGatewayConnectAuth(opts: HttpProxyOptions):\n | { token?: string; password?: string }\n | undefined {\n const token = opts.gatewayToken?.trim() || undefined;\n const password = opts.gatewayPassword?.trim() || undefined;\n if (!token && !password) return undefined;\n return { token, password };\n}\n\nexport function buildLocalGatewayAuthAttempts(\n opts: HttpProxyOptions,\n baseHeaders: Record<string, string>,\n): Array<{ label: string; headers: Record<string, string> }> {\n const auth = resolveGatewayConnectAuth(opts);\n const attempts: Array<{ label: string; headers: Record<string, string> }> = [];\n const seen = new Set<string>();\n const authMode = opts.gatewayAuthMode;\n\n const addAttempt = (kind: \"token\" | \"password\", secret?: string): void => {\n if (!secret) return;\n\n const dedupeKey = `${kind}:${secret}`;\n if (seen.has(dedupeKey)) return;\n seen.add(dedupeKey);\n\n const headers = { ...baseHeaders };\n headers.authorization = `Bearer ${secret}`;\n\n if (kind === \"password\") {\n headers[\"x-openclaw-password\"] = secret;\n } else {\n delete headers[\"x-openclaw-password\"];\n }\n\n attempts.push({\n label: kind === \"token\" ? \"gateway-token\" : \"gateway-password\",\n headers,\n });\n };\n\n if (authMode === \"password\") {\n addAttempt(\"password\", auth?.password);\n addAttempt(\"token\", auth?.token);\n } else {\n addAttempt(\"token\", auth?.token);\n addAttempt(\"password\", auth?.password);\n }\n\n if (attempts.length === 0) {\n attempts.push({\n label: \"no-auth\",\n headers: { ...baseHeaders },\n });\n }\n\n return attempts;\n}\n\n// ─── HTTP request proxy ───\n\nexport async function handleHttpRequest(\n opts: HttpProxyOptions,\n frame: RequestFrame,\n): Promise<void> {\n const mappedPath = mapPath(frame.path);\n const url = new URL(mappedPath, opts.gatewayBaseUrl);\n const startedAtMs = Date.now();\n\n // 代理到本地 gateway 时,替换外部鉴权头为本地 gateway token/password。\n const localHeaders: Record<string, string> = {};\n for (const [k, v] of Object.entries(frame.headers ?? {})) {\n const lower = k.toLowerCase();\n if (lower !== \"authorization\" && lower !== \"x-openclaw-password\") {\n localHeaders[k] = v;\n }\n }\n localHeaders[RELAY_INTERNAL_HTTP_HEADER] = \"1\";\n\n const authAttempts = buildLocalGatewayAuthAttempts(opts, localHeaders);\n opts.logger.info(\n `TunnelProxy: HTTP id=${frame.id} ${frame.method} ${frame.path} → ${url.toString()}${summarizeRequestHeaders(frame.headers)}, authAttempts=${authAttempts.map((a) => a.label).join(\" -> \")}, body=${previewText(frame.body)}`,\n );\n\n try {\n for (let attemptIndex = 0; attemptIndex < authAttempts.length; attemptIndex++) {\n const attempt = authAttempts[attemptIndex];\n opts.logger.info(\n `TunnelProxy: HTTP id=${frame.id} attempt ${attemptIndex + 1}/${authAttempts.length} auth=${attempt.label}`,\n );\n const res = await fetch(url.toString(), {\n method: frame.method,\n headers: attempt.headers,\n body:\n frame.method !== \"GET\" && frame.method !== \"HEAD\"\n ? frame.body\n : undefined,\n });\n\n const hasFallback = attemptIndex < authAttempts.length - 1;\n if (res.status === 401 && hasFallback) {\n const body = await res.text();\n opts.logger.warn(\n `TunnelProxy: HTTP id=${frame.id} local gateway auth via ${attempt.label} returned 401 after ${Date.now() - startedAtMs}ms, retrying next credential${body ? `, body=${previewText(body)}` : \"\"}`,\n );\n continue;\n }\n\n await sendHttpResponse(opts, {\n frameId: frame.id,\n method: frame.method,\n path: mappedPath,\n authLabel: attempt.label,\n startedAtMs,\n res,\n });\n return;\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n opts.logger.error(\n `TunnelProxy: HTTP id=${frame.id} ${frame.method} ${mappedPath} failed after ${Date.now() - startedAtMs}ms: ${message}`,\n );\n opts.client.send({\n type: \"proxy_error\",\n id: frame.id,\n status: 502,\n message: `gateway unreachable: ${message}`,\n });\n }\n}\n\n// ─── Response helpers ───\n\nasync function sendHttpResponse(\n opts: HttpProxyOptions,\n params: {\n frameId: string;\n method: string;\n path: string;\n authLabel: string;\n startedAtMs: number;\n res: Response;\n },\n): Promise<void> {\n const { frameId, method, path, authLabel, startedAtMs, res } = params;\n const contentType = res.headers.get(\"content-type\") ?? \"\";\n const isStreaming = contentType.includes(\"text/event-stream\");\n const elapsedMs = Date.now() - startedAtMs;\n\n opts.logger.info(\n `TunnelProxy: HTTP id=${frameId} ${method} ${path} <= ${res.status} (${elapsedMs}ms, auth=${authLabel}, content-type=${contentType}, streaming=${isStreaming})`,\n );\n\n if (isStreaming && res.body) {\n await streamResponse(opts, frameId, res, startedAtMs);\n return;\n }\n\n const body = await res.text();\n opts.logger.info(\n `TunnelProxy: HTTP id=${frameId} response body=${previewText(body)}`,\n );\n const headers: Record<string, string> = {};\n res.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n opts.client.send({\n type: \"proxy_response\",\n id: frameId,\n status: res.status,\n headers,\n body,\n });\n}\n\nasync function streamResponse(\n opts: HttpProxyOptions,\n requestId: string,\n res: Response,\n startedAtMs: number,\n): Promise<void> {\n const reader = res.body!.getReader();\n const decoder = new TextDecoder();\n let chunkCount = 0;\n\n opts.logger.info(`TunnelProxy: stream start id=${requestId}`);\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n chunkCount++;\n const chunk = decoder.decode(value, { stream: true });\n opts.logger.info(\n `TunnelProxy: stream delta id=${requestId} chunk#${chunkCount} (${chunk.length} chars)`,\n );\n opts.client.send({\n type: \"stream\",\n id: requestId,\n state: \"delta\",\n data: chunk,\n });\n }\n\n opts.logger.info(\n `TunnelProxy: stream end id=${requestId}, total chunks=${chunkCount}, totalElapsedMs=${Date.now() - startedAtMs}`,\n );\n opts.client.send({\n type: \"stream\",\n id: requestId,\n state: \"end\",\n data: \"\",\n });\n } catch (err) {\n opts.logger.error(\n `TunnelProxy: stream error id=${requestId} after ${chunkCount} chunks and ${Date.now() - startedAtMs}ms: ${err instanceof Error ? err.message : String(err)}`,\n );\n opts.client.send({\n type: \"proxy_error\",\n id: requestId,\n status: 502,\n message: `stream error: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n}\n","import WebSocket from \"ws\";\nimport type { RelayClient } from \"./relay-client.js\";\nimport type { WsOpenFrame, WsDataFrame, WsCloseFrame } from \"./types.js\";\nimport { mapPath } from \"./http-proxy.js\";\n\nexport interface WsProxyOptions {\n gatewayBaseUrl: string;\n client: RelayClient;\n logger: {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n };\n}\n\nexport class WsProxy {\n /** 活跃的 WebSocket 代理连接,按帧 id 索引 */\n private connections = new Map<string, WebSocket>();\n\n constructor(private readonly opts: WsProxyOptions) {}\n\n get activeCount(): number {\n return this.connections.size;\n }\n\n cleanup(): void {\n for (const [id, ws] of this.connections) {\n this.opts.logger.info(`WsProxy: closing WS id=${id}`);\n try {\n ws.close();\n } catch {\n // ignore\n }\n }\n this.connections.clear();\n }\n\n handleWsOpen(frame: WsOpenFrame): void {\n const wsUrl =\n this.opts.gatewayBaseUrl.replace(/^http/, \"ws\") +\n mapPath(frame.path);\n this.opts.logger.info(\n `TunnelProxy: WS open id=${frame.id}, path=${frame.path} → ${wsUrl}`,\n );\n\n try {\n const ws = new WebSocket(wsUrl, {\n headers: frame.headers,\n });\n\n ws.on(\"open\", () => {\n this.connections.set(frame.id, ws);\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} connected to gateway, active=${this.connections.size}`,\n );\n this.opts.client.send({\n type: \"ws_opened\",\n id: frame.id,\n });\n });\n\n ws.on(\"message\", (data: WebSocket.RawData) => {\n const text =\n typeof data === \"string\"\n ? data\n : Buffer.isBuffer(data)\n ? data.toString()\n : String(data);\n\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} ← gateway data (${text.length} chars): ${text.substring(0, 200)}`,\n );\n this.opts.client.send({\n type: \"ws_data\",\n id: frame.id,\n data: text,\n });\n });\n\n ws.on(\"close\", (code: number, reason: Buffer) => {\n this.connections.delete(frame.id);\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} closed by gateway (code=${code}, reason=${reason.toString()}), active=${this.connections.size}`,\n );\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code,\n reason: reason.toString(),\n });\n });\n\n ws.on(\"error\", (err: Error) => {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} error: ${err.message}, active=${this.connections.size}`,\n );\n this.connections.delete(frame.id);\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code: 1011,\n reason: err.message,\n });\n });\n } catch (err) {\n this.opts.logger.error(\n `TunnelProxy: WS id=${frame.id} failed to connect: ${err instanceof Error ? err.message : String(err)}`,\n );\n this.opts.client.send({\n type: \"ws_close\",\n id: frame.id,\n code: 1011,\n reason: `failed to connect: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n }\n\n handleWsData(frame: WsDataFrame): void {\n const ws = this.connections.get(frame.id);\n if (ws?.readyState === WebSocket.OPEN) {\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} → gateway data (${frame.data.length} chars): ${frame.data.substring(0, 200)}`,\n );\n ws.send(frame.data);\n } else {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} data dropped, ws not open (exists=${!!ws}, readyState=${ws?.readyState ?? \"N/A\"})`,\n );\n }\n }\n\n handleWsClose(frame: WsCloseFrame): void {\n const ws = this.connections.get(frame.id);\n if (ws) {\n this.opts.logger.info(\n `TunnelProxy: WS id=${frame.id} close requested by relay (code=${frame.code ?? 1000}, reason=${frame.reason ?? \"\"})`,\n );\n this.connections.delete(frame.id);\n try {\n ws.close(frame.code ?? 1000, frame.reason ?? \"\");\n } catch {\n // ignore\n }\n } else {\n this.opts.logger.warn(\n `TunnelProxy: WS id=${frame.id} close requested but connection not found`,\n );\n }\n }\n}\n","import type { IncomingMessage } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\n\nexport type GatewayHandler = Parameters<OpenClawPluginApi[\"registerGatewayMethod\"]>[1];\n\nexport type GatewayMethodRegistrar = (\n method: string,\n handler: GatewayHandler,\n) => void;\n\nexport function readBody(req: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n req.on(\"end\", () => resolve(Buffer.concat(chunks).toString()));\n req.on(\"error\", reject);\n });\n}\n\nexport function trimToUndefined(value: unknown): string | undefined {\n if (typeof value !== \"string\") {\n return undefined;\n }\n\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport type { CronServiceLike } from \"../light-rules/evaluator-job.js\";\nimport {\n type NotificationIngestResult,\n NotificationStorage,\n} from \"../notification/storage.js\";\nimport { RELAY_INTERNAL_HTTP_HEADER } from \"../tunnel/http-proxy.js\";\nimport type { RelayTunnelService } from \"../tunnel/service.js\";\nimport type {\n HttpNotificationBody,\n NotificationPushParams,\n RawNotification,\n} from \"../types.js\";\nimport {\n readBody,\n type GatewayMethodRegistrar,\n} from \"./shared.js\";\n\nfunction createEmptyIngestResult(): NotificationIngestResult {\n return {\n received: 0,\n ingested: 0,\n dedupedById: 0,\n dedupedByContent: 0,\n invalid: 0,\n inserted: [],\n };\n}\n\nfunction isRelayInternalHttpRequest(req: IncomingMessage): boolean {\n const header = req.headers?.[RELAY_INTERNAL_HTTP_HEADER];\n if (Array.isArray(header)) {\n return header.includes(\"1\");\n }\n return header === \"1\";\n}\n\n/**\n * 将 ingest 内部结果转成对外响应:丢弃 `inserted` 字段,\n * 它只供插件内部下游链路(如 light-rule agent 评估)使用,\n * 不应该出现在 gateway / HTTP 响应里。\n */\nfunction toIngestResponse(\n result: NotificationIngestResult,\n): Omit<NotificationIngestResult, \"inserted\"> {\n const { inserted: _inserted, ...rest } = result;\n return rest;\n}\n\ninterface NotificationInterfaceDeps {\n api: OpenClawPluginApi;\n logger: Logger;\n getStorage: () => NotificationStorage | null;\n filterNotifications: (items: RawNotification[]) => RawNotification[];\n registerGatewayMethod: GatewayMethodRegistrar;\n tunnelService?: RelayTunnelService | null;\n /**\n * 通知落盘后的钩子,用于触发灯效规则评估。\n * gateway 路径优先使用本次 context.cron;HTTP 路径使用外部缓存的 cron service。\n */\n onAfterIngest?: (insertedCount: number, cron: CronServiceLike | null | undefined) => void;\n getCronForHttpIngest?: () => CronServiceLike | null | undefined;\n}\n\nexport function registerNotificationInterfaces(\n deps: NotificationInterfaceDeps,\n): void {\n const {\n api,\n logger,\n getStorage,\n filterNotifications,\n registerGatewayMethod,\n tunnelService,\n onAfterIngest,\n getCronForHttpIngest,\n } = deps;\n\n function triggerAfterIngest(\n insertedCount: number,\n cron: CronServiceLike | null | undefined,\n ): void {\n if (insertedCount <= 0 || !onAfterIngest) return;\n void Promise.resolve()\n .then(() => onAfterIngest(insertedCount, cron))\n .catch((err) => logger.warn(`onAfterIngest failed: ${err?.message ?? err}`));\n }\n\n registerGatewayMethod(\n \"notifications.push\",\n async ({ params, respond, context }) => {\n const storage = getStorage();\n if (!storage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Storage service not ready\",\n });\n return;\n }\n\n const { items } = params as unknown as NotificationPushParams;\n if (!Array.isArray(items)) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"items must be an array\",\n });\n return;\n }\n\n const filtered = filterNotifications(items);\n const result = filtered.length\n ? await storage.ingest(filtered)\n : createEmptyIngestResult();\n\n // 主响应先返回,不阻塞灯效评估\n respond(true, toIngestResponse(result));\n\n // 落盘后异步 force-trigger 灯效评估 job(fire-and-forget)\n triggerAfterIngest(result.inserted.length, context?.cron as CronServiceLike | undefined);\n },\n );\n\n api.registerHttpRoute({\n path: \"/notifications\",\n auth: \"gateway\",\n async handler(req: IncomingMessage, res: ServerResponse) {\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Method Not Allowed\" }));\n return;\n }\n\n if (!isRelayInternalHttpRequest(req)) {\n await tunnelService?.deactivateForExternalTunnel(\"POST /notifications\");\n }\n\n const storage = getStorage();\n if (!storage) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Service Not Ready\" }));\n return;\n }\n\n let body: HttpNotificationBody;\n try {\n const raw = await readBody(req);\n body = JSON.parse(raw);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Invalid JSON\" }));\n return;\n }\n\n if (!Array.isArray(body.notifications)) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"notifications must be an array\",\n }),\n );\n return;\n }\n\n const filtered = filterNotifications(body.notifications);\n const result = filtered.length\n ? await storage.ingest(filtered)\n : createEmptyIngestResult();\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, ...toIngestResponse(result) }));\n\n // Relay tunnel 会把手机通知转发到 HTTP 端点;这里也要触发事件驱动灯效评估。\n triggerAfterIngest(result.inserted.length, getCronForHttpIngest?.());\n },\n });\n\n logger.info(\"Gateway 通知方法已注册: notifications.push\");\n logger.info(\"HTTP 通知端点已注册: POST /notifications\");\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { OpenClawPluginApi } from \"openclaw/plugin-sdk\";\nimport type { Logger } from \"../logger.js\";\nimport {\n RecordingStorage,\n canStartTranscription,\n extractSourceTextListFromDocument,\n extractTranscriptTitleFromDocument,\n handleRecordingSync,\n initializeAsr,\n triggerTranscription,\n type RecordingIndexEntry,\n type RecordingStatusEvent,\n validateAsrConfig,\n} from \"../recording/index.js\";\nimport { RELAY_INTERNAL_HTTP_HEADER } from \"../tunnel/http-proxy.js\";\nimport type { RelayTunnelService } from \"../tunnel/service.js\";\nimport type {\n HttpRecordingBody,\n RecordingAsrInitParams,\n RecordingDetail,\n RecordingListItem,\n RecordingListParams,\n RecordingRenameParams,\n RecordingRetranscribeParams,\n RecordingStatusParams,\n RecordingSyncParams,\n RecordingTransferStatus,\n} from \"../types.js\";\nimport {\n readBody,\n trimToUndefined,\n type GatewayMethodRegistrar,\n} from \"./shared.js\";\n\nconst RECORDING_TRANSFER_STATUSES = new Set<RecordingTransferStatus>([\n \"receiving_failed\",\n \"receiving\",\n \"pending_oss_upload\",\n \"uploading_oss\",\n \"oss_uploaded\",\n \"syncing_openclaw\",\n \"synced\",\n \"transcribing\",\n \"transcribe_failed\",\n \"transcribed\",\n]);\n\nfunction isRecordingTransferStatus(\n value: string,\n): value is RecordingTransferStatus {\n return RECORDING_TRANSFER_STATUSES.has(value as RecordingTransferStatus);\n}\n\nfunction buildRecordingListItem(entry: RecordingIndexEntry): RecordingListItem {\n return {\n recordingId: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n created_at: entry.metadata.created_at,\n transfer_status: entry.status,\n marker_count: entry.metadata.markers?.length ?? 0,\n has_audio: !!entry.audioFile,\n has_srt: !!entry.srtFile,\n has_transcript: !!entry.transcriptFile,\n audioFile: entry.audioFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n updatedAt: entry.updatedAt,\n };\n}\n\nfunction isRelayInternalHttpRequest(req: IncomingMessage): boolean {\n const header = req.headers?.[RELAY_INTERNAL_HTTP_HEADER];\n if (Array.isArray(header)) {\n return header.includes(\"1\");\n }\n return header === \"1\";\n}\n\nfunction buildRecordingDetail(\n entry: RecordingIndexEntry,\n extras?: Partial<Pick<\n RecordingDetail,\n \"summary\" | \"title\" | \"transcript\" | \"transcriptData\"\n >>,\n): RecordingDetail {\n const title = entry.title?.trim()\n || extras?.title?.trim()\n || entry.metadata.name?.trim()\n || entry.id;\n\n return {\n recordingId: entry.id,\n name: entry.metadata.name,\n duration_sec: entry.metadata.duration_sec,\n file_size_bytes: entry.metadata.file_size_bytes,\n created_at: entry.metadata.created_at,\n location: entry.metadata.location,\n oss_audio_url: entry.metadata.oss_audio_url,\n oss_srt_url: entry.metadata.oss_srt_url,\n markers: entry.metadata.markers ?? [],\n transfer_status: entry.status,\n audioFile: entry.audioFile,\n srtFile: entry.srtFile,\n transcriptDataFile: entry.transcriptDataFile,\n transcriptFile: entry.transcriptFile,\n summaryFile: entry.summaryFile,\n title,\n summary: extras?.summary,\n transcript: extras?.transcript,\n transcriptData: extras?.transcriptData,\n ingestedAt: entry.ingestedAt,\n updatedAt: entry.updatedAt,\n };\n}\n\ninterface RecordingInterfaceDeps {\n api: OpenClawPluginApi;\n logger: Logger;\n asrDataDir: string;\n getRecordingStorage: () => RecordingStorage | null;\n notifyRecordingStatus: (event: RecordingStatusEvent) => void;\n registerGatewayMethod: GatewayMethodRegistrar;\n shouldBroadcastStatusOnHttp: () => boolean;\n tunnelService?: RelayTunnelService | null;\n}\n\nexport function registerRecordingInterfaces(\n deps: RecordingInterfaceDeps,\n): void {\n const {\n api,\n logger,\n asrDataDir,\n getRecordingStorage,\n notifyRecordingStatus,\n registerGatewayMethod,\n shouldBroadcastStatusOnHttp,\n tunnelService,\n } = deps;\n\n registerGatewayMethod(\"recordings.sync\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const {\n recordingId: rawRecordingId,\n recording,\n asr,\n } = params as unknown as RecordingSyncParams;\n const recordingId = trimToUndefined(rawRecordingId);\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n if (!recording || !recording.oss_audio_url || !recording.created_at) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recording with oss_audio_url and created_at is required\",\n });\n return;\n }\n\n const asrError = asr ? validateAsrConfig(asr) : undefined;\n if (asrError) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: asrError,\n });\n return;\n }\n\n const result = await handleRecordingSync(\n recordingId,\n recording,\n recordingStorage,\n asr,\n logger,\n { notifyStatus: notifyRecordingStatus },\n );\n respond(\n result.ok,\n result,\n result.ok\n ? undefined\n : {\n code: \"SYNC_FAILED\",\n message: result.error ?? \"Unknown error\",\n },\n );\n });\n\n registerGatewayMethod(\"recordings.list\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const rawStatus = trimToUndefined(\n (params as RecordingListParams | undefined)?.status,\n );\n if (rawStatus && !isRecordingTransferStatus(rawStatus)) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: `invalid recording status: ${rawStatus}`,\n });\n return;\n }\n\n const status = rawStatus as RecordingTransferStatus | undefined;\n const entries = status\n ? recordingStorage.listByStatus(status)\n : recordingStorage.listAll();\n\n respond(true, {\n total: entries.length,\n recordings: entries.map(buildRecordingListItem),\n });\n });\n\n registerGatewayMethod(\"recordings.status\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId } = params as unknown as RecordingStatusParams;\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n respond(\n true,\n (() => {\n const transcriptDocument =\n recordingStorage.readTranscriptDocument(recordingId);\n\n return buildRecordingDetail(entry, {\n summary: recordingStorage.readSummary(recordingId),\n title: extractTranscriptTitleFromDocument(transcriptDocument),\n transcript: extractSourceTextListFromDocument(transcriptDocument),\n transcriptData: transcriptDocument,\n });\n })(),\n );\n });\n\n registerGatewayMethod(\"recordings.rename\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId: rawRecordingId, name: rawName } =\n params as unknown as RecordingRenameParams;\n const recordingId = trimToUndefined(rawRecordingId);\n const name = trimToUndefined(rawName);\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n if (!name) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"name is required\",\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n const updated = recordingStorage.rename(recordingId, name);\n respond(true, buildRecordingDetail(updated));\n });\n\n registerGatewayMethod(\"recordings.delete\", async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId, deleteRemote } = params as {\n recordingId: string;\n deleteRemote?: boolean;\n };\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n if (deleteRemote) {\n const deleted = recordingStorage.delete(recordingId);\n respond(\n deleted,\n { ok: deleted, recordingId, deletedRemote: true },\n deleted\n ? undefined\n : {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n },\n );\n return;\n }\n\n const deleted = recordingStorage.delete(recordingId, {\n localOnly: true,\n });\n respond(\n deleted,\n { ok: deleted, recordingId, deletedRemote: false },\n deleted\n ? undefined\n : {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n },\n );\n });\n\n registerGatewayMethod(\n \"recordings.retranscribe\",\n async ({ params, respond }) => {\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n respond(false, null, {\n code: \"NOT_READY\",\n message: \"Recording storage service not ready\",\n });\n return;\n }\n\n const { recordingId, asr } =\n params as unknown as RecordingRetranscribeParams;\n if (!recordingId) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: \"recordingId is required\",\n });\n return;\n }\n\n const asrError = validateAsrConfig(asr);\n if (asrError) {\n respond(false, null, {\n code: \"ASR_NOT_CONFIGURED\",\n message: asrError,\n });\n return;\n }\n\n const entry = recordingStorage.findById(recordingId);\n if (!entry) {\n respond(false, null, {\n code: \"NOT_FOUND\",\n message: `Recording not found: ${recordingId}`,\n });\n return;\n }\n\n if (!canStartTranscription(entry.status)) {\n respond(false, null, {\n code: \"INVALID_STATE\",\n message: `Recording status does not allow retranscribe: ${entry.status}`,\n });\n return;\n }\n\n triggerTranscription(recordingId, recordingStorage, asr, logger, {\n notifyStatus: notifyRecordingStatus,\n }).catch((err) => {\n logger.error(\n `[recordings.retranscribe] 重试转写失败: ${recordingId}, ${err?.message ?? err}`,\n );\n });\n\n respond(true, { ok: true, recordingId, message: \"转写已重新触发\" });\n },\n );\n\n registerGatewayMethod(\"recordings.asr.init\", async ({ params, respond }) => {\n const { asr } = params as unknown as RecordingAsrInitParams;\n const asrError = validateAsrConfig(asr);\n if (asrError) {\n respond(false, null, {\n code: \"INVALID_PARAMS\",\n message: asrError,\n });\n return;\n }\n\n const result = await initializeAsr(asr, asrDataDir, logger);\n respond(\n result.ok,\n result,\n result.ok\n ? undefined\n : {\n code: \"ASR_INIT_FAILED\",\n message: result.error ?? \"ASR init failed\",\n },\n );\n });\n\n api.registerHttpRoute({\n path: \"/recordings\",\n auth: \"gateway\",\n async handler(req: IncomingMessage, res: ServerResponse) {\n if (req.method !== \"POST\") {\n res.writeHead(405, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Method Not Allowed\" }));\n return;\n }\n\n if (!isRelayInternalHttpRequest(req)) {\n await tunnelService?.deactivateForExternalTunnel(\"POST /recordings\");\n }\n\n const recordingStorage = getRecordingStorage();\n if (!recordingStorage) {\n res.writeHead(503, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Service Not Ready\" }));\n return;\n }\n\n let body: HttpRecordingBody;\n try {\n const raw = await readBody(req);\n body = JSON.parse(raw);\n } catch {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: \"Invalid JSON\" }));\n return;\n }\n\n const recordingId = trimToUndefined(body.recordingId);\n if (!recordingId) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"recordingId is required\",\n }),\n );\n return;\n }\n\n if (!body.recording || !body.recording.oss_audio_url) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n ok: false,\n error: \"recording with oss_audio_url is required\",\n }),\n );\n return;\n }\n\n const asrError = body.asr ? validateAsrConfig(body.asr) : undefined;\n if (asrError) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: false, error: asrError }));\n return;\n }\n\n const result = await handleRecordingSync(\n recordingId,\n body.recording,\n recordingStorage,\n body.asr,\n logger,\n shouldBroadcastStatusOnHttp()\n ? { notifyStatus: notifyRecordingStatus }\n : undefined,\n );\n\n res.writeHead(result.ok ? 200 : 500, {\n \"Content-Type\": \"application/json\",\n });\n res.end(JSON.stringify(result));\n },\n } as any);\n\n logger.info(\n \"Gateway 录音方法已注册: recordings.sync / recordings.list / recordings.status / recordings.rename / recordings.delete / recordings.retranscribe / recordings.asr.init\",\n );\n logger.info(\"HTTP 录音端点已注册: POST /recordings\");\n}\n","const PLUGIN_CLI_COMMANDS = new Set([\"ntf\", \"phone-notifications\"]);\nconst GLOBAL_OPTIONS_WITH_VALUE = [\n \"--container\",\n \"--log-level\",\n \"--profile\",\n] as const;\nconst GLOBAL_OPTIONS_WITH_VALUE_SET = new Set<string>(GLOBAL_OPTIONS_WITH_VALUE);\n\nfunction resolvePrimaryCommand(argv = process.argv): string | undefined {\n const args = argv.slice(2);\n\n for (let index = 0; index < args.length; index++) {\n const arg = args[index];\n if (!arg || arg === \"--\") {\n return undefined;\n }\n\n if (GLOBAL_OPTIONS_WITH_VALUE_SET.has(arg)) {\n index++;\n continue;\n }\n\n if (\n GLOBAL_OPTIONS_WITH_VALUE.some((option) => arg.startsWith(`${option}=`))\n ) {\n continue;\n }\n\n if (arg.startsWith(\"-\")) {\n continue;\n }\n\n return arg;\n }\n\n return undefined;\n}\n\nexport function isPluginCliInvocation(argv = process.argv): boolean {\n const primaryCommand = resolvePrimaryCommand(argv);\n return primaryCommand ? PLUGIN_CLI_COMMANDS.has(primaryCommand) : false;\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","path","import_node_fs","import_node_path","os","formatBytes","output","path","import_node_child_process","import_node_fs","import_node_path","import_promises","import_node_stream","import_node_os","getWhisperLocalStatus","downloadModel","resolveModelsDir","transcribeWithWhisperLocal","normalizeOptionalText","sleep","normalizeOptionalInteger","import_node_fs","import_node_path","exports","module","exports","module","output","exports","module","exports","module","data","exports","module","exports","module","Receiver","exports","module","Sender","exports","module","exports","module","exports","module","createHash","Readable","URL","Receiver","Sender","WebSocket","key","exports","module","WebSocket","createWebSocketStream","err","exports","module","protocol","exports","module","createHash","WebSocket","WebSocketServer","import_node_fs","import_node_fs","import_node_path","import_node_fs","import_node_path","formatDate","import_node_fs","import_node_path","import_node_fs","import_node_path","tasksDir","import_node_path","import_node_fs","path","import_node_fs","import_node_path","import_node_fs","import_node_path","tasksDir","readMeta","writeMeta","checkpointPath","import_node_crypto","import_node_fs","import_node_path","resolveConfigPath","import_node_fs","import_node_path","import_node_fs","import_node_path","import_node_fs","import_node_fs","isObject","isObject","import_node_fs","isObject","import_node_fs","import_node_path","STATUS_REL_PATH","isObject","import_node_readline","import_node_fs","import_node_fs","import_node_path","import_node_os","os","import_node_fs","import_node_fs","import_node_path","path","import_node_fs","import_node_path","import_node_fs","import_node_path","import_promises","import_node_fs","import_node_path","import_node_fs","import_node_path","import_sender","WebSocket","import_node_crypto","previewText","import_node_crypto","import_node_fs","import_node_path","crypto","fs","path","previewText","path","previewText","trimToUndefined","trimToUndefined","isRelayInternalHttpRequest","trimToUndefined","deleted"]}