@delexec/ops 0.1.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/README.md +3 -0
- package/README.zh-CN.md +6 -0
- package/node_modules/@delexec/caller-controller/README.md +3 -0
- package/node_modules/@delexec/caller-controller/README.zh-CN.md +6 -0
- package/node_modules/@delexec/caller-controller/package.json +53 -0
- package/node_modules/@delexec/caller-controller/src/server.js +127 -0
- package/node_modules/@delexec/caller-controller-core/README.md +3 -0
- package/node_modules/@delexec/caller-controller-core/README.zh-CN.md +6 -0
- package/node_modules/@delexec/caller-controller-core/package.json +26 -0
- package/node_modules/@delexec/caller-controller-core/src/index.js +1612 -0
- package/node_modules/@delexec/caller-skill-adapter/package.json +12 -0
- package/node_modules/@delexec/caller-skill-adapter/src/server.js +1042 -0
- package/node_modules/@delexec/caller-skill-mcp-adapter/README.md +65 -0
- package/node_modules/@delexec/caller-skill-mcp-adapter/package.json +16 -0
- package/node_modules/@delexec/caller-skill-mcp-adapter/src/server.js +527 -0
- package/node_modules/@delexec/responder-controller/README.md +3 -0
- package/node_modules/@delexec/responder-controller/README.zh-CN.md +6 -0
- package/node_modules/@delexec/responder-controller/package.json +53 -0
- package/node_modules/@delexec/responder-controller/src/server.js +254 -0
- package/node_modules/@delexec/responder-runtime-core/README.md +3 -0
- package/node_modules/@delexec/responder-runtime-core/README.zh-CN.md +6 -0
- package/node_modules/@delexec/responder-runtime-core/package.json +26 -0
- package/node_modules/@delexec/responder-runtime-core/src/executors.js +326 -0
- package/node_modules/@delexec/responder-runtime-core/src/index.js +1202 -0
- package/node_modules/@delexec/runtime-utils/README.md +3 -0
- package/node_modules/@delexec/runtime-utils/README.zh-CN.md +6 -0
- package/node_modules/@delexec/runtime-utils/package.json +23 -0
- package/node_modules/@delexec/runtime-utils/src/index.js +338 -0
- package/node_modules/@delexec/sqlite-store/README.md +3 -0
- package/node_modules/@delexec/sqlite-store/README.zh-CN.md +6 -0
- package/node_modules/@delexec/sqlite-store/package.json +26 -0
- package/node_modules/@delexec/sqlite-store/src/index.js +68 -0
- package/node_modules/@delexec/transport-email/README.md +3 -0
- package/node_modules/@delexec/transport-email/README.zh-CN.md +6 -0
- package/node_modules/@delexec/transport-email/package.json +23 -0
- package/node_modules/@delexec/transport-email/src/index.js +185 -0
- package/node_modules/@delexec/transport-emailengine/README.md +3 -0
- package/node_modules/@delexec/transport-emailengine/README.zh-CN.md +6 -0
- package/node_modules/@delexec/transport-emailengine/package.json +26 -0
- package/node_modules/@delexec/transport-emailengine/src/index.js +210 -0
- package/node_modules/@delexec/transport-gmail/README.md +3 -0
- package/node_modules/@delexec/transport-gmail/README.zh-CN.md +6 -0
- package/node_modules/@delexec/transport-gmail/package.json +26 -0
- package/node_modules/@delexec/transport-gmail/src/index.js +295 -0
- package/node_modules/@delexec/transport-relay-http/README.md +3 -0
- package/node_modules/@delexec/transport-relay-http/README.zh-CN.md +6 -0
- package/node_modules/@delexec/transport-relay-http/package.json +23 -0
- package/node_modules/@delexec/transport-relay-http/src/index.js +124 -0
- package/package.json +64 -0
- package/src/cli.js +1571 -0
- package/src/config.js +1180 -0
- package/src/example-hotline-worker.js +65 -0
- package/src/example-hotline.js +196 -0
- package/src/logging.js +56 -0
- package/src/supervisor.js +3070 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildEmailSubject,
|
|
3
|
+
buildRspHeaders,
|
|
4
|
+
isRspEmailSubject,
|
|
5
|
+
normalizeEnvelope,
|
|
6
|
+
RSP_EMAIL_SUBJECT_PREFIX
|
|
7
|
+
} from "@delexec/transport-email";
|
|
8
|
+
|
|
9
|
+
function base64UrlEncode(buffer) {
|
|
10
|
+
return Buffer.from(buffer)
|
|
11
|
+
.toString("base64")
|
|
12
|
+
.replace(/\+/g, "-")
|
|
13
|
+
.replace(/\//g, "_")
|
|
14
|
+
.replace(/=+$/g, "");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function base64UrlDecode(value) {
|
|
18
|
+
const normalized = String(value || "").replace(/-/g, "+").replace(/_/g, "/");
|
|
19
|
+
const pad = normalized.length % 4 === 0 ? "" : "=".repeat(4 - (normalized.length % 4));
|
|
20
|
+
return Buffer.from(normalized + pad, "base64");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function request(url, { method = "GET", headers = {}, body } = {}) {
|
|
24
|
+
const response = await fetch(url, {
|
|
25
|
+
method,
|
|
26
|
+
headers,
|
|
27
|
+
body
|
|
28
|
+
});
|
|
29
|
+
const text = await response.text();
|
|
30
|
+
return {
|
|
31
|
+
status: response.status,
|
|
32
|
+
headers: response.headers,
|
|
33
|
+
body: text ? JSON.parse(text) : null
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function authHeaders(accessToken, extra = {}) {
|
|
38
|
+
return {
|
|
39
|
+
Authorization: `Bearer ${accessToken}`,
|
|
40
|
+
...extra
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function refreshAccessToken({ tokenUrl, clientId, clientSecret, refreshToken }) {
|
|
45
|
+
const response = await request(tokenUrl, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"content-type": "application/x-www-form-urlencoded"
|
|
49
|
+
},
|
|
50
|
+
body: new URLSearchParams({
|
|
51
|
+
client_id: clientId,
|
|
52
|
+
client_secret: clientSecret,
|
|
53
|
+
refresh_token: refreshToken,
|
|
54
|
+
grant_type: "refresh_token"
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
if (response.status !== 200 || !response.body?.access_token) {
|
|
58
|
+
throw new Error(`gmail_token_refresh_failed:${response.status}`);
|
|
59
|
+
}
|
|
60
|
+
return response.body.access_token;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function buildMimeMessage(envelope) {
|
|
64
|
+
const normalized = normalizeEnvelope(envelope);
|
|
65
|
+
const headers = buildRspHeaders(normalized);
|
|
66
|
+
const headerLines = [
|
|
67
|
+
`From: ${normalized.from}`,
|
|
68
|
+
`To: ${normalized.to}`,
|
|
69
|
+
`Subject: ${buildEmailSubject(normalized)}`,
|
|
70
|
+
"MIME-Version: 1.0"
|
|
71
|
+
];
|
|
72
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
73
|
+
headerLines.push(`${key}: ${value}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (normalized.attachments.length === 0) {
|
|
77
|
+
return `${headerLines.join("\r\n")}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${normalized.body_text}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const boundary = `rsp-${normalized.message_id}`;
|
|
81
|
+
const parts = [
|
|
82
|
+
`--${boundary}\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${normalized.body_text}\r\n`
|
|
83
|
+
];
|
|
84
|
+
for (const attachment of normalized.attachments) {
|
|
85
|
+
parts.push(
|
|
86
|
+
`--${boundary}\r\nContent-Type: ${attachment.media_type}\r\nContent-Disposition: attachment; filename="${attachment.name}"\r\nContent-Transfer-Encoding: base64\r\n\r\n${attachment.content_base64}\r\n`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
parts.push(`--${boundary}--`);
|
|
90
|
+
return `${headerLines.join("\r\n")}\r\nContent-Type: multipart/mixed; boundary="${boundary}"\r\n\r\n${parts.join("")}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function findHeader(headers = [], name) {
|
|
94
|
+
const match = headers.find((header) => String(header.name || "").toLowerCase() === String(name).toLowerCase());
|
|
95
|
+
return match?.value || null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function walkParts(part, visitor) {
|
|
99
|
+
if (!part) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
visitor(part);
|
|
103
|
+
for (const child of part.parts || []) {
|
|
104
|
+
walkParts(child, visitor);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function extractPlainText(payload) {
|
|
109
|
+
if (!payload) {
|
|
110
|
+
return "";
|
|
111
|
+
}
|
|
112
|
+
let text = "";
|
|
113
|
+
walkParts(payload, (part) => {
|
|
114
|
+
if (text) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (part.mimeType === "text/plain" && part.body?.data) {
|
|
118
|
+
text = base64UrlDecode(part.body.data).toString("utf8");
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
if (!text && payload.body?.data) {
|
|
122
|
+
text = base64UrlDecode(payload.body.data).toString("utf8");
|
|
123
|
+
}
|
|
124
|
+
return text;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function extractAttachments(apiBaseUrl, user, accessToken, messageId, payload) {
|
|
128
|
+
const attachments = [];
|
|
129
|
+
const parts = [];
|
|
130
|
+
walkParts(payload, (part) => {
|
|
131
|
+
if (part.filename && (part.body?.attachmentId || part.body?.data)) {
|
|
132
|
+
parts.push(part);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
for (const part of parts) {
|
|
136
|
+
let content;
|
|
137
|
+
if (part.body?.data) {
|
|
138
|
+
content = base64UrlDecode(part.body.data);
|
|
139
|
+
} else {
|
|
140
|
+
const response = await request(
|
|
141
|
+
`${apiBaseUrl}/users/${encodeURIComponent(user)}/messages/${encodeURIComponent(messageId)}/attachments/${encodeURIComponent(part.body.attachmentId)}`,
|
|
142
|
+
{
|
|
143
|
+
headers: authHeaders(accessToken)
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
if (response.status !== 200) {
|
|
147
|
+
throw new Error(`gmail_attachment_fetch_failed:${response.status}`);
|
|
148
|
+
}
|
|
149
|
+
content = base64UrlDecode(response.body?.data || "");
|
|
150
|
+
}
|
|
151
|
+
attachments.push({
|
|
152
|
+
attachment_id: part.body?.attachmentId || null,
|
|
153
|
+
name: part.filename,
|
|
154
|
+
media_type: part.mimeType || "application/octet-stream",
|
|
155
|
+
content_base64: content.toString("base64"),
|
|
156
|
+
byte_size: content.length
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return attachments;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function loadMessage(apiBaseUrl, user, accessToken, message) {
|
|
163
|
+
const response = await request(`${apiBaseUrl}/users/${encodeURIComponent(user)}/messages/${encodeURIComponent(message.id)}?format=full`, {
|
|
164
|
+
headers: authHeaders(accessToken)
|
|
165
|
+
});
|
|
166
|
+
if (response.status !== 200) {
|
|
167
|
+
throw new Error(`gmail_message_fetch_failed:${response.status}`);
|
|
168
|
+
}
|
|
169
|
+
const payload = response.body?.payload || {};
|
|
170
|
+
const headers = payload.headers || [];
|
|
171
|
+
const attachments = await extractAttachments(apiBaseUrl, user, accessToken, message.id, payload);
|
|
172
|
+
const textBody = extractPlainText(payload);
|
|
173
|
+
let parsedPayload = null;
|
|
174
|
+
try {
|
|
175
|
+
parsedPayload = textBody ? JSON.parse(textBody) : null;
|
|
176
|
+
} catch {
|
|
177
|
+
parsedPayload = null;
|
|
178
|
+
}
|
|
179
|
+
return normalizeEnvelope({
|
|
180
|
+
message_id: response.body?.id || message.id,
|
|
181
|
+
thread_id: response.body?.threadId || message.threadId || null,
|
|
182
|
+
thread_hint: response.body?.threadId || message.threadId || null,
|
|
183
|
+
request_id: findHeader(headers, "X-RSP-Request-Id") || parsedPayload?.request_id,
|
|
184
|
+
from: findHeader(headers, "From"),
|
|
185
|
+
to: findHeader(headers, "To"),
|
|
186
|
+
subject: findHeader(headers, "Subject"),
|
|
187
|
+
type: findHeader(headers, "X-RSP-Type") || parsedPayload?.type || "email.message",
|
|
188
|
+
body_text: textBody,
|
|
189
|
+
payload: parsedPayload,
|
|
190
|
+
attachments
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function createGmailTransportAdapter({
|
|
195
|
+
clientId,
|
|
196
|
+
clientSecret,
|
|
197
|
+
refreshToken,
|
|
198
|
+
user,
|
|
199
|
+
receiver = user,
|
|
200
|
+
sender = user,
|
|
201
|
+
apiBaseUrl = "https://gmail.googleapis.com/gmail/v1",
|
|
202
|
+
tokenUrl = "https://oauth2.googleapis.com/token"
|
|
203
|
+
}) {
|
|
204
|
+
if (!clientId) {
|
|
205
|
+
throw new Error("gmail_client_id_required");
|
|
206
|
+
}
|
|
207
|
+
if (!clientSecret) {
|
|
208
|
+
throw new Error("gmail_client_secret_required");
|
|
209
|
+
}
|
|
210
|
+
if (!refreshToken) {
|
|
211
|
+
throw new Error("gmail_refresh_token_required");
|
|
212
|
+
}
|
|
213
|
+
if (!user) {
|
|
214
|
+
throw new Error("gmail_user_required");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
async send(envelope) {
|
|
219
|
+
const normalized = normalizeEnvelope({
|
|
220
|
+
...envelope,
|
|
221
|
+
from: envelope.from || sender,
|
|
222
|
+
to: envelope.to || receiver
|
|
223
|
+
});
|
|
224
|
+
const accessToken = await refreshAccessToken({ tokenUrl, clientId, clientSecret, refreshToken });
|
|
225
|
+
const raw = base64UrlEncode(Buffer.from(buildMimeMessage(normalized), "utf8"));
|
|
226
|
+
const response = await request(`${apiBaseUrl}/users/${encodeURIComponent(user)}/messages/send`, {
|
|
227
|
+
method: "POST",
|
|
228
|
+
headers: authHeaders(accessToken, {
|
|
229
|
+
"content-type": "application/json; charset=utf-8"
|
|
230
|
+
}),
|
|
231
|
+
body: JSON.stringify({ raw })
|
|
232
|
+
});
|
|
233
|
+
if (response.status !== 200) {
|
|
234
|
+
throw new Error(`gmail_send_failed:${response.status}`);
|
|
235
|
+
}
|
|
236
|
+
return normalized;
|
|
237
|
+
},
|
|
238
|
+
|
|
239
|
+
async poll({ limit = 10 } = {}) {
|
|
240
|
+
const accessToken = await refreshAccessToken({ tokenUrl, clientId, clientSecret, refreshToken });
|
|
241
|
+
const query = new URLSearchParams({
|
|
242
|
+
q: `in:inbox is:unread subject:"${RSP_EMAIL_SUBJECT_PREFIX}"`,
|
|
243
|
+
maxResults: String(limit)
|
|
244
|
+
});
|
|
245
|
+
const response = await request(`${apiBaseUrl}/users/${encodeURIComponent(user)}/messages?${query.toString()}`, {
|
|
246
|
+
headers: authHeaders(accessToken)
|
|
247
|
+
});
|
|
248
|
+
if (response.status !== 200) {
|
|
249
|
+
throw new Error(`gmail_poll_failed:${response.status}`);
|
|
250
|
+
}
|
|
251
|
+
const items = [];
|
|
252
|
+
for (const message of response.body?.messages || []) {
|
|
253
|
+
const loaded = await loadMessage(apiBaseUrl, user, accessToken, message);
|
|
254
|
+
if (!isRspEmailSubject(loaded.subject || "")) {
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
items.push(loaded);
|
|
258
|
+
}
|
|
259
|
+
return { items };
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
async ack(messageId) {
|
|
263
|
+
const accessToken = await refreshAccessToken({ tokenUrl, clientId, clientSecret, refreshToken });
|
|
264
|
+
const response = await request(`${apiBaseUrl}/users/${encodeURIComponent(user)}/messages/${encodeURIComponent(messageId)}/modify`, {
|
|
265
|
+
method: "POST",
|
|
266
|
+
headers: authHeaders(accessToken, {
|
|
267
|
+
"content-type": "application/json; charset=utf-8"
|
|
268
|
+
}),
|
|
269
|
+
body: JSON.stringify({
|
|
270
|
+
removeLabelIds: ["UNREAD"]
|
|
271
|
+
})
|
|
272
|
+
});
|
|
273
|
+
if (response.status !== 200) {
|
|
274
|
+
throw new Error(`gmail_ack_failed:${response.status}`);
|
|
275
|
+
}
|
|
276
|
+
return { acked: true };
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
async health() {
|
|
280
|
+
const accessToken = await refreshAccessToken({ tokenUrl, clientId, clientSecret, refreshToken });
|
|
281
|
+
const response = await request(`${apiBaseUrl}/users/${encodeURIComponent(user)}/profile`, {
|
|
282
|
+
headers: authHeaders(accessToken)
|
|
283
|
+
});
|
|
284
|
+
if (response.status !== 200) {
|
|
285
|
+
throw new Error(`gmail_health_failed:${response.status}`);
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
ok: true,
|
|
289
|
+
provider: "gmail",
|
|
290
|
+
version: "gmail/v1",
|
|
291
|
+
user
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@delexec/transport-relay-http",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "HTTP relay transport adapter for delegated execution",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js",
|
|
9
|
+
"./package.json": "./package.json"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"src",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"delegated-execution",
|
|
20
|
+
"transport",
|
|
21
|
+
"relay"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
|
|
3
|
+
function nowIso() {
|
|
4
|
+
return new Date().toISOString();
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function resolveReceiver(target) {
|
|
8
|
+
if (!target || typeof target !== "string" || !target.startsWith("local://")) {
|
|
9
|
+
return target;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const parsed = new URL(target);
|
|
14
|
+
const segments = parsed.pathname.split("/").filter(Boolean);
|
|
15
|
+
if (parsed.hostname === "relay" && segments[0]) {
|
|
16
|
+
return segments[0];
|
|
17
|
+
}
|
|
18
|
+
if (segments[0]) {
|
|
19
|
+
return segments[0];
|
|
20
|
+
}
|
|
21
|
+
if (parsed.hostname) {
|
|
22
|
+
return parsed.hostname;
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
return target;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return target;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function requestJson(baseUrl, pathname, { method = "GET", body } = {}) {
|
|
32
|
+
const response = await fetch(new URL(pathname, baseUrl), {
|
|
33
|
+
method,
|
|
34
|
+
headers: body === undefined ? undefined : { "content-type": "application/json; charset=utf-8" },
|
|
35
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
36
|
+
});
|
|
37
|
+
const text = await response.text();
|
|
38
|
+
return {
|
|
39
|
+
status: response.status,
|
|
40
|
+
body: text ? JSON.parse(text) : null
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createRelayHttpTransportAdapter({ baseUrl, receiver }) {
|
|
45
|
+
if (!baseUrl) {
|
|
46
|
+
throw new Error("relay_http_base_url_required");
|
|
47
|
+
}
|
|
48
|
+
if (!receiver) {
|
|
49
|
+
throw new Error("relay_http_receiver_required");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
async send(envelope) {
|
|
54
|
+
const target = resolveReceiver(envelope.to || envelope.responder_id || receiver);
|
|
55
|
+
const message = {
|
|
56
|
+
...envelope,
|
|
57
|
+
to: envelope.to || target,
|
|
58
|
+
message_id: envelope.message_id || `msg_${crypto.randomUUID()}`,
|
|
59
|
+
queued_at: envelope.queued_at || nowIso()
|
|
60
|
+
};
|
|
61
|
+
const response = await requestJson(baseUrl, "/v1/messages/send", {
|
|
62
|
+
method: "POST",
|
|
63
|
+
body: {
|
|
64
|
+
receiver: target,
|
|
65
|
+
envelope: message
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
if (response.status !== 201) {
|
|
69
|
+
throw new Error(`relay_http_send_failed:${response.status}`);
|
|
70
|
+
}
|
|
71
|
+
return response.body;
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
async poll({ limit = 10, receiver: overrideReceiver } = {}) {
|
|
75
|
+
const response = await requestJson(baseUrl, "/v1/messages/poll", {
|
|
76
|
+
method: "POST",
|
|
77
|
+
body: {
|
|
78
|
+
receiver: overrideReceiver || receiver,
|
|
79
|
+
limit
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
if (response.status !== 200) {
|
|
83
|
+
throw new Error(`relay_http_poll_failed:${response.status}`);
|
|
84
|
+
}
|
|
85
|
+
return response.body;
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
async ack(messageId, { receiver: overrideReceiver } = {}) {
|
|
89
|
+
const response = await requestJson(baseUrl, "/v1/messages/ack", {
|
|
90
|
+
method: "POST",
|
|
91
|
+
body: {
|
|
92
|
+
receiver: overrideReceiver || receiver,
|
|
93
|
+
message_id: messageId
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
if (response.status !== 200) {
|
|
97
|
+
throw new Error(`relay_http_ack_failed:${response.status}`);
|
|
98
|
+
}
|
|
99
|
+
return response.body;
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
async peek({ thread_id, receiver: overrideReceiver } = {}) {
|
|
103
|
+
const params = new URLSearchParams({
|
|
104
|
+
receiver: overrideReceiver || receiver
|
|
105
|
+
});
|
|
106
|
+
if (thread_id) {
|
|
107
|
+
params.set("thread_id", thread_id);
|
|
108
|
+
}
|
|
109
|
+
const response = await requestJson(baseUrl, `/v1/messages/peek?${params.toString()}`);
|
|
110
|
+
if (response.status !== 200) {
|
|
111
|
+
throw new Error(`relay_http_peek_failed:${response.status}`);
|
|
112
|
+
}
|
|
113
|
+
return response.body;
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
async health() {
|
|
117
|
+
const response = await requestJson(baseUrl, `/v1/receivers/${encodeURIComponent(receiver)}/health`);
|
|
118
|
+
if (response.status !== 200) {
|
|
119
|
+
throw new Error(`relay_http_health_failed:${response.status}`);
|
|
120
|
+
}
|
|
121
|
+
return response.body;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@delexec/ops",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Unified operator CLI for delegated execution clients",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"delexec-ops": "src/cli.js",
|
|
8
|
+
"croc-ops": "src/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"bundleDependencies": [
|
|
11
|
+
"@delexec/caller-controller",
|
|
12
|
+
"@delexec/caller-controller-core",
|
|
13
|
+
"@delexec/caller-skill-mcp-adapter",
|
|
14
|
+
"@delexec/caller-skill-adapter",
|
|
15
|
+
"@delexec/runtime-utils",
|
|
16
|
+
"@delexec/responder-controller",
|
|
17
|
+
"@delexec/responder-runtime-core",
|
|
18
|
+
"@delexec/sqlite-store",
|
|
19
|
+
"@delexec/transport-email",
|
|
20
|
+
"@delexec/transport-emailengine",
|
|
21
|
+
"@delexec/transport-gmail",
|
|
22
|
+
"@delexec/transport-relay-http"
|
|
23
|
+
],
|
|
24
|
+
"main": "src/cli.js",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": "./src/cli.js",
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"src",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"prepack": "node ../../scripts/bundle-workspace-deps.mjs stage apps/ops",
|
|
35
|
+
"postpack": "node ../../scripts/bundle-workspace-deps.mjs cleanup apps/ops",
|
|
36
|
+
"start": "node src/cli.js"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"delegated-execution",
|
|
43
|
+
"ops",
|
|
44
|
+
"cli"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@delexec/caller-controller": "0.1.0",
|
|
48
|
+
"@delexec/caller-controller-core": "0.1.0",
|
|
49
|
+
"@delexec/caller-skill-mcp-adapter": "0.1.0",
|
|
50
|
+
"@delexec/caller-skill-adapter": "0.1.0",
|
|
51
|
+
"@delexec/contracts": "^0.1.0",
|
|
52
|
+
"@delexec/runtime-utils": "0.1.0",
|
|
53
|
+
"@delexec/responder-controller": "0.1.0",
|
|
54
|
+
"@delexec/responder-runtime-core": "0.1.0",
|
|
55
|
+
"@delexec/sqlite-store": "0.1.0",
|
|
56
|
+
"@delexec/transport-email": "0.1.0",
|
|
57
|
+
"@delexec/transport-emailengine": "0.1.0",
|
|
58
|
+
"@delexec/transport-gmail": "0.1.0",
|
|
59
|
+
"@delexec/transport-relay-http": "0.1.0",
|
|
60
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
61
|
+
"better-sqlite3": "^12.6.2",
|
|
62
|
+
"zod": "^4.1.12"
|
|
63
|
+
}
|
|
64
|
+
}
|