@mnemom/mnemom 0.10.0 → 0.12.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 +25 -25
- package/dist/commands/agents.js +2 -7
- package/dist/commands/api-key.d.ts +37 -0
- package/dist/commands/api-key.js +179 -0
- package/dist/commands/auth.js +1 -2
- package/dist/commands/card.js +33 -22
- package/dist/commands/governance.d.ts +85 -0
- package/dist/commands/governance.js +329 -0
- package/dist/commands/integrity.js +1 -2
- package/dist/commands/license.js +13 -4
- package/dist/commands/listen.d.ts +29 -0
- package/dist/commands/listen.js +201 -0
- package/dist/commands/logs.js +1 -3
- package/dist/commands/org.js +4 -6
- package/dist/commands/protection.js +70 -23
- package/dist/commands/recipes.d.ts +34 -0
- package/dist/commands/recipes.js +80 -0
- package/dist/commands/status.js +6 -169
- package/dist/commands/team.js +5 -10
- package/dist/commands/validate.js +7 -4
- package/dist/commands/webhooks.d.ts +61 -0
- package/dist/commands/webhooks.js +328 -0
- package/dist/index.js +489 -1
- package/dist/lib/api.d.ts +199 -2
- package/dist/lib/api.js +207 -0
- package/dist/lib/auth.js +1 -5
- package/dist/lib/format.d.ts +4 -0
- package/dist/lib/format.js +6 -0
- package/dist/lib/listen-stream.d.ts +40 -0
- package/dist/lib/listen-stream.js +101 -0
- package/dist/lib/webhooks-api.d.ts +80 -0
- package/dist/lib/webhooks-api.js +172 -0
- package/dist/smoltbot-shim.js +3 -3
- package/package.json +1 -1
- package/dist/lib/model-cache.d.ts +0 -16
- package/dist/lib/model-cache.js +0 -137
- package/dist/lib/models.d.ts +0 -41
- package/dist/lib/models.js +0 -357
- package/dist/lib/openclaw.d.ts +0 -221
- package/dist/lib/openclaw.js +0 -474
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mnemom webhooks ...` commands — Track 2 W3.5.
|
|
3
|
+
*
|
|
4
|
+
* mnemom webhooks list <org_id> — list endpoints
|
|
5
|
+
* mnemom webhooks get <org_id> <endpoint_id> — show one
|
|
6
|
+
* mnemom webhooks create <org_id> --url <u> [--events <list>]
|
|
7
|
+
* [--description <d>]
|
|
8
|
+
* mnemom webhooks update <org_id> <endpoint_id> [--url <u>]
|
|
9
|
+
* [--events <list>]
|
|
10
|
+
* [--active <bool>]
|
|
11
|
+
* mnemom webhooks delete <org_id> <endpoint_id> — remove endpoint
|
|
12
|
+
* mnemom webhooks rotate-secret <org_id> <endpoint_id> — mint new secret
|
|
13
|
+
* mnemom webhooks list-deliveries <org_id> [--endpoint <id>] [--limit <n>]
|
|
14
|
+
* mnemom webhooks redeliver <org_id> <delivery_id> — retry one delivery
|
|
15
|
+
* mnemom webhooks replay <org_id> <event_id> [--endpoint <id>...]
|
|
16
|
+
* mnemom webhooks trigger <org_id> <endpoint_id> — fire a test event
|
|
17
|
+
*
|
|
18
|
+
* Every mutation auto-generates a fresh `Idempotency-Key`. Re-running the
|
|
19
|
+
* same command does NOT replay the cache (you'd need to keep the key
|
|
20
|
+
* around for that — the curl/programmatic clients do); for the typical
|
|
21
|
+
* CLI ergonomic path, each invocation is its own logical mutation.
|
|
22
|
+
*/
|
|
23
|
+
import { listWebhookEndpoints, getWebhookEndpoint, createWebhookEndpoint, updateWebhookEndpoint, deleteWebhookEndpoint, rotateWebhookSecret, testWebhookEndpoint, listWebhookDeliveries, redeliverWebhookEvent, replayWebhookEvent, } from "../lib/webhooks-api.js";
|
|
24
|
+
import { requireAuth } from "../lib/auth.js";
|
|
25
|
+
import { fmt } from "../lib/format.js";
|
|
26
|
+
function parseEventList(value) {
|
|
27
|
+
if (!value)
|
|
28
|
+
return undefined;
|
|
29
|
+
return value
|
|
30
|
+
.split(",")
|
|
31
|
+
.map((s) => s.trim())
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
}
|
|
34
|
+
function fail(msg) {
|
|
35
|
+
console.log(fmt.error(msg) + "\n");
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
function shortenSecret(secret) {
|
|
39
|
+
if (!secret)
|
|
40
|
+
return "—";
|
|
41
|
+
if (secret.length <= 16)
|
|
42
|
+
return secret;
|
|
43
|
+
return `${secret.slice(0, 8)}…${secret.slice(-4)}`;
|
|
44
|
+
}
|
|
45
|
+
function formatTime(ts) {
|
|
46
|
+
if (!ts)
|
|
47
|
+
return "—";
|
|
48
|
+
try {
|
|
49
|
+
return new Date(ts).toISOString().replace("T", " ").slice(0, 19) + "Z";
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return ts;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// ─── list ────────────────────────────────────────────────────────────────
|
|
56
|
+
export async function webhooksListCommand(orgId, opts = {}) {
|
|
57
|
+
await requireAuth();
|
|
58
|
+
let endpoints;
|
|
59
|
+
try {
|
|
60
|
+
endpoints = await listWebhookEndpoints(orgId);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
fail(`Failed to list endpoints: ${err instanceof Error ? err.message : String(err)}`);
|
|
64
|
+
}
|
|
65
|
+
if (opts.json) {
|
|
66
|
+
console.log(JSON.stringify(endpoints, null, 2));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
console.log(fmt.header(`Webhook endpoints — org ${orgId}`));
|
|
70
|
+
console.log();
|
|
71
|
+
if (endpoints.length === 0) {
|
|
72
|
+
console.log(" No endpoints configured. Create one with `mnemom webhooks create`.\n");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const idW = 26;
|
|
76
|
+
const urlW = 44;
|
|
77
|
+
const eventsW = 8;
|
|
78
|
+
const activeW = 8;
|
|
79
|
+
console.log("Endpoint".padEnd(idW) +
|
|
80
|
+
"URL".padEnd(urlW) +
|
|
81
|
+
"Events".padEnd(eventsW) +
|
|
82
|
+
"Active".padEnd(activeW));
|
|
83
|
+
console.log("─".repeat(idW + urlW + eventsW + activeW));
|
|
84
|
+
for (const ep of endpoints) {
|
|
85
|
+
const url = ep.url.length > urlW - 1 ? ep.url.slice(0, urlW - 4) + "…" : ep.url;
|
|
86
|
+
console.log(ep.endpoint_id.padEnd(idW) +
|
|
87
|
+
url.padEnd(urlW) +
|
|
88
|
+
String(ep.event_types.length).padEnd(eventsW) +
|
|
89
|
+
(ep.is_active ? "yes" : "no").padEnd(activeW));
|
|
90
|
+
}
|
|
91
|
+
console.log();
|
|
92
|
+
}
|
|
93
|
+
// ─── get ─────────────────────────────────────────────────────────────────
|
|
94
|
+
export async function webhooksGetCommand(orgId, endpointId, opts = {}) {
|
|
95
|
+
await requireAuth();
|
|
96
|
+
let ep;
|
|
97
|
+
try {
|
|
98
|
+
ep = await getWebhookEndpoint(orgId, endpointId);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
fail(`Failed to fetch endpoint: ${err instanceof Error ? err.message : String(err)}`);
|
|
102
|
+
}
|
|
103
|
+
if (opts.json) {
|
|
104
|
+
console.log(JSON.stringify(ep, null, 2));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
console.log(fmt.header(`Webhook endpoint ${ep.endpoint_id}`));
|
|
108
|
+
console.log();
|
|
109
|
+
console.log(` URL ${ep.url}`);
|
|
110
|
+
console.log(` Description ${ep.description || "(none)"}`);
|
|
111
|
+
console.log(` Events ${ep.event_types.length === 0 ? "(none)" : ep.event_types.join(", ")}`);
|
|
112
|
+
console.log(` Active ${ep.is_active ? "yes" : "no"}`);
|
|
113
|
+
console.log(` Failures ${ep.consecutive_failures}`);
|
|
114
|
+
if (ep.disabled_at) {
|
|
115
|
+
console.log(` Disabled at ${formatTime(ep.disabled_at)} — ${ep.disabled_reason ?? "(no reason)"}`);
|
|
116
|
+
}
|
|
117
|
+
console.log(` Created ${formatTime(ep.created_at)}`);
|
|
118
|
+
console.log(` Updated ${formatTime(ep.updated_at)}`);
|
|
119
|
+
if (ep.signing_secret) {
|
|
120
|
+
console.log(` Secret ${shortenSecret(ep.signing_secret)} (shown only on create / rotate)`);
|
|
121
|
+
}
|
|
122
|
+
console.log();
|
|
123
|
+
}
|
|
124
|
+
// ─── create ──────────────────────────────────────────────────────────────
|
|
125
|
+
export async function webhooksCreateCommand(orgId, opts = {}) {
|
|
126
|
+
await requireAuth();
|
|
127
|
+
if (!opts.url)
|
|
128
|
+
fail("--url is required (HTTPS only; private/internal IPs blocked)");
|
|
129
|
+
let created;
|
|
130
|
+
try {
|
|
131
|
+
created = await createWebhookEndpoint(orgId, {
|
|
132
|
+
url: opts.url,
|
|
133
|
+
description: opts.description,
|
|
134
|
+
event_types: parseEventList(opts.events),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
fail(`Failed to create endpoint: ${err instanceof Error ? err.message : String(err)}`);
|
|
139
|
+
}
|
|
140
|
+
if (opts.json) {
|
|
141
|
+
console.log(JSON.stringify(created, null, 2));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
console.log(fmt.success("Webhook endpoint created"));
|
|
145
|
+
console.log();
|
|
146
|
+
console.log(` Endpoint ID ${created.endpoint_id}`);
|
|
147
|
+
console.log(` URL ${created.url}`);
|
|
148
|
+
console.log(` Events ${created.event_types.length === 0 ? "(none — explicit per-event opt-in required)" : created.event_types.join(", ")}`);
|
|
149
|
+
if (created.signing_secret) {
|
|
150
|
+
console.log();
|
|
151
|
+
console.log(fmt.warn("Signing secret (shown ONCE — store it now):"));
|
|
152
|
+
console.log(` ${created.signing_secret}`);
|
|
153
|
+
}
|
|
154
|
+
console.log();
|
|
155
|
+
}
|
|
156
|
+
// ─── update ──────────────────────────────────────────────────────────────
|
|
157
|
+
export async function webhooksUpdateCommand(orgId, endpointId, opts = {}) {
|
|
158
|
+
await requireAuth();
|
|
159
|
+
const body = {};
|
|
160
|
+
if (opts.url !== undefined)
|
|
161
|
+
body.url = opts.url;
|
|
162
|
+
if (opts.description !== undefined)
|
|
163
|
+
body.description = opts.description;
|
|
164
|
+
const events = parseEventList(opts.events);
|
|
165
|
+
if (events !== undefined)
|
|
166
|
+
body.event_types = events;
|
|
167
|
+
if (opts.active !== undefined) {
|
|
168
|
+
if (opts.active === "true")
|
|
169
|
+
body.is_active = true;
|
|
170
|
+
else if (opts.active === "false")
|
|
171
|
+
body.is_active = false;
|
|
172
|
+
else
|
|
173
|
+
fail("--active must be 'true' or 'false'");
|
|
174
|
+
}
|
|
175
|
+
if (Object.keys(body).length === 0)
|
|
176
|
+
fail("Nothing to update — pass --url / --events / --description / --active.");
|
|
177
|
+
let updated;
|
|
178
|
+
try {
|
|
179
|
+
updated = await updateWebhookEndpoint(orgId, endpointId, body);
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
fail(`Failed to update endpoint: ${err instanceof Error ? err.message : String(err)}`);
|
|
183
|
+
}
|
|
184
|
+
if (opts.json) {
|
|
185
|
+
console.log(JSON.stringify(updated, null, 2));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
console.log(fmt.success(`Updated endpoint ${updated.endpoint_id}`));
|
|
189
|
+
console.log();
|
|
190
|
+
}
|
|
191
|
+
// ─── delete ──────────────────────────────────────────────────────────────
|
|
192
|
+
export async function webhooksDeleteCommand(orgId, endpointId) {
|
|
193
|
+
await requireAuth();
|
|
194
|
+
try {
|
|
195
|
+
await deleteWebhookEndpoint(orgId, endpointId);
|
|
196
|
+
}
|
|
197
|
+
catch (err) {
|
|
198
|
+
fail(`Failed to delete endpoint: ${err instanceof Error ? err.message : String(err)}`);
|
|
199
|
+
}
|
|
200
|
+
console.log(fmt.success(`Deleted endpoint ${endpointId}`));
|
|
201
|
+
console.log();
|
|
202
|
+
}
|
|
203
|
+
// ─── rotate-secret ───────────────────────────────────────────────────────
|
|
204
|
+
export async function webhooksRotateSecretCommand(orgId, endpointId, opts = {}) {
|
|
205
|
+
await requireAuth();
|
|
206
|
+
let result;
|
|
207
|
+
try {
|
|
208
|
+
result = await rotateWebhookSecret(orgId, endpointId);
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
fail(`Failed to rotate secret: ${err instanceof Error ? err.message : String(err)}`);
|
|
212
|
+
}
|
|
213
|
+
if (opts.json) {
|
|
214
|
+
console.log(JSON.stringify(result, null, 2));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
console.log(fmt.success(`Rotated signing secret for ${result.endpoint_id}`));
|
|
218
|
+
console.log();
|
|
219
|
+
console.log(fmt.warn("New signing secret (shown ONCE — store it now):"));
|
|
220
|
+
console.log(` ${result.signing_secret}`);
|
|
221
|
+
console.log();
|
|
222
|
+
}
|
|
223
|
+
// ─── trigger (test) ──────────────────────────────────────────────────────
|
|
224
|
+
export async function webhooksTriggerCommand(orgId, endpointId, opts = {}) {
|
|
225
|
+
await requireAuth();
|
|
226
|
+
let result;
|
|
227
|
+
try {
|
|
228
|
+
result = await testWebhookEndpoint(orgId, endpointId);
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
fail(`Failed to trigger test: ${err instanceof Error ? err.message : String(err)}`);
|
|
232
|
+
}
|
|
233
|
+
if (opts.json) {
|
|
234
|
+
console.log(JSON.stringify(result, null, 2));
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (result.success) {
|
|
238
|
+
console.log(fmt.success(`Test delivery succeeded — receiver returned ${result.status} in ${result.latency_ms}ms`));
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
console.log(fmt.error(`Test delivery failed — status ${result.status ?? "(no response)"}`));
|
|
242
|
+
if (result.error)
|
|
243
|
+
console.log(` ${result.error}`);
|
|
244
|
+
}
|
|
245
|
+
console.log();
|
|
246
|
+
}
|
|
247
|
+
// ─── list-deliveries ─────────────────────────────────────────────────────
|
|
248
|
+
export async function webhooksListDeliveriesCommand(orgId, opts = {}) {
|
|
249
|
+
await requireAuth();
|
|
250
|
+
const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;
|
|
251
|
+
const offset = opts.offset ? parseInt(opts.offset, 10) : undefined;
|
|
252
|
+
let deliveries;
|
|
253
|
+
try {
|
|
254
|
+
deliveries = await listWebhookDeliveries(orgId, {
|
|
255
|
+
endpointId: opts.endpoint,
|
|
256
|
+
limit: limit && !Number.isNaN(limit) ? limit : undefined,
|
|
257
|
+
offset: offset && !Number.isNaN(offset) ? offset : undefined,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
fail(`Failed to list deliveries: ${err instanceof Error ? err.message : String(err)}`);
|
|
262
|
+
}
|
|
263
|
+
if (opts.json) {
|
|
264
|
+
console.log(JSON.stringify(deliveries, null, 2));
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
console.log(fmt.header(`Webhook deliveries — org ${orgId}`));
|
|
268
|
+
console.log();
|
|
269
|
+
if (deliveries.length === 0) {
|
|
270
|
+
console.log(" No deliveries on record.\n");
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
for (const d of deliveries) {
|
|
274
|
+
const ts = formatTime(d.last_attempt_at ?? d.created_at);
|
|
275
|
+
console.log(` ${d.delivery_id} ${d.status.padEnd(10)} → endpoint ${d.endpoint_id} (${ts})`);
|
|
276
|
+
}
|
|
277
|
+
console.log();
|
|
278
|
+
}
|
|
279
|
+
// ─── redeliver ───────────────────────────────────────────────────────────
|
|
280
|
+
export async function webhooksRedeliverCommand(orgId, deliveryId, opts = {}) {
|
|
281
|
+
await requireAuth();
|
|
282
|
+
let result;
|
|
283
|
+
try {
|
|
284
|
+
result = await redeliverWebhookEvent(orgId, deliveryId);
|
|
285
|
+
}
|
|
286
|
+
catch (err) {
|
|
287
|
+
fail(`Failed to redeliver: ${err instanceof Error ? err.message : String(err)}`);
|
|
288
|
+
}
|
|
289
|
+
if (opts.json) {
|
|
290
|
+
console.log(JSON.stringify(result, null, 2));
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
console.log(fmt.success(`Redelivery queued — new delivery_id ${result.delivery_id} (status ${result.status})`));
|
|
294
|
+
console.log();
|
|
295
|
+
}
|
|
296
|
+
// ─── replay ──────────────────────────────────────────────────────────────
|
|
297
|
+
export async function webhooksReplayCommand(orgId, eventId, opts = {}) {
|
|
298
|
+
await requireAuth();
|
|
299
|
+
let result;
|
|
300
|
+
try {
|
|
301
|
+
result = await replayWebhookEvent(orgId, eventId, { endpointIds: opts.endpoint });
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
fail(`Failed to replay event: ${err instanceof Error ? err.message : String(err)}`);
|
|
305
|
+
}
|
|
306
|
+
if (opts.json) {
|
|
307
|
+
console.log(JSON.stringify(result, null, 2));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
console.log(fmt.header(`Replay — event ${eventId} (${result.event_type})`));
|
|
311
|
+
console.log();
|
|
312
|
+
if (result.deliveries.length === 0) {
|
|
313
|
+
console.log(" " + (result.message ?? "No subscribed endpoints to replay to."));
|
|
314
|
+
console.log();
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
for (const d of result.deliveries) {
|
|
318
|
+
console.log(` ✓ ${d.delivery_id} → endpoint ${d.endpoint_id}`);
|
|
319
|
+
}
|
|
320
|
+
if (result.failed_endpoints && result.failed_endpoints.length > 0) {
|
|
321
|
+
console.log();
|
|
322
|
+
console.log(fmt.warn("Failed endpoints:"));
|
|
323
|
+
for (const f of result.failed_endpoints) {
|
|
324
|
+
console.log(` ✗ ${f.endpoint_id}: ${f.error}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
console.log();
|
|
328
|
+
}
|