fastbrowser_cli 1.0.37 → 1.0.40
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/contribs/_shared/fastbrowser_helper.d.ts +13 -0
- package/dist/contribs/_shared/fastbrowser_helper.d.ts.map +1 -0
- package/dist/contribs/_shared/fastbrowser_helper.js +44 -0
- package/dist/contribs/_shared/fastbrowser_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/cli.d.ts +3 -0
- package/dist/contribs/linkedin_cli/src/cli.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/cli.js +299 -0
- package/dist/contribs/linkedin_cli/src/cli.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.d.ts +73 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.js +866 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_profile_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.d.ts +61 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.js +885 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.js.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.d.ts +11 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.d.ts.map +1 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.js +145 -0
- package/dist/contribs/linkedin_cli/src/libs/linkedin_thread_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/cli.d.ts +3 -0
- package/dist/contribs/twitter_cli/src/cli.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/cli.js +273 -0
- package/dist/contribs/twitter_cli/src/cli.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.d.ts +28 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.js +274 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_profile_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.d.ts +43 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.js +519 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.js.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.d.ts +11 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.d.ts.map +1 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.js +213 -0
- package/dist/contribs/twitter_cli/src/libs/twitter_thread_helper.js.map +1 -0
- package/dist/fastbrowser_cli/fastbrowser_cli.js +43 -0
- package/dist/fastbrowser_cli/fastbrowser_cli.js.map +1 -1
- package/dist/fastbrowser_httpd/libs/tool-schemas.d.ts +4 -0
- package/dist/fastbrowser_httpd/libs/tool-schemas.d.ts.map +1 -1
- package/dist/fastbrowser_httpd/libs/tool-schemas.js +4 -0
- package/dist/fastbrowser_httpd/libs/tool-schemas.js.map +1 -1
- package/dist/fastbrowser_mcp/fastbrowser_mcp.js +36 -2
- package/dist/fastbrowser_mcp/fastbrowser_mcp.js.map +1 -1
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.d.ts +2 -0
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.d.ts.map +1 -1
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.js +12 -0
- package/dist/fastbrowser_mcp/libs/mcp_target_helper.js.map +1 -1
- package/dist/fastbrowser_mcp/libs/response_formatter.d.ts +1 -0
- package/dist/fastbrowser_mcp/libs/response_formatter.d.ts.map +1 -1
- package/dist/fastbrowser_mcp/libs/response_formatter.js +27 -0
- package/dist/fastbrowser_mcp/libs/response_formatter.js.map +1 -1
- package/dist/shared/fastbrowser_helper.d.ts +13 -0
- package/dist/shared/fastbrowser_helper.d.ts.map +1 -0
- package/dist/shared/fastbrowser_helper.js +39 -0
- package/dist/shared/fastbrowser_helper.js.map +1 -0
- package/examples/linkedin_cli_TOREMOVE/README.md +7 -0
- package/examples/{linkedin_cli → linkedin_cli_TOREMOVE}/linkedin_dm.sh +8 -4
- package/examples/linkedin_cli_TOREMOVE/linkedin_dm.ts +326 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_dm_messages.ts +279 -0
- package/examples/linkedin_cli_TOREMOVE/linkedin_full_cycle.sh +5 -0
- package/examples/{linkedin_cli → linkedin_cli_TOREMOVE}/linkedin_post.sh +3 -0
- package/examples/linkedin_cli_TOREMOVE/message_thread.a11y.txt +252 -0
- package/listitem +4 -0
- package/package.json +7 -3
- package/skills/fastbrowser/SKILL.md +33 -25
- package/src/contribs/_shared/fastbrowser_helper.ts +54 -0
- package/src/contribs/linkedin_cli/README.md +80 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_jeromeetienne.a11y.txt +2364 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_jontwigge.a11y.txt +2740 -0
- package/src/contribs/linkedin_cli/data/linkedin_posts_julien_guezennec.a11y.txt +2073 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_jeromeetienne.a11y.txt +1863 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_jontwigge.a11y.txt +1738 -0
- package/src/contribs/linkedin_cli/data/linkedin_profile_julien_guezennec.a11y.txt +2182 -0
- package/src/contribs/linkedin_cli/src/cli.ts +345 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_profile_helper.ts +964 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_recent_posts_helper.ts +982 -0
- package/src/contribs/linkedin_cli/src/libs/linkedin_thread_helper.ts +171 -0
- package/src/contribs/twitter_cli/README.md +79 -0
- package/src/contribs/twitter_cli/data/twitter_chat.a11y.txt +215 -0
- package/src/contribs/twitter_cli/data/twitter_home.a11y.txt +467 -0
- package/src/contribs/twitter_cli/data/twitter_profile.a11y.txt +418 -0
- package/src/contribs/twitter_cli/data/twitter_profile_jontwigge.a11y.txt +484 -0
- package/src/contribs/twitter_cli/data/twitter_profile_molokoloco.a11y.txt +483 -0
- package/src/contribs/twitter_cli/src/cli.ts +315 -0
- package/src/contribs/twitter_cli/src/libs/twitter_profile_helper.ts +328 -0
- package/src/contribs/twitter_cli/src/libs/twitter_recent_posts_helper.ts +607 -0
- package/src/contribs/twitter_cli/src/libs/twitter_thread_helper.ts +240 -0
- package/src/fastbrowser_cli/fastbrowser_cli.ts +51 -0
- package/src/fastbrowser_httpd/libs/tool-schemas.ts +6 -0
- package/src/fastbrowser_mcp/fastbrowser_mcp.ts +46 -3
- package/src/fastbrowser_mcp/libs/mcp_target_helper.ts +11 -0
- package/src/fastbrowser_mcp/libs/response_formatter.ts +29 -0
- package/src/shared/fastbrowser_helper.ts +49 -0
- package/tsconfig.json +1 -1
- package/examples/mcp_client_playwright.ts +0 -34
- /package/examples/{linkedin_cli → linkedin_cli_TOREMOVE}/linkedin.snapshot.txt +0 -0
- /package/examples/{twitter_cli → twitter_cli_TOREMOVE}/twitter_post.sh +0 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import Fs from 'fs';
|
|
3
|
+
|
|
4
|
+
import { A11yDisplay, A11yQuery, A11yTree, AxNode } from 'a11y_parse';
|
|
5
|
+
|
|
6
|
+
class MessagesThreadHelper {
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
10
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
11
|
+
//
|
|
12
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
13
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
+
|
|
15
|
+
static async parseMessagesThread(
|
|
16
|
+
axNodeThread: AxNode,
|
|
17
|
+
overrideYear?: number,
|
|
18
|
+
): Promise<string> {
|
|
19
|
+
const lines: string[] = [];
|
|
20
|
+
let currentDate: Date | null = null;
|
|
21
|
+
let currentSender: string | null = null;
|
|
22
|
+
let currentTime: { hours: number; minutes: number } | null = null;
|
|
23
|
+
const year = overrideYear !== undefined ? overrideYear : new Date().getFullYear();
|
|
24
|
+
|
|
25
|
+
for (const item of axNodeThread.children) {
|
|
26
|
+
if (item.children.length === 0) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const dateChild = item.children.find(
|
|
31
|
+
(c) => c.role === 'time'
|
|
32
|
+
&& c.attributes['value'] !== undefined
|
|
33
|
+
&& c.attributes['value'].startsWith('•') === false,
|
|
34
|
+
);
|
|
35
|
+
if (dateChild !== undefined && dateChild.attributes['value'] !== undefined) {
|
|
36
|
+
currentDate = MessagesThreadHelper.parseDateMarker(dateChild.attributes['value'], year);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const headerChild = item.children.find(
|
|
40
|
+
(c) => c.role === 'generic'
|
|
41
|
+
&& c.attributes['value'] !== undefined
|
|
42
|
+
&& / sent the following messages at /.test(c.attributes['value']),
|
|
43
|
+
);
|
|
44
|
+
if (headerChild !== undefined && headerChild.attributes['value'] !== undefined) {
|
|
45
|
+
const parsed = MessagesThreadHelper.extractSenderFromHeader(headerChild.attributes['value']);
|
|
46
|
+
if (parsed !== null) {
|
|
47
|
+
currentSender = parsed.sender;
|
|
48
|
+
currentTime = MessagesThreadHelper.parseTimeOfDay(parsed.time);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const innerTimes = A11yQuery.querySelectorAll(item, 'time');
|
|
53
|
+
const bulletTime = innerTimes.find(
|
|
54
|
+
(t) => t.attributes['value'] !== undefined && t.attributes['value'].startsWith('•'),
|
|
55
|
+
);
|
|
56
|
+
if (bulletTime !== undefined && bulletTime.attributes['value'] !== undefined) {
|
|
57
|
+
currentTime = MessagesThreadHelper.parseTimeOfDay(bulletTime.attributes['value']);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (headerChild === undefined) {
|
|
61
|
+
const linkNodes = A11yQuery.querySelectorAll(item, 'link[url*="linkedin.com/in/"]');
|
|
62
|
+
const senderLink = linkNodes.find(
|
|
63
|
+
(l) => l.name !== undefined
|
|
64
|
+
&& l.name.length > 0
|
|
65
|
+
&& l.name.startsWith('View ') === false,
|
|
66
|
+
);
|
|
67
|
+
if (senderLink !== undefined && senderLink.name !== undefined) {
|
|
68
|
+
currentSender = senderLink.name;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const paragraphs = A11yQuery.querySelectorAll(item, 'paragraph')
|
|
73
|
+
.filter((p) => MessagesThreadHelper.hasButtonAncestor(p, item) === false);
|
|
74
|
+
const texts = paragraphs
|
|
75
|
+
.map((p) => MessagesThreadHelper.extractParagraphText(p))
|
|
76
|
+
.filter((t) => t.length > 0);
|
|
77
|
+
if (texts.length === 0) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (currentDate === null || currentSender === null || currentTime === null) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const iso = MessagesThreadHelper.combineDateTime(currentDate, currentTime);
|
|
85
|
+
lines.push(`${iso}:${currentSender}: ${texts.join(' ')}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return lines.join('\n');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
92
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
93
|
+
//
|
|
94
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
95
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
96
|
+
|
|
97
|
+
private static parseDateMarker(value: string, fallbackYear: number): Date {
|
|
98
|
+
const months: Record<string, number> = {
|
|
99
|
+
Jan: 0, Feb: 1, Mar: 2, Apr: 3, May: 4, Jun: 5,
|
|
100
|
+
Jul: 6, Aug: 7, Sep: 8, Oct: 9, Nov: 10, Dec: 11,
|
|
101
|
+
};
|
|
102
|
+
const match = value.match(/^([A-Za-z]+)\s+(\d{1,2})(?:,\s*(\d{4}))?$/);
|
|
103
|
+
if (match === null) {
|
|
104
|
+
throw new Error(`Cannot parse date marker: "${value}"`);
|
|
105
|
+
}
|
|
106
|
+
const monthIndex = months[match[1]];
|
|
107
|
+
if (monthIndex === undefined) {
|
|
108
|
+
throw new Error(`Unknown month name: "${match[1]}"`);
|
|
109
|
+
}
|
|
110
|
+
const year = match[3] !== undefined ? parseInt(match[3], 10) : fallbackYear;
|
|
111
|
+
return new Date(year, monthIndex, parseInt(match[2], 10));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private static parseTimeOfDay(value: string): { hours: number; minutes: number } {
|
|
115
|
+
const cleaned = value.replace(/^•\s*/, '').trim();
|
|
116
|
+
const match = cleaned.match(/^(\d{1,2}):(\d{2})\s*(AM|PM)$/i);
|
|
117
|
+
if (match === null) {
|
|
118
|
+
throw new Error(`Cannot parse time of day: "${value}"`);
|
|
119
|
+
}
|
|
120
|
+
let hours = parseInt(match[1], 10);
|
|
121
|
+
const minutes = parseInt(match[2], 10);
|
|
122
|
+
const meridiem = match[3].toUpperCase();
|
|
123
|
+
if (meridiem === 'AM' && hours === 12) {
|
|
124
|
+
hours = 0;
|
|
125
|
+
} else if (meridiem === 'PM' && hours !== 12) {
|
|
126
|
+
hours += 12;
|
|
127
|
+
}
|
|
128
|
+
return { hours, minutes };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private static combineDateTime(date: Date, time: { hours: number; minutes: number }): string {
|
|
132
|
+
const yyyy = date.getFullYear().toString().padStart(4, '0');
|
|
133
|
+
const mm = (date.getMonth() + 1).toString().padStart(2, '0');
|
|
134
|
+
const dd = date.getDate().toString().padStart(2, '0');
|
|
135
|
+
const hh = time.hours.toString().padStart(2, '0');
|
|
136
|
+
const mi = time.minutes.toString().padStart(2, '0');
|
|
137
|
+
return `${yyyy}-${mm}-${dd}T${hh}:${mi}:00`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private static extractParagraphText(paragraph: AxNode): string {
|
|
141
|
+
if (paragraph.attributes['value'] !== undefined) {
|
|
142
|
+
return paragraph.attributes['value'].trim();
|
|
143
|
+
}
|
|
144
|
+
const parts: string[] = [];
|
|
145
|
+
for (const child of paragraph.children) {
|
|
146
|
+
if (child.name !== undefined && child.name.length > 0) {
|
|
147
|
+
parts.push(child.name);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (child.attributes['value'] !== undefined) {
|
|
151
|
+
parts.push(child.attributes['value']);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return parts.join(' ').trim();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private static extractSenderFromHeader(value: string): { sender: string; time: string } | null {
|
|
158
|
+
const match = value.match(/^(.+?) sent the following messages at (.+)$/);
|
|
159
|
+
if (match === null) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
return { sender: match[1], time: match[2] };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private static hasButtonAncestor(node: AxNode, stopAt: AxNode): boolean {
|
|
166
|
+
let current: AxNode | undefined = node.parent;
|
|
167
|
+
while (current !== undefined && current.uid !== stopAt.uid) {
|
|
168
|
+
if (current.role === 'button') {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
current = current.parent;
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
178
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
179
|
+
//
|
|
180
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
181
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
182
|
+
|
|
183
|
+
class MainHelper {
|
|
184
|
+
|
|
185
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
186
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
187
|
+
//
|
|
188
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
189
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
190
|
+
|
|
191
|
+
static async readFileContent(filePath: string): Promise<string> {
|
|
192
|
+
if (filePath !== '-') {
|
|
193
|
+
const fileContent = await Fs.promises.readFile(filePath, 'utf-8');
|
|
194
|
+
return fileContent;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return await new Promise<string>((resolve, reject) => {
|
|
198
|
+
let data = '';
|
|
199
|
+
process.stdin.setEncoding('utf-8');
|
|
200
|
+
process.stdin.on('data', (chunk) => {
|
|
201
|
+
data += chunk;
|
|
202
|
+
});
|
|
203
|
+
process.stdin.on('end', () => {
|
|
204
|
+
resolve(data);
|
|
205
|
+
});
|
|
206
|
+
process.stdin.on('error', (err) => {
|
|
207
|
+
reject(err);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
213
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
214
|
+
//
|
|
215
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
216
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
217
|
+
|
|
218
|
+
static async getAxNodeThread(axTree: AxNode): Promise<AxNode> {
|
|
219
|
+
const axNodeConvList: AxNode | undefined = A11yQuery.querySelector(axTree, 'list[name="Conversation List"]')
|
|
220
|
+
if (axNodeConvList === undefined) throw new Error('Could not find conversation list node');
|
|
221
|
+
|
|
222
|
+
console.log('axNodeConvList:', A11yDisplay.stringifyNode(axNodeConvList));
|
|
223
|
+
const axNodeConvListParent = axNodeConvList.parent
|
|
224
|
+
if (axNodeConvListParent === undefined) throw new Error('Conversation list node has no parent');
|
|
225
|
+
|
|
226
|
+
console.log('axNodeConvListParent:', A11yDisplay.stringifyNode(axNodeConvListParent));
|
|
227
|
+
|
|
228
|
+
// goto next sibling of conv list parent, which is the "Conversation details" container
|
|
229
|
+
const axNodeConvDetails: AxNode | undefined = A11yTree.nextSibling(axNodeConvListParent);
|
|
230
|
+
if (axNodeConvDetails === undefined) throw new Error('Could not find conversation details node');
|
|
231
|
+
|
|
232
|
+
console.log('axNodeConvDetails:', A11yDisplay.stringifyNode(axNodeConvDetails));
|
|
233
|
+
|
|
234
|
+
// console.log('Conversation List node:', axNodeConvList);
|
|
235
|
+
console.log('axNodeConvDetails:')
|
|
236
|
+
// console.log(A11yDisplay.stringifyTree(axNodeConvDetails));
|
|
237
|
+
|
|
238
|
+
const axNodeThread = A11yQuery.querySelector(axNodeConvDetails, 'list');
|
|
239
|
+
if (axNodeThread === undefined) throw new Error('Could not find thread node');
|
|
240
|
+
|
|
241
|
+
return axNodeThread;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
246
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
247
|
+
//
|
|
248
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
249
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
250
|
+
|
|
251
|
+
async function main(): Promise<void> {
|
|
252
|
+
const program = new Command();
|
|
253
|
+
|
|
254
|
+
// NODE_OPTIONS='' NPM_CONFIG_LOGLEVEL=silent npm run dev:cli -- take_snapshot | npx tsx ./examples/linkedin_cli/linkedin_dm_messages.ts -f -
|
|
255
|
+
program
|
|
256
|
+
.name('linkedin_dm_messages')
|
|
257
|
+
.description('Linkedin DM messages CLI')
|
|
258
|
+
.requiredOption('-f, --a11y_file <a11y_path>', 'path to the a11y file')
|
|
259
|
+
.parse(process.argv);
|
|
260
|
+
|
|
261
|
+
const options = program.opts<{
|
|
262
|
+
a11y_file: string;
|
|
263
|
+
}>();
|
|
264
|
+
|
|
265
|
+
console.log('Options:', options);
|
|
266
|
+
|
|
267
|
+
// Get and parse the whole snapshot tree, then find the relevant subtree for the messages thread container and print it
|
|
268
|
+
const fileContent = await MainHelper.readFileContent(options.a11y_file);
|
|
269
|
+
const axTree = A11yTree.parse(fileContent);
|
|
270
|
+
const axNodeThread = axTree.role === 'list'
|
|
271
|
+
? axTree
|
|
272
|
+
: await MainHelper.getAxNodeThread(axTree);
|
|
273
|
+
|
|
274
|
+
const transcript = await MessagesThreadHelper.parseMessagesThread(axNodeThread);
|
|
275
|
+
console.log(transcript);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
void main()
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
|
|
3
|
+
# Check if the CLI is working properly
|
|
4
|
+
NODE_OPTIONS='' NPM_CONFIG_LOGLEVEL=silent npm run dev:cli -- check
|
|
5
|
+
|
|
3
6
|
# Goto linkedin feed page using the CLI commands below:
|
|
4
7
|
NODE_OPTIONS='' NPM_CONFIG_LOGLEVEL=silent npm run dev:cli -- navigate_page --url https://www.linkedin.com/feed/
|
|
5
8
|
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
uid=e481 list
|
|
2
|
+
uid=s46 listitem
|
|
3
|
+
uid=e482 listitem
|
|
4
|
+
uid=e483 time value="Apr 14"
|
|
5
|
+
uid=e484 generic value="Julien Guézennec sent the following messages at 3:52 PM"
|
|
6
|
+
uid=e485 generic
|
|
7
|
+
uid=s47 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
8
|
+
uid=e487 generic value="View Julien’s profile"
|
|
9
|
+
uid=s48 unknown
|
|
10
|
+
uid=e489 generic
|
|
11
|
+
uid=e490 generic
|
|
12
|
+
uid=e491 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
13
|
+
uid=e492 generic value="Julien Guézennec"
|
|
14
|
+
uid=e493 img "LinkedIn Verified"
|
|
15
|
+
uid=e495 time value="• 3:52 PM"
|
|
16
|
+
uid=e499 paragraph value="😝🙃😅 je suis dyschromatique ! On se moque pas des handicaps !"
|
|
17
|
+
uid=e500 listitem
|
|
18
|
+
uid=e501 generic
|
|
19
|
+
uid=s49 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
20
|
+
uid=e503 generic value="View Julien’s profile"
|
|
21
|
+
uid=s50 unknown
|
|
22
|
+
uid=e505 generic
|
|
23
|
+
uid=e506 generic
|
|
24
|
+
uid=e507 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
25
|
+
uid=e508 generic value="Julien Guézennec"
|
|
26
|
+
uid=e509 img "LinkedIn Verified"
|
|
27
|
+
uid=e511 time value="• 4:12 PM"
|
|
28
|
+
uid=e515 paragraph value="Just for you i have send my futur newsletter ! Full of flying colors for reaching the contact i have scrapped around my town with Claude ! Unfortunatly, see in attached image"
|
|
29
|
+
uid=e520 button "Click or press enter to display in the image preview"
|
|
30
|
+
uid=e521 generic value="Click or press enter to display in the image preview"
|
|
31
|
+
uid=e522 img
|
|
32
|
+
uid=e523 listitem
|
|
33
|
+
uid=e524 generic
|
|
34
|
+
uid=s51 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
35
|
+
uid=e526 generic value="View Julien’s profile"
|
|
36
|
+
uid=s52 unknown
|
|
37
|
+
uid=e528 generic
|
|
38
|
+
uid=e529 generic
|
|
39
|
+
uid=e530 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
40
|
+
uid=e531 generic value="Julien Guézennec"
|
|
41
|
+
uid=e532 img "LinkedIn Verified"
|
|
42
|
+
uid=e534 time value="• 4:13 PM"
|
|
43
|
+
uid=e538 paragraph
|
|
44
|
+
uid=s53 StaticText "Is that a good path ?"
|
|
45
|
+
uid=e539 link "https://julienweb.fr/blog/dashboard-local-node-claude-sqlite/9555/" url="https://julienweb.fr/blog/dashboard-local-node-claude-sqlite/9555/"
|
|
46
|
+
uid=e544 generic
|
|
47
|
+
uid=s54 unknown url="https://julienweb.fr/blog/dashboard-local-node-claude-sqlite/9555/"
|
|
48
|
+
uid=e551 link "J'ai construit mon dashboard local avec Claude — Node.js + SQLite" url="https://julienweb.fr/blog/dashboard-local-node-claude-sqlite/9555/"
|
|
49
|
+
uid=e554 generic
|
|
50
|
+
uid=e556 generic value="J'ai construit mon dashboard local avec Claude — Node.js + SQLite"
|
|
51
|
+
uid=e557 generic value="julienweb.fr"
|
|
52
|
+
uid=e558 listitem
|
|
53
|
+
uid=e559 generic
|
|
54
|
+
uid=e563 paragraph
|
|
55
|
+
uid=e564 link "https://julienweb.fr/wp-content/uploads/claude-dashboard-julienweb-fr-ia-2026-2.png" url="https://julienweb.fr/wp-content/uploads/claude-dashboard-julienweb-fr-ia-2026-2.png"
|
|
56
|
+
uid=e569 generic
|
|
57
|
+
uid=s55 unknown url="https://julienweb.fr/wp-content/uploads/claude-dashboard-julienweb-fr-ia-2026-2.png"
|
|
58
|
+
uid=e576 link "Web Link" url="https://julienweb.fr/wp-content/uploads/claude-dashboard-julienweb-fr-ia-2026-2.png"
|
|
59
|
+
uid=e579 generic
|
|
60
|
+
uid=e580 generic value="Web Link"
|
|
61
|
+
uid=e581 generic value="julienweb.fr"
|
|
62
|
+
uid=e582 listitem
|
|
63
|
+
uid=e583 generic
|
|
64
|
+
uid=s56 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
65
|
+
uid=e585 generic value="View Julien’s profile"
|
|
66
|
+
uid=s57 unknown
|
|
67
|
+
uid=e587 generic
|
|
68
|
+
uid=e588 generic
|
|
69
|
+
uid=e589 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
70
|
+
uid=e590 generic value="Julien Guézennec"
|
|
71
|
+
uid=e591 img "LinkedIn Verified"
|
|
72
|
+
uid=e593 time value="• 4:18 PM"
|
|
73
|
+
uid=e597 paragraph
|
|
74
|
+
uid=s58 StaticText "Regarde ca :)"
|
|
75
|
+
uid=e598 link "https://passerelles.economie.gouv.fr/offre-de-emploi/emploi-chef-de-projet-cafe-ia-relations-territoriales-sen-cian-219-h-f_29182.aspx" url="https://passerelles.economie.gouv.fr/offre-de-emploi/emploi-chef-de-projet-cafe-ia-relations-territoriales-sen-cian-219-h-f_29182.aspx"
|
|
76
|
+
uid=s59 StaticText "Je suis un ouf j'ai candidaté ^^ CV full IA ^^ LOL"
|
|
77
|
+
uid=e603 generic
|
|
78
|
+
uid=s60 unknown url="https://passerelles.economie.gouv.fr/offre-de-emploi/emploi-chef-de-projet-cafe-ia-relations-territoriales-sen-cian-219-h-f_29182.aspx"
|
|
79
|
+
uid=e610 link "Chef de projet Café IA - Relations territoriales SEN-CIAN-219 H/F" url="https://passerelles.economie.gouv.fr/offre-de-emploi/emploi-chef-de-projet-cafe-ia-relations-territoriales-sen-cian-219-h-f_29182.aspx"
|
|
80
|
+
uid=e613 generic
|
|
81
|
+
uid=e615 generic value="Chef de projet Café IA - Relations territoriales SEN-CIAN-219 H/F"
|
|
82
|
+
uid=e616 generic value="passerelles.economie.gouv.fr"
|
|
83
|
+
uid=e617 listitem
|
|
84
|
+
uid=e622 button "PDF CV Julien Guézennec — Chef de projet Café IA.pdf 1 MB Download"
|
|
85
|
+
uid=e623 generic
|
|
86
|
+
uid=s61 StaticText "PDF"
|
|
87
|
+
uid=e624 generic
|
|
88
|
+
uid=e625 paragraph value="CV Julien Guézennec — Chef de projet Café IA.pdf"
|
|
89
|
+
uid=e626 paragraph value="1 MB"
|
|
90
|
+
uid=e627 generic
|
|
91
|
+
uid=e628 img
|
|
92
|
+
uid=e630 paragraph value="Download"
|
|
93
|
+
uid=e631 listitem
|
|
94
|
+
uid=e632 generic value="Jerome Etienne sent the following messages at 6:42 PM"
|
|
95
|
+
uid=e633 generic
|
|
96
|
+
uid=e634 link "View Jerome’s profile Jerome Etienne" url="https://www.linkedin.com/in/ACoAAABV1ZYB_x7AQ_K0oe15LPzT32jClDzkqjQ"
|
|
97
|
+
uid=e635 generic value="View Jerome’s profile"
|
|
98
|
+
uid=e636 img "Jerome Etienne"
|
|
99
|
+
uid=e637 generic
|
|
100
|
+
uid=e638 generic
|
|
101
|
+
uid=e639 link "Jerome Etienne" url="https://www.linkedin.com/in/ACoAAABV1ZYB_x7AQ_K0oe15LPzT32jClDzkqjQ"
|
|
102
|
+
uid=e640 generic value="Jerome Etienne"
|
|
103
|
+
uid=e641 img "LinkedIn Verified"
|
|
104
|
+
uid=e643 time value="• 6:42 PM"
|
|
105
|
+
uid=e647 paragraph value="Se déplacer sur l’ensemble du territoire français pour rencontrer les collectivités, les conseillers numériques, et assurer notre présence lors d’événements dédiés à l’inclusion numérique et animer des cafés IA partout en France – déplacements réguliers à prévoir – environ 1 par semaine <- tu as vu ca ?"
|
|
106
|
+
uid=e648 list
|
|
107
|
+
uid=e649 listitem
|
|
108
|
+
uid=e650 button "React with 👍 1"
|
|
109
|
+
uid=e651 generic
|
|
110
|
+
uid=e652 generic value="React with"
|
|
111
|
+
uid=s62 generic value="👍"
|
|
112
|
+
uid=s63 generic value="1"
|
|
113
|
+
uid=e653 listitem
|
|
114
|
+
uid=e656 button "Open Emoji Keyboard"
|
|
115
|
+
uid=e657 listitem
|
|
116
|
+
uid=e662 paragraph value="tiens moi aussi je dois refaire un resume"
|
|
117
|
+
uid=e663 listitem
|
|
118
|
+
uid=e668 paragraph value="faudra que tu mexplique comment tu as fait"
|
|
119
|
+
uid=e669 listitem
|
|
120
|
+
uid=e670 generic value="Julien Guézennec sent the following messages at 6:59 PM"
|
|
121
|
+
uid=e671 generic
|
|
122
|
+
uid=s64 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
123
|
+
uid=e673 generic value="View Julien’s profile"
|
|
124
|
+
uid=s65 unknown
|
|
125
|
+
uid=e675 generic
|
|
126
|
+
uid=e676 generic
|
|
127
|
+
uid=e677 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
128
|
+
uid=e678 generic value="Julien Guézennec"
|
|
129
|
+
uid=e679 img "LinkedIn Verified"
|
|
130
|
+
uid=e681 time value="• 6:59 PM"
|
|
131
|
+
uid=e685 paragraph value="👍"
|
|
132
|
+
uid=e686 listitem
|
|
133
|
+
uid=e687 generic
|
|
134
|
+
uid=s66 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
135
|
+
uid=e689 generic value="View Julien’s profile"
|
|
136
|
+
uid=s67 unknown
|
|
137
|
+
uid=e691 generic
|
|
138
|
+
uid=e692 generic
|
|
139
|
+
uid=e693 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
140
|
+
uid=e694 generic value="Julien Guézennec"
|
|
141
|
+
uid=e695 img "LinkedIn Verified"
|
|
142
|
+
uid=e697 time value="• 7:38 PM"
|
|
143
|
+
uid=e701 paragraph
|
|
144
|
+
uid=e702 link "https://www.instagram.com/p/ChcTUsoD1rZ/" url="https://www.instagram.com/p/ChcTUsoD1rZ/"
|
|
145
|
+
uid=s68 StaticText "Go :)"
|
|
146
|
+
uid=e710 link "Julien Guézennec on Instagram" url="https://www.instagram.com/julienweb.fr/p/ChcTUsoD1rZ/"
|
|
147
|
+
uid=e712 generic
|
|
148
|
+
uid=e713 generic
|
|
149
|
+
uid=e715 generic value="Julien Guézennec on Instagram"
|
|
150
|
+
uid=e716 generic value="instagram.com"
|
|
151
|
+
uid=e717 generic value="27 likes, 3 comments - julienweb.fr on August 19, 2022"
|
|
152
|
+
uid=e718 listitem
|
|
153
|
+
uid=e719 generic value="Jerome Etienne sent the following messages at 8:16 PM"
|
|
154
|
+
uid=e720 generic
|
|
155
|
+
uid=e721 link "View Jerome’s profile Jerome Etienne" url="https://www.linkedin.com/in/ACoAAABV1ZYB_x7AQ_K0oe15LPzT32jClDzkqjQ"
|
|
156
|
+
uid=e722 generic value="View Jerome’s profile"
|
|
157
|
+
uid=e723 img "Jerome Etienne"
|
|
158
|
+
uid=e724 generic
|
|
159
|
+
uid=e725 generic
|
|
160
|
+
uid=e726 link "Jerome Etienne" url="https://www.linkedin.com/in/ACoAAABV1ZYB_x7AQ_K0oe15LPzT32jClDzkqjQ"
|
|
161
|
+
uid=e727 generic value="Jerome Etienne"
|
|
162
|
+
uid=e728 img "LinkedIn Verified"
|
|
163
|
+
uid=e730 time value="• 8:16 PM"
|
|
164
|
+
uid=e734 paragraph value="hehe"
|
|
165
|
+
uid=e735 listitem
|
|
166
|
+
uid=e740 paragraph value="et tu te vois represente letat ?"
|
|
167
|
+
uid=e741 listitem
|
|
168
|
+
uid=e742 generic value="Julien Guézennec sent the following messages at 8:18 PM"
|
|
169
|
+
uid=e743 generic
|
|
170
|
+
uid=s69 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
171
|
+
uid=e745 generic value="View Julien’s profile"
|
|
172
|
+
uid=s70 unknown
|
|
173
|
+
uid=e747 generic
|
|
174
|
+
uid=e748 generic
|
|
175
|
+
uid=e749 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
176
|
+
uid=e750 generic value="Julien Guézennec"
|
|
177
|
+
uid=e751 img "LinkedIn Verified"
|
|
178
|
+
uid=e753 time value="• 8:18 PM"
|
|
179
|
+
uid=e757 paragraph value="Yes ! Je suis :)"
|
|
180
|
+
uid=e758 listitem
|
|
181
|
+
uid=e759 time value="Apr 16"
|
|
182
|
+
uid=e760 generic
|
|
183
|
+
uid=s71 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
184
|
+
uid=e762 generic value="View Julien’s profile"
|
|
185
|
+
uid=s72 unknown
|
|
186
|
+
uid=e764 generic
|
|
187
|
+
uid=e765 generic
|
|
188
|
+
uid=e766 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
189
|
+
uid=e767 generic value="Julien Guézennec"
|
|
190
|
+
uid=e768 img "LinkedIn Verified"
|
|
191
|
+
uid=e770 time value="• 10:25 PM"
|
|
192
|
+
uid=e774 paragraph
|
|
193
|
+
uid=s73 StaticText "Je crois que j'ai trouvé mes tarifs ;)"
|
|
194
|
+
uid=e775 link "https://julienweb.fr/services-julienweb-fr/intervention-durgence-piratage-incident-de-securite/" url="https://julienweb.fr/services-julienweb-fr/intervention-durgence-piratage-incident-de-securite/"
|
|
195
|
+
uid=s74 StaticText "Aussi bientôt validé \""
|
|
196
|
+
uid=e776 link "https://www.cybermalveillance.gouv.fr/" url="https://www.cybermalveillance.gouv.fr/"
|
|
197
|
+
uid=s75 StaticText "\""
|
|
198
|
+
uid=e781 button "Click or press enter to display in the image preview"
|
|
199
|
+
uid=e782 generic value="Click or press enter to display in the image preview"
|
|
200
|
+
uid=e783 img
|
|
201
|
+
uid=e784 listitem
|
|
202
|
+
uid=e785 generic
|
|
203
|
+
uid=s76 unknown url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
204
|
+
uid=e787 generic value="View Julien’s profile"
|
|
205
|
+
uid=s77 unknown
|
|
206
|
+
uid=e789 generic
|
|
207
|
+
uid=e790 generic
|
|
208
|
+
uid=e791 link "Julien Guézennec" url="https://www.linkedin.com/in/ACoAAADjYaoBKCGNtZN_m0INLC4MnN9yFkTDUqY"
|
|
209
|
+
uid=e792 generic value="Julien Guézennec"
|
|
210
|
+
uid=e793 img "LinkedIn Verified"
|
|
211
|
+
uid=e795 time value="• 10:27 PM"
|
|
212
|
+
uid=e799 paragraph value=":p"
|
|
213
|
+
uid=e804 button "Click or press enter to display in the image preview"
|
|
214
|
+
uid=e805 generic value="Click or press enter to display in the image preview"
|
|
215
|
+
uid=e806 img
|
|
216
|
+
uid=e807 listitem
|
|
217
|
+
uid=e808 time value="Apr 18"
|
|
218
|
+
uid=e809 generic value="Jerome Etienne sent the following messages at 1:17 PM"
|
|
219
|
+
uid=e810 generic
|
|
220
|
+
uid=e811 link "View Jerome’s profile Jerome Etienne" url="https://www.linkedin.com/in/ACoAAABV1ZYB_x7AQ_K0oe15LPzT32jClDzkqjQ"
|
|
221
|
+
uid=e812 generic value="View Jerome’s profile"
|
|
222
|
+
uid=e813 img "Jerome Etienne"
|
|
223
|
+
uid=e814 generic
|
|
224
|
+
uid=e815 generic
|
|
225
|
+
uid=e816 link "Jerome Etienne" url="https://www.linkedin.com/in/ACoAAABV1ZYB_x7AQ_K0oe15LPzT32jClDzkqjQ"
|
|
226
|
+
uid=e817 generic value="Jerome Etienne"
|
|
227
|
+
uid=e818 img "LinkedIn Verified"
|
|
228
|
+
uid=e820 time value="• 1:17 PM"
|
|
229
|
+
uid=e824 paragraph value="youpi!"
|
|
230
|
+
uid=e825 listitem
|
|
231
|
+
uid=e830 paragraph
|
|
232
|
+
uid=s78 StaticText "dit moi tu as whatapps ?"
|
|
233
|
+
uid=s79 StaticText "je passe pas si souvent que ca sur linkedin"
|
|
234
|
+
uid=e831 listitem
|
|
235
|
+
uid=e836 paragraph value="ca fluidifirai la communication :)"
|
|
236
|
+
uid=e837 listitem
|
|
237
|
+
uid=e838 generic
|
|
238
|
+
uid=e839 link "View Jerome’s profile Jerome Etienne" url="https://www.linkedin.com/in/ACoAAABV1ZYB_x7AQ_K0oe15LPzT32jClDzkqjQ"
|
|
239
|
+
uid=e840 generic value="View Jerome’s profile"
|
|
240
|
+
uid=e841 img "Jerome Etienne"
|
|
241
|
+
uid=e842 generic
|
|
242
|
+
uid=e843 generic
|
|
243
|
+
uid=e844 link "Jerome Etienne" url="https://www.linkedin.com/in/ACoAAABV1ZYB_x7AQ_K0oe15LPzT32jClDzkqjQ"
|
|
244
|
+
uid=e845 generic value="Jerome Etienne"
|
|
245
|
+
uid=e846 img "LinkedIn Verified"
|
|
246
|
+
uid=e848 time value="• 1:20 PM"
|
|
247
|
+
uid=e852 paragraph
|
|
248
|
+
uid=s80 StaticText "jai trouve sur ton site"
|
|
249
|
+
uid=s81 StaticText "je tai envoye un message :)"
|
|
250
|
+
uid=e854 img "Seen by Julien Guézennec at 2:04 PM."
|
|
251
|
+
uid=e855 listitem
|
|
252
|
+
uid=s82 listitem
|
package/listitem
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastbrowser_cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.40",
|
|
4
4
|
"description": "A CLI tool for FastBrowser, providing commands to interact with the FastBrowser MCP (Model Context Protocol) server and perform various browser automation tasks.",
|
|
5
5
|
"main": "dist/fastbrowser_cli/fastbrowser_cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"fastbrowser_cli": "./dist/fastbrowser_cli/fastbrowser_cli.js",
|
|
8
|
-
"fastbrowser_mcp": "./dist/fastbrowser_mcp/fastbrowser_mcp.js"
|
|
8
|
+
"fastbrowser_mcp": "./dist/fastbrowser_mcp/fastbrowser_mcp.js",
|
|
9
|
+
"linkedin_cli": "./dist/contribs/linkedin_cli/src/cli.js",
|
|
10
|
+
"twitter_cli": "./dist/contribs/twitter_cli/src/cli.js"
|
|
9
11
|
},
|
|
10
12
|
"keywords": [],
|
|
11
13
|
"author": "",
|
|
@@ -30,7 +32,7 @@
|
|
|
30
32
|
"typescript": "^6.0.3",
|
|
31
33
|
"zod": "^4.3.6",
|
|
32
34
|
"zod-from-json-schema": "^0.5.2",
|
|
33
|
-
"a11y_parse": "^1.0.
|
|
35
|
+
"a11y_parse": "^1.0.8"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
36
38
|
"@types/express": "^4.17.21",
|
|
@@ -47,6 +49,8 @@
|
|
|
47
49
|
"inspect:playwright:chrome": "npx @modelcontextprotocol/inspector npx @playwright/mcp@latest --cdp-endpoint=chrome",
|
|
48
50
|
"inspect:playwright:cdp_endpoint": "npx @modelcontextprotocol/inspector npx @playwright/mcp@latest --cdp-endpoint=http://localhost:9222",
|
|
49
51
|
"inspect:playwright:extension": "npx @modelcontextprotocol/inspector npx @playwright/mcp@latest --extension",
|
|
52
|
+
"contribs:linkedin:profile": "npx tsx ./src/contribs/linkedin_cli/src/cli.ts profile jeromeetienne",
|
|
53
|
+
"contribs:twitter:profile": "npx tsx ./src/contribs/twitter_cli/src/cli.ts profile jerome_etienne",
|
|
50
54
|
"build": "tsc -p tsconfig.build.json",
|
|
51
55
|
"prepublish:check": "test -z \"$(git status --porcelain)\" || (echo 'Working tree dirty — commit or stash first' && exit 1)",
|
|
52
56
|
"version:bump": "npm version patch --no-git-tag-version && git add package.json && git commit -m \"feat: bump version in fastbrowser_cli package.json\"",
|