@erdoai/cli 0.104.1 → 0.107.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 +149 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -576,6 +576,31 @@ var ErdoClient = class {
|
|
|
576
576
|
`/v1/voice/sms-conversations/${encodeURIComponent(sessionID)}${qs ? `?${qs}` : ""}`
|
|
577
577
|
);
|
|
578
578
|
}
|
|
579
|
+
// WhatsApp conversations on those same numbers — their own resource rather
|
|
580
|
+
// than a channel on the SMS reads, addressed and filtered the same way.
|
|
581
|
+
listWhatsAppConversations(params) {
|
|
582
|
+
const q = new URLSearchParams();
|
|
583
|
+
if (params?.phone_number) q.set("phone_number", params.phone_number);
|
|
584
|
+
if (params?.address) q.set("address", params.address);
|
|
585
|
+
if (params?.canonical_lead_id) q.set("canonical_lead_id", params.canonical_lead_id);
|
|
586
|
+
if (params?.limit !== void 0) q.set("limit", String(params.limit));
|
|
587
|
+
if (params?.cursor) q.set("cursor", params.cursor);
|
|
588
|
+
const qs = q.toString();
|
|
589
|
+
return this.request(
|
|
590
|
+
"GET",
|
|
591
|
+
`/v1/voice/whatsapp-conversations${qs ? `?${qs}` : ""}`
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
getWhatsAppConversation(sessionID, params) {
|
|
595
|
+
const q = new URLSearchParams();
|
|
596
|
+
if (params?.limit !== void 0) q.set("limit", String(params.limit));
|
|
597
|
+
if (params?.cursor) q.set("cursor", params.cursor);
|
|
598
|
+
const qs = q.toString();
|
|
599
|
+
return this.request(
|
|
600
|
+
"GET",
|
|
601
|
+
`/v1/voice/whatsapp-conversations/${encodeURIComponent(sessionID)}${qs ? `?${qs}` : ""}`
|
|
602
|
+
);
|
|
603
|
+
}
|
|
579
604
|
// The organization's business profile: its legal identity, which every A2P
|
|
580
605
|
// registration on the account is checked against. It follows the org
|
|
581
606
|
// convention rather than the voice one because it is the organization's, not
|
|
@@ -5203,8 +5228,8 @@ pagesCmd.command("restore <id>").description("Restore a previously deleted page
|
|
|
5203
5228
|
}
|
|
5204
5229
|
});
|
|
5205
5230
|
pagesCmd.command("monitor <id>").description(
|
|
5206
|
-
"Control health monitoring for a published page: --exclude stops all probing (dashboards, trackers, demos); --ack <sig> acknowledges a known failure class (mobile:overflow, desktop:resource, visual:defect, visual:score) so it stops alerting and never auto-repairs while a NEW failure class still alerts"
|
|
5207
|
-
).option("--exclude [reason]", "exclude this page from monitoring entirely (optional reason)").option("--include", "re-include the page in monitoring").option("--ack <sigs>", "comma-separated failure signatures to acknowledge (e.g. mobile:overflow,desktop:resource,visual:defect,visual:score)").option("--unack <sigs>", "comma-separated failure signatures to un-acknowledge").option("--reset", "clear all acknowledged failure signatures").action(async (id, opts) => {
|
|
5231
|
+
"Control health monitoring for a published page: --exclude stops all probing (dashboards, trackers, demos); --canary opts a PRIVATE page into the browser canary (renders it as its owner sees it and reports a broken render to the owner); --ack <sig> acknowledges a known failure class (mobile:overflow, desktop:resource, visual:defect, visual:score) so it stops alerting and never auto-repairs while a NEW failure class still alerts"
|
|
5232
|
+
).option("--exclude [reason]", "exclude this page from monitoring entirely (optional reason)").option("--include", "re-include the page in monitoring").option("--canary", "opt this private page into the browser canary").option("--no-canary", "opt this private page out of the browser canary").option("--ack <sigs>", "comma-separated failure signatures to acknowledge (e.g. mobile:overflow,desktop:resource,visual:defect,visual:score)").option("--unack <sigs>", "comma-separated failure signatures to un-acknowledge").option("--reset", "clear all acknowledged failure signatures").action(async (id, opts) => {
|
|
5208
5233
|
try {
|
|
5209
5234
|
const api = new ErdoClient();
|
|
5210
5235
|
const body = {};
|
|
@@ -5213,6 +5238,7 @@ pagesCmd.command("monitor <id>").description(
|
|
|
5213
5238
|
body.excluded = true;
|
|
5214
5239
|
body.excluded_reason = opts.exclude;
|
|
5215
5240
|
} else if (opts.exclude === true) body.excluded = true;
|
|
5241
|
+
if (opts.canary !== void 0) body.canary = opts.canary;
|
|
5216
5242
|
if (opts.ack) body.ack_add = opts.ack.split(",").map((s) => s.trim()).filter(Boolean);
|
|
5217
5243
|
if (opts.unack) body.ack_remove = opts.unack.split(",").map((s) => s.trim()).filter(Boolean);
|
|
5218
5244
|
if (opts.reset) body.ack_reset = true;
|
|
@@ -5967,6 +5993,127 @@ contact: ${parts.join(" \xB7 ")}`);
|
|
|
5967
5993
|
}
|
|
5968
5994
|
}
|
|
5969
5995
|
);
|
|
5996
|
+
var voiceWhatsAppCmd = voiceCmd.command("whatsapp").description("WhatsApp conversations on a voice agent's own number");
|
|
5997
|
+
voiceWhatsAppCmd.command("list").description("List the organization's WhatsApp conversations, most recently active first").option("--phone-number <number>", "only conversations on this Erdo number (any format)").option("--address <number>", "only the conversation with this person (any format)").option("--lead <lead>", LEAD_FILTER_HELP).option("--limit <n>", "page size (default 25, max 100)").option("--cursor <cursor>", "next_cursor from the preceding page (stable paging)").option("--json", "print the raw JSON result instead of a table").action(
|
|
5998
|
+
async (opts) => {
|
|
5999
|
+
try {
|
|
6000
|
+
const res = await new ErdoClient().listWhatsAppConversations({
|
|
6001
|
+
phone_number: opts.phoneNumber,
|
|
6002
|
+
address: opts.address,
|
|
6003
|
+
canonical_lead_id: opts.lead,
|
|
6004
|
+
limit: opts.limit ? Number(opts.limit) : void 0,
|
|
6005
|
+
cursor: opts.cursor
|
|
6006
|
+
});
|
|
6007
|
+
if (opts.json) {
|
|
6008
|
+
print(res);
|
|
6009
|
+
return;
|
|
6010
|
+
}
|
|
6011
|
+
const conversations = res.conversations ?? [];
|
|
6012
|
+
if (conversations.length === 0) {
|
|
6013
|
+
console.log("No WhatsApp conversations match those filters.");
|
|
6014
|
+
return;
|
|
6015
|
+
}
|
|
6016
|
+
printAlignedTable(
|
|
6017
|
+
["session id", "phone", "address", "name", "msgs", "last inbound", "last outbound", "lead ref", "summary"],
|
|
6018
|
+
conversations.map((c) => [
|
|
6019
|
+
c.session_id,
|
|
6020
|
+
c.phone_number,
|
|
6021
|
+
c.suppressed ? `${c.address} (suppressed)` : c.address,
|
|
6022
|
+
c.display_name ?? "",
|
|
6023
|
+
c.message_count,
|
|
6024
|
+
c.last_inbound_at ?? "",
|
|
6025
|
+
c.last_outbound_at ?? "",
|
|
6026
|
+
leadReferenceLabel(c.lead_reference),
|
|
6027
|
+
c.summary
|
|
6028
|
+
])
|
|
6029
|
+
);
|
|
6030
|
+
process.stderr.write(`showing ${conversations.length} conversation(s)
|
|
6031
|
+
`);
|
|
6032
|
+
if (res.next_cursor) {
|
|
6033
|
+
process.stderr.write(`more available \u2014 re-run with --cursor ${res.next_cursor}
|
|
6034
|
+
`);
|
|
6035
|
+
}
|
|
6036
|
+
} catch (e) {
|
|
6037
|
+
fail(e);
|
|
6038
|
+
}
|
|
6039
|
+
}
|
|
6040
|
+
);
|
|
6041
|
+
function whatsAppMessageText(m) {
|
|
6042
|
+
const parts = [];
|
|
6043
|
+
if (m.body) parts.push(m.body);
|
|
6044
|
+
if (m.location) {
|
|
6045
|
+
const where = [m.location.label, m.location.address].filter(Boolean).join(", ");
|
|
6046
|
+
parts.push(`[location ${m.location.latitude},${m.location.longitude}${where ? ` ${where}` : ""}]`);
|
|
6047
|
+
}
|
|
6048
|
+
if (m.context?.button_text) parts.push(`[tapped "${m.context.button_text}"]`);
|
|
6049
|
+
else if (m.context?.replied_message_id) parts.push(`[reply to ${m.context.replied_message_id}]`);
|
|
6050
|
+
if (m.referral) parts.push(`[from ad${m.referral.Headline ? ` "${m.referral.Headline}"` : ""}]`);
|
|
6051
|
+
if (parts.length === 0 && m.message_type && m.message_type !== "text") parts.push(`[${m.message_type}]`);
|
|
6052
|
+
return parts.join(" ");
|
|
6053
|
+
}
|
|
6054
|
+
voiceWhatsAppCmd.command("get <sessionID>").description("Read one WhatsApp conversation: its metadata, then every message oldest first").option("--limit <n>", "messages per page (default 50, max 200)").option("--cursor <cursor>", "next_cursor from the preceding page of messages").option("--json", "print the raw JSON result instead of a table").action(
|
|
6055
|
+
async (sessionID, opts) => {
|
|
6056
|
+
try {
|
|
6057
|
+
const res = await new ErdoClient().getWhatsAppConversation(sessionID, {
|
|
6058
|
+
limit: opts.limit ? Number(opts.limit) : void 0,
|
|
6059
|
+
cursor: opts.cursor
|
|
6060
|
+
});
|
|
6061
|
+
if (opts.json) {
|
|
6062
|
+
print(res);
|
|
6063
|
+
return;
|
|
6064
|
+
}
|
|
6065
|
+
const c = res.conversation;
|
|
6066
|
+
printAlignedTable(
|
|
6067
|
+
["session id", "phone", "address", "name", "msgs", "last inbound", "last outbound", "summary"],
|
|
6068
|
+
[
|
|
6069
|
+
[
|
|
6070
|
+
c.session_id,
|
|
6071
|
+
c.phone_number,
|
|
6072
|
+
c.suppressed ? `${c.address} (suppressed)` : c.address,
|
|
6073
|
+
c.display_name ?? "",
|
|
6074
|
+
c.message_count,
|
|
6075
|
+
c.last_inbound_at ?? "",
|
|
6076
|
+
c.last_outbound_at ?? "",
|
|
6077
|
+
c.summary
|
|
6078
|
+
]
|
|
6079
|
+
]
|
|
6080
|
+
);
|
|
6081
|
+
const contact = c.contact;
|
|
6082
|
+
if (contact && (contact.name || contact.email || contact.phone || contact.company)) {
|
|
6083
|
+
const parts = [contact.name, contact.email, contact.phone, contact.company].filter(Boolean);
|
|
6084
|
+
console.log(`
|
|
6085
|
+
contact: ${parts.join(" \xB7 ")}`);
|
|
6086
|
+
}
|
|
6087
|
+
if (c.lead_reference) {
|
|
6088
|
+
console.log(`lead: ${c.lead_reference} (${c.canonical_lead_id})`);
|
|
6089
|
+
}
|
|
6090
|
+
const messages = res.messages ?? [];
|
|
6091
|
+
if (messages.length === 0) {
|
|
6092
|
+
console.log("\nNo messages have been recorded in this conversation yet.");
|
|
6093
|
+
return;
|
|
6094
|
+
}
|
|
6095
|
+
console.log("");
|
|
6096
|
+
printAlignedTable(
|
|
6097
|
+
["at", "direction", "status", "media", "message"],
|
|
6098
|
+
messages.map((m) => [
|
|
6099
|
+
m.created_at,
|
|
6100
|
+
m.direction,
|
|
6101
|
+
m.status,
|
|
6102
|
+
m.num_media > 0 ? m.num_media : "",
|
|
6103
|
+
whatsAppMessageText(m)
|
|
6104
|
+
])
|
|
6105
|
+
);
|
|
6106
|
+
process.stderr.write(`showing ${messages.length} message(s), oldest first
|
|
6107
|
+
`);
|
|
6108
|
+
if (res.next_cursor) {
|
|
6109
|
+
process.stderr.write(`more available \u2014 re-run with --cursor ${res.next_cursor}
|
|
6110
|
+
`);
|
|
6111
|
+
}
|
|
6112
|
+
} catch (e) {
|
|
6113
|
+
fail(e);
|
|
6114
|
+
}
|
|
6115
|
+
}
|
|
6116
|
+
);
|
|
5970
6117
|
var voiceNumbersCmd = voiceCmd.command("numbers").description("The organization's phone numbers, their A2P SMS registration and their caller name");
|
|
5971
6118
|
function printRegistrationState(registration) {
|
|
5972
6119
|
if (registration === null || typeof registration !== "object") {
|