@elmohq/cli 0.2.18 → 0.2.19
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 +54 -33
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -388,10 +388,11 @@ async function runInit(options, version) {
|
|
|
388
388
|
p.log.message(`If you find Elmo useful, star us on GitHub!\n ${link(pc.cyan("https://github.com/elmohq/elmo"), "https://github.com/elmohq/elmo")}`);
|
|
389
389
|
p.outro(pc.green("Setup complete!"));
|
|
390
390
|
}
|
|
391
|
+
const CLORO_AFFILIATE = "https://cloro.dev?fpr=elmo";
|
|
391
392
|
const BRIGHTDATA_AFFILIATE = "https://get.brightdata.com/67h1b7h0shcn";
|
|
392
|
-
const OLOSTEP_AFFILIATE = "https://olostep.com/?ref=elmo";
|
|
393
393
|
const OXYLABS_AFFILIATE = "https://oxylabs.go2cloud.org/aff_c?offer_id=7&aff_id=2263&url_id=32";
|
|
394
|
-
const
|
|
394
|
+
const OLOSTEP_AFFILIATE = "https://olostep.com/?ref=elmo";
|
|
395
|
+
const DATAFORSEO_AFFILIATE = "https://dataforseo.com/?aff=184966";
|
|
395
396
|
const PROVIDERS_DOC_URL = "https://docs.elmohq.com/docs/user-guide/providers";
|
|
396
397
|
const BRIGHTDATA_MODELS = [
|
|
397
398
|
"chatgpt",
|
|
@@ -455,10 +456,11 @@ async function configureProvidersInteractive(env) {
|
|
|
455
456
|
"Elmo needs two kinds of providers:",
|
|
456
457
|
"",
|
|
457
458
|
pc.bold("1. A scraper") + " — to track ChatGPT and Google AI Mode (no public APIs):",
|
|
458
|
-
` • ${pc.cyan("
|
|
459
|
-
` • ${pc.cyan("
|
|
460
|
-
` • ${pc.cyan("
|
|
461
|
-
` • ${pc.cyan("Olostep")} — premium
|
|
459
|
+
` • ${pc.cyan("Cloro")} — most reliable, every surface, ~$0.65/mo per prompt ($30/mo min)`,
|
|
460
|
+
` • ${pc.cyan("BrightData")} — pay-as-you-go and cheaper, but slower, ~$0.45/mo per prompt`,
|
|
461
|
+
` • ${pc.cyan("Oxylabs")} — cheapest per run, no Gemini/Copilot, $49/mo min`,
|
|
462
|
+
` • ${pc.cyan("Olostep")} — premium, built for high volume, ~$2.25/mo per prompt`,
|
|
463
|
+
` • ${pc.cyan("DataForSEO")} — pay-as-you-go, scrapers + direct APIs, ~$1.20/mo per prompt`,
|
|
462
464
|
"",
|
|
463
465
|
pc.bold("2. A direct LLM API") + " — for low-latency tasks (onboarding analysis, sentiment scoring,",
|
|
464
466
|
" ad-hoc LLM calls). Required:",
|
|
@@ -488,24 +490,28 @@ async function configureProvidersRecommended(env) {
|
|
|
488
490
|
const scraper = await p.select({
|
|
489
491
|
message: "Scraper (tracks ChatGPT + Google AI Mode)",
|
|
490
492
|
options: [
|
|
493
|
+
{
|
|
494
|
+
value: "cloro",
|
|
495
|
+
label: "Cloro — most reliable, every surface (~$0.65/mo per prompt, $30/mo min)"
|
|
496
|
+
},
|
|
491
497
|
{
|
|
492
498
|
value: "brightdata",
|
|
493
|
-
label: "BrightData — ~$0.45/mo per prompt
|
|
499
|
+
label: "BrightData — pay-as-you-go, cheaper but slower (~$0.45/mo per prompt)"
|
|
494
500
|
},
|
|
495
501
|
{
|
|
496
502
|
value: "oxylabs",
|
|
497
|
-
label: "Oxylabs —
|
|
503
|
+
label: "Oxylabs — cheapest per run, no Gemini/Copilot ($49/mo min)"
|
|
498
504
|
},
|
|
499
505
|
{
|
|
500
|
-
value: "
|
|
501
|
-
label: "
|
|
506
|
+
value: "olostep",
|
|
507
|
+
label: "Olostep — premium, built for high volume (~$2.25/mo per prompt)"
|
|
502
508
|
},
|
|
503
509
|
{
|
|
504
|
-
value: "
|
|
505
|
-
label: "
|
|
510
|
+
value: "dataforseo",
|
|
511
|
+
label: "DataForSEO — pay-as-you-go, scrapers + direct APIs (~$1.20/mo per prompt)"
|
|
506
512
|
}
|
|
507
513
|
],
|
|
508
|
-
initialValue: "
|
|
514
|
+
initialValue: "cloro"
|
|
509
515
|
});
|
|
510
516
|
assertNotCancelled(scraper);
|
|
511
517
|
await collectScraperKey(scraper, env);
|
|
@@ -551,9 +557,9 @@ async function configureProvidersCustom(env) {
|
|
|
551
557
|
if (!hasDirectApiConfigured(env)) p.log.warn("Onboarding analysis and other low-latency LLM tasks require a direct API. Configure at least one before continuing.");
|
|
552
558
|
}
|
|
553
559
|
p.log.step(pc.bold("Step 2 of 2 — Scrapers (optional, but needed to track ChatGPT / Google AI Mode)"));
|
|
560
|
+
await collectCloro(env, targets);
|
|
554
561
|
await collectBrightData(env, targets);
|
|
555
562
|
await collectOxylabs(env, targets);
|
|
556
|
-
await collectCloro(env, targets);
|
|
557
563
|
await collectOlostep(env, targets);
|
|
558
564
|
await collectDataForSEO(env, targets);
|
|
559
565
|
await finalizeScrapeTargets(env, targets);
|
|
@@ -562,7 +568,15 @@ function hasDirectApiConfigured(env) {
|
|
|
562
568
|
return Boolean(env.ANTHROPIC_API_KEY || env.OPENAI_API_KEY || env.MISTRAL_API_KEY || env.OPENROUTER_API_KEY);
|
|
563
569
|
}
|
|
564
570
|
async function collectScraperKey(scraper, env) {
|
|
565
|
-
if (scraper === "
|
|
571
|
+
if (scraper === "cloro") {
|
|
572
|
+
p.log.info(`Sign up: ${link(pc.cyan(CLORO_AFFILIATE), CLORO_AFFILIATE)}`);
|
|
573
|
+
const key = await p.password({
|
|
574
|
+
message: "Cloro API key",
|
|
575
|
+
validate: (v) => !v ? "Required" : void 0
|
|
576
|
+
});
|
|
577
|
+
assertNotCancelled(key);
|
|
578
|
+
env.CLORO_API_KEY = key;
|
|
579
|
+
} else if (scraper === "brightdata") {
|
|
566
580
|
p.log.info(`Sign up: ${link(pc.cyan(BRIGHTDATA_AFFILIATE), BRIGHTDATA_AFFILIATE)}`);
|
|
567
581
|
const key = await p.password({
|
|
568
582
|
message: "BrightData API token",
|
|
@@ -584,15 +598,7 @@ async function collectScraperKey(scraper, env) {
|
|
|
584
598
|
});
|
|
585
599
|
assertNotCancelled(password);
|
|
586
600
|
env.OXYLABS_PASSWORD = password;
|
|
587
|
-
} else if (scraper === "
|
|
588
|
-
p.log.info(`Sign up: ${link(pc.cyan(CLORO_AFFILIATE), CLORO_AFFILIATE)}`);
|
|
589
|
-
const key = await p.password({
|
|
590
|
-
message: "Cloro API key",
|
|
591
|
-
validate: (v) => !v ? "Required" : void 0
|
|
592
|
-
});
|
|
593
|
-
assertNotCancelled(key);
|
|
594
|
-
env.CLORO_API_KEY = key;
|
|
595
|
-
} else {
|
|
601
|
+
} else if (scraper === "olostep") {
|
|
596
602
|
p.log.info(`Sign up: ${link(pc.cyan(OLOSTEP_AFFILIATE), OLOSTEP_AFFILIATE)}`);
|
|
597
603
|
const key = await p.password({
|
|
598
604
|
message: "Olostep API key",
|
|
@@ -600,6 +606,20 @@ async function collectScraperKey(scraper, env) {
|
|
|
600
606
|
});
|
|
601
607
|
assertNotCancelled(key);
|
|
602
608
|
env.OLOSTEP_API_KEY = key;
|
|
609
|
+
} else {
|
|
610
|
+
p.log.info(`Sign up: ${link(pc.cyan(DATAFORSEO_AFFILIATE), DATAFORSEO_AFFILIATE)}`);
|
|
611
|
+
const login = await p.text({
|
|
612
|
+
message: "DataForSEO login",
|
|
613
|
+
validate: (v) => !v ? "Required" : void 0
|
|
614
|
+
});
|
|
615
|
+
assertNotCancelled(login);
|
|
616
|
+
env.DATAFORSEO_LOGIN = login;
|
|
617
|
+
const password = await p.password({
|
|
618
|
+
message: "DataForSEO password",
|
|
619
|
+
validate: (v) => !v ? "Required" : void 0
|
|
620
|
+
});
|
|
621
|
+
assertNotCancelled(password);
|
|
622
|
+
env.DATAFORSEO_PASSWORD = password;
|
|
603
623
|
}
|
|
604
624
|
}
|
|
605
625
|
async function collectDirectApiQuick(kind, env) {
|
|
@@ -635,8 +655,8 @@ async function collectDirectApiQuick(kind, env) {
|
|
|
635
655
|
}
|
|
636
656
|
async function collectBrightData(env, targets) {
|
|
637
657
|
const enable = await p.confirm({
|
|
638
|
-
message: `Configure ${pc.bold("BrightData")}? (~$0.45/mo per prompt)`,
|
|
639
|
-
initialValue:
|
|
658
|
+
message: `Configure ${pc.bold("BrightData")}? (pay-as-you-go, cheaper but slower — ~$0.45/mo per prompt)`,
|
|
659
|
+
initialValue: false
|
|
640
660
|
});
|
|
641
661
|
assertNotCancelled(enable);
|
|
642
662
|
if (!enable) return;
|
|
@@ -656,7 +676,7 @@ async function collectBrightData(env, targets) {
|
|
|
656
676
|
}
|
|
657
677
|
async function collectOlostep(env, targets) {
|
|
658
678
|
const enable = await p.confirm({
|
|
659
|
-
message: `Configure ${pc.bold("Olostep")}? (~$2.25/mo per prompt)`,
|
|
679
|
+
message: `Configure ${pc.bold("Olostep")}? (premium, built for high volume — ~$2.25/mo per prompt)`,
|
|
660
680
|
initialValue: false
|
|
661
681
|
});
|
|
662
682
|
assertNotCancelled(enable);
|
|
@@ -677,7 +697,7 @@ async function collectOlostep(env, targets) {
|
|
|
677
697
|
}
|
|
678
698
|
async function collectOxylabs(env, targets) {
|
|
679
699
|
const enable = await p.confirm({
|
|
680
|
-
message: `Configure ${pc.bold("Oxylabs")}? (
|
|
700
|
+
message: `Configure ${pc.bold("Oxylabs")}? (cheapest per run, no Gemini/Copilot — $49/mo min)`,
|
|
681
701
|
initialValue: false
|
|
682
702
|
});
|
|
683
703
|
assertNotCancelled(enable);
|
|
@@ -704,8 +724,8 @@ async function collectOxylabs(env, targets) {
|
|
|
704
724
|
}
|
|
705
725
|
async function collectCloro(env, targets) {
|
|
706
726
|
const enable = await p.confirm({
|
|
707
|
-
message: `Configure ${pc.bold("Cloro")}? (
|
|
708
|
-
initialValue:
|
|
727
|
+
message: `Configure ${pc.bold("Cloro")}? (most reliable, every surface — ~$0.65/mo per prompt, $30/mo min)`,
|
|
728
|
+
initialValue: true
|
|
709
729
|
});
|
|
710
730
|
assertNotCancelled(enable);
|
|
711
731
|
if (!enable) return;
|
|
@@ -870,11 +890,12 @@ async function collectOpenRouter(env, targets) {
|
|
|
870
890
|
}
|
|
871
891
|
async function collectDataForSEO(env, targets) {
|
|
872
892
|
const enable = await p.confirm({
|
|
873
|
-
message: `Configure ${pc.bold("DataForSEO")}? (
|
|
893
|
+
message: `Configure ${pc.bold("DataForSEO")}? (pay-as-you-go, scrapers + direct APIs — ~$1.20/mo per prompt)`,
|
|
874
894
|
initialValue: false
|
|
875
895
|
});
|
|
876
896
|
assertNotCancelled(enable);
|
|
877
897
|
if (!enable) return;
|
|
898
|
+
p.log.info(`Sign up: ${link(pc.cyan(DATAFORSEO_AFFILIATE), DATAFORSEO_AFFILIATE)}`);
|
|
878
899
|
const login = await p.text({
|
|
879
900
|
message: "DataForSEO login",
|
|
880
901
|
validate: (v) => !v ? "Required" : void 0
|
|
@@ -1229,13 +1250,13 @@ function buildComposeYaml(options) {
|
|
|
1229
1250
|
function buildPostgresService() {
|
|
1230
1251
|
return [
|
|
1231
1252
|
"postgres:",
|
|
1232
|
-
" image: postgres:
|
|
1253
|
+
" image: postgres:18-alpine",
|
|
1233
1254
|
" environment:",
|
|
1234
1255
|
" POSTGRES_USER: postgres",
|
|
1235
1256
|
" POSTGRES_PASSWORD: postgres",
|
|
1236
1257
|
" POSTGRES_DB: elmo",
|
|
1237
1258
|
" volumes:",
|
|
1238
|
-
" - postgres_data:/var/lib/postgresql
|
|
1259
|
+
" - postgres_data:/var/lib/postgresql",
|
|
1239
1260
|
" ports:",
|
|
1240
1261
|
" - \"5432:5432\"",
|
|
1241
1262
|
" healthcheck:",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elmohq/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"marketing",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"rolldown": "^1.2.1",
|
|
42
42
|
"typescript": "^7.0.2",
|
|
43
43
|
"vitest": "^4.1.10",
|
|
44
|
-
"@workspace/config": "0.2.
|
|
44
|
+
"@workspace/config": "0.2.19"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "node scripts/build.mjs",
|