@yoooclaw/phone-notifications 1.10.2 → 1.10.4

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/index.cjs CHANGED
@@ -206,9 +206,38 @@ var init_credentials = __esm({
206
206
  });
207
207
 
208
208
  // src/env.ts
209
+ function writeDotEnv(key, value) {
210
+ const path2 = resolveStateFile(".env");
211
+ (0, import_node_fs9.mkdirSync)((0, import_node_path8.dirname)(path2), { recursive: true });
212
+ const existing = (0, import_node_fs9.existsSync)(path2) ? (0, import_node_fs9.readFileSync)(path2, "utf-8") : "";
213
+ const lines = existing.split("\n");
214
+ const prefix = `${key}=`;
215
+ const idx = lines.findIndex((l) => l.startsWith(prefix));
216
+ const newLine = `${prefix}${value}`;
217
+ if (idx >= 0) {
218
+ lines[idx] = newLine;
219
+ } else {
220
+ if (existing && !existing.endsWith("\n")) lines.push("");
221
+ lines.push(newLine);
222
+ }
223
+ (0, import_node_fs9.writeFileSync)(path2, lines.join("\n"), "utf-8");
224
+ }
225
+ function readDotEnv() {
226
+ const path2 = resolveStateFile(".env");
227
+ if (!(0, import_node_fs9.existsSync)(path2)) return {};
228
+ return Object.fromEntries(
229
+ (0, import_node_fs9.readFileSync)(path2, "utf-8").split("\n").flatMap((line) => {
230
+ const eq = line.indexOf("=");
231
+ if (eq < 1) return [];
232
+ return [[line.slice(0, eq).trim(), line.slice(eq + 1).trim()]];
233
+ })
234
+ );
235
+ }
209
236
  function loadEnvName() {
210
- const fromEnvVar = process.env.OPENCLAW_ENV?.trim();
237
+ const fromEnvVar = process.env.PHONE_NOTIFICATIONS_ENV?.trim();
211
238
  if (fromEnvVar && VALID_ENVS.has(fromEnvVar)) return fromEnvVar;
239
+ const fromDotEnv = readDotEnv()["PHONE_NOTIFICATIONS_ENV"]?.trim();
240
+ if (fromDotEnv && VALID_ENVS.has(fromDotEnv)) return fromDotEnv;
212
241
  const { env } = readCredentials();
213
242
  if (env && VALID_ENVS.has(env)) return env;
214
243
  return "production";
@@ -219,7 +248,7 @@ function saveEnvName(env) {
219
248
  `\u65E0\u6548\u7684\u73AF\u5883\u540D\u79F0: ${env}\uFF0C\u53EF\u9009\u503C: ${[...VALID_ENVS].join(", ")}`
220
249
  );
221
250
  }
222
- writeCredentials({ ...readCredentials(), env });
251
+ writeDotEnv("PHONE_NOTIFICATIONS_ENV", env);
223
252
  }
224
253
  function getEnvUrls(env) {
225
254
  return ENV_CONFIG[env ?? loadEnvName()];
@@ -227,11 +256,14 @@ function getEnvUrls(env) {
227
256
  function getAvailableEnvs() {
228
257
  return Object.keys(ENV_CONFIG);
229
258
  }
230
- var ENV_CONFIG, VALID_ENVS;
259
+ var import_node_fs9, import_node_path8, ENV_CONFIG, VALID_ENVS;
231
260
  var init_env = __esm({
232
261
  "src/env.ts"() {
233
262
  "use strict";
263
+ import_node_fs9 = require("fs");
264
+ import_node_path8 = require("path");
234
265
  init_credentials();
266
+ init_host();
235
267
  ENV_CONFIG = {
236
268
  development: {
237
269
  lightApiUrl: "https://openclaw-service-dev.yoooclaw.com/api/message/tob/sendMessage",
@@ -461,8 +493,8 @@ __export(whisper_local_exports, {
461
493
  transcribeWithWhisperLocal: () => transcribeWithWhisperLocal
462
494
  });
463
495
  function detectEnvironment(logger) {
464
- const os2 = (0, import_node_os3.platform)();
465
- const cpuArch = (0, import_node_os3.arch)();
496
+ const os2 = (0, import_node_os4.platform)();
497
+ const cpuArch = (0, import_node_os4.arch)();
466
498
  const isAppleSilicon = os2 === "darwin" && cpuArch === "arm64";
467
499
  const hasCuda = detectCuda(logger);
468
500
  let recommendedBackend;
@@ -500,20 +532,20 @@ function selectModelByMemory(availableGB, isAppleSilicon = false) {
500
532
  return "tiny";
501
533
  }
502
534
  function resolveModelsDir(dataDir) {
503
- const dir = (0, import_node_path19.join)(dataDir, WHISPER_MODELS_DIR);
504
- (0, import_node_fs24.mkdirSync)(dir, { recursive: true });
535
+ const dir = (0, import_node_path22.join)(dataDir, WHISPER_MODELS_DIR);
536
+ (0, import_node_fs26.mkdirSync)(dir, { recursive: true });
505
537
  return dir;
506
538
  }
507
539
  function resolveBinDir(dataDir) {
508
- const dir = (0, import_node_path19.join)(dataDir, WHISPER_BIN_DIR);
509
- (0, import_node_fs24.mkdirSync)(dir, { recursive: true });
540
+ const dir = (0, import_node_path22.join)(dataDir, WHISPER_BIN_DIR);
541
+ (0, import_node_fs26.mkdirSync)(dir, { recursive: true });
510
542
  return dir;
511
543
  }
512
544
  function isModelDownloaded(modelsDir, modelSize) {
513
- const modelPath = (0, import_node_path19.join)(modelsDir, MODEL_FILENAMES[modelSize]);
514
- if (!(0, import_node_fs24.existsSync)(modelPath)) return false;
545
+ const modelPath = (0, import_node_path22.join)(modelsDir, MODEL_FILENAMES[modelSize]);
546
+ if (!(0, import_node_fs26.existsSync)(modelPath)) return false;
515
547
  try {
516
- const stat = (0, import_node_fs24.statSync)(modelPath);
548
+ const stat = (0, import_node_fs26.statSync)(modelPath);
517
549
  const expectedSize = MODEL_DISK_SIZES[modelSize];
518
550
  return stat.size >= expectedSize * 0.8;
519
551
  } catch {
@@ -522,7 +554,7 @@ function isModelDownloaded(modelsDir, modelSize) {
522
554
  }
523
555
  async function downloadModel(modelsDir, modelSize, logger, modelSource, mirrorUrl) {
524
556
  const filename = MODEL_FILENAMES[modelSize];
525
- const modelPath = (0, import_node_path19.join)(modelsDir, filename);
557
+ const modelPath = (0, import_node_path22.join)(modelsDir, filename);
526
558
  if (isModelDownloaded(modelsDir, modelSize)) {
527
559
  logger.info(`[whisper-local] \u6A21\u578B\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u4E0B\u8F7D: ${filename}`);
528
560
  return { ok: true, modelPath };
@@ -588,7 +620,7 @@ async function probeUrl(url, logger) {
588
620
  async function downloadFromUrl(url, modelPath, logger) {
589
621
  const tmpPath = `${modelPath}.downloading`;
590
622
  try {
591
- (0, import_node_fs24.mkdirSync)((0, import_node_path19.dirname)(modelPath), { recursive: true });
623
+ (0, import_node_fs26.mkdirSync)((0, import_node_path22.dirname)(modelPath), { recursive: true });
592
624
  const controller = new AbortController();
593
625
  const timer = setTimeout(() => controller.abort(), 30 * 60 * 1e3);
594
626
  try {
@@ -604,7 +636,7 @@ async function downloadFromUrl(url, modelPath, logger) {
604
636
  return { ok: false, modelPath, error: "\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: \u54CD\u5E94\u4F53\u4E3A\u7A7A" };
605
637
  }
606
638
  const contentLength = Number(res.headers.get("content-length") ?? 0);
607
- const writeStream = (0, import_node_fs24.createWriteStream)(tmpPath);
639
+ const writeStream = (0, import_node_fs26.createWriteStream)(tmpPath);
608
640
  const readable = import_node_stream2.Readable.fromWeb(res.body);
609
641
  let downloaded = 0;
610
642
  let lastLogPercent = 0;
@@ -624,16 +656,16 @@ async function downloadFromUrl(url, modelPath, logger) {
624
656
  } finally {
625
657
  clearTimeout(timer);
626
658
  }
627
- const { renameSync } = await import("fs");
628
- renameSync(tmpPath, modelPath);
629
- const fileSize = (0, import_node_fs24.statSync)(modelPath).size;
659
+ const { renameSync: renameSync2 } = await import("fs");
660
+ renameSync2(tmpPath, modelPath);
661
+ const fileSize = (0, import_node_fs26.statSync)(modelPath).size;
630
662
  logger.info(
631
- `[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path19.basename)(modelPath)} (${formatBytes2(fileSize)})`
663
+ `[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path22.basename)(modelPath)} (${formatBytes2(fileSize)})`
632
664
  );
633
665
  return { ok: true, modelPath };
634
666
  } catch (err) {
635
667
  try {
636
- if ((0, import_node_fs24.existsSync)(tmpPath)) (0, import_node_fs24.unlinkSync)(tmpPath);
668
+ if ((0, import_node_fs26.existsSync)(tmpPath)) (0, import_node_fs26.unlinkSync)(tmpPath);
637
669
  } catch {
638
670
  }
639
671
  const msg = err?.name === "AbortError" ? "\u6A21\u578B\u4E0B\u8F7D\u8D85\u65F6\uFF0830 \u5206\u949F\uFF09" : err?.message ?? String(err);
@@ -643,18 +675,18 @@ async function downloadFromUrl(url, modelPath, logger) {
643
675
  }
644
676
  function findWhisperBinary(dataDir, logger) {
645
677
  const binDir = resolveBinDir(dataDir);
646
- const binNames = (0, import_node_os3.platform)() === "win32" ? ["whisper-cli.exe", "whisper.exe", "main.exe"] : ["whisper-cli", "whisper", "main"];
678
+ const binNames = (0, import_node_os4.platform)() === "win32" ? ["whisper-cli.exe", "whisper.exe", "main.exe"] : ["whisper-cli", "whisper", "main"];
647
679
  for (const name of binNames) {
648
- const binPath = (0, import_node_path19.join)(binDir, name);
649
- if ((0, import_node_fs24.existsSync)(binPath)) {
680
+ const binPath = (0, import_node_path22.join)(binDir, name);
681
+ if ((0, import_node_fs26.existsSync)(binPath)) {
650
682
  logger.info(`[whisper-local] \u627E\u5230\u672C\u5730\u4E8C\u8FDB\u5236: ${binPath}`);
651
683
  return binPath;
652
684
  }
653
685
  }
654
- const pathNames = (0, import_node_os3.platform)() === "win32" ? ["whisper-cli", "whisper-cpp", "whisper"] : ["whisper-cli", "whisper-cpp", "whisper"];
686
+ const pathNames = (0, import_node_os4.platform)() === "win32" ? ["whisper-cli", "whisper-cpp", "whisper"] : ["whisper-cli", "whisper-cpp", "whisper"];
655
687
  for (const name of pathNames) {
656
688
  try {
657
- const cmd = (0, import_node_os3.platform)() === "win32" ? "where" : "which";
689
+ const cmd = (0, import_node_os4.platform)() === "win32" ? "where" : "which";
658
690
  const result = (0, import_node_child_process2.execSync)(`${cmd} ${name}`, { encoding: "utf-8", stdio: "pipe" }).trim();
659
691
  if (result) {
660
692
  logger.info(`[whisper-local] \u627E\u5230\u7CFB\u7EDF PATH \u4E8C\u8FDB\u5236: ${result}`);
@@ -697,7 +729,7 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
697
729
  return { ok: false, error: `\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: ${downloadResult.error}` };
698
730
  }
699
731
  }
700
- const modelPath = (0, import_node_path19.join)(modelsDir, MODEL_FILENAMES[modelSize]);
732
+ const modelPath = (0, import_node_path22.join)(modelsDir, MODEL_FILENAMES[modelSize]);
701
733
  let inputPath = audioFilePath;
702
734
  let tmpWavPath = null;
703
735
  const actualFmt = detectAudioFormat(audioFilePath);
@@ -749,10 +781,10 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
749
781
  logger.info(`[whisper-local] \u8F6C\u5199\u8017\u65F6: ${Math.round(elapsed / 1e3)}s`);
750
782
  const jsonPath = inputPath + ".json";
751
783
  let jsonContent;
752
- if ((0, import_node_fs24.existsSync)(jsonPath)) {
753
- jsonContent = (0, import_node_fs24.readFileSync)(jsonPath, "utf-8");
784
+ if ((0, import_node_fs26.existsSync)(jsonPath)) {
785
+ jsonContent = (0, import_node_fs26.readFileSync)(jsonPath, "utf-8");
754
786
  try {
755
- (0, import_node_fs24.unlinkSync)(jsonPath);
787
+ (0, import_node_fs26.unlinkSync)(jsonPath);
756
788
  } catch {
757
789
  }
758
790
  } else {
@@ -785,7 +817,7 @@ function detectCuda(logger) {
785
817
  return true;
786
818
  } catch {
787
819
  }
788
- if ((0, import_node_os3.platform)() === "linux") {
820
+ if ((0, import_node_os4.platform)() === "linux") {
789
821
  try {
790
822
  const ldconfig = (0, import_node_child_process2.execSync)("ldconfig -p 2>/dev/null | grep libcudart", {
791
823
  encoding: "utf-8",
@@ -816,24 +848,24 @@ function getAvailableMemoryGB(backend, logger) {
816
848
  logger.warn("[whisper-local] \u65E0\u6CD5\u83B7\u53D6 GPU VRAM\uFF0C\u4F7F\u7528\u7CFB\u7EDF RAM \u4EE3\u66FF");
817
849
  }
818
850
  }
819
- const totalGB = (0, import_node_os3.totalmem)() / (1024 * 1024 * 1024);
820
- const freeGB = (0, import_node_os3.freemem)() / (1024 * 1024 * 1024);
851
+ const totalGB = (0, import_node_os4.totalmem)() / (1024 * 1024 * 1024);
852
+ const freeGB = (0, import_node_os4.freemem)() / (1024 * 1024 * 1024);
821
853
  return Math.max(freeGB, totalGB * 0.6);
822
854
  }
823
855
  function getPhysicalCoreCount() {
824
- const cpuList = (0, import_node_os3.cpus)();
856
+ const cpuList = (0, import_node_os4.cpus)();
825
857
  if (cpuList.length === 0) return 4;
826
- if ((0, import_node_os3.platform)() === "darwin" && (0, import_node_os3.arch)() === "arm64") {
858
+ if ((0, import_node_os4.platform)() === "darwin" && (0, import_node_os4.arch)() === "arm64") {
827
859
  return cpuList.length;
828
860
  }
829
861
  return Math.max(1, Math.floor(cpuList.length / 2));
830
862
  }
831
863
  function detectAudioFormat(filePath) {
832
864
  try {
833
- const fd = (0, import_node_fs24.openSync)(filePath, "r");
865
+ const fd = (0, import_node_fs26.openSync)(filePath, "r");
834
866
  const buf = Buffer.alloc(12);
835
- (0, import_node_fs24.readSync)(fd, buf, 0, 12, 0);
836
- (0, import_node_fs24.closeSync)(fd);
867
+ (0, import_node_fs26.readSync)(fd, buf, 0, 12, 0);
868
+ (0, import_node_fs26.closeSync)(fd);
837
869
  const header = buf.toString("ascii", 0, 4);
838
870
  const header8 = buf.toString("ascii", 0, 8);
839
871
  if (header === "RIFF" && buf.toString("ascii", 8, 12) === "WAVE") return ".wav";
@@ -868,7 +900,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
868
900
  timeout: 12e4,
869
901
  stdio: ["pipe", "pipe", "pipe"]
870
902
  });
871
- if (ffmpegResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
903
+ if (ffmpegResult.status === 0 && (0, import_node_fs26.existsSync)(outputPath)) {
872
904
  logger.info(`[whisper-local] ffmpeg \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
873
905
  return { ok: true };
874
906
  }
@@ -881,7 +913,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
881
913
  ["--rate", "16000", "--mono", inputPath, outputPath],
882
914
  { encoding: "utf-8", timeout: 12e4, stdio: ["pipe", "pipe", "pipe"] }
883
915
  );
884
- if (opusResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
916
+ if (opusResult.status === 0 && (0, import_node_fs26.existsSync)(outputPath)) {
885
917
  logger.info(`[whisper-local] opusdec \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
886
918
  return { ok: true };
887
919
  }
@@ -895,7 +927,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
895
927
  if (detectedExt && !inputPath.endsWith(detectedExt)) {
896
928
  tmpCopy = inputPath + ".detected" + detectedExt;
897
929
  try {
898
- (0, import_node_fs24.copyFileSync)(inputPath, tmpCopy);
930
+ (0, import_node_fs26.copyFileSync)(inputPath, tmpCopy);
899
931
  actualInputPath = tmpCopy;
900
932
  logger.info(
901
933
  `[whisper-local] \u68C0\u6D4B\u5230\u5B9E\u9645\u683C\u5F0F ${detectedExt}\uFF0C\u4E34\u65F6\u91CD\u547D\u540D`
@@ -919,22 +951,22 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
919
951
  timeout: 12e4,
920
952
  stdio: ["pipe", "pipe", "pipe"]
921
953
  });
922
- if (tmpCopy && (0, import_node_fs24.existsSync)(tmpCopy)) {
954
+ if (tmpCopy && (0, import_node_fs26.existsSync)(tmpCopy)) {
923
955
  try {
924
- (0, import_node_fs24.unlinkSync)(tmpCopy);
956
+ (0, import_node_fs26.unlinkSync)(tmpCopy);
925
957
  } catch {
926
958
  }
927
959
  }
928
- if (afResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
960
+ if (afResult.status === 0 && (0, import_node_fs26.existsSync)(outputPath)) {
929
961
  logger.info(`[whisper-local] afconvert \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
930
962
  return { ok: true };
931
963
  }
932
964
  const stderr = afResult.stderr?.slice(0, 200) ?? "";
933
965
  return { ok: false, error: `afconvert \u8F6C\u6362\u5931\u8D25 (exit ${afResult.status}): ${stderr}` };
934
966
  } catch (err) {
935
- if (tmpCopy && (0, import_node_fs24.existsSync)(tmpCopy)) {
967
+ if (tmpCopy && (0, import_node_fs26.existsSync)(tmpCopy)) {
936
968
  try {
937
- (0, import_node_fs24.unlinkSync)(tmpCopy);
969
+ (0, import_node_fs26.unlinkSync)(tmpCopy);
938
970
  } catch {
939
971
  }
940
972
  }
@@ -945,9 +977,9 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
945
977
  return { ok: false, error: `\u65E0\u6CD5\u5C06\u97F3\u9891\u8F6C\u6362\u4E3A WAV \u683C\u5F0F\u3002${fmtHint}` };
946
978
  }
947
979
  function cleanupTmpWav(path2) {
948
- if (path2 && (0, import_node_fs24.existsSync)(path2)) {
980
+ if (path2 && (0, import_node_fs26.existsSync)(path2)) {
949
981
  try {
950
- (0, import_node_fs24.unlinkSync)(path2);
982
+ (0, import_node_fs26.unlinkSync)(path2);
951
983
  } catch {
952
984
  }
953
985
  }
@@ -1033,16 +1065,16 @@ function formatBytes2(bytes) {
1033
1065
  if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
1034
1066
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;
1035
1067
  }
1036
- var import_node_child_process2, import_node_fs24, import_node_path19, import_promises3, import_node_stream2, import_node_os3, WHISPER_MODELS_DIR, WHISPER_BIN_DIR, HF_MODEL_URL_TEMPLATE, MODELSCOPE_MODEL_URL_TEMPLATE, PROBE_TIMEOUT_MS, MODEL_FILENAMES, MODEL_DISK_SIZES;
1068
+ var import_node_child_process2, import_node_fs26, import_node_path22, import_promises3, import_node_stream2, import_node_os4, WHISPER_MODELS_DIR, WHISPER_BIN_DIR, HF_MODEL_URL_TEMPLATE, MODELSCOPE_MODEL_URL_TEMPLATE, PROBE_TIMEOUT_MS, MODEL_FILENAMES, MODEL_DISK_SIZES;
1037
1069
  var init_whisper_local = __esm({
1038
1070
  "src/recording/whisper-local.ts"() {
1039
1071
  "use strict";
1040
1072
  import_node_child_process2 = require("child_process");
1041
- import_node_fs24 = require("fs");
1042
- import_node_path19 = require("path");
1073
+ import_node_fs26 = require("fs");
1074
+ import_node_path22 = require("path");
1043
1075
  import_promises3 = require("stream/promises");
1044
1076
  import_node_stream2 = require("stream");
1045
- import_node_os3 = require("os");
1077
+ import_node_os4 = require("os");
1046
1078
  WHISPER_MODELS_DIR = "whisper-models";
1047
1079
  WHISPER_BIN_DIR = "whisper-bin";
1048
1080
  HF_MODEL_URL_TEMPLATE = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-{model}.bin";
@@ -1194,7 +1226,7 @@ async function initializeAsr(config, dataDir, logger) {
1194
1226
  }
1195
1227
  }
1196
1228
  async function transcribeAudio(audioFilePath, config, logger, options = {}) {
1197
- if (!(0, import_node_fs25.existsSync)(audioFilePath)) {
1229
+ if (!(0, import_node_fs27.existsSync)(audioFilePath)) {
1198
1230
  return { ok: false, error: `\u97F3\u9891\u6587\u4EF6\u4E0D\u5B58\u5728: ${audioFilePath}` };
1199
1231
  }
1200
1232
  logger.info(
@@ -1310,7 +1342,7 @@ async function runTranscriptionWorkflow(params) {
1310
1342
  return { ok: false, error: result.error };
1311
1343
  }
1312
1344
  const title = normalizeOptionalText2(result.summary) ? normalizeOptionalText2(result.summary) : extractSummary(result.text ?? "");
1313
- const summary = normalizeOptionalText2(result.summaryText) ? normalizeOptionalText2(result.summaryText) : extractTranscriptSummary(result.text ?? "");
1345
+ const summary = normalizeOptionalText2(result.summaryText);
1314
1346
  result.summary = title;
1315
1347
  const transcriptData = buildTranscriptDocument({
1316
1348
  recordingId,
@@ -1338,8 +1370,8 @@ async function runTranscriptionWorkflow(params) {
1338
1370
  createdAt
1339
1371
  );
1340
1372
  const transcriptDataFilename = buildTranscriptDataFilename(recordingId);
1341
- const transcriptDataPath = (0, import_node_path20.join)(transcriptDataDir, transcriptDataFilename);
1342
- (0, import_node_fs25.writeFileSync)(
1373
+ const transcriptDataPath = (0, import_node_path23.join)(transcriptDataDir, transcriptDataFilename);
1374
+ (0, import_node_fs27.writeFileSync)(
1343
1375
  transcriptDataPath,
1344
1376
  JSON.stringify(transcriptData, null, 2),
1345
1377
  "utf-8"
@@ -1347,13 +1379,16 @@ async function runTranscriptionWorkflow(params) {
1347
1379
  logger.info(`[asr] \u8F6C\u5199 JSON \u5DF2\u5199\u5165: ${transcriptDataPath}`);
1348
1380
  const safeSummary = title.replace(/[/\\:*?"<>|]/g, "").trim().slice(0, 20);
1349
1381
  const filename = safeSummary ? `${recordingId}_${safeSummary}.md` : `${recordingId}.md`;
1350
- const filePath = (0, import_node_path20.join)(transcriptsDir, filename);
1351
- (0, import_node_fs25.writeFileSync)(filePath, markdown, "utf-8");
1382
+ const filePath = (0, import_node_path23.join)(transcriptsDir, filename);
1383
+ (0, import_node_fs27.writeFileSync)(filePath, markdown, "utf-8");
1352
1384
  logger.info(`[asr] \u8F6C\u5199\u6587\u672C\u5DF2\u5199\u5165: ${filePath}`);
1353
- const summaryFilename = `${recordingId}.md`;
1354
- const summaryFilePath = (0, import_node_path20.join)(summariesDir, summaryFilename);
1355
- (0, import_node_fs25.writeFileSync)(summaryFilePath, summary, "utf-8");
1356
- logger.info(`[asr] \u6458\u8981\u6587\u672C\u5DF2\u5199\u5165: ${summaryFilePath}`);
1385
+ let summaryFilename;
1386
+ if (summary) {
1387
+ summaryFilename = `${recordingId}.md`;
1388
+ const summaryFilePath = (0, import_node_path23.join)(summariesDir, summaryFilename);
1389
+ (0, import_node_fs27.writeFileSync)(summaryFilePath, summary, "utf-8");
1390
+ logger.info(`[asr] \u6458\u8981\u6587\u672C\u5DF2\u5199\u5165: ${summaryFilePath}`);
1391
+ }
1357
1392
  return {
1358
1393
  ok: true,
1359
1394
  transcriptFilename: filename,
@@ -1436,7 +1471,7 @@ async function transcribeWithModelProxy(audioOssUrl, apiConfig, logger) {
1436
1471
  }
1437
1472
  async function transcribeWithWhisperLocal2(audioFilePath, config, logger) {
1438
1473
  const { transcribeWithWhisperLocal: runLocal } = await Promise.resolve().then(() => (init_whisper_local(), whisper_local_exports));
1439
- const dataDir = process.env.OPENCLAW_STATE_DIR ?? process.env.QCLAW_STATE_DIR ?? (0, import_node_path20.join)(audioFilePath, "..", "..", "..");
1474
+ const dataDir = process.env.OPENCLAW_STATE_DIR ?? process.env.QCLAW_STATE_DIR ?? (0, import_node_path23.join)(audioFilePath, "..", "..", "..");
1440
1475
  const localConfig = config.local ?? {};
1441
1476
  const result = await runLocal(
1442
1477
  audioFilePath,
@@ -1590,8 +1625,8 @@ function buildLongRecordingSuccessResult(taskId, requestId, data, logger) {
1590
1625
  ok: true,
1591
1626
  text,
1592
1627
  segments: listResult.segments,
1593
- summary: title ?? extractSummary(text),
1594
- summaryText: summaryText ?? extractTranscriptSummary(text),
1628
+ summary: title,
1629
+ summaryText,
1595
1630
  category,
1596
1631
  sourceInfo: {
1597
1632
  provider: "model-proxy",
@@ -1711,15 +1746,6 @@ function stringifyForLog(value, maxLength = 500) {
1711
1746
  async function sleep2(ms) {
1712
1747
  await new Promise((resolve) => setTimeout(resolve, ms));
1713
1748
  }
1714
- function extractTranscriptSummary(text) {
1715
- const normalized = text.replace(/\s+/g, " ").trim();
1716
- if (!normalized) {
1717
- return "";
1718
- }
1719
- const sentence = normalized.split(/[。!?!?]/).map((part) => part.trim()).find((part) => part.length > 0);
1720
- const candidate = sentence || normalized;
1721
- return candidate.length <= 120 ? candidate : `${candidate.slice(0, 117).trimEnd()}...`;
1722
- }
1723
1749
  function formatTimestamp(ms) {
1724
1750
  const totalSeconds = Math.floor(ms / 1e3);
1725
1751
  const minutes = Math.floor(totalSeconds / 60);
@@ -1748,12 +1774,12 @@ function formatTranscriptSegmentText(segment) {
1748
1774
  }
1749
1775
  return text;
1750
1776
  }
1751
- var import_node_fs25, import_node_path20, DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS, DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS, LONG_RECORDING_RUNNING_STATUSES, LONG_RECORDING_TERMINAL_FAILURE_STATUSES;
1777
+ var import_node_fs27, import_node_path23, DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS, DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS, LONG_RECORDING_RUNNING_STATUSES, LONG_RECORDING_TERMINAL_FAILURE_STATUSES;
1752
1778
  var init_asr = __esm({
1753
1779
  "src/recording/asr.ts"() {
1754
1780
  "use strict";
1755
- import_node_fs25 = require("fs");
1756
- import_node_path20 = require("path");
1781
+ import_node_fs27 = require("fs");
1782
+ import_node_path23 = require("path");
1757
1783
  init_credentials();
1758
1784
  init_env();
1759
1785
  init_transcript_document();
@@ -5398,7 +5424,7 @@ function readBuildInjectedVersion() {
5398
5424
  if (false) {
5399
5425
  return void 0;
5400
5426
  }
5401
- const version = "1.10.2".trim();
5427
+ const version = "1.10.4".trim();
5402
5428
  return version || void 0;
5403
5429
  }
5404
5430
  function readPluginVersionFromPackageJson() {
@@ -7201,8 +7227,48 @@ function resolveUpdateChannel(params) {
7201
7227
  return params.envName === "development" ? "beta" : "latest";
7202
7228
  }
7203
7229
 
7230
+ // src/update/index.ts
7231
+ var import_node_path10 = require("path");
7232
+
7204
7233
  // src/update/checker.ts
7205
- var CDN_BASE_URL = "https://cdn.yoootek.com/openclaw-plugin";
7234
+ function parseSemver(v) {
7235
+ const [main, pre = null] = v.split("-", 2);
7236
+ const [major = 0, minor = 0, patch = 0] = main.split(".").map(Number);
7237
+ return { major, minor, patch, pre: pre ?? null };
7238
+ }
7239
+ function comparePreRelease(a, b) {
7240
+ const aParts = a.split(".");
7241
+ const bParts = b.split(".");
7242
+ for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
7243
+ const ap = aParts[i] ?? "";
7244
+ const bp = bParts[i] ?? "";
7245
+ const an = Number(ap);
7246
+ const bn = Number(bp);
7247
+ let diff;
7248
+ if (!Number.isNaN(an) && !Number.isNaN(bn)) {
7249
+ diff = an - bn;
7250
+ } else if (ap < bp) {
7251
+ diff = -1;
7252
+ } else if (ap > bp) {
7253
+ diff = 1;
7254
+ } else {
7255
+ diff = 0;
7256
+ }
7257
+ if (diff !== 0) return diff;
7258
+ }
7259
+ return 0;
7260
+ }
7261
+ function isNewerVersion(candidate, current) {
7262
+ const a = parseSemver(candidate);
7263
+ const b = parseSemver(current);
7264
+ if (a.major !== b.major) return a.major > b.major;
7265
+ if (a.minor !== b.minor) return a.minor > b.minor;
7266
+ if (a.patch !== b.patch) return a.patch > b.patch;
7267
+ if (a.pre === null) return b.pre !== null;
7268
+ if (b.pre === null) return false;
7269
+ return comparePreRelease(a.pre, b.pre) > 0;
7270
+ }
7271
+ var CDN_BASE_URL = "https://artifact.yoooclaw.com/plugin";
7206
7272
  var NPM_BASE_URL = "https://registry.npmjs.org/@yoooclaw/phone-notifications";
7207
7273
  var FETCH_TIMEOUT_MS = 5e3;
7208
7274
  var UpdateChecker = class {
@@ -7231,6 +7297,7 @@ var UpdateChecker = class {
7231
7297
  if (!latest || latest === PLUGIN_VERSION) return;
7232
7298
  if (latest === this.notifiedVersion) return;
7233
7299
  if (PLUGIN_VERSION.includes("-") && this.channel !== "beta") return;
7300
+ if (!isNewerVersion(latest, PLUGIN_VERSION)) return;
7234
7301
  this.notifiedVersion = latest;
7235
7302
  this.logger.info(`\u53D1\u73B0\u65B0\u7248\u672C: ${PLUGIN_VERSION} \u2192 ${latest}`);
7236
7303
  this.onUpdateFound({ current: PLUGIN_VERSION, latest });
@@ -7263,36 +7330,109 @@ var UpdateChecker = class {
7263
7330
  };
7264
7331
 
7265
7332
  // src/update/executor.ts
7333
+ var import_node_fs10 = require("fs");
7334
+ var import_node_path9 = require("path");
7335
+ var import_node_os = require("os");
7266
7336
  var VERSION_PATTERN = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
7267
- async function executeUpdate(version, runCommand, logger) {
7337
+ var BASE_URL = "https://artifact.yoooclaw.com/plugin";
7338
+ async function executeUpdate(version, runCommand, logger, targetDir, updateConfigRecord2) {
7268
7339
  if (!VERSION_PATTERN.test(version)) {
7269
7340
  return { success: false, message: `\u975E\u6CD5\u7248\u672C\u53F7: ${version}` };
7270
7341
  }
7271
- const argv = [
7272
- "openclaw",
7273
- "extension",
7274
- "install",
7275
- `@yoooclaw/phone-notifications@${version}`
7276
- ];
7277
- logger.info(`\u6267\u884C\u66F4\u65B0: ${argv.join(" ")}`);
7342
+ const tgzUrl = `${BASE_URL}/v${version}/yoooclaw-phone-notifications-${version}.tgz`;
7343
+ logger.info(`\u6267\u884C\u66F4\u65B0: ${tgzUrl} \u2192 ${targetDir}`);
7344
+ const workDir = (0, import_node_fs10.mkdtempSync)((0, import_node_path9.join)((0, import_node_os.tmpdir)(), ".openclaw-plugin-update-"));
7345
+ const tgzPath = (0, import_node_path9.join)(workDir, "plugin.tgz");
7346
+ const stagingDir = (0, import_node_path9.join)(workDir, "staged");
7347
+ let backupDir = null;
7278
7348
  try {
7279
- const result = await runCommand(argv, { timeoutMs: 12e4 });
7280
- if (result.code === 0) {
7281
- const msg = `\u5DF2\u66F4\u65B0\u5230 ${version}\uFF0C\u8BF7\u91CD\u542F gateway \u751F\u6548`;
7282
- logger.info(msg);
7283
- return { success: true, message: msg };
7349
+ logger.info("\u4E0B\u8F7D\u63D2\u4EF6\u5305...");
7350
+ const response = await fetch(tgzUrl, { signal: AbortSignal.timeout(6e4) });
7351
+ if (!response.ok) {
7352
+ return { success: false, message: `\u4E0B\u8F7D\u5931\u8D25 (HTTP ${response.status}): ${tgzUrl}` };
7353
+ }
7354
+ const buffer = Buffer.from(await response.arrayBuffer());
7355
+ (0, import_node_fs10.writeFileSync)(tgzPath, buffer);
7356
+ logger.info(`\u4E0B\u8F7D\u5B8C\u6210 (${buffer.length} bytes)`);
7357
+ (0, import_node_fs10.mkdirSync)(stagingDir, { recursive: true });
7358
+ const tarResult = await runCommand(
7359
+ ["tar", "-xzf", tgzPath, "-C", stagingDir, "--strip-components=1"],
7360
+ { timeoutMs: 3e4 }
7361
+ );
7362
+ if (tarResult.code !== 0) {
7363
+ const err = tarResult.stderr || tarResult.stdout || "unknown error";
7364
+ return { success: false, message: `\u89E3\u538B\u5931\u8D25: ${err}` };
7284
7365
  }
7285
- const errMsg = `\u66F4\u65B0\u5931\u8D25 (exit ${result.code}): ${result.stderr || result.stdout}`;
7286
- logger.error(errMsg);
7287
- return { success: false, message: errMsg };
7366
+ (0, import_node_fs10.mkdirSync)((0, import_node_path9.dirname)(targetDir), { recursive: true });
7367
+ try {
7368
+ backupDir = `${targetDir}.bak.${Date.now()}`;
7369
+ (0, import_node_fs10.renameSync)(targetDir, backupDir);
7370
+ } catch {
7371
+ backupDir = null;
7372
+ }
7373
+ (0, import_node_fs10.renameSync)(stagingDir, targetDir);
7374
+ try {
7375
+ await updateConfigRecord2(version, tgzUrl);
7376
+ } catch (err) {
7377
+ logger.warn(`\u914D\u7F6E\u8BB0\u5F55\u66F4\u65B0\u5931\u8D25\uFF08\u63D2\u4EF6\u6587\u4EF6\u5DF2\u5C31\u4F4D\uFF09: ${String(err)}`);
7378
+ }
7379
+ if (backupDir) {
7380
+ try {
7381
+ (0, import_node_fs10.rmSync)(backupDir, { force: true, recursive: true });
7382
+ } catch {
7383
+ }
7384
+ }
7385
+ const msg = `\u5DF2\u66F4\u65B0\u5230 ${version}\uFF0C\u8BF7\u91CD\u542F gateway \u751F\u6548`;
7386
+ logger.info(msg);
7387
+ return { success: true, message: msg };
7288
7388
  } catch (err) {
7289
- const errMsg = `\u66F4\u65B0\u547D\u4EE4\u6267\u884C\u5F02\u5E38: ${String(err)}`;
7389
+ if (backupDir) {
7390
+ try {
7391
+ (0, import_node_fs10.rmSync)(targetDir, { force: true, recursive: true });
7392
+ (0, import_node_fs10.renameSync)(backupDir, targetDir);
7393
+ logger.info("\u5DF2\u56DE\u6EDA\u5230\u4E4B\u524D\u7248\u672C");
7394
+ } catch (rollbackErr) {
7395
+ logger.error(`\u56DE\u6EDA\u5931\u8D25: ${String(rollbackErr)}`);
7396
+ }
7397
+ }
7398
+ const errMsg = `\u66F4\u65B0\u6267\u884C\u5F02\u5E38: ${String(err)}`;
7290
7399
  logger.error(errMsg);
7291
7400
  return { success: false, message: errMsg };
7401
+ } finally {
7402
+ try {
7403
+ (0, import_node_fs10.rmSync)(workDir, { force: true, recursive: true });
7404
+ } catch {
7405
+ }
7292
7406
  }
7293
7407
  }
7294
7408
 
7295
7409
  // src/update/index.ts
7410
+ var PLUGIN_ID = "phone-notifications";
7411
+ function resolveTargetDir(api) {
7412
+ try {
7413
+ const cfg = api.runtime.config?.loadConfig?.();
7414
+ const installPath = cfg?.plugins?.installs?.[PLUGIN_ID]?.installPath;
7415
+ if (installPath) return installPath;
7416
+ } catch {
7417
+ }
7418
+ return (0, import_node_path10.join)(api.runtime.state.resolveStateDir(), "extensions", PLUGIN_ID);
7419
+ }
7420
+ async function updateConfigRecord(api, version, targetDir, tgzUrl) {
7421
+ const configApi = api.runtime.config;
7422
+ if (!configApi) return;
7423
+ const cfg = configApi.loadConfig();
7424
+ if (!cfg.plugins) cfg.plugins = {};
7425
+ if (!cfg.plugins.installs) cfg.plugins.installs = {};
7426
+ cfg.plugins.installs[PLUGIN_ID] = {
7427
+ ...cfg.plugins.installs[PLUGIN_ID],
7428
+ source: "archive",
7429
+ sourcePath: tgzUrl,
7430
+ installPath: targetDir,
7431
+ version,
7432
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
7433
+ };
7434
+ await configApi.writeConfigFile(cfg);
7435
+ }
7296
7436
  function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast, externalUpdateNotifier) {
7297
7437
  if (config.enabled === false) {
7298
7438
  logger.info("\u81EA\u52A8\u66F4\u65B0\u5DF2\u7981\u7528 (autoUpdate.enabled = false)");
@@ -7338,10 +7478,13 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
7338
7478
  },
7339
7479
  async execute(_toolCallId, params) {
7340
7480
  const { version } = params;
7481
+ const targetDir = resolveTargetDir(api);
7341
7482
  const result = await executeUpdate(
7342
7483
  version,
7343
7484
  api.runtime.system.runCommandWithTimeout,
7344
- logger
7485
+ logger,
7486
+ targetDir,
7487
+ (v, url) => updateConfigRecord(api, v, targetDir, url)
7345
7488
  );
7346
7489
  if (result.success) {
7347
7490
  pendingUpdate = null;
@@ -7363,10 +7506,13 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
7363
7506
  });
7364
7507
  return;
7365
7508
  }
7509
+ const targetDir = resolveTargetDir(api);
7366
7510
  const result = await executeUpdate(
7367
7511
  version,
7368
7512
  api.runtime.system.runCommandWithTimeout,
7369
- logger
7513
+ logger,
7514
+ targetDir,
7515
+ (v, url) => updateConfigRecord(api, v, targetDir, url)
7370
7516
  );
7371
7517
  if (result.success) {
7372
7518
  pendingUpdate = null;
@@ -7457,10 +7603,10 @@ function registerAutoUpdateLifecycle(deps) {
7457
7603
  }
7458
7604
 
7459
7605
  // src/plugin/cli.ts
7460
- var import_node_path15 = require("path");
7606
+ var import_node_path18 = require("path");
7461
7607
 
7462
7608
  // src/cli/auth.ts
7463
- var import_node_fs9 = require("fs");
7609
+ var import_node_fs11 = require("fs");
7464
7610
  init_credentials();
7465
7611
  function registerAuthCli(program) {
7466
7612
  const auth = program.command("auth").description("\u7528\u6237\u8BA4\u8BC1\u7BA1\u7406");
@@ -7496,12 +7642,12 @@ function registerAuthCli(program) {
7496
7642
  });
7497
7643
  auth.command("clear").description("\u6E05\u9664\u5DF2\u4FDD\u5B58\u7684\u8BA4\u8BC1\u4FE1\u606F").action(() => {
7498
7644
  const path2 = credentialsPath();
7499
- if ((0, import_node_fs9.existsSync)(path2)) {
7645
+ if ((0, import_node_fs11.existsSync)(path2)) {
7500
7646
  const creds = readCredentials();
7501
7647
  delete creds.apiKey;
7502
7648
  delete creds.token;
7503
7649
  if (Object.keys(creds).length === 0) {
7504
- (0, import_node_fs9.rmSync)(path2, { force: true });
7650
+ (0, import_node_fs11.rmSync)(path2, { force: true });
7505
7651
  } else {
7506
7652
  writeCredentials(creds);
7507
7653
  }
@@ -7633,23 +7779,23 @@ function registerNtfStats(ntf, ctx) {
7633
7779
  }
7634
7780
 
7635
7781
  // src/cli/ntf-sync.ts
7636
- var import_node_fs10 = require("fs");
7637
- var import_node_path8 = require("path");
7782
+ var import_node_fs12 = require("fs");
7783
+ var import_node_path11 = require("path");
7638
7784
  var SYNC_FETCH_LIMIT = 300;
7639
7785
  function checkpointPath(dir) {
7640
- return (0, import_node_path8.join)(dir, ".checkpoint.json");
7786
+ return (0, import_node_path11.join)(dir, ".checkpoint.json");
7641
7787
  }
7642
7788
  function readCheckpoint(dir) {
7643
7789
  const p = checkpointPath(dir);
7644
- if (!(0, import_node_fs10.existsSync)(p)) return {};
7790
+ if (!(0, import_node_fs12.existsSync)(p)) return {};
7645
7791
  try {
7646
- return JSON.parse((0, import_node_fs10.readFileSync)(p, "utf-8"));
7792
+ return JSON.parse((0, import_node_fs12.readFileSync)(p, "utf-8"));
7647
7793
  } catch {
7648
7794
  return {};
7649
7795
  }
7650
7796
  }
7651
7797
  function writeCheckpoint(dir, data) {
7652
- (0, import_node_fs10.writeFileSync)(checkpointPath(dir), JSON.stringify(data, null, 2), "utf-8");
7798
+ (0, import_node_fs12.writeFileSync)(checkpointPath(dir), JSON.stringify(data, null, 2), "utf-8");
7653
7799
  }
7654
7800
  function registerNtfSync(ntf, ctx) {
7655
7801
  const sync = ntf.command("sync").description("\u540C\u6B65\u901A\u77E5\u5230\u8BB0\u5FC6\u7CFB\u7EDF");
@@ -7742,24 +7888,24 @@ function registerNtfSync(ntf, ctx) {
7742
7888
  }
7743
7889
 
7744
7890
  // src/cli/ntf-monitor.ts
7745
- var import_node_fs11 = require("fs");
7746
- var import_node_path9 = require("path");
7891
+ var import_node_fs13 = require("fs");
7892
+ var import_node_path12 = require("path");
7747
7893
  function tasksDir2(ctx) {
7748
7894
  const base = ctx.workspaceDir || ctx.stateDir;
7749
7895
  if (!base) throw new Error("workspaceDir and stateDir both unavailable");
7750
- return (0, import_node_path9.join)(base, "tasks");
7896
+ return (0, import_node_path12.join)(base, "tasks");
7751
7897
  }
7752
7898
  function readMeta2(taskDir) {
7753
- const metaPath = (0, import_node_path9.join)(taskDir, "meta.json");
7754
- if (!(0, import_node_fs11.existsSync)(metaPath)) return null;
7899
+ const metaPath = (0, import_node_path12.join)(taskDir, "meta.json");
7900
+ if (!(0, import_node_fs13.existsSync)(metaPath)) return null;
7755
7901
  try {
7756
- return JSON.parse((0, import_node_fs11.readFileSync)(metaPath, "utf-8"));
7902
+ return JSON.parse((0, import_node_fs13.readFileSync)(metaPath, "utf-8"));
7757
7903
  } catch {
7758
7904
  return null;
7759
7905
  }
7760
7906
  }
7761
7907
  function writeMeta2(taskDir, meta) {
7762
- (0, import_node_fs11.writeFileSync)((0, import_node_path9.join)(taskDir, "meta.json"), JSON.stringify(meta, null, 2), "utf-8");
7908
+ (0, import_node_fs13.writeFileSync)((0, import_node_path12.join)(taskDir, "meta.json"), JSON.stringify(meta, null, 2), "utf-8");
7763
7909
  }
7764
7910
  function generateReadme(name, description) {
7765
7911
  return `# Monitor Task: ${name}
@@ -7778,27 +7924,27 @@ function registerNtfMonitor(ntf, ctx) {
7778
7924
  const monitor = ntf.command("monitor").description("\u901A\u77E5\u76D1\u63A7\u4EFB\u52A1\u7BA1\u7406");
7779
7925
  monitor.command("list").description("\u5217\u51FA\u6240\u6709\u76D1\u63A7\u4EFB\u52A1").action(() => {
7780
7926
  const dir = tasksDir2(ctx);
7781
- if (!(0, import_node_fs11.existsSync)(dir)) {
7927
+ if (!(0, import_node_fs13.existsSync)(dir)) {
7782
7928
  output({ ok: true, tasks: [] });
7783
7929
  return;
7784
7930
  }
7785
7931
  const tasks = [];
7786
- for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
7932
+ for (const entry of (0, import_node_fs13.readdirSync)(dir, { withFileTypes: true })) {
7787
7933
  if (!entry.isDirectory()) continue;
7788
- const meta = readMeta2((0, import_node_path9.join)(dir, entry.name));
7934
+ const meta = readMeta2((0, import_node_path12.join)(dir, entry.name));
7789
7935
  if (meta) tasks.push(meta);
7790
7936
  }
7791
7937
  output({ ok: true, tasks });
7792
7938
  });
7793
7939
  monitor.command("show <name>").description("\u67E5\u770B\u76D1\u63A7\u4EFB\u52A1\u8BE6\u60C5").action((name) => {
7794
- const taskDir = (0, import_node_path9.join)(tasksDir2(ctx), name);
7940
+ const taskDir = (0, import_node_path12.join)(tasksDir2(ctx), name);
7795
7941
  const meta = readMeta2(taskDir);
7796
7942
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
7797
- const checkpointPath2 = (0, import_node_path9.join)(taskDir, "checkpoint.json");
7943
+ const checkpointPath2 = (0, import_node_path12.join)(taskDir, "checkpoint.json");
7798
7944
  let checkpoint = {};
7799
- if ((0, import_node_fs11.existsSync)(checkpointPath2)) {
7945
+ if ((0, import_node_fs13.existsSync)(checkpointPath2)) {
7800
7946
  try {
7801
- checkpoint = JSON.parse((0, import_node_fs11.readFileSync)(checkpointPath2, "utf-8"));
7947
+ checkpoint = JSON.parse((0, import_node_fs13.readFileSync)(checkpointPath2, "utf-8"));
7802
7948
  } catch {
7803
7949
  }
7804
7950
  }
@@ -7813,8 +7959,8 @@ function registerNtfMonitor(ntf, ctx) {
7813
7959
  monitor.command("create <name>").description("\u521B\u5EFA\u76D1\u63A7\u4EFB\u52A1").requiredOption("--description <text>", "\u4EFB\u52A1\u63CF\u8FF0").requiredOption("--match-rules <json>", "\u5339\u914D\u89C4\u5219 JSON").requiredOption("--schedule <cron>", "cron \u8868\u8FBE\u5F0F").action(
7814
7960
  (name, opts) => {
7815
7961
  const dir = tasksDir2(ctx);
7816
- const taskDir = (0, import_node_path9.join)(dir, name);
7817
- if ((0, import_node_fs11.existsSync)(taskDir)) {
7962
+ const taskDir = (0, import_node_path12.join)(dir, name);
7963
+ if ((0, import_node_fs13.existsSync)(taskDir)) {
7818
7964
  exitError("ALREADY_EXISTS", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u5DF2\u5B58\u5728`);
7819
7965
  }
7820
7966
  let matchRules;
@@ -7826,7 +7972,7 @@ function registerNtfMonitor(ntf, ctx) {
7826
7972
  "match-rules \u5FC5\u987B\u662F\u5408\u6CD5\u7684 JSON"
7827
7973
  );
7828
7974
  }
7829
- (0, import_node_fs11.mkdirSync)(taskDir, { recursive: true });
7975
+ (0, import_node_fs13.mkdirSync)(taskDir, { recursive: true });
7830
7976
  const meta = {
7831
7977
  name,
7832
7978
  description: opts.description,
@@ -7836,13 +7982,13 @@ function registerNtfMonitor(ntf, ctx) {
7836
7982
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
7837
7983
  };
7838
7984
  writeMeta2(taskDir, meta);
7839
- (0, import_node_fs11.writeFileSync)(
7840
- (0, import_node_path9.join)(taskDir, "fetch.py"),
7985
+ (0, import_node_fs13.writeFileSync)(
7986
+ (0, import_node_path12.join)(taskDir, "fetch.py"),
7841
7987
  generateFetchPy(name, matchRules),
7842
7988
  "utf-8"
7843
7989
  );
7844
- (0, import_node_fs11.writeFileSync)(
7845
- (0, import_node_path9.join)(taskDir, "README.md"),
7990
+ (0, import_node_fs13.writeFileSync)(
7991
+ (0, import_node_path12.join)(taskDir, "README.md"),
7846
7992
  generateReadme(name, opts.description),
7847
7993
  "utf-8"
7848
7994
  );
@@ -7870,8 +8016,8 @@ function registerNtfMonitor(ntf, ctx) {
7870
8016
  }
7871
8017
  );
7872
8018
  monitor.command("delete <name>").description("\u5220\u9664\u76D1\u63A7\u4EFB\u52A1").option("--yes", "\u8DF3\u8FC7\u786E\u8BA4").action((name, opts) => {
7873
- const taskDir = (0, import_node_path9.join)(tasksDir2(ctx), name);
7874
- if (!(0, import_node_fs11.existsSync)(taskDir)) {
8019
+ const taskDir = (0, import_node_path12.join)(tasksDir2(ctx), name);
8020
+ if (!(0, import_node_fs13.existsSync)(taskDir)) {
7875
8021
  exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
7876
8022
  }
7877
8023
  if (!opts.yes) {
@@ -7884,7 +8030,7 @@ function registerNtfMonitor(ntf, ctx) {
7884
8030
  });
7885
8031
  process.exit(1);
7886
8032
  }
7887
- (0, import_node_fs11.rmSync)(taskDir, { recursive: true, force: true });
8033
+ (0, import_node_fs13.rmSync)(taskDir, { recursive: true, force: true });
7888
8034
  output({
7889
8035
  ok: true,
7890
8036
  name,
@@ -7896,7 +8042,7 @@ function registerNtfMonitor(ntf, ctx) {
7896
8042
  });
7897
8043
  });
7898
8044
  monitor.command("enable <name>").description("\u542F\u7528\u76D1\u63A7\u4EFB\u52A1").action((name) => {
7899
- const taskDir = (0, import_node_path9.join)(tasksDir2(ctx), name);
8045
+ const taskDir = (0, import_node_path12.join)(tasksDir2(ctx), name);
7900
8046
  const meta = readMeta2(taskDir);
7901
8047
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
7902
8048
  meta.enabled = true;
@@ -7904,7 +8050,7 @@ function registerNtfMonitor(ntf, ctx) {
7904
8050
  output({ ok: true, name, enabled: true });
7905
8051
  });
7906
8052
  monitor.command("disable <name>").description("\u6682\u505C\u76D1\u63A7\u4EFB\u52A1").action((name) => {
7907
- const taskDir = (0, import_node_path9.join)(tasksDir2(ctx), name);
8053
+ const taskDir = (0, import_node_path12.join)(tasksDir2(ctx), name);
7908
8054
  const meta = readMeta2(taskDir);
7909
8055
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
7910
8056
  meta.enabled = false;
@@ -8213,9 +8359,9 @@ function registerLightSend(light) {
8213
8359
  }
8214
8360
 
8215
8361
  // src/cli/light-setup-tools.ts
8216
- var import_node_fs12 = require("fs");
8217
- var import_node_os = require("os");
8218
- var import_node_path10 = require("path");
8362
+ var import_node_fs14 = require("fs");
8363
+ var import_node_os2 = require("os");
8364
+ var import_node_path13 = require("path");
8219
8365
  function isObject(value) {
8220
8366
  return !!value && typeof value === "object" && !Array.isArray(value);
8221
8367
  }
@@ -8229,7 +8375,7 @@ function ensureArray(obj, key) {
8229
8375
  function resolveConfigPath2() {
8230
8376
  const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();
8231
8377
  if (fromEnv) return fromEnv;
8232
- return (0, import_node_path10.join)((0, import_node_os.homedir)(), ".openclaw", "openclaw.json");
8378
+ return (0, import_node_path13.join)((0, import_node_os2.homedir)(), ".openclaw", "openclaw.json");
8233
8379
  }
8234
8380
  function upsertLightControlAlsoAllow(cfg) {
8235
8381
  if (!isObject(cfg.tools)) cfg.tools = {};
@@ -8258,12 +8404,12 @@ function upsertLightControlAlsoAllow(cfg) {
8258
8404
  function registerLightSetupTools(light) {
8259
8405
  light.command("setup").description("\u81EA\u52A8\u653E\u884C light_control\uFF08\u5199\u5165 tools.alsoAllow \u4E0E agents.main.tools.alsoAllow\uFF09").action(() => {
8260
8406
  const configPath = resolveConfigPath2();
8261
- if (!(0, import_node_fs12.existsSync)(configPath)) {
8407
+ if (!(0, import_node_fs14.existsSync)(configPath)) {
8262
8408
  exitError("CONFIG_NOT_FOUND", `\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6: ${configPath}`);
8263
8409
  }
8264
8410
  let cfg = {};
8265
8411
  try {
8266
- const raw = (0, import_node_fs12.readFileSync)(configPath, "utf-8");
8412
+ const raw = (0, import_node_fs14.readFileSync)(configPath, "utf-8");
8267
8413
  const parsed = JSON.parse(raw);
8268
8414
  if (isObject(parsed)) cfg = parsed;
8269
8415
  } catch (err) {
@@ -8271,8 +8417,8 @@ function registerLightSetupTools(light) {
8271
8417
  }
8272
8418
  const result = upsertLightControlAlsoAllow(cfg);
8273
8419
  try {
8274
- (0, import_node_fs12.mkdirSync)((0, import_node_path10.dirname)(configPath), { recursive: true });
8275
- (0, import_node_fs12.writeFileSync)(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
8420
+ (0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(configPath), { recursive: true });
8421
+ (0, import_node_fs14.writeFileSync)(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
8276
8422
  } catch (err) {
8277
8423
  exitError("WRITE_FAILED", `\u5199\u5165\u914D\u7F6E\u5931\u8D25: ${err?.message ?? String(err)}`);
8278
8424
  }
@@ -8290,17 +8436,17 @@ function registerLightSetupTools(light) {
8290
8436
  }
8291
8437
 
8292
8438
  // src/cli/tunnel-status.ts
8293
- var import_node_fs13 = require("fs");
8294
- var import_node_path11 = require("path");
8439
+ var import_node_fs15 = require("fs");
8440
+ var import_node_path14 = require("path");
8295
8441
  init_credentials();
8296
8442
  init_env();
8297
- var STATUS_REL_PATH = (0, import_node_path11.join)("plugins", "phone-notifications", "tunnel-status.json");
8443
+ var STATUS_REL_PATH = (0, import_node_path14.join)("plugins", "phone-notifications", "tunnel-status.json");
8298
8444
  function readTunnelStatus(ctx) {
8299
8445
  if (!ctx.stateDir) return null;
8300
- const filePath = (0, import_node_path11.join)(ctx.stateDir, STATUS_REL_PATH);
8301
- if (!(0, import_node_fs13.existsSync)(filePath)) return null;
8446
+ const filePath = (0, import_node_path14.join)(ctx.stateDir, STATUS_REL_PATH);
8447
+ if (!(0, import_node_fs15.existsSync)(filePath)) return null;
8302
8448
  try {
8303
- return JSON.parse((0, import_node_fs13.readFileSync)(filePath, "utf-8"));
8449
+ return JSON.parse((0, import_node_fs15.readFileSync)(filePath, "utf-8"));
8304
8450
  } catch {
8305
8451
  return null;
8306
8452
  }
@@ -8368,24 +8514,24 @@ function registerNtfStoragePath(ntf, ctx) {
8368
8514
  }
8369
8515
 
8370
8516
  // src/cli/log-search.ts
8371
- var import_node_fs14 = require("fs");
8372
- var import_node_path12 = require("path");
8517
+ var import_node_fs16 = require("fs");
8518
+ var import_node_path15 = require("path");
8373
8519
  function resolveLogsDir(ctx) {
8374
8520
  if (ctx.stateDir) {
8375
- const dir = (0, import_node_path12.join)(
8521
+ const dir = (0, import_node_path15.join)(
8376
8522
  ctx.stateDir,
8377
8523
  "plugins",
8378
8524
  "phone-notifications",
8379
8525
  "logs"
8380
8526
  );
8381
- if ((0, import_node_fs14.existsSync)(dir)) return dir;
8527
+ if ((0, import_node_fs16.existsSync)(dir)) return dir;
8382
8528
  }
8383
8529
  return null;
8384
8530
  }
8385
8531
  function listLogDateKeys(dir) {
8386
8532
  const pattern = /^(\d{4}-\d{2}-\d{2})\.log$/;
8387
8533
  const keys = [];
8388
- for (const entry of (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true })) {
8534
+ for (const entry of (0, import_node_fs16.readdirSync)(dir, { withFileTypes: true })) {
8389
8535
  if (!entry.isFile()) continue;
8390
8536
  const m = pattern.exec(entry.name);
8391
8537
  if (m) keys.push(m[1]);
@@ -8393,9 +8539,9 @@ function listLogDateKeys(dir) {
8393
8539
  return keys.sort().reverse();
8394
8540
  }
8395
8541
  function collectLogLines(dir, dateKey, keyword, limit, collected) {
8396
- const filePath = (0, import_node_path12.join)(dir, `${dateKey}.log`);
8397
- if (!(0, import_node_fs14.existsSync)(filePath)) return;
8398
- const content = (0, import_node_fs14.readFileSync)(filePath, "utf-8");
8542
+ const filePath = (0, import_node_path15.join)(dir, `${dateKey}.log`);
8543
+ if (!(0, import_node_fs16.existsSync)(filePath)) return;
8544
+ const content = (0, import_node_fs16.readFileSync)(filePath, "utf-8");
8399
8545
  const lowerKeyword = keyword?.toLowerCase();
8400
8546
  for (const line of content.split("\n")) {
8401
8547
  if (collected.length >= limit) return;
@@ -8462,12 +8608,12 @@ function registerEnvCli(ntf) {
8462
8608
  }
8463
8609
 
8464
8610
  // src/cli/doctor.ts
8465
- var import_node_fs18 = require("fs");
8611
+ var import_node_fs20 = require("fs");
8466
8612
  var import_node_readline = require("readline");
8467
8613
  init_host();
8468
8614
 
8469
8615
  // src/cli/doctor/check-dangerous-flags.ts
8470
- var import_node_fs15 = require("fs");
8616
+ var import_node_fs17 = require("fs");
8471
8617
  function isObject2(v) {
8472
8618
  return !!v && typeof v === "object" && !Array.isArray(v);
8473
8619
  }
@@ -8484,13 +8630,13 @@ var checkDangerousFlags = ({ cfg, configPath }) => {
8484
8630
  detail: "\u8FD9\u4F1A\u5173\u95ED Control UI \u7684\u8BBE\u5907\u8EAB\u4EFD\u9A8C\u8BC1\uFF0C\u4EFB\u4F55\u4EBA\u90FD\u53EF\u4EE5\u8BBF\u95EE\u63A7\u5236\u9762\u677F\u3002",
8485
8631
  fixDescription: "\u8BBE\u4E3A false",
8486
8632
  fix: () => {
8487
- const raw = (0, import_node_fs15.readFileSync)(configPath, "utf-8");
8633
+ const raw = (0, import_node_fs17.readFileSync)(configPath, "utf-8");
8488
8634
  const config = JSON.parse(raw);
8489
8635
  const gw = config.gateway;
8490
8636
  const cui = gw.controlUi;
8491
8637
  cui.dangerouslyDisableDeviceAuth = false;
8492
- (0, import_node_fs15.copyFileSync)(configPath, configPath + ".bak");
8493
- (0, import_node_fs15.writeFileSync)(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
8638
+ (0, import_node_fs17.copyFileSync)(configPath, configPath + ".bak");
8639
+ (0, import_node_fs17.writeFileSync)(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
8494
8640
  }
8495
8641
  };
8496
8642
  };
@@ -8538,11 +8684,11 @@ function warnEmpty() {
8538
8684
  }
8539
8685
 
8540
8686
  // src/cli/doctor/check-state-dir-perms.ts
8541
- var import_node_fs16 = require("fs");
8687
+ var import_node_fs18 = require("fs");
8542
8688
  var checkStateDirPerms = ({ stateDir }) => {
8543
8689
  let mode;
8544
8690
  try {
8545
- mode = (0, import_node_fs16.statSync)(stateDir).mode;
8691
+ mode = (0, import_node_fs18.statSync)(stateDir).mode;
8546
8692
  } catch {
8547
8693
  return null;
8548
8694
  }
@@ -8556,7 +8702,7 @@ var checkStateDirPerms = ({ stateDir }) => {
8556
8702
  detail: "\u5176\u4ED6\u7528\u6237\u53EF\u4EE5\u8BFB\u53D6\u8BE5\u76EE\u5F55\u4E0B\u7684\u51ED\u8BC1\u548C\u914D\u7F6E\u6587\u4EF6\u3002",
8557
8703
  fixDescription: "chmod 700 " + stateDir,
8558
8704
  fix: () => {
8559
- (0, import_node_fs16.chmodSync)(stateDir, 448);
8705
+ (0, import_node_fs18.chmodSync)(stateDir, 448);
8560
8706
  }
8561
8707
  };
8562
8708
  };
@@ -8611,16 +8757,16 @@ var checkCredentials = () => {
8611
8757
  };
8612
8758
 
8613
8759
  // src/cli/doctor/check-tunnel.ts
8614
- var import_node_fs17 = require("fs");
8615
- var import_node_path13 = require("path");
8616
- var STATUS_REL_PATH2 = (0, import_node_path13.join)(
8760
+ var import_node_fs19 = require("fs");
8761
+ var import_node_path16 = require("path");
8762
+ var STATUS_REL_PATH2 = (0, import_node_path16.join)(
8617
8763
  "plugins",
8618
8764
  "phone-notifications",
8619
8765
  "tunnel-status.json"
8620
8766
  );
8621
8767
  var checkTunnel = ({ stateDir }) => {
8622
- const filePath = (0, import_node_path13.join)(stateDir, STATUS_REL_PATH2);
8623
- if (!(0, import_node_fs17.existsSync)(filePath)) {
8768
+ const filePath = (0, import_node_path16.join)(stateDir, STATUS_REL_PATH2);
8769
+ if (!(0, import_node_fs19.existsSync)(filePath)) {
8624
8770
  return {
8625
8771
  id: "tunnel",
8626
8772
  severity: "warn",
@@ -8632,7 +8778,7 @@ var checkTunnel = ({ stateDir }) => {
8632
8778
  }
8633
8779
  let status;
8634
8780
  try {
8635
- status = JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
8781
+ status = JSON.parse((0, import_node_fs19.readFileSync)(filePath, "utf-8"));
8636
8782
  } catch {
8637
8783
  return {
8638
8784
  id: "tunnel",
@@ -8725,9 +8871,9 @@ function isObject5(v) {
8725
8871
  return !!v && typeof v === "object" && !Array.isArray(v);
8726
8872
  }
8727
8873
  function readConfig(configPath) {
8728
- if (!(0, import_node_fs18.existsSync)(configPath)) return {};
8874
+ if (!(0, import_node_fs20.existsSync)(configPath)) return {};
8729
8875
  try {
8730
- const parsed = JSON.parse((0, import_node_fs18.readFileSync)(configPath, "utf-8"));
8876
+ const parsed = JSON.parse((0, import_node_fs20.readFileSync)(configPath, "utf-8"));
8731
8877
  return isObject5(parsed) ? parsed : {};
8732
8878
  } catch {
8733
8879
  return {};
@@ -8928,7 +9074,7 @@ function registerRecStoragePath(rec, ctx) {
8928
9074
 
8929
9075
  // src/cli/rec-setup.ts
8930
9076
  var import_node_readline2 = require("readline");
8931
- var import_node_fs19 = require("fs");
9077
+ var import_node_fs21 = require("fs");
8932
9078
  function ask(rl, question) {
8933
9079
  return new Promise((resolve) => rl.question(question, resolve));
8934
9080
  }
@@ -9014,9 +9160,9 @@ async function setupLocal(rl) {
9014
9160
  function registerRecSetup(rec, ctx) {
9015
9161
  rec.command("setup").description("\u4EA4\u4E92\u5F0F\u914D\u7F6E ASR \u8F6C\u5199\u53C2\u6570\uFF0C\u4FDD\u5B58\u5230\u672C\u5730\u914D\u7F6E\u6587\u4EF6").action(async () => {
9016
9162
  const configPath = resolveAsrConfigPath(ctx);
9017
- if ((0, import_node_fs19.existsSync)(configPath)) {
9163
+ if ((0, import_node_fs21.existsSync)(configPath)) {
9018
9164
  try {
9019
- const existing = JSON.parse((0, import_node_fs19.readFileSync)(configPath, "utf-8"));
9165
+ const existing = JSON.parse((0, import_node_fs21.readFileSync)(configPath, "utf-8"));
9020
9166
  process.stderr.write(`\u5F53\u524D\u5DF2\u6709\u914D\u7F6E\uFF1Amode = ${existing.mode}`);
9021
9167
  if (existing.updatedAt) process.stderr.write(`\uFF0C\u66F4\u65B0\u4E8E ${existing.updatedAt}`);
9022
9168
  process.stderr.write("\n");
@@ -9029,7 +9175,7 @@ function registerRecSetup(rec, ctx) {
9029
9175
  const modeIdx = await askChoice(rl, "\u9009\u62E9\u6A21\u5F0F", ["api\uFF08\u4E91\u7AEF model-proxy \u957F\u5F55\u97F3\uFF09", "local\uFF08\u672C\u5730 Whisper\uFF09"]);
9030
9176
  const config = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);
9031
9177
  const stored = { ...config, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9032
- (0, import_node_fs19.writeFileSync)(configPath, JSON.stringify(stored, null, 2), "utf-8");
9178
+ (0, import_node_fs21.writeFileSync)(configPath, JSON.stringify(stored, null, 2), "utf-8");
9033
9179
  process.stderr.write(`
9034
9180
  \u2713 \u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230 ${configPath}
9035
9181
 
@@ -9043,11 +9189,11 @@ function registerRecSetup(rec, ctx) {
9043
9189
 
9044
9190
  // src/cli/update.ts
9045
9191
  var import_node_child_process = require("child_process");
9046
- var import_node_fs20 = require("fs");
9047
- var import_node_path14 = require("path");
9048
- var import_node_os2 = __toESM(require("os"), 1);
9192
+ var import_node_fs22 = require("fs");
9193
+ var import_node_path17 = require("path");
9194
+ var import_node_os3 = __toESM(require("os"), 1);
9049
9195
  init_host();
9050
- var BASE_URL = "https://cdn.yoootek.com/openclaw-plugin";
9196
+ var BASE_URL2 = "https://artifact.yoooclaw.com/plugin";
9051
9197
  async function fetchText(url) {
9052
9198
  const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
9053
9199
  if (!res.ok) {
@@ -9067,7 +9213,7 @@ async function runUpdate(ctx, opts) {
9067
9213
  log(`\u68C0\u67E5${beta ? " beta" : ""}\u6700\u65B0\u7248\u672C ...`);
9068
9214
  let latest;
9069
9215
  try {
9070
- latest = (await fetchText(`${BASE_URL}/${channel}`)).trim();
9216
+ latest = (await fetchText(`${BASE_URL2}/${channel}`)).trim();
9071
9217
  } catch (err) {
9072
9218
  const msg = `\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C: ${err?.message ?? String(err)}`;
9073
9219
  if (json) {
@@ -9092,7 +9238,7 @@ async function runUpdate(ctx, opts) {
9092
9238
  log("\u4E0B\u8F7D\u5B89\u88C5\u811A\u672C ...");
9093
9239
  let installScript;
9094
9240
  try {
9095
- installScript = await fetchText(`${BASE_URL}/install-core.mjs`);
9241
+ installScript = await fetchText(`${BASE_URL2}/install-core.mjs`);
9096
9242
  } catch (err) {
9097
9243
  const msg = `\u4E0B\u8F7D\u5B89\u88C5\u811A\u672C\u5931\u8D25: ${err?.message ?? String(err)}`;
9098
9244
  if (json) {
@@ -9103,9 +9249,9 @@ async function runUpdate(ctx, opts) {
9103
9249
  `);
9104
9250
  process.exit(1);
9105
9251
  }
9106
- const tmpScript = (0, import_node_path14.join)(import_node_os2.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
9252
+ const tmpScript = (0, import_node_path17.join)(import_node_os3.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
9107
9253
  try {
9108
- (0, import_node_fs20.writeFileSync)(tmpScript, installScript, "utf-8");
9254
+ (0, import_node_fs22.writeFileSync)(tmpScript, installScript, "utf-8");
9109
9255
  } catch (err) {
9110
9256
  const msg = `\u5199\u5165\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${err?.message ?? String(err)}`;
9111
9257
  if (json) {
@@ -9123,7 +9269,7 @@ async function runUpdate(ctx, opts) {
9123
9269
  { stdio: "inherit" }
9124
9270
  );
9125
9271
  try {
9126
- (0, import_node_fs20.unlinkSync)(tmpScript);
9272
+ (0, import_node_fs22.unlinkSync)(tmpScript);
9127
9273
  } catch {
9128
9274
  }
9129
9275
  if (result.error) {
@@ -9187,10 +9333,10 @@ function inferOpenClawRootDir(workspaceDir) {
9187
9333
  if (!workspaceDir) {
9188
9334
  return void 0;
9189
9335
  }
9190
- if ((0, import_node_path15.basename)(workspaceDir) !== "workspace") {
9336
+ if ((0, import_node_path18.basename)(workspaceDir) !== "workspace") {
9191
9337
  return void 0;
9192
9338
  }
9193
- return (0, import_node_path15.dirname)(workspaceDir);
9339
+ return (0, import_node_path18.dirname)(workspaceDir);
9194
9340
  }
9195
9341
  function registerPluginCli(api, params) {
9196
9342
  const { logger, openclawDir } = params;
@@ -9436,12 +9582,12 @@ function registerLightControlTool(api, logger) {
9436
9582
  }
9437
9583
 
9438
9584
  // src/plugin/lifecycle.ts
9439
- var import_node_fs29 = require("fs");
9585
+ var import_node_fs31 = require("fs");
9440
9586
  init_host();
9441
9587
 
9442
9588
  // src/notification/app-name-map.ts
9443
- var import_node_fs21 = require("fs");
9444
- var import_node_path16 = require("path");
9589
+ var import_node_fs23 = require("fs");
9590
+ var import_node_path19 = require("path");
9445
9591
  init_credentials();
9446
9592
  init_env();
9447
9593
  var PLUGIN_STATE_DIR = "phone-notifications";
@@ -9462,7 +9608,7 @@ function isAppNameMapApiResponse(v) {
9462
9608
  );
9463
9609
  }
9464
9610
  function getCachePath(stateDir) {
9465
- return (0, import_node_path16.join)(stateDir, "plugins", PLUGIN_STATE_DIR, CACHE_FILE);
9611
+ return (0, import_node_path19.join)(stateDir, "plugins", PLUGIN_STATE_DIR, CACHE_FILE);
9466
9612
  }
9467
9613
  function createAppNameMapProvider(opts) {
9468
9614
  const { stateDir, logger } = opts;
@@ -9474,9 +9620,9 @@ function createAppNameMapProvider(opts) {
9474
9620
  let inFlightFetch = null;
9475
9621
  function loadFromDisk() {
9476
9622
  const path2 = getCachePath(stateDir);
9477
- if (!(0, import_node_fs21.existsSync)(path2)) return;
9623
+ if (!(0, import_node_fs23.existsSync)(path2)) return;
9478
9624
  try {
9479
- const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf-8"));
9625
+ const raw = JSON.parse((0, import_node_fs23.readFileSync)(path2, "utf-8"));
9480
9626
  if (!isRecordOfStrings(raw)) return;
9481
9627
  map.clear();
9482
9628
  for (const [k, v] of Object.entries(raw)) map.set(k, v);
@@ -9520,10 +9666,10 @@ function createAppNameMapProvider(opts) {
9520
9666
  logger.warn("[app-name-map] refresh succeeded but got 0 entries");
9521
9667
  return;
9522
9668
  }
9523
- const dir = (0, import_node_path16.join)(stateDir, "plugins", PLUGIN_STATE_DIR);
9524
- (0, import_node_fs21.mkdirSync)(dir, { recursive: true });
9669
+ const dir = (0, import_node_path19.join)(stateDir, "plugins", PLUGIN_STATE_DIR);
9670
+ (0, import_node_fs23.mkdirSync)(dir, { recursive: true });
9525
9671
  const cachePath = getCachePath(stateDir);
9526
- (0, import_node_fs21.writeFileSync)(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), "utf-8");
9672
+ (0, import_node_fs23.writeFileSync)(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), "utf-8");
9527
9673
  logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);
9528
9674
  } catch (e) {
9529
9675
  const message = e instanceof Error ? e.message : String(e);
@@ -9567,8 +9713,8 @@ function createAppNameMapProvider(opts) {
9567
9713
  }
9568
9714
 
9569
9715
  // src/recording/storage.ts
9570
- var import_node_fs22 = require("fs");
9571
- var import_node_path17 = require("path");
9716
+ var import_node_fs24 = require("fs");
9717
+ var import_node_path20 = require("path");
9572
9718
 
9573
9719
  // src/recording/state-machine.ts
9574
9720
  var VALID_TRANSITIONS = /* @__PURE__ */ new Map([
@@ -9629,7 +9775,7 @@ function stripMarkdownFence(markdown) {
9629
9775
  }
9630
9776
  function deriveTitleFromTranscriptPath(transcriptFile, recordingId) {
9631
9777
  if (!transcriptFile) return void 0;
9632
- const name = (0, import_node_path17.basename)(transcriptFile, ".md");
9778
+ const name = (0, import_node_path20.basename)(transcriptFile, ".md");
9633
9779
  const prefix = `${recordingId}_`;
9634
9780
  if (name.startsWith(prefix)) {
9635
9781
  const derived = name.slice(prefix.length).trim();
@@ -9657,22 +9803,22 @@ function extractTranscriptContent(markdown) {
9657
9803
  return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
9658
9804
  }
9659
9805
  function resolveRecordingStorageDir(ctx, logger) {
9660
- const stateRecDir = (0, import_node_path17.join)(
9806
+ const stateRecDir = (0, import_node_path20.join)(
9661
9807
  ctx.stateDir,
9662
9808
  "plugins",
9663
9809
  "phone-notifications",
9664
9810
  RECORDINGS_DIR
9665
9811
  );
9666
9812
  try {
9667
- (0, import_node_fs22.mkdirSync)(stateRecDir, { recursive: true });
9813
+ (0, import_node_fs24.mkdirSync)(stateRecDir, { recursive: true });
9668
9814
  logger.info(`\u5F55\u97F3\u5C06\u5199\u5165 stateDir \u8DEF\u5F84: ${stateRecDir}`);
9669
9815
  return stateRecDir;
9670
9816
  } catch {
9671
9817
  }
9672
9818
  if (ctx.workspaceDir) {
9673
- const wsRecDir = (0, import_node_path17.join)(ctx.workspaceDir, RECORDINGS_DIR);
9819
+ const wsRecDir = (0, import_node_path20.join)(ctx.workspaceDir, RECORDINGS_DIR);
9674
9820
  try {
9675
- (0, import_node_fs22.mkdirSync)(wsRecDir, { recursive: true });
9821
+ (0, import_node_fs24.mkdirSync)(wsRecDir, { recursive: true });
9676
9822
  logger.warn(`stateDir \u4E0D\u53EF\u7528\uFF0C\u5F55\u97F3\u5DF2\u56DE\u9000\u5230 workspace \u8DEF\u5F84: ${wsRecDir}`);
9677
9823
  return wsRecDir;
9678
9824
  } catch {
@@ -9684,11 +9830,11 @@ var RecordingStorage = class {
9684
9830
  constructor(dir, logger) {
9685
9831
  this.logger = logger;
9686
9832
  this.dir = dir;
9687
- this.audioDir = (0, import_node_path17.join)(dir, AUDIO_DIR);
9688
- this.transcriptDataDir = (0, import_node_path17.join)(dir, TRANSCRIPT_DATA_DIR);
9689
- this.transcriptsDir = (0, import_node_path17.join)(dir, TRANSCRIPTS_DIR);
9690
- this.summariesDir = (0, import_node_path17.join)(dir, SUMMARIES_DIR);
9691
- this.indexPath = (0, import_node_path17.join)(dir, INDEX_FILE);
9833
+ this.audioDir = (0, import_node_path20.join)(dir, AUDIO_DIR);
9834
+ this.transcriptDataDir = (0, import_node_path20.join)(dir, TRANSCRIPT_DATA_DIR);
9835
+ this.transcriptsDir = (0, import_node_path20.join)(dir, TRANSCRIPTS_DIR);
9836
+ this.summariesDir = (0, import_node_path20.join)(dir, SUMMARIES_DIR);
9837
+ this.indexPath = (0, import_node_path20.join)(dir, INDEX_FILE);
9692
9838
  }
9693
9839
  dir;
9694
9840
  audioDir;
@@ -9699,10 +9845,10 @@ var RecordingStorage = class {
9699
9845
  index = { recordings: [] };
9700
9846
  /** 初始化目录结构并加载索引 */
9701
9847
  async init() {
9702
- (0, import_node_fs22.mkdirSync)(this.audioDir, { recursive: true });
9703
- (0, import_node_fs22.mkdirSync)(this.transcriptDataDir, { recursive: true });
9704
- (0, import_node_fs22.mkdirSync)(this.transcriptsDir, { recursive: true });
9705
- (0, import_node_fs22.mkdirSync)(this.summariesDir, { recursive: true });
9848
+ (0, import_node_fs24.mkdirSync)(this.audioDir, { recursive: true });
9849
+ (0, import_node_fs24.mkdirSync)(this.transcriptDataDir, { recursive: true });
9850
+ (0, import_node_fs24.mkdirSync)(this.transcriptsDir, { recursive: true });
9851
+ (0, import_node_fs24.mkdirSync)(this.summariesDir, { recursive: true });
9706
9852
  this.loadIndex();
9707
9853
  this.logger.info(
9708
9854
  `\u5F55\u97F3\u5B58\u50A8\u5DF2\u521D\u59CB\u5316: ${this.dir}\uFF08\u5171 ${this.index.recordings.length} \u6761\u8BB0\u5F55\uFF09`
@@ -9746,13 +9892,13 @@ var RecordingStorage = class {
9746
9892
  return id;
9747
9893
  }
9748
9894
  if (existing.transcriptDataFile) {
9749
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, existing.transcriptDataFile), { force: true });
9895
+ (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, existing.transcriptDataFile), { force: true });
9750
9896
  }
9751
9897
  if (existing.transcriptFile) {
9752
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, existing.transcriptFile), { force: true });
9898
+ (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, existing.transcriptFile), { force: true });
9753
9899
  }
9754
9900
  if (existing.summaryFile) {
9755
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, existing.summaryFile), { force: true });
9901
+ (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, existing.summaryFile), { force: true });
9756
9902
  }
9757
9903
  existing.metadata = metadata;
9758
9904
  existing.status = "syncing_openclaw";
@@ -9820,7 +9966,7 @@ var RecordingStorage = class {
9820
9966
  if (!entry) return;
9821
9967
  const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;
9822
9968
  if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {
9823
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, entry.transcriptDataFile), { force: true });
9969
+ (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, entry.transcriptDataFile), { force: true });
9824
9970
  }
9825
9971
  entry.transcriptDataFile = nextTranscriptDataFile;
9826
9972
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -9834,7 +9980,7 @@ var RecordingStorage = class {
9834
9980
  if (!entry) return;
9835
9981
  const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;
9836
9982
  if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {
9837
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, entry.transcriptFile), { force: true });
9983
+ (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, entry.transcriptFile), { force: true });
9838
9984
  }
9839
9985
  entry.transcriptFile = nextTranscriptFile;
9840
9986
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -9848,7 +9994,7 @@ var RecordingStorage = class {
9848
9994
  if (!entry) return;
9849
9995
  const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;
9850
9996
  if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {
9851
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, entry.summaryFile), { force: true });
9997
+ (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, entry.summaryFile), { force: true });
9852
9998
  }
9853
9999
  entry.summaryFile = nextSummaryFile;
9854
10000
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -9946,24 +10092,24 @@ var RecordingStorage = class {
9946
10092
  const entry = this.findById(recordingId);
9947
10093
  if (!entry) return false;
9948
10094
  if (entry.audioFile) {
9949
- const audioPath = (0, import_node_path17.join)(this.dir, entry.audioFile);
9950
- (0, import_node_fs22.rmSync)(audioPath, { force: true });
10095
+ const audioPath = (0, import_node_path20.join)(this.dir, entry.audioFile);
10096
+ (0, import_node_fs24.rmSync)(audioPath, { force: true });
9951
10097
  }
9952
10098
  if (entry.srtFile) {
9953
- const srtPath = (0, import_node_path17.join)(this.dir, entry.srtFile);
9954
- (0, import_node_fs22.rmSync)(srtPath, { force: true });
10099
+ const srtPath = (0, import_node_path20.join)(this.dir, entry.srtFile);
10100
+ (0, import_node_fs24.rmSync)(srtPath, { force: true });
9955
10101
  }
9956
10102
  if (entry.transcriptDataFile) {
9957
- const transcriptDataPath = (0, import_node_path17.join)(this.dir, entry.transcriptDataFile);
9958
- (0, import_node_fs22.rmSync)(transcriptDataPath, { force: true });
10103
+ const transcriptDataPath = (0, import_node_path20.join)(this.dir, entry.transcriptDataFile);
10104
+ (0, import_node_fs24.rmSync)(transcriptDataPath, { force: true });
9959
10105
  }
9960
10106
  if (entry.transcriptFile) {
9961
- const transcriptPath = (0, import_node_path17.join)(this.dir, entry.transcriptFile);
9962
- (0, import_node_fs22.rmSync)(transcriptPath, { force: true });
10107
+ const transcriptPath = (0, import_node_path20.join)(this.dir, entry.transcriptFile);
10108
+ (0, import_node_fs24.rmSync)(transcriptPath, { force: true });
9963
10109
  }
9964
10110
  if (entry.summaryFile) {
9965
- const summaryPath = (0, import_node_path17.join)(this.dir, entry.summaryFile);
9966
- (0, import_node_fs22.rmSync)(summaryPath, { force: true });
10111
+ const summaryPath = (0, import_node_path20.join)(this.dir, entry.summaryFile);
10112
+ (0, import_node_fs24.rmSync)(summaryPath, { force: true });
9967
10113
  }
9968
10114
  if (opts?.localOnly) {
9969
10115
  entry.audioFile = void 0;
@@ -10021,34 +10167,34 @@ var RecordingStorage = class {
10021
10167
  * 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名
10022
10168
  */
10023
10169
  getAudioFilePath(recordingId, ossUrl) {
10024
- return (0, import_node_path17.join)(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));
10170
+ return (0, import_node_path20.join)(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));
10025
10171
  }
10026
10172
  /**
10027
10173
  * 获取打点文件的绝对路径
10028
10174
  */
10029
10175
  getSrtFilePath(recordingId) {
10030
- return (0, import_node_path17.join)(this.audioDir, this.buildSrtFilename(recordingId));
10176
+ return (0, import_node_path20.join)(this.audioDir, this.buildSrtFilename(recordingId));
10031
10177
  }
10032
10178
  /**
10033
10179
  * 获取转写 JSON 文件的绝对路径
10034
10180
  */
10035
10181
  getTranscriptDataFilePath(recordingId) {
10036
- return (0, import_node_path17.join)(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));
10182
+ return (0, import_node_path20.join)(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));
10037
10183
  }
10038
10184
  /**
10039
10185
  * 获取摘要文件的绝对路径
10040
10186
  */
10041
10187
  getSummaryFilePath(recordingId) {
10042
- return (0, import_node_path17.join)(this.summariesDir, this.buildSummaryFilename(recordingId));
10188
+ return (0, import_node_path20.join)(this.summariesDir, this.buildSummaryFilename(recordingId));
10043
10189
  }
10044
10190
  // ─── Persistence ───
10045
10191
  loadIndex() {
10046
- if (!(0, import_node_fs22.existsSync)(this.indexPath)) {
10192
+ if (!(0, import_node_fs24.existsSync)(this.indexPath)) {
10047
10193
  this.index = { recordings: [] };
10048
10194
  return;
10049
10195
  }
10050
10196
  try {
10051
- const raw = JSON.parse((0, import_node_fs22.readFileSync)(this.indexPath, "utf-8"));
10197
+ const raw = JSON.parse((0, import_node_fs24.readFileSync)(this.indexPath, "utf-8"));
10052
10198
  if (raw && Array.isArray(raw.recordings)) {
10053
10199
  let needsRewrite = false;
10054
10200
  const normalized = raw.recordings.filter((entry) => entry && typeof entry === "object").map((entry) => {
@@ -10086,8 +10232,8 @@ var RecordingStorage = class {
10086
10232
  segments: []
10087
10233
  });
10088
10234
  const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);
10089
- (0, import_node_fs22.writeFileSync)(
10090
- (0, import_node_path17.join)(this.transcriptDataDir, transcriptDataFilename),
10235
+ (0, import_node_fs24.writeFileSync)(
10236
+ (0, import_node_path20.join)(this.transcriptDataDir, transcriptDataFilename),
10091
10237
  JSON.stringify(transcriptDoc, null, 2),
10092
10238
  "utf-8"
10093
10239
  );
@@ -10099,8 +10245,8 @@ var RecordingStorage = class {
10099
10245
  compacted.summaryFile = entry.summaryFile;
10100
10246
  } else if (typeof entry.summary === "string" && entry.summary.trim()) {
10101
10247
  const summaryFilename = this.buildSummaryFilename(entry.id);
10102
- (0, import_node_fs22.writeFileSync)(
10103
- (0, import_node_path17.join)(this.summariesDir, summaryFilename),
10248
+ (0, import_node_fs24.writeFileSync)(
10249
+ (0, import_node_path20.join)(this.summariesDir, summaryFilename),
10104
10250
  entry.summary.trim(),
10105
10251
  "utf-8"
10106
10252
  );
@@ -10110,8 +10256,8 @@ var RecordingStorage = class {
10110
10256
  const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);
10111
10257
  if (summaryFromDocument) {
10112
10258
  const summaryFilename = this.buildSummaryFilename(entry.id);
10113
- (0, import_node_fs22.writeFileSync)(
10114
- (0, import_node_path17.join)(this.summariesDir, summaryFilename),
10259
+ (0, import_node_fs24.writeFileSync)(
10260
+ (0, import_node_path20.join)(this.summariesDir, summaryFilename),
10115
10261
  summaryFromDocument,
10116
10262
  "utf-8"
10117
10263
  );
@@ -10151,7 +10297,7 @@ var RecordingStorage = class {
10151
10297
  }
10152
10298
  readRelativeTextFile(relativePath) {
10153
10299
  try {
10154
- return (0, import_node_fs22.readFileSync)((0, import_node_path17.join)(this.dir, relativePath), "utf-8");
10300
+ return (0, import_node_fs24.readFileSync)((0, import_node_path20.join)(this.dir, relativePath), "utf-8");
10155
10301
  } catch {
10156
10302
  return void 0;
10157
10303
  }
@@ -10164,7 +10310,7 @@ var RecordingStorage = class {
10164
10310
  return parseTranscriptDocument(raw);
10165
10311
  }
10166
10312
  saveIndex() {
10167
- (0, import_node_fs22.writeFileSync)(
10313
+ (0, import_node_fs24.writeFileSync)(
10168
10314
  this.indexPath,
10169
10315
  JSON.stringify(this.index, null, 2),
10170
10316
  "utf-8"
@@ -10178,8 +10324,8 @@ var RecordingStorage = class {
10178
10324
  init_transcript_document();
10179
10325
 
10180
10326
  // src/recording/downloader.ts
10181
- var import_node_fs23 = require("fs");
10182
- var import_node_path18 = require("path");
10327
+ var import_node_fs25 = require("fs");
10328
+ var import_node_path21 = require("path");
10183
10329
  var import_promises2 = require("stream/promises");
10184
10330
  var import_node_stream = require("stream");
10185
10331
  var DEFAULT_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -10189,7 +10335,7 @@ async function downloadFile(url, destPath, logger, options) {
10189
10335
  const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
10190
10336
  const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
10191
10337
  const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;
10192
- (0, import_node_fs23.mkdirSync)((0, import_node_path18.dirname)(destPath), { recursive: true });
10338
+ (0, import_node_fs25.mkdirSync)((0, import_node_path21.dirname)(destPath), { recursive: true });
10193
10339
  let lastError;
10194
10340
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
10195
10341
  const startMs = Date.now();
@@ -10207,11 +10353,11 @@ async function downloadFile(url, destPath, logger, options) {
10207
10353
  if (!res.body) {
10208
10354
  throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
10209
10355
  }
10210
- const writeStream = (0, import_node_fs23.createWriteStream)(destPath);
10356
+ const writeStream = (0, import_node_fs25.createWriteStream)(destPath);
10211
10357
  const readable = import_node_stream.Readable.fromWeb(res.body);
10212
10358
  await (0, import_promises2.pipeline)(readable, writeStream);
10213
10359
  const elapsed = Date.now() - startMs;
10214
- const fileSize = (0, import_node_fs23.existsSync)(destPath) ? (0, import_node_fs23.statSync)(destPath).size : 0;
10360
+ const fileSize = (0, import_node_fs25.existsSync)(destPath) ? (0, import_node_fs25.statSync)(destPath).size : 0;
10215
10361
  logger.info(
10216
10362
  `[downloader] \u4E0B\u8F7D\u5B8C\u6210: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`
10217
10363
  );
@@ -10222,7 +10368,7 @@ async function downloadFile(url, destPath, logger, options) {
10222
10368
  } catch (err) {
10223
10369
  lastError = err?.message ?? String(err);
10224
10370
  try {
10225
- if ((0, import_node_fs23.existsSync)(destPath)) (0, import_node_fs23.unlinkSync)(destPath);
10371
+ if ((0, import_node_fs25.existsSync)(destPath)) (0, import_node_fs25.unlinkSync)(destPath);
10226
10372
  } catch {
10227
10373
  }
10228
10374
  const isAbort = err?.name === "AbortError";
@@ -10460,13 +10606,13 @@ async function triggerTranscription(recordingId, storage, asrConfig, logger, opt
10460
10606
  }
10461
10607
 
10462
10608
  // src/tunnel/service.ts
10463
- var import_node_fs28 = require("fs");
10464
- var import_node_path23 = require("path");
10609
+ var import_node_fs30 = require("fs");
10610
+ var import_node_path26 = require("path");
10465
10611
  init_credentials();
10466
10612
 
10467
10613
  // src/tunnel/relay-client.ts
10468
- var import_node_fs26 = require("fs");
10469
- var import_node_path21 = require("path");
10614
+ var import_node_fs28 = require("fs");
10615
+ var import_node_path24 = require("path");
10470
10616
 
10471
10617
  // node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
10472
10618
  var import_stream = __toESM(require_stream(), 1);
@@ -10510,8 +10656,8 @@ var RelayClient = class {
10510
10656
  lastDisconnectReason
10511
10657
  };
10512
10658
  try {
10513
- (0, import_node_fs26.mkdirSync)((0, import_node_path21.dirname)(this.opts.statusFilePath), { recursive: true });
10514
- (0, import_node_fs26.writeFileSync)(this.opts.statusFilePath, JSON.stringify(info, null, 2));
10659
+ (0, import_node_fs28.mkdirSync)((0, import_node_path24.dirname)(this.opts.statusFilePath), { recursive: true });
10660
+ (0, import_node_fs28.writeFileSync)(this.opts.statusFilePath, JSON.stringify(info, null, 2));
10515
10661
  } catch {
10516
10662
  }
10517
10663
  }
@@ -10893,8 +11039,8 @@ init_host();
10893
11039
 
10894
11040
  // src/tunnel/device-identity.ts
10895
11041
  var import_node_crypto3 = __toESM(require("crypto"), 1);
10896
- var import_node_fs27 = __toESM(require("fs"), 1);
10897
- var import_node_path22 = __toESM(require("path"), 1);
11042
+ var import_node_fs29 = __toESM(require("fs"), 1);
11043
+ var import_node_path25 = __toESM(require("path"), 1);
10898
11044
  init_host();
10899
11045
  var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
10900
11046
  function base64UrlEncode(buf) {
@@ -10939,10 +11085,10 @@ function resolveClientStateDir(stateDir) {
10939
11085
  return stateDir ?? resolveStateDir();
10940
11086
  }
10941
11087
  function ensureDir(filePath) {
10942
- import_node_fs27.default.mkdirSync(import_node_path22.default.dirname(filePath), { recursive: true });
11088
+ import_node_fs29.default.mkdirSync(import_node_path25.default.dirname(filePath), { recursive: true });
10943
11089
  }
10944
11090
  function resolveIdentityPath(stateDir) {
10945
- return import_node_path22.default.join(stateDir, "identity", "device.json");
11091
+ return import_node_path25.default.join(stateDir, "identity", "device.json");
10946
11092
  }
10947
11093
  function normalizeDeviceAuthRole(role) {
10948
11094
  return role.trim();
@@ -10958,12 +11104,12 @@ function normalizeDeviceAuthScopes(scopes) {
10958
11104
  return [...out].sort();
10959
11105
  }
10960
11106
  function resolveDeviceAuthPath(stateDir) {
10961
- return import_node_path22.default.join(stateDir, "identity", "device-auth.json");
11107
+ return import_node_path25.default.join(stateDir, "identity", "device-auth.json");
10962
11108
  }
10963
11109
  function readDeviceAuthStore(filePath) {
10964
11110
  try {
10965
- if (!import_node_fs27.default.existsSync(filePath)) return null;
10966
- const raw = import_node_fs27.default.readFileSync(filePath, "utf8");
11111
+ if (!import_node_fs29.default.existsSync(filePath)) return null;
11112
+ const raw = import_node_fs29.default.readFileSync(filePath, "utf8");
10967
11113
  const parsed = JSON.parse(raw);
10968
11114
  if (parsed?.version !== 1 || typeof parsed.deviceId !== "string") return null;
10969
11115
  if (!parsed.tokens || typeof parsed.tokens !== "object") return null;
@@ -10974,12 +11120,12 @@ function readDeviceAuthStore(filePath) {
10974
11120
  }
10975
11121
  function writeDeviceAuthStore(filePath, store) {
10976
11122
  ensureDir(filePath);
10977
- import_node_fs27.default.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
11123
+ import_node_fs29.default.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
10978
11124
  `, {
10979
11125
  mode: 384
10980
11126
  });
10981
11127
  try {
10982
- import_node_fs27.default.chmodSync(filePath, 384);
11128
+ import_node_fs29.default.chmodSync(filePath, 384);
10983
11129
  } catch {
10984
11130
  }
10985
11131
  }
@@ -11026,8 +11172,8 @@ function clearDeviceAuthToken(params) {
11026
11172
  function loadOrCreateDeviceIdentity(stateDir) {
11027
11173
  const filePath = resolveIdentityPath(stateDir);
11028
11174
  try {
11029
- if (import_node_fs27.default.existsSync(filePath)) {
11030
- const raw = import_node_fs27.default.readFileSync(filePath, "utf8");
11175
+ if (import_node_fs29.default.existsSync(filePath)) {
11176
+ const raw = import_node_fs29.default.readFileSync(filePath, "utf8");
11031
11177
  const parsed = JSON.parse(raw);
11032
11178
  if (parsed?.version === 1 && typeof parsed.deviceId === "string" && typeof parsed.publicKeyPem === "string" && typeof parsed.privateKeyPem === "string") {
11033
11179
  const derivedId = fingerprintPublicKey(parsed.publicKeyPem);
@@ -11048,14 +11194,14 @@ function loadOrCreateDeviceIdentity(stateDir) {
11048
11194
  publicKeyPem,
11049
11195
  privateKeyPem
11050
11196
  };
11051
- import_node_fs27.default.mkdirSync(import_node_path22.default.dirname(filePath), { recursive: true });
11197
+ import_node_fs29.default.mkdirSync(import_node_path25.default.dirname(filePath), { recursive: true });
11052
11198
  const stored = {
11053
11199
  version: 1,
11054
11200
  ...identity,
11055
11201
  createdAtMs: Date.now()
11056
11202
  };
11057
11203
  ensureDir(filePath);
11058
- import_node_fs27.default.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}
11204
+ import_node_fs29.default.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}
11059
11205
  `, {
11060
11206
  mode: 384
11061
11207
  });
@@ -11825,7 +11971,7 @@ function createTunnelService(opts) {
11825
11971
  }
11826
11972
  function readLockOwner(filePath) {
11827
11973
  try {
11828
- const parsed = JSON.parse((0, import_node_fs28.readFileSync)(filePath, "utf-8"));
11974
+ const parsed = JSON.parse((0, import_node_fs30.readFileSync)(filePath, "utf-8"));
11829
11975
  return typeof parsed.pid === "number" ? parsed.pid : null;
11830
11976
  } catch {
11831
11977
  return null;
@@ -11838,23 +11984,23 @@ function createTunnelService(opts) {
11838
11984
  lockFd = null;
11839
11985
  if (fd !== null) {
11840
11986
  try {
11841
- (0, import_node_fs28.closeSync)(fd);
11987
+ (0, import_node_fs30.closeSync)(fd);
11842
11988
  } catch {
11843
11989
  }
11844
11990
  }
11845
11991
  if (filePath) {
11846
11992
  try {
11847
- (0, import_node_fs28.unlinkSync)(filePath);
11993
+ (0, import_node_fs30.unlinkSync)(filePath);
11848
11994
  } catch {
11849
11995
  }
11850
11996
  }
11851
11997
  }
11852
11998
  function acquireLock(filePath) {
11853
- (0, import_node_fs28.mkdirSync)((0, import_node_path23.dirname)(filePath), { recursive: true });
11999
+ (0, import_node_fs30.mkdirSync)((0, import_node_path26.dirname)(filePath), { recursive: true });
11854
12000
  for (let attempt = 0; attempt < 2; attempt++) {
11855
12001
  try {
11856
- const fd = (0, import_node_fs28.openSync)(filePath, "wx", 384);
11857
- (0, import_node_fs28.writeFileSync)(
12002
+ const fd = (0, import_node_fs30.openSync)(filePath, "wx", 384);
12003
+ (0, import_node_fs30.writeFileSync)(
11858
12004
  fd,
11859
12005
  JSON.stringify({
11860
12006
  pid: process.pid,
@@ -11878,7 +12024,7 @@ function createTunnelService(opts) {
11878
12024
  `Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`
11879
12025
  );
11880
12026
  try {
11881
- (0, import_node_fs28.unlinkSync)(filePath);
12027
+ (0, import_node_fs30.unlinkSync)(filePath);
11882
12028
  } catch {
11883
12029
  }
11884
12030
  continue;
@@ -11923,12 +12069,12 @@ function createTunnelService(opts) {
11923
12069
  return;
11924
12070
  }
11925
12071
  const { logger } = opts;
11926
- const baseStateDir = (0, import_node_path23.join)(ctx.stateDir, "plugins", "phone-notifications");
12072
+ const baseStateDir = (0, import_node_path26.join)(ctx.stateDir, "plugins", "phone-notifications");
11927
12073
  logger.info(
11928
12074
  `Relay tunnel: starting (pid=${process.pid}, url=${opts.tunnelUrl}, heartbeat=${opts.heartbeatSec ?? DEFAULT_HEARTBEAT_SEC}s, backoff=${opts.reconnectBackoffMs ?? DEFAULT_RECONNECT_BACKOFF_MS}ms, gateway=${opts.gatewayBaseUrl}, hasGatewayToken=${!!opts.gatewayToken}, hasGatewayPwd=${!!opts.gatewayPassword})`
11929
12075
  );
11930
- const statusFilePath = (0, import_node_path23.join)(baseStateDir, "tunnel-status.json");
11931
- const lockPath = (0, import_node_path23.join)(baseStateDir, "relay-tunnel.lock");
12076
+ const statusFilePath = (0, import_node_path26.join)(baseStateDir, "tunnel-status.json");
12077
+ const lockPath = (0, import_node_path26.join)(baseStateDir, "relay-tunnel.lock");
11932
12078
  if (!acquireLock(lockPath)) {
11933
12079
  return;
11934
12080
  }
@@ -12068,7 +12214,7 @@ function readHostGatewayConfig(params) {
12068
12214
  let configData;
12069
12215
  if (configPath) {
12070
12216
  try {
12071
- configData = JSON.parse((0, import_node_fs29.readFileSync)(configPath, "utf-8"));
12217
+ configData = JSON.parse((0, import_node_fs31.readFileSync)(configPath, "utf-8"));
12072
12218
  } catch (err) {
12073
12219
  if (err?.code !== "ENOENT") {
12074
12220
  params.logger.warn(