@dench.com/cli 3.8.0-staging.389 → 3.8.2-staging.391
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/ads.ts +6 -2
- package/app-sdk.d.ts +132 -27
- package/apps.ts +7 -3
- package/browser.ts +8 -3
- package/campaign.ts +336 -55
- package/chat.ts +8 -6
- package/cron.ts +7 -3
- package/dench.ts +52 -94
- package/image.ts +6 -2
- package/leads.ts +6 -2
- package/lib/api-schemas.ts +186 -20
- package/lib/app-sdk-catalog.generated.ts +3 -3
- package/lib/campaign-steps.ts +474 -12
- package/lib/campaign-timeline.ts +69 -4
- package/lib/command-args.ts +26 -9
- package/lib/command-help.ts +192 -39
- package/lib/command-registry.ts +3 -3
- package/lib/file-command-contract.ts +106 -0
- package/lib/references.generated.json +14 -14
- package/meetings.ts +6 -2
- package/members.ts +6 -2
- package/package.json +1 -1
- package/search.ts +6 -2
- package/tools.ts +9 -5
- package/web.ts +20 -6
package/ads.ts
CHANGED
|
@@ -2000,7 +2000,11 @@ async function runWithdrawCommand(opts: {
|
|
|
2000
2000
|
// ---------------------------------------------------------------------------
|
|
2001
2001
|
|
|
2002
2002
|
function adsHelp(): void {
|
|
2003
|
-
console.log(
|
|
2003
|
+
console.log(adsHelpText());
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
export function adsHelpText(): string {
|
|
2007
|
+
return `\`dench ads\` — monetize the AI "thinking…" line. (aliases: dench ad, dench adline)
|
|
2004
2008
|
|
|
2005
2009
|
Usage:
|
|
2006
2010
|
dench ads Print the sponsored ad in a decorated rainbow box
|
|
@@ -2035,7 +2039,7 @@ Notes:
|
|
|
2035
2039
|
• Set DENCH_ADS_ENDPOINT=https://your-server/ads to serve real ads:
|
|
2036
2040
|
GET returns {id,label,url,icon,iconUrl}; POST {endpoint}/impressions
|
|
2037
2041
|
takes {events:[{adId,count,flushId}]}.
|
|
2038
|
-
|
|
2042
|
+
`;
|
|
2039
2043
|
}
|
|
2040
2044
|
|
|
2041
2045
|
// ---------------------------------------------------------------------------
|
package/app-sdk.d.ts
CHANGED
|
@@ -2594,7 +2594,7 @@ export interface ApiRequests {
|
|
|
2594
2594
|
"campaigns.get": {
|
|
2595
2595
|
sequenceId: string;
|
|
2596
2596
|
};
|
|
2597
|
-
/** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks. — `dench campaign get` — GET /api/v1/campaigns/{sequenceId}/analytics */
|
|
2597
|
+
/** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks, and for a workflow how many people took each If / else and Wait for them to accept path (branchStats). — `dench campaign get` — GET /api/v1/campaigns/{sequenceId}/analytics */
|
|
2598
2598
|
"campaigns.analytics": {
|
|
2599
2599
|
sequenceId: string;
|
|
2600
2600
|
};
|
|
@@ -2643,13 +2643,13 @@ export interface ApiRequests {
|
|
|
2643
2643
|
/** Cold emails per day, 1-100. */
|
|
2644
2644
|
dailySendCap?: number;
|
|
2645
2645
|
};
|
|
2646
|
-
/** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message, post reaction, InMail). Steps are checked first: a field the step type would drop, missing text
|
|
2646
|
+
/** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message, post reaction, InMail, If / else, Wait for them to accept). A workflow (stepModel workflow, or steps with key, next, yesNext or noNext) branches: condition and wait_for_connection steps continue on yesNext or noNext, other steps on next; each points at another step's key or end. Steps are checked first: a field the step type would drop, missing text, {TOKEN} single braces or paths that don't hold together are rejected, not saved. Configure sender pools on the campaign; step sender ids are legacy-only. — `dench campaign steps set` — PUT /api/v1/campaigns/{sequenceId}/steps */
|
|
2647
2647
|
"campaigns.steps.replace": {
|
|
2648
2648
|
sequenceId: string;
|
|
2649
|
-
/** Every step, in send order. Rejected, not trimmed: a field the step type would drop (onlyIf off email/post-like steps, a body on a visit, reply-in-thread on the first email), a missing subject or required body, an overlength note/message/InMail subject, out-of-range wait/withdrawal/post-age values,
|
|
2649
|
+
/** Every step, in send order (a workflow may list them in any order; they are stored in path order). Rejected, not trimmed: a field the step type would drop (onlyIf off email/post-like steps, a body on a visit, reply-in-thread on the first email, condition fields its check ignores), a missing subject or required body, an overlength note/message/InMail subject, out-of-range wait/withdrawal/post-age/acceptance values, {TOKEN} single braces, which would be sent as typed, and workflow paths that don't hold together (duplicate keys, a target that isn't a key or end, a condition or wait_for_connection without both yesNext and noNext, or any other step with them). */
|
|
2650
2650
|
steps: Array<{
|
|
2651
|
-
/** Step type. */
|
|
2652
|
-
type: "
|
|
2651
|
+
/** Step type. condition (If / else) and wait_for_connection (Wait for them to accept) send nothing; they continue on yesNext or noNext and make the campaign a workflow. */
|
|
2652
|
+
type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
|
|
2653
2653
|
/** wait steps: hours to wait before the next step. */
|
|
2654
2654
|
waitHours?: number;
|
|
2655
2655
|
/** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
|
|
@@ -2664,35 +2664,57 @@ export interface ApiRequests {
|
|
|
2664
2664
|
emailReplyToPrevious?: boolean;
|
|
2665
2665
|
/** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
|
|
2666
2666
|
onlyIf?: "always" | "connected" | "not_connected";
|
|
2667
|
-
/** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
|
|
2667
|
+
/** Legacy LinkedIn step sender (also on wait_for_connection, and on a condition that checks linkedin_connected). Pool campaigns use the campaign's linkedinAccountIds instead. */
|
|
2668
2668
|
linkedinAccountId?: string;
|
|
2669
2669
|
/** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the required message (up to 3000 chars); linkedin_inmail: the required message (up to 1900 chars). */
|
|
2670
2670
|
linkedinMessageBody?: string;
|
|
2671
2671
|
/** linkedin_message: what to do when the invite is still pending. */
|
|
2672
2672
|
linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
|
|
2673
|
-
/** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720)
|
|
2673
|
+
/** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720); after a connection step this mode is the default in a linear campaign. wait_for_connection: wait 24-2160 hours (1-90 days, default 720) before taking the Not accepted path. */
|
|
2674
2674
|
connectionTimeoutHours?: number;
|
|
2675
2675
|
/** linkedin_like_post only: the reaction to leave (default like). */
|
|
2676
2676
|
likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
|
|
2677
2677
|
/** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
|
|
2678
2678
|
likeMaxPostAgeDays?: number;
|
|
2679
|
+
/** linkedin_like_post only: before the immediately preceding wait starts, check for eligible posts. If none exist, skip that wait and the like step, keeping following waits. Defaults to false when omitted. */
|
|
2680
|
+
likeSkipPreviousWait?: boolean;
|
|
2679
2681
|
/** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
|
|
2680
2682
|
likeSkipNextWait?: boolean;
|
|
2683
|
+
/** linkedin_like_post only: how many recent posts to react to, 1-3 (default 1). */
|
|
2684
|
+
likeCount?: number;
|
|
2681
2685
|
/** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
|
|
2682
2686
|
inmailSubject?: string;
|
|
2683
2687
|
/** linkedin_connection only: withdraw a still-pending invitation sent by this campaign after 168-2160 hours (7-90 days). Omitted means off on creation; null turns it off on edit. */
|
|
2684
2688
|
withdrawAfterHours?: number | null;
|
|
2689
|
+
/** Workflow steps: this step's id, unique in the campaign, which next, yesNext and noNext point at (not "end"). Left out, one is made. */
|
|
2690
|
+
key?: string;
|
|
2691
|
+
/** Workflow steps: where a step that isn't a condition or wait_for_connection goes; left out, the following step: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
2692
|
+
next?: string;
|
|
2693
|
+
/** Workflow steps: condition and wait_for_connection only, required: where the Yes (Accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
2694
|
+
yesNext?: string;
|
|
2695
|
+
/** Workflow steps: condition and wait_for_connection only, required: where the No (Not accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
2696
|
+
noNext?: string;
|
|
2697
|
+
/** condition only, required: linkedin_connected, has_email, opened_last_email (needs an email before it on every path) or field_value. Fixed once the campaign launches. */
|
|
2698
|
+
check?: "linkedin_connected" | "has_email" | "opened_last_email" | "field_value";
|
|
2699
|
+
/** condition with check=field_value: the lead field to check, like "Job Title" or "Source" (the campaign itself changes Status, Last touch and LinkedIn connection). Fixed once the campaign launches. */
|
|
2700
|
+
conditionField?: string;
|
|
2701
|
+
/** condition with check=field_value: is, is_not, contains, is_empty or is_not_empty (all case-insensitive). Fixed once the campaign launches. */
|
|
2702
|
+
conditionOperator?: "is" | "is_not" | "is_empty" | "is_not_empty" | "contains";
|
|
2703
|
+
/** condition with check=field_value and is, is_not or contains: the text to compare with. Editable after launch. */
|
|
2704
|
+
conditionValue?: string;
|
|
2685
2705
|
}>;
|
|
2706
|
+
/** linear: steps run in order. workflow: steps have keys and paths (next, yesNext, noNext) and may include condition and wait_for_connection. Left out, a workflow stays one and steps with keys, paths or those types make one; nothing turns a workflow back into a list. When replacing a workflow's steps, send workflow, so steps without keys or paths are checked here the way they will be saved. */
|
|
2707
|
+
stepModel?: "linear" | "workflow";
|
|
2686
2708
|
/** Send {single braces} exactly as typed instead of rejecting them. Merge tokens always use {{double braces}}. */
|
|
2687
2709
|
allowSingleBraces?: boolean;
|
|
2688
2710
|
};
|
|
2689
|
-
/** Edit the text, waits and conditions of a launched (or paused) campaign's steps in place. Each step keeps its id, type and place; pass the stepId and the updatedAt you read, and only the fields you change. Messages already sent or being prepared keep their text; drafts use campaigns.steps.replace. — `dench campaign steps edit` — PATCH /api/v1/campaigns/{sequenceId}/steps */
|
|
2711
|
+
/** Edit the text, waits and conditions of a launched (or paused) campaign's steps in place. Each step keeps its id, type and place; pass the stepId and the updatedAt you read, and only the fields you change. A workflow keeps its paths and what each If / else checks (key, next, yesNext, noNext, check, conditionField, conditionOperator); conditionValue and acceptance waits stay editable. Messages already sent or being prepared keep their text; drafts use campaigns.steps.replace. — `dench campaign steps edit` — PATCH /api/v1/campaigns/{sequenceId}/steps */
|
|
2690
2712
|
"campaigns.steps.update": {
|
|
2691
2713
|
sequenceId: string;
|
|
2692
|
-
/** The steps to change. Rejected, not trimmed: a field the step type would drop, an overlength note/message/InMail subject, out-of-range wait/withdrawal/post-age values,
|
|
2714
|
+
/** The steps to change. Rejected, not trimmed: a field the step type would drop, an overlength note/message/InMail subject, out-of-range wait/withdrawal/post-age/acceptance values, {TOKEN} single braces, and a changed path or If / else check. */
|
|
2693
2715
|
steps: Array<{
|
|
2694
2716
|
/** The step's current type. A launched step's type can't change. */
|
|
2695
|
-
type: "
|
|
2717
|
+
type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
|
|
2696
2718
|
/** wait steps: hours to wait before the next step. */
|
|
2697
2719
|
waitHours?: number;
|
|
2698
2720
|
/** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
|
|
@@ -2707,24 +2729,44 @@ export interface ApiRequests {
|
|
|
2707
2729
|
emailReplyToPrevious?: boolean;
|
|
2708
2730
|
/** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
|
|
2709
2731
|
onlyIf?: "always" | "connected" | "not_connected";
|
|
2710
|
-
/** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
|
|
2732
|
+
/** Legacy LinkedIn step sender (also on wait_for_connection, and on a condition that checks linkedin_connected). Pool campaigns use the campaign's linkedinAccountIds instead. */
|
|
2711
2733
|
linkedinAccountId?: string;
|
|
2712
2734
|
/** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the required message (up to 3000 chars); linkedin_inmail: the required message (up to 1900 chars). */
|
|
2713
2735
|
linkedinMessageBody?: string;
|
|
2714
2736
|
/** linkedin_message: what to do when the invite is still pending. */
|
|
2715
2737
|
linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
|
|
2716
|
-
/** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720)
|
|
2738
|
+
/** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720); after a connection step this mode is the default in a linear campaign. wait_for_connection: wait 24-2160 hours (1-90 days, default 720) before taking the Not accepted path. */
|
|
2717
2739
|
connectionTimeoutHours?: number;
|
|
2718
2740
|
/** linkedin_like_post only: the reaction to leave (default like). */
|
|
2719
2741
|
likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
|
|
2720
2742
|
/** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
|
|
2721
2743
|
likeMaxPostAgeDays?: number;
|
|
2744
|
+
/** linkedin_like_post only: before the immediately preceding wait starts, check for eligible posts. If none exist, skip that wait and the like step, keeping following waits. Defaults to false when omitted. */
|
|
2745
|
+
likeSkipPreviousWait?: boolean;
|
|
2722
2746
|
/** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
|
|
2723
2747
|
likeSkipNextWait?: boolean;
|
|
2748
|
+
/** linkedin_like_post only: how many recent posts to react to, 1-3 (default 1). */
|
|
2749
|
+
likeCount?: number;
|
|
2724
2750
|
/** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
|
|
2725
2751
|
inmailSubject?: string;
|
|
2726
2752
|
/** linkedin_connection only: withdraw a still-pending invitation sent by this campaign after 168-2160 hours (7-90 days). Omitted means off on creation; null turns it off on edit. */
|
|
2727
2753
|
withdrawAfterHours?: number | null;
|
|
2754
|
+
/** Workflow steps: this step's id, unique in the campaign, which next, yesNext and noNext point at (not "end"). Left out, one is made. */
|
|
2755
|
+
key?: string;
|
|
2756
|
+
/** Workflow steps: where a step that isn't a condition or wait_for_connection goes; left out, the following step: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
2757
|
+
next?: string;
|
|
2758
|
+
/** Workflow steps: condition and wait_for_connection only, required: where the Yes (Accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
2759
|
+
yesNext?: string;
|
|
2760
|
+
/** Workflow steps: condition and wait_for_connection only, required: where the No (Not accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
2761
|
+
noNext?: string;
|
|
2762
|
+
/** condition only, required: linkedin_connected, has_email, opened_last_email (needs an email before it on every path) or field_value. Fixed once the campaign launches. */
|
|
2763
|
+
check?: "linkedin_connected" | "has_email" | "opened_last_email" | "field_value";
|
|
2764
|
+
/** condition with check=field_value: the lead field to check, like "Job Title" or "Source" (the campaign itself changes Status, Last touch and LinkedIn connection). Fixed once the campaign launches. */
|
|
2765
|
+
conditionField?: string;
|
|
2766
|
+
/** condition with check=field_value: is, is_not, contains, is_empty or is_not_empty (all case-insensitive). Fixed once the campaign launches. */
|
|
2767
|
+
conditionOperator?: "is" | "is_not" | "is_empty" | "is_not_empty" | "contains";
|
|
2768
|
+
/** condition with check=field_value and is, is_not or contains: the text to compare with. Editable after launch. */
|
|
2769
|
+
conditionValue?: string;
|
|
2728
2770
|
/** The step's _id from campaigns.get steps[]. */
|
|
2729
2771
|
stepId: string;
|
|
2730
2772
|
/** The step's updatedAt when you read it. If someone saved it since, the edit is refused instead of overwriting theirs. */
|
|
@@ -6117,6 +6159,8 @@ export interface ApiResponses {
|
|
|
6117
6159
|
}[];
|
|
6118
6160
|
dailySendCap?: number;
|
|
6119
6161
|
stepCount: number;
|
|
6162
|
+
/** linear: steps run in order. workflow: steps have keys and paths (next, yesNext, noNext) and may include condition and wait_for_connection. Left out, a workflow stays one and steps with keys, paths or those types make one; nothing turns a workflow back into a list. */
|
|
6163
|
+
stepModel?: "linear" | "workflow";
|
|
6120
6164
|
totalEnrolled: number;
|
|
6121
6165
|
activeCount: number;
|
|
6122
6166
|
pausedCount: number;
|
|
@@ -6166,6 +6210,8 @@ export interface ApiResponses {
|
|
|
6166
6210
|
}[];
|
|
6167
6211
|
dailySendCap?: number;
|
|
6168
6212
|
stepCount: number;
|
|
6213
|
+
/** linear: steps run in order. workflow: steps have keys and paths (next, yesNext, noNext) and may include condition and wait_for_connection. Left out, a workflow stays one and steps with keys, paths or those types make one; nothing turns a workflow back into a list. */
|
|
6214
|
+
stepModel?: "linear" | "workflow";
|
|
6169
6215
|
totalEnrolled: number;
|
|
6170
6216
|
activeCount: number;
|
|
6171
6217
|
pausedCount: number;
|
|
@@ -6180,9 +6226,10 @@ export interface ApiResponses {
|
|
|
6180
6226
|
updatedAt: number;
|
|
6181
6227
|
[key: string]: unknown;
|
|
6182
6228
|
};
|
|
6229
|
+
/** The steps in order, each with its _id. condition and wait_for_connection steps also carry a readable label. */
|
|
6183
6230
|
steps: Array<{
|
|
6184
|
-
/** Step type. */
|
|
6185
|
-
type: "
|
|
6231
|
+
/** Step type. condition (If / else) and wait_for_connection (Wait for them to accept) send nothing; they continue on yesNext or noNext and make the campaign a workflow. */
|
|
6232
|
+
type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
|
|
6186
6233
|
/** wait steps: hours to wait before the next step. */
|
|
6187
6234
|
waitHours?: number;
|
|
6188
6235
|
/** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
|
|
@@ -6197,24 +6244,44 @@ export interface ApiResponses {
|
|
|
6197
6244
|
emailReplyToPrevious?: boolean;
|
|
6198
6245
|
/** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
|
|
6199
6246
|
onlyIf?: "always" | "connected" | "not_connected";
|
|
6200
|
-
/** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
|
|
6247
|
+
/** Legacy LinkedIn step sender (also on wait_for_connection, and on a condition that checks linkedin_connected). Pool campaigns use the campaign's linkedinAccountIds instead. */
|
|
6201
6248
|
linkedinAccountId?: string;
|
|
6202
6249
|
/** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the required message (up to 3000 chars); linkedin_inmail: the required message (up to 1900 chars). */
|
|
6203
6250
|
linkedinMessageBody?: string;
|
|
6204
6251
|
/** linkedin_message: what to do when the invite is still pending. */
|
|
6205
6252
|
linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
|
|
6206
|
-
/** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720)
|
|
6253
|
+
/** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720); after a connection step this mode is the default in a linear campaign. wait_for_connection: wait 24-2160 hours (1-90 days, default 720) before taking the Not accepted path. */
|
|
6207
6254
|
connectionTimeoutHours?: number;
|
|
6208
6255
|
/** linkedin_like_post only: the reaction to leave (default like). */
|
|
6209
6256
|
likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
|
|
6210
6257
|
/** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
|
|
6211
6258
|
likeMaxPostAgeDays?: number;
|
|
6259
|
+
/** linkedin_like_post only: before the immediately preceding wait starts, check for eligible posts. If none exist, skip that wait and the like step, keeping following waits. Defaults to false when omitted. */
|
|
6260
|
+
likeSkipPreviousWait?: boolean;
|
|
6212
6261
|
/** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
|
|
6213
6262
|
likeSkipNextWait?: boolean;
|
|
6263
|
+
/** linkedin_like_post only: how many recent posts to react to, 1-3 (default 1). */
|
|
6264
|
+
likeCount?: number;
|
|
6214
6265
|
/** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
|
|
6215
6266
|
inmailSubject?: string;
|
|
6216
6267
|
/** linkedin_connection only: withdraw a still-pending invitation sent by this campaign after 168-2160 hours (7-90 days). Omitted means off on creation; null turns it off on edit. */
|
|
6217
6268
|
withdrawAfterHours?: number | null;
|
|
6269
|
+
/** Workflow steps: this step's id, unique in the campaign, which next, yesNext and noNext point at (not "end"). Left out, one is made. */
|
|
6270
|
+
key?: string;
|
|
6271
|
+
/** Workflow steps: where a step that isn't a condition or wait_for_connection goes; left out, the following step: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
6272
|
+
next?: string;
|
|
6273
|
+
/** Workflow steps: condition and wait_for_connection only, required: where the Yes (Accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
6274
|
+
yesNext?: string;
|
|
6275
|
+
/** Workflow steps: condition and wait_for_connection only, required: where the No (Not accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
6276
|
+
noNext?: string;
|
|
6277
|
+
/** condition only, required: linkedin_connected, has_email, opened_last_email (needs an email before it on every path) or field_value. Fixed once the campaign launches. */
|
|
6278
|
+
check?: "linkedin_connected" | "has_email" | "opened_last_email" | "field_value";
|
|
6279
|
+
/** condition with check=field_value: the lead field to check, like "Job Title" or "Source" (the campaign itself changes Status, Last touch and LinkedIn connection). Fixed once the campaign launches. */
|
|
6280
|
+
conditionField?: string;
|
|
6281
|
+
/** condition with check=field_value: is, is_not, contains, is_empty or is_not_empty (all case-insensitive). Fixed once the campaign launches. */
|
|
6282
|
+
conditionOperator?: "is" | "is_not" | "is_empty" | "is_not_empty" | "contains";
|
|
6283
|
+
/** condition with check=field_value and is, is_not or contains: the text to compare with. Editable after launch. */
|
|
6284
|
+
conditionValue?: string;
|
|
6218
6285
|
[key: string]: unknown;
|
|
6219
6286
|
}>;
|
|
6220
6287
|
enrollments: Record<string, unknown>[];
|
|
@@ -6250,6 +6317,14 @@ export interface ApiResponses {
|
|
|
6250
6317
|
replyRate: number;
|
|
6251
6318
|
openRate: number;
|
|
6252
6319
|
clickRate: number;
|
|
6320
|
+
/** Workflows only: each condition and wait_for_connection step, in step order, with how many people took each path. */
|
|
6321
|
+
branchStats?: {
|
|
6322
|
+
stepId: string;
|
|
6323
|
+
/** People who took the Yes (Accepted) path. */
|
|
6324
|
+
yes: number;
|
|
6325
|
+
/** People who took the No (Not accepted) path. */
|
|
6326
|
+
no: number;
|
|
6327
|
+
}[];
|
|
6253
6328
|
truncated: boolean;
|
|
6254
6329
|
[key: string]: unknown;
|
|
6255
6330
|
};
|
|
@@ -6262,7 +6337,15 @@ export interface ApiResponses {
|
|
|
6262
6337
|
dailySendCap: number | null;
|
|
6263
6338
|
nextEmailAt: number | null;
|
|
6264
6339
|
now: Record<string, unknown> | null;
|
|
6265
|
-
next:
|
|
6340
|
+
next: {
|
|
6341
|
+
/** profile, visit, invite, message, like, inmail, withdraw, email, wait or check (an If / else). */
|
|
6342
|
+
kind: string;
|
|
6343
|
+
/** Waiting for them to accept: when the wait ends either way. */
|
|
6344
|
+
acceptanceDeadline?: number;
|
|
6345
|
+
/** kind check: what the If / else checks, e.g. "Has an email address". */
|
|
6346
|
+
label?: string;
|
|
6347
|
+
[key: string]: unknown;
|
|
6348
|
+
} | null;
|
|
6266
6349
|
paused: Record<string, unknown> | null;
|
|
6267
6350
|
senders: Record<string, unknown>[];
|
|
6268
6351
|
[key: string]: unknown;
|
|
@@ -6538,8 +6621,8 @@ export interface ApiResponses {
|
|
|
6538
6621
|
sequence: Record<string, unknown> | null;
|
|
6539
6622
|
/** The campaign's steps in order, each with its _id. */
|
|
6540
6623
|
steps: Array<{
|
|
6541
|
-
/** Step type. */
|
|
6542
|
-
type: "
|
|
6624
|
+
/** Step type. condition (If / else) and wait_for_connection (Wait for them to accept) send nothing; they continue on yesNext or noNext and make the campaign a workflow. */
|
|
6625
|
+
type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
|
|
6543
6626
|
/** wait steps: hours to wait before the next step. */
|
|
6544
6627
|
waitHours?: number;
|
|
6545
6628
|
/** Legacy email step sender. Pool campaigns choose senders in emailMailboxAccountIds on the campaign, not on individual steps. */
|
|
@@ -6554,24 +6637,44 @@ export interface ApiResponses {
|
|
|
6554
6637
|
emailReplyToPrevious?: boolean;
|
|
6555
6638
|
/** email and linkedin_like_post only: always (default), connected or not_connected. InMail automatically skips connected people; do not set a condition on it. */
|
|
6556
6639
|
onlyIf?: "always" | "connected" | "not_connected";
|
|
6557
|
-
/** Legacy LinkedIn step sender. Pool campaigns use the campaign's linkedinAccountIds instead. */
|
|
6640
|
+
/** Legacy LinkedIn step sender (also on wait_for_connection, and on a condition that checks linkedin_connected). Pool campaigns use the campaign's linkedinAccountIds instead. */
|
|
6558
6641
|
linkedinAccountId?: string;
|
|
6559
6642
|
/** linkedin_connection: the invite note (optional, up to 300 chars; sent without it if LinkedIn refuses the note); linkedin_message: the required message (up to 3000 chars); linkedin_inmail: the required message (up to 1900 chars). */
|
|
6560
6643
|
linkedinMessageBody?: string;
|
|
6561
6644
|
/** linkedin_message: what to do when the invite is still pending. */
|
|
6562
6645
|
linkedinMessageMode?: "skip_if_not_connected" | "wait_until_connected";
|
|
6563
|
-
/** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720)
|
|
6646
|
+
/** linkedin_message with linkedinMessageMode=wait_until_connected: wait 1-2160 hours for acceptance (default 720); after a connection step this mode is the default in a linear campaign. wait_for_connection: wait 24-2160 hours (1-90 days, default 720) before taking the Not accepted path. */
|
|
6564
6647
|
connectionTimeoutHours?: number;
|
|
6565
6648
|
/** linkedin_like_post only: the reaction to leave (default like). */
|
|
6566
6649
|
likeReaction?: "like" | "celebrate" | "support" | "love" | "insightful" | "funny";
|
|
6567
6650
|
/** linkedin_like_post only: select the newest eligible original post from the last 1-365 days (default 30). */
|
|
6568
6651
|
likeMaxPostAgeDays?: number;
|
|
6652
|
+
/** linkedin_like_post only: before the immediately preceding wait starts, check for eligible posts. If none exist, skip that wait and the like step, keeping following waits. Defaults to false when omitted. */
|
|
6653
|
+
likeSkipPreviousWait?: boolean;
|
|
6569
6654
|
/** linkedin_like_post only: skip consecutive following wait steps whenever the reaction step is skipped (default true). False keeps those waits. */
|
|
6570
6655
|
likeSkipNextWait?: boolean;
|
|
6656
|
+
/** linkedin_like_post only: how many recent posts to react to, 1-3 (default 1). */
|
|
6657
|
+
likeCount?: number;
|
|
6571
6658
|
/** linkedin_inmail only: optional subject, up to 200 characters; merge tokens allowed. Clear with an empty string. */
|
|
6572
6659
|
inmailSubject?: string;
|
|
6573
6660
|
/** linkedin_connection only: withdraw a still-pending invitation sent by this campaign after 168-2160 hours (7-90 days). Omitted means off on creation; null turns it off on edit. */
|
|
6574
6661
|
withdrawAfterHours?: number | null;
|
|
6662
|
+
/** Workflow steps: this step's id, unique in the campaign, which next, yesNext and noNext point at (not "end"). Left out, one is made. */
|
|
6663
|
+
key?: string;
|
|
6664
|
+
/** Workflow steps: where a step that isn't a condition or wait_for_connection goes; left out, the following step: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
6665
|
+
next?: string;
|
|
6666
|
+
/** Workflow steps: condition and wait_for_connection only, required: where the Yes (Accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
6667
|
+
yesNext?: string;
|
|
6668
|
+
/** Workflow steps: condition and wait_for_connection only, required: where the No (Not accepted) path goes: another step's key, or "end" to stop there. Fixed once the campaign launches. */
|
|
6669
|
+
noNext?: string;
|
|
6670
|
+
/** condition only, required: linkedin_connected, has_email, opened_last_email (needs an email before it on every path) or field_value. Fixed once the campaign launches. */
|
|
6671
|
+
check?: "linkedin_connected" | "has_email" | "opened_last_email" | "field_value";
|
|
6672
|
+
/** condition with check=field_value: the lead field to check, like "Job Title" or "Source" (the campaign itself changes Status, Last touch and LinkedIn connection). Fixed once the campaign launches. */
|
|
6673
|
+
conditionField?: string;
|
|
6674
|
+
/** condition with check=field_value: is, is_not, contains, is_empty or is_not_empty (all case-insensitive). Fixed once the campaign launches. */
|
|
6675
|
+
conditionOperator?: "is" | "is_not" | "is_empty" | "is_not_empty" | "contains";
|
|
6676
|
+
/** condition with check=field_value and is, is_not or contains: the text to compare with. Editable after launch. */
|
|
6677
|
+
conditionValue?: string;
|
|
6575
6678
|
[key: string]: unknown;
|
|
6576
6679
|
}>;
|
|
6577
6680
|
/** One run for each step the person has reached, in order. */
|
|
@@ -6581,8 +6684,8 @@ export interface ApiResponses {
|
|
|
6581
6684
|
stepId: string;
|
|
6582
6685
|
/** The step's place, from 0. */
|
|
6583
6686
|
stepIndex: number;
|
|
6584
|
-
/** Step type. */
|
|
6585
|
-
type: "
|
|
6687
|
+
/** Step type. condition (If / else) and wait_for_connection (Wait for them to accept) send nothing; they continue on yesNext or noNext and make the campaign a workflow. */
|
|
6688
|
+
type: "wait" | "email" | "linkedin_connection" | "linkedin_message" | "linkedin_visit" | "linkedin_like_post" | "linkedin_inmail" | "condition" | "wait_for_connection";
|
|
6586
6689
|
/** sent: done (a wait that finished is sent too). skipped: see result.reason. retry: will be tried again at retryAt. unknown: needs a look. */
|
|
6587
6690
|
status: "queued" | "running" | "waiting" | "retry" | "sent" | "skipped" | "failed" | "unknown";
|
|
6588
6691
|
scheduledAt?: number;
|
|
@@ -6593,7 +6696,9 @@ export interface ApiResponses {
|
|
|
6593
6696
|
/** The email this run sent, in emailMessages[]. */
|
|
6594
6697
|
emailMessageId?: string;
|
|
6595
6698
|
lastError?: string;
|
|
6596
|
-
/**
|
|
6699
|
+
/** wait_for_connection: when it stops waiting for the accept. */
|
|
6700
|
+
timeoutAt?: number;
|
|
6701
|
+
/** For a skipped step, { reason } says why. A finished condition or wait_for_connection has { branch: "yes" | "no" } (Yes / Accepted or No / Not accepted), and { reason } for some No paths. */
|
|
6597
6702
|
result?: unknown;
|
|
6598
6703
|
[key: string]: unknown;
|
|
6599
6704
|
}>;
|
|
@@ -7760,7 +7865,7 @@ export type DenchApiTree = {
|
|
|
7760
7865
|
/** Discover LinkedIn sender ids, labels, availability and remaining capacity visible to the acting workspace member. Never returns provider credentials. (`dench campaign accounts`) */
|
|
7761
7866
|
linkedin(args?: Req<"campaigns.accounts.linkedin">): Promise<Res<"campaigns.accounts.linkedin">>;
|
|
7762
7867
|
};
|
|
7763
|
-
/** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks. (`dench campaign get`) */
|
|
7868
|
+
/** Campaign funnel: enrolled, contacted, invited, accepted, messaged, replied, opens and clicks, and for a workflow how many people took each If / else and Wait for them to accept path (branchStats). (`dench campaign get`) */
|
|
7764
7869
|
analytics(args: Req<"campaigns.analytics">): Promise<Res<"campaigns.analytics">>;
|
|
7765
7870
|
/** Archive a campaign and stop everyone still in flight. This is the app's Delete: campaigns are never erased, and their people, leads and activity stay. (`dench campaign archive`) */
|
|
7766
7871
|
archive(args: Req<"campaigns.archive">): Promise<Res<"campaigns.archive">>;
|
|
@@ -7874,9 +7979,9 @@ export type DenchApiTree = {
|
|
|
7874
7979
|
update(args: Req<"campaigns.sources.update">): Promise<Res<"campaigns.sources.update">>;
|
|
7875
7980
|
};
|
|
7876
7981
|
steps: {
|
|
7877
|
-
/** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message, post reaction, InMail). Steps are checked first: a field the step type would drop, missing text
|
|
7982
|
+
/** Replace every step of a draft campaign (email, wait, LinkedIn visit, connection request, message, post reaction, InMail, If / else, Wait for them to accept). A workflow (stepModel workflow, or steps with key, next, yesNext or noNext) branches: condition and wait_for_connection steps continue on yesNext or noNext, other steps on next; each points at another step's key or end. Steps are checked first: a field the step type would drop, missing text, {TOKEN} single braces or paths that don't hold together are rejected, not saved. Configure sender pools on the campaign; step sender ids are legacy-only. (`dench campaign steps set`) */
|
|
7878
7983
|
replace(args: Req<"campaigns.steps.replace">): Promise<Res<"campaigns.steps.replace">>;
|
|
7879
|
-
/** Edit the text, waits and conditions of a launched (or paused) campaign's steps in place. Each step keeps its id, type and place; pass the stepId and the updatedAt you read, and only the fields you change. Messages already sent or being prepared keep their text; drafts use campaigns.steps.replace. (`dench campaign steps edit`) */
|
|
7984
|
+
/** Edit the text, waits and conditions of a launched (or paused) campaign's steps in place. Each step keeps its id, type and place; pass the stepId and the updatedAt you read, and only the fields you change. A workflow keeps its paths and what each If / else checks (key, next, yesNext, noNext, check, conditionField, conditionOperator); conditionValue and acceptance waits stay editable. Messages already sent or being prepared keep their text; drafts use campaigns.steps.replace. (`dench campaign steps edit`) */
|
|
7880
7985
|
update(args: Req<"campaigns.steps.update">): Promise<Res<"campaigns.steps.update">>;
|
|
7881
7986
|
};
|
|
7882
7987
|
/** Change a campaign's name, sender pools, send windows, daily email cap, stop-on-reply, start or end. Works until archived; existing conversations keep their assigned sender. (`dench campaign set`) */
|
package/apps.ts
CHANGED
|
@@ -91,8 +91,12 @@ function withAuth(ctx: Ctx, args: Record<string, unknown>) {
|
|
|
91
91
|
} as never;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
function appsHelp() {
|
|
95
|
-
console.log(
|
|
94
|
+
function appsHelp(): void {
|
|
95
|
+
console.log(appsHelpText());
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function appsHelpText(): string {
|
|
99
|
+
return `Usage: dench apps <subcommand> (App Store — not connected apps; see 'dench integrations')
|
|
96
100
|
|
|
97
101
|
dench apps list [--json] Installed apps in this workspace
|
|
98
102
|
dench apps gallery [--json] Discover listings — Official (Dench) + Community
|
|
@@ -113,7 +117,7 @@ function appsHelp() {
|
|
|
113
117
|
dench apps webhooks list <slug>
|
|
114
118
|
dench apps webhooks poll <slug> <hookName> [--since <ms>] [--limit <n>]
|
|
115
119
|
dench apps webhooks delete <slug> <hookName>
|
|
116
|
-
|
|
120
|
+
`;
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
const TEXT_FILE = /\.(html?|js|mjs|cjs|ts|jsx|tsx|css|json|ya?ml|md|txt|svg)$/i;
|
package/browser.ts
CHANGED
|
@@ -81,7 +81,11 @@ const ACTIONS = new Set([
|
|
|
81
81
|
]);
|
|
82
82
|
|
|
83
83
|
function browserHelp(): void {
|
|
84
|
-
console.log(
|
|
84
|
+
console.log(browserHelpText());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function browserHelpText(): string {
|
|
88
|
+
return `Usage: dench browser <action> [options]
|
|
85
89
|
|
|
86
90
|
Control Dench Browser without opening dench.com locally.
|
|
87
91
|
Commands authenticate with the active dench signin session or DENCH_API_KEY.
|
|
@@ -105,6 +109,7 @@ Common:
|
|
|
105
109
|
dench browser activate-tab <targetId>
|
|
106
110
|
dench browser close-tab <targetId>
|
|
107
111
|
dench browser stop
|
|
112
|
+
dench browser reset
|
|
108
113
|
|
|
109
114
|
Playwright sessions:
|
|
110
115
|
dench browser session create --json
|
|
@@ -114,8 +119,8 @@ Playwright sessions:
|
|
|
114
119
|
State:
|
|
115
120
|
The CLI remembers the latest browser thread per Dench host/session.
|
|
116
121
|
Use --thread <threadId> to control a specific thread, or
|
|
117
|
-
dench browser reset to forget the local remembered thread.
|
|
118
|
-
|
|
122
|
+
\`dench browser reset\` to forget the local remembered thread.
|
|
123
|
+
`;
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
function consumeFlagValue(args: string[], name: string): string | undefined {
|