conduyt 1.38.0 → 1.40.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/dist/index.js +51 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -804,8 +804,45 @@ messages
|
|
|
804
804
|
}));
|
|
805
805
|
messages
|
|
806
806
|
.command("transports")
|
|
807
|
-
.description("What a workflow Send SMS step can speak through today (GET /sms/transports): Twilio {connected, numbers = account number + active reps' lines, valid send_sms fromNumber values}, Project Blue {connected, lines held by active reps, valid projectBlueLineId values for smsMode project_blue}, WhatsApp {connected, sender for smsMode whatsapp}, Voice drop {connected, recordings = the Voicemail Drop catalog for smsMode voice_drop}, webhook provider count, FromK.ai
|
|
807
|
+
.description("What a workflow Send SMS step can speak through today (GET /sms/transports): Twilio {connected, numbers = account number + active reps' lines, valid send_sms fromNumber values}, Project Blue {connected, lines held by active reps, valid projectBlueLineId values for smsMode project_blue}, WhatsApp {connected, sender for smsMode whatsapp}, Voice drop {connected, recordings = the Voicemail Drop catalog for smsMode voice_drop}, webhook provider count, FromK.ai {connected, lines = the workspace's send-ready lines, valid fromkPhoneNumberId values for smsMode fromk} (automations scope)")
|
|
808
808
|
.action(run(async (client) => client.get("/api/v1/sms/transports")));
|
|
809
|
+
// ---- FromK.ai (2026-09-14): Conduyt's own texting platform as a native transport ----
|
|
810
|
+
const fromk = program.command("fromk").description("FromK.ai: text through your FromK.ai workspace (its lines, credits, consent and STOP rules); Conduyt drives it with the workspace's API key (settings scope)");
|
|
811
|
+
fromk
|
|
812
|
+
.command("status")
|
|
813
|
+
.description("Connection status (GET /settings/fromk): key masked, the lines snapshot with sendReady, the webhook URL to paste into FromK.ai and whether its signing secret is stored")
|
|
814
|
+
.action(run(async (client) => client.get("/api/v1/settings/fromk")));
|
|
815
|
+
fromk
|
|
816
|
+
.command("connect")
|
|
817
|
+
.description("Connect or replace the workspace API key (fk_…, numbers:read + contacts:write + messages:send) — verified with FromK.ai before it is stored")
|
|
818
|
+
.option("--key <apiKey>", "FromK.ai workspace API key; omit to read FROMK_API_KEY from the environment and keep the key out of shell history")
|
|
819
|
+
.action(run(async (client, opts) => {
|
|
820
|
+
const apiKey = (opts.key ?? process.env.FROMK_API_KEY ?? "").trim();
|
|
821
|
+
if (!apiKey)
|
|
822
|
+
throw new Error("Pass --key or set FROMK_API_KEY.");
|
|
823
|
+
return client.put("/api/v1/settings/fromk", { apiKey });
|
|
824
|
+
}));
|
|
825
|
+
fromk
|
|
826
|
+
.command("disconnect")
|
|
827
|
+
.description("Forget the key, the signing secret, the lines and every contact link; FromK.ai workflow steps stop sending")
|
|
828
|
+
.action(run(async (client) => client.del("/api/v1/settings/fromk")));
|
|
829
|
+
fromk
|
|
830
|
+
.command("lines")
|
|
831
|
+
.description("Refresh the line list from the workspace and store it as the new snapshot: each send-ready phoneNumberId is a valid --fromk-line / fromkPhoneNumberId")
|
|
832
|
+
.action(run(async (client) => client.get("/api/v1/settings/fromk/lines")));
|
|
833
|
+
fromk
|
|
834
|
+
.command("webhook-secret")
|
|
835
|
+
.description("Store the signing secret of the FromK.ai webhook endpoint pointed at Conduyt (whsec_…); --clear forgets it")
|
|
836
|
+
.option("--secret <secret>", "the endpoint's signing secret; omit to read FROMK_WEBHOOK_SECRET from the environment")
|
|
837
|
+
.option("--clear", "forget the stored secret")
|
|
838
|
+
.action(run(async (client, opts) => {
|
|
839
|
+
if (opts.clear)
|
|
840
|
+
return client.del("/api/v1/settings/fromk/webhook");
|
|
841
|
+
const secret = (opts.secret ?? process.env.FROMK_WEBHOOK_SECRET ?? "").trim();
|
|
842
|
+
if (!secret)
|
|
843
|
+
throw new Error("Pass --secret or set FROMK_WEBHOOK_SECRET (or --clear).");
|
|
844
|
+
return client.put("/api/v1/settings/fromk/webhook", { secret });
|
|
845
|
+
}));
|
|
809
846
|
// ---- WhatsApp via Twilio (2026-09-11) ----
|
|
810
847
|
const whatsapp = program.command("whatsapp").description("WhatsApp via your own Twilio account: a Meta-approved sender, approved templates for outreach, free-form replies within a contact's 24-hour window");
|
|
811
848
|
whatsapp
|
|
@@ -834,12 +871,13 @@ whatsapp
|
|
|
834
871
|
.action(run(async (client) => client.get("/api/v1/sms/whatsapp/templates")));
|
|
835
872
|
messages
|
|
836
873
|
.command("send-sms")
|
|
837
|
-
.description("Send an outbound SMS (POST /messages/sms/send) — via Twilio,
|
|
874
|
+
.description("Send an outbound SMS (POST /messages/sms/send) — via Twilio, from your own Project Blue iPhone line (--transport project_blue), on WhatsApp (--transport whatsapp) or through your FromK.ai workspace (--transport fromk)")
|
|
838
875
|
.option("--contact <id>", "contact UUID (required)")
|
|
839
876
|
.option("--body <text>", "SMS body, 1-1600 chars (required)")
|
|
840
877
|
.option("--from <number>", "from number — must be an account-owned Twilio number/agent DID")
|
|
841
878
|
.option("--provider <id>", "smsProviderId UUID")
|
|
842
|
-
.option("--transport <transport>", "twilio (default) | project_blue — your assigned Project Blue iPhone line (iMessage when the lead is on Apple, SMS otherwise) | whatsapp — the account's WhatsApp sender (free-form only within 24 hours of the lead's last WhatsApp message, else an approved template via --whatsapp-template)")
|
|
879
|
+
.option("--transport <transport>", "twilio (default) | project_blue — your assigned Project Blue iPhone line (iMessage when the lead is on Apple, SMS otherwise) | whatsapp — the account's WhatsApp sender (free-form only within 24 hours of the lead's last WhatsApp message, else an approved template via --whatsapp-template) | fromk — through your FromK.ai workspace (Settings → FromK.ai), from --fromk-line or the workspace's single send-ready line")
|
|
880
|
+
.option("--fromk-line <phoneNumberId>", "transport fromk: the FromK.ai line to send from (a send-ready phoneNumberId from `fromk status`); omit when the workspace has one send-ready line")
|
|
843
881
|
.option("--whatsapp-template <sid>", "transport whatsapp: an APPROVED template (Twilio Content SID HX…, see `whatsapp templates`); Conduyt reads it from Twilio at send time and records its text with the variables in place")
|
|
844
882
|
.option("--whatsapp-variables <json>", 'transport whatsapp with a template: placeholder number → value as JSON, e.g. {"1":"Alex"}')
|
|
845
883
|
.option("--idempotency-key <key>", "operation key (8-200 chars) for at-most-once sends: reuse the SAME key when retrying a send whose outcome you did not see")
|
|
@@ -860,6 +898,8 @@ messages
|
|
|
860
898
|
body.whatsappContentSid = opts.whatsappTemplate;
|
|
861
899
|
if (opts.whatsappVariables !== undefined)
|
|
862
900
|
body.whatsappContentVariables = jsonArg(opts.whatsappVariables, "--whatsapp-variables");
|
|
901
|
+
if (opts.fromkLine !== undefined)
|
|
902
|
+
body.fromkPhoneNumberId = opts.fromkLine;
|
|
863
903
|
if (opts.idempotencyKey !== undefined)
|
|
864
904
|
body.idempotencyKey = opts.idempotencyKey;
|
|
865
905
|
if (opts.json !== undefined)
|
|
@@ -2740,6 +2780,8 @@ smartViews
|
|
|
2740
2780
|
.option("--max-attempts <n>", "stop after N calls to a lead, ever (1-20)")
|
|
2741
2781
|
.option("--per-day <n>", "most calls to one lead per account-local day (1-20); pass 'none' to remove the daily cap")
|
|
2742
2782
|
.option("--cooldown <minutes>", "minutes to wait between calls to the same lead (0-10080)")
|
|
2783
|
+
.option("--include-unassigned", "also hand out leads nobody owns yet (shared pool; the lead is assigned to the rep at hand-out)")
|
|
2784
|
+
.option("--assigned-only", "the rep's own leads only (turns the shared pool off)")
|
|
2743
2785
|
.option("--schedule <json>", 'retry schedule JSON, e.g. \'[{"attemptNumber":1,"delayMinutes":0},{"attemptNumber":2,"delayMinutes":60}]\'')
|
|
2744
2786
|
.action(run(async (client, id, opts) => {
|
|
2745
2787
|
assertUuid(id, "smart view id");
|
|
@@ -2750,6 +2792,12 @@ smartViews
|
|
|
2750
2792
|
body.dialEnabled = true;
|
|
2751
2793
|
if (opts.disable)
|
|
2752
2794
|
body.dialEnabled = false;
|
|
2795
|
+
if (opts.includeUnassigned && opts.assignedOnly)
|
|
2796
|
+
throw new Error("--include-unassigned and --assigned-only are exclusive");
|
|
2797
|
+
if (opts.includeUnassigned)
|
|
2798
|
+
body.dialIncludeUnassigned = true;
|
|
2799
|
+
if (opts.assignedOnly)
|
|
2800
|
+
body.dialIncludeUnassigned = false;
|
|
2753
2801
|
const intFlag = (raw, flag, min, max) => {
|
|
2754
2802
|
if (raw === undefined)
|
|
2755
2803
|
return undefined;
|
package/package.json
CHANGED