aamp-openclaw-plugin 0.1.37 → 0.1.38
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/bin/aamp-openclaw-plugin.mjs +7 -41
- package/dist/index.js +51 -77
- package/dist/index.js.map +3 -3
- package/package.json +2 -1
|
@@ -8,6 +8,7 @@ import { stdin as input, stdout as output, stderr } from 'node:process'
|
|
|
8
8
|
import { spawnSync } from 'node:child_process'
|
|
9
9
|
import { createRequire } from 'node:module'
|
|
10
10
|
import { fileURLToPath } from 'node:url'
|
|
11
|
+
import { AampClient } from 'aamp-sdk'
|
|
11
12
|
|
|
12
13
|
const PLUGIN_ID = 'aamp-openclaw-plugin'
|
|
13
14
|
const DEFAULT_AAMP_HOST = 'https://meshmail.ai'
|
|
@@ -444,50 +445,15 @@ export async function ensureMailboxIdentity({ aampHost, slug, credentialsFile })
|
|
|
444
445
|
}
|
|
445
446
|
}
|
|
446
447
|
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
throw new Error(`AAMP discovery failed (${discoveryRes.status}): ${text || discoveryRes.statusText}`)
|
|
452
|
-
}
|
|
453
|
-
const discovery = await discoveryRes.json()
|
|
454
|
-
const apiUrl = discovery?.api?.url
|
|
455
|
-
if (!apiUrl) {
|
|
456
|
-
throw new Error('AAMP discovery did not return api.url')
|
|
457
|
-
}
|
|
458
|
-
const apiBase = new URL(apiUrl, `${base}/`).toString()
|
|
459
|
-
|
|
460
|
-
const registerRes = await fetch(`${apiBase}?action=aamp.mailbox.register`, {
|
|
461
|
-
method: 'POST',
|
|
462
|
-
headers: { 'Content-Type': 'application/json' },
|
|
463
|
-
body: JSON.stringify({
|
|
464
|
-
slug,
|
|
465
|
-
description: 'OpenClaw AAMP agent node',
|
|
466
|
-
}),
|
|
448
|
+
const credData = await AampClient.registerMailbox({
|
|
449
|
+
aampHost: normalizeBaseUrl(aampHost),
|
|
450
|
+
slug,
|
|
451
|
+
description: 'OpenClaw AAMP agent node',
|
|
467
452
|
})
|
|
468
|
-
|
|
469
|
-
if (!registerRes.ok) {
|
|
470
|
-
const text = await registerRes.text().catch(() => '')
|
|
471
|
-
throw new Error(`AAMP self-register failed (${registerRes.status}): ${text || registerRes.statusText}`)
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
const registerData = await registerRes.json()
|
|
475
|
-
const code = registerData?.registrationCode
|
|
476
|
-
if (!code) {
|
|
477
|
-
throw new Error('AAMP self-register succeeded but no registrationCode was returned')
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
const credRes = await fetch(`${apiBase}?action=aamp.mailbox.credentials&code=${encodeURIComponent(code)}`)
|
|
481
|
-
if (!credRes.ok) {
|
|
482
|
-
const text = await credRes.text().catch(() => '')
|
|
483
|
-
throw new Error(`AAMP credential exchange failed (${credRes.status}): ${text || credRes.statusText}`)
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
const credData = await credRes.json()
|
|
487
453
|
const identity = {
|
|
488
454
|
email: credData?.email,
|
|
489
|
-
mailboxToken: credData?.
|
|
490
|
-
smtpPassword: credData?.
|
|
455
|
+
mailboxToken: credData?.mailboxToken,
|
|
456
|
+
smtpPassword: credData?.smtpPassword,
|
|
491
457
|
}
|
|
492
458
|
|
|
493
459
|
if (!identity.email || !identity.mailboxToken || !identity.smtpPassword) {
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
// ../sdk/
|
|
1
|
+
// ../sdk/dist/jmap-push.js
|
|
2
2
|
import WebSocket from "ws";
|
|
3
3
|
|
|
4
|
-
// ../sdk/
|
|
4
|
+
// ../sdk/dist/types.js
|
|
5
5
|
var AAMP_PROTOCOL_VERSION = "1.1";
|
|
6
6
|
var AAMP_HEADER = {
|
|
7
7
|
VERSION: "X-AAMP-Version",
|
|
8
8
|
INTENT: "X-AAMP-Intent",
|
|
9
9
|
TASK_ID: "X-AAMP-TaskId",
|
|
10
|
+
SESSION_KEY: "X-AAMP-Session-Key",
|
|
10
11
|
CONTEXT_LINKS: "X-AAMP-ContextLinks",
|
|
11
12
|
DISPATCH_CONTEXT: "X-AAMP-Dispatch-Context",
|
|
12
13
|
PRIORITY: "X-AAMP-Priority",
|
|
@@ -23,7 +24,7 @@ var AAMP_HEADER = {
|
|
|
23
24
|
CARD_SUMMARY: "X-AAMP-Card-Summary"
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
// ../sdk/
|
|
27
|
+
// ../sdk/dist/parser.js
|
|
27
28
|
function normalizeBodyText(value) {
|
|
28
29
|
return value?.replace(/\r\n/g, "\n").trim() ?? "";
|
|
29
30
|
}
|
|
@@ -171,6 +172,7 @@ function parseAampHeaders(meta) {
|
|
|
171
172
|
if (intent === "task.dispatch") {
|
|
172
173
|
const contextLinksStr = getAampHeader(headers, AAMP_HEADER.CONTEXT_LINKS) ?? "";
|
|
173
174
|
const dispatchContext = parseDispatchContextHeader(getAampHeader(headers, AAMP_HEADER.DISPATCH_CONTEXT));
|
|
175
|
+
const sessionKey = getAampHeader(headers, AAMP_HEADER.SESSION_KEY);
|
|
174
176
|
const parentTaskId = getAampHeader(headers, AAMP_HEADER.PARENT_TASK_ID);
|
|
175
177
|
const priority = getAampHeader(headers, AAMP_HEADER.PRIORITY) ?? "normal";
|
|
176
178
|
const expiresAt = getAampHeader(headers, AAMP_HEADER.EXPIRES_AT);
|
|
@@ -178,6 +180,7 @@ function parseAampHeaders(meta) {
|
|
|
178
180
|
protocolVersion,
|
|
179
181
|
intent: "task.dispatch",
|
|
180
182
|
taskId,
|
|
183
|
+
...sessionKey ? { sessionKey } : {},
|
|
181
184
|
title: decodedSubject.replace(/^\[AAMP Task\]\s*/, "").trim() || "Untitled Task",
|
|
182
185
|
priority: priority === "urgent" || priority === "high" ? priority : "normal",
|
|
183
186
|
...expiresAt ? { expiresAt } : {},
|
|
@@ -310,6 +313,9 @@ function buildDispatchHeaders(params) {
|
|
|
310
313
|
if (params.expiresAt) {
|
|
311
314
|
headers[AAMP_HEADER.EXPIRES_AT] = params.expiresAt;
|
|
312
315
|
}
|
|
316
|
+
if (params.sessionKey?.trim()) {
|
|
317
|
+
headers[AAMP_HEADER.SESSION_KEY] = params.sessionKey.trim();
|
|
318
|
+
}
|
|
313
319
|
if (params.contextLinks.length > 0) {
|
|
314
320
|
headers[AAMP_HEADER.CONTEXT_LINKS] = params.contextLinks.join(",");
|
|
315
321
|
}
|
|
@@ -381,7 +387,7 @@ function buildCardResponseHeaders(params) {
|
|
|
381
387
|
};
|
|
382
388
|
}
|
|
383
389
|
|
|
384
|
-
// ../sdk/
|
|
390
|
+
// ../sdk/dist/tiny-emitter.js
|
|
385
391
|
var TinyEmitter = class {
|
|
386
392
|
listeners = /* @__PURE__ */ new Map();
|
|
387
393
|
onceWrappers = /* @__PURE__ */ new WeakMap();
|
|
@@ -434,7 +440,7 @@ var TinyEmitter = class {
|
|
|
434
440
|
}
|
|
435
441
|
};
|
|
436
442
|
|
|
437
|
-
// ../sdk/
|
|
443
|
+
// ../sdk/dist/jmap-push.js
|
|
438
444
|
function describeError(err) {
|
|
439
445
|
if (!(err instanceof Error))
|
|
440
446
|
return String(err);
|
|
@@ -1114,7 +1120,7 @@ var JmapPushClient = class extends TinyEmitter {
|
|
|
1114
1120
|
}
|
|
1115
1121
|
};
|
|
1116
1122
|
|
|
1117
|
-
// ../sdk/
|
|
1123
|
+
// ../sdk/dist/smtp-sender.js
|
|
1118
1124
|
import { createTransport } from "nodemailer";
|
|
1119
1125
|
import { randomUUID } from "crypto";
|
|
1120
1126
|
var sanitize = (s) => s.replace(/[\r\n]/g, " ").trim();
|
|
@@ -1372,7 +1378,7 @@ var SmtpSender = class _SmtpSender {
|
|
|
1372
1378
|
from: this.config.user,
|
|
1373
1379
|
to: opts.to,
|
|
1374
1380
|
subject: `[AAMP Task] ${sanitize(opts.title)}`,
|
|
1375
|
-
text: [
|
|
1381
|
+
text: opts.rawBodyText ?? [
|
|
1376
1382
|
`Task: ${opts.title}`,
|
|
1377
1383
|
`Task ID: ${taskId}`,
|
|
1378
1384
|
`Priority: ${opts.priority ?? "normal"}`,
|
|
@@ -1440,7 +1446,7 @@ ${opts.contextLinks.map((l) => ` ${l}`).join("\n")}` : "",
|
|
|
1440
1446
|
from: this.config.user,
|
|
1441
1447
|
to: opts.to,
|
|
1442
1448
|
subject: `[AAMP Result] Task ${opts.taskId} \u2014 ${opts.status}`,
|
|
1443
|
-
text: [
|
|
1449
|
+
text: opts.rawBodyText ?? [
|
|
1444
1450
|
`AAMP Task Result`,
|
|
1445
1451
|
``,
|
|
1446
1452
|
`Task ID: ${opts.taskId}`,
|
|
@@ -1514,7 +1520,7 @@ Error: ${opts.errorMsg}` : ""
|
|
|
1514
1520
|
from: this.config.user,
|
|
1515
1521
|
to: opts.to,
|
|
1516
1522
|
subject: `[AAMP Help] Task ${opts.taskId} needs assistance`,
|
|
1517
|
-
text: [
|
|
1523
|
+
text: opts.rawBodyText ?? [
|
|
1518
1524
|
`AAMP Task Help Request`,
|
|
1519
1525
|
``,
|
|
1520
1526
|
`Task ID: ${opts.taskId}`,
|
|
@@ -1830,7 +1836,7 @@ Stream ID: ${opts.streamId}`,
|
|
|
1830
1836
|
}
|
|
1831
1837
|
};
|
|
1832
1838
|
|
|
1833
|
-
// ../sdk/
|
|
1839
|
+
// ../sdk/dist/thread.js
|
|
1834
1840
|
function singleLine(value, maxLength = 220) {
|
|
1835
1841
|
const normalized = (value ?? "").replace(/\s+/g, " ").trim();
|
|
1836
1842
|
if (!normalized)
|
|
@@ -1884,7 +1890,7 @@ function renderThreadHistoryForAgent(events, options = {}) {
|
|
|
1884
1890
|
].join("\n");
|
|
1885
1891
|
}
|
|
1886
1892
|
|
|
1887
|
-
// ../sdk/
|
|
1893
|
+
// ../sdk/dist/client.js
|
|
1888
1894
|
function buildRegisteredCommandDispatchPayload(opts) {
|
|
1889
1895
|
const command = opts.command.trim();
|
|
1890
1896
|
if (!command) {
|
|
@@ -2088,6 +2094,22 @@ var AampClient = class _AampClient extends TinyEmitter {
|
|
|
2088
2094
|
baseUrl: base
|
|
2089
2095
|
};
|
|
2090
2096
|
}
|
|
2097
|
+
static async checkMailbox(opts) {
|
|
2098
|
+
const base = opts.aampHost.replace(/\/$/, "");
|
|
2099
|
+
const res = await _AampClient.callDiscoveredApi(base, {
|
|
2100
|
+
action: "aamp.mailbox.check",
|
|
2101
|
+
query: { email: opts.email }
|
|
2102
|
+
});
|
|
2103
|
+
if (!res.ok) {
|
|
2104
|
+
const body = await res.text().catch(() => "");
|
|
2105
|
+
throw new Error(`Mailbox check failed: ${res.status} ${body || res.statusText}`);
|
|
2106
|
+
}
|
|
2107
|
+
const payload = await res.json();
|
|
2108
|
+
return {
|
|
2109
|
+
aamp: Boolean(payload.aamp),
|
|
2110
|
+
...payload.domain ? { domain: payload.domain } : {}
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2091
2113
|
// =====================================================
|
|
2092
2114
|
// Lifecycle
|
|
2093
2115
|
// =====================================================
|
|
@@ -2134,6 +2156,7 @@ var AampClient = class _AampClient extends TinyEmitter {
|
|
|
2134
2156
|
rawBodyText: JSON.stringify(payload, null, 2),
|
|
2135
2157
|
priority: opts.priority,
|
|
2136
2158
|
expiresAt: opts.expiresAt,
|
|
2159
|
+
sessionKey: opts.sessionKey,
|
|
2137
2160
|
contextLinks: opts.contextLinks,
|
|
2138
2161
|
dispatchContext: opts.dispatchContext,
|
|
2139
2162
|
parentTaskId: opts.parentTaskId,
|
|
@@ -2756,17 +2779,8 @@ function isTaskAwaitingHelpReply(task) {
|
|
|
2756
2779
|
return task.awaitingHelpReply === true;
|
|
2757
2780
|
}
|
|
2758
2781
|
function isConversationalTask(task) {
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
function firstDispatchContextValue(context, keys) {
|
|
2762
|
-
if (!context)
|
|
2763
|
-
return void 0;
|
|
2764
|
-
for (const key of keys) {
|
|
2765
|
-
const value = context[key]?.trim();
|
|
2766
|
-
if (value)
|
|
2767
|
-
return value;
|
|
2768
|
-
}
|
|
2769
|
-
return void 0;
|
|
2782
|
+
const source = task.dispatchContext?.source?.trim().toLowerCase();
|
|
2783
|
+
return source === "feishu" || source === "wechat";
|
|
2770
2784
|
}
|
|
2771
2785
|
function threadAlreadyTerminal(events) {
|
|
2772
2786
|
return (events ?? []).some(
|
|
@@ -2814,8 +2828,8 @@ function buildOpenClawMainSessionKey(mainKey, config) {
|
|
|
2814
2828
|
function buildAampConversationSessionKey(value, config) {
|
|
2815
2829
|
return buildOpenClawMainSessionKey(`${AAMP_SESSION_PREFIX}default:${value}`, config);
|
|
2816
2830
|
}
|
|
2817
|
-
function buildAampStickySessionKey(
|
|
2818
|
-
const stickyValue =
|
|
2831
|
+
function buildAampStickySessionKey(sessionKey, config) {
|
|
2832
|
+
const stickyValue = sessionKey?.trim();
|
|
2819
2833
|
if (!stickyValue)
|
|
2820
2834
|
return void 0;
|
|
2821
2835
|
return buildAampConversationSessionKey(`session:${stickyValue}`, config);
|
|
@@ -2827,10 +2841,10 @@ function buildAampWakeSessionKey(kind, id) {
|
|
|
2827
2841
|
return `${AAMP_SESSION_PREFIX}wake:${kind}:${id}`;
|
|
2828
2842
|
}
|
|
2829
2843
|
function buildSessionKeyForPendingTask(task, config) {
|
|
2830
|
-
return buildAampStickySessionKey(task.
|
|
2844
|
+
return buildAampStickySessionKey(task.sessionKey, config) ?? buildAampTaskSessionKey(task.taskId, config);
|
|
2831
2845
|
}
|
|
2832
2846
|
function buildWakeSessionKeyForPendingTask(task, config) {
|
|
2833
|
-
return buildAampStickySessionKey(task.
|
|
2847
|
+
return buildAampStickySessionKey(task.sessionKey, config) ?? buildAampWakeSessionKey("task", task.taskId);
|
|
2834
2848
|
}
|
|
2835
2849
|
function findPendingEntryForSession(sessionKey, config) {
|
|
2836
2850
|
if (typeof sessionKey !== "string" || !isAampSessionKey(sessionKey))
|
|
@@ -2952,39 +2966,15 @@ function queuePendingTask(task) {
|
|
|
2952
2966
|
}
|
|
2953
2967
|
async function registerNode(cfg) {
|
|
2954
2968
|
const slug = (cfg.slug ?? "openclaw-agent").toLowerCase().replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
2955
|
-
const
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
}
|
|
2960
|
-
const discovery = await discoveryRes.json();
|
|
2961
|
-
const apiUrl = discovery.api?.url;
|
|
2962
|
-
if (!apiUrl) {
|
|
2963
|
-
throw new Error("AAMP discovery did not return api.url");
|
|
2964
|
-
}
|
|
2965
|
-
const apiBase = new URL(apiUrl, `${base}/`).toString();
|
|
2966
|
-
const res = await fetch(`${apiBase}?action=aamp.mailbox.register`, {
|
|
2967
|
-
method: "POST",
|
|
2968
|
-
headers: { "Content-Type": "application/json" },
|
|
2969
|
-
body: JSON.stringify({ slug, description: "OpenClaw AAMP agent node" })
|
|
2969
|
+
const credData = await AampClient.registerMailbox({
|
|
2970
|
+
aampHost: cfg.aampHost,
|
|
2971
|
+
slug,
|
|
2972
|
+
description: "OpenClaw AAMP agent node"
|
|
2970
2973
|
});
|
|
2971
|
-
if (!res.ok) {
|
|
2972
|
-
const err = await res.json().catch(() => ({}));
|
|
2973
|
-
throw new Error(`AAMP registration failed (${res.status}): ${err.error ?? res.statusText}`);
|
|
2974
|
-
}
|
|
2975
|
-
const regData = await res.json();
|
|
2976
|
-
const credRes = await fetch(
|
|
2977
|
-
`${apiBase}?action=aamp.mailbox.credentials&code=${encodeURIComponent(regData.registrationCode)}`
|
|
2978
|
-
);
|
|
2979
|
-
if (!credRes.ok) {
|
|
2980
|
-
const err = await credRes.json().catch(() => ({}));
|
|
2981
|
-
throw new Error(`AAMP credential exchange failed (${credRes.status}): ${err.error ?? credRes.statusText}`);
|
|
2982
|
-
}
|
|
2983
|
-
const credData = await credRes.json();
|
|
2984
2974
|
return {
|
|
2985
2975
|
email: credData.email,
|
|
2986
|
-
mailboxToken: credData.
|
|
2987
|
-
smtpPassword: credData.
|
|
2976
|
+
mailboxToken: credData.mailboxToken,
|
|
2977
|
+
smtpPassword: credData.smtpPassword
|
|
2988
2978
|
};
|
|
2989
2979
|
}
|
|
2990
2980
|
async function resolveIdentity(cfg) {
|
|
@@ -4207,17 +4197,9 @@ ${lines.join("\n")}`
|
|
|
4207
4197
|
const dir = "/tmp/aamp-files";
|
|
4208
4198
|
ensureDir(dir);
|
|
4209
4199
|
const downloaded = [];
|
|
4210
|
-
const base = baseUrl(cfg.aampHost);
|
|
4211
|
-
const identity = loadCachedIdentity(cfg.credentialsFile ?? defaultCredentialsPath());
|
|
4212
|
-
const authHeader = identity ? `Basic ${Buffer.from(identity.email + ":" + identity.smtpPassword).toString("base64")}` : "";
|
|
4213
4200
|
for (const att of r.attachments) {
|
|
4214
4201
|
try {
|
|
4215
|
-
const
|
|
4216
|
-
api.logger.info(`[AAMP] Fetching ${dlUrl}`);
|
|
4217
|
-
const dlRes = await fetch(dlUrl, { headers: { Authorization: authHeader } });
|
|
4218
|
-
if (!dlRes.ok)
|
|
4219
|
-
throw new Error(`HTTP ${dlRes.status}`);
|
|
4220
|
-
const buffer = Buffer.from(await dlRes.arrayBuffer());
|
|
4202
|
+
const buffer = await aampClient.downloadBlob(att.blobId, att.filename);
|
|
4221
4203
|
const filepath = `${dir}/${att.filename}`;
|
|
4222
4204
|
writeBinaryFile(filepath, buffer);
|
|
4223
4205
|
downloaded.push(`${att.filename} (${(buffer.length / 1024).toFixed(1)} KB) \u2192 ${filepath}`);
|
|
@@ -4289,18 +4271,10 @@ Question: ${h.question}`,
|
|
|
4289
4271
|
return { content: [{ type: "text", text: "Error: email parameter is required" }] };
|
|
4290
4272
|
}
|
|
4291
4273
|
try {
|
|
4292
|
-
const
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
const apiUrl = discovery.api?.url;
|
|
4297
|
-
if (!apiUrl)
|
|
4298
|
-
throw new Error("AAMP discovery did not return api.url");
|
|
4299
|
-
const apiBase = new URL(apiUrl, `${base}/`).toString();
|
|
4300
|
-
const res = await fetch(`${apiBase}?action=aamp.mailbox.check&email=${encodeURIComponent(email)}`);
|
|
4301
|
-
if (!res.ok)
|
|
4302
|
-
throw new Error(`HTTP ${res.status}`);
|
|
4303
|
-
const data = await res.json();
|
|
4274
|
+
const data = await AampClient.checkMailbox({
|
|
4275
|
+
aampHost: base,
|
|
4276
|
+
email
|
|
4277
|
+
});
|
|
4304
4278
|
return {
|
|
4305
4279
|
content: [{
|
|
4306
4280
|
type: "text",
|