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.
@@ -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 base = normalizeBaseUrl(aampHost)
448
- const discoveryRes = await fetch(`${base}/.well-known/aamp`)
449
- if (!discoveryRes.ok) {
450
- const text = await discoveryRes.text().catch(() => '')
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?.mailbox?.token ?? credData?.jmap?.token,
490
- smtpPassword: credData?.smtp?.password,
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/src/jmap-push.js
1
+ // ../sdk/dist/jmap-push.js
2
2
  import WebSocket from "ws";
3
3
 
4
- // ../sdk/src/types.js
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/src/parser.js
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/src/tiny-emitter.js
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/src/jmap-push.js
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/src/smtp-sender.js
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/src/thread.js
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/src/client.js
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
- return task.dispatchContext?.source === "feishu";
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(dispatchContext, config) {
2818
- const stickyValue = firstDispatchContextValue(dispatchContext, ["session_key", "conversation_key", "thread_key"]);
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.dispatchContext, config) ?? buildAampTaskSessionKey(task.taskId, config);
2844
+ return buildAampStickySessionKey(task.sessionKey, config) ?? buildAampTaskSessionKey(task.taskId, config);
2831
2845
  }
2832
2846
  function buildWakeSessionKeyForPendingTask(task, config) {
2833
- return buildAampStickySessionKey(task.dispatchContext, config) ?? buildAampWakeSessionKey("task", task.taskId);
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 base = baseUrl(cfg.aampHost);
2956
- const discoveryRes = await fetch(`${base}/.well-known/aamp`);
2957
- if (!discoveryRes.ok) {
2958
- throw new Error(`AAMP discovery failed (${discoveryRes.status}): ${discoveryRes.statusText}`);
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.mailbox.token,
2987
- smtpPassword: credData.smtp.password
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 dlUrl = `${base}/jmap/download/n/${encodeURIComponent(att.blobId)}/${encodeURIComponent(att.filename)}?accept=application/octet-stream`;
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 discoveryRes = await fetch(`${base}/.well-known/aamp`);
4293
- if (!discoveryRes.ok)
4294
- throw new Error(`HTTP ${discoveryRes.status}`);
4295
- const discovery = await discoveryRes.json();
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",