frigatebird 0.2.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/CHANGELOG.md +21 -0
- package/LICENSE +21 -0
- package/README.md +186 -0
- package/SKILL.md +51 -0
- package/SPEC.md +59 -0
- package/TASKS.md +29 -0
- package/dist/browser/auth-store.js +145 -0
- package/dist/browser/scrape.js +247 -0
- package/dist/browser/session-manager.js +102 -0
- package/dist/cli/program.js +299 -0
- package/dist/cli.js +112 -0
- package/dist/client/client.js +1 -0
- package/dist/client/playwright-client.js +1058 -0
- package/dist/commands/handlers.js +295 -0
- package/dist/lib/config.js +75 -0
- package/dist/lib/identifiers.js +60 -0
- package/dist/lib/invocation.js +49 -0
- package/dist/lib/options.js +169 -0
- package/dist/lib/output.js +171 -0
- package/dist/lib/types.js +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import kleur from "kleur";
|
|
2
|
+
function paint(enabled) {
|
|
3
|
+
if (!enabled) {
|
|
4
|
+
return {
|
|
5
|
+
title: (v) => v,
|
|
6
|
+
key: (v) => v,
|
|
7
|
+
muted: (v) => v,
|
|
8
|
+
success: (v) => v,
|
|
9
|
+
warning: (v) => v,
|
|
10
|
+
error: (v) => v,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
title: (v) => kleur.bold().cyan(v),
|
|
15
|
+
key: (v) => kleur.bold(v),
|
|
16
|
+
muted: (v) => kleur.gray(v),
|
|
17
|
+
success: (v) => kleur.green(v),
|
|
18
|
+
warning: (v) => kleur.yellow(v),
|
|
19
|
+
error: (v) => kleur.red(v),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export class Output {
|
|
23
|
+
cfg;
|
|
24
|
+
c;
|
|
25
|
+
constructor(cfg) {
|
|
26
|
+
this.cfg = cfg;
|
|
27
|
+
this.c = paint((cfg.plain ? false : cfg.color) !== false);
|
|
28
|
+
}
|
|
29
|
+
warn(message) {
|
|
30
|
+
console.warn(this.c.warning(message));
|
|
31
|
+
}
|
|
32
|
+
info(message) {
|
|
33
|
+
console.log(message);
|
|
34
|
+
}
|
|
35
|
+
error(message) {
|
|
36
|
+
console.error(this.c.error(message));
|
|
37
|
+
}
|
|
38
|
+
json(value) {
|
|
39
|
+
console.log(JSON.stringify(value, null, 2));
|
|
40
|
+
}
|
|
41
|
+
mutation(result) {
|
|
42
|
+
const icon = this.cfg.emoji === false ? "" : result.ok ? "✓ " : "✗ ";
|
|
43
|
+
const painter = result.ok ? this.c.success : this.c.error;
|
|
44
|
+
console.log(painter(`${icon}${result.message}`.trim()));
|
|
45
|
+
}
|
|
46
|
+
tweets(result) {
|
|
47
|
+
if (result.items.length === 0) {
|
|
48
|
+
console.log(this.c.muted("No tweets found."));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
for (const tweet of result.items) {
|
|
52
|
+
const headerParts = [];
|
|
53
|
+
if (tweet.createdAt)
|
|
54
|
+
headerParts.push(tweet.createdAt);
|
|
55
|
+
if (tweet.authorName || tweet.authorHandle) {
|
|
56
|
+
const identity = [
|
|
57
|
+
tweet.authorName,
|
|
58
|
+
tweet.authorHandle ? `(@${tweet.authorHandle})` : "",
|
|
59
|
+
]
|
|
60
|
+
.filter(Boolean)
|
|
61
|
+
.join(" ");
|
|
62
|
+
headerParts.push(identity.trim());
|
|
63
|
+
}
|
|
64
|
+
if (tweet.id)
|
|
65
|
+
headerParts.push(`#${tweet.id}`);
|
|
66
|
+
console.log(this.c.title(headerParts.join(" • ")));
|
|
67
|
+
console.log(tweet.text || "[media-only tweet]");
|
|
68
|
+
console.log(this.c.muted(tweet.url));
|
|
69
|
+
console.log("");
|
|
70
|
+
}
|
|
71
|
+
if (result.nextCursor) {
|
|
72
|
+
console.log(this.c.muted(`next_cursor: ${result.nextCursor}`));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
users(result) {
|
|
76
|
+
if (result.items.length === 0) {
|
|
77
|
+
console.log(this.c.muted("No users found."));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
for (const user of result.items) {
|
|
81
|
+
const identity = [user.name, user.handle ? `(@${user.handle})` : ""]
|
|
82
|
+
.filter(Boolean)
|
|
83
|
+
.join(" ");
|
|
84
|
+
console.log(this.c.title(identity || user.url || "Unknown user"));
|
|
85
|
+
if (user.bio)
|
|
86
|
+
console.log(user.bio);
|
|
87
|
+
if (user.url)
|
|
88
|
+
console.log(this.c.muted(user.url));
|
|
89
|
+
console.log("");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
lists(result) {
|
|
93
|
+
if (result.items.length === 0) {
|
|
94
|
+
console.log(this.c.muted("No lists found."));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
for (const item of result.items) {
|
|
98
|
+
const stats = [
|
|
99
|
+
item.memberCount !== undefined ? `${item.memberCount} members` : null,
|
|
100
|
+
item.subscriberCount !== undefined
|
|
101
|
+
? `${item.subscriberCount} subscribers`
|
|
102
|
+
: null,
|
|
103
|
+
]
|
|
104
|
+
.filter(Boolean)
|
|
105
|
+
.join(" • ");
|
|
106
|
+
console.log(this.c.title(`${item.name} (${item.id})`));
|
|
107
|
+
if (item.description)
|
|
108
|
+
console.log(item.description);
|
|
109
|
+
if (stats)
|
|
110
|
+
console.log(this.c.muted(stats));
|
|
111
|
+
console.log(this.c.muted(item.url));
|
|
112
|
+
console.log("");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
profile(profile) {
|
|
116
|
+
console.log(this.c.title(profile.name || profile.handle || "Unknown user"));
|
|
117
|
+
if (profile.handle)
|
|
118
|
+
console.log(`${this.c.key("Handle")}: @${profile.handle}`);
|
|
119
|
+
if (profile.id)
|
|
120
|
+
console.log(`${this.c.key("ID")}: ${profile.id}`);
|
|
121
|
+
if (profile.bio)
|
|
122
|
+
console.log(`${this.c.key("Bio")}: ${profile.bio}`);
|
|
123
|
+
if (profile.location)
|
|
124
|
+
console.log(`${this.c.key("Location")}: ${profile.location}`);
|
|
125
|
+
if (profile.joined)
|
|
126
|
+
console.log(`${this.c.key("Joined")}: ${profile.joined}`);
|
|
127
|
+
if (profile.website)
|
|
128
|
+
console.log(`${this.c.key("Website")}: ${profile.website}`);
|
|
129
|
+
if (profile.verified !== undefined)
|
|
130
|
+
console.log(`${this.c.key("Verified")}: ${profile.verified ? "yes" : "no"}`);
|
|
131
|
+
if (profile.accountBasedIn)
|
|
132
|
+
console.log(`${this.c.key("Account Based In")}: ${profile.accountBasedIn}`);
|
|
133
|
+
if (profile.source)
|
|
134
|
+
console.log(`${this.c.key("Source")}: ${profile.source}`);
|
|
135
|
+
if (profile.createdCountryAccurate !== undefined)
|
|
136
|
+
console.log(`${this.c.key("Created Country Accurate")}: ${profile.createdCountryAccurate ? "yes" : "no"}`);
|
|
137
|
+
if (profile.locationAccurate !== undefined)
|
|
138
|
+
console.log(`${this.c.key("Location Accurate")}: ${profile.locationAccurate ? "yes" : "no"}`);
|
|
139
|
+
if (profile.learnMoreUrl)
|
|
140
|
+
console.log(`${this.c.key("Learn More")}: ${profile.learnMoreUrl}`);
|
|
141
|
+
}
|
|
142
|
+
news(result) {
|
|
143
|
+
if (result.items.length === 0) {
|
|
144
|
+
console.log(this.c.muted("No news items found."));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
for (const item of result.items) {
|
|
148
|
+
console.log(this.c.title(`${item.headline} [${item.sourceTab}]`));
|
|
149
|
+
if (item.category)
|
|
150
|
+
console.log(this.c.muted(item.category));
|
|
151
|
+
if (item.summary)
|
|
152
|
+
console.log(item.summary);
|
|
153
|
+
if (item.url)
|
|
154
|
+
console.log(this.c.muted(item.url));
|
|
155
|
+
if (item.relatedTweets && item.relatedTweets.length > 0) {
|
|
156
|
+
console.log(this.c.key("Related Tweets:"));
|
|
157
|
+
for (const tweet of item.relatedTweets) {
|
|
158
|
+
console.log(`- ${tweet.authorHandle ? `@${tweet.authorHandle}: ` : ""}${tweet.text}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
console.log("");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
queryIds(result) {
|
|
165
|
+
console.log(this.c.title("Query IDs Compatibility"));
|
|
166
|
+
console.log(`${this.c.key("Backend")}: ${result.mode}`);
|
|
167
|
+
console.log(`${this.c.key("Refreshed")}: ${result.refreshed ? "yes" : "no"}`);
|
|
168
|
+
console.log(`${this.c.key("Timestamp")}: ${result.timestamp}`);
|
|
169
|
+
console.log(result.note);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "frigatebird",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Playwright-first X CLI with bird and x-list-manager parity",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cli.js",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "Sean McLellan",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/Oceanswave/frigatebird.git"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20.0.0"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"x",
|
|
18
|
+
"twitter",
|
|
19
|
+
"cli",
|
|
20
|
+
"automation",
|
|
21
|
+
"playwright",
|
|
22
|
+
"bird",
|
|
23
|
+
"lists"
|
|
24
|
+
],
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"README.md",
|
|
28
|
+
"CHANGELOG.md",
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"SKILL.md",
|
|
31
|
+
"SPEC.md",
|
|
32
|
+
"TASKS.md"
|
|
33
|
+
],
|
|
34
|
+
"bin": {
|
|
35
|
+
"frigatebird": "./dist/cli.js"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc",
|
|
39
|
+
"dev": "tsx src/cli.ts",
|
|
40
|
+
"start": "node dist/cli.js",
|
|
41
|
+
"test": "vitest --config vitest.config.ts",
|
|
42
|
+
"test:run": "vitest run --config vitest.config.ts",
|
|
43
|
+
"test:coverage": "vitest run --config vitest.config.ts --coverage",
|
|
44
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
45
|
+
"lint": "biome check .",
|
|
46
|
+
"lint:fix": "biome check --write .",
|
|
47
|
+
"release:check": "npm run lint && npm run build && npm run test:coverage",
|
|
48
|
+
"smoke:pack-install": "bash scripts/smoke-pack-install.sh",
|
|
49
|
+
"prepublishOnly": "npm run release:check"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@steipete/sweet-cookie": "^0.1.0",
|
|
53
|
+
"commander": "^13.0.0",
|
|
54
|
+
"json5": "^2.2.3",
|
|
55
|
+
"kleur": "^4.1.5",
|
|
56
|
+
"playwright": "^1.49.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@biomejs/biome": "^1.9.0",
|
|
60
|
+
"@types/node": "^22.0.0",
|
|
61
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
62
|
+
"tsx": "^4.19.0",
|
|
63
|
+
"typescript": "^5.7.0",
|
|
64
|
+
"vitest": "^3.2.4"
|
|
65
|
+
}
|
|
66
|
+
}
|