@mingxy/ocosay 1.1.32 → 1.2.0

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
@@ -7471,6 +7471,8 @@ import { execFile as execFile3 } from "child_process";
7471
7471
  import { tmpdir as tmpdir4 } from "os";
7472
7472
  import { join as join5 } from "path";
7473
7473
  import { writeFileSync as writeFileSync4, unlinkSync as unlinkSync4, existsSync as existsSync5 } from "fs";
7474
+ import { promisify } from "util";
7475
+ var execFileAsync = promisify(execFile3);
7474
7476
  var SAFE_PATH_REGEX4 = /^[\w\/\.]+$/;
7475
7477
  var PlaySoundBackend = class {
7476
7478
  name = "play-sound";
@@ -7487,7 +7489,7 @@ var PlaySoundBackend = class {
7487
7489
  constructor(options = {}) {
7488
7490
  this.events = options.events;
7489
7491
  }
7490
- start(filePath) {
7492
+ async start(filePath) {
7491
7493
  if (this._started) return;
7492
7494
  if (!SAFE_PATH_REGEX4.test(filePath)) {
7493
7495
  throw new Error(`Invalid file path: ${filePath}`);
@@ -7496,57 +7498,86 @@ var PlaySoundBackend = class {
7496
7498
  this._started = true;
7497
7499
  this._stopped = false;
7498
7500
  this.events?.onStart?.();
7499
- this.playWithPlaySound(filePath);
7500
- }
7501
- async playWithPlaySound(filePath) {
7502
- try {
7503
- const play = (await import("play-sound")).default;
7504
- const opts = {
7505
- players: ["ffplay", "aplay", "mpg123", "afplay"]
7506
- // 优先级
7507
- };
7508
- if (process.platform === "linux") {
7509
- this.player = execFile3("ffplay", [
7510
- "-nodisp",
7511
- // 不显示窗口
7512
- "-autoexit",
7513
- // 播放完自动退出
7514
- "-loglevel",
7515
- "error",
7516
- // 减少日志输出
7517
- filePath
7518
- ], (error) => {
7519
- if (this._stopped) return;
7520
- if (error) {
7501
+ await this.playWithPlaySound(filePath);
7502
+ }
7503
+ playWithPlaySound(filePath) {
7504
+ return new Promise((resolve, reject) => {
7505
+ import("play-sound").then((playModule) => {
7506
+ const play = playModule.default;
7507
+ if (process.platform === "linux") {
7508
+ execFileAsync("ffplay", [
7509
+ "-nodisp",
7510
+ // 不显示窗口
7511
+ "-autoexit",
7512
+ // 播放完自动退出
7513
+ "-loglevel",
7514
+ "error",
7515
+ // 减少日志输出
7516
+ filePath
7517
+ ]).then(() => {
7518
+ if (this._stopped) {
7519
+ resolve();
7520
+ return;
7521
+ }
7522
+ this._started = false;
7523
+ this.events?.onEnd?.();
7524
+ resolve();
7525
+ }).catch((error) => {
7526
+ if (this._stopped) {
7527
+ resolve();
7528
+ return;
7529
+ }
7530
+ this._started = false;
7521
7531
  this.handleError(error);
7522
- return;
7523
- }
7524
- this._started = false;
7525
- this.events?.onEnd?.();
7526
- });
7527
- } else {
7528
- const audio = play;
7529
- const p = audio.play(filePath, (err) => {
7530
- if (this._stopped) return;
7531
- if (err) {
7532
- this.handleError(err);
7533
- return;
7532
+ reject(error);
7533
+ });
7534
+ } else {
7535
+ const playerSound = play;
7536
+ const p = playerSound.play(filePath);
7537
+ if (p && p.then) {
7538
+ p.then(() => {
7539
+ if (this._stopped) {
7540
+ resolve();
7541
+ return;
7542
+ }
7543
+ this._started = false;
7544
+ this.events?.onEnd?.();
7545
+ resolve();
7546
+ }).catch((err) => {
7547
+ if (this._stopped) {
7548
+ resolve();
7549
+ return;
7550
+ }
7551
+ this._started = false;
7552
+ this.handleError(err);
7553
+ reject(err);
7554
+ });
7555
+ } else if (p && p.kill) {
7556
+ this.player = p;
7557
+ p.on("error", (error) => {
7558
+ this.handleError(error);
7559
+ reject(error);
7560
+ });
7561
+ p.on("close", () => {
7562
+ if (this._stopped) {
7563
+ resolve();
7564
+ return;
7565
+ }
7566
+ this._started = false;
7567
+ this.events?.onEnd?.();
7568
+ resolve();
7569
+ });
7570
+ } else {
7571
+ resolve();
7534
7572
  }
7535
- this._started = false;
7536
- this.events?.onEnd?.();
7537
- });
7538
- if (p && p.kill) {
7539
- this.player = p;
7540
7573
  }
7541
- }
7542
- if (this.player) {
7543
- this.player.on("error", (error) => {
7544
- this.handleError(error);
7545
- });
7546
- }
7547
- } catch (err) {
7548
- this.handleError(err instanceof Error ? err : new Error(String(err)));
7549
- }
7574
+ }).catch((err) => {
7575
+ const error = err instanceof Error ? err : new Error(String(err));
7576
+ error.message = `play-sound load failed: ${error.message}`;
7577
+ this.handleError(error);
7578
+ reject(error);
7579
+ });
7580
+ });
7550
7581
  }
7551
7582
  write(chunk) {
7552
7583
  if (this._stopped) return;
@@ -7694,7 +7725,7 @@ var SpeakerBackend = class {
7694
7725
  return false;
7695
7726
  }
7696
7727
  stripWavHeader(chunk) {
7697
- return chunk.slice(44);
7728
+ return chunk.subarray(44);
7698
7729
  }
7699
7730
  createSpeaker() {
7700
7731
  try {
@@ -7767,6 +7798,130 @@ var SpeakerBackend = class {
7767
7798
 
7768
7799
  // src/core/backends/index.ts
7769
7800
  import { execSync } from "child_process";
7801
+
7802
+ // src/core/notification.ts
7803
+ var logger3 = createModuleLogger("NotificationService");
7804
+ var SISYPHUS_SPINNER = ["\xB7", "\u2022", "\u25CF", "\u25CB", "\u25CC", "\u25E6", " "];
7805
+ var NotificationService = class {
7806
+ tui = null;
7807
+ pendingToasts = [];
7808
+ retryTimer;
7809
+ setTui(tui) {
7810
+ this.tui = tui;
7811
+ logger3.debug("tui reference set");
7812
+ this.flushPending();
7813
+ }
7814
+ showToast(options) {
7815
+ const title = options.title || this.getTitleForVariant(options.variant || "info");
7816
+ const { message, variant = "info", duration = 5e3 } = options;
7817
+ if (!this.tui) {
7818
+ logger3.debug({ title }, "tui not ready, queueing toast");
7819
+ this.pendingToasts.push({ ...options, title });
7820
+ this.scheduleRetry();
7821
+ return false;
7822
+ }
7823
+ try {
7824
+ this.tui.showToast({
7825
+ body: {
7826
+ title,
7827
+ message,
7828
+ variant,
7829
+ duration
7830
+ }
7831
+ });
7832
+ logger3.debug({ title, variant }, "toast shown");
7833
+ return true;
7834
+ } catch (err) {
7835
+ logger3.warn({ err, title }, "toast call failed, queueing for retry");
7836
+ this.pendingToasts.push({ ...options, title });
7837
+ this.scheduleRetry();
7838
+ return false;
7839
+ }
7840
+ }
7841
+ scheduleRetry() {
7842
+ if (this.retryTimer) return;
7843
+ this.retryTimer = setTimeout(() => {
7844
+ this.retryTimer = void 0;
7845
+ this.flushPending();
7846
+ }, 2e3);
7847
+ }
7848
+ flushPending() {
7849
+ if (this.pendingToasts.length === 0 || !this.tui) return;
7850
+ logger3.info({ count: this.pendingToasts.length }, "flushing pending toasts");
7851
+ const pending = [...this.pendingToasts];
7852
+ this.pendingToasts = [];
7853
+ for (const toast of pending) {
7854
+ try {
7855
+ this.showToast(toast);
7856
+ } catch (err) {
7857
+ this.pendingToasts.push(toast);
7858
+ logger3.warn({ err }, "showToast threw unexpected error, re-queued");
7859
+ }
7860
+ }
7861
+ }
7862
+ success(titleOrMessage, messageOrDuration, duration) {
7863
+ if (typeof messageOrDuration === "string") {
7864
+ return this.showToast({ title: titleOrMessage, message: messageOrDuration, variant: "success", duration });
7865
+ }
7866
+ return this.showToast({ message: titleOrMessage, variant: "success", duration: messageOrDuration });
7867
+ }
7868
+ error(titleOrMessage, messageOrDuration, duration) {
7869
+ if (typeof messageOrDuration === "string") {
7870
+ return this.showToast({ title: titleOrMessage, message: messageOrDuration, variant: "error", duration });
7871
+ }
7872
+ return this.showToast({ message: titleOrMessage, variant: "error", duration: messageOrDuration || 8e3 });
7873
+ }
7874
+ info(titleOrMessage, messageOrDuration, duration) {
7875
+ if (typeof messageOrDuration === "string") {
7876
+ return this.showToast({ title: titleOrMessage, message: messageOrDuration, variant: "info", duration });
7877
+ }
7878
+ return this.showToast({ message: titleOrMessage, variant: "info", duration: messageOrDuration });
7879
+ }
7880
+ warning(titleOrMessage, messageOrDuration, duration) {
7881
+ if (typeof messageOrDuration === "string") {
7882
+ return this.showToast({ title: titleOrMessage, message: messageOrDuration, variant: "warning", duration });
7883
+ }
7884
+ return this.showToast({ message: titleOrMessage, variant: "warning", duration: messageOrDuration });
7885
+ }
7886
+ async showSpinnerToast(title, message, duration = 2e3) {
7887
+ const frameInterval = 100;
7888
+ const totalFrames = Math.ceil(duration / frameInterval);
7889
+ for (let i = 0; i < totalFrames; i++) {
7890
+ const spinner = SISYPHUS_SPINNER[i % SISYPHUS_SPINNER.length];
7891
+ const toastDuration = Math.min(frameInterval + 50, duration - i * frameInterval);
7892
+ if (toastDuration <= 0) break;
7893
+ if (this.tui?.showToast) {
7894
+ try {
7895
+ await this.tui.showToast({
7896
+ body: {
7897
+ title: `${spinner} ${title}`,
7898
+ message,
7899
+ variant: "info",
7900
+ duration: toastDuration
7901
+ }
7902
+ });
7903
+ } catch (err) {
7904
+ logger3.warn({ err }, "showSpinnerToast failed");
7905
+ }
7906
+ }
7907
+ if (i < totalFrames - 1) {
7908
+ await new Promise((resolve) => setTimeout(resolve, frameInterval));
7909
+ }
7910
+ }
7911
+ }
7912
+ getTitleForVariant(variant) {
7913
+ const titles = {
7914
+ success: "Success",
7915
+ error: "Error",
7916
+ warning: "Warning",
7917
+ info: "Info"
7918
+ };
7919
+ return titles[variant];
7920
+ }
7921
+ };
7922
+ var notificationService = new NotificationService();
7923
+
7924
+ // src/core/backends/index.ts
7770
7925
  function execCmd(cmd) {
7771
7926
  try {
7772
7927
  const output = execSync(cmd, { stdio: "pipe", encoding: "utf8" });
@@ -7796,12 +7951,21 @@ function isSpeakerAvailable() {
7796
7951
  return false;
7797
7952
  }
7798
7953
  }
7954
+ function isWSL() {
7955
+ if (process.platform !== "linux") return false;
7956
+ try {
7957
+ const output = execSync("uname -r", { stdio: "pipe", encoding: "utf8" });
7958
+ return output.toLowerCase().includes("microsoft");
7959
+ } catch {
7960
+ return false;
7961
+ }
7962
+ }
7799
7963
  function createBackend(type = "auto" /* AUTO */, options = {}) {
7800
7964
  const platform = process.platform;
7801
7965
  if (type !== "auto" /* AUTO */) {
7802
7966
  return createBackendByType(type, options);
7803
7967
  }
7804
- if (isNaudiodonAvailable()) {
7968
+ if (!isWSL() && isNaudiodonAvailable()) {
7805
7969
  try {
7806
7970
  const naudiodon = __require("naudiodon");
7807
7971
  if (naudiodon) {
@@ -7813,12 +7977,35 @@ function createBackend(type = "auto" /* AUTO */, options = {}) {
7813
7977
  }
7814
7978
  } catch (err) {
7815
7979
  logger.error({ err }, "failed to initialize naudiodon backend");
7980
+ notificationService.warning(
7981
+ "naudiodon \u521D\u59CB\u5316\u5931\u8D25",
7982
+ "\u5C06\u4F7F\u7528\u5176\u4ED6\u97F3\u9891\u540E\u7AEF",
7983
+ 5e3
7984
+ );
7816
7985
  }
7817
7986
  }
7818
7987
  switch (platform) {
7819
7988
  case "darwin":
7820
7989
  return new AfplayBackend(options);
7821
- case "linux":
7990
+ case "linux": {
7991
+ const wsl = isWSL();
7992
+ if (wsl) {
7993
+ logger.debug("Running on WSL, skipping naudiodon (may not work with Windows audio)");
7994
+ }
7995
+ if (!wsl && isNaudiodonAvailable()) {
7996
+ try {
7997
+ const naudiodon = __require("naudiodon");
7998
+ if (naudiodon) {
7999
+ const devices = naudiodon.getDevices();
8000
+ if (devices && devices.length > 0) {
8001
+ return new NaudiodonBackend(options);
8002
+ }
8003
+ logger.debug("naudiodon has no audio devices, skipping");
8004
+ }
8005
+ } catch (err) {
8006
+ logger.error({ err }, "failed to initialize naudiodon backend");
8007
+ }
8008
+ }
7822
8009
  if (isCommandAvailable("aplay")) {
7823
8010
  const test = execCmd("aplay -l");
7824
8011
  if (test.success && !test.output.includes("no soundcards")) {
@@ -7833,6 +8020,7 @@ function createBackend(type = "auto" /* AUTO */, options = {}) {
7833
8020
  }
7834
8021
  logger.warn("All Linux audio backends failed, using HowlerBackend as fallback");
7835
8022
  return new HowlerBackend(options);
8023
+ }
7836
8024
  case "win32":
7837
8025
  return new PowerShellBackend(options);
7838
8026
  default:
@@ -7966,11 +8154,8 @@ var AudioPlayer = class extends EventEmitter {
7966
8154
  * 播放音频文件
7967
8155
  * 使用 AudioBackend 统一后端播放
7968
8156
  */
7969
- playFile(filePath, _format) {
7970
- return new Promise((resolve) => {
7971
- this.backend.start(filePath);
7972
- resolve();
7973
- });
8157
+ async playFile(filePath, _format) {
8158
+ await Promise.resolve(this.backend.start(filePath));
7974
8159
  }
7975
8160
  pause() {
7976
8161
  if (!this._playing || this._paused) return;
@@ -8016,79 +8201,6 @@ var AudioPlayer = class extends EventEmitter {
8016
8201
  }
8017
8202
  };
8018
8203
 
8019
- // src/core/notification.ts
8020
- var logger3 = createModuleLogger("NotificationService");
8021
- var NotificationService = class {
8022
- tui = null;
8023
- pendingToasts = [];
8024
- retryTimer;
8025
- setTui(tui) {
8026
- this.tui = tui;
8027
- logger3.debug("tui reference set");
8028
- this.flushPending();
8029
- }
8030
- showToast(options) {
8031
- const { title, message, variant = "info", duration = 5e3 } = options;
8032
- if (!this.tui) {
8033
- logger3.debug({ title }, "tui not ready, queueing toast");
8034
- this.pendingToasts.push(options);
8035
- this.scheduleRetry();
8036
- return false;
8037
- }
8038
- try {
8039
- this.tui.showToast({
8040
- body: {
8041
- title,
8042
- message,
8043
- variant,
8044
- duration
8045
- }
8046
- });
8047
- logger3.debug({ title, variant }, "toast shown");
8048
- return true;
8049
- } catch (err) {
8050
- logger3.warn({ err, title }, "toast call failed, queueing for retry");
8051
- this.pendingToasts.push(options);
8052
- this.scheduleRetry();
8053
- return false;
8054
- }
8055
- }
8056
- scheduleRetry() {
8057
- if (this.retryTimer) return;
8058
- this.retryTimer = setTimeout(() => {
8059
- this.retryTimer = void 0;
8060
- this.flushPending();
8061
- }, 2e3);
8062
- }
8063
- flushPending() {
8064
- if (this.pendingToasts.length === 0 || !this.tui) return;
8065
- logger3.info({ count: this.pendingToasts.length }, "flushing pending toasts");
8066
- const pending = [...this.pendingToasts];
8067
- this.pendingToasts = [];
8068
- for (const toast of pending) {
8069
- try {
8070
- this.showToast(toast);
8071
- } catch (err) {
8072
- this.pendingToasts.push(toast);
8073
- logger3.warn({ err }, "showToast threw unexpected error, re-queued");
8074
- }
8075
- }
8076
- }
8077
- success(title, message, duration) {
8078
- return this.showToast({ title, message, variant: "success", duration });
8079
- }
8080
- error(title, message, duration) {
8081
- return this.showToast({ title, message, variant: "error", duration });
8082
- }
8083
- info(title, message, duration) {
8084
- return this.showToast({ title, message, variant: "info", duration });
8085
- }
8086
- warning(title, message, duration) {
8087
- return this.showToast({ title, message, variant: "warning", duration });
8088
- }
8089
- };
8090
- var notificationService = new NotificationService();
8091
-
8092
8204
  // src/core/speaker.ts
8093
8205
  var logger4 = createModuleLogger("Speaker");
8094
8206
  var Speaker2 = class extends EventEmitter2 {
@@ -8294,12 +8406,10 @@ async function listVoices(providerName) {
8294
8406
 
8295
8407
  // src/services/speaker-service.ts
8296
8408
  var SpeakerService = class {
8297
- constructor(options = {}) {
8298
- this.options = options;
8409
+ speaker;
8410
+ constructor(_options = {}) {
8299
8411
  this.speaker = getDefaultSpeaker();
8300
8412
  }
8301
- options;
8302
- speaker;
8303
8413
  async speak(text, options) {
8304
8414
  const timestamp = this.getTimestamp();
8305
8415
  logger.info(`[Ocosay][${timestamp}][INFO][Speaker] \u5BF9\u5E94\u4E8B\u4EF6{\u64AD\u653E\u5F00\u59CB} - \u6587\u672C\u957F\u5EA6: ${text.length}`);
@@ -8375,13 +8485,14 @@ var StreamPlayer = class extends EventEmitter3 {
8375
8485
  _started = false;
8376
8486
  _paused = false;
8377
8487
  _stopped = false;
8488
+ _starting = false;
8378
8489
  format = "mp3";
8379
8490
  events;
8380
8491
  constructor(options = {}) {
8381
8492
  super();
8382
8493
  this.format = options.format || "mp3";
8383
8494
  this.events = options.events;
8384
- const backendType = options.backendType || "naudiodon" /* NAUDIODON */;
8495
+ const backendType = options.backendType || "auto" /* AUTO */;
8385
8496
  this.backend = createBackend(backendType, {
8386
8497
  format: this.format,
8387
8498
  events: {
@@ -8421,7 +8532,7 @@ var StreamPlayer = class extends EventEmitter3 {
8421
8532
  * 开始播放
8422
8533
  * 初始化后端,准备接收音频数据
8423
8534
  */
8424
- start() {
8535
+ async start() {
8425
8536
  if (this._started) {
8426
8537
  return;
8427
8538
  }
@@ -8429,7 +8540,7 @@ var StreamPlayer = class extends EventEmitter3 {
8429
8540
  this.handleError(new Error("Audio backend not initialized"));
8430
8541
  return;
8431
8542
  }
8432
- this.backend.start("");
8543
+ await Promise.resolve(this.backend.start(""));
8433
8544
  this._started = true;
8434
8545
  this._stopped = false;
8435
8546
  this._paused = false;
@@ -8439,15 +8550,23 @@ var StreamPlayer = class extends EventEmitter3 {
8439
8550
  * 写入音频数据块(边收边播)
8440
8551
  * 如果尚未 start(),会自动调用
8441
8552
  */
8442
- write(chunk) {
8553
+ async write(chunk) {
8443
8554
  if (this._stopped) {
8444
8555
  return;
8445
8556
  }
8446
8557
  if (!this._started) {
8447
- this.start();
8558
+ while (this._starting) {
8559
+ await new Promise((resolve) => setTimeout(resolve, 10));
8560
+ }
8561
+ this._starting = true;
8562
+ try {
8563
+ await this.start();
8564
+ } finally {
8565
+ this._starting = false;
8566
+ }
8448
8567
  }
8449
8568
  if (this.backend) {
8450
- this.backend.write(chunk);
8569
+ await Promise.resolve(this.backend.write(chunk));
8451
8570
  this._bytesWritten += chunk.length;
8452
8571
  this.events?.onProgress?.(this._bytesWritten);
8453
8572
  this.emit("progress", this._bytesWritten);
@@ -8637,7 +8756,7 @@ var StreamingService = class extends EventEmitter4 {
8637
8756
  );
8638
8757
  }
8639
8758
  const player = this.initPlayer();
8640
- player.start();
8759
+ await player.start();
8641
8760
  this._isActive = true;
8642
8761
  this._bytesWritten = 0;
8643
8762
  const result = await provider.speak(text, {
@@ -8663,7 +8782,7 @@ var StreamingService = class extends EventEmitter4 {
8663
8782
  if (result.isStream && result.audioData instanceof ReadableStream) {
8664
8783
  await this.streamAudioChunks(result.audioData, player);
8665
8784
  } else if (Buffer.isBuffer(result.audioData)) {
8666
- player.write(result.audioData);
8785
+ await player.write(result.audioData);
8667
8786
  player.end();
8668
8787
  }
8669
8788
  }
@@ -8680,7 +8799,7 @@ var StreamingService = class extends EventEmitter4 {
8680
8799
  }
8681
8800
  if (value) {
8682
8801
  const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
8683
- player.write(chunk);
8802
+ await player.write(chunk);
8684
8803
  }
8685
8804
  }
8686
8805
  } finally {
@@ -8942,7 +9061,6 @@ var MiniMaxProvider = class extends BaseTTSProvider {
8942
9061
  config;
8943
9062
  httpClient;
8944
9063
  wsConnection;
8945
- currentAudioData = [];
8946
9064
  audioFormat = "mp3";
8947
9065
  constructor(config) {
8948
9066
  super();
@@ -9668,7 +9786,7 @@ function initializeStreamComponents(config) {
9668
9786
  },
9669
9787
  onEnd: () => {
9670
9788
  },
9671
- onProgress: (bytesWritten) => {
9789
+ onProgress: (_bytesWritten) => {
9672
9790
  },
9673
9791
  onError: (error) => logger.error({ error }, "stream player error"),
9674
9792
  onStop: () => {
@@ -10119,15 +10237,15 @@ async function ensureSpeakerInstalledAsync() {
10119
10237
  await ensurePlaySoundInstalled();
10120
10238
  }
10121
10239
  async function initAsync() {
10122
- setTimeout(async () => {
10123
- await ensureSpeakerInstalledAsync();
10124
- }, 100);
10240
+ await new Promise((resolve) => setTimeout(resolve, 100));
10241
+ await ensureSpeakerInstalledAsync();
10125
10242
  }
10126
10243
  async function ensurePlaySoundInstalled() {
10127
10244
  const dep = "play-sound";
10128
10245
  if (isModuleInstalled(dep)) {
10129
10246
  logger8.info("play-sound already installed");
10130
10247
  if (await verifyModuleLoad(dep)) {
10248
+ notificationService.success("play-sound \u5DF2\u5C31\u7EEA", "\u97F3\u9891\u540E\u7AEF\u6B63\u5E38", 5e3);
10131
10249
  return;
10132
10250
  }
10133
10251
  }
@@ -10429,6 +10547,45 @@ var server = (async (input, _options) => {
10429
10547
  global.__opencode_tui__ = opencodeTui;
10430
10548
  notificationService.setTui(opencodeTui);
10431
10549
  const config = loadOrCreateConfig();
10550
+ function collectEnvironmentInfo() {
10551
+ const lines = [];
10552
+ lines.push(`Auto-read: ${config.autoRead ? "ON" : "OFF"}`);
10553
+ let naudiodonOk = false;
10554
+ try {
10555
+ pluginRequire.resolve("naudiodon");
10556
+ naudiodonOk = true;
10557
+ } catch {
10558
+ naudiodonOk = false;
10559
+ }
10560
+ const playSoundOk = isModuleInstalled("play-sound");
10561
+ const platform = process.platform;
10562
+ let backend = "unknown";
10563
+ if (naudiodonOk) {
10564
+ backend = "naudiodon";
10565
+ } else if (platform === "linux") {
10566
+ if (checkAlsa()) {
10567
+ backend = "aplay";
10568
+ } else if (checkFFplay()) {
10569
+ backend = "ffplay";
10570
+ } else {
10571
+ backend = "howler";
10572
+ }
10573
+ } else if (platform === "darwin") {
10574
+ backend = "afplay";
10575
+ } else if (platform === "win32") {
10576
+ backend = "powershell";
10577
+ } else {
10578
+ backend = "howler";
10579
+ }
10580
+ const ffplayOk = checkFFplay();
10581
+ const alsaOk = checkAlsa();
10582
+ lines.push(`naudiodon: ${naudiodonOk ? "\u2713" : "\u2717"}`);
10583
+ lines.push(`play-sound: ${playSoundOk ? "\u2713" : "\u2717"}`);
10584
+ lines.push(`backend: ${backend}`);
10585
+ lines.push(`ffplay: ${ffplayOk ? "\u2713" : "\u2717"}`);
10586
+ lines.push(`alsa: ${alsaOk ? "\u2713" : "\u2717"}`);
10587
+ return lines.join("\n");
10588
+ }
10432
10589
  try {
10433
10590
  await initialize({
10434
10591
  autoRead: config.autoRead,
@@ -10444,21 +10601,22 @@ var server = (async (input, _options) => {
10444
10601
  initError = err instanceof Error ? err : new Error(String(err));
10445
10602
  logger8.error({ error: initError }, "initialization failed");
10446
10603
  }
10447
- initAsync();
10604
+ await initAsync();
10448
10605
  await ensureNaudiodonCompiled();
10449
10606
  await ensureOptionalDepsInstalled();
10450
10607
  await checkAudioEnvironmentForBackend();
10451
10608
  setTimeout(() => {
10609
+ const envInfo = collectEnvironmentInfo();
10452
10610
  if (initError) {
10453
10611
  notificationService.error(
10454
- `Ocosay v${pluginVersion} Init Failed`,
10455
- "Please check your config file",
10612
+ `Ocosay v${pluginVersion} Init Failed
10613
+ Please check your config file`,
10456
10614
  8e3
10457
10615
  );
10458
10616
  } else {
10459
- notificationService.success(
10617
+ notificationService.showSpinnerToast(
10460
10618
  `Ocosay v${pluginVersion} Ready`,
10461
- `Auto-read: ${config.autoRead ? "ON" : "OFF"}`,
10619
+ envInfo,
10462
10620
  5e3
10463
10621
  );
10464
10622
  }
@@ -35,7 +35,6 @@ export declare class MiniMaxProvider extends BaseTTSProvider {
35
35
  private config;
36
36
  private httpClient;
37
37
  private wsConnection?;
38
- private currentAudioData;
39
38
  private audioFormat;
40
39
  constructor(config: MiniMaxConfig);
41
40
  initialize(): Promise<void>;
@@ -24,7 +24,6 @@ export class MiniMaxProvider extends BaseTTSProvider {
24
24
  config;
25
25
  httpClient;
26
26
  wsConnection;
27
- currentAudioData = [];
28
27
  audioFormat = 'mp3';
29
28
  constructor(config) {
30
29
  super();