@mingxy/ocosay 1.1.23 → 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,13 +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 pluginPath = dirname2(fileURLToPath(import.meta.url));
9909
- var opencodeNodeModules = join8(pluginPath, "..", "node_modules");
9910
- var pluginRequire = createRequire(join8(opencodeNodeModules, "package.json"));
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();
10260
+ var opencodeRoot = dirname2(dirname2(opencodeBinPath));
10261
+ var opencodeNodeModules = join8(opencodeRoot, "node_modules");
10262
+ var pluginRequire = createRequire2(join8(opencodeNodeModules, "package.json"));
9911
10263
  function getSkipFilePath() {
9912
10264
  return join8(homedir3(), ".config", "opencode", ".naudiodon_skip");
9913
10265
  }
@@ -9918,7 +10270,7 @@ function markNaudiodonSkipped() {
9918
10270
  try {
9919
10271
  const dir = join8(homedir3(), ".config", "opencode");
9920
10272
  if (!existsSync7(dir)) {
9921
- execSync2("mkdir -p", { cwd: dir });
10273
+ execSync4("mkdir -p", { cwd: dir });
9922
10274
  }
9923
10275
  writeFileSync6(getSkipFilePath(), Date.now().toString(), "utf-8");
9924
10276
  } catch {
@@ -9926,70 +10278,70 @@ function markNaudiodonSkipped() {
9926
10278
  }
9927
10279
  async function verifyNaudiodonLoad() {
9928
10280
  try {
9929
- require2("naudiodon");
9930
- logger8.info("naudiodon loaded successfully");
10281
+ require3("naudiodon");
10282
+ logger9.info("naudiodon loaded successfully");
9931
10283
  return true;
9932
10284
  } catch (err) {
9933
- logger8.warn({ err }, "naudiodon load failed after rebuild");
10285
+ logger9.warn({ err }, "naudiodon load failed after rebuild");
9934
10286
  return false;
9935
10287
  }
9936
10288
  }
9937
10289
  async function rebuildNaudiodonDependency(dep) {
9938
- const naudiodonPath = dirname2(require2.resolve("naudiodon"));
10290
+ const naudiodonPath = dirname2(require3.resolve("naudiodon"));
9939
10291
  try {
9940
10292
  notificationService.info(`\u6B63\u5728\u7F16\u8BD1 ${dep}...`, "Ocosay \u4F9D\u8D56", 4e3);
9941
- execSync2(`npm rebuild ${dep}`, {
10293
+ execSync4(`npm rebuild ${dep}`, {
9942
10294
  cwd: naudiodonPath,
9943
10295
  stdio: "inherit"
9944
10296
  });
9945
- logger8.info(`${dep} rebuilt successfully`);
10297
+ logger9.info(`${dep} rebuilt successfully`);
9946
10298
  return true;
9947
10299
  } catch (err) {
9948
- logger8.warn({ err }, `${dep} rebuild failed`);
10300
+ logger9.warn({ err }, `${dep} rebuild failed`);
9949
10301
  return false;
9950
10302
  }
9951
10303
  }
9952
10304
  async function fixNaudiodonDependencies(maxRetries = 5) {
9953
- const naudiodonPath = dirname2(require2.resolve("naudiodon"));
10305
+ const naudiodonPath = dirname2(require3.resolve("naudiodon"));
9954
10306
  const criticalDeps = ["segfault-handler", "bindings", "node-pre-gyp"];
9955
10307
  for (let attempt = 0; attempt < maxRetries; attempt++) {
9956
10308
  if (await verifyNaudiodonLoad()) {
9957
10309
  return true;
9958
10310
  }
9959
- logger8.info({ attempt }, "naudiodon not loadable, trying dependency rebuild");
10311
+ logger9.info({ attempt }, "naudiodon not loadable, trying dependency rebuild");
9960
10312
  notificationService.info(`\u6B63\u5728\u68C0\u67E5\u4F9D\u8D56 (${attempt + 1}/${maxRetries})...`, "Ocosay", 3e3);
9961
10313
  let anySuccess = false;
9962
10314
  for (const dep of criticalDeps) {
9963
10315
  try {
9964
- require2.resolve(dep, { paths: [naudiodonPath] });
10316
+ require3.resolve(dep, { paths: [naudiodonPath] });
9965
10317
  if (await rebuildNaudiodonDependency(dep)) {
9966
10318
  anySuccess = true;
9967
10319
  }
9968
10320
  } catch {
9969
10321
  try {
9970
10322
  notificationService.info(`\u6B63\u5728\u5B89\u88C5 ${dep}...`, "Ocosay", 4e3);
9971
- execSync2(`npm install ${dep}`, {
10323
+ execSync4(`npm install ${dep}`, {
9972
10324
  cwd: naudiodonPath,
9973
10325
  stdio: "inherit"
9974
10326
  });
9975
- logger8.info(`${dep} installed successfully`);
10327
+ logger9.info(`${dep} installed successfully`);
9976
10328
  anySuccess = true;
9977
10329
  } catch (installErr) {
9978
- logger8.warn({ err: installErr }, `${dep} install failed`);
10330
+ logger9.warn({ err: installErr }, `${dep} install failed`);
9979
10331
  }
9980
10332
  }
9981
10333
  }
9982
10334
  if (!anySuccess || !await verifyNaudiodonLoad()) {
9983
10335
  try {
9984
10336
  notificationService.info("\u6B63\u5728\u91CD\u65B0\u7F16\u8BD1 naudiodon...", "Ocosay", 4e3);
9985
- execSync2("npm rebuild naudiodon", {
10337
+ execSync4("npm rebuild naudiodon", {
9986
10338
  cwd: naudiodonPath,
9987
10339
  stdio: "inherit"
9988
10340
  });
9989
- logger8.info("naudiodon rebuilt");
10341
+ logger9.info("naudiodon rebuilt");
9990
10342
  anySuccess = true;
9991
10343
  } catch (err) {
9992
- logger8.warn({ err }, "naudiodon rebuild failed");
10344
+ logger9.warn({ err }, "naudiodon rebuild failed");
9993
10345
  }
9994
10346
  }
9995
10347
  if (await verifyNaudiodonLoad()) {
@@ -10003,25 +10355,25 @@ async function fixNaudiodonDependencies(maxRetries = 5) {
10003
10355
  }
10004
10356
  async function ensureNaudiodonCompiled() {
10005
10357
  if (shouldSkipNaudiodon()) {
10006
- logger8.info("naudiodon skipped previously");
10358
+ logger9.info("naudiodon skipped previously");
10007
10359
  return;
10008
10360
  }
10009
10361
  try {
10010
- require2("naudiodon");
10011
- logger8.info("naudiodon already compiled");
10362
+ require3("naudiodon");
10363
+ logger9.info("naudiodon already compiled");
10012
10364
  return;
10013
10365
  } catch {
10014
- logger8.info("naudiodon not compiled, will attempt to compile");
10366
+ logger9.info("naudiodon not compiled, will attempt to compile");
10015
10367
  notificationService.info("\u6B63\u5728\u7F16\u8BD1 naudiodon...", "Ocosay \u97F3\u9891\u540E\u7AEF", 5e3);
10016
10368
  }
10017
10369
  try {
10018
- const naudiodonPath = dirname2(require2.resolve("naudiodon"));
10019
- logger8.info({ naudiodonPath }, "found naudiodon, rebuilding");
10020
- execSync2("npm rebuild naudiodon", {
10370
+ const naudiodonPath = dirname2(require3.resolve("naudiodon"));
10371
+ logger9.info({ naudiodonPath }, "found naudiodon, rebuilding");
10372
+ execSync4("npm rebuild naudiodon", {
10021
10373
  cwd: naudiodonPath,
10022
10374
  stdio: "inherit"
10023
10375
  });
10024
- logger8.info("naudiodon compiled, verifying...");
10376
+ logger9.info("naudiodon compiled, verifying...");
10025
10377
  const loadSuccess = await verifyNaudiodonLoad();
10026
10378
  if (loadSuccess) {
10027
10379
  notificationService.success("naudiodon \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
@@ -10035,18 +10387,18 @@ async function ensureNaudiodonCompiled() {
10035
10387
  }
10036
10388
  }
10037
10389
  } catch (err) {
10038
- logger8.warn({ err }, "naudiodon rebuild failed, checking for PortAudio");
10390
+ logger9.warn({ err }, "naudiodon rebuild failed, checking for PortAudio");
10039
10391
  notificationService.warning("naudiodon \u7F16\u8BD1\u5931\u8D25", "\u6B63\u5728\u5C1D\u8BD5\u5B89\u88C5 PortAudio...", 5e3);
10040
10392
  const installed = await installPortAudio();
10041
10393
  if (installed.success) {
10042
10394
  try {
10043
- const naudiodonPath = dirname2(require2.resolve("naudiodon"));
10395
+ const naudiodonPath = dirname2(require3.resolve("naudiodon"));
10044
10396
  notificationService.info("\u6B63\u5728\u91CD\u65B0\u7F16\u8BD1 naudiodon...", "Ocosay", 5e3);
10045
- execSync2("npm rebuild naudiodon", {
10397
+ execSync4("npm rebuild naudiodon", {
10046
10398
  cwd: naudiodonPath,
10047
10399
  stdio: "inherit"
10048
10400
  });
10049
- logger8.info("naudiodon compiled successfully after PortAudio install");
10401
+ logger9.info("naudiodon compiled successfully after PortAudio install");
10050
10402
  const loadSuccess = await verifyNaudiodonLoad();
10051
10403
  if (loadSuccess) {
10052
10404
  notificationService.success("naudiodon \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
@@ -10060,12 +10412,12 @@ async function ensureNaudiodonCompiled() {
10060
10412
  }
10061
10413
  }
10062
10414
  } catch (retryErr) {
10063
- logger8.error({ err: retryErr }, "naudiodon compile failed even after PortAudio install");
10415
+ logger9.error({ err: retryErr }, "naudiodon compile failed even after PortAudio install");
10064
10416
  notificationService.error("naudiodon \u7F16\u8BD1\u5931\u8D25", "\u81EA\u52A8\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u5C1D\u8BD5\u624B\u52A8\u5B89\u88C5", 8e3);
10065
10417
  markNaudiodonSkipped();
10066
10418
  }
10067
10419
  } else {
10068
- logger8.error("PortAudio install failed");
10420
+ logger9.error("PortAudio install failed");
10069
10421
  notificationService.error("PortAudio \u5B89\u88C5\u5931\u8D25", "\u81EA\u52A8\u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u5C1D\u8BD5\u624B\u52A8\u5B89\u88C5", 8e3);
10070
10422
  markNaudiodonSkipped();
10071
10423
  }
@@ -10082,46 +10434,113 @@ function isModuleInstalled(moduleName) {
10082
10434
  async function verifyModuleLoad(dep) {
10083
10435
  try {
10084
10436
  pluginRequire(dep);
10085
- logger8.info(`${dep} loaded successfully`);
10437
+ logger9.info(`${dep} loaded successfully`);
10086
10438
  return true;
10087
10439
  } catch (err) {
10088
- logger8.warn({ err }, `${dep} load failed`);
10440
+ logger9.warn({ err }, `${dep} load failed`);
10089
10441
  return false;
10090
10442
  }
10091
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
+ }
10092
10511
  async function ensureSpeakerCompiled(maxRetries = 5) {
10093
10512
  const dep = "speaker";
10094
10513
  if (isModuleInstalled(dep)) {
10095
- logger8.info("speaker already installed");
10514
+ logger9.info("speaker already installed");
10096
10515
  if (await verifyModuleLoad(dep)) {
10097
10516
  return;
10098
10517
  }
10099
- logger8.info("speaker installed but not loadable, rebuilding");
10518
+ logger9.info("speaker installed but not loadable, rebuilding");
10100
10519
  notificationService.info("\u6B63\u5728\u7F16\u8BD1 speaker...", "Ocosay \u97F3\u9891\u540E\u7AEF", 5e3);
10101
10520
  try {
10102
- execSync2("npm rebuild speaker", {
10521
+ execSync4("npm rebuild speaker", {
10103
10522
  cwd: opencodeNodeModules,
10104
10523
  stdio: "inherit"
10105
10524
  });
10106
- logger8.info("speaker rebuilt");
10525
+ logger9.info("speaker rebuilt");
10107
10526
  } catch (err) {
10108
- logger8.warn({ err }, "speaker rebuild failed");
10527
+ logger9.warn({ err }, "speaker rebuild failed");
10109
10528
  }
10110
10529
  if (await verifyModuleLoad(dep)) {
10111
10530
  notificationService.success("speaker \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
10112
10531
  return;
10113
10532
  }
10114
10533
  } else {
10115
- logger8.info("speaker not found, installing");
10534
+ logger9.info("speaker not found, installing");
10116
10535
  notificationService.info("\u6B63\u5728\u5B89\u88C5 speaker...", "Ocosay \u97F3\u9891\u540E\u7AEF", 5e3);
10117
10536
  try {
10118
- execSync2("npm install speaker", {
10537
+ execSync4("npm install speaker", {
10119
10538
  cwd: opencodeNodeModules,
10120
10539
  stdio: "inherit"
10121
10540
  });
10122
- logger8.info("speaker installed");
10541
+ logger9.info("speaker installed");
10123
10542
  } catch (err) {
10124
- logger8.warn({ err }, "speaker install failed");
10543
+ logger9.warn({ err }, "speaker install failed");
10125
10544
  }
10126
10545
  }
10127
10546
  for (let attempt = 0; attempt < maxRetries; attempt++) {
@@ -10129,16 +10548,16 @@ async function ensureSpeakerCompiled(maxRetries = 5) {
10129
10548
  notificationService.success("speaker \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
10130
10549
  return;
10131
10550
  }
10132
- logger8.info({ attempt, dep }, "speaker not loadable, trying rebuild");
10551
+ logger9.info({ attempt, dep }, "speaker not loadable, trying rebuild");
10133
10552
  notificationService.info(`\u6B63\u5728\u91CD\u65B0\u7F16\u8BD1 speaker (${attempt + 1}/${maxRetries})...`, "Ocosay", 3e3);
10134
10553
  try {
10135
- execSync2("npm rebuild speaker", {
10554
+ execSync4("npm rebuild speaker", {
10136
10555
  cwd: opencodeNodeModules,
10137
10556
  stdio: "inherit"
10138
10557
  });
10139
- logger8.info("speaker rebuilt");
10558
+ logger9.info("speaker rebuilt");
10140
10559
  } catch (err) {
10141
- logger8.warn({ err }, "speaker rebuild failed");
10560
+ logger9.warn({ err }, "speaker rebuild failed");
10142
10561
  }
10143
10562
  if (await verifyModuleLoad(dep)) {
10144
10563
  notificationService.success("speaker \u7F16\u8BD1\u6210\u529F", "\u97F3\u9891\u540E\u7AEF\u5DF2\u5C31\u7EEA", 5e3);
@@ -10148,27 +10567,27 @@ async function ensureSpeakerCompiled(maxRetries = 5) {
10148
10567
  await new Promise((resolve) => setTimeout(resolve, 1e3));
10149
10568
  }
10150
10569
  }
10151
- logger8.error({ dep }, "speaker could not be compiled");
10570
+ logger9.error({ dep }, "speaker could not be compiled");
10152
10571
  notificationService.error("speaker \u7F16\u8BD1\u5931\u8D25", "\u8BF7\u624B\u52A8\u8FD0\u884C: npm install speaker && npm rebuild speaker", 8e3);
10153
10572
  }
10154
10573
  async function ensurePlaySoundInstalled() {
10155
10574
  const dep = "play-sound";
10156
10575
  if (isModuleInstalled(dep)) {
10157
- logger8.info("play-sound already installed");
10576
+ logger9.info("play-sound already installed");
10158
10577
  if (await verifyModuleLoad(dep)) {
10159
10578
  return;
10160
10579
  }
10161
10580
  }
10162
- logger8.info("play-sound not found, installing");
10581
+ logger9.info("play-sound not found, installing");
10163
10582
  notificationService.info("\u6B63\u5728\u5B89\u88C5 play-sound...", "Ocosay \u97F3\u9891\u540E\u7AEF", 5e3);
10164
10583
  try {
10165
- execSync2("npm install play-sound", {
10584
+ execSync4("npm install play-sound", {
10166
10585
  cwd: opencodeNodeModules,
10167
10586
  stdio: "inherit"
10168
10587
  });
10169
- logger8.info("play-sound installed");
10588
+ logger9.info("play-sound installed");
10170
10589
  } catch (err) {
10171
- logger8.warn({ err }, "play-sound install failed");
10590
+ logger9.warn({ err }, "play-sound install failed");
10172
10591
  notificationService.warning(
10173
10592
  "play-sound \u5B89\u88C5\u5931\u8D25",
10174
10593
  "\u8BF7\u624B\u52A8\u8FD0\u884C: npm install play-sound",
@@ -10192,7 +10611,7 @@ async function ensureOptionalDepsInstalled() {
10192
10611
  }
10193
10612
  function execCmd2(cmd) {
10194
10613
  try {
10195
- const output = execSync2(cmd, { stdio: "pipe", encoding: "utf8" });
10614
+ const output = execSync4(cmd, { stdio: "pipe", encoding: "utf8" });
10196
10615
  return { success: true, output };
10197
10616
  } catch (err) {
10198
10617
  return { success: false, output: err.message || "" };
@@ -10201,7 +10620,7 @@ function execCmd2(cmd) {
10201
10620
  function isWsl2() {
10202
10621
  if (process.platform !== "linux") return false;
10203
10622
  try {
10204
- return require2("fs").readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
10623
+ return require3("fs").readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft");
10205
10624
  } catch {
10206
10625
  return false;
10207
10626
  }
@@ -10238,12 +10657,12 @@ async function checkAudioEnvironmentForBackend() {
10238
10657
  async function installPortAudio() {
10239
10658
  const platform = process.platform;
10240
10659
  const wsl = isWsl2();
10241
- logger8.info({ platform, wsl }, "installing PortAudio");
10660
+ logger9.info({ platform, wsl }, "installing PortAudio");
10242
10661
  const runInstall = async (cmd, desc) => {
10243
- logger8.info(`Running: ${cmd}`);
10662
+ logger9.info(`Running: ${cmd}`);
10244
10663
  notificationService.info(desc, "\u6B63\u5728\u5B89\u88C5...", 5e3);
10245
10664
  try {
10246
- execSync2(cmd, { stdio: "inherit" });
10665
+ execSync4(cmd, { stdio: "inherit" });
10247
10666
  return true;
10248
10667
  } catch (err) {
10249
10668
  const msg = err.message || "";
@@ -10253,15 +10672,15 @@ async function installPortAudio() {
10253
10672
  "# \u8BF7\u5728WSL\u7EC8\u7AEF\u6267\u884C\u4E00\u6B21\nsudo visudo\n# \u6DFB\u52A0\u884C\uFF1Ayour user name ALL=(ALL) NOPASSWD: ALL",
10254
10673
  1e4
10255
10674
  );
10256
- 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");
10257
10676
  return false;
10258
10677
  }
10259
10678
  if (msg.includes("already") || msg.includes("is already")) {
10260
- logger8.info("already installed");
10679
+ logger9.info("already installed");
10261
10680
  return true;
10262
10681
  }
10263
10682
  notificationService.error(desc + " \u5931\u8D25", msg.substring(0, 100), 8e3);
10264
- logger8.error({ err }, `install failed: ${desc}`);
10683
+ logger9.error({ err }, `install failed: ${desc}`);
10265
10684
  return false;
10266
10685
  }
10267
10686
  };
@@ -10269,7 +10688,7 @@ async function installPortAudio() {
10269
10688
  notificationService.info("\u68C0\u6D4B ffmpeg...", "\u97F3\u9891\u540E\u7AEF", 5e3);
10270
10689
  const ffmpegCheck = execCmd2("which ffplay");
10271
10690
  if (ffmpegCheck.success) {
10272
- logger8.info("ffmpeg already available");
10691
+ logger9.info("ffmpeg already available");
10273
10692
  notificationService.success("ffmpeg \u5C31\u7EEA", "ffplay \u53EF\u7528\u4E8E\u65E0\u58F0\u5361\u64AD\u653E", 5e3);
10274
10693
  } else {
10275
10694
  notificationService.info("\u5B89\u88C5 ffmpeg...", "\u97F3\u9891\u540E\u7AEF", 5e3);
@@ -10285,7 +10704,7 @@ async function installPortAudio() {
10285
10704
  }
10286
10705
  notificationService.info("\u68C0\u6D4B\u97F3\u9891\u8BBE\u5907...", "\u97F3\u9891\u540E\u7AEF", 5e3);
10287
10706
  if (checkAlsa()) {
10288
- logger8.info("alsa-utils already available and working");
10707
+ logger9.info("alsa-utils already available and working");
10289
10708
  notificationService.success("alsa-utils \u5C31\u7EEA", "\u97F3\u9891\u540E\u7AEF\u5DF2\u53EF\u7528", 5e3);
10290
10709
  return { success: true, message: "alsa" };
10291
10710
  }
@@ -10476,8 +10895,9 @@ var server = (async (input, _options) => {
10476
10895
  });
10477
10896
  } catch (err) {
10478
10897
  initError = err instanceof Error ? err : new Error(String(err));
10479
- logger8.error({ error: initError }, "initialization failed");
10898
+ logger9.error({ error: initError }, "initialization failed");
10480
10899
  }
10900
+ initAsync();
10481
10901
  await ensureNaudiodonCompiled();
10482
10902
  await ensureOptionalDepsInstalled();
10483
10903
  await checkAudioEnvironmentForBackend();