@yoooclaw/phone-notifications 1.11.1 → 1.11.2-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -270,14 +270,16 @@ var init_env = __esm({
270
270
  relayTunnelUrl: "wss://openclaw-service-dev.yoooclaw.com/message/messages/ws/plugin",
271
271
  appNameMapUrl: "https://openclaw-service-dev.yoooclaw.com/api/application-config/app-package/config-all",
272
272
  modelProxyLongRecordingSubmitTaskUrl: "https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/submit-task",
273
- modelProxyLongRecordingQueryTaskResultBaseUrl: "https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/query-task-result"
273
+ modelProxyLongRecordingQueryTaskResultBaseUrl: "https://openclaw-service-dev.yoooclaw.com/api/model-proxy/long-recording/query-task-result",
274
+ accountFileDeleteUrl: "https://openclaw-service-dev.yoooclaw.com/account/file/delete"
274
275
  },
275
276
  production: {
276
277
  lightApiUrl: "https://openclaw-service.yoootek.com/api/message/tob/sendMessage",
277
278
  relayTunnelUrl: "wss://openclaw-service.yoootek.com/message/messages/ws/plugin",
278
279
  appNameMapUrl: "https://openclaw-service.yoootek.com/api/application-config/app-package/config-all",
279
280
  modelProxyLongRecordingSubmitTaskUrl: "https://openclaw-service.yoootek.com/api/model-proxy/long-recording/submit-task",
280
- modelProxyLongRecordingQueryTaskResultBaseUrl: "https://openclaw-service.yoootek.com/api/model-proxy/long-recording/query-task-result"
281
+ modelProxyLongRecordingQueryTaskResultBaseUrl: "https://openclaw-service.yoootek.com/api/model-proxy/long-recording/query-task-result",
282
+ accountFileDeleteUrl: "https://openclaw-service.yoootek.com/account/file/delete"
281
283
  }
282
284
  };
283
285
  VALID_ENVS = new Set(Object.keys(ENV_CONFIG));
@@ -535,20 +537,20 @@ function selectModelByMemory(availableGB, isAppleSilicon = false) {
535
537
  return "tiny";
536
538
  }
537
539
  function resolveModelsDir(dataDir) {
538
- const dir = (0, import_node_path22.join)(dataDir, WHISPER_MODELS_DIR);
539
- (0, import_node_fs26.mkdirSync)(dir, { recursive: true });
540
+ const dir = (0, import_node_path21.join)(dataDir, WHISPER_MODELS_DIR);
541
+ (0, import_node_fs25.mkdirSync)(dir, { recursive: true });
540
542
  return dir;
541
543
  }
542
544
  function resolveBinDir(dataDir) {
543
- const dir = (0, import_node_path22.join)(dataDir, WHISPER_BIN_DIR);
544
- (0, import_node_fs26.mkdirSync)(dir, { recursive: true });
545
+ const dir = (0, import_node_path21.join)(dataDir, WHISPER_BIN_DIR);
546
+ (0, import_node_fs25.mkdirSync)(dir, { recursive: true });
545
547
  return dir;
546
548
  }
547
549
  function isModelDownloaded(modelsDir, modelSize) {
548
- const modelPath = (0, import_node_path22.join)(modelsDir, MODEL_FILENAMES[modelSize]);
549
- if (!(0, import_node_fs26.existsSync)(modelPath)) return false;
550
+ const modelPath = (0, import_node_path21.join)(modelsDir, MODEL_FILENAMES[modelSize]);
551
+ if (!(0, import_node_fs25.existsSync)(modelPath)) return false;
550
552
  try {
551
- const stat = (0, import_node_fs26.statSync)(modelPath);
553
+ const stat = (0, import_node_fs25.statSync)(modelPath);
552
554
  const expectedSize = MODEL_DISK_SIZES[modelSize];
553
555
  return stat.size >= expectedSize * 0.8;
554
556
  } catch {
@@ -557,7 +559,7 @@ function isModelDownloaded(modelsDir, modelSize) {
557
559
  }
558
560
  async function downloadModel(modelsDir, modelSize, logger, modelSource, mirrorUrl) {
559
561
  const filename = MODEL_FILENAMES[modelSize];
560
- const modelPath = (0, import_node_path22.join)(modelsDir, filename);
562
+ const modelPath = (0, import_node_path21.join)(modelsDir, filename);
561
563
  if (isModelDownloaded(modelsDir, modelSize)) {
562
564
  logger.info(`[whisper-local] \u6A21\u578B\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u4E0B\u8F7D: ${filename}`);
563
565
  return { ok: true, modelPath };
@@ -623,7 +625,7 @@ async function probeUrl(url, logger) {
623
625
  async function downloadFromUrl(url, modelPath, logger) {
624
626
  const tmpPath = `${modelPath}.downloading`;
625
627
  try {
626
- (0, import_node_fs26.mkdirSync)((0, import_node_path22.dirname)(modelPath), { recursive: true });
628
+ (0, import_node_fs25.mkdirSync)((0, import_node_path21.dirname)(modelPath), { recursive: true });
627
629
  const controller = new AbortController();
628
630
  const timer = setTimeout(() => controller.abort(), 30 * 60 * 1e3);
629
631
  try {
@@ -639,7 +641,7 @@ async function downloadFromUrl(url, modelPath, logger) {
639
641
  return { ok: false, modelPath, error: "\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: \u54CD\u5E94\u4F53\u4E3A\u7A7A" };
640
642
  }
641
643
  const contentLength = Number(res.headers.get("content-length") ?? 0);
642
- const writeStream = (0, import_node_fs26.createWriteStream)(tmpPath);
644
+ const writeStream = (0, import_node_fs25.createWriteStream)(tmpPath);
643
645
  const readable = import_node_stream2.Readable.fromWeb(res.body);
644
646
  let downloaded = 0;
645
647
  let lastLogPercent = 0;
@@ -661,14 +663,14 @@ async function downloadFromUrl(url, modelPath, logger) {
661
663
  }
662
664
  const { renameSync: renameSync2 } = await import("fs");
663
665
  renameSync2(tmpPath, modelPath);
664
- const fileSize = (0, import_node_fs26.statSync)(modelPath).size;
666
+ const fileSize = (0, import_node_fs25.statSync)(modelPath).size;
665
667
  logger.info(
666
- `[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path22.basename)(modelPath)} (${formatBytes2(fileSize)})`
668
+ `[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path21.basename)(modelPath)} (${formatBytes2(fileSize)})`
667
669
  );
668
670
  return { ok: true, modelPath };
669
671
  } catch (err2) {
670
672
  try {
671
- if ((0, import_node_fs26.existsSync)(tmpPath)) (0, import_node_fs26.unlinkSync)(tmpPath);
673
+ if ((0, import_node_fs25.existsSync)(tmpPath)) (0, import_node_fs25.unlinkSync)(tmpPath);
672
674
  } catch {
673
675
  }
674
676
  const msg = err2?.name === "AbortError" ? "\u6A21\u578B\u4E0B\u8F7D\u8D85\u65F6\uFF0830 \u5206\u949F\uFF09" : err2?.message ?? String(err2);
@@ -680,8 +682,8 @@ function findWhisperBinary(dataDir, logger) {
680
682
  const binDir = resolveBinDir(dataDir);
681
683
  const binNames = (0, import_node_os4.platform)() === "win32" ? ["whisper-cli.exe", "whisper.exe", "main.exe"] : ["whisper-cli", "whisper", "main"];
682
684
  for (const name of binNames) {
683
- const binPath = (0, import_node_path22.join)(binDir, name);
684
- if ((0, import_node_fs26.existsSync)(binPath)) {
685
+ const binPath = (0, import_node_path21.join)(binDir, name);
686
+ if ((0, import_node_fs25.existsSync)(binPath)) {
685
687
  logger.info(`[whisper-local] \u627E\u5230\u672C\u5730\u4E8C\u8FDB\u5236: ${binPath}`);
686
688
  return binPath;
687
689
  }
@@ -732,7 +734,7 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
732
734
  return { ok: false, error: `\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: ${downloadResult.error}` };
733
735
  }
734
736
  }
735
- const modelPath = (0, import_node_path22.join)(modelsDir, MODEL_FILENAMES[modelSize]);
737
+ const modelPath = (0, import_node_path21.join)(modelsDir, MODEL_FILENAMES[modelSize]);
736
738
  let inputPath = audioFilePath;
737
739
  let tmpWavPath = null;
738
740
  const actualFmt = detectAudioFormat(audioFilePath);
@@ -784,10 +786,10 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
784
786
  logger.info(`[whisper-local] \u8F6C\u5199\u8017\u65F6: ${Math.round(elapsed / 1e3)}s`);
785
787
  const jsonPath = inputPath + ".json";
786
788
  let jsonContent;
787
- if ((0, import_node_fs26.existsSync)(jsonPath)) {
788
- jsonContent = (0, import_node_fs26.readFileSync)(jsonPath, "utf-8");
789
+ if ((0, import_node_fs25.existsSync)(jsonPath)) {
790
+ jsonContent = (0, import_node_fs25.readFileSync)(jsonPath, "utf-8");
789
791
  try {
790
- (0, import_node_fs26.unlinkSync)(jsonPath);
792
+ (0, import_node_fs25.unlinkSync)(jsonPath);
791
793
  } catch {
792
794
  }
793
795
  } else {
@@ -865,10 +867,10 @@ function getPhysicalCoreCount() {
865
867
  }
866
868
  function detectAudioFormat(filePath) {
867
869
  try {
868
- const fd = (0, import_node_fs26.openSync)(filePath, "r");
870
+ const fd = (0, import_node_fs25.openSync)(filePath, "r");
869
871
  const buf = Buffer.alloc(12);
870
- (0, import_node_fs26.readSync)(fd, buf, 0, 12, 0);
871
- (0, import_node_fs26.closeSync)(fd);
872
+ (0, import_node_fs25.readSync)(fd, buf, 0, 12, 0);
873
+ (0, import_node_fs25.closeSync)(fd);
872
874
  const header = buf.toString("ascii", 0, 4);
873
875
  const header8 = buf.toString("ascii", 0, 8);
874
876
  if (header === "RIFF" && buf.toString("ascii", 8, 12) === "WAVE") return ".wav";
@@ -903,7 +905,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
903
905
  timeout: 12e4,
904
906
  stdio: ["pipe", "pipe", "pipe"]
905
907
  });
906
- if (ffmpegResult.status === 0 && (0, import_node_fs26.existsSync)(outputPath)) {
908
+ if (ffmpegResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
907
909
  logger.info(`[whisper-local] ffmpeg \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
908
910
  return { ok: true };
909
911
  }
@@ -916,7 +918,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
916
918
  ["--rate", "16000", "--mono", inputPath, outputPath],
917
919
  { encoding: "utf-8", timeout: 12e4, stdio: ["pipe", "pipe", "pipe"] }
918
920
  );
919
- if (opusResult.status === 0 && (0, import_node_fs26.existsSync)(outputPath)) {
921
+ if (opusResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
920
922
  logger.info(`[whisper-local] opusdec \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
921
923
  return { ok: true };
922
924
  }
@@ -930,7 +932,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
930
932
  if (detectedExt && !inputPath.endsWith(detectedExt)) {
931
933
  tmpCopy = inputPath + ".detected" + detectedExt;
932
934
  try {
933
- (0, import_node_fs26.copyFileSync)(inputPath, tmpCopy);
935
+ (0, import_node_fs25.copyFileSync)(inputPath, tmpCopy);
934
936
  actualInputPath = tmpCopy;
935
937
  logger.info(
936
938
  `[whisper-local] \u68C0\u6D4B\u5230\u5B9E\u9645\u683C\u5F0F ${detectedExt}\uFF0C\u4E34\u65F6\u91CD\u547D\u540D`
@@ -954,22 +956,22 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
954
956
  timeout: 12e4,
955
957
  stdio: ["pipe", "pipe", "pipe"]
956
958
  });
957
- if (tmpCopy && (0, import_node_fs26.existsSync)(tmpCopy)) {
959
+ if (tmpCopy && (0, import_node_fs25.existsSync)(tmpCopy)) {
958
960
  try {
959
- (0, import_node_fs26.unlinkSync)(tmpCopy);
961
+ (0, import_node_fs25.unlinkSync)(tmpCopy);
960
962
  } catch {
961
963
  }
962
964
  }
963
- if (afResult.status === 0 && (0, import_node_fs26.existsSync)(outputPath)) {
965
+ if (afResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
964
966
  logger.info(`[whisper-local] afconvert \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
965
967
  return { ok: true };
966
968
  }
967
969
  const stderr = afResult.stderr?.slice(0, 200) ?? "";
968
970
  return { ok: false, error: `afconvert \u8F6C\u6362\u5931\u8D25 (exit ${afResult.status}): ${stderr}` };
969
971
  } catch (err2) {
970
- if (tmpCopy && (0, import_node_fs26.existsSync)(tmpCopy)) {
972
+ if (tmpCopy && (0, import_node_fs25.existsSync)(tmpCopy)) {
971
973
  try {
972
- (0, import_node_fs26.unlinkSync)(tmpCopy);
974
+ (0, import_node_fs25.unlinkSync)(tmpCopy);
973
975
  } catch {
974
976
  }
975
977
  }
@@ -980,9 +982,9 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
980
982
  return { ok: false, error: `\u65E0\u6CD5\u5C06\u97F3\u9891\u8F6C\u6362\u4E3A WAV \u683C\u5F0F\u3002${fmtHint}` };
981
983
  }
982
984
  function cleanupTmpWav(path2) {
983
- if (path2 && (0, import_node_fs26.existsSync)(path2)) {
985
+ if (path2 && (0, import_node_fs25.existsSync)(path2)) {
984
986
  try {
985
- (0, import_node_fs26.unlinkSync)(path2);
987
+ (0, import_node_fs25.unlinkSync)(path2);
986
988
  } catch {
987
989
  }
988
990
  }
@@ -1068,13 +1070,13 @@ function formatBytes2(bytes) {
1068
1070
  if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
1069
1071
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;
1070
1072
  }
1071
- 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;
1073
+ 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;
1072
1074
  var init_whisper_local = __esm({
1073
1075
  "src/recording/whisper-local.ts"() {
1074
1076
  "use strict";
1075
1077
  import_node_child_process2 = require("child_process");
1076
- import_node_fs26 = require("fs");
1077
- import_node_path22 = require("path");
1078
+ import_node_fs25 = require("fs");
1079
+ import_node_path21 = require("path");
1078
1080
  import_promises3 = require("stream/promises");
1079
1081
  import_node_stream2 = require("stream");
1080
1082
  import_node_os4 = require("os");
@@ -1229,7 +1231,7 @@ async function initializeAsr(config, dataDir, logger) {
1229
1231
  }
1230
1232
  }
1231
1233
  async function transcribeAudio(audioFilePath, config, logger, options = {}) {
1232
- if (!(0, import_node_fs27.existsSync)(audioFilePath)) {
1234
+ if (!(0, import_node_fs26.existsSync)(audioFilePath)) {
1233
1235
  return { ok: false, error: `\u97F3\u9891\u6587\u4EF6\u4E0D\u5B58\u5728: ${audioFilePath}` };
1234
1236
  }
1235
1237
  logger.info(
@@ -1240,6 +1242,7 @@ async function transcribeAudio(audioFilePath, config, logger, options = {}) {
1240
1242
  case "api":
1241
1243
  return await transcribeWithModelProxy(
1242
1244
  options.audioOssUrl,
1245
+ options.audioDurationMs,
1243
1246
  config.api,
1244
1247
  logger
1245
1248
  );
@@ -1339,7 +1342,8 @@ async function runTranscriptionWorkflow(params) {
1339
1342
  logger
1340
1343
  } = params;
1341
1344
  const result = await transcribeAudio(audioFilePath, config, logger, {
1342
- audioOssUrl
1345
+ audioOssUrl,
1346
+ audioDurationMs: Math.max(0, Math.round(durationSec * 1e3))
1343
1347
  });
1344
1348
  if (!result.ok) {
1345
1349
  return { ok: false, error: result.error };
@@ -1373,8 +1377,8 @@ async function runTranscriptionWorkflow(params) {
1373
1377
  createdAt
1374
1378
  );
1375
1379
  const transcriptDataFilename = buildTranscriptDataFilename(recordingId);
1376
- const transcriptDataPath = (0, import_node_path23.join)(transcriptDataDir, transcriptDataFilename);
1377
- (0, import_node_fs27.writeFileSync)(
1380
+ const transcriptDataPath = (0, import_node_path22.join)(transcriptDataDir, transcriptDataFilename);
1381
+ (0, import_node_fs26.writeFileSync)(
1378
1382
  transcriptDataPath,
1379
1383
  JSON.stringify(transcriptData, null, 2),
1380
1384
  "utf-8"
@@ -1382,14 +1386,14 @@ async function runTranscriptionWorkflow(params) {
1382
1386
  logger.info(`[asr] \u8F6C\u5199 JSON \u5DF2\u5199\u5165: ${transcriptDataPath}`);
1383
1387
  const safeSummary = title.replace(/[/\\:*?"<>|]/g, "").trim().slice(0, 20);
1384
1388
  const filename = safeSummary ? `${recordingId}_${safeSummary}.md` : `${recordingId}.md`;
1385
- const filePath = (0, import_node_path23.join)(transcriptsDir, filename);
1386
- (0, import_node_fs27.writeFileSync)(filePath, markdown, "utf-8");
1389
+ const filePath = (0, import_node_path22.join)(transcriptsDir, filename);
1390
+ (0, import_node_fs26.writeFileSync)(filePath, markdown, "utf-8");
1387
1391
  logger.info(`[asr] \u8F6C\u5199\u6587\u672C\u5DF2\u5199\u5165: ${filePath}`);
1388
1392
  let summaryFilename;
1389
1393
  if (summary) {
1390
1394
  summaryFilename = `${recordingId}.md`;
1391
- const summaryFilePath = (0, import_node_path23.join)(summariesDir, summaryFilename);
1392
- (0, import_node_fs27.writeFileSync)(summaryFilePath, summary, "utf-8");
1395
+ const summaryFilePath = (0, import_node_path22.join)(summariesDir, summaryFilename);
1396
+ (0, import_node_fs26.writeFileSync)(summaryFilePath, summary, "utf-8");
1393
1397
  logger.info(`[asr] \u6458\u8981\u6587\u672C\u5DF2\u5199\u5165: ${summaryFilePath}`);
1394
1398
  }
1395
1399
  return {
@@ -1402,7 +1406,7 @@ async function runTranscriptionWorkflow(params) {
1402
1406
  title
1403
1407
  };
1404
1408
  }
1405
- async function transcribeWithModelProxy(audioOssUrl, apiConfig, logger) {
1409
+ async function transcribeWithModelProxy(audioOssUrl, audioDurationMs, apiConfig, logger) {
1406
1410
  const normalizedAudioOssUrl = normalizeOptionalText2(audioOssUrl);
1407
1411
  if (!normalizedAudioOssUrl) {
1408
1412
  return { ok: false, error: "API \u6A21\u5F0F\u7F3A\u5C11 audioOssUrl\uFF0C\u65E0\u6CD5\u8C03\u7528 model-proxy" };
@@ -1468,13 +1472,14 @@ async function transcribeWithModelProxy(audioOssUrl, apiConfig, logger) {
1468
1472
  apiKey,
1469
1473
  taskId,
1470
1474
  initialRequestId: requestId,
1475
+ audioDurationMs,
1471
1476
  apiConfig,
1472
1477
  logger
1473
1478
  });
1474
1479
  }
1475
1480
  async function transcribeWithWhisperLocal2(audioFilePath, config, logger) {
1476
1481
  const { transcribeWithWhisperLocal: runLocal } = await Promise.resolve().then(() => (init_whisper_local(), whisper_local_exports));
1477
- const dataDir = process.env.OPENCLAW_STATE_DIR ?? process.env.QCLAW_STATE_DIR ?? (0, import_node_path23.join)(audioFilePath, "..", "..", "..");
1482
+ const dataDir = process.env.OPENCLAW_STATE_DIR ?? process.env.QCLAW_STATE_DIR ?? (0, import_node_path22.join)(audioFilePath, "..", "..", "..");
1478
1483
  const localConfig = config.local ?? {};
1479
1484
  const result = await runLocal(
1480
1485
  audioFilePath,
@@ -1530,6 +1535,7 @@ async function pollLongRecordingTaskResult(params) {
1530
1535
  apiKey,
1531
1536
  taskId,
1532
1537
  initialRequestId,
1538
+ audioDurationMs,
1533
1539
  apiConfig,
1534
1540
  logger
1535
1541
  } = params;
@@ -1577,7 +1583,13 @@ async function pollLongRecordingTaskResult(params) {
1577
1583
  lastStatus = status;
1578
1584
  }
1579
1585
  if (status === "SUCCEEDED") {
1580
- return buildLongRecordingSuccessResult(taskId, requestId, data, logger);
1586
+ return buildLongRecordingSuccessResult(
1587
+ taskId,
1588
+ requestId,
1589
+ data,
1590
+ audioDurationMs,
1591
+ logger
1592
+ );
1581
1593
  }
1582
1594
  if (LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {
1583
1595
  return {
@@ -1600,11 +1612,11 @@ async function pollLongRecordingTaskResult(params) {
1600
1612
  error: `Model Proxy ASR \u8F6E\u8BE2\u8D85\u65F6: taskId=${taskId}, waited=${DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS * DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS}ms`
1601
1613
  };
1602
1614
  }
1603
- function buildLongRecordingSuccessResult(taskId, requestId, data, logger) {
1615
+ function buildLongRecordingSuccessResult(taskId, requestId, data, audioDurationMs, logger) {
1604
1616
  const sourceTextList = normalizeLongRecordingSourceTextList(
1605
1617
  data?.recordResult?.sourceTextList
1606
1618
  );
1607
- const listResult = extractLongRecordingTextFromList(sourceTextList);
1619
+ const listResult = extractLongRecordingTextFromList(sourceTextList, audioDurationMs);
1608
1620
  const sourceText = normalizeOptionalText2(data?.recordResult?.sourceText);
1609
1621
  const summaryText = normalizeOptionalText2(data?.recordResult?.summaryResult) ?? "";
1610
1622
  const title = normalizeOptionalText2(data?.recordResult?.title);
@@ -1701,11 +1713,12 @@ function normalizeLongRecordingSourceTextList(value) {
1701
1713
  return [{
1702
1714
  content,
1703
1715
  speakerId: normalizeOptionalInteger2(record.speakerId),
1704
- startTime: normalizeOptionalNonNegativeNumber(record.startTime)
1716
+ startTime: normalizeOptionalNonNegativeNumber(record.startTime),
1717
+ endTime: normalizeOptionalNonNegativeNumber(record.endTime)
1705
1718
  }];
1706
1719
  });
1707
1720
  }
1708
- function extractLongRecordingTextFromList(items) {
1721
+ function extractLongRecordingTextFromList(items, finalFallbackEndMs) {
1709
1722
  if (items.length === 0) {
1710
1723
  return {
1711
1724
  segments: []
@@ -1713,10 +1726,13 @@ function extractLongRecordingTextFromList(items) {
1713
1726
  }
1714
1727
  const segments = items.map((item, index) => {
1715
1728
  const startMs = item.startTime ?? 0;
1729
+ const explicitEndMs = item.endTime;
1716
1730
  const nextStart = items[index + 1]?.startTime;
1731
+ const fallbackEndMs = index === items.length - 1 ? normalizeOptionalNonNegativeNumber(finalFallbackEndMs) : void 0;
1732
+ const endMs = explicitEndMs ?? nextStart ?? fallbackEndMs ?? startMs;
1717
1733
  return {
1718
1734
  start_ms: startMs,
1719
- end_ms: nextStart ?? startMs,
1735
+ end_ms: Math.max(startMs, endMs),
1720
1736
  text: item.content,
1721
1737
  speaker_id: item.speakerId
1722
1738
  };
@@ -1772,17 +1788,17 @@ function formatTranscriptSegmentText(segment) {
1772
1788
  }
1773
1789
  return text;
1774
1790
  }
1775
- 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;
1791
+ 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;
1776
1792
  var init_asr = __esm({
1777
1793
  "src/recording/asr.ts"() {
1778
1794
  "use strict";
1779
- import_node_fs27 = require("fs");
1780
- import_node_path23 = require("path");
1795
+ import_node_fs26 = require("fs");
1796
+ import_node_path22 = require("path");
1781
1797
  init_credentials();
1782
1798
  init_env();
1783
1799
  init_transcript_document();
1784
1800
  DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS = 2e3;
1785
- DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS = 1800;
1801
+ DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS = 3600;
1786
1802
  LONG_RECORDING_RUNNING_STATUSES = /* @__PURE__ */ new Set(["PENDING", "RUNNING", "SUSPENDED"]);
1787
1803
  LONG_RECORDING_TERMINAL_FAILURE_STATUSES = /* @__PURE__ */ new Set(["FAILED", "CANCELED", "UNKNOWN"]);
1788
1804
  }
@@ -5422,7 +5438,7 @@ function readBuildInjectedVersion() {
5422
5438
  if (false) {
5423
5439
  return void 0;
5424
5440
  }
5425
- const version = "1.11.1".trim();
5441
+ const version = "1.11.2-beta.1".trim();
5426
5442
  return version || void 0;
5427
5443
  }
5428
5444
  function readPluginVersionFromPackageJson() {
@@ -6035,20 +6051,17 @@ function readOptionalString(value) {
6035
6051
  const trimmed = value.trim();
6036
6052
  return trimmed || void 0;
6037
6053
  }
6038
- function isLegacyLightRuleWithoutType(raw) {
6039
- return raw.type === void 0 && readOptionalString(raw.name) !== void 0 && readOptionalString(raw.description) !== void 0 && Array.isArray(raw.segments);
6040
- }
6041
6054
  function readMeta(taskDir) {
6042
6055
  const metaPath = (0, import_node_path3.join)(taskDir, "meta.json");
6043
6056
  if (!(0, import_node_fs4.existsSync)(metaPath)) return null;
6044
6057
  try {
6045
6058
  const raw = JSON.parse((0, import_node_fs4.readFileSync)(metaPath, "utf-8"));
6046
6059
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
6047
- if (raw.type !== "light-rule" && !isLegacyLightRuleWithoutType(raw)) return null;
6060
+ if (raw.type !== "light-rule") return null;
6048
6061
  if (!Array.isArray(raw.segments)) return null;
6049
6062
  const name = readOptionalString(raw.name) ?? (0, import_node_path3.basename)(taskDir);
6050
6063
  const title = readOptionalString(raw.title) ?? name;
6051
- const description = readOptionalString(raw.description) ?? readOptionalString(raw.reason) ?? name;
6064
+ const description = readOptionalString(raw.description) ?? name;
6052
6065
  const createdAt = readOptionalString(raw.createdAt) ?? (0, import_node_fs4.statSync)(metaPath).birthtime.toISOString();
6053
6066
  const enabled = typeof raw.enabled === "boolean" ? raw.enabled : true;
6054
6067
  const repeatTimes = normalizeRepeatTimes({
@@ -7075,115 +7088,6 @@ var InlineLightRuleEvaluator = class {
7075
7088
  }
7076
7089
  };
7077
7090
 
7078
- // src/light-rules/migration.ts
7079
- var import_node_fs8 = require("fs");
7080
- var import_node_path7 = require("path");
7081
- var NO_MATCH_FETCH_PY = `#!/usr/bin/env python3
7082
- # \u6B64\u6587\u4EF6\u7531\u8FC1\u79FB\u5DE5\u5177\u751F\u6210\u3002
7083
- # \u706F\u6548\u89C4\u5219\u5DF2\u8FC1\u79FB\u81F3\u4E8B\u4EF6\u9A71\u52A8\u67B6\u6784\uFF0C\u6B64 cron job \u4E0D\u518D\u6267\u884C\u5B9E\u9645\u5DE5\u4F5C\u3002
7084
- print("NO_MATCH")
7085
- `;
7086
- function normalizeScriptText(text) {
7087
- return text.replace(/\r\n/g, "\n").trim();
7088
- }
7089
- function resolveTasksDir(ctx) {
7090
- if (ctx.workspaceDir) return (0, import_node_path7.join)(ctx.workspaceDir, "tasks");
7091
- if (ctx.stateDir) {
7092
- const inferredWorkspaceDir = (0, import_node_path7.join)(ctx.stateDir, "workspace");
7093
- if ((0, import_node_fs8.existsSync)(inferredWorkspaceDir)) return (0, import_node_path7.join)(inferredWorkspaceDir, "tasks");
7094
- return (0, import_node_path7.join)(ctx.stateDir, "tasks");
7095
- }
7096
- return null;
7097
- }
7098
- function migrateLegacyLightRuleTasks(ctx, logger) {
7099
- const tasksDir3 = resolveTasksDir(ctx);
7100
- if (!tasksDir3 || !(0, import_node_fs8.existsSync)(tasksDir3)) return;
7101
- try {
7102
- for (const entry of (0, import_node_fs8.readdirSync)(tasksDir3, { withFileTypes: true })) {
7103
- if (!entry.isDirectory()) continue;
7104
- migrateTaskDir((0, import_node_path7.join)(tasksDir3, String(entry.name)), logger);
7105
- }
7106
- } catch (err2) {
7107
- logger.warn(`migration: failed to read tasks dir: ${err2?.message}`);
7108
- }
7109
- }
7110
- function migrateTaskDir(taskDir, logger) {
7111
- const metaPath = (0, import_node_path7.join)(taskDir, "meta.json");
7112
- if (!(0, import_node_fs8.existsSync)(metaPath)) return;
7113
- let meta;
7114
- try {
7115
- meta = JSON.parse((0, import_node_fs8.readFileSync)(metaPath, "utf-8"));
7116
- } catch {
7117
- return;
7118
- }
7119
- if (meta.type !== "light-rule") return;
7120
- const name = typeof meta.name === "string" ? meta.name : taskDir;
7121
- cleanupLegacyMetaFields(meta, name, metaPath, logger);
7122
- replaceFetchPy(taskDir, name, logger);
7123
- for (const filename of ["README.md", "checkpoint.json"]) {
7124
- removeFile((0, import_node_path7.join)(taskDir, filename), name, filename, logger);
7125
- }
7126
- }
7127
- function cleanupLegacyMetaFields(meta, name, metaPath, logger) {
7128
- const cleaned = [];
7129
- if (mergeMatchRulesIntoDescription(meta)) cleaned.push("matchRules");
7130
- if (meta.cronSchedule !== void 0) {
7131
- delete meta.cronSchedule;
7132
- cleaned.push("cronSchedule");
7133
- }
7134
- if (cleaned.length === 0) return;
7135
- try {
7136
- (0, import_node_fs8.writeFileSync)(metaPath, JSON.stringify(meta, null, 2), "utf-8");
7137
- logger.info(
7138
- `migration: cleaned deprecated field(s) [${cleaned.join(", ")}] in meta.json for light rule: ${name}`
7139
- );
7140
- } catch (err2) {
7141
- logger.warn(`migration: failed to update meta.json for ${name}: ${err2?.message}`);
7142
- }
7143
- }
7144
- function mergeMatchRulesIntoDescription(meta) {
7145
- const matchRules = meta.matchRules;
7146
- if (!matchRules || typeof matchRules !== "object") return false;
7147
- const rules = matchRules;
7148
- const parts = [];
7149
- if (rules.appName) parts.push(`app=${rules.appName}`);
7150
- if (rules.senderKeywords?.length) {
7151
- parts.push(`\u53D1\u4EF6\u4EBA\u5173\u952E\u8BCD=${rules.senderKeywords.join("\u3001")}`);
7152
- }
7153
- if (rules.contentKeywords?.length) {
7154
- parts.push(`\u5185\u5BB9\u5173\u952E\u8BCD=${rules.contentKeywords.join("\u3001")}`);
7155
- }
7156
- if (parts.length > 0) {
7157
- const existing = typeof meta.description === "string" ? meta.description.trim() : "";
7158
- meta.description = existing ? `${existing}\u3002\u5339\u914D\u89C4\u5219\uFF1A${parts.join("\uFF0C")}` : `\u5339\u914D\u89C4\u5219\uFF1A${parts.join("\uFF0C")}`;
7159
- }
7160
- delete meta.matchRules;
7161
- return true;
7162
- }
7163
- function replaceFetchPy(taskDir, name, logger) {
7164
- const fetchPyPath = (0, import_node_path7.join)(taskDir, "fetch.py");
7165
- if (!(0, import_node_fs8.existsSync)(fetchPyPath)) return;
7166
- try {
7167
- const existing = (0, import_node_fs8.readFileSync)(fetchPyPath, "utf-8");
7168
- if (normalizeScriptText(existing) === normalizeScriptText(NO_MATCH_FETCH_PY)) {
7169
- return;
7170
- }
7171
- (0, import_node_fs8.writeFileSync)(fetchPyPath, NO_MATCH_FETCH_PY, "utf-8");
7172
- logger.info(`migration: replaced fetch.py with NO_MATCH placeholder for ${name}`);
7173
- } catch (err2) {
7174
- logger.warn(`migration: failed to replace fetch.py for ${name}: ${err2?.message}`);
7175
- }
7176
- }
7177
- function removeFile(filePath, ruleName, filename, logger) {
7178
- if (!(0, import_node_fs8.existsSync)(filePath)) return;
7179
- try {
7180
- (0, import_node_fs8.rmSync)(filePath);
7181
- logger.info(`migration: removed ${filename} for light rule: ${ruleName}`);
7182
- } catch (err2) {
7183
- logger.warn(`migration: failed to remove ${filename} for ${ruleName}: ${err2?.message}`);
7184
- }
7185
- }
7186
-
7187
7091
  // src/light-rules/pi-invoker.ts
7188
7092
  var import_agent_runtime = require("openclaw/plugin-sdk/agent-runtime");
7189
7093
  var DEFAULT_PROVIDER = "anthropic";
@@ -7365,7 +7269,7 @@ function resolveUpdateChannel(params) {
7365
7269
  }
7366
7270
 
7367
7271
  // src/update/index.ts
7368
- var import_node_path9 = require("path");
7272
+ var import_node_path8 = require("path");
7369
7273
 
7370
7274
  // src/update/checker.ts
7371
7275
  function parseSemver(v) {
@@ -7467,8 +7371,8 @@ var UpdateChecker = class {
7467
7371
  };
7468
7372
 
7469
7373
  // src/update/executor.ts
7470
- var import_node_fs9 = require("fs");
7471
- var import_node_path8 = require("path");
7374
+ var import_node_fs8 = require("fs");
7375
+ var import_node_path7 = require("path");
7472
7376
  var import_node_os = require("os");
7473
7377
  var VERSION_PATTERN = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
7474
7378
  var BASE_URL = "https://artifact.yoooclaw.com/plugin";
@@ -7478,9 +7382,9 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
7478
7382
  }
7479
7383
  const tgzUrl = `${BASE_URL}/v${version}/yoooclaw-phone-notifications-${version}.tgz`;
7480
7384
  logger.info(`\u6267\u884C\u66F4\u65B0: ${tgzUrl} \u2192 ${targetDir}`);
7481
- const workDir = (0, import_node_fs9.mkdtempSync)((0, import_node_path8.join)((0, import_node_os.tmpdir)(), ".openclaw-plugin-update-"));
7482
- const tgzPath = (0, import_node_path8.join)(workDir, "plugin.tgz");
7483
- const stagingDir = (0, import_node_path8.join)(workDir, "staged");
7385
+ const workDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path7.join)((0, import_node_os.tmpdir)(), ".openclaw-plugin-update-"));
7386
+ const tgzPath = (0, import_node_path7.join)(workDir, "plugin.tgz");
7387
+ const stagingDir = (0, import_node_path7.join)(workDir, "staged");
7484
7388
  let backupDir = null;
7485
7389
  try {
7486
7390
  logger.info("\u4E0B\u8F7D\u63D2\u4EF6\u5305...");
@@ -7489,9 +7393,9 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
7489
7393
  return { success: false, message: `\u4E0B\u8F7D\u5931\u8D25 (HTTP ${response.status}): ${tgzUrl}` };
7490
7394
  }
7491
7395
  const buffer = Buffer.from(await response.arrayBuffer());
7492
- (0, import_node_fs9.writeFileSync)(tgzPath, buffer);
7396
+ (0, import_node_fs8.writeFileSync)(tgzPath, buffer);
7493
7397
  logger.info(`\u4E0B\u8F7D\u5B8C\u6210 (${buffer.length} bytes)`);
7494
- (0, import_node_fs9.mkdirSync)(stagingDir, { recursive: true });
7398
+ (0, import_node_fs8.mkdirSync)(stagingDir, { recursive: true });
7495
7399
  const tarResult = await runCommand(
7496
7400
  ["tar", "-xzf", tgzPath, "-C", stagingDir, "--strip-components=1"],
7497
7401
  { timeoutMs: 3e4 }
@@ -7500,14 +7404,14 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
7500
7404
  const err2 = tarResult.stderr || tarResult.stdout || "unknown error";
7501
7405
  return { success: false, message: `\u89E3\u538B\u5931\u8D25: ${err2}` };
7502
7406
  }
7503
- (0, import_node_fs9.mkdirSync)((0, import_node_path8.dirname)(targetDir), { recursive: true });
7407
+ (0, import_node_fs8.mkdirSync)((0, import_node_path7.dirname)(targetDir), { recursive: true });
7504
7408
  try {
7505
7409
  backupDir = `${targetDir}.bak.${Date.now()}`;
7506
- (0, import_node_fs9.renameSync)(targetDir, backupDir);
7410
+ (0, import_node_fs8.renameSync)(targetDir, backupDir);
7507
7411
  } catch {
7508
7412
  backupDir = null;
7509
7413
  }
7510
- (0, import_node_fs9.renameSync)(stagingDir, targetDir);
7414
+ (0, import_node_fs8.renameSync)(stagingDir, targetDir);
7511
7415
  try {
7512
7416
  await updateConfigRecord2(version, tgzUrl);
7513
7417
  } catch (err2) {
@@ -7515,18 +7419,18 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
7515
7419
  }
7516
7420
  if (backupDir) {
7517
7421
  try {
7518
- (0, import_node_fs9.rmSync)(backupDir, { force: true, recursive: true });
7422
+ (0, import_node_fs8.rmSync)(backupDir, { force: true, recursive: true });
7519
7423
  } catch {
7520
7424
  }
7521
7425
  }
7522
- const msg = `\u5DF2\u66F4\u65B0\u5230 ${version}\uFF0C\u8BF7\u91CD\u542F gateway \u751F\u6548`;
7426
+ const msg = `\u5DF2\u66F4\u65B0\u5230 ${version}`;
7523
7427
  logger.info(msg);
7524
- return { success: true, message: msg };
7428
+ return { success: true, message: msg, version };
7525
7429
  } catch (err2) {
7526
7430
  if (backupDir) {
7527
7431
  try {
7528
- (0, import_node_fs9.rmSync)(targetDir, { force: true, recursive: true });
7529
- (0, import_node_fs9.renameSync)(backupDir, targetDir);
7432
+ (0, import_node_fs8.rmSync)(targetDir, { force: true, recursive: true });
7433
+ (0, import_node_fs8.renameSync)(backupDir, targetDir);
7530
7434
  logger.info("\u5DF2\u56DE\u6EDA\u5230\u4E4B\u524D\u7248\u672C");
7531
7435
  } catch (rollbackErr) {
7532
7436
  logger.error(`\u56DE\u6EDA\u5931\u8D25: ${String(rollbackErr)}`);
@@ -7537,12 +7441,47 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
7537
7441
  return { success: false, message: errMsg };
7538
7442
  } finally {
7539
7443
  try {
7540
- (0, import_node_fs9.rmSync)(workDir, { force: true, recursive: true });
7444
+ (0, import_node_fs8.rmSync)(workDir, { force: true, recursive: true });
7541
7445
  } catch {
7542
7446
  }
7543
7447
  }
7544
7448
  }
7545
7449
 
7450
+ // src/update/restart.ts
7451
+ function scheduleGatewayRestart(logger, deps = {}) {
7452
+ try {
7453
+ const cfg = deps.loadConfig?.();
7454
+ if (cfg?.commands?.restart === false) {
7455
+ logger.warn("\u66F4\u65B0\u540E\u8DF3\u8FC7 gateway \u91CD\u542F: commands.restart=false");
7456
+ return { scheduled: false };
7457
+ }
7458
+ } catch (err2) {
7459
+ logger.warn(`\u66F4\u65B0\u540E\u68C0\u67E5 gateway \u91CD\u542F\u914D\u7F6E\u5931\u8D25: ${String(err2)}`);
7460
+ }
7461
+ const getListenerCount = deps.getListenerCount ?? ((signal) => process.listenerCount(signal));
7462
+ if (getListenerCount("SIGUSR1") < 1) {
7463
+ logger.warn("\u66F4\u65B0\u540E\u8DF3\u8FC7 gateway \u91CD\u542F: \u5F53\u524D\u8FDB\u7A0B\u672A\u6CE8\u518C SIGUSR1 \u76D1\u542C\u5668");
7464
+ return { scheduled: false };
7465
+ }
7466
+ const emitSignal = deps.emitSignal ?? ((signal) => process.emit(signal));
7467
+ const schedule = deps.schedule ?? ((task) => {
7468
+ setTimeout(task, 0);
7469
+ });
7470
+ schedule(() => {
7471
+ try {
7472
+ const accepted = emitSignal("SIGUSR1");
7473
+ if (accepted) {
7474
+ logger.info("\u66F4\u65B0\u5B8C\u6210\uFF0C\u5DF2\u89E6\u53D1 gateway SIGUSR1 \u91CD\u542F");
7475
+ } else {
7476
+ logger.warn("\u66F4\u65B0\u5B8C\u6210\uFF0C\u4F46 gateway SIGUSR1 \u4FE1\u53F7\u672A\u88AB\u5904\u7406");
7477
+ }
7478
+ } catch (err2) {
7479
+ logger.warn(`\u66F4\u65B0\u540E\u89E6\u53D1 gateway \u91CD\u542F\u5931\u8D25: ${String(err2)}`);
7480
+ }
7481
+ });
7482
+ return { scheduled: true };
7483
+ }
7484
+
7546
7485
  // src/update/index.ts
7547
7486
  var PLUGIN_ID = "phone-notifications";
7548
7487
  function resolveTargetDir(api) {
@@ -7552,7 +7491,7 @@ function resolveTargetDir(api) {
7552
7491
  if (installPath) return installPath;
7553
7492
  } catch {
7554
7493
  }
7555
- return (0, import_node_path9.join)(api.runtime.state.resolveStateDir(), "extensions", PLUGIN_ID);
7494
+ return (0, import_node_path8.join)(api.runtime.state.resolveStateDir(), "extensions", PLUGIN_ID);
7556
7495
  }
7557
7496
  async function updateConfigRecord(api, version, targetDir, tgzUrl) {
7558
7497
  const configApi = api.runtime.config;
@@ -7570,6 +7509,23 @@ async function updateConfigRecord(api, version, targetDir, tgzUrl) {
7570
7509
  };
7571
7510
  await configApi.writeConfigFile(cfg);
7572
7511
  }
7512
+ function finalizeUpdateResult(api, logger, result) {
7513
+ if (!result.success) {
7514
+ return result;
7515
+ }
7516
+ const restart = scheduleGatewayRestart(logger, {
7517
+ loadConfig: () => {
7518
+ const configApi = api.runtime.config;
7519
+ return configApi?.loadConfig?.();
7520
+ }
7521
+ });
7522
+ const version = result.version ?? "\u76EE\u6807\u7248\u672C";
7523
+ return {
7524
+ ...result,
7525
+ restartScheduled: restart.scheduled,
7526
+ message: restart.scheduled ? `\u5DF2\u66F4\u65B0\u5230 ${version}\uFF0C\u5DF2\u89E6\u53D1 gateway \u91CD\u542F` : `\u5DF2\u66F4\u65B0\u5230 ${version}\uFF0C\u8BF7\u624B\u52A8\u91CD\u542F gateway \u751F\u6548`
7527
+ };
7528
+ }
7573
7529
  function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast, externalUpdateNotifier) {
7574
7530
  if (config.enabled === false) {
7575
7531
  logger.info("\u81EA\u52A8\u66F4\u65B0\u5DF2\u7981\u7528 (autoUpdate.enabled = false)");
@@ -7601,7 +7557,7 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
7601
7557
  api.registerTool({
7602
7558
  name: "plugin-update",
7603
7559
  label: "Plugin Update",
7604
- description: "\u5C06 phone-notifications \u63D2\u4EF6\u66F4\u65B0\u5230\u6307\u5B9A\u7248\u672C\u3002\u4EC5\u5728\u7528\u6237\u660E\u786E\u540C\u610F\u66F4\u65B0\u540E\u8C03\u7528\u3002\u66F4\u65B0\u5B8C\u6210\u540E\u9700\u91CD\u542F gateway \u751F\u6548\u3002",
7560
+ description: "\u5C06 phone-notifications \u63D2\u4EF6\u66F4\u65B0\u5230\u6307\u5B9A\u7248\u672C\u3002\u4EC5\u5728\u7528\u6237\u660E\u786E\u540C\u610F\u66F4\u65B0\u540E\u8C03\u7528\u3002\u66F4\u65B0\u5B8C\u6210\u540E\u4F1A\u81EA\u52A8\u5C1D\u8BD5\u91CD\u542F gateway\uFF1B\u5982\u5BBF\u4E3B\u4E0D\u652F\u6301\uFF0C\u5219\u9700\u624B\u52A8\u91CD\u542F\u3002",
7605
7561
  parameters: {
7606
7562
  type: "object",
7607
7563
  required: ["version"],
@@ -7623,13 +7579,14 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
7623
7579
  targetDir,
7624
7580
  (v, url) => updateConfigRecord(api, v, targetDir, url)
7625
7581
  );
7626
- if (result.success) {
7582
+ const finalResult = finalizeUpdateResult(api, logger, result);
7583
+ if (finalResult.success) {
7627
7584
  pendingUpdate = null;
7628
7585
  externalUpdateNotifier?.clearPendingUpdate();
7629
7586
  }
7630
7587
  return {
7631
- content: [{ type: "text", text: result.message }],
7632
- details: result
7588
+ content: [{ type: "text", text: finalResult.message }],
7589
+ details: finalResult
7633
7590
  };
7634
7591
  }
7635
7592
  });
@@ -7651,16 +7608,20 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
7651
7608
  targetDir,
7652
7609
  (v, url) => updateConfigRecord(api, v, targetDir, url)
7653
7610
  );
7654
- if (result.success) {
7611
+ const finalResult = finalizeUpdateResult(api, logger, result);
7612
+ if (finalResult.success) {
7655
7613
  pendingUpdate = null;
7656
7614
  externalUpdateNotifier?.clearPendingUpdate();
7657
7615
  }
7658
- if (result.success) {
7659
- respond(true, { message: result.message });
7616
+ if (finalResult.success) {
7617
+ respond(true, {
7618
+ message: finalResult.message,
7619
+ restartScheduled: finalResult.restartScheduled === true
7620
+ });
7660
7621
  } else {
7661
7622
  respond(false, void 0, {
7662
7623
  code: "UPDATE_FAILED",
7663
- message: result.message
7624
+ message: finalResult.message
7664
7625
  });
7665
7626
  }
7666
7627
  });
@@ -7740,10 +7701,10 @@ function registerAutoUpdateLifecycle(deps) {
7740
7701
  }
7741
7702
 
7742
7703
  // src/plugin/cli.ts
7743
- var import_node_path17 = require("path");
7704
+ var import_node_path16 = require("path");
7744
7705
 
7745
7706
  // src/cli/auth.ts
7746
- var import_node_fs10 = require("fs");
7707
+ var import_node_fs9 = require("fs");
7747
7708
  init_credentials();
7748
7709
  function registerAuthCli(program) {
7749
7710
  const auth = program.command("auth").description("\u7528\u6237\u8BA4\u8BC1\u7BA1\u7406");
@@ -7779,12 +7740,12 @@ function registerAuthCli(program) {
7779
7740
  });
7780
7741
  auth.command("clear").description("\u6E05\u9664\u5DF2\u4FDD\u5B58\u7684\u8BA4\u8BC1\u4FE1\u606F").action(() => {
7781
7742
  const path2 = credentialsPath();
7782
- if ((0, import_node_fs10.existsSync)(path2)) {
7743
+ if ((0, import_node_fs9.existsSync)(path2)) {
7783
7744
  const creds = readCredentials();
7784
7745
  delete creds.apiKey;
7785
7746
  delete creds.token;
7786
7747
  if (Object.keys(creds).length === 0) {
7787
- (0, import_node_fs10.rmSync)(path2, { force: true });
7748
+ (0, import_node_fs9.rmSync)(path2, { force: true });
7788
7749
  } else {
7789
7750
  writeCredentials(creds);
7790
7751
  }
@@ -7916,23 +7877,23 @@ function registerNtfStats(ntf, ctx) {
7916
7877
  }
7917
7878
 
7918
7879
  // src/cli/ntf-sync.ts
7919
- var import_node_fs11 = require("fs");
7920
- var import_node_path10 = require("path");
7880
+ var import_node_fs10 = require("fs");
7881
+ var import_node_path9 = require("path");
7921
7882
  var SYNC_FETCH_LIMIT = 300;
7922
7883
  function checkpointPath(dir) {
7923
- return (0, import_node_path10.join)(dir, ".checkpoint.json");
7884
+ return (0, import_node_path9.join)(dir, ".checkpoint.json");
7924
7885
  }
7925
7886
  function readCheckpoint(dir) {
7926
7887
  const p = checkpointPath(dir);
7927
- if (!(0, import_node_fs11.existsSync)(p)) return {};
7888
+ if (!(0, import_node_fs10.existsSync)(p)) return {};
7928
7889
  try {
7929
- return JSON.parse((0, import_node_fs11.readFileSync)(p, "utf-8"));
7890
+ return JSON.parse((0, import_node_fs10.readFileSync)(p, "utf-8"));
7930
7891
  } catch {
7931
7892
  return {};
7932
7893
  }
7933
7894
  }
7934
7895
  function writeCheckpoint(dir, data) {
7935
- (0, import_node_fs11.writeFileSync)(checkpointPath(dir), JSON.stringify(data, null, 2), "utf-8");
7896
+ (0, import_node_fs10.writeFileSync)(checkpointPath(dir), JSON.stringify(data, null, 2), "utf-8");
7936
7897
  }
7937
7898
  function registerNtfSync(ntf, ctx) {
7938
7899
  const sync = ntf.command("sync").description("\u540C\u6B65\u901A\u77E5\u5230\u8BB0\u5FC6\u7CFB\u7EDF");
@@ -8025,8 +7986,8 @@ function registerNtfSync(ntf, ctx) {
8025
7986
  }
8026
7987
 
8027
7988
  // src/cli/ntf-monitor.ts
8028
- var import_node_fs12 = require("fs");
8029
- var import_node_path11 = require("path");
7989
+ var import_node_fs11 = require("fs");
7990
+ var import_node_path10 = require("path");
8030
7991
 
8031
7992
  // src/monitor/fetch-gen.ts
8032
7993
  function generateFetchPy(name, matchRules) {
@@ -8111,19 +8072,19 @@ function pyLiteral(value) {
8111
8072
  function tasksDir2(ctx) {
8112
8073
  const base = ctx.workspaceDir || ctx.stateDir;
8113
8074
  if (!base) throw new Error("workspaceDir and stateDir both unavailable");
8114
- return (0, import_node_path11.join)(base, "tasks");
8075
+ return (0, import_node_path10.join)(base, "tasks");
8115
8076
  }
8116
8077
  function readMeta2(taskDir) {
8117
- const metaPath = (0, import_node_path11.join)(taskDir, "meta.json");
8118
- if (!(0, import_node_fs12.existsSync)(metaPath)) return null;
8078
+ const metaPath = (0, import_node_path10.join)(taskDir, "meta.json");
8079
+ if (!(0, import_node_fs11.existsSync)(metaPath)) return null;
8119
8080
  try {
8120
- return JSON.parse((0, import_node_fs12.readFileSync)(metaPath, "utf-8"));
8081
+ return JSON.parse((0, import_node_fs11.readFileSync)(metaPath, "utf-8"));
8121
8082
  } catch {
8122
8083
  return null;
8123
8084
  }
8124
8085
  }
8125
8086
  function writeMeta2(taskDir, meta) {
8126
- (0, import_node_fs12.writeFileSync)((0, import_node_path11.join)(taskDir, "meta.json"), JSON.stringify(meta, null, 2), "utf-8");
8087
+ (0, import_node_fs11.writeFileSync)((0, import_node_path10.join)(taskDir, "meta.json"), JSON.stringify(meta, null, 2), "utf-8");
8127
8088
  }
8128
8089
  function generateReadme(name, description) {
8129
8090
  return `# Monitor Task: ${name}
@@ -8142,27 +8103,27 @@ function registerNtfMonitor(ntf, ctx) {
8142
8103
  const monitor = ntf.command("monitor").description("\u901A\u77E5\u76D1\u63A7\u4EFB\u52A1\u7BA1\u7406");
8143
8104
  monitor.command("list").description("\u5217\u51FA\u6240\u6709\u76D1\u63A7\u4EFB\u52A1").action(() => {
8144
8105
  const dir = tasksDir2(ctx);
8145
- if (!(0, import_node_fs12.existsSync)(dir)) {
8106
+ if (!(0, import_node_fs11.existsSync)(dir)) {
8146
8107
  output({ ok: true, tasks: [] });
8147
8108
  return;
8148
8109
  }
8149
8110
  const tasks = [];
8150
- for (const entry of (0, import_node_fs12.readdirSync)(dir, { withFileTypes: true })) {
8111
+ for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
8151
8112
  if (!entry.isDirectory()) continue;
8152
- const meta = readMeta2((0, import_node_path11.join)(dir, entry.name));
8113
+ const meta = readMeta2((0, import_node_path10.join)(dir, entry.name));
8153
8114
  if (meta) tasks.push(meta);
8154
8115
  }
8155
8116
  output({ ok: true, tasks });
8156
8117
  });
8157
8118
  monitor.command("show <name>").description("\u67E5\u770B\u76D1\u63A7\u4EFB\u52A1\u8BE6\u60C5").action((name) => {
8158
- const taskDir = (0, import_node_path11.join)(tasksDir2(ctx), name);
8119
+ const taskDir = (0, import_node_path10.join)(tasksDir2(ctx), name);
8159
8120
  const meta = readMeta2(taskDir);
8160
8121
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
8161
- const checkpointPath2 = (0, import_node_path11.join)(taskDir, "checkpoint.json");
8122
+ const checkpointPath2 = (0, import_node_path10.join)(taskDir, "checkpoint.json");
8162
8123
  let checkpoint = {};
8163
- if ((0, import_node_fs12.existsSync)(checkpointPath2)) {
8124
+ if ((0, import_node_fs11.existsSync)(checkpointPath2)) {
8164
8125
  try {
8165
- checkpoint = JSON.parse((0, import_node_fs12.readFileSync)(checkpointPath2, "utf-8"));
8126
+ checkpoint = JSON.parse((0, import_node_fs11.readFileSync)(checkpointPath2, "utf-8"));
8166
8127
  } catch {
8167
8128
  }
8168
8129
  }
@@ -8177,8 +8138,8 @@ function registerNtfMonitor(ntf, ctx) {
8177
8138
  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(
8178
8139
  (name, opts) => {
8179
8140
  const dir = tasksDir2(ctx);
8180
- const taskDir = (0, import_node_path11.join)(dir, name);
8181
- if ((0, import_node_fs12.existsSync)(taskDir)) {
8141
+ const taskDir = (0, import_node_path10.join)(dir, name);
8142
+ if ((0, import_node_fs11.existsSync)(taskDir)) {
8182
8143
  exitError("ALREADY_EXISTS", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u5DF2\u5B58\u5728`);
8183
8144
  }
8184
8145
  let matchRules;
@@ -8190,7 +8151,7 @@ function registerNtfMonitor(ntf, ctx) {
8190
8151
  "match-rules \u5FC5\u987B\u662F\u5408\u6CD5\u7684 JSON"
8191
8152
  );
8192
8153
  }
8193
- (0, import_node_fs12.mkdirSync)(taskDir, { recursive: true });
8154
+ (0, import_node_fs11.mkdirSync)(taskDir, { recursive: true });
8194
8155
  const meta = {
8195
8156
  name,
8196
8157
  description: opts.description,
@@ -8200,13 +8161,13 @@ function registerNtfMonitor(ntf, ctx) {
8200
8161
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
8201
8162
  };
8202
8163
  writeMeta2(taskDir, meta);
8203
- (0, import_node_fs12.writeFileSync)(
8204
- (0, import_node_path11.join)(taskDir, "fetch.py"),
8164
+ (0, import_node_fs11.writeFileSync)(
8165
+ (0, import_node_path10.join)(taskDir, "fetch.py"),
8205
8166
  generateFetchPy(name, matchRules),
8206
8167
  "utf-8"
8207
8168
  );
8208
- (0, import_node_fs12.writeFileSync)(
8209
- (0, import_node_path11.join)(taskDir, "README.md"),
8169
+ (0, import_node_fs11.writeFileSync)(
8170
+ (0, import_node_path10.join)(taskDir, "README.md"),
8210
8171
  generateReadme(name, opts.description),
8211
8172
  "utf-8"
8212
8173
  );
@@ -8234,8 +8195,8 @@ function registerNtfMonitor(ntf, ctx) {
8234
8195
  }
8235
8196
  );
8236
8197
  monitor.command("delete <name>").description("\u5220\u9664\u76D1\u63A7\u4EFB\u52A1").option("--yes", "\u8DF3\u8FC7\u786E\u8BA4").action((name, opts) => {
8237
- const taskDir = (0, import_node_path11.join)(tasksDir2(ctx), name);
8238
- if (!(0, import_node_fs12.existsSync)(taskDir)) {
8198
+ const taskDir = (0, import_node_path10.join)(tasksDir2(ctx), name);
8199
+ if (!(0, import_node_fs11.existsSync)(taskDir)) {
8239
8200
  exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
8240
8201
  }
8241
8202
  if (!opts.yes) {
@@ -8248,7 +8209,7 @@ function registerNtfMonitor(ntf, ctx) {
8248
8209
  });
8249
8210
  process.exit(1);
8250
8211
  }
8251
- (0, import_node_fs12.rmSync)(taskDir, { recursive: true, force: true });
8212
+ (0, import_node_fs11.rmSync)(taskDir, { recursive: true, force: true });
8252
8213
  output({
8253
8214
  ok: true,
8254
8215
  name,
@@ -8260,7 +8221,7 @@ function registerNtfMonitor(ntf, ctx) {
8260
8221
  });
8261
8222
  });
8262
8223
  monitor.command("enable <name>").description("\u542F\u7528\u76D1\u63A7\u4EFB\u52A1").action((name) => {
8263
- const taskDir = (0, import_node_path11.join)(tasksDir2(ctx), name);
8224
+ const taskDir = (0, import_node_path10.join)(tasksDir2(ctx), name);
8264
8225
  const meta = readMeta2(taskDir);
8265
8226
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
8266
8227
  meta.enabled = true;
@@ -8268,7 +8229,7 @@ function registerNtfMonitor(ntf, ctx) {
8268
8229
  output({ ok: true, name, enabled: true });
8269
8230
  });
8270
8231
  monitor.command("disable <name>").description("\u6682\u505C\u76D1\u63A7\u4EFB\u52A1").action((name) => {
8271
- const taskDir = (0, import_node_path11.join)(tasksDir2(ctx), name);
8232
+ const taskDir = (0, import_node_path10.join)(tasksDir2(ctx), name);
8272
8233
  const meta = readMeta2(taskDir);
8273
8234
  if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
8274
8235
  meta.enabled = false;
@@ -8312,9 +8273,9 @@ function registerLightSend(light) {
8312
8273
  }
8313
8274
 
8314
8275
  // src/cli/light-setup-tools.ts
8315
- var import_node_fs13 = require("fs");
8276
+ var import_node_fs12 = require("fs");
8316
8277
  var import_node_os2 = require("os");
8317
- var import_node_path12 = require("path");
8278
+ var import_node_path11 = require("path");
8318
8279
  function isObject(value) {
8319
8280
  return !!value && typeof value === "object" && !Array.isArray(value);
8320
8281
  }
@@ -8328,7 +8289,7 @@ function ensureArray(obj, key) {
8328
8289
  function resolveConfigPath2() {
8329
8290
  const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();
8330
8291
  if (fromEnv) return fromEnv;
8331
- return (0, import_node_path12.join)((0, import_node_os2.homedir)(), ".openclaw", "openclaw.json");
8292
+ return (0, import_node_path11.join)((0, import_node_os2.homedir)(), ".openclaw", "openclaw.json");
8332
8293
  }
8333
8294
  var LIGHT_TOOLS = [
8334
8295
  "light_control",
@@ -8375,12 +8336,12 @@ function upsertLightControlAlsoAllow(cfg) {
8375
8336
  function registerLightSetupTools(light) {
8376
8337
  light.command("setup").description("\u81EA\u52A8\u653E\u884C light_control\uFF08\u5199\u5165 tools.alsoAllow \u4E0E agents.main.tools.alsoAllow\uFF09").action(() => {
8377
8338
  const configPath = resolveConfigPath2();
8378
- if (!(0, import_node_fs13.existsSync)(configPath)) {
8339
+ if (!(0, import_node_fs12.existsSync)(configPath)) {
8379
8340
  exitError("CONFIG_NOT_FOUND", `\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6: ${configPath}`);
8380
8341
  }
8381
8342
  let cfg = {};
8382
8343
  try {
8383
- const raw = (0, import_node_fs13.readFileSync)(configPath, "utf-8");
8344
+ const raw = (0, import_node_fs12.readFileSync)(configPath, "utf-8");
8384
8345
  const parsed = JSON.parse(raw);
8385
8346
  if (isObject(parsed)) cfg = parsed;
8386
8347
  } catch (err2) {
@@ -8388,8 +8349,8 @@ function registerLightSetupTools(light) {
8388
8349
  }
8389
8350
  const result = upsertLightControlAlsoAllow(cfg);
8390
8351
  try {
8391
- (0, import_node_fs13.mkdirSync)((0, import_node_path12.dirname)(configPath), { recursive: true });
8392
- (0, import_node_fs13.writeFileSync)(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
8352
+ (0, import_node_fs12.mkdirSync)((0, import_node_path11.dirname)(configPath), { recursive: true });
8353
+ (0, import_node_fs12.writeFileSync)(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
8393
8354
  } catch (err2) {
8394
8355
  exitError("WRITE_FAILED", `\u5199\u5165\u914D\u7F6E\u5931\u8D25: ${err2?.message ?? String(err2)}`);
8395
8356
  }
@@ -8407,17 +8368,17 @@ function registerLightSetupTools(light) {
8407
8368
  }
8408
8369
 
8409
8370
  // src/cli/tunnel-status.ts
8410
- var import_node_fs14 = require("fs");
8411
- var import_node_path13 = require("path");
8371
+ var import_node_fs13 = require("fs");
8372
+ var import_node_path12 = require("path");
8412
8373
  init_credentials();
8413
8374
  init_env();
8414
- var STATUS_REL_PATH = (0, import_node_path13.join)("plugins", "phone-notifications", "tunnel-status.json");
8375
+ var STATUS_REL_PATH = (0, import_node_path12.join)("plugins", "phone-notifications", "tunnel-status.json");
8415
8376
  function readTunnelStatus(ctx) {
8416
8377
  if (!ctx.stateDir) return null;
8417
- const filePath = (0, import_node_path13.join)(ctx.stateDir, STATUS_REL_PATH);
8418
- if (!(0, import_node_fs14.existsSync)(filePath)) return null;
8378
+ const filePath = (0, import_node_path12.join)(ctx.stateDir, STATUS_REL_PATH);
8379
+ if (!(0, import_node_fs13.existsSync)(filePath)) return null;
8419
8380
  try {
8420
- return JSON.parse((0, import_node_fs14.readFileSync)(filePath, "utf-8"));
8381
+ return JSON.parse((0, import_node_fs13.readFileSync)(filePath, "utf-8"));
8421
8382
  } catch {
8422
8383
  return null;
8423
8384
  }
@@ -8485,24 +8446,24 @@ function registerNtfStoragePath(ntf, ctx) {
8485
8446
  }
8486
8447
 
8487
8448
  // src/cli/log-search.ts
8488
- var import_node_fs15 = require("fs");
8489
- var import_node_path14 = require("path");
8449
+ var import_node_fs14 = require("fs");
8450
+ var import_node_path13 = require("path");
8490
8451
  function resolveLogsDir(ctx) {
8491
8452
  if (ctx.stateDir) {
8492
- const dir = (0, import_node_path14.join)(
8453
+ const dir = (0, import_node_path13.join)(
8493
8454
  ctx.stateDir,
8494
8455
  "plugins",
8495
8456
  "phone-notifications",
8496
8457
  "logs"
8497
8458
  );
8498
- if ((0, import_node_fs15.existsSync)(dir)) return dir;
8459
+ if ((0, import_node_fs14.existsSync)(dir)) return dir;
8499
8460
  }
8500
8461
  return null;
8501
8462
  }
8502
8463
  function listLogDateKeys(dir) {
8503
8464
  const pattern = /^(\d{4}-\d{2}-\d{2})\.log$/;
8504
8465
  const keys = [];
8505
- for (const entry of (0, import_node_fs15.readdirSync)(dir, { withFileTypes: true })) {
8466
+ for (const entry of (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true })) {
8506
8467
  if (!entry.isFile()) continue;
8507
8468
  const m = pattern.exec(entry.name);
8508
8469
  if (m) keys.push(m[1]);
@@ -8510,9 +8471,9 @@ function listLogDateKeys(dir) {
8510
8471
  return keys.sort().reverse();
8511
8472
  }
8512
8473
  function collectLogLines(dir, dateKey, keyword, limit, collected) {
8513
- const filePath = (0, import_node_path14.join)(dir, `${dateKey}.log`);
8514
- if (!(0, import_node_fs15.existsSync)(filePath)) return;
8515
- const content = (0, import_node_fs15.readFileSync)(filePath, "utf-8");
8474
+ const filePath = (0, import_node_path13.join)(dir, `${dateKey}.log`);
8475
+ if (!(0, import_node_fs14.existsSync)(filePath)) return;
8476
+ const content = (0, import_node_fs14.readFileSync)(filePath, "utf-8");
8516
8477
  const lowerKeyword = keyword?.toLowerCase();
8517
8478
  for (const line of content.split("\n")) {
8518
8479
  if (collected.length >= limit) return;
@@ -8579,12 +8540,12 @@ function registerEnvCli(ntf) {
8579
8540
  }
8580
8541
 
8581
8542
  // src/cli/doctor.ts
8582
- var import_node_fs19 = require("fs");
8543
+ var import_node_fs18 = require("fs");
8583
8544
  var import_node_readline = require("readline");
8584
8545
  init_host();
8585
8546
 
8586
8547
  // src/cli/doctor/check-dangerous-flags.ts
8587
- var import_node_fs16 = require("fs");
8548
+ var import_node_fs15 = require("fs");
8588
8549
  function isObject2(v) {
8589
8550
  return !!v && typeof v === "object" && !Array.isArray(v);
8590
8551
  }
@@ -8601,13 +8562,13 @@ var checkDangerousFlags = ({ cfg, configPath }) => {
8601
8562
  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",
8602
8563
  fixDescription: "\u8BBE\u4E3A false",
8603
8564
  fix: () => {
8604
- const raw = (0, import_node_fs16.readFileSync)(configPath, "utf-8");
8565
+ const raw = (0, import_node_fs15.readFileSync)(configPath, "utf-8");
8605
8566
  const config = JSON.parse(raw);
8606
8567
  const gw = config.gateway;
8607
8568
  const cui = gw.controlUi;
8608
8569
  cui.dangerouslyDisableDeviceAuth = false;
8609
- (0, import_node_fs16.copyFileSync)(configPath, configPath + ".bak");
8610
- (0, import_node_fs16.writeFileSync)(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
8570
+ (0, import_node_fs15.copyFileSync)(configPath, configPath + ".bak");
8571
+ (0, import_node_fs15.writeFileSync)(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
8611
8572
  }
8612
8573
  };
8613
8574
  };
@@ -8655,11 +8616,11 @@ function warnEmpty() {
8655
8616
  }
8656
8617
 
8657
8618
  // src/cli/doctor/check-state-dir-perms.ts
8658
- var import_node_fs17 = require("fs");
8619
+ var import_node_fs16 = require("fs");
8659
8620
  var checkStateDirPerms = ({ stateDir }) => {
8660
8621
  let mode;
8661
8622
  try {
8662
- mode = (0, import_node_fs17.statSync)(stateDir).mode;
8623
+ mode = (0, import_node_fs16.statSync)(stateDir).mode;
8663
8624
  } catch {
8664
8625
  return null;
8665
8626
  }
@@ -8673,7 +8634,7 @@ var checkStateDirPerms = ({ stateDir }) => {
8673
8634
  detail: "\u5176\u4ED6\u7528\u6237\u53EF\u4EE5\u8BFB\u53D6\u8BE5\u76EE\u5F55\u4E0B\u7684\u51ED\u8BC1\u548C\u914D\u7F6E\u6587\u4EF6\u3002",
8674
8635
  fixDescription: "chmod 700 " + stateDir,
8675
8636
  fix: () => {
8676
- (0, import_node_fs17.chmodSync)(stateDir, 448);
8637
+ (0, import_node_fs16.chmodSync)(stateDir, 448);
8677
8638
  }
8678
8639
  };
8679
8640
  };
@@ -8728,16 +8689,16 @@ var checkCredentials = () => {
8728
8689
  };
8729
8690
 
8730
8691
  // src/cli/doctor/check-tunnel.ts
8731
- var import_node_fs18 = require("fs");
8732
- var import_node_path15 = require("path");
8733
- var STATUS_REL_PATH2 = (0, import_node_path15.join)(
8692
+ var import_node_fs17 = require("fs");
8693
+ var import_node_path14 = require("path");
8694
+ var STATUS_REL_PATH2 = (0, import_node_path14.join)(
8734
8695
  "plugins",
8735
8696
  "phone-notifications",
8736
8697
  "tunnel-status.json"
8737
8698
  );
8738
8699
  var checkTunnel = ({ stateDir }) => {
8739
- const filePath = (0, import_node_path15.join)(stateDir, STATUS_REL_PATH2);
8740
- if (!(0, import_node_fs18.existsSync)(filePath)) {
8700
+ const filePath = (0, import_node_path14.join)(stateDir, STATUS_REL_PATH2);
8701
+ if (!(0, import_node_fs17.existsSync)(filePath)) {
8741
8702
  return {
8742
8703
  id: "tunnel",
8743
8704
  severity: "warn",
@@ -8749,7 +8710,7 @@ var checkTunnel = ({ stateDir }) => {
8749
8710
  }
8750
8711
  let status;
8751
8712
  try {
8752
- status = JSON.parse((0, import_node_fs18.readFileSync)(filePath, "utf-8"));
8713
+ status = JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
8753
8714
  } catch {
8754
8715
  return {
8755
8716
  id: "tunnel",
@@ -8842,9 +8803,9 @@ function isObject5(v) {
8842
8803
  return !!v && typeof v === "object" && !Array.isArray(v);
8843
8804
  }
8844
8805
  function readConfig(configPath) {
8845
- if (!(0, import_node_fs19.existsSync)(configPath)) return {};
8806
+ if (!(0, import_node_fs18.existsSync)(configPath)) return {};
8846
8807
  try {
8847
- const parsed = JSON.parse((0, import_node_fs19.readFileSync)(configPath, "utf-8"));
8808
+ const parsed = JSON.parse((0, import_node_fs18.readFileSync)(configPath, "utf-8"));
8848
8809
  return isObject5(parsed) ? parsed : {};
8849
8810
  } catch {
8850
8811
  return {};
@@ -9045,7 +9006,7 @@ function registerRecStoragePath(rec, ctx) {
9045
9006
 
9046
9007
  // src/cli/rec-setup.ts
9047
9008
  var import_node_readline2 = require("readline");
9048
- var import_node_fs20 = require("fs");
9009
+ var import_node_fs19 = require("fs");
9049
9010
  function ask(rl, question) {
9050
9011
  return new Promise((resolve) => rl.question(question, resolve));
9051
9012
  }
@@ -9131,9 +9092,9 @@ async function setupLocal(rl) {
9131
9092
  function registerRecSetup(rec, ctx) {
9132
9093
  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 () => {
9133
9094
  const configPath = resolveAsrConfigPath(ctx);
9134
- if ((0, import_node_fs20.existsSync)(configPath)) {
9095
+ if ((0, import_node_fs19.existsSync)(configPath)) {
9135
9096
  try {
9136
- const existing = JSON.parse((0, import_node_fs20.readFileSync)(configPath, "utf-8"));
9097
+ const existing = JSON.parse((0, import_node_fs19.readFileSync)(configPath, "utf-8"));
9137
9098
  process.stderr.write(`\u5F53\u524D\u5DF2\u6709\u914D\u7F6E\uFF1Amode = ${existing.mode}`);
9138
9099
  if (existing.updatedAt) process.stderr.write(`\uFF0C\u66F4\u65B0\u4E8E ${existing.updatedAt}`);
9139
9100
  process.stderr.write("\n");
@@ -9146,7 +9107,7 @@ function registerRecSetup(rec, ctx) {
9146
9107
  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"]);
9147
9108
  const config = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);
9148
9109
  const stored = { ...config, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
9149
- (0, import_node_fs20.writeFileSync)(configPath, JSON.stringify(stored, null, 2), "utf-8");
9110
+ (0, import_node_fs19.writeFileSync)(configPath, JSON.stringify(stored, null, 2), "utf-8");
9150
9111
  process.stderr.write(`
9151
9112
  \u2713 \u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230 ${configPath}
9152
9113
 
@@ -9160,8 +9121,8 @@ function registerRecSetup(rec, ctx) {
9160
9121
 
9161
9122
  // src/cli/update.ts
9162
9123
  var import_node_child_process = require("child_process");
9163
- var import_node_fs21 = require("fs");
9164
- var import_node_path16 = require("path");
9124
+ var import_node_fs20 = require("fs");
9125
+ var import_node_path15 = require("path");
9165
9126
  var import_node_os3 = __toESM(require("os"), 1);
9166
9127
  init_host();
9167
9128
  var BASE_URL2 = "https://artifact.yoooclaw.com/plugin";
@@ -9220,9 +9181,9 @@ async function runUpdate(ctx, opts) {
9220
9181
  `);
9221
9182
  process.exit(1);
9222
9183
  }
9223
- const tmpScript = (0, import_node_path16.join)(import_node_os3.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
9184
+ const tmpScript = (0, import_node_path15.join)(import_node_os3.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
9224
9185
  try {
9225
- (0, import_node_fs21.writeFileSync)(tmpScript, installScript, "utf-8");
9186
+ (0, import_node_fs20.writeFileSync)(tmpScript, installScript, "utf-8");
9226
9187
  } catch (err2) {
9227
9188
  const msg = `\u5199\u5165\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${err2?.message ?? String(err2)}`;
9228
9189
  if (json) {
@@ -9240,7 +9201,7 @@ async function runUpdate(ctx, opts) {
9240
9201
  { stdio: "inherit" }
9241
9202
  );
9242
9203
  try {
9243
- (0, import_node_fs21.unlinkSync)(tmpScript);
9204
+ (0, import_node_fs20.unlinkSync)(tmpScript);
9244
9205
  } catch {
9245
9206
  }
9246
9207
  if (result.error) {
@@ -9304,10 +9265,10 @@ function inferOpenClawRootDir(workspaceDir) {
9304
9265
  if (!workspaceDir) {
9305
9266
  return void 0;
9306
9267
  }
9307
- if ((0, import_node_path17.basename)(workspaceDir) !== "workspace") {
9268
+ if ((0, import_node_path16.basename)(workspaceDir) !== "workspace") {
9308
9269
  return void 0;
9309
9270
  }
9310
- return (0, import_node_path17.dirname)(workspaceDir);
9271
+ return (0, import_node_path16.dirname)(workspaceDir);
9311
9272
  }
9312
9273
  function registerPluginCli(api, params) {
9313
9274
  const { logger, openclawDir } = params;
@@ -9558,12 +9519,12 @@ function registerLightControlTool(api, logger) {
9558
9519
  }
9559
9520
 
9560
9521
  // src/plugin/lifecycle.ts
9561
- var import_node_fs31 = require("fs");
9522
+ var import_node_fs30 = require("fs");
9562
9523
  init_host();
9563
9524
 
9564
9525
  // src/notification/app-name-map.ts
9565
- var import_node_fs22 = require("fs");
9566
- var import_node_path18 = require("path");
9526
+ var import_node_fs21 = require("fs");
9527
+ var import_node_path17 = require("path");
9567
9528
  init_credentials();
9568
9529
  init_env();
9569
9530
  var PLUGIN_STATE_DIR = "phone-notifications";
@@ -9584,7 +9545,7 @@ function isAppNameMapApiResponse(v) {
9584
9545
  );
9585
9546
  }
9586
9547
  function getCachePath(stateDir) {
9587
- return (0, import_node_path18.join)(stateDir, "plugins", PLUGIN_STATE_DIR, CACHE_FILE);
9548
+ return (0, import_node_path17.join)(stateDir, "plugins", PLUGIN_STATE_DIR, CACHE_FILE);
9588
9549
  }
9589
9550
  function createAppNameMapProvider(opts) {
9590
9551
  const { stateDir, logger } = opts;
@@ -9596,9 +9557,9 @@ function createAppNameMapProvider(opts) {
9596
9557
  let inFlightFetch = null;
9597
9558
  function loadFromDisk() {
9598
9559
  const path2 = getCachePath(stateDir);
9599
- if (!(0, import_node_fs22.existsSync)(path2)) return;
9560
+ if (!(0, import_node_fs21.existsSync)(path2)) return;
9600
9561
  try {
9601
- const raw = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf-8"));
9562
+ const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf-8"));
9602
9563
  if (!isRecordOfStrings(raw)) return;
9603
9564
  map.clear();
9604
9565
  for (const [k, v] of Object.entries(raw)) map.set(k, v);
@@ -9642,10 +9603,10 @@ function createAppNameMapProvider(opts) {
9642
9603
  logger.warn("[app-name-map] refresh succeeded but got 0 entries");
9643
9604
  return;
9644
9605
  }
9645
- const dir = (0, import_node_path18.join)(stateDir, "plugins", PLUGIN_STATE_DIR);
9646
- (0, import_node_fs22.mkdirSync)(dir, { recursive: true });
9606
+ const dir = (0, import_node_path17.join)(stateDir, "plugins", PLUGIN_STATE_DIR);
9607
+ (0, import_node_fs21.mkdirSync)(dir, { recursive: true });
9647
9608
  const cachePath = getCachePath(stateDir);
9648
- (0, import_node_fs22.writeFileSync)(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), "utf-8");
9609
+ (0, import_node_fs21.writeFileSync)(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), "utf-8");
9649
9610
  logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);
9650
9611
  } catch (e) {
9651
9612
  const message = e instanceof Error ? e.message : String(e);
@@ -9689,19 +9650,19 @@ function createAppNameMapProvider(opts) {
9689
9650
  }
9690
9651
 
9691
9652
  // src/notification/storage.ts
9692
- var import_node_fs23 = require("fs");
9653
+ var import_node_fs22 = require("fs");
9693
9654
  var import_node_crypto2 = require("crypto");
9694
- var import_node_path19 = require("path");
9655
+ var import_node_path18 = require("path");
9695
9656
  var NOTIFICATION_DIR_NAME = "notifications";
9696
9657
  var ID_INDEX_DIR_NAME = ".ids";
9697
9658
  var CONTENT_KEY_INDEX_DIR_NAME = ".keys";
9698
9659
  function getStateFallbackNotificationDir(stateDir) {
9699
- return (0, import_node_path19.join)(stateDir, "plugins", "phone-notifications", NOTIFICATION_DIR_NAME);
9660
+ return (0, import_node_path18.join)(stateDir, "plugins", "phone-notifications", NOTIFICATION_DIR_NAME);
9700
9661
  }
9701
9662
  function ensureWritableDirectory(dir) {
9702
9663
  try {
9703
- (0, import_node_fs23.mkdirSync)(dir, { recursive: true });
9704
- (0, import_node_fs23.accessSync)(dir, import_node_fs23.constants.R_OK | import_node_fs23.constants.W_OK);
9664
+ (0, import_node_fs22.mkdirSync)(dir, { recursive: true });
9665
+ (0, import_node_fs22.accessSync)(dir, import_node_fs22.constants.R_OK | import_node_fs22.constants.W_OK);
9705
9666
  return true;
9706
9667
  } catch {
9707
9668
  return false;
@@ -9714,7 +9675,7 @@ function resolveNotificationStorageDir(ctx, logger) {
9714
9675
  return stateNotifDir;
9715
9676
  }
9716
9677
  if (ctx.workspaceDir) {
9717
- const workspaceDir = (0, import_node_path19.join)(ctx.workspaceDir, NOTIFICATION_DIR_NAME);
9678
+ const workspaceDir = (0, import_node_path18.join)(ctx.workspaceDir, NOTIFICATION_DIR_NAME);
9718
9679
  if (ensureWritableDirectory(workspaceDir)) {
9719
9680
  logger.warn(
9720
9681
  `stateDir \u4E0D\u53EF\u7528\uFF0C\u901A\u77E5\u5DF2\u56DE\u9000\u5230 workspace \u8DEF\u5F84: ${workspaceDir}`
@@ -9729,8 +9690,8 @@ var NotificationStorage = class {
9729
9690
  this.config = config;
9730
9691
  this.logger = logger;
9731
9692
  this.dir = dir;
9732
- this.idIndexDir = (0, import_node_path19.join)(dir, ID_INDEX_DIR_NAME);
9733
- this.contentKeyIndexDir = (0, import_node_path19.join)(dir, CONTENT_KEY_INDEX_DIR_NAME);
9693
+ this.idIndexDir = (0, import_node_path18.join)(dir, ID_INDEX_DIR_NAME);
9694
+ this.contentKeyIndexDir = (0, import_node_path18.join)(dir, CONTENT_KEY_INDEX_DIR_NAME);
9734
9695
  this.resolveDisplayName = resolveDisplayName;
9735
9696
  }
9736
9697
  dir;
@@ -9741,10 +9702,10 @@ var NotificationStorage = class {
9741
9702
  dateWriteChains = /* @__PURE__ */ new Map();
9742
9703
  resolveDisplayName;
9743
9704
  async init() {
9744
- (0, import_node_fs23.mkdirSync)(this.dir, { recursive: true });
9745
- (0, import_node_fs23.mkdirSync)(this.idIndexDir, { recursive: true });
9746
- (0, import_node_fs23.rmSync)(this.contentKeyIndexDir, { recursive: true, force: true });
9747
- (0, import_node_fs23.mkdirSync)(this.contentKeyIndexDir, { recursive: true });
9705
+ (0, import_node_fs22.mkdirSync)(this.dir, { recursive: true });
9706
+ (0, import_node_fs22.mkdirSync)(this.idIndexDir, { recursive: true });
9707
+ (0, import_node_fs22.rmSync)(this.contentKeyIndexDir, { recursive: true, force: true });
9708
+ (0, import_node_fs22.mkdirSync)(this.contentKeyIndexDir, { recursive: true });
9748
9709
  }
9749
9710
  async ingest(items) {
9750
9711
  const result = {
@@ -9783,7 +9744,7 @@ var NotificationStorage = class {
9783
9744
  return { kind: "invalid" };
9784
9745
  }
9785
9746
  const dateKey = this.formatDate(ts);
9786
- const filePath = (0, import_node_path19.join)(this.dir, `${dateKey}.json`);
9747
+ const filePath = (0, import_node_path18.join)(this.dir, `${dateKey}.json`);
9787
9748
  const normalizedId = typeof n.id === "string" ? n.id.trim() : "";
9788
9749
  const entry = this.buildStoredNotification(n);
9789
9750
  return this.withDateWriteLock(dateKey, async () => {
@@ -9800,7 +9761,7 @@ var NotificationStorage = class {
9800
9761
  };
9801
9762
  const arr = this.readStoredNotifications(filePath);
9802
9763
  arr.push(storedEntry);
9803
- (0, import_node_fs23.writeFileSync)(filePath, JSON.stringify(arr, null, 2), "utf-8");
9764
+ (0, import_node_fs22.writeFileSync)(filePath, JSON.stringify(arr, null, 2), "utf-8");
9804
9765
  if (normalizedId) {
9805
9766
  this.recordNotificationId(dateKey, normalizedId);
9806
9767
  }
@@ -9837,7 +9798,7 @@ var NotificationStorage = class {
9837
9798
  return `${year}-${month}-${day}`;
9838
9799
  }
9839
9800
  getIdIndexPath(dateKey) {
9840
- return (0, import_node_path19.join)(this.idIndexDir, `${dateKey}.ids`);
9801
+ return (0, import_node_path18.join)(this.idIndexDir, `${dateKey}.ids`);
9841
9802
  }
9842
9803
  getIdSet(dateKey) {
9843
9804
  const cached = this.idCache.get(dateKey);
@@ -9846,8 +9807,8 @@ var NotificationStorage = class {
9846
9807
  }
9847
9808
  const idPath = this.getIdIndexPath(dateKey);
9848
9809
  const ids = /* @__PURE__ */ new Set();
9849
- if ((0, import_node_fs23.existsSync)(idPath)) {
9850
- const lines = (0, import_node_fs23.readFileSync)(idPath, "utf-8").split(/\r?\n/);
9810
+ if ((0, import_node_fs22.existsSync)(idPath)) {
9811
+ const lines = (0, import_node_fs22.readFileSync)(idPath, "utf-8").split(/\r?\n/);
9851
9812
  for (const line of lines) {
9852
9813
  const id = line.trim();
9853
9814
  if (id) {
@@ -9862,7 +9823,7 @@ var NotificationStorage = class {
9862
9823
  return this.getIdSet(dateKey).has(id);
9863
9824
  }
9864
9825
  getContentKeyIndexPath(dateKey) {
9865
- return (0, import_node_path19.join)(this.contentKeyIndexDir, `${dateKey}.keys`);
9826
+ return (0, import_node_path18.join)(this.contentKeyIndexDir, `${dateKey}.keys`);
9866
9827
  }
9867
9828
  getContentKeySet(dateKey, filePath) {
9868
9829
  const cached = this.contentKeyCache.get(dateKey);
@@ -9871,16 +9832,16 @@ var NotificationStorage = class {
9871
9832
  }
9872
9833
  const keyPath = this.getContentKeyIndexPath(dateKey);
9873
9834
  const keys = /* @__PURE__ */ new Set();
9874
- if ((0, import_node_fs23.existsSync)(filePath)) {
9835
+ if ((0, import_node_fs22.existsSync)(filePath)) {
9875
9836
  for (const item of this.readStoredNotifications(filePath)) {
9876
9837
  keys.add(this.buildNotificationContentKey(item));
9877
9838
  }
9878
9839
  }
9879
9840
  if (keys.size > 0) {
9880
- (0, import_node_fs23.writeFileSync)(keyPath, `${Array.from(keys).join("\n")}
9841
+ (0, import_node_fs22.writeFileSync)(keyPath, `${Array.from(keys).join("\n")}
9881
9842
  `, "utf-8");
9882
- } else if ((0, import_node_fs23.existsSync)(keyPath)) {
9883
- (0, import_node_fs23.rmSync)(keyPath, { force: true });
9843
+ } else if ((0, import_node_fs22.existsSync)(keyPath)) {
9844
+ (0, import_node_fs22.rmSync)(keyPath, { force: true });
9884
9845
  }
9885
9846
  this.contentKeyCache.set(dateKey, keys);
9886
9847
  return keys;
@@ -9895,7 +9856,7 @@ var NotificationStorage = class {
9895
9856
  if (ids.has(id)) {
9896
9857
  return;
9897
9858
  }
9898
- (0, import_node_fs23.appendFileSync)(this.getIdIndexPath(dateKey), `${id}
9859
+ (0, import_node_fs22.appendFileSync)(this.getIdIndexPath(dateKey), `${id}
9899
9860
  `, "utf-8");
9900
9861
  ids.add(id);
9901
9862
  }
@@ -9905,7 +9866,7 @@ var NotificationStorage = class {
9905
9866
  if (keys.has(key)) {
9906
9867
  return;
9907
9868
  }
9908
- (0, import_node_fs23.appendFileSync)(this.getContentKeyIndexPath(dateKey), `${key}
9869
+ (0, import_node_fs22.appendFileSync)(this.getContentKeyIndexPath(dateKey), `${key}
9909
9870
  `, "utf-8");
9910
9871
  keys.add(key);
9911
9872
  }
@@ -9913,11 +9874,11 @@ var NotificationStorage = class {
9913
9874
  return (0, import_node_crypto2.createHash)("sha256").update(entry.appName).update("").update(entry.title).update("").update(entry.content).update("").update(entry.timestamp).digest("hex");
9914
9875
  }
9915
9876
  readStoredNotifications(filePath) {
9916
- if (!(0, import_node_fs23.existsSync)(filePath)) {
9877
+ if (!(0, import_node_fs22.existsSync)(filePath)) {
9917
9878
  return [];
9918
9879
  }
9919
9880
  try {
9920
- const parsed = JSON.parse((0, import_node_fs23.readFileSync)(filePath, "utf-8"));
9881
+ const parsed = JSON.parse((0, import_node_fs22.readFileSync)(filePath, "utf-8"));
9921
9882
  return Array.isArray(parsed) ? parsed : [];
9922
9883
  } catch {
9923
9884
  return [];
@@ -9957,14 +9918,14 @@ var NotificationStorage = class {
9957
9918
  const dateFilePattern = /^(\d{4}-\d{2}-\d{2})\.(json|md)$/;
9958
9919
  const dateDirPattern = /^\d{4}-\d{2}-\d{2}$/;
9959
9920
  try {
9960
- for (const entry of (0, import_node_fs23.readdirSync)(this.dir, { withFileTypes: true })) {
9921
+ for (const entry of (0, import_node_fs22.readdirSync)(this.dir, { withFileTypes: true })) {
9961
9922
  if (entry.isFile()) {
9962
9923
  const match = dateFilePattern.exec(entry.name);
9963
9924
  if (match && match[1] < cutoffDate) {
9964
- (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.name), { force: true });
9925
+ (0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, entry.name), { force: true });
9965
9926
  }
9966
9927
  } else if (entry.isDirectory() && dateDirPattern.test(entry.name) && entry.name < cutoffDate) {
9967
- (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.name), { recursive: true, force: true });
9928
+ (0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, entry.name), { recursive: true, force: true });
9968
9929
  }
9969
9930
  }
9970
9931
  } catch {
@@ -9973,11 +9934,11 @@ var NotificationStorage = class {
9973
9934
  /** Remove expired .ids index files */
9974
9935
  pruneIdIndex(cutoffDate) {
9975
9936
  try {
9976
- for (const entry of (0, import_node_fs23.readdirSync)(this.idIndexDir, { withFileTypes: true })) {
9937
+ for (const entry of (0, import_node_fs22.readdirSync)(this.idIndexDir, { withFileTypes: true })) {
9977
9938
  if (!entry.isFile()) continue;
9978
9939
  const match = /^(\d{4}-\d{2}-\d{2})\.ids$/.exec(entry.name);
9979
9940
  if (match && match[1] < cutoffDate) {
9980
- (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.idIndexDir, entry.name), { force: true });
9941
+ (0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.idIndexDir, entry.name), { force: true });
9981
9942
  this.idCache.delete(match[1]);
9982
9943
  }
9983
9944
  }
@@ -9986,11 +9947,11 @@ var NotificationStorage = class {
9986
9947
  }
9987
9948
  pruneContentKeyIndex(cutoffDate) {
9988
9949
  try {
9989
- for (const entry of (0, import_node_fs23.readdirSync)(this.contentKeyIndexDir, { withFileTypes: true })) {
9950
+ for (const entry of (0, import_node_fs22.readdirSync)(this.contentKeyIndexDir, { withFileTypes: true })) {
9990
9951
  if (!entry.isFile()) continue;
9991
9952
  const match = /^(\d{4}-\d{2}-\d{2})\.keys$/.exec(entry.name);
9992
9953
  if (match && match[1] < cutoffDate) {
9993
- (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.contentKeyIndexDir, entry.name), { force: true });
9954
+ (0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.contentKeyIndexDir, entry.name), { force: true });
9994
9955
  this.contentKeyCache.delete(match[1]);
9995
9956
  }
9996
9957
  }
@@ -10005,8 +9966,8 @@ var NotificationStorage = class {
10005
9966
  };
10006
9967
 
10007
9968
  // src/recording/storage.ts
10008
- var import_node_fs24 = require("fs");
10009
- var import_node_path20 = require("path");
9969
+ var import_node_fs23 = require("fs");
9970
+ var import_node_path19 = require("path");
10010
9971
 
10011
9972
  // src/recording/state-machine.ts
10012
9973
  var VALID_TRANSITIONS = /* @__PURE__ */ new Map([
@@ -10067,7 +10028,7 @@ function stripMarkdownFence(markdown) {
10067
10028
  }
10068
10029
  function deriveTitleFromTranscriptPath(transcriptFile, recordingId) {
10069
10030
  if (!transcriptFile) return void 0;
10070
- const name = (0, import_node_path20.basename)(transcriptFile, ".md");
10031
+ const name = (0, import_node_path19.basename)(transcriptFile, ".md");
10071
10032
  const prefix = `${recordingId}_`;
10072
10033
  if (name.startsWith(prefix)) {
10073
10034
  const derived = name.slice(prefix.length).trim();
@@ -10095,22 +10056,22 @@ function extractTranscriptContent(markdown) {
10095
10056
  return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
10096
10057
  }
10097
10058
  function resolveRecordingStorageDir(ctx, logger) {
10098
- const stateRecDir = (0, import_node_path20.join)(
10059
+ const stateRecDir = (0, import_node_path19.join)(
10099
10060
  ctx.stateDir,
10100
10061
  "plugins",
10101
10062
  "phone-notifications",
10102
10063
  RECORDINGS_DIR
10103
10064
  );
10104
10065
  try {
10105
- (0, import_node_fs24.mkdirSync)(stateRecDir, { recursive: true });
10066
+ (0, import_node_fs23.mkdirSync)(stateRecDir, { recursive: true });
10106
10067
  logger.info(`\u5F55\u97F3\u5C06\u5199\u5165 stateDir \u8DEF\u5F84: ${stateRecDir}`);
10107
10068
  return stateRecDir;
10108
10069
  } catch {
10109
10070
  }
10110
10071
  if (ctx.workspaceDir) {
10111
- const wsRecDir = (0, import_node_path20.join)(ctx.workspaceDir, RECORDINGS_DIR);
10072
+ const wsRecDir = (0, import_node_path19.join)(ctx.workspaceDir, RECORDINGS_DIR);
10112
10073
  try {
10113
- (0, import_node_fs24.mkdirSync)(wsRecDir, { recursive: true });
10074
+ (0, import_node_fs23.mkdirSync)(wsRecDir, { recursive: true });
10114
10075
  logger.warn(`stateDir \u4E0D\u53EF\u7528\uFF0C\u5F55\u97F3\u5DF2\u56DE\u9000\u5230 workspace \u8DEF\u5F84: ${wsRecDir}`);
10115
10076
  return wsRecDir;
10116
10077
  } catch {
@@ -10122,11 +10083,11 @@ var RecordingStorage = class {
10122
10083
  constructor(dir, logger) {
10123
10084
  this.logger = logger;
10124
10085
  this.dir = dir;
10125
- this.audioDir = (0, import_node_path20.join)(dir, AUDIO_DIR);
10126
- this.transcriptDataDir = (0, import_node_path20.join)(dir, TRANSCRIPT_DATA_DIR);
10127
- this.transcriptsDir = (0, import_node_path20.join)(dir, TRANSCRIPTS_DIR);
10128
- this.summariesDir = (0, import_node_path20.join)(dir, SUMMARIES_DIR);
10129
- this.indexPath = (0, import_node_path20.join)(dir, INDEX_FILE);
10086
+ this.audioDir = (0, import_node_path19.join)(dir, AUDIO_DIR);
10087
+ this.transcriptDataDir = (0, import_node_path19.join)(dir, TRANSCRIPT_DATA_DIR);
10088
+ this.transcriptsDir = (0, import_node_path19.join)(dir, TRANSCRIPTS_DIR);
10089
+ this.summariesDir = (0, import_node_path19.join)(dir, SUMMARIES_DIR);
10090
+ this.indexPath = (0, import_node_path19.join)(dir, INDEX_FILE);
10130
10091
  }
10131
10092
  dir;
10132
10093
  audioDir;
@@ -10137,10 +10098,10 @@ var RecordingStorage = class {
10137
10098
  index = { recordings: [] };
10138
10099
  /** 初始化目录结构并加载索引 */
10139
10100
  async init() {
10140
- (0, import_node_fs24.mkdirSync)(this.audioDir, { recursive: true });
10141
- (0, import_node_fs24.mkdirSync)(this.transcriptDataDir, { recursive: true });
10142
- (0, import_node_fs24.mkdirSync)(this.transcriptsDir, { recursive: true });
10143
- (0, import_node_fs24.mkdirSync)(this.summariesDir, { recursive: true });
10101
+ (0, import_node_fs23.mkdirSync)(this.audioDir, { recursive: true });
10102
+ (0, import_node_fs23.mkdirSync)(this.transcriptDataDir, { recursive: true });
10103
+ (0, import_node_fs23.mkdirSync)(this.transcriptsDir, { recursive: true });
10104
+ (0, import_node_fs23.mkdirSync)(this.summariesDir, { recursive: true });
10144
10105
  this.loadIndex();
10145
10106
  this.logger.info(
10146
10107
  `\u5F55\u97F3\u5B58\u50A8\u5DF2\u521D\u59CB\u5316: ${this.dir}\uFF08\u5171 ${this.index.recordings.length} \u6761\u8BB0\u5F55\uFF09`
@@ -10184,13 +10145,13 @@ var RecordingStorage = class {
10184
10145
  return id;
10185
10146
  }
10186
10147
  if (existing.transcriptDataFile) {
10187
- (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, existing.transcriptDataFile), { force: true });
10148
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.transcriptDataFile), { force: true });
10188
10149
  }
10189
10150
  if (existing.transcriptFile) {
10190
- (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, existing.transcriptFile), { force: true });
10151
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.transcriptFile), { force: true });
10191
10152
  }
10192
10153
  if (existing.summaryFile) {
10193
- (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, existing.summaryFile), { force: true });
10154
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.summaryFile), { force: true });
10194
10155
  }
10195
10156
  existing.metadata = metadata;
10196
10157
  existing.status = "syncing_openclaw";
@@ -10258,7 +10219,7 @@ var RecordingStorage = class {
10258
10219
  if (!entry) return;
10259
10220
  const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;
10260
10221
  if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {
10261
- (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, entry.transcriptDataFile), { force: true });
10222
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.transcriptDataFile), { force: true });
10262
10223
  }
10263
10224
  entry.transcriptDataFile = nextTranscriptDataFile;
10264
10225
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -10272,7 +10233,7 @@ var RecordingStorage = class {
10272
10233
  if (!entry) return;
10273
10234
  const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;
10274
10235
  if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {
10275
- (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, entry.transcriptFile), { force: true });
10236
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.transcriptFile), { force: true });
10276
10237
  }
10277
10238
  entry.transcriptFile = nextTranscriptFile;
10278
10239
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -10286,7 +10247,7 @@ var RecordingStorage = class {
10286
10247
  if (!entry) return;
10287
10248
  const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;
10288
10249
  if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {
10289
- (0, import_node_fs24.rmSync)((0, import_node_path20.join)(this.dir, entry.summaryFile), { force: true });
10250
+ (0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.summaryFile), { force: true });
10290
10251
  }
10291
10252
  entry.summaryFile = nextSummaryFile;
10292
10253
  entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -10384,24 +10345,24 @@ var RecordingStorage = class {
10384
10345
  const entry = this.findById(recordingId);
10385
10346
  if (!entry) return false;
10386
10347
  if (entry.audioFile) {
10387
- const audioPath = (0, import_node_path20.join)(this.dir, entry.audioFile);
10388
- (0, import_node_fs24.rmSync)(audioPath, { force: true });
10348
+ const audioPath = (0, import_node_path19.join)(this.dir, entry.audioFile);
10349
+ (0, import_node_fs23.rmSync)(audioPath, { force: true });
10389
10350
  }
10390
10351
  if (entry.srtFile) {
10391
- const srtPath = (0, import_node_path20.join)(this.dir, entry.srtFile);
10392
- (0, import_node_fs24.rmSync)(srtPath, { force: true });
10352
+ const srtPath = (0, import_node_path19.join)(this.dir, entry.srtFile);
10353
+ (0, import_node_fs23.rmSync)(srtPath, { force: true });
10393
10354
  }
10394
10355
  if (entry.transcriptDataFile) {
10395
- const transcriptDataPath = (0, import_node_path20.join)(this.dir, entry.transcriptDataFile);
10396
- (0, import_node_fs24.rmSync)(transcriptDataPath, { force: true });
10356
+ const transcriptDataPath = (0, import_node_path19.join)(this.dir, entry.transcriptDataFile);
10357
+ (0, import_node_fs23.rmSync)(transcriptDataPath, { force: true });
10397
10358
  }
10398
10359
  if (entry.transcriptFile) {
10399
- const transcriptPath = (0, import_node_path20.join)(this.dir, entry.transcriptFile);
10400
- (0, import_node_fs24.rmSync)(transcriptPath, { force: true });
10360
+ const transcriptPath = (0, import_node_path19.join)(this.dir, entry.transcriptFile);
10361
+ (0, import_node_fs23.rmSync)(transcriptPath, { force: true });
10401
10362
  }
10402
10363
  if (entry.summaryFile) {
10403
- const summaryPath = (0, import_node_path20.join)(this.dir, entry.summaryFile);
10404
- (0, import_node_fs24.rmSync)(summaryPath, { force: true });
10364
+ const summaryPath = (0, import_node_path19.join)(this.dir, entry.summaryFile);
10365
+ (0, import_node_fs23.rmSync)(summaryPath, { force: true });
10405
10366
  }
10406
10367
  if (opts?.localOnly) {
10407
10368
  entry.audioFile = void 0;
@@ -10459,34 +10420,34 @@ var RecordingStorage = class {
10459
10420
  * 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名
10460
10421
  */
10461
10422
  getAudioFilePath(recordingId, ossUrl) {
10462
- return (0, import_node_path20.join)(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));
10423
+ return (0, import_node_path19.join)(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));
10463
10424
  }
10464
10425
  /**
10465
10426
  * 获取打点文件的绝对路径
10466
10427
  */
10467
10428
  getSrtFilePath(recordingId) {
10468
- return (0, import_node_path20.join)(this.audioDir, this.buildSrtFilename(recordingId));
10429
+ return (0, import_node_path19.join)(this.audioDir, this.buildSrtFilename(recordingId));
10469
10430
  }
10470
10431
  /**
10471
10432
  * 获取转写 JSON 文件的绝对路径
10472
10433
  */
10473
10434
  getTranscriptDataFilePath(recordingId) {
10474
- return (0, import_node_path20.join)(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));
10435
+ return (0, import_node_path19.join)(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));
10475
10436
  }
10476
10437
  /**
10477
10438
  * 获取摘要文件的绝对路径
10478
10439
  */
10479
10440
  getSummaryFilePath(recordingId) {
10480
- return (0, import_node_path20.join)(this.summariesDir, this.buildSummaryFilename(recordingId));
10441
+ return (0, import_node_path19.join)(this.summariesDir, this.buildSummaryFilename(recordingId));
10481
10442
  }
10482
10443
  // ─── Persistence ───
10483
10444
  loadIndex() {
10484
- if (!(0, import_node_fs24.existsSync)(this.indexPath)) {
10445
+ if (!(0, import_node_fs23.existsSync)(this.indexPath)) {
10485
10446
  this.index = { recordings: [] };
10486
10447
  return;
10487
10448
  }
10488
10449
  try {
10489
- const raw = JSON.parse((0, import_node_fs24.readFileSync)(this.indexPath, "utf-8"));
10450
+ const raw = JSON.parse((0, import_node_fs23.readFileSync)(this.indexPath, "utf-8"));
10490
10451
  if (raw && Array.isArray(raw.recordings)) {
10491
10452
  let needsRewrite = false;
10492
10453
  const normalized = raw.recordings.filter((entry) => entry && typeof entry === "object").map((entry) => {
@@ -10524,8 +10485,8 @@ var RecordingStorage = class {
10524
10485
  segments: []
10525
10486
  });
10526
10487
  const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);
10527
- (0, import_node_fs24.writeFileSync)(
10528
- (0, import_node_path20.join)(this.transcriptDataDir, transcriptDataFilename),
10488
+ (0, import_node_fs23.writeFileSync)(
10489
+ (0, import_node_path19.join)(this.transcriptDataDir, transcriptDataFilename),
10529
10490
  JSON.stringify(transcriptDoc, null, 2),
10530
10491
  "utf-8"
10531
10492
  );
@@ -10537,8 +10498,8 @@ var RecordingStorage = class {
10537
10498
  compacted.summaryFile = entry.summaryFile;
10538
10499
  } else if (typeof entry.summary === "string" && entry.summary.trim()) {
10539
10500
  const summaryFilename = this.buildSummaryFilename(entry.id);
10540
- (0, import_node_fs24.writeFileSync)(
10541
- (0, import_node_path20.join)(this.summariesDir, summaryFilename),
10501
+ (0, import_node_fs23.writeFileSync)(
10502
+ (0, import_node_path19.join)(this.summariesDir, summaryFilename),
10542
10503
  entry.summary.trim(),
10543
10504
  "utf-8"
10544
10505
  );
@@ -10548,8 +10509,8 @@ var RecordingStorage = class {
10548
10509
  const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);
10549
10510
  if (summaryFromDocument) {
10550
10511
  const summaryFilename = this.buildSummaryFilename(entry.id);
10551
- (0, import_node_fs24.writeFileSync)(
10552
- (0, import_node_path20.join)(this.summariesDir, summaryFilename),
10512
+ (0, import_node_fs23.writeFileSync)(
10513
+ (0, import_node_path19.join)(this.summariesDir, summaryFilename),
10553
10514
  summaryFromDocument,
10554
10515
  "utf-8"
10555
10516
  );
@@ -10589,7 +10550,7 @@ var RecordingStorage = class {
10589
10550
  }
10590
10551
  readRelativeTextFile(relativePath) {
10591
10552
  try {
10592
- return (0, import_node_fs24.readFileSync)((0, import_node_path20.join)(this.dir, relativePath), "utf-8");
10553
+ return (0, import_node_fs23.readFileSync)((0, import_node_path19.join)(this.dir, relativePath), "utf-8");
10593
10554
  } catch {
10594
10555
  return void 0;
10595
10556
  }
@@ -10602,7 +10563,7 @@ var RecordingStorage = class {
10602
10563
  return parseTranscriptDocument(raw);
10603
10564
  }
10604
10565
  saveIndex() {
10605
- (0, import_node_fs24.writeFileSync)(
10566
+ (0, import_node_fs23.writeFileSync)(
10606
10567
  this.indexPath,
10607
10568
  JSON.stringify(this.index, null, 2),
10608
10569
  "utf-8"
@@ -10616,8 +10577,8 @@ var RecordingStorage = class {
10616
10577
  init_transcript_document();
10617
10578
 
10618
10579
  // src/recording/downloader.ts
10619
- var import_node_fs25 = require("fs");
10620
- var import_node_path21 = require("path");
10580
+ var import_node_fs24 = require("fs");
10581
+ var import_node_path20 = require("path");
10621
10582
  var import_promises2 = require("stream/promises");
10622
10583
  var import_node_stream = require("stream");
10623
10584
  var DEFAULT_TIMEOUT_MS2 = 5 * 60 * 1e3;
@@ -10627,7 +10588,7 @@ async function downloadFile(url, destPath, logger, options) {
10627
10588
  const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
10628
10589
  const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
10629
10590
  const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;
10630
- (0, import_node_fs25.mkdirSync)((0, import_node_path21.dirname)(destPath), { recursive: true });
10591
+ (0, import_node_fs24.mkdirSync)((0, import_node_path20.dirname)(destPath), { recursive: true });
10631
10592
  let lastError;
10632
10593
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
10633
10594
  const startMs = Date.now();
@@ -10645,11 +10606,11 @@ async function downloadFile(url, destPath, logger, options) {
10645
10606
  if (!res.body) {
10646
10607
  throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
10647
10608
  }
10648
- const writeStream = (0, import_node_fs25.createWriteStream)(destPath);
10609
+ const writeStream = (0, import_node_fs24.createWriteStream)(destPath);
10649
10610
  const readable = import_node_stream.Readable.fromWeb(res.body);
10650
10611
  await (0, import_promises2.pipeline)(readable, writeStream);
10651
10612
  const elapsed = Date.now() - startMs;
10652
- const fileSize = (0, import_node_fs25.existsSync)(destPath) ? (0, import_node_fs25.statSync)(destPath).size : 0;
10613
+ const fileSize = (0, import_node_fs24.existsSync)(destPath) ? (0, import_node_fs24.statSync)(destPath).size : 0;
10653
10614
  logger.info(
10654
10615
  `[downloader] \u4E0B\u8F7D\u5B8C\u6210: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`
10655
10616
  );
@@ -10660,7 +10621,7 @@ async function downloadFile(url, destPath, logger, options) {
10660
10621
  } catch (err2) {
10661
10622
  lastError = err2?.message ?? String(err2);
10662
10623
  try {
10663
- if ((0, import_node_fs25.existsSync)(destPath)) (0, import_node_fs25.unlinkSync)(destPath);
10624
+ if ((0, import_node_fs24.existsSync)(destPath)) (0, import_node_fs24.unlinkSync)(destPath);
10664
10625
  } catch {
10665
10626
  }
10666
10627
  const isAbort = err2?.name === "AbortError";
@@ -10702,6 +10663,63 @@ init_whisper_local();
10702
10663
 
10703
10664
  // src/recording/handler.ts
10704
10665
  init_asr();
10666
+
10667
+ // src/recording/account-oss.ts
10668
+ init_credentials();
10669
+ init_env();
10670
+ async function deleteAccountOssFile(fileUrl, logger) {
10671
+ const trimmed = fileUrl?.trim();
10672
+ if (!trimmed) {
10673
+ return { ok: false, error: "fileUrl is empty" };
10674
+ }
10675
+ const apiKey = loadApiKey();
10676
+ if (!apiKey) {
10677
+ return { ok: false, error: "API Key \u672A\u8BBE\u7F6E\uFF0C\u8DF3\u8FC7 OSS \u6587\u4EF6\u5220\u9664" };
10678
+ }
10679
+ const endpoint = getEnvUrls().accountFileDeleteUrl;
10680
+ const headerKey = apiKey.startsWith("Bearer ") ? apiKey.slice("Bearer ".length) : apiKey;
10681
+ const body = new URLSearchParams({ fileUrl: trimmed }).toString();
10682
+ logger.info(`[account-oss-delete] \u63D0\u4EA4 OSS \u6587\u4EF6\u5220\u9664: endpoint=${endpoint}, fileUrl=${trimmed}`);
10683
+ let res;
10684
+ try {
10685
+ res = await fetch(endpoint, {
10686
+ method: "POST",
10687
+ headers: {
10688
+ "Content-Type": "application/x-www-form-urlencoded",
10689
+ "X-Api-Key-Id": headerKey
10690
+ },
10691
+ body
10692
+ });
10693
+ } catch (err2) {
10694
+ const error = err2?.message ?? String(err2);
10695
+ logger.warn(`[account-oss-delete] \u7F51\u7EDC\u5F02\u5E38: ${error}`);
10696
+ return { ok: false, error };
10697
+ }
10698
+ const text = await res.text();
10699
+ if (!res.ok) {
10700
+ logger.warn(
10701
+ `[account-oss-delete] HTTP \u9519\u8BEF: status=${res.status}, body=${text.slice(0, 300)}`
10702
+ );
10703
+ return { ok: false, error: `HTTP ${res.status} ${text.slice(0, 200)}` };
10704
+ }
10705
+ let payload;
10706
+ try {
10707
+ payload = text ? JSON.parse(text) : void 0;
10708
+ } catch {
10709
+ logger.warn(`[account-oss-delete] \u54CD\u5E94\u975E JSON: body=${text.slice(0, 300)}`);
10710
+ return { ok: false, error: "response is not JSON" };
10711
+ }
10712
+ const code = typeof payload?.code === "number" ? String(payload.code) : payload?.code?.trim?.();
10713
+ if (code !== "000000") {
10714
+ const msg = payload?.msg?.trim?.() || text.slice(0, 200);
10715
+ logger.warn(`[account-oss-delete] \u4E1A\u52A1\u5931\u8D25: code=${code ?? "n/a"}, msg=${msg}`);
10716
+ return { ok: false, error: `${code ?? "unknown"} ${msg}`.trim() };
10717
+ }
10718
+ logger.info(`[account-oss-delete] OSS \u6587\u4EF6\u5DF2\u5220\u9664: fileUrl=${trimmed}`);
10719
+ return { ok: true };
10720
+ }
10721
+
10722
+ // src/recording/handler.ts
10705
10723
  function emitRecordingStatus(recordingId, storage, logger, notifyStatus, error, extras) {
10706
10724
  if (!notifyStatus) {
10707
10725
  return;
@@ -10882,6 +10900,14 @@ async function triggerTranscription(recordingId, storage, asrConfig, logger, opt
10882
10900
  logger.info(
10883
10901
  `[asr-trigger] \u8F6C\u5199\u5B8C\u6210: ${recordingId}, summary="${result.summary}"`
10884
10902
  );
10903
+ const ossAudioUrl = entry.metadata.oss_audio_url?.trim();
10904
+ if (ossAudioUrl) {
10905
+ void deleteAccountOssFile(ossAudioUrl, logger).catch((err2) => {
10906
+ logger.warn(
10907
+ `[asr-trigger] OSS \u97F3\u9891\u6E05\u7406\u5F02\u5E38 (\u975E\u81F4\u547D): ${recordingId}, ${err2?.message ?? err2}`
10908
+ );
10909
+ });
10910
+ }
10885
10911
  } else {
10886
10912
  storage.updateStatus(recordingId, "transcribe_failed");
10887
10913
  emitRecordingStatus(
@@ -10898,13 +10924,13 @@ async function triggerTranscription(recordingId, storage, asrConfig, logger, opt
10898
10924
  }
10899
10925
 
10900
10926
  // src/tunnel/service.ts
10901
- var import_node_fs30 = require("fs");
10902
- var import_node_path26 = require("path");
10927
+ var import_node_fs29 = require("fs");
10928
+ var import_node_path25 = require("path");
10903
10929
  init_credentials();
10904
10930
 
10905
10931
  // src/tunnel/relay-client.ts
10906
- var import_node_fs28 = require("fs");
10907
- var import_node_path24 = require("path");
10932
+ var import_node_fs27 = require("fs");
10933
+ var import_node_path23 = require("path");
10908
10934
 
10909
10935
  // node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
10910
10936
  var import_stream = __toESM(require_stream(), 1);
@@ -10948,8 +10974,8 @@ var RelayClient = class {
10948
10974
  lastDisconnectReason
10949
10975
  };
10950
10976
  try {
10951
- (0, import_node_fs28.mkdirSync)((0, import_node_path24.dirname)(this.opts.statusFilePath), { recursive: true });
10952
- (0, import_node_fs28.writeFileSync)(this.opts.statusFilePath, JSON.stringify(info, null, 2));
10977
+ (0, import_node_fs27.mkdirSync)((0, import_node_path23.dirname)(this.opts.statusFilePath), { recursive: true });
10978
+ (0, import_node_fs27.writeFileSync)(this.opts.statusFilePath, JSON.stringify(info, null, 2));
10953
10979
  } catch {
10954
10980
  }
10955
10981
  }
@@ -11331,8 +11357,8 @@ init_host();
11331
11357
 
11332
11358
  // src/tunnel/device-identity.ts
11333
11359
  var import_node_crypto3 = __toESM(require("crypto"), 1);
11334
- var import_node_fs29 = __toESM(require("fs"), 1);
11335
- var import_node_path25 = __toESM(require("path"), 1);
11360
+ var import_node_fs28 = __toESM(require("fs"), 1);
11361
+ var import_node_path24 = __toESM(require("path"), 1);
11336
11362
  init_host();
11337
11363
  var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
11338
11364
  function base64UrlEncode(buf) {
@@ -11377,10 +11403,10 @@ function resolveClientStateDir(stateDir) {
11377
11403
  return stateDir ?? resolveStateDir();
11378
11404
  }
11379
11405
  function ensureDir(filePath) {
11380
- import_node_fs29.default.mkdirSync(import_node_path25.default.dirname(filePath), { recursive: true });
11406
+ import_node_fs28.default.mkdirSync(import_node_path24.default.dirname(filePath), { recursive: true });
11381
11407
  }
11382
11408
  function resolveIdentityPath(stateDir) {
11383
- return import_node_path25.default.join(stateDir, "identity", "device.json");
11409
+ return import_node_path24.default.join(stateDir, "identity", "device.json");
11384
11410
  }
11385
11411
  function normalizeDeviceAuthRole(role) {
11386
11412
  return role.trim();
@@ -11396,12 +11422,12 @@ function normalizeDeviceAuthScopes(scopes) {
11396
11422
  return [...out].sort();
11397
11423
  }
11398
11424
  function resolveDeviceAuthPath(stateDir) {
11399
- return import_node_path25.default.join(stateDir, "identity", "device-auth.json");
11425
+ return import_node_path24.default.join(stateDir, "identity", "device-auth.json");
11400
11426
  }
11401
11427
  function readDeviceAuthStore(filePath) {
11402
11428
  try {
11403
- if (!import_node_fs29.default.existsSync(filePath)) return null;
11404
- const raw = import_node_fs29.default.readFileSync(filePath, "utf8");
11429
+ if (!import_node_fs28.default.existsSync(filePath)) return null;
11430
+ const raw = import_node_fs28.default.readFileSync(filePath, "utf8");
11405
11431
  const parsed = JSON.parse(raw);
11406
11432
  if (parsed?.version !== 1 || typeof parsed.deviceId !== "string") return null;
11407
11433
  if (!parsed.tokens || typeof parsed.tokens !== "object") return null;
@@ -11412,12 +11438,12 @@ function readDeviceAuthStore(filePath) {
11412
11438
  }
11413
11439
  function writeDeviceAuthStore(filePath, store) {
11414
11440
  ensureDir(filePath);
11415
- import_node_fs29.default.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
11441
+ import_node_fs28.default.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
11416
11442
  `, {
11417
11443
  mode: 384
11418
11444
  });
11419
11445
  try {
11420
- import_node_fs29.default.chmodSync(filePath, 384);
11446
+ import_node_fs28.default.chmodSync(filePath, 384);
11421
11447
  } catch {
11422
11448
  }
11423
11449
  }
@@ -11464,8 +11490,8 @@ function clearDeviceAuthToken(params) {
11464
11490
  function loadOrCreateDeviceIdentity(stateDir) {
11465
11491
  const filePath = resolveIdentityPath(stateDir);
11466
11492
  try {
11467
- if (import_node_fs29.default.existsSync(filePath)) {
11468
- const raw = import_node_fs29.default.readFileSync(filePath, "utf8");
11493
+ if (import_node_fs28.default.existsSync(filePath)) {
11494
+ const raw = import_node_fs28.default.readFileSync(filePath, "utf8");
11469
11495
  const parsed = JSON.parse(raw);
11470
11496
  if (parsed?.version === 1 && typeof parsed.deviceId === "string" && typeof parsed.publicKeyPem === "string" && typeof parsed.privateKeyPem === "string") {
11471
11497
  const derivedId = fingerprintPublicKey(parsed.publicKeyPem);
@@ -11486,14 +11512,14 @@ function loadOrCreateDeviceIdentity(stateDir) {
11486
11512
  publicKeyPem,
11487
11513
  privateKeyPem
11488
11514
  };
11489
- import_node_fs29.default.mkdirSync(import_node_path25.default.dirname(filePath), { recursive: true });
11515
+ import_node_fs28.default.mkdirSync(import_node_path24.default.dirname(filePath), { recursive: true });
11490
11516
  const stored = {
11491
11517
  version: 1,
11492
11518
  ...identity,
11493
11519
  createdAtMs: Date.now()
11494
11520
  };
11495
11521
  ensureDir(filePath);
11496
- import_node_fs29.default.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}
11522
+ import_node_fs28.default.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}
11497
11523
  `, {
11498
11524
  mode: 384
11499
11525
  });
@@ -12265,7 +12291,7 @@ function createTunnelService(opts) {
12265
12291
  }
12266
12292
  function readLockOwner(filePath) {
12267
12293
  try {
12268
- const parsed = JSON.parse((0, import_node_fs30.readFileSync)(filePath, "utf-8"));
12294
+ const parsed = JSON.parse((0, import_node_fs29.readFileSync)(filePath, "utf-8"));
12269
12295
  return typeof parsed.pid === "number" ? parsed.pid : null;
12270
12296
  } catch {
12271
12297
  return null;
@@ -12278,23 +12304,23 @@ function createTunnelService(opts) {
12278
12304
  lockFd = null;
12279
12305
  if (fd !== null) {
12280
12306
  try {
12281
- (0, import_node_fs30.closeSync)(fd);
12307
+ (0, import_node_fs29.closeSync)(fd);
12282
12308
  } catch {
12283
12309
  }
12284
12310
  }
12285
12311
  if (filePath) {
12286
12312
  try {
12287
- (0, import_node_fs30.unlinkSync)(filePath);
12313
+ (0, import_node_fs29.unlinkSync)(filePath);
12288
12314
  } catch {
12289
12315
  }
12290
12316
  }
12291
12317
  }
12292
12318
  function acquireLock(filePath) {
12293
- (0, import_node_fs30.mkdirSync)((0, import_node_path26.dirname)(filePath), { recursive: true });
12319
+ (0, import_node_fs29.mkdirSync)((0, import_node_path25.dirname)(filePath), { recursive: true });
12294
12320
  for (let attempt = 0; attempt < 2; attempt++) {
12295
12321
  try {
12296
- const fd = (0, import_node_fs30.openSync)(filePath, "wx", 384);
12297
- (0, import_node_fs30.writeFileSync)(
12322
+ const fd = (0, import_node_fs29.openSync)(filePath, "wx", 384);
12323
+ (0, import_node_fs29.writeFileSync)(
12298
12324
  fd,
12299
12325
  JSON.stringify({
12300
12326
  pid: process.pid,
@@ -12318,7 +12344,7 @@ function createTunnelService(opts) {
12318
12344
  `Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`
12319
12345
  );
12320
12346
  try {
12321
- (0, import_node_fs30.unlinkSync)(filePath);
12347
+ (0, import_node_fs29.unlinkSync)(filePath);
12322
12348
  } catch {
12323
12349
  }
12324
12350
  continue;
@@ -12363,12 +12389,12 @@ function createTunnelService(opts) {
12363
12389
  return;
12364
12390
  }
12365
12391
  const { logger } = opts;
12366
- const baseStateDir = (0, import_node_path26.join)(ctx.stateDir, "plugins", "phone-notifications");
12392
+ const baseStateDir = (0, import_node_path25.join)(ctx.stateDir, "plugins", "phone-notifications");
12367
12393
  logger.info(
12368
12394
  `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})`
12369
12395
  );
12370
- const statusFilePath = (0, import_node_path26.join)(baseStateDir, "tunnel-status.json");
12371
- const lockPath = (0, import_node_path26.join)(baseStateDir, "relay-tunnel.lock");
12396
+ const statusFilePath = (0, import_node_path25.join)(baseStateDir, "tunnel-status.json");
12397
+ const lockPath = (0, import_node_path25.join)(baseStateDir, "relay-tunnel.lock");
12372
12398
  if (!acquireLock(lockPath)) {
12373
12399
  return;
12374
12400
  }
@@ -12508,7 +12534,7 @@ function readHostGatewayConfig(params) {
12508
12534
  let configData;
12509
12535
  if (configPath) {
12510
12536
  try {
12511
- configData = JSON.parse((0, import_node_fs31.readFileSync)(configPath, "utf-8"));
12537
+ configData = JSON.parse((0, import_node_fs30.readFileSync)(configPath, "utf-8"));
12512
12538
  } catch (err2) {
12513
12539
  if (err2?.code !== "ENOENT") {
12514
12540
  params.logger.warn(
@@ -13270,7 +13296,6 @@ var index_default = {
13270
13296
  recordingStorage = nextRecordingStorage;
13271
13297
  },
13272
13298
  onStorageReady() {
13273
- migrateLegacyLightRuleTasks(lightRuleCtx, logger);
13274
13299
  lightRuleRegistry.reload();
13275
13300
  }
13276
13301
  });