@series-a/cli 0.2.1 → 0.6.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/LICENSE +3 -2
- package/README.md +17 -2
- package/package.json +4 -3
- package/src/api.mjs +2 -1
- package/src/commands/insights.mjs +1034 -0
- package/src/commands/knowledge-sync.mjs +519 -0
- package/src/commands/resources.mjs +168 -5
- package/src/index.mjs +29 -2
|
@@ -110,6 +110,77 @@ export function registerLeads(program) {
|
|
|
110
110
|
} catch (e) { fail(e); }
|
|
111
111
|
});
|
|
112
112
|
|
|
113
|
+
withCommonOpts(leads.command("import-from <source>"))
|
|
114
|
+
.description("Import leads from any source: linkedin_search | company_search | post_reactors | paste_profiles | csv | heyreach")
|
|
115
|
+
.option("--query <q>", "search keywords (linkedin_search / company_search)")
|
|
116
|
+
.option("--post <url>", "LinkedIn post URL (post_reactors)")
|
|
117
|
+
.option("--file <path>", "CSV or pasted-profile text file (csv / paste_profiles / heyreach)")
|
|
118
|
+
.option("--audience <name>", "audience (segment) name or id to attach to")
|
|
119
|
+
.option("--campaign <id>", "campaign id (required for heyreach)")
|
|
120
|
+
.option("--limit <n>", "max prospects for LinkedIn sources", "50")
|
|
121
|
+
.option("--no-enrich", "skip the LinkedIn verify + enrich chain")
|
|
122
|
+
.action(async function (source) {
|
|
123
|
+
try {
|
|
124
|
+
const o = this.optsWithGlobals();
|
|
125
|
+
const params = {
|
|
126
|
+
source,
|
|
127
|
+
query: o.query,
|
|
128
|
+
post_url: o.post,
|
|
129
|
+
audience: o.audience,
|
|
130
|
+
campaign_id: o.campaign,
|
|
131
|
+
limit: Number(o.limit),
|
|
132
|
+
enrich: o.enrich !== false,
|
|
133
|
+
};
|
|
134
|
+
if (o.file) {
|
|
135
|
+
const text = await readFile(o.file, "utf8");
|
|
136
|
+
if (source === "paste_profiles") params.text = text;
|
|
137
|
+
else params.csv = text;
|
|
138
|
+
}
|
|
139
|
+
const r = await call("leads", "import", params, ctxFrom(this));
|
|
140
|
+
emit(this, r, (d) => process.stdout.write(
|
|
141
|
+
`✓ Imported ${d.imported ?? 0} leads (${d.duplicates ?? 0} duplicates, ${d.skipped ?? 0} skipped, ${d.failed ?? 0} failed)\n` +
|
|
142
|
+
(d.job_id ? ` job: ${d.job_id}\n` : "")));
|
|
143
|
+
} catch (e) { fail(e); }
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
withCommonOpts(leads.command("import-status <jobId>"))
|
|
147
|
+
.description("Poll a running lead import")
|
|
148
|
+
.action(async function (jobId) {
|
|
149
|
+
try {
|
|
150
|
+
const r = await call("leads", "import_status", { job_id: jobId }, ctxFrom(this));
|
|
151
|
+
emit(this, r, (d) => process.stdout.write(JSON.stringify(d.job, null, 2) + "\n"));
|
|
152
|
+
} catch (e) { fail(e); }
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
withCommonOpts(leads.command("update <id>"))
|
|
156
|
+
.description("Update a single lead")
|
|
157
|
+
.option("--name <v>").option("--title <v>").option("--company <v>")
|
|
158
|
+
.option("--email <v>").option("--linkedin <v>").option("--persona <v>")
|
|
159
|
+
.option("--score <n>").option("--status <v>").option("--notes <v>")
|
|
160
|
+
.action(async function (id) {
|
|
161
|
+
try {
|
|
162
|
+
const o = this.optsWithGlobals();
|
|
163
|
+
const params = { id };
|
|
164
|
+
for (const [k, v] of Object.entries({
|
|
165
|
+
name: o.name, title: o.title, company: o.company, email: o.email,
|
|
166
|
+
linkedin_url: o.linkedin, persona_tag: o.persona,
|
|
167
|
+
score: o.score !== undefined ? Number(o.score) : undefined,
|
|
168
|
+
status: o.status, notes: o.notes,
|
|
169
|
+
})) if (v !== undefined) params[k] = v;
|
|
170
|
+
const r = await call("leads", "update", params, ctxFrom(this));
|
|
171
|
+
emit(this, r, (d) => process.stdout.write(`✓ Updated ${d.lead?.name ?? id}\n`));
|
|
172
|
+
} catch (e) { fail(e); }
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
withCommonOpts(leads.command("delete <id>"))
|
|
176
|
+
.description("Delete a lead")
|
|
177
|
+
.action(async function (id) {
|
|
178
|
+
try {
|
|
179
|
+
const r = await call("leads", "delete", { id }, ctxFrom(this));
|
|
180
|
+
emit(this, r, () => process.stdout.write(`✓ Deleted ${id}\n`));
|
|
181
|
+
} catch (e) { fail(e); }
|
|
182
|
+
});
|
|
183
|
+
|
|
113
184
|
withCommonOpts(leads.command("verify <id>"))
|
|
114
185
|
.description("Run LinkedIn verification on a lead")
|
|
115
186
|
.action(async function (id) {
|
|
@@ -300,13 +371,16 @@ export function registerSequences(program) {
|
|
|
300
371
|
|
|
301
372
|
withCommonOpts(s.command("add-step <id>"))
|
|
302
373
|
.description("Append a step to a sequence")
|
|
303
|
-
.requiredOption(
|
|
374
|
+
.requiredOption(
|
|
375
|
+
"--action <action>",
|
|
376
|
+
"viewProfile|addReaction|addComment|sendInvitation|sendMessage|loopBack|createOpportunity|enrichLead|ifAccepted|ifReplied|ifConnection|ifNetworkDistance|stopOnReply|wait|wait_3h|wait_1d|wait_2d|wait_3d|wait_5d",
|
|
377
|
+
)
|
|
304
378
|
.option("--text <message>", "message_content (required for addComment/sendInvitation/sendMessage)")
|
|
305
379
|
.option("--delay <days>", "delay_days before this step", "0")
|
|
306
380
|
.option("--variant <v>", "variant label", "A")
|
|
307
|
-
.option("--step-type <t>", "action|
|
|
308
|
-
.option("--channel <c>", "channel
|
|
309
|
-
.option("--branch <label>", "branch_label (for
|
|
381
|
+
.option("--step-type <t>", "action|condition|delay (defaults from --action)")
|
|
382
|
+
.option("--channel <c>", "channel (defaults from --action)")
|
|
383
|
+
.option("--branch <label>", "branch_label: yes|no (for steps under a condition)")
|
|
310
384
|
.option("--parent-step <id>", "parent_step_id (for branches)")
|
|
311
385
|
.option("--order <n>", "explicit step_order (defaults to max+1)")
|
|
312
386
|
.action(async function (id, opts) {
|
|
@@ -552,6 +626,8 @@ export function registerKnowledge(program) {
|
|
|
552
626
|
.option("--visibility <v>", "workspace | private (default: workspace)")
|
|
553
627
|
.option("--no-summarize", "skip AI auto-tag/classify (raw insert only)")
|
|
554
628
|
.option("--no-scrape", "skip Firecrawl scrape for --url (URL stored as bookmark)")
|
|
629
|
+
.option("--style-reference", "flag as a Tone-of-Voice style reference (for known author documents)")
|
|
630
|
+
.option("--auto-style", "score as a style reference on arrival and auto-flag if it meets the threshold (default 70)")
|
|
555
631
|
.action(async function (opts) {
|
|
556
632
|
try {
|
|
557
633
|
const sources = [opts.url, opts.text, opts.file].filter(Boolean);
|
|
@@ -575,6 +651,8 @@ export function registerKnowledge(program) {
|
|
|
575
651
|
visibility: opts.visibility,
|
|
576
652
|
skip_summarize: opts.summarize === false ? true : undefined,
|
|
577
653
|
skip_scrape: opts.scrape === false ? true : undefined,
|
|
654
|
+
is_style_reference: opts.styleReference === true ? true : undefined,
|
|
655
|
+
auto_style_reference: opts.autoStyle === true ? true : undefined,
|
|
578
656
|
};
|
|
579
657
|
const r = await call("knowledge", "add", params, ctxFrom(this));
|
|
580
658
|
emit(this, r, (d) => {
|
|
@@ -586,7 +664,11 @@ export function registerKnowledge(program) {
|
|
|
586
664
|
` category: ${it.category}\n` +
|
|
587
665
|
` tags: ${(it.tags || []).join(", ") || "(none)"}\n` +
|
|
588
666
|
(it.summary ? ` summary: ${truncate(it.summary, 240)}\n` : "") +
|
|
589
|
-
(
|
|
667
|
+
(it.is_style_reference ? ` ★ style reference\n` : "") +
|
|
668
|
+
(d.ai?.success === false ? ` ⚠ AI classify: ${d.ai.error}\n` : "") +
|
|
669
|
+
(d.style_reference_triage?.data?.results?.[0] && !it.is_style_reference
|
|
670
|
+
? ` style triage: ${d.style_reference_triage.data.results[0].score}/100 — ${d.style_reference_triage.data.results[0].reason}\n`
|
|
671
|
+
: ""),
|
|
590
672
|
);
|
|
591
673
|
});
|
|
592
674
|
} catch (e) { fail(e); }
|
|
@@ -599,6 +681,7 @@ export function registerKnowledge(program) {
|
|
|
599
681
|
.option("--category <c>", "set category")
|
|
600
682
|
.option("--tags <csv>", "replace tags (comma-separated)")
|
|
601
683
|
.option("--visibility <v>", "workspace | private")
|
|
684
|
+
.option("--style-reference <on|off>", "flag/unflag as a Tone-of-Voice style reference")
|
|
602
685
|
.action(async function (id, opts) {
|
|
603
686
|
try {
|
|
604
687
|
const patch = {
|
|
@@ -608,6 +691,7 @@ export function registerKnowledge(program) {
|
|
|
608
691
|
category: opts.category,
|
|
609
692
|
tags: opts.tags ? opts.tags.split(",").map((s) => s.trim()).filter(Boolean) : undefined,
|
|
610
693
|
visibility: opts.visibility,
|
|
694
|
+
is_style_reference: opts.styleReference === "on" ? true : opts.styleReference === "off" ? false : undefined,
|
|
611
695
|
};
|
|
612
696
|
const r = await call("knowledge", "update", patch, ctxFrom(this));
|
|
613
697
|
emit(this, r, (d) => process.stdout.write(`✓ Updated ${d.item?.id}\n`));
|
|
@@ -759,8 +843,51 @@ export function registerContent(program) {
|
|
|
759
843
|
emit(this, r, (d) => process.stdout.write(`✓ Deleted ${d.deleted}\n`));
|
|
760
844
|
} catch (e) { fail(e); }
|
|
761
845
|
});
|
|
846
|
+
|
|
847
|
+
withCommonOpts(c.command("generate"))
|
|
848
|
+
.description("Generate a draft via agent-content-creator (KB + reference library grounded, URL-sanitised, citations recorded)")
|
|
849
|
+
.requiredOption("--angle <text>", "topic / angle for the draft")
|
|
850
|
+
.option("--format <f>", "blog | linkedin_post | video | explainer_video", "blog")
|
|
851
|
+
.option("--signal <id...>", "intelligence_signals ids to ground on (repeatable)")
|
|
852
|
+
.option("--reference <id...>", "knowledge_items ids to ground on (repeatable)")
|
|
853
|
+
.option("--grounding-text <text>", "extra freeform grounding to append")
|
|
854
|
+
.option("--wait", "block until the job completes (up to 4 min)")
|
|
855
|
+
.action(async function (opts) {
|
|
856
|
+
try {
|
|
857
|
+
const r = await call("content", "generate", {
|
|
858
|
+
angle: opts.angle,
|
|
859
|
+
format: opts.format,
|
|
860
|
+
signal_ids: opts.signal,
|
|
861
|
+
reference_item_ids: opts.reference,
|
|
862
|
+
grounding_text: opts.groundingText,
|
|
863
|
+
async: !opts.wait,
|
|
864
|
+
}, ctxFrom(this));
|
|
865
|
+
emit(this, r, (d) => {
|
|
866
|
+
if (d.content) {
|
|
867
|
+
process.stdout.write(`✓ Draft ${d.content.id} (${d.content.type}, ${d.citations?.length ?? 0} citations)\n`);
|
|
868
|
+
} else {
|
|
869
|
+
process.stdout.write(`⏳ Queued job ${d.job_id} — poll with: advisoros agents job-status ${d.job_id}\n`);
|
|
870
|
+
}
|
|
871
|
+
});
|
|
872
|
+
} catch (e) { fail(e); }
|
|
873
|
+
});
|
|
874
|
+
|
|
875
|
+
withCommonOpts(c.command("citations <id>"))
|
|
876
|
+
.description("List every source (signal, reference, transcript, published) recorded for a content item")
|
|
877
|
+
.action(async function (id) {
|
|
878
|
+
try {
|
|
879
|
+
const r = await call("content", "citations", { id }, ctxFrom(this));
|
|
880
|
+
emit(this, r, (d) => {
|
|
881
|
+
process.stdout.write(table(
|
|
882
|
+
["kind", "id", "title", "url"],
|
|
883
|
+
(d.citations || []).map((c) => [c.source_kind, truncate(c.source_id ?? "", 8), truncate(c.title ?? "", 40), truncate(c.source_url ?? "", 60)]),
|
|
884
|
+
) + `\n${d.citations?.length ?? 0} citations\n`);
|
|
885
|
+
});
|
|
886
|
+
} catch (e) { fail(e); }
|
|
887
|
+
});
|
|
762
888
|
}
|
|
763
889
|
|
|
890
|
+
|
|
764
891
|
export function registerCalendar(program) {
|
|
765
892
|
const cal = program.command("calendar").description("Manage the content calendar");
|
|
766
893
|
|
|
@@ -1104,6 +1231,42 @@ export function registerPipelines(program) {
|
|
|
1104
1231
|
export function registerAgents(program) {
|
|
1105
1232
|
const a = program.command("agents").description("List, create, configure and invoke agents");
|
|
1106
1233
|
|
|
1234
|
+
withCommonOpts(a.command("trigger <name>"))
|
|
1235
|
+
.description("Trigger an agent by name with optional JSON input")
|
|
1236
|
+
.option("--input <json>", "JSON input payload", "{}")
|
|
1237
|
+
.action(async function (name) {
|
|
1238
|
+
try {
|
|
1239
|
+
const o = this.optsWithGlobals();
|
|
1240
|
+
let input = {};
|
|
1241
|
+
try { input = JSON.parse(o.input); } catch { throw new Error("--input must be valid JSON"); }
|
|
1242
|
+
const r = await call("agents", "trigger", { agent_name: name, input }, ctxFrom(this));
|
|
1243
|
+
emit(this, r, (d) => process.stdout.write(JSON.stringify(d.run, null, 2) + "\n"));
|
|
1244
|
+
} catch (e) { fail(e); }
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
withCommonOpts(a.command("history"))
|
|
1248
|
+
.description("Recent agent runs and jobs")
|
|
1249
|
+
.option("--agent <name>", "filter by agent name")
|
|
1250
|
+
.option("--days <n>", "look-back window", "30")
|
|
1251
|
+
.option("--limit <n>", "max rows", "50")
|
|
1252
|
+
.action(async function () {
|
|
1253
|
+
try {
|
|
1254
|
+
const o = this.optsWithGlobals();
|
|
1255
|
+
const r = await call("agents", "history", {
|
|
1256
|
+
agent_name: o.agent, days: Number(o.days), limit: Number(o.limit),
|
|
1257
|
+
}, ctxFrom(this));
|
|
1258
|
+
emit(this, r, (d) => {
|
|
1259
|
+
process.stdout.write(table(
|
|
1260
|
+
["when", "agent", "status", "results"],
|
|
1261
|
+
(d.runs || []).map((x) => [
|
|
1262
|
+
String(x.created_at ?? "").slice(0, 16), truncate(x.agent_name, 30),
|
|
1263
|
+
x.status ?? "", String(x.results_count ?? ""),
|
|
1264
|
+
]),
|
|
1265
|
+
) + `\n${d.runs?.length ?? 0} runs, ${d.jobs?.length ?? 0} jobs\n`);
|
|
1266
|
+
});
|
|
1267
|
+
} catch (e) { fail(e); }
|
|
1268
|
+
});
|
|
1269
|
+
|
|
1107
1270
|
withCommonOpts(a.command("list"))
|
|
1108
1271
|
.description("List available agents")
|
|
1109
1272
|
.option("--scope <s>", "workspace | global | both (default: both)")
|
package/src/index.mjs
CHANGED
|
@@ -6,14 +6,21 @@ import {
|
|
|
6
6
|
registerCalendar, registerSignals, registerPipelines, registerAuthority,
|
|
7
7
|
registerBriefs,
|
|
8
8
|
} from "./commands/resources.mjs";
|
|
9
|
+
import {
|
|
10
|
+
registerCampaignAnalytics, registerAnalytics, registerSafety, registerCtas,
|
|
11
|
+
registerNotifications, registerAudiences, registerNewsletter, registerVideo,
|
|
12
|
+
registerWatchlist, registerMeetings, registerActivity, registerWorkspacesExtras,
|
|
13
|
+
registerExport, registerIntegrations,
|
|
14
|
+
} from "./commands/insights.mjs";
|
|
9
15
|
import { registerFlow } from "./commands/flow.mjs";
|
|
16
|
+
import { registerVaultSync } from "./commands/knowledge-sync.mjs";
|
|
10
17
|
|
|
11
18
|
const program = new Command();
|
|
12
19
|
|
|
13
20
|
program
|
|
14
21
|
.name("advisoros")
|
|
15
|
-
.description("
|
|
16
|
-
.version("0.
|
|
22
|
+
.description("AdvisorPro CLI — drive leads, campaigns, sequences and agents from your terminal.")
|
|
23
|
+
.version("0.5.0")
|
|
17
24
|
.option("--json", "machine-readable JSON output (applies to all subcommands)");
|
|
18
25
|
|
|
19
26
|
registerAuth(program);
|
|
@@ -29,9 +36,29 @@ registerPipelines(program);
|
|
|
29
36
|
registerAuthority(program);
|
|
30
37
|
registerBriefs(program);
|
|
31
38
|
registerAgents(program);
|
|
39
|
+
registerIntegrations(program);
|
|
40
|
+
|
|
41
|
+
// Analytics, safety guardrails and the remaining resource surface.
|
|
42
|
+
registerCampaignAnalytics(program);
|
|
43
|
+
registerAnalytics(program);
|
|
44
|
+
registerSafety(program);
|
|
45
|
+
registerCtas(program);
|
|
46
|
+
registerNotifications(program);
|
|
47
|
+
registerAudiences(program);
|
|
48
|
+
registerNewsletter(program);
|
|
49
|
+
registerVideo(program);
|
|
50
|
+
registerWatchlist(program);
|
|
51
|
+
registerMeetings(program);
|
|
52
|
+
registerActivity(program);
|
|
53
|
+
registerWorkspacesExtras(program);
|
|
54
|
+
registerExport(program);
|
|
55
|
+
|
|
56
|
+
registerVaultSync(program);
|
|
57
|
+
|
|
32
58
|
registerFlow(program);
|
|
33
59
|
|
|
34
60
|
program.parseAsync(process.argv).catch((e) => {
|
|
35
61
|
process.stderr.write(`✖ ${e?.message ?? e}\n`);
|
|
36
62
|
process.exit(1);
|
|
37
63
|
});
|
|
64
|
+
|