@mingxy/ocosay 1.0.35 → 1.1.1

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.
Files changed (72) hide show
  1. package/dist/config.js +4 -1
  2. package/dist/core/backends/index.js +8 -3
  3. package/dist/core/notification.d.ts +27 -0
  4. package/dist/core/notification.js +86 -0
  5. package/dist/core/speaker.js +6 -35
  6. package/dist/core/stream-reader.js +2 -1
  7. package/dist/core/streaming-synthesizer.js +2 -0
  8. package/dist/index.d.ts +1 -13
  9. package/dist/index.js +4 -23
  10. package/dist/package.json +2 -2
  11. package/dist/plugin.js +990 -586
  12. package/dist/providers/minimax.js +43 -20
  13. package/dist/services/notification-service.d.ts +17 -0
  14. package/dist/services/notification-service.js +74 -0
  15. package/dist/services/speaker-service.d.ts +34 -0
  16. package/dist/services/speaker-service.js +74 -0
  17. package/dist/services/streaming-service.d.ts +109 -0
  18. package/dist/services/streaming-service.js +281 -0
  19. package/dist/tools/tts.js +32 -19
  20. package/dist/utils/logger.d.ts +6 -0
  21. package/dist/utils/logger.js +42 -6
  22. package/package.json +2 -2
  23. package/.idea/UniappTool.xml +0 -10
  24. package/.idea/inspectionProfiles/profiles_settings.xml +0 -5
  25. package/.idea/modules.xml +0 -8
  26. package/.idea/ocosay.iml +0 -12
  27. package/.idea/vcs.xml +0 -6
  28. package/.sisyphus/boulder.json +0 -23
  29. package/dist/config.d.ts.map +0 -1
  30. package/dist/config.js.map +0 -1
  31. package/dist/core/backends/afplay-backend.d.ts.map +0 -1
  32. package/dist/core/backends/afplay-backend.js.map +0 -1
  33. package/dist/core/backends/aplay-backend.d.ts.map +0 -1
  34. package/dist/core/backends/aplay-backend.js.map +0 -1
  35. package/dist/core/backends/base.d.ts.map +0 -1
  36. package/dist/core/backends/base.js.map +0 -1
  37. package/dist/core/backends/howler-backend.d.ts.map +0 -1
  38. package/dist/core/backends/howler-backend.js.map +0 -1
  39. package/dist/core/backends/index.d.ts.map +0 -1
  40. package/dist/core/backends/index.js.map +0 -1
  41. package/dist/core/backends/naudiodon-backend.d.ts.map +0 -1
  42. package/dist/core/backends/naudiodon-backend.js.map +0 -1
  43. package/dist/core/backends/powershell-backend.d.ts.map +0 -1
  44. package/dist/core/backends/powershell-backend.js.map +0 -1
  45. package/dist/core/logger.d.ts.map +0 -1
  46. package/dist/core/logger.js.map +0 -1
  47. package/dist/core/player.d.ts.map +0 -1
  48. package/dist/core/player.js.map +0 -1
  49. package/dist/core/speaker.d.ts.map +0 -1
  50. package/dist/core/speaker.js.map +0 -1
  51. package/dist/core/stream-player.d.ts.map +0 -1
  52. package/dist/core/stream-player.js.map +0 -1
  53. package/dist/core/stream-reader.d.ts.map +0 -1
  54. package/dist/core/stream-reader.js.map +0 -1
  55. package/dist/core/streaming-synthesizer.d.ts.map +0 -1
  56. package/dist/core/streaming-synthesizer.js.map +0 -1
  57. package/dist/core/types.d.ts.map +0 -1
  58. package/dist/core/types.js.map +0 -1
  59. package/dist/index.d.ts.map +0 -1
  60. package/dist/index.js.map +0 -1
  61. package/dist/plugin.d.ts.map +0 -1
  62. package/dist/plugin.js.map +0 -7
  63. package/dist/providers/base.d.ts.map +0 -1
  64. package/dist/providers/base.js.map +0 -1
  65. package/dist/providers/minimax.d.ts.map +0 -1
  66. package/dist/providers/minimax.js.map +0 -1
  67. package/dist/tools/tts.d.ts.map +0 -1
  68. package/dist/tools/tts.js.map +0 -1
  69. package/dist/types/config.d.ts.map +0 -1
  70. package/dist/types/config.js.map +0 -1
  71. package/dist/utils/logger.d.ts.map +0 -1
  72. package/dist/utils/logger.js.map +0 -1
package/dist/plugin.js CHANGED
@@ -593,17 +593,17 @@ var require_howler = __commonJS({
593
593
  var duration = Math.max(0, (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1e3 - seek);
594
594
  var timeout = duration * 1e3 / Math.abs(sound._rate);
595
595
  var start = self._sprite[sprite][0] / 1e3;
596
- var stop2 = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1e3;
596
+ var stop3 = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1e3;
597
597
  sound._sprite = sprite;
598
598
  sound._ended = false;
599
599
  var setParams = function() {
600
600
  sound._paused = false;
601
601
  sound._seek = seek;
602
602
  sound._start = start;
603
- sound._stop = stop2;
603
+ sound._stop = stop3;
604
604
  sound._loop = !!(sound._loop || self._sprite[sprite][2]);
605
605
  };
606
- if (seek >= stop2) {
606
+ if (seek >= stop3) {
607
607
  self._ended(sound);
608
608
  return;
609
609
  }
@@ -3418,7 +3418,7 @@ var require_sonic_boom = __commonJS({
3418
3418
  "node_modules/sonic-boom/index.js"(exports, module) {
3419
3419
  "use strict";
3420
3420
  var fs3 = __require("fs");
3421
- var EventEmitter6 = __require("events");
3421
+ var EventEmitter7 = __require("events");
3422
3422
  var inherits = __require("util").inherits;
3423
3423
  var path2 = __require("path");
3424
3424
  var sleep = require_atomic_sleep();
@@ -3655,7 +3655,7 @@ var require_sonic_boom = __commonJS({
3655
3655
  sonic._asyncDrainScheduled = false;
3656
3656
  sonic.emit("drain");
3657
3657
  }
3658
- inherits(SonicBoom, EventEmitter6);
3658
+ inherits(SonicBoom, EventEmitter7);
3659
3659
  function mergeBuf(bufs, len) {
3660
3660
  if (bufs.length === 0) {
3661
3661
  return kEmptyBuffer;
@@ -4223,7 +4223,7 @@ var require_thread_stream = __commonJS({
4223
4223
  "node_modules/thread-stream/index.js"(exports, module) {
4224
4224
  "use strict";
4225
4225
  var { version } = require_package();
4226
- var { EventEmitter: EventEmitter6 } = __require("events");
4226
+ var { EventEmitter: EventEmitter7 } = __require("events");
4227
4227
  var { Worker } = __require("worker_threads");
4228
4228
  var { join: join8 } = __require("path");
4229
4229
  var { pathToFileURL } = __require("url");
@@ -4258,7 +4258,7 @@ var require_thread_stream = __commonJS({
4258
4258
  }
4259
4259
  worker.terminate();
4260
4260
  });
4261
- function createWorker(stream, opts) {
4261
+ function createWorker(stream2, opts) {
4262
4262
  const { filename, workerData } = opts;
4263
4263
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
4264
4264
  const toExecute = bundlerOverrides["thread-stream-worker"] || join8(__dirname, "lib", "worker.js");
@@ -4267,8 +4267,8 @@ var require_thread_stream = __commonJS({
4267
4267
  trackUnmanagedFds: false,
4268
4268
  workerData: {
4269
4269
  filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL(filename).href,
4270
- dataBuf: stream[kImpl].dataBuf,
4271
- stateBuf: stream[kImpl].stateBuf,
4270
+ dataBuf: stream2[kImpl].dataBuf,
4271
+ stateBuf: stream2[kImpl].stateBuf,
4272
4272
  workerData: {
4273
4273
  $context: {
4274
4274
  threadStreamVersion: version
@@ -4277,111 +4277,111 @@ var require_thread_stream = __commonJS({
4277
4277
  }
4278
4278
  }
4279
4279
  });
4280
- worker.stream = new FakeWeakRef(stream);
4280
+ worker.stream = new FakeWeakRef(stream2);
4281
4281
  worker.on("message", onWorkerMessage);
4282
4282
  worker.on("exit", onWorkerExit);
4283
- registry.register(stream, worker);
4283
+ registry.register(stream2, worker);
4284
4284
  return worker;
4285
4285
  }
4286
- function drain(stream) {
4287
- assert(!stream[kImpl].sync);
4288
- if (stream[kImpl].needDrain) {
4289
- stream[kImpl].needDrain = false;
4290
- stream.emit("drain");
4286
+ function drain(stream2) {
4287
+ assert(!stream2[kImpl].sync);
4288
+ if (stream2[kImpl].needDrain) {
4289
+ stream2[kImpl].needDrain = false;
4290
+ stream2.emit("drain");
4291
4291
  }
4292
4292
  }
4293
- function nextFlush(stream) {
4294
- const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX);
4295
- let leftover = stream[kImpl].data.length - writeIndex;
4293
+ function nextFlush(stream2) {
4294
+ const writeIndex = Atomics.load(stream2[kImpl].state, WRITE_INDEX);
4295
+ let leftover = stream2[kImpl].data.length - writeIndex;
4296
4296
  if (leftover > 0) {
4297
- if (stream[kImpl].buf.length === 0) {
4298
- stream[kImpl].flushing = false;
4299
- if (stream[kImpl].ending) {
4300
- end(stream);
4301
- } else if (stream[kImpl].needDrain) {
4302
- process.nextTick(drain, stream);
4297
+ if (stream2[kImpl].buf.length === 0) {
4298
+ stream2[kImpl].flushing = false;
4299
+ if (stream2[kImpl].ending) {
4300
+ end(stream2);
4301
+ } else if (stream2[kImpl].needDrain) {
4302
+ process.nextTick(drain, stream2);
4303
4303
  }
4304
4304
  return;
4305
4305
  }
4306
- let toWrite = stream[kImpl].buf.slice(0, leftover);
4306
+ let toWrite = stream2[kImpl].buf.slice(0, leftover);
4307
4307
  let toWriteBytes = Buffer.byteLength(toWrite);
4308
4308
  if (toWriteBytes <= leftover) {
4309
- stream[kImpl].buf = stream[kImpl].buf.slice(leftover);
4310
- write(stream, toWrite, nextFlush.bind(null, stream));
4309
+ stream2[kImpl].buf = stream2[kImpl].buf.slice(leftover);
4310
+ write(stream2, toWrite, nextFlush.bind(null, stream2));
4311
4311
  } else {
4312
- stream.flush(() => {
4313
- if (stream.destroyed) {
4312
+ stream2.flush(() => {
4313
+ if (stream2.destroyed) {
4314
4314
  return;
4315
4315
  }
4316
- Atomics.store(stream[kImpl].state, READ_INDEX, 0);
4317
- Atomics.store(stream[kImpl].state, WRITE_INDEX, 0);
4318
- Atomics.notify(stream[kImpl].state, READ_INDEX);
4319
- while (toWriteBytes > stream[kImpl].data.length) {
4316
+ Atomics.store(stream2[kImpl].state, READ_INDEX, 0);
4317
+ Atomics.store(stream2[kImpl].state, WRITE_INDEX, 0);
4318
+ Atomics.notify(stream2[kImpl].state, READ_INDEX);
4319
+ while (toWriteBytes > stream2[kImpl].data.length) {
4320
4320
  leftover = leftover / 2;
4321
- toWrite = stream[kImpl].buf.slice(0, leftover);
4321
+ toWrite = stream2[kImpl].buf.slice(0, leftover);
4322
4322
  toWriteBytes = Buffer.byteLength(toWrite);
4323
4323
  }
4324
- stream[kImpl].buf = stream[kImpl].buf.slice(leftover);
4325
- write(stream, toWrite, nextFlush.bind(null, stream));
4324
+ stream2[kImpl].buf = stream2[kImpl].buf.slice(leftover);
4325
+ write(stream2, toWrite, nextFlush.bind(null, stream2));
4326
4326
  });
4327
4327
  }
4328
4328
  } else if (leftover === 0) {
4329
- if (writeIndex === 0 && stream[kImpl].buf.length === 0) {
4329
+ if (writeIndex === 0 && stream2[kImpl].buf.length === 0) {
4330
4330
  return;
4331
4331
  }
4332
- stream.flush(() => {
4333
- Atomics.store(stream[kImpl].state, READ_INDEX, 0);
4334
- Atomics.store(stream[kImpl].state, WRITE_INDEX, 0);
4335
- Atomics.notify(stream[kImpl].state, READ_INDEX);
4336
- nextFlush(stream);
4332
+ stream2.flush(() => {
4333
+ Atomics.store(stream2[kImpl].state, READ_INDEX, 0);
4334
+ Atomics.store(stream2[kImpl].state, WRITE_INDEX, 0);
4335
+ Atomics.notify(stream2[kImpl].state, READ_INDEX);
4336
+ nextFlush(stream2);
4337
4337
  });
4338
4338
  } else {
4339
- destroy(stream, new Error("overwritten"));
4339
+ destroy(stream2, new Error("overwritten"));
4340
4340
  }
4341
4341
  }
4342
4342
  function onWorkerMessage(msg) {
4343
- const stream = this.stream.deref();
4344
- if (stream === void 0) {
4343
+ const stream2 = this.stream.deref();
4344
+ if (stream2 === void 0) {
4345
4345
  this.exited = true;
4346
4346
  this.terminate();
4347
4347
  return;
4348
4348
  }
4349
4349
  switch (msg.code) {
4350
4350
  case "READY":
4351
- this.stream = new WeakRef2(stream);
4352
- stream.flush(() => {
4353
- stream[kImpl].ready = true;
4354
- stream.emit("ready");
4351
+ this.stream = new WeakRef2(stream2);
4352
+ stream2.flush(() => {
4353
+ stream2[kImpl].ready = true;
4354
+ stream2.emit("ready");
4355
4355
  });
4356
4356
  break;
4357
4357
  case "ERROR":
4358
- destroy(stream, msg.err);
4358
+ destroy(stream2, msg.err);
4359
4359
  break;
4360
4360
  case "EVENT":
4361
4361
  if (Array.isArray(msg.args)) {
4362
- stream.emit(msg.name, ...msg.args);
4362
+ stream2.emit(msg.name, ...msg.args);
4363
4363
  } else {
4364
- stream.emit(msg.name, msg.args);
4364
+ stream2.emit(msg.name, msg.args);
4365
4365
  }
4366
4366
  break;
4367
4367
  case "WARNING":
4368
4368
  process.emitWarning(msg.err);
4369
4369
  break;
4370
4370
  default:
4371
- destroy(stream, new Error("this should not happen: " + msg.code));
4371
+ destroy(stream2, new Error("this should not happen: " + msg.code));
4372
4372
  }
4373
4373
  }
4374
4374
  function onWorkerExit(code) {
4375
- const stream = this.stream.deref();
4376
- if (stream === void 0) {
4375
+ const stream2 = this.stream.deref();
4376
+ if (stream2 === void 0) {
4377
4377
  return;
4378
4378
  }
4379
- registry.unregister(stream);
4380
- stream.worker.exited = true;
4381
- stream.worker.off("exit", onWorkerExit);
4382
- destroy(stream, code !== 0 ? new Error("the worker thread exited") : null);
4379
+ registry.unregister(stream2);
4380
+ stream2.worker.exited = true;
4381
+ stream2.worker.off("exit", onWorkerExit);
4382
+ destroy(stream2, code !== 0 ? new Error("the worker thread exited") : null);
4383
4383
  }
4384
- var ThreadStream = class extends EventEmitter6 {
4384
+ var ThreadStream = class extends EventEmitter7 {
4385
4385
  constructor(opts = {}) {
4386
4386
  super();
4387
4387
  if (opts.bufferSize < 4) {
@@ -4512,127 +4512,127 @@ var require_thread_stream = __commonJS({
4512
4512
  return this[kImpl].errored;
4513
4513
  }
4514
4514
  };
4515
- function error(stream, err) {
4515
+ function error(stream2, err) {
4516
4516
  setImmediate(() => {
4517
- stream.emit("error", err);
4517
+ stream2.emit("error", err);
4518
4518
  });
4519
4519
  }
4520
- function destroy(stream, err) {
4521
- if (stream[kImpl].destroyed) {
4520
+ function destroy(stream2, err) {
4521
+ if (stream2[kImpl].destroyed) {
4522
4522
  return;
4523
4523
  }
4524
- stream[kImpl].destroyed = true;
4524
+ stream2[kImpl].destroyed = true;
4525
4525
  if (err) {
4526
- stream[kImpl].errored = err;
4527
- error(stream, err);
4526
+ stream2[kImpl].errored = err;
4527
+ error(stream2, err);
4528
4528
  }
4529
- if (!stream.worker.exited) {
4530
- stream.worker.terminate().catch(() => {
4529
+ if (!stream2.worker.exited) {
4530
+ stream2.worker.terminate().catch(() => {
4531
4531
  }).then(() => {
4532
- stream[kImpl].closed = true;
4533
- stream.emit("close");
4532
+ stream2[kImpl].closed = true;
4533
+ stream2.emit("close");
4534
4534
  });
4535
4535
  } else {
4536
4536
  setImmediate(() => {
4537
- stream[kImpl].closed = true;
4538
- stream.emit("close");
4537
+ stream2[kImpl].closed = true;
4538
+ stream2.emit("close");
4539
4539
  });
4540
4540
  }
4541
4541
  }
4542
- function write(stream, data, cb) {
4543
- const current = Atomics.load(stream[kImpl].state, WRITE_INDEX);
4542
+ function write(stream2, data, cb) {
4543
+ const current = Atomics.load(stream2[kImpl].state, WRITE_INDEX);
4544
4544
  const length = Buffer.byteLength(data);
4545
- stream[kImpl].data.write(data, current);
4546
- Atomics.store(stream[kImpl].state, WRITE_INDEX, current + length);
4547
- Atomics.notify(stream[kImpl].state, WRITE_INDEX);
4545
+ stream2[kImpl].data.write(data, current);
4546
+ Atomics.store(stream2[kImpl].state, WRITE_INDEX, current + length);
4547
+ Atomics.notify(stream2[kImpl].state, WRITE_INDEX);
4548
4548
  cb();
4549
4549
  return true;
4550
4550
  }
4551
- function end(stream) {
4552
- if (stream[kImpl].ended || !stream[kImpl].ending || stream[kImpl].flushing) {
4551
+ function end(stream2) {
4552
+ if (stream2[kImpl].ended || !stream2[kImpl].ending || stream2[kImpl].flushing) {
4553
4553
  return;
4554
4554
  }
4555
- stream[kImpl].ended = true;
4555
+ stream2[kImpl].ended = true;
4556
4556
  try {
4557
- stream.flushSync();
4558
- let readIndex = Atomics.load(stream[kImpl].state, READ_INDEX);
4559
- Atomics.store(stream[kImpl].state, WRITE_INDEX, -1);
4560
- Atomics.notify(stream[kImpl].state, WRITE_INDEX);
4557
+ stream2.flushSync();
4558
+ let readIndex = Atomics.load(stream2[kImpl].state, READ_INDEX);
4559
+ Atomics.store(stream2[kImpl].state, WRITE_INDEX, -1);
4560
+ Atomics.notify(stream2[kImpl].state, WRITE_INDEX);
4561
4561
  let spins = 0;
4562
4562
  while (readIndex !== -1) {
4563
- Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3);
4564
- readIndex = Atomics.load(stream[kImpl].state, READ_INDEX);
4563
+ Atomics.wait(stream2[kImpl].state, READ_INDEX, readIndex, 1e3);
4564
+ readIndex = Atomics.load(stream2[kImpl].state, READ_INDEX);
4565
4565
  if (readIndex === -2) {
4566
- destroy(stream, new Error("end() failed"));
4566
+ destroy(stream2, new Error("end() failed"));
4567
4567
  return;
4568
4568
  }
4569
4569
  if (++spins === 10) {
4570
- destroy(stream, new Error("end() took too long (10s)"));
4570
+ destroy(stream2, new Error("end() took too long (10s)"));
4571
4571
  return;
4572
4572
  }
4573
4573
  }
4574
4574
  process.nextTick(() => {
4575
- stream[kImpl].finished = true;
4576
- stream.emit("finish");
4575
+ stream2[kImpl].finished = true;
4576
+ stream2.emit("finish");
4577
4577
  });
4578
4578
  } catch (err) {
4579
- destroy(stream, err);
4579
+ destroy(stream2, err);
4580
4580
  }
4581
4581
  }
4582
- function writeSync(stream) {
4582
+ function writeSync(stream2) {
4583
4583
  const cb = () => {
4584
- if (stream[kImpl].ending) {
4585
- end(stream);
4586
- } else if (stream[kImpl].needDrain) {
4587
- process.nextTick(drain, stream);
4584
+ if (stream2[kImpl].ending) {
4585
+ end(stream2);
4586
+ } else if (stream2[kImpl].needDrain) {
4587
+ process.nextTick(drain, stream2);
4588
4588
  }
4589
4589
  };
4590
- stream[kImpl].flushing = false;
4591
- while (stream[kImpl].buf.length !== 0) {
4592
- const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX);
4593
- let leftover = stream[kImpl].data.length - writeIndex;
4590
+ stream2[kImpl].flushing = false;
4591
+ while (stream2[kImpl].buf.length !== 0) {
4592
+ const writeIndex = Atomics.load(stream2[kImpl].state, WRITE_INDEX);
4593
+ let leftover = stream2[kImpl].data.length - writeIndex;
4594
4594
  if (leftover === 0) {
4595
- flushSync(stream);
4596
- Atomics.store(stream[kImpl].state, READ_INDEX, 0);
4597
- Atomics.store(stream[kImpl].state, WRITE_INDEX, 0);
4598
- Atomics.notify(stream[kImpl].state, READ_INDEX);
4595
+ flushSync(stream2);
4596
+ Atomics.store(stream2[kImpl].state, READ_INDEX, 0);
4597
+ Atomics.store(stream2[kImpl].state, WRITE_INDEX, 0);
4598
+ Atomics.notify(stream2[kImpl].state, READ_INDEX);
4599
4599
  continue;
4600
4600
  } else if (leftover < 0) {
4601
4601
  throw new Error("overwritten");
4602
4602
  }
4603
- let toWrite = stream[kImpl].buf.slice(0, leftover);
4603
+ let toWrite = stream2[kImpl].buf.slice(0, leftover);
4604
4604
  let toWriteBytes = Buffer.byteLength(toWrite);
4605
4605
  if (toWriteBytes <= leftover) {
4606
- stream[kImpl].buf = stream[kImpl].buf.slice(leftover);
4607
- write(stream, toWrite, cb);
4606
+ stream2[kImpl].buf = stream2[kImpl].buf.slice(leftover);
4607
+ write(stream2, toWrite, cb);
4608
4608
  } else {
4609
- flushSync(stream);
4610
- Atomics.store(stream[kImpl].state, READ_INDEX, 0);
4611
- Atomics.store(stream[kImpl].state, WRITE_INDEX, 0);
4612
- Atomics.notify(stream[kImpl].state, READ_INDEX);
4613
- while (toWriteBytes > stream[kImpl].buf.length) {
4609
+ flushSync(stream2);
4610
+ Atomics.store(stream2[kImpl].state, READ_INDEX, 0);
4611
+ Atomics.store(stream2[kImpl].state, WRITE_INDEX, 0);
4612
+ Atomics.notify(stream2[kImpl].state, READ_INDEX);
4613
+ while (toWriteBytes > stream2[kImpl].buf.length) {
4614
4614
  leftover = leftover / 2;
4615
- toWrite = stream[kImpl].buf.slice(0, leftover);
4615
+ toWrite = stream2[kImpl].buf.slice(0, leftover);
4616
4616
  toWriteBytes = Buffer.byteLength(toWrite);
4617
4617
  }
4618
- stream[kImpl].buf = stream[kImpl].buf.slice(leftover);
4619
- write(stream, toWrite, cb);
4618
+ stream2[kImpl].buf = stream2[kImpl].buf.slice(leftover);
4619
+ write(stream2, toWrite, cb);
4620
4620
  }
4621
4621
  }
4622
4622
  }
4623
- function flushSync(stream) {
4624
- if (stream[kImpl].flushing) {
4623
+ function flushSync(stream2) {
4624
+ if (stream2[kImpl].flushing) {
4625
4625
  throw new Error("unable to flush while flushing");
4626
4626
  }
4627
- const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX);
4627
+ const writeIndex = Atomics.load(stream2[kImpl].state, WRITE_INDEX);
4628
4628
  let spins = 0;
4629
4629
  while (true) {
4630
- const readIndex = Atomics.load(stream[kImpl].state, READ_INDEX);
4630
+ const readIndex = Atomics.load(stream2[kImpl].state, READ_INDEX);
4631
4631
  if (readIndex === -2) {
4632
4632
  throw Error("_flushSync failed");
4633
4633
  }
4634
4634
  if (readIndex !== writeIndex) {
4635
- Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3);
4635
+ Atomics.wait(stream2[kImpl].state, READ_INDEX, readIndex, 1e3);
4636
4636
  } else {
4637
4637
  break;
4638
4638
  }
@@ -4657,11 +4657,11 @@ var require_transport = __commonJS({
4657
4657
  var sleep = require_atomic_sleep();
4658
4658
  var onExit = require_on_exit_leak_free();
4659
4659
  var ThreadStream = require_thread_stream();
4660
- function setupOnExit(stream) {
4661
- onExit.register(stream, autoEnd);
4662
- onExit.registerBeforeExit(stream, flush);
4663
- stream.on("close", function() {
4664
- onExit.unregister(stream);
4660
+ function setupOnExit(stream2) {
4661
+ onExit.register(stream2, autoEnd);
4662
+ onExit.registerBeforeExit(stream2, flush);
4663
+ stream2.on("close", function() {
4664
+ onExit.unregister(stream2);
4665
4665
  });
4666
4666
  }
4667
4667
  function hasPreloadFlags() {
@@ -4754,44 +4754,44 @@ var require_transport = __commonJS({
4754
4754
  }
4755
4755
  }
4756
4756
  workerOpts = { ...workerOpts, name };
4757
- const stream = new ThreadStream({
4757
+ const stream2 = new ThreadStream({
4758
4758
  filename,
4759
4759
  workerData,
4760
4760
  workerOpts,
4761
4761
  sync
4762
4762
  });
4763
- stream.on("ready", onReady);
4764
- stream.on("close", function() {
4763
+ stream2.on("ready", onReady);
4764
+ stream2.on("close", function() {
4765
4765
  process.removeListener("exit", onExit2);
4766
4766
  });
4767
4767
  process.on("exit", onExit2);
4768
4768
  function onReady() {
4769
4769
  process.removeListener("exit", onExit2);
4770
- stream.unref();
4770
+ stream2.unref();
4771
4771
  if (workerOpts.autoEnd !== false) {
4772
- setupOnExit(stream);
4772
+ setupOnExit(stream2);
4773
4773
  }
4774
4774
  }
4775
4775
  function onExit2() {
4776
- if (stream.closed) {
4776
+ if (stream2.closed) {
4777
4777
  return;
4778
4778
  }
4779
- stream.flushSync();
4779
+ stream2.flushSync();
4780
4780
  sleep(100);
4781
- stream.end();
4781
+ stream2.end();
4782
4782
  }
4783
- return stream;
4783
+ return stream2;
4784
4784
  }
4785
- function autoEnd(stream) {
4786
- stream.ref();
4787
- stream.flushSync();
4788
- stream.end();
4789
- stream.once("close", function() {
4790
- stream.unref();
4785
+ function autoEnd(stream2) {
4786
+ stream2.ref();
4787
+ stream2.flushSync();
4788
+ stream2.end();
4789
+ stream2.once("close", function() {
4790
+ stream2.unref();
4791
4791
  });
4792
4792
  }
4793
- function flush(stream) {
4794
- stream.flushSync();
4793
+ function flush(stream2) {
4794
+ stream2.flushSync();
4795
4795
  }
4796
4796
  function transport(fullOptions) {
4797
4797
  const { pipeline, targets, levels, dedupe, worker = {}, caller = getCallers(), sync = false } = fullOptions;
@@ -5071,56 +5071,56 @@ var require_tools = __commonJS({
5071
5071
  }
5072
5072
  return data;
5073
5073
  }
5074
- function hasBeenTampered(stream) {
5075
- return stream.write !== stream.constructor.prototype.write;
5074
+ function hasBeenTampered(stream2) {
5075
+ return stream2.write !== stream2.constructor.prototype.write;
5076
5076
  }
5077
5077
  function buildSafeSonicBoom(opts) {
5078
- const stream = new SonicBoom(opts);
5079
- stream.on("error", filterBrokenPipe);
5078
+ const stream2 = new SonicBoom(opts);
5079
+ stream2.on("error", filterBrokenPipe);
5080
5080
  if (!opts.sync && isMainThread) {
5081
- onExit.register(stream, autoEnd);
5082
- stream.on("close", function() {
5083
- onExit.unregister(stream);
5081
+ onExit.register(stream2, autoEnd);
5082
+ stream2.on("close", function() {
5083
+ onExit.unregister(stream2);
5084
5084
  });
5085
5085
  }
5086
- return stream;
5086
+ return stream2;
5087
5087
  function filterBrokenPipe(err) {
5088
5088
  if (err.code === "EPIPE") {
5089
- stream.write = noop;
5090
- stream.end = noop;
5091
- stream.flushSync = noop;
5092
- stream.destroy = noop;
5089
+ stream2.write = noop;
5090
+ stream2.end = noop;
5091
+ stream2.flushSync = noop;
5092
+ stream2.destroy = noop;
5093
5093
  return;
5094
5094
  }
5095
- stream.removeListener("error", filterBrokenPipe);
5096
- stream.emit("error", err);
5095
+ stream2.removeListener("error", filterBrokenPipe);
5096
+ stream2.emit("error", err);
5097
5097
  }
5098
5098
  }
5099
- function autoEnd(stream, eventName) {
5100
- if (stream.destroyed) {
5099
+ function autoEnd(stream2, eventName) {
5100
+ if (stream2.destroyed) {
5101
5101
  return;
5102
5102
  }
5103
5103
  if (eventName === "beforeExit") {
5104
- stream.flush();
5105
- stream.on("drain", function() {
5106
- stream.end();
5104
+ stream2.flush();
5105
+ stream2.on("drain", function() {
5106
+ stream2.end();
5107
5107
  });
5108
5108
  } else {
5109
- stream.flushSync();
5109
+ stream2.flushSync();
5110
5110
  }
5111
5111
  }
5112
5112
  function createArgsNormalizer(defaultOptions) {
5113
- return function normalizeArgs(instance, caller, opts = {}, stream) {
5113
+ return function normalizeArgs(instance, caller, opts = {}, stream2) {
5114
5114
  if (typeof opts === "string") {
5115
- stream = buildSafeSonicBoom({ dest: opts });
5115
+ stream2 = buildSafeSonicBoom({ dest: opts });
5116
5116
  opts = {};
5117
- } else if (typeof stream === "string") {
5117
+ } else if (typeof stream2 === "string") {
5118
5118
  if (opts && opts.transport) {
5119
5119
  throw Error("only one of option.transport or stream can be specified");
5120
5120
  }
5121
- stream = buildSafeSonicBoom({ dest: stream });
5121
+ stream2 = buildSafeSonicBoom({ dest: stream2 });
5122
5122
  } else if (opts instanceof SonicBoom || opts.writable || opts._writableState) {
5123
- stream = opts;
5123
+ stream2 = opts;
5124
5124
  opts = {};
5125
5125
  } else if (opts.transport) {
5126
5126
  if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) {
@@ -5133,7 +5133,7 @@ var require_tools = __commonJS({
5133
5133
  if (opts.customLevels) {
5134
5134
  customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels);
5135
5135
  }
5136
- stream = transport({ caller, ...opts.transport, levels: customLevels });
5136
+ stream2 = transport({ caller, ...opts.transport, levels: customLevels });
5137
5137
  }
5138
5138
  opts = Object.assign({}, defaultOptions, opts);
5139
5139
  opts.serializers = Object.assign({}, defaultOptions.serializers, opts.serializers);
@@ -5144,14 +5144,14 @@ var require_tools = __commonJS({
5144
5144
  const { enabled, onChild } = opts;
5145
5145
  if (enabled === false) opts.level = "silent";
5146
5146
  if (!onChild) opts.onChild = noop;
5147
- if (!stream) {
5147
+ if (!stream2) {
5148
5148
  if (!hasBeenTampered(process.stdout)) {
5149
- stream = buildSafeSonicBoom({ fd: process.stdout.fd || 1 });
5149
+ stream2 = buildSafeSonicBoom({ fd: process.stdout.fd || 1 });
5150
5150
  } else {
5151
- stream = process.stdout;
5151
+ stream2 = process.stdout;
5152
5152
  }
5153
5153
  }
5154
- return { opts, stream };
5154
+ return { opts, stream: stream2 };
5155
5155
  };
5156
5156
  }
5157
5157
  function stringify(obj, stringifySafeFn) {
@@ -5238,11 +5238,11 @@ var require_levels = __commonJS({
5238
5238
  fatal: (hook) => {
5239
5239
  const logFatal = genLog(DEFAULT_LEVELS.fatal, hook);
5240
5240
  return function(...args) {
5241
- const stream = this[streamSym];
5241
+ const stream2 = this[streamSym];
5242
5242
  logFatal.call(this, ...args);
5243
- if (typeof stream.flushSync === "function") {
5243
+ if (typeof stream2.flushSync === "function") {
5244
5244
  try {
5245
- stream.flushSync();
5245
+ stream2.flushSync();
5246
5246
  } catch (e) {
5247
5247
  }
5248
5248
  }
@@ -5424,7 +5424,7 @@ var require_meta = __commonJS({
5424
5424
  var require_proto = __commonJS({
5425
5425
  "node_modules/pino/lib/proto.js"(exports, module) {
5426
5426
  "use strict";
5427
- var { EventEmitter: EventEmitter6 } = __require("node:events");
5427
+ var { EventEmitter: EventEmitter7 } = __require("node:events");
5428
5428
  var {
5429
5429
  lsCacheSym,
5430
5430
  levelValSym,
@@ -5505,7 +5505,7 @@ var require_proto = __commonJS({
5505
5505
  [getLevelSym]: getLevel,
5506
5506
  [setLevelSym]: setLevel
5507
5507
  };
5508
- Object.setPrototypeOf(prototype, EventEmitter6.prototype);
5508
+ Object.setPrototypeOf(prototype, EventEmitter7.prototype);
5509
5509
  module.exports = function() {
5510
5510
  return Object.create(prototype);
5511
5511
  };
@@ -5628,23 +5628,23 @@ var require_proto = __commonJS({
5628
5628
  obj = mixinMergeStrategy(obj, mixin(obj, num, this));
5629
5629
  }
5630
5630
  const s = this[asJsonSym](obj, msg, num, t);
5631
- const stream = this[streamSym];
5632
- if (stream[needsMetadataGsym] === true) {
5633
- stream.lastLevel = num;
5634
- stream.lastObj = obj;
5635
- stream.lastMsg = msg;
5636
- stream.lastTime = t.slice(this[timeSliceIndexSym]);
5637
- stream.lastLogger = this;
5631
+ const stream2 = this[streamSym];
5632
+ if (stream2[needsMetadataGsym] === true) {
5633
+ stream2.lastLevel = num;
5634
+ stream2.lastObj = obj;
5635
+ stream2.lastMsg = msg;
5636
+ stream2.lastTime = t.slice(this[timeSliceIndexSym]);
5637
+ stream2.lastLogger = this;
5638
5638
  }
5639
- stream.write(streamWriteHook ? streamWriteHook(s) : s);
5639
+ stream2.write(streamWriteHook ? streamWriteHook(s) : s);
5640
5640
  }
5641
5641
  function flush(cb) {
5642
5642
  if (cb != null && typeof cb !== "function") {
5643
5643
  throw Error("callback must be a function");
5644
5644
  }
5645
- const stream = this[streamSym];
5646
- if (typeof stream.flush === "function") {
5647
- stream.flush(cb || noop);
5645
+ const stream2 = this[streamSym];
5646
+ if (typeof stream2.flush === "function") {
5647
+ stream2.flush(cb || noop);
5648
5648
  } else if (cb) cb();
5649
5649
  }
5650
5650
  }
@@ -6287,25 +6287,25 @@ var require_multistream = __commonJS({
6287
6287
  function write(data) {
6288
6288
  let dest;
6289
6289
  const level2 = this.lastLevel;
6290
- const { streams: streams2 } = this;
6290
+ const { streams } = this;
6291
6291
  let recordedLevel = 0;
6292
- let stream;
6293
- for (let i = initLoopVar(streams2.length, opts.dedupe); checkLoopVar(i, streams2.length, opts.dedupe); i = adjustLoopVar(i, opts.dedupe)) {
6294
- dest = streams2[i];
6292
+ let stream2;
6293
+ for (let i = initLoopVar(streams.length, opts.dedupe); checkLoopVar(i, streams.length, opts.dedupe); i = adjustLoopVar(i, opts.dedupe)) {
6294
+ dest = streams[i];
6295
6295
  if (dest.level <= level2) {
6296
6296
  if (recordedLevel !== 0 && recordedLevel !== dest.level) {
6297
6297
  break;
6298
6298
  }
6299
- stream = dest.stream;
6300
- if (stream[metadata]) {
6299
+ stream2 = dest.stream;
6300
+ if (stream2[metadata]) {
6301
6301
  const { lastTime, lastMsg, lastObj, lastLogger } = this;
6302
- stream.lastLevel = level2;
6303
- stream.lastTime = lastTime;
6304
- stream.lastMsg = lastMsg;
6305
- stream.lastObj = lastObj;
6306
- stream.lastLogger = lastLogger;
6302
+ stream2.lastLevel = level2;
6303
+ stream2.lastTime = lastTime;
6304
+ stream2.lastMsg = lastMsg;
6305
+ stream2.lastObj = lastObj;
6306
+ stream2.lastLogger = lastLogger;
6307
6307
  }
6308
- stream.write(data);
6308
+ stream2.write(data);
6309
6309
  if (opts.dedupe) {
6310
6310
  recordedLevel = dest.level;
6311
6311
  }
@@ -6315,16 +6315,16 @@ var require_multistream = __commonJS({
6315
6315
  }
6316
6316
  }
6317
6317
  function emit(...args) {
6318
- for (const { stream } of this.streams) {
6319
- if (typeof stream.emit === "function") {
6320
- stream.emit(...args);
6318
+ for (const { stream: stream2 } of this.streams) {
6319
+ if (typeof stream2.emit === "function") {
6320
+ stream2.emit(...args);
6321
6321
  }
6322
6322
  }
6323
6323
  }
6324
6324
  function flushSync() {
6325
- for (const { stream } of this.streams) {
6326
- if (typeof stream.flushSync === "function") {
6327
- stream.flushSync();
6325
+ for (const { stream: stream2 } of this.streams) {
6326
+ if (typeof stream2.flushSync === "function") {
6327
+ stream2.flushSync();
6328
6328
  }
6329
6329
  }
6330
6330
  }
@@ -6337,7 +6337,7 @@ var require_multistream = __commonJS({
6337
6337
  if (!isStream) {
6338
6338
  throw Error("stream object needs to implement either StreamEntry or DestinationStream interface");
6339
6339
  }
6340
- const { streams: streams2, streamLevels: streamLevels2 } = this;
6340
+ const { streams, streamLevels: streamLevels2 } = this;
6341
6341
  let level2;
6342
6342
  if (typeof dest.levelVal === "number") {
6343
6343
  level2 = dest.levelVal;
@@ -6354,33 +6354,33 @@ var require_multistream = __commonJS({
6354
6354
  levelVal: void 0,
6355
6355
  id: ++res.lastId
6356
6356
  };
6357
- streams2.unshift(dest_);
6358
- streams2.sort(compareByLevel);
6359
- this.minLevel = streams2[0].level;
6357
+ streams.unshift(dest_);
6358
+ streams.sort(compareByLevel);
6359
+ this.minLevel = streams[0].level;
6360
6360
  return res;
6361
6361
  }
6362
6362
  function remove(id2) {
6363
- const { streams: streams2 } = this;
6364
- const index = streams2.findIndex((s) => s.id === id2);
6363
+ const { streams } = this;
6364
+ const index = streams.findIndex((s) => s.id === id2);
6365
6365
  if (index >= 0) {
6366
- streams2.splice(index, 1);
6367
- streams2.sort(compareByLevel);
6368
- this.minLevel = streams2.length > 0 ? streams2[0].level : -1;
6366
+ streams.splice(index, 1);
6367
+ streams.sort(compareByLevel);
6368
+ this.minLevel = streams.length > 0 ? streams[0].level : -1;
6369
6369
  }
6370
6370
  return res;
6371
6371
  }
6372
6372
  function end() {
6373
- for (const { stream } of this.streams) {
6374
- if (typeof stream.flushSync === "function") {
6375
- stream.flushSync();
6373
+ for (const { stream: stream2 } of this.streams) {
6374
+ if (typeof stream2.flushSync === "function") {
6375
+ stream2.flushSync();
6376
6376
  }
6377
- stream.end();
6377
+ stream2.end();
6378
6378
  }
6379
6379
  }
6380
6380
  function clone(level2) {
6381
- const streams2 = new Array(this.streams.length);
6382
- for (let i = 0; i < streams2.length; i++) {
6383
- streams2[i] = {
6381
+ const streams = new Array(this.streams.length);
6382
+ for (let i = 0; i < streams.length; i++) {
6383
+ streams[i] = {
6384
6384
  level: level2,
6385
6385
  stream: this.streams[i].stream
6386
6386
  };
@@ -6390,7 +6390,7 @@ var require_multistream = __commonJS({
6390
6390
  add,
6391
6391
  remove,
6392
6392
  minLevel: level2,
6393
- streams: streams2,
6393
+ streams,
6394
6394
  clone,
6395
6395
  emit,
6396
6396
  flushSync,
@@ -6503,7 +6503,7 @@ var require_pino = __commonJS({
6503
6503
  var serializers = Object.assign(/* @__PURE__ */ Object.create(null), stdSerializers);
6504
6504
  function pino2(...args) {
6505
6505
  const instance = {};
6506
- const { opts, stream } = normalize(instance, caller(), ...args);
6506
+ const { opts, stream: stream2 } = normalize(instance, caller(), ...args);
6507
6507
  if (opts.level && typeof opts.level === "string" && DEFAULT_LEVELS[opts.level.toLowerCase()] !== void 0) opts.level = opts.level.toLowerCase();
6508
6508
  const {
6509
6509
  redact,
@@ -6566,8 +6566,8 @@ var require_pino = __commonJS({
6566
6566
  if (msgPrefix && typeof msgPrefix !== "string") throw Error(`Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"`);
6567
6567
  assertDefaultLevelFound(level2, customLevels, useOnlyCustomLevels);
6568
6568
  const levels = mappings(customLevels, useOnlyCustomLevels);
6569
- if (typeof stream.emit === "function") {
6570
- stream.emit("message", { code: "PINO_CONFIG", config: { levels, messageKey, errorKey } });
6569
+ if (typeof stream2.emit === "function") {
6570
+ stream2.emit("message", { code: "PINO_CONFIG", config: { levels, messageKey, errorKey } });
6571
6571
  }
6572
6572
  assertLevelComparison(levelComparison);
6573
6573
  const levelCompFunc = genLevelComparison(levelComparison);
@@ -6575,7 +6575,7 @@ var require_pino = __commonJS({
6575
6575
  levels,
6576
6576
  [levelCompSym]: levelCompFunc,
6577
6577
  [useOnlyCustomLevelsSym]: useOnlyCustomLevels,
6578
- [streamSym]: stream,
6578
+ [streamSym]: stream2,
6579
6579
  [timeSym]: time2,
6580
6580
  [timeSliceIndexSym]: timeSliceIndex,
6581
6581
  [stringifySym]: stringify,
@@ -6738,7 +6738,7 @@ import { EventEmitter } from "events";
6738
6738
  import fs from "fs";
6739
6739
  import { createWriteStream } from "fs";
6740
6740
  import { tmpdir as tmpdir4 } from "os";
6741
- import { join as join4 } from "path";
6741
+ import { join as join5 } from "path";
6742
6742
 
6743
6743
  // src/core/backends/naudiodon-backend.ts
6744
6744
  var UnsupportedError = class extends Error {
@@ -7389,12 +7389,74 @@ var HowlerBackend = class {
7389
7389
  }
7390
7390
  };
7391
7391
 
7392
+ // src/utils/logger.ts
7393
+ var import_pino = __toESM(require_pino(), 1);
7394
+ import { Transform } from "stream";
7395
+ import { homedir } from "os";
7396
+ import { join as join4 } from "path";
7397
+ import { existsSync as existsSync4, mkdirSync } from "fs";
7398
+ var logDir = join4(homedir(), ".ocosay");
7399
+ var logFile = join4(logDir, "ocosay.log");
7400
+ if (!existsSync4(logDir)) {
7401
+ try {
7402
+ mkdirSync(logDir, { recursive: true });
7403
+ } catch {
7404
+ }
7405
+ }
7406
+ var level = process.env.NODE_ENV !== "production" ? "debug" : process.env.OCOSAY_LOG_LEVEL || "info";
7407
+ var formatLog = (log) => {
7408
+ const time = log.time ? new Date(log.time).toISOString().replace("T", " ").replace("Z", "") : "";
7409
+ const levelStr = log.level === 30 ? "INFO" : log.level === 40 ? "WARNING" : log.level === 50 ? "ERROR" : "DEBUG";
7410
+ const module = log.module || "App";
7411
+ const msg = log.msg || "";
7412
+ return `[Ocosay][${time}][${levelStr}][${module}] \u5BF9\u5E94\u4E8B\u4EF6{${msg}}
7413
+ `;
7414
+ };
7415
+ var createFormatStream = () => new Transform({
7416
+ transform(chunk, _encoding, callback) {
7417
+ try {
7418
+ const log = JSON.parse(chunk.toString());
7419
+ this.push(formatLog(log));
7420
+ } catch {
7421
+ this.push(chunk);
7422
+ }
7423
+ callback();
7424
+ }
7425
+ });
7426
+ var stdoutStream = createFormatStream();
7427
+ stdoutStream.pipe(process.stdout);
7428
+ var fileStream = null;
7429
+ try {
7430
+ const fileDest = import_pino.default.destination({ dest: logFile, mkdir: true });
7431
+ fileStream = createFormatStream();
7432
+ fileStream.pipe(fileDest);
7433
+ } catch {
7434
+ }
7435
+ var logger = (0, import_pino.default)(
7436
+ {
7437
+ level,
7438
+ base: { service: "ocosay" },
7439
+ timestamp: import_pino.default.stdTimeFunctions.isoTime,
7440
+ formatters: {
7441
+ level: (label) => ({ level: label })
7442
+ }
7443
+ },
7444
+ import_pino.default.multistream([
7445
+ { stream: stdoutStream },
7446
+ ...fileStream ? [{ stream: fileStream }] : []
7447
+ ])
7448
+ );
7449
+ function createModuleLogger(module) {
7450
+ return logger.child({ module });
7451
+ }
7452
+
7392
7453
  // src/core/backends/index.ts
7393
7454
  function isNaudiodonAvailable() {
7394
7455
  try {
7395
7456
  __require.resolve("naudiodon");
7396
7457
  return true;
7397
- } catch (e) {
7458
+ } catch (err) {
7459
+ logger.debug({ err }, "naudiodon not available");
7398
7460
  return false;
7399
7461
  }
7400
7462
  }
@@ -7417,7 +7479,8 @@ function createBackend(type = "auto" /* AUTO */, options = {}) {
7417
7479
  if (naudiodon) {
7418
7480
  return new NaudiodonBackend(options);
7419
7481
  }
7420
- } catch (e) {
7482
+ } catch (err) {
7483
+ logger.warn({ err }, "failed to initialize naudiodon backend");
7421
7484
  }
7422
7485
  }
7423
7486
  switch (platform) {
@@ -7510,7 +7573,7 @@ var AudioPlayer = class extends EventEmitter {
7510
7573
  this._playing = true;
7511
7574
  this._paused = false;
7512
7575
  try {
7513
- const tempFile = join4(tmpdir4(), `ocosay-${Date.now()}.${format}`);
7576
+ const tempFile = join5(tmpdir4(), `ocosay-${Date.now()}.${format}`);
7514
7577
  this.currentFile = tempFile;
7515
7578
  if (Buffer.isBuffer(audioData)) {
7516
7579
  fs.writeFileSync(tempFile, audioData);
@@ -7607,52 +7670,81 @@ var AudioPlayer = class extends EventEmitter {
7607
7670
  }
7608
7671
  };
7609
7672
 
7610
- // src/utils/logger.ts
7611
- var import_pino = __toESM(require_pino(), 1);
7612
- import { homedir } from "os";
7613
- import { join as join5 } from "path";
7614
- import { existsSync as existsSync4, mkdirSync } from "fs";
7615
- var logDir = join5(homedir(), ".ocosay");
7616
- var logFile = join5(logDir, "ocosay.log");
7617
- if (!existsSync4(logDir)) {
7618
- try {
7619
- mkdirSync(logDir, { recursive: true });
7620
- } catch {
7621
- }
7622
- }
7623
- var streams = [
7624
- { stream: process.stdout }
7625
- ];
7626
- try {
7627
- streams.push({ stream: import_pino.default.destination({ dest: logFile, mkdir: true }) });
7628
- } catch {
7629
- }
7630
- var level = process.env.NODE_ENV !== "production" ? "debug" : process.env.OCOSAY_LOG_LEVEL || "info";
7631
- var logger = (0, import_pino.default)(
7632
- {
7633
- level,
7634
- base: { service: "ocosay" },
7635
- timestamp: import_pino.default.stdTimeFunctions.isoTime
7636
- },
7637
- import_pino.default.multistream(streams)
7638
- );
7639
-
7640
- // src/core/speaker.ts
7641
- function toast(options) {
7642
- const tui = global.__opencode_tui__;
7643
- if (tui?.showToast) {
7673
+ // src/core/notification.ts
7674
+ var logger2 = createModuleLogger("NotificationService");
7675
+ var NotificationService = class {
7676
+ tui = null;
7677
+ pendingToasts = [];
7678
+ retryTimer;
7679
+ setTui(tui) {
7680
+ this.tui = tui;
7681
+ logger2.debug("tui reference set");
7682
+ this.flushPending();
7683
+ }
7684
+ showToast(options) {
7685
+ const { title, message, variant = "info", duration = 5e3 } = options;
7686
+ if (!this.tui) {
7687
+ logger2.debug({ title }, "tui not ready, queueing toast");
7688
+ this.pendingToasts.push(options);
7689
+ this.scheduleRetry();
7690
+ return false;
7691
+ }
7644
7692
  try {
7645
- tui.showToast({
7646
- title: options.title,
7647
- message: options.body,
7648
- variant: options.type,
7649
- duration: 3e3
7693
+ this.tui.showToast({
7694
+ body: {
7695
+ title,
7696
+ message,
7697
+ variant,
7698
+ duration
7699
+ }
7650
7700
  });
7701
+ logger2.debug({ title, variant }, "toast shown");
7702
+ return true;
7651
7703
  } catch (err) {
7652
- logger.warn({ err }, "toast call failed");
7704
+ logger2.warn({ err, title }, "toast call failed, queueing for retry");
7705
+ this.pendingToasts.push(options);
7706
+ this.scheduleRetry();
7707
+ return false;
7653
7708
  }
7654
7709
  }
7655
- }
7710
+ scheduleRetry() {
7711
+ if (this.retryTimer) return;
7712
+ this.retryTimer = setTimeout(() => {
7713
+ this.retryTimer = void 0;
7714
+ this.flushPending();
7715
+ }, 2e3);
7716
+ }
7717
+ flushPending() {
7718
+ if (this.pendingToasts.length === 0 || !this.tui) return;
7719
+ logger2.info({ count: this.pendingToasts.length }, "flushing pending toasts");
7720
+ const pending = [...this.pendingToasts];
7721
+ this.pendingToasts = [];
7722
+ for (const toast of pending) {
7723
+ try {
7724
+ this.showToast(toast);
7725
+ } catch (err) {
7726
+ this.pendingToasts.push(toast);
7727
+ logger2.warn({ err }, "showToast threw unexpected error, re-queued");
7728
+ }
7729
+ }
7730
+ }
7731
+ success(title, message, duration) {
7732
+ return this.showToast({ title, message, variant: "success", duration });
7733
+ }
7734
+ error(title, message, duration) {
7735
+ return this.showToast({ title, message, variant: "error", duration });
7736
+ }
7737
+ info(title, message, duration) {
7738
+ return this.showToast({ title, message, variant: "info", duration });
7739
+ }
7740
+ warning(title, message, duration) {
7741
+ return this.showToast({ title, message, variant: "warning", duration });
7742
+ }
7743
+ };
7744
+ var notificationService = new NotificationService();
7745
+
7746
+ // src/core/speaker.ts
7747
+ var logger3 = createModuleLogger("Speaker");
7656
7748
  var Speaker = class extends EventEmitter2 {
7657
7749
  constructor(options = {}) {
7658
7750
  super();
@@ -7662,11 +7754,10 @@ var Speaker = class extends EventEmitter2 {
7662
7754
  onEnd: () => {
7663
7755
  this.isSpeaking = false;
7664
7756
  this.emit("end", this.currentText);
7665
- toast({
7666
- title: "TTS playback success",
7667
- body: "Audio generated and playing",
7668
- type: "info"
7669
- });
7757
+ notificationService.info(
7758
+ "TTS playback success",
7759
+ "Audio generated and playing"
7760
+ );
7670
7761
  },
7671
7762
  onError: (error) => this.emit("error", error),
7672
7763
  onPause: () => {
@@ -7729,16 +7820,16 @@ var Speaker = class extends EventEmitter2 {
7729
7820
  });
7730
7821
  if (this.player) {
7731
7822
  await this.player.play(result.audioData, result.format);
7732
- logger.info({ textLength: text.length, model: options.model }, "TTS playback completed");
7823
+ logger3.info({ textLength: text.length, model: options.model }, "TTS playback completed");
7733
7824
  }
7734
7825
  } catch (error) {
7735
7826
  this.isSpeaking = false;
7827
+ logger3.error({ error }, "speak failed");
7736
7828
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
7737
- toast({
7738
- title: "TTS playback error",
7739
- body: errorMessage,
7740
- type: "error"
7741
- });
7829
+ notificationService.error(
7830
+ "TTS playback error",
7831
+ errorMessage
7832
+ );
7742
7833
  if (error instanceof TTSError) {
7743
7834
  this.emit("error", error);
7744
7835
  throw error;
@@ -7801,61 +7892,524 @@ var Speaker = class extends EventEmitter2 {
7801
7892
  return provider.listVoices();
7802
7893
  }
7803
7894
  /**
7804
- * 获取 Provider 能力
7895
+ * 获取 Provider 能力
7896
+ */
7897
+ getCapabilities(providerName) {
7898
+ const name = providerName || this.options.defaultProvider || "minimax";
7899
+ const provider = getProvider(name);
7900
+ return provider.getCapabilities();
7901
+ }
7902
+ /**
7903
+ * 获取所有已注册的 Provider
7904
+ */
7905
+ getProviders() {
7906
+ return listProviders();
7907
+ }
7908
+ /**
7909
+ * 是否正在播放
7910
+ */
7911
+ isPlaying() {
7912
+ return this.isSpeaking && !this.isPaused;
7913
+ }
7914
+ /**
7915
+ * 是否暂停
7916
+ */
7917
+ isPausedState() {
7918
+ return this.isPaused;
7919
+ }
7920
+ };
7921
+ var defaultSpeaker;
7922
+ function getDefaultSpeaker() {
7923
+ if (!defaultSpeaker) {
7924
+ defaultSpeaker = new Speaker();
7925
+ }
7926
+ return defaultSpeaker;
7927
+ }
7928
+ async function speak(text, options) {
7929
+ const speaker2 = getDefaultSpeaker();
7930
+ return speaker2.speak(text, options);
7931
+ }
7932
+ async function stop() {
7933
+ const speaker2 = getDefaultSpeaker();
7934
+ return speaker2.stop();
7935
+ }
7936
+ function pause() {
7937
+ const speaker2 = getDefaultSpeaker();
7938
+ speaker2.pause();
7939
+ }
7940
+ function resume() {
7941
+ const speaker2 = getDefaultSpeaker();
7942
+ speaker2.resume();
7943
+ }
7944
+ async function listVoices(providerName) {
7945
+ const speaker2 = getDefaultSpeaker();
7946
+ return speaker2.listVoices(providerName);
7947
+ }
7948
+
7949
+ // src/services/speaker-service.ts
7950
+ var SpeakerService = class {
7951
+ constructor(options = {}) {
7952
+ this.options = options;
7953
+ this.speaker = getDefaultSpeaker();
7954
+ }
7955
+ options;
7956
+ speaker;
7957
+ async speak(text, options) {
7958
+ const timestamp = this.getTimestamp();
7959
+ logger.info(`[Ocosay][${timestamp}][INFO][Speaker] \u5BF9\u5E94\u4E8B\u4EF6{\u64AD\u653E\u5F00\u59CB} - \u6587\u672C\u957F\u5EA6: ${text.length}`);
7960
+ return this.speaker.speak(text, options);
7961
+ }
7962
+ pause() {
7963
+ this.speaker.pause();
7964
+ }
7965
+ resume() {
7966
+ this.speaker.resume();
7967
+ }
7968
+ async stop() {
7969
+ return this.speaker.stop();
7970
+ }
7971
+ async listVoices(providerName) {
7972
+ return this.speaker.listVoices(providerName);
7973
+ }
7974
+ getCapabilities(providerName) {
7975
+ return this.speaker.getCapabilities(providerName);
7976
+ }
7977
+ getProviders() {
7978
+ return this.speaker.getProviders();
7979
+ }
7980
+ isPlaying() {
7981
+ return this.speaker.isPlaying();
7982
+ }
7983
+ isPausedState() {
7984
+ return this.speaker.isPausedState();
7985
+ }
7986
+ async destroy() {
7987
+ return this.speaker.destroy();
7988
+ }
7989
+ getTimestamp() {
7990
+ const now = /* @__PURE__ */ new Date();
7991
+ const pad = (n) => n.toString().padStart(2, "0");
7992
+ return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
7993
+ }
7994
+ };
7995
+ var defaultSpeakerService;
7996
+ function getDefaultSpeakerService() {
7997
+ if (!defaultSpeakerService) {
7998
+ defaultSpeakerService = new SpeakerService();
7999
+ }
8000
+ return defaultSpeakerService;
8001
+ }
8002
+ async function speak2(text, options) {
8003
+ if (options) {
8004
+ return speak(text, options);
8005
+ }
8006
+ return speak(text);
8007
+ }
8008
+ async function stop2() {
8009
+ return stop();
8010
+ }
8011
+ function pause2() {
8012
+ pause();
8013
+ }
8014
+ function resume2() {
8015
+ resume();
8016
+ }
8017
+ async function listVoices2(providerName) {
8018
+ return listVoices(providerName);
8019
+ }
8020
+
8021
+ // src/services/streaming-service.ts
8022
+ import { EventEmitter as EventEmitter4 } from "events";
8023
+
8024
+ // src/core/stream-player.ts
8025
+ import { EventEmitter as EventEmitter3 } from "events";
8026
+ var StreamPlayer = class extends EventEmitter3 {
8027
+ backend = null;
8028
+ _bytesWritten = 0;
8029
+ _started = false;
8030
+ _paused = false;
8031
+ _stopped = false;
8032
+ format = "mp3";
8033
+ events;
8034
+ constructor(options = {}) {
8035
+ super();
8036
+ this.format = options.format || "mp3";
8037
+ this.events = options.events;
8038
+ const backendType = options.backendType || "naudiodon" /* NAUDIODON */;
8039
+ this.backend = createBackend(backendType, {
8040
+ format: this.format,
8041
+ events: {
8042
+ onStart: () => {
8043
+ this.events?.onStart?.();
8044
+ this.emit("start");
8045
+ },
8046
+ onEnd: () => {
8047
+ this.events?.onEnd?.();
8048
+ this.emit("end");
8049
+ },
8050
+ onError: (error) => {
8051
+ this.handleError(error);
8052
+ },
8053
+ onPause: () => {
8054
+ this._paused = true;
8055
+ this.events?.onPause?.();
8056
+ this.emit("pause");
8057
+ },
8058
+ onResume: () => {
8059
+ this._paused = false;
8060
+ this.events?.onResume?.();
8061
+ this.emit("resume");
8062
+ },
8063
+ onStop: () => {
8064
+ this.events?.onStop?.();
8065
+ this.emit("stop");
8066
+ },
8067
+ onProgress: (bytes) => {
8068
+ this.events?.onProgress?.(bytes);
8069
+ this.emit("progress", bytes);
8070
+ }
8071
+ }
8072
+ });
8073
+ }
8074
+ /**
8075
+ * 开始播放
8076
+ * 初始化后端,准备接收音频数据
8077
+ */
8078
+ start() {
8079
+ if (this._started) {
8080
+ return;
8081
+ }
8082
+ if (!this.backend) {
8083
+ this.handleError(new Error("Audio backend not initialized"));
8084
+ return;
8085
+ }
8086
+ this.backend.start("");
8087
+ this._started = true;
8088
+ this._stopped = false;
8089
+ this._paused = false;
8090
+ this._bytesWritten = 0;
8091
+ }
8092
+ /**
8093
+ * 写入音频数据块(边收边播)
8094
+ * 如果尚未 start(),会自动调用
8095
+ */
8096
+ write(chunk) {
8097
+ if (this._stopped) {
8098
+ return;
8099
+ }
8100
+ if (!this._started) {
8101
+ this.start();
8102
+ }
8103
+ if (this.backend) {
8104
+ this.backend.write(chunk);
8105
+ this._bytesWritten += chunk.length;
8106
+ this.events?.onProgress?.(this._bytesWritten);
8107
+ this.emit("progress", this._bytesWritten);
8108
+ }
8109
+ }
8110
+ /**
8111
+ * 结束写入
8112
+ * 通知后端写入完成,但保持播放直到结束
8113
+ */
8114
+ end() {
8115
+ if (this.backend) {
8116
+ this.backend.end();
8117
+ }
8118
+ }
8119
+ /**
8120
+ * 停止播放
8121
+ * 立即停止播放并释放资源
8122
+ */
8123
+ stop() {
8124
+ this._stopped = true;
8125
+ this._started = false;
8126
+ this._paused = false;
8127
+ if (this.backend) {
8128
+ this.backend.stop();
8129
+ }
8130
+ this._bytesWritten = 0;
8131
+ this.events?.onStop?.();
8132
+ this.emit("stop");
8133
+ }
8134
+ /**
8135
+ * 暂停播放
8136
+ */
8137
+ pause() {
8138
+ if (!this._started || this._paused || this._stopped) {
8139
+ return;
8140
+ }
8141
+ if (this.backend) {
8142
+ this.backend.pause();
8143
+ }
8144
+ }
8145
+ /**
8146
+ * 恢复播放
8147
+ */
8148
+ resume() {
8149
+ if (!this._paused || this._stopped) {
8150
+ return;
8151
+ }
8152
+ if (this.backend) {
8153
+ this.backend.resume();
8154
+ }
8155
+ }
8156
+ /**
8157
+ * 是否已启动
8158
+ */
8159
+ isStarted() {
8160
+ return this._started;
8161
+ }
8162
+ /**
8163
+ * 是否暂停
8164
+ */
8165
+ isPaused() {
8166
+ return this._paused;
8167
+ }
8168
+ /**
8169
+ * 是否已停止
8170
+ */
8171
+ isStopped() {
8172
+ return this._stopped;
8173
+ }
8174
+ /**
8175
+ * 获取已写入的字节数
8176
+ */
8177
+ getBytesWritten() {
8178
+ return this._bytesWritten;
8179
+ }
8180
+ /**
8181
+ * 处理错误
8182
+ */
8183
+ handleError(error) {
8184
+ this.events?.onError?.(error);
8185
+ this.emit("error", error);
8186
+ }
8187
+ };
8188
+
8189
+ // src/services/streaming-service.ts
8190
+ var StreamingService = class extends EventEmitter4 {
8191
+ player = null;
8192
+ providerName;
8193
+ voice;
8194
+ speed;
8195
+ volume;
8196
+ pitch;
8197
+ backendType;
8198
+ _isActive = false;
8199
+ _bytesWritten = 0;
8200
+ constructor(options = {}) {
8201
+ super();
8202
+ this.providerName = options.provider || "minimax";
8203
+ this.voice = options.voice;
8204
+ this.speed = options.speed;
8205
+ this.volume = options.volume;
8206
+ this.pitch = options.pitch;
8207
+ this.backendType = options.backendType || "naudiodon" /* NAUDIODON */;
8208
+ }
8209
+ /**
8210
+ * 获取时间戳
8211
+ */
8212
+ getTimestamp() {
8213
+ const now = /* @__PURE__ */ new Date();
8214
+ const pad = (n) => n.toString().padStart(2, "0");
8215
+ return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
8216
+ }
8217
+ /**
8218
+ * 初始化播放器
8219
+ */
8220
+ initPlayer() {
8221
+ if (this.player) {
8222
+ this.player.stop();
8223
+ this.player = null;
8224
+ }
8225
+ const playerOptions = {
8226
+ format: "mp3",
8227
+ backendType: this.backendType,
8228
+ events: {
8229
+ onStart: () => {
8230
+ const timestamp = this.getTimestamp();
8231
+ logger.info(`[Ocosay][${timestamp}][INFO][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u6D41\u5F0F\u64AD\u653E\u5F00\u59CB}`);
8232
+ this.emit("start");
8233
+ },
8234
+ onEnd: () => {
8235
+ const timestamp = this.getTimestamp();
8236
+ logger.info(`[Ocosay][${timestamp}][INFO][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u6D41\u5F0F\u64AD\u653E\u7ED3\u675F}`);
8237
+ this._isActive = false;
8238
+ this.emit("end");
8239
+ },
8240
+ onError: (error) => {
8241
+ const timestamp = this.getTimestamp();
8242
+ logger.error(`[Ocosay][${timestamp}][ERROR][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u6D41\u5F0F\u64AD\u653E\u9519\u8BEF} - ${error.message}`);
8243
+ this._isActive = false;
8244
+ this.emit("error", error);
8245
+ },
8246
+ onProgress: (bytes) => {
8247
+ this._bytesWritten = bytes;
8248
+ this.emit("progress", bytes);
8249
+ },
8250
+ onPause: () => {
8251
+ const timestamp = this.getTimestamp();
8252
+ logger.info(`[Ocosay][${timestamp}][INFO][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u6D41\u5F0F\u64AD\u653E\u6682\u505C}`);
8253
+ this.emit("pause");
8254
+ },
8255
+ onResume: () => {
8256
+ const timestamp = this.getTimestamp();
8257
+ logger.info(`[Ocosay][${timestamp}][INFO][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u6D41\u5F0F\u64AD\u653E\u6062\u590D}`);
8258
+ this.emit("resume");
8259
+ },
8260
+ onStop: () => {
8261
+ const timestamp = this.getTimestamp();
8262
+ logger.info(`[Ocosay][${timestamp}][INFO][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u6D41\u5F0F\u64AD\u653E\u505C\u6B62}`);
8263
+ this._isActive = false;
8264
+ this._bytesWritten = 0;
8265
+ this.emit("stop");
8266
+ }
8267
+ }
8268
+ };
8269
+ this.player = new StreamPlayer(playerOptions);
8270
+ return this.player;
8271
+ }
8272
+ /**
8273
+ * 流式播放文本
8274
+ * 边接收边播放(豆包模式)
8275
+ */
8276
+ async stream(text) {
8277
+ if (!text || text.trim().length === 0) {
8278
+ const timestamp2 = this.getTimestamp();
8279
+ logger.warn(`[Ocosay][${timestamp2}][WARNING][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u7A7A\u6587\u672C\u8DF3\u8FC7}`);
8280
+ return;
8281
+ }
8282
+ const timestamp = this.getTimestamp();
8283
+ logger.info(`[Ocosay][${timestamp}][INFO][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u6D41\u5F0F\u64AD\u653E\u5F00\u59CB} - \u6587\u672C\u957F\u5EA6: ${text.length}`);
8284
+ try {
8285
+ const provider = getProvider(this.providerName);
8286
+ if (!provider) {
8287
+ throw new TTSError(
8288
+ `Provider ${this.providerName} not found`,
8289
+ "UNKNOWN" /* UNKNOWN */,
8290
+ this.providerName
8291
+ );
8292
+ }
8293
+ const player = this.initPlayer();
8294
+ player.start();
8295
+ this._isActive = true;
8296
+ this._bytesWritten = 0;
8297
+ const result = await provider.speak(text, {
8298
+ voice: this.voice,
8299
+ model: "stream",
8300
+ speed: this.speed,
8301
+ volume: this.volume,
8302
+ pitch: this.pitch
8303
+ });
8304
+ await this.processAudioResult(result, player);
8305
+ } catch (error) {
8306
+ const ts = this.getTimestamp();
8307
+ const errorMsg = error instanceof Error ? error.message : String(error);
8308
+ logger.error(`[Ocosay][${ts}][ERROR][Streaming] \u5BF9\u5E94\u4E8B\u4EF6{\u6D41\u5F0F\u64AD\u653E\u9519\u8BEF} - ${errorMsg}`);
8309
+ this._isActive = false;
8310
+ throw error;
8311
+ }
8312
+ }
8313
+ /**
8314
+ * 处理音频结果
8315
+ */
8316
+ async processAudioResult(result, player) {
8317
+ if (result.isStream && result.audioData instanceof ReadableStream) {
8318
+ await this.streamAudioChunks(result.audioData, player);
8319
+ } else if (Buffer.isBuffer(result.audioData)) {
8320
+ player.write(result.audioData);
8321
+ player.end();
8322
+ }
8323
+ }
8324
+ /**
8325
+ * 流式处理音频chunk
8326
+ */
8327
+ async streamAudioChunks(stream2, player) {
8328
+ const reader = stream2.getReader();
8329
+ try {
8330
+ while (true) {
8331
+ const { done, value } = await reader.read();
8332
+ if (done) {
8333
+ break;
8334
+ }
8335
+ if (value) {
8336
+ const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
8337
+ player.write(chunk);
8338
+ }
8339
+ }
8340
+ } finally {
8341
+ reader.releaseLock();
8342
+ player.end();
8343
+ }
8344
+ }
8345
+ /**
8346
+ * 停止流式播放
8347
+ */
8348
+ stop() {
8349
+ if (this.player) {
8350
+ this.player.stop();
8351
+ }
8352
+ this._isActive = false;
8353
+ this._bytesWritten = 0;
8354
+ }
8355
+ /**
8356
+ * 暂停流式播放
8357
+ */
8358
+ pause() {
8359
+ if (this.player) {
8360
+ this.player.pause();
8361
+ }
8362
+ }
8363
+ /**
8364
+ * 恢复流式播放
7805
8365
  */
7806
- getCapabilities(providerName) {
7807
- const name = providerName || this.options.defaultProvider || "minimax";
7808
- const provider = getProvider(name);
7809
- return provider.getCapabilities();
8366
+ resume() {
8367
+ if (this.player) {
8368
+ this.player.resume();
8369
+ }
7810
8370
  }
7811
8371
  /**
7812
- * 获取所有已注册的 Provider
8372
+ * 获取流式播放状态
7813
8373
  */
7814
- getProviders() {
7815
- return listProviders();
8374
+ getStatus() {
8375
+ return {
8376
+ isActive: this._isActive,
8377
+ bytesWritten: this._bytesWritten,
8378
+ state: this.player?.isStopped() ? "stopped" : this.player?.isPaused() ? "paused" : this._isActive ? "playing" : "idle"
8379
+ };
7816
8380
  }
7817
8381
  /**
7818
- * 是否正在播放
8382
+ * 是否处于活跃状态
7819
8383
  */
7820
- isPlaying() {
7821
- return this.isSpeaking && !this.isPaused;
8384
+ isActive() {
8385
+ return this._isActive;
7822
8386
  }
7823
8387
  /**
7824
- * 是否暂停
8388
+ * 销毁服务
7825
8389
  */
7826
- isPausedState() {
7827
- return this.isPaused;
8390
+ async destroy() {
8391
+ if (this.player) {
8392
+ this.player.stop();
8393
+ this.player = null;
8394
+ }
8395
+ this._isActive = false;
8396
+ this._bytesWritten = 0;
7828
8397
  }
7829
8398
  };
7830
- var defaultSpeaker;
7831
- function getDefaultSpeaker() {
7832
- if (!defaultSpeaker) {
7833
- defaultSpeaker = new Speaker();
8399
+ var defaultStreamingService;
8400
+ function getDefaultStreamingService() {
8401
+ if (!defaultStreamingService) {
8402
+ defaultStreamingService = new StreamingService();
7834
8403
  }
7835
- return defaultSpeaker;
7836
- }
7837
- async function speak(text, options) {
7838
- const speaker2 = getDefaultSpeaker();
7839
- return speaker2.speak(text, options);
7840
- }
7841
- async function stop() {
7842
- const speaker2 = getDefaultSpeaker();
7843
- return speaker2.stop();
7844
- }
7845
- function pause() {
7846
- const speaker2 = getDefaultSpeaker();
7847
- speaker2.pause();
8404
+ return defaultStreamingService;
7848
8405
  }
7849
- function resume() {
7850
- const speaker2 = getDefaultSpeaker();
7851
- speaker2.resume();
7852
- }
7853
- async function listVoices(providerName) {
7854
- const speaker2 = getDefaultSpeaker();
7855
- return speaker2.listVoices(providerName);
8406
+ async function stream(text, options) {
8407
+ const service = options ? new StreamingService(options) : getDefaultStreamingService();
8408
+ return service.stream(text);
7856
8409
  }
7857
8410
 
7858
8411
  // src/tools/tts.ts
8412
+ var logger4 = createModuleLogger("TTS");
7859
8413
  function extractTextArg(args) {
7860
8414
  if (!args || typeof args !== "object") {
7861
8415
  return void 0;
@@ -7868,17 +8422,26 @@ function extractTextArg(args) {
7868
8422
  const text7 = argObj.text7;
7869
8423
  if (text7 != null) {
7870
8424
  if (typeof text7 === "string" && text7.trim().length > 0) {
7871
- logger.warn("received text7 instead of text from OpenCode framework");
8425
+ logger4.warn("received text7 instead of text from OpenCode framework");
7872
8426
  return text7.trim();
7873
8427
  }
7874
- if (typeof text7 === "object" && "content" in text7) {
7875
- const content = text7.content;
7876
- if (typeof content === "string" && content.trim().length > 0) {
7877
- logger.warn("text7 is an object with content field");
7878
- return content.trim();
8428
+ if (typeof text7 === "object") {
8429
+ if ("split" in text7 && "content" in text7) {
8430
+ const content = text7.content;
8431
+ if (typeof content === "string" && content.trim().length > 0) {
8432
+ logger4.info("text7 split format detected");
8433
+ return content.trim();
8434
+ }
8435
+ }
8436
+ if ("content" in text7) {
8437
+ const content = text7.content;
8438
+ if (typeof content === "string" && content.trim().length > 0) {
8439
+ logger4.info("text7 content format detected");
8440
+ return content.trim();
8441
+ }
7879
8442
  }
7880
8443
  }
7881
- logger.warn({ type: typeof text7 }, "text7 is not a valid string or object with content");
8444
+ logger4.warn({ type: typeof text7 }, "text7 is not a valid string or object with content");
7882
8445
  return void 0;
7883
8446
  }
7884
8447
  for (const key of Object.keys(argObj)) {
@@ -7890,7 +8453,7 @@ function extractTextArg(args) {
7890
8453
  }
7891
8454
  }
7892
8455
  if (text !== void 0) {
7893
- logger.warn({ type: typeof text }, "text arg is not a valid string");
8456
+ logger4.warn({ type: typeof text }, "text arg is not a valid string");
7894
8457
  }
7895
8458
  return void 0;
7896
8459
  }
@@ -7902,29 +8465,29 @@ async function handleToolCall(toolName, args) {
7902
8465
  if (!text) {
7903
8466
  return { success: false, error: "No valid text found in args" };
7904
8467
  }
7905
- await speak(text);
8468
+ await speak2(text);
7906
8469
  return { success: true, message: "Speech completed" };
7907
8470
  }
7908
8471
  case "tts_stop":
7909
- await stop();
8472
+ await stop2();
7910
8473
  return { success: true, message: "Stopped" };
7911
8474
  case "tts_pause":
7912
- pause();
8475
+ pause2();
7913
8476
  return { success: true, message: "Paused" };
7914
8477
  case "tts_resume":
7915
- resume();
8478
+ resume2();
7916
8479
  return { success: true, message: "Resumed" };
7917
8480
  case "tts_list_voices": {
7918
- const voices = await listVoices(args?.provider);
8481
+ const voices = await listVoices2(args?.provider);
7919
8482
  return { success: true, voices };
7920
8483
  }
7921
8484
  case "tts_list_providers": {
7922
- const speaker2 = getDefaultSpeaker();
8485
+ const speaker2 = getDefaultSpeakerService();
7923
8486
  const providers2 = speaker2.getProviders();
7924
8487
  return { success: true, providers: providers2 };
7925
8488
  }
7926
8489
  case "tts_status": {
7927
- const s = getDefaultSpeaker();
8490
+ const s = getDefaultSpeakerService();
7928
8491
  return {
7929
8492
  success: true,
7930
8493
  isPlaying: s.isPlaying(),
@@ -7946,14 +8509,14 @@ async function handleToolCall(toolName, args) {
7946
8509
  "tts_stream"
7947
8510
  );
7948
8511
  }
7949
- const streamReader2 = getStreamReader();
7950
- const synthesizer = getStreamingSynthesizer();
7951
- if (streamReader2 && synthesizer) {
7952
- streamReader2.start();
8512
+ const streamingService = getDefaultStreamingService();
8513
+ if (streamingService) {
7953
8514
  const textArg = extractTextArg(args);
7954
8515
  if (textArg && typeof textArg === "string" && textArg.trim().length > 0) {
7955
- logger.info({ text: textArg.substring(0, 50) + "..." }, "synthesizing text");
7956
- synthesizer.synthesize(textArg);
8516
+ logger4.info({ text: textArg.substring(0, 50) + "..." }, "synthesizing text");
8517
+ stream(textArg).catch((error) => {
8518
+ logger4.error({ error }, "stream failed");
8519
+ });
7957
8520
  }
7958
8521
  return { success: true, message: "Stream speak started" };
7959
8522
  }
@@ -7971,13 +8534,13 @@ async function handleToolCall(toolName, args) {
7971
8534
  "tts_stream"
7972
8535
  );
7973
8536
  }
7974
- const player = getStreamPlayer();
7975
- if (player) {
7976
- player.stop();
8537
+ const streamingService = getDefaultStreamingService();
8538
+ if (streamingService) {
8539
+ streamingService.stop();
7977
8540
  return { success: true, message: "Stream stopped" };
7978
8541
  }
7979
8542
  throw new TTSError(
7980
- "Stream player not available",
8543
+ "Stream service not available",
7981
8544
  "UNKNOWN" /* UNKNOWN */,
7982
8545
  "tts_stream"
7983
8546
  );
@@ -8105,34 +8668,39 @@ var MiniMaxProvider = class extends BaseTTSProvider {
8105
8668
  },
8106
8669
  responseType: "stream"
8107
8670
  });
8108
- const stream = response.data;
8671
+ const stream2 = response.data;
8109
8672
  const audioChunks = [];
8673
+ let lineBuffer = "";
8110
8674
  return new Promise((resolve, reject) => {
8111
- stream.on("data", (chunk) => {
8112
- try {
8113
- const lines = chunk.toString().split("\n");
8114
- for (const line of lines) {
8115
- if (line.startsWith("data:")) {
8116
- const data = JSON.parse(line.slice(5));
8117
- if (data.data?.audio) {
8118
- audioChunks.push(Buffer.from(data.data.audio, "hex"));
8119
- }
8120
- if (data.data?.status === 2) {
8121
- const fullAudio = Buffer.concat(audioChunks);
8122
- resolve({
8123
- audioData: fullAudio,
8124
- format: this.audioFormat,
8125
- isStream: true,
8126
- duration: this.estimateDuration(fullAudio.length)
8127
- });
8128
- }
8675
+ stream2.on("data", (chunk) => {
8676
+ lineBuffer += chunk.toString();
8677
+ while (true) {
8678
+ const lineEnd = lineBuffer.indexOf("\n");
8679
+ if (lineEnd === -1) break;
8680
+ const line = lineBuffer.slice(0, lineEnd).trim();
8681
+ lineBuffer = lineBuffer.slice(lineEnd + 1);
8682
+ if (!line || !line.startsWith("data:")) continue;
8683
+ const jsonStr = line.slice(5).trim();
8684
+ if (!jsonStr) continue;
8685
+ try {
8686
+ const data = JSON.parse(jsonStr);
8687
+ if (data.audio) {
8688
+ audioChunks.push(Buffer.from(data.audio, "hex"));
8689
+ }
8690
+ if (data.is_final === true) {
8691
+ const fullAudio = Buffer.concat(audioChunks);
8692
+ resolve({
8693
+ audioData: fullAudio,
8694
+ format: this.audioFormat,
8695
+ isStream: true,
8696
+ duration: this.estimateDuration(fullAudio.length)
8697
+ });
8129
8698
  }
8699
+ } catch (e) {
8130
8700
  }
8131
- } catch (e) {
8132
- audioChunks.push(chunk);
8133
8701
  }
8134
8702
  });
8135
- stream.on("error", (err) => {
8703
+ stream2.on("error", (err) => {
8136
8704
  reject(new TTSError(
8137
8705
  "Stream error",
8138
8706
  "NETWORK" /* NETWORK */,
@@ -8140,7 +8708,19 @@ var MiniMaxProvider = class extends BaseTTSProvider {
8140
8708
  err
8141
8709
  ));
8142
8710
  });
8143
- stream.on("end", () => {
8711
+ stream2.on("end", () => {
8712
+ if (lineBuffer.trim() && lineBuffer.startsWith("data:")) {
8713
+ const jsonStr = lineBuffer.slice(5).trim();
8714
+ if (jsonStr) {
8715
+ try {
8716
+ const data = JSON.parse(jsonStr);
8717
+ if (data.audio) {
8718
+ audioChunks.push(Buffer.from(data.audio, "hex"));
8719
+ }
8720
+ } catch (e) {
8721
+ }
8722
+ }
8723
+ }
8144
8724
  if (audioChunks.length > 0) {
8145
8725
  const fullAudio = Buffer.concat(audioChunks);
8146
8726
  resolve({
@@ -8430,8 +9010,9 @@ var MINIMAX_VOICES = [
8430
9010
  ];
8431
9011
 
8432
9012
  // src/core/stream-reader.ts
8433
- import { EventEmitter as EventEmitter3 } from "events";
8434
- var StreamReader = class extends EventEmitter3 {
9013
+ import { EventEmitter as EventEmitter5 } from "events";
9014
+ var logger5 = createModuleLogger("StreamReader");
9015
+ var StreamReader = class extends EventEmitter5 {
8435
9016
  constructor(bufferSize = 30, bufferTimeout = 2e3) {
8436
9017
  super();
8437
9018
  this.bufferSize = bufferSize;
@@ -8457,7 +9038,7 @@ var StreamReader = class extends EventEmitter3 {
8457
9038
  }
8458
9039
  handleDelta(sessionID, messageID, partID, delta) {
8459
9040
  if (typeof delta !== "string") {
8460
- logger.warn({ delta }, "handleDelta received non-string delta, skipping");
9041
+ logger5.warn({ delta }, "handleDelta received non-string delta, skipping");
8461
9042
  return;
8462
9043
  }
8463
9044
  if (this.state === "idle" /* IDLE */) {
@@ -8466,11 +9047,11 @@ var StreamReader = class extends EventEmitter3 {
8466
9047
  this.messageID = messageID;
8467
9048
  this.partID = partID;
8468
9049
  this.emit("streamStart");
8469
- logger.debug({ sessionID, messageID, partID }, "Stream started");
9050
+ logger5.debug({ sessionID, messageID, partID }, "Stream started");
8470
9051
  }
8471
9052
  this.buffer += delta;
8472
9053
  this.resetTimeout();
8473
- logger.debug({ deltaLength: delta.length, bufferLength: this.buffer.length }, "Delta received");
9054
+ logger5.debug({ deltaLength: delta.length, bufferLength: this.buffer.length }, "Delta received");
8474
9055
  if (this.shouldFlush()) {
8475
9056
  this.flushBuffer();
8476
9057
  }
@@ -8595,8 +9176,8 @@ var StreamReader = class extends EventEmitter3 {
8595
9176
  };
8596
9177
 
8597
9178
  // src/core/streaming-synthesizer.ts
8598
- import { EventEmitter as EventEmitter4 } from "events";
8599
- var StreamingSynthesizer = class extends EventEmitter4 {
9179
+ import { EventEmitter as EventEmitter6 } from "events";
9180
+ var StreamingSynthesizer = class extends EventEmitter6 {
8600
9181
  constructor(options) {
8601
9182
  super();
8602
9183
  this.options = options;
@@ -8622,6 +9203,7 @@ var StreamingSynthesizer = class extends EventEmitter4 {
8622
9203
  await this.processAudioResult(result);
8623
9204
  this.emit("done");
8624
9205
  } catch (error) {
9206
+ logger.error({ error }, "synthesize failed");
8625
9207
  const ttsError = error instanceof TTSError ? error : new TTSError(
8626
9208
  error instanceof Error ? error.message : "Synthesis failed",
8627
9209
  "UNKNOWN",
@@ -8644,8 +9226,8 @@ var StreamingSynthesizer = class extends EventEmitter4 {
8644
9226
  /**
8645
9227
  * 处理 ReadableStream,逐chunk emit
8646
9228
  */
8647
- async processReadableStream(stream) {
8648
- const reader = stream.getReader();
9229
+ async processReadableStream(stream2) {
9230
+ const reader = stream2.getReader();
8649
9231
  try {
8650
9232
  while (true) {
8651
9233
  const { done, value } = await reader.read();
@@ -8684,171 +9266,6 @@ var StreamingSynthesizer = class extends EventEmitter4 {
8684
9266
  }
8685
9267
  };
8686
9268
 
8687
- // src/core/stream-player.ts
8688
- import { EventEmitter as EventEmitter5 } from "events";
8689
- var StreamPlayer = class extends EventEmitter5 {
8690
- backend = null;
8691
- _bytesWritten = 0;
8692
- _started = false;
8693
- _paused = false;
8694
- _stopped = false;
8695
- format = "mp3";
8696
- events;
8697
- constructor(options = {}) {
8698
- super();
8699
- this.format = options.format || "mp3";
8700
- this.events = options.events;
8701
- const backendType = options.backendType || "naudiodon" /* NAUDIODON */;
8702
- this.backend = createBackend(backendType, {
8703
- format: this.format,
8704
- events: {
8705
- onStart: () => {
8706
- this.events?.onStart?.();
8707
- this.emit("start");
8708
- },
8709
- onEnd: () => {
8710
- this.events?.onEnd?.();
8711
- this.emit("end");
8712
- },
8713
- onError: (error) => {
8714
- this.handleError(error);
8715
- },
8716
- onPause: () => {
8717
- this._paused = true;
8718
- this.events?.onPause?.();
8719
- this.emit("pause");
8720
- },
8721
- onResume: () => {
8722
- this._paused = false;
8723
- this.events?.onResume?.();
8724
- this.emit("resume");
8725
- },
8726
- onStop: () => {
8727
- this.events?.onStop?.();
8728
- this.emit("stop");
8729
- },
8730
- onProgress: (bytes) => {
8731
- this.events?.onProgress?.(bytes);
8732
- this.emit("progress", bytes);
8733
- }
8734
- }
8735
- });
8736
- }
8737
- /**
8738
- * 开始播放
8739
- * 初始化后端,准备接收音频数据
8740
- */
8741
- start() {
8742
- if (this._started) {
8743
- return;
8744
- }
8745
- if (!this.backend) {
8746
- this.handleError(new Error("Audio backend not initialized"));
8747
- return;
8748
- }
8749
- this.backend.start("");
8750
- this._started = true;
8751
- this._stopped = false;
8752
- this._paused = false;
8753
- this._bytesWritten = 0;
8754
- }
8755
- /**
8756
- * 写入音频数据块(边收边播)
8757
- * 如果尚未 start(),会自动调用
8758
- */
8759
- write(chunk) {
8760
- if (this._stopped) {
8761
- return;
8762
- }
8763
- if (!this._started) {
8764
- this.start();
8765
- }
8766
- if (this.backend) {
8767
- this.backend.write(chunk);
8768
- this._bytesWritten += chunk.length;
8769
- this.events?.onProgress?.(this._bytesWritten);
8770
- this.emit("progress", this._bytesWritten);
8771
- }
8772
- }
8773
- /**
8774
- * 结束写入
8775
- * 通知后端写入完成,但保持播放直到结束
8776
- */
8777
- end() {
8778
- if (this.backend) {
8779
- this.backend.end();
8780
- }
8781
- }
8782
- /**
8783
- * 停止播放
8784
- * 立即停止播放并释放资源
8785
- */
8786
- stop() {
8787
- this._stopped = true;
8788
- this._started = false;
8789
- this._paused = false;
8790
- if (this.backend) {
8791
- this.backend.stop();
8792
- }
8793
- this._bytesWritten = 0;
8794
- this.events?.onStop?.();
8795
- this.emit("stop");
8796
- }
8797
- /**
8798
- * 暂停播放
8799
- */
8800
- pause() {
8801
- if (!this._started || this._paused || this._stopped) {
8802
- return;
8803
- }
8804
- if (this.backend) {
8805
- this.backend.pause();
8806
- }
8807
- }
8808
- /**
8809
- * 恢复播放
8810
- */
8811
- resume() {
8812
- if (!this._paused || this._stopped) {
8813
- return;
8814
- }
8815
- if (this.backend) {
8816
- this.backend.resume();
8817
- }
8818
- }
8819
- /**
8820
- * 是否已启动
8821
- */
8822
- isStarted() {
8823
- return this._started;
8824
- }
8825
- /**
8826
- * 是否暂停
8827
- */
8828
- isPaused() {
8829
- return this._paused;
8830
- }
8831
- /**
8832
- * 是否已停止
8833
- */
8834
- isStopped() {
8835
- return this._stopped;
8836
- }
8837
- /**
8838
- * 获取已写入的字节数
8839
- */
8840
- getBytesWritten() {
8841
- return this._bytesWritten;
8842
- }
8843
- /**
8844
- * 处理错误
8845
- */
8846
- handleError(error) {
8847
- this.events?.onError?.(error);
8848
- this.emit("error", error);
8849
- }
8850
- };
8851
-
8852
9269
  // src/index.ts
8853
9270
  var speaker;
8854
9271
  var streamReader;
@@ -8982,20 +9399,12 @@ function getStreamStatus() {
8982
9399
  state: streamReader.getState()
8983
9400
  };
8984
9401
  }
8985
- function getStreamReader() {
8986
- return streamReader;
8987
- }
8988
- function getStreamingSynthesizer() {
8989
- return streamingSynthesizer;
8990
- }
8991
- function getStreamPlayer() {
8992
- return streamPlayer;
8993
- }
8994
9402
 
8995
9403
  // src/config.ts
8996
9404
  import * as fs2 from "fs";
8997
9405
  import * as path from "path";
8998
9406
  import * as os from "os";
9407
+ var logger6 = createModuleLogger("Config");
8999
9408
  var DEFAULT_CONFIG = {
9000
9409
  enabled: true,
9001
9410
  autoPlay: false,
@@ -9094,11 +9503,12 @@ function loadOrCreateConfig() {
9094
9503
  try {
9095
9504
  fs2.mkdirSync(configDir, { recursive: true });
9096
9505
  } catch (err) {
9506
+ logger6.error({ err }, "failed to create config directory");
9097
9507
  throw new Error(`[ocosay] \u65E0\u6CD5\u521B\u5EFA\u914D\u7F6E\u76EE\u5F55 ${configDir}: ${err}`);
9098
9508
  }
9099
9509
  }
9100
9510
  if (!fs2.existsSync(CONFIG_PATH)) {
9101
- logger.info("config file not found, creating default config");
9511
+ logger6.info("config file not found, creating default config");
9102
9512
  const defaultConfig = generateDefaultConfig();
9103
9513
  const configContent = JSON.stringify(defaultConfig, null, 2);
9104
9514
  try {
@@ -9106,13 +9516,14 @@ function loadOrCreateConfig() {
9106
9516
  try {
9107
9517
  fs2.chmodSync(CONFIG_PATH, 384);
9108
9518
  } catch (err) {
9109
- logger.warn({ err }, "failed to set config file permissions");
9519
+ logger6.warn({ err }, "failed to set config file permissions");
9110
9520
  }
9111
9521
  } catch (err) {
9522
+ logger6.error({ err }, "failed to write config file");
9112
9523
  throw new Error(`[ocosay] cannot write config file ${CONFIG_PATH}: ${err}`);
9113
9524
  }
9114
- logger.info({ path: CONFIG_PATH }, "config file created");
9115
- logger.info("please edit config file to add API Key and Base URL");
9525
+ logger6.info({ path: CONFIG_PATH }, "config file created");
9526
+ logger6.info("please edit config file to add API Key and Base URL");
9116
9527
  return defaultConfig;
9117
9528
  }
9118
9529
  try {
@@ -9134,7 +9545,7 @@ function loadOrCreateConfig() {
9134
9545
  }
9135
9546
  };
9136
9547
  } catch (error) {
9137
- logger.error({ error }, "config file read failed, using default config");
9548
+ logger6.error({ error }, "config file read failed, using default config");
9138
9549
  return generateDefaultConfig();
9139
9550
  }
9140
9551
  }
@@ -9143,6 +9554,7 @@ function loadOrCreateConfig() {
9143
9554
  import { readFileSync as readFileSync2 } from "fs";
9144
9555
  import { fileURLToPath } from "url";
9145
9556
  import { dirname as dirname2, join as join7 } from "path";
9557
+ var logger7 = createModuleLogger("Plugin");
9146
9558
  var __filename = fileURLToPath(import.meta.url);
9147
9559
  var __dirname2 = dirname2(__filename);
9148
9560
  var id = "ocosay";
@@ -9282,30 +9694,26 @@ var server = (async (input, _options) => {
9282
9694
  });
9283
9695
  } catch (err) {
9284
9696
  initError = err instanceof Error ? err : new Error(String(err));
9285
- logger.error({ error: initError }, "initialization failed");
9697
+ logger7.error({ error: initError }, "initialization failed");
9286
9698
  }
9287
9699
  const opencodeTui = input.client?.tui;
9288
9700
  global.__opencode_tui__ = opencodeTui;
9289
- setTimeout(async () => {
9290
- if (!opencodeTui?.showToast) return;
9701
+ notificationService.setTui(opencodeTui);
9702
+ setTimeout(() => {
9291
9703
  if (initError) {
9292
- await opencodeTui.showToast({
9293
- body: {
9294
- title: `Ocosay v${pluginVersion} Initialization Failed`,
9295
- message: "Initialization failed, please check config",
9296
- variant: "error"
9297
- }
9298
- });
9704
+ notificationService.error(
9705
+ `Ocosay v${pluginVersion} Init Failed`,
9706
+ "Please check your config file",
9707
+ 8e3
9708
+ );
9299
9709
  } else {
9300
- await opencodeTui.showToast({
9301
- body: {
9302
- title: `Ocosay v${pluginVersion} Plugin Loaded`,
9303
- message: `Auto-read: ${config.autoRead ? "ON" : "OFF"}`,
9304
- variant: "success"
9305
- }
9306
- });
9710
+ notificationService.success(
9711
+ `Ocosay v${pluginVersion} Ready`,
9712
+ `Auto-read: ${config.autoRead ? "ON" : "OFF"}`,
9713
+ 5e3
9714
+ );
9307
9715
  }
9308
- }, 7e3);
9716
+ }, 1500);
9309
9717
  return {
9310
9718
  tool: {
9311
9719
  tts_speak: ttsSpeakTool,
@@ -9338,15 +9746,11 @@ var server = (async (input, _options) => {
9338
9746
  });
9339
9747
  initError = null;
9340
9748
  } catch (err) {
9341
- if (opencodeTui?.showToast) {
9342
- await opencodeTui.showToast({
9343
- body: {
9344
- title: `Ocosay v${pluginVersion} Initialization Failed`,
9345
- message: "Initialization failed, please check config",
9346
- variant: "error"
9347
- }
9348
- });
9349
- }
9749
+ notificationService.error(
9750
+ `Ocosay v${pluginVersion} Init Failed`,
9751
+ "Initialization failed, please check config",
9752
+ 8e3
9753
+ );
9350
9754
  }
9351
9755
  }
9352
9756
  }