@yoooclaw/phone-notifications 1.10.4 → 1.10.6-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
CHANGED
|
@@ -610,9 +610,9 @@ async function probeUrl(url, logger) {
|
|
|
610
610
|
} finally {
|
|
611
611
|
clearTimeout(timer);
|
|
612
612
|
}
|
|
613
|
-
} catch (
|
|
613
|
+
} catch (err2) {
|
|
614
614
|
logger.info(
|
|
615
|
-
`[whisper-local] \u8FDE\u901A\u6027\u63A2\u6D4B\u5931\u8D25: ${url} (${
|
|
615
|
+
`[whisper-local] \u8FDE\u901A\u6027\u63A2\u6D4B\u5931\u8D25: ${url} (${err2?.name ?? err2?.message ?? "unknown"})`
|
|
616
616
|
);
|
|
617
617
|
return false;
|
|
618
618
|
}
|
|
@@ -663,12 +663,12 @@ async function downloadFromUrl(url, modelPath, logger) {
|
|
|
663
663
|
`[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5B8C\u6210: ${(0, import_node_path22.basename)(modelPath)} (${formatBytes2(fileSize)})`
|
|
664
664
|
);
|
|
665
665
|
return { ok: true, modelPath };
|
|
666
|
-
} catch (
|
|
666
|
+
} catch (err2) {
|
|
667
667
|
try {
|
|
668
668
|
if ((0, import_node_fs26.existsSync)(tmpPath)) (0, import_node_fs26.unlinkSync)(tmpPath);
|
|
669
669
|
} catch {
|
|
670
670
|
}
|
|
671
|
-
const msg =
|
|
671
|
+
const msg = err2?.name === "AbortError" ? "\u6A21\u578B\u4E0B\u8F7D\u8D85\u65F6\uFF0830 \u5206\u949F\uFF09" : err2?.message ?? String(err2);
|
|
672
672
|
logger.error(`[whisper-local] \u6A21\u578B\u4E0B\u8F7D\u5931\u8D25: ${msg}`);
|
|
673
673
|
return { ok: false, modelPath, error: msg };
|
|
674
674
|
}
|
|
@@ -765,9 +765,9 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
|
|
|
765
765
|
// 100MB stdout buffer
|
|
766
766
|
stdio: ["pipe", "pipe", "pipe"]
|
|
767
767
|
});
|
|
768
|
-
} catch (
|
|
768
|
+
} catch (err2) {
|
|
769
769
|
cleanupTmpWav(tmpWavPath);
|
|
770
|
-
return { ok: false, error: `whisper.cpp \u6267\u884C\u5931\u8D25: ${
|
|
770
|
+
return { ok: false, error: `whisper.cpp \u6267\u884C\u5931\u8D25: ${err2?.message ?? err2}` };
|
|
771
771
|
}
|
|
772
772
|
if (result.status !== 0) {
|
|
773
773
|
cleanupTmpWav(tmpWavPath);
|
|
@@ -792,9 +792,9 @@ async function transcribeWithWhisperLocal(audioFilePath, localConfig, dataDir, l
|
|
|
792
792
|
}
|
|
793
793
|
cleanupTmpWav(tmpWavPath);
|
|
794
794
|
return parseWhisperOutput(jsonContent, logger);
|
|
795
|
-
} catch (
|
|
795
|
+
} catch (err2) {
|
|
796
796
|
cleanupTmpWav(tmpWavPath);
|
|
797
|
-
return { ok: false, error: `whisper.cpp \u8F6C\u5199\u5F02\u5E38: ${
|
|
797
|
+
return { ok: false, error: `whisper.cpp \u8F6C\u5199\u5F02\u5E38: ${err2?.message ?? err2}` };
|
|
798
798
|
}
|
|
799
799
|
}
|
|
800
800
|
function getWhisperLocalStatus(dataDir, logger) {
|
|
@@ -963,14 +963,14 @@ function convertToWav(inputPath, outputPath, actualFmt, logger) {
|
|
|
963
963
|
}
|
|
964
964
|
const stderr = afResult.stderr?.slice(0, 200) ?? "";
|
|
965
965
|
return { ok: false, error: `afconvert \u8F6C\u6362\u5931\u8D25 (exit ${afResult.status}): ${stderr}` };
|
|
966
|
-
} catch (
|
|
966
|
+
} catch (err2) {
|
|
967
967
|
if (tmpCopy && (0, import_node_fs26.existsSync)(tmpCopy)) {
|
|
968
968
|
try {
|
|
969
969
|
(0, import_node_fs26.unlinkSync)(tmpCopy);
|
|
970
970
|
} catch {
|
|
971
971
|
}
|
|
972
972
|
}
|
|
973
|
-
return { ok: false, error: `afconvert \u4E0D\u53EF\u7528: ${
|
|
973
|
+
return { ok: false, error: `afconvert \u4E0D\u53EF\u7528: ${err2?.message}` };
|
|
974
974
|
}
|
|
975
975
|
}
|
|
976
976
|
const fmtHint = actualFmt === ".ogg" ? "OGG/Opus \u683C\u5F0F\u9700\u8981 ffmpeg \u6216 opus-tools\uFF08brew install opus-tools\uFF09" : "\u8BF7\u5B89\u88C5 ffmpeg\uFF08brew install ffmpeg\uFF09\u6216\u786E\u4FDD\u97F3\u9891\u6587\u4EF6\u4E3A WAV \u683C\u5F0F";
|
|
@@ -1043,8 +1043,8 @@ function parseWhisperOutput(stdout, logger) {
|
|
|
1043
1043
|
text: fullText,
|
|
1044
1044
|
segments
|
|
1045
1045
|
};
|
|
1046
|
-
} catch (
|
|
1047
|
-
logger.warn(`[whisper-local] JSON \u89E3\u6790\u5931\u8D25\uFF0C\u5C1D\u8BD5\u7EAF\u6587\u672C: ${
|
|
1046
|
+
} catch (err2) {
|
|
1047
|
+
logger.warn(`[whisper-local] JSON \u89E3\u6790\u5931\u8D25\uFF0C\u5C1D\u8BD5\u7EAF\u6587\u672C: ${err2?.message}`);
|
|
1048
1048
|
return {
|
|
1049
1049
|
ok: true,
|
|
1050
1050
|
text: stdout.trim(),
|
|
@@ -1250,8 +1250,8 @@ async function transcribeAudio(audioFilePath, config, logger, options = {}) {
|
|
|
1250
1250
|
error: `\u672A\u77E5\u7684 ASR mode: ${config.mode}`
|
|
1251
1251
|
};
|
|
1252
1252
|
}
|
|
1253
|
-
} catch (
|
|
1254
|
-
const msg =
|
|
1253
|
+
} catch (err2) {
|
|
1254
|
+
const msg = err2?.message ?? String(err2);
|
|
1255
1255
|
logger.error(`[asr] \u8F6C\u5199\u5F02\u5E38: ${msg}`);
|
|
1256
1256
|
return { ok: false, error: msg };
|
|
1257
1257
|
}
|
|
@@ -2175,9 +2175,9 @@ var require_permessage_deflate = __commonJS({
|
|
|
2175
2175
|
*/
|
|
2176
2176
|
decompress(data, fin, callback) {
|
|
2177
2177
|
zlibLimiter.add((done) => {
|
|
2178
|
-
this._decompress(data, fin, (
|
|
2178
|
+
this._decompress(data, fin, (err2, result) => {
|
|
2179
2179
|
done();
|
|
2180
|
-
callback(
|
|
2180
|
+
callback(err2, result);
|
|
2181
2181
|
});
|
|
2182
2182
|
});
|
|
2183
2183
|
}
|
|
@@ -2191,9 +2191,9 @@ var require_permessage_deflate = __commonJS({
|
|
|
2191
2191
|
*/
|
|
2192
2192
|
compress(data, fin, callback) {
|
|
2193
2193
|
zlibLimiter.add((done) => {
|
|
2194
|
-
this._compress(data, fin, (
|
|
2194
|
+
this._compress(data, fin, (err2, result) => {
|
|
2195
2195
|
done();
|
|
2196
|
-
callback(
|
|
2196
|
+
callback(err2, result);
|
|
2197
2197
|
});
|
|
2198
2198
|
});
|
|
2199
2199
|
}
|
|
@@ -2224,11 +2224,11 @@ var require_permessage_deflate = __commonJS({
|
|
|
2224
2224
|
this._inflate.write(data);
|
|
2225
2225
|
if (fin) this._inflate.write(TRAILER);
|
|
2226
2226
|
this._inflate.flush(() => {
|
|
2227
|
-
const
|
|
2228
|
-
if (
|
|
2227
|
+
const err2 = this._inflate[kError];
|
|
2228
|
+
if (err2) {
|
|
2229
2229
|
this._inflate.close();
|
|
2230
2230
|
this._inflate = null;
|
|
2231
|
-
callback(
|
|
2231
|
+
callback(err2);
|
|
2232
2232
|
return;
|
|
2233
2233
|
}
|
|
2234
2234
|
const data2 = bufferUtil.concat(
|
|
@@ -2309,14 +2309,14 @@ var require_permessage_deflate = __commonJS({
|
|
|
2309
2309
|
this.removeListener("data", inflateOnData);
|
|
2310
2310
|
this.reset();
|
|
2311
2311
|
}
|
|
2312
|
-
function inflateOnError(
|
|
2312
|
+
function inflateOnError(err2) {
|
|
2313
2313
|
this[kPerMessageDeflate]._inflate = null;
|
|
2314
2314
|
if (this[kError]) {
|
|
2315
2315
|
this[kCallback](this[kError]);
|
|
2316
2316
|
return;
|
|
2317
2317
|
}
|
|
2318
|
-
|
|
2319
|
-
this[kCallback](
|
|
2318
|
+
err2[kStatusCode] = 1007;
|
|
2319
|
+
this[kCallback](err2);
|
|
2320
2320
|
}
|
|
2321
2321
|
}
|
|
2322
2322
|
});
|
|
@@ -2939,8 +2939,8 @@ var require_receiver = __commonJS({
|
|
|
2939
2939
|
*/
|
|
2940
2940
|
decompress(data, cb) {
|
|
2941
2941
|
const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
|
|
2942
|
-
perMessageDeflate.decompress(data, this._fin, (
|
|
2943
|
-
if (
|
|
2942
|
+
perMessageDeflate.decompress(data, this._fin, (err2, buf) => {
|
|
2943
|
+
if (err2) return cb(err2);
|
|
2944
2944
|
if (buf.length) {
|
|
2945
2945
|
this._messageLength += buf.length;
|
|
2946
2946
|
if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
|
|
@@ -3101,13 +3101,13 @@ var require_receiver = __commonJS({
|
|
|
3101
3101
|
createError(ErrorCtor, message, prefix, statusCode, errorCode) {
|
|
3102
3102
|
this._loop = false;
|
|
3103
3103
|
this._errored = true;
|
|
3104
|
-
const
|
|
3104
|
+
const err2 = new ErrorCtor(
|
|
3105
3105
|
prefix ? `Invalid WebSocket frame: ${message}` : message
|
|
3106
3106
|
);
|
|
3107
|
-
Error.captureStackTrace(
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
return
|
|
3107
|
+
Error.captureStackTrace(err2, this.createError);
|
|
3108
|
+
err2.code = errorCode;
|
|
3109
|
+
err2[kStatusCode] = statusCode;
|
|
3110
|
+
return err2;
|
|
3111
3111
|
}
|
|
3112
3112
|
};
|
|
3113
3113
|
module2.exports = Receiver2;
|
|
@@ -3481,10 +3481,10 @@ var require_sender = __commonJS({
|
|
|
3481
3481
|
this._state = GET_BLOB_DATA;
|
|
3482
3482
|
blob.arrayBuffer().then((arrayBuffer) => {
|
|
3483
3483
|
if (this._socket.destroyed) {
|
|
3484
|
-
const
|
|
3484
|
+
const err2 = new Error(
|
|
3485
3485
|
"The socket was closed while the blob was being read"
|
|
3486
3486
|
);
|
|
3487
|
-
process.nextTick(callCallbacks, this,
|
|
3487
|
+
process.nextTick(callCallbacks, this, err2, cb);
|
|
3488
3488
|
return;
|
|
3489
3489
|
}
|
|
3490
3490
|
this._bufferedBytes -= options[kByteLength];
|
|
@@ -3496,8 +3496,8 @@ var require_sender = __commonJS({
|
|
|
3496
3496
|
} else {
|
|
3497
3497
|
this.dispatch(data, compress, options, cb);
|
|
3498
3498
|
}
|
|
3499
|
-
}).catch((
|
|
3500
|
-
process.nextTick(onError, this,
|
|
3499
|
+
}).catch((err2) => {
|
|
3500
|
+
process.nextTick(onError, this, err2, cb);
|
|
3501
3501
|
});
|
|
3502
3502
|
}
|
|
3503
3503
|
/**
|
|
@@ -3533,10 +3533,10 @@ var require_sender = __commonJS({
|
|
|
3533
3533
|
this._state = DEFLATING;
|
|
3534
3534
|
perMessageDeflate.compress(data, options.fin, (_, buf) => {
|
|
3535
3535
|
if (this._socket.destroyed) {
|
|
3536
|
-
const
|
|
3536
|
+
const err2 = new Error(
|
|
3537
3537
|
"The socket was closed while data was being compressed"
|
|
3538
3538
|
);
|
|
3539
|
-
callCallbacks(this,
|
|
3539
|
+
callCallbacks(this, err2, cb);
|
|
3540
3540
|
return;
|
|
3541
3541
|
}
|
|
3542
3542
|
this._bufferedBytes -= options[kByteLength];
|
|
@@ -3587,17 +3587,17 @@ var require_sender = __commonJS({
|
|
|
3587
3587
|
}
|
|
3588
3588
|
};
|
|
3589
3589
|
module2.exports = Sender2;
|
|
3590
|
-
function callCallbacks(sender,
|
|
3591
|
-
if (typeof cb === "function") cb(
|
|
3590
|
+
function callCallbacks(sender, err2, cb) {
|
|
3591
|
+
if (typeof cb === "function") cb(err2);
|
|
3592
3592
|
for (let i = 0; i < sender._queue.length; i++) {
|
|
3593
3593
|
const params = sender._queue[i];
|
|
3594
3594
|
const callback = params[params.length - 1];
|
|
3595
|
-
if (typeof callback === "function") callback(
|
|
3595
|
+
if (typeof callback === "function") callback(err2);
|
|
3596
3596
|
}
|
|
3597
3597
|
}
|
|
3598
|
-
function onError(sender,
|
|
3599
|
-
callCallbacks(sender,
|
|
3600
|
-
sender.onerror(
|
|
3598
|
+
function onError(sender, err2, cb) {
|
|
3599
|
+
callCallbacks(sender, err2, cb);
|
|
3600
|
+
sender.onerror(err2);
|
|
3601
3601
|
}
|
|
3602
3602
|
}
|
|
3603
3603
|
});
|
|
@@ -4245,8 +4245,8 @@ var require_websocket = __commonJS({
|
|
|
4245
4245
|
return;
|
|
4246
4246
|
}
|
|
4247
4247
|
this._readyState = _WebSocket.CLOSING;
|
|
4248
|
-
this._sender.close(code, data, !this._isServer, (
|
|
4249
|
-
if (
|
|
4248
|
+
this._sender.close(code, data, !this._isServer, (err2) => {
|
|
4249
|
+
if (err2) return;
|
|
4250
4250
|
this._closeFrameSent = true;
|
|
4251
4251
|
if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) {
|
|
4252
4252
|
this._socket.end();
|
|
@@ -4514,11 +4514,11 @@ var require_websocket = __commonJS({
|
|
|
4514
4514
|
invalidUrlMessage = "The URL contains a fragment identifier";
|
|
4515
4515
|
}
|
|
4516
4516
|
if (invalidUrlMessage) {
|
|
4517
|
-
const
|
|
4517
|
+
const err2 = new SyntaxError(invalidUrlMessage);
|
|
4518
4518
|
if (websocket._redirects === 0) {
|
|
4519
|
-
throw
|
|
4519
|
+
throw err2;
|
|
4520
4520
|
} else {
|
|
4521
|
-
emitErrorAndClose(websocket,
|
|
4521
|
+
emitErrorAndClose(websocket, err2);
|
|
4522
4522
|
return;
|
|
4523
4523
|
}
|
|
4524
4524
|
}
|
|
@@ -4613,10 +4613,10 @@ var require_websocket = __commonJS({
|
|
|
4613
4613
|
abortHandshake(websocket, req, "Opening handshake has timed out");
|
|
4614
4614
|
});
|
|
4615
4615
|
}
|
|
4616
|
-
req.on("error", (
|
|
4616
|
+
req.on("error", (err2) => {
|
|
4617
4617
|
if (req === null || req[kAborted]) return;
|
|
4618
4618
|
req = websocket._req = null;
|
|
4619
|
-
emitErrorAndClose(websocket,
|
|
4619
|
+
emitErrorAndClose(websocket, err2);
|
|
4620
4620
|
});
|
|
4621
4621
|
req.on("response", (res) => {
|
|
4622
4622
|
const location = res.headers.location;
|
|
@@ -4631,8 +4631,8 @@ var require_websocket = __commonJS({
|
|
|
4631
4631
|
try {
|
|
4632
4632
|
addr = new URL2(location, address);
|
|
4633
4633
|
} catch (e) {
|
|
4634
|
-
const
|
|
4635
|
-
emitErrorAndClose(websocket,
|
|
4634
|
+
const err2 = new SyntaxError(`Invalid URL: ${location}`);
|
|
4635
|
+
emitErrorAndClose(websocket, err2);
|
|
4636
4636
|
return;
|
|
4637
4637
|
}
|
|
4638
4638
|
initAsClient(websocket, addr, protocols, options);
|
|
@@ -4684,7 +4684,7 @@ var require_websocket = __commonJS({
|
|
|
4684
4684
|
let extensions;
|
|
4685
4685
|
try {
|
|
4686
4686
|
extensions = parse(secWebSocketExtensions);
|
|
4687
|
-
} catch (
|
|
4687
|
+
} catch (err2) {
|
|
4688
4688
|
const message = "Invalid Sec-WebSocket-Extensions header";
|
|
4689
4689
|
abortHandshake(websocket, socket, message);
|
|
4690
4690
|
return;
|
|
@@ -4697,7 +4697,7 @@ var require_websocket = __commonJS({
|
|
|
4697
4697
|
}
|
|
4698
4698
|
try {
|
|
4699
4699
|
perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
|
|
4700
|
-
} catch (
|
|
4700
|
+
} catch (err2) {
|
|
4701
4701
|
const message = "Invalid Sec-WebSocket-Extensions header";
|
|
4702
4702
|
abortHandshake(websocket, socket, message);
|
|
4703
4703
|
return;
|
|
@@ -4717,10 +4717,10 @@ var require_websocket = __commonJS({
|
|
|
4717
4717
|
req.end();
|
|
4718
4718
|
}
|
|
4719
4719
|
}
|
|
4720
|
-
function emitErrorAndClose(websocket,
|
|
4720
|
+
function emitErrorAndClose(websocket, err2) {
|
|
4721
4721
|
websocket._readyState = WebSocket2.CLOSING;
|
|
4722
4722
|
websocket._errorEmitted = true;
|
|
4723
|
-
websocket.emit("error",
|
|
4723
|
+
websocket.emit("error", err2);
|
|
4724
4724
|
websocket.emitClose();
|
|
4725
4725
|
}
|
|
4726
4726
|
function netConnect(options) {
|
|
@@ -4736,17 +4736,17 @@ var require_websocket = __commonJS({
|
|
|
4736
4736
|
}
|
|
4737
4737
|
function abortHandshake(websocket, stream, message) {
|
|
4738
4738
|
websocket._readyState = WebSocket2.CLOSING;
|
|
4739
|
-
const
|
|
4740
|
-
Error.captureStackTrace(
|
|
4739
|
+
const err2 = new Error(message);
|
|
4740
|
+
Error.captureStackTrace(err2, abortHandshake);
|
|
4741
4741
|
if (stream.setHeader) {
|
|
4742
4742
|
stream[kAborted] = true;
|
|
4743
4743
|
stream.abort();
|
|
4744
4744
|
if (stream.socket && !stream.socket.destroyed) {
|
|
4745
4745
|
stream.socket.destroy();
|
|
4746
4746
|
}
|
|
4747
|
-
process.nextTick(emitErrorAndClose, websocket,
|
|
4747
|
+
process.nextTick(emitErrorAndClose, websocket, err2);
|
|
4748
4748
|
} else {
|
|
4749
|
-
stream.destroy(
|
|
4749
|
+
stream.destroy(err2);
|
|
4750
4750
|
stream.once("error", websocket.emit.bind(websocket, "error"));
|
|
4751
4751
|
stream.once("close", websocket.emitClose.bind(websocket));
|
|
4752
4752
|
}
|
|
@@ -4758,10 +4758,10 @@ var require_websocket = __commonJS({
|
|
|
4758
4758
|
else websocket._bufferedAmount += length;
|
|
4759
4759
|
}
|
|
4760
4760
|
if (cb) {
|
|
4761
|
-
const
|
|
4761
|
+
const err2 = new Error(
|
|
4762
4762
|
`WebSocket is not open: readyState ${websocket.readyState} (${readyStates[websocket.readyState]})`
|
|
4763
4763
|
);
|
|
4764
|
-
process.nextTick(cb,
|
|
4764
|
+
process.nextTick(cb, err2);
|
|
4765
4765
|
}
|
|
4766
4766
|
}
|
|
4767
4767
|
function receiverOnConclude(code, reason) {
|
|
@@ -4779,16 +4779,16 @@ var require_websocket = __commonJS({
|
|
|
4779
4779
|
const websocket = this[kWebSocket];
|
|
4780
4780
|
if (!websocket.isPaused) websocket._socket.resume();
|
|
4781
4781
|
}
|
|
4782
|
-
function receiverOnError(
|
|
4782
|
+
function receiverOnError(err2) {
|
|
4783
4783
|
const websocket = this[kWebSocket];
|
|
4784
4784
|
if (websocket._socket[kWebSocket] !== void 0) {
|
|
4785
4785
|
websocket._socket.removeListener("data", socketOnData);
|
|
4786
4786
|
process.nextTick(resume, websocket._socket);
|
|
4787
|
-
websocket.close(
|
|
4787
|
+
websocket.close(err2[kStatusCode]);
|
|
4788
4788
|
}
|
|
4789
4789
|
if (!websocket._errorEmitted) {
|
|
4790
4790
|
websocket._errorEmitted = true;
|
|
4791
|
-
websocket.emit("error",
|
|
4791
|
+
websocket.emit("error", err2);
|
|
4792
4792
|
}
|
|
4793
4793
|
}
|
|
4794
4794
|
function receiverOnFinish() {
|
|
@@ -4808,7 +4808,7 @@ var require_websocket = __commonJS({
|
|
|
4808
4808
|
function resume(stream) {
|
|
4809
4809
|
stream.resume();
|
|
4810
4810
|
}
|
|
4811
|
-
function senderOnError(
|
|
4811
|
+
function senderOnError(err2) {
|
|
4812
4812
|
const websocket = this[kWebSocket];
|
|
4813
4813
|
if (websocket.readyState === WebSocket2.CLOSED) return;
|
|
4814
4814
|
if (websocket.readyState === WebSocket2.OPEN) {
|
|
@@ -4818,7 +4818,7 @@ var require_websocket = __commonJS({
|
|
|
4818
4818
|
this._socket.end();
|
|
4819
4819
|
if (!websocket._errorEmitted) {
|
|
4820
4820
|
websocket._errorEmitted = true;
|
|
4821
|
-
websocket.emit("error",
|
|
4821
|
+
websocket.emit("error", err2);
|
|
4822
4822
|
}
|
|
4823
4823
|
}
|
|
4824
4824
|
function setCloseTimer(websocket) {
|
|
@@ -4884,11 +4884,11 @@ var require_stream = __commonJS({
|
|
|
4884
4884
|
this.destroy();
|
|
4885
4885
|
}
|
|
4886
4886
|
}
|
|
4887
|
-
function duplexOnError(
|
|
4887
|
+
function duplexOnError(err2) {
|
|
4888
4888
|
this.removeListener("error", duplexOnError);
|
|
4889
4889
|
this.destroy();
|
|
4890
4890
|
if (this.listenerCount("error") === 0) {
|
|
4891
|
-
this.emit("error",
|
|
4891
|
+
this.emit("error", err2);
|
|
4892
4892
|
}
|
|
4893
4893
|
}
|
|
4894
4894
|
function createWebSocketStream2(ws, options) {
|
|
@@ -4904,28 +4904,28 @@ var require_stream = __commonJS({
|
|
|
4904
4904
|
const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;
|
|
4905
4905
|
if (!duplex.push(data)) ws.pause();
|
|
4906
4906
|
});
|
|
4907
|
-
ws.once("error", function error(
|
|
4907
|
+
ws.once("error", function error(err2) {
|
|
4908
4908
|
if (duplex.destroyed) return;
|
|
4909
4909
|
terminateOnDestroy = false;
|
|
4910
|
-
duplex.destroy(
|
|
4910
|
+
duplex.destroy(err2);
|
|
4911
4911
|
});
|
|
4912
4912
|
ws.once("close", function close() {
|
|
4913
4913
|
if (duplex.destroyed) return;
|
|
4914
4914
|
duplex.push(null);
|
|
4915
4915
|
});
|
|
4916
|
-
duplex._destroy = function(
|
|
4916
|
+
duplex._destroy = function(err2, callback) {
|
|
4917
4917
|
if (ws.readyState === ws.CLOSED) {
|
|
4918
|
-
callback(
|
|
4918
|
+
callback(err2);
|
|
4919
4919
|
process.nextTick(emitClose, duplex);
|
|
4920
4920
|
return;
|
|
4921
4921
|
}
|
|
4922
4922
|
let called = false;
|
|
4923
|
-
ws.once("error", function error(
|
|
4923
|
+
ws.once("error", function error(err3) {
|
|
4924
4924
|
called = true;
|
|
4925
|
-
callback(
|
|
4925
|
+
callback(err3);
|
|
4926
4926
|
});
|
|
4927
4927
|
ws.once("close", function close() {
|
|
4928
|
-
if (!called) callback(
|
|
4928
|
+
if (!called) callback(err2);
|
|
4929
4929
|
process.nextTick(emitClose, duplex);
|
|
4930
4930
|
});
|
|
4931
4931
|
if (terminateOnDestroy) ws.terminate();
|
|
@@ -5247,7 +5247,7 @@ var require_websocket_server = __commonJS({
|
|
|
5247
5247
|
if (secWebSocketProtocol !== void 0) {
|
|
5248
5248
|
try {
|
|
5249
5249
|
protocols = subprotocol.parse(secWebSocketProtocol);
|
|
5250
|
-
} catch (
|
|
5250
|
+
} catch (err2) {
|
|
5251
5251
|
const message = "Invalid Sec-WebSocket-Protocol header";
|
|
5252
5252
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
5253
5253
|
return;
|
|
@@ -5267,7 +5267,7 @@ var require_websocket_server = __commonJS({
|
|
|
5267
5267
|
perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
|
|
5268
5268
|
extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
|
|
5269
5269
|
}
|
|
5270
|
-
} catch (
|
|
5270
|
+
} catch (err2) {
|
|
5271
5271
|
const message = "Invalid or unacceptable Sec-WebSocket-Extensions header";
|
|
5272
5272
|
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
|
|
5273
5273
|
return;
|
|
@@ -5396,9 +5396,9 @@ var require_websocket_server = __commonJS({
|
|
|
5396
5396
|
}
|
|
5397
5397
|
function abortHandshakeOrEmitwsClientError(server, req, socket, code, message, headers) {
|
|
5398
5398
|
if (server.listenerCount("wsClientError")) {
|
|
5399
|
-
const
|
|
5400
|
-
Error.captureStackTrace(
|
|
5401
|
-
server.emit("wsClientError",
|
|
5399
|
+
const err2 = new Error(message);
|
|
5400
|
+
Error.captureStackTrace(err2, abortHandshakeOrEmitwsClientError);
|
|
5401
|
+
server.emit("wsClientError", err2, socket, req);
|
|
5402
5402
|
} else {
|
|
5403
5403
|
abortHandshake(socket, code, message, headers);
|
|
5404
5404
|
}
|
|
@@ -5424,7 +5424,7 @@ function readBuildInjectedVersion() {
|
|
|
5424
5424
|
if (false) {
|
|
5425
5425
|
return void 0;
|
|
5426
5426
|
}
|
|
5427
|
-
const version = "1.10.
|
|
5427
|
+
const version = "1.10.6-beta.0".trim();
|
|
5428
5428
|
return version || void 0;
|
|
5429
5429
|
}
|
|
5430
5430
|
function readPluginVersionFromPackageJson() {
|
|
@@ -6681,11 +6681,11 @@ function registerLightRulesGateway(api, registry, logger, rememberBroadcast) {
|
|
|
6681
6681
|
id: rule.name
|
|
6682
6682
|
}));
|
|
6683
6683
|
respond(true, { ok: true, rules });
|
|
6684
|
-
} catch (
|
|
6685
|
-
logger.warn(`lightrules.list failed: ${
|
|
6684
|
+
} catch (err2) {
|
|
6685
|
+
logger.warn(`lightrules.list failed: ${err2?.message}`);
|
|
6686
6686
|
respond(false, null, {
|
|
6687
6687
|
code: "INTERNAL_ERROR",
|
|
6688
|
-
message:
|
|
6688
|
+
message: err2?.message ?? "Unknown error"
|
|
6689
6689
|
});
|
|
6690
6690
|
}
|
|
6691
6691
|
});
|
|
@@ -6715,8 +6715,8 @@ function registerLightRulesGateway(api, registry, logger, rememberBroadcast) {
|
|
|
6715
6715
|
try {
|
|
6716
6716
|
repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });
|
|
6717
6717
|
assertAncsRepeatTimes(repeatTimes);
|
|
6718
|
-
} catch (
|
|
6719
|
-
respond(false, null, { code: "VALIDATION_FAILED", message:
|
|
6718
|
+
} catch (err2) {
|
|
6719
|
+
respond(false, null, { code: "VALIDATION_FAILED", message: err2?.message ?? "Unknown error" });
|
|
6720
6720
|
return;
|
|
6721
6721
|
}
|
|
6722
6722
|
try {
|
|
@@ -6730,12 +6730,12 @@ function registerLightRulesGateway(api, registry, logger, rememberBroadcast) {
|
|
|
6730
6730
|
});
|
|
6731
6731
|
logger.info(`Light rule created: ${name}`);
|
|
6732
6732
|
respond(true, { ok: true, name, cronHint: result.cronHint });
|
|
6733
|
-
} catch (
|
|
6734
|
-
if (
|
|
6735
|
-
respond(false, null, { code:
|
|
6733
|
+
} catch (err2) {
|
|
6734
|
+
if (err2 instanceof LightRuleError) {
|
|
6735
|
+
respond(false, null, { code: err2.code, message: err2.message });
|
|
6736
6736
|
} else {
|
|
6737
|
-
logger.warn(`lightrules.create failed: ${
|
|
6738
|
-
respond(false, null, { code: "INTERNAL_ERROR", message:
|
|
6737
|
+
logger.warn(`lightrules.create failed: ${err2?.message}`);
|
|
6738
|
+
respond(false, null, { code: "INTERNAL_ERROR", message: err2?.message ?? "Unknown error" });
|
|
6739
6739
|
}
|
|
6740
6740
|
}
|
|
6741
6741
|
});
|
|
@@ -6774,8 +6774,8 @@ function registerLightRulesGateway(api, registry, logger, rememberBroadcast) {
|
|
|
6774
6774
|
try {
|
|
6775
6775
|
repeatTimes = normalizeRepeatTimes({ repeat, repeat_times });
|
|
6776
6776
|
assertAncsRepeatTimes(repeatTimes);
|
|
6777
|
-
} catch (
|
|
6778
|
-
respond(false, null, { code: "VALIDATION_FAILED", message:
|
|
6777
|
+
} catch (err2) {
|
|
6778
|
+
respond(false, null, { code: "VALIDATION_FAILED", message: err2?.message ?? "Unknown error" });
|
|
6779
6779
|
return;
|
|
6780
6780
|
}
|
|
6781
6781
|
}
|
|
@@ -6798,12 +6798,12 @@ function registerLightRulesGateway(api, registry, logger, rememberBroadcast) {
|
|
|
6798
6798
|
rule: result.meta,
|
|
6799
6799
|
cronHint: result.cronHint
|
|
6800
6800
|
});
|
|
6801
|
-
} catch (
|
|
6802
|
-
if (
|
|
6803
|
-
respond(false, null, { code:
|
|
6801
|
+
} catch (err2) {
|
|
6802
|
+
if (err2 instanceof LightRuleError) {
|
|
6803
|
+
respond(false, null, { code: err2.code, message: err2.message });
|
|
6804
6804
|
} else {
|
|
6805
|
-
logger.warn(`lightrules.update failed: ${
|
|
6806
|
-
respond(false, null, { code: "INTERNAL_ERROR", message:
|
|
6805
|
+
logger.warn(`lightrules.update failed: ${err2?.message}`);
|
|
6806
|
+
respond(false, null, { code: "INTERNAL_ERROR", message: err2?.message ?? "Unknown error" });
|
|
6807
6807
|
}
|
|
6808
6808
|
}
|
|
6809
6809
|
});
|
|
@@ -6826,273 +6826,17 @@ function registerLightRulesGateway(api, registry, logger, rememberBroadcast) {
|
|
|
6826
6826
|
deleted: true,
|
|
6827
6827
|
cronHint: result.cronHint
|
|
6828
6828
|
});
|
|
6829
|
-
} catch (
|
|
6830
|
-
if (
|
|
6831
|
-
respond(false, null, { code:
|
|
6829
|
+
} catch (err2) {
|
|
6830
|
+
if (err2 instanceof LightRuleError) {
|
|
6831
|
+
respond(false, null, { code: err2.code, message: err2.message });
|
|
6832
6832
|
} else {
|
|
6833
|
-
logger.warn(`lightrules.delete failed: ${
|
|
6834
|
-
respond(false, null, { code: "INTERNAL_ERROR", message:
|
|
6833
|
+
logger.warn(`lightrules.delete failed: ${err2?.message}`);
|
|
6834
|
+
respond(false, null, { code: "INTERNAL_ERROR", message: err2?.message ?? "Unknown error" });
|
|
6835
6835
|
}
|
|
6836
6836
|
}
|
|
6837
6837
|
});
|
|
6838
6838
|
}
|
|
6839
6839
|
|
|
6840
|
-
// src/light-rules/evaluator-job.ts
|
|
6841
|
-
var EVALUATOR_JOB_ID = "light-rules-evaluator";
|
|
6842
|
-
var EVALUATOR_SUBAGENT_SESSION_KEY = EVALUATOR_JOB_ID;
|
|
6843
|
-
var FALLBACK_CRON_EXPR = "0 0 1 1 *";
|
|
6844
|
-
function buildEvaluatorJobMessage(notificationsDir) {
|
|
6845
|
-
return `\u706F\u6548\u89C4\u5219\u8BC4\u4F30\u4EFB\u52A1\u3002
|
|
6846
|
-
|
|
6847
|
-
\u6267\u884C\u6B65\u9AA4\uFF1A
|
|
6848
|
-
1. \u8BFB\u53D6 tasks/light-rules-evaluator/checkpoint.json\uFF08\u8BB0\u5F55\u4E0A\u6B21\u5904\u7406\u8FDB\u5EA6\uFF09
|
|
6849
|
-
2. \u626B\u63CF ${notificationsDir} \u76EE\u5F55\uFF0C\u83B7\u53D6 checkpoint \u4E4B\u540E\u7684\u65B0\u901A\u77E5
|
|
6850
|
-
3. \u626B\u63CF tasks/ \u76EE\u5F55\uFF0C\u8BFB\u53D6\u6240\u6709 type=light-rule \u4E14 enabled=true \u7684 meta.json
|
|
6851
|
-
4. \u5BF9\u6BCF\u6761\u65B0\u901A\u77E5\uFF0C\u9010\u4E00\u5224\u65AD\u662F\u5426\u547D\u4E2D\u6BCF\u6761\u89C4\u5219\u7684 description\uFF08\u8BED\u4E49\u5339\u914D\uFF09
|
|
6852
|
-
5. \u547D\u4E2D\u65F6\uFF1A\u4EE5\u8BE5\u89C4\u5219\u7684 segments \u548C repeat_times \u8C03\u7528 light_control \u5DE5\u5177
|
|
6853
|
-
6. \u66F4\u65B0 checkpoint.json\uFF0C\u8BB0\u5F55\u5DF2\u5904\u7406\u5230\u7684\u6700\u65B0\u901A\u77E5\u4F4D\u7F6E
|
|
6854
|
-
7. \u82E5\u65E0\u65B0\u901A\u77E5\u6216\u65E0 enabled \u89C4\u5219\uFF1A\u8F93\u51FA NO_CHANGE\uFF0C\u76F4\u63A5\u7ED3\u675F`;
|
|
6855
|
-
}
|
|
6856
|
-
var LightRulesEvaluatorJob = class {
|
|
6857
|
-
logger;
|
|
6858
|
-
registry;
|
|
6859
|
-
subagentRunner;
|
|
6860
|
-
getNotificationsDir;
|
|
6861
|
-
/**
|
|
6862
|
-
* 记录本进程生命周期内 job 是否已确认存在。
|
|
6863
|
-
* 仅在 `ensureJobExists` 成功后置 true,避免每次 push 都做检查。
|
|
6864
|
-
*/
|
|
6865
|
-
jobEnsured = false;
|
|
6866
|
-
/**
|
|
6867
|
-
* 首次创建 job 时的并发保护。
|
|
6868
|
-
* 避免冷启动瞬间多条通知并发到达时重复调用 `cron.add`。
|
|
6869
|
-
*/
|
|
6870
|
-
ensureJobPromise = null;
|
|
6871
|
-
/**
|
|
6872
|
-
* subagent fallback 路径的并发保护。
|
|
6873
|
-
* 若评估 session 已在运行中,跳过本次触发(checkpoint 保证下次补处理)。
|
|
6874
|
-
*/
|
|
6875
|
-
subagentInFlight = false;
|
|
6876
|
-
constructor(deps) {
|
|
6877
|
-
this.logger = deps.logger;
|
|
6878
|
-
this.registry = deps.registry;
|
|
6879
|
-
this.subagentRunner = deps.subagentRunner;
|
|
6880
|
-
this.getNotificationsDir = deps.getNotificationsDir ?? (() => void 0);
|
|
6881
|
-
}
|
|
6882
|
-
/**
|
|
6883
|
-
* 通知落盘后调用。若有新增通知且存在 enabled 规则,则触发评估。
|
|
6884
|
-
*
|
|
6885
|
-
* 两条路径:
|
|
6886
|
-
* - cron 不为 null:enqueueRun("force") 入队(gateway context 路径,正常路径)
|
|
6887
|
-
* - cron 为 null:通过 subagentRunner 直接运行(HTTP Relay 路径,fallback)
|
|
6888
|
-
*
|
|
6889
|
-
* @param cron 来自 gateway context 的 CronService;HTTP 路径下为 null
|
|
6890
|
-
* @param insertedCount 本次 ingest 新落盘的通知条数(StoredNotification 去重后)
|
|
6891
|
-
*/
|
|
6892
|
-
async triggerIfNeeded(cron, insertedCount) {
|
|
6893
|
-
if (insertedCount === 0) return;
|
|
6894
|
-
if (this.registry.getEnabled().length === 0) return;
|
|
6895
|
-
if (!cron) {
|
|
6896
|
-
await this.triggerViaSubagent();
|
|
6897
|
-
return;
|
|
6898
|
-
}
|
|
6899
|
-
try {
|
|
6900
|
-
await this.ensureJobExists(cron);
|
|
6901
|
-
} catch (err) {
|
|
6902
|
-
this.logger.warn(`light-rules-evaluator: job ensure failed: ${err?.message ?? err}`);
|
|
6903
|
-
return;
|
|
6904
|
-
}
|
|
6905
|
-
try {
|
|
6906
|
-
const result = await cron.enqueueRun(EVALUATOR_JOB_ID, "force");
|
|
6907
|
-
if (!result.ok) {
|
|
6908
|
-
this.logger.warn("light-rules-evaluator: enqueueRun returned ok=false");
|
|
6909
|
-
return;
|
|
6910
|
-
}
|
|
6911
|
-
if ("enqueued" in result && result.enqueued) {
|
|
6912
|
-
this.logger.info(`light-rules-evaluator: enqueued runId=${result.runId}`);
|
|
6913
|
-
} else if ("reason" in result) {
|
|
6914
|
-
this.logger.info(`light-rules-evaluator: enqueueRun skipped (${result.reason})`);
|
|
6915
|
-
}
|
|
6916
|
-
} catch (err) {
|
|
6917
|
-
this.logger.warn(`light-rules-evaluator: enqueueRun failed: ${err?.message ?? err}`);
|
|
6918
|
-
}
|
|
6919
|
-
}
|
|
6920
|
-
/**
|
|
6921
|
-
* cron service 不可用时的 fallback:直接通过 subagentRunner 运行评估 session。
|
|
6922
|
-
*
|
|
6923
|
-
* 并发保护:若上一次 subagent 运行尚未完成,本次跳过。
|
|
6924
|
-
* checkpoint 保证即使本次跳过,下次触发时会处理所有积压通知。
|
|
6925
|
-
*/
|
|
6926
|
-
async triggerViaSubagent() {
|
|
6927
|
-
if (!this.subagentRunner) {
|
|
6928
|
-
this.logger.warn(
|
|
6929
|
-
"light-rules-evaluator: cron service unavailable and no subagent fallback configured; notifications ingested via HTTP will not trigger light rules until an agent session is active"
|
|
6930
|
-
);
|
|
6931
|
-
return;
|
|
6932
|
-
}
|
|
6933
|
-
if (this.subagentInFlight) {
|
|
6934
|
-
this.logger.info("light-rules-evaluator: subagent run in-flight, skipping this trigger");
|
|
6935
|
-
return;
|
|
6936
|
-
}
|
|
6937
|
-
const notificationsDir = this.getNotificationsDir();
|
|
6938
|
-
if (!notificationsDir) {
|
|
6939
|
-
this.logger.warn("light-rules-evaluator: notifications dir not ready, skipping subagent trigger");
|
|
6940
|
-
return;
|
|
6941
|
-
}
|
|
6942
|
-
this.subagentInFlight = true;
|
|
6943
|
-
try {
|
|
6944
|
-
const result = await this.subagentRunner.run({
|
|
6945
|
-
sessionKey: EVALUATOR_SUBAGENT_SESSION_KEY,
|
|
6946
|
-
message: buildEvaluatorJobMessage(notificationsDir),
|
|
6947
|
-
deliver: false,
|
|
6948
|
-
idempotencyKey: `${EVALUATOR_SUBAGENT_SESSION_KEY}-${Date.now()}`
|
|
6949
|
-
});
|
|
6950
|
-
this.logger.info(`light-rules-evaluator: subagent triggered runId=${result.runId}`);
|
|
6951
|
-
} catch (err) {
|
|
6952
|
-
this.logger.warn(`light-rules-evaluator: subagent trigger failed: ${err?.message ?? err}`);
|
|
6953
|
-
} finally {
|
|
6954
|
-
this.subagentInFlight = false;
|
|
6955
|
-
}
|
|
6956
|
-
}
|
|
6957
|
-
/**
|
|
6958
|
-
* 按需创建 `light-rules-evaluator` job。
|
|
6959
|
-
* 若 job 已存在(内存缓存或 cron store),直接返回;否则调用 `cron.add`。
|
|
6960
|
-
*/
|
|
6961
|
-
async ensureJobExists(cron) {
|
|
6962
|
-
if (this.jobEnsured) return;
|
|
6963
|
-
if (!this.ensureJobPromise) {
|
|
6964
|
-
this.ensureJobPromise = this.createJobIfNeeded(cron).finally(() => {
|
|
6965
|
-
this.ensureJobPromise = null;
|
|
6966
|
-
});
|
|
6967
|
-
}
|
|
6968
|
-
await this.ensureJobPromise;
|
|
6969
|
-
}
|
|
6970
|
-
async createJobIfNeeded(cron) {
|
|
6971
|
-
if (cron.getJob(EVALUATOR_JOB_ID)) {
|
|
6972
|
-
this.jobEnsured = true;
|
|
6973
|
-
return;
|
|
6974
|
-
}
|
|
6975
|
-
try {
|
|
6976
|
-
await cron.add({
|
|
6977
|
-
id: EVALUATOR_JOB_ID,
|
|
6978
|
-
name: "\u706F\u6548\u89C4\u5219\u8BC4\u4F30",
|
|
6979
|
-
description: "\u4E8B\u4EF6\u9A71\u52A8\uFF1A\u901A\u77E5\u5230\u8FBE\u65F6\u8BC4\u4F30\u6240\u6709 enabled \u706F\u6548\u89C4\u5219\uFF0C\u547D\u4E2D\u5219\u8C03\u7528 light_control \u89E6\u53D1\u706F\u6548",
|
|
6980
|
-
enabled: true,
|
|
6981
|
-
schedule: { kind: "cron", expr: FALLBACK_CRON_EXPR },
|
|
6982
|
-
sessionTarget: "isolated",
|
|
6983
|
-
wakeMode: "now",
|
|
6984
|
-
payload: {
|
|
6985
|
-
kind: "agentTurn",
|
|
6986
|
-
message: buildEvaluatorJobMessage(this.getNotificationsDir() ?? "notifications")
|
|
6987
|
-
}
|
|
6988
|
-
});
|
|
6989
|
-
this.logger.info("light-rules-evaluator: job created");
|
|
6990
|
-
} catch (err) {
|
|
6991
|
-
if (!cron.getJob(EVALUATOR_JOB_ID)) {
|
|
6992
|
-
throw err;
|
|
6993
|
-
}
|
|
6994
|
-
}
|
|
6995
|
-
this.jobEnsured = true;
|
|
6996
|
-
}
|
|
6997
|
-
};
|
|
6998
|
-
|
|
6999
|
-
// src/light-rules/migration.ts
|
|
7000
|
-
var import_node_fs6 = require("fs");
|
|
7001
|
-
var import_node_path5 = require("path");
|
|
7002
|
-
var NO_MATCH_FETCH_PY = `#!/usr/bin/env python3
|
|
7003
|
-
# \u6B64\u6587\u4EF6\u7531\u8FC1\u79FB\u5DE5\u5177\u751F\u6210\u3002
|
|
7004
|
-
# \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
|
|
7005
|
-
print("NO_MATCH")
|
|
7006
|
-
`;
|
|
7007
|
-
function normalizeScriptText(text) {
|
|
7008
|
-
return text.replace(/\r\n/g, "\n").trim();
|
|
7009
|
-
}
|
|
7010
|
-
function resolveTasksDir(ctx) {
|
|
7011
|
-
if (ctx.workspaceDir) return (0, import_node_path5.join)(ctx.workspaceDir, "tasks");
|
|
7012
|
-
if (ctx.stateDir) {
|
|
7013
|
-
const inferredWorkspaceDir = (0, import_node_path5.join)(ctx.stateDir, "workspace");
|
|
7014
|
-
if ((0, import_node_fs6.existsSync)(inferredWorkspaceDir)) return (0, import_node_path5.join)(inferredWorkspaceDir, "tasks");
|
|
7015
|
-
return (0, import_node_path5.join)(ctx.stateDir, "tasks");
|
|
7016
|
-
}
|
|
7017
|
-
return null;
|
|
7018
|
-
}
|
|
7019
|
-
function migrateLegacyLightRuleTasks(ctx, logger) {
|
|
7020
|
-
const tasksDir3 = resolveTasksDir(ctx);
|
|
7021
|
-
if (!tasksDir3 || !(0, import_node_fs6.existsSync)(tasksDir3)) return;
|
|
7022
|
-
try {
|
|
7023
|
-
for (const entry of (0, import_node_fs6.readdirSync)(tasksDir3, { withFileTypes: true })) {
|
|
7024
|
-
if (!entry.isDirectory()) continue;
|
|
7025
|
-
migrateTaskDir((0, import_node_path5.join)(tasksDir3, String(entry.name)), logger);
|
|
7026
|
-
}
|
|
7027
|
-
} catch (err) {
|
|
7028
|
-
logger.warn(`migration: failed to read tasks dir: ${err?.message}`);
|
|
7029
|
-
}
|
|
7030
|
-
}
|
|
7031
|
-
function migrateTaskDir(taskDir, logger) {
|
|
7032
|
-
const metaPath = (0, import_node_path5.join)(taskDir, "meta.json");
|
|
7033
|
-
if (!(0, import_node_fs6.existsSync)(metaPath)) return;
|
|
7034
|
-
let meta;
|
|
7035
|
-
try {
|
|
7036
|
-
meta = JSON.parse((0, import_node_fs6.readFileSync)(metaPath, "utf-8"));
|
|
7037
|
-
} catch {
|
|
7038
|
-
return;
|
|
7039
|
-
}
|
|
7040
|
-
if (meta.type !== "light-rule") return;
|
|
7041
|
-
const name = typeof meta.name === "string" ? meta.name : taskDir;
|
|
7042
|
-
mergeMatchRulesIntoDescription(meta, name, metaPath, logger);
|
|
7043
|
-
replaceFetchPy(taskDir, name, logger);
|
|
7044
|
-
for (const filename of ["README.md", "checkpoint.json"]) {
|
|
7045
|
-
removeFile((0, import_node_path5.join)(taskDir, filename), name, filename, logger);
|
|
7046
|
-
}
|
|
7047
|
-
}
|
|
7048
|
-
function mergeMatchRulesIntoDescription(meta, name, metaPath, logger) {
|
|
7049
|
-
const matchRules = meta.matchRules;
|
|
7050
|
-
if (!matchRules || typeof matchRules !== "object") return;
|
|
7051
|
-
const rules = matchRules;
|
|
7052
|
-
const parts = [];
|
|
7053
|
-
if (rules.appName) parts.push(`app=${rules.appName}`);
|
|
7054
|
-
if (rules.senderKeywords?.length) {
|
|
7055
|
-
parts.push(`\u53D1\u4EF6\u4EBA\u5173\u952E\u8BCD=${rules.senderKeywords.join("\u3001")}`);
|
|
7056
|
-
}
|
|
7057
|
-
if (rules.contentKeywords?.length) {
|
|
7058
|
-
parts.push(`\u5185\u5BB9\u5173\u952E\u8BCD=${rules.contentKeywords.join("\u3001")}`);
|
|
7059
|
-
}
|
|
7060
|
-
if (parts.length > 0) {
|
|
7061
|
-
const existing = typeof meta.description === "string" ? meta.description.trim() : "";
|
|
7062
|
-
meta.description = existing ? `${existing}\u3002\u5339\u914D\u89C4\u5219\uFF1A${parts.join("\uFF0C")}` : `\u5339\u914D\u89C4\u5219\uFF1A${parts.join("\uFF0C")}`;
|
|
7063
|
-
}
|
|
7064
|
-
delete meta.matchRules;
|
|
7065
|
-
try {
|
|
7066
|
-
(0, import_node_fs6.writeFileSync)(metaPath, JSON.stringify(meta, null, 2), "utf-8");
|
|
7067
|
-
logger.info(`migration: merged matchRules into description for light rule: ${name}`);
|
|
7068
|
-
} catch (err) {
|
|
7069
|
-
logger.warn(`migration: failed to update meta.json for ${name}: ${err?.message}`);
|
|
7070
|
-
}
|
|
7071
|
-
}
|
|
7072
|
-
function replaceFetchPy(taskDir, name, logger) {
|
|
7073
|
-
const fetchPyPath = (0, import_node_path5.join)(taskDir, "fetch.py");
|
|
7074
|
-
if (!(0, import_node_fs6.existsSync)(fetchPyPath)) return;
|
|
7075
|
-
try {
|
|
7076
|
-
const existing = (0, import_node_fs6.readFileSync)(fetchPyPath, "utf-8");
|
|
7077
|
-
if (normalizeScriptText(existing) === normalizeScriptText(NO_MATCH_FETCH_PY)) {
|
|
7078
|
-
return;
|
|
7079
|
-
}
|
|
7080
|
-
(0, import_node_fs6.writeFileSync)(fetchPyPath, NO_MATCH_FETCH_PY, "utf-8");
|
|
7081
|
-
logger.info(`migration: replaced fetch.py with NO_MATCH placeholder for ${name}`);
|
|
7082
|
-
} catch (err) {
|
|
7083
|
-
logger.warn(`migration: failed to replace fetch.py for ${name}: ${err?.message}`);
|
|
7084
|
-
}
|
|
7085
|
-
}
|
|
7086
|
-
function removeFile(filePath, ruleName, filename, logger) {
|
|
7087
|
-
if (!(0, import_node_fs6.existsSync)(filePath)) return;
|
|
7088
|
-
try {
|
|
7089
|
-
(0, import_node_fs6.rmSync)(filePath);
|
|
7090
|
-
logger.info(`migration: removed ${filename} for light rule: ${ruleName}`);
|
|
7091
|
-
} catch (err) {
|
|
7092
|
-
logger.warn(`migration: failed to remove ${filename} for ${ruleName}: ${err?.message}`);
|
|
7093
|
-
}
|
|
7094
|
-
}
|
|
7095
|
-
|
|
7096
6840
|
// src/light-rules/registry.ts
|
|
7097
6841
|
var LightRuleRegistry = class {
|
|
7098
6842
|
ctx;
|
|
@@ -7213,20 +6957,705 @@ var LightRuleRegistry = class {
|
|
|
7213
6957
|
}
|
|
7214
6958
|
};
|
|
7215
6959
|
|
|
7216
|
-
// src/
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7229
|
-
|
|
6960
|
+
// src/light/protocol.ts
|
|
6961
|
+
var MAX_LIGHT_SEGMENTS = 12;
|
|
6962
|
+
var PROTOCOL_DIGITS = [
|
|
6963
|
+
"\x80",
|
|
6964
|
+
"\x81",
|
|
6965
|
+
"\x82",
|
|
6966
|
+
"\x83",
|
|
6967
|
+
"\x84",
|
|
6968
|
+
"\x91",
|
|
6969
|
+
"\x92",
|
|
6970
|
+
"\x93",
|
|
6971
|
+
"\x94",
|
|
6972
|
+
"\x95",
|
|
6973
|
+
"\x96",
|
|
6974
|
+
"\x97"
|
|
6975
|
+
];
|
|
6976
|
+
var LED_SEPARATOR_ONCE = "\x9A";
|
|
6977
|
+
var LED_SEPARATOR_LOOP = "\x9B";
|
|
6978
|
+
var DURATION_STEPS_S = [0.5, 1, 2, 3, 5, 6, 8, 16, 24, 32, 48];
|
|
6979
|
+
var INTERVAL_STEPS_MS = [50, 100, 200, 300, 500, 600, 800, 1600, 2400, 3200, 4800];
|
|
6980
|
+
var BREATH_STEPS_MS = [1040, 1560, 2080, 2600, 3100, 4160];
|
|
6981
|
+
var BRIGHTNESS_STEPS = [32, 64, 96, 128, 192, 255];
|
|
6982
|
+
var COLOR_STEPS = [0, 32, 64, 128, 192, 255];
|
|
6983
|
+
var BACKGROUND_BRIGHTNESS_STEPS = [0, 32, 64, 96, 128, 192, 255];
|
|
6984
|
+
var MULTI_CHANNEL_COLOR_COEFFICIENTS = { r: 1, g: 0.25, b: 0.25 };
|
|
6985
|
+
var PURE_WHITE_COLOR_COEFFICIENTS = { r: 1, g: 0.35, b: 0.35 };
|
|
6986
|
+
var MODE_TO_INDEX = {
|
|
6987
|
+
wave: 0,
|
|
6988
|
+
breath: 1,
|
|
6989
|
+
strobe: 2,
|
|
6990
|
+
steady: 3,
|
|
6991
|
+
wave_rainbow: 4,
|
|
6992
|
+
pixel_frame: 5
|
|
6993
|
+
};
|
|
6994
|
+
function buildLightEffectApnsBody(segments, repeatInput) {
|
|
6995
|
+
assertSegmentCount(segments);
|
|
6996
|
+
assertSegmentsValid(segments);
|
|
6997
|
+
const repeatTimes = normalizeRepeatTimes(repeatInput);
|
|
6998
|
+
assertAncsRepeatTimes(repeatTimes);
|
|
6999
|
+
const visibleText = summarizeSegments(segments);
|
|
7000
|
+
const separator = repeatTimes === 0 ? LED_SEPARATOR_LOOP : LED_SEPARATOR_ONCE;
|
|
7001
|
+
const payload = segments.map((segment) => encodeSegment(segment)).join("");
|
|
7002
|
+
return `${visibleText}${separator}${payload}`;
|
|
7003
|
+
}
|
|
7004
|
+
function assertSegmentCount(segments) {
|
|
7005
|
+
if (segments.length < 1 || segments.length > MAX_LIGHT_SEGMENTS) {
|
|
7006
|
+
throw new Error(`light_control supports 1-${MAX_LIGHT_SEGMENTS} segments`);
|
|
7007
|
+
}
|
|
7008
|
+
}
|
|
7009
|
+
function summarizeSegments(segments) {
|
|
7010
|
+
const modeDesc = segments.map((segment) => segment.mode).join("+");
|
|
7011
|
+
return `Effect: ${modeDesc} (${segments.length} segment${segments.length > 1 ? "s" : ""})`;
|
|
7012
|
+
}
|
|
7013
|
+
function assertSegmentsValid(segments) {
|
|
7014
|
+
const validation = validateSegments(segments);
|
|
7015
|
+
if (!validation.valid) {
|
|
7016
|
+
throw new Error(
|
|
7017
|
+
validation.errors.map((error) => `${error.field}: ${error.message}`).join("; ")
|
|
7018
|
+
);
|
|
7019
|
+
}
|
|
7020
|
+
}
|
|
7021
|
+
function encodeSegment(segment) {
|
|
7022
|
+
const common = [
|
|
7023
|
+
MODE_TO_INDEX[segment.mode],
|
|
7024
|
+
quantizeDuration(segment.duration_s)
|
|
7025
|
+
];
|
|
7026
|
+
let values;
|
|
7027
|
+
switch (segment.mode) {
|
|
7028
|
+
case "wave":
|
|
7029
|
+
case "wave_rainbow":
|
|
7030
|
+
const color = normalizeProtocolColor(segment.color);
|
|
7031
|
+
const background = normalizeProtocolColor(segment.background);
|
|
7032
|
+
values = [
|
|
7033
|
+
...common,
|
|
7034
|
+
quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),
|
|
7035
|
+
quantizeBrightnessValue(segment.brightness ?? 0),
|
|
7036
|
+
quantize(color.r, COLOR_STEPS),
|
|
7037
|
+
quantize(color.g, COLOR_STEPS),
|
|
7038
|
+
quantize(color.b, COLOR_STEPS),
|
|
7039
|
+
segment.direction === "rtl" ? 1 : 0,
|
|
7040
|
+
quantizeWindow(segment.window ?? 2),
|
|
7041
|
+
quantize(background.r, COLOR_STEPS),
|
|
7042
|
+
quantize(background.g, COLOR_STEPS),
|
|
7043
|
+
quantize(background.b, COLOR_STEPS),
|
|
7044
|
+
quantize(segment.background?.brightness ?? 0, BACKGROUND_BRIGHTNESS_STEPS)
|
|
7045
|
+
];
|
|
7046
|
+
break;
|
|
7047
|
+
case "breath":
|
|
7048
|
+
const breathColor = normalizeProtocolColor(segment.color);
|
|
7049
|
+
values = [
|
|
7050
|
+
...common,
|
|
7051
|
+
quantizeBreathRiseFall(segment.breath_timing?.rise_ms),
|
|
7052
|
+
quantizeBreathHoldOff(segment.breath_timing?.hold_ms),
|
|
7053
|
+
quantizeBreathRiseFall(segment.breath_timing?.fall_ms),
|
|
7054
|
+
quantizeBreathHoldOff(segment.breath_timing?.off_ms),
|
|
7055
|
+
quantizeBrightnessValue(segment.brightness ?? 0),
|
|
7056
|
+
quantize(breathColor.r, COLOR_STEPS),
|
|
7057
|
+
quantize(breathColor.g, COLOR_STEPS),
|
|
7058
|
+
quantize(breathColor.b, COLOR_STEPS)
|
|
7059
|
+
];
|
|
7060
|
+
break;
|
|
7061
|
+
case "strobe":
|
|
7062
|
+
const strobeColor = normalizeProtocolColor(segment.color);
|
|
7063
|
+
values = [
|
|
7064
|
+
...common,
|
|
7065
|
+
quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),
|
|
7066
|
+
quantizeBrightnessValue(segment.brightness ?? 0),
|
|
7067
|
+
quantize(strobeColor.r, COLOR_STEPS),
|
|
7068
|
+
quantize(strobeColor.g, COLOR_STEPS),
|
|
7069
|
+
quantize(strobeColor.b, COLOR_STEPS)
|
|
7070
|
+
];
|
|
7071
|
+
break;
|
|
7072
|
+
case "steady":
|
|
7073
|
+
const steadyColor = normalizeProtocolColor(segment.color);
|
|
7074
|
+
values = [
|
|
7075
|
+
...common,
|
|
7076
|
+
quantizeBrightnessValue(segment.brightness ?? 0),
|
|
7077
|
+
quantize(steadyColor.r, COLOR_STEPS),
|
|
7078
|
+
quantize(steadyColor.g, COLOR_STEPS),
|
|
7079
|
+
quantize(steadyColor.b, COLOR_STEPS)
|
|
7080
|
+
];
|
|
7081
|
+
break;
|
|
7082
|
+
case "pixel_frame":
|
|
7083
|
+
values = encodePixelFrameValues(common, segment);
|
|
7084
|
+
break;
|
|
7085
|
+
}
|
|
7086
|
+
return values.map((value) => PROTOCOL_DIGITS[value]).join("");
|
|
7087
|
+
}
|
|
7088
|
+
function encodePixelFrameValues(common, segment) {
|
|
7089
|
+
const pixels = segment.pixels ?? [];
|
|
7090
|
+
return [
|
|
7091
|
+
...common,
|
|
7092
|
+
pixels.length - 1,
|
|
7093
|
+
...pixels.flatMap((pixel) => {
|
|
7094
|
+
const color = normalizeProtocolColor(pixel.color);
|
|
7095
|
+
return [
|
|
7096
|
+
pixel.index,
|
|
7097
|
+
quantize(color.r, COLOR_STEPS),
|
|
7098
|
+
quantize(color.g, COLOR_STEPS),
|
|
7099
|
+
quantize(color.b, COLOR_STEPS),
|
|
7100
|
+
quantizeBrightnessValue(pixel.brightness)
|
|
7101
|
+
];
|
|
7102
|
+
})
|
|
7103
|
+
];
|
|
7104
|
+
}
|
|
7105
|
+
function normalizeProtocolColor(color) {
|
|
7106
|
+
const normalized = {
|
|
7107
|
+
r: color?.r ?? 0,
|
|
7108
|
+
g: color?.g ?? 0,
|
|
7109
|
+
b: color?.b ?? 0
|
|
7110
|
+
};
|
|
7111
|
+
if (isPureWhiteProtocolColor(normalized)) {
|
|
7112
|
+
return applyProtocolColorCoefficients(normalized, PURE_WHITE_COLOR_COEFFICIENTS);
|
|
7113
|
+
}
|
|
7114
|
+
if (countActiveProtocolColorChannels(normalized) <= 1) {
|
|
7115
|
+
return normalized;
|
|
7116
|
+
}
|
|
7117
|
+
return applyProtocolColorCoefficients(normalized, MULTI_CHANNEL_COLOR_COEFFICIENTS);
|
|
7118
|
+
}
|
|
7119
|
+
function countActiveProtocolColorChannels(color) {
|
|
7120
|
+
return Number(color.r > 0) + Number(color.g > 0) + Number(color.b > 0);
|
|
7121
|
+
}
|
|
7122
|
+
function isPureWhiteProtocolColor(color) {
|
|
7123
|
+
return color.r === 255 && color.g === 255 && color.b === 255;
|
|
7124
|
+
}
|
|
7125
|
+
function applyProtocolColorCoefficients(color, coefficients) {
|
|
7126
|
+
return {
|
|
7127
|
+
r: scaleProtocolColorChannel(color.r, coefficients.r),
|
|
7128
|
+
g: scaleProtocolColorChannel(color.g, coefficients.g),
|
|
7129
|
+
b: scaleProtocolColorChannel(color.b, coefficients.b)
|
|
7130
|
+
};
|
|
7131
|
+
}
|
|
7132
|
+
function scaleProtocolColorChannel(value, coefficient) {
|
|
7133
|
+
return Math.max(0, Math.min(255, Math.round(value * coefficient)));
|
|
7134
|
+
}
|
|
7135
|
+
function quantize(value, steps) {
|
|
7136
|
+
let bestIndex = 0;
|
|
7137
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
7138
|
+
for (const [index, step] of steps.entries()) {
|
|
7139
|
+
const distance = Math.abs(value - step);
|
|
7140
|
+
if (distance < bestDistance) {
|
|
7141
|
+
bestIndex = index;
|
|
7142
|
+
bestDistance = distance;
|
|
7143
|
+
}
|
|
7144
|
+
}
|
|
7145
|
+
return bestIndex;
|
|
7146
|
+
}
|
|
7147
|
+
function quantizeDuration(duration_s) {
|
|
7148
|
+
if (duration_s === 0) return 11;
|
|
7149
|
+
return quantize(duration_s, DURATION_STEPS_S);
|
|
7150
|
+
}
|
|
7151
|
+
function quantizeBrightnessValue(brightness) {
|
|
7152
|
+
if (brightness === 0) return 11;
|
|
7153
|
+
return quantize(brightness, BRIGHTNESS_STEPS);
|
|
7154
|
+
}
|
|
7155
|
+
function quantizeBreathRiseFall(value) {
|
|
7156
|
+
return quantize(value ?? 1040, BREATH_STEPS_MS);
|
|
7157
|
+
}
|
|
7158
|
+
function quantizeBreathHoldOff(value) {
|
|
7159
|
+
if (value === 0) {
|
|
7160
|
+
return 5;
|
|
7161
|
+
}
|
|
7162
|
+
return quantize(value ?? 1040, BREATH_STEPS_MS.slice(0, 5));
|
|
7163
|
+
}
|
|
7164
|
+
function quantizeWindow(value) {
|
|
7165
|
+
return value - 1;
|
|
7166
|
+
}
|
|
7167
|
+
|
|
7168
|
+
// src/plugin/light-rules-tools.ts
|
|
7169
|
+
var segmentItemSchema = {
|
|
7170
|
+
type: "object",
|
|
7171
|
+
required: ["mode", "duration_s"],
|
|
7172
|
+
additionalProperties: false,
|
|
7173
|
+
properties: {
|
|
7174
|
+
mode: {
|
|
7175
|
+
type: "string",
|
|
7176
|
+
enum: ["wave", "breath", "strobe", "steady", "wave_rainbow", "pixel_frame"],
|
|
7177
|
+
description: "\u706F\u6548\u6A21\u5F0F\uFF1Awave \u6CE2\u6D6A / breath \u547C\u5438 / strobe \u9891\u95EA / steady \u5E38\u4EAE / wave_rainbow \u6D41\u5149 / pixel_frame \u9010\u7EC4\u50CF\u7D20\u5E27"
|
|
7178
|
+
},
|
|
7179
|
+
duration_s: { type: "number", minimum: 0, description: "\u6301\u7EED\u65F6\u957F\uFF08\u79D2\uFF09\uFF0C0 \u8868\u793A\u65E0\u9650" },
|
|
7180
|
+
brightness: { type: "number", minimum: 0, maximum: 255 },
|
|
7181
|
+
color: {
|
|
7182
|
+
type: "object",
|
|
7183
|
+
required: ["r", "g", "b"],
|
|
7184
|
+
additionalProperties: false,
|
|
7185
|
+
properties: {
|
|
7186
|
+
r: { type: "number", minimum: 0, maximum: 255 },
|
|
7187
|
+
g: { type: "number", minimum: 0, maximum: 255 },
|
|
7188
|
+
b: { type: "number", minimum: 0, maximum: 255 }
|
|
7189
|
+
}
|
|
7190
|
+
},
|
|
7191
|
+
interval_ms: { type: "number", minimum: 0 },
|
|
7192
|
+
direction: { type: "string", enum: ["ltr", "rtl"] },
|
|
7193
|
+
window: { type: "number", enum: [1, 2, 3] },
|
|
7194
|
+
breath_timing: {
|
|
7195
|
+
type: "object",
|
|
7196
|
+
additionalProperties: false,
|
|
7197
|
+
properties: {
|
|
7198
|
+
rise_ms: { type: "number", minimum: 0 },
|
|
7199
|
+
hold_ms: { type: "number", minimum: 0 },
|
|
7200
|
+
fall_ms: { type: "number", minimum: 0 },
|
|
7201
|
+
off_ms: { type: "number", minimum: 0 }
|
|
7202
|
+
}
|
|
7203
|
+
},
|
|
7204
|
+
frames: { type: "array", items: { type: "array", items: { type: "number" } } },
|
|
7205
|
+
frame_duration_ms: { type: "number", minimum: 0 },
|
|
7206
|
+
background: {
|
|
7207
|
+
type: "object",
|
|
7208
|
+
required: ["r", "g", "b"],
|
|
7209
|
+
additionalProperties: false,
|
|
7210
|
+
properties: {
|
|
7211
|
+
r: { type: "number", minimum: 0, maximum: 255 },
|
|
7212
|
+
g: { type: "number", minimum: 0, maximum: 255 },
|
|
7213
|
+
b: { type: "number", minimum: 0, maximum: 255 }
|
|
7214
|
+
}
|
|
7215
|
+
}
|
|
7216
|
+
}
|
|
7217
|
+
};
|
|
7218
|
+
var segmentsSchema = {
|
|
7219
|
+
type: "array",
|
|
7220
|
+
description: "\u706F\u6548\u6BB5\u5E8F\u5217\uFF0C1\u201312 \u6BB5\uFF0C\u6309\u987A\u5E8F\u64AD\u653E",
|
|
7221
|
+
minItems: 1,
|
|
7222
|
+
maxItems: MAX_LIGHT_SEGMENTS,
|
|
7223
|
+
items: segmentItemSchema
|
|
7224
|
+
};
|
|
7225
|
+
function ok(data) {
|
|
7226
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }], details: data };
|
|
7227
|
+
}
|
|
7228
|
+
function err(code, message) {
|
|
7229
|
+
const data = { ok: false, error: { code, message } };
|
|
7230
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }], details: data };
|
|
7231
|
+
}
|
|
7232
|
+
function registerLightRulesTools(api, registry, logger) {
|
|
7233
|
+
api.registerTool({
|
|
7234
|
+
name: "lightrules.list",
|
|
7235
|
+
label: "List Light Rules",
|
|
7236
|
+
description: '\u5217\u51FA\u6240\u6709\u706F\u6548\u89C4\u5219\uFF08\u5305\u542B enabled/disabled \u72B6\u6001\uFF09\u3002\u5F53\u7528\u6237\u8BF4"\u5217\u51FA\u706F\u6548\u89C4\u5219"\u3001"\u6709\u54EA\u4E9B\u706F\u6548\u89C4\u5219"\u3001"\u67E5\u770B\u89C4\u5219"\u7B49\u65F6\u8C03\u7528\u3002\u6CE8\u610F\uFF1A\u706F\u6548\u89C4\u5219\u7684\u6240\u6709 CRUD \u64CD\u4F5C\u5FC5\u987B\u901A\u8FC7 lightrules.* \u5DE5\u5177\u5B8C\u6210\uFF0C\u7981\u6B62\u76F4\u63A5\u7528 write/edit \u4FEE\u6539 tasks/*/meta.json\u3002',
|
|
7237
|
+
parameters: { type: "object", properties: {}, additionalProperties: false },
|
|
7238
|
+
async execute(_toolCallId, _params) {
|
|
7239
|
+
try {
|
|
7240
|
+
const rules = registry.list().map((rule) => ({ ...rule, id: rule.name }));
|
|
7241
|
+
return ok({ ok: true, rules });
|
|
7242
|
+
} catch (e) {
|
|
7243
|
+
logger.warn(`lightrules.list tool failed: ${e?.message}`);
|
|
7244
|
+
return err("INTERNAL_ERROR", e?.message ?? "Unknown error");
|
|
7245
|
+
}
|
|
7246
|
+
}
|
|
7247
|
+
});
|
|
7248
|
+
api.registerTool({
|
|
7249
|
+
name: "lightrules.create",
|
|
7250
|
+
label: "Create Light Rule",
|
|
7251
|
+
description: '\u521B\u5EFA\u4E00\u6761\u706F\u6548\u89C4\u5219\uFF0C\u6307\u5B9A\u540D\u79F0\u3001\u81EA\u7136\u8BED\u8A00\u89E6\u53D1\u63CF\u8FF0\u548C\u706F\u6548\u53C2\u6570\u3002\u5F53\u7528\u6237\u8BF4"\u521B\u5EFA\u706F\u6548\u89C4\u5219"\u3001"\u65B0\u589E\u89C4\u5219"\u7B49\u65F6\u8C03\u7528\u3002',
|
|
7252
|
+
parameters: {
|
|
7253
|
+
type: "object",
|
|
7254
|
+
required: ["name", "description", "segments"],
|
|
7255
|
+
additionalProperties: false,
|
|
7256
|
+
properties: {
|
|
7257
|
+
name: { type: "string", description: "\u89C4\u5219\u7684\u552F\u4E00\u6807\u8BC6\u7B26\uFF08\u82F1\u6587 slug\uFF0C\u5982 red_light_on_wechat\uFF09" },
|
|
7258
|
+
description: {
|
|
7259
|
+
type: "string",
|
|
7260
|
+
description: "\u81EA\u7136\u8BED\u8A00\u89E6\u53D1\u6761\u4EF6\uFF0C\u540C\u65F6\u4F5C\u4E3A\u89C4\u5219\u7528\u9014\u8BF4\u660E\u3002Agent \u6309\u6B64\u5B57\u6BB5\u5224\u65AD\u662F\u5426\u547D\u4E2D\uFF0C\u5FC5\u987B\u6E05\u6670\u63CF\u8FF0\u300C\u4F55\u65F6\u89E6\u53D1\u300D"
|
|
7261
|
+
},
|
|
7262
|
+
segments: segmentsSchema,
|
|
7263
|
+
repeat_times: {
|
|
7264
|
+
type: "number",
|
|
7265
|
+
description: "\u6574\u6761\u706F\u6548\u5E8F\u5217\u91CD\u590D\u6B21\u6570\uFF0C0=\u65E0\u9650\u5FAA\u73AF\uFF0C1=\u64AD\u653E\u4E00\u6B21\uFF08\u9ED8\u8BA4\uFF09"
|
|
7266
|
+
}
|
|
7267
|
+
}
|
|
7268
|
+
},
|
|
7269
|
+
async execute(_toolCallId, params) {
|
|
7270
|
+
const { name, description, segments, repeat_times } = params;
|
|
7271
|
+
if (!name || typeof name !== "string")
|
|
7272
|
+
return err("INVALID_PARAMS", "name is required");
|
|
7273
|
+
if (!description || typeof description !== "string")
|
|
7274
|
+
return err("INVALID_PARAMS", "description is required");
|
|
7275
|
+
const validation = validateSegments(segments);
|
|
7276
|
+
if (!validation.valid) return err("VALIDATION_FAILED", JSON.stringify(validation.errors));
|
|
7277
|
+
let repeatTimes;
|
|
7278
|
+
try {
|
|
7279
|
+
repeatTimes = normalizeRepeatTimes({ repeat_times });
|
|
7280
|
+
assertAncsRepeatTimes(repeatTimes);
|
|
7281
|
+
} catch (e) {
|
|
7282
|
+
return err("VALIDATION_FAILED", e?.message ?? "Unknown error");
|
|
7283
|
+
}
|
|
7284
|
+
try {
|
|
7285
|
+
const result = await registry.create({
|
|
7286
|
+
name,
|
|
7287
|
+
description,
|
|
7288
|
+
matchRules: {},
|
|
7289
|
+
segments: validation.segments,
|
|
7290
|
+
repeat_times: repeatTimes,
|
|
7291
|
+
cronSchedule: "*/5 * * * *"
|
|
7292
|
+
});
|
|
7293
|
+
logger.info(`lightrules.create tool: created ${name}`);
|
|
7294
|
+
return ok({ ok: true, name, cronHint: result.cronHint });
|
|
7295
|
+
} catch (e) {
|
|
7296
|
+
if (e instanceof LightRuleError) return err(e.code, e.message);
|
|
7297
|
+
logger.warn(`lightrules.create tool failed: ${e?.message}`);
|
|
7298
|
+
return err("INTERNAL_ERROR", e?.message ?? "Unknown error");
|
|
7299
|
+
}
|
|
7300
|
+
}
|
|
7301
|
+
});
|
|
7302
|
+
api.registerTool({
|
|
7303
|
+
name: "lightrules.update",
|
|
7304
|
+
label: "Update Light Rule",
|
|
7305
|
+
description: '\u4FEE\u6539\u706F\u6548\u89C4\u5219\uFF08\u542F\u7528/\u7981\u7528\u3001\u6539\u63CF\u8FF0\u3001\u6539\u706F\u6548\u53C2\u6570\uFF09\u3002\u5F53\u7528\u6237\u8BF4"\u7981\u7528\u67D0\u6761\u89C4\u5219"\u3001"\u542F\u7528\u89C4\u5219"\u3001"\u4FEE\u6539\u706F\u6548\u89C4\u5219"\u7B49\u65F6\u8C03\u7528\u3002',
|
|
7306
|
+
parameters: {
|
|
7307
|
+
type: "object",
|
|
7308
|
+
required: ["name"],
|
|
7309
|
+
additionalProperties: false,
|
|
7310
|
+
properties: {
|
|
7311
|
+
name: { type: "string", description: "\u8981\u4FEE\u6539\u7684\u89C4\u5219\u540D\u79F0\uFF08\u552F\u4E00\u6807\u8BC6\u7B26\uFF09" },
|
|
7312
|
+
description: { type: "string", description: "\u65B0\u7684\u89E6\u53D1\u6761\u4EF6\u63CF\u8FF0\uFF08\u53EF\u9009\uFF09" },
|
|
7313
|
+
enabled: { type: "boolean", description: "true=\u542F\u7528\uFF0Cfalse=\u7981\u7528" },
|
|
7314
|
+
segments: { ...segmentsSchema, description: "\u65B0\u7684\u706F\u6548\u6BB5\u5E8F\u5217\uFF08\u53EF\u9009\uFF0C\u4E0D\u586B\u5219\u4FDD\u6301\u4E0D\u53D8\uFF09" },
|
|
7315
|
+
repeat_times: { type: "number", description: "\u65B0\u7684\u91CD\u590D\u6B21\u6570\uFF08\u53EF\u9009\uFF09" }
|
|
7316
|
+
}
|
|
7317
|
+
},
|
|
7318
|
+
async execute(_toolCallId, params) {
|
|
7319
|
+
const { name, description, enabled, segments, repeat_times } = params;
|
|
7320
|
+
if (!name || typeof name !== "string")
|
|
7321
|
+
return err("INVALID_PARAMS", "name is required");
|
|
7322
|
+
let validatedSegments;
|
|
7323
|
+
if (segments !== void 0) {
|
|
7324
|
+
const validation = validateSegments(segments);
|
|
7325
|
+
if (!validation.valid) return err("VALIDATION_FAILED", JSON.stringify(validation.errors));
|
|
7326
|
+
validatedSegments = validation.segments;
|
|
7327
|
+
}
|
|
7328
|
+
let repeatTimes;
|
|
7329
|
+
if (repeat_times !== void 0) {
|
|
7330
|
+
try {
|
|
7331
|
+
repeatTimes = normalizeRepeatTimes({ repeat_times });
|
|
7332
|
+
assertAncsRepeatTimes(repeatTimes);
|
|
7333
|
+
} catch (e) {
|
|
7334
|
+
return err("VALIDATION_FAILED", e?.message ?? "Unknown error");
|
|
7335
|
+
}
|
|
7336
|
+
}
|
|
7337
|
+
try {
|
|
7338
|
+
const result = await registry.update({
|
|
7339
|
+
name,
|
|
7340
|
+
description,
|
|
7341
|
+
segments: validatedSegments,
|
|
7342
|
+
repeat_times: repeatTimes,
|
|
7343
|
+
enabled
|
|
7344
|
+
});
|
|
7345
|
+
logger.info(`lightrules.update tool: updated ${name}`);
|
|
7346
|
+
return ok({
|
|
7347
|
+
ok: true,
|
|
7348
|
+
name: result.meta.name,
|
|
7349
|
+
updated: true,
|
|
7350
|
+
rule: result.meta,
|
|
7351
|
+
cronHint: result.cronHint
|
|
7352
|
+
});
|
|
7353
|
+
} catch (e) {
|
|
7354
|
+
if (e instanceof LightRuleError) return err(e.code, e.message);
|
|
7355
|
+
logger.warn(`lightrules.update tool failed: ${e?.message}`);
|
|
7356
|
+
return err("INTERNAL_ERROR", e?.message ?? "Unknown error");
|
|
7357
|
+
}
|
|
7358
|
+
}
|
|
7359
|
+
});
|
|
7360
|
+
api.registerTool({
|
|
7361
|
+
name: "lightrules.delete",
|
|
7362
|
+
label: "Delete Light Rule",
|
|
7363
|
+
description: '\u5220\u9664\u4E00\u6761\u706F\u6548\u89C4\u5219\uFF08\u4E0D\u53EF\u6062\u590D\uFF09\u3002\u5F53\u7528\u6237\u8BF4"\u5220\u9664\u706F\u6548\u89C4\u5219"\u3001"\u79FB\u9664\u89C4\u5219"\u7B49\u65F6\u8C03\u7528\u3002',
|
|
7364
|
+
parameters: {
|
|
7365
|
+
type: "object",
|
|
7366
|
+
required: ["name"],
|
|
7367
|
+
additionalProperties: false,
|
|
7368
|
+
properties: {
|
|
7369
|
+
name: { type: "string", description: "\u8981\u5220\u9664\u7684\u89C4\u5219\u540D\u79F0" }
|
|
7370
|
+
}
|
|
7371
|
+
},
|
|
7372
|
+
async execute(_toolCallId, params) {
|
|
7373
|
+
const { name } = params;
|
|
7374
|
+
if (!name || typeof name !== "string")
|
|
7375
|
+
return err("INVALID_PARAMS", "name is required");
|
|
7376
|
+
try {
|
|
7377
|
+
const result = await registry.delete(name);
|
|
7378
|
+
logger.info(`lightrules.delete tool: deleted ${name}`);
|
|
7379
|
+
return ok({ ok: true, name: result.name, deleted: true, cronHint: result.cronHint });
|
|
7380
|
+
} catch (e) {
|
|
7381
|
+
if (e instanceof LightRuleError) return err(e.code, e.message);
|
|
7382
|
+
logger.warn(`lightrules.delete tool failed: ${e?.message}`);
|
|
7383
|
+
return err("INTERNAL_ERROR", e?.message ?? "Unknown error");
|
|
7384
|
+
}
|
|
7385
|
+
}
|
|
7386
|
+
});
|
|
7387
|
+
}
|
|
7388
|
+
|
|
7389
|
+
// src/light-rules/evaluator-job.ts
|
|
7390
|
+
var EVALUATOR_JOB_ID = "light-rules-evaluator";
|
|
7391
|
+
var EVALUATOR_SUBAGENT_SESSION_KEY = EVALUATOR_JOB_ID;
|
|
7392
|
+
var FALLBACK_CRON_EXPR = "0 0 1 1 *";
|
|
7393
|
+
function buildEvaluatorJobMessage(notificationsDir) {
|
|
7394
|
+
return `\u706F\u6548\u89C4\u5219\u8BC4\u4F30\u4EFB\u52A1\u3002
|
|
7395
|
+
|
|
7396
|
+
\u6267\u884C\u6B65\u9AA4\uFF1A
|
|
7397
|
+
1. \u8BFB\u53D6 tasks/light-rules-evaluator/checkpoint.json\uFF08\u8BB0\u5F55\u4E0A\u6B21\u5904\u7406\u8FDB\u5EA6\uFF09
|
|
7398
|
+
2. \u626B\u63CF ${notificationsDir} \u76EE\u5F55\uFF0C\u83B7\u53D6 checkpoint \u4E4B\u540E\u7684\u65B0\u901A\u77E5
|
|
7399
|
+
3. \u626B\u63CF tasks/ \u76EE\u5F55\uFF0C\u8BFB\u53D6\u6240\u6709 type=light-rule \u4E14 enabled=true \u7684 meta.json
|
|
7400
|
+
4. \u5BF9\u6BCF\u6761\u65B0\u901A\u77E5\uFF0C\u9010\u4E00\u5224\u65AD\u662F\u5426\u547D\u4E2D\u6BCF\u6761\u89C4\u5219\u7684 description\uFF08\u8BED\u4E49\u5339\u914D\uFF09
|
|
7401
|
+
5. \u547D\u4E2D\u65F6\uFF1A\u4EE5\u8BE5\u89C4\u5219\u7684 segments \u548C repeat_times \u8C03\u7528 light_control \u5DE5\u5177
|
|
7402
|
+
6. \u66F4\u65B0 checkpoint.json\uFF0C\u8BB0\u5F55\u5DF2\u5904\u7406\u5230\u7684\u6700\u65B0\u901A\u77E5\u4F4D\u7F6E
|
|
7403
|
+
7. \u82E5\u65E0\u65B0\u901A\u77E5\u6216\u65E0 enabled \u89C4\u5219\uFF1A\u8F93\u51FA NO_CHANGE\uFF0C\u76F4\u63A5\u7ED3\u675F`;
|
|
7404
|
+
}
|
|
7405
|
+
var LightRulesEvaluatorJob = class {
|
|
7406
|
+
logger;
|
|
7407
|
+
registry;
|
|
7408
|
+
subagentRunner;
|
|
7409
|
+
getNotificationsDir;
|
|
7410
|
+
/**
|
|
7411
|
+
* 记录本进程生命周期内 job 是否已确认存在。
|
|
7412
|
+
* 仅在 `ensureJobExists` 成功后置 true,避免每次 push 都做检查。
|
|
7413
|
+
*/
|
|
7414
|
+
jobEnsured = false;
|
|
7415
|
+
/**
|
|
7416
|
+
* 首次创建 job 时的并发保护。
|
|
7417
|
+
* 避免冷启动瞬间多条通知并发到达时重复调用 `cron.add`。
|
|
7418
|
+
*/
|
|
7419
|
+
ensureJobPromise = null;
|
|
7420
|
+
/**
|
|
7421
|
+
* subagent fallback 路径的并发保护。
|
|
7422
|
+
* 若评估 session 已在运行中,跳过本次触发(checkpoint 保证下次补处理)。
|
|
7423
|
+
*/
|
|
7424
|
+
subagentInFlight = false;
|
|
7425
|
+
constructor(deps) {
|
|
7426
|
+
this.logger = deps.logger;
|
|
7427
|
+
this.registry = deps.registry;
|
|
7428
|
+
this.subagentRunner = deps.subagentRunner;
|
|
7429
|
+
this.getNotificationsDir = deps.getNotificationsDir ?? (() => void 0);
|
|
7430
|
+
}
|
|
7431
|
+
/**
|
|
7432
|
+
* 通知落盘后调用。若有新增通知且存在 enabled 规则,则触发评估。
|
|
7433
|
+
*
|
|
7434
|
+
* 两条路径:
|
|
7435
|
+
* - cron 不为 null:enqueueRun("force") 入队(gateway context 路径,正常路径)
|
|
7436
|
+
* - cron 为 null:通过 subagentRunner 直接运行(HTTP Relay 路径,fallback)
|
|
7437
|
+
*
|
|
7438
|
+
* @param cron 来自 gateway context 的 CronService;HTTP 路径下为 null
|
|
7439
|
+
* @param insertedCount 本次 ingest 新落盘的通知条数(StoredNotification 去重后)
|
|
7440
|
+
*/
|
|
7441
|
+
async triggerIfNeeded(cron, insertedCount) {
|
|
7442
|
+
if (insertedCount === 0) return;
|
|
7443
|
+
if (this.registry.getEnabled().length === 0) return;
|
|
7444
|
+
if (!cron) {
|
|
7445
|
+
await this.triggerViaSubagent();
|
|
7446
|
+
return;
|
|
7447
|
+
}
|
|
7448
|
+
try {
|
|
7449
|
+
await this.ensureJobExists(cron);
|
|
7450
|
+
} catch (err2) {
|
|
7451
|
+
this.logger.warn(`light-rules-evaluator: job ensure failed: ${err2?.message ?? err2}`);
|
|
7452
|
+
return;
|
|
7453
|
+
}
|
|
7454
|
+
try {
|
|
7455
|
+
const result = await cron.enqueueRun(EVALUATOR_JOB_ID, "force");
|
|
7456
|
+
if (!result.ok) {
|
|
7457
|
+
this.logger.warn("light-rules-evaluator: enqueueRun returned ok=false");
|
|
7458
|
+
return;
|
|
7459
|
+
}
|
|
7460
|
+
if ("enqueued" in result && result.enqueued) {
|
|
7461
|
+
this.logger.info(`light-rules-evaluator: enqueued runId=${result.runId}`);
|
|
7462
|
+
} else if ("reason" in result) {
|
|
7463
|
+
this.logger.info(`light-rules-evaluator: enqueueRun skipped (${result.reason})`);
|
|
7464
|
+
}
|
|
7465
|
+
} catch (err2) {
|
|
7466
|
+
this.logger.warn(`light-rules-evaluator: enqueueRun failed: ${err2?.message ?? err2}`);
|
|
7467
|
+
}
|
|
7468
|
+
}
|
|
7469
|
+
/**
|
|
7470
|
+
* cron service 不可用时的 fallback:直接通过 subagentRunner 运行评估 session。
|
|
7471
|
+
*
|
|
7472
|
+
* 并发保护:若上一次 subagent 运行尚未完成,本次跳过。
|
|
7473
|
+
* checkpoint 保证即使本次跳过,下次触发时会处理所有积压通知。
|
|
7474
|
+
*/
|
|
7475
|
+
async triggerViaSubagent() {
|
|
7476
|
+
if (!this.subagentRunner) {
|
|
7477
|
+
this.logger.warn(
|
|
7478
|
+
"light-rules-evaluator: cron service unavailable and no subagent fallback configured; notifications ingested via HTTP will not trigger light rules until an agent session is active"
|
|
7479
|
+
);
|
|
7480
|
+
return;
|
|
7481
|
+
}
|
|
7482
|
+
if (this.subagentInFlight) {
|
|
7483
|
+
this.logger.info("light-rules-evaluator: subagent run in-flight, skipping this trigger");
|
|
7484
|
+
return;
|
|
7485
|
+
}
|
|
7486
|
+
const notificationsDir = this.getNotificationsDir();
|
|
7487
|
+
if (!notificationsDir) {
|
|
7488
|
+
this.logger.warn("light-rules-evaluator: notifications dir not ready, skipping subagent trigger");
|
|
7489
|
+
return;
|
|
7490
|
+
}
|
|
7491
|
+
this.subagentInFlight = true;
|
|
7492
|
+
try {
|
|
7493
|
+
const result = await this.subagentRunner.run({
|
|
7494
|
+
sessionKey: EVALUATOR_SUBAGENT_SESSION_KEY,
|
|
7495
|
+
message: buildEvaluatorJobMessage(notificationsDir),
|
|
7496
|
+
deliver: false,
|
|
7497
|
+
idempotencyKey: `${EVALUATOR_SUBAGENT_SESSION_KEY}-${Date.now()}`
|
|
7498
|
+
});
|
|
7499
|
+
this.logger.info(`light-rules-evaluator: subagent triggered runId=${result.runId}`);
|
|
7500
|
+
} catch (err2) {
|
|
7501
|
+
this.logger.warn(`light-rules-evaluator: subagent trigger failed: ${err2?.message ?? err2}`);
|
|
7502
|
+
} finally {
|
|
7503
|
+
this.subagentInFlight = false;
|
|
7504
|
+
}
|
|
7505
|
+
}
|
|
7506
|
+
/**
|
|
7507
|
+
* 按需创建 `light-rules-evaluator` job。
|
|
7508
|
+
* 若 job 已存在(内存缓存或 cron store),直接返回;否则调用 `cron.add`。
|
|
7509
|
+
*/
|
|
7510
|
+
async ensureJobExists(cron) {
|
|
7511
|
+
if (this.jobEnsured) return;
|
|
7512
|
+
if (!this.ensureJobPromise) {
|
|
7513
|
+
this.ensureJobPromise = this.createJobIfNeeded(cron).finally(() => {
|
|
7514
|
+
this.ensureJobPromise = null;
|
|
7515
|
+
});
|
|
7516
|
+
}
|
|
7517
|
+
await this.ensureJobPromise;
|
|
7518
|
+
}
|
|
7519
|
+
async createJobIfNeeded(cron) {
|
|
7520
|
+
if (cron.getJob(EVALUATOR_JOB_ID)) {
|
|
7521
|
+
this.jobEnsured = true;
|
|
7522
|
+
return;
|
|
7523
|
+
}
|
|
7524
|
+
try {
|
|
7525
|
+
await cron.add({
|
|
7526
|
+
id: EVALUATOR_JOB_ID,
|
|
7527
|
+
name: "\u706F\u6548\u89C4\u5219\u8BC4\u4F30",
|
|
7528
|
+
description: "\u4E8B\u4EF6\u9A71\u52A8\uFF1A\u901A\u77E5\u5230\u8FBE\u65F6\u8BC4\u4F30\u6240\u6709 enabled \u706F\u6548\u89C4\u5219\uFF0C\u547D\u4E2D\u5219\u8C03\u7528 light_control \u89E6\u53D1\u706F\u6548",
|
|
7529
|
+
enabled: true,
|
|
7530
|
+
schedule: { kind: "cron", expr: FALLBACK_CRON_EXPR },
|
|
7531
|
+
sessionTarget: "isolated",
|
|
7532
|
+
wakeMode: "now",
|
|
7533
|
+
payload: {
|
|
7534
|
+
kind: "agentTurn",
|
|
7535
|
+
message: buildEvaluatorJobMessage(this.getNotificationsDir() ?? "notifications")
|
|
7536
|
+
}
|
|
7537
|
+
});
|
|
7538
|
+
this.logger.info("light-rules-evaluator: job created");
|
|
7539
|
+
} catch (err2) {
|
|
7540
|
+
if (!cron.getJob(EVALUATOR_JOB_ID)) {
|
|
7541
|
+
throw err2;
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
this.jobEnsured = true;
|
|
7545
|
+
}
|
|
7546
|
+
};
|
|
7547
|
+
|
|
7548
|
+
// src/light-rules/migration.ts
|
|
7549
|
+
var import_node_fs6 = require("fs");
|
|
7550
|
+
var import_node_path5 = require("path");
|
|
7551
|
+
var NO_MATCH_FETCH_PY = `#!/usr/bin/env python3
|
|
7552
|
+
# \u6B64\u6587\u4EF6\u7531\u8FC1\u79FB\u5DE5\u5177\u751F\u6210\u3002
|
|
7553
|
+
# \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
|
|
7554
|
+
print("NO_MATCH")
|
|
7555
|
+
`;
|
|
7556
|
+
function normalizeScriptText(text) {
|
|
7557
|
+
return text.replace(/\r\n/g, "\n").trim();
|
|
7558
|
+
}
|
|
7559
|
+
function resolveTasksDir(ctx) {
|
|
7560
|
+
if (ctx.workspaceDir) return (0, import_node_path5.join)(ctx.workspaceDir, "tasks");
|
|
7561
|
+
if (ctx.stateDir) {
|
|
7562
|
+
const inferredWorkspaceDir = (0, import_node_path5.join)(ctx.stateDir, "workspace");
|
|
7563
|
+
if ((0, import_node_fs6.existsSync)(inferredWorkspaceDir)) return (0, import_node_path5.join)(inferredWorkspaceDir, "tasks");
|
|
7564
|
+
return (0, import_node_path5.join)(ctx.stateDir, "tasks");
|
|
7565
|
+
}
|
|
7566
|
+
return null;
|
|
7567
|
+
}
|
|
7568
|
+
function migrateLegacyLightRuleTasks(ctx, logger) {
|
|
7569
|
+
const tasksDir3 = resolveTasksDir(ctx);
|
|
7570
|
+
if (!tasksDir3 || !(0, import_node_fs6.existsSync)(tasksDir3)) return;
|
|
7571
|
+
try {
|
|
7572
|
+
for (const entry of (0, import_node_fs6.readdirSync)(tasksDir3, { withFileTypes: true })) {
|
|
7573
|
+
if (!entry.isDirectory()) continue;
|
|
7574
|
+
migrateTaskDir((0, import_node_path5.join)(tasksDir3, String(entry.name)), logger);
|
|
7575
|
+
}
|
|
7576
|
+
} catch (err2) {
|
|
7577
|
+
logger.warn(`migration: failed to read tasks dir: ${err2?.message}`);
|
|
7578
|
+
}
|
|
7579
|
+
}
|
|
7580
|
+
function migrateTaskDir(taskDir, logger) {
|
|
7581
|
+
const metaPath = (0, import_node_path5.join)(taskDir, "meta.json");
|
|
7582
|
+
if (!(0, import_node_fs6.existsSync)(metaPath)) return;
|
|
7583
|
+
let meta;
|
|
7584
|
+
try {
|
|
7585
|
+
meta = JSON.parse((0, import_node_fs6.readFileSync)(metaPath, "utf-8"));
|
|
7586
|
+
} catch {
|
|
7587
|
+
return;
|
|
7588
|
+
}
|
|
7589
|
+
if (meta.type !== "light-rule") return;
|
|
7590
|
+
const name = typeof meta.name === "string" ? meta.name : taskDir;
|
|
7591
|
+
mergeMatchRulesIntoDescription(meta, name, metaPath, logger);
|
|
7592
|
+
replaceFetchPy(taskDir, name, logger);
|
|
7593
|
+
for (const filename of ["README.md", "checkpoint.json"]) {
|
|
7594
|
+
removeFile((0, import_node_path5.join)(taskDir, filename), name, filename, logger);
|
|
7595
|
+
}
|
|
7596
|
+
}
|
|
7597
|
+
function mergeMatchRulesIntoDescription(meta, name, metaPath, logger) {
|
|
7598
|
+
const matchRules = meta.matchRules;
|
|
7599
|
+
if (!matchRules || typeof matchRules !== "object") return;
|
|
7600
|
+
const rules = matchRules;
|
|
7601
|
+
const parts = [];
|
|
7602
|
+
if (rules.appName) parts.push(`app=${rules.appName}`);
|
|
7603
|
+
if (rules.senderKeywords?.length) {
|
|
7604
|
+
parts.push(`\u53D1\u4EF6\u4EBA\u5173\u952E\u8BCD=${rules.senderKeywords.join("\u3001")}`);
|
|
7605
|
+
}
|
|
7606
|
+
if (rules.contentKeywords?.length) {
|
|
7607
|
+
parts.push(`\u5185\u5BB9\u5173\u952E\u8BCD=${rules.contentKeywords.join("\u3001")}`);
|
|
7608
|
+
}
|
|
7609
|
+
if (parts.length > 0) {
|
|
7610
|
+
const existing = typeof meta.description === "string" ? meta.description.trim() : "";
|
|
7611
|
+
meta.description = existing ? `${existing}\u3002\u5339\u914D\u89C4\u5219\uFF1A${parts.join("\uFF0C")}` : `\u5339\u914D\u89C4\u5219\uFF1A${parts.join("\uFF0C")}`;
|
|
7612
|
+
}
|
|
7613
|
+
delete meta.matchRules;
|
|
7614
|
+
try {
|
|
7615
|
+
(0, import_node_fs6.writeFileSync)(metaPath, JSON.stringify(meta, null, 2), "utf-8");
|
|
7616
|
+
logger.info(`migration: merged matchRules into description for light rule: ${name}`);
|
|
7617
|
+
} catch (err2) {
|
|
7618
|
+
logger.warn(`migration: failed to update meta.json for ${name}: ${err2?.message}`);
|
|
7619
|
+
}
|
|
7620
|
+
}
|
|
7621
|
+
function replaceFetchPy(taskDir, name, logger) {
|
|
7622
|
+
const fetchPyPath = (0, import_node_path5.join)(taskDir, "fetch.py");
|
|
7623
|
+
if (!(0, import_node_fs6.existsSync)(fetchPyPath)) return;
|
|
7624
|
+
try {
|
|
7625
|
+
const existing = (0, import_node_fs6.readFileSync)(fetchPyPath, "utf-8");
|
|
7626
|
+
if (normalizeScriptText(existing) === normalizeScriptText(NO_MATCH_FETCH_PY)) {
|
|
7627
|
+
return;
|
|
7628
|
+
}
|
|
7629
|
+
(0, import_node_fs6.writeFileSync)(fetchPyPath, NO_MATCH_FETCH_PY, "utf-8");
|
|
7630
|
+
logger.info(`migration: replaced fetch.py with NO_MATCH placeholder for ${name}`);
|
|
7631
|
+
} catch (err2) {
|
|
7632
|
+
logger.warn(`migration: failed to replace fetch.py for ${name}: ${err2?.message}`);
|
|
7633
|
+
}
|
|
7634
|
+
}
|
|
7635
|
+
function removeFile(filePath, ruleName, filename, logger) {
|
|
7636
|
+
if (!(0, import_node_fs6.existsSync)(filePath)) return;
|
|
7637
|
+
try {
|
|
7638
|
+
(0, import_node_fs6.rmSync)(filePath);
|
|
7639
|
+
logger.info(`migration: removed ${filename} for light rule: ${ruleName}`);
|
|
7640
|
+
} catch (err2) {
|
|
7641
|
+
logger.warn(`migration: failed to remove ${filename} for ${ruleName}: ${err2?.message}`);
|
|
7642
|
+
}
|
|
7643
|
+
}
|
|
7644
|
+
|
|
7645
|
+
// src/plugin/auto-update.ts
|
|
7646
|
+
init_env();
|
|
7647
|
+
|
|
7648
|
+
// src/update/channel.ts
|
|
7649
|
+
function resolveUpdateChannel(params) {
|
|
7650
|
+
if (params.configuredChannel) {
|
|
7651
|
+
return params.configuredChannel;
|
|
7652
|
+
}
|
|
7653
|
+
if (params.currentVersion.includes("-")) {
|
|
7654
|
+
return "beta";
|
|
7655
|
+
}
|
|
7656
|
+
return params.envName === "development" ? "beta" : "latest";
|
|
7657
|
+
}
|
|
7658
|
+
|
|
7230
7659
|
// src/update/index.ts
|
|
7231
7660
|
var import_node_path10 = require("path");
|
|
7232
7661
|
|
|
@@ -7360,8 +7789,8 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7360
7789
|
{ timeoutMs: 3e4 }
|
|
7361
7790
|
);
|
|
7362
7791
|
if (tarResult.code !== 0) {
|
|
7363
|
-
const
|
|
7364
|
-
return { success: false, message: `\u89E3\u538B\u5931\u8D25: ${
|
|
7792
|
+
const err2 = tarResult.stderr || tarResult.stdout || "unknown error";
|
|
7793
|
+
return { success: false, message: `\u89E3\u538B\u5931\u8D25: ${err2}` };
|
|
7365
7794
|
}
|
|
7366
7795
|
(0, import_node_fs10.mkdirSync)((0, import_node_path9.dirname)(targetDir), { recursive: true });
|
|
7367
7796
|
try {
|
|
@@ -7373,8 +7802,8 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7373
7802
|
(0, import_node_fs10.renameSync)(stagingDir, targetDir);
|
|
7374
7803
|
try {
|
|
7375
7804
|
await updateConfigRecord2(version, tgzUrl);
|
|
7376
|
-
} catch (
|
|
7377
|
-
logger.warn(`\u914D\u7F6E\u8BB0\u5F55\u66F4\u65B0\u5931\u8D25\uFF08\u63D2\u4EF6\u6587\u4EF6\u5DF2\u5C31\u4F4D\uFF09: ${String(
|
|
7805
|
+
} catch (err2) {
|
|
7806
|
+
logger.warn(`\u914D\u7F6E\u8BB0\u5F55\u66F4\u65B0\u5931\u8D25\uFF08\u63D2\u4EF6\u6587\u4EF6\u5DF2\u5C31\u4F4D\uFF09: ${String(err2)}`);
|
|
7378
7807
|
}
|
|
7379
7808
|
if (backupDir) {
|
|
7380
7809
|
try {
|
|
@@ -7385,7 +7814,7 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7385
7814
|
const msg = `\u5DF2\u66F4\u65B0\u5230 ${version}\uFF0C\u8BF7\u91CD\u542F gateway \u751F\u6548`;
|
|
7386
7815
|
logger.info(msg);
|
|
7387
7816
|
return { success: true, message: msg };
|
|
7388
|
-
} catch (
|
|
7817
|
+
} catch (err2) {
|
|
7389
7818
|
if (backupDir) {
|
|
7390
7819
|
try {
|
|
7391
7820
|
(0, import_node_fs10.rmSync)(targetDir, { force: true, recursive: true });
|
|
@@ -7395,7 +7824,7 @@ async function executeUpdate(version, runCommand, logger, targetDir, updateConfi
|
|
|
7395
7824
|
logger.error(`\u56DE\u6EDA\u5931\u8D25: ${String(rollbackErr)}`);
|
|
7396
7825
|
}
|
|
7397
7826
|
}
|
|
7398
|
-
const errMsg = `\u66F4\u65B0\u6267\u884C\u5F02\u5E38: ${String(
|
|
7827
|
+
const errMsg = `\u66F4\u65B0\u6267\u884C\u5F02\u5E38: ${String(err2)}`;
|
|
7399
7828
|
logger.error(errMsg);
|
|
7400
7829
|
return { success: false, message: errMsg };
|
|
7401
7830
|
} finally {
|
|
@@ -8064,216 +8493,6 @@ init_credentials();
|
|
|
8064
8493
|
|
|
8065
8494
|
// src/light/sender.ts
|
|
8066
8495
|
var import_node_crypto2 = require("crypto");
|
|
8067
|
-
|
|
8068
|
-
// src/light/protocol.ts
|
|
8069
|
-
var MAX_LIGHT_SEGMENTS = 12;
|
|
8070
|
-
var PROTOCOL_DIGITS = [
|
|
8071
|
-
"\x80",
|
|
8072
|
-
"\x81",
|
|
8073
|
-
"\x82",
|
|
8074
|
-
"\x83",
|
|
8075
|
-
"\x84",
|
|
8076
|
-
"\x91",
|
|
8077
|
-
"\x92",
|
|
8078
|
-
"\x93",
|
|
8079
|
-
"\x94",
|
|
8080
|
-
"\x95",
|
|
8081
|
-
"\x96",
|
|
8082
|
-
"\x97"
|
|
8083
|
-
];
|
|
8084
|
-
var LED_SEPARATOR_ONCE = "\x9A";
|
|
8085
|
-
var LED_SEPARATOR_LOOP = "\x9B";
|
|
8086
|
-
var DURATION_STEPS_S = [0.5, 1, 2, 3, 5, 6, 8, 16, 24, 32, 48];
|
|
8087
|
-
var INTERVAL_STEPS_MS = [50, 100, 200, 300, 500, 600, 800, 1600, 2400, 3200, 4800];
|
|
8088
|
-
var BREATH_STEPS_MS = [1040, 1560, 2080, 2600, 3100, 4160];
|
|
8089
|
-
var BRIGHTNESS_STEPS = [32, 64, 96, 128, 192, 255];
|
|
8090
|
-
var COLOR_STEPS = [0, 32, 64, 128, 192, 255];
|
|
8091
|
-
var BACKGROUND_BRIGHTNESS_STEPS = [0, 32, 64, 96, 128, 192, 255];
|
|
8092
|
-
var MULTI_CHANNEL_COLOR_COEFFICIENTS = { r: 1, g: 0.25, b: 0.25 };
|
|
8093
|
-
var PURE_WHITE_COLOR_COEFFICIENTS = { r: 1, g: 0.35, b: 0.35 };
|
|
8094
|
-
var MODE_TO_INDEX = {
|
|
8095
|
-
wave: 0,
|
|
8096
|
-
breath: 1,
|
|
8097
|
-
strobe: 2,
|
|
8098
|
-
steady: 3,
|
|
8099
|
-
wave_rainbow: 4,
|
|
8100
|
-
pixel_frame: 5
|
|
8101
|
-
};
|
|
8102
|
-
function buildLightEffectApnsBody(segments, repeatInput) {
|
|
8103
|
-
assertSegmentCount(segments);
|
|
8104
|
-
assertSegmentsValid(segments);
|
|
8105
|
-
const repeatTimes = normalizeRepeatTimes(repeatInput);
|
|
8106
|
-
assertAncsRepeatTimes(repeatTimes);
|
|
8107
|
-
const visibleText = summarizeSegments(segments);
|
|
8108
|
-
const separator = repeatTimes === 0 ? LED_SEPARATOR_LOOP : LED_SEPARATOR_ONCE;
|
|
8109
|
-
const payload = segments.map((segment) => encodeSegment(segment)).join("");
|
|
8110
|
-
return `${visibleText}${separator}${payload}`;
|
|
8111
|
-
}
|
|
8112
|
-
function assertSegmentCount(segments) {
|
|
8113
|
-
if (segments.length < 1 || segments.length > MAX_LIGHT_SEGMENTS) {
|
|
8114
|
-
throw new Error(`light_control supports 1-${MAX_LIGHT_SEGMENTS} segments`);
|
|
8115
|
-
}
|
|
8116
|
-
}
|
|
8117
|
-
function summarizeSegments(segments) {
|
|
8118
|
-
const modeDesc = segments.map((segment) => segment.mode).join("+");
|
|
8119
|
-
return `Effect: ${modeDesc} (${segments.length} segment${segments.length > 1 ? "s" : ""})`;
|
|
8120
|
-
}
|
|
8121
|
-
function assertSegmentsValid(segments) {
|
|
8122
|
-
const validation = validateSegments(segments);
|
|
8123
|
-
if (!validation.valid) {
|
|
8124
|
-
throw new Error(
|
|
8125
|
-
validation.errors.map((error) => `${error.field}: ${error.message}`).join("; ")
|
|
8126
|
-
);
|
|
8127
|
-
}
|
|
8128
|
-
}
|
|
8129
|
-
function encodeSegment(segment) {
|
|
8130
|
-
const common = [
|
|
8131
|
-
MODE_TO_INDEX[segment.mode],
|
|
8132
|
-
quantizeDuration(segment.duration_s)
|
|
8133
|
-
];
|
|
8134
|
-
let values;
|
|
8135
|
-
switch (segment.mode) {
|
|
8136
|
-
case "wave":
|
|
8137
|
-
case "wave_rainbow":
|
|
8138
|
-
const color = normalizeProtocolColor(segment.color);
|
|
8139
|
-
const background = normalizeProtocolColor(segment.background);
|
|
8140
|
-
values = [
|
|
8141
|
-
...common,
|
|
8142
|
-
quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),
|
|
8143
|
-
quantizeBrightnessValue(segment.brightness ?? 0),
|
|
8144
|
-
quantize(color.r, COLOR_STEPS),
|
|
8145
|
-
quantize(color.g, COLOR_STEPS),
|
|
8146
|
-
quantize(color.b, COLOR_STEPS),
|
|
8147
|
-
segment.direction === "rtl" ? 1 : 0,
|
|
8148
|
-
quantizeWindow(segment.window ?? 2),
|
|
8149
|
-
quantize(background.r, COLOR_STEPS),
|
|
8150
|
-
quantize(background.g, COLOR_STEPS),
|
|
8151
|
-
quantize(background.b, COLOR_STEPS),
|
|
8152
|
-
quantize(segment.background?.brightness ?? 0, BACKGROUND_BRIGHTNESS_STEPS)
|
|
8153
|
-
];
|
|
8154
|
-
break;
|
|
8155
|
-
case "breath":
|
|
8156
|
-
const breathColor = normalizeProtocolColor(segment.color);
|
|
8157
|
-
values = [
|
|
8158
|
-
...common,
|
|
8159
|
-
quantizeBreathRiseFall(segment.breath_timing?.rise_ms),
|
|
8160
|
-
quantizeBreathHoldOff(segment.breath_timing?.hold_ms),
|
|
8161
|
-
quantizeBreathRiseFall(segment.breath_timing?.fall_ms),
|
|
8162
|
-
quantizeBreathHoldOff(segment.breath_timing?.off_ms),
|
|
8163
|
-
quantizeBrightnessValue(segment.brightness ?? 0),
|
|
8164
|
-
quantize(breathColor.r, COLOR_STEPS),
|
|
8165
|
-
quantize(breathColor.g, COLOR_STEPS),
|
|
8166
|
-
quantize(breathColor.b, COLOR_STEPS)
|
|
8167
|
-
];
|
|
8168
|
-
break;
|
|
8169
|
-
case "strobe":
|
|
8170
|
-
const strobeColor = normalizeProtocolColor(segment.color);
|
|
8171
|
-
values = [
|
|
8172
|
-
...common,
|
|
8173
|
-
quantize(segment.interval_ms ?? 200, INTERVAL_STEPS_MS),
|
|
8174
|
-
quantizeBrightnessValue(segment.brightness ?? 0),
|
|
8175
|
-
quantize(strobeColor.r, COLOR_STEPS),
|
|
8176
|
-
quantize(strobeColor.g, COLOR_STEPS),
|
|
8177
|
-
quantize(strobeColor.b, COLOR_STEPS)
|
|
8178
|
-
];
|
|
8179
|
-
break;
|
|
8180
|
-
case "steady":
|
|
8181
|
-
const steadyColor = normalizeProtocolColor(segment.color);
|
|
8182
|
-
values = [
|
|
8183
|
-
...common,
|
|
8184
|
-
quantizeBrightnessValue(segment.brightness ?? 0),
|
|
8185
|
-
quantize(steadyColor.r, COLOR_STEPS),
|
|
8186
|
-
quantize(steadyColor.g, COLOR_STEPS),
|
|
8187
|
-
quantize(steadyColor.b, COLOR_STEPS)
|
|
8188
|
-
];
|
|
8189
|
-
break;
|
|
8190
|
-
case "pixel_frame":
|
|
8191
|
-
values = encodePixelFrameValues(common, segment);
|
|
8192
|
-
break;
|
|
8193
|
-
}
|
|
8194
|
-
return values.map((value) => PROTOCOL_DIGITS[value]).join("");
|
|
8195
|
-
}
|
|
8196
|
-
function encodePixelFrameValues(common, segment) {
|
|
8197
|
-
const pixels = segment.pixels ?? [];
|
|
8198
|
-
return [
|
|
8199
|
-
...common,
|
|
8200
|
-
pixels.length - 1,
|
|
8201
|
-
...pixels.flatMap((pixel) => {
|
|
8202
|
-
const color = normalizeProtocolColor(pixel.color);
|
|
8203
|
-
return [
|
|
8204
|
-
pixel.index,
|
|
8205
|
-
quantize(color.r, COLOR_STEPS),
|
|
8206
|
-
quantize(color.g, COLOR_STEPS),
|
|
8207
|
-
quantize(color.b, COLOR_STEPS),
|
|
8208
|
-
quantizeBrightnessValue(pixel.brightness)
|
|
8209
|
-
];
|
|
8210
|
-
})
|
|
8211
|
-
];
|
|
8212
|
-
}
|
|
8213
|
-
function normalizeProtocolColor(color) {
|
|
8214
|
-
const normalized = {
|
|
8215
|
-
r: color?.r ?? 0,
|
|
8216
|
-
g: color?.g ?? 0,
|
|
8217
|
-
b: color?.b ?? 0
|
|
8218
|
-
};
|
|
8219
|
-
if (isPureWhiteProtocolColor(normalized)) {
|
|
8220
|
-
return applyProtocolColorCoefficients(normalized, PURE_WHITE_COLOR_COEFFICIENTS);
|
|
8221
|
-
}
|
|
8222
|
-
if (countActiveProtocolColorChannels(normalized) <= 1) {
|
|
8223
|
-
return normalized;
|
|
8224
|
-
}
|
|
8225
|
-
return applyProtocolColorCoefficients(normalized, MULTI_CHANNEL_COLOR_COEFFICIENTS);
|
|
8226
|
-
}
|
|
8227
|
-
function countActiveProtocolColorChannels(color) {
|
|
8228
|
-
return Number(color.r > 0) + Number(color.g > 0) + Number(color.b > 0);
|
|
8229
|
-
}
|
|
8230
|
-
function isPureWhiteProtocolColor(color) {
|
|
8231
|
-
return color.r === 255 && color.g === 255 && color.b === 255;
|
|
8232
|
-
}
|
|
8233
|
-
function applyProtocolColorCoefficients(color, coefficients) {
|
|
8234
|
-
return {
|
|
8235
|
-
r: scaleProtocolColorChannel(color.r, coefficients.r),
|
|
8236
|
-
g: scaleProtocolColorChannel(color.g, coefficients.g),
|
|
8237
|
-
b: scaleProtocolColorChannel(color.b, coefficients.b)
|
|
8238
|
-
};
|
|
8239
|
-
}
|
|
8240
|
-
function scaleProtocolColorChannel(value, coefficient) {
|
|
8241
|
-
return Math.max(0, Math.min(255, Math.round(value * coefficient)));
|
|
8242
|
-
}
|
|
8243
|
-
function quantize(value, steps) {
|
|
8244
|
-
let bestIndex = 0;
|
|
8245
|
-
let bestDistance = Number.POSITIVE_INFINITY;
|
|
8246
|
-
for (const [index, step] of steps.entries()) {
|
|
8247
|
-
const distance = Math.abs(value - step);
|
|
8248
|
-
if (distance < bestDistance) {
|
|
8249
|
-
bestIndex = index;
|
|
8250
|
-
bestDistance = distance;
|
|
8251
|
-
}
|
|
8252
|
-
}
|
|
8253
|
-
return bestIndex;
|
|
8254
|
-
}
|
|
8255
|
-
function quantizeDuration(duration_s) {
|
|
8256
|
-
if (duration_s === 0) return 11;
|
|
8257
|
-
return quantize(duration_s, DURATION_STEPS_S);
|
|
8258
|
-
}
|
|
8259
|
-
function quantizeBrightnessValue(brightness) {
|
|
8260
|
-
if (brightness === 0) return 11;
|
|
8261
|
-
return quantize(brightness, BRIGHTNESS_STEPS);
|
|
8262
|
-
}
|
|
8263
|
-
function quantizeBreathRiseFall(value) {
|
|
8264
|
-
return quantize(value ?? 1040, BREATH_STEPS_MS);
|
|
8265
|
-
}
|
|
8266
|
-
function quantizeBreathHoldOff(value) {
|
|
8267
|
-
if (value === 0) {
|
|
8268
|
-
return 5;
|
|
8269
|
-
}
|
|
8270
|
-
return quantize(value ?? 1040, BREATH_STEPS_MS.slice(0, 5));
|
|
8271
|
-
}
|
|
8272
|
-
function quantizeWindow(value) {
|
|
8273
|
-
return value - 1;
|
|
8274
|
-
}
|
|
8275
|
-
|
|
8276
|
-
// src/light/sender.ts
|
|
8277
8496
|
init_env();
|
|
8278
8497
|
async function sendLightEffect(apiKey, segments, logger, repeatInput, reason) {
|
|
8279
8498
|
const apiUrl = getEnvUrls().lightApiUrl;
|
|
@@ -8377,11 +8596,23 @@ function resolveConfigPath2() {
|
|
|
8377
8596
|
if (fromEnv) return fromEnv;
|
|
8378
8597
|
return (0, import_node_path13.join)((0, import_node_os2.homedir)(), ".openclaw", "openclaw.json");
|
|
8379
8598
|
}
|
|
8599
|
+
var LIGHT_TOOLS = [
|
|
8600
|
+
"light_control",
|
|
8601
|
+
"lightrules.list",
|
|
8602
|
+
"lightrules.create",
|
|
8603
|
+
"lightrules.update",
|
|
8604
|
+
"lightrules.delete"
|
|
8605
|
+
];
|
|
8380
8606
|
function upsertLightControlAlsoAllow(cfg) {
|
|
8381
8607
|
if (!isObject(cfg.tools)) cfg.tools = {};
|
|
8382
8608
|
const toolsAlsoAllow = ensureArray(cfg.tools, "alsoAllow");
|
|
8383
|
-
|
|
8384
|
-
|
|
8609
|
+
let globalChanged = false;
|
|
8610
|
+
for (const tool of LIGHT_TOOLS) {
|
|
8611
|
+
if (!toolsAlsoAllow.includes(tool)) {
|
|
8612
|
+
toolsAlsoAllow.push(tool);
|
|
8613
|
+
globalChanged = true;
|
|
8614
|
+
}
|
|
8615
|
+
}
|
|
8385
8616
|
if (!isObject(cfg.agents)) cfg.agents = {};
|
|
8386
8617
|
const agents = cfg.agents;
|
|
8387
8618
|
const list = ensureArray(agents, "list");
|
|
@@ -8394,12 +8625,14 @@ function upsertLightControlAlsoAllow(cfg) {
|
|
|
8394
8625
|
}
|
|
8395
8626
|
if (!isObject(mainAgent.tools)) mainAgent.tools = {};
|
|
8396
8627
|
const mainAlsoAllow = ensureArray(mainAgent.tools, "alsoAllow");
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8628
|
+
let mainAgentChanged = false;
|
|
8629
|
+
for (const tool of LIGHT_TOOLS) {
|
|
8630
|
+
if (!mainAlsoAllow.includes(tool)) {
|
|
8631
|
+
mainAlsoAllow.push(tool);
|
|
8632
|
+
mainAgentChanged = true;
|
|
8633
|
+
}
|
|
8634
|
+
}
|
|
8635
|
+
return { globalChanged, mainAgentChanged };
|
|
8403
8636
|
}
|
|
8404
8637
|
function registerLightSetupTools(light) {
|
|
8405
8638
|
light.command("setup").description("\u81EA\u52A8\u653E\u884C light_control\uFF08\u5199\u5165 tools.alsoAllow \u4E0E agents.main.tools.alsoAllow\uFF09").action(() => {
|
|
@@ -8412,15 +8645,15 @@ function registerLightSetupTools(light) {
|
|
|
8412
8645
|
const raw = (0, import_node_fs14.readFileSync)(configPath, "utf-8");
|
|
8413
8646
|
const parsed = JSON.parse(raw);
|
|
8414
8647
|
if (isObject(parsed)) cfg = parsed;
|
|
8415
|
-
} catch (
|
|
8416
|
-
exitError("CONFIG_INVALID", `\u8BFB\u53D6/\u89E3\u6790\u914D\u7F6E\u5931\u8D25: ${
|
|
8648
|
+
} catch (err2) {
|
|
8649
|
+
exitError("CONFIG_INVALID", `\u8BFB\u53D6/\u89E3\u6790\u914D\u7F6E\u5931\u8D25: ${err2?.message ?? String(err2)}`);
|
|
8417
8650
|
}
|
|
8418
8651
|
const result = upsertLightControlAlsoAllow(cfg);
|
|
8419
8652
|
try {
|
|
8420
8653
|
(0, import_node_fs14.mkdirSync)((0, import_node_path13.dirname)(configPath), { recursive: true });
|
|
8421
8654
|
(0, import_node_fs14.writeFileSync)(configPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
|
|
8422
|
-
} catch (
|
|
8423
|
-
exitError("WRITE_FAILED", `\u5199\u5165\u914D\u7F6E\u5931\u8D25: ${
|
|
8655
|
+
} catch (err2) {
|
|
8656
|
+
exitError("WRITE_FAILED", `\u5199\u5165\u914D\u7F6E\u5931\u8D25: ${err2?.message ?? String(err2)}`);
|
|
8424
8657
|
}
|
|
8425
8658
|
output({
|
|
8426
8659
|
ok: true,
|
|
@@ -8488,9 +8721,9 @@ function registerTunnelStatus(ntf, ctx) {
|
|
|
8488
8721
|
"\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"
|
|
8489
8722
|
);
|
|
8490
8723
|
}
|
|
8491
|
-
const
|
|
8724
|
+
const ok2 = status.state === "connected";
|
|
8492
8725
|
output({
|
|
8493
|
-
ok,
|
|
8726
|
+
ok: ok2,
|
|
8494
8727
|
tunnelUrl,
|
|
8495
8728
|
connection: {
|
|
8496
8729
|
state: status.state,
|
|
@@ -8500,7 +8733,7 @@ function registerTunnelStatus(ntf, ctx) {
|
|
|
8500
8733
|
},
|
|
8501
8734
|
message: formatMessage(status)
|
|
8502
8735
|
});
|
|
8503
|
-
if (!
|
|
8736
|
+
if (!ok2) process.exit(1);
|
|
8504
8737
|
});
|
|
8505
8738
|
}
|
|
8506
8739
|
|
|
@@ -8982,9 +9215,9 @@ async function runDoctor(ctx, json, fix) {
|
|
|
8982
9215
|
await issue.fix();
|
|
8983
9216
|
log(`\x1B[32m\u2705\x1B[0m ${issue.title} \u2192 ${issue.fixDescription}`);
|
|
8984
9217
|
fixed++;
|
|
8985
|
-
} catch (
|
|
9218
|
+
} catch (err2) {
|
|
8986
9219
|
log(
|
|
8987
|
-
`\x1B[31m\u274C\x1B[0m ${issue.title} \u4FEE\u590D\u5931\u8D25: ${
|
|
9220
|
+
`\x1B[31m\u274C\x1B[0m ${issue.title} \u4FEE\u590D\u5931\u8D25: ${err2?.message ?? String(err2)}`
|
|
8988
9221
|
);
|
|
8989
9222
|
}
|
|
8990
9223
|
}
|
|
@@ -9214,8 +9447,8 @@ async function runUpdate(ctx, opts) {
|
|
|
9214
9447
|
let latest;
|
|
9215
9448
|
try {
|
|
9216
9449
|
latest = (await fetchText(`${BASE_URL2}/${channel}`)).trim();
|
|
9217
|
-
} catch (
|
|
9218
|
-
const msg = `\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C: ${
|
|
9450
|
+
} catch (err2) {
|
|
9451
|
+
const msg = `\u65E0\u6CD5\u83B7\u53D6\u6700\u65B0\u7248\u672C: ${err2?.message ?? String(err2)}`;
|
|
9219
9452
|
if (json) {
|
|
9220
9453
|
output({ ok: false, error: { code: "FETCH_FAILED", message: msg } });
|
|
9221
9454
|
process.exit(1);
|
|
@@ -9239,8 +9472,8 @@ async function runUpdate(ctx, opts) {
|
|
|
9239
9472
|
let installScript;
|
|
9240
9473
|
try {
|
|
9241
9474
|
installScript = await fetchText(`${BASE_URL2}/install-core.mjs`);
|
|
9242
|
-
} catch (
|
|
9243
|
-
const msg = `\u4E0B\u8F7D\u5B89\u88C5\u811A\u672C\u5931\u8D25: ${
|
|
9475
|
+
} catch (err2) {
|
|
9476
|
+
const msg = `\u4E0B\u8F7D\u5B89\u88C5\u811A\u672C\u5931\u8D25: ${err2?.message ?? String(err2)}`;
|
|
9244
9477
|
if (json) {
|
|
9245
9478
|
output({ ok: false, error: { code: "DOWNLOAD_FAILED", message: msg } });
|
|
9246
9479
|
process.exit(1);
|
|
@@ -9252,8 +9485,8 @@ async function runUpdate(ctx, opts) {
|
|
|
9252
9485
|
const tmpScript = (0, import_node_path17.join)(import_node_os3.default.tmpdir(), `openclaw-install-${Date.now()}.mjs`);
|
|
9253
9486
|
try {
|
|
9254
9487
|
(0, import_node_fs22.writeFileSync)(tmpScript, installScript, "utf-8");
|
|
9255
|
-
} catch (
|
|
9256
|
-
const msg = `\u5199\u5165\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${
|
|
9488
|
+
} catch (err2) {
|
|
9489
|
+
const msg = `\u5199\u5165\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${err2?.message ?? String(err2)}`;
|
|
9257
9490
|
if (json) {
|
|
9258
9491
|
output({ ok: false, error: { code: "WRITE_FAILED", message: msg } });
|
|
9259
9492
|
process.exit(1);
|
|
@@ -10365,13 +10598,13 @@ async function downloadFile(url, destPath, logger, options) {
|
|
|
10365
10598
|
} finally {
|
|
10366
10599
|
clearTimeout(timer);
|
|
10367
10600
|
}
|
|
10368
|
-
} catch (
|
|
10369
|
-
lastError =
|
|
10601
|
+
} catch (err2) {
|
|
10602
|
+
lastError = err2?.message ?? String(err2);
|
|
10370
10603
|
try {
|
|
10371
10604
|
if ((0, import_node_fs25.existsSync)(destPath)) (0, import_node_fs25.unlinkSync)(destPath);
|
|
10372
10605
|
} catch {
|
|
10373
10606
|
}
|
|
10374
|
-
const isAbort =
|
|
10607
|
+
const isAbort = err2?.name === "AbortError";
|
|
10375
10608
|
logger.warn(
|
|
10376
10609
|
`[downloader] \u4E0B\u8F7D\u5931\u8D25 (attempt ${attempt}/${maxRetries}): ${isAbort ? "\u8D85\u65F6" : lastError}`
|
|
10377
10610
|
);
|
|
@@ -10433,9 +10666,9 @@ function emitRecordingStatus(recordingId, storage, logger, notifyStatus, error,
|
|
|
10433
10666
|
updatedAt: entry.updatedAt,
|
|
10434
10667
|
error
|
|
10435
10668
|
});
|
|
10436
|
-
} catch (
|
|
10669
|
+
} catch (err2) {
|
|
10437
10670
|
logger.error(
|
|
10438
|
-
`[recording-status] \u72B6\u6001\u4E8B\u4EF6\u53D1\u9001\u5931\u8D25: ${recordingId}, ${
|
|
10671
|
+
`[recording-status] \u72B6\u6001\u4E8B\u4EF6\u53D1\u9001\u5931\u8D25: ${recordingId}, ${err2?.message ?? err2}`
|
|
10439
10672
|
);
|
|
10440
10673
|
}
|
|
10441
10674
|
}
|
|
@@ -10499,8 +10732,8 @@ async function handleRecordingSync(recordingId, metadata, storage, asrConfig, lo
|
|
|
10499
10732
|
asrConfig,
|
|
10500
10733
|
logger,
|
|
10501
10734
|
options
|
|
10502
|
-
).catch((
|
|
10503
|
-
const error = `\u5F55\u97F3\u540C\u6B65\u5931\u8D25: ${
|
|
10735
|
+
).catch((err2) => {
|
|
10736
|
+
const error = `\u5F55\u97F3\u540C\u6B65\u5931\u8D25: ${err2?.message ?? err2}`;
|
|
10504
10737
|
logger.error(`[recording-sync] ${error}: ${recordingId}`);
|
|
10505
10738
|
emitRecordingStatus(
|
|
10506
10739
|
recordingId,
|
|
@@ -10523,9 +10756,9 @@ async function handleRecordingSync(recordingId, metadata, storage, asrConfig, lo
|
|
|
10523
10756
|
asrConfig,
|
|
10524
10757
|
logger,
|
|
10525
10758
|
options
|
|
10526
|
-
).catch((
|
|
10759
|
+
).catch((err2) => {
|
|
10527
10760
|
logger.error(
|
|
10528
|
-
`[asr-trigger] \u8F6C\u5199\u89E6\u53D1\u5931\u8D25: ${recordingId}, ${
|
|
10761
|
+
`[asr-trigger] \u8F6C\u5199\u89E6\u53D1\u5931\u8D25: ${recordingId}, ${err2?.message ?? err2}`
|
|
10529
10762
|
);
|
|
10530
10763
|
});
|
|
10531
10764
|
}
|
|
@@ -10861,9 +11094,9 @@ var RelayClient = class {
|
|
|
10861
11094
|
}
|
|
10862
11095
|
settle();
|
|
10863
11096
|
});
|
|
10864
|
-
ws.on("error", (
|
|
11097
|
+
ws.on("error", (err2) => {
|
|
10865
11098
|
this.opts.logger.error(
|
|
10866
|
-
`Relay tunnel: WebSocket error: ${
|
|
11099
|
+
`Relay tunnel: WebSocket error: ${err2.message} (readyState=${ws.readyState}, reconnectAttempt=${this.reconnectAttempt}, url=${wsUrl.toString()})`
|
|
10867
11100
|
);
|
|
10868
11101
|
settle();
|
|
10869
11102
|
});
|
|
@@ -10871,9 +11104,9 @@ var RelayClient = class {
|
|
|
10871
11104
|
}
|
|
10872
11105
|
emitConnected() {
|
|
10873
11106
|
for (const handler of this.connectedHandlers) {
|
|
10874
|
-
Promise.resolve(handler()).catch((
|
|
11107
|
+
Promise.resolve(handler()).catch((err2) => {
|
|
10875
11108
|
this.opts.logger.warn(
|
|
10876
|
-
`Relay tunnel: onConnected handler failed: ${
|
|
11109
|
+
`Relay tunnel: onConnected handler failed: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
10877
11110
|
);
|
|
10878
11111
|
});
|
|
10879
11112
|
}
|
|
@@ -10901,12 +11134,12 @@ var RelayClient = class {
|
|
|
10901
11134
|
try {
|
|
10902
11135
|
const result = handler(frame);
|
|
10903
11136
|
if (result instanceof Promise) {
|
|
10904
|
-
result.catch((
|
|
10905
|
-
this.opts.logger.error(`Relay tunnel: handler error: ${
|
|
11137
|
+
result.catch((err2) => {
|
|
11138
|
+
this.opts.logger.error(`Relay tunnel: handler error: ${err2}`);
|
|
10906
11139
|
});
|
|
10907
11140
|
}
|
|
10908
|
-
} catch (
|
|
10909
|
-
this.opts.logger.error(`Relay tunnel: handler error: ${
|
|
11141
|
+
} catch (err2) {
|
|
11142
|
+
this.opts.logger.error(`Relay tunnel: handler error: ${err2}`);
|
|
10910
11143
|
}
|
|
10911
11144
|
}
|
|
10912
11145
|
}
|
|
@@ -10995,8 +11228,8 @@ var RelayClient = class {
|
|
|
10995
11228
|
this.reconnectTimer = setTimeout(() => {
|
|
10996
11229
|
this.reconnectTimer = null;
|
|
10997
11230
|
if (!this.aborted) {
|
|
10998
|
-
this.connect().catch((
|
|
10999
|
-
this.opts.logger.error(`Relay tunnel: reconnect failed: ${
|
|
11231
|
+
this.connect().catch((err2) => {
|
|
11232
|
+
this.opts.logger.error(`Relay tunnel: reconnect failed: ${err2}`);
|
|
11000
11233
|
});
|
|
11001
11234
|
}
|
|
11002
11235
|
}, delayMs);
|
|
@@ -11304,8 +11537,8 @@ async function handleHttpRequest(opts, frame) {
|
|
|
11304
11537
|
});
|
|
11305
11538
|
return;
|
|
11306
11539
|
}
|
|
11307
|
-
} catch (
|
|
11308
|
-
const message =
|
|
11540
|
+
} catch (err2) {
|
|
11541
|
+
const message = err2 instanceof Error ? err2.message : String(err2);
|
|
11309
11542
|
opts.logger.error(
|
|
11310
11543
|
`TunnelProxy: HTTP id=${frame.id} ${frame.method} ${mappedPath} failed after ${Date.now() - startedAtMs}ms: ${message}`
|
|
11311
11544
|
);
|
|
@@ -11375,15 +11608,15 @@ async function streamResponse(opts, requestId, res, startedAtMs) {
|
|
|
11375
11608
|
state: "end",
|
|
11376
11609
|
data: ""
|
|
11377
11610
|
});
|
|
11378
|
-
} catch (
|
|
11611
|
+
} catch (err2) {
|
|
11379
11612
|
opts.logger.error(
|
|
11380
|
-
`TunnelProxy: stream error id=${requestId} after ${chunkCount} chunks and ${Date.now() - startedAtMs}ms: ${
|
|
11613
|
+
`TunnelProxy: stream error id=${requestId} after ${chunkCount} chunks and ${Date.now() - startedAtMs}ms: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
11381
11614
|
);
|
|
11382
11615
|
opts.client.send({
|
|
11383
11616
|
type: "proxy_error",
|
|
11384
11617
|
id: requestId,
|
|
11385
11618
|
status: 502,
|
|
11386
|
-
message: `stream error: ${
|
|
11619
|
+
message: `stream error: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
11387
11620
|
});
|
|
11388
11621
|
}
|
|
11389
11622
|
}
|
|
@@ -11450,27 +11683,27 @@ var WsProxy = class {
|
|
|
11450
11683
|
reason: reason.toString()
|
|
11451
11684
|
});
|
|
11452
11685
|
});
|
|
11453
|
-
ws.on("error", (
|
|
11686
|
+
ws.on("error", (err2) => {
|
|
11454
11687
|
this.opts.logger.warn(
|
|
11455
|
-
`TunnelProxy: WS id=${frame.id} error: ${
|
|
11688
|
+
`TunnelProxy: WS id=${frame.id} error: ${err2.message}, active=${this.connections.size}`
|
|
11456
11689
|
);
|
|
11457
11690
|
this.connections.delete(frame.id);
|
|
11458
11691
|
this.opts.client.send({
|
|
11459
11692
|
type: "ws_close",
|
|
11460
11693
|
id: frame.id,
|
|
11461
11694
|
code: 1011,
|
|
11462
|
-
reason:
|
|
11695
|
+
reason: err2.message
|
|
11463
11696
|
});
|
|
11464
11697
|
});
|
|
11465
|
-
} catch (
|
|
11698
|
+
} catch (err2) {
|
|
11466
11699
|
this.opts.logger.error(
|
|
11467
|
-
`TunnelProxy: WS id=${frame.id} failed to connect: ${
|
|
11700
|
+
`TunnelProxy: WS id=${frame.id} failed to connect: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
11468
11701
|
);
|
|
11469
11702
|
this.opts.client.send({
|
|
11470
11703
|
type: "ws_close",
|
|
11471
11704
|
id: frame.id,
|
|
11472
11705
|
code: 1011,
|
|
11473
|
-
reason: `failed to connect: ${
|
|
11706
|
+
reason: `failed to connect: ${err2 instanceof Error ? err2.message : String(err2)}`
|
|
11474
11707
|
});
|
|
11475
11708
|
}
|
|
11476
11709
|
}
|
|
@@ -11510,19 +11743,19 @@ var WsProxy = class {
|
|
|
11510
11743
|
var MAX_AUTO_PAIRING_APPROVALS = 3;
|
|
11511
11744
|
var approveDevicePairingPromise = null;
|
|
11512
11745
|
var approveDevicePairingWarned = false;
|
|
11513
|
-
function formatErrorMessage(
|
|
11514
|
-
if (
|
|
11515
|
-
return String(
|
|
11746
|
+
function formatErrorMessage(err2) {
|
|
11747
|
+
if (err2 instanceof Error && err2.message) return err2.message;
|
|
11748
|
+
return String(err2);
|
|
11516
11749
|
}
|
|
11517
11750
|
async function loadApproveDevicePairing(logger) {
|
|
11518
11751
|
if (!approveDevicePairingPromise) {
|
|
11519
11752
|
approveDevicePairingPromise = import("openclaw/plugin-sdk/device-bootstrap").then(
|
|
11520
11753
|
(mod) => typeof mod.approveDevicePairing === "function" ? mod.approveDevicePairing : null
|
|
11521
|
-
).catch((
|
|
11754
|
+
).catch((err2) => {
|
|
11522
11755
|
if (!approveDevicePairingWarned) {
|
|
11523
11756
|
approveDevicePairingWarned = true;
|
|
11524
11757
|
logger.warn(
|
|
11525
|
-
`TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK (${formatErrorMessage(
|
|
11758
|
+
`TunnelProxy: local gateway auto-pairing disabled because current OpenClaw runtime does not expose device bootstrap SDK (${formatErrorMessage(err2)})`
|
|
11526
11759
|
);
|
|
11527
11760
|
}
|
|
11528
11761
|
return null;
|
|
@@ -11747,9 +11980,9 @@ var TunnelProxy = class {
|
|
|
11747
11980
|
`TunnelProxy: auto-approved local gateway pairing request ${requestId} (reason=${reason || "not-paired"}, hostStateDir=${this.hostStateDir}, approval=${this.gatewayWsAutoPairingApprovals}/${MAX_AUTO_PAIRING_APPROVALS})`
|
|
11748
11981
|
);
|
|
11749
11982
|
return true;
|
|
11750
|
-
} catch (
|
|
11983
|
+
} catch (err2) {
|
|
11751
11984
|
this.opts.logger.warn(
|
|
11752
|
-
`TunnelProxy: failed to auto-approve gateway pairing request ${requestId}: ${
|
|
11985
|
+
`TunnelProxy: failed to auto-approve gateway pairing request ${requestId}: ${err2?.message ?? String(err2)}`
|
|
11753
11986
|
);
|
|
11754
11987
|
return false;
|
|
11755
11988
|
}
|
|
@@ -11863,9 +12096,9 @@ var TunnelProxy = class {
|
|
|
11863
12096
|
queueMicrotask(() => this.ensureGatewayWs());
|
|
11864
12097
|
}
|
|
11865
12098
|
});
|
|
11866
|
-
ws.on("error", (
|
|
12099
|
+
ws.on("error", (err2) => {
|
|
11867
12100
|
this.opts.logger.warn(
|
|
11868
|
-
`TunnelProxy: RPC WS error: ${
|
|
12101
|
+
`TunnelProxy: RPC WS error: ${err2.message} (ready=${this.gatewayWsReady}, pending=${this.gatewayWsPending.length}, activeWs=${this.wsProxy.activeCount})`
|
|
11869
12102
|
);
|
|
11870
12103
|
this.gatewayWsConnecting = false;
|
|
11871
12104
|
if (this.gatewayWs === ws) {
|
|
@@ -11965,8 +12198,8 @@ function createTunnelService(opts) {
|
|
|
11965
12198
|
try {
|
|
11966
12199
|
process.kill(pid, 0);
|
|
11967
12200
|
return true;
|
|
11968
|
-
} catch (
|
|
11969
|
-
return
|
|
12201
|
+
} catch (err2) {
|
|
12202
|
+
return err2?.code === "EPERM";
|
|
11970
12203
|
}
|
|
11971
12204
|
}
|
|
11972
12205
|
function readLockOwner(filePath) {
|
|
@@ -12011,10 +12244,10 @@ function createTunnelService(opts) {
|
|
|
12011
12244
|
lockFilePath = filePath;
|
|
12012
12245
|
lockFd = fd;
|
|
12013
12246
|
return true;
|
|
12014
|
-
} catch (
|
|
12015
|
-
if (
|
|
12247
|
+
} catch (err2) {
|
|
12248
|
+
if (err2?.code !== "EEXIST") {
|
|
12016
12249
|
opts.logger.error(
|
|
12017
|
-
`Relay tunnel: failed to acquire local lock ${filePath}: ${String(
|
|
12250
|
+
`Relay tunnel: failed to acquire local lock ${filePath}: ${String(err2)}`
|
|
12018
12251
|
);
|
|
12019
12252
|
return false;
|
|
12020
12253
|
}
|
|
@@ -12102,14 +12335,14 @@ function createTunnelService(opts) {
|
|
|
12102
12335
|
emitPendingPluginUpdate("relay connected");
|
|
12103
12336
|
});
|
|
12104
12337
|
abortController = new AbortController();
|
|
12105
|
-
client.connectWithAutoReconnect(abortController.signal).catch((
|
|
12338
|
+
client.connectWithAutoReconnect(abortController.signal).catch((err2) => {
|
|
12106
12339
|
releaseLock();
|
|
12107
|
-
logger.error(`Relay tunnel: unexpected error: ${
|
|
12340
|
+
logger.error(`Relay tunnel: unexpected error: ${err2}`);
|
|
12108
12341
|
});
|
|
12109
12342
|
logger.info("Relay tunnel \u670D\u52A1\u5DF2\u542F\u52A8");
|
|
12110
|
-
} catch (
|
|
12343
|
+
} catch (err2) {
|
|
12111
12344
|
releaseLock();
|
|
12112
|
-
throw
|
|
12345
|
+
throw err2;
|
|
12113
12346
|
}
|
|
12114
12347
|
},
|
|
12115
12348
|
async stop() {
|
|
@@ -12215,8 +12448,8 @@ function readHostGatewayConfig(params) {
|
|
|
12215
12448
|
if (configPath) {
|
|
12216
12449
|
try {
|
|
12217
12450
|
configData = JSON.parse((0, import_node_fs31.readFileSync)(configPath, "utf-8"));
|
|
12218
|
-
} catch (
|
|
12219
|
-
if (
|
|
12451
|
+
} catch (err2) {
|
|
12452
|
+
if (err2?.code !== "ENOENT") {
|
|
12220
12453
|
params.logger.warn(
|
|
12221
12454
|
`Relay tunnel: \u65E0\u6CD5\u8BFB\u53D6 gateway \u9274\u6743\u914D\u7F6E (${configPath})`
|
|
12222
12455
|
);
|
|
@@ -12326,7 +12559,7 @@ function registerNotificationInterfaces(deps) {
|
|
|
12326
12559
|
} = deps;
|
|
12327
12560
|
function triggerAfterIngest(insertedCount, cron) {
|
|
12328
12561
|
if (insertedCount <= 0 || !onAfterIngest) return;
|
|
12329
|
-
void Promise.resolve().then(() => onAfterIngest(insertedCount, cron)).catch((
|
|
12562
|
+
void Promise.resolve().then(() => onAfterIngest(insertedCount, cron)).catch((err2) => logger.warn(`onAfterIngest failed: ${err2?.message ?? err2}`));
|
|
12330
12563
|
}
|
|
12331
12564
|
registerGatewayMethod(
|
|
12332
12565
|
"notifications.push",
|
|
@@ -12719,9 +12952,9 @@ function registerRecordingInterfaces(deps) {
|
|
|
12719
12952
|
}
|
|
12720
12953
|
triggerTranscription(recordingId, recordingStorage, asr, logger, {
|
|
12721
12954
|
notifyStatus: notifyRecordingStatus
|
|
12722
|
-
}).catch((
|
|
12955
|
+
}).catch((err2) => {
|
|
12723
12956
|
logger.error(
|
|
12724
|
-
`[recordings.retranscribe] \u91CD\u8BD5\u8F6C\u5199\u5931\u8D25: ${recordingId}, ${
|
|
12957
|
+
`[recordings.retranscribe] \u91CD\u8BD5\u8F6C\u5199\u5931\u8D25: ${recordingId}, ${err2?.message ?? err2}`
|
|
12725
12958
|
);
|
|
12726
12959
|
});
|
|
12727
12960
|
respond(true, { ok: true, recordingId, message: "\u8F6C\u5199\u5DF2\u91CD\u65B0\u89E6\u53D1" });
|
|
@@ -12967,8 +13200,9 @@ var index_default = {
|
|
|
12967
13200
|
tunnelService
|
|
12968
13201
|
});
|
|
12969
13202
|
registerLightRulesGateway(api, lightRuleRegistry, logger, cacheBroadcast);
|
|
13203
|
+
registerLightRulesTools(api, lightRuleRegistry, logger);
|
|
12970
13204
|
logger.info(
|
|
12971
|
-
"
|
|
13205
|
+
"\u706F\u6548\u89C4\u5219\u65B9\u6CD5\u5DF2\u6CE8\u518C: lightrules.list / lightrules.create / lightrules.update / lightrules.delete"
|
|
12972
13206
|
);
|
|
12973
13207
|
autoUpdateLifecycle = registerAutoUpdateLifecycle({
|
|
12974
13208
|
api,
|