@yoooclaw/phone-notifications 1.11.4-beta.2 → 1.11.4-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +433 -380
- package/dist/index.cjs.map +1 -1
- package/openclaw.plugin.json +3 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -579,20 +579,20 @@ function selectModelByMemory(availableGB, isAppleSilicon = false) {
|
|
|
579
579
|
return "tiny";
|
|
580
580
|
}
|
|
581
581
|
function resolveModelsDir(dataDir) {
|
|
582
|
-
const dir = (0,
|
|
583
|
-
(0,
|
|
582
|
+
const dir = (0, import_node_path20.join)(dataDir, WHISPER_MODELS_DIR);
|
|
583
|
+
(0, import_node_fs24.mkdirSync)(dir, { recursive: true });
|
|
584
584
|
return dir;
|
|
585
585
|
}
|
|
586
586
|
function resolveBinDir(dataDir) {
|
|
587
|
-
const dir = (0,
|
|
588
|
-
(0,
|
|
587
|
+
const dir = (0, import_node_path20.join)(dataDir, WHISPER_BIN_DIR);
|
|
588
|
+
(0, import_node_fs24.mkdirSync)(dir, { recursive: true });
|
|
589
589
|
return dir;
|
|
590
590
|
}
|
|
591
591
|
function isModelDownloaded(modelsDir, modelSize) {
|
|
592
|
-
const modelPath = (0,
|
|
593
|
-
if (!(0,
|
|
592
|
+
const modelPath = (0, import_node_path20.join)(modelsDir, MODEL_FILENAMES[modelSize]);
|
|
593
|
+
if (!(0, import_node_fs24.existsSync)(modelPath)) return false;
|
|
594
594
|
try {
|
|
595
|
-
const stat = (0,
|
|
595
|
+
const stat = (0, import_node_fs24.statSync)(modelPath);
|
|
596
596
|
const expectedSize = MODEL_DISK_SIZES[modelSize];
|
|
597
597
|
return stat.size >= expectedSize * 0.8;
|
|
598
598
|
} catch {
|
|
@@ -601,7 +601,7 @@ function isModelDownloaded(modelsDir, modelSize) {
|
|
|
601
601
|
}
|
|
602
602
|
async function downloadModel(modelsDir, modelSize, logger, modelSource, mirrorUrl) {
|
|
603
603
|
const filename = MODEL_FILENAMES[modelSize];
|
|
604
|
-
const modelPath = (0,
|
|
604
|
+
const modelPath = (0, import_node_path20.join)(modelsDir, filename);
|
|
605
605
|
if (isModelDownloaded(modelsDir, modelSize)) {
|
|
606
606
|
logger.info(`[whisper-local] \u6A21\u578B\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u4E0B\u8F7D: ${filename}`);
|
|
607
607
|
return { ok: true, modelPath };
|
|
@@ -667,7 +667,7 @@ async function probeUrl(url, logger) {
|
|
|
667
667
|
async function downloadFromUrl(url, modelPath, logger) {
|
|
668
668
|
const tmpPath = `${modelPath}.downloading`;
|
|
669
669
|
try {
|
|
670
|
-
(0,
|
|
670
|
+
(0, import_node_fs24.mkdirSync)((0, import_node_path20.dirname)(modelPath), { recursive: true });
|
|
671
671
|
const controller = new AbortController();
|
|
672
672
|
const timer = setTimeout(() => controller.abort(), 30 * 60 * 1e3);
|
|
673
673
|
try {
|
|
@@ -683,7 +683,7 @@ async function downloadFromUrl(url, modelPath, logger) {
|
|
|
683
683
|
return { ok: false, modelPath, error: "\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: \u54CD\u5E94\u4F53\u4E3A\u7A7A" };
|
|
684
684
|
}
|
|
685
685
|
const contentLength = Number(res.headers.get("content-length") ?? 0);
|
|
686
|
-
const writeStream = (0,
|
|
686
|
+
const writeStream = (0, import_node_fs24.createWriteStream)(tmpPath);
|
|
687
687
|
const readable = import_node_stream2.Readable.fromWeb(res.body);
|
|
688
688
|
let downloaded = 0;
|
|
689
689
|
let lastLogPercent = 0;
|
|
@@ -705,14 +705,14 @@ async function downloadFromUrl(url, modelPath, logger) {
|
|
|
705
705
|
}
|
|
706
706
|
const { renameSync: renameSync2 } = await import("fs");
|
|
707
707
|
renameSync2(tmpPath, modelPath);
|
|
708
|
-
const fileSize = (0,
|
|
708
|
+
const fileSize = (0, import_node_fs24.statSync)(modelPath).size;
|
|
709
709
|
logger.info(
|
|
710
|
-
`[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0,
|
|
710
|
+
`[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path20.basename)(modelPath)} (${formatBytes2(fileSize)})`
|
|
711
711
|
);
|
|
712
712
|
return { ok: true, modelPath };
|
|
713
713
|
} catch (err2) {
|
|
714
714
|
try {
|
|
715
|
-
if ((0,
|
|
715
|
+
if ((0, import_node_fs24.existsSync)(tmpPath)) (0, import_node_fs24.unlinkSync)(tmpPath);
|
|
716
716
|
} catch {
|
|
717
717
|
}
|
|
718
718
|
const msg = err2?.name === "AbortError" ? "\u6A21\u578B\u4E0B\u8F7D\u8D85\u65F6\uFF0830 \u5206\u949F\uFF09" : err2?.message ?? String(err2);
|
|
@@ -724,8 +724,8 @@ function findWhisperBinary(dataDir, logger) {
|
|
|
724
724
|
const binDir = resolveBinDir(dataDir);
|
|
725
725
|
const binNames = (0, import_node_os4.platform)() === "win32" ? ["whisper-cli.exe", "whisper.exe", "main.exe"] : ["whisper-cli", "whisper", "main"];
|
|
726
726
|
for (const name of binNames) {
|
|
727
|
-
const binPath = (0,
|
|
728
|
-
if ((0,
|
|
727
|
+
const binPath = (0, import_node_path20.join)(binDir, name);
|
|
728
|
+
if ((0, import_node_fs24.existsSync)(binPath)) {
|
|
729
729
|
logger.info(`[whisper-local] \u627E\u5230\u672C\u5730\u4E8C\u8FDB\u5236: ${binPath}`);
|
|
730
730
|
return binPath;
|
|
731
731
|
}
|
|
@@ -776,7 +776,7 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
|
|
|
776
776
|
return { ok: false, error: `\u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: ${downloadResult.error}` };
|
|
777
777
|
}
|
|
778
778
|
}
|
|
779
|
-
const modelPath = (0,
|
|
779
|
+
const modelPath = (0, import_node_path20.join)(modelsDir, MODEL_FILENAMES[modelSize]);
|
|
780
780
|
let inputPath = audioFilePath;
|
|
781
781
|
let tmpWavPath = null;
|
|
782
782
|
const actualFmt = detectAudioFormat(audioFilePath);
|
|
@@ -828,10 +828,10 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
|
|
|
828
828
|
logger.info(`[whisper-local] \u8F6C\u5199\u8017\u65F6: ${Math.round(elapsed / 1e3)}s`);
|
|
829
829
|
const jsonPath = inputPath + ".json";
|
|
830
830
|
let jsonContent;
|
|
831
|
-
if ((0,
|
|
832
|
-
jsonContent = (0,
|
|
831
|
+
if ((0, import_node_fs24.existsSync)(jsonPath)) {
|
|
832
|
+
jsonContent = (0, import_node_fs24.readFileSync)(jsonPath, "utf-8");
|
|
833
833
|
try {
|
|
834
|
-
(0,
|
|
834
|
+
(0, import_node_fs24.unlinkSync)(jsonPath);
|
|
835
835
|
} catch {
|
|
836
836
|
}
|
|
837
837
|
} else {
|
|
@@ -909,10 +909,10 @@ function getPhysicalCoreCount() {
|
|
|
909
909
|
}
|
|
910
910
|
function detectAudioFormat(filePath) {
|
|
911
911
|
try {
|
|
912
|
-
const fd = (0,
|
|
912
|
+
const fd = (0, import_node_fs24.openSync)(filePath, "r");
|
|
913
913
|
const buf = Buffer.alloc(12);
|
|
914
|
-
(0,
|
|
915
|
-
(0,
|
|
914
|
+
(0, import_node_fs24.readSync)(fd, buf, 0, 12, 0);
|
|
915
|
+
(0, import_node_fs24.closeSync)(fd);
|
|
916
916
|
const header = buf.toString("ascii", 0, 4);
|
|
917
917
|
const header8 = buf.toString("ascii", 0, 8);
|
|
918
918
|
if (header === "RIFF" && buf.toString("ascii", 8, 12) === "WAVE") return ".wav";
|
|
@@ -947,7 +947,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
947
947
|
timeout: 12e4,
|
|
948
948
|
stdio: ["pipe", "pipe", "pipe"]
|
|
949
949
|
});
|
|
950
|
-
if (ffmpegResult.status === 0 && (0,
|
|
950
|
+
if (ffmpegResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
|
|
951
951
|
logger.info(`[whisper-local] ffmpeg \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
|
|
952
952
|
return { ok: true };
|
|
953
953
|
}
|
|
@@ -960,7 +960,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
960
960
|
["--rate", "16000", "--mono", inputPath, outputPath],
|
|
961
961
|
{ encoding: "utf-8", timeout: 12e4, stdio: ["pipe", "pipe", "pipe"] }
|
|
962
962
|
);
|
|
963
|
-
if (opusResult.status === 0 && (0,
|
|
963
|
+
if (opusResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
|
|
964
964
|
logger.info(`[whisper-local] opusdec \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
|
|
965
965
|
return { ok: true };
|
|
966
966
|
}
|
|
@@ -974,7 +974,7 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
974
974
|
if (detectedExt && !inputPath.endsWith(detectedExt)) {
|
|
975
975
|
tmpCopy = inputPath + ".detected" + detectedExt;
|
|
976
976
|
try {
|
|
977
|
-
(0,
|
|
977
|
+
(0, import_node_fs24.copyFileSync)(inputPath, tmpCopy);
|
|
978
978
|
actualInputPath = tmpCopy;
|
|
979
979
|
logger.info(
|
|
980
980
|
`[whisper-local] \u68C0\u6D4B\u5230\u5B9E\u9645\u683C\u5F0F ${detectedExt}\uFF0C\u4E34\u65F6\u91CD\u547D\u540D`
|
|
@@ -998,22 +998,22 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
998
998
|
timeout: 12e4,
|
|
999
999
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1000
1000
|
});
|
|
1001
|
-
if (tmpCopy && (0,
|
|
1001
|
+
if (tmpCopy && (0, import_node_fs24.existsSync)(tmpCopy)) {
|
|
1002
1002
|
try {
|
|
1003
|
-
(0,
|
|
1003
|
+
(0, import_node_fs24.unlinkSync)(tmpCopy);
|
|
1004
1004
|
} catch {
|
|
1005
1005
|
}
|
|
1006
1006
|
}
|
|
1007
|
-
if (afResult.status === 0 && (0,
|
|
1007
|
+
if (afResult.status === 0 && (0, import_node_fs24.existsSync)(outputPath)) {
|
|
1008
1008
|
logger.info(`[whisper-local] afconvert \u8F6C\u6362\u5B8C\u6210: ${outputPath}`);
|
|
1009
1009
|
return { ok: true };
|
|
1010
1010
|
}
|
|
1011
1011
|
const stderr = afResult.stderr?.slice(0, 200) ?? "";
|
|
1012
1012
|
return { ok: false, error: `afconvert \u8F6C\u6362\u5931\u8D25 (exit ${afResult.status}): ${stderr}` };
|
|
1013
1013
|
} catch (err2) {
|
|
1014
|
-
if (tmpCopy && (0,
|
|
1014
|
+
if (tmpCopy && (0, import_node_fs24.existsSync)(tmpCopy)) {
|
|
1015
1015
|
try {
|
|
1016
|
-
(0,
|
|
1016
|
+
(0, import_node_fs24.unlinkSync)(tmpCopy);
|
|
1017
1017
|
} catch {
|
|
1018
1018
|
}
|
|
1019
1019
|
}
|
|
@@ -1024,9 +1024,9 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
1024
1024
|
return { ok: false, error: `\u65E0\u6CD5\u5C06\u97F3\u9891\u8F6C\u6362\u4E3A WAV \u683C\u5F0F\u3002${fmtHint}` };
|
|
1025
1025
|
}
|
|
1026
1026
|
function cleanupTmpWav(path2) {
|
|
1027
|
-
if (path2 && (0,
|
|
1027
|
+
if (path2 && (0, import_node_fs24.existsSync)(path2)) {
|
|
1028
1028
|
try {
|
|
1029
|
-
(0,
|
|
1029
|
+
(0, import_node_fs24.unlinkSync)(path2);
|
|
1030
1030
|
} catch {
|
|
1031
1031
|
}
|
|
1032
1032
|
}
|
|
@@ -1112,13 +1112,13 @@ function formatBytes2(bytes) {
|
|
|
1112
1112
|
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
1113
1113
|
return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;
|
|
1114
1114
|
}
|
|
1115
|
-
var import_node_child_process3,
|
|
1115
|
+
var import_node_child_process3, import_node_fs24, import_node_path20, 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;
|
|
1116
1116
|
var init_whisper_local = __esm({
|
|
1117
1117
|
"src/recording/whisper-local.ts"() {
|
|
1118
1118
|
"use strict";
|
|
1119
1119
|
import_node_child_process3 = require("child_process");
|
|
1120
|
-
|
|
1121
|
-
|
|
1120
|
+
import_node_fs24 = require("fs");
|
|
1121
|
+
import_node_path20 = require("path");
|
|
1122
1122
|
import_promises3 = require("stream/promises");
|
|
1123
1123
|
import_node_stream2 = require("stream");
|
|
1124
1124
|
import_node_os4 = require("os");
|
|
@@ -1273,7 +1273,7 @@ async function initializeAsr(config, dataDir, logger) {
|
|
|
1273
1273
|
}
|
|
1274
1274
|
}
|
|
1275
1275
|
async function transcribeAudio(audioFilePath, config, logger, options = {}) {
|
|
1276
|
-
if (!(0,
|
|
1276
|
+
if (!(0, import_node_fs25.existsSync)(audioFilePath)) {
|
|
1277
1277
|
return { ok: false, error: `\u97F3\u9891\u6587\u4EF6\u4E0D\u5B58\u5728: ${audioFilePath}` };
|
|
1278
1278
|
}
|
|
1279
1279
|
logger.info(
|
|
@@ -1419,8 +1419,8 @@ async function runTranscriptionWorkflow(params) {
|
|
|
1419
1419
|
createdAt
|
|
1420
1420
|
);
|
|
1421
1421
|
const transcriptDataFilename = buildTranscriptDataFilename(recordingId);
|
|
1422
|
-
const transcriptDataPath = (0,
|
|
1423
|
-
(0,
|
|
1422
|
+
const transcriptDataPath = (0, import_node_path21.join)(transcriptDataDir, transcriptDataFilename);
|
|
1423
|
+
(0, import_node_fs25.writeFileSync)(
|
|
1424
1424
|
transcriptDataPath,
|
|
1425
1425
|
JSON.stringify(transcriptData, null, 2),
|
|
1426
1426
|
"utf-8"
|
|
@@ -1428,14 +1428,14 @@ async function runTranscriptionWorkflow(params) {
|
|
|
1428
1428
|
logger.info(`[asr] \u8F6C\u5199 JSON \u5DF2\u5199\u5165: ${transcriptDataPath}`);
|
|
1429
1429
|
const safeSummary = title.replace(/[/\\:*?"<>|]/g, "").trim().slice(0, 20);
|
|
1430
1430
|
const filename = safeSummary ? `${recordingId}_${safeSummary}.md` : `${recordingId}.md`;
|
|
1431
|
-
const filePath = (0,
|
|
1432
|
-
(0,
|
|
1431
|
+
const filePath = (0, import_node_path21.join)(transcriptsDir, filename);
|
|
1432
|
+
(0, import_node_fs25.writeFileSync)(filePath, markdown, "utf-8");
|
|
1433
1433
|
logger.info(`[asr] \u8F6C\u5199\u6587\u672C\u5DF2\u5199\u5165: ${filePath}`);
|
|
1434
1434
|
let summaryFilename;
|
|
1435
1435
|
if (summary) {
|
|
1436
1436
|
summaryFilename = `${recordingId}.md`;
|
|
1437
|
-
const summaryFilePath = (0,
|
|
1438
|
-
(0,
|
|
1437
|
+
const summaryFilePath = (0, import_node_path21.join)(summariesDir, summaryFilename);
|
|
1438
|
+
(0, import_node_fs25.writeFileSync)(summaryFilePath, summary, "utf-8");
|
|
1439
1439
|
logger.info(`[asr] \u6458\u8981\u6587\u672C\u5DF2\u5199\u5165: ${summaryFilePath}`);
|
|
1440
1440
|
}
|
|
1441
1441
|
return {
|
|
@@ -1521,7 +1521,7 @@ async function transcribeWithModelProxy(audioOssUrl, audioDurationMs, apiConfig,
|
|
|
1521
1521
|
}
|
|
1522
1522
|
async function transcribeWithWhisperLocal2(audioFilePath, config, logger) {
|
|
1523
1523
|
const { transcribeWithWhisperLocal: runLocal } = await Promise.resolve().then(() => (init_whisper_local(), whisper_local_exports));
|
|
1524
|
-
const dataDir = process.env.OPENCLAW_STATE_DIR ?? process.env.QCLAW_STATE_DIR ?? (0,
|
|
1524
|
+
const dataDir = process.env.OPENCLAW_STATE_DIR ?? process.env.QCLAW_STATE_DIR ?? (0, import_node_path21.join)(audioFilePath, "..", "..", "..");
|
|
1525
1525
|
const localConfig = config.local ?? {};
|
|
1526
1526
|
const result = await runLocal(
|
|
1527
1527
|
audioFilePath,
|
|
@@ -1830,12 +1830,12 @@ function formatTranscriptSegmentText(segment) {
|
|
|
1830
1830
|
}
|
|
1831
1831
|
return text;
|
|
1832
1832
|
}
|
|
1833
|
-
var
|
|
1833
|
+
var import_node_fs25, import_node_path21, DEFAULT_LONG_RECORDING_POLL_INTERVAL_MS, DEFAULT_LONG_RECORDING_MAX_POLL_ATTEMPTS, LONG_RECORDING_RUNNING_STATUSES, LONG_RECORDING_TERMINAL_FAILURE_STATUSES;
|
|
1834
1834
|
var init_asr = __esm({
|
|
1835
1835
|
"src/recording/asr.ts"() {
|
|
1836
1836
|
"use strict";
|
|
1837
|
-
|
|
1838
|
-
|
|
1837
|
+
import_node_fs25 = require("fs");
|
|
1838
|
+
import_node_path21 = require("path");
|
|
1839
1839
|
init_credentials();
|
|
1840
1840
|
init_env();
|
|
1841
1841
|
init_transcript_document();
|
|
@@ -5480,7 +5480,7 @@ function readBuildInjectedVersion() {
|
|
|
5480
5480
|
if (false) {
|
|
5481
5481
|
return void 0;
|
|
5482
5482
|
}
|
|
5483
|
-
const version = "1.11.4-beta.
|
|
5483
|
+
const version = "1.11.4-beta.4".trim();
|
|
5484
5484
|
return version || void 0;
|
|
5485
5485
|
}
|
|
5486
5486
|
function readPluginVersionFromPackageJson() {
|
|
@@ -7097,109 +7097,6 @@ function resolveLightTitle(title, reason, segments) {
|
|
|
7097
7097
|
return `Effect: ${modeDesc || "custom"}`;
|
|
7098
7098
|
}
|
|
7099
7099
|
|
|
7100
|
-
// src/light-rules/local-matcher.ts
|
|
7101
|
-
var CONTACT_PREFIXES = ["\u91CD\u8981\u8054\u7CFB\u4EBA", "\u8054\u7CFB\u4EBA"];
|
|
7102
|
-
var CONTACT_ACTION_RE = /(给我)?发(?:来)?消息|(给我)?发信息|来消息|回复(?:我)?|回应(?:我)?|私聊(?:我)?/u;
|
|
7103
|
-
var LEADING_SENDER_RE = /^(.{1,40}?)(?:\s+回应)?\s*[::]/u;
|
|
7104
|
-
function matchNotificationsLocally(notifications, rules) {
|
|
7105
|
-
const parsedRules = rules.map((rule) => parseContactRule(rule)).filter((item) => item !== null);
|
|
7106
|
-
if (parsedRules.length === 0) {
|
|
7107
|
-
return [];
|
|
7108
|
-
}
|
|
7109
|
-
const results = [];
|
|
7110
|
-
notifications.forEach((notification, notificationIndex) => {
|
|
7111
|
-
const senders = collectSenderCandidates(notification);
|
|
7112
|
-
if (senders.length === 0) {
|
|
7113
|
-
return;
|
|
7114
|
-
}
|
|
7115
|
-
parsedRules.forEach((rule) => {
|
|
7116
|
-
if (senders.some((sender) => senderMatchesContact(sender, rule.contactName))) {
|
|
7117
|
-
results.push({ notificationIndex, ruleName: rule.ruleName });
|
|
7118
|
-
}
|
|
7119
|
-
});
|
|
7120
|
-
});
|
|
7121
|
-
return results;
|
|
7122
|
-
}
|
|
7123
|
-
function parseContactRule(rule) {
|
|
7124
|
-
const contactName = extractImportantContact(rule.description);
|
|
7125
|
-
if (!contactName) {
|
|
7126
|
-
return null;
|
|
7127
|
-
}
|
|
7128
|
-
return {
|
|
7129
|
-
ruleName: rule.name,
|
|
7130
|
-
contactName
|
|
7131
|
-
};
|
|
7132
|
-
}
|
|
7133
|
-
function extractImportantContact(description) {
|
|
7134
|
-
const text = description.trim();
|
|
7135
|
-
if (!text) {
|
|
7136
|
-
return null;
|
|
7137
|
-
}
|
|
7138
|
-
for (const prefix of CONTACT_PREFIXES) {
|
|
7139
|
-
const start = text.indexOf(prefix);
|
|
7140
|
-
if (start < 0) {
|
|
7141
|
-
continue;
|
|
7142
|
-
}
|
|
7143
|
-
const tail = text.slice(start + prefix.length);
|
|
7144
|
-
const actionMatch = CONTACT_ACTION_RE.exec(tail);
|
|
7145
|
-
if (!actionMatch || actionMatch.index === 0) {
|
|
7146
|
-
continue;
|
|
7147
|
-
}
|
|
7148
|
-
const rawName = tail.slice(0, actionMatch.index).trim();
|
|
7149
|
-
const cleaned = trimContactName(rawName);
|
|
7150
|
-
if (cleaned) {
|
|
7151
|
-
return cleaned;
|
|
7152
|
-
}
|
|
7153
|
-
}
|
|
7154
|
-
return null;
|
|
7155
|
-
}
|
|
7156
|
-
function trimContactName(value) {
|
|
7157
|
-
const cleaned = value.replace(/^[是为叫做名为\s]+/u, "").replace(/[,。,.;;].*$/u, "").trim();
|
|
7158
|
-
return cleaned || null;
|
|
7159
|
-
}
|
|
7160
|
-
function collectSenderCandidates(notification) {
|
|
7161
|
-
const candidates = [
|
|
7162
|
-
notification.senderName,
|
|
7163
|
-
notification.title,
|
|
7164
|
-
notification.conversationName,
|
|
7165
|
-
extractLeadingSender(notification.content)
|
|
7166
|
-
];
|
|
7167
|
-
const deduped = /* @__PURE__ */ new Map();
|
|
7168
|
-
for (const candidate of candidates) {
|
|
7169
|
-
if (!candidate) {
|
|
7170
|
-
continue;
|
|
7171
|
-
}
|
|
7172
|
-
const normalized = normalizeComparableName(candidate);
|
|
7173
|
-
if (normalized.length < 2) {
|
|
7174
|
-
continue;
|
|
7175
|
-
}
|
|
7176
|
-
deduped.set(normalized, candidate);
|
|
7177
|
-
}
|
|
7178
|
-
return Array.from(deduped.values());
|
|
7179
|
-
}
|
|
7180
|
-
function extractLeadingSender(content) {
|
|
7181
|
-
const text = content.trim();
|
|
7182
|
-
if (!text) {
|
|
7183
|
-
return null;
|
|
7184
|
-
}
|
|
7185
|
-
const match = LEADING_SENDER_RE.exec(text);
|
|
7186
|
-
if (!match) {
|
|
7187
|
-
return null;
|
|
7188
|
-
}
|
|
7189
|
-
return match[1]?.trim() || null;
|
|
7190
|
-
}
|
|
7191
|
-
function senderMatchesContact(sender, contactName) {
|
|
7192
|
-
const normalizedSender = normalizeComparableName(sender);
|
|
7193
|
-
const normalizedContact = normalizeComparableName(contactName);
|
|
7194
|
-
if (!normalizedSender || !normalizedContact) {
|
|
7195
|
-
return false;
|
|
7196
|
-
}
|
|
7197
|
-
return normalizedSender.includes(normalizedContact) || normalizedContact.includes(normalizedSender);
|
|
7198
|
-
}
|
|
7199
|
-
function normalizeComparableName(value) {
|
|
7200
|
-
return value.normalize("NFKC").replace(new RegExp("\\p{Extended_Pictographic}", "gu"), "").replace(/\s+/gu, "").replace(/[^\p{L}\p{N}]/gu, "");
|
|
7201
|
-
}
|
|
7202
|
-
|
|
7203
7100
|
// src/light-rules/inline-evaluator.ts
|
|
7204
7101
|
var InlineLightRuleEvaluator = class {
|
|
7205
7102
|
logger;
|
|
@@ -7219,40 +7116,8 @@ var InlineLightRuleEvaluator = class {
|
|
|
7219
7116
|
if (notifications.length === 0) return true;
|
|
7220
7117
|
const rules = this.registry.getEnabled();
|
|
7221
7118
|
if (rules.length === 0) return true;
|
|
7222
|
-
const
|
|
7223
|
-
|
|
7224
|
-
const llmCandidateRules = rules.filter((rule) => !localMatchedRuleNames.has(rule.name));
|
|
7225
|
-
const combinedMatches = /* @__PURE__ */ new Map();
|
|
7226
|
-
for (const match of localMatches) {
|
|
7227
|
-
combinedMatches.set(
|
|
7228
|
-
`${match.notificationIndex}:${match.ruleName}`,
|
|
7229
|
-
match
|
|
7230
|
-
);
|
|
7231
|
-
}
|
|
7232
|
-
if (localMatches.length > 0) {
|
|
7233
|
-
this.logger.info(
|
|
7234
|
-
`lightrules: local matched ${localMatchedRuleNames.size} rule(s) (notifications=${notifications.length}, remainingRules=${llmCandidateRules.length})`
|
|
7235
|
-
);
|
|
7236
|
-
}
|
|
7237
|
-
if (llmCandidateRules.length > 0) {
|
|
7238
|
-
const llmMatches = await this.invoker.matchNotifications(notifications, llmCandidateRules);
|
|
7239
|
-
if (llmMatches === null) {
|
|
7240
|
-
if (combinedMatches.size === 0) {
|
|
7241
|
-
return false;
|
|
7242
|
-
}
|
|
7243
|
-
this.logger.warn(
|
|
7244
|
-
`lightrules: invoker failed; using ${combinedMatches.size} local fallback match(es)`
|
|
7245
|
-
);
|
|
7246
|
-
} else {
|
|
7247
|
-
for (const match of llmMatches) {
|
|
7248
|
-
combinedMatches.set(
|
|
7249
|
-
`${match.notificationIndex}:${match.ruleName}`,
|
|
7250
|
-
match
|
|
7251
|
-
);
|
|
7252
|
-
}
|
|
7253
|
-
}
|
|
7254
|
-
}
|
|
7255
|
-
const matches = Array.from(combinedMatches.values());
|
|
7119
|
+
const matches = await this.invoker.matchNotifications(notifications, rules);
|
|
7120
|
+
if (matches === null) return false;
|
|
7256
7121
|
if (matches.length === 0) {
|
|
7257
7122
|
this.logger.info(
|
|
7258
7123
|
`lightrules: 0 matches (notifications=${notifications.length}, rules=${rules.length})`
|
|
@@ -7465,15 +7330,35 @@ function buildSystemPrompt(rules) {
|
|
|
7465
7330
|
lines.push("");
|
|
7466
7331
|
});
|
|
7467
7332
|
lines.push(
|
|
7468
|
-
"\
|
|
7333
|
+
"\u5DE5\u4F5C\u6B65\u9AA4\uFF08\u5FC5\u987B\u6309\u987A\u5E8F\u6267\u884C\uFF09\uFF1A",
|
|
7334
|
+
"",
|
|
7335
|
+
"1. \u5148\u628A\u6BCF\u6761\u89C4\u5219\u6309 description \u5F52\u7C7B\uFF1A",
|
|
7336
|
+
' - \u53D1\u4EF6\u4EBA\u578B\uFF1A\u63CF\u8FF0\u91CC\u51FA\u73B0\u5177\u4F53\u4EBA\u540D/\u79F0\u8C13\uFF08\u542B"\u91CD\u8981\u8054\u7CFB\u4EBA X""\u8001\u5A46""\u5F20\u67D0\u67D0"\u7B49\uFF09+ "\u53D1\u6D88\u606F/\u6765\u6D88\u606F/\u56DE\u590D/\u79C1\u804A"\u7B49\u52A8\u4F5C',
|
|
7337
|
+
" - \u5173\u952E\u8BCD\u578B\uFF1A\u63CF\u8FF0\u8981\u6C42\u6D88\u606F\u4E2D\u5305\u542B\u7279\u5B9A\u5B57\u773C/\u8BDD\u9898",
|
|
7338
|
+
" - \u8BED\u4E49\u578B\uFF1A\u9700\u8981\u7406\u89E3\u6D88\u606F\u542B\u4E49\u624D\u80FD\u5224\u65AD\uFF08\u60C5\u7EEA\u3001\u610F\u56FE\u3001\u573A\u666F\u7B49\uFF09",
|
|
7469
7339
|
"",
|
|
7470
|
-
"
|
|
7340
|
+
"2. \u6309\u7C7B\u578B\u5224\u65AD\u6BCF\u6761\u901A\u77E5\u662F\u5426\u547D\u4E2D\uFF1A",
|
|
7341
|
+
' - \u53D1\u4EF6\u4EBA\u578B\uFF1A\u4F9D\u6B21\u6BD4\u5BF9 sender \u2192 conversation_name \u2192 title \u2192 content \u5F00\u5934\u7684 "X:"/"X\uFF1A" \u524D\u7F00\u3002',
|
|
7342
|
+
" \u6BD4\u8F83\u524D\u5148\u5F52\u4E00\u5316\uFF08NFKC\u3001\u53BB\u7A7A\u767D\u3001\u53BB emoji\u3001\u5FFD\u7565\u4E2D\u82F1\u6587\u6807\u70B9\u5DEE\u5F02\uFF09\u3002",
|
|
7343
|
+
" \u4EFB\u4E00\u5B57\u6BB5\u4E0E\u63CF\u8FF0\u4E2D\u7684\u4EBA\u540D\u4E92\u76F8\u5305\u542B\uFF08A \u662F B \u7684\u5B50\u4E32\u6216\u53CD\u4E4B\uFF09\u5373\u89C6\u4E3A\u547D\u4E2D\u3002",
|
|
7344
|
+
' \u4E0D\u8981\u6C42\u901A\u77E5\u91CC\u51FA\u73B0"\u91CD\u8981\u8054\u7CFB\u4EBA"\u7B49\u4FEE\u9970\u8BCD\uFF0C\u53EA\u8981\u540D\u5B57\u5BF9\u5F97\u4E0A\u5C31\u89E6\u53D1\u3002',
|
|
7345
|
+
" - \u5173\u952E\u8BCD\u578B\uFF1A\u5728 title + content \u4E2D\u67E5\u627E\u5173\u952E\u8BCD\uFF08\u540C\u6837\u5F52\u4E00\u5316\u540E\u6BD4\u8F83\uFF0C\u652F\u6301\u540C\u4E49/\u8FD1\u4E49\u5339\u914D\uFF09",
|
|
7346
|
+
" - \u8BED\u4E49\u578B\uFF1A\u7EFC\u5408\u7406\u89E3 title + content \u540E\u5224\u65AD\uFF1B\u8FD9\u4E00\u7C7B\u62FF\u4E0D\u51C6\u65F6\u503E\u5411\u4E8E\u4E0D\u89E6\u53D1",
|
|
7347
|
+
"",
|
|
7348
|
+
"3. \u8F93\u51FA JSON\u3002",
|
|
7349
|
+
"",
|
|
7350
|
+
"\u8F93\u51FA\u683C\u5F0F\uFF08\u7EAF JSON\uFF0C\u4E0D\u8981 Markdown \u4EE3\u7801\u5757\u3001\u4E0D\u8981\u4EFB\u4F55\u89E3\u91CA\u6587\u5B57\uFF09\uFF1A",
|
|
7471
7351
|
'{"matches":[{"i":<\u901A\u77E5\u4E0B\u6807>,"rule":"<\u89C4\u5219name>"}]}',
|
|
7472
7352
|
"",
|
|
7473
7353
|
'- \u547D\u4E2D 0 \u6761 \u2192 \u8F93\u51FA {"matches":[]}',
|
|
7474
|
-
"- \u4E00\u6761\u901A\u77E5\u53EF\
|
|
7475
|
-
|
|
7476
|
-
"
|
|
7354
|
+
"- \u4E00\u6761\u901A\u77E5\u53EF\u547D\u4E2D\u591A\u6761\u89C4\u5219 \u2192 \u6BCF\u4E2A\u7EC4\u5408\u4E00\u4E2A\u6761\u76EE",
|
|
7355
|
+
"- rule \u5FC5\u987B\u7CBE\u786E\u7B49\u4E8E\u4E0A\u9762\u5217\u51FA\u7684 name \u5B57\u7B26\u4E32",
|
|
7356
|
+
"",
|
|
7357
|
+
"\u793A\u4F8B\uFF08\u4EC5\u4F9B\u53C2\u8003\u5339\u914D\u7B56\u7565\uFF0C\u4E0D\u4EE3\u8868\u5F53\u524D\u89C4\u5219\uFF09\uFF1A",
|
|
7358
|
+
' \u89C4\u5219 description: "\u91CD\u8981\u8054\u7CFB\u4EBA \u7814\u53D1\u5C0F\u52A9\u7406 \u53D1\u6D88\u606F\u65F6\u63D0\u9192"',
|
|
7359
|
+
' \u901A\u77E5 sender="\u7814\u53D1\u5C0F\u52A9\u7406\u{1F990}" \u2192 \u547D\u4E2D\uFF08\u53BB emoji \u540E\u540D\u5B57\u76F8\u540C\uFF09',
|
|
7360
|
+
' \u901A\u77E5 sender="\u674E\u56DB", content="\u7814\u53D1\u5C0F\u52A9\u7406 \u56DE\u5E94: \u6536\u5230" \u2192 \u547D\u4E2D\uFF08content \u5934\u90E8\u524D\u7F00\u5339\u914D\uFF09',
|
|
7361
|
+
' \u901A\u77E5 sender="\u738B\u4E94", content="\u7814\u53D1\u5C0F\u52A9\u7406\u8FD9\u4E2A\u4EA7\u54C1\u633A\u597D" \u2192 \u4E0D\u547D\u4E2D\uFF08\u540D\u5B57\u51FA\u73B0\u5728\u6B63\u6587\u4F46\u4E0D\u662F\u53D1\u4EF6\u4EBA\uFF09'
|
|
7477
7362
|
);
|
|
7478
7363
|
return lines.join("\n");
|
|
7479
7364
|
}
|
|
@@ -7542,6 +7427,43 @@ function resolveUpdateChannel(params) {
|
|
|
7542
7427
|
// src/update/index.ts
|
|
7543
7428
|
var import_node_path8 = require("path");
|
|
7544
7429
|
|
|
7430
|
+
// src/plugin/runtime-state.ts
|
|
7431
|
+
init_host();
|
|
7432
|
+
|
|
7433
|
+
// src/plugin/shared.ts
|
|
7434
|
+
function readBody(req) {
|
|
7435
|
+
return new Promise((resolve, reject) => {
|
|
7436
|
+
const chunks = [];
|
|
7437
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
7438
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
7439
|
+
req.on("error", reject);
|
|
7440
|
+
});
|
|
7441
|
+
}
|
|
7442
|
+
function trimToUndefined2(value) {
|
|
7443
|
+
if (typeof value !== "string") {
|
|
7444
|
+
return void 0;
|
|
7445
|
+
}
|
|
7446
|
+
const trimmed = value.trim();
|
|
7447
|
+
return trimmed || void 0;
|
|
7448
|
+
}
|
|
7449
|
+
|
|
7450
|
+
// src/plugin/runtime-state.ts
|
|
7451
|
+
function tryResolveRuntimeStateDir(api) {
|
|
7452
|
+
const runtimeState = api?.runtime?.state;
|
|
7453
|
+
const resolveStateDir2 = runtimeState?.resolveStateDir;
|
|
7454
|
+
if (typeof resolveStateDir2 !== "function") {
|
|
7455
|
+
return void 0;
|
|
7456
|
+
}
|
|
7457
|
+
try {
|
|
7458
|
+
return trimToUndefined2(resolveStateDir2.call(runtimeState));
|
|
7459
|
+
} catch {
|
|
7460
|
+
return void 0;
|
|
7461
|
+
}
|
|
7462
|
+
}
|
|
7463
|
+
function resolvePluginStateDir(api) {
|
|
7464
|
+
return tryResolveRuntimeStateDir(api) ?? resolveStateDir();
|
|
7465
|
+
}
|
|
7466
|
+
|
|
7545
7467
|
// src/update/checker.ts
|
|
7546
7468
|
function parseSemver(v) {
|
|
7547
7469
|
const [main, pre = null] = v.split("-", 2);
|
|
@@ -7762,7 +7684,7 @@ function resolveTargetDir(api) {
|
|
|
7762
7684
|
if (installPath) return installPath;
|
|
7763
7685
|
} catch {
|
|
7764
7686
|
}
|
|
7765
|
-
return (0, import_node_path8.join)(api
|
|
7687
|
+
return (0, import_node_path8.join)(resolvePluginStateDir(api), "extensions", PLUGIN_ID);
|
|
7766
7688
|
}
|
|
7767
7689
|
async function updateConfigRecord(api, version, targetDir, tgzUrl) {
|
|
7768
7690
|
const configApi = api.runtime.config;
|
|
@@ -7972,7 +7894,7 @@ function registerAutoUpdateLifecycle(deps) {
|
|
|
7972
7894
|
}
|
|
7973
7895
|
|
|
7974
7896
|
// src/plugin/cli.ts
|
|
7975
|
-
var
|
|
7897
|
+
var import_node_path15 = require("path");
|
|
7976
7898
|
|
|
7977
7899
|
// src/cli/auth.ts
|
|
7978
7900
|
var import_node_fs9 = require("fs");
|
|
@@ -8647,21 +8569,155 @@ function registerLightSetupTools(light) {
|
|
|
8647
8569
|
}
|
|
8648
8570
|
|
|
8649
8571
|
// src/cli/tunnel-status.ts
|
|
8650
|
-
var import_node_fs13 = require("fs");
|
|
8651
|
-
var import_node_path12 = require("path");
|
|
8652
8572
|
init_credentials();
|
|
8653
8573
|
init_env();
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8574
|
+
|
|
8575
|
+
// src/tunnel/status.ts
|
|
8576
|
+
var import_node_fs13 = require("fs");
|
|
8577
|
+
var import_node_path12 = require("path");
|
|
8578
|
+
var TUNNEL_STATUS_REL_PATH = (0, import_node_path12.join)(
|
|
8579
|
+
"plugins",
|
|
8580
|
+
"phone-notifications",
|
|
8581
|
+
"tunnel-status.json"
|
|
8582
|
+
);
|
|
8583
|
+
var TUNNEL_LOCK_REL_PATH = (0, import_node_path12.join)(
|
|
8584
|
+
"plugins",
|
|
8585
|
+
"phone-notifications",
|
|
8586
|
+
"relay-tunnel.lock"
|
|
8587
|
+
);
|
|
8588
|
+
function isTunnelState(value) {
|
|
8589
|
+
return value === "connected" || value === "connecting" || value === "disconnected" || value === "stopped";
|
|
8590
|
+
}
|
|
8591
|
+
function isTunnelStatusInfo(value) {
|
|
8592
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
8593
|
+
const obj = value;
|
|
8594
|
+
return isTunnelState(obj.state) && typeof obj.since === "string" && typeof obj.reconnectAttempt === "number" && (obj.lastDisconnectReason === void 0 || typeof obj.lastDisconnectReason === "string");
|
|
8595
|
+
}
|
|
8596
|
+
function parseTunnelLockInfo(value) {
|
|
8597
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
8598
|
+
const obj = value;
|
|
8599
|
+
return typeof obj.pid === "number" && typeof obj.startedAt === "string" ? { pid: obj.pid, startedAt: obj.startedAt } : null;
|
|
8600
|
+
}
|
|
8601
|
+
function isProcessAlive(pid) {
|
|
8602
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
8603
|
+
if (pid === process.pid) return true;
|
|
8604
|
+
try {
|
|
8605
|
+
process.kill(pid, 0);
|
|
8606
|
+
return true;
|
|
8607
|
+
} catch (err2) {
|
|
8608
|
+
return err2?.code === "EPERM";
|
|
8609
|
+
}
|
|
8610
|
+
}
|
|
8611
|
+
function isStatusOlderThanLock(statusSince, lockStartedAt) {
|
|
8612
|
+
const statusTs = Date.parse(statusSince);
|
|
8613
|
+
const lockTs = Date.parse(lockStartedAt);
|
|
8614
|
+
if (Number.isNaN(statusTs) || Number.isNaN(lockTs)) return false;
|
|
8615
|
+
return statusTs + 1e3 < lockTs;
|
|
8616
|
+
}
|
|
8617
|
+
function staleStatusMessage(status, lock) {
|
|
8618
|
+
const prefix = `\u96A7\u9053\u72B6\u6001\u6587\u4EF6\u663E\u793A\u5DF2\u8FDE\u63A5\uFF08\u81EA ${status.since}\uFF09`;
|
|
8619
|
+
if (!lock.exists) {
|
|
8620
|
+
return `${prefix}\uFF0C\u4F46\u672A\u627E\u5230\u672C\u5730\u8FD0\u884C\u9501\uFF0C\u72B6\u6001\u53EF\u80FD\u5DF2\u8FC7\u671F\u3002\u8BF7\u91CD\u542F openclaw \u4E3B\u8FDB\u7A0B\u3002`;
|
|
8621
|
+
}
|
|
8622
|
+
if (lock.pid === null || lock.startedAt === null) {
|
|
8623
|
+
return `${prefix}\uFF0C\u4F46\u672C\u5730\u8FD0\u884C\u9501\u5185\u5BB9\u4E0D\u5B8C\u6574\uFF0C\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u8FDE\u63A5\u662F\u5426\u4ECD\u7136\u6709\u6548\u3002\u8BF7\u91CD\u542F openclaw \u4E3B\u8FDB\u7A0B\u3002`;
|
|
8624
|
+
}
|
|
8625
|
+
if (lock.active === false) {
|
|
8626
|
+
return `${prefix}\uFF0C\u4F46\u672C\u5730\u8FD0\u884C\u9501\u4ECD\u6307\u5411\u5DF2\u9000\u51FA\u7684\u8FDB\u7A0B pid=${lock.pid}\uFF0C\u72B6\u6001\u53EF\u80FD\u5DF2\u8FC7\u671F\u3002\u8BF7\u91CD\u542F openclaw \u4E3B\u8FDB\u7A0B\u3002`;
|
|
8627
|
+
}
|
|
8628
|
+
return `${prefix}\uFF0C\u4F46\u5F53\u524D\u8FD0\u884C\u9501\u542F\u52A8\u4E8E ${lock.startedAt}\uFF0C\u665A\u4E8E\u72B6\u6001\u65F6\u95F4\uFF0C\u8BF4\u660E\u72B6\u6001\u672A\u968F\u65B0\u8FDB\u7A0B\u5237\u65B0\u3002\u8BF7\u91CD\u542F openclaw \u4E3B\u8FDB\u7A0B\u3002`;
|
|
8629
|
+
}
|
|
8630
|
+
function assessTunnelStatus(stateDir) {
|
|
8631
|
+
const statusFilePath = (0, import_node_path12.join)(stateDir, TUNNEL_STATUS_REL_PATH);
|
|
8632
|
+
const lockFilePath = (0, import_node_path12.join)(stateDir, TUNNEL_LOCK_REL_PATH);
|
|
8633
|
+
if (!(0, import_node_fs13.existsSync)(statusFilePath)) {
|
|
8634
|
+
return {
|
|
8635
|
+
status: null,
|
|
8636
|
+
issueCode: "STATUS_NOT_FOUND",
|
|
8637
|
+
issueMessage: "\u672A\u627E\u5230\u96A7\u9053\u72B6\u6001\u6587\u4EF6\uFF0C\u96A7\u9053\u670D\u52A1\u53EF\u80FD\u5C1A\u672A\u542F\u52A8\u8FC7\u3002\u8BF7\u786E\u8BA4 openclaw \u4E3B\u8FDB\u7A0B\u6B63\u5728\u8FD0\u884C\u3002",
|
|
8638
|
+
statusFilePath,
|
|
8639
|
+
lockFilePath,
|
|
8640
|
+
lock: {
|
|
8641
|
+
exists: (0, import_node_fs13.existsSync)(lockFilePath),
|
|
8642
|
+
pid: null,
|
|
8643
|
+
startedAt: null,
|
|
8644
|
+
active: null
|
|
8645
|
+
}
|
|
8646
|
+
};
|
|
8647
|
+
}
|
|
8648
|
+
let rawStatus;
|
|
8659
8649
|
try {
|
|
8660
|
-
|
|
8650
|
+
rawStatus = JSON.parse((0, import_node_fs13.readFileSync)(statusFilePath, "utf-8"));
|
|
8661
8651
|
} catch {
|
|
8662
|
-
return
|
|
8652
|
+
return {
|
|
8653
|
+
status: null,
|
|
8654
|
+
issueCode: "STATUS_INVALID",
|
|
8655
|
+
issueMessage: "\u96A7\u9053\u72B6\u6001\u6587\u4EF6\u89E3\u6790\u5931\u8D25\uFF0C\u6587\u4EF6\u5185\u5BB9\u635F\u574F\u6216\u683C\u5F0F\u4E0D\u6B63\u786E\u3002\u8BF7\u91CD\u542F openclaw \u4E3B\u8FDB\u7A0B\u3002",
|
|
8656
|
+
statusFilePath,
|
|
8657
|
+
lockFilePath,
|
|
8658
|
+
lock: {
|
|
8659
|
+
exists: (0, import_node_fs13.existsSync)(lockFilePath),
|
|
8660
|
+
pid: null,
|
|
8661
|
+
startedAt: null,
|
|
8662
|
+
active: null
|
|
8663
|
+
}
|
|
8664
|
+
};
|
|
8665
|
+
}
|
|
8666
|
+
if (!isTunnelStatusInfo(rawStatus)) {
|
|
8667
|
+
return {
|
|
8668
|
+
status: null,
|
|
8669
|
+
issueCode: "STATUS_INVALID",
|
|
8670
|
+
issueMessage: "\u96A7\u9053\u72B6\u6001\u6587\u4EF6\u7F3A\u5C11\u5FC5\u8981\u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E\u3002\u8BF7\u91CD\u542F openclaw \u4E3B\u8FDB\u7A0B\u3002",
|
|
8671
|
+
statusFilePath,
|
|
8672
|
+
lockFilePath,
|
|
8673
|
+
lock: {
|
|
8674
|
+
exists: (0, import_node_fs13.existsSync)(lockFilePath),
|
|
8675
|
+
pid: null,
|
|
8676
|
+
startedAt: null,
|
|
8677
|
+
active: null
|
|
8678
|
+
}
|
|
8679
|
+
};
|
|
8663
8680
|
}
|
|
8681
|
+
const status = rawStatus;
|
|
8682
|
+
const lockExists = (0, import_node_fs13.existsSync)(lockFilePath);
|
|
8683
|
+
let lockInfo = null;
|
|
8684
|
+
if (lockExists) {
|
|
8685
|
+
try {
|
|
8686
|
+
lockInfo = parseTunnelLockInfo(JSON.parse((0, import_node_fs13.readFileSync)(lockFilePath, "utf-8")));
|
|
8687
|
+
} catch {
|
|
8688
|
+
lockInfo = null;
|
|
8689
|
+
}
|
|
8690
|
+
}
|
|
8691
|
+
const lock = {
|
|
8692
|
+
exists: lockExists,
|
|
8693
|
+
pid: lockInfo?.pid ?? null,
|
|
8694
|
+
startedAt: lockInfo?.startedAt ?? null,
|
|
8695
|
+
active: lockInfo ? isProcessAlive(lockInfo.pid) : null
|
|
8696
|
+
};
|
|
8697
|
+
if (status.state === "connected") {
|
|
8698
|
+
const isStale = !lock.exists || lock.pid === null || lock.startedAt === null || lock.active === false || isStatusOlderThanLock(status.since, lock.startedAt);
|
|
8699
|
+
if (isStale) {
|
|
8700
|
+
return {
|
|
8701
|
+
status,
|
|
8702
|
+
issueCode: "STATUS_STALE",
|
|
8703
|
+
issueMessage: staleStatusMessage(status, lock),
|
|
8704
|
+
statusFilePath,
|
|
8705
|
+
lockFilePath,
|
|
8706
|
+
lock
|
|
8707
|
+
};
|
|
8708
|
+
}
|
|
8709
|
+
}
|
|
8710
|
+
return {
|
|
8711
|
+
status,
|
|
8712
|
+
issueCode: null,
|
|
8713
|
+
issueMessage: null,
|
|
8714
|
+
statusFilePath,
|
|
8715
|
+
lockFilePath,
|
|
8716
|
+
lock
|
|
8717
|
+
};
|
|
8664
8718
|
}
|
|
8719
|
+
|
|
8720
|
+
// src/cli/tunnel-status.ts
|
|
8665
8721
|
function formatMessage(status) {
|
|
8666
8722
|
switch (status.state) {
|
|
8667
8723
|
case "connected":
|
|
@@ -8692,13 +8748,23 @@ function registerTunnelStatus(ntf, ctx) {
|
|
|
8692
8748
|
"API Key \u672A\u8BBE\u7F6E\uFF0C\u96A7\u9053\u65E0\u6CD5\u8FDE\u63A5\u3002\u8BF7\u6267\u884C openclaw ntf auth set-api-key <apiKey>"
|
|
8693
8749
|
);
|
|
8694
8750
|
}
|
|
8695
|
-
|
|
8751
|
+
if (!ctx.stateDir) {
|
|
8752
|
+
exitError(
|
|
8753
|
+
"STATE_DIR_UNAVAILABLE",
|
|
8754
|
+
"\u65E0\u6CD5\u786E\u5B9A\u72B6\u6001\u76EE\u5F55\uFF0C\u65E0\u6CD5\u68C0\u67E5\u96A7\u9053\u72B6\u6001\u3002\u8BF7\u5728 openclaw \u4E3B\u73AF\u5883\u4E2D\u6267\u884C\u8BE5\u547D\u4EE4\u3002"
|
|
8755
|
+
);
|
|
8756
|
+
}
|
|
8757
|
+
const assessment = assessTunnelStatus(ctx.stateDir);
|
|
8758
|
+
const status = assessment.status;
|
|
8696
8759
|
if (!status) {
|
|
8697
8760
|
exitError(
|
|
8698
|
-
"STATUS_NOT_FOUND",
|
|
8699
|
-
"\u672A\u627E\u5230\u96A7\u9053\u72B6\u6001\u6587\u4EF6\uFF0C\u96A7\u9053\u670D\u52A1\u53EF\u80FD\u5C1A\u672A\u542F\u52A8\u8FC7\u3002\u8BF7\u786E\u8BA4 openclaw \u4E3B\u8FDB\u7A0B\u6B63\u5728\u8FD0\u884C\u3002"
|
|
8761
|
+
assessment.issueCode ?? "STATUS_NOT_FOUND",
|
|
8762
|
+
assessment.issueMessage ?? "\u672A\u627E\u5230\u96A7\u9053\u72B6\u6001\u6587\u4EF6\uFF0C\u96A7\u9053\u670D\u52A1\u53EF\u80FD\u5C1A\u672A\u542F\u52A8\u8FC7\u3002\u8BF7\u786E\u8BA4 openclaw \u4E3B\u8FDB\u7A0B\u6B63\u5728\u8FD0\u884C\u3002"
|
|
8700
8763
|
);
|
|
8701
8764
|
}
|
|
8765
|
+
if (assessment.issueCode) {
|
|
8766
|
+
exitError(assessment.issueCode, assessment.issueMessage ?? formatMessage(status));
|
|
8767
|
+
}
|
|
8702
8768
|
const ok2 = status.state === "connected";
|
|
8703
8769
|
output({
|
|
8704
8770
|
ok: ok2,
|
|
@@ -8709,6 +8775,11 @@ function registerTunnelStatus(ntf, ctx) {
|
|
|
8709
8775
|
reconnectAttempt: status.reconnectAttempt,
|
|
8710
8776
|
lastDisconnectReason: status.lastDisconnectReason
|
|
8711
8777
|
},
|
|
8778
|
+
runtime: {
|
|
8779
|
+
lockOwnerPid: assessment.lock.pid,
|
|
8780
|
+
lockOwnerStartedAt: assessment.lock.startedAt,
|
|
8781
|
+
lockOwnerActive: assessment.lock.active
|
|
8782
|
+
},
|
|
8712
8783
|
message: formatMessage(status)
|
|
8713
8784
|
});
|
|
8714
8785
|
if (!ok2) process.exit(1);
|
|
@@ -8888,7 +8959,7 @@ function registerEnvCli(ntf, deps = {}) {
|
|
|
8888
8959
|
}
|
|
8889
8960
|
|
|
8890
8961
|
// src/cli/doctor.ts
|
|
8891
|
-
var
|
|
8962
|
+
var import_node_fs17 = require("fs");
|
|
8892
8963
|
var import_node_readline = require("readline");
|
|
8893
8964
|
init_host();
|
|
8894
8965
|
|
|
@@ -9037,39 +9108,40 @@ var checkCredentials = () => {
|
|
|
9037
9108
|
};
|
|
9038
9109
|
|
|
9039
9110
|
// src/cli/doctor/check-tunnel.ts
|
|
9040
|
-
var import_node_fs17 = require("fs");
|
|
9041
|
-
var import_node_path14 = require("path");
|
|
9042
|
-
var STATUS_REL_PATH2 = (0, import_node_path14.join)(
|
|
9043
|
-
"plugins",
|
|
9044
|
-
"phone-notifications",
|
|
9045
|
-
"tunnel-status.json"
|
|
9046
|
-
);
|
|
9047
9111
|
var checkTunnel = ({ stateDir }) => {
|
|
9048
|
-
const
|
|
9049
|
-
|
|
9112
|
+
const assessment = assessTunnelStatus(stateDir);
|
|
9113
|
+
const status = assessment.status;
|
|
9114
|
+
if (assessment.issueCode === "STATUS_NOT_FOUND") {
|
|
9050
9115
|
return {
|
|
9051
9116
|
id: "tunnel",
|
|
9052
9117
|
severity: "warn",
|
|
9053
9118
|
title: "\u96A7\u9053\u72B6\u6001\u6587\u4EF6\u4E0D\u5B58\u5728",
|
|
9054
|
-
detail: "\u96A7\u9053\u670D\u52A1\u53EF\u80FD\u5C1A\u672A\u542F\u52A8\u8FC7\uFF0C\u6216\u72B6\u6001\u6587\u4EF6\u5DF2\u88AB\u5220\u9664\u3002",
|
|
9119
|
+
detail: assessment.issueMessage ?? "\u96A7\u9053\u670D\u52A1\u53EF\u80FD\u5C1A\u672A\u542F\u52A8\u8FC7\uFF0C\u6216\u72B6\u6001\u6587\u4EF6\u5DF2\u88AB\u5220\u9664\u3002",
|
|
9055
9120
|
fixDescription: "\u8BF7\u786E\u8BA4 openclaw \u4E3B\u8FDB\u7A0B\u6B63\u5728\u8FD0\u884C",
|
|
9056
9121
|
fix: null
|
|
9057
9122
|
};
|
|
9058
9123
|
}
|
|
9059
|
-
|
|
9060
|
-
try {
|
|
9061
|
-
status = JSON.parse((0, import_node_fs17.readFileSync)(filePath, "utf-8"));
|
|
9062
|
-
} catch {
|
|
9124
|
+
if (assessment.issueCode === "STATUS_INVALID") {
|
|
9063
9125
|
return {
|
|
9064
9126
|
id: "tunnel",
|
|
9065
9127
|
severity: "warn",
|
|
9066
9128
|
title: "\u96A7\u9053\u72B6\u6001\u6587\u4EF6\u89E3\u6790\u5931\u8D25",
|
|
9067
|
-
detail: "\u6587\u4EF6\u5185\u5BB9\u635F\u574F\u6216\u683C\u5F0F\u4E0D\u6B63\u786E\u3002",
|
|
9129
|
+
detail: assessment.issueMessage ?? "\u6587\u4EF6\u5185\u5BB9\u635F\u574F\u6216\u683C\u5F0F\u4E0D\u6B63\u786E\u3002",
|
|
9068
9130
|
fixDescription: "\u8BF7\u91CD\u542F openclaw \u4E3B\u8FDB\u7A0B",
|
|
9069
9131
|
fix: null
|
|
9070
9132
|
};
|
|
9071
9133
|
}
|
|
9072
|
-
if (
|
|
9134
|
+
if (assessment.issueCode === "STATUS_STALE") {
|
|
9135
|
+
return {
|
|
9136
|
+
id: "tunnel",
|
|
9137
|
+
severity: "warn",
|
|
9138
|
+
title: "\u96A7\u9053\u72B6\u6001\u5DF2\u8FC7\u671F",
|
|
9139
|
+
detail: assessment.issueMessage ?? "\u96A7\u9053\u72B6\u6001\u6587\u4EF6\u4ECD\u663E\u793A\u5DF2\u8FDE\u63A5\uFF0C\u4F46\u8FD0\u884C\u65F6\u72B6\u6001\u5DF2\u5931\u6548\u3002",
|
|
9140
|
+
fixDescription: "\u8BF7\u91CD\u542F openclaw \u4E3B\u8FDB\u7A0B",
|
|
9141
|
+
fix: null
|
|
9142
|
+
};
|
|
9143
|
+
}
|
|
9144
|
+
if (!status || status.state === "connected") return null;
|
|
9073
9145
|
const reasonSuffix = status.lastDisconnectReason ? `\uFF0C\u539F\u56E0: ${status.lastDisconnectReason}` : "";
|
|
9074
9146
|
return {
|
|
9075
9147
|
id: "tunnel",
|
|
@@ -9151,9 +9223,9 @@ function isObject5(v) {
|
|
|
9151
9223
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
9152
9224
|
}
|
|
9153
9225
|
function readConfig(configPath) {
|
|
9154
|
-
if (!(0,
|
|
9226
|
+
if (!(0, import_node_fs17.existsSync)(configPath)) return {};
|
|
9155
9227
|
try {
|
|
9156
|
-
const parsed = JSON.parse((0,
|
|
9228
|
+
const parsed = JSON.parse((0, import_node_fs17.readFileSync)(configPath, "utf-8"));
|
|
9157
9229
|
return isObject5(parsed) ? parsed : {};
|
|
9158
9230
|
} catch {
|
|
9159
9231
|
return {};
|
|
@@ -9356,7 +9428,7 @@ function registerRecStoragePath(rec, ctx) {
|
|
|
9356
9428
|
|
|
9357
9429
|
// src/cli/rec-setup.ts
|
|
9358
9430
|
var import_node_readline2 = require("readline");
|
|
9359
|
-
var
|
|
9431
|
+
var import_node_fs18 = require("fs");
|
|
9360
9432
|
function ask(rl, question) {
|
|
9361
9433
|
return new Promise((resolve) => rl.question(question, resolve));
|
|
9362
9434
|
}
|
|
@@ -9442,9 +9514,9 @@ async function setupLocal(rl) {
|
|
|
9442
9514
|
function registerRecSetup(rec, ctx) {
|
|
9443
9515
|
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 () => {
|
|
9444
9516
|
const configPath = resolveAsrConfigPath(ctx);
|
|
9445
|
-
if ((0,
|
|
9517
|
+
if ((0, import_node_fs18.existsSync)(configPath)) {
|
|
9446
9518
|
try {
|
|
9447
|
-
const existing = JSON.parse((0,
|
|
9519
|
+
const existing = JSON.parse((0, import_node_fs18.readFileSync)(configPath, "utf-8"));
|
|
9448
9520
|
process.stderr.write(`\u5F53\u524D\u5DF2\u6709\u914D\u7F6E\uFF1Amode = ${existing.mode}`);
|
|
9449
9521
|
if (existing.updatedAt) process.stderr.write(`\uFF0C\u66F4\u65B0\u4E8E ${existing.updatedAt}`);
|
|
9450
9522
|
process.stderr.write("\n");
|
|
@@ -9457,7 +9529,7 @@ function registerRecSetup(rec, ctx) {
|
|
|
9457
9529
|
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"]);
|
|
9458
9530
|
const config = modeIdx === 0 ? await setupApi(rl) : await setupLocal(rl);
|
|
9459
9531
|
const stored = { ...config, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
9460
|
-
(0,
|
|
9532
|
+
(0, import_node_fs18.writeFileSync)(configPath, JSON.stringify(stored, null, 2), "utf-8");
|
|
9461
9533
|
process.stderr.write(`
|
|
9462
9534
|
\u2713 \u914D\u7F6E\u5DF2\u4FDD\u5B58\u5230 ${configPath}
|
|
9463
9535
|
|
|
@@ -9471,8 +9543,8 @@ function registerRecSetup(rec, ctx) {
|
|
|
9471
9543
|
|
|
9472
9544
|
// src/cli/update.ts
|
|
9473
9545
|
var import_node_child_process2 = require("child_process");
|
|
9474
|
-
var
|
|
9475
|
-
var
|
|
9546
|
+
var import_node_fs19 = require("fs");
|
|
9547
|
+
var import_node_path14 = require("path");
|
|
9476
9548
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
9477
9549
|
init_host();
|
|
9478
9550
|
var BASE_URL2 = "https://artifact.yoooclaw.com/plugin";
|
|
@@ -9531,9 +9603,9 @@ async function runUpdate(ctx, opts) {
|
|
|
9531
9603
|
`);
|
|
9532
9604
|
process.exit(1);
|
|
9533
9605
|
}
|
|
9534
|
-
const tmpScript = (0,
|
|
9606
|
+
const tmpScript = (0, import_node_path14.join)(import_node_os3.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
|
|
9535
9607
|
try {
|
|
9536
|
-
(0,
|
|
9608
|
+
(0, import_node_fs19.writeFileSync)(tmpScript, installScript, "utf-8");
|
|
9537
9609
|
} catch (err2) {
|
|
9538
9610
|
const msg = `\u5199\u5165\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${err2?.message ?? String(err2)}`;
|
|
9539
9611
|
if (json) {
|
|
@@ -9551,7 +9623,7 @@ async function runUpdate(ctx, opts) {
|
|
|
9551
9623
|
{ stdio: "inherit" }
|
|
9552
9624
|
);
|
|
9553
9625
|
try {
|
|
9554
|
-
(0,
|
|
9626
|
+
(0, import_node_fs19.unlinkSync)(tmpScript);
|
|
9555
9627
|
} catch {
|
|
9556
9628
|
}
|
|
9557
9629
|
if (result.error) {
|
|
@@ -9615,17 +9687,17 @@ function inferOpenClawRootDir(workspaceDir) {
|
|
|
9615
9687
|
if (!workspaceDir) {
|
|
9616
9688
|
return void 0;
|
|
9617
9689
|
}
|
|
9618
|
-
if ((0,
|
|
9690
|
+
if ((0, import_node_path15.basename)(workspaceDir) !== "workspace") {
|
|
9619
9691
|
return void 0;
|
|
9620
9692
|
}
|
|
9621
|
-
return (0,
|
|
9693
|
+
return (0, import_node_path15.dirname)(workspaceDir);
|
|
9622
9694
|
}
|
|
9623
9695
|
function registerPluginCli(api, params) {
|
|
9624
9696
|
const { logger, openclawDir } = params;
|
|
9625
9697
|
const registerAlias = (command) => {
|
|
9626
9698
|
api.registerCli(
|
|
9627
9699
|
(ctx) => {
|
|
9628
|
-
const effectiveStateDir = openclawDir ?? inferOpenClawRootDir(ctx.workspaceDir);
|
|
9700
|
+
const effectiveStateDir = openclawDir ?? ctx.stateDir ?? inferOpenClawRootDir(ctx.workspaceDir);
|
|
9629
9701
|
registerAllCli(
|
|
9630
9702
|
ctx.program,
|
|
9631
9703
|
{
|
|
@@ -9869,12 +9941,12 @@ function registerLightControlTool(api, logger) {
|
|
|
9869
9941
|
}
|
|
9870
9942
|
|
|
9871
9943
|
// src/plugin/lifecycle.ts
|
|
9872
|
-
var
|
|
9944
|
+
var import_node_fs29 = require("fs");
|
|
9873
9945
|
init_host();
|
|
9874
9946
|
|
|
9875
9947
|
// src/notification/app-name-map.ts
|
|
9876
|
-
var
|
|
9877
|
-
var
|
|
9948
|
+
var import_node_fs20 = require("fs");
|
|
9949
|
+
var import_node_path16 = require("path");
|
|
9878
9950
|
init_credentials();
|
|
9879
9951
|
init_env();
|
|
9880
9952
|
var PLUGIN_STATE_DIR = "phone-notifications";
|
|
@@ -9895,7 +9967,7 @@ function isAppNameMapApiResponse(v) {
|
|
|
9895
9967
|
);
|
|
9896
9968
|
}
|
|
9897
9969
|
function getCachePath(stateDir) {
|
|
9898
|
-
return (0,
|
|
9970
|
+
return (0, import_node_path16.join)(stateDir, "plugins", PLUGIN_STATE_DIR, CACHE_FILE);
|
|
9899
9971
|
}
|
|
9900
9972
|
function createAppNameMapProvider(opts) {
|
|
9901
9973
|
const { stateDir, logger } = opts;
|
|
@@ -9907,9 +9979,9 @@ function createAppNameMapProvider(opts) {
|
|
|
9907
9979
|
let inFlightFetch = null;
|
|
9908
9980
|
function loadFromDisk() {
|
|
9909
9981
|
const path2 = getCachePath(stateDir);
|
|
9910
|
-
if (!(0,
|
|
9982
|
+
if (!(0, import_node_fs20.existsSync)(path2)) return;
|
|
9911
9983
|
try {
|
|
9912
|
-
const raw = JSON.parse((0,
|
|
9984
|
+
const raw = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf-8"));
|
|
9913
9985
|
if (!isRecordOfStrings(raw)) return;
|
|
9914
9986
|
map.clear();
|
|
9915
9987
|
for (const [k, v] of Object.entries(raw)) map.set(k, v);
|
|
@@ -9953,10 +10025,10 @@ function createAppNameMapProvider(opts) {
|
|
|
9953
10025
|
logger.warn("[app-name-map] refresh succeeded but got 0 entries");
|
|
9954
10026
|
return;
|
|
9955
10027
|
}
|
|
9956
|
-
const dir = (0,
|
|
9957
|
-
(0,
|
|
10028
|
+
const dir = (0, import_node_path16.join)(stateDir, "plugins", PLUGIN_STATE_DIR);
|
|
10029
|
+
(0, import_node_fs20.mkdirSync)(dir, { recursive: true });
|
|
9958
10030
|
const cachePath = getCachePath(stateDir);
|
|
9959
|
-
(0,
|
|
10031
|
+
(0, import_node_fs20.writeFileSync)(cachePath, JSON.stringify(Object.fromEntries(map), null, 2), "utf-8");
|
|
9960
10032
|
logger.info(`[app-name-map] refreshed ${map.size} entries from server and saved: ${cachePath}`);
|
|
9961
10033
|
} catch (e) {
|
|
9962
10034
|
const message = e instanceof Error ? e.message : String(e);
|
|
@@ -10000,9 +10072,9 @@ function createAppNameMapProvider(opts) {
|
|
|
10000
10072
|
}
|
|
10001
10073
|
|
|
10002
10074
|
// src/notification/storage.ts
|
|
10003
|
-
var
|
|
10075
|
+
var import_node_fs21 = require("fs");
|
|
10004
10076
|
var import_node_crypto2 = require("crypto");
|
|
10005
|
-
var
|
|
10077
|
+
var import_node_path17 = require("path");
|
|
10006
10078
|
|
|
10007
10079
|
// src/notification/feishu-normalize.ts
|
|
10008
10080
|
function normalizeOptionalText(value) {
|
|
@@ -10130,7 +10202,7 @@ var NOTIFICATION_DIR_NAME = "notifications";
|
|
|
10130
10202
|
var ID_INDEX_DIR_NAME = ".ids";
|
|
10131
10203
|
var CONTENT_KEY_INDEX_DIR_NAME = ".keys";
|
|
10132
10204
|
function getStateFallbackNotificationDir(stateDir) {
|
|
10133
|
-
return (0,
|
|
10205
|
+
return (0, import_node_path17.join)(stateDir, "plugins", "phone-notifications", NOTIFICATION_DIR_NAME);
|
|
10134
10206
|
}
|
|
10135
10207
|
function buildFallbackContent(n) {
|
|
10136
10208
|
const body = n.body?.trim();
|
|
@@ -10148,8 +10220,8 @@ function buildFallbackContent(n) {
|
|
|
10148
10220
|
}
|
|
10149
10221
|
function ensureWritableDirectory(dir) {
|
|
10150
10222
|
try {
|
|
10151
|
-
(0,
|
|
10152
|
-
(0,
|
|
10223
|
+
(0, import_node_fs21.mkdirSync)(dir, { recursive: true });
|
|
10224
|
+
(0, import_node_fs21.accessSync)(dir, import_node_fs21.constants.R_OK | import_node_fs21.constants.W_OK);
|
|
10153
10225
|
return true;
|
|
10154
10226
|
} catch {
|
|
10155
10227
|
return false;
|
|
@@ -10162,7 +10234,7 @@ function resolveNotificationStorageDir(ctx, logger) {
|
|
|
10162
10234
|
return stateNotifDir;
|
|
10163
10235
|
}
|
|
10164
10236
|
if (ctx.workspaceDir) {
|
|
10165
|
-
const workspaceDir = (0,
|
|
10237
|
+
const workspaceDir = (0, import_node_path17.join)(ctx.workspaceDir, NOTIFICATION_DIR_NAME);
|
|
10166
10238
|
if (ensureWritableDirectory(workspaceDir)) {
|
|
10167
10239
|
logger.warn(
|
|
10168
10240
|
`stateDir \u4E0D\u53EF\u7528\uFF0C\u901A\u77E5\u5DF2\u56DE\u9000\u5230 workspace \u8DEF\u5F84: ${workspaceDir}`
|
|
@@ -10177,8 +10249,8 @@ var NotificationStorage = class {
|
|
|
10177
10249
|
this.config = config;
|
|
10178
10250
|
this.logger = logger;
|
|
10179
10251
|
this.dir = dir;
|
|
10180
|
-
this.idIndexDir = (0,
|
|
10181
|
-
this.contentKeyIndexDir = (0,
|
|
10252
|
+
this.idIndexDir = (0, import_node_path17.join)(dir, ID_INDEX_DIR_NAME);
|
|
10253
|
+
this.contentKeyIndexDir = (0, import_node_path17.join)(dir, CONTENT_KEY_INDEX_DIR_NAME);
|
|
10182
10254
|
this.resolveDisplayName = resolveDisplayName;
|
|
10183
10255
|
}
|
|
10184
10256
|
dir;
|
|
@@ -10189,10 +10261,10 @@ var NotificationStorage = class {
|
|
|
10189
10261
|
dateWriteChains = /* @__PURE__ */ new Map();
|
|
10190
10262
|
resolveDisplayName;
|
|
10191
10263
|
async init() {
|
|
10192
|
-
(0,
|
|
10193
|
-
(0,
|
|
10194
|
-
(0,
|
|
10195
|
-
(0,
|
|
10264
|
+
(0, import_node_fs21.mkdirSync)(this.dir, { recursive: true });
|
|
10265
|
+
(0, import_node_fs21.mkdirSync)(this.idIndexDir, { recursive: true });
|
|
10266
|
+
(0, import_node_fs21.rmSync)(this.contentKeyIndexDir, { recursive: true, force: true });
|
|
10267
|
+
(0, import_node_fs21.mkdirSync)(this.contentKeyIndexDir, { recursive: true });
|
|
10196
10268
|
}
|
|
10197
10269
|
async ingest(items) {
|
|
10198
10270
|
const result = {
|
|
@@ -10231,7 +10303,7 @@ var NotificationStorage = class {
|
|
|
10231
10303
|
return { kind: "invalid" };
|
|
10232
10304
|
}
|
|
10233
10305
|
const dateKey = this.formatDate(ts);
|
|
10234
|
-
const filePath = (0,
|
|
10306
|
+
const filePath = (0, import_node_path17.join)(this.dir, `${dateKey}.json`);
|
|
10235
10307
|
const normalizedId = typeof n.id === "string" ? n.id.trim() : "";
|
|
10236
10308
|
const entry = this.buildStoredNotification(n);
|
|
10237
10309
|
return this.withDateWriteLock(dateKey, async () => {
|
|
@@ -10248,7 +10320,7 @@ var NotificationStorage = class {
|
|
|
10248
10320
|
};
|
|
10249
10321
|
const arr = this.readStoredNotifications(filePath);
|
|
10250
10322
|
arr.push(storedEntry);
|
|
10251
|
-
(0,
|
|
10323
|
+
(0, import_node_fs21.writeFileSync)(filePath, JSON.stringify(arr, null, 2), "utf-8");
|
|
10252
10324
|
if (normalizedId) {
|
|
10253
10325
|
this.recordNotificationId(dateKey, normalizedId);
|
|
10254
10326
|
}
|
|
@@ -10282,7 +10354,7 @@ var NotificationStorage = class {
|
|
|
10282
10354
|
return `${year}-${month}-${day}`;
|
|
10283
10355
|
}
|
|
10284
10356
|
getIdIndexPath(dateKey) {
|
|
10285
|
-
return (0,
|
|
10357
|
+
return (0, import_node_path17.join)(this.idIndexDir, `${dateKey}.ids`);
|
|
10286
10358
|
}
|
|
10287
10359
|
getIdSet(dateKey) {
|
|
10288
10360
|
const cached = this.idCache.get(dateKey);
|
|
@@ -10291,8 +10363,8 @@ var NotificationStorage = class {
|
|
|
10291
10363
|
}
|
|
10292
10364
|
const idPath = this.getIdIndexPath(dateKey);
|
|
10293
10365
|
const ids = /* @__PURE__ */ new Set();
|
|
10294
|
-
if ((0,
|
|
10295
|
-
const lines = (0,
|
|
10366
|
+
if ((0, import_node_fs21.existsSync)(idPath)) {
|
|
10367
|
+
const lines = (0, import_node_fs21.readFileSync)(idPath, "utf-8").split(/\r?\n/);
|
|
10296
10368
|
for (const line of lines) {
|
|
10297
10369
|
const id = line.trim();
|
|
10298
10370
|
if (id) {
|
|
@@ -10307,7 +10379,7 @@ var NotificationStorage = class {
|
|
|
10307
10379
|
return this.getIdSet(dateKey).has(id);
|
|
10308
10380
|
}
|
|
10309
10381
|
getContentKeyIndexPath(dateKey) {
|
|
10310
|
-
return (0,
|
|
10382
|
+
return (0, import_node_path17.join)(this.contentKeyIndexDir, `${dateKey}.keys`);
|
|
10311
10383
|
}
|
|
10312
10384
|
getContentKeySet(dateKey, filePath) {
|
|
10313
10385
|
const cached = this.contentKeyCache.get(dateKey);
|
|
@@ -10316,16 +10388,16 @@ var NotificationStorage = class {
|
|
|
10316
10388
|
}
|
|
10317
10389
|
const keyPath = this.getContentKeyIndexPath(dateKey);
|
|
10318
10390
|
const keys = /* @__PURE__ */ new Set();
|
|
10319
|
-
if ((0,
|
|
10391
|
+
if ((0, import_node_fs21.existsSync)(filePath)) {
|
|
10320
10392
|
for (const item of this.readStoredNotifications(filePath)) {
|
|
10321
10393
|
keys.add(this.buildNotificationContentKey(item));
|
|
10322
10394
|
}
|
|
10323
10395
|
}
|
|
10324
10396
|
if (keys.size > 0) {
|
|
10325
|
-
(0,
|
|
10397
|
+
(0, import_node_fs21.writeFileSync)(keyPath, `${Array.from(keys).join("\n")}
|
|
10326
10398
|
`, "utf-8");
|
|
10327
|
-
} else if ((0,
|
|
10328
|
-
(0,
|
|
10399
|
+
} else if ((0, import_node_fs21.existsSync)(keyPath)) {
|
|
10400
|
+
(0, import_node_fs21.rmSync)(keyPath, { force: true });
|
|
10329
10401
|
}
|
|
10330
10402
|
this.contentKeyCache.set(dateKey, keys);
|
|
10331
10403
|
return keys;
|
|
@@ -10340,7 +10412,7 @@ var NotificationStorage = class {
|
|
|
10340
10412
|
if (ids.has(id)) {
|
|
10341
10413
|
return;
|
|
10342
10414
|
}
|
|
10343
|
-
(0,
|
|
10415
|
+
(0, import_node_fs21.appendFileSync)(this.getIdIndexPath(dateKey), `${id}
|
|
10344
10416
|
`, "utf-8");
|
|
10345
10417
|
ids.add(id);
|
|
10346
10418
|
}
|
|
@@ -10350,7 +10422,7 @@ var NotificationStorage = class {
|
|
|
10350
10422
|
if (keys.has(key)) {
|
|
10351
10423
|
return;
|
|
10352
10424
|
}
|
|
10353
|
-
(0,
|
|
10425
|
+
(0, import_node_fs21.appendFileSync)(this.getContentKeyIndexPath(dateKey), `${key}
|
|
10354
10426
|
`, "utf-8");
|
|
10355
10427
|
keys.add(key);
|
|
10356
10428
|
}
|
|
@@ -10358,11 +10430,11 @@ var NotificationStorage = class {
|
|
|
10358
10430
|
return (0, import_node_crypto2.createHash)("sha256").update(entry.appName).update("").update(entry.title).update("").update(entry.content).update("").update(entry.timestamp).digest("hex");
|
|
10359
10431
|
}
|
|
10360
10432
|
readStoredNotifications(filePath) {
|
|
10361
|
-
if (!(0,
|
|
10433
|
+
if (!(0, import_node_fs21.existsSync)(filePath)) {
|
|
10362
10434
|
return [];
|
|
10363
10435
|
}
|
|
10364
10436
|
try {
|
|
10365
|
-
const parsed = JSON.parse((0,
|
|
10437
|
+
const parsed = JSON.parse((0, import_node_fs21.readFileSync)(filePath, "utf-8"));
|
|
10366
10438
|
return Array.isArray(parsed) ? parsed : [];
|
|
10367
10439
|
} catch {
|
|
10368
10440
|
return [];
|
|
@@ -10402,14 +10474,14 @@ var NotificationStorage = class {
|
|
|
10402
10474
|
const dateFilePattern = /^(\d{4}-\d{2}-\d{2})\.(json|md)$/;
|
|
10403
10475
|
const dateDirPattern = /^\d{4}-\d{2}-\d{2}$/;
|
|
10404
10476
|
try {
|
|
10405
|
-
for (const entry of (0,
|
|
10477
|
+
for (const entry of (0, import_node_fs21.readdirSync)(this.dir, { withFileTypes: true })) {
|
|
10406
10478
|
if (entry.isFile()) {
|
|
10407
10479
|
const match = dateFilePattern.exec(entry.name);
|
|
10408
10480
|
if (match && match[1] < cutoffDate) {
|
|
10409
|
-
(0,
|
|
10481
|
+
(0, import_node_fs21.rmSync)((0, import_node_path17.join)(this.dir, entry.name), { force: true });
|
|
10410
10482
|
}
|
|
10411
10483
|
} else if (entry.isDirectory() && dateDirPattern.test(entry.name) && entry.name < cutoffDate) {
|
|
10412
|
-
(0,
|
|
10484
|
+
(0, import_node_fs21.rmSync)((0, import_node_path17.join)(this.dir, entry.name), { recursive: true, force: true });
|
|
10413
10485
|
}
|
|
10414
10486
|
}
|
|
10415
10487
|
} catch {
|
|
@@ -10418,11 +10490,11 @@ var NotificationStorage = class {
|
|
|
10418
10490
|
/** Remove expired .ids index files */
|
|
10419
10491
|
pruneIdIndex(cutoffDate) {
|
|
10420
10492
|
try {
|
|
10421
|
-
for (const entry of (0,
|
|
10493
|
+
for (const entry of (0, import_node_fs21.readdirSync)(this.idIndexDir, { withFileTypes: true })) {
|
|
10422
10494
|
if (!entry.isFile()) continue;
|
|
10423
10495
|
const match = /^(\d{4}-\d{2}-\d{2})\.ids$/.exec(entry.name);
|
|
10424
10496
|
if (match && match[1] < cutoffDate) {
|
|
10425
|
-
(0,
|
|
10497
|
+
(0, import_node_fs21.rmSync)((0, import_node_path17.join)(this.idIndexDir, entry.name), { force: true });
|
|
10426
10498
|
this.idCache.delete(match[1]);
|
|
10427
10499
|
}
|
|
10428
10500
|
}
|
|
@@ -10431,11 +10503,11 @@ var NotificationStorage = class {
|
|
|
10431
10503
|
}
|
|
10432
10504
|
pruneContentKeyIndex(cutoffDate) {
|
|
10433
10505
|
try {
|
|
10434
|
-
for (const entry of (0,
|
|
10506
|
+
for (const entry of (0, import_node_fs21.readdirSync)(this.contentKeyIndexDir, { withFileTypes: true })) {
|
|
10435
10507
|
if (!entry.isFile()) continue;
|
|
10436
10508
|
const match = /^(\d{4}-\d{2}-\d{2})\.keys$/.exec(entry.name);
|
|
10437
10509
|
if (match && match[1] < cutoffDate) {
|
|
10438
|
-
(0,
|
|
10510
|
+
(0, import_node_fs21.rmSync)((0, import_node_path17.join)(this.contentKeyIndexDir, entry.name), { force: true });
|
|
10439
10511
|
this.contentKeyCache.delete(match[1]);
|
|
10440
10512
|
}
|
|
10441
10513
|
}
|
|
@@ -10450,8 +10522,8 @@ var NotificationStorage = class {
|
|
|
10450
10522
|
};
|
|
10451
10523
|
|
|
10452
10524
|
// src/recording/storage.ts
|
|
10453
|
-
var
|
|
10454
|
-
var
|
|
10525
|
+
var import_node_fs22 = require("fs");
|
|
10526
|
+
var import_node_path18 = require("path");
|
|
10455
10527
|
|
|
10456
10528
|
// src/recording/state-machine.ts
|
|
10457
10529
|
var VALID_TRANSITIONS = /* @__PURE__ */ new Map([
|
|
@@ -10513,7 +10585,7 @@ function stripMarkdownFence(markdown) {
|
|
|
10513
10585
|
}
|
|
10514
10586
|
function deriveTitleFromTranscriptPath(transcriptFile, recordingId) {
|
|
10515
10587
|
if (!transcriptFile) return void 0;
|
|
10516
|
-
const name = (0,
|
|
10588
|
+
const name = (0, import_node_path18.basename)(transcriptFile, ".md");
|
|
10517
10589
|
const prefix = `${recordingId}_`;
|
|
10518
10590
|
if (name.startsWith(prefix)) {
|
|
10519
10591
|
const derived = name.slice(prefix.length).trim();
|
|
@@ -10541,22 +10613,22 @@ function extractTranscriptContent(markdown) {
|
|
|
10541
10613
|
return lines.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
10542
10614
|
}
|
|
10543
10615
|
function resolveRecordingStorageDir(ctx, logger) {
|
|
10544
|
-
const stateRecDir = (0,
|
|
10616
|
+
const stateRecDir = (0, import_node_path18.join)(
|
|
10545
10617
|
ctx.stateDir,
|
|
10546
10618
|
"plugins",
|
|
10547
10619
|
"phone-notifications",
|
|
10548
10620
|
RECORDINGS_DIR
|
|
10549
10621
|
);
|
|
10550
10622
|
try {
|
|
10551
|
-
(0,
|
|
10623
|
+
(0, import_node_fs22.mkdirSync)(stateRecDir, { recursive: true });
|
|
10552
10624
|
logger.info(`\u5F55\u97F3\u5C06\u5199\u5165 stateDir \u8DEF\u5F84: ${stateRecDir}`);
|
|
10553
10625
|
return stateRecDir;
|
|
10554
10626
|
} catch {
|
|
10555
10627
|
}
|
|
10556
10628
|
if (ctx.workspaceDir) {
|
|
10557
|
-
const wsRecDir = (0,
|
|
10629
|
+
const wsRecDir = (0, import_node_path18.join)(ctx.workspaceDir, RECORDINGS_DIR);
|
|
10558
10630
|
try {
|
|
10559
|
-
(0,
|
|
10631
|
+
(0, import_node_fs22.mkdirSync)(wsRecDir, { recursive: true });
|
|
10560
10632
|
logger.warn(`stateDir \u4E0D\u53EF\u7528\uFF0C\u5F55\u97F3\u5DF2\u56DE\u9000\u5230 workspace \u8DEF\u5F84: ${wsRecDir}`);
|
|
10561
10633
|
return wsRecDir;
|
|
10562
10634
|
} catch {
|
|
@@ -10568,11 +10640,11 @@ var RecordingStorage = class {
|
|
|
10568
10640
|
constructor(dir, logger) {
|
|
10569
10641
|
this.logger = logger;
|
|
10570
10642
|
this.dir = dir;
|
|
10571
|
-
this.audioDir = (0,
|
|
10572
|
-
this.transcriptDataDir = (0,
|
|
10573
|
-
this.transcriptsDir = (0,
|
|
10574
|
-
this.summariesDir = (0,
|
|
10575
|
-
this.indexPath = (0,
|
|
10643
|
+
this.audioDir = (0, import_node_path18.join)(dir, AUDIO_DIR);
|
|
10644
|
+
this.transcriptDataDir = (0, import_node_path18.join)(dir, TRANSCRIPT_DATA_DIR);
|
|
10645
|
+
this.transcriptsDir = (0, import_node_path18.join)(dir, TRANSCRIPTS_DIR);
|
|
10646
|
+
this.summariesDir = (0, import_node_path18.join)(dir, SUMMARIES_DIR);
|
|
10647
|
+
this.indexPath = (0, import_node_path18.join)(dir, INDEX_FILE);
|
|
10576
10648
|
}
|
|
10577
10649
|
dir;
|
|
10578
10650
|
audioDir;
|
|
@@ -10583,10 +10655,10 @@ var RecordingStorage = class {
|
|
|
10583
10655
|
index = { recordings: [] };
|
|
10584
10656
|
/** 初始化目录结构并加载索引 */
|
|
10585
10657
|
async init() {
|
|
10586
|
-
(0,
|
|
10587
|
-
(0,
|
|
10588
|
-
(0,
|
|
10589
|
-
(0,
|
|
10658
|
+
(0, import_node_fs22.mkdirSync)(this.audioDir, { recursive: true });
|
|
10659
|
+
(0, import_node_fs22.mkdirSync)(this.transcriptDataDir, { recursive: true });
|
|
10660
|
+
(0, import_node_fs22.mkdirSync)(this.transcriptsDir, { recursive: true });
|
|
10661
|
+
(0, import_node_fs22.mkdirSync)(this.summariesDir, { recursive: true });
|
|
10590
10662
|
this.loadIndex();
|
|
10591
10663
|
this.logger.info(
|
|
10592
10664
|
`\u5F55\u97F3\u5B58\u50A8\u5DF2\u521D\u59CB\u5316: ${this.dir}\uFF08\u5171 ${this.index.recordings.length} \u6761\u8BB0\u5F55\uFF09`
|
|
@@ -10630,13 +10702,13 @@ var RecordingStorage = class {
|
|
|
10630
10702
|
return id;
|
|
10631
10703
|
}
|
|
10632
10704
|
if (existing.transcriptDataFile) {
|
|
10633
|
-
(0,
|
|
10705
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, existing.transcriptDataFile), { force: true });
|
|
10634
10706
|
}
|
|
10635
10707
|
if (existing.transcriptFile) {
|
|
10636
|
-
(0,
|
|
10708
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, existing.transcriptFile), { force: true });
|
|
10637
10709
|
}
|
|
10638
10710
|
if (existing.summaryFile) {
|
|
10639
|
-
(0,
|
|
10711
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, existing.summaryFile), { force: true });
|
|
10640
10712
|
}
|
|
10641
10713
|
existing.metadata = metadata;
|
|
10642
10714
|
existing.status = "syncing_openclaw";
|
|
@@ -10705,7 +10777,7 @@ var RecordingStorage = class {
|
|
|
10705
10777
|
if (!entry) return;
|
|
10706
10778
|
const nextTranscriptDataFile = `${TRANSCRIPT_DATA_DIR}/${filename}`;
|
|
10707
10779
|
if (entry.transcriptDataFile && entry.transcriptDataFile !== nextTranscriptDataFile) {
|
|
10708
|
-
(0,
|
|
10780
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, entry.transcriptDataFile), { force: true });
|
|
10709
10781
|
}
|
|
10710
10782
|
entry.transcriptDataFile = nextTranscriptDataFile;
|
|
10711
10783
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -10719,7 +10791,7 @@ var RecordingStorage = class {
|
|
|
10719
10791
|
if (!entry) return;
|
|
10720
10792
|
const nextTranscriptFile = `${TRANSCRIPTS_DIR}/${filename}`;
|
|
10721
10793
|
if (entry.transcriptFile && entry.transcriptFile !== nextTranscriptFile) {
|
|
10722
|
-
(0,
|
|
10794
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, entry.transcriptFile), { force: true });
|
|
10723
10795
|
}
|
|
10724
10796
|
entry.transcriptFile = nextTranscriptFile;
|
|
10725
10797
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -10733,7 +10805,7 @@ var RecordingStorage = class {
|
|
|
10733
10805
|
if (!entry) return;
|
|
10734
10806
|
const nextSummaryFile = `${SUMMARIES_DIR}/${filename}`;
|
|
10735
10807
|
if (entry.summaryFile && entry.summaryFile !== nextSummaryFile) {
|
|
10736
|
-
(0,
|
|
10808
|
+
(0, import_node_fs22.rmSync)((0, import_node_path18.join)(this.dir, entry.summaryFile), { force: true });
|
|
10737
10809
|
}
|
|
10738
10810
|
entry.summaryFile = nextSummaryFile;
|
|
10739
10811
|
entry.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -10841,24 +10913,24 @@ var RecordingStorage = class {
|
|
|
10841
10913
|
const entry = this.findById(recordingId);
|
|
10842
10914
|
if (!entry) return false;
|
|
10843
10915
|
if (entry.audioFile) {
|
|
10844
|
-
const audioPath = (0,
|
|
10845
|
-
(0,
|
|
10916
|
+
const audioPath = (0, import_node_path18.join)(this.dir, entry.audioFile);
|
|
10917
|
+
(0, import_node_fs22.rmSync)(audioPath, { force: true });
|
|
10846
10918
|
}
|
|
10847
10919
|
if (entry.srtFile) {
|
|
10848
|
-
const srtPath = (0,
|
|
10849
|
-
(0,
|
|
10920
|
+
const srtPath = (0, import_node_path18.join)(this.dir, entry.srtFile);
|
|
10921
|
+
(0, import_node_fs22.rmSync)(srtPath, { force: true });
|
|
10850
10922
|
}
|
|
10851
10923
|
if (entry.transcriptDataFile) {
|
|
10852
|
-
const transcriptDataPath = (0,
|
|
10853
|
-
(0,
|
|
10924
|
+
const transcriptDataPath = (0, import_node_path18.join)(this.dir, entry.transcriptDataFile);
|
|
10925
|
+
(0, import_node_fs22.rmSync)(transcriptDataPath, { force: true });
|
|
10854
10926
|
}
|
|
10855
10927
|
if (entry.transcriptFile) {
|
|
10856
|
-
const transcriptPath = (0,
|
|
10857
|
-
(0,
|
|
10928
|
+
const transcriptPath = (0, import_node_path18.join)(this.dir, entry.transcriptFile);
|
|
10929
|
+
(0, import_node_fs22.rmSync)(transcriptPath, { force: true });
|
|
10858
10930
|
}
|
|
10859
10931
|
if (entry.summaryFile) {
|
|
10860
|
-
const summaryPath = (0,
|
|
10861
|
-
(0,
|
|
10932
|
+
const summaryPath = (0, import_node_path18.join)(this.dir, entry.summaryFile);
|
|
10933
|
+
(0, import_node_fs22.rmSync)(summaryPath, { force: true });
|
|
10862
10934
|
}
|
|
10863
10935
|
if (opts?.localOnly) {
|
|
10864
10936
|
entry.audioFile = void 0;
|
|
@@ -10916,34 +10988,34 @@ var RecordingStorage = class {
|
|
|
10916
10988
|
* 获取音频文件的绝对路径。ossUrl 用于推断文件扩展名
|
|
10917
10989
|
*/
|
|
10918
10990
|
getAudioFilePath(recordingId, ossUrl) {
|
|
10919
|
-
return (0,
|
|
10991
|
+
return (0, import_node_path18.join)(this.audioDir, this.buildAudioFilename(recordingId, ossUrl));
|
|
10920
10992
|
}
|
|
10921
10993
|
/**
|
|
10922
10994
|
* 获取打点文件的绝对路径
|
|
10923
10995
|
*/
|
|
10924
10996
|
getSrtFilePath(recordingId) {
|
|
10925
|
-
return (0,
|
|
10997
|
+
return (0, import_node_path18.join)(this.audioDir, this.buildSrtFilename(recordingId));
|
|
10926
10998
|
}
|
|
10927
10999
|
/**
|
|
10928
11000
|
* 获取转写 JSON 文件的绝对路径
|
|
10929
11001
|
*/
|
|
10930
11002
|
getTranscriptDataFilePath(recordingId) {
|
|
10931
|
-
return (0,
|
|
11003
|
+
return (0, import_node_path18.join)(this.transcriptDataDir, this.buildTranscriptDataFilename(recordingId));
|
|
10932
11004
|
}
|
|
10933
11005
|
/**
|
|
10934
11006
|
* 获取摘要文件的绝对路径
|
|
10935
11007
|
*/
|
|
10936
11008
|
getSummaryFilePath(recordingId) {
|
|
10937
|
-
return (0,
|
|
11009
|
+
return (0, import_node_path18.join)(this.summariesDir, this.buildSummaryFilename(recordingId));
|
|
10938
11010
|
}
|
|
10939
11011
|
// ─── Persistence ───
|
|
10940
11012
|
loadIndex() {
|
|
10941
|
-
if (!(0,
|
|
11013
|
+
if (!(0, import_node_fs22.existsSync)(this.indexPath)) {
|
|
10942
11014
|
this.index = { recordings: [] };
|
|
10943
11015
|
return;
|
|
10944
11016
|
}
|
|
10945
11017
|
try {
|
|
10946
|
-
const raw = JSON.parse((0,
|
|
11018
|
+
const raw = JSON.parse((0, import_node_fs22.readFileSync)(this.indexPath, "utf-8"));
|
|
10947
11019
|
if (raw && Array.isArray(raw.recordings)) {
|
|
10948
11020
|
let needsRewrite = false;
|
|
10949
11021
|
const normalized = raw.recordings.filter((entry) => entry && typeof entry === "object").map((entry) => {
|
|
@@ -10981,8 +11053,8 @@ var RecordingStorage = class {
|
|
|
10981
11053
|
segments: []
|
|
10982
11054
|
});
|
|
10983
11055
|
const transcriptDataFilename = this.buildTranscriptDataFilename(compacted.id);
|
|
10984
|
-
(0,
|
|
10985
|
-
(0,
|
|
11056
|
+
(0, import_node_fs22.writeFileSync)(
|
|
11057
|
+
(0, import_node_path18.join)(this.transcriptDataDir, transcriptDataFilename),
|
|
10986
11058
|
JSON.stringify(transcriptDoc, null, 2),
|
|
10987
11059
|
"utf-8"
|
|
10988
11060
|
);
|
|
@@ -10994,8 +11066,8 @@ var RecordingStorage = class {
|
|
|
10994
11066
|
compacted.summaryFile = entry.summaryFile;
|
|
10995
11067
|
} else if (typeof entry.summary === "string" && entry.summary.trim()) {
|
|
10996
11068
|
const summaryFilename = this.buildSummaryFilename(entry.id);
|
|
10997
|
-
(0,
|
|
10998
|
-
(0,
|
|
11069
|
+
(0, import_node_fs22.writeFileSync)(
|
|
11070
|
+
(0, import_node_path18.join)(this.summariesDir, summaryFilename),
|
|
10999
11071
|
entry.summary.trim(),
|
|
11000
11072
|
"utf-8"
|
|
11001
11073
|
);
|
|
@@ -11005,8 +11077,8 @@ var RecordingStorage = class {
|
|
|
11005
11077
|
const summaryFromDocument = extractTranscriptSummaryFromDocument(transcriptDoc);
|
|
11006
11078
|
if (summaryFromDocument) {
|
|
11007
11079
|
const summaryFilename = this.buildSummaryFilename(entry.id);
|
|
11008
|
-
(0,
|
|
11009
|
-
(0,
|
|
11080
|
+
(0, import_node_fs22.writeFileSync)(
|
|
11081
|
+
(0, import_node_path18.join)(this.summariesDir, summaryFilename),
|
|
11010
11082
|
summaryFromDocument,
|
|
11011
11083
|
"utf-8"
|
|
11012
11084
|
);
|
|
@@ -11049,7 +11121,7 @@ var RecordingStorage = class {
|
|
|
11049
11121
|
}
|
|
11050
11122
|
readRelativeTextFile(relativePath) {
|
|
11051
11123
|
try {
|
|
11052
|
-
return (0,
|
|
11124
|
+
return (0, import_node_fs22.readFileSync)((0, import_node_path18.join)(this.dir, relativePath), "utf-8");
|
|
11053
11125
|
} catch {
|
|
11054
11126
|
return void 0;
|
|
11055
11127
|
}
|
|
@@ -11062,7 +11134,7 @@ var RecordingStorage = class {
|
|
|
11062
11134
|
return parseTranscriptDocument(raw);
|
|
11063
11135
|
}
|
|
11064
11136
|
saveIndex() {
|
|
11065
|
-
(0,
|
|
11137
|
+
(0, import_node_fs22.writeFileSync)(
|
|
11066
11138
|
this.indexPath,
|
|
11067
11139
|
JSON.stringify(this.index, null, 2),
|
|
11068
11140
|
"utf-8"
|
|
@@ -11076,8 +11148,8 @@ var RecordingStorage = class {
|
|
|
11076
11148
|
init_transcript_document();
|
|
11077
11149
|
|
|
11078
11150
|
// src/recording/downloader.ts
|
|
11079
|
-
var
|
|
11080
|
-
var
|
|
11151
|
+
var import_node_fs23 = require("fs");
|
|
11152
|
+
var import_node_path19 = require("path");
|
|
11081
11153
|
var import_promises2 = require("stream/promises");
|
|
11082
11154
|
var import_node_stream = require("stream");
|
|
11083
11155
|
var DEFAULT_TIMEOUT_MS2 = 5 * 60 * 1e3;
|
|
@@ -11087,7 +11159,7 @@ async function downloadFile(url, destPath, logger, options) {
|
|
|
11087
11159
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
11088
11160
|
const maxRetries = options?.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
11089
11161
|
const retryBackoffMs = options?.retryBackoffMs ?? DEFAULT_RETRY_BACKOFF_MS;
|
|
11090
|
-
(0,
|
|
11162
|
+
(0, import_node_fs23.mkdirSync)((0, import_node_path19.dirname)(destPath), { recursive: true });
|
|
11091
11163
|
let lastError;
|
|
11092
11164
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
11093
11165
|
const startMs = Date.now();
|
|
@@ -11105,11 +11177,11 @@ async function downloadFile(url, destPath, logger, options) {
|
|
|
11105
11177
|
if (!res.body) {
|
|
11106
11178
|
throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
|
|
11107
11179
|
}
|
|
11108
|
-
const writeStream = (0,
|
|
11180
|
+
const writeStream = (0, import_node_fs23.createWriteStream)(destPath);
|
|
11109
11181
|
const readable = import_node_stream.Readable.fromWeb(res.body);
|
|
11110
11182
|
await (0, import_promises2.pipeline)(readable, writeStream);
|
|
11111
11183
|
const elapsed = Date.now() - startMs;
|
|
11112
|
-
const fileSize = (0,
|
|
11184
|
+
const fileSize = (0, import_node_fs23.existsSync)(destPath) ? (0, import_node_fs23.statSync)(destPath).size : 0;
|
|
11113
11185
|
logger.info(
|
|
11114
11186
|
`[downloader] \u4E0B\u8F7D\u5B8C\u6210: ${destPath} (${formatBytes(fileSize)}, ${elapsed}ms)`
|
|
11115
11187
|
);
|
|
@@ -11120,7 +11192,7 @@ async function downloadFile(url, destPath, logger, options) {
|
|
|
11120
11192
|
} catch (err2) {
|
|
11121
11193
|
lastError = err2?.message ?? String(err2);
|
|
11122
11194
|
try {
|
|
11123
|
-
if ((0,
|
|
11195
|
+
if ((0, import_node_fs23.existsSync)(destPath)) (0, import_node_fs23.unlinkSync)(destPath);
|
|
11124
11196
|
} catch {
|
|
11125
11197
|
}
|
|
11126
11198
|
const isAbort = err2?.name === "AbortError";
|
|
@@ -11436,13 +11508,13 @@ async function triggerTranscription(recordingId, storage, asrConfig, logger, opt
|
|
|
11436
11508
|
}
|
|
11437
11509
|
|
|
11438
11510
|
// src/tunnel/service.ts
|
|
11439
|
-
var
|
|
11440
|
-
var
|
|
11511
|
+
var import_node_fs28 = require("fs");
|
|
11512
|
+
var import_node_path24 = require("path");
|
|
11441
11513
|
init_credentials();
|
|
11442
11514
|
|
|
11443
11515
|
// src/tunnel/relay-client.ts
|
|
11444
|
-
var
|
|
11445
|
-
var
|
|
11516
|
+
var import_node_fs26 = require("fs");
|
|
11517
|
+
var import_node_path22 = require("path");
|
|
11446
11518
|
|
|
11447
11519
|
// node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
|
|
11448
11520
|
var import_stream = __toESM(require_stream(), 1);
|
|
@@ -11486,8 +11558,8 @@ var RelayClient = class {
|
|
|
11486
11558
|
lastDisconnectReason
|
|
11487
11559
|
};
|
|
11488
11560
|
try {
|
|
11489
|
-
(0,
|
|
11490
|
-
(0,
|
|
11561
|
+
(0, import_node_fs26.mkdirSync)((0, import_node_path22.dirname)(this.opts.statusFilePath), { recursive: true });
|
|
11562
|
+
(0, import_node_fs26.writeFileSync)(this.opts.statusFilePath, JSON.stringify(info, null, 2));
|
|
11491
11563
|
} catch {
|
|
11492
11564
|
}
|
|
11493
11565
|
}
|
|
@@ -11869,8 +11941,8 @@ init_host();
|
|
|
11869
11941
|
|
|
11870
11942
|
// src/tunnel/device-identity.ts
|
|
11871
11943
|
var import_node_crypto3 = __toESM(require("crypto"), 1);
|
|
11872
|
-
var
|
|
11873
|
-
var
|
|
11944
|
+
var import_node_fs27 = __toESM(require("fs"), 1);
|
|
11945
|
+
var import_node_path23 = __toESM(require("path"), 1);
|
|
11874
11946
|
init_host();
|
|
11875
11947
|
var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
|
|
11876
11948
|
function base64UrlEncode(buf) {
|
|
@@ -11915,10 +11987,10 @@ function resolveClientStateDir(stateDir) {
|
|
|
11915
11987
|
return stateDir ?? resolveStateDir();
|
|
11916
11988
|
}
|
|
11917
11989
|
function ensureDir(filePath) {
|
|
11918
|
-
|
|
11990
|
+
import_node_fs27.default.mkdirSync(import_node_path23.default.dirname(filePath), { recursive: true });
|
|
11919
11991
|
}
|
|
11920
11992
|
function resolveIdentityPath(stateDir) {
|
|
11921
|
-
return
|
|
11993
|
+
return import_node_path23.default.join(stateDir, "identity", "device.json");
|
|
11922
11994
|
}
|
|
11923
11995
|
function normalizeDeviceAuthRole(role) {
|
|
11924
11996
|
return role.trim();
|
|
@@ -11934,12 +12006,12 @@ function normalizeDeviceAuthScopes(scopes) {
|
|
|
11934
12006
|
return [...out].sort();
|
|
11935
12007
|
}
|
|
11936
12008
|
function resolveDeviceAuthPath(stateDir) {
|
|
11937
|
-
return
|
|
12009
|
+
return import_node_path23.default.join(stateDir, "identity", "device-auth.json");
|
|
11938
12010
|
}
|
|
11939
12011
|
function readDeviceAuthStore(filePath) {
|
|
11940
12012
|
try {
|
|
11941
|
-
if (!
|
|
11942
|
-
const raw =
|
|
12013
|
+
if (!import_node_fs27.default.existsSync(filePath)) return null;
|
|
12014
|
+
const raw = import_node_fs27.default.readFileSync(filePath, "utf8");
|
|
11943
12015
|
const parsed = JSON.parse(raw);
|
|
11944
12016
|
if (parsed?.version !== 1 || typeof parsed.deviceId !== "string") return null;
|
|
11945
12017
|
if (!parsed.tokens || typeof parsed.tokens !== "object") return null;
|
|
@@ -11950,12 +12022,12 @@ function readDeviceAuthStore(filePath) {
|
|
|
11950
12022
|
}
|
|
11951
12023
|
function writeDeviceAuthStore(filePath, store) {
|
|
11952
12024
|
ensureDir(filePath);
|
|
11953
|
-
|
|
12025
|
+
import_node_fs27.default.writeFileSync(filePath, `${JSON.stringify(store, null, 2)}
|
|
11954
12026
|
`, {
|
|
11955
12027
|
mode: 384
|
|
11956
12028
|
});
|
|
11957
12029
|
try {
|
|
11958
|
-
|
|
12030
|
+
import_node_fs27.default.chmodSync(filePath, 384);
|
|
11959
12031
|
} catch {
|
|
11960
12032
|
}
|
|
11961
12033
|
}
|
|
@@ -12002,8 +12074,8 @@ function clearDeviceAuthToken(params) {
|
|
|
12002
12074
|
function loadOrCreateDeviceIdentity(stateDir) {
|
|
12003
12075
|
const filePath = resolveIdentityPath(stateDir);
|
|
12004
12076
|
try {
|
|
12005
|
-
if (
|
|
12006
|
-
const raw =
|
|
12077
|
+
if (import_node_fs27.default.existsSync(filePath)) {
|
|
12078
|
+
const raw = import_node_fs27.default.readFileSync(filePath, "utf8");
|
|
12007
12079
|
const parsed = JSON.parse(raw);
|
|
12008
12080
|
if (parsed?.version === 1 && typeof parsed.deviceId === "string" && typeof parsed.publicKeyPem === "string" && typeof parsed.privateKeyPem === "string") {
|
|
12009
12081
|
const derivedId = fingerprintPublicKey(parsed.publicKeyPem);
|
|
@@ -12024,14 +12096,14 @@ function loadOrCreateDeviceIdentity(stateDir) {
|
|
|
12024
12096
|
publicKeyPem,
|
|
12025
12097
|
privateKeyPem
|
|
12026
12098
|
};
|
|
12027
|
-
|
|
12099
|
+
import_node_fs27.default.mkdirSync(import_node_path23.default.dirname(filePath), { recursive: true });
|
|
12028
12100
|
const stored = {
|
|
12029
12101
|
version: 1,
|
|
12030
12102
|
...identity,
|
|
12031
12103
|
createdAtMs: Date.now()
|
|
12032
12104
|
};
|
|
12033
12105
|
ensureDir(filePath);
|
|
12034
|
-
|
|
12106
|
+
import_node_fs27.default.writeFileSync(filePath, `${JSON.stringify(stored, null, 2)}
|
|
12035
12107
|
`, {
|
|
12036
12108
|
mode: 384
|
|
12037
12109
|
});
|
|
@@ -12915,7 +12987,7 @@ function createTunnelService(opts) {
|
|
|
12915
12987
|
);
|
|
12916
12988
|
client.sendRaw(frame);
|
|
12917
12989
|
}
|
|
12918
|
-
function
|
|
12990
|
+
function isProcessAlive2(pid) {
|
|
12919
12991
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
12920
12992
|
if (pid === process.pid) return true;
|
|
12921
12993
|
try {
|
|
@@ -12927,7 +12999,7 @@ function createTunnelService(opts) {
|
|
|
12927
12999
|
}
|
|
12928
13000
|
function readLockOwner(filePath) {
|
|
12929
13001
|
try {
|
|
12930
|
-
const parsed = JSON.parse((0,
|
|
13002
|
+
const parsed = JSON.parse((0, import_node_fs28.readFileSync)(filePath, "utf-8"));
|
|
12931
13003
|
return typeof parsed.pid === "number" ? parsed.pid : null;
|
|
12932
13004
|
} catch {
|
|
12933
13005
|
return null;
|
|
@@ -12940,23 +13012,23 @@ function createTunnelService(opts) {
|
|
|
12940
13012
|
lockFd = null;
|
|
12941
13013
|
if (fd !== null) {
|
|
12942
13014
|
try {
|
|
12943
|
-
(0,
|
|
13015
|
+
(0, import_node_fs28.closeSync)(fd);
|
|
12944
13016
|
} catch {
|
|
12945
13017
|
}
|
|
12946
13018
|
}
|
|
12947
13019
|
if (filePath) {
|
|
12948
13020
|
try {
|
|
12949
|
-
(0,
|
|
13021
|
+
(0, import_node_fs28.unlinkSync)(filePath);
|
|
12950
13022
|
} catch {
|
|
12951
13023
|
}
|
|
12952
13024
|
}
|
|
12953
13025
|
}
|
|
12954
13026
|
function acquireLock(filePath) {
|
|
12955
|
-
(0,
|
|
13027
|
+
(0, import_node_fs28.mkdirSync)((0, import_node_path24.dirname)(filePath), { recursive: true });
|
|
12956
13028
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
12957
13029
|
try {
|
|
12958
|
-
const fd = (0,
|
|
12959
|
-
(0,
|
|
13030
|
+
const fd = (0, import_node_fs28.openSync)(filePath, "wx", 384);
|
|
13031
|
+
(0, import_node_fs28.writeFileSync)(
|
|
12960
13032
|
fd,
|
|
12961
13033
|
JSON.stringify({
|
|
12962
13034
|
pid: process.pid,
|
|
@@ -12975,12 +13047,12 @@ function createTunnelService(opts) {
|
|
|
12975
13047
|
return false;
|
|
12976
13048
|
}
|
|
12977
13049
|
const ownerPid = readLockOwner(filePath);
|
|
12978
|
-
if (ownerPid && !
|
|
13050
|
+
if (ownerPid && !isProcessAlive2(ownerPid)) {
|
|
12979
13051
|
opts.logger.warn(
|
|
12980
13052
|
`Relay tunnel: removing stale local lock owned by dead pid=${ownerPid}`
|
|
12981
13053
|
);
|
|
12982
13054
|
try {
|
|
12983
|
-
(0,
|
|
13055
|
+
(0, import_node_fs28.unlinkSync)(filePath);
|
|
12984
13056
|
} catch {
|
|
12985
13057
|
}
|
|
12986
13058
|
continue;
|
|
@@ -13025,12 +13097,12 @@ function createTunnelService(opts) {
|
|
|
13025
13097
|
return;
|
|
13026
13098
|
}
|
|
13027
13099
|
const { logger } = opts;
|
|
13028
|
-
const baseStateDir = (0,
|
|
13100
|
+
const baseStateDir = (0, import_node_path24.join)(ctx.stateDir, "plugins", "phone-notifications");
|
|
13029
13101
|
logger.info(
|
|
13030
13102
|
`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})`
|
|
13031
13103
|
);
|
|
13032
|
-
const statusFilePath = (0,
|
|
13033
|
-
const lockPath = (0,
|
|
13104
|
+
const statusFilePath = (0, import_node_path24.join)(baseStateDir, "tunnel-status.json");
|
|
13105
|
+
const lockPath = (0, import_node_path24.join)(baseStateDir, "relay-tunnel.lock");
|
|
13034
13106
|
if (!acquireLock(lockPath)) {
|
|
13035
13107
|
return;
|
|
13036
13108
|
}
|
|
@@ -13095,25 +13167,6 @@ function createTunnelService(opts) {
|
|
|
13095
13167
|
|
|
13096
13168
|
// src/plugin/lifecycle.ts
|
|
13097
13169
|
init_env();
|
|
13098
|
-
|
|
13099
|
-
// src/plugin/shared.ts
|
|
13100
|
-
function readBody(req) {
|
|
13101
|
-
return new Promise((resolve, reject) => {
|
|
13102
|
-
const chunks = [];
|
|
13103
|
-
req.on("data", (chunk) => chunks.push(chunk));
|
|
13104
|
-
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
13105
|
-
req.on("error", reject);
|
|
13106
|
-
});
|
|
13107
|
-
}
|
|
13108
|
-
function trimToUndefined2(value) {
|
|
13109
|
-
if (typeof value !== "string") {
|
|
13110
|
-
return void 0;
|
|
13111
|
-
}
|
|
13112
|
-
const trimmed = value.trim();
|
|
13113
|
-
return trimmed || void 0;
|
|
13114
|
-
}
|
|
13115
|
-
|
|
13116
|
-
// src/plugin/lifecycle.ts
|
|
13117
13170
|
function registerStorageLifecycle(deps) {
|
|
13118
13171
|
const {
|
|
13119
13172
|
api,
|
|
@@ -13170,7 +13223,7 @@ function readHostGatewayConfig(params) {
|
|
|
13170
13223
|
let configData;
|
|
13171
13224
|
if (configPath) {
|
|
13172
13225
|
try {
|
|
13173
|
-
configData = JSON.parse((0,
|
|
13226
|
+
configData = JSON.parse((0, import_node_fs29.readFileSync)(configPath, "utf-8"));
|
|
13174
13227
|
} catch (err2) {
|
|
13175
13228
|
if (err2?.code !== "ENOENT") {
|
|
13176
13229
|
params.logger.warn(
|
|
@@ -13847,7 +13900,7 @@ var index_default = {
|
|
|
13847
13900
|
let broadcastFn = null;
|
|
13848
13901
|
let autoUpdateLifecycle = null;
|
|
13849
13902
|
let tunnelService = null;
|
|
13850
|
-
const openclawDir = api
|
|
13903
|
+
const openclawDir = resolvePluginStateDir(api);
|
|
13851
13904
|
const logger = openclawDir ? new PluginFileLogger(api.logger, openclawDir) : createVersionAwareLogger(api.logger);
|
|
13852
13905
|
const lightRuleCtx = {
|
|
13853
13906
|
stateDir: openclawDir
|