@yoooclaw/phone-notifications 1.10.2 → 1.10.3

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
@@ -461,8 +461,8 @@ __export(whisper_local_exports, {
461
461
  transcribeWithWhisperLocal: () => transcribeWithWhisperLocal
462
462
  });
463
463
  function detectEnvironment(logger) {
464
- const os2 = (0, import_node_os3.platform)();
465
- const cpuArch = (0, import_node_os3.arch)();
464
+ const os2 = (0, import_node_os4.platform)();
465
+ const cpuArch = (0, import_node_os4.arch)();
466
466
  const isAppleSilicon = os2 === "darwin" && cpuArch === "arm64";
467
467
  const hasCuda = detectCuda(logger);
468
468
  let recommendedBackend;
@@ -500,20 +500,20 @@ function selectModelByMemory(availableGB, isAppleSilicon = false) {
500
500
  return "tiny";
501
501
  }
502
502
  function resolveModelsDir(dataDir) {
503
- const dir = (0, import_node_path19.join)(dataDir, WHISPER_MODELS_DIR);
504
- (0, import_node_fs24.mkdirSync)(dir, { recursive: true });
503
+ const dir = (0, import_node_path21.join)(dataDir, WHISPER_MODELS_DIR);
504
+ (0, import_node_fs25.mkdirSync)(dir, { recursive: true });
505
505
  return dir;
506
506
  }
507
507
  function resolveBinDir(dataDir) {
508
- const dir = (0, import_node_path19.join)(dataDir, WHISPER_BIN_DIR);
509
- (0, import_node_fs24.mkdirSync)(dir, { recursive: true });
508
+ const dir = (0, import_node_path21.join)(dataDir, WHISPER_BIN_DIR);
509
+ (0, import_node_fs25.mkdirSync)(dir, { recursive: true });
510
510
  return dir;
511
511
  }
512
512
  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;
513
+ const modelPath = (0, import_node_path21.join)(modelsDir, MODEL_FILENAMES[modelSize]);
514
+ if (!(0, import_node_fs25.existsSync)(modelPath)) return false;
515
515
  try {
516
- const stat = (0, import_node_fs24.statSync)(modelPath);
516
+ const stat = (0, import_node_fs25.statSync)(modelPath);
517
517
  const expectedSize = MODEL_DISK_SIZES[modelSize];
518
518
  return stat.size >= expectedSize * 0.8;
519
519
  } catch {
@@ -522,7 +522,7 @@ function isModelDownloaded(modelsDir, modelSize) {
522
522
  }
523
523
  async function downloadModel(modelsDir, modelSize, logger, modelSource, mirrorUrl) {
524
524
  const filename = MODEL_FILENAMES[modelSize];
525
- const modelPath = (0, import_node_path19.join)(modelsDir, filename);
525
+ const modelPath = (0, import_node_path21.join)(modelsDir, filename);
526
526
  if (isModelDownloaded(modelsDir, modelSize)) {
527
527
  logger.info(`[whisper-local] \u6A21\u578B\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u4E0B\u8F7D: ${filename}`);
528
528
  return { ok: true, modelPath };
@@ -588,7 +588,7 @@ async function probeUrl(url, logger) {
588
588
  async function downloadFromUrl(url, modelPath, logger) {
589
589
  const tmpPath = `${modelPath}.downloading`;
590
590
  try {
591
- (0, import_node_fs24.mkdirSync)((0, import_node_path19.dirname)(modelPath), { recursive: true });
591
+ (0, import_node_fs25.mkdirSync)((0, import_node_path21.dirname)(modelPath), { recursive: true });
592
592
  const controller = new AbortController();
593
593
  const timer = setTimeout(() => controller.abort(), 30 * 60 * 1e3);
594
594
  try {
@@ -604,7 +604,7 @@ async function downloadFromUrl(url, modelPath, logger) {
604
604
  return { ok: false, modelPath, error: "\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: \u54CD\u5E94\u4F53\u4E3A\u7A7A" };
605
605
  }
606
606
  const contentLength = Number(res.headers.get("content-length") ?? 0);
607
- const writeStream = (0, import_node_fs24.createWriteStream)(tmpPath);
607
+ const writeStream = (0, import_node_fs25.createWriteStream)(tmpPath);
608
608
  const readable = import_node_stream2.Readable.fromWeb(res.body);
609
609
  let downloaded = 0;
610
610
  let lastLogPercent = 0;
@@ -624,16 +624,16 @@ async function downloadFromUrl(url, modelPath, logger) {
624
624
  } finally {
625
625
  clearTimeout(timer);
626
626
  }
627
- const { renameSync } = await import("fs");
628
- renameSync(tmpPath, modelPath);
629
- const fileSize = (0, import_node_fs24.statSync)(modelPath).size;
627
+ const { renameSync: renameSync2 } = await import("fs");
628
+ renameSync2(tmpPath, modelPath);
629
+ const fileSize = (0, import_node_fs25.statSync)(modelPath).size;
630
630
  logger.info(
631
- `[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path19.basename)(modelPath)} (${formatBytes2(fileSize)})`
631
+ `[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path21.basename)(modelPath)} (${formatBytes2(fileSize)})`
632
632
  );
633
633
  return { ok: true, modelPath };
634
634
  } catch (err) {
635
635
  try {
636
- if ((0, import_node_fs24.existsSync)(tmpPath)) (0, import_node_fs24.unlinkSync)(tmpPath);
636
+ if ((0, import_node_fs25.existsSync)(tmpPath)) (0, import_node_fs25.unlinkSync)(tmpPath);
637
637
  } catch {
638
638
  }
639
639
  const msg = err?.name === "AbortError" ? "\u6A21\u578B\u4E0B\u8F7D\u8D85\u65F6\uFF0830 \u5206\u949F\uFF09" : err?.message ?? String(err);
@@ -643,18 +643,18 @@ async function downloadFromUrl(url, modelPath, logger) {
643
643
  }
644
644
  function findWhisperBinary(dataDir, logger) {
645
645
  const binDir = resolveBinDir(dataDir);
646
- const binNames = (0, import_node_os3.platform)() === "win32" ? ["whisper-cli.exe", "whisper.exe", "main.exe"] : ["whisper-cli", "whisper", "main"];
646
+ const binNames = (0, import_node_os4.platform)() === "win32" ? ["whisper-cli.exe", "whisper.exe", "main.exe"] : ["whisper-cli", "whisper", "main"];
647
647
  for (const name of binNames) {
648
- const binPath = (0, import_node_path19.join)(binDir, name);
649
- if ((0, import_node_fs24.existsSync)(binPath)) {
648
+ const binPath = (0, import_node_path21.join)(binDir, name);
649
+ if ((0, import_node_fs25.existsSync)(binPath)) {
650
650
  logger.info(`[whisper-local] \u627E\u5230\u672C\u5730\u4E8C\u8FDB\u5236: ${binPath}`);
651
651
  return binPath;
652
652
  }
653
653
  }
654
- const pathNames = (0, import_node_os3.platform)() === "win32" ? ["whisper-cli", "whisper-cpp", "whisper"] : ["whisper-cli", "whisper-cpp", "whisper"];
654
+ const pathNames = (0, import_node_os4.platform)() === "win32" ? ["whisper-cli", "whisper-cpp", "whisper"] : ["whisper-cli", "whisper-cpp", "whisper"];
655
655
  for (const name of pathNames) {
656
656
  try {
657
- const cmd = (0, import_node_os3.platform)() === "win32" ? "where" : "which";
657
+ const cmd = (0, import_node_os4.platform)() === "win32" ? "where" : "which";
658
658
  const result = (0, import_node_child_process2.execSync)(`${cmd} ${name}`, { encoding: "utf-8", stdio: "pipe" }).trim();
659
659
  if (result) {
660
660
  logger.info(`[whisper-local] \u627E\u5230\u7CFB\u7EDF PATH \u4E8C\u8FDB\u5236: ${result}`);
@@ -697,7 +697,7 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
697
697
  return { ok: false, error: `\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: ${downloadResult.error}` };
698
698
  }
699
699
  }
700
- const modelPath = (0, import_node_path19.join)(modelsDir, MODEL_FILENAMES[modelSize]);
700
+ const modelPath = (0, import_node_path21.join)(modelsDir, MODEL_FILENAMES[modelSize]);
701
701
  let inputPath = audioFilePath;
702
702
  let tmpWavPath = null;
703
703
  const actualFmt = detectAudioFormat(audioFilePath);
@@ -749,10 +749,10 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
749
749
  logger.info(`[whisper-local] \u8F6C\u5199\u8017\u65F6: ${Math.round(elapsed / 1e3)}s`);
750
750
  const jsonPath = inputPath + ".json";
751
751
  let jsonContent;
752
- if ((0, import_node_fs24.existsSync)(jsonPath)) {
753
- jsonContent = (0, import_node_fs24.readFileSync)(jsonPath, "utf-8");
752
+ if ((0, import_node_fs25.existsSync)(jsonPath)) {
753
+ jsonContent = (0, import_node_fs25.readFileSync)(jsonPath, "utf-8");
754
754
  try {
755
- (0, import_node_fs24.unlinkSync)(jsonPath);
755
+ (0, import_node_fs25.unlinkSync)(jsonPath);
756
756
  } catch {
757
757
  }
758
758
  } else {
@@ -785,7 +785,7 @@ function detectCuda(logger) {
785
785
  return true;
786
786
  } catch {
787
787
  }
788
- if ((0, import_node_os3.platform)() === "linux") {
788
+ if ((0, import_node_os4.platform)() === "linux") {
789
789
  try {
790
790
  const ldconfig = (0, import_node_child_process2.execSync)("ldconfig -p 2>/dev/null | grep libcudart", {
791
791
  encoding: "utf-8",
@@ -816,24 +816,24 @@ function getAvailableMemoryGB(backend, logger) {
816
816
  logger.warn("[whisper-local] \u65E0\u6CD5\u83B7\u53D6 GPU VRAM\uFF0C\u4F7F\u7528\u7CFB\u7EDF RAM \u4EE3\u66FF");
817
817
  }
818
818
  }
819
- const totalGB = (0, import_node_os3.totalmem)() / (1024 * 1024 * 1024);
820
- const freeGB = (0, import_node_os3.freemem)() / (1024 * 1024 * 1024);
819
+ const totalGB = (0, import_node_os4.totalmem)() / (1024 * 1024 * 1024);
820
+ const freeGB = (0, import_node_os4.freemem)() / (1024 * 1024 * 1024);
821
821
  return Math.max(freeGB, totalGB * 0.6);
822
822
  }
823
823
  function getPhysicalCoreCount() {
824
- const cpuList = (0, import_node_os3.cpus)();
824
+ const cpuList = (0, import_node_os4.cpus)();
825
825
  if (cpuList.length === 0) return 4;
826
- if ((0, import_node_os3.platform)() === "darwin" && (0, import_node_os3.arch)() === "arm64") {
826
+ if ((0, import_node_os4.platform)() === "darwin" && (0, import_node_os4.arch)() === "arm64") {
827
827
  return cpuList.length;
828
828
  }
829
829
  return Math.max(1, Math.floor(cpuList.length / 2));
830
830
  }
831
831
  function detectAudioFormat(filePath) {
832
832
  try {
833
- const fd = (0, import_node_fs24.openSync)(filePath, "r");
833
+ const fd = (0, import_node_fs25.openSync)(filePath, "r");
834
834
  const buf = Buffer.alloc(12);
835
- (0, import_node_fs24.readSync)(fd, buf, 0, 12, 0);
836
- (0, import_node_fs24.closeSync)(fd);
835
+ (0, import_node_fs25.readSync)(fd, buf, 0, 12, 0);
836
+ (0, import_node_fs25.closeSync)(fd);
837
837
  const header = buf.toString("ascii", 0, 4);
838
838
  const header8 = buf.toString("ascii", 0, 8);
839
839
  if (header === "RIFF" && buf.toString("ascii", 8, 12) === "WAVE") return ".wav";
@@ -868,7 +868,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
868
868
  timeout: 12e4,
869
869
  stdio: ["pipe", "pipe", "pipe"]
870
870
  });
871
- if (ffmpegResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
871
+ if (ffmpegResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
872
872
  logger.info(`[whisper-local] ffmpeg \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
873
873
  return { ok: true };
874
874
  }
@@ -881,7 +881,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
881
881
  ["--rate", "16000", "--mono", inputPath, outputPath],
882
882
  { encoding: "utf-8", timeout: 12e4, stdio: ["pipe", "pipe", "pipe"] }
883
883
  );
884
- if (opusResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
884
+ if (opusResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
885
885
  logger.info(`[whisper-local] opusdec \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
886
886
  return { ok: true };
887
887
  }
@@ -895,7 +895,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
895
895
  if (detectedExt && !inputPath.endsWith(detectedExt)) {
896
896
  tmpCopy = inputPath + ".detected" + detectedExt;
897
897
  try {
898
- (0, import_node_fs24.copyFileSync)(inputPath, tmpCopy);
898
+ (0, import_node_fs25.copyFileSync)(inputPath, tmpCopy);
899
899
  actualInputPath = tmpCopy;
900
900
  logger.info(
901
901
  `[whisper-local] \u68C0\u6D4B\u5230\u5B9E\u9645\u683C\u5F0F ${detectedExt}\uFF0C\u4E34\u65F6\u91CD\u547D\u540D`
@@ -919,22 +919,22 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
919
919
  timeout: 12e4,
920
920
  stdio: ["pipe", "pipe", "pipe"]
921
921
  });
922
- if (tmpCopy && (0, import_node_fs24.existsSync)(tmpCopy)) {
922
+ if (tmpCopy && (0, import_node_fs25.existsSync)(tmpCopy)) {
923
923
  try {
924
- (0, import_node_fs24.unlinkSync)(tmpCopy);
924
+ (0, import_node_fs25.unlinkSync)(tmpCopy);
925
925
  } catch {
926
926
  }
927
927
  }
928
- if (afResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
928
+ if (afResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
929
929
  logger.info(`[whisper-local] afconvert \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
930
930
  return { ok: true };
931
931
  }
932
932
  const stderr = afResult.stderr?.slice(0, 200) ?? "";
933
933
  return { ok: false, error: `afconvert \u8F6C\u6362\u5931\u8D25 (exit ${afResult.status}): ${stderr}` };
934
934
  } catch (err) {
935
- if (tmpCopy && (0, import_node_fs24.existsSync)(tmpCopy)) {
935
+ if (tmpCopy && (0, import_node_fs25.existsSync)(tmpCopy)) {
936
936
  try {
937
- (0, import_node_fs24.unlinkSync)(tmpCopy);
937
+ (0, import_node_fs25.unlinkSync)(tmpCopy);
938
938
  } catch {
939
939
  }
940
940
  }
@@ -945,9 +945,9 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
945
945
  return { ok: false, error: `\u65E0\u6CD5\u5C06\u97F3\u9891\u8F6C\u6362\u4E3A WAV \u683C\u5F0F\u3002${fmtHint}` };
946
946
  }
947
947
  function cleanupTmpWav(path2) {
948
- if (path2 && (0, import_node_fs24.existsSync)(path2)) {
948
+ if (path2 && (0, import_node_fs25.existsSync)(path2)) {
949
949
  try {
950
- (0, import_node_fs24.unlinkSync)(path2);
950
+ (0, import_node_fs25.unlinkSync)(path2);
951
951
  } catch {
952
952
  }
953
953
  }
@@ -1033,16 +1033,16 @@ function formatBytes2(bytes) {
1033
1033
  if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
1034
1034
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;
1035
1035
  }
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;
1036
+ var import_node_child_process2, import_node_fs25, import_node_path21, 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
1037
  var init_whisper_local = __esm({
1038
1038
  "src/recording/whisper-local.ts"() {
1039
1039
  "use strict";
1040
1040
  import_node_child_process2 = require("child_process");
1041
- import_node_fs24 = require("fs");
1042
- import_node_path19 = require("path");
1041
+ import_node_fs25 = require("fs");
1042
+ import_node_path21 = require("path");
1043
1043
  import_promises3 = require("stream/promises");
1044
1044
  import_node_stream2 = require("stream");
1045
- import_node_os3 = require("os");
1045
+ import_node_os4 = require("os");
1046
1046
  WHISPER_MODELS_DIR = "whisper-models";
1047
1047
  WHISPER_BIN_DIR = "whisper-bin";
1048
1048
  HF_MODEL_URL_TEMPLATE = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-{model}.bin";
@@ -1194,7 +1194,7 @@ async function initializeAsr(config, dataDir, logger) {
1194
1194
  }
1195
1195
  }
1196
1196
  async function transcribeAudio(audioFilePath, config, logger, options = {}) {
1197
- if (!(0, import_node_fs25.existsSync)(audioFilePath)) {
1197
+ if (!(0, import_node_fs26.existsSync)(audioFilePath)) {
1198
1198
  return { ok: false, error: `\u97F3\u9891\u6587\u4EF6\u4E0D\u5B58\u5728: ${audioFilePath}` };
1199
1199
  }
1200
1200
  logger.info(
@@ -1310,7 +1310,7 @@ async function runTranscriptionWorkflow(params) {
1310
1310
  return { ok: false, error: result.error };
1311
1311
  }
1312
1312
  const title = normalizeOptionalText2(result.summary) ? normalizeOptionalText2(result.summary) : extractSummary(result.text ?? "");
1313
- const summary = normalizeOptionalText2(result.summaryText) ? normalizeOptionalText2(result.summaryText) : extractTranscriptSummary(result.text ?? "");
1313
+ const summary = normalizeOptionalText2(result.summaryText);
1314
1314
  result.summary = title;
1315
1315
  const transcriptData = buildTranscriptDocument({
1316
1316
  recordingId,
@@ -1338,8 +1338,8 @@ async function runTranscriptionWorkflow(params) {
1338
1338
  createdAt
1339
1339
  );
1340
1340
  const transcriptDataFilename = buildTranscriptDataFilename(recordingId);
1341
- const transcriptDataPath = (0, import_node_path20.join)(transcriptDataDir, transcriptDataFilename);
1342
- (0, import_node_fs25.writeFileSync)(
1341
+ const transcriptDataPath = (0, import_node_path22.join)(transcriptDataDir, transcriptDataFilename);
1342
+ (0, import_node_fs26.writeFileSync)(
1343
1343
  transcriptDataPath,
1344
1344
  JSON.stringify(transcriptData, null, 2),
1345
1345
  "utf-8"
@@ -1347,13 +1347,16 @@ async function runTranscriptionWorkflow(params) {
1347
1347
  logger.info(`[asr] \u8F6C\u5199 JSON \u5DF2\u5199\u5165: ${transcriptDataPath}`);
1348
1348
  const safeSummary = title.replace(/[/\\:*?"<>|]/g, "").trim().slice(0, 20);
1349
1349
  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");
1350
+ const filePath = (0, import_node_path22.join)(transcriptsDir, filename);
1351
+ (0, import_node_fs26.writeFileSync)(filePath, markdown, "utf-8");
1352
1352
  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}`);
1353
+ let summaryFilename;
1354
+ if (summary) {
1355
+ summaryFilename = `${recordingId}.md`;
1356
+ const summaryFilePath = (0, import_node_path22.join)(summariesDir, summaryFilename);
1357
+ (0, import_node_fs26.writeFileSync)(summaryFilePath, summary, "utf-8");
1358
+ logger.info(`[asr] \u6458\u8981\u6587\u672C\u5DF2\u5199\u5165: ${summaryFilePath}`);
1359
+ }
1357
1360
  return {
1358
1361
  ok: true,
1359
1362
  transcriptFilename: filename,
@@ -1436,7 +1439,7 @@ async function transcribeWithModelProxy(audioOssUrl, apiConfig, logger) {
1436
1439
  }
1437
1440
  async function transcribeWithWhisperLocal2(audioFilePath, config, logger) {
1438
1441
  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, "..", "..", "..");
1442
+ const dataDir = process.env.OPENCLAW_STATE_DIR ?? process.env.QCLAW_STATE_DIR ?? (0, import_node_path22.join)(audioFilePath, "..", "..", "..");
1440
1443
  const localConfig = config.local ?? {};
1441
1444
  const result = await runLocal(
1442
1445
  audioFilePath,
@@ -1590,8 +1593,8 @@ function buildLongRecordingSuccessResult(taskId, requestId, data, logger) {
1590
1593
  ok: true,
1591
1594
  text,
1592
1595
  segments: listResult.segments,
1593
- summary: title ?? extractSummary(text),
1594
- summaryText: summaryText ?? extractTranscriptSummary(text),
1596
+ summary: title,
1597
+ summaryText,
1595
1598
  category,
1596
1599
  sourceInfo: {
1597
1600
  provider: "model-proxy",
@@ -1711,15 +1714,6 @@ function stringifyForLog(value, maxLength = 500) {
1711
1714
  async function sleep2(ms) {
1712
1715
  await new Promise((resolve) => setTimeout(resolve, ms));
1713
1716
  }
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
1717
  function formatTimestamp(ms) {
1724
1718
  const totalSeconds = Math.floor(ms / 1e3);
1725
1719
  const minutes = Math.floor(totalSeconds / 60);
@@ -1748,12 +1742,12 @@ function formatTranscriptSegmentText(segment) {
1748
1742
  }
1749
1743
  return text;
1750
1744
  }
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;
1745
+ var import_node_fs26, import_node_path22, DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS, DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS, LONG_RECORDING_RUNNING_STATUSES, LONG_RECORDING_TERMINAL_FAILURE_STATUSES;
1752
1746
  var init_asr = __esm({
1753
1747
  "src/recording/asr.ts"() {
1754
1748
  "use strict";
1755
- import_node_fs25 = require("fs");
1756
- import_node_path20 = require("path");
1749
+ import_node_fs26 = require("fs");
1750
+ import_node_path22 = require("path");
1757
1751
  init_credentials();
1758
1752
  init_env();
1759
1753
  init_transcript_document();
@@ -5398,7 +5392,7 @@ function readBuildInjectedVersion() {
5398
5392
  if (false) {
5399
5393
  return void 0;
5400
5394
  }
5401
- const version = "1.10.2".trim();
5395
+ const version = "1.10.3".trim();
5402
5396
  return version || void 0;
5403
5397
  }
5404
5398
  function readPluginVersionFromPackageJson() {
@@ -7201,8 +7195,48 @@ function resolveUpdateChannel(params) {
7201
7195
  return params.envName === "development" ? "beta" : "latest";
7202
7196
  }
7203
7197
 
7198
+ // src/update/index.ts
7199
+ var import_node_path9 = require("path");
7200
+
7204
7201
  // src/update/checker.ts
7205
- var CDN_BASE_URL = "https://cdn.yoootek.com/openclaw-plugin";
7202
+ function parseSemver(v) {
7203
+ const [main, pre = null] = v.split("-", 2);
7204
+ const [major = 0, minor = 0, patch = 0] = main.split(".").map(Number);
7205
+ return { major, minor, patch, pre: pre ?? null };
7206
+ }
7207
+ function comparePreRelease(a, b) {
7208
+ const aParts = a.split(".");
7209
+ const bParts = b.split(".");
7210
+ for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
7211
+ const ap = aParts[i] ?? "";
7212
+ const bp = bParts[i] ?? "";
7213
+ const an = Number(ap);
7214
+ const bn = Number(bp);
7215
+ let diff;
7216
+ if (!Number.isNaN(an) && !Number.isNaN(bn)) {
7217
+ diff = an - bn;
7218
+ } else if (ap < bp) {
7219
+ diff = -1;
7220
+ } else if (ap > bp) {
7221
+ diff = 1;
7222
+ } else {
7223
+ diff = 0;
7224
+ }
7225
+ if (diff !== 0) return diff;
7226
+ }
7227
+ return 0;
7228
+ }
7229
+ function isNewerVersion(candidate, current) {
7230
+ const a = parseSemver(candidate);
7231
+ const b = parseSemver(current);
7232
+ if (a.major !== b.major) return a.major > b.major;
7233
+ if (a.minor !== b.minor) return a.minor > b.minor;
7234
+ if (a.patch !== b.patch) return a.patch > b.patch;
7235
+ if (a.pre === null) return b.pre !== null;
7236
+ if (b.pre === null) return false;
7237
+ return comparePreRelease(a.pre, b.pre) > 0;
7238
+ }
7239
+ var CDN_BASE_URL = "https://artifact.yoooclaw.com/plugin";
7206
7240
  var NPM_BASE_URL = "https://registry.npmjs.org/@yoooclaw/phone-notifications";
7207
7241
  var FETCH_TIMEOUT_MS = 5e3;
7208
7242
  var UpdateChecker = class {
@@ -7231,6 +7265,7 @@ var UpdateChecker = class {
7231
7265
  if (!latest || latest === PLUGIN_VERSION) return;
7232
7266
  if (latest === this.notifiedVersion) return;
7233
7267
  if (PLUGIN_VERSION.includes("-") && this.channel !== "beta") return;
7268
+ if (!isNewerVersion(latest, PLUGIN_VERSION)) return;
7234
7269
  this.notifiedVersion = latest;
7235
7270
  this.logger.info(`\u53D1\u73B0\u65B0\u7248\u672C: ${PLUGIN_VERSION} \u2192 ${latest}`);
7236
7271
  this.onUpdateFound({ current: PLUGIN_VERSION, latest });
@@ -7263,36 +7298,109 @@ var UpdateChecker = class {
7263
7298
  };
7264
7299
 
7265
7300
  // src/update/executor.ts
7301
+ var import_node_fs9 = require("fs");
7302
+ var import_node_path8 = require("path");
7303
+ var import_node_os = require("os");
7266
7304
  var VERSION_PATTERN = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
7267
- async function executeUpdate(version, runCommand, logger) {
7305
+ var BASE_URL = "https://artifact.yoooclaw.com/plugin";
7306
+ async function executeUpdate(version, runCommand, logger, targetDir, updateConfigRecord2) {
7268
7307
  if (!VERSION_PATTERN.test(version)) {
7269
7308
  return { success: false, message: `\u975E\u6CD5\u7248\u672C\u53F7: ${version}` };
7270
7309
  }
7271
- const argv = [
7272
- "openclaw",
7273
- "extension",
7274
- "install",
7275
- `@yoooclaw/phone-notifications@${version}`
7276
- ];
7277
- logger.info(`\u6267\u884C\u66F4\u65B0: ${argv.join(" ")}`);
7310
+ const tgzUrl = `${BASE_URL}/v${version}/yoooclaw-phone-notifications-${version}.tgz`;
7311
+ logger.info(`\u6267\u884C\u66F4\u65B0: ${tgzUrl} \u2192 ${targetDir}`);
7312
+ const workDir = (0, import_node_fs9.mkdtempSync)((0, import_node_path8.join)((0, import_node_os.tmpdir)(), ".openclaw-plugin-update-"));
7313
+ const tgzPath = (0, import_node_path8.join)(workDir, "plugin.tgz");
7314
+ const stagingDir = (0, import_node_path8.join)(workDir, "staged");
7315
+ let backupDir = null;
7278
7316
  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 };
7317
+ logger.info("\u4E0B\u8F7D\u63D2\u4EF6\u5305...");
7318
+ const response = await fetch(tgzUrl, { signal: AbortSignal.timeout(6e4) });
7319
+ if (!response.ok) {
7320
+ return { success: false, message: `\u4E0B\u8F7D\u5931\u8D25 (HTTP ${response.status}): ${tgzUrl}` };
7321
+ }
7322
+ const buffer = Buffer.from(await response.arrayBuffer());
7323
+ (0, import_node_fs9.writeFileSync)(tgzPath, buffer);
7324
+ logger.info(`\u4E0B\u8F7D\u5B8C\u6210 (${buffer.length} bytes)`);
7325
+ (0, import_node_fs9.mkdirSync)(stagingDir, { recursive: true });
7326
+ const tarResult = await runCommand(
7327
+ ["tar", "-xzf", tgzPath, "-C", stagingDir, "--strip-components=1"],
7328
+ { timeoutMs: 3e4 }
7329
+ );
7330
+ if (tarResult.code !== 0) {
7331
+ const err = tarResult.stderr || tarResult.stdout || "unknown error";
7332
+ return { success: false, message: `\u89E3\u538B\u5931\u8D25: ${err}` };
7284
7333
  }
7285
- const errMsg = `\u66F4\u65B0\u5931\u8D25 (exit ${result.code}): ${result.stderr || result.stdout}`;
7286
- logger.error(errMsg);
7287
- return { success: false, message: errMsg };
7334
+ (0, import_node_fs9.mkdirSync)((0, import_node_path8.dirname)(targetDir), { recursive: true });
7335
+ try {
7336
+ backupDir = `${targetDir}.bak.${Date.now()}`;
7337
+ (0, import_node_fs9.renameSync)(targetDir, backupDir);
7338
+ } catch {
7339
+ backupDir = null;
7340
+ }
7341
+ (0, import_node_fs9.renameSync)(stagingDir, targetDir);
7342
+ try {
7343
+ await updateConfigRecord2(version, tgzUrl);
7344
+ } catch (err) {
7345
+ logger.warn(`\u914D\u7F6E\u8BB0\u5F55\u66F4\u65B0\u5931\u8D25\uFF08\u63D2\u4EF6\u6587\u4EF6\u5DF2\u5C31\u4F4D\uFF09: ${String(err)}`);
7346
+ }
7347
+ if (backupDir) {
7348
+ try {
7349
+ (0, import_node_fs9.rmSync)(backupDir, { force: true, recursive: true });
7350
+ } catch {
7351
+ }
7352
+ }
7353
+ const msg = `\u5DF2\u66F4\u65B0\u5230 ${version}\uFF0C\u8BF7\u91CD\u542F gateway \u751F\u6548`;
7354
+ logger.info(msg);
7355
+ return { success: true, message: msg };
7288
7356
  } catch (err) {
7289
- const errMsg = `\u66F4\u65B0\u547D\u4EE4\u6267\u884C\u5F02\u5E38: ${String(err)}`;
7357
+ if (backupDir) {
7358
+ try {
7359
+ (0, import_node_fs9.rmSync)(targetDir, { force: true, recursive: true });
7360
+ (0, import_node_fs9.renameSync)(backupDir, targetDir);
7361
+ logger.info("\u5DF2\u56DE\u6EDA\u5230\u4E4B\u524D\u7248\u672C");
7362
+ } catch (rollbackErr) {
7363
+ logger.error(`\u56DE\u6EDA\u5931\u8D25: ${String(rollbackErr)}`);
7364
+ }
7365
+ }
7366
+ const errMsg = `\u66F4\u65B0\u6267\u884C\u5F02\u5E38: ${String(err)}`;
7290
7367
  logger.error(errMsg);
7291
7368
  return { success: false, message: errMsg };
7369
+ } finally {
7370
+ try {
7371
+ (0, import_node_fs9.rmSync)(workDir, { force: true, recursive: true });
7372
+ } catch {
7373
+ }
7292
7374
  }
7293
7375
  }
7294
7376
 
7295
7377
  // src/update/index.ts
7378
+ var PLUGIN_ID = "phone-notifications";
7379
+ function resolveTargetDir(api) {
7380
+ try {
7381
+ const cfg = api.runtime.config?.loadConfig?.();
7382
+ const installPath = cfg?.plugins?.installs?.[PLUGIN_ID]?.installPath;
7383
+ if (installPath) return installPath;
7384
+ } catch {
7385
+ }
7386
+ return (0, import_node_path9.join)(api.runtime.state.resolveStateDir(), "extensions", PLUGIN_ID);
7387
+ }
7388
+ async function updateConfigRecord(api, version, targetDir, tgzUrl) {
7389
+ const configApi = api.runtime.config;
7390
+ if (!configApi) return;
7391
+ const cfg = configApi.loadConfig();
7392
+ if (!cfg.plugins) cfg.plugins = {};
7393
+ if (!cfg.plugins.installs) cfg.plugins.installs = {};
7394
+ cfg.plugins.installs[PLUGIN_ID] = {
7395
+ ...cfg.plugins.installs[PLUGIN_ID],
7396
+ source: "archive",
7397
+ sourcePath: tgzUrl,
7398
+ installPath: targetDir,
7399
+ version,
7400
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
7401
+ };
7402
+ await configApi.writeConfigFile(cfg);
7403
+ }
7296
7404
  function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast, externalUpdateNotifier) {
7297
7405
  if (config.enabled === false) {
7298
7406
  logger.info("\u81EA\u52A8\u66F4\u65B0\u5DF2\u7981\u7528 (autoUpdate.enabled = false)");
@@ -7338,10 +7446,13 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
7338
7446
  },
7339
7447
  async execute(_toolCallId, params) {
7340
7448
  const { version } = params;
7449
+ const targetDir = resolveTargetDir(api);
7341
7450
  const result = await executeUpdate(
7342
7451
  version,
7343
7452
  api.runtime.system.runCommandWithTimeout,
7344
- logger
7453
+ logger,
7454
+ targetDir,
7455
+ (v, url) => updateConfigRecord(api, v, targetDir, url)
7345
7456
  );
7346
7457
  if (result.success) {
7347
7458
  pendingUpdate = null;
@@ -7363,10 +7474,13 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
7363
7474
  });
7364
7475
  return;
7365
7476
  }
7477
+ const targetDir = resolveTargetDir(api);
7366
7478
  const result = await executeUpdate(
7367
7479
  version,
7368
7480
  api.runtime.system.runCommandWithTimeout,
7369
- logger
7481
+ logger,
7482
+ targetDir,
7483
+ (v, url) => updateConfigRecord(api, v, targetDir, url)
7370
7484
  );
7371
7485
  if (result.success) {
7372
7486
  pendingUpdate = null;
@@ -7457,10 +7571,10 @@ function registerAutoUpdateLifecycle(deps) {
7457
7571
  }
7458
7572
 
7459
7573
  // src/plugin/cli.ts
7460
- var import_node_path15 = require("path");
7574
+ var import_node_path17 = require("path");
7461
7575
 
7462
7576
  // src/cli/auth.ts
7463
- var import_node_fs9 = require("fs");
7577
+ var import_node_fs10 = require("fs");
7464
7578
  init_credentials();
7465
7579
  function registerAuthCli(program) {
7466
7580
  const auth = program.command("auth").description("\u7528\u6237\u8BA4\u8BC1\u7BA1\u7406");
@@ -7496,12 +7610,12 @@ function registerAuthCli(program) {
7496
7610
  });
7497
7611
  auth.command("clear").description("\u6E05\u9664\u5DF2\u4FDD\u5B58\u7684\u8BA4\u8BC1\u4FE1\u606F").action(() => {
7498
7612
  const path2 = credentialsPath();
7499
- if ((0, import_node_fs9.existsSync)(path2)) {
7613
+ if ((0, import_node_fs10.existsSync)(path2)) {
7500
7614
  const creds = readCredentials();
7501
7615
  delete creds.apiKey;
7502
7616
  delete creds.token;
7503
7617
  if (Object.keys(creds).length === 0) {
7504
- (0, import_node_fs9.rmSync)(path2, { force: true });
7618
+ (0, import_node_fs10.rmSync)(path2, { force: true });
7505
7619
  } else {
7506
7620
  writeCredentials(creds);
7507
7621
  }
@@ -7633,23 +7747,23 @@ function registerNtfStats(ntf, ctx) {
7633
7747
  }
7634
7748
 
7635
7749
  // src/cli/ntf-sync.ts
7636
- var import_node_fs10 = require("fs");
7637
- var import_node_path8 = require("path");
7750
+ var import_node_fs11 = require("fs");
7751
+ var import_node_path10 = require("path");
7638
7752
  var SYNC_FETCH_LIMIT = 300;
7639
7753
  function checkpointPath(dir) {
7640
- return (0, import_node_path8.join)(dir, ".checkpoint.json");
7754
+ return (0, import_node_path10.join)(dir, ".checkpoint.json");
7641
7755
  }
7642
7756
  function readCheckpoint(dir) {
7643
7757
  const p = checkpointPath(dir);
7644
- if (!(0, import_node_fs10.existsSync)(p)) return {};
7758
+ if (!(0, import_node_fs11.existsSync)(p)) return {};
7645
7759
  try {
7646
- return JSON.parse((0, import_node_fs10.readFileSync)(p, "utf-8"));
7760
+ return JSON.parse((0, import_node_fs11.readFileSync)(p, "utf-8"));
7647
7761
  } catch {
7648
7762
  return {};
7649
7763
  }
7650
7764
  }
7651
7765
  function writeCheckpoint(dir, data) {
7652
- (0, import_node_fs10.writeFileSync)(checkpointPath(dir), JSON.stringify(data, null, 2), "utf-8");
7766
+ (0, import_node_fs11.writeFileSync)(checkpointPath(dir), JSON.stringify(data, null, 2), "utf-8");
7653
7767
  }
7654
7768
  function registerNtfSync(ntf, ctx) {
7655
7769
  const sync = ntf.command("sync").description("\u540C\u6B65\u901A\u77E5\u5230\u8BB0\u5FC6\u7CFB\u7EDF");
@@ -7742,24 +7856,24 @@ function registerNtfSync(ntf, ctx) {
7742
7856
  }
7743
7857
 
7744
7858
  // src/cli/ntf-monitor.ts
7745
- var import_node_fs11 = require("fs");
7746
- var import_node_path9 = require("path");
7859
+ var import_node_fs12 = require("fs");
7860
+ var import_node_path11 = require("path");
7747
7861
  function tasksDir2(ctx) {
7748
7862
  const base = ctx.workspaceDir || ctx.stateDir;
7749
7863
  if (!base) throw new Error("workspaceDir and stateDir both unavailable");
7750
- return (0, import_node_path9.join)(base, "tasks");
7864
+ return (0, import_node_path11.join)(base, "tasks");
7751
7865
  }
7752
7866
  function readMeta2(taskDir) {
7753
- const metaPath = (0, import_node_path9.join)(taskDir, "meta.json");
7754
- if (!(0, import_node_fs11.existsSync)(metaPath)) return null;
7867
+ const metaPath = (0, import_node_path11.join)(taskDir, "meta.json");
7868
+ if (!(0, import_node_fs12.existsSync)(metaPath)) return null;
7755
7869
  try {
7756
- return JSON.parse((0, import_node_fs11.readFileSync)(metaPath, "utf-8"));
7870
+ return JSON.parse((0, import_node_fs12.readFileSync)(metaPath, "utf-8"));
7757
7871
  } catch {
7758
7872
  return null;
7759
7873
  }
7760
7874
  }
7761
7875
  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");
7876
+ (0, import_node_fs12.writeFileSync)((0, import_node_path11.join)(taskDir, "meta.json"), JSON.stringify(meta, null, 2), "utf-8");
7763
7877
  }
7764
7878
  function generateReadme(name, description) {
7765
7879
  return `# Monitor Task: ${name}
@@ -7778,27 +7892,27 @@ function registerNtfMonitor(ntf, ctx) {
7778
7892
  const monitor = ntf.command("monitor").description("\u901A\u77E5\u76D1\u63A7\u4EFB\u52A1\u7BA1\u7406");
7779
7893
  monitor.command("list").description("\u5217\u51FA\u6240\u6709\u76D1\u63A7\u4EFB\u52A1").action(() => {
7780
7894
  const dir = tasksDir2(ctx);
7781
- if (!(0, import_node_fs11.existsSync)(dir)) {
7895
+ if (!(0, import_node_fs12.existsSync)(dir)) {
7782
7896
  output({ ok: true, tasks: [] });
7783
7897
  return;
7784
7898
  }
7785
7899
  const tasks = [];
7786
- for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
7900
+ for (const entry of (0, import_node_fs12.readdirSync)(dir, { withFileTypes: true })) {
7787
7901
  if (!entry.isDirectory()) continue;
7788
- const meta = readMeta2((0, import_node_path9.join)(dir, entry.name));
7902
+ const meta = readMeta2((0, import_node_path11.join)(dir, entry.name));
7789
7903
  if (meta) tasks.push(meta);
7790
7904
  }
7791
7905
  output({ ok: true, tasks });
7792
7906
  });
7793
7907
  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);
7908
+ const taskDir = (0, import_node_path11.join)(tasksDir2(ctx), name);
7795
7909
  const meta = readMeta2(taskDir);
7796
7910
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
7797
- const checkpointPath2 = (0, import_node_path9.join)(taskDir, "checkpoint.json");
7911
+ const checkpointPath2 = (0, import_node_path11.join)(taskDir, "checkpoint.json");
7798
7912
  let checkpoint = {};
7799
- if ((0, import_node_fs11.existsSync)(checkpointPath2)) {
7913
+ if ((0, import_node_fs12.existsSync)(checkpointPath2)) {
7800
7914
  try {
7801
- checkpoint = JSON.parse((0, import_node_fs11.readFileSync)(checkpointPath2, "utf-8"));
7915
+ checkpoint = JSON.parse((0, import_node_fs12.readFileSync)(checkpointPath2, "utf-8"));
7802
7916
  } catch {
7803
7917
  }
7804
7918
  }
@@ -7813,8 +7927,8 @@ function registerNtfMonitor(ntf, ctx) {
7813
7927
  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
7928
  (name, opts) => {
7815
7929
  const dir = tasksDir2(ctx);
7816
- const taskDir = (0, import_node_path9.join)(dir, name);
7817
- if ((0, import_node_fs11.existsSync)(taskDir)) {
7930
+ const taskDir = (0, import_node_path11.join)(dir, name);
7931
+ if ((0, import_node_fs12.existsSync)(taskDir)) {
7818
7932
  exitError("ALREADY_EXISTS", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u5DF2\u5B58\u5728`);
7819
7933
  }
7820
7934
  let matchRules;
@@ -7826,7 +7940,7 @@ function registerNtfMonitor(ntf, ctx) {
7826
7940
  "match-rules \u5FC5\u987B\u662F\u5408\u6CD5\u7684 JSON"
7827
7941
  );
7828
7942
  }
7829
- (0, import_node_fs11.mkdirSync)(taskDir, { recursive: true });
7943
+ (0, import_node_fs12.mkdirSync)(taskDir, { recursive: true });
7830
7944
  const meta = {
7831
7945
  name,
7832
7946
  description: opts.description,
@@ -7836,13 +7950,13 @@ function registerNtfMonitor(ntf, ctx) {
7836
7950
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
7837
7951
  };
7838
7952
  writeMeta2(taskDir, meta);
7839
- (0, import_node_fs11.writeFileSync)(
7840
- (0, import_node_path9.join)(taskDir, "fetch.py"),
7953
+ (0, import_node_fs12.writeFileSync)(
7954
+ (0, import_node_path11.join)(taskDir, "fetch.py"),
7841
7955
  generateFetchPy(name, matchRules),
7842
7956
  "utf-8"
7843
7957
  );
7844
- (0, import_node_fs11.writeFileSync)(
7845
- (0, import_node_path9.join)(taskDir, "README.md"),
7958
+ (0, import_node_fs12.writeFileSync)(
7959
+ (0, import_node_path11.join)(taskDir, "README.md"),
7846
7960
  generateReadme(name, opts.description),
7847
7961
  "utf-8"
7848
7962
  );
@@ -7870,8 +7984,8 @@ function registerNtfMonitor(ntf, ctx) {
7870
7984
  }
7871
7985
  );
7872
7986
  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)) {
7987
+ const taskDir = (0, import_node_path11.join)(tasksDir2(ctx), name);
7988
+ if (!(0, import_node_fs12.existsSync)(taskDir)) {
7875
7989
  exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
7876
7990
  }
7877
7991
  if (!opts.yes) {
@@ -7884,7 +7998,7 @@ function registerNtfMonitor(ntf, ctx) {
7884
7998
  });
7885
7999
  process.exit(1);
7886
8000
  }
7887
- (0, import_node_fs11.rmSync)(taskDir, { recursive: true, force: true });
8001
+ (0, import_node_fs12.rmSync)(taskDir, { recursive: true, force: true });
7888
8002
  output({
7889
8003
  ok: true,
7890
8004
  name,
@@ -7896,7 +8010,7 @@ function registerNtfMonitor(ntf, ctx) {
7896
8010
  });
7897
8011
  });
7898
8012
  monitor.command("enable <name>").description("\u542F\u7528\u76D1\u63A7\u4EFB\u52A1").action((name) => {
7899
- const taskDir = (0, import_node_path9.join)(tasksDir2(ctx), name);
8013
+ const taskDir = (0, import_node_path11.join)(tasksDir2(ctx), name);
7900
8014
  const meta = readMeta2(taskDir);
7901
8015
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
7902
8016
  meta.enabled = true;
@@ -7904,7 +8018,7 @@ function registerNtfMonitor(ntf, ctx) {
7904
8018
  output({ ok: true, name, enabled: true });
7905
8019
  });
7906
8020
  monitor.command("disable <name>").description("\u6682\u505C\u76D1\u63A7\u4EFB\u52A1").action((name) => {
7907
- const taskDir = (0, import_node_path9.join)(tasksDir2(ctx), name);
8021
+ const taskDir = (0, import_node_path11.join)(tasksDir2(ctx), name);
7908
8022
  const meta = readMeta2(taskDir);
7909
8023
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
7910
8024
  meta.enabled = false;
@@ -8213,9 +8327,9 @@ function registerLightSend(light) {
8213
8327
  }
8214
8328
 
8215
8329
  // 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");
8330
+ var import_node_fs13 = require("fs");
8331
+ var import_node_os2 = require("os");
8332
+ var import_node_path12 = require("path");
8219
8333
  function isObject(value) {
8220
8334
  return !!value && typeof value === "object" && !Array.isArray(value);
8221
8335
  }
@@ -8229,7 +8343,7 @@ function ensureArray(obj, key) {
8229
8343
  function resolveConfigPath2() {
8230
8344
  const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();
8231
8345
  if (fromEnv) return fromEnv;
8232
- return (0, import_node_path10.join)((0, import_node_os.homedir)(), ".openclaw", "openclaw.json");
8346
+ return (0, import_node_path12.join)((0, import_node_os2.homedir)(), ".openclaw", "openclaw.json");
8233
8347
  }
8234
8348
  function upsertLightControlAlsoAllow(cfg) {
8235
8349
  if (!isObject(cfg.tools)) cfg.tools = {};
@@ -8258,12 +8372,12 @@ function upsertLightControlAlsoAllow(cfg) {
8258
8372
  function registerLightSetupTools(light) {
8259
8373
  light.command("setup").description("\u81EA\u52A8\u653E\u884C light_control\uFF08\u5199\u5165 tools.alsoAllow \u4E0E agents.main.tools.alsoAllow\uFF09").action(() => {
8260
8374
  const configPath = resolveConfigPath2();
8261
- if (!(0, import_node_fs12.existsSync)(configPath)) {
8375
+ if (!(0, import_node_fs13.existsSync)(configPath)) {
8262
8376
  exitError("CONFIG_NOT_FOUND", `\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6: ${configPath}`);
8263
8377
  }
8264
8378
  let cfg = {};
8265
8379
  try {
8266
- const raw = (0, import_node_fs12.readFileSync)(configPath, "utf-8");
8380
+ const raw = (0, import_node_fs13.readFileSync)(configPath, "utf-8");
8267
8381
  const parsed = JSON.parse(raw);
8268
8382
  if (isObject(parsed)) cfg = parsed;
8269
8383
  } catch (err) {
@@ -8271,8 +8385,8 @@ function registerLightSetupTools(light) {
8271
8385
  }
8272
8386
  const result = upsertLightControlAlsoAllow(cfg);
8273
8387
  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");
8388
+ (0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(configPath), { recursive: true });
8389
+ (0, import_node_fs13.writeFileSync)(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
8276
8390
  } catch (err) {
8277
8391
  exitError("WRITE_FAILED", `\u5199\u5165\u914D\u7F6E\u5931\u8D25: ${err?.message ?? String(err)}`);
8278
8392
  }
@@ -8290,17 +8404,17 @@ function registerLightSetupTools(light) {
8290
8404
  }
8291
8405
 
8292
8406
  // src/cli/tunnel-status.ts
8293
- var import_node_fs13 = require("fs");
8294
- var import_node_path11 = require("path");
8407
+ var import_node_fs14 = require("fs");
8408
+ var import_node_path13 = require("path");
8295
8409
  init_credentials();
8296
8410
  init_env();
8297
- var STATUS_REL_PATH = (0, import_node_path11.join)("plugins", "phone-notifications", "tunnel-status.json");
8411
+ var STATUS_REL_PATH = (0, import_node_path13.join)("plugins", "phone-notifications", "tunnel-status.json");
8298
8412
  function readTunnelStatus(ctx) {
8299
8413
  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;
8414
+ const filePath = (0, import_node_path13.join)(ctx.stateDir, STATUS_REL_PATH);
8415
+ if (!(0, import_node_fs14.existsSync)(filePath)) return null;
8302
8416
  try {
8303
- return JSON.parse((0, import_node_fs13.readFileSync)(filePath, "utf-8"));
8417
+ return JSON.parse((0, import_node_fs14.readFileSync)(filePath, "utf-8"));
8304
8418
  } catch {
8305
8419
  return null;
8306
8420
  }
@@ -8368,24 +8482,24 @@ function registerNtfStoragePath(ntf, ctx) {
8368
8482
  }
8369
8483
 
8370
8484
  // src/cli/log-search.ts
8371
- var import_node_fs14 = require("fs");
8372
- var import_node_path12 = require("path");
8485
+ var import_node_fs15 = require("fs");
8486
+ var import_node_path14 = require("path");
8373
8487
  function resolveLogsDir(ctx) {
8374
8488
  if (ctx.stateDir) {
8375
- const dir = (0, import_node_path12.join)(
8489
+ const dir = (0, import_node_path14.join)(
8376
8490
  ctx.stateDir,
8377
8491
  "plugins",
8378
8492
  "phone-notifications",
8379
8493
  "logs"
8380
8494
  );
8381
- if ((0, import_node_fs14.existsSync)(dir)) return dir;
8495
+ if ((0, import_node_fs15.existsSync)(dir)) return dir;
8382
8496
  }
8383
8497
  return null;
8384
8498
  }
8385
8499
  function listLogDateKeys(dir) {
8386
8500
  const pattern = /^(\d{4}-\d{2}-\d{2})\.log$/;
8387
8501
  const keys = [];
8388
- for (const entry of (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true })) {
8502
+ for (const entry of (0, import_node_fs15.readdirSync)(dir, { withFileTypes: true })) {
8389
8503
  if (!entry.isFile()) continue;
8390
8504
  const m = pattern.exec(entry.name);
8391
8505
  if (m) keys.push(m[1]);
@@ -8393,9 +8507,9 @@ function listLogDateKeys(dir) {
8393
8507
  return keys.sort().reverse();
8394
8508
  }
8395
8509
  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");
8510
+ const filePath = (0, import_node_path14.join)(dir, `${dateKey}.log`);
8511
+ if (!(0, import_node_fs15.existsSync)(filePath)) return;
8512
+ const content = (0, import_node_fs15.readFileSync)(filePath, "utf-8");
8399
8513
  const lowerKeyword = keyword?.toLowerCase();
8400
8514
  for (const line of content.split("\n")) {
8401
8515
  if (collected.length >= limit) return;
@@ -8462,12 +8576,12 @@ function registerEnvCli(ntf) {
8462
8576
  }
8463
8577
 
8464
8578
  // src/cli/doctor.ts
8465
- var import_node_fs18 = require("fs");
8579
+ var import_node_fs19 = require("fs");
8466
8580
  var import_node_readline = require("readline");
8467
8581
  init_host();
8468
8582
 
8469
8583
  // src/cli/doctor/check-dangerous-flags.ts
8470
- var import_node_fs15 = require("fs");
8584
+ var import_node_fs16 = require("fs");
8471
8585
  function isObject2(v) {
8472
8586
  return !!v && typeof v === "object" && !Array.isArray(v);
8473
8587
  }
@@ -8484,13 +8598,13 @@ var checkDangerousFlags = ({ cfg, configPath }) => {
8484
8598
  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
8599
  fixDescription: "\u8BBE\u4E3A false",
8486
8600
  fix: () => {
8487
- const raw = (0, import_node_fs15.readFileSync)(configPath, "utf-8");
8601
+ const raw = (0, import_node_fs16.readFileSync)(configPath, "utf-8");
8488
8602
  const config = JSON.parse(raw);
8489
8603
  const gw = config.gateway;
8490
8604
  const cui = gw.controlUi;
8491
8605
  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");
8606
+ (0, import_node_fs16.copyFileSync)(configPath, configPath + ".bak");
8607
+ (0, import_node_fs16.writeFileSync)(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
8494
8608
  }
8495
8609
  };
8496
8610
  };
@@ -8538,11 +8652,11 @@ function warnEmpty() {
8538
8652
  }
8539
8653
 
8540
8654
  // src/cli/doctor/check-state-dir-perms.ts
8541
- var import_node_fs16 = require("fs");
8655
+ var import_node_fs17 = require("fs");
8542
8656
  var checkStateDirPerms = ({ stateDir }) => {
8543
8657
  let mode;
8544
8658
  try {
8545
- mode = (0, import_node_fs16.statSync)(stateDir).mode;
8659
+ mode = (0, import_node_fs17.statSync)(stateDir).mode;
8546
8660
  } catch {
8547
8661
  return null;
8548
8662
  }
@@ -8556,7 +8670,7 @@ var checkStateDirPerms = ({ stateDir }) => {
8556
8670
  detail: "\u5176\u4ED6\u7528\u6237\u53EF\u4EE5\u8BFB\u53D6\u8BE5\u76EE\u5F55\u4E0B\u7684\u51ED\u8BC1\u548C\u914D\u7F6E\u6587\u4EF6\u3002",
8557
8671
  fixDescription: "chmod 700 " + stateDir,
8558
8672
  fix: () => {
8559
- (0, import_node_fs16.chmodSync)(stateDir, 448);
8673
+ (0, import_node_fs17.chmodSync)(stateDir, 448);
8560
8674
  }
8561
8675
  };
8562
8676
  };
@@ -8611,16 +8725,16 @@ var checkCredentials = () => {
8611
8725
  };
8612
8726
 
8613
8727
  // 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)(
8728
+ var import_node_fs18 = require("fs");
8729
+ var import_node_path15 = require("path");
8730
+ var STATUS_REL_PATH2 = (0, import_node_path15.join)(
8617
8731
  "plugins",
8618
8732
  "phone-notifications",
8619
8733
  "tunnel-status.json"
8620
8734
  );
8621
8735
  var checkTunnel = ({ stateDir }) => {
8622
- const filePath = (0, import_node_path13.join)(stateDir, STATUS_REL_PATH2);
8623
- if (!(0, import_node_fs17.existsSync)(filePath)) {
8736
+ const filePath = (0, import_node_path15.join)(stateDir, STATUS_REL_PATH2);
8737
+ if (!(0, import_node_fs18.existsSync)(filePath)) {
8624
8738
  return {
8625
8739
  id: "tunnel",
8626
8740
  severity: "warn",
@@ -8632,7 +8746,7 @@ var checkTunnel = ({ stateDir }) => {
8632
8746
  }
8633
8747
  let status;
8634
8748
  try {
8635
- status = JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
8749
+ status = JSON.parse((0, import_node_fs18.readFileSync)(filePath, "utf-8"));
8636
8750
  } catch {
8637
8751
  return {
8638
8752
  id: "tunnel",
@@ -8725,9 +8839,9 @@ function isObject5(v) {
8725
8839
  return !!v && typeof v === "object" && !Array.isArray(v);
8726
8840
  }
8727
8841
  function readConfig(configPath) {
8728
- if (!(0, import_node_fs18.existsSync)(configPath)) return {};
8842
+ if (!(0, import_node_fs19.existsSync)(configPath)) return {};
8729
8843
  try {
8730
- const parsed = JSON.parse((0, import_node_fs18.readFileSync)(configPath, "utf-8"));
8844
+ const parsed = JSON.parse((0, import_node_fs19.readFileSync)(configPath, "utf-8"));
8731
8845
  return isObject5(parsed) ? parsed : {};
8732
8846
  } catch {
8733
8847
  return {};
@@ -8928,7 +9042,7 @@ function registerRecStoragePath(rec, ctx) {
8928
9042
 
8929
9043
  // src/cli/rec-setup.ts
8930
9044
  var import_node_readline2 = require("readline");
8931
- var import_node_fs19 = require("fs");
9045
+ var import_node_fs20 = require("fs");
8932
9046
  function ask(rl, question) {
8933
9047
  return new Promise((resolve) => rl.question(question, resolve));
8934
9048
  }
@@ -9014,9 +9128,9 @@ async function setupLocal(rl) {
9014
9128
  function registerRecSetup(rec, ctx) {
9015
9129
  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
9130
  const configPath = resolveAsrConfigPath(ctx);
9017
- if ((0, import_node_fs19.existsSync)(configPath)) {
9131
+ if ((0, import_node_fs20.existsSync)(configPath)) {
9018
9132
  try {
9019
- const existing = JSON.parse((0, import_node_fs19.readFileSync)(configPath, "utf-8"));
9133
+ const existing = JSON.parse((0, import_node_fs20.readFileSync)(configPath, "utf-8"));
9020
9134
  process.stderr.write(`\u5F53\u524D\u5DF2\u6709\u914D\u7F6E\uFF1Amode = ${existing.mode}`);
9021
9135
  if (existing.updatedAt) process.stderr.write(`\uFF0C\u66F4\u65B0\u4E8E ${existing.updatedAt}`);
9022
9136
  process.stderr.write("\n");
@@ -9029,7 +9143,7 @@ function registerRecSetup(rec, ctx) {
9029
9143
  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
9144
  const config = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);
9031
9145
  const stored = { ...config, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9032
- (0, import_node_fs19.writeFileSync)(configPath, JSON.stringify(stored, null, 2), "utf-8");
9146
+ (0, import_node_fs20.writeFileSync)(configPath, JSON.stringify(stored, null, 2), "utf-8");
9033
9147
  process.stderr.write(`
9034
9148
  \u2713 \u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230 ${configPath}
9035
9149
 
@@ -9043,11 +9157,11 @@ function registerRecSetup(rec, ctx) {
9043
9157
 
9044
9158
  // src/cli/update.ts
9045
9159
  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);
9160
+ var import_node_fs21 = require("fs");
9161
+ var import_node_path16 = require("path");
9162
+ var import_node_os3 = __toESM(require("os"), 1);
9049
9163
  init_host();
9050
- var BASE_URL = "https://cdn.yoootek.com/openclaw-plugin";
9164
+ var BASE_URL2 = "https://artifact.yoooclaw.com/plugin";
9051
9165
  async function fetchText(url) {
9052
9166
  const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
9053
9167
  if (!res.ok) {
@@ -9067,7 +9181,7 @@ async function runUpdate(ctx, opts) {
9067
9181
  log(`\u68C0\u67E5${beta ? " beta" : ""}\u6700\u65B0\u7248\u672C ...`);
9068
9182
  let latest;
9069
9183
  try {
9070
- latest = (await fetchText(`${BASE_URL}/${channel}`)).trim();
9184
+ latest = (await fetchText(`${BASE_URL2}/${channel}`)).trim();
9071
9185
  } catch (err) {
9072
9186
  const msg = `\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C: ${err?.message ?? String(err)}`;
9073
9187
  if (json) {
@@ -9092,7 +9206,7 @@ async function runUpdate(ctx, opts) {
9092
9206
  log("\u4E0B\u8F7D\u5B89\u88C5\u811A\u672C ...");
9093
9207
  let installScript;
9094
9208
  try {
9095
- installScript = await fetchText(`${BASE_URL}/install-core.mjs`);
9209
+ installScript = await fetchText(`${BASE_URL2}/install-core.mjs`);
9096
9210
  } catch (err) {
9097
9211
  const msg = `\u4E0B\u8F7D\u5B89\u88C5\u811A\u672C\u5931\u8D25: ${err?.message ?? String(err)}`;
9098
9212
  if (json) {
@@ -9103,9 +9217,9 @@ async function runUpdate(ctx, opts) {
9103
9217
  `);
9104
9218
  process.exit(1);
9105
9219
  }
9106
- const tmpScript = (0, import_node_path14.join)(import_node_os2.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
9220
+ const tmpScript = (0, import_node_path16.join)(import_node_os3.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
9107
9221
  try {
9108
- (0, import_node_fs20.writeFileSync)(tmpScript, installScript, "utf-8");
9222
+ (0, import_node_fs21.writeFileSync)(tmpScript, installScript, "utf-8");
9109
9223
  } catch (err) {
9110
9224
  const msg = `\u5199\u5165\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${err?.message ?? String(err)}`;
9111
9225
  if (json) {
@@ -9123,7 +9237,7 @@ async function runUpdate(ctx, opts) {
9123
9237
  { stdio: "inherit" }
9124
9238
  );
9125
9239
  try {
9126
- (0, import_node_fs20.unlinkSync)(tmpScript);
9240
+ (0, import_node_fs21.unlinkSync)(tmpScript);
9127
9241
  } catch {
9128
9242
  }
9129
9243
  if (result.error) {
@@ -9187,10 +9301,10 @@ function inferOpenClawRootDir(workspaceDir) {
9187
9301
  if (!workspaceDir) {
9188
9302
  return void 0;
9189
9303
  }
9190
- if ((0, import_node_path15.basename)(workspaceDir) !== "workspace") {
9304
+ if ((0, import_node_path17.basename)(workspaceDir) !== "workspace") {
9191
9305
  return void 0;
9192
9306
  }
9193
- return (0, import_node_path15.dirname)(workspaceDir);
9307
+ return (0, import_node_path17.dirname)(workspaceDir);
9194
9308
  }
9195
9309
  function registerPluginCli(api, params) {
9196
9310
  const { logger, openclawDir } = params;
@@ -9436,12 +9550,12 @@ function registerLightControlTool(api, logger) {
9436
9550
  }
9437
9551
 
9438
9552
  // src/plugin/lifecycle.ts
9439
- var import_node_fs29 = require("fs");
9553
+ var import_node_fs30 = require("fs");
9440
9554
  init_host();
9441
9555
 
9442
9556
  // src/notification/app-name-map.ts
9443
- var import_node_fs21 = require("fs");
9444
- var import_node_path16 = require("path");
9557
+ var import_node_fs22 = require("fs");
9558
+ var import_node_path18 = require("path");
9445
9559
  init_credentials();
9446
9560
  init_env();
9447
9561
  var PLUGIN_STATE_DIR = "phone-notifications";
@@ -9462,7 +9576,7 @@ function isAppNameMapApiResponse(v) {
9462
9576
  );
9463
9577
  }
9464
9578
  function getCachePath(stateDir) {
9465
- return (0, import_node_path16.join)(stateDir, "plugins", PLUGIN_STATE_DIR, CACHE_FILE);
9579
+ return (0, import_node_path18.join)(stateDir, "plugins", PLUGIN_STATE_DIR, CACHE_FILE);
9466
9580
  }
9467
9581
  function createAppNameMapProvider(opts) {
9468
9582
  const { stateDir, logger } = opts;
@@ -9474,9 +9588,9 @@ function createAppNameMapProvider(opts) {
9474
9588
  let inFlightFetch = null;
9475
9589
  function loadFromDisk() {
9476
9590
  const path2 = getCachePath(stateDir);
9477
- if (!(0, import_node_fs21.existsSync)(path2)) return;
9591
+ if (!(0, import_node_fs22.existsSync)(path2)) return;
9478
9592
  try {
9479
- const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf-8"));
9593
+ const raw = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf-8"));
9480
9594
  if (!isRecordOfStrings(raw)) return;
9481
9595
  map.clear();
9482
9596
  for (const [k, v] of Object.entries(raw)) map.set(k, v);
@@ -9520,10 +9634,10 @@ function createAppNameMapProvider(opts) {
9520
9634
  logger.warn("[app-name-map] refresh succeeded but got 0 entries");
9521
9635
  return;
9522
9636
  }
9523
- const dir = (0, import_node_path16.join)(stateDir, "plugins", PLUGIN_STATE_DIR);
9524
- (0, import_node_fs21.mkdirSync)(dir, { recursive: true });
9637
+ const dir = (0, import_node_path18.join)(stateDir, "plugins", PLUGIN_STATE_DIR);
9638
+ (0, import_node_fs22.mkdirSync)(dir, { recursive: true });
9525
9639
  const cachePath = getCachePath(stateDir);
9526
- (0, import_node_fs21.writeFileSync)(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), "utf-8");
9640
+ (0, import_node_fs22.writeFileSync)(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), "utf-8");
9527
9641
  logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);
9528
9642
  } catch (e) {
9529
9643
  const message = e instanceof Error ? e.message : String(e);
@@ -9567,8 +9681,8 @@ function createAppNameMapProvider(opts) {
9567
9681
  }
9568
9682
 
9569
9683
  // src/recording/storage.ts
9570
- var import_node_fs22 = require("fs");
9571
- var import_node_path17 = require("path");
9684
+ var import_node_fs23 = require("fs");
9685
+ var import_node_path19 = require("path");
9572
9686
 
9573
9687
  // src/recording/state-machine.ts
9574
9688
  var VALID_TRANSITIONS = /* @__PURE__ */ new Map([
@@ -9629,7 +9743,7 @@ function stripMarkdownFence(markdown) {
9629
9743
  }
9630
9744
  function deriveTitleFromTranscriptPath(transcriptFile, recordingId) {
9631
9745
  if (!transcriptFile) return void 0;
9632
- const name = (0, import_node_path17.basename)(transcriptFile, ".md");
9746
+ const name = (0, import_node_path19.basename)(transcriptFile, ".md");
9633
9747
  const prefix = `${recordingId}_`;
9634
9748
  if (name.startsWith(prefix)) {
9635
9749
  const derived = name.slice(prefix.length).trim();
@@ -9657,22 +9771,22 @@ function extractTranscriptContent(markdown) {
9657
9771
  return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
9658
9772
  }
9659
9773
  function resolveRecordingStorageDir(ctx, logger) {
9660
- const stateRecDir = (0, import_node_path17.join)(
9774
+ const stateRecDir = (0, import_node_path19.join)(
9661
9775
  ctx.stateDir,
9662
9776
  "plugins",
9663
9777
  "phone-notifications",
9664
9778
  RECORDINGS_DIR
9665
9779
  );
9666
9780
  try {
9667
- (0, import_node_fs22.mkdirSync)(stateRecDir, { recursive: true });
9781
+ (0, import_node_fs23.mkdirSync)(stateRecDir, { recursive: true });
9668
9782
  logger.info(`\u5F55\u97F3\u5C06\u5199\u5165 stateDir \u8DEF\u5F84: ${stateRecDir}`);
9669
9783
  return stateRecDir;
9670
9784
  } catch {
9671
9785
  }
9672
9786
  if (ctx.workspaceDir) {
9673
- const wsRecDir = (0, import_node_path17.join)(ctx.workspaceDir, RECORDINGS_DIR);
9787
+ const wsRecDir = (0, import_node_path19.join)(ctx.workspaceDir, RECORDINGS_DIR);
9674
9788
  try {
9675
- (0, import_node_fs22.mkdirSync)(wsRecDir, { recursive: true });
9789
+ (0, import_node_fs23.mkdirSync)(wsRecDir, { recursive: true });
9676
9790
  logger.warn(`stateDir \u4E0D\u53EF\u7528\uFF0C\u5F55\u97F3\u5DF2\u56DE\u9000\u5230 workspace \u8DEF\u5F84: ${wsRecDir}`);
9677
9791
  return wsRecDir;
9678
9792
  } catch {
@@ -9684,11 +9798,11 @@ var RecordingStorage = class {
9684
9798
  constructor(dir, logger) {
9685
9799
  this.logger = logger;
9686
9800
  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);
9801
+ this.audioDir = (0, import_node_path19.join)(dir, AUDIO_DIR);
9802
+ this.transcriptDataDir = (0, import_node_path19.join)(dir, TRANSCRIPT_DATA_DIR);
9803
+ this.transcriptsDir = (0, import_node_path19.join)(dir, TRANSCRIPTS_DIR);
9804
+ this.summariesDir = (0, import_node_path19.join)(dir, SUMMARIES_DIR);
9805
+ this.indexPath = (0, import_node_path19.join)(dir, INDEX_FILE);
9692
9806
  }
9693
9807
  dir;
9694
9808
  audioDir;
@@ -9699,10 +9813,10 @@ var RecordingStorage = class {
9699
9813
  index = { recordings: [] };
9700
9814
  /** 初始化目录结构并加载索引 */
9701
9815
  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 });
9816
+ (0, import_node_fs23.mkdirSync)(this.audioDir, { recursive: true });
9817
+ (0, import_node_fs23.mkdirSync)(this.transcriptDataDir, { recursive: true });
9818
+ (0, import_node_fs23.mkdirSync)(this.transcriptsDir, { recursive: true });
9819
+ (0, import_node_fs23.mkdirSync)(this.summariesDir, { recursive: true });
9706
9820
  this.loadIndex();
9707
9821
  this.logger.info(
9708
9822
  `\u5F55\u97F3\u5B58\u50A8\u5DF2\u521D\u59CB\u5316: ${this.dir}\uFF08\u5171 ${this.index.recordings.length} \u6761\u8BB0\u5F55\uFF09`
@@ -9746,13 +9860,13 @@ var RecordingStorage = class {
9746
9860
  return id;
9747
9861
  }
9748
9862
  if (existing.transcriptDataFile) {
9749
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, existing.transcriptDataFile), { force: true });
9863
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.transcriptDataFile), { force: true });
9750
9864
  }
9751
9865
  if (existing.transcriptFile) {
9752
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, existing.transcriptFile), { force: true });
9866
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.transcriptFile), { force: true });
9753
9867
  }
9754
9868
  if (existing.summaryFile) {
9755
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, existing.summaryFile), { force: true });
9869
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.summaryFile), { force: true });
9756
9870
  }
9757
9871
  existing.metadata = metadata;
9758
9872
  existing.status = "syncing_openclaw";
@@ -9820,7 +9934,7 @@ var RecordingStorage = class {
9820
9934
  if (!entry) return;
9821
9935
  const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;
9822
9936
  if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {
9823
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, entry.transcriptDataFile), { force: true });
9937
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.transcriptDataFile), { force: true });
9824
9938
  }
9825
9939
  entry.transcriptDataFile = nextTranscriptDataFile;
9826
9940
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -9834,7 +9948,7 @@ var RecordingStorage = class {
9834
9948
  if (!entry) return;
9835
9949
  const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;
9836
9950
  if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {
9837
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, entry.transcriptFile), { force: true });
9951
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.transcriptFile), { force: true });
9838
9952
  }
9839
9953
  entry.transcriptFile = nextTranscriptFile;
9840
9954
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -9848,7 +9962,7 @@ var RecordingStorage = class {
9848
9962
  if (!entry) return;
9849
9963
  const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;
9850
9964
  if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {
9851
- (0, import_node_fs22.rmSync)((0, import_node_path17.join)(this.dir, entry.summaryFile), { force: true });
9965
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.summaryFile), { force: true });
9852
9966
  }
9853
9967
  entry.summaryFile = nextSummaryFile;
9854
9968
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -9946,24 +10060,24 @@ var RecordingStorage = class {
9946
10060
  const entry = this.findById(recordingId);
9947
10061
  if (!entry) return false;
9948
10062
  if (entry.audioFile) {
9949
- const audioPath = (0, import_node_path17.join)(this.dir, entry.audioFile);
9950
- (0, import_node_fs22.rmSync)(audioPath, { force: true });
10063
+ const audioPath = (0, import_node_path19.join)(this.dir, entry.audioFile);
10064
+ (0, import_node_fs23.rmSync)(audioPath, { force: true });
9951
10065
  }
9952
10066
  if (entry.srtFile) {
9953
- const srtPath = (0, import_node_path17.join)(this.dir, entry.srtFile);
9954
- (0, import_node_fs22.rmSync)(srtPath, { force: true });
10067
+ const srtPath = (0, import_node_path19.join)(this.dir, entry.srtFile);
10068
+ (0, import_node_fs23.rmSync)(srtPath, { force: true });
9955
10069
  }
9956
10070
  if (entry.transcriptDataFile) {
9957
- const transcriptDataPath = (0, import_node_path17.join)(this.dir, entry.transcriptDataFile);
9958
- (0, import_node_fs22.rmSync)(transcriptDataPath, { force: true });
10071
+ const transcriptDataPath = (0, import_node_path19.join)(this.dir, entry.transcriptDataFile);
10072
+ (0, import_node_fs23.rmSync)(transcriptDataPath, { force: true });
9959
10073
  }
9960
10074
  if (entry.transcriptFile) {
9961
- const transcriptPath = (0, import_node_path17.join)(this.dir, entry.transcriptFile);
9962
- (0, import_node_fs22.rmSync)(transcriptPath, { force: true });
10075
+ const transcriptPath = (0, import_node_path19.join)(this.dir, entry.transcriptFile);
10076
+ (0, import_node_fs23.rmSync)(transcriptPath, { force: true });
9963
10077
  }
9964
10078
  if (entry.summaryFile) {
9965
- const summaryPath = (0, import_node_path17.join)(this.dir, entry.summaryFile);
9966
- (0, import_node_fs22.rmSync)(summaryPath, { force: true });
10079
+ const summaryPath = (0, import_node_path19.join)(this.dir, entry.summaryFile);
10080
+ (0, import_node_fs23.rmSync)(summaryPath, { force: true });
9967
10081
  }
9968
10082
  if (opts?.localOnly) {
9969
10083
  entry.audioFile = void 0;
@@ -10021,34 +10135,34 @@ var RecordingStorage = class {
10021
10135
  * 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名
10022
10136
  */
10023
10137
  getAudioFilePath(recordingId, ossUrl) {
10024
- return (0, import_node_path17.join)(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));
10138
+ return (0, import_node_path19.join)(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));
10025
10139
  }
10026
10140
  /**
10027
10141
  * 获取打点文件的绝对路径
10028
10142
  */
10029
10143
  getSrtFilePath(recordingId) {
10030
- return (0, import_node_path17.join)(this.audioDir, this.buildSrtFilename(recordingId));
10144
+ return (0, import_node_path19.join)(this.audioDir, this.buildSrtFilename(recordingId));
10031
10145
  }
10032
10146
  /**
10033
10147
  * 获取转写 JSON 文件的绝对路径
10034
10148
  */
10035
10149
  getTranscriptDataFilePath(recordingId) {
10036
- return (0, import_node_path17.join)(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));
10150
+ return (0, import_node_path19.join)(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));
10037
10151
  }
10038
10152
  /**
10039
10153
  * 获取摘要文件的绝对路径
10040
10154
  */
10041
10155
  getSummaryFilePath(recordingId) {
10042
- return (0, import_node_path17.join)(this.summariesDir, this.buildSummaryFilename(recordingId));
10156
+ return (0, import_node_path19.join)(this.summariesDir, this.buildSummaryFilename(recordingId));
10043
10157
  }
10044
10158
  // ─── Persistence ───
10045
10159
  loadIndex() {
10046
- if (!(0, import_node_fs22.existsSync)(this.indexPath)) {
10160
+ if (!(0, import_node_fs23.existsSync)(this.indexPath)) {
10047
10161
  this.index = { recordings: [] };
10048
10162
  return;
10049
10163
  }
10050
10164
  try {
10051
- const raw = JSON.parse((0, import_node_fs22.readFileSync)(this.indexPath, "utf-8"));
10165
+ const raw = JSON.parse((0, import_node_fs23.readFileSync)(this.indexPath, "utf-8"));
10052
10166
  if (raw && Array.isArray(raw.recordings)) {
10053
10167
  let needsRewrite = false;
10054
10168
  const normalized = raw.recordings.filter((entry) => entry && typeof entry === "object").map((entry) => {
@@ -10086,8 +10200,8 @@ var RecordingStorage = class {
10086
10200
  segments: []
10087
10201
  });
10088
10202
  const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);
10089
- (0, import_node_fs22.writeFileSync)(
10090
- (0, import_node_path17.join)(this.transcriptDataDir, transcriptDataFilename),
10203
+ (0, import_node_fs23.writeFileSync)(
10204
+ (0, import_node_path19.join)(this.transcriptDataDir, transcriptDataFilename),
10091
10205
  JSON.stringify(transcriptDoc, null, 2),
10092
10206
  "utf-8"
10093
10207
  );
@@ -10099,8 +10213,8 @@ var RecordingStorage = class {
10099
10213
  compacted.summaryFile = entry.summaryFile;
10100
10214
  } else if (typeof entry.summary === "string" && entry.summary.trim()) {
10101
10215
  const summaryFilename = this.buildSummaryFilename(entry.id);
10102
- (0, import_node_fs22.writeFileSync)(
10103
- (0, import_node_path17.join)(this.summariesDir, summaryFilename),
10216
+ (0, import_node_fs23.writeFileSync)(
10217
+ (0, import_node_path19.join)(this.summariesDir, summaryFilename),
10104
10218
  entry.summary.trim(),
10105
10219
  "utf-8"
10106
10220
  );
@@ -10110,8 +10224,8 @@ var RecordingStorage = class {
10110
10224
  const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);
10111
10225
  if (summaryFromDocument) {
10112
10226
  const summaryFilename = this.buildSummaryFilename(entry.id);
10113
- (0, import_node_fs22.writeFileSync)(
10114
- (0, import_node_path17.join)(this.summariesDir, summaryFilename),
10227
+ (0, import_node_fs23.writeFileSync)(
10228
+ (0, import_node_path19.join)(this.summariesDir, summaryFilename),
10115
10229
  summaryFromDocument,
10116
10230
  "utf-8"
10117
10231
  );
@@ -10151,7 +10265,7 @@ var RecordingStorage = class {
10151
10265
  }
10152
10266
  readRelativeTextFile(relativePath) {
10153
10267
  try {
10154
- return (0, import_node_fs22.readFileSync)((0, import_node_path17.join)(this.dir, relativePath), "utf-8");
10268
+ return (0, import_node_fs23.readFileSync)((0, import_node_path19.join)(this.dir, relativePath), "utf-8");
10155
10269
  } catch {
10156
10270
  return void 0;
10157
10271
  }
@@ -10164,7 +10278,7 @@ var RecordingStorage = class {
10164
10278
  return parseTranscriptDocument(raw);
10165
10279
  }
10166
10280
  saveIndex() {
10167
- (0, import_node_fs22.writeFileSync)(
10281
+ (0, import_node_fs23.writeFileSync)(
10168
10282
  this.indexPath,
10169
10283
  JSON.stringify(this.index, null, 2),
10170
10284
  "utf-8"
@@ -10178,8 +10292,8 @@ var RecordingStorage = class {
10178
10292
  init_transcript_document();
10179
10293
 
10180
10294
  // src/recording/downloader.ts
10181
- var import_node_fs23 = require("fs");
10182
- var import_node_path18 = require("path");
10295
+ var import_node_fs24 = require("fs");
10296
+ var import_node_path20 = require("path");
10183
10297
  var import_promises2 = require("stream/promises");
10184
10298
  var import_node_stream = require("stream");
10185
10299
  var DEFAULT_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -10189,7 +10303,7 @@ async function downloadFile(url, destPath, logger, options) {
10189
10303
  const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
10190
10304
  const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
10191
10305
  const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;
10192
- (0, import_node_fs23.mkdirSync)((0, import_node_path18.dirname)(destPath), { recursive: true });
10306
+ (0, import_node_fs24.mkdirSync)((0, import_node_path20.dirname)(destPath), { recursive: true });
10193
10307
  let lastError;
10194
10308
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
10195
10309
  const startMs = Date.now();
@@ -10207,11 +10321,11 @@ async function downloadFile(url, destPath, logger, options) {
10207
10321
  if (!res.body) {
10208
10322
  throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
10209
10323
  }
10210
- const writeStream = (0, import_node_fs23.createWriteStream)(destPath);
10324
+ const writeStream = (0, import_node_fs24.createWriteStream)(destPath);
10211
10325
  const readable = import_node_stream.Readable.fromWeb(res.body);
10212
10326
  await (0, import_promises2.pipeline)(readable, writeStream);
10213
10327
  const elapsed = Date.now() - startMs;
10214
- const fileSize = (0, import_node_fs23.existsSync)(destPath) ? (0, import_node_fs23.statSync)(destPath).size : 0;
10328
+ const fileSize = (0, import_node_fs24.existsSync)(destPath) ? (0, import_node_fs24.statSync)(destPath).size : 0;
10215
10329
  logger.info(
10216
10330
  `[downloader] \u4E0B\u8F7D\u5B8C\u6210: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`
10217
10331
  );
@@ -10222,7 +10336,7 @@ async function downloadFile(url, destPath, logger, options) {
10222
10336
  } catch (err) {
10223
10337
  lastError = err?.message ?? String(err);
10224
10338
  try {
10225
- if ((0, import_node_fs23.existsSync)(destPath)) (0, import_node_fs23.unlinkSync)(destPath);
10339
+ if ((0, import_node_fs24.existsSync)(destPath)) (0, import_node_fs24.unlinkSync)(destPath);
10226
10340
  } catch {
10227
10341
  }
10228
10342
  const isAbort = err?.name === "AbortError";
@@ -10460,13 +10574,13 @@ async function triggerTranscription(recordingId, storage, asrConfig, logger, opt
10460
10574
  }
10461
10575
 
10462
10576
  // src/tunnel/service.ts
10463
- var import_node_fs28 = require("fs");
10464
- var import_node_path23 = require("path");
10577
+ var import_node_fs29 = require("fs");
10578
+ var import_node_path25 = require("path");
10465
10579
  init_credentials();
10466
10580
 
10467
10581
  // src/tunnel/relay-client.ts
10468
- var import_node_fs26 = require("fs");
10469
- var import_node_path21 = require("path");
10582
+ var import_node_fs27 = require("fs");
10583
+ var import_node_path23 = require("path");
10470
10584
 
10471
10585
  // node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
10472
10586
  var import_stream = __toESM(require_stream(), 1);
@@ -10510,8 +10624,8 @@ var RelayClient = class {
10510
10624
  lastDisconnectReason
10511
10625
  };
10512
10626
  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));
10627
+ (0, import_node_fs27.mkdirSync)((0, import_node_path23.dirname)(this.opts.statusFilePath), { recursive: true });
10628
+ (0, import_node_fs27.writeFileSync)(this.opts.statusFilePath, JSON.stringify(info, null, 2));
10515
10629
  } catch {
10516
10630
  }
10517
10631
  }
@@ -10893,8 +11007,8 @@ init_host();
10893
11007
 
10894
11008
  // src/tunnel/device-identity.ts
10895
11009
  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);
11010
+ var import_node_fs28 = __toESM(require("fs"), 1);
11011
+ var import_node_path24 = __toESM(require("path"), 1);
10898
11012
  init_host();
10899
11013
  var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
10900
11014
  function base64UrlEncode(buf) {
@@ -10939,10 +11053,10 @@ function resolveClientStateDir(stateDir) {
10939
11053
  return stateDir ?? resolveStateDir();
10940
11054
  }
10941
11055
  function ensureDir(filePath) {
10942
- import_node_fs27.default.mkdirSync(import_node_path22.default.dirname(filePath), { recursive: true });
11056
+ import_node_fs28.default.mkdirSync(import_node_path24.default.dirname(filePath), { recursive: true });
10943
11057
  }
10944
11058
  function resolveIdentityPath(stateDir) {
10945
- return import_node_path22.default.join(stateDir, "identity", "device.json");
11059
+ return import_node_path24.default.join(stateDir, "identity", "device.json");
10946
11060
  }
10947
11061
  function normalizeDeviceAuthRole(role) {
10948
11062
  return role.trim();
@@ -10958,12 +11072,12 @@ function normalizeDeviceAuthScopes(scopes) {
10958
11072
  return [...out].sort();
10959
11073
  }
10960
11074
  function resolveDeviceAuthPath(stateDir) {
10961
- return import_node_path22.default.join(stateDir, "identity", "device-auth.json");
11075
+ return import_node_path24.default.join(stateDir, "identity", "device-auth.json");
10962
11076
  }
10963
11077
  function readDeviceAuthStore(filePath) {
10964
11078
  try {
10965
- if (!import_node_fs27.default.existsSync(filePath)) return null;
10966
- const raw = import_node_fs27.default.readFileSync(filePath, "utf8");
11079
+ if (!import_node_fs28.default.existsSync(filePath)) return null;
11080
+ const raw = import_node_fs28.default.readFileSync(filePath, "utf8");
10967
11081
  const parsed = JSON.parse(raw);
10968
11082
  if (parsed?.version !== 1 || typeof parsed.deviceId !== "string") return null;
10969
11083
  if (!parsed.tokens || typeof parsed.tokens !== "object") return null;
@@ -10974,12 +11088,12 @@ function readDeviceAuthStore(filePath) {
10974
11088
  }
10975
11089
  function writeDeviceAuthStore(filePath, store) {
10976
11090
  ensureDir(filePath);
10977
- import_node_fs27.default.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
11091
+ import_node_fs28.default.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
10978
11092
  `, {
10979
11093
  mode: 384
10980
11094
  });
10981
11095
  try {
10982
- import_node_fs27.default.chmodSync(filePath, 384);
11096
+ import_node_fs28.default.chmodSync(filePath, 384);
10983
11097
  } catch {
10984
11098
  }
10985
11099
  }
@@ -11026,8 +11140,8 @@ function clearDeviceAuthToken(params) {
11026
11140
  function loadOrCreateDeviceIdentity(stateDir) {
11027
11141
  const filePath = resolveIdentityPath(stateDir);
11028
11142
  try {
11029
- if (import_node_fs27.default.existsSync(filePath)) {
11030
- const raw = import_node_fs27.default.readFileSync(filePath, "utf8");
11143
+ if (import_node_fs28.default.existsSync(filePath)) {
11144
+ const raw = import_node_fs28.default.readFileSync(filePath, "utf8");
11031
11145
  const parsed = JSON.parse(raw);
11032
11146
  if (parsed?.version === 1 && typeof parsed.deviceId === "string" && typeof parsed.publicKeyPem === "string" && typeof parsed.privateKeyPem === "string") {
11033
11147
  const derivedId = fingerprintPublicKey(parsed.publicKeyPem);
@@ -11048,14 +11162,14 @@ function loadOrCreateDeviceIdentity(stateDir) {
11048
11162
  publicKeyPem,
11049
11163
  privateKeyPem
11050
11164
  };
11051
- import_node_fs27.default.mkdirSync(import_node_path22.default.dirname(filePath), { recursive: true });
11165
+ import_node_fs28.default.mkdirSync(import_node_path24.default.dirname(filePath), { recursive: true });
11052
11166
  const stored = {
11053
11167
  version: 1,
11054
11168
  ...identity,
11055
11169
  createdAtMs: Date.now()
11056
11170
  };
11057
11171
  ensureDir(filePath);
11058
- import_node_fs27.default.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}
11172
+ import_node_fs28.default.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}
11059
11173
  `, {
11060
11174
  mode: 384
11061
11175
  });
@@ -11825,7 +11939,7 @@ function createTunnelService(opts) {
11825
11939
  }
11826
11940
  function readLockOwner(filePath) {
11827
11941
  try {
11828
- const parsed = JSON.parse((0, import_node_fs28.readFileSync)(filePath, "utf-8"));
11942
+ const parsed = JSON.parse((0, import_node_fs29.readFileSync)(filePath, "utf-8"));
11829
11943
  return typeof parsed.pid === "number" ? parsed.pid : null;
11830
11944
  } catch {
11831
11945
  return null;
@@ -11838,23 +11952,23 @@ function createTunnelService(opts) {
11838
11952
  lockFd = null;
11839
11953
  if (fd !== null) {
11840
11954
  try {
11841
- (0, import_node_fs28.closeSync)(fd);
11955
+ (0, import_node_fs29.closeSync)(fd);
11842
11956
  } catch {
11843
11957
  }
11844
11958
  }
11845
11959
  if (filePath) {
11846
11960
  try {
11847
- (0, import_node_fs28.unlinkSync)(filePath);
11961
+ (0, import_node_fs29.unlinkSync)(filePath);
11848
11962
  } catch {
11849
11963
  }
11850
11964
  }
11851
11965
  }
11852
11966
  function acquireLock(filePath) {
11853
- (0, import_node_fs28.mkdirSync)((0, import_node_path23.dirname)(filePath), { recursive: true });
11967
+ (0, import_node_fs29.mkdirSync)((0, import_node_path25.dirname)(filePath), { recursive: true });
11854
11968
  for (let attempt = 0; attempt < 2; attempt++) {
11855
11969
  try {
11856
- const fd = (0, import_node_fs28.openSync)(filePath, "wx", 384);
11857
- (0, import_node_fs28.writeFileSync)(
11970
+ const fd = (0, import_node_fs29.openSync)(filePath, "wx", 384);
11971
+ (0, import_node_fs29.writeFileSync)(
11858
11972
  fd,
11859
11973
  JSON.stringify({
11860
11974
  pid: process.pid,
@@ -11878,7 +11992,7 @@ function createTunnelService(opts) {
11878
11992
  `Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`
11879
11993
  );
11880
11994
  try {
11881
- (0, import_node_fs28.unlinkSync)(filePath);
11995
+ (0, import_node_fs29.unlinkSync)(filePath);
11882
11996
  } catch {
11883
11997
  }
11884
11998
  continue;
@@ -11923,12 +12037,12 @@ function createTunnelService(opts) {
11923
12037
  return;
11924
12038
  }
11925
12039
  const { logger } = opts;
11926
- const baseStateDir = (0, import_node_path23.join)(ctx.stateDir, "plugins", "phone-notifications");
12040
+ const baseStateDir = (0, import_node_path25.join)(ctx.stateDir, "plugins", "phone-notifications");
11927
12041
  logger.info(
11928
12042
  `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
12043
  );
11930
- const statusFilePath = (0, import_node_path23.join)(baseStateDir, "tunnel-status.json");
11931
- const lockPath = (0, import_node_path23.join)(baseStateDir, "relay-tunnel.lock");
12044
+ const statusFilePath = (0, import_node_path25.join)(baseStateDir, "tunnel-status.json");
12045
+ const lockPath = (0, import_node_path25.join)(baseStateDir, "relay-tunnel.lock");
11932
12046
  if (!acquireLock(lockPath)) {
11933
12047
  return;
11934
12048
  }
@@ -12068,7 +12182,7 @@ function readHostGatewayConfig(params) {
12068
12182
  let configData;
12069
12183
  if (configPath) {
12070
12184
  try {
12071
- configData = JSON.parse((0, import_node_fs29.readFileSync)(configPath, "utf-8"));
12185
+ configData = JSON.parse((0, import_node_fs30.readFileSync)(configPath, "utf-8"));
12072
12186
  } catch (err) {
12073
12187
  if (err?.code !== "ENOENT") {
12074
12188
  params.logger.warn(