@ynhcj/xiaoyi-channel 0.0.203-beta → 0.0.205-beta
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.js +3 -3
- package/dist/src/bot.js +52 -34
- package/dist/src/channel.js +68 -64
- package/dist/src/client.d.ts +5 -0
- package/dist/src/client.js +10 -0
- package/dist/src/cspl/call_api.js +2 -0
- package/dist/src/cspl/sentinel_hook.js +9 -8
- package/dist/src/formatter.js +21 -31
- package/dist/src/monitor.js +20 -9
- package/dist/src/outbound.js +5 -0
- package/dist/src/provider.js +49 -14
- package/dist/src/reply-dispatcher.d.ts +3 -0
- package/dist/src/reply-dispatcher.js +152 -159
- package/dist/src/self-evolution-handler.js +2 -1
- package/dist/src/task-manager.d.ts +5 -6
- package/dist/src/task-manager.js +5 -9
- package/dist/src/tools/agent-as-skill-tool.d.ts +41 -2
- package/dist/src/tools/agent-as-skill-tool.js +144 -146
- package/dist/src/tools/calendar-tool.d.ts +24 -2
- package/dist/src/tools/calendar-tool.js +115 -117
- package/dist/src/tools/call-device-tool.d.ts +20 -6
- package/dist/src/tools/call-device-tool.js +116 -138
- package/dist/src/tools/call-phone-tool.d.ts +21 -2
- package/dist/src/tools/call-phone-tool.js +112 -114
- package/dist/src/tools/check-plugin-privilege-tool.d.ts +16 -2
- package/dist/src/tools/check-plugin-privilege-tool.js +141 -143
- package/dist/src/tools/create-alarm-tool.d.ts +39 -2
- package/dist/src/tools/create-alarm-tool.js +229 -231
- package/dist/src/tools/delete-alarm-tool.d.ts +15 -2
- package/dist/src/tools/delete-alarm-tool.js +134 -136
- package/dist/src/tools/device-tool-map.js +3 -1
- package/dist/src/tools/discover-cross-devices-tool.d.ts +16 -2
- package/dist/src/tools/discover-cross-devices-tool.js +121 -124
- package/dist/src/tools/display-a2ui-card-bypath-tool.d.ts +21 -2
- package/dist/src/tools/display-a2ui-card-bypath-tool.js +53 -56
- package/dist/src/tools/get-alarm-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-alarm-tool-schema.js +10 -16
- package/dist/src/tools/get-calendar-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-calendar-tool-schema.js +8 -12
- package/dist/src/tools/get-collection-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-collection-tool-schema.js +9 -11
- package/dist/src/tools/get-contact-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-contact-tool-schema.js +10 -16
- package/dist/src/tools/get-device-file-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-device-file-tool-schema.js +9 -13
- package/dist/src/tools/get-email-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-email-tool-schema.js +8 -11
- package/dist/src/tools/get-note-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-note-tool-schema.js +9 -14
- package/dist/src/tools/get-photo-tool-schema.d.ts +1 -2
- package/dist/src/tools/get-photo-tool-schema.js +9 -12
- package/dist/src/tools/image-reading-tool.d.ts +28 -2
- package/dist/src/tools/image-reading-tool.js +76 -76
- package/dist/src/tools/location-tool.d.ts +11 -2
- package/dist/src/tools/location-tool.js +93 -92
- package/dist/src/tools/login-token-tool.d.ts +20 -2
- package/dist/src/tools/login-token-tool.js +123 -125
- package/dist/src/tools/modify-alarm-tool.d.ts +47 -2
- package/dist/src/tools/modify-alarm-tool.js +250 -252
- package/dist/src/tools/modify-note-tool.d.ts +20 -2
- package/dist/src/tools/modify-note-tool.js +107 -109
- package/dist/src/tools/note-tool.d.ts +20 -2
- package/dist/src/tools/note-tool.js +106 -108
- package/dist/src/tools/query-app-message-tool.d.ts +28 -2
- package/dist/src/tools/query-app-message-tool.js +111 -113
- package/dist/src/tools/query-memory-data-tool.d.ts +28 -2
- package/dist/src/tools/query-memory-data-tool.js +112 -114
- package/dist/src/tools/query-todo-task-tool.d.ts +24 -2
- package/dist/src/tools/query-todo-task-tool.js +106 -108
- package/dist/src/tools/save-file-to-phone-tool.d.ts +24 -2
- package/dist/src/tools/save-file-to-phone-tool.js +130 -132
- package/dist/src/tools/save-media-to-gallery-tool.d.ts +24 -2
- package/dist/src/tools/save-media-to-gallery-tool.js +137 -139
- package/dist/src/tools/save-self-evolution-skill-tool.d.ts +54 -2
- package/dist/src/tools/save-self-evolution-skill-tool.js +194 -194
- package/dist/src/tools/search-alarm-tool.d.ts +34 -2
- package/dist/src/tools/search-alarm-tool.js +174 -176
- package/dist/src/tools/search-calendar-tool.d.ts +24 -2
- package/dist/src/tools/search-calendar-tool.js +148 -150
- package/dist/src/tools/search-contact-tool.d.ts +16 -2
- package/dist/src/tools/search-contact-tool.js +101 -103
- package/dist/src/tools/search-email-tool.d.ts +21 -2
- package/dist/src/tools/search-email-tool.js +110 -112
- package/dist/src/tools/search-file-tool.d.ts +16 -2
- package/dist/src/tools/search-file-tool.js +104 -106
- package/dist/src/tools/search-message-tool.d.ts +16 -2
- package/dist/src/tools/search-message-tool.js +103 -105
- package/dist/src/tools/search-note-tool.d.ts +16 -2
- package/dist/src/tools/search-note-tool.js +98 -100
- package/dist/src/tools/search-photo-gallery-tool.d.ts +21 -2
- package/dist/src/tools/search-photo-gallery-tool.js +35 -37
- package/dist/src/tools/send-cross-device-task-tool.d.ts +35 -2
- package/dist/src/tools/send-cross-device-task-tool.js +140 -143
- package/dist/src/tools/send-email-tool.d.ts +24 -2
- package/dist/src/tools/send-email-tool.js +108 -110
- package/dist/src/tools/send-file-to-user-tool.d.ts +20 -2
- package/dist/src/tools/send-file-to-user-tool.js +174 -176
- package/dist/src/tools/send-html-card-tool.d.ts +20 -2
- package/dist/src/tools/send-html-card-tool.js +85 -87
- package/dist/src/tools/send-message-tool.d.ts +20 -2
- package/dist/src/tools/send-message-tool.js +122 -124
- package/dist/src/tools/session-manager.d.ts +7 -50
- package/dist/src/tools/session-manager.js +40 -231
- package/dist/src/tools/upload-file-tool.d.ts +20 -2
- package/dist/src/tools/upload-file-tool.js +80 -82
- package/dist/src/tools/upload-photo-tool.d.ts +20 -2
- package/dist/src/tools/upload-photo-tool.js +68 -70
- package/dist/src/tools/xiaoyi-add-collection-tool.d.ts +32 -2
- package/dist/src/tools/xiaoyi-add-collection-tool.js +146 -148
- package/dist/src/tools/xiaoyi-collection-tool.d.ts +20 -2
- package/dist/src/tools/xiaoyi-collection-tool.js +114 -116
- package/dist/src/tools/xiaoyi-delete-collection-tool.d.ts +15 -2
- package/dist/src/tools/xiaoyi-delete-collection-tool.js +127 -129
- package/dist/src/tools/xiaoyi-gui-tool.d.ts +16 -2
- package/dist/src/tools/xiaoyi-gui-tool.js +92 -95
- package/dist/src/utils/logger.js +3 -14
- package/dist/src/websocket.d.ts +1 -1
- package/package.json +2 -2
package/dist/src/monitor.js
CHANGED
|
@@ -10,8 +10,9 @@ import { handleLoginTokenEvent } from "./login-token-handler.js";
|
|
|
10
10
|
import { handleCronQueryEvent } from "./cron-query-handler.js";
|
|
11
11
|
import { handleMemoryQueryEvent } from "./memory-query-handler.js";
|
|
12
12
|
import { cleanupStaleTempFiles } from "./reply-dispatcher.js";
|
|
13
|
-
import { cleanupStaleSessions, getActiveSessionCount, cleanupAllSessions } from "./tools/session-manager.js";
|
|
14
13
|
import { logger } from "./utils/logger.js";
|
|
14
|
+
import { XYFileUploadService } from "./file-upload.js";
|
|
15
|
+
import { startLogReporter } from "./log-reporter/index.js";
|
|
15
16
|
/**
|
|
16
17
|
* Per-session serial queue that ensures messages from the same session are processed
|
|
17
18
|
* in arrival order while allowing different sessions to run concurrently.
|
|
@@ -75,6 +76,8 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
75
76
|
let globalDispatchInitGate = Promise.resolve();
|
|
76
77
|
// Health check interval
|
|
77
78
|
let healthCheckInterval = null;
|
|
79
|
+
// Log reporter stop handle
|
|
80
|
+
let stopLogReporter = null;
|
|
78
81
|
return new Promise((resolve, reject) => {
|
|
79
82
|
// Event handlers (defined early so they can be referenced in cleanup)
|
|
80
83
|
const messageHandler = (message, sessionId, serverId) => {
|
|
@@ -214,6 +217,11 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
214
217
|
};
|
|
215
218
|
const cleanup = () => {
|
|
216
219
|
logger.log("XY gateway: cleaning up...");
|
|
220
|
+
// Stop log reporter
|
|
221
|
+
if (stopLogReporter) {
|
|
222
|
+
stopLogReporter();
|
|
223
|
+
stopLogReporter = null;
|
|
224
|
+
}
|
|
217
225
|
// 🔍 Diagnose before cleanup
|
|
218
226
|
logger.log("[DIAGNOSTICS] Checking WebSocket managers before cleanup...");
|
|
219
227
|
diagnoseAllManagers();
|
|
@@ -239,8 +247,7 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
239
247
|
wsManager.disconnect();
|
|
240
248
|
// ✅ Remove manager from cache to prevent reusing dirty state
|
|
241
249
|
removeXYWebSocketManager(account);
|
|
242
|
-
//
|
|
243
|
-
cleanupAllSessions();
|
|
250
|
+
// Session context is ALS-scoped now — nothing global to clean up.
|
|
244
251
|
loggedServers.clear();
|
|
245
252
|
activeMessages.clear();
|
|
246
253
|
logger.log(`[MONITOR-HANDLER] Cleanup complete, cleared active messages and sessions`);
|
|
@@ -309,12 +316,7 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
309
316
|
if (cleaned > 0) {
|
|
310
317
|
logger.log(`[HEALTH CHECK] Auto-cleaned ${cleaned} manager(s) with orphan connections`);
|
|
311
318
|
}
|
|
312
|
-
//
|
|
313
|
-
const cleanedSessions = cleanupStaleSessions();
|
|
314
|
-
const remainingSessions = getActiveSessionCount();
|
|
315
|
-
if (cleanedSessions > 0 || remainingSessions > 0) {
|
|
316
|
-
logger.log(`[HEALTH CHECK] Sessions: cleaned=${cleanedSessions}, active=${remainingSessions}`);
|
|
317
|
-
}
|
|
319
|
+
// Session context is ALS-scoped — no global session cleanup needed.
|
|
318
320
|
// Cleanup stale temp files (older than 24 hours)
|
|
319
321
|
void cleanupStaleTempFiles();
|
|
320
322
|
}, 6 * 60 * 60 * 1000); // 6 hours
|
|
@@ -322,6 +324,15 @@ export async function monitorXYProvider(opts = {}) {
|
|
|
322
324
|
wsManager.connect()
|
|
323
325
|
.then(() => {
|
|
324
326
|
logger.log("XY gateway: started successfully");
|
|
327
|
+
// Start log reporter (independent periodic scanner + uploader)
|
|
328
|
+
startLogReporter({
|
|
329
|
+
configPath: "/home/ynhcj/.openclaw/log-reporter-config.json",
|
|
330
|
+
uploadService: new XYFileUploadService(account.fileUploadUrl, account.apiKey, account.uid),
|
|
331
|
+
}).then((stop) => {
|
|
332
|
+
stopLogReporter = stop;
|
|
333
|
+
}).catch((err) => {
|
|
334
|
+
logger.warn(`Log reporter not started: ${String(err)}`);
|
|
335
|
+
});
|
|
325
336
|
})
|
|
326
337
|
.catch((err) => {
|
|
327
338
|
// Connection failed but don't reject - continue monitoring for reconnection
|
package/dist/src/outbound.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// Outbound adapter for XY channel
|
|
2
|
+
// Following feishu/outbound.ts pattern
|
|
3
|
+
// NOTE: Using any for compatibility with SDK 2026.3.24
|
|
4
|
+
import os from "os";
|
|
1
5
|
import { resolveXYConfig } from "./config.js";
|
|
2
6
|
import { XYFileUploadService } from "./file-upload.js";
|
|
3
7
|
import { XYPushService } from "./push.js";
|
|
@@ -219,6 +223,7 @@ export const xyOutbound = {
|
|
|
219
223
|
},
|
|
220
224
|
},
|
|
221
225
|
error: { code: 0 },
|
|
226
|
+
hostname: os.hostname(),
|
|
222
227
|
}),
|
|
223
228
|
};
|
|
224
229
|
// Get WebSocket manager and send message
|
package/dist/src/provider.js
CHANGED
|
@@ -128,6 +128,7 @@ function createRetryingStream(createStream, cronJob) {
|
|
|
128
128
|
let hasContent = false;
|
|
129
129
|
const buffer = [];
|
|
130
130
|
let errorResult = null;
|
|
131
|
+
const fullResponseEvents = [];
|
|
131
132
|
for await (const event of stream) {
|
|
132
133
|
const isContent = CONTENT_EVENT_TYPES.has(event.type);
|
|
133
134
|
if (!hasContent && !isContent) {
|
|
@@ -150,9 +151,14 @@ function createRetryingStream(createStream, cronJob) {
|
|
|
150
151
|
if (!hasContent) {
|
|
151
152
|
logger.log("[xiaoyiprovider] first content event received, switching to streaming mode");
|
|
152
153
|
hasContent = true;
|
|
153
|
-
for (const b of buffer)
|
|
154
|
+
for (const b of buffer) {
|
|
155
|
+
if (CONTENT_EVENT_TYPES.has(b.type))
|
|
156
|
+
fullResponseEvents.push(b);
|
|
154
157
|
yield b;
|
|
158
|
+
}
|
|
155
159
|
}
|
|
160
|
+
if (isContent)
|
|
161
|
+
fullResponseEvents.push(event);
|
|
156
162
|
// IMPORTANT: resolve result() BEFORE yielding terminal events to avoid deadlock.
|
|
157
163
|
// The SDK calls result() when it sees done/error — if we yield first, the generator
|
|
158
164
|
// suspends and can never reach resolve, causing a permanent deadlock.
|
|
@@ -398,6 +404,10 @@ function trimUserMetadata(text) {
|
|
|
398
404
|
* bot.ts stores them as MessageSid = "xiaoyi_taskId_deviceType".
|
|
399
405
|
* The "xiaoyi_" prefix ensures extraction only happens for messages
|
|
400
406
|
* routed through xiaoyi-channel, not other channels sharing the provider.
|
|
407
|
+
*
|
|
408
|
+
* This is the most reliable source during steer scenarios: ALS still holds
|
|
409
|
+
* the first message's taskId, but the text extraction sees the latest
|
|
410
|
+
* injected user message which carries the updated taskId.
|
|
401
411
|
*/
|
|
402
412
|
function extractA2AFromConversationInfo(text) {
|
|
403
413
|
const match = text.match(/Conversation info \(untrusted metadata\):\n```json\n([\s\S]*?)\n```/);
|
|
@@ -424,7 +434,12 @@ export const xiaoyiProvider = {
|
|
|
424
434
|
* xiaoyiprovider as long as the provider has a configured baseUrl.
|
|
425
435
|
*/
|
|
426
436
|
resolveDynamicModel: (ctx) => {
|
|
427
|
-
|
|
437
|
+
// providerConfig from models.providers.xiaoyiprovider is preferred;
|
|
438
|
+
// fall back to zai baseUrl when config-driven provider setup is unavailable.
|
|
439
|
+
let baseUrl = ctx.providerConfig?.baseUrl;
|
|
440
|
+
if (!baseUrl || typeof baseUrl !== "string") {
|
|
441
|
+
baseUrl = ctx.config?.models?.providers?.zai?.baseUrl;
|
|
442
|
+
}
|
|
428
443
|
if (!baseUrl || typeof baseUrl !== "string")
|
|
429
444
|
return null;
|
|
430
445
|
return {
|
|
@@ -433,7 +448,7 @@ export const xiaoyiProvider = {
|
|
|
433
448
|
api: ctx.providerConfig?.api ?? "openai-completions",
|
|
434
449
|
provider: "xiaoyiprovider",
|
|
435
450
|
baseUrl,
|
|
436
|
-
reasoning:
|
|
451
|
+
reasoning: true,
|
|
437
452
|
input: ["text"],
|
|
438
453
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
439
454
|
contextWindow: 256_000,
|
|
@@ -477,6 +492,8 @@ export const xiaoyiProvider = {
|
|
|
477
492
|
// ── Extract A2A taskId/deviceType from Conversation info ──
|
|
478
493
|
// bot.ts stores taskId_deviceType as MessageSid, which the framework
|
|
479
494
|
// renders as message_id in the Conversation info JSON block.
|
|
495
|
+
// This is the priority source: it reflects the latest user message
|
|
496
|
+
// even during steer when ALS still holds the first message's taskId.
|
|
480
497
|
let extractedTaskId = null;
|
|
481
498
|
let extractedDeviceType = null;
|
|
482
499
|
if (context.messages) {
|
|
@@ -502,8 +519,9 @@ export const xiaoyiProvider = {
|
|
|
502
519
|
// ── Build dynamic headers ────────────────────────────
|
|
503
520
|
// Priority:
|
|
504
521
|
// 1. Cron-triggered: uid → cronUuid, with cron-specific headers
|
|
505
|
-
// 2. Xiaoyi A2A: taskId
|
|
506
|
-
// 3.
|
|
522
|
+
// 2. Xiaoyi A2A: taskId from Conversation info text (latest msg, steer-safe)
|
|
523
|
+
// 3. ALS fallback: rawTaskId from AsyncLocalStorage
|
|
524
|
+
// 4. UID-based fallback: sha256(uid).hex[:32]_timestamp
|
|
507
525
|
const isCron = isCronTriggered(context.messages);
|
|
508
526
|
if (isCron) {
|
|
509
527
|
// fire 期 jobId 桥:把首条消息 `[cron:<jobId> ...]` 解析出的真实 jobId
|
|
@@ -533,6 +551,7 @@ export const xiaoyiProvider = {
|
|
|
533
551
|
dynamicHeaders["x-cron-title"] = encodeURIComponent(cronTitle);
|
|
534
552
|
if (context.messages?.length === 1)
|
|
535
553
|
dynamicHeaders["x-cron-flag"] = "begin";
|
|
554
|
+
logger.log(`[ALS-PROOF] provider headers source=cron`);
|
|
536
555
|
}
|
|
537
556
|
else if (extractedTaskId) {
|
|
538
557
|
const sessionId = extractedTaskId.split("&")[0];
|
|
@@ -540,14 +559,31 @@ export const xiaoyiProvider = {
|
|
|
540
559
|
dynamicHeaders[HEADER_TRACE_ID] = extractedTaskId;
|
|
541
560
|
dynamicHeaders[HEADER_SESSION_ID] = sessionId;
|
|
542
561
|
dynamicHeaders[HEADER_INTERACTION_ID] = interactionId;
|
|
562
|
+
logger.log(`[ALS-PROOF] provider headers source=text-extract traceId=${extractedTaskId} sessionId=${sessionId} interactionId=${interactionId}`);
|
|
543
563
|
}
|
|
544
564
|
else {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
565
|
+
// ALS fallback: rawTaskId from the per-turn AsyncLocalStorage scope.
|
|
566
|
+
// Text extraction (above) is preferred because during steer the ALS
|
|
567
|
+
// scope may still hold the first message's taskId.
|
|
568
|
+
const als = getCurrentSessionContext();
|
|
569
|
+
const rawTaskId = als?.taskId;
|
|
570
|
+
if (rawTaskId) {
|
|
571
|
+
const sessionId = rawTaskId.split("&")[0];
|
|
572
|
+
const interactionId = rawTaskId.split("&")[1] ?? "";
|
|
573
|
+
dynamicHeaders[HEADER_TRACE_ID] = rawTaskId;
|
|
574
|
+
dynamicHeaders[HEADER_SESSION_ID] = sessionId;
|
|
575
|
+
dynamicHeaders[HEADER_INTERACTION_ID] = interactionId;
|
|
576
|
+
logger.log(`[ALS-PROOF] provider headers source=ALS traceId=${rawTaskId} sessionId=${sessionId} interactionId=${interactionId}`);
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
const fallbackPrefix = ctx.extraParams?.[FALLBACK_PREFIX_KEY];
|
|
580
|
+
if (typeof fallbackPrefix === "string") {
|
|
581
|
+
const fallbackValue = `${fallbackPrefix}_${Date.now()}`;
|
|
582
|
+
dynamicHeaders[HEADER_TRACE_ID] = fallbackValue;
|
|
583
|
+
dynamicHeaders[HEADER_SESSION_ID] = fallbackValue;
|
|
584
|
+
dynamicHeaders[HEADER_INTERACTION_ID] = fallbackValue;
|
|
585
|
+
}
|
|
586
|
+
logger.log(`[ALS-PROOF] provider headers source=uid-fallback (ALS miss)`);
|
|
551
587
|
}
|
|
552
588
|
}
|
|
553
589
|
// 记录输入
|
|
@@ -560,8 +596,7 @@ export const xiaoyiProvider = {
|
|
|
560
596
|
if (context.systemPrompt) {
|
|
561
597
|
logger.log(`[xiaoyiprovider] system prompt length: ${context.systemPrompt.length}`);
|
|
562
598
|
}
|
|
563
|
-
// deviceType: prefer value
|
|
564
|
-
// then ALS fallback.
|
|
599
|
+
// deviceType: prefer text-extracted value, ALS as fallback.
|
|
565
600
|
const deviceType = extractedDeviceType
|
|
566
601
|
?? getCurrentSessionContext()?.deviceType;
|
|
567
602
|
// app_ver and sdk_api_version from session context (ALS)
|
|
@@ -618,7 +653,7 @@ export const xiaoyiProvider = {
|
|
|
618
653
|
deviceSection += `当前用户小艺APP版本是${appVer}\n`;
|
|
619
654
|
}
|
|
620
655
|
if (sdkApiVersion) {
|
|
621
|
-
deviceSection +=
|
|
656
|
+
deviceSection += `当前用户系统Rom版本是${sdkApiVersion}\n`;
|
|
622
657
|
}
|
|
623
658
|
deviceSection += `You need to be aware of the user's current device and provide guidance accordingly. If the response involves device-related tools or actions, you must tailor the reply based on the user's current device, using device-specific references such as "saved to the Notes/Calendar on your {deviceType}.\n"`;
|
|
624
659
|
context.systemPrompt = (context.systemPrompt ?? "") + deviceSection;
|
|
@@ -9,6 +9,9 @@ export interface CreateXYReplyDispatcherParams {
|
|
|
9
9
|
steerState: {
|
|
10
10
|
steered: boolean;
|
|
11
11
|
};
|
|
12
|
+
/** Called at end of onIdle, after final frame is sent. openclaw's waitForIdle() does
|
|
13
|
+
* not await the async onIdle, so cleanup must happen inside onIdle itself. */
|
|
14
|
+
onIdleComplete?: () => void | Promise<void>;
|
|
12
15
|
}
|
|
13
16
|
/**
|
|
14
17
|
* 清理 /tmp/xy_channel 目录中超过 24 小时的旧文件
|