domainstorm 0.2.0 → 0.2.2
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/README.md
CHANGED
|
@@ -1,99 +1,150 @@
|
|
|
1
|
-
# Domainstorm
|
|
1
|
+
# Domainstorm
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/domainstorm)
|
|
4
|
+
[](https://www.npmjs.com/package/domainstorm)
|
|
5
|
+
[](https://github.com/tanishqsh/domain-cli/actions/workflows/npm-publish.yml)
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
Domainstorm is the fastest way to go from "we need a name" to "these are the domains we can buy now."
|
|
8
|
+
|
|
9
|
+
It is built for AI and agent products where naming cycles happen fast and every good domain disappears quickly.
|
|
10
|
+
|
|
11
|
+
## Why Domainstorm
|
|
12
|
+
|
|
13
|
+
- One command for ideation and availability checks
|
|
14
|
+
- Built for agent-native products (`agent`, `mcp`, `ops`, `runtime`, `router` naming patterns)
|
|
15
|
+
- WHOIS-based checks across TLDs with optional registry server override
|
|
16
|
+
- CLI-first output that works cleanly in agent and CI workflows
|
|
17
|
+
- CSV export for founders, marketers, and legal review
|
|
7
18
|
|
|
8
|
-
|
|
19
|
+
## Install
|
|
9
20
|
|
|
10
21
|
```bash
|
|
11
|
-
npm i -g
|
|
22
|
+
npm i -g domainstorm
|
|
12
23
|
```
|
|
13
24
|
|
|
14
|
-
|
|
25
|
+
Run instantly without global install:
|
|
15
26
|
|
|
16
27
|
```bash
|
|
17
|
-
|
|
28
|
+
npx --yes domainstorm --help
|
|
18
29
|
```
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
## Quick Wins
|
|
32
|
+
|
|
33
|
+
Brainstorm + check + return only likely available:
|
|
21
34
|
|
|
22
35
|
```bash
|
|
23
|
-
|
|
36
|
+
domainstorm --brainstorm "agent orchestration" "mcp broker" --tld md --server whois.nic.md --only-available --table
|
|
24
37
|
```
|
|
25
38
|
|
|
26
|
-
|
|
39
|
+
Check exact domains:
|
|
27
40
|
|
|
28
41
|
```bash
|
|
29
|
-
domainstorm
|
|
42
|
+
domainstorm agentmesh.ai agentmesh.com agentmesh.md
|
|
30
43
|
```
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
- Appends your target TLD
|
|
35
|
-
- Checks registration status
|
|
36
|
-
- Prints a narrative hint (`story=...`) for each candidate
|
|
45
|
+
Default output is plain English (for example: `broker.md is available.`).
|
|
46
|
+
Use `--table` if you want a structured table view.
|
|
37
47
|
|
|
38
|
-
|
|
48
|
+
Check from file and export CSV:
|
|
39
49
|
|
|
40
50
|
```bash
|
|
41
|
-
domainstorm
|
|
51
|
+
domainstorm --input domains.txt --output /tmp/domainstorm.csv
|
|
42
52
|
```
|
|
43
53
|
|
|
54
|
+
Try immediately with the bundled candidate list:
|
|
55
|
+
|
|
44
56
|
```bash
|
|
45
|
-
domainstorm --input agent-
|
|
57
|
+
domainstorm --input agent-candidates.txt --tld md --server whois.nic.md --only-available --table
|
|
46
58
|
```
|
|
47
59
|
|
|
48
|
-
|
|
60
|
+
## Built For Agent Workflows
|
|
61
|
+
|
|
62
|
+
Use Domainstorm when your coding/research agent needs to propose names and validate them in the same run.
|
|
49
63
|
|
|
50
|
-
|
|
64
|
+
- Deterministic CLI output
|
|
65
|
+
- Works with shell pipelines
|
|
66
|
+
- No external AI API keys required
|
|
67
|
+
- Easy to trigger in CI on release or branch workflows
|
|
68
|
+
- No seed ideas? Ask your agent of choice (Codex, Claude, etc.) for seed phrases and pass them to `--brainstorm`
|
|
51
69
|
|
|
52
|
-
|
|
53
|
-
- `#` comments are ignored
|
|
54
|
-
- Labels without a TLD are converted to `<label>.<tld>` (default: `md`)
|
|
55
|
-
- Comma-separated values are accepted per line
|
|
70
|
+
Compatibility alias:
|
|
56
71
|
|
|
57
|
-
|
|
72
|
+
```bash
|
|
73
|
+
domain-check --help
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Example Output
|
|
58
77
|
|
|
59
78
|
```txt
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
agenthub.md
|
|
63
|
-
mcpbroker,mcprouter
|
|
79
|
+
agentmesh.md likely_available availability_pattern_match low story=Keyword + product framing
|
|
80
|
+
agentops.md registered registration_pattern_match low story=Keyword + product framing
|
|
64
81
|
```
|
|
65
82
|
|
|
66
|
-
|
|
83
|
+
Output columns:
|
|
67
84
|
|
|
68
85
|
- `domain`
|
|
69
|
-
- `status
|
|
70
|
-
- `reason
|
|
71
|
-
- `legal_risk
|
|
72
|
-
- `story
|
|
73
|
-
- `error
|
|
86
|
+
- `status` (`registered`, `likely_available`, `unknown`)
|
|
87
|
+
- `reason`
|
|
88
|
+
- `legal_risk` (`low`, `high_tm_risk`)
|
|
89
|
+
- `story` (brainstorm narrative tag)
|
|
90
|
+
- `error`
|
|
74
91
|
|
|
75
|
-
##
|
|
92
|
+
## Key Flags
|
|
76
93
|
|
|
94
|
+
- `--brainstorm` / `--storm`
|
|
95
|
+
- `--max-suggestions <n>` (default: `120`)
|
|
96
|
+
- `--table`
|
|
77
97
|
- `--input <file>`
|
|
78
98
|
- `--output <file>`
|
|
79
|
-
- `--tld <tld>` default `md`
|
|
80
|
-
- `--server <whois-host>`
|
|
99
|
+
- `--tld <tld>` (default: `md`)
|
|
100
|
+
- `--server <whois-host>`
|
|
101
|
+
- `--only-available`
|
|
81
102
|
- `--concurrency <n>`
|
|
82
103
|
- `--timeout-ms <n>`
|
|
83
|
-
- `--brainstorm` / `--storm`
|
|
84
|
-
- `--max-suggestions <n>` default `120`
|
|
85
|
-
- `--only-available`
|
|
86
104
|
- `--raw`
|
|
87
105
|
|
|
88
|
-
##
|
|
106
|
+
## Add `NPM_TOKEN` In GitHub (2 Minutes)
|
|
107
|
+
|
|
108
|
+
1. Create an npm Automation token:
|
|
109
|
+
`npmjs.com -> Account Settings -> Access Tokens -> Generate New Token -> Automation`
|
|
110
|
+
2. Open your repo:
|
|
111
|
+
`github.com/tanishqsh/domain-cli`
|
|
112
|
+
3. Go to:
|
|
113
|
+
`Settings -> Secrets and variables -> Actions`
|
|
114
|
+
4. Click:
|
|
115
|
+
`New repository secret`
|
|
116
|
+
5. Set:
|
|
117
|
+
`Name = NPM_TOKEN`
|
|
118
|
+
`Secret = <your npm automation token>`
|
|
119
|
+
6. Save.
|
|
120
|
+
|
|
121
|
+
Now GitHub Actions can publish with `.github/workflows/npm-publish.yml`.
|
|
122
|
+
|
|
123
|
+
## GitHub -> npm Auto Publish
|
|
124
|
+
|
|
125
|
+
The publish workflow triggers on:
|
|
89
126
|
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
- `whois` must be installed locally (`brew install whois` on macOS).
|
|
127
|
+
- GitHub Release published
|
|
128
|
+
- Manual `workflow_dispatch`
|
|
93
129
|
|
|
94
|
-
|
|
130
|
+
Workflow path:
|
|
131
|
+
|
|
132
|
+
`/.github/workflows/npm-publish.yml`
|
|
133
|
+
|
|
134
|
+
Important:
|
|
135
|
+
|
|
136
|
+
- Bump `package.json` version before publishing a new release
|
|
137
|
+
- npm will reject already-published versions
|
|
138
|
+
|
|
139
|
+
## Local Publish
|
|
95
140
|
|
|
96
141
|
```bash
|
|
97
142
|
npm login
|
|
98
143
|
npm publish --access public
|
|
99
144
|
```
|
|
145
|
+
|
|
146
|
+
## Notes
|
|
147
|
+
|
|
148
|
+
- WHOIS formats vary by registry; treat `likely_available` as a pre-check, not final registrar checkout.
|
|
149
|
+
- Registries can rate-limit bulk lookups; retry `unknown` rows after cooldown.
|
|
150
|
+
- Install `whois` locally (`brew install whois` on macOS).
|
|
@@ -75,59 +75,6 @@ const STOP_WORDS = new Set([
|
|
|
75
75
|
"agents",
|
|
76
76
|
]);
|
|
77
77
|
|
|
78
|
-
const DEFAULT_STORM_SEEDS = [
|
|
79
|
-
"agent",
|
|
80
|
-
"mcp",
|
|
81
|
-
"ai",
|
|
82
|
-
"broker",
|
|
83
|
-
"router",
|
|
84
|
-
"runtime",
|
|
85
|
-
"ops",
|
|
86
|
-
"stack",
|
|
87
|
-
"forge",
|
|
88
|
-
"mesh",
|
|
89
|
-
"pilot",
|
|
90
|
-
"flow",
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
const STORM_SUFFIXES = [
|
|
94
|
-
"storm",
|
|
95
|
-
"ops",
|
|
96
|
-
"hub",
|
|
97
|
-
"mesh",
|
|
98
|
-
"forge",
|
|
99
|
-
"stack",
|
|
100
|
-
"pilot",
|
|
101
|
-
"route",
|
|
102
|
-
"router",
|
|
103
|
-
"broker",
|
|
104
|
-
"runtime",
|
|
105
|
-
"engine",
|
|
106
|
-
"works",
|
|
107
|
-
"cloud",
|
|
108
|
-
"grid",
|
|
109
|
-
"terminal",
|
|
110
|
-
"dock",
|
|
111
|
-
"labs",
|
|
112
|
-
"studio",
|
|
113
|
-
];
|
|
114
|
-
|
|
115
|
-
const STORM_PREFIXES = [
|
|
116
|
-
"agent",
|
|
117
|
-
"ai",
|
|
118
|
-
"mcp",
|
|
119
|
-
"task",
|
|
120
|
-
"flow",
|
|
121
|
-
"auto",
|
|
122
|
-
"tool",
|
|
123
|
-
"prompt",
|
|
124
|
-
"context",
|
|
125
|
-
"trace",
|
|
126
|
-
"guard",
|
|
127
|
-
"secure",
|
|
128
|
-
"fleet",
|
|
129
|
-
];
|
|
130
|
-
|
|
131
78
|
// Small, non-authoritative heuristic list for quick legal-risk triage.
|
|
132
79
|
const TRADEMARK_KEYWORDS = [
|
|
133
80
|
"openai",
|
|
@@ -169,12 +116,16 @@ function printUsage() {
|
|
|
169
116
|
" --timeout-ms <n> WHOIS timeout per domain (default: 12000)",
|
|
170
117
|
" --brainstorm Generate domain ideas from seeds, then check availability",
|
|
171
118
|
" --max-suggestions <n> Max brainstormed candidates (default: 120)",
|
|
119
|
+
" --table Render results in a readable terminal table",
|
|
120
|
+
" --plain Emit machine-friendly TSV output",
|
|
172
121
|
" --only-available Print only likely available domains",
|
|
173
122
|
" --raw Include WHOIS snippet in console output",
|
|
174
123
|
" --help Show this help",
|
|
175
124
|
"",
|
|
176
125
|
"Notes:",
|
|
177
126
|
" - Labels without a dot are auto-converted to <label>.<tld>",
|
|
127
|
+
" - Brainstorm mode uses your seed words only (no hardcoded keyword packs)",
|
|
128
|
+
" - No seed ideas? Ask your agent (Codex, Claude, etc.) and pass them to --brainstorm",
|
|
178
129
|
" - WHOIS-based checks are heuristic; always confirm at registrar checkout",
|
|
179
130
|
].join("\n"),
|
|
180
131
|
);
|
|
@@ -190,6 +141,8 @@ function parseArgs(argv) {
|
|
|
190
141
|
server: null,
|
|
191
142
|
brainstorm: false,
|
|
192
143
|
maxSuggestions: DEFAULT_MAX_SUGGESTIONS,
|
|
144
|
+
table: false,
|
|
145
|
+
plain: false,
|
|
193
146
|
onlyAvailable: false,
|
|
194
147
|
raw: false,
|
|
195
148
|
labels: [],
|
|
@@ -226,6 +179,12 @@ function parseArgs(argv) {
|
|
|
226
179
|
case "--max-suggestions":
|
|
227
180
|
options.maxSuggestions = Number.parseInt(argv[++i], 10);
|
|
228
181
|
break;
|
|
182
|
+
case "--table":
|
|
183
|
+
options.table = true;
|
|
184
|
+
break;
|
|
185
|
+
case "--plain":
|
|
186
|
+
options.plain = true;
|
|
187
|
+
break;
|
|
229
188
|
case "--only-available":
|
|
230
189
|
options.onlyAvailable = true;
|
|
231
190
|
break;
|
|
@@ -249,7 +208,9 @@ function parseArgs(argv) {
|
|
|
249
208
|
}
|
|
250
209
|
|
|
251
210
|
if (!options.input && options.labels.length === 0 && !options.brainstorm) {
|
|
252
|
-
throw new Error(
|
|
211
|
+
throw new Error(
|
|
212
|
+
"Provide --input <file>, one/more labels/domains, or use --brainstorm. Tip: ask your agent (Codex, Claude, etc.) for seed phrases.",
|
|
213
|
+
);
|
|
253
214
|
}
|
|
254
215
|
if (!Number.isInteger(options.concurrency) || options.concurrency < 1 || options.concurrency > 50) {
|
|
255
216
|
throw new Error("--concurrency must be an integer between 1 and 50.");
|
|
@@ -349,7 +310,12 @@ function tokenizeSeeds(rawValues) {
|
|
|
349
310
|
|
|
350
311
|
function brainstormCandidates(rawSeeds, maxSuggestions) {
|
|
351
312
|
const seedTokens = tokenizeSeeds(rawSeeds);
|
|
352
|
-
|
|
313
|
+
if (seedTokens.length === 0) {
|
|
314
|
+
throw new Error(
|
|
315
|
+
"Brainstorm mode needs seed words. Ask your agent of choice (Codex, Claude, etc.) for naming seeds, then run: --brainstorm \"seed one\" \"seed two\"",
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
const seedPool = Array.from(new Set(seedTokens)).slice(0, 24);
|
|
353
319
|
const scored = new Map();
|
|
354
320
|
|
|
355
321
|
function add(label, story, bonus = 0) {
|
|
@@ -368,24 +334,67 @@ function brainstormCandidates(rawSeeds, maxSuggestions) {
|
|
|
368
334
|
}
|
|
369
335
|
}
|
|
370
336
|
|
|
337
|
+
function shortForm(token) {
|
|
338
|
+
if (token.length < 5) {
|
|
339
|
+
return token;
|
|
340
|
+
}
|
|
341
|
+
const withoutVowels = token[0] + token.slice(1).replace(/[aeiou]/g, "");
|
|
342
|
+
if (withoutVowels.length >= 3 && withoutVowels.length < token.length) {
|
|
343
|
+
return withoutVowels;
|
|
344
|
+
}
|
|
345
|
+
return token;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const formsBySeed = new Map();
|
|
371
349
|
for (const seed of seedPool) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
add(
|
|
350
|
+
const forms = new Set([seed, shortForm(seed)]);
|
|
351
|
+
if (seed.length > 8) {
|
|
352
|
+
forms.add(seed.slice(0, 7));
|
|
375
353
|
}
|
|
376
|
-
|
|
377
|
-
|
|
354
|
+
formsBySeed.set(seed, Array.from(forms));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
for (const seed of seedPool) {
|
|
358
|
+
for (const form of formsBySeed.get(seed)) {
|
|
359
|
+
add(form, form === seed ? "Seed keyword" : "Compressed variant", form === seed ? 18 : 10);
|
|
378
360
|
}
|
|
379
361
|
}
|
|
380
362
|
|
|
381
363
|
for (let i = 0; i < seedPool.length; i += 1) {
|
|
382
|
-
for (let j =
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
364
|
+
for (let j = 0; j < seedPool.length; j += 1) {
|
|
365
|
+
if (i === j) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
const aForms = formsBySeed.get(seedPool[i]);
|
|
369
|
+
const bForms = formsBySeed.get(seedPool[j]);
|
|
370
|
+
for (const a of aForms) {
|
|
371
|
+
for (const b of bForms) {
|
|
372
|
+
add(`${a}${b}`, "Two-seed compound", 20);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
for (let i = 0; i < seedPool.length; i += 1) {
|
|
379
|
+
for (let j = 0; j < seedPool.length; j += 1) {
|
|
380
|
+
for (let k = 0; k < seedPool.length; k += 1) {
|
|
381
|
+
if (i === j || j === k || i === k) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const a = formsBySeed.get(seedPool[i])[0];
|
|
385
|
+
const b = formsBySeed.get(seedPool[j])[0];
|
|
386
|
+
const c = formsBySeed.get(seedPool[k])[0];
|
|
387
|
+
add(`${a}${b}${c}`, "Three-seed compound", 10);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const acronym = seedPool.map((token) => token[0]).join("");
|
|
393
|
+
if (acronym.length >= 3) {
|
|
394
|
+
add(acronym, "Seed acronym", 16);
|
|
395
|
+
for (const seed of seedPool) {
|
|
396
|
+
add(`${acronym}${seed}`, "Acronym + seed", 12);
|
|
397
|
+
add(`${seed}${acronym}`, "Seed + acronym", 12);
|
|
389
398
|
}
|
|
390
399
|
}
|
|
391
400
|
|
|
@@ -396,7 +405,7 @@ function brainstormCandidates(rawSeeds, maxSuggestions) {
|
|
|
396
405
|
return {
|
|
397
406
|
labels: sorted.map((item) => item.label),
|
|
398
407
|
storyByLabel: new Map(sorted.map((item) => [item.label, item.story])),
|
|
399
|
-
usedSeeds:
|
|
408
|
+
usedSeeds: seedPool,
|
|
400
409
|
};
|
|
401
410
|
}
|
|
402
411
|
|
|
@@ -558,6 +567,125 @@ function snippet(raw) {
|
|
|
558
567
|
return raw.replace(/\s+/g, " ").slice(0, 120);
|
|
559
568
|
}
|
|
560
569
|
|
|
570
|
+
function verdictForStatus(status) {
|
|
571
|
+
switch (status) {
|
|
572
|
+
case "likely_available":
|
|
573
|
+
return "AVAILABLE";
|
|
574
|
+
case "registered":
|
|
575
|
+
return "TAKEN";
|
|
576
|
+
default:
|
|
577
|
+
return "UNKNOWN";
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function sentenceForRow(row) {
|
|
582
|
+
if (row.status === "likely_available") {
|
|
583
|
+
return `${row.domain} is available.`;
|
|
584
|
+
}
|
|
585
|
+
if (row.status === "registered") {
|
|
586
|
+
return `${row.domain} is not available (already registered).`;
|
|
587
|
+
}
|
|
588
|
+
return `${row.domain} availability is unknown (whois could not confirm).`;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function toDisplayRow(row, options) {
|
|
592
|
+
return {
|
|
593
|
+
verdict: verdictForStatus(row.status),
|
|
594
|
+
domain: row.domain,
|
|
595
|
+
whois: row.status,
|
|
596
|
+
reason: row.reason,
|
|
597
|
+
risk: row.legalRisk,
|
|
598
|
+
story: row.story ?? "",
|
|
599
|
+
error: row.error ?? "",
|
|
600
|
+
raw: options.raw ? snippet(row.raw) : "",
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
function truncateCell(value, maxWidth) {
|
|
605
|
+
const text = String(value ?? "");
|
|
606
|
+
if (text.length <= maxWidth) {
|
|
607
|
+
return text;
|
|
608
|
+
}
|
|
609
|
+
if (maxWidth <= 1) {
|
|
610
|
+
return text.slice(0, maxWidth);
|
|
611
|
+
}
|
|
612
|
+
return `${text.slice(0, maxWidth - 1)}…`;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function printTable(rows, options) {
|
|
616
|
+
const displayRows = rows.map((row) => toDisplayRow(row, options));
|
|
617
|
+
const hasStory = displayRows.some((row) => row.story);
|
|
618
|
+
const hasError = displayRows.some((row) => row.error);
|
|
619
|
+
const columns = [
|
|
620
|
+
{ key: "verdict", label: "Verdict", maxWidth: 10 },
|
|
621
|
+
{ key: "domain", label: "Domain", maxWidth: 44 },
|
|
622
|
+
{ key: "whois", label: "Whois", maxWidth: 18 },
|
|
623
|
+
{ key: "reason", label: "Reason", maxWidth: 34 },
|
|
624
|
+
{ key: "risk", label: "Risk", maxWidth: 14 },
|
|
625
|
+
...(hasStory ? [{ key: "story", label: "Story", maxWidth: 36 }] : []),
|
|
626
|
+
...(hasError ? [{ key: "error", label: "Error", maxWidth: 44 }] : []),
|
|
627
|
+
...(options.raw ? [{ key: "raw", label: "Raw", maxWidth: 44 }] : []),
|
|
628
|
+
];
|
|
629
|
+
|
|
630
|
+
const widths = new Map();
|
|
631
|
+
for (const col of columns) {
|
|
632
|
+
const maxValueLen = displayRows.reduce((max, row) => Math.max(max, String(row[col.key] ?? "").length), 0);
|
|
633
|
+
widths.set(col.key, Math.min(Math.max(col.label.length, maxValueLen), col.maxWidth));
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
const formatCell = (value, width) => truncateCell(value, width).padEnd(width, " ");
|
|
637
|
+
const header = columns.map((col) => formatCell(col.label, widths.get(col.key))).join(" | ");
|
|
638
|
+
const separator = columns.map((col) => "-".repeat(widths.get(col.key))).join("-+-");
|
|
639
|
+
console.log(header);
|
|
640
|
+
console.log(separator);
|
|
641
|
+
for (const row of displayRows) {
|
|
642
|
+
const line = columns.map((col) => formatCell(row[col.key], widths.get(col.key))).join(" | ");
|
|
643
|
+
console.log(line);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function printDecoratedResults(rows, options) {
|
|
648
|
+
const title = " DOMAINSTORM RESULTS ";
|
|
649
|
+
const border = "=".repeat(Math.max(68, title.length + 8));
|
|
650
|
+
console.log(border);
|
|
651
|
+
console.log(title);
|
|
652
|
+
console.log(border);
|
|
653
|
+
if (rows.length === 0) {
|
|
654
|
+
console.log("No domains matched your filters.");
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
printTable(rows, options);
|
|
658
|
+
if (rows.length === 1) {
|
|
659
|
+
const row = rows[0];
|
|
660
|
+
console.log("");
|
|
661
|
+
console.log(`Result: ${row.domain} is ${verdictForStatus(row.status)}.`);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function printNarrativeResults(rows, options) {
|
|
666
|
+
if (rows.length === 0) {
|
|
667
|
+
console.log("No domains matched your filters.");
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
for (const row of rows) {
|
|
672
|
+
console.log(sentenceForRow(row));
|
|
673
|
+
if (row.status === "unknown" || row.error) {
|
|
674
|
+
let detail = ` reason: ${row.reason}`;
|
|
675
|
+
if (row.error) {
|
|
676
|
+
detail += ` | error: ${row.error}`;
|
|
677
|
+
}
|
|
678
|
+
console.log(detail);
|
|
679
|
+
}
|
|
680
|
+
if (row.story) {
|
|
681
|
+
console.log(` story: ${row.story}`);
|
|
682
|
+
}
|
|
683
|
+
if (options.raw) {
|
|
684
|
+
console.log(` raw: ${snippet(row.raw)}`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
561
689
|
async function main() {
|
|
562
690
|
const options = parseArgs(process.argv.slice(2));
|
|
563
691
|
let rawLabels = await loadLabels(options);
|
|
@@ -609,26 +737,30 @@ async function main() {
|
|
|
609
737
|
? checked.filter((row) => row.status === "likely_available")
|
|
610
738
|
: checked;
|
|
611
739
|
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
740
|
+
if (options.plain) {
|
|
741
|
+
for (const row of filtered) {
|
|
742
|
+
let line = `${row.domain}\t${row.status}\t${row.reason}\t${row.legalRisk}`;
|
|
743
|
+
if (row.story) {
|
|
744
|
+
line += `\tstory=${row.story}`;
|
|
745
|
+
}
|
|
746
|
+
if (row.error) {
|
|
747
|
+
line += `\terror=${row.error}`;
|
|
748
|
+
}
|
|
749
|
+
if (options.raw) {
|
|
750
|
+
line += `\t${snippet(row.raw)}`;
|
|
751
|
+
}
|
|
752
|
+
console.log(line);
|
|
622
753
|
}
|
|
623
|
-
|
|
754
|
+
} else if (options.table) {
|
|
755
|
+
printDecoratedResults(filtered, options);
|
|
756
|
+
} else {
|
|
757
|
+
printNarrativeResults(filtered, options);
|
|
624
758
|
}
|
|
625
759
|
|
|
626
760
|
await maybeWriteCsv(checked, options.output);
|
|
627
761
|
|
|
628
762
|
const counts = summarize(checked);
|
|
629
|
-
console.error(
|
|
630
|
-
`Summary: likely_available=${counts.likelyAvailable}, registered=${counts.registered}, unknown=${counts.unknown}`,
|
|
631
|
-
);
|
|
763
|
+
console.error(`Summary: ${counts.likelyAvailable} available, ${counts.registered} taken, ${counts.unknown} unknown.`);
|
|
632
764
|
if (options.output) {
|
|
633
765
|
console.error(`CSV written: ${path.resolve(options.output)}`);
|
|
634
766
|
}
|
package/package.json
CHANGED
|
@@ -1,27 +1,45 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domainstorm",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Brainstorm and check domain names in one command.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/tanishqsh/domain-cli.git"
|
|
8
|
+
},
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/tanishqsh/domain-cli/issues"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/tanishqsh/domain-cli#readme",
|
|
5
13
|
"type": "module",
|
|
6
14
|
"bin": {
|
|
7
|
-
"domainstorm": "check-
|
|
8
|
-
"domain-check": "check-
|
|
15
|
+
"domainstorm": "check-domains.mjs",
|
|
16
|
+
"domain-check": "check-domains.mjs"
|
|
9
17
|
},
|
|
10
18
|
"files": [
|
|
11
|
-
"check-
|
|
12
|
-
"agent-
|
|
19
|
+
"check-domains.mjs",
|
|
20
|
+
"agent-candidates.txt",
|
|
13
21
|
"README.md"
|
|
14
22
|
],
|
|
15
23
|
"scripts": {
|
|
16
|
-
"
|
|
24
|
+
"check": "node check-domains.mjs --help > /dev/null",
|
|
25
|
+
"start": "node check-domains.mjs --help"
|
|
17
26
|
},
|
|
18
27
|
"keywords": [
|
|
19
28
|
"domain",
|
|
29
|
+
"domains",
|
|
20
30
|
"whois",
|
|
21
31
|
"cli",
|
|
22
|
-
"availability"
|
|
32
|
+
"availability",
|
|
33
|
+
"brainstorm",
|
|
34
|
+
"branding",
|
|
35
|
+
"agents",
|
|
36
|
+
"naming"
|
|
23
37
|
],
|
|
24
38
|
"license": "MIT",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public",
|
|
41
|
+
"provenance": true
|
|
42
|
+
},
|
|
25
43
|
"engines": {
|
|
26
44
|
"node": ">=18"
|
|
27
45
|
}
|
|
File without changes
|