@ardennguyen/zalo-agent-cli 2.2.0 → 2.2.2
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/README.md +6 -6
- package/package.json +2 -2
- package/src/commands/mcp.js +42 -0
- package/src/core/db.js +44 -0
- package/src/mcp/mcp-config.js +1 -0
- package/src/mcp/mcp-http-transport.js +40 -0
- package/src/mcp/mcp-tools.js +1080 -42
- package/src/mcp/message-buffer.js +62 -1
|
@@ -28,6 +28,8 @@ export class MessageBuffer {
|
|
|
28
28
|
this._globalCursor = 0;
|
|
29
29
|
/** @type {Map<string, { cursor: number, at: number }>} */
|
|
30
30
|
this._readCursors = new Map();
|
|
31
|
+
/** @type {Set<{ threadId: string|null, resolve: Function, timer: NodeJS.Timeout }>} */
|
|
32
|
+
this._waiters = new Set();
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
/**
|
|
@@ -40,7 +42,8 @@ export class MessageBuffer {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
/**
|
|
43
|
-
* Add message to thread buffer. Auto-evicts stale messages
|
|
45
|
+
* Add message to thread buffer. Auto-evicts stale messages and wakes any
|
|
46
|
+
* long-poll waiters matching the thread.
|
|
44
47
|
* @param {string} threadId
|
|
45
48
|
* @param {object} message - Normalized message object
|
|
46
49
|
*/
|
|
@@ -54,6 +57,64 @@ export class MessageBuffer {
|
|
|
54
57
|
thread.messages.push(message);
|
|
55
58
|
thread.lastActivity = Date.now();
|
|
56
59
|
this._evict(threadId);
|
|
60
|
+
|
|
61
|
+
for (const waiter of [...this._waiters]) {
|
|
62
|
+
if (!waiter.threadId || waiter.threadId === String(threadId)) {
|
|
63
|
+
this._waiters.delete(waiter);
|
|
64
|
+
clearTimeout(waiter.timer);
|
|
65
|
+
waiter.resolve(message);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Wait for the next buffered message (or return immediately if `since` is
|
|
72
|
+
* provided and a newer message is already in the buffer).
|
|
73
|
+
*
|
|
74
|
+
* @param {object} [opts]
|
|
75
|
+
* @param {string} [opts.threadId] - Optional thread filter
|
|
76
|
+
* @param {number} [opts.since] - Optional cursor; if a message > since already exists, resolves immediately
|
|
77
|
+
* @param {number} [opts.timeoutMs=60000] - Max wait duration in milliseconds
|
|
78
|
+
* @param {AbortSignal} [opts.signal] - Optional abort signal (e.g. when HTTP client disconnects)
|
|
79
|
+
* @returns {Promise<object|null>} The message object, or null on timeout/abort
|
|
80
|
+
*/
|
|
81
|
+
waitForMessage({ threadId = null, since = undefined, timeoutMs = 60000, signal = undefined } = {}) {
|
|
82
|
+
if (since !== undefined && since !== null && Number.isFinite(Number(since))) {
|
|
83
|
+
const existing = this.read(threadId || undefined, Number(since), 1);
|
|
84
|
+
if (existing.messages.length > 0) {
|
|
85
|
+
return Promise.resolve(existing.messages[0]);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (signal?.aborted) {
|
|
89
|
+
return Promise.resolve(null);
|
|
90
|
+
}
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
const waiter = {
|
|
93
|
+
threadId: threadId ? String(threadId) : null,
|
|
94
|
+
resolve: (msg) => {
|
|
95
|
+
signal?.removeEventListener("abort", onAbort);
|
|
96
|
+
resolve(msg);
|
|
97
|
+
},
|
|
98
|
+
timer: null,
|
|
99
|
+
};
|
|
100
|
+
const onAbort = () => {
|
|
101
|
+
if (this._waiters.delete(waiter)) {
|
|
102
|
+
clearTimeout(waiter.timer);
|
|
103
|
+
resolve(null);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
waiter.timer = setTimeout(
|
|
107
|
+
() => {
|
|
108
|
+
if (this._waiters.delete(waiter)) {
|
|
109
|
+
signal?.removeEventListener("abort", onAbort);
|
|
110
|
+
resolve(null);
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
Math.max(1, Number(timeoutMs) || 60000),
|
|
114
|
+
);
|
|
115
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
116
|
+
this._waiters.add(waiter);
|
|
117
|
+
});
|
|
57
118
|
}
|
|
58
119
|
|
|
59
120
|
/**
|