@mingxy/ocosay 1.1.24 → 1.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.js CHANGED
@@ -2437,7 +2437,7 @@ var require_thread_stream = __commonJS({
2437
2437
  var require_transport = __commonJS({
2438
2438
  "node_modules/pino/lib/transport.js"(exports, module) {
2439
2439
  "use strict";
2440
- var { createRequire: createRequire2 } = __require("module");
2440
+ var { createRequire: createRequire3 } = __require("module");
2441
2441
  var { existsSync: existsSync8 } = __require("node:fs");
2442
2442
  var getCallers = require_caller();
2443
2443
  var { join: join9, isAbsolute, sep } = __require("node:path");
@@ -2640,7 +2640,7 @@ var require_transport = __commonJS({
2640
2640
  for (const filePath of callers) {
2641
2641
  try {
2642
2642
  const context = filePath === "node:repl" ? process.cwd() + sep : filePath;
2643
- fixTarget2 = createRequire2(context).resolve(origin);
2643
+ fixTarget2 = createRequire3(context).resolve(origin);
2644
2644
  break;
2645
2645
  } catch (err) {
2646
2646
  continue;
@@ -9901,14 +9901,365 @@ import { readFileSync as readFileSync2, existsSync as existsSync7, writeFileSync
9901
9901
  import { fileURLToPath } from "url";
9902
9902
  import { dirname as dirname2, join as join8 } from "path";
9903
9903
  import { homedir as homedir3 } from "os";
9904
+ import { execSync as execSync4 } from "child_process";
9905
+ import { createRequire as createRequire2 } from "module";
9906
+
9907
+ // src/core/dependency-detector.ts
9904
9908
  import { execSync as execSync2 } from "child_process";
9909
+ function parseMissingHeaders(errorOutput) {
9910
+ const pattern = /fatal error:\s+([^:]+):\s+No such file or directory/g;
9911
+ const headers = [];
9912
+ let match = pattern.exec(errorOutput);
9913
+ while (match !== null) {
9914
+ headers.push(match[1]);
9915
+ match = pattern.exec(errorOutput);
9916
+ }
9917
+ return headers;
9918
+ }
9919
+ function execCapture(cmd, cwd) {
9920
+ try {
9921
+ const stdout = execSync2(cmd, {
9922
+ cwd,
9923
+ encoding: "utf8",
9924
+ stdio: ["pipe", "pipe", "pipe"]
9925
+ });
9926
+ return { success: true, stdout, stderr: "" };
9927
+ } catch (err) {
9928
+ const error = err;
9929
+ return {
9930
+ success: false,
9931
+ stdout: error.stdout ? error.stdout.toString() : "",
9932
+ stderr: error.stderr ? error.stderr.toString() : ""
9933
+ };
9934
+ }
9935
+ }
9936
+ function detectMissingDependencies(cmd, cwd) {
9937
+ const result = execCapture(cmd, cwd);
9938
+ const missingHeaders = parseMissingHeaders(result.stderr);
9939
+ return {
9940
+ missingHeaders,
9941
+ rawOutput: result.stderr
9942
+ };
9943
+ }
9944
+
9945
+ // src/core/dependency-mapper.ts
9905
9946
  import { createRequire } from "module";
9906
- var logger8 = createModuleLogger("Plugin");
9907
9947
  var require2 = createRequire(import.meta.url);
9908
- var opencodeBinPath = execSync2("which opencode").toString().trim();
9948
+ var HEADER_TO_PACKAGE = [
9949
+ // ALSA - Linux音频库
9950
+ {
9951
+ header: "alsa/asoundlib.h",
9952
+ package: "libasound2-dev"
9953
+ },
9954
+ // PortAudio - 跨平台音频I/O库
9955
+ {
9956
+ header: "portaudio.h",
9957
+ package: "libportaudio-dev",
9958
+ packageMac: "portaudio",
9959
+ packageWin: "portaudio"
9960
+ },
9961
+ // FFmpeg相关
9962
+ {
9963
+ header: "libavcodec/avcodec.h",
9964
+ package: "libavcodec-dev",
9965
+ packageMac: "ffmpeg",
9966
+ packageWin: "ffmpeg"
9967
+ },
9968
+ {
9969
+ header: "libavformat/avformat.h",
9970
+ package: "libavformat-dev",
9971
+ packageMac: "ffmpeg",
9972
+ packageWin: "ffmpeg"
9973
+ },
9974
+ {
9975
+ header: "libavutil/avutil.h",
9976
+ package: "libavutil-dev",
9977
+ packageMac: "ffmpeg",
9978
+ packageWin: "ffmpeg"
9979
+ },
9980
+ {
9981
+ header: "libswresample/swresample.h",
9982
+ package: "libswresample-dev",
9983
+ packageMac: "ffmpeg",
9984
+ packageWin: "ffmpeg"
9985
+ },
9986
+ // OpenAL - 3D音频API
9987
+ {
9988
+ header: "AL/al.h",
9989
+ package: "libopenal-dev",
9990
+ packageMac: "openal",
9991
+ packageWin: "openal"
9992
+ },
9993
+ // SDL - 多媒体库
9994
+ {
9995
+ header: "SDL2/SDL.h",
9996
+ package: "libsdl2-dev",
9997
+ packageMac: "sdl2",
9998
+ packageWin: "sdl2"
9999
+ },
10000
+ // PulseAudio - Linux音频服务
10001
+ {
10002
+ header: "pulse/pulseaudio.h",
10003
+ package: "libpulse-dev"
10004
+ },
10005
+ // CoreAudio - macOS音频框架 (无头文件,纯框架)
10006
+ {
10007
+ header: "CoreAudio/CoreAudio.h",
10008
+ package: "\u81FA",
10009
+ // macOS系统框架,无需安装包
10010
+ packageMac: ""
10011
+ },
10012
+ // Windows特定
10013
+ {
10014
+ header: "windows.h",
10015
+ package: "",
10016
+ // Linux上不存在
10017
+ packageWin: ""
10018
+ // Windows SDK自带
10019
+ }
10020
+ ];
10021
+ function detectPlatform() {
10022
+ const platform = process.platform;
10023
+ const isWsl3 = detectWsl();
10024
+ let packageManager;
10025
+ let installCommand;
10026
+ if (platform === "linux" || isWsl3) {
10027
+ packageManager = "apt-get";
10028
+ installCommand = "sudo apt-get install -y";
10029
+ } else if (platform === "darwin") {
10030
+ packageManager = "brew";
10031
+ installCommand = "brew install";
10032
+ } else {
10033
+ packageManager = "choco";
10034
+ installCommand = "choco install -y";
10035
+ }
10036
+ return {
10037
+ platform,
10038
+ isWsl: isWsl3,
10039
+ packageManager,
10040
+ installCommand
10041
+ };
10042
+ }
10043
+ function detectWsl() {
10044
+ if (process.platform !== "linux") return false;
10045
+ try {
10046
+ return require2("fs").readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
10047
+ } catch {
10048
+ return false;
10049
+ }
10050
+ }
10051
+ function getPackageForPlatform(mapping, platform, isWsl3) {
10052
+ if (platform === "win32") {
10053
+ if (isWsl3) {
10054
+ return mapping.package || null;
10055
+ }
10056
+ return mapping.packageWin || mapping.package || null;
10057
+ }
10058
+ if (platform === "darwin") {
10059
+ if (mapping.packageMac === "") return null;
10060
+ return mapping.packageMac || mapping.package || null;
10061
+ }
10062
+ if (mapping.package === "") return null;
10063
+ return mapping.package || null;
10064
+ }
10065
+ function mapHeaderToPackages(header, platform) {
10066
+ const exactMatch = HEADER_TO_PACKAGE.find(
10067
+ (m) => m.header.toLowerCase() === header.toLowerCase()
10068
+ );
10069
+ if (exactMatch) {
10070
+ const pkg = getPackageForPlatform(exactMatch, platform, detectWsl());
10071
+ if (pkg && pkg.length > 0 && pkg !== "\u81FA") {
10072
+ return [pkg];
10073
+ }
10074
+ return [];
10075
+ }
10076
+ const headerBasename = header.split("/").pop()?.toLowerCase() || "";
10077
+ const fuzzyMatch = HEADER_TO_PACKAGE.find((m) => {
10078
+ const mappingBasename = m.header.split("/").pop()?.toLowerCase() || "";
10079
+ return mappingBasename === headerBasename;
10080
+ });
10081
+ if (fuzzyMatch) {
10082
+ const pkg = getPackageForPlatform(fuzzyMatch, platform, detectWsl());
10083
+ if (pkg && pkg.length > 0 && pkg !== "\u81FA") {
10084
+ return [pkg];
10085
+ }
10086
+ return [];
10087
+ }
10088
+ return [];
10089
+ }
10090
+ function mapHeadersToPackages(headers, platform) {
10091
+ const packageSet = /* @__PURE__ */ new Set();
10092
+ for (const header of headers) {
10093
+ const packages = mapHeaderToPackages(header, platform);
10094
+ for (const pkg of packages) {
10095
+ if (pkg.length > 0) {
10096
+ packageSet.add(pkg);
10097
+ }
10098
+ }
10099
+ }
10100
+ return Array.from(packageSet);
10101
+ }
10102
+
10103
+ // src/core/dependency-installer.ts
10104
+ import { execSync as execSync3 } from "child_process";
10105
+ var logger8 = createModuleLogger("DependencyInstaller");
10106
+ function getInstallCommandPrefix() {
10107
+ const { platform, isWsl: isWsl3 } = detectPlatform();
10108
+ if (platform === "linux" || isWsl3) {
10109
+ return "sudo apt-get install -y";
10110
+ } else if (platform === "darwin") {
10111
+ return "brew install";
10112
+ }
10113
+ return "choco install -y";
10114
+ }
10115
+ function getCheckCommand(packageName) {
10116
+ const { platform, isWsl: isWsl3 } = detectPlatform();
10117
+ if (platform === "linux" || isWsl3) {
10118
+ return `dpkg -s ${packageName} 2>/dev/null | grep -q "Status: install ok installed"`;
10119
+ } else if (platform === "darwin") {
10120
+ return `brew list ${packageName} &>/dev/null`;
10121
+ }
10122
+ return `choco list --local-only ${packageName} &>/dev/null`;
10123
+ }
10124
+ function silentLog(level2, message, extra) {
10125
+ switch (level2) {
10126
+ case "info":
10127
+ logger8.info(extra || {}, message);
10128
+ break;
10129
+ case "warn":
10130
+ logger8.warn(extra || {}, message);
10131
+ break;
10132
+ case "error":
10133
+ logger8.error(extra || {}, message);
10134
+ break;
10135
+ }
10136
+ }
10137
+ function canSudoWithoutPassword() {
10138
+ try {
10139
+ execSync3("sudo -n true 2>&1", { stdio: "pipe" });
10140
+ return true;
10141
+ } catch {
10142
+ return false;
10143
+ }
10144
+ }
10145
+ async function installSystemPackages(packages, notifSvc) {
10146
+ const result = {
10147
+ success: false,
10148
+ installedPackages: [],
10149
+ failedPackages: []
10150
+ };
10151
+ const validPackages = packages.filter((p) => p && p.length > 0 && p !== "\u81FA");
10152
+ if (validPackages.length === 0) {
10153
+ silentLog("info", "\u6CA1\u6709\u9700\u8981\u5B89\u88C5\u7684\u5305");
10154
+ return { ...result, success: true };
10155
+ }
10156
+ silentLog("info", `\u5F00\u59CB\u5B89\u88C5\u7CFB\u7EDF\u4F9D\u8D56: ${validPackages.join(", ")}`, { packages: validPackages });
10157
+ notifSvc?.info("\u6B63\u5728\u5B89\u88C5\u7CFB\u7EDF\u4F9D\u8D56...", "Ocosay", 3e3);
10158
+ const installCommand = getInstallCommandPrefix();
10159
+ const fullCommand = `${installCommand} ${validPackages.join(" ")}`;
10160
+ silentLog("info", `\u6267\u884C\u5B89\u88C5\u547D\u4EE4: ${fullCommand}`);
10161
+ if (!canSudoWithoutPassword()) {
10162
+ const msg = "\u9700\u8981 sudo \u6743\u9650\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u914D\u7F6E NOPASSWD";
10163
+ result.error = msg;
10164
+ notifSvc?.error("\u9700\u8981 sudo \u6743\u9650", "\u8BF7\u5728\u7EC8\u7AEF\u6267\u884C: sudo visudo \u6DFB\u52A0 NOPASSWD \u914D\u7F6E\uFF0C\u914D\u7F6E\u597D\u540E\u8BF7\u91CD\u542F OpenCode", 1e4);
10165
+ silentLog("error", msg);
10166
+ return result;
10167
+ }
10168
+ try {
10169
+ const { platform, isWsl: isWsl3 } = detectPlatform();
10170
+ if (platform === "linux" || isWsl3) {
10171
+ notifSvc?.info("\u6B63\u5728\u66F4\u65B0\u5305\u5217\u8868...", "Ocosay", 3e3);
10172
+ silentLog("info", "\u66F4\u65B0 apt \u5305\u5217\u8868");
10173
+ try {
10174
+ execSync3("sudo apt-get update", {
10175
+ timeout: 12e4,
10176
+ encoding: "utf8"
10177
+ });
10178
+ silentLog("info", "apt-get update \u5B8C\u6210");
10179
+ } catch (updateErr) {
10180
+ silentLog("warn", "apt-get update \u5931\u8D25\uFF0C\u7EE7\u7EED\u5C1D\u8BD5\u5B89\u88C5", { error: String(updateErr) });
10181
+ }
10182
+ }
10183
+ notifSvc?.info(`\u6B63\u5728\u5B89\u88C5 ${validPackages.length} \u4E2A\u5305...`, "Ocosay", 5e3);
10184
+ const output = execSync3(fullCommand, {
10185
+ timeout: 3e5,
10186
+ encoding: "utf8"
10187
+ });
10188
+ silentLog("info", `\u5B89\u88C5\u8F93\u51FA: ${output.substring(0, 500)}`);
10189
+ const verifiedPackages = [];
10190
+ const failedPackages = [];
10191
+ for (const pkg of validPackages) {
10192
+ const isInstalled = await verifyInstallation([pkg]);
10193
+ if (isInstalled) {
10194
+ verifiedPackages.push(pkg);
10195
+ silentLog("info", `\u5305 ${pkg} \u5B89\u88C5\u9A8C\u8BC1\u6210\u529F`);
10196
+ } else {
10197
+ failedPackages.push(pkg);
10198
+ silentLog("warn", `\u5305 ${pkg} \u5B89\u88C5\u9A8C\u8BC1\u5931\u8D25`);
10199
+ }
10200
+ }
10201
+ result.installedPackages = verifiedPackages;
10202
+ result.failedPackages = failedPackages;
10203
+ result.success = failedPackages.length === 0;
10204
+ if (result.success) {
10205
+ notifSvc?.success("\u7CFB\u7EDF\u4F9D\u8D56\u5B89\u88C5\u6210\u529F", verifiedPackages.join(", "), 5e3);
10206
+ silentLog("info", `\u6240\u6709\u5305\u5B89\u88C5\u6210\u529F: ${verifiedPackages.join(", ")}`);
10207
+ } else {
10208
+ const errorMsg = failedPackages.length > 0 ? `\u4EE5\u4E0B\u5305\u5B89\u88C5\u5931\u8D25: ${failedPackages.join(", ")}` : "\u90E8\u5206\u5305\u5B89\u88C5\u5931\u8D25";
10209
+ result.error = errorMsg;
10210
+ notifSvc?.warning("\u90E8\u5206\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25", errorMsg, 8e3);
10211
+ silentLog("warn", errorMsg);
10212
+ }
10213
+ } catch (err) {
10214
+ const errorMessage = err instanceof Error ? err.message : String(err);
10215
+ silentLog("error", `\u5B89\u88C5\u547D\u4EE4\u6267\u884C\u5931\u8D25: ${errorMessage}`, { error: errorMessage });
10216
+ if (errorMessage.includes("sudo") || errorMessage.toLowerCase().includes("password")) {
10217
+ result.error = "\u9700\u8981 sudo \u6743\u9650\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u914D\u7F6E NOPASSWD";
10218
+ notifSvc?.error("\u9700\u8981 sudo \u6743\u9650", "\u8BF7\u5728\u7EC8\u7AEF\u6267\u884C: sudo visudo", 1e4);
10219
+ } else if (errorMessage.includes("already") || errorMessage.includes("is already")) {
10220
+ result.success = true;
10221
+ result.installedPackages = validPackages;
10222
+ notifSvc?.success("\u4F9D\u8D56\u5DF2\u5B58\u5728", "\u65E0\u9700\u91CD\u65B0\u5B89\u88C5", 3e3);
10223
+ } else {
10224
+ result.error = errorMessage;
10225
+ notifSvc?.error("\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25", errorMessage.substring(0, 200), 8e3);
10226
+ }
10227
+ }
10228
+ return result;
10229
+ }
10230
+ async function verifyInstallation(packages) {
10231
+ if (packages.length === 0) {
10232
+ return true;
10233
+ }
10234
+ const validPackages = packages.filter((p) => p && p.length > 0 && p !== "\u81FA");
10235
+ if (validPackages.length === 0) {
10236
+ return true;
10237
+ }
10238
+ silentLog("info", `\u9A8C\u8BC1\u5305\u5B89\u88C5\u72B6\u6001: ${validPackages.join(", ")}`);
10239
+ try {
10240
+ for (const pkg of validPackages) {
10241
+ const checkCmd = getCheckCommand(pkg);
10242
+ const { success } = execCapture(checkCmd);
10243
+ if (!success) {
10244
+ silentLog("warn", `\u5305 ${pkg} \u9A8C\u8BC1\u5931\u8D25`);
10245
+ return false;
10246
+ }
10247
+ }
10248
+ silentLog("info", `\u6240\u6709\u5305\u9A8C\u8BC1\u901A\u8FC7: ${validPackages.join(", ")}`);
10249
+ return true;
10250
+ } catch (err) {
10251
+ silentLog("error", `\u9A8C\u8BC1\u8FC7\u7A0B\u5F02\u5E38: ${String(err)}`);
10252
+ return false;
10253
+ }
10254
+ }
10255
+
10256
+ // src/plugin.ts
10257
+ var logger9 = createModuleLogger("Plugin");
10258
+ var require3 = createRequire2(import.meta.url);
10259
+ var opencodeBinPath = execSync4("which opencode").toString().trim();
9909
10260
  var opencodeRoot = dirname2(dirname2(opencodeBinPath));
9910
10261
  var opencodeNodeModules = join8(opencodeRoot, "node_modules");
9911
- var pluginRequire = createRequire(join8(opencodeNodeModules, "package.json"));
10262
+ var pluginRequire = createRequire2(join8(opencodeNodeModules, "package.json"));
9912
10263
  function getSkipFilePath() {
9913
10264
  return join8(homedir3(), ".config", "opencode", ".naudiodon_skip");
9914
10265
  }
@@ -9919,7 +10270,7 @@ function markNaudiodonSkipped() {
9919
10270
  try {
9920
10271
  const dir = join8(homedir3(), ".config", "opencode");
9921
10272
  if (!existsSync7(dir)) {
9922
- execSync2("mkdir -p", { cwd: dir });
10273
+ execSync4("mkdir -p", { cwd: dir });
9923
10274
  }
9924
10275
  writeFileSync6(getSkipFilePath(), Date.now().toString(), "utf-8");
9925
10276
  } catch {
@@ -9927,70 +10278,70 @@ function markNaudiodonSkipped() {
9927
10278
  }
9928
10279
  async function verifyNaudiodonLoad() {
9929
10280
  try {
9930
- require2("naudiodon");
9931
- logger8.info("naudiodon loaded successfully");
10281
+ require3("naudiodon");
10282
+ logger9.info("naudiodon loaded successfully");
9932
10283
  return true;
9933
10284
  } catch (err) {
9934
- logger8.warn({ err }, "naudiodon load failed after rebuild");
10285
+ logger9.warn({ err }, "naudiodon load failed after rebuild");
9935
10286
  return false;
9936
10287
  }
9937
10288
  }
9938
10289
  async function rebuildNaudiodonDependency(dep) {
9939
- const naudiodonPath = dirname2(require2.resolve("naudiodon"));
10290
+ const naudiodonPath = dirname2(require3.resolve("naudiodon"));
9940
10291
  try {
9941
10292
  notificationService.info(`\u6B63\u5728\u7F16\u8BD1 ${dep}...`, "Ocosay \u4F9D\u8D56", 4e3);
9942
- execSync2(`npm rebuild ${dep}`, {
10293
+ execSync4(`npm rebuild ${dep}`, {
9943
10294
  cwd: naudiodonPath,
9944
10295
  stdio: "inherit"
9945
10296
  });
9946
- logger8.info(`${dep} rebuilt successfully`);
10297
+ logger9.info(`${dep} rebuilt successfully`);
9947
10298
  return true;
9948
10299
  } catch (err) {
9949
- logger8.warn({ err }, `${dep} rebuild failed`);
10300
+ logger9.warn({ err }, `${dep} rebuild failed`);
9950
10301
  return false;
9951
10302
  }
9952
10303
  }
9953
10304
  async function fixNaudiodonDependencies(maxRetries = 5) {
9954
- const naudiodonPath = dirname2(require2.resolve("naudiodon"));
10305
+ const naudiodonPath = dirname2(require3.resolve("naudiodon"));
9955
10306
  const criticalDeps = ["segfault-handler", "bindings", "node-pre-gyp"];
9956
10307
  for (let attempt = 0; attempt < maxRetries; attempt++) {
9957
10308
  if (await verifyNaudiodonLoad()) {
9958
10309
  return true;
9959
10310
  }
9960
- logger8.info({ attempt }, "naudiodon not loadable, trying dependency rebuild");
10311
+ logger9.info({ attempt }, "naudiodon not loadable, trying dependency rebuild");
9961
10312
  notificationService.info(`\u6B63\u5728\u68C0\u67E5\u4F9D\u8D56 (${attempt + 1}/${maxRetries})...`, "Ocosay", 3e3);
9962
10313
  let anySuccess = false;
9963
10314
  for (const dep of criticalDeps) {
9964
10315
  try {
9965
- require2.resolve(dep, { paths: [naudiodonPath] });
10316
+ require3.resolve(dep, { paths: [naudiodonPath] });
9966
10317
  if (await rebuildNaudiodonDependency(dep)) {
9967
10318
  anySuccess = true;
9968
10319
  }
9969
10320
  } catch {
9970
10321
  try {
9971
10322
  notificationService.info(`\u6B63\u5728\u5B89\u88C5 ${dep}...`, "Ocosay", 4e3);
9972
- execSync2(`npm install ${dep}`, {
10323
+ execSync4(`npm install ${dep}`, {
9973
10324
  cwd: naudiodonPath,
9974
10325
  stdio: "inherit"
9975
10326
  });
9976
- logger8.info(`${dep} installed successfully`);
10327
+ logger9.info(`${dep} installed successfully`);
9977
10328
  anySuccess = true;
9978
10329
  } catch (installErr) {
9979
- logger8.warn({ err: installErr }, `${dep} install failed`);
10330
+ logger9.warn({ err: installErr }, `${dep} install failed`);
9980
10331
  }
9981
10332
  }
9982
10333
  }
9983
10334
  if (!anySuccess || !await verifyNaudiodonLoad()) {
9984
10335
  try {
9985
10336
  notificationService.info("\u6B63\u5728\u91CD\u65B0\u7F16\u8BD1 naudiodon...", "Ocosay", 4e3);
9986
- execSync2("npm rebuild naudiodon", {
10337
+ execSync4("npm rebuild naudiodon", {
9987
10338
  cwd: naudiodonPath,
9988
10339
  stdio: "inherit"
9989
10340
  });
9990
- logger8.info("naudiodon rebuilt");
10341
+ logger9.info("naudiodon rebuilt");
9991
10342
  anySuccess = true;
9992
10343
  } catch (err) {
9993
- logger8.warn({ err }, "naudiodon rebuild failed");
10344
+ logger9.warn({ err }, "naudiodon rebuild failed");
9994
10345
  }
9995
10346
  }
9996
10347
  if (await verifyNaudiodonLoad()) {
@@ -10004,25 +10355,25 @@ async function fixNaudiodonDependencies(maxRetries = 5) {
10004
10355
  }
10005
10356
  async function ensureNaudiodonCompiled() {
10006
10357
  if (shouldSkipNaudiodon()) {
10007
- logger8.info("naudiodon skipped previously");
10358
+ logger9.info("naudiodon skipped previously");
10008
10359
  return;
10009
10360
  }
10010
10361
  try {
10011
- require2("naudiodon");
10012
- logger8.info("naudiodon already compiled");
10362
+ require3("naudiodon");
10363
+ logger9.info("naudiodon already compiled");
10013
10364
  return;
10014
10365
  } catch {
10015
- logger8.info("naudiodon not compiled, will attempt to compile");
10366
+ logger9.info("naudiodon not compiled, will attempt to compile");
10016
10367
  notificationService.info("\u6B63\u5728\u7F16\u8BD1 naudiodon...", "Ocosay \u97F3\u9891\u540E\u7AEF", 5e3);
10017
10368
  }
10018
10369
  try {
10019
- const naudiodonPath = dirname2(require2.resolve("naudiodon"));
10020
- logger8.info({ naudiodonPath }, "found naudiodon, rebuilding");
10021
- execSync2("npm rebuild naudiodon", {
10370
+ const naudiodonPath = dirname2(require3.resolve("naudiodon"));
10371
+ logger9.info({ naudiodonPath }, "found naudiodon, rebuilding");
10372
+ execSync4("npm rebuild naudiodon", {
10022
10373
  cwd: naudiodonPath,
10023
10374
  stdio: "inherit"
10024
10375
  });
10025
- logger8.info("naudiodon compiled, verifying...");
10376
+ logger9.info("naudiodon compiled, verifying...");
10026
10377
  const loadSuccess = await verifyNaudiodonLoad();
10027
10378
  if (loadSuccess) {
10028
10379
  notificationService.success("naudiodon \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
@@ -10036,18 +10387,18 @@ async function ensureNaudiodonCompiled() {
10036
10387
  }
10037
10388
  }
10038
10389
  } catch (err) {
10039
- logger8.warn({ err }, "naudiodon rebuild failed, checking for PortAudio");
10390
+ logger9.warn({ err }, "naudiodon rebuild failed, checking for PortAudio");
10040
10391
  notificationService.warning("naudiodon \u7F16\u8BD1\u5931\u8D25", "\u6B63\u5728\u5C1D\u8BD5\u5B89\u88C5 PortAudio...", 5e3);
10041
10392
  const installed = await installPortAudio();
10042
10393
  if (installed.success) {
10043
10394
  try {
10044
- const naudiodonPath = dirname2(require2.resolve("naudiodon"));
10395
+ const naudiodonPath = dirname2(require3.resolve("naudiodon"));
10045
10396
  notificationService.info("\u6B63\u5728\u91CD\u65B0\u7F16\u8BD1 naudiodon...", "Ocosay", 5e3);
10046
- execSync2("npm rebuild naudiodon", {
10397
+ execSync4("npm rebuild naudiodon", {
10047
10398
  cwd: naudiodonPath,
10048
10399
  stdio: "inherit"
10049
10400
  });
10050
- logger8.info("naudiodon compiled successfully after PortAudio install");
10401
+ logger9.info("naudiodon compiled successfully after PortAudio install");
10051
10402
  const loadSuccess = await verifyNaudiodonLoad();
10052
10403
  if (loadSuccess) {
10053
10404
  notificationService.success("naudiodon \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
@@ -10061,12 +10412,12 @@ async function ensureNaudiodonCompiled() {
10061
10412
  }
10062
10413
  }
10063
10414
  } catch (retryErr) {
10064
- logger8.error({ err: retryErr }, "naudiodon compile failed even after PortAudio install");
10415
+ logger9.error({ err: retryErr }, "naudiodon compile failed even after PortAudio install");
10065
10416
  notificationService.error("naudiodon \u7F16\u8BD1\u5931\u8D25", "\u81EA\u52A8\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u5C1D\u8BD5\u624B\u52A8\u5B89\u88C5", 8e3);
10066
10417
  markNaudiodonSkipped();
10067
10418
  }
10068
10419
  } else {
10069
- logger8.error("PortAudio install failed");
10420
+ logger9.error("PortAudio install failed");
10070
10421
  notificationService.error("PortAudio \u5B89\u88C5\u5931\u8D25", "\u81EA\u52A8\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u5C1D\u8BD5\u624B\u52A8\u5B89\u88C5", 8e3);
10071
10422
  markNaudiodonSkipped();
10072
10423
  }
@@ -10083,46 +10434,113 @@ function isModuleInstalled(moduleName) {
10083
10434
  async function verifyModuleLoad(dep) {
10084
10435
  try {
10085
10436
  pluginRequire(dep);
10086
- logger8.info(`${dep} loaded successfully`);
10437
+ logger9.info(`${dep} loaded successfully`);
10087
10438
  return true;
10088
10439
  } catch (err) {
10089
- logger8.warn({ err }, `${dep} load failed`);
10440
+ logger9.warn({ err }, `${dep} load failed`);
10090
10441
  return false;
10091
10442
  }
10092
10443
  }
10444
+ async function tryCompileSpeaker() {
10445
+ const dep = "speaker";
10446
+ const result = { success: false, stderr: "" };
10447
+ if (isModuleInstalled(dep)) {
10448
+ if (await verifyModuleLoad(dep)) {
10449
+ result.success = true;
10450
+ return result;
10451
+ }
10452
+ }
10453
+ if (!isModuleInstalled(dep)) {
10454
+ try {
10455
+ execSync4("npm install speaker", {
10456
+ cwd: opencodeNodeModules,
10457
+ stdio: "pipe"
10458
+ });
10459
+ } catch {
10460
+ }
10461
+ }
10462
+ try {
10463
+ execSync4("npm rebuild speaker", {
10464
+ cwd: opencodeNodeModules,
10465
+ stdio: "pipe"
10466
+ });
10467
+ if (await verifyModuleLoad(dep)) {
10468
+ result.success = true;
10469
+ }
10470
+ } catch (err) {
10471
+ result.stderr = err.stderr?.toString() || err.message || "";
10472
+ }
10473
+ return result;
10474
+ }
10475
+ async function ensureSpeakerCompiledAsync() {
10476
+ const compileResult = await tryCompileSpeaker();
10477
+ if (compileResult.success) {
10478
+ logger9.info("speaker compiled successfully");
10479
+ return;
10480
+ }
10481
+ const detectResult = detectMissingDependencies(compileResult.stderr);
10482
+ if (detectResult.missingHeaders.length === 0) {
10483
+ logger9.info("speaker compile failed with unknown error");
10484
+ return;
10485
+ }
10486
+ logger9.info({ missingHeaders: detectResult.missingHeaders }, "detected missing headers");
10487
+ const platformInfo = detectPlatform();
10488
+ const packages = mapHeadersToPackages(detectResult.missingHeaders, platformInfo.platform);
10489
+ if (packages.length === 0) {
10490
+ logger9.info("no known packages for missing headers");
10491
+ return;
10492
+ }
10493
+ logger9.info({ packages }, "mapped headers to packages, installing");
10494
+ await installSystemPackages(packages, notificationService);
10495
+ const retryResult = await tryCompileSpeaker();
10496
+ if (retryResult.success) {
10497
+ logger9.info("speaker compiled successfully after installing dependencies");
10498
+ } else {
10499
+ logger9.warn("speaker compile still failed after dependency installation");
10500
+ }
10501
+ }
10502
+ async function ensureSpeakerInstalledAsync() {
10503
+ await ensurePlaySoundInstalled();
10504
+ }
10505
+ async function initAsync() {
10506
+ setTimeout(async () => {
10507
+ await ensureSpeakerCompiledAsync();
10508
+ await ensureSpeakerInstalledAsync();
10509
+ }, 100);
10510
+ }
10093
10511
  async function ensureSpeakerCompiled(maxRetries = 5) {
10094
10512
  const dep = "speaker";
10095
10513
  if (isModuleInstalled(dep)) {
10096
- logger8.info("speaker already installed");
10514
+ logger9.info("speaker already installed");
10097
10515
  if (await verifyModuleLoad(dep)) {
10098
10516
  return;
10099
10517
  }
10100
- logger8.info("speaker installed but not loadable, rebuilding");
10518
+ logger9.info("speaker installed but not loadable, rebuilding");
10101
10519
  notificationService.info("\u6B63\u5728\u7F16\u8BD1 speaker...", "Ocosay \u97F3\u9891\u540E\u7AEF", 5e3);
10102
10520
  try {
10103
- execSync2("npm rebuild speaker", {
10521
+ execSync4("npm rebuild speaker", {
10104
10522
  cwd: opencodeNodeModules,
10105
10523
  stdio: "inherit"
10106
10524
  });
10107
- logger8.info("speaker rebuilt");
10525
+ logger9.info("speaker rebuilt");
10108
10526
  } catch (err) {
10109
- logger8.warn({ err }, "speaker rebuild failed");
10527
+ logger9.warn({ err }, "speaker rebuild failed");
10110
10528
  }
10111
10529
  if (await verifyModuleLoad(dep)) {
10112
10530
  notificationService.success("speaker \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
10113
10531
  return;
10114
10532
  }
10115
10533
  } else {
10116
- logger8.info("speaker not found, installing");
10534
+ logger9.info("speaker not found, installing");
10117
10535
  notificationService.info("\u6B63\u5728\u5B89\u88C5 speaker...", "Ocosay \u97F3\u9891\u540E\u7AEF", 5e3);
10118
10536
  try {
10119
- execSync2("npm install speaker", {
10537
+ execSync4("npm install speaker", {
10120
10538
  cwd: opencodeNodeModules,
10121
10539
  stdio: "inherit"
10122
10540
  });
10123
- logger8.info("speaker installed");
10541
+ logger9.info("speaker installed");
10124
10542
  } catch (err) {
10125
- logger8.warn({ err }, "speaker install failed");
10543
+ logger9.warn({ err }, "speaker install failed");
10126
10544
  }
10127
10545
  }
10128
10546
  for (let attempt = 0; attempt < maxRetries; attempt++) {
@@ -10130,16 +10548,16 @@ async function ensureSpeakerCompiled(maxRetries = 5) {
10130
10548
  notificationService.success("speaker \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
10131
10549
  return;
10132
10550
  }
10133
- logger8.info({ attempt, dep }, "speaker not loadable, trying rebuild");
10551
+ logger9.info({ attempt, dep }, "speaker not loadable, trying rebuild");
10134
10552
  notificationService.info(`\u6B63\u5728\u91CD\u65B0\u7F16\u8BD1 speaker (${attempt + 1}/${maxRetries})...`, "Ocosay", 3e3);
10135
10553
  try {
10136
- execSync2("npm rebuild speaker", {
10554
+ execSync4("npm rebuild speaker", {
10137
10555
  cwd: opencodeNodeModules,
10138
10556
  stdio: "inherit"
10139
10557
  });
10140
- logger8.info("speaker rebuilt");
10558
+ logger9.info("speaker rebuilt");
10141
10559
  } catch (err) {
10142
- logger8.warn({ err }, "speaker rebuild failed");
10560
+ logger9.warn({ err }, "speaker rebuild failed");
10143
10561
  }
10144
10562
  if (await verifyModuleLoad(dep)) {
10145
10563
  notificationService.success("speaker \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
@@ -10149,27 +10567,27 @@ async function ensureSpeakerCompiled(maxRetries = 5) {
10149
10567
  await new Promise((resolve) => setTimeout(resolve, 1e3));
10150
10568
  }
10151
10569
  }
10152
- logger8.error({ dep }, "speaker could not be compiled");
10570
+ logger9.error({ dep }, "speaker could not be compiled");
10153
10571
  notificationService.error("speaker \u7F16\u8BD1\u5931\u8D25", "\u8BF7\u624B\u52A8\u8FD0\u884C: npm install speaker && npm rebuild speaker", 8e3);
10154
10572
  }
10155
10573
  async function ensurePlaySoundInstalled() {
10156
10574
  const dep = "play-sound";
10157
10575
  if (isModuleInstalled(dep)) {
10158
- logger8.info("play-sound already installed");
10576
+ logger9.info("play-sound already installed");
10159
10577
  if (await verifyModuleLoad(dep)) {
10160
10578
  return;
10161
10579
  }
10162
10580
  }
10163
- logger8.info("play-sound not found, installing");
10581
+ logger9.info("play-sound not found, installing");
10164
10582
  notificationService.info("\u6B63\u5728\u5B89\u88C5 play-sound...", "Ocosay \u97F3\u9891\u540E\u7AEF", 5e3);
10165
10583
  try {
10166
- execSync2("npm install play-sound", {
10584
+ execSync4("npm install play-sound", {
10167
10585
  cwd: opencodeNodeModules,
10168
10586
  stdio: "inherit"
10169
10587
  });
10170
- logger8.info("play-sound installed");
10588
+ logger9.info("play-sound installed");
10171
10589
  } catch (err) {
10172
- logger8.warn({ err }, "play-sound install failed");
10590
+ logger9.warn({ err }, "play-sound install failed");
10173
10591
  notificationService.warning(
10174
10592
  "play-sound \u5B89\u88C5\u5931\u8D25",
10175
10593
  "\u8BF7\u624B\u52A8\u8FD0\u884C: npm install play-sound",
@@ -10193,7 +10611,7 @@ async function ensureOptionalDepsInstalled() {
10193
10611
  }
10194
10612
  function execCmd2(cmd) {
10195
10613
  try {
10196
- const output = execSync2(cmd, { stdio: "pipe", encoding: "utf8" });
10614
+ const output = execSync4(cmd, { stdio: "pipe", encoding: "utf8" });
10197
10615
  return { success: true, output };
10198
10616
  } catch (err) {
10199
10617
  return { success: false, output: err.message || "" };
@@ -10202,7 +10620,7 @@ function execCmd2(cmd) {
10202
10620
  function isWsl2() {
10203
10621
  if (process.platform !== "linux") return false;
10204
10622
  try {
10205
- return require2("fs").readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
10623
+ return require3("fs").readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
10206
10624
  } catch {
10207
10625
  return false;
10208
10626
  }
@@ -10239,12 +10657,12 @@ async function checkAudioEnvironmentForBackend() {
10239
10657
  async function installPortAudio() {
10240
10658
  const platform = process.platform;
10241
10659
  const wsl = isWsl2();
10242
- logger8.info({ platform, wsl }, "installing PortAudio");
10660
+ logger9.info({ platform, wsl }, "installing PortAudio");
10243
10661
  const runInstall = async (cmd, desc) => {
10244
- logger8.info(`Running: ${cmd}`);
10662
+ logger9.info(`Running: ${cmd}`);
10245
10663
  notificationService.info(desc, "\u6B63\u5728\u5B89\u88C5...", 5e3);
10246
10664
  try {
10247
- execSync2(cmd, { stdio: "inherit" });
10665
+ execSync4(cmd, { stdio: "inherit" });
10248
10666
  return true;
10249
10667
  } catch (err) {
10250
10668
  const msg = err.message || "";
@@ -10254,15 +10672,15 @@ async function installPortAudio() {
10254
10672
  "# \u8BF7\u5728WSL\u7EC8\u7AEF\u6267\u884C\u4E00\u6B21\nsudo visudo\n# \u6DFB\u52A0\u884C\uFF1Ayour user name ALL=(ALL) NOPASSWD: ALL",
10255
10673
  1e4
10256
10674
  );
10257
- logger8.error({ err }, "\u9700\u8981 sudo \u6743\u9650 \u8BF7\u5728WSL\u7EC8\u7AEF\u6267\u884C\u4E00\u6B21sudo visudo # \u6DFB\u52A0\u884C\uFF1Ayour user name ALL=(ALL) NOPASSWD: ALL");
10675
+ logger9.error({ err }, "\u9700\u8981 sudo \u6743\u9650 \u8BF7\u5728WSL\u7EC8\u7AEF\u6267\u884C\u4E00\u6B21sudo visudo # \u6DFB\u52A0\u884C\uFF1Ayour user name ALL=(ALL) NOPASSWD: ALL");
10258
10676
  return false;
10259
10677
  }
10260
10678
  if (msg.includes("already") || msg.includes("is already")) {
10261
- logger8.info("already installed");
10679
+ logger9.info("already installed");
10262
10680
  return true;
10263
10681
  }
10264
10682
  notificationService.error(desc + " \u5931\u8D25", msg.substring(0, 100), 8e3);
10265
- logger8.error({ err }, `install failed: ${desc}`);
10683
+ logger9.error({ err }, `install failed: ${desc}`);
10266
10684
  return false;
10267
10685
  }
10268
10686
  };
@@ -10270,7 +10688,7 @@ async function installPortAudio() {
10270
10688
  notificationService.info("\u68C0\u6D4B ffmpeg...", "\u97F3\u9891\u540E\u7AEF", 5e3);
10271
10689
  const ffmpegCheck = execCmd2("which ffplay");
10272
10690
  if (ffmpegCheck.success) {
10273
- logger8.info("ffmpeg already available");
10691
+ logger9.info("ffmpeg already available");
10274
10692
  notificationService.success("ffmpeg \u5C31\u7EEA", "ffplay \u53EF\u7528\u4E8E\u65E0\u58F0\u5361\u64AD\u653E", 5e3);
10275
10693
  } else {
10276
10694
  notificationService.info("\u5B89\u88C5 ffmpeg...", "\u97F3\u9891\u540E\u7AEF", 5e3);
@@ -10286,7 +10704,7 @@ async function installPortAudio() {
10286
10704
  }
10287
10705
  notificationService.info("\u68C0\u6D4B\u97F3\u9891\u8BBE\u5907...", "\u97F3\u9891\u540E\u7AEF", 5e3);
10288
10706
  if (checkAlsa()) {
10289
- logger8.info("alsa-utils already available and working");
10707
+ logger9.info("alsa-utils already available and working");
10290
10708
  notificationService.success("alsa-utils \u5C31\u7EEA", "\u97F3\u9891\u540E\u7AEF\u5DF2\u53EF\u7528", 5e3);
10291
10709
  return { success: true, message: "alsa" };
10292
10710
  }
@@ -10477,8 +10895,9 @@ var server = (async (input, _options) => {
10477
10895
  });
10478
10896
  } catch (err) {
10479
10897
  initError = err instanceof Error ? err : new Error(String(err));
10480
- logger8.error({ error: initError }, "initialization failed");
10898
+ logger9.error({ error: initError }, "initialization failed");
10481
10899
  }
10900
+ initAsync();
10482
10901
  await ensureNaudiodonCompiled();
10483
10902
  await ensureOptionalDepsInstalled();
10484
10903
  await checkAudioEnvironmentForBackend();