@yoooclaw/phone-notifications 1.11.0 → 1.11.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +384 -411
- package/dist/index.cjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -535,20 +535,20 @@ function selectModelByMemory(availableGB, isAppleSilicon = false) {
|
|
|
535
535
|
return "tiny";
|
|
536
536
|
}
|
|
537
537
|
function resolveModelsDir(dataDir) {
|
|
538
|
-
const dir = (0,
|
|
539
|
-
(0,
|
|
538
|
+
const dir = (0, import_node_path21.join)(dataDir, WHISPER_MODELS_DIR);
|
|
539
|
+
(0, import_node_fs25.mkdirSync)(dir, { recursive: true });
|
|
540
540
|
return dir;
|
|
541
541
|
}
|
|
542
542
|
function resolveBinDir(dataDir) {
|
|
543
|
-
const dir = (0,
|
|
544
|
-
(0,
|
|
543
|
+
const dir = (0, import_node_path21.join)(dataDir, WHISPER_BIN_DIR);
|
|
544
|
+
(0, import_node_fs25.mkdirSync)(dir, { recursive: true });
|
|
545
545
|
return dir;
|
|
546
546
|
}
|
|
547
547
|
function isModelDownloaded(modelsDir, modelSize) {
|
|
548
|
-
const modelPath = (0,
|
|
549
|
-
if (!(0,
|
|
548
|
+
const modelPath = (0, import_node_path21.join)(modelsDir, MODEL_FILENAMES[modelSize]);
|
|
549
|
+
if (!(0, import_node_fs25.existsSync)(modelPath)) return false;
|
|
550
550
|
try {
|
|
551
|
-
const stat = (0,
|
|
551
|
+
const stat = (0, import_node_fs25.statSync)(modelPath);
|
|
552
552
|
const expectedSize = MODEL_DISK_SIZES[modelSize];
|
|
553
553
|
return stat.size >= expectedSize * 0.8;
|
|
554
554
|
} catch {
|
|
@@ -557,7 +557,7 @@ function isModelDownloaded(modelsDir, modelSize) {
|
|
|
557
557
|
}
|
|
558
558
|
async function downloadModel(modelsDir, modelSize, logger, modelSource, mirrorUrl) {
|
|
559
559
|
const filename = MODEL_FILENAMES[modelSize];
|
|
560
|
-
const modelPath = (0,
|
|
560
|
+
const modelPath = (0, import_node_path21.join)(modelsDir, filename);
|
|
561
561
|
if (isModelDownloaded(modelsDir, modelSize)) {
|
|
562
562
|
logger.info(`[whisper-local] \u6A21\u578B\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u4E0B\u8F7D: ${filename}`);
|
|
563
563
|
return { ok: true, modelPath };
|
|
@@ -623,7 +623,7 @@ async function probeUrl(url, logger) {
|
|
|
623
623
|
async function downloadFromUrl(url, modelPath, logger) {
|
|
624
624
|
const tmpPath = `${modelPath}.downloading`;
|
|
625
625
|
try {
|
|
626
|
-
(0,
|
|
626
|
+
(0, import_node_fs25.mkdirSync)((0, import_node_path21.dirname)(modelPath), { recursive: true });
|
|
627
627
|
const controller = new AbortController();
|
|
628
628
|
const timer = setTimeout(() => controller.abort(), 30 * 60 * 1e3);
|
|
629
629
|
try {
|
|
@@ -639,7 +639,7 @@ async function downloadFromUrl(url, modelPath, logger) {
|
|
|
639
639
|
return { ok: false, modelPath, error: "\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: \u54CD\u5E94\u4F53\u4E3A\u7A7A" };
|
|
640
640
|
}
|
|
641
641
|
const contentLength = Number(res.headers.get("content-length") ?? 0);
|
|
642
|
-
const writeStream = (0,
|
|
642
|
+
const writeStream = (0, import_node_fs25.createWriteStream)(tmpPath);
|
|
643
643
|
const readable = import_node_stream2.Readable.fromWeb(res.body);
|
|
644
644
|
let downloaded = 0;
|
|
645
645
|
let lastLogPercent = 0;
|
|
@@ -661,14 +661,14 @@ async function downloadFromUrl(url, modelPath, logger) {
|
|
|
661
661
|
}
|
|
662
662
|
const { renameSync: renameSync2 } = await import("fs");
|
|
663
663
|
renameSync2(tmpPath, modelPath);
|
|
664
|
-
const fileSize = (0,
|
|
664
|
+
const fileSize = (0, import_node_fs25.statSync)(modelPath).size;
|
|
665
665
|
logger.info(
|
|
666
|
-
`[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0,
|
|
666
|
+
`[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path21.basename)(modelPath)} (${formatBytes2(fileSize)})`
|
|
667
667
|
);
|
|
668
668
|
return { ok: true, modelPath };
|
|
669
669
|
} catch (err2) {
|
|
670
670
|
try {
|
|
671
|
-
if ((0,
|
|
671
|
+
if ((0, import_node_fs25.existsSync)(tmpPath)) (0, import_node_fs25.unlinkSync)(tmpPath);
|
|
672
672
|
} catch {
|
|
673
673
|
}
|
|
674
674
|
const msg = err2?.name === "AbortError" ? "\u6A21\u578B\u4E0B\u8F7D\u8D85\u65F6\uFF0830 \u5206\u949F\uFF09" : err2?.message ?? String(err2);
|
|
@@ -680,8 +680,8 @@ function findWhisperBinary(dataDir, logger) {
|
|
|
680
680
|
const binDir = resolveBinDir(dataDir);
|
|
681
681
|
const binNames = (0, import_node_os4.platform)() === "win32" ? ["whisper-cli.exe", "whisper.exe", "main.exe"] : ["whisper-cli", "whisper", "main"];
|
|
682
682
|
for (const name of binNames) {
|
|
683
|
-
const binPath = (0,
|
|
684
|
-
if ((0,
|
|
683
|
+
const binPath = (0, import_node_path21.join)(binDir, name);
|
|
684
|
+
if ((0, import_node_fs25.existsSync)(binPath)) {
|
|
685
685
|
logger.info(`[whisper-local] \u627E\u5230\u672C\u5730\u4E8C\u8FDB\u5236: ${binPath}`);
|
|
686
686
|
return binPath;
|
|
687
687
|
}
|
|
@@ -732,7 +732,7 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
|
|
|
732
732
|
return { ok: false, error: `\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: ${downloadResult.error}` };
|
|
733
733
|
}
|
|
734
734
|
}
|
|
735
|
-
const modelPath = (0,
|
|
735
|
+
const modelPath = (0, import_node_path21.join)(modelsDir, MODEL_FILENAMES[modelSize]);
|
|
736
736
|
let inputPath = audioFilePath;
|
|
737
737
|
let tmpWavPath = null;
|
|
738
738
|
const actualFmt = detectAudioFormat(audioFilePath);
|
|
@@ -784,10 +784,10 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
|
|
|
784
784
|
logger.info(`[whisper-local] \u8F6C\u5199\u8017\u65F6: ${Math.round(elapsed / 1e3)}s`);
|
|
785
785
|
const jsonPath = inputPath + ".json";
|
|
786
786
|
let jsonContent;
|
|
787
|
-
if ((0,
|
|
788
|
-
jsonContent = (0,
|
|
787
|
+
if ((0, import_node_fs25.existsSync)(jsonPath)) {
|
|
788
|
+
jsonContent = (0, import_node_fs25.readFileSync)(jsonPath, "utf-8");
|
|
789
789
|
try {
|
|
790
|
-
(0,
|
|
790
|
+
(0, import_node_fs25.unlinkSync)(jsonPath);
|
|
791
791
|
} catch {
|
|
792
792
|
}
|
|
793
793
|
} else {
|
|
@@ -865,10 +865,10 @@ function getPhysicalCoreCount() {
|
|
|
865
865
|
}
|
|
866
866
|
function detectAudioFormat(filePath) {
|
|
867
867
|
try {
|
|
868
|
-
const fd = (0,
|
|
868
|
+
const fd = (0, import_node_fs25.openSync)(filePath, "r");
|
|
869
869
|
const buf = Buffer.alloc(12);
|
|
870
|
-
(0,
|
|
871
|
-
(0,
|
|
870
|
+
(0, import_node_fs25.readSync)(fd, buf, 0, 12, 0);
|
|
871
|
+
(0, import_node_fs25.closeSync)(fd);
|
|
872
872
|
const header = buf.toString("ascii", 0, 4);
|
|
873
873
|
const header8 = buf.toString("ascii", 0, 8);
|
|
874
874
|
if (header === "RIFF" && buf.toString("ascii", 8, 12) === "WAVE") return ".wav";
|
|
@@ -903,7 +903,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
903
903
|
timeout: 12e4,
|
|
904
904
|
stdio: ["pipe", "pipe", "pipe"]
|
|
905
905
|
});
|
|
906
|
-
if (ffmpegResult.status === 0 && (0,
|
|
906
|
+
if (ffmpegResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
|
|
907
907
|
logger.info(`[whisper-local] ffmpeg \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
|
|
908
908
|
return { ok: true };
|
|
909
909
|
}
|
|
@@ -916,7 +916,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
916
916
|
["--rate", "16000", "--mono", inputPath, outputPath],
|
|
917
917
|
{ encoding: "utf-8", timeout: 12e4, stdio: ["pipe", "pipe", "pipe"] }
|
|
918
918
|
);
|
|
919
|
-
if (opusResult.status === 0 && (0,
|
|
919
|
+
if (opusResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
|
|
920
920
|
logger.info(`[whisper-local] opusdec \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
|
|
921
921
|
return { ok: true };
|
|
922
922
|
}
|
|
@@ -930,7 +930,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
930
930
|
if (detectedExt && !inputPath.endsWith(detectedExt)) {
|
|
931
931
|
tmpCopy = inputPath + ".detected" + detectedExt;
|
|
932
932
|
try {
|
|
933
|
-
(0,
|
|
933
|
+
(0, import_node_fs25.copyFileSync)(inputPath, tmpCopy);
|
|
934
934
|
actualInputPath = tmpCopy;
|
|
935
935
|
logger.info(
|
|
936
936
|
`[whisper-local] \u68C0\u6D4B\u5230\u5B9E\u9645\u683C\u5F0F ${detectedExt}\uFF0C\u4E34\u65F6\u91CD\u547D\u540D`
|
|
@@ -954,22 +954,22 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
954
954
|
timeout: 12e4,
|
|
955
955
|
stdio: ["pipe", "pipe", "pipe"]
|
|
956
956
|
});
|
|
957
|
-
if (tmpCopy && (0,
|
|
957
|
+
if (tmpCopy && (0, import_node_fs25.existsSync)(tmpCopy)) {
|
|
958
958
|
try {
|
|
959
|
-
(0,
|
|
959
|
+
(0, import_node_fs25.unlinkSync)(tmpCopy);
|
|
960
960
|
} catch {
|
|
961
961
|
}
|
|
962
962
|
}
|
|
963
|
-
if (afResult.status === 0 && (0,
|
|
963
|
+
if (afResult.status === 0 && (0, import_node_fs25.existsSync)(outputPath)) {
|
|
964
964
|
logger.info(`[whisper-local] afconvert \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
|
|
965
965
|
return { ok: true };
|
|
966
966
|
}
|
|
967
967
|
const stderr = afResult.stderr?.slice(0, 200) ?? "";
|
|
968
968
|
return { ok: false, error: `afconvert \u8F6C\u6362\u5931\u8D25 (exit ${afResult.status}): ${stderr}` };
|
|
969
969
|
} catch (err2) {
|
|
970
|
-
if (tmpCopy && (0,
|
|
970
|
+
if (tmpCopy && (0, import_node_fs25.existsSync)(tmpCopy)) {
|
|
971
971
|
try {
|
|
972
|
-
(0,
|
|
972
|
+
(0, import_node_fs25.unlinkSync)(tmpCopy);
|
|
973
973
|
} catch {
|
|
974
974
|
}
|
|
975
975
|
}
|
|
@@ -980,9 +980,9 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
980
980
|
return { ok: false, error: `\u65E0\u6CD5\u5C06\u97F3\u9891\u8F6C\u6362\u4E3A WAV \u683C\u5F0F\u3002${fmtHint}` };
|
|
981
981
|
}
|
|
982
982
|
function cleanupTmpWav(path2) {
|
|
983
|
-
if (path2 && (0,
|
|
983
|
+
if (path2 && (0, import_node_fs25.existsSync)(path2)) {
|
|
984
984
|
try {
|
|
985
|
-
(0,
|
|
985
|
+
(0, import_node_fs25.unlinkSync)(path2);
|
|
986
986
|
} catch {
|
|
987
987
|
}
|
|
988
988
|
}
|
|
@@ -1068,13 +1068,13 @@ function formatBytes2(bytes) {
|
|
|
1068
1068
|
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
1069
1069
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;
|
|
1070
1070
|
}
|
|
1071
|
-
var import_node_child_process2,
|
|
1071
|
+
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
1072
|
var init_whisper_local = __esm({
|
|
1073
1073
|
"src/recording/whisper-local.ts"() {
|
|
1074
1074
|
"use strict";
|
|
1075
1075
|
import_node_child_process2 = require("child_process");
|
|
1076
|
-
|
|
1077
|
-
|
|
1076
|
+
import_node_fs25 = require("fs");
|
|
1077
|
+
import_node_path21 = require("path");
|
|
1078
1078
|
import_promises3 = require("stream/promises");
|
|
1079
1079
|
import_node_stream2 = require("stream");
|
|
1080
1080
|
import_node_os4 = require("os");
|
|
@@ -1229,7 +1229,7 @@ async function initializeAsr(config, dataDir, logger) {
|
|
|
1229
1229
|
}
|
|
1230
1230
|
}
|
|
1231
1231
|
async function transcribeAudio(audioFilePath, config, logger, options = {}) {
|
|
1232
|
-
if (!(0,
|
|
1232
|
+
if (!(0, import_node_fs26.existsSync)(audioFilePath)) {
|
|
1233
1233
|
return { ok: false, error: `\u97F3\u9891\u6587\u4EF6\u4E0D\u5B58\u5728: ${audioFilePath}` };
|
|
1234
1234
|
}
|
|
1235
1235
|
logger.info(
|
|
@@ -1240,6 +1240,7 @@ async function transcribeAudio(audioFilePath, config, logger, options = {}) {
|
|
|
1240
1240
|
case "api":
|
|
1241
1241
|
return await transcribeWithModelProxy(
|
|
1242
1242
|
options.audioOssUrl,
|
|
1243
|
+
options.audioDurationMs,
|
|
1243
1244
|
config.api,
|
|
1244
1245
|
logger
|
|
1245
1246
|
);
|
|
@@ -1339,7 +1340,8 @@ async function runTranscriptionWorkflow(params) {
|
|
|
1339
1340
|
logger
|
|
1340
1341
|
} = params;
|
|
1341
1342
|
const result = await transcribeAudio(audioFilePath, config, logger, {
|
|
1342
|
-
audioOssUrl
|
|
1343
|
+
audioOssUrl,
|
|
1344
|
+
audioDurationMs: Math.max(0, Math.round(durationSec * 1e3))
|
|
1343
1345
|
});
|
|
1344
1346
|
if (!result.ok) {
|
|
1345
1347
|
return { ok: false, error: result.error };
|
|
@@ -1373,8 +1375,8 @@ async function runTranscriptionWorkflow(params) {
|
|
|
1373
1375
|
createdAt
|
|
1374
1376
|
);
|
|
1375
1377
|
const transcriptDataFilename = buildTranscriptDataFilename(recordingId);
|
|
1376
|
-
const transcriptDataPath = (0,
|
|
1377
|
-
(0,
|
|
1378
|
+
const transcriptDataPath = (0, import_node_path22.join)(transcriptDataDir, transcriptDataFilename);
|
|
1379
|
+
(0, import_node_fs26.writeFileSync)(
|
|
1378
1380
|
transcriptDataPath,
|
|
1379
1381
|
JSON.stringify(transcriptData, null, 2),
|
|
1380
1382
|
"utf-8"
|
|
@@ -1382,14 +1384,14 @@ async function runTranscriptionWorkflow(params) {
|
|
|
1382
1384
|
logger.info(`[asr] \u8F6C\u5199 JSON \u5DF2\u5199\u5165: ${transcriptDataPath}`);
|
|
1383
1385
|
const safeSummary = title.replace(/[/\\:*?"<>|]/g, "").trim().slice(0, 20);
|
|
1384
1386
|
const filename = safeSummary ? `${recordingId}_${safeSummary}.md` : `${recordingId}.md`;
|
|
1385
|
-
const filePath = (0,
|
|
1386
|
-
(0,
|
|
1387
|
+
const filePath = (0, import_node_path22.join)(transcriptsDir, filename);
|
|
1388
|
+
(0, import_node_fs26.writeFileSync)(filePath, markdown, "utf-8");
|
|
1387
1389
|
logger.info(`[asr] \u8F6C\u5199\u6587\u672C\u5DF2\u5199\u5165: ${filePath}`);
|
|
1388
1390
|
let summaryFilename;
|
|
1389
1391
|
if (summary) {
|
|
1390
1392
|
summaryFilename = `${recordingId}.md`;
|
|
1391
|
-
const summaryFilePath = (0,
|
|
1392
|
-
(0,
|
|
1393
|
+
const summaryFilePath = (0, import_node_path22.join)(summariesDir, summaryFilename);
|
|
1394
|
+
(0, import_node_fs26.writeFileSync)(summaryFilePath, summary, "utf-8");
|
|
1393
1395
|
logger.info(`[asr] \u6458\u8981\u6587\u672C\u5DF2\u5199\u5165: ${summaryFilePath}`);
|
|
1394
1396
|
}
|
|
1395
1397
|
return {
|
|
@@ -1402,7 +1404,7 @@ async function runTranscriptionWorkflow(params) {
|
|
|
1402
1404
|
title
|
|
1403
1405
|
};
|
|
1404
1406
|
}
|
|
1405
|
-
async function transcribeWithModelProxy(audioOssUrl, apiConfig, logger) {
|
|
1407
|
+
async function transcribeWithModelProxy(audioOssUrl, audioDurationMs, apiConfig, logger) {
|
|
1406
1408
|
const normalizedAudioOssUrl = normalizeOptionalText2(audioOssUrl);
|
|
1407
1409
|
if (!normalizedAudioOssUrl) {
|
|
1408
1410
|
return { ok: false, error: "API \u6A21\u5F0F\u7F3A\u5C11 audioOssUrl\uFF0C\u65E0\u6CD5\u8C03\u7528 model-proxy" };
|
|
@@ -1468,13 +1470,14 @@ async function transcribeWithModelProxy(audioOssUrl, apiConfig, logger) {
|
|
|
1468
1470
|
apiKey,
|
|
1469
1471
|
taskId,
|
|
1470
1472
|
initialRequestId: requestId,
|
|
1473
|
+
audioDurationMs,
|
|
1471
1474
|
apiConfig,
|
|
1472
1475
|
logger
|
|
1473
1476
|
});
|
|
1474
1477
|
}
|
|
1475
1478
|
async function transcribeWithWhisperLocal2(audioFilePath, config, logger) {
|
|
1476
1479
|
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,
|
|
1480
|
+
const dataDir = process.env.OPENCLAW_STATE_DIR ?? process.env.QCLAW_STATE_DIR ?? (0, import_node_path22.join)(audioFilePath, "..", "..", "..");
|
|
1478
1481
|
const localConfig = config.local ?? {};
|
|
1479
1482
|
const result = await runLocal(
|
|
1480
1483
|
audioFilePath,
|
|
@@ -1530,6 +1533,7 @@ async function pollLongRecordingTaskResult(params) {
|
|
|
1530
1533
|
apiKey,
|
|
1531
1534
|
taskId,
|
|
1532
1535
|
initialRequestId,
|
|
1536
|
+
audioDurationMs,
|
|
1533
1537
|
apiConfig,
|
|
1534
1538
|
logger
|
|
1535
1539
|
} = params;
|
|
@@ -1577,7 +1581,13 @@ async function pollLongRecordingTaskResult(params) {
|
|
|
1577
1581
|
lastStatus = status;
|
|
1578
1582
|
}
|
|
1579
1583
|
if (status === "SUCCEEDED") {
|
|
1580
|
-
return buildLongRecordingSuccessResult(
|
|
1584
|
+
return buildLongRecordingSuccessResult(
|
|
1585
|
+
taskId,
|
|
1586
|
+
requestId,
|
|
1587
|
+
data,
|
|
1588
|
+
audioDurationMs,
|
|
1589
|
+
logger
|
|
1590
|
+
);
|
|
1581
1591
|
}
|
|
1582
1592
|
if (LONG_RECORDING_TERMINAL_FAILURE_STATUSES.has(status)) {
|
|
1583
1593
|
return {
|
|
@@ -1600,11 +1610,11 @@ async function pollLongRecordingTaskResult(params) {
|
|
|
1600
1610
|
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
1611
|
};
|
|
1602
1612
|
}
|
|
1603
|
-
function buildLongRecordingSuccessResult(taskId, requestId, data, logger) {
|
|
1613
|
+
function buildLongRecordingSuccessResult(taskId, requestId, data, audioDurationMs, logger) {
|
|
1604
1614
|
const sourceTextList = normalizeLongRecordingSourceTextList(
|
|
1605
1615
|
data?.recordResult?.sourceTextList
|
|
1606
1616
|
);
|
|
1607
|
-
const listResult = extractLongRecordingTextFromList(sourceTextList);
|
|
1617
|
+
const listResult = extractLongRecordingTextFromList(sourceTextList, audioDurationMs);
|
|
1608
1618
|
const sourceText = normalizeOptionalText2(data?.recordResult?.sourceText);
|
|
1609
1619
|
const summaryText = normalizeOptionalText2(data?.recordResult?.summaryResult) ?? "";
|
|
1610
1620
|
const title = normalizeOptionalText2(data?.recordResult?.title);
|
|
@@ -1701,11 +1711,12 @@ function normalizeLongRecordingSourceTextList(value) {
|
|
|
1701
1711
|
return [{
|
|
1702
1712
|
content,
|
|
1703
1713
|
speakerId: normalizeOptionalInteger2(record.speakerId),
|
|
1704
|
-
startTime: normalizeOptionalNonNegativeNumber(record.startTime)
|
|
1714
|
+
startTime: normalizeOptionalNonNegativeNumber(record.startTime),
|
|
1715
|
+
endTime: normalizeOptionalNonNegativeNumber(record.endTime)
|
|
1705
1716
|
}];
|
|
1706
1717
|
});
|
|
1707
1718
|
}
|
|
1708
|
-
function extractLongRecordingTextFromList(items) {
|
|
1719
|
+
function extractLongRecordingTextFromList(items, finalFallbackEndMs) {
|
|
1709
1720
|
if (items.length === 0) {
|
|
1710
1721
|
return {
|
|
1711
1722
|
segments: []
|
|
@@ -1713,10 +1724,13 @@ function extractLongRecordingTextFromList(items) {
|
|
|
1713
1724
|
}
|
|
1714
1725
|
const segments = items.map((item, index) => {
|
|
1715
1726
|
const startMs = item.startTime ?? 0;
|
|
1727
|
+
const explicitEndMs = item.endTime;
|
|
1716
1728
|
const nextStart = items[index + 1]?.startTime;
|
|
1729
|
+
const fallbackEndMs = index === items.length - 1 ? normalizeOptionalNonNegativeNumber(finalFallbackEndMs) : void 0;
|
|
1730
|
+
const endMs = explicitEndMs ?? nextStart ?? fallbackEndMs ?? startMs;
|
|
1717
1731
|
return {
|
|
1718
1732
|
start_ms: startMs,
|
|
1719
|
-
end_ms:
|
|
1733
|
+
end_ms: Math.max(startMs, endMs),
|
|
1720
1734
|
text: item.content,
|
|
1721
1735
|
speaker_id: item.speakerId
|
|
1722
1736
|
};
|
|
@@ -1772,12 +1786,12 @@ function formatTranscriptSegmentText(segment) {
|
|
|
1772
1786
|
}
|
|
1773
1787
|
return text;
|
|
1774
1788
|
}
|
|
1775
|
-
var
|
|
1789
|
+
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
1790
|
var init_asr = __esm({
|
|
1777
1791
|
"src/recording/asr.ts"() {
|
|
1778
1792
|
"use strict";
|
|
1779
|
-
|
|
1780
|
-
|
|
1793
|
+
import_node_fs26 = require("fs");
|
|
1794
|
+
import_node_path22 = require("path");
|
|
1781
1795
|
init_credentials();
|
|
1782
1796
|
init_env();
|
|
1783
1797
|
init_transcript_document();
|
|
@@ -5422,7 +5436,7 @@ function readBuildInjectedVersion() {
|
|
|
5422
5436
|
if (false) {
|
|
5423
5437
|
return void 0;
|
|
5424
5438
|
}
|
|
5425
|
-
const version = "1.11.0".trim();
|
|
5439
|
+
const version = "1.11.2-beta.0".trim();
|
|
5426
5440
|
return version || void 0;
|
|
5427
5441
|
}
|
|
5428
5442
|
function readPluginVersionFromPackageJson() {
|
|
@@ -6035,20 +6049,17 @@ function readOptionalString(value) {
|
|
|
6035
6049
|
const trimmed = value.trim();
|
|
6036
6050
|
return trimmed || void 0;
|
|
6037
6051
|
}
|
|
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
6052
|
function readMeta(taskDir) {
|
|
6042
6053
|
const metaPath = (0, import_node_path3.join)(taskDir, "meta.json");
|
|
6043
6054
|
if (!(0, import_node_fs4.existsSync)(metaPath)) return null;
|
|
6044
6055
|
try {
|
|
6045
6056
|
const raw = JSON.parse((0, import_node_fs4.readFileSync)(metaPath, "utf-8"));
|
|
6046
6057
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
6047
|
-
if (raw.type !== "light-rule"
|
|
6058
|
+
if (raw.type !== "light-rule") return null;
|
|
6048
6059
|
if (!Array.isArray(raw.segments)) return null;
|
|
6049
6060
|
const name = readOptionalString(raw.name) ?? (0, import_node_path3.basename)(taskDir);
|
|
6050
6061
|
const title = readOptionalString(raw.title) ?? name;
|
|
6051
|
-
const description = readOptionalString(raw.description) ??
|
|
6062
|
+
const description = readOptionalString(raw.description) ?? name;
|
|
6052
6063
|
const createdAt = readOptionalString(raw.createdAt) ?? (0, import_node_fs4.statSync)(metaPath).birthtime.toISOString();
|
|
6053
6064
|
const enabled = typeof raw.enabled === "boolean" ? raw.enabled : true;
|
|
6054
6065
|
const repeatTimes = normalizeRepeatTimes({
|
|
@@ -6939,12 +6950,13 @@ init_credentials();
|
|
|
6939
6950
|
// src/light/sender.ts
|
|
6940
6951
|
var import_node_crypto = require("crypto");
|
|
6941
6952
|
init_env();
|
|
6942
|
-
async function sendLightEffect(apiKey, segments, logger, repeatInput, reason) {
|
|
6953
|
+
async function sendLightEffect(apiKey, segments, logger, repeatInput, reason, title) {
|
|
6943
6954
|
const apiUrl = getEnvUrls().lightApiUrl;
|
|
6944
6955
|
const appKey = "7Q617S1G5WD274JI";
|
|
6945
6956
|
const templateId = "1990771146010017800";
|
|
6957
|
+
const resolvedTitle = resolveLightTitle(title, reason, segments);
|
|
6946
6958
|
logger?.info(
|
|
6947
|
-
`Light sender: apiUrl=${apiUrl ?? "UNSET"}, appKey=${appKey ? appKey.substring(0, 8) + "\u2026" : "UNSET"}, templateId=${templateId ?? "UNSET"}, apiKey=${apiKey ? apiKey.substring(0, 20) + "\u2026" : "EMPTY"}, segments=${JSON.stringify(segments)}`
|
|
6959
|
+
`Light sender: apiUrl=${apiUrl ?? "UNSET"}, appKey=${appKey ? appKey.substring(0, 8) + "\u2026" : "UNSET"}, templateId=${templateId ?? "UNSET"}, apiKey=${apiKey ? apiKey.substring(0, 20) + "\u2026" : "EMPTY"}, title=${resolvedTitle}, reason=${reason ?? ""}, segments=${JSON.stringify(segments)}`
|
|
6948
6960
|
);
|
|
6949
6961
|
if (!apiUrl || !appKey || !templateId) {
|
|
6950
6962
|
return {
|
|
@@ -6961,7 +6973,7 @@ async function sendLightEffect(apiKey, segments, logger, repeatInput, reason) {
|
|
|
6961
6973
|
const bizUniqueId = (0, import_node_crypto.randomUUID)();
|
|
6962
6974
|
const requestBody = {
|
|
6963
6975
|
appKey,
|
|
6964
|
-
bizMap: { noticeType: "APP_NOTIFICATION_IMPORTANT", reason },
|
|
6976
|
+
bizMap: { noticeType: "APP_NOTIFICATION_IMPORTANT", title: resolvedTitle, reason },
|
|
6965
6977
|
bizUniqueId,
|
|
6966
6978
|
paramsMap: { bizContent },
|
|
6967
6979
|
pushType: "SPECIFY_PUSH",
|
|
@@ -6988,6 +7000,14 @@ async function sendLightEffect(apiKey, segments, logger, repeatInput, reason) {
|
|
|
6988
7000
|
logger?.info(`Light sender: OK bizUniqueId=${bizUniqueId}, resBody=${resBody.substring(0, 200)}`);
|
|
6989
7001
|
return { ok: true, bizUniqueId, response: JSON.parse(resBody) };
|
|
6990
7002
|
}
|
|
7003
|
+
function resolveLightTitle(title, reason, segments) {
|
|
7004
|
+
const trimmedTitle = title?.trim();
|
|
7005
|
+
if (trimmedTitle) return trimmedTitle;
|
|
7006
|
+
const trimmedReason = reason?.trim();
|
|
7007
|
+
if (trimmedReason) return trimmedReason;
|
|
7008
|
+
const modeDesc = segments.map((segment) => segment.mode).join("+");
|
|
7009
|
+
return `Effect: ${modeDesc || "custom"}`;
|
|
7010
|
+
}
|
|
6991
7011
|
|
|
6992
7012
|
// src/light-rules/inline-evaluator.ts
|
|
6993
7013
|
var InlineLightRuleEvaluator = class {
|
|
@@ -7050,7 +7070,8 @@ var InlineLightRuleEvaluator = class {
|
|
|
7050
7070
|
rule.segments,
|
|
7051
7071
|
this.logger,
|
|
7052
7072
|
{ repeat_times: rule.repeat_times },
|
|
7053
|
-
rule.description
|
|
7073
|
+
rule.description,
|
|
7074
|
+
rule.title
|
|
7054
7075
|
);
|
|
7055
7076
|
if (!result.ok) {
|
|
7056
7077
|
this.logger.warn(
|
|
@@ -7065,115 +7086,6 @@ var InlineLightRuleEvaluator = class {
|
|
|
7065
7086
|
}
|
|
7066
7087
|
};
|
|
7067
7088
|
|
|
7068
|
-
// src/light-rules/migration.ts
|
|
7069
|
-
var import_node_fs8 = require("fs");
|
|
7070
|
-
var import_node_path7 = require("path");
|
|
7071
|
-
var NO_MATCH_FETCH_PY = `#!/usr/bin/env python3
|
|
7072
|
-
# \u6B64\u6587\u4EF6\u7531\u8FC1\u79FB\u5DE5\u5177\u751F\u6210\u3002
|
|
7073
|
-
# \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
|
|
7074
|
-
print("NO_MATCH")
|
|
7075
|
-
`;
|
|
7076
|
-
function normalizeScriptText(text) {
|
|
7077
|
-
return text.replace(/\r\n/g, "\n").trim();
|
|
7078
|
-
}
|
|
7079
|
-
function resolveTasksDir(ctx) {
|
|
7080
|
-
if (ctx.workspaceDir) return (0, import_node_path7.join)(ctx.workspaceDir, "tasks");
|
|
7081
|
-
if (ctx.stateDir) {
|
|
7082
|
-
const inferredWorkspaceDir = (0, import_node_path7.join)(ctx.stateDir, "workspace");
|
|
7083
|
-
if ((0, import_node_fs8.existsSync)(inferredWorkspaceDir)) return (0, import_node_path7.join)(inferredWorkspaceDir, "tasks");
|
|
7084
|
-
return (0, import_node_path7.join)(ctx.stateDir, "tasks");
|
|
7085
|
-
}
|
|
7086
|
-
return null;
|
|
7087
|
-
}
|
|
7088
|
-
function migrateLegacyLightRuleTasks(ctx, logger) {
|
|
7089
|
-
const tasksDir3 = resolveTasksDir(ctx);
|
|
7090
|
-
if (!tasksDir3 || !(0, import_node_fs8.existsSync)(tasksDir3)) return;
|
|
7091
|
-
try {
|
|
7092
|
-
for (const entry of (0, import_node_fs8.readdirSync)(tasksDir3, { withFileTypes: true })) {
|
|
7093
|
-
if (!entry.isDirectory()) continue;
|
|
7094
|
-
migrateTaskDir((0, import_node_path7.join)(tasksDir3, String(entry.name)), logger);
|
|
7095
|
-
}
|
|
7096
|
-
} catch (err2) {
|
|
7097
|
-
logger.warn(`migration: failed to read tasks dir: ${err2?.message}`);
|
|
7098
|
-
}
|
|
7099
|
-
}
|
|
7100
|
-
function migrateTaskDir(taskDir, logger) {
|
|
7101
|
-
const metaPath = (0, import_node_path7.join)(taskDir, "meta.json");
|
|
7102
|
-
if (!(0, import_node_fs8.existsSync)(metaPath)) return;
|
|
7103
|
-
let meta;
|
|
7104
|
-
try {
|
|
7105
|
-
meta = JSON.parse((0, import_node_fs8.readFileSync)(metaPath, "utf-8"));
|
|
7106
|
-
} catch {
|
|
7107
|
-
return;
|
|
7108
|
-
}
|
|
7109
|
-
if (meta.type !== "light-rule") return;
|
|
7110
|
-
const name = typeof meta.name === "string" ? meta.name : taskDir;
|
|
7111
|
-
cleanupLegacyMetaFields(meta, name, metaPath, logger);
|
|
7112
|
-
replaceFetchPy(taskDir, name, logger);
|
|
7113
|
-
for (const filename of ["README.md", "checkpoint.json"]) {
|
|
7114
|
-
removeFile((0, import_node_path7.join)(taskDir, filename), name, filename, logger);
|
|
7115
|
-
}
|
|
7116
|
-
}
|
|
7117
|
-
function cleanupLegacyMetaFields(meta, name, metaPath, logger) {
|
|
7118
|
-
const cleaned = [];
|
|
7119
|
-
if (mergeMatchRulesIntoDescription(meta)) cleaned.push("matchRules");
|
|
7120
|
-
if (meta.cronSchedule !== void 0) {
|
|
7121
|
-
delete meta.cronSchedule;
|
|
7122
|
-
cleaned.push("cronSchedule");
|
|
7123
|
-
}
|
|
7124
|
-
if (cleaned.length === 0) return;
|
|
7125
|
-
try {
|
|
7126
|
-
(0, import_node_fs8.writeFileSync)(metaPath, JSON.stringify(meta, null, 2), "utf-8");
|
|
7127
|
-
logger.info(
|
|
7128
|
-
`migration: cleaned deprecated field(s) [${cleaned.join(", ")}] in meta.json for light rule: ${name}`
|
|
7129
|
-
);
|
|
7130
|
-
} catch (err2) {
|
|
7131
|
-
logger.warn(`migration: failed to update meta.json for ${name}: ${err2?.message}`);
|
|
7132
|
-
}
|
|
7133
|
-
}
|
|
7134
|
-
function mergeMatchRulesIntoDescription(meta) {
|
|
7135
|
-
const matchRules = meta.matchRules;
|
|
7136
|
-
if (!matchRules || typeof matchRules !== "object") return false;
|
|
7137
|
-
const rules = matchRules;
|
|
7138
|
-
const parts = [];
|
|
7139
|
-
if (rules.appName) parts.push(`app=${rules.appName}`);
|
|
7140
|
-
if (rules.senderKeywords?.length) {
|
|
7141
|
-
parts.push(`\u53D1\u4EF6\u4EBA\u5173\u952E\u8BCD=${rules.senderKeywords.join("\u3001")}`);
|
|
7142
|
-
}
|
|
7143
|
-
if (rules.contentKeywords?.length) {
|
|
7144
|
-
parts.push(`\u5185\u5BB9\u5173\u952E\u8BCD=${rules.contentKeywords.join("\u3001")}`);
|
|
7145
|
-
}
|
|
7146
|
-
if (parts.length > 0) {
|
|
7147
|
-
const existing = typeof meta.description === "string" ? meta.description.trim() : "";
|
|
7148
|
-
meta.description = existing ? `${existing}\u3002\u5339\u914D\u89C4\u5219\uFF1A${parts.join("\uFF0C")}` : `\u5339\u914D\u89C4\u5219\uFF1A${parts.join("\uFF0C")}`;
|
|
7149
|
-
}
|
|
7150
|
-
delete meta.matchRules;
|
|
7151
|
-
return true;
|
|
7152
|
-
}
|
|
7153
|
-
function replaceFetchPy(taskDir, name, logger) {
|
|
7154
|
-
const fetchPyPath = (0, import_node_path7.join)(taskDir, "fetch.py");
|
|
7155
|
-
if (!(0, import_node_fs8.existsSync)(fetchPyPath)) return;
|
|
7156
|
-
try {
|
|
7157
|
-
const existing = (0, import_node_fs8.readFileSync)(fetchPyPath, "utf-8");
|
|
7158
|
-
if (normalizeScriptText(existing) === normalizeScriptText(NO_MATCH_FETCH_PY)) {
|
|
7159
|
-
return;
|
|
7160
|
-
}
|
|
7161
|
-
(0, import_node_fs8.writeFileSync)(fetchPyPath, NO_MATCH_FETCH_PY, "utf-8");
|
|
7162
|
-
logger.info(`migration: replaced fetch.py with NO_MATCH placeholder for ${name}`);
|
|
7163
|
-
} catch (err2) {
|
|
7164
|
-
logger.warn(`migration: failed to replace fetch.py for ${name}: ${err2?.message}`);
|
|
7165
|
-
}
|
|
7166
|
-
}
|
|
7167
|
-
function removeFile(filePath, ruleName, filename, logger) {
|
|
7168
|
-
if (!(0, import_node_fs8.existsSync)(filePath)) return;
|
|
7169
|
-
try {
|
|
7170
|
-
(0, import_node_fs8.rmSync)(filePath);
|
|
7171
|
-
logger.info(`migration: removed ${filename} for light rule: ${ruleName}`);
|
|
7172
|
-
} catch (err2) {
|
|
7173
|
-
logger.warn(`migration: failed to remove ${filename} for ${ruleName}: ${err2?.message}`);
|
|
7174
|
-
}
|
|
7175
|
-
}
|
|
7176
|
-
|
|
7177
7089
|
// src/light-rules/pi-invoker.ts
|
|
7178
7090
|
var import_agent_runtime = require("openclaw/plugin-sdk/agent-runtime");
|
|
7179
7091
|
var DEFAULT_PROVIDER = "anthropic";
|
|
@@ -7355,7 +7267,7 @@ function resolveUpdateChannel(params) {
|
|
|
7355
7267
|
}
|
|
7356
7268
|
|
|
7357
7269
|
// src/update/index.ts
|
|
7358
|
-
var
|
|
7270
|
+
var import_node_path8 = require("path");
|
|
7359
7271
|
|
|
7360
7272
|
// src/update/checker.ts
|
|
7361
7273
|
function parseSemver(v) {
|
|
@@ -7457,8 +7369,8 @@ var UpdateChecker = class {
|
|
|
7457
7369
|
};
|
|
7458
7370
|
|
|
7459
7371
|
// src/update/executor.ts
|
|
7460
|
-
var
|
|
7461
|
-
var
|
|
7372
|
+
var import_node_fs8 = require("fs");
|
|
7373
|
+
var import_node_path7 = require("path");
|
|
7462
7374
|
var import_node_os = require("os");
|
|
7463
7375
|
var VERSION_PATTERN = /^\d+\.\d+\.\d+(-[\w.]+)?$/;
|
|
7464
7376
|
var BASE_URL = "https://artifact.yoooclaw.com/plugin";
|
|
@@ -7468,9 +7380,9 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7468
7380
|
}
|
|
7469
7381
|
const tgzUrl = `${BASE_URL}/v${version}/yoooclaw-phone-notifications-${version}.tgz`;
|
|
7470
7382
|
logger.info(`\u6267\u884C\u66F4\u65B0: ${tgzUrl} \u2192 ${targetDir}`);
|
|
7471
|
-
const workDir = (0,
|
|
7472
|
-
const tgzPath = (0,
|
|
7473
|
-
const stagingDir = (0,
|
|
7383
|
+
const workDir = (0, import_node_fs8.mkdtempSync)((0, import_node_path7.join)((0, import_node_os.tmpdir)(), ".openclaw-plugin-update-"));
|
|
7384
|
+
const tgzPath = (0, import_node_path7.join)(workDir, "plugin.tgz");
|
|
7385
|
+
const stagingDir = (0, import_node_path7.join)(workDir, "staged");
|
|
7474
7386
|
let backupDir = null;
|
|
7475
7387
|
try {
|
|
7476
7388
|
logger.info("\u4E0B\u8F7D\u63D2\u4EF6\u5305...");
|
|
@@ -7479,9 +7391,9 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7479
7391
|
return { success: false, message: `\u4E0B\u8F7D\u5931\u8D25 (HTTP ${response.status}): ${tgzUrl}` };
|
|
7480
7392
|
}
|
|
7481
7393
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
7482
|
-
(0,
|
|
7394
|
+
(0, import_node_fs8.writeFileSync)(tgzPath, buffer);
|
|
7483
7395
|
logger.info(`\u4E0B\u8F7D\u5B8C\u6210 (${buffer.length} bytes)`);
|
|
7484
|
-
(0,
|
|
7396
|
+
(0, import_node_fs8.mkdirSync)(stagingDir, { recursive: true });
|
|
7485
7397
|
const tarResult = await runCommand(
|
|
7486
7398
|
["tar", "-xzf", tgzPath, "-C", stagingDir, "--strip-components=1"],
|
|
7487
7399
|
{ timeoutMs: 3e4 }
|
|
@@ -7490,14 +7402,14 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7490
7402
|
const err2 = tarResult.stderr || tarResult.stdout || "unknown error";
|
|
7491
7403
|
return { success: false, message: `\u89E3\u538B\u5931\u8D25: ${err2}` };
|
|
7492
7404
|
}
|
|
7493
|
-
(0,
|
|
7405
|
+
(0, import_node_fs8.mkdirSync)((0, import_node_path7.dirname)(targetDir), { recursive: true });
|
|
7494
7406
|
try {
|
|
7495
7407
|
backupDir = `${targetDir}.bak.${Date.now()}`;
|
|
7496
|
-
(0,
|
|
7408
|
+
(0, import_node_fs8.renameSync)(targetDir, backupDir);
|
|
7497
7409
|
} catch {
|
|
7498
7410
|
backupDir = null;
|
|
7499
7411
|
}
|
|
7500
|
-
(0,
|
|
7412
|
+
(0, import_node_fs8.renameSync)(stagingDir, targetDir);
|
|
7501
7413
|
try {
|
|
7502
7414
|
await updateConfigRecord2(version, tgzUrl);
|
|
7503
7415
|
} catch (err2) {
|
|
@@ -7505,18 +7417,18 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7505
7417
|
}
|
|
7506
7418
|
if (backupDir) {
|
|
7507
7419
|
try {
|
|
7508
|
-
(0,
|
|
7420
|
+
(0, import_node_fs8.rmSync)(backupDir, { force: true, recursive: true });
|
|
7509
7421
|
} catch {
|
|
7510
7422
|
}
|
|
7511
7423
|
}
|
|
7512
|
-
const msg = `\u5DF2\u66F4\u65B0\u5230 ${version}
|
|
7424
|
+
const msg = `\u5DF2\u66F4\u65B0\u5230 ${version}`;
|
|
7513
7425
|
logger.info(msg);
|
|
7514
|
-
return { success: true, message: msg };
|
|
7426
|
+
return { success: true, message: msg, version };
|
|
7515
7427
|
} catch (err2) {
|
|
7516
7428
|
if (backupDir) {
|
|
7517
7429
|
try {
|
|
7518
|
-
(0,
|
|
7519
|
-
(0,
|
|
7430
|
+
(0, import_node_fs8.rmSync)(targetDir, { force: true, recursive: true });
|
|
7431
|
+
(0, import_node_fs8.renameSync)(backupDir, targetDir);
|
|
7520
7432
|
logger.info("\u5DF2\u56DE\u6EDA\u5230\u4E4B\u524D\u7248\u672C");
|
|
7521
7433
|
} catch (rollbackErr) {
|
|
7522
7434
|
logger.error(`\u56DE\u6EDA\u5931\u8D25: ${String(rollbackErr)}`);
|
|
@@ -7527,12 +7439,47 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7527
7439
|
return { success: false, message: errMsg };
|
|
7528
7440
|
} finally {
|
|
7529
7441
|
try {
|
|
7530
|
-
(0,
|
|
7442
|
+
(0, import_node_fs8.rmSync)(workDir, { force: true, recursive: true });
|
|
7531
7443
|
} catch {
|
|
7532
7444
|
}
|
|
7533
7445
|
}
|
|
7534
7446
|
}
|
|
7535
7447
|
|
|
7448
|
+
// src/update/restart.ts
|
|
7449
|
+
function scheduleGatewayRestart(logger, deps = {}) {
|
|
7450
|
+
try {
|
|
7451
|
+
const cfg = deps.loadConfig?.();
|
|
7452
|
+
if (cfg?.commands?.restart === false) {
|
|
7453
|
+
logger.warn("\u66F4\u65B0\u540E\u8DF3\u8FC7 gateway \u91CD\u542F: commands.restart=false");
|
|
7454
|
+
return { scheduled: false };
|
|
7455
|
+
}
|
|
7456
|
+
} catch (err2) {
|
|
7457
|
+
logger.warn(`\u66F4\u65B0\u540E\u68C0\u67E5 gateway \u91CD\u542F\u914D\u7F6E\u5931\u8D25: ${String(err2)}`);
|
|
7458
|
+
}
|
|
7459
|
+
const getListenerCount = deps.getListenerCount ?? ((signal) => process.listenerCount(signal));
|
|
7460
|
+
if (getListenerCount("SIGUSR1") < 1) {
|
|
7461
|
+
logger.warn("\u66F4\u65B0\u540E\u8DF3\u8FC7 gateway \u91CD\u542F: \u5F53\u524D\u8FDB\u7A0B\u672A\u6CE8\u518C SIGUSR1 \u76D1\u542C\u5668");
|
|
7462
|
+
return { scheduled: false };
|
|
7463
|
+
}
|
|
7464
|
+
const emitSignal = deps.emitSignal ?? ((signal) => process.emit(signal));
|
|
7465
|
+
const schedule = deps.schedule ?? ((task) => {
|
|
7466
|
+
setTimeout(task, 0);
|
|
7467
|
+
});
|
|
7468
|
+
schedule(() => {
|
|
7469
|
+
try {
|
|
7470
|
+
const accepted = emitSignal("SIGUSR1");
|
|
7471
|
+
if (accepted) {
|
|
7472
|
+
logger.info("\u66F4\u65B0\u5B8C\u6210\uFF0C\u5DF2\u89E6\u53D1 gateway SIGUSR1 \u91CD\u542F");
|
|
7473
|
+
} else {
|
|
7474
|
+
logger.warn("\u66F4\u65B0\u5B8C\u6210\uFF0C\u4F46 gateway SIGUSR1 \u4FE1\u53F7\u672A\u88AB\u5904\u7406");
|
|
7475
|
+
}
|
|
7476
|
+
} catch (err2) {
|
|
7477
|
+
logger.warn(`\u66F4\u65B0\u540E\u89E6\u53D1 gateway \u91CD\u542F\u5931\u8D25: ${String(err2)}`);
|
|
7478
|
+
}
|
|
7479
|
+
});
|
|
7480
|
+
return { scheduled: true };
|
|
7481
|
+
}
|
|
7482
|
+
|
|
7536
7483
|
// src/update/index.ts
|
|
7537
7484
|
var PLUGIN_ID = "phone-notifications";
|
|
7538
7485
|
function resolveTargetDir(api) {
|
|
@@ -7542,7 +7489,7 @@ function resolveTargetDir(api) {
|
|
|
7542
7489
|
if (installPath) return installPath;
|
|
7543
7490
|
} catch {
|
|
7544
7491
|
}
|
|
7545
|
-
return (0,
|
|
7492
|
+
return (0, import_node_path8.join)(api.runtime.state.resolveStateDir(), "extensions", PLUGIN_ID);
|
|
7546
7493
|
}
|
|
7547
7494
|
async function updateConfigRecord(api, version, targetDir, tgzUrl) {
|
|
7548
7495
|
const configApi = api.runtime.config;
|
|
@@ -7560,6 +7507,23 @@ async function updateConfigRecord(api, version, targetDir, tgzUrl) {
|
|
|
7560
7507
|
};
|
|
7561
7508
|
await configApi.writeConfigFile(cfg);
|
|
7562
7509
|
}
|
|
7510
|
+
function finalizeUpdateResult(api, logger, result) {
|
|
7511
|
+
if (!result.success) {
|
|
7512
|
+
return result;
|
|
7513
|
+
}
|
|
7514
|
+
const restart = scheduleGatewayRestart(logger, {
|
|
7515
|
+
loadConfig: () => {
|
|
7516
|
+
const configApi = api.runtime.config;
|
|
7517
|
+
return configApi?.loadConfig?.();
|
|
7518
|
+
}
|
|
7519
|
+
});
|
|
7520
|
+
const version = result.version ?? "\u76EE\u6807\u7248\u672C";
|
|
7521
|
+
return {
|
|
7522
|
+
...result,
|
|
7523
|
+
restartScheduled: restart.scheduled,
|
|
7524
|
+
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`
|
|
7525
|
+
};
|
|
7526
|
+
}
|
|
7563
7527
|
function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast, externalUpdateNotifier) {
|
|
7564
7528
|
if (config.enabled === false) {
|
|
7565
7529
|
logger.info("\u81EA\u52A8\u66F4\u65B0\u5DF2\u7981\u7528 (autoUpdate.enabled = false)");
|
|
@@ -7591,7 +7555,7 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
|
|
|
7591
7555
|
api.registerTool({
|
|
7592
7556
|
name: "plugin-update",
|
|
7593
7557
|
label: "Plugin Update",
|
|
7594
|
-
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\
|
|
7558
|
+
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",
|
|
7595
7559
|
parameters: {
|
|
7596
7560
|
type: "object",
|
|
7597
7561
|
required: ["version"],
|
|
@@ -7613,13 +7577,14 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
|
|
|
7613
7577
|
targetDir,
|
|
7614
7578
|
(v, url) => updateConfigRecord(api, v, targetDir, url)
|
|
7615
7579
|
);
|
|
7616
|
-
|
|
7580
|
+
const finalResult = finalizeUpdateResult(api, logger, result);
|
|
7581
|
+
if (finalResult.success) {
|
|
7617
7582
|
pendingUpdate = null;
|
|
7618
7583
|
externalUpdateNotifier?.clearPendingUpdate();
|
|
7619
7584
|
}
|
|
7620
7585
|
return {
|
|
7621
|
-
content: [{ type: "text", text:
|
|
7622
|
-
details:
|
|
7586
|
+
content: [{ type: "text", text: finalResult.message }],
|
|
7587
|
+
details: finalResult
|
|
7623
7588
|
};
|
|
7624
7589
|
}
|
|
7625
7590
|
});
|
|
@@ -7641,16 +7606,20 @@ function registerAutoUpdate(api, logger, config, getBroadcast, rememberBroadcast
|
|
|
7641
7606
|
targetDir,
|
|
7642
7607
|
(v, url) => updateConfigRecord(api, v, targetDir, url)
|
|
7643
7608
|
);
|
|
7644
|
-
|
|
7609
|
+
const finalResult = finalizeUpdateResult(api, logger, result);
|
|
7610
|
+
if (finalResult.success) {
|
|
7645
7611
|
pendingUpdate = null;
|
|
7646
7612
|
externalUpdateNotifier?.clearPendingUpdate();
|
|
7647
7613
|
}
|
|
7648
|
-
if (
|
|
7649
|
-
respond(true, {
|
|
7614
|
+
if (finalResult.success) {
|
|
7615
|
+
respond(true, {
|
|
7616
|
+
message: finalResult.message,
|
|
7617
|
+
restartScheduled: finalResult.restartScheduled === true
|
|
7618
|
+
});
|
|
7650
7619
|
} else {
|
|
7651
7620
|
respond(false, void 0, {
|
|
7652
7621
|
code: "UPDATE_FAILED",
|
|
7653
|
-
message:
|
|
7622
|
+
message: finalResult.message
|
|
7654
7623
|
});
|
|
7655
7624
|
}
|
|
7656
7625
|
});
|
|
@@ -7730,10 +7699,10 @@ function registerAutoUpdateLifecycle(deps) {
|
|
|
7730
7699
|
}
|
|
7731
7700
|
|
|
7732
7701
|
// src/plugin/cli.ts
|
|
7733
|
-
var
|
|
7702
|
+
var import_node_path16 = require("path");
|
|
7734
7703
|
|
|
7735
7704
|
// src/cli/auth.ts
|
|
7736
|
-
var
|
|
7705
|
+
var import_node_fs9 = require("fs");
|
|
7737
7706
|
init_credentials();
|
|
7738
7707
|
function registerAuthCli(program) {
|
|
7739
7708
|
const auth = program.command("auth").description("\u7528\u6237\u8BA4\u8BC1\u7BA1\u7406");
|
|
@@ -7769,12 +7738,12 @@ function registerAuthCli(program) {
|
|
|
7769
7738
|
});
|
|
7770
7739
|
auth.command("clear").description("\u6E05\u9664\u5DF2\u4FDD\u5B58\u7684\u8BA4\u8BC1\u4FE1\u606F").action(() => {
|
|
7771
7740
|
const path2 = credentialsPath();
|
|
7772
|
-
if ((0,
|
|
7741
|
+
if ((0, import_node_fs9.existsSync)(path2)) {
|
|
7773
7742
|
const creds = readCredentials();
|
|
7774
7743
|
delete creds.apiKey;
|
|
7775
7744
|
delete creds.token;
|
|
7776
7745
|
if (Object.keys(creds).length === 0) {
|
|
7777
|
-
(0,
|
|
7746
|
+
(0, import_node_fs9.rmSync)(path2, { force: true });
|
|
7778
7747
|
} else {
|
|
7779
7748
|
writeCredentials(creds);
|
|
7780
7749
|
}
|
|
@@ -7906,23 +7875,23 @@ function registerNtfStats(ntf, ctx) {
|
|
|
7906
7875
|
}
|
|
7907
7876
|
|
|
7908
7877
|
// src/cli/ntf-sync.ts
|
|
7909
|
-
var
|
|
7910
|
-
var
|
|
7878
|
+
var import_node_fs10 = require("fs");
|
|
7879
|
+
var import_node_path9 = require("path");
|
|
7911
7880
|
var SYNC_FETCH_LIMIT = 300;
|
|
7912
7881
|
function checkpointPath(dir) {
|
|
7913
|
-
return (0,
|
|
7882
|
+
return (0, import_node_path9.join)(dir, ".checkpoint.json");
|
|
7914
7883
|
}
|
|
7915
7884
|
function readCheckpoint(dir) {
|
|
7916
7885
|
const p = checkpointPath(dir);
|
|
7917
|
-
if (!(0,
|
|
7886
|
+
if (!(0, import_node_fs10.existsSync)(p)) return {};
|
|
7918
7887
|
try {
|
|
7919
|
-
return JSON.parse((0,
|
|
7888
|
+
return JSON.parse((0, import_node_fs10.readFileSync)(p, "utf-8"));
|
|
7920
7889
|
} catch {
|
|
7921
7890
|
return {};
|
|
7922
7891
|
}
|
|
7923
7892
|
}
|
|
7924
7893
|
function writeCheckpoint(dir, data) {
|
|
7925
|
-
(0,
|
|
7894
|
+
(0, import_node_fs10.writeFileSync)(checkpointPath(dir), JSON.stringify(data, null, 2), "utf-8");
|
|
7926
7895
|
}
|
|
7927
7896
|
function registerNtfSync(ntf, ctx) {
|
|
7928
7897
|
const sync = ntf.command("sync").description("\u540C\u6B65\u901A\u77E5\u5230\u8BB0\u5FC6\u7CFB\u7EDF");
|
|
@@ -8015,8 +7984,8 @@ function registerNtfSync(ntf, ctx) {
|
|
|
8015
7984
|
}
|
|
8016
7985
|
|
|
8017
7986
|
// src/cli/ntf-monitor.ts
|
|
8018
|
-
var
|
|
8019
|
-
var
|
|
7987
|
+
var import_node_fs11 = require("fs");
|
|
7988
|
+
var import_node_path10 = require("path");
|
|
8020
7989
|
|
|
8021
7990
|
// src/monitor/fetch-gen.ts
|
|
8022
7991
|
function generateFetchPy(name, matchRules) {
|
|
@@ -8101,19 +8070,19 @@ function pyLiteral(value) {
|
|
|
8101
8070
|
function tasksDir2(ctx) {
|
|
8102
8071
|
const base = ctx.workspaceDir || ctx.stateDir;
|
|
8103
8072
|
if (!base) throw new Error("workspaceDir and stateDir both unavailable");
|
|
8104
|
-
return (0,
|
|
8073
|
+
return (0, import_node_path10.join)(base, "tasks");
|
|
8105
8074
|
}
|
|
8106
8075
|
function readMeta2(taskDir) {
|
|
8107
|
-
const metaPath = (0,
|
|
8108
|
-
if (!(0,
|
|
8076
|
+
const metaPath = (0, import_node_path10.join)(taskDir, "meta.json");
|
|
8077
|
+
if (!(0, import_node_fs11.existsSync)(metaPath)) return null;
|
|
8109
8078
|
try {
|
|
8110
|
-
return JSON.parse((0,
|
|
8079
|
+
return JSON.parse((0, import_node_fs11.readFileSync)(metaPath, "utf-8"));
|
|
8111
8080
|
} catch {
|
|
8112
8081
|
return null;
|
|
8113
8082
|
}
|
|
8114
8083
|
}
|
|
8115
8084
|
function writeMeta2(taskDir, meta) {
|
|
8116
|
-
(0,
|
|
8085
|
+
(0, import_node_fs11.writeFileSync)((0, import_node_path10.join)(taskDir, "meta.json"), JSON.stringify(meta, null, 2), "utf-8");
|
|
8117
8086
|
}
|
|
8118
8087
|
function generateReadme(name, description) {
|
|
8119
8088
|
return `# Monitor Task: ${name}
|
|
@@ -8132,27 +8101,27 @@ function registerNtfMonitor(ntf, ctx) {
|
|
|
8132
8101
|
const monitor = ntf.command("monitor").description("\u901A\u77E5\u76D1\u63A7\u4EFB\u52A1\u7BA1\u7406");
|
|
8133
8102
|
monitor.command("list").description("\u5217\u51FA\u6240\u6709\u76D1\u63A7\u4EFB\u52A1").action(() => {
|
|
8134
8103
|
const dir = tasksDir2(ctx);
|
|
8135
|
-
if (!(0,
|
|
8104
|
+
if (!(0, import_node_fs11.existsSync)(dir)) {
|
|
8136
8105
|
output({ ok: true, tasks: [] });
|
|
8137
8106
|
return;
|
|
8138
8107
|
}
|
|
8139
8108
|
const tasks = [];
|
|
8140
|
-
for (const entry of (0,
|
|
8109
|
+
for (const entry of (0, import_node_fs11.readdirSync)(dir, { withFileTypes: true })) {
|
|
8141
8110
|
if (!entry.isDirectory()) continue;
|
|
8142
|
-
const meta = readMeta2((0,
|
|
8111
|
+
const meta = readMeta2((0, import_node_path10.join)(dir, entry.name));
|
|
8143
8112
|
if (meta) tasks.push(meta);
|
|
8144
8113
|
}
|
|
8145
8114
|
output({ ok: true, tasks });
|
|
8146
8115
|
});
|
|
8147
8116
|
monitor.command("show <name>").description("\u67E5\u770B\u76D1\u63A7\u4EFB\u52A1\u8BE6\u60C5").action((name) => {
|
|
8148
|
-
const taskDir = (0,
|
|
8117
|
+
const taskDir = (0, import_node_path10.join)(tasksDir2(ctx), name);
|
|
8149
8118
|
const meta = readMeta2(taskDir);
|
|
8150
8119
|
if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
|
|
8151
|
-
const checkpointPath2 = (0,
|
|
8120
|
+
const checkpointPath2 = (0, import_node_path10.join)(taskDir, "checkpoint.json");
|
|
8152
8121
|
let checkpoint = {};
|
|
8153
|
-
if ((0,
|
|
8122
|
+
if ((0, import_node_fs11.existsSync)(checkpointPath2)) {
|
|
8154
8123
|
try {
|
|
8155
|
-
checkpoint = JSON.parse((0,
|
|
8124
|
+
checkpoint = JSON.parse((0, import_node_fs11.readFileSync)(checkpointPath2, "utf-8"));
|
|
8156
8125
|
} catch {
|
|
8157
8126
|
}
|
|
8158
8127
|
}
|
|
@@ -8167,8 +8136,8 @@ function registerNtfMonitor(ntf, ctx) {
|
|
|
8167
8136
|
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(
|
|
8168
8137
|
(name, opts) => {
|
|
8169
8138
|
const dir = tasksDir2(ctx);
|
|
8170
|
-
const taskDir = (0,
|
|
8171
|
-
if ((0,
|
|
8139
|
+
const taskDir = (0, import_node_path10.join)(dir, name);
|
|
8140
|
+
if ((0, import_node_fs11.existsSync)(taskDir)) {
|
|
8172
8141
|
exitError("ALREADY_EXISTS", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u5DF2\u5B58\u5728`);
|
|
8173
8142
|
}
|
|
8174
8143
|
let matchRules;
|
|
@@ -8180,7 +8149,7 @@ function registerNtfMonitor(ntf, ctx) {
|
|
|
8180
8149
|
"match-rules \u5FC5\u987B\u662F\u5408\u6CD5\u7684 JSON"
|
|
8181
8150
|
);
|
|
8182
8151
|
}
|
|
8183
|
-
(0,
|
|
8152
|
+
(0, import_node_fs11.mkdirSync)(taskDir, { recursive: true });
|
|
8184
8153
|
const meta = {
|
|
8185
8154
|
name,
|
|
8186
8155
|
description: opts.description,
|
|
@@ -8190,13 +8159,13 @@ function registerNtfMonitor(ntf, ctx) {
|
|
|
8190
8159
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8191
8160
|
};
|
|
8192
8161
|
writeMeta2(taskDir, meta);
|
|
8193
|
-
(0,
|
|
8194
|
-
(0,
|
|
8162
|
+
(0, import_node_fs11.writeFileSync)(
|
|
8163
|
+
(0, import_node_path10.join)(taskDir, "fetch.py"),
|
|
8195
8164
|
generateFetchPy(name, matchRules),
|
|
8196
8165
|
"utf-8"
|
|
8197
8166
|
);
|
|
8198
|
-
(0,
|
|
8199
|
-
(0,
|
|
8167
|
+
(0, import_node_fs11.writeFileSync)(
|
|
8168
|
+
(0, import_node_path10.join)(taskDir, "README.md"),
|
|
8200
8169
|
generateReadme(name, opts.description),
|
|
8201
8170
|
"utf-8"
|
|
8202
8171
|
);
|
|
@@ -8224,8 +8193,8 @@ function registerNtfMonitor(ntf, ctx) {
|
|
|
8224
8193
|
}
|
|
8225
8194
|
);
|
|
8226
8195
|
monitor.command("delete <name>").description("\u5220\u9664\u76D1\u63A7\u4EFB\u52A1").option("--yes", "\u8DF3\u8FC7\u786E\u8BA4").action((name, opts) => {
|
|
8227
|
-
const taskDir = (0,
|
|
8228
|
-
if (!(0,
|
|
8196
|
+
const taskDir = (0, import_node_path10.join)(tasksDir2(ctx), name);
|
|
8197
|
+
if (!(0, import_node_fs11.existsSync)(taskDir)) {
|
|
8229
8198
|
exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
|
|
8230
8199
|
}
|
|
8231
8200
|
if (!opts.yes) {
|
|
@@ -8238,7 +8207,7 @@ function registerNtfMonitor(ntf, ctx) {
|
|
|
8238
8207
|
});
|
|
8239
8208
|
process.exit(1);
|
|
8240
8209
|
}
|
|
8241
|
-
(0,
|
|
8210
|
+
(0, import_node_fs11.rmSync)(taskDir, { recursive: true, force: true });
|
|
8242
8211
|
output({
|
|
8243
8212
|
ok: true,
|
|
8244
8213
|
name,
|
|
@@ -8250,7 +8219,7 @@ function registerNtfMonitor(ntf, ctx) {
|
|
|
8250
8219
|
});
|
|
8251
8220
|
});
|
|
8252
8221
|
monitor.command("enable <name>").description("\u542F\u7528\u76D1\u63A7\u4EFB\u52A1").action((name) => {
|
|
8253
|
-
const taskDir = (0,
|
|
8222
|
+
const taskDir = (0, import_node_path10.join)(tasksDir2(ctx), name);
|
|
8254
8223
|
const meta = readMeta2(taskDir);
|
|
8255
8224
|
if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
|
|
8256
8225
|
meta.enabled = true;
|
|
@@ -8258,7 +8227,7 @@ function registerNtfMonitor(ntf, ctx) {
|
|
|
8258
8227
|
output({ ok: true, name, enabled: true });
|
|
8259
8228
|
});
|
|
8260
8229
|
monitor.command("disable <name>").description("\u6682\u505C\u76D1\u63A7\u4EFB\u52A1").action((name) => {
|
|
8261
|
-
const taskDir = (0,
|
|
8230
|
+
const taskDir = (0, import_node_path10.join)(tasksDir2(ctx), name);
|
|
8262
8231
|
const meta = readMeta2(taskDir);
|
|
8263
8232
|
if (!meta) exitError("NOT_FOUND", `\u76D1\u63A7\u4EFB\u52A1 '${name}' \u4E0D\u5B58\u5728`);
|
|
8264
8233
|
meta.enabled = false;
|
|
@@ -8302,9 +8271,9 @@ function registerLightSend(light) {
|
|
|
8302
8271
|
}
|
|
8303
8272
|
|
|
8304
8273
|
// src/cli/light-setup-tools.ts
|
|
8305
|
-
var
|
|
8274
|
+
var import_node_fs12 = require("fs");
|
|
8306
8275
|
var import_node_os2 = require("os");
|
|
8307
|
-
var
|
|
8276
|
+
var import_node_path11 = require("path");
|
|
8308
8277
|
function isObject(value) {
|
|
8309
8278
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
8310
8279
|
}
|
|
@@ -8318,7 +8287,7 @@ function ensureArray(obj, key) {
|
|
|
8318
8287
|
function resolveConfigPath2() {
|
|
8319
8288
|
const fromEnv = process.env.OPENCLAW_CONFIG_PATH?.trim();
|
|
8320
8289
|
if (fromEnv) return fromEnv;
|
|
8321
|
-
return (0,
|
|
8290
|
+
return (0, import_node_path11.join)((0, import_node_os2.homedir)(), ".openclaw", "openclaw.json");
|
|
8322
8291
|
}
|
|
8323
8292
|
var LIGHT_TOOLS = [
|
|
8324
8293
|
"light_control",
|
|
@@ -8365,12 +8334,12 @@ function upsertLightControlAlsoAllow(cfg) {
|
|
|
8365
8334
|
function registerLightSetupTools(light) {
|
|
8366
8335
|
light.command("setup").description("\u81EA\u52A8\u653E\u884C light_control\uFF08\u5199\u5165 tools.alsoAllow \u4E0E agents.main.tools.alsoAllow\uFF09").action(() => {
|
|
8367
8336
|
const configPath = resolveConfigPath2();
|
|
8368
|
-
if (!(0,
|
|
8337
|
+
if (!(0, import_node_fs12.existsSync)(configPath)) {
|
|
8369
8338
|
exitError("CONFIG_NOT_FOUND", `\u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6: ${configPath}`);
|
|
8370
8339
|
}
|
|
8371
8340
|
let cfg = {};
|
|
8372
8341
|
try {
|
|
8373
|
-
const raw = (0,
|
|
8342
|
+
const raw = (0, import_node_fs12.readFileSync)(configPath, "utf-8");
|
|
8374
8343
|
const parsed = JSON.parse(raw);
|
|
8375
8344
|
if (isObject(parsed)) cfg = parsed;
|
|
8376
8345
|
} catch (err2) {
|
|
@@ -8378,8 +8347,8 @@ function registerLightSetupTools(light) {
|
|
|
8378
8347
|
}
|
|
8379
8348
|
const result = upsertLightControlAlsoAllow(cfg);
|
|
8380
8349
|
try {
|
|
8381
|
-
(0,
|
|
8382
|
-
(0,
|
|
8350
|
+
(0, import_node_fs12.mkdirSync)((0, import_node_path11.dirname)(configPath), { recursive: true });
|
|
8351
|
+
(0, import_node_fs12.writeFileSync)(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
|
|
8383
8352
|
} catch (err2) {
|
|
8384
8353
|
exitError("WRITE_FAILED", `\u5199\u5165\u914D\u7F6E\u5931\u8D25: ${err2?.message ?? String(err2)}`);
|
|
8385
8354
|
}
|
|
@@ -8397,17 +8366,17 @@ function registerLightSetupTools(light) {
|
|
|
8397
8366
|
}
|
|
8398
8367
|
|
|
8399
8368
|
// src/cli/tunnel-status.ts
|
|
8400
|
-
var
|
|
8401
|
-
var
|
|
8369
|
+
var import_node_fs13 = require("fs");
|
|
8370
|
+
var import_node_path12 = require("path");
|
|
8402
8371
|
init_credentials();
|
|
8403
8372
|
init_env();
|
|
8404
|
-
var STATUS_REL_PATH = (0,
|
|
8373
|
+
var STATUS_REL_PATH = (0, import_node_path12.join)("plugins", "phone-notifications", "tunnel-status.json");
|
|
8405
8374
|
function readTunnelStatus(ctx) {
|
|
8406
8375
|
if (!ctx.stateDir) return null;
|
|
8407
|
-
const filePath = (0,
|
|
8408
|
-
if (!(0,
|
|
8376
|
+
const filePath = (0, import_node_path12.join)(ctx.stateDir, STATUS_REL_PATH);
|
|
8377
|
+
if (!(0, import_node_fs13.existsSync)(filePath)) return null;
|
|
8409
8378
|
try {
|
|
8410
|
-
return JSON.parse((0,
|
|
8379
|
+
return JSON.parse((0, import_node_fs13.readFileSync)(filePath, "utf-8"));
|
|
8411
8380
|
} catch {
|
|
8412
8381
|
return null;
|
|
8413
8382
|
}
|
|
@@ -8475,24 +8444,24 @@ function registerNtfStoragePath(ntf, ctx) {
|
|
|
8475
8444
|
}
|
|
8476
8445
|
|
|
8477
8446
|
// src/cli/log-search.ts
|
|
8478
|
-
var
|
|
8479
|
-
var
|
|
8447
|
+
var import_node_fs14 = require("fs");
|
|
8448
|
+
var import_node_path13 = require("path");
|
|
8480
8449
|
function resolveLogsDir(ctx) {
|
|
8481
8450
|
if (ctx.stateDir) {
|
|
8482
|
-
const dir = (0,
|
|
8451
|
+
const dir = (0, import_node_path13.join)(
|
|
8483
8452
|
ctx.stateDir,
|
|
8484
8453
|
"plugins",
|
|
8485
8454
|
"phone-notifications",
|
|
8486
8455
|
"logs"
|
|
8487
8456
|
);
|
|
8488
|
-
if ((0,
|
|
8457
|
+
if ((0, import_node_fs14.existsSync)(dir)) return dir;
|
|
8489
8458
|
}
|
|
8490
8459
|
return null;
|
|
8491
8460
|
}
|
|
8492
8461
|
function listLogDateKeys(dir) {
|
|
8493
8462
|
const pattern = /^(\d{4}-\d{2}-\d{2})\.log$/;
|
|
8494
8463
|
const keys = [];
|
|
8495
|
-
for (const entry of (0,
|
|
8464
|
+
for (const entry of (0, import_node_fs14.readdirSync)(dir, { withFileTypes: true })) {
|
|
8496
8465
|
if (!entry.isFile()) continue;
|
|
8497
8466
|
const m = pattern.exec(entry.name);
|
|
8498
8467
|
if (m) keys.push(m[1]);
|
|
@@ -8500,9 +8469,9 @@ function listLogDateKeys(dir) {
|
|
|
8500
8469
|
return keys.sort().reverse();
|
|
8501
8470
|
}
|
|
8502
8471
|
function collectLogLines(dir, dateKey, keyword, limit, collected) {
|
|
8503
|
-
const filePath = (0,
|
|
8504
|
-
if (!(0,
|
|
8505
|
-
const content = (0,
|
|
8472
|
+
const filePath = (0, import_node_path13.join)(dir, `${dateKey}.log`);
|
|
8473
|
+
if (!(0, import_node_fs14.existsSync)(filePath)) return;
|
|
8474
|
+
const content = (0, import_node_fs14.readFileSync)(filePath, "utf-8");
|
|
8506
8475
|
const lowerKeyword = keyword?.toLowerCase();
|
|
8507
8476
|
for (const line of content.split("\n")) {
|
|
8508
8477
|
if (collected.length >= limit) return;
|
|
@@ -8569,12 +8538,12 @@ function registerEnvCli(ntf) {
|
|
|
8569
8538
|
}
|
|
8570
8539
|
|
|
8571
8540
|
// src/cli/doctor.ts
|
|
8572
|
-
var
|
|
8541
|
+
var import_node_fs18 = require("fs");
|
|
8573
8542
|
var import_node_readline = require("readline");
|
|
8574
8543
|
init_host();
|
|
8575
8544
|
|
|
8576
8545
|
// src/cli/doctor/check-dangerous-flags.ts
|
|
8577
|
-
var
|
|
8546
|
+
var import_node_fs15 = require("fs");
|
|
8578
8547
|
function isObject2(v) {
|
|
8579
8548
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
8580
8549
|
}
|
|
@@ -8591,13 +8560,13 @@ var checkDangerousFlags = ({ cfg, configPath }) => {
|
|
|
8591
8560
|
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",
|
|
8592
8561
|
fixDescription: "\u8BBE\u4E3A false",
|
|
8593
8562
|
fix: () => {
|
|
8594
|
-
const raw = (0,
|
|
8563
|
+
const raw = (0, import_node_fs15.readFileSync)(configPath, "utf-8");
|
|
8595
8564
|
const config = JSON.parse(raw);
|
|
8596
8565
|
const gw = config.gateway;
|
|
8597
8566
|
const cui = gw.controlUi;
|
|
8598
8567
|
cui.dangerouslyDisableDeviceAuth = false;
|
|
8599
|
-
(0,
|
|
8600
|
-
(0,
|
|
8568
|
+
(0, import_node_fs15.copyFileSync)(configPath, configPath + ".bak");
|
|
8569
|
+
(0, import_node_fs15.writeFileSync)(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
8601
8570
|
}
|
|
8602
8571
|
};
|
|
8603
8572
|
};
|
|
@@ -8645,11 +8614,11 @@ function warnEmpty() {
|
|
|
8645
8614
|
}
|
|
8646
8615
|
|
|
8647
8616
|
// src/cli/doctor/check-state-dir-perms.ts
|
|
8648
|
-
var
|
|
8617
|
+
var import_node_fs16 = require("fs");
|
|
8649
8618
|
var checkStateDirPerms = ({ stateDir }) => {
|
|
8650
8619
|
let mode;
|
|
8651
8620
|
try {
|
|
8652
|
-
mode = (0,
|
|
8621
|
+
mode = (0, import_node_fs16.statSync)(stateDir).mode;
|
|
8653
8622
|
} catch {
|
|
8654
8623
|
return null;
|
|
8655
8624
|
}
|
|
@@ -8663,7 +8632,7 @@ var checkStateDirPerms = ({ stateDir }) => {
|
|
|
8663
8632
|
detail: "\u5176\u4ED6\u7528\u6237\u53EF\u4EE5\u8BFB\u53D6\u8BE5\u76EE\u5F55\u4E0B\u7684\u51ED\u8BC1\u548C\u914D\u7F6E\u6587\u4EF6\u3002",
|
|
8664
8633
|
fixDescription: "chmod 700 " + stateDir,
|
|
8665
8634
|
fix: () => {
|
|
8666
|
-
(0,
|
|
8635
|
+
(0, import_node_fs16.chmodSync)(stateDir, 448);
|
|
8667
8636
|
}
|
|
8668
8637
|
};
|
|
8669
8638
|
};
|
|
@@ -8718,16 +8687,16 @@ var checkCredentials = () => {
|
|
|
8718
8687
|
};
|
|
8719
8688
|
|
|
8720
8689
|
// src/cli/doctor/check-tunnel.ts
|
|
8721
|
-
var
|
|
8722
|
-
var
|
|
8723
|
-
var STATUS_REL_PATH2 = (0,
|
|
8690
|
+
var import_node_fs17 = require("fs");
|
|
8691
|
+
var import_node_path14 = require("path");
|
|
8692
|
+
var STATUS_REL_PATH2 = (0, import_node_path14.join)(
|
|
8724
8693
|
"plugins",
|
|
8725
8694
|
"phone-notifications",
|
|
8726
8695
|
"tunnel-status.json"
|
|
8727
8696
|
);
|
|
8728
8697
|
var checkTunnel = ({ stateDir }) => {
|
|
8729
|
-
const filePath = (0,
|
|
8730
|
-
if (!(0,
|
|
8698
|
+
const filePath = (0, import_node_path14.join)(stateDir, STATUS_REL_PATH2);
|
|
8699
|
+
if (!(0, import_node_fs17.existsSync)(filePath)) {
|
|
8731
8700
|
return {
|
|
8732
8701
|
id: "tunnel",
|
|
8733
8702
|
severity: "warn",
|
|
@@ -8739,7 +8708,7 @@ var checkTunnel = ({ stateDir }) => {
|
|
|
8739
8708
|
}
|
|
8740
8709
|
let status;
|
|
8741
8710
|
try {
|
|
8742
|
-
status = JSON.parse((0,
|
|
8711
|
+
status = JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
|
|
8743
8712
|
} catch {
|
|
8744
8713
|
return {
|
|
8745
8714
|
id: "tunnel",
|
|
@@ -8832,9 +8801,9 @@ function isObject5(v) {
|
|
|
8832
8801
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
8833
8802
|
}
|
|
8834
8803
|
function readConfig(configPath) {
|
|
8835
|
-
if (!(0,
|
|
8804
|
+
if (!(0, import_node_fs18.existsSync)(configPath)) return {};
|
|
8836
8805
|
try {
|
|
8837
|
-
const parsed = JSON.parse((0,
|
|
8806
|
+
const parsed = JSON.parse((0, import_node_fs18.readFileSync)(configPath, "utf-8"));
|
|
8838
8807
|
return isObject5(parsed) ? parsed : {};
|
|
8839
8808
|
} catch {
|
|
8840
8809
|
return {};
|
|
@@ -9035,7 +9004,7 @@ function registerRecStoragePath(rec, ctx) {
|
|
|
9035
9004
|
|
|
9036
9005
|
// src/cli/rec-setup.ts
|
|
9037
9006
|
var import_node_readline2 = require("readline");
|
|
9038
|
-
var
|
|
9007
|
+
var import_node_fs19 = require("fs");
|
|
9039
9008
|
function ask(rl, question) {
|
|
9040
9009
|
return new Promise((resolve) => rl.question(question, resolve));
|
|
9041
9010
|
}
|
|
@@ -9121,9 +9090,9 @@ async function setupLocal(rl) {
|
|
|
9121
9090
|
function registerRecSetup(rec, ctx) {
|
|
9122
9091
|
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 () => {
|
|
9123
9092
|
const configPath = resolveAsrConfigPath(ctx);
|
|
9124
|
-
if ((0,
|
|
9093
|
+
if ((0, import_node_fs19.existsSync)(configPath)) {
|
|
9125
9094
|
try {
|
|
9126
|
-
const existing = JSON.parse((0,
|
|
9095
|
+
const existing = JSON.parse((0, import_node_fs19.readFileSync)(configPath, "utf-8"));
|
|
9127
9096
|
process.stderr.write(`\u5F53\u524D\u5DF2\u6709\u914D\u7F6E\uFF1Amode = ${existing.mode}`);
|
|
9128
9097
|
if (existing.updatedAt) process.stderr.write(`\uFF0C\u66F4\u65B0\u4E8E ${existing.updatedAt}`);
|
|
9129
9098
|
process.stderr.write("\n");
|
|
@@ -9136,7 +9105,7 @@ function registerRecSetup(rec, ctx) {
|
|
|
9136
9105
|
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"]);
|
|
9137
9106
|
const config = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);
|
|
9138
9107
|
const stored = { ...config, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9139
|
-
(0,
|
|
9108
|
+
(0, import_node_fs19.writeFileSync)(configPath, JSON.stringify(stored, null, 2), "utf-8");
|
|
9140
9109
|
process.stderr.write(`
|
|
9141
9110
|
\u2713 \u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230 ${configPath}
|
|
9142
9111
|
|
|
@@ -9150,8 +9119,8 @@ function registerRecSetup(rec, ctx) {
|
|
|
9150
9119
|
|
|
9151
9120
|
// src/cli/update.ts
|
|
9152
9121
|
var import_node_child_process = require("child_process");
|
|
9153
|
-
var
|
|
9154
|
-
var
|
|
9122
|
+
var import_node_fs20 = require("fs");
|
|
9123
|
+
var import_node_path15 = require("path");
|
|
9155
9124
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
9156
9125
|
init_host();
|
|
9157
9126
|
var BASE_URL2 = "https://artifact.yoooclaw.com/plugin";
|
|
@@ -9210,9 +9179,9 @@ async function runUpdate(ctx, opts) {
|
|
|
9210
9179
|
`);
|
|
9211
9180
|
process.exit(1);
|
|
9212
9181
|
}
|
|
9213
|
-
const tmpScript = (0,
|
|
9182
|
+
const tmpScript = (0, import_node_path15.join)(import_node_os3.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
|
|
9214
9183
|
try {
|
|
9215
|
-
(0,
|
|
9184
|
+
(0, import_node_fs20.writeFileSync)(tmpScript, installScript, "utf-8");
|
|
9216
9185
|
} catch (err2) {
|
|
9217
9186
|
const msg = `\u5199\u5165\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${err2?.message ?? String(err2)}`;
|
|
9218
9187
|
if (json) {
|
|
@@ -9230,7 +9199,7 @@ async function runUpdate(ctx, opts) {
|
|
|
9230
9199
|
{ stdio: "inherit" }
|
|
9231
9200
|
);
|
|
9232
9201
|
try {
|
|
9233
|
-
(0,
|
|
9202
|
+
(0, import_node_fs20.unlinkSync)(tmpScript);
|
|
9234
9203
|
} catch {
|
|
9235
9204
|
}
|
|
9236
9205
|
if (result.error) {
|
|
@@ -9294,10 +9263,10 @@ function inferOpenClawRootDir(workspaceDir) {
|
|
|
9294
9263
|
if (!workspaceDir) {
|
|
9295
9264
|
return void 0;
|
|
9296
9265
|
}
|
|
9297
|
-
if ((0,
|
|
9266
|
+
if ((0, import_node_path16.basename)(workspaceDir) !== "workspace") {
|
|
9298
9267
|
return void 0;
|
|
9299
9268
|
}
|
|
9300
|
-
return (0,
|
|
9269
|
+
return (0, import_node_path16.dirname)(workspaceDir);
|
|
9301
9270
|
}
|
|
9302
9271
|
function registerPluginCli(api, params) {
|
|
9303
9272
|
const { logger, openclawDir } = params;
|
|
@@ -9468,6 +9437,10 @@ var lightControlParameters = {
|
|
|
9468
9437
|
type: "string",
|
|
9469
9438
|
description: "\u7ED3\u5408\u5BF9\u8BDD\u4E0A\u4E0B\u6587\uFF0C\u7B80\u8981\u8BF4\u660E\u4E3A\u4EC0\u4E48\u8981\u4EAE\u706F\uFF08\u4F8B\u5982\uFF1A\u7528\u6237\u5FC3\u60C5\u4F4E\u843D\u60F3\u8981\u6E29\u6696\u6C1B\u56F4\u3001\u5E86\u795D\u751F\u65E5\u3001\u63D0\u9192\u559D\u6C34\u7B49\uFF09\u3002\u8FD9\u4E2A\u5B57\u6BB5\u5E2E\u52A9\u8BB0\u5F55\u6BCF\u6B21\u4EAE\u706F\u7684\u610F\u56FE\u548C\u52A8\u673A\u3002"
|
|
9470
9439
|
},
|
|
9440
|
+
title: {
|
|
9441
|
+
type: "string",
|
|
9442
|
+
description: "\u5BF9\u672C\u6B21\u4EAE\u706F\u7684\u7B80\u77ED\u6807\u9898/\u6458\u8981\uFF08\u4F8B\u5982\uFF1A\u6E29\u6696\u6C1B\u56F4\u3001\u751F\u65E5\u5E86\u795D\u3001\u559D\u6C34\u63D0\u9192\uFF09\u3002\u4E0D\u586B\u65F6\u9ED8\u8BA4\u56DE\u9000\u5230 reason\u3002"
|
|
9443
|
+
},
|
|
9471
9444
|
repeat: {
|
|
9472
9445
|
type: "boolean",
|
|
9473
9446
|
description: "\u517C\u5BB9\u65E7\u53C2\u6570\u3002true = \u65E0\u9650\u5FAA\u73AF\uFF0Cfalse/\u4E0D\u586B = \u4E00\u8F6E\uFF1B\u82E5\u540C\u65F6\u63D0\u4F9B repeat_times\uFF0C\u5219\u4EE5\u540E\u8005\u4E3A\u51C6"
|
|
@@ -9495,7 +9468,7 @@ function registerLightControlTool(api, logger) {
|
|
|
9495
9468
|
details: { ok: false, error: { code: "AUTH_REQUIRED", message: e.message } }
|
|
9496
9469
|
};
|
|
9497
9470
|
}
|
|
9498
|
-
const { segments, reason, repeat, repeat_times } = params;
|
|
9471
|
+
const { segments, title, reason, repeat, repeat_times } = params;
|
|
9499
9472
|
const validation = validateSegments(segments);
|
|
9500
9473
|
if (!validation.valid) {
|
|
9501
9474
|
return {
|
|
@@ -9519,13 +9492,14 @@ function registerLightControlTool(api, logger) {
|
|
|
9519
9492
|
}
|
|
9520
9493
|
};
|
|
9521
9494
|
}
|
|
9522
|
-
logger.info(`Light control reason: ${reason}`);
|
|
9495
|
+
logger.info(`Light control title: ${title ?? ""}, reason: ${reason}`);
|
|
9523
9496
|
const result = await sendLightEffect(
|
|
9524
9497
|
apiKey,
|
|
9525
9498
|
validation.segments,
|
|
9526
9499
|
logger,
|
|
9527
9500
|
{ repeat_times: repeatTimes },
|
|
9528
|
-
reason
|
|
9501
|
+
reason,
|
|
9502
|
+
title
|
|
9529
9503
|
);
|
|
9530
9504
|
if (!result.ok) {
|
|
9531
9505
|
logger.warn(
|
|
@@ -9543,12 +9517,12 @@ function registerLightControlTool(api, logger) {
|
|
|
9543
9517
|
}
|
|
9544
9518
|
|
|
9545
9519
|
// src/plugin/lifecycle.ts
|
|
9546
|
-
var
|
|
9520
|
+
var import_node_fs30 = require("fs");
|
|
9547
9521
|
init_host();
|
|
9548
9522
|
|
|
9549
9523
|
// src/notification/app-name-map.ts
|
|
9550
|
-
var
|
|
9551
|
-
var
|
|
9524
|
+
var import_node_fs21 = require("fs");
|
|
9525
|
+
var import_node_path17 = require("path");
|
|
9552
9526
|
init_credentials();
|
|
9553
9527
|
init_env();
|
|
9554
9528
|
var PLUGIN_STATE_DIR = "phone-notifications";
|
|
@@ -9569,7 +9543,7 @@ function isAppNameMapApiResponse(v) {
|
|
|
9569
9543
|
);
|
|
9570
9544
|
}
|
|
9571
9545
|
function getCachePath(stateDir) {
|
|
9572
|
-
return (0,
|
|
9546
|
+
return (0, import_node_path17.join)(stateDir, "plugins", PLUGIN_STATE_DIR, CACHE_FILE);
|
|
9573
9547
|
}
|
|
9574
9548
|
function createAppNameMapProvider(opts) {
|
|
9575
9549
|
const { stateDir, logger } = opts;
|
|
@@ -9581,9 +9555,9 @@ function createAppNameMapProvider(opts) {
|
|
|
9581
9555
|
let inFlightFetch = null;
|
|
9582
9556
|
function loadFromDisk() {
|
|
9583
9557
|
const path2 = getCachePath(stateDir);
|
|
9584
|
-
if (!(0,
|
|
9558
|
+
if (!(0, import_node_fs21.existsSync)(path2)) return;
|
|
9585
9559
|
try {
|
|
9586
|
-
const raw = JSON.parse((0,
|
|
9560
|
+
const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf-8"));
|
|
9587
9561
|
if (!isRecordOfStrings(raw)) return;
|
|
9588
9562
|
map.clear();
|
|
9589
9563
|
for (const [k, v] of Object.entries(raw)) map.set(k, v);
|
|
@@ -9627,10 +9601,10 @@ function createAppNameMapProvider(opts) {
|
|
|
9627
9601
|
logger.warn("[app-name-map] refresh succeeded but got 0 entries");
|
|
9628
9602
|
return;
|
|
9629
9603
|
}
|
|
9630
|
-
const dir = (0,
|
|
9631
|
-
(0,
|
|
9604
|
+
const dir = (0, import_node_path17.join)(stateDir, "plugins", PLUGIN_STATE_DIR);
|
|
9605
|
+
(0, import_node_fs21.mkdirSync)(dir, { recursive: true });
|
|
9632
9606
|
const cachePath = getCachePath(stateDir);
|
|
9633
|
-
(0,
|
|
9607
|
+
(0, import_node_fs21.writeFileSync)(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), "utf-8");
|
|
9634
9608
|
logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);
|
|
9635
9609
|
} catch (e) {
|
|
9636
9610
|
const message = e instanceof Error ? e.message : String(e);
|
|
@@ -9674,19 +9648,19 @@ function createAppNameMapProvider(opts) {
|
|
|
9674
9648
|
}
|
|
9675
9649
|
|
|
9676
9650
|
// src/notification/storage.ts
|
|
9677
|
-
var
|
|
9651
|
+
var import_node_fs22 = require("fs");
|
|
9678
9652
|
var import_node_crypto2 = require("crypto");
|
|
9679
|
-
var
|
|
9653
|
+
var import_node_path18 = require("path");
|
|
9680
9654
|
var NOTIFICATION_DIR_NAME = "notifications";
|
|
9681
9655
|
var ID_INDEX_DIR_NAME = ".ids";
|
|
9682
9656
|
var CONTENT_KEY_INDEX_DIR_NAME = ".keys";
|
|
9683
9657
|
function getStateFallbackNotificationDir(stateDir) {
|
|
9684
|
-
return (0,
|
|
9658
|
+
return (0, import_node_path18.join)(stateDir, "plugins", "phone-notifications", NOTIFICATION_DIR_NAME);
|
|
9685
9659
|
}
|
|
9686
9660
|
function ensureWritableDirectory(dir) {
|
|
9687
9661
|
try {
|
|
9688
|
-
(0,
|
|
9689
|
-
(0,
|
|
9662
|
+
(0, import_node_fs22.mkdirSync)(dir, { recursive: true });
|
|
9663
|
+
(0, import_node_fs22.accessSync)(dir, import_node_fs22.constants.R_OK | import_node_fs22.constants.W_OK);
|
|
9690
9664
|
return true;
|
|
9691
9665
|
} catch {
|
|
9692
9666
|
return false;
|
|
@@ -9699,7 +9673,7 @@ function resolveNotificationStorageDir(ctx, logger) {
|
|
|
9699
9673
|
return stateNotifDir;
|
|
9700
9674
|
}
|
|
9701
9675
|
if (ctx.workspaceDir) {
|
|
9702
|
-
const workspaceDir = (0,
|
|
9676
|
+
const workspaceDir = (0, import_node_path18.join)(ctx.workspaceDir, NOTIFICATION_DIR_NAME);
|
|
9703
9677
|
if (ensureWritableDirectory(workspaceDir)) {
|
|
9704
9678
|
logger.warn(
|
|
9705
9679
|
`stateDir \u4E0D\u53EF\u7528\uFF0C\u901A\u77E5\u5DF2\u56DE\u9000\u5230 workspace \u8DEF\u5F84: ${workspaceDir}`
|
|
@@ -9714,8 +9688,8 @@ var NotificationStorage = class {
|
|
|
9714
9688
|
this.config = config;
|
|
9715
9689
|
this.logger = logger;
|
|
9716
9690
|
this.dir = dir;
|
|
9717
|
-
this.idIndexDir = (0,
|
|
9718
|
-
this.contentKeyIndexDir = (0,
|
|
9691
|
+
this.idIndexDir = (0, import_node_path18.join)(dir, ID_INDEX_DIR_NAME);
|
|
9692
|
+
this.contentKeyIndexDir = (0, import_node_path18.join)(dir, CONTENT_KEY_INDEX_DIR_NAME);
|
|
9719
9693
|
this.resolveDisplayName = resolveDisplayName;
|
|
9720
9694
|
}
|
|
9721
9695
|
dir;
|
|
@@ -9726,10 +9700,10 @@ var NotificationStorage = class {
|
|
|
9726
9700
|
dateWriteChains = /* @__PURE__ */ new Map();
|
|
9727
9701
|
resolveDisplayName;
|
|
9728
9702
|
async init() {
|
|
9729
|
-
(0,
|
|
9730
|
-
(0,
|
|
9731
|
-
(0,
|
|
9732
|
-
(0,
|
|
9703
|
+
(0, import_node_fs22.mkdirSync)(this.dir, { recursive: true });
|
|
9704
|
+
(0, import_node_fs22.mkdirSync)(this.idIndexDir, { recursive: true });
|
|
9705
|
+
(0, import_node_fs22.rmSync)(this.contentKeyIndexDir, { recursive: true, force: true });
|
|
9706
|
+
(0, import_node_fs22.mkdirSync)(this.contentKeyIndexDir, { recursive: true });
|
|
9733
9707
|
}
|
|
9734
9708
|
async ingest(items) {
|
|
9735
9709
|
const result = {
|
|
@@ -9768,7 +9742,7 @@ var NotificationStorage = class {
|
|
|
9768
9742
|
return { kind: "invalid" };
|
|
9769
9743
|
}
|
|
9770
9744
|
const dateKey = this.formatDate(ts);
|
|
9771
|
-
const filePath = (0,
|
|
9745
|
+
const filePath = (0, import_node_path18.join)(this.dir, `${dateKey}.json`);
|
|
9772
9746
|
const normalizedId = typeof n.id === "string" ? n.id.trim() : "";
|
|
9773
9747
|
const entry = this.buildStoredNotification(n);
|
|
9774
9748
|
return this.withDateWriteLock(dateKey, async () => {
|
|
@@ -9785,7 +9759,7 @@ var NotificationStorage = class {
|
|
|
9785
9759
|
};
|
|
9786
9760
|
const arr = this.readStoredNotifications(filePath);
|
|
9787
9761
|
arr.push(storedEntry);
|
|
9788
|
-
(0,
|
|
9762
|
+
(0, import_node_fs22.writeFileSync)(filePath, JSON.stringify(arr, null, 2), "utf-8");
|
|
9789
9763
|
if (normalizedId) {
|
|
9790
9764
|
this.recordNotificationId(dateKey, normalizedId);
|
|
9791
9765
|
}
|
|
@@ -9822,7 +9796,7 @@ var NotificationStorage = class {
|
|
|
9822
9796
|
return `${year}-${month}-${day}`;
|
|
9823
9797
|
}
|
|
9824
9798
|
getIdIndexPath(dateKey) {
|
|
9825
|
-
return (0,
|
|
9799
|
+
return (0, import_node_path18.join)(this.idIndexDir, `${dateKey}.ids`);
|
|
9826
9800
|
}
|
|
9827
9801
|
getIdSet(dateKey) {
|
|
9828
9802
|
const cached = this.idCache.get(dateKey);
|
|
@@ -9831,8 +9805,8 @@ var NotificationStorage = class {
|
|
|
9831
9805
|
}
|
|
9832
9806
|
const idPath = this.getIdIndexPath(dateKey);
|
|
9833
9807
|
const ids = /* @__PURE__ */ new Set();
|
|
9834
|
-
if ((0,
|
|
9835
|
-
const lines = (0,
|
|
9808
|
+
if ((0, import_node_fs22.existsSync)(idPath)) {
|
|
9809
|
+
const lines = (0, import_node_fs22.readFileSync)(idPath, "utf-8").split(/\r?\n/);
|
|
9836
9810
|
for (const line of lines) {
|
|
9837
9811
|
const id = line.trim();
|
|
9838
9812
|
if (id) {
|
|
@@ -9847,7 +9821,7 @@ var NotificationStorage = class {
|
|
|
9847
9821
|
return this.getIdSet(dateKey).has(id);
|
|
9848
9822
|
}
|
|
9849
9823
|
getContentKeyIndexPath(dateKey) {
|
|
9850
|
-
return (0,
|
|
9824
|
+
return (0, import_node_path18.join)(this.contentKeyIndexDir, `${dateKey}.keys`);
|
|
9851
9825
|
}
|
|
9852
9826
|
getContentKeySet(dateKey, filePath) {
|
|
9853
9827
|
const cached = this.contentKeyCache.get(dateKey);
|
|
@@ -9856,16 +9830,16 @@ var NotificationStorage = class {
|
|
|
9856
9830
|
}
|
|
9857
9831
|
const keyPath = this.getContentKeyIndexPath(dateKey);
|
|
9858
9832
|
const keys = /* @__PURE__ */ new Set();
|
|
9859
|
-
if ((0,
|
|
9833
|
+
if ((0, import_node_fs22.existsSync)(filePath)) {
|
|
9860
9834
|
for (const item of this.readStoredNotifications(filePath)) {
|
|
9861
9835
|
keys.add(this.buildNotificationContentKey(item));
|
|
9862
9836
|
}
|
|
9863
9837
|
}
|
|
9864
9838
|
if (keys.size > 0) {
|
|
9865
|
-
(0,
|
|
9839
|
+
(0, import_node_fs22.writeFileSync)(keyPath, `${Array.from(keys).join("\n")}
|
|
9866
9840
|
`, "utf-8");
|
|
9867
|
-
} else if ((0,
|
|
9868
|
-
(0,
|
|
9841
|
+
} else if ((0, import_node_fs22.existsSync)(keyPath)) {
|
|
9842
|
+
(0, import_node_fs22.rmSync)(keyPath, { force: true });
|
|
9869
9843
|
}
|
|
9870
9844
|
this.contentKeyCache.set(dateKey, keys);
|
|
9871
9845
|
return keys;
|
|
@@ -9880,7 +9854,7 @@ var NotificationStorage = class {
|
|
|
9880
9854
|
if (ids.has(id)) {
|
|
9881
9855
|
return;
|
|
9882
9856
|
}
|
|
9883
|
-
(0,
|
|
9857
|
+
(0, import_node_fs22.appendFileSync)(this.getIdIndexPath(dateKey), `${id}
|
|
9884
9858
|
`, "utf-8");
|
|
9885
9859
|
ids.add(id);
|
|
9886
9860
|
}
|
|
@@ -9890,7 +9864,7 @@ var NotificationStorage = class {
|
|
|
9890
9864
|
if (keys.has(key)) {
|
|
9891
9865
|
return;
|
|
9892
9866
|
}
|
|
9893
|
-
(0,
|
|
9867
|
+
(0, import_node_fs22.appendFileSync)(this.getContentKeyIndexPath(dateKey), `${key}
|
|
9894
9868
|
`, "utf-8");
|
|
9895
9869
|
keys.add(key);
|
|
9896
9870
|
}
|
|
@@ -9898,11 +9872,11 @@ var NotificationStorage = class {
|
|
|
9898
9872
|
return (0, import_node_crypto2.createHash)("sha256").update(entry.appName).update("").update(entry.title).update("").update(entry.content).update("").update(entry.timestamp).digest("hex");
|
|
9899
9873
|
}
|
|
9900
9874
|
readStoredNotifications(filePath) {
|
|
9901
|
-
if (!(0,
|
|
9875
|
+
if (!(0, import_node_fs22.existsSync)(filePath)) {
|
|
9902
9876
|
return [];
|
|
9903
9877
|
}
|
|
9904
9878
|
try {
|
|
9905
|
-
const parsed = JSON.parse((0,
|
|
9879
|
+
const parsed = JSON.parse((0, import_node_fs22.readFileSync)(filePath, "utf-8"));
|
|
9906
9880
|
return Array.isArray(parsed) ? parsed : [];
|
|
9907
9881
|
} catch {
|
|
9908
9882
|
return [];
|
|
@@ -9942,14 +9916,14 @@ var NotificationStorage = class {
|
|
|
9942
9916
|
const dateFilePattern = /^(\d{4}-\d{2}-\d{2})\.(json|md)$/;
|
|
9943
9917
|
const dateDirPattern = /^\d{4}-\d{2}-\d{2}$/;
|
|
9944
9918
|
try {
|
|
9945
|
-
for (const entry of (0,
|
|
9919
|
+
for (const entry of (0, import_node_fs22.readdirSync)(this.dir, { withFileTypes: true })) {
|
|
9946
9920
|
if (entry.isFile()) {
|
|
9947
9921
|
const match = dateFilePattern.exec(entry.name);
|
|
9948
9922
|
if (match && match[1] < cutoffDate) {
|
|
9949
|
-
(0,
|
|
9923
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, entry.name), { force: true });
|
|
9950
9924
|
}
|
|
9951
9925
|
} else if (entry.isDirectory() && dateDirPattern.test(entry.name) && entry.name < cutoffDate) {
|
|
9952
|
-
(0,
|
|
9926
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, entry.name), { recursive: true, force: true });
|
|
9953
9927
|
}
|
|
9954
9928
|
}
|
|
9955
9929
|
} catch {
|
|
@@ -9958,11 +9932,11 @@ var NotificationStorage = class {
|
|
|
9958
9932
|
/** Remove expired .ids index files */
|
|
9959
9933
|
pruneIdIndex(cutoffDate) {
|
|
9960
9934
|
try {
|
|
9961
|
-
for (const entry of (0,
|
|
9935
|
+
for (const entry of (0, import_node_fs22.readdirSync)(this.idIndexDir, { withFileTypes: true })) {
|
|
9962
9936
|
if (!entry.isFile()) continue;
|
|
9963
9937
|
const match = /^(\d{4}-\d{2}-\d{2})\.ids$/.exec(entry.name);
|
|
9964
9938
|
if (match && match[1] < cutoffDate) {
|
|
9965
|
-
(0,
|
|
9939
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.idIndexDir, entry.name), { force: true });
|
|
9966
9940
|
this.idCache.delete(match[1]);
|
|
9967
9941
|
}
|
|
9968
9942
|
}
|
|
@@ -9971,11 +9945,11 @@ var NotificationStorage = class {
|
|
|
9971
9945
|
}
|
|
9972
9946
|
pruneContentKeyIndex(cutoffDate) {
|
|
9973
9947
|
try {
|
|
9974
|
-
for (const entry of (0,
|
|
9948
|
+
for (const entry of (0, import_node_fs22.readdirSync)(this.contentKeyIndexDir, { withFileTypes: true })) {
|
|
9975
9949
|
if (!entry.isFile()) continue;
|
|
9976
9950
|
const match = /^(\d{4}-\d{2}-\d{2})\.keys$/.exec(entry.name);
|
|
9977
9951
|
if (match && match[1] < cutoffDate) {
|
|
9978
|
-
(0,
|
|
9952
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.contentKeyIndexDir, entry.name), { force: true });
|
|
9979
9953
|
this.contentKeyCache.delete(match[1]);
|
|
9980
9954
|
}
|
|
9981
9955
|
}
|
|
@@ -9990,8 +9964,8 @@ var NotificationStorage = class {
|
|
|
9990
9964
|
};
|
|
9991
9965
|
|
|
9992
9966
|
// src/recording/storage.ts
|
|
9993
|
-
var
|
|
9994
|
-
var
|
|
9967
|
+
var import_node_fs23 = require("fs");
|
|
9968
|
+
var import_node_path19 = require("path");
|
|
9995
9969
|
|
|
9996
9970
|
// src/recording/state-machine.ts
|
|
9997
9971
|
var VALID_TRANSITIONS = /* @__PURE__ */ new Map([
|
|
@@ -10052,7 +10026,7 @@ function stripMarkdownFence(markdown) {
|
|
|
10052
10026
|
}
|
|
10053
10027
|
function deriveTitleFromTranscriptPath(transcriptFile, recordingId) {
|
|
10054
10028
|
if (!transcriptFile) return void 0;
|
|
10055
|
-
const name = (0,
|
|
10029
|
+
const name = (0, import_node_path19.basename)(transcriptFile, ".md");
|
|
10056
10030
|
const prefix = `${recordingId}_`;
|
|
10057
10031
|
if (name.startsWith(prefix)) {
|
|
10058
10032
|
const derived = name.slice(prefix.length).trim();
|
|
@@ -10080,22 +10054,22 @@ function extractTranscriptContent(markdown) {
|
|
|
10080
10054
|
return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
10081
10055
|
}
|
|
10082
10056
|
function resolveRecordingStorageDir(ctx, logger) {
|
|
10083
|
-
const stateRecDir = (0,
|
|
10057
|
+
const stateRecDir = (0, import_node_path19.join)(
|
|
10084
10058
|
ctx.stateDir,
|
|
10085
10059
|
"plugins",
|
|
10086
10060
|
"phone-notifications",
|
|
10087
10061
|
RECORDINGS_DIR
|
|
10088
10062
|
);
|
|
10089
10063
|
try {
|
|
10090
|
-
(0,
|
|
10064
|
+
(0, import_node_fs23.mkdirSync)(stateRecDir, { recursive: true });
|
|
10091
10065
|
logger.info(`\u5F55\u97F3\u5C06\u5199\u5165 stateDir \u8DEF\u5F84: ${stateRecDir}`);
|
|
10092
10066
|
return stateRecDir;
|
|
10093
10067
|
} catch {
|
|
10094
10068
|
}
|
|
10095
10069
|
if (ctx.workspaceDir) {
|
|
10096
|
-
const wsRecDir = (0,
|
|
10070
|
+
const wsRecDir = (0, import_node_path19.join)(ctx.workspaceDir, RECORDINGS_DIR);
|
|
10097
10071
|
try {
|
|
10098
|
-
(0,
|
|
10072
|
+
(0, import_node_fs23.mkdirSync)(wsRecDir, { recursive: true });
|
|
10099
10073
|
logger.warn(`stateDir \u4E0D\u53EF\u7528\uFF0C\u5F55\u97F3\u5DF2\u56DE\u9000\u5230 workspace \u8DEF\u5F84: ${wsRecDir}`);
|
|
10100
10074
|
return wsRecDir;
|
|
10101
10075
|
} catch {
|
|
@@ -10107,11 +10081,11 @@ var RecordingStorage = class {
|
|
|
10107
10081
|
constructor(dir, logger) {
|
|
10108
10082
|
this.logger = logger;
|
|
10109
10083
|
this.dir = dir;
|
|
10110
|
-
this.audioDir = (0,
|
|
10111
|
-
this.transcriptDataDir = (0,
|
|
10112
|
-
this.transcriptsDir = (0,
|
|
10113
|
-
this.summariesDir = (0,
|
|
10114
|
-
this.indexPath = (0,
|
|
10084
|
+
this.audioDir = (0, import_node_path19.join)(dir, AUDIO_DIR);
|
|
10085
|
+
this.transcriptDataDir = (0, import_node_path19.join)(dir, TRANSCRIPT_DATA_DIR);
|
|
10086
|
+
this.transcriptsDir = (0, import_node_path19.join)(dir, TRANSCRIPTS_DIR);
|
|
10087
|
+
this.summariesDir = (0, import_node_path19.join)(dir, SUMMARIES_DIR);
|
|
10088
|
+
this.indexPath = (0, import_node_path19.join)(dir, INDEX_FILE);
|
|
10115
10089
|
}
|
|
10116
10090
|
dir;
|
|
10117
10091
|
audioDir;
|
|
@@ -10122,10 +10096,10 @@ var RecordingStorage = class {
|
|
|
10122
10096
|
index = { recordings: [] };
|
|
10123
10097
|
/** 初始化目录结构并加载索引 */
|
|
10124
10098
|
async init() {
|
|
10125
|
-
(0,
|
|
10126
|
-
(0,
|
|
10127
|
-
(0,
|
|
10128
|
-
(0,
|
|
10099
|
+
(0, import_node_fs23.mkdirSync)(this.audioDir, { recursive: true });
|
|
10100
|
+
(0, import_node_fs23.mkdirSync)(this.transcriptDataDir, { recursive: true });
|
|
10101
|
+
(0, import_node_fs23.mkdirSync)(this.transcriptsDir, { recursive: true });
|
|
10102
|
+
(0, import_node_fs23.mkdirSync)(this.summariesDir, { recursive: true });
|
|
10129
10103
|
this.loadIndex();
|
|
10130
10104
|
this.logger.info(
|
|
10131
10105
|
`\u5F55\u97F3\u5B58\u50A8\u5DF2\u521D\u59CB\u5316: ${this.dir}\uFF08\u5171 ${this.index.recordings.length} \u6761\u8BB0\u5F55\uFF09`
|
|
@@ -10169,13 +10143,13 @@ var RecordingStorage = class {
|
|
|
10169
10143
|
return id;
|
|
10170
10144
|
}
|
|
10171
10145
|
if (existing.transcriptDataFile) {
|
|
10172
|
-
(0,
|
|
10146
|
+
(0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.transcriptDataFile), { force: true });
|
|
10173
10147
|
}
|
|
10174
10148
|
if (existing.transcriptFile) {
|
|
10175
|
-
(0,
|
|
10149
|
+
(0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.transcriptFile), { force: true });
|
|
10176
10150
|
}
|
|
10177
10151
|
if (existing.summaryFile) {
|
|
10178
|
-
(0,
|
|
10152
|
+
(0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, existing.summaryFile), { force: true });
|
|
10179
10153
|
}
|
|
10180
10154
|
existing.metadata = metadata;
|
|
10181
10155
|
existing.status = "syncing_openclaw";
|
|
@@ -10243,7 +10217,7 @@ var RecordingStorage = class {
|
|
|
10243
10217
|
if (!entry) return;
|
|
10244
10218
|
const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;
|
|
10245
10219
|
if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {
|
|
10246
|
-
(0,
|
|
10220
|
+
(0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.transcriptDataFile), { force: true });
|
|
10247
10221
|
}
|
|
10248
10222
|
entry.transcriptDataFile = nextTranscriptDataFile;
|
|
10249
10223
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -10257,7 +10231,7 @@ var RecordingStorage = class {
|
|
|
10257
10231
|
if (!entry) return;
|
|
10258
10232
|
const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;
|
|
10259
10233
|
if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {
|
|
10260
|
-
(0,
|
|
10234
|
+
(0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.transcriptFile), { force: true });
|
|
10261
10235
|
}
|
|
10262
10236
|
entry.transcriptFile = nextTranscriptFile;
|
|
10263
10237
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -10271,7 +10245,7 @@ var RecordingStorage = class {
|
|
|
10271
10245
|
if (!entry) return;
|
|
10272
10246
|
const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;
|
|
10273
10247
|
if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {
|
|
10274
|
-
(0,
|
|
10248
|
+
(0, import_node_fs23.rmSync)((0, import_node_path19.join)(this.dir, entry.summaryFile), { force: true });
|
|
10275
10249
|
}
|
|
10276
10250
|
entry.summaryFile = nextSummaryFile;
|
|
10277
10251
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -10369,24 +10343,24 @@ var RecordingStorage = class {
|
|
|
10369
10343
|
const entry = this.findById(recordingId);
|
|
10370
10344
|
if (!entry) return false;
|
|
10371
10345
|
if (entry.audioFile) {
|
|
10372
|
-
const audioPath = (0,
|
|
10373
|
-
(0,
|
|
10346
|
+
const audioPath = (0, import_node_path19.join)(this.dir, entry.audioFile);
|
|
10347
|
+
(0, import_node_fs23.rmSync)(audioPath, { force: true });
|
|
10374
10348
|
}
|
|
10375
10349
|
if (entry.srtFile) {
|
|
10376
|
-
const srtPath = (0,
|
|
10377
|
-
(0,
|
|
10350
|
+
const srtPath = (0, import_node_path19.join)(this.dir, entry.srtFile);
|
|
10351
|
+
(0, import_node_fs23.rmSync)(srtPath, { force: true });
|
|
10378
10352
|
}
|
|
10379
10353
|
if (entry.transcriptDataFile) {
|
|
10380
|
-
const transcriptDataPath = (0,
|
|
10381
|
-
(0,
|
|
10354
|
+
const transcriptDataPath = (0, import_node_path19.join)(this.dir, entry.transcriptDataFile);
|
|
10355
|
+
(0, import_node_fs23.rmSync)(transcriptDataPath, { force: true });
|
|
10382
10356
|
}
|
|
10383
10357
|
if (entry.transcriptFile) {
|
|
10384
|
-
const transcriptPath = (0,
|
|
10385
|
-
(0,
|
|
10358
|
+
const transcriptPath = (0, import_node_path19.join)(this.dir, entry.transcriptFile);
|
|
10359
|
+
(0, import_node_fs23.rmSync)(transcriptPath, { force: true });
|
|
10386
10360
|
}
|
|
10387
10361
|
if (entry.summaryFile) {
|
|
10388
|
-
const summaryPath = (0,
|
|
10389
|
-
(0,
|
|
10362
|
+
const summaryPath = (0, import_node_path19.join)(this.dir, entry.summaryFile);
|
|
10363
|
+
(0, import_node_fs23.rmSync)(summaryPath, { force: true });
|
|
10390
10364
|
}
|
|
10391
10365
|
if (opts?.localOnly) {
|
|
10392
10366
|
entry.audioFile = void 0;
|
|
@@ -10444,34 +10418,34 @@ var RecordingStorage = class {
|
|
|
10444
10418
|
* 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名
|
|
10445
10419
|
*/
|
|
10446
10420
|
getAudioFilePath(recordingId, ossUrl) {
|
|
10447
|
-
return (0,
|
|
10421
|
+
return (0, import_node_path19.join)(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));
|
|
10448
10422
|
}
|
|
10449
10423
|
/**
|
|
10450
10424
|
* 获取打点文件的绝对路径
|
|
10451
10425
|
*/
|
|
10452
10426
|
getSrtFilePath(recordingId) {
|
|
10453
|
-
return (0,
|
|
10427
|
+
return (0, import_node_path19.join)(this.audioDir, this.buildSrtFilename(recordingId));
|
|
10454
10428
|
}
|
|
10455
10429
|
/**
|
|
10456
10430
|
* 获取转写 JSON 文件的绝对路径
|
|
10457
10431
|
*/
|
|
10458
10432
|
getTranscriptDataFilePath(recordingId) {
|
|
10459
|
-
return (0,
|
|
10433
|
+
return (0, import_node_path19.join)(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));
|
|
10460
10434
|
}
|
|
10461
10435
|
/**
|
|
10462
10436
|
* 获取摘要文件的绝对路径
|
|
10463
10437
|
*/
|
|
10464
10438
|
getSummaryFilePath(recordingId) {
|
|
10465
|
-
return (0,
|
|
10439
|
+
return (0, import_node_path19.join)(this.summariesDir, this.buildSummaryFilename(recordingId));
|
|
10466
10440
|
}
|
|
10467
10441
|
// ─── Persistence ───
|
|
10468
10442
|
loadIndex() {
|
|
10469
|
-
if (!(0,
|
|
10443
|
+
if (!(0, import_node_fs23.existsSync)(this.indexPath)) {
|
|
10470
10444
|
this.index = { recordings: [] };
|
|
10471
10445
|
return;
|
|
10472
10446
|
}
|
|
10473
10447
|
try {
|
|
10474
|
-
const raw = JSON.parse((0,
|
|
10448
|
+
const raw = JSON.parse((0, import_node_fs23.readFileSync)(this.indexPath, "utf-8"));
|
|
10475
10449
|
if (raw && Array.isArray(raw.recordings)) {
|
|
10476
10450
|
let needsRewrite = false;
|
|
10477
10451
|
const normalized = raw.recordings.filter((entry) => entry && typeof entry === "object").map((entry) => {
|
|
@@ -10509,8 +10483,8 @@ var RecordingStorage = class {
|
|
|
10509
10483
|
segments: []
|
|
10510
10484
|
});
|
|
10511
10485
|
const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);
|
|
10512
|
-
(0,
|
|
10513
|
-
(0,
|
|
10486
|
+
(0, import_node_fs23.writeFileSync)(
|
|
10487
|
+
(0, import_node_path19.join)(this.transcriptDataDir, transcriptDataFilename),
|
|
10514
10488
|
JSON.stringify(transcriptDoc, null, 2),
|
|
10515
10489
|
"utf-8"
|
|
10516
10490
|
);
|
|
@@ -10522,8 +10496,8 @@ var RecordingStorage = class {
|
|
|
10522
10496
|
compacted.summaryFile = entry.summaryFile;
|
|
10523
10497
|
} else if (typeof entry.summary === "string" && entry.summary.trim()) {
|
|
10524
10498
|
const summaryFilename = this.buildSummaryFilename(entry.id);
|
|
10525
|
-
(0,
|
|
10526
|
-
(0,
|
|
10499
|
+
(0, import_node_fs23.writeFileSync)(
|
|
10500
|
+
(0, import_node_path19.join)(this.summariesDir, summaryFilename),
|
|
10527
10501
|
entry.summary.trim(),
|
|
10528
10502
|
"utf-8"
|
|
10529
10503
|
);
|
|
@@ -10533,8 +10507,8 @@ var RecordingStorage = class {
|
|
|
10533
10507
|
const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);
|
|
10534
10508
|
if (summaryFromDocument) {
|
|
10535
10509
|
const summaryFilename = this.buildSummaryFilename(entry.id);
|
|
10536
|
-
(0,
|
|
10537
|
-
(0,
|
|
10510
|
+
(0, import_node_fs23.writeFileSync)(
|
|
10511
|
+
(0, import_node_path19.join)(this.summariesDir, summaryFilename),
|
|
10538
10512
|
summaryFromDocument,
|
|
10539
10513
|
"utf-8"
|
|
10540
10514
|
);
|
|
@@ -10574,7 +10548,7 @@ var RecordingStorage = class {
|
|
|
10574
10548
|
}
|
|
10575
10549
|
readRelativeTextFile(relativePath) {
|
|
10576
10550
|
try {
|
|
10577
|
-
return (0,
|
|
10551
|
+
return (0, import_node_fs23.readFileSync)((0, import_node_path19.join)(this.dir, relativePath), "utf-8");
|
|
10578
10552
|
} catch {
|
|
10579
10553
|
return void 0;
|
|
10580
10554
|
}
|
|
@@ -10587,7 +10561,7 @@ var RecordingStorage = class {
|
|
|
10587
10561
|
return parseTranscriptDocument(raw);
|
|
10588
10562
|
}
|
|
10589
10563
|
saveIndex() {
|
|
10590
|
-
(0,
|
|
10564
|
+
(0, import_node_fs23.writeFileSync)(
|
|
10591
10565
|
this.indexPath,
|
|
10592
10566
|
JSON.stringify(this.index, null, 2),
|
|
10593
10567
|
"utf-8"
|
|
@@ -10601,8 +10575,8 @@ var RecordingStorage = class {
|
|
|
10601
10575
|
init_transcript_document();
|
|
10602
10576
|
|
|
10603
10577
|
// src/recording/downloader.ts
|
|
10604
|
-
var
|
|
10605
|
-
var
|
|
10578
|
+
var import_node_fs24 = require("fs");
|
|
10579
|
+
var import_node_path20 = require("path");
|
|
10606
10580
|
var import_promises2 = require("stream/promises");
|
|
10607
10581
|
var import_node_stream = require("stream");
|
|
10608
10582
|
var DEFAULT_TIMEOUT_MS2 = 5 * 60 * 1e3;
|
|
@@ -10612,7 +10586,7 @@ async function downloadFile(url, destPath, logger, options) {
|
|
|
10612
10586
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
10613
10587
|
const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
10614
10588
|
const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;
|
|
10615
|
-
(0,
|
|
10589
|
+
(0, import_node_fs24.mkdirSync)((0, import_node_path20.dirname)(destPath), { recursive: true });
|
|
10616
10590
|
let lastError;
|
|
10617
10591
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
10618
10592
|
const startMs = Date.now();
|
|
@@ -10630,11 +10604,11 @@ async function downloadFile(url, destPath, logger, options) {
|
|
|
10630
10604
|
if (!res.body) {
|
|
10631
10605
|
throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
|
|
10632
10606
|
}
|
|
10633
|
-
const writeStream = (0,
|
|
10607
|
+
const writeStream = (0, import_node_fs24.createWriteStream)(destPath);
|
|
10634
10608
|
const readable = import_node_stream.Readable.fromWeb(res.body);
|
|
10635
10609
|
await (0, import_promises2.pipeline)(readable, writeStream);
|
|
10636
10610
|
const elapsed = Date.now() - startMs;
|
|
10637
|
-
const fileSize = (0,
|
|
10611
|
+
const fileSize = (0, import_node_fs24.existsSync)(destPath) ? (0, import_node_fs24.statSync)(destPath).size : 0;
|
|
10638
10612
|
logger.info(
|
|
10639
10613
|
`[downloader] \u4E0B\u8F7D\u5B8C\u6210: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`
|
|
10640
10614
|
);
|
|
@@ -10645,7 +10619,7 @@ async function downloadFile(url, destPath, logger, options) {
|
|
|
10645
10619
|
} catch (err2) {
|
|
10646
10620
|
lastError = err2?.message ?? String(err2);
|
|
10647
10621
|
try {
|
|
10648
|
-
if ((0,
|
|
10622
|
+
if ((0, import_node_fs24.existsSync)(destPath)) (0, import_node_fs24.unlinkSync)(destPath);
|
|
10649
10623
|
} catch {
|
|
10650
10624
|
}
|
|
10651
10625
|
const isAbort = err2?.name === "AbortError";
|
|
@@ -10883,13 +10857,13 @@ async function triggerTranscription(recordingId, storage, asrConfig, logger, opt
|
|
|
10883
10857
|
}
|
|
10884
10858
|
|
|
10885
10859
|
// src/tunnel/service.ts
|
|
10886
|
-
var
|
|
10887
|
-
var
|
|
10860
|
+
var import_node_fs29 = require("fs");
|
|
10861
|
+
var import_node_path25 = require("path");
|
|
10888
10862
|
init_credentials();
|
|
10889
10863
|
|
|
10890
10864
|
// src/tunnel/relay-client.ts
|
|
10891
|
-
var
|
|
10892
|
-
var
|
|
10865
|
+
var import_node_fs27 = require("fs");
|
|
10866
|
+
var import_node_path23 = require("path");
|
|
10893
10867
|
|
|
10894
10868
|
// node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
|
|
10895
10869
|
var import_stream = __toESM(require_stream(), 1);
|
|
@@ -10933,8 +10907,8 @@ var RelayClient = class {
|
|
|
10933
10907
|
lastDisconnectReason
|
|
10934
10908
|
};
|
|
10935
10909
|
try {
|
|
10936
|
-
(0,
|
|
10937
|
-
(0,
|
|
10910
|
+
(0, import_node_fs27.mkdirSync)((0, import_node_path23.dirname)(this.opts.statusFilePath), { recursive: true });
|
|
10911
|
+
(0, import_node_fs27.writeFileSync)(this.opts.statusFilePath, JSON.stringify(info, null, 2));
|
|
10938
10912
|
} catch {
|
|
10939
10913
|
}
|
|
10940
10914
|
}
|
|
@@ -11316,8 +11290,8 @@ init_host();
|
|
|
11316
11290
|
|
|
11317
11291
|
// src/tunnel/device-identity.ts
|
|
11318
11292
|
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
11319
|
-
var
|
|
11320
|
-
var
|
|
11293
|
+
var import_node_fs28 = __toESM(require("fs"), 1);
|
|
11294
|
+
var import_node_path24 = __toESM(require("path"), 1);
|
|
11321
11295
|
init_host();
|
|
11322
11296
|
var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
|
|
11323
11297
|
function base64UrlEncode(buf) {
|
|
@@ -11362,10 +11336,10 @@ function resolveClientStateDir(stateDir) {
|
|
|
11362
11336
|
return stateDir ?? resolveStateDir();
|
|
11363
11337
|
}
|
|
11364
11338
|
function ensureDir(filePath) {
|
|
11365
|
-
|
|
11339
|
+
import_node_fs28.default.mkdirSync(import_node_path24.default.dirname(filePath), { recursive: true });
|
|
11366
11340
|
}
|
|
11367
11341
|
function resolveIdentityPath(stateDir) {
|
|
11368
|
-
return
|
|
11342
|
+
return import_node_path24.default.join(stateDir, "identity", "device.json");
|
|
11369
11343
|
}
|
|
11370
11344
|
function normalizeDeviceAuthRole(role) {
|
|
11371
11345
|
return role.trim();
|
|
@@ -11381,12 +11355,12 @@ function normalizeDeviceAuthScopes(scopes) {
|
|
|
11381
11355
|
return [...out].sort();
|
|
11382
11356
|
}
|
|
11383
11357
|
function resolveDeviceAuthPath(stateDir) {
|
|
11384
|
-
return
|
|
11358
|
+
return import_node_path24.default.join(stateDir, "identity", "device-auth.json");
|
|
11385
11359
|
}
|
|
11386
11360
|
function readDeviceAuthStore(filePath) {
|
|
11387
11361
|
try {
|
|
11388
|
-
if (!
|
|
11389
|
-
const raw =
|
|
11362
|
+
if (!import_node_fs28.default.existsSync(filePath)) return null;
|
|
11363
|
+
const raw = import_node_fs28.default.readFileSync(filePath, "utf8");
|
|
11390
11364
|
const parsed = JSON.parse(raw);
|
|
11391
11365
|
if (parsed?.version !== 1 || typeof parsed.deviceId !== "string") return null;
|
|
11392
11366
|
if (!parsed.tokens || typeof parsed.tokens !== "object") return null;
|
|
@@ -11397,12 +11371,12 @@ function readDeviceAuthStore(filePath) {
|
|
|
11397
11371
|
}
|
|
11398
11372
|
function writeDeviceAuthStore(filePath, store) {
|
|
11399
11373
|
ensureDir(filePath);
|
|
11400
|
-
|
|
11374
|
+
import_node_fs28.default.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
|
|
11401
11375
|
`, {
|
|
11402
11376
|
mode: 384
|
|
11403
11377
|
});
|
|
11404
11378
|
try {
|
|
11405
|
-
|
|
11379
|
+
import_node_fs28.default.chmodSync(filePath, 384);
|
|
11406
11380
|
} catch {
|
|
11407
11381
|
}
|
|
11408
11382
|
}
|
|
@@ -11449,8 +11423,8 @@ function clearDeviceAuthToken(params) {
|
|
|
11449
11423
|
function loadOrCreateDeviceIdentity(stateDir) {
|
|
11450
11424
|
const filePath = resolveIdentityPath(stateDir);
|
|
11451
11425
|
try {
|
|
11452
|
-
if (
|
|
11453
|
-
const raw =
|
|
11426
|
+
if (import_node_fs28.default.existsSync(filePath)) {
|
|
11427
|
+
const raw = import_node_fs28.default.readFileSync(filePath, "utf8");
|
|
11454
11428
|
const parsed = JSON.parse(raw);
|
|
11455
11429
|
if (parsed?.version === 1 && typeof parsed.deviceId === "string" && typeof parsed.publicKeyPem === "string" && typeof parsed.privateKeyPem === "string") {
|
|
11456
11430
|
const derivedId = fingerprintPublicKey(parsed.publicKeyPem);
|
|
@@ -11471,14 +11445,14 @@ function loadOrCreateDeviceIdentity(stateDir) {
|
|
|
11471
11445
|
publicKeyPem,
|
|
11472
11446
|
privateKeyPem
|
|
11473
11447
|
};
|
|
11474
|
-
|
|
11448
|
+
import_node_fs28.default.mkdirSync(import_node_path24.default.dirname(filePath), { recursive: true });
|
|
11475
11449
|
const stored = {
|
|
11476
11450
|
version: 1,
|
|
11477
11451
|
...identity,
|
|
11478
11452
|
createdAtMs: Date.now()
|
|
11479
11453
|
};
|
|
11480
11454
|
ensureDir(filePath);
|
|
11481
|
-
|
|
11455
|
+
import_node_fs28.default.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}
|
|
11482
11456
|
`, {
|
|
11483
11457
|
mode: 384
|
|
11484
11458
|
});
|
|
@@ -12250,7 +12224,7 @@ function createTunnelService(opts) {
|
|
|
12250
12224
|
}
|
|
12251
12225
|
function readLockOwner(filePath) {
|
|
12252
12226
|
try {
|
|
12253
|
-
const parsed = JSON.parse((0,
|
|
12227
|
+
const parsed = JSON.parse((0, import_node_fs29.readFileSync)(filePath, "utf-8"));
|
|
12254
12228
|
return typeof parsed.pid === "number" ? parsed.pid : null;
|
|
12255
12229
|
} catch {
|
|
12256
12230
|
return null;
|
|
@@ -12263,23 +12237,23 @@ function createTunnelService(opts) {
|
|
|
12263
12237
|
lockFd = null;
|
|
12264
12238
|
if (fd !== null) {
|
|
12265
12239
|
try {
|
|
12266
|
-
(0,
|
|
12240
|
+
(0, import_node_fs29.closeSync)(fd);
|
|
12267
12241
|
} catch {
|
|
12268
12242
|
}
|
|
12269
12243
|
}
|
|
12270
12244
|
if (filePath) {
|
|
12271
12245
|
try {
|
|
12272
|
-
(0,
|
|
12246
|
+
(0, import_node_fs29.unlinkSync)(filePath);
|
|
12273
12247
|
} catch {
|
|
12274
12248
|
}
|
|
12275
12249
|
}
|
|
12276
12250
|
}
|
|
12277
12251
|
function acquireLock(filePath) {
|
|
12278
|
-
(0,
|
|
12252
|
+
(0, import_node_fs29.mkdirSync)((0, import_node_path25.dirname)(filePath), { recursive: true });
|
|
12279
12253
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
12280
12254
|
try {
|
|
12281
|
-
const fd = (0,
|
|
12282
|
-
(0,
|
|
12255
|
+
const fd = (0, import_node_fs29.openSync)(filePath, "wx", 384);
|
|
12256
|
+
(0, import_node_fs29.writeFileSync)(
|
|
12283
12257
|
fd,
|
|
12284
12258
|
JSON.stringify({
|
|
12285
12259
|
pid: process.pid,
|
|
@@ -12303,7 +12277,7 @@ function createTunnelService(opts) {
|
|
|
12303
12277
|
`Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`
|
|
12304
12278
|
);
|
|
12305
12279
|
try {
|
|
12306
|
-
(0,
|
|
12280
|
+
(0, import_node_fs29.unlinkSync)(filePath);
|
|
12307
12281
|
} catch {
|
|
12308
12282
|
}
|
|
12309
12283
|
continue;
|
|
@@ -12348,12 +12322,12 @@ function createTunnelService(opts) {
|
|
|
12348
12322
|
return;
|
|
12349
12323
|
}
|
|
12350
12324
|
const { logger } = opts;
|
|
12351
|
-
const baseStateDir = (0,
|
|
12325
|
+
const baseStateDir = (0, import_node_path25.join)(ctx.stateDir, "plugins", "phone-notifications");
|
|
12352
12326
|
logger.info(
|
|
12353
12327
|
`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})`
|
|
12354
12328
|
);
|
|
12355
|
-
const statusFilePath = (0,
|
|
12356
|
-
const lockPath = (0,
|
|
12329
|
+
const statusFilePath = (0, import_node_path25.join)(baseStateDir, "tunnel-status.json");
|
|
12330
|
+
const lockPath = (0, import_node_path25.join)(baseStateDir, "relay-tunnel.lock");
|
|
12357
12331
|
if (!acquireLock(lockPath)) {
|
|
12358
12332
|
return;
|
|
12359
12333
|
}
|
|
@@ -12493,7 +12467,7 @@ function readHostGatewayConfig(params) {
|
|
|
12493
12467
|
let configData;
|
|
12494
12468
|
if (configPath) {
|
|
12495
12469
|
try {
|
|
12496
|
-
configData = JSON.parse((0,
|
|
12470
|
+
configData = JSON.parse((0, import_node_fs30.readFileSync)(configPath, "utf-8"));
|
|
12497
12471
|
} catch (err2) {
|
|
12498
12472
|
if (err2?.code !== "ENOENT") {
|
|
12499
12473
|
params.logger.warn(
|
|
@@ -13255,7 +13229,6 @@ var index_default = {
|
|
|
13255
13229
|
recordingStorage = nextRecordingStorage;
|
|
13256
13230
|
},
|
|
13257
13231
|
onStorageReady() {
|
|
13258
|
-
migrateLegacyLightRuleTasks(lightRuleCtx, logger);
|
|
13259
13232
|
lightRuleRegistry.reload();
|
|
13260
13233
|
}
|
|
13261
13234
|
});
|