@erdoai/cli 0.130.0 → 0.131.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 +61 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1283,6 +1283,16 @@ var ErdoClient = class {
|
|
|
1283
1283
|
input
|
|
1284
1284
|
);
|
|
1285
1285
|
}
|
|
1286
|
+
// Cannot be undone. Removes the lead from every Erdo store so the same phone
|
|
1287
|
+
// and email can arrive as a new lead. Staff-only, for demos and tests. A
|
|
1288
|
+
// retry of a delete that stopped part-way resumes it, and a lead already
|
|
1289
|
+
// deleted answers "already_deleted".
|
|
1290
|
+
deleteLead(datasetSlug, lead) {
|
|
1291
|
+
return this.request(
|
|
1292
|
+
"DELETE",
|
|
1293
|
+
`/v1/datasets/${encodeURIComponent(datasetSlug)}/leads/${encodeURIComponent(lead)}`
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1286
1296
|
// The lead playbook: plain text that decides each lead's next action. An
|
|
1287
1297
|
// organization that never saved one gets the default template, exists=false.
|
|
1288
1298
|
getLeadPlaybook() {
|
|
@@ -2054,7 +2064,7 @@ async function browserLogin() {
|
|
|
2054
2064
|
// src/input.ts
|
|
2055
2065
|
import { readFileSync as readFileSync2 } from "fs";
|
|
2056
2066
|
function readMaybeFile(value) {
|
|
2057
|
-
if (
|
|
2067
|
+
if (value === void 0) return void 0;
|
|
2058
2068
|
if (value.startsWith("@@")) return value.slice(1);
|
|
2059
2069
|
return value.startsWith("@") ? readFileSync2(value.slice(1), "utf8") : value;
|
|
2060
2070
|
}
|
|
@@ -4679,6 +4689,7 @@ function renderApproval(r) {
|
|
|
4679
4689
|
}
|
|
4680
4690
|
facts.push(["created", r.created_at]);
|
|
4681
4691
|
if (r.decided_at) facts.push(["decided", r.decided_at]);
|
|
4692
|
+
if (r.decision_reason) facts.push(["because", r.decision_reason]);
|
|
4682
4693
|
if (r.expires_at) facts.push(["expires", r.expires_at]);
|
|
4683
4694
|
if (r.execution) {
|
|
4684
4695
|
const reason = r.execution.summary ? ` \u2014 ${r.execution.summary}` : "";
|
|
@@ -4738,6 +4749,9 @@ approvalsCmd.command("decide <id>").description("Approve or reject a pending app
|
|
|
4738
4749
|
).option(
|
|
4739
4750
|
"--constraints <json>",
|
|
4740
4751
|
`explicit parameter constraints for the standing policy, e.g. '{"spreadsheet_id":{"values":["..."]}}'`
|
|
4752
|
+
).option(
|
|
4753
|
+
"--reason <text>",
|
|
4754
|
+
"why you decided this way. On --reject it holds the same proposal back for 7 days: a re-proposal of the same subject that states no new reason is answered with your decline instead of a new approval, and the decision record keeps it as the decider's rationale"
|
|
4741
4755
|
).action(
|
|
4742
4756
|
async (id, opts) => {
|
|
4743
4757
|
try {
|
|
@@ -4774,7 +4788,8 @@ ${listing}`);
|
|
|
4774
4788
|
const res = await client.decideApproval(id, {
|
|
4775
4789
|
decision: opts.approve ? "approved" : "rejected",
|
|
4776
4790
|
scope: opts.scope,
|
|
4777
|
-
parameter_constraints: constraints
|
|
4791
|
+
parameter_constraints: constraints,
|
|
4792
|
+
...opts.reason?.trim() ? { reason: opts.reason.trim() } : {}
|
|
4778
4793
|
});
|
|
4779
4794
|
console.log(res.message);
|
|
4780
4795
|
} catch (e) {
|
|
@@ -4828,7 +4843,7 @@ approvalsCmd.command("settings [mode]").description(
|
|
|
4828
4843
|
});
|
|
4829
4844
|
var attnCmd = program.command("attention").description("The attention feed \u2014 digests, choices, escalations awaiting a human");
|
|
4830
4845
|
function attentionItemLine(item) {
|
|
4831
|
-
return [item.slug, item.severity, item.kind, item.status, item.title].join(" ");
|
|
4846
|
+
return [item.slug, item.severity, item.kind, item.ask ?? "", item.status, item.title].join(" ");
|
|
4832
4847
|
}
|
|
4833
4848
|
function renderAttentionItemReport(item, report) {
|
|
4834
4849
|
console.log("");
|
|
@@ -5359,6 +5374,12 @@ pagesCmd.command("update <id>").description(
|
|
|
5359
5374
|
).option(
|
|
5360
5375
|
"--meta-image-asset <attachmentId>",
|
|
5361
5376
|
'new public share image: a Brand Style attachment id (og-image / hero photo) (omit to keep current; pass "" to clear)'
|
|
5377
|
+
).option(
|
|
5378
|
+
"--build-brief <textOr@file>",
|
|
5379
|
+
"new judge build brief (or @path to a UTF-8 file; omit to keep current, pass an empty string to clear)"
|
|
5380
|
+
).option(
|
|
5381
|
+
"--required-modules <csv>",
|
|
5382
|
+
'replacement runtime module list (comma-separated; "[]" clears)'
|
|
5362
5383
|
).option("--datasets <csv>", 'replacement read-dataset slugs ("[]" clears)').option("--writable-datasets <csv>", 'replacement writable-dataset slugs ("[]" clears)').option("--kv <csv>", 'replacement read KV-store slugs ("[]" clears)').option("--writable-kv <csv>", 'replacement writable KV-store slugs ("[]" clears)').option("--public", "make the page publicly viewable").option("--private", "make the page private").option(
|
|
5363
5384
|
"--request-review",
|
|
5364
5385
|
"ask the judge lenses to review the page after this update and report findings -- for material edits to a LIVE page (layout, forms/CTA, legal/compliance copy, restructured sections), not cosmetic tweaks. First builds and full rewrites are already reviewed automatically"
|
|
@@ -5374,6 +5395,8 @@ pagesCmd.command("update <id>").description(
|
|
|
5374
5395
|
meta_description: opts.metaDescription,
|
|
5375
5396
|
meta_icon_asset_id: opts.metaIconAsset,
|
|
5376
5397
|
meta_image_asset_id: opts.metaImageAsset,
|
|
5398
|
+
build_brief: readMaybeFile(opts.buildBrief),
|
|
5399
|
+
required_modules: grantList(opts.requiredModules),
|
|
5377
5400
|
dataset_slugs: grantList(opts.datasets),
|
|
5378
5401
|
writable_dataset_slugs: grantList(opts.writableDatasets),
|
|
5379
5402
|
kv_slugs: grantList(opts.kv),
|
|
@@ -7402,7 +7425,7 @@ filterCmd.command("list <slug>").description("List the default filters on a data
|
|
|
7402
7425
|
}
|
|
7403
7426
|
});
|
|
7404
7427
|
var leadsCmd = program.command("leads").description(
|
|
7405
|
-
"Read leads in a lead dataset, merge two that are the same person, and run the lead playbook that suggests each lead's next action"
|
|
7428
|
+
"Read leads in a lead dataset, merge two that are the same person, delete one, and run the lead playbook that suggests each lead's next action"
|
|
7406
7429
|
);
|
|
7407
7430
|
leadsCmd.command("get <dataset> <lead>").description(
|
|
7408
7431
|
"Read one lead: its permanent canonical_lead_id, what it told us (on the form and in every call, chat, text and email reply since), the email and phone evidence bound to it, its dataset row, the leads merged into it, and its capture history. <lead> is either the canonical_lead_id UUID or the 22-character lead reference, and an id that has since been merged away resolves to the lead it became \u2014 so an id read off an old capture response still works."
|
|
@@ -7516,6 +7539,40 @@ leadsCmd.command("merge <dataset> <survivor>").description(
|
|
|
7516
7539
|
}
|
|
7517
7540
|
}
|
|
7518
7541
|
);
|
|
7542
|
+
leadsCmd.command("delete <dataset> <lead>").description(
|
|
7543
|
+
"Delete a lead from every Erdo store: its row and identity, its text and WhatsApp conversations, its calls and website chats, its emails, and the follow-up engine's decisions about it. The same phone and email submitted again then make a new lead with nothing behind it. This cannot be undone. A staff tool for demos and tests: copies held by providers (message bodies, call audio, sent mail) and in logs stay, and so do opt-outs. A phone or email another lead in the organization also holds is not released until that lead is deleted too. Read the lead with `leads get` before running it."
|
|
7544
|
+
).option("-y, --yes", "skip the confirmation prompt").option("--json", "print the raw JSON result instead of a summary").action(async (dataset, lead, opts) => {
|
|
7545
|
+
try {
|
|
7546
|
+
if (!opts.yes) {
|
|
7547
|
+
const answer = await promptLine(
|
|
7548
|
+
`Delete lead ${lead} from ${dataset}? Its row, conversations, calls, emails and follow-up history are removed and this cannot be undone. Type "delete" to continue: `
|
|
7549
|
+
);
|
|
7550
|
+
if (answer.trim() !== "delete") {
|
|
7551
|
+
console.error("Not deleted.");
|
|
7552
|
+
process.exit(1);
|
|
7553
|
+
}
|
|
7554
|
+
}
|
|
7555
|
+
const res = await new ErdoClient().deleteLead(dataset, lead);
|
|
7556
|
+
if (opts.json) {
|
|
7557
|
+
print(res);
|
|
7558
|
+
return;
|
|
7559
|
+
}
|
|
7560
|
+
console.log(
|
|
7561
|
+
res.state === "already_deleted" ? `Lead ${res.reference} was already deleted. That delete removed:` : `Deleted lead ${res.reference}. Removed:`
|
|
7562
|
+
);
|
|
7563
|
+
const removed = Object.entries(res.removed ?? {}).filter(([, count]) => count > 0).sort(([a], [b]) => a.localeCompare(b));
|
|
7564
|
+
if (removed.length === 0) console.log(" nothing");
|
|
7565
|
+
for (const [kind, count] of removed) console.log(` ${kind.replace(/_/g, " ")}: ${count}`);
|
|
7566
|
+
const shared = (res.shared_phones ?? 0) + (res.shared_emails ?? 0);
|
|
7567
|
+
if (shared > 0) {
|
|
7568
|
+
console.log(
|
|
7569
|
+
`${shared} of this lead's contact details ${shared === 1 ? "is" : "are"} also held by another lead in the organization, so what is kept by number or address for ${shared === 1 ? "it" : "them"} was left in place. Delete that lead too to release ${shared === 1 ? "it" : "them"}.`
|
|
7570
|
+
);
|
|
7571
|
+
}
|
|
7572
|
+
} catch (e) {
|
|
7573
|
+
fail(e);
|
|
7574
|
+
}
|
|
7575
|
+
});
|
|
7519
7576
|
var leadPlaybookCmd = leadsCmd.command("playbook").description("Read, try and save the lead playbook: the plain-text rules for what Erdo does next with each lead");
|
|
7520
7577
|
leadPlaybookCmd.command("get").description(
|
|
7521
7578
|
"Show the saved playbook: whether the sweep is enabled, the daily contact cap, the read-back Erdo enforces (each action's mode and the working hours), and the text. An organization that never saved one sees the default template."
|