@dench.com/cli 2.1.2 → 2.1.3
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/agent-config.ts +3 -126
- package/chat.ts +1 -1
- package/dench.ts +49 -8
- package/lib/api-schemas.ts +0 -5
- package/lib/command-registry.ts +174 -22
- package/lib/enrichment-gateway.ts +23 -12
- package/package.json +1 -1
package/agent-config.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `dench identity / organisation / user /
|
|
3
|
-
*
|
|
2
|
+
* `dench identity / organisation / user / bootstrap / model / daily /
|
|
3
|
+
* mem aggregate` — CLI surface for the OpenClaw-
|
|
4
4
|
* parity self-updating harness.
|
|
5
5
|
*
|
|
6
6
|
* Mirrors the auth pattern in `cli/cron.ts`:
|
|
@@ -17,14 +17,12 @@
|
|
|
17
17
|
* user show | edit
|
|
18
18
|
* tools show | notes-edit
|
|
19
19
|
* memory show | append <text> | set (MEMORY.md aggregate)
|
|
20
|
-
* heartbeat status | enable | disable | interval <duration> |
|
|
21
|
-
* instructions
|
|
22
20
|
* bootstrap status | complete | reopen | template
|
|
23
21
|
* model default <id> | model default clear |
|
|
24
22
|
* model thread <threadId> <id> | model thread <threadId> clear
|
|
25
23
|
* daily today | daily show <YYYY-MM-DD> | daily append <text>
|
|
26
24
|
*
|
|
27
|
-
* `edit` / `notes-edit` / `
|
|
25
|
+
* `edit` / `notes-edit` / `template` open the
|
|
28
26
|
* user's `$EDITOR` (default `vi`) to capture the new body. The
|
|
29
27
|
* stdin path is also supported via `--stdin`, useful in scripts.
|
|
30
28
|
*/
|
|
@@ -60,9 +58,6 @@ const api = {
|
|
|
60
58
|
updateUserProfile: makeFunctionReference<"mutation">(
|
|
61
59
|
"functions/agentConfig:updateUserProfile",
|
|
62
60
|
),
|
|
63
|
-
updateHeartbeat: makeFunctionReference<"mutation">(
|
|
64
|
-
"functions/agentConfig:updateHeartbeat",
|
|
65
|
-
),
|
|
66
61
|
updateBootstrapTemplate: makeFunctionReference<"mutation">(
|
|
67
62
|
"functions/agentConfig:updateBootstrapTemplate",
|
|
68
63
|
),
|
|
@@ -182,12 +177,6 @@ async function loadAgentConfig(ctx: CliCtx): Promise<{
|
|
|
182
177
|
completedAt?: number;
|
|
183
178
|
template?: string;
|
|
184
179
|
};
|
|
185
|
-
heartbeat: {
|
|
186
|
-
enabled: boolean;
|
|
187
|
-
intervalMs: number;
|
|
188
|
-
instructions: string;
|
|
189
|
-
lastFiredAt?: number;
|
|
190
|
-
};
|
|
191
180
|
};
|
|
192
181
|
userProfile: { content: string; updatedAt: number } | null;
|
|
193
182
|
organizationId: string;
|
|
@@ -206,12 +195,6 @@ async function loadAgentConfig(ctx: CliCtx): Promise<{
|
|
|
206
195
|
completedAt?: number;
|
|
207
196
|
template?: string;
|
|
208
197
|
};
|
|
209
|
-
heartbeat: {
|
|
210
|
-
enabled: boolean;
|
|
211
|
-
intervalMs: number;
|
|
212
|
-
instructions: string;
|
|
213
|
-
lastFiredAt?: number;
|
|
214
|
-
};
|
|
215
198
|
};
|
|
216
199
|
userProfile: { content: string; updatedAt: number } | null;
|
|
217
200
|
organizationId: string;
|
|
@@ -306,106 +289,6 @@ async function handleSimpleMagicFile(
|
|
|
306
289
|
);
|
|
307
290
|
}
|
|
308
291
|
|
|
309
|
-
function formatInterval(ms: number): string {
|
|
310
|
-
if (ms < 60_000) return `${Math.round(ms / 1000)}s`;
|
|
311
|
-
if (ms < 60 * 60_000) return `${Math.round(ms / 60_000)}m`;
|
|
312
|
-
if (ms < 24 * 60 * 60_000) {
|
|
313
|
-
const hours = ms / (60 * 60_000);
|
|
314
|
-
return Number.isInteger(hours) ? `${hours}h` : `${hours.toFixed(1)}h`;
|
|
315
|
-
}
|
|
316
|
-
return `${(ms / (24 * 60 * 60_000)).toFixed(1)}d`;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const DURATION_RE = /^(\d+)\s*(ms|s|m|h|d)$/i;
|
|
320
|
-
function parseDurationFlagToMs(input: string): number | null {
|
|
321
|
-
const m = DURATION_RE.exec(input.trim());
|
|
322
|
-
if (!m) return null;
|
|
323
|
-
const n = parseInt(m[1], 10);
|
|
324
|
-
if (!Number.isFinite(n) || n <= 0) return null;
|
|
325
|
-
switch (m[2].toLowerCase()) {
|
|
326
|
-
case "ms":
|
|
327
|
-
return n;
|
|
328
|
-
case "s":
|
|
329
|
-
return n * 1000;
|
|
330
|
-
case "m":
|
|
331
|
-
return n * 60_000;
|
|
332
|
-
case "h":
|
|
333
|
-
return n * 3_600_000;
|
|
334
|
-
case "d":
|
|
335
|
-
return n * 86_400_000;
|
|
336
|
-
}
|
|
337
|
-
return null;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
async function handleHeartbeat(ctx: CliCtx, args: string[]): Promise<void> {
|
|
341
|
-
const sub = args[0];
|
|
342
|
-
if (!sub || sub === "status" || sub === "show") {
|
|
343
|
-
const config = await loadAgentConfig(ctx);
|
|
344
|
-
const hb = config.agentConfig.heartbeat;
|
|
345
|
-
if (ctx.jsonOutput) {
|
|
346
|
-
out(ctx, hb);
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
out(
|
|
350
|
-
ctx,
|
|
351
|
-
`enabled=${hb.enabled} interval=${formatInterval(hb.intervalMs)}\n\n${hb.instructions}`,
|
|
352
|
-
);
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
if (sub === "enable") {
|
|
356
|
-
await runMutation(ctx, api.functions.agentConfig.updateHeartbeat, {
|
|
357
|
-
enabled: true,
|
|
358
|
-
});
|
|
359
|
-
out(ctx, { ok: true, enabled: true });
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
if (sub === "disable") {
|
|
363
|
-
await runMutation(ctx, api.functions.agentConfig.updateHeartbeat, {
|
|
364
|
-
enabled: false,
|
|
365
|
-
});
|
|
366
|
-
out(ctx, { ok: true, enabled: false });
|
|
367
|
-
return;
|
|
368
|
-
}
|
|
369
|
-
if (sub === "interval") {
|
|
370
|
-
const raw = args[1];
|
|
371
|
-
if (!raw) {
|
|
372
|
-
throw new AgentConfigCliError(
|
|
373
|
-
"Usage: dench heartbeat interval <duration> (e.g. 30m, 2h, 1d)",
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
const ms = parseDurationFlagToMs(raw);
|
|
377
|
-
if (!ms) throw new AgentConfigCliError(`Invalid duration: ${raw}`);
|
|
378
|
-
await runMutation(ctx, api.functions.agentConfig.updateHeartbeat, {
|
|
379
|
-
intervalMs: ms,
|
|
380
|
-
});
|
|
381
|
-
out(ctx, { ok: true, intervalMs: ms, label: formatInterval(ms) });
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
if (sub === "instructions" || sub === "edit") {
|
|
385
|
-
let content: string;
|
|
386
|
-
if (hasFlag(args, "--stdin") || getFlag(args, "--content")) {
|
|
387
|
-
content = await resolveContent(args);
|
|
388
|
-
} else {
|
|
389
|
-
const config = await loadAgentConfig(ctx);
|
|
390
|
-
content = openEditor(
|
|
391
|
-
config.agentConfig.heartbeat.instructions,
|
|
392
|
-
"heartbeat",
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
if (!content.trim().length) {
|
|
396
|
-
throw new AgentConfigCliError("heartbeat instructions cannot be empty");
|
|
397
|
-
}
|
|
398
|
-
await runMutation(ctx, api.functions.agentConfig.updateHeartbeat, {
|
|
399
|
-
instructions: content,
|
|
400
|
-
});
|
|
401
|
-
out(ctx, { ok: true, kind: "heartbeat" });
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
throw new AgentConfigCliError(
|
|
405
|
-
`Unknown heartbeat subcommand: "${sub}". Try "status", "enable", "disable", "interval <duration>", "instructions".`,
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
292
|
async function handleBootstrap(ctx: CliCtx, args: string[]): Promise<void> {
|
|
410
293
|
const sub = args[0];
|
|
411
294
|
if (!sub || sub === "status" || sub === "show") {
|
|
@@ -598,10 +481,6 @@ export async function runMemoryAggregateCommand(ctx: CliCtx): Promise<void> {
|
|
|
598
481
|
);
|
|
599
482
|
}
|
|
600
483
|
|
|
601
|
-
export async function runHeartbeatCommand(ctx: CliCtx): Promise<void> {
|
|
602
|
-
await handleHeartbeat(ctx, ctx.args);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
484
|
export async function runBootstrapCommand(ctx: CliCtx): Promise<void> {
|
|
606
485
|
await handleBootstrap(ctx, ctx.args);
|
|
607
486
|
}
|
|
@@ -666,8 +545,6 @@ export function printAgentConfigCliHelp(): void {
|
|
|
666
545
|
dench user show | edit USER.md (per-member)
|
|
667
546
|
dench tools show | notes-edit TOOLS.md notes section
|
|
668
547
|
dench mem show | append <text> | set MEMORY.md aggregate
|
|
669
|
-
dench heartbeat status | enable | disable Heartbeat cron
|
|
670
|
-
| interval <30m|1h|…> | instructions
|
|
671
548
|
dench bootstrap status | complete | reopen | template
|
|
672
549
|
dench model default <id|clear> | model thread <threadId> <id|clear>
|
|
673
550
|
dench daily today | show <YYYY-MM-DD> Activity log paths
|
package/chat.ts
CHANGED
|
@@ -433,7 +433,7 @@ async function runChatDeleteCommand(ctx: ChatCliContext): Promise<void> {
|
|
|
433
433
|
);
|
|
434
434
|
}
|
|
435
435
|
const automatedSuffix = includeAutomated
|
|
436
|
-
? " (INCLUDING ROUTINES
|
|
436
|
+
? " (INCLUDING AUTOMATED ROUTINES — automated thread protection bypassed)"
|
|
437
437
|
: "";
|
|
438
438
|
const ok = await promptYesNo(
|
|
439
439
|
`PERMANENTLY queue delete of ${threadIds.length} chat${
|
package/dench.ts
CHANGED
|
@@ -490,6 +490,15 @@ LinkedIn outreach (Browserbase, verified before CRM update):
|
|
|
490
490
|
dench linkedin connect <profileUrl> [--entry people:<entryId>] [--json]
|
|
491
491
|
Help: dench linkedin help
|
|
492
492
|
|
|
493
|
+
Managed email campaigns (Dench Emailing Service):
|
|
494
|
+
dench email identity verify --from founder@example.com [--json]
|
|
495
|
+
dench email template create --name "Intro" --subject "Hi {{firstName}}" --html-file body.html [--json]
|
|
496
|
+
dench email campaign create --name "Q2 outreach" --identity <id> --template <id> [--json]
|
|
497
|
+
dench email campaign recipients add --campaign <id> --file recipients.jsonl [--json]
|
|
498
|
+
dench email campaign submit --campaign <id> [--json]
|
|
499
|
+
dench email campaign status --campaign <id> [--json]
|
|
500
|
+
Help: dench email help
|
|
501
|
+
|
|
493
502
|
Image generation / editing (via the Dench Gateway):
|
|
494
503
|
dench image generate "<prompt>" [--size 1024x1024] [--quality auto|low|medium|high] [--format png|jpeg|webp] [--save-path /workspace/path/file.png] [--output <local file>] [--no-write] [--json]
|
|
495
504
|
dench image edit "<prompt>" --input <path> [--input <path> ...] [--mask <path>] [--size ...] [--quality ...] [--format ...] [--save-path ...] [--output ...] [--json]
|
|
@@ -552,8 +561,6 @@ Self-updating agent harness:
|
|
|
552
561
|
dench user show | edit USER.md (per-member)
|
|
553
562
|
dench tools show | edit TOOLS.md notes section
|
|
554
563
|
dench mem show | append "<text>" | set MEMORY.md aggregate
|
|
555
|
-
dench heartbeat status | enable | disable
|
|
556
|
-
| interval <30m|1h|…> | instructions
|
|
557
564
|
dench bootstrap status | complete | reopen | template
|
|
558
565
|
dench model default <id|clear>
|
|
559
566
|
dench model thread <threadId> <id|clear>
|
|
@@ -3666,6 +3673,20 @@ async function main() {
|
|
|
3666
3673
|
return;
|
|
3667
3674
|
}
|
|
3668
3675
|
|
|
3676
|
+
if (
|
|
3677
|
+
command === "email" &&
|
|
3678
|
+
(!subcommand || subcommand === "help" || hasFlag("--help"))
|
|
3679
|
+
) {
|
|
3680
|
+
const { runEmailCommand } = await import("./email");
|
|
3681
|
+
await runEmailCommand({
|
|
3682
|
+
// biome-ignore lint/suspicious/noExplicitAny: harmless help-only stub
|
|
3683
|
+
convex: {} as any,
|
|
3684
|
+
args: subcommand ? [subcommand] : ["help"],
|
|
3685
|
+
jsonOutput: json,
|
|
3686
|
+
});
|
|
3687
|
+
return;
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3669
3690
|
if (
|
|
3670
3691
|
command === "billing" &&
|
|
3671
3692
|
(!subcommand || subcommand === "help" || hasFlag("--help"))
|
|
@@ -3897,6 +3918,31 @@ async function main() {
|
|
|
3897
3918
|
return;
|
|
3898
3919
|
}
|
|
3899
3920
|
|
|
3921
|
+
if (command === "email") {
|
|
3922
|
+
const subArgs = args.slice(args.indexOf("email") + 1);
|
|
3923
|
+
const { runEmailCommand } = await import("./email");
|
|
3924
|
+
const runtime = await getRuntime();
|
|
3925
|
+
const authedRuntime = requireAuthenticatedRuntime(runtime, "dench email");
|
|
3926
|
+
let gatewayAuth:
|
|
3927
|
+
| Awaited<ReturnType<typeof resolveGatewayCommandAuth>>
|
|
3928
|
+
| undefined;
|
|
3929
|
+
try {
|
|
3930
|
+
gatewayAuth = await resolveGatewayCommandAuth(runtime, "dench email");
|
|
3931
|
+
} catch {
|
|
3932
|
+
gatewayAuth = undefined;
|
|
3933
|
+
}
|
|
3934
|
+
await runEmailCommand({
|
|
3935
|
+
convex: authedRuntime.client,
|
|
3936
|
+
args: subArgs.filter((arg) => arg !== "--json"),
|
|
3937
|
+
jsonOutput: json,
|
|
3938
|
+
sessionToken: authedRuntime.sessionToken,
|
|
3939
|
+
bearerToken: gatewayAuth?.bearerToken ?? authedRuntime.sessionToken,
|
|
3940
|
+
gatewayBaseUrl: gatewayAuth?.gatewayBaseUrl,
|
|
3941
|
+
gatewayHeaders: gatewayAuth?.gatewayHeaders,
|
|
3942
|
+
});
|
|
3943
|
+
return;
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3900
3946
|
if (command === "apps") {
|
|
3901
3947
|
const runtime = await getRuntime();
|
|
3902
3948
|
const gatewayAuth = await resolveGatewayCommandAuth(runtime, "dench apps");
|
|
@@ -4093,7 +4139,7 @@ async function main() {
|
|
|
4093
4139
|
// ── OpenClaw-parity self-update CLI surface ──────────────────────────
|
|
4094
4140
|
//
|
|
4095
4141
|
// Dispatch all `dench identity / organisation / user / tools / mem /
|
|
4096
|
-
//
|
|
4142
|
+
// bootstrap / model / daily` traffic through the shared
|
|
4097
4143
|
// agent-config CLI module. Each command requires the same auth shape
|
|
4098
4144
|
// as `dench cron` (Bearer DENCH_API_KEY or `dench signin` session
|
|
4099
4145
|
// token) so server-side `requireCronAccess` accepts both.
|
|
@@ -4103,7 +4149,6 @@ async function main() {
|
|
|
4103
4149
|
"user",
|
|
4104
4150
|
"tools",
|
|
4105
4151
|
"mem",
|
|
4106
|
-
"heartbeat",
|
|
4107
4152
|
"bootstrap",
|
|
4108
4153
|
"model",
|
|
4109
4154
|
"daily",
|
|
@@ -4151,10 +4196,6 @@ async function main() {
|
|
|
4151
4196
|
await mod.runMemoryAggregateCommand(ctxBase);
|
|
4152
4197
|
return;
|
|
4153
4198
|
}
|
|
4154
|
-
if (command === "heartbeat") {
|
|
4155
|
-
await mod.runHeartbeatCommand(ctxBase);
|
|
4156
|
-
return;
|
|
4157
|
-
}
|
|
4158
4199
|
if (command === "bootstrap") {
|
|
4159
4200
|
await mod.runBootstrapCommand(ctxBase);
|
|
4160
4201
|
return;
|
package/lib/api-schemas.ts
CHANGED
|
@@ -888,11 +888,6 @@ export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
|
888
888
|
content: z.string(),
|
|
889
889
|
append: z.boolean().optional(),
|
|
890
890
|
}),
|
|
891
|
-
"agentConfig.heartbeat.update": z.object({
|
|
892
|
-
enabled: z.boolean().optional(),
|
|
893
|
-
intervalMs: z.number().int().optional(),
|
|
894
|
-
instructions: z.string().optional(),
|
|
895
|
-
}),
|
|
896
891
|
"agentConfig.bootstrap.complete": z.object({
|
|
897
892
|
completed: z.boolean().optional(),
|
|
898
893
|
}),
|
package/lib/command-registry.ts
CHANGED
|
@@ -1095,6 +1095,180 @@ const rawApiOperations = [
|
|
|
1095
1095
|
),
|
|
1096
1096
|
}),
|
|
1097
1097
|
|
|
1098
|
+
// Managed email campaigns.
|
|
1099
|
+
op({
|
|
1100
|
+
id: "email.identity.verify",
|
|
1101
|
+
group: "email",
|
|
1102
|
+
summary: "Start Dench Emailing Service sender verification.",
|
|
1103
|
+
cli: "dench email identity verify",
|
|
1104
|
+
method: "POST",
|
|
1105
|
+
path: "/email/identities/verify",
|
|
1106
|
+
requestSchema: anyObject,
|
|
1107
|
+
responseSchema: anyResponse,
|
|
1108
|
+
backend: gateway("POST", "/email/identities/verify"),
|
|
1109
|
+
}),
|
|
1110
|
+
op({
|
|
1111
|
+
id: "email.identity.create",
|
|
1112
|
+
group: "email",
|
|
1113
|
+
summary: "Create a durable Dench email sending identity record.",
|
|
1114
|
+
cli: "dench email identity verify",
|
|
1115
|
+
method: "POST",
|
|
1116
|
+
path: "/email/sending-identities",
|
|
1117
|
+
requestSchema: anyObject,
|
|
1118
|
+
responseSchema: anyResponse,
|
|
1119
|
+
backend: convex("mutation", "functions/emailCampaigns:createIdentity"),
|
|
1120
|
+
}),
|
|
1121
|
+
op({
|
|
1122
|
+
id: "email.identity.refresh",
|
|
1123
|
+
group: "email",
|
|
1124
|
+
summary: "Refresh a Dench Emailing Service sender verification status.",
|
|
1125
|
+
cli: "dench email identity status --identity-id",
|
|
1126
|
+
method: "POST",
|
|
1127
|
+
path: "/email/sending-identities/{identityId}/status",
|
|
1128
|
+
requestSchema: anyObject,
|
|
1129
|
+
responseSchema: anyResponse,
|
|
1130
|
+
backend: convex(
|
|
1131
|
+
"action",
|
|
1132
|
+
"functions/emailCampaignsNode:refreshIdentityStatus",
|
|
1133
|
+
),
|
|
1134
|
+
}),
|
|
1135
|
+
op({
|
|
1136
|
+
id: "email.identity.beginVerification",
|
|
1137
|
+
group: "email",
|
|
1138
|
+
summary:
|
|
1139
|
+
"Begin the full Dench sender verification flow for a sending identity.",
|
|
1140
|
+
cli: "dench email identity verify",
|
|
1141
|
+
method: "POST",
|
|
1142
|
+
path: "/email/sending-identities/{identityId}/verify",
|
|
1143
|
+
requestSchema: anyObject,
|
|
1144
|
+
responseSchema: anyResponse,
|
|
1145
|
+
backend: convex(
|
|
1146
|
+
"action",
|
|
1147
|
+
"functions/emailCampaignsNode:beginSenderVerification",
|
|
1148
|
+
),
|
|
1149
|
+
}),
|
|
1150
|
+
op({
|
|
1151
|
+
id: "email.identity.status",
|
|
1152
|
+
group: "email",
|
|
1153
|
+
summary: "Read Dench Emailing Service sender verification status.",
|
|
1154
|
+
cli: "dench email identity status",
|
|
1155
|
+
method: "GET",
|
|
1156
|
+
path: "/email/identities/{identity}/status",
|
|
1157
|
+
requestSchema: anyObject,
|
|
1158
|
+
responseSchema: anyResponse,
|
|
1159
|
+
backend: gateway("GET", "/email/identities/{identity}/status"),
|
|
1160
|
+
}),
|
|
1161
|
+
op({
|
|
1162
|
+
id: "email.template.create",
|
|
1163
|
+
group: "email",
|
|
1164
|
+
summary: "Create a managed email campaign template.",
|
|
1165
|
+
cli: "dench email template create",
|
|
1166
|
+
method: "POST",
|
|
1167
|
+
path: "/email/templates",
|
|
1168
|
+
requestSchema: anyObject,
|
|
1169
|
+
responseSchema: anyResponse,
|
|
1170
|
+
backend: convex("mutation", "functions/emailCampaigns:createTemplate"),
|
|
1171
|
+
}),
|
|
1172
|
+
op({
|
|
1173
|
+
id: "email.template.preview",
|
|
1174
|
+
group: "email",
|
|
1175
|
+
summary: "Preview a managed email campaign template.",
|
|
1176
|
+
cli: "dench email template preview",
|
|
1177
|
+
method: "POST",
|
|
1178
|
+
path: "/email/templates/{templateId}/preview",
|
|
1179
|
+
requestSchema: anyObject,
|
|
1180
|
+
responseSchema: anyResponse,
|
|
1181
|
+
backend: convex("query", "functions/emailCampaigns:previewTemplate"),
|
|
1182
|
+
}),
|
|
1183
|
+
op({
|
|
1184
|
+
id: "email.campaign.create",
|
|
1185
|
+
group: "email",
|
|
1186
|
+
summary: "Create a managed email campaign draft.",
|
|
1187
|
+
cli: "dench email campaign create",
|
|
1188
|
+
method: "POST",
|
|
1189
|
+
path: "/email/campaigns",
|
|
1190
|
+
requestSchema: anyObject,
|
|
1191
|
+
responseSchema: anyResponse,
|
|
1192
|
+
backend: convex("mutation", "functions/emailCampaigns:createCampaign"),
|
|
1193
|
+
}),
|
|
1194
|
+
op({
|
|
1195
|
+
id: "email.campaign.get",
|
|
1196
|
+
group: "email",
|
|
1197
|
+
summary: "Read campaign status and counters.",
|
|
1198
|
+
cli: "dench email campaign status",
|
|
1199
|
+
method: "GET",
|
|
1200
|
+
path: "/email/campaigns/{campaignId}",
|
|
1201
|
+
requestSchema: anyObject,
|
|
1202
|
+
responseSchema: anyResponse,
|
|
1203
|
+
backend: convex("query", "functions/emailCampaigns:getCampaign"),
|
|
1204
|
+
}),
|
|
1205
|
+
op({
|
|
1206
|
+
id: "email.campaign.recipients.add",
|
|
1207
|
+
group: "email",
|
|
1208
|
+
summary: "Add recipients to a managed email campaign.",
|
|
1209
|
+
cli: "dench email campaign recipients add",
|
|
1210
|
+
method: "POST",
|
|
1211
|
+
path: "/email/campaigns/{campaignId}/recipients",
|
|
1212
|
+
requestSchema: anyObject,
|
|
1213
|
+
responseSchema: anyResponse,
|
|
1214
|
+
backend: convex("mutation", "functions/emailCampaigns:addRecipients"),
|
|
1215
|
+
}),
|
|
1216
|
+
op({
|
|
1217
|
+
id: "email.campaign.preview",
|
|
1218
|
+
group: "email",
|
|
1219
|
+
summary: "Preview rendered messages for a campaign sample.",
|
|
1220
|
+
cli: "dench email campaign preview",
|
|
1221
|
+
method: "POST",
|
|
1222
|
+
path: "/email/campaigns/{campaignId}/preview",
|
|
1223
|
+
requestSchema: anyObject,
|
|
1224
|
+
responseSchema: anyResponse,
|
|
1225
|
+
backend: convex("query", "functions/emailCampaigns:previewCampaign"),
|
|
1226
|
+
}),
|
|
1227
|
+
op({
|
|
1228
|
+
id: "email.campaign.submit",
|
|
1229
|
+
group: "email",
|
|
1230
|
+
summary: "Submit a campaign for approval or sending.",
|
|
1231
|
+
cli: "dench email campaign submit",
|
|
1232
|
+
method: "POST",
|
|
1233
|
+
path: "/email/campaigns/{campaignId}/submit",
|
|
1234
|
+
requestSchema: anyObject,
|
|
1235
|
+
responseSchema: anyResponse,
|
|
1236
|
+
backend: convex("mutation", "functions/emailCampaigns:submitCampaign"),
|
|
1237
|
+
}),
|
|
1238
|
+
op({
|
|
1239
|
+
id: "email.campaign.pause",
|
|
1240
|
+
group: "email",
|
|
1241
|
+
summary: "Pause a sending email campaign.",
|
|
1242
|
+
cli: "dench email campaign pause",
|
|
1243
|
+
method: "POST",
|
|
1244
|
+
path: "/email/campaigns/{campaignId}/pause",
|
|
1245
|
+
requestSchema: anyObject,
|
|
1246
|
+
responseSchema: anyResponse,
|
|
1247
|
+
backend: convex("mutation", "functions/emailCampaigns:pauseCampaign"),
|
|
1248
|
+
}),
|
|
1249
|
+
op({
|
|
1250
|
+
id: "email.campaign.resume",
|
|
1251
|
+
group: "email",
|
|
1252
|
+
summary: "Resume a paused email campaign.",
|
|
1253
|
+
cli: "dench email campaign resume",
|
|
1254
|
+
method: "POST",
|
|
1255
|
+
path: "/email/campaigns/{campaignId}/resume",
|
|
1256
|
+
requestSchema: anyObject,
|
|
1257
|
+
responseSchema: anyResponse,
|
|
1258
|
+
backend: convex("mutation", "functions/emailCampaigns:resumeCampaign"),
|
|
1259
|
+
}),
|
|
1260
|
+
op({
|
|
1261
|
+
id: "email.campaign.cancel",
|
|
1262
|
+
group: "email",
|
|
1263
|
+
summary: "Cancel an email campaign.",
|
|
1264
|
+
cli: "dench email campaign cancel",
|
|
1265
|
+
method: "POST",
|
|
1266
|
+
path: "/email/campaigns/{campaignId}/cancel",
|
|
1267
|
+
requestSchema: anyObject,
|
|
1268
|
+
responseSchema: anyResponse,
|
|
1269
|
+
backend: convex("mutation", "functions/emailCampaigns:cancelCampaign"),
|
|
1270
|
+
}),
|
|
1271
|
+
|
|
1098
1272
|
// Routines.
|
|
1099
1273
|
op({
|
|
1100
1274
|
id: "cron.list",
|
|
@@ -1521,28 +1695,6 @@ const rawApiOperations = [
|
|
|
1521
1695
|
responseSchema: anyResponse,
|
|
1522
1696
|
backend: convex("mutation", "functions/agentConfig:updateMemory"),
|
|
1523
1697
|
}),
|
|
1524
|
-
op({
|
|
1525
|
-
id: "agentConfig.heartbeat.show",
|
|
1526
|
-
group: "agent-config",
|
|
1527
|
-
summary: "Read heartbeat config.",
|
|
1528
|
-
cli: "dench heartbeat status",
|
|
1529
|
-
method: "GET",
|
|
1530
|
-
path: "/agent-config/heartbeat",
|
|
1531
|
-
requestSchema: noBody,
|
|
1532
|
-
responseSchema: anyResponse,
|
|
1533
|
-
backend: convex("query", "functions/agentConfig:getAgentConfig"),
|
|
1534
|
-
}),
|
|
1535
|
-
op({
|
|
1536
|
-
id: "agentConfig.heartbeat.update",
|
|
1537
|
-
group: "agent-config",
|
|
1538
|
-
summary: "Update heartbeat config.",
|
|
1539
|
-
cli: "dench heartbeat enable|disable|interval|instructions",
|
|
1540
|
-
method: "PATCH",
|
|
1541
|
-
path: "/agent-config/heartbeat",
|
|
1542
|
-
requestSchema: anyObject,
|
|
1543
|
-
responseSchema: anyResponse,
|
|
1544
|
-
backend: convex("mutation", "functions/agentConfig:updateHeartbeat"),
|
|
1545
|
-
}),
|
|
1546
1698
|
op({
|
|
1547
1699
|
id: "agentConfig.bootstrap.show",
|
|
1548
1700
|
group: "agent-config",
|
|
@@ -1055,12 +1055,13 @@ export async function aviatoEnrichPerson(
|
|
|
1055
1055
|
body: AviatoEnrichPersonBody,
|
|
1056
1056
|
options: EnrichmentGatewayOptions = {},
|
|
1057
1057
|
): Promise<Record<string, unknown>> {
|
|
1058
|
+
const linkedinUrl = body.linkedinUrl?.trim();
|
|
1059
|
+
const linkedinID = body.linkedinID?.trim();
|
|
1060
|
+
const linkedinNumID = body.linkedinNumID?.trim();
|
|
1061
|
+
const linkedinEntityId = body.linkedinEntityId?.trim();
|
|
1062
|
+
const email = body.email?.trim();
|
|
1058
1063
|
const hasIdentifier =
|
|
1059
|
-
|
|
1060
|
-
body.linkedinID ||
|
|
1061
|
-
body.linkedinNumID ||
|
|
1062
|
-
body.linkedinEntityId ||
|
|
1063
|
-
body.email;
|
|
1064
|
+
linkedinUrl || linkedinID || linkedinNumID || linkedinEntityId || email;
|
|
1064
1065
|
if (!hasIdentifier) {
|
|
1065
1066
|
throw new EnrichmentGatewayError(
|
|
1066
1067
|
"Aviato person enrichment requires at least one identifier: linkedinUrl, linkedinID, linkedinNumID, linkedinEntityId, or email.",
|
|
@@ -1068,14 +1069,24 @@ export async function aviatoEnrichPerson(
|
|
|
1068
1069
|
);
|
|
1069
1070
|
}
|
|
1070
1071
|
|
|
1072
|
+
// Aviato rejects email-only lookups in preview mode ("Email lookups are
|
|
1073
|
+
// not allowed in preview mode"), so when email is the sole identifier we
|
|
1074
|
+
// upgrade to a full (charged) lookup rather than surfacing a hard 400.
|
|
1075
|
+
const emailOnly =
|
|
1076
|
+
Boolean(email) &&
|
|
1077
|
+
!linkedinUrl &&
|
|
1078
|
+
!linkedinID &&
|
|
1079
|
+
!linkedinNumID &&
|
|
1080
|
+
!linkedinEntityId;
|
|
1081
|
+
|
|
1071
1082
|
const requestBody: Record<string, unknown> = {};
|
|
1072
|
-
if (
|
|
1073
|
-
if (
|
|
1074
|
-
if (
|
|
1075
|
-
if (
|
|
1076
|
-
|
|
1077
|
-
if (body.
|
|
1078
|
-
|
|
1083
|
+
if (linkedinUrl) requestBody.linkedinURL = linkedinUrl;
|
|
1084
|
+
if (linkedinID) requestBody.linkedinID = linkedinID;
|
|
1085
|
+
if (linkedinNumID) requestBody.linkedinNumID = linkedinNumID;
|
|
1086
|
+
if (linkedinEntityId) requestBody.linkedinEntityId = linkedinEntityId;
|
|
1087
|
+
if (email) requestBody.email = email;
|
|
1088
|
+
if (body.preview !== undefined && !(body.preview && emailOnly))
|
|
1089
|
+
requestBody.preview = body.preview;
|
|
1079
1090
|
|
|
1080
1091
|
const raw = await callGatewayJson("/v1/enrichment/aviato/person", {
|
|
1081
1092
|
method: "POST",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dench.com/cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "Dench agent workspace CLI. v2 unifies auth behind `dench signin`; the legacy `dench login` / `dench onboard` / `dench setup` / `dench what-can-i-do` / `dench register` commands now error with a redirect.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|