@monoes/monobrowse 1.0.0 → 1.0.1
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/package.json +75 -0
- package/dist/src/browser/adapters/index.d.ts.map +1 -1
- package/dist/src/browser/adapters/index.js +4 -0
- package/dist/src/browser/adapters/index.js.map +1 -1
- package/dist/src/browser/browser.js +2 -2
- package/dist/src/browser/browser.js.map +1 -1
- package/dist/src/browser/cdp.d.ts +6 -0
- package/dist/src/browser/cdp.d.ts.map +1 -1
- package/dist/src/browser/cdp.js +56 -1
- package/dist/src/browser/cdp.js.map +1 -1
- package/dist/src/browser/dashboard/api-types.d.ts +1 -1
- package/dist/src/browser/dashboard/server.d.ts +1 -1
- package/dist/src/browser/dashboard/server.d.ts.map +1 -1
- package/dist/src/browser/dashboard/server.js +204 -15
- package/dist/src/browser/dashboard/server.js.map +1 -1
- package/dist/src/browser/dashboard/ui.html +1811 -0
- package/dist/src/browser/playbook/browser-handlers.d.ts +3 -0
- package/dist/src/browser/playbook/browser-handlers.d.ts.map +1 -0
- package/dist/src/browser/playbook/browser-handlers.js +377 -0
- package/dist/src/browser/playbook/browser-handlers.js.map +1 -0
- package/dist/src/browser/playbook/builtin-handlers.d.ts +3 -0
- package/dist/src/browser/playbook/builtin-handlers.d.ts.map +1 -0
- package/dist/src/browser/playbook/builtin-handlers.js +364 -0
- package/dist/src/browser/playbook/builtin-handlers.js.map +1 -0
- package/dist/src/browser/playbook/index.d.ts +3 -0
- package/dist/src/browser/playbook/index.d.ts.map +1 -0
- package/dist/src/browser/playbook/index.js +3 -0
- package/dist/src/browser/playbook/index.js.map +1 -0
- package/dist/src/browser/playbook/store.d.ts +8 -0
- package/dist/src/browser/playbook/store.d.ts.map +1 -0
- package/dist/src/browser/playbook/store.js +87 -0
- package/dist/src/browser/playbook/store.js.map +1 -0
- package/dist/src/browser/screenshot.d.ts +2 -0
- package/dist/src/browser/screenshot.d.ts.map +1 -1
- package/dist/src/browser/screenshot.js +69 -2
- package/dist/src/browser/screenshot.js.map +1 -1
- package/dist/src/browser/types.d.ts.map +1 -1
- package/dist/src/browser/types.js +11 -0
- package/dist/src/browser/types.js.map +1 -1
- package/dist/src/cli/action.d.ts +3 -0
- package/dist/src/cli/action.d.ts.map +1 -0
- package/dist/src/cli/action.js +139 -0
- package/dist/src/cli/action.js.map +1 -0
- package/dist/src/cli/commands.d.ts +8 -0
- package/dist/src/cli/commands.d.ts.map +1 -0
- package/dist/src/cli/commands.js +3021 -0
- package/dist/src/cli/commands.js.map +1 -0
- package/dist/src/cli/output.d.ts +11 -0
- package/dist/src/cli/output.d.ts.map +1 -0
- package/dist/src/cli/output.js +33 -0
- package/dist/src/cli/output.js.map +1 -0
- package/dist/src/cli/platform.d.ts +7 -0
- package/dist/src/cli/platform.d.ts.map +1 -0
- package/dist/src/cli/platform.js +193 -0
- package/dist/src/cli/platform.js.map +1 -0
- package/dist/src/cli/playbook.d.ts +3 -0
- package/dist/src/cli/playbook.d.ts.map +1 -0
- package/dist/src/cli/playbook.js +265 -0
- package/dist/src/cli/playbook.js.map +1 -0
- package/dist/src/cli/types.d.ts +42 -0
- package/dist/src/cli/types.d.ts.map +1 -0
- package/dist/src/cli/types.js +2 -0
- package/dist/src/cli/types.js.map +1 -0
- package/dist/src/cli/workflow.d.ts +2 -0
- package/dist/src/cli/workflow.d.ts.map +1 -0
- package/dist/src/cli/workflow.js +3 -0
- package/dist/src/cli/workflow.js.map +1 -0
- package/dist/src/cli.d.ts +7 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +187 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/index.d.ts +5 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +16 -1
- package/dist/src/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +24 -5
- package/src/browser/adapters/index.ts +4 -0
- package/src/browser/browser.ts +2 -2
- package/src/browser/cdp.ts +68 -1
- package/src/browser/dashboard/api-types.ts +1 -1
- package/src/browser/dashboard/server.ts +210 -17
- package/src/browser/dashboard/ui.html +1412 -45
- package/src/browser/playbook/browser-handlers.ts +449 -0
- package/src/browser/{workflow → playbook}/builtin-handlers.ts +35 -14
- package/src/browser/playbook/index.ts +2 -0
- package/src/browser/{workflow → playbook}/store.ts +14 -14
- package/src/browser/screenshot.ts +78 -3
- package/src/browser/types.ts +11 -0
- package/src/cli/action.ts +145 -0
- package/src/cli/commands.ts +2895 -0
- package/src/cli/output.ts +37 -0
- package/src/cli/platform.ts +211 -0
- package/src/cli/playbook.ts +280 -0
- package/src/cli/types.ts +47 -0
- package/src/cli.ts +208 -0
- package/src/index.ts +20 -1
- package/src/browser/workflow/engine.ts +0 -202
- package/src/browser/workflow/expression.ts +0 -107
- package/src/browser/workflow/index.ts +0 -5
- package/src/browser/workflow/types.ts +0 -62
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { CdpClient } from './cdp.js';
|
|
2
|
+
import type { ElementRef } from './types.js';
|
|
3
|
+
import { getObjectIdForRef } from './snapshot.js';
|
|
2
4
|
import { writeFile, mkdir } from 'fs/promises';
|
|
3
5
|
import { join, dirname } from 'path';
|
|
4
6
|
import { tmpdir } from 'os';
|
|
@@ -9,6 +11,68 @@ export interface ScreenshotOptions {
|
|
|
9
11
|
quality?: number;
|
|
10
12
|
format?: 'jpeg' | 'png' | 'webp';
|
|
11
13
|
annotate?: boolean;
|
|
14
|
+
refs?: Map<string, ElementRef>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function getViewportTopLeft(
|
|
18
|
+
client: CdpClient,
|
|
19
|
+
sessionId: string,
|
|
20
|
+
ref: ElementRef
|
|
21
|
+
): Promise<{ x: number; y: number } | null> {
|
|
22
|
+
const objectId = await getObjectIdForRef(client, sessionId, ref).catch(() => null);
|
|
23
|
+
if (!objectId) return null;
|
|
24
|
+
try {
|
|
25
|
+
const r = await client.send<{ result: { value?: string } }>('Runtime.callFunctionOn', {
|
|
26
|
+
functionDeclaration: 'function() { var r=this.getBoundingClientRect(); if(r.width===0&&r.height===0)return null; return JSON.stringify({x:Math.round(r.left),y:Math.round(r.top)}); }',
|
|
27
|
+
objectId,
|
|
28
|
+
returnByValue: true,
|
|
29
|
+
}, sessionId);
|
|
30
|
+
if (!r.result?.value) return null;
|
|
31
|
+
return JSON.parse(r.result.value) as { x: number; y: number };
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function injectAnnotationOverlay(
|
|
38
|
+
client: CdpClient,
|
|
39
|
+
sessionId: string,
|
|
40
|
+
refs: Map<string, ElementRef>
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
const badges: Array<{ num: number; x: number; y: number }> = [];
|
|
43
|
+
for (const [key, ref] of refs) {
|
|
44
|
+
const m = key.match(/^e(\d+)$/);
|
|
45
|
+
if (!m) continue;
|
|
46
|
+
const pos = await getViewportTopLeft(client, sessionId, ref);
|
|
47
|
+
if (pos) badges.push({ num: parseInt(m[1], 10), x: pos.x, y: pos.y });
|
|
48
|
+
}
|
|
49
|
+
if (badges.length === 0) return;
|
|
50
|
+
|
|
51
|
+
const badgesJson = JSON.stringify(badges);
|
|
52
|
+
await client.send('Runtime.evaluate', {
|
|
53
|
+
expression: `(function(){
|
|
54
|
+
var p=document.getElementById('__mm_ann__');if(p)p.remove();
|
|
55
|
+
var c=document.createElement('div');
|
|
56
|
+
c.id='__mm_ann__';
|
|
57
|
+
c.style.cssText='position:fixed;top:0;left:0;width:0;height:0;z-index:2147483647;pointer-events:none;';
|
|
58
|
+
var bs=${badgesJson};
|
|
59
|
+
bs.forEach(function(b){
|
|
60
|
+
var d=document.createElement('div');
|
|
61
|
+
d.style.cssText='position:fixed;left:'+b.x+'px;top:'+b.y+'px;background:#e74c3c;color:#fff;border-radius:3px;padding:0 4px;font-size:11px;font-family:monospace;font-weight:bold;line-height:18px;box-shadow:0 1px 3px rgba(0,0,0,.5);';
|
|
62
|
+
d.textContent=b.num;
|
|
63
|
+
c.appendChild(d);
|
|
64
|
+
});
|
|
65
|
+
document.body.appendChild(c);
|
|
66
|
+
})()`,
|
|
67
|
+
returnByValue: false,
|
|
68
|
+
}, sessionId).catch(() => {});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function removeAnnotationOverlay(client: CdpClient, sessionId: string): Promise<void> {
|
|
72
|
+
await client.send('Runtime.evaluate', {
|
|
73
|
+
expression: `(function(){var e=document.getElementById('__mm_ann__');if(e)e.remove();})()`,
|
|
74
|
+
returnByValue: false,
|
|
75
|
+
}, sessionId).catch(() => {});
|
|
12
76
|
}
|
|
13
77
|
|
|
14
78
|
export async function captureScreenshot(
|
|
@@ -33,10 +97,21 @@ export async function captureScreenshot(
|
|
|
33
97
|
params.captureBeyondViewport = true;
|
|
34
98
|
}
|
|
35
99
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
100
|
+
if (options.annotate && options.refs) {
|
|
101
|
+
await injectAnnotationOverlay(client, sessionId, options.refs);
|
|
102
|
+
}
|
|
39
103
|
|
|
104
|
+
let data: string;
|
|
105
|
+
try {
|
|
106
|
+
const result = await client.send<{ data: string }>('Page.captureScreenshot', params, sessionId);
|
|
107
|
+
data = result.data;
|
|
108
|
+
} finally {
|
|
109
|
+
if (options.annotate) {
|
|
110
|
+
await removeAnnotationOverlay(client, sessionId);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const dataUrl = `data:image/${format};base64,${data}`;
|
|
40
115
|
const outputPath = options.path ?? join(tmpdir(), `monomind-screenshot-${Date.now()}.${format}`);
|
|
41
116
|
await mkdir(dirname(outputPath), { recursive: true });
|
|
42
117
|
await writeFile(outputPath, Buffer.from(data, 'base64'));
|
package/src/browser/types.ts
CHANGED
|
@@ -125,11 +125,22 @@ export const INTERACTIVE_ROLES = new Set([
|
|
|
125
125
|
]);
|
|
126
126
|
|
|
127
127
|
export const CHROME_EXECUTABLES = [
|
|
128
|
+
// macOS — Chrome
|
|
128
129
|
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
129
130
|
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
131
|
+
// macOS — Edge
|
|
132
|
+
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
|
133
|
+
// Linux — Chrome
|
|
130
134
|
'/usr/bin/google-chrome',
|
|
131
135
|
'/usr/bin/chromium-browser',
|
|
132
136
|
'/usr/bin/chromium',
|
|
137
|
+
// Linux — Edge
|
|
138
|
+
'/usr/bin/microsoft-edge',
|
|
139
|
+
'/usr/bin/microsoft-edge-stable',
|
|
140
|
+
// Windows — Chrome
|
|
133
141
|
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
134
142
|
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
143
|
+
// Windows — Edge (pre-installed on all Windows 10/11 machines)
|
|
144
|
+
'C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
145
|
+
'C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe',
|
|
135
146
|
];
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// src/commands/browse-action.ts
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { readdir, writeFile, mkdir } from 'node:fs/promises';
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { analyzePageForAction, type AnalyzerPage, readAction } from '../index.js';
|
|
7
|
+
import type { ActionDef } from '../index.js';
|
|
8
|
+
|
|
9
|
+
// Built-in actions (shipped with the CLI) — actual step definitions live in adapters/
|
|
10
|
+
const BUILTIN_ACTIONS: { id: string; platform: string; name: string }[] = [
|
|
11
|
+
{ id: 'linkedin:comment_post', platform: 'linkedin', name: 'Comment on Post' },
|
|
12
|
+
{ id: 'linkedin:like_post', platform: 'linkedin', name: 'Like Post' },
|
|
13
|
+
{ id: 'linkedin:send_connection', platform: 'linkedin', name: 'Send Connection Request' },
|
|
14
|
+
{ id: 'linkedin:publish_post', platform: 'linkedin', name: 'Publish Post' },
|
|
15
|
+
{ id: 'linkedin:keyword_search', platform: 'linkedin', name: 'Keyword Search' },
|
|
16
|
+
{ id: 'instagram:like_post', platform: 'instagram', name: 'Like Post' },
|
|
17
|
+
{ id: 'instagram:comment_post', platform: 'instagram', name: 'Comment on Post' },
|
|
18
|
+
{ id: 'instagram:follow_user', platform: 'instagram', name: 'Follow User' },
|
|
19
|
+
{ id: 'instagram:send_dm', platform: 'instagram', name: 'Send DM' },
|
|
20
|
+
{ id: 'instagram:hashtag_search', platform: 'instagram', name: 'Hashtag Search' },
|
|
21
|
+
{ id: 'x:like_post', platform: 'x', name: 'Like Post' },
|
|
22
|
+
{ id: 'x:reply_post', platform: 'x', name: 'Reply to Post' },
|
|
23
|
+
{ id: 'x:follow_user', platform: 'x', name: 'Follow User' },
|
|
24
|
+
{ id: 'x:publish_post', platform: 'x', name: 'Publish Post' },
|
|
25
|
+
{ id: 'x:keyword_search', platform: 'x', name: 'Keyword Search' },
|
|
26
|
+
{ id: 'gemini:submit_prompt', platform: 'gemini', name: 'Submit Prompt' },
|
|
27
|
+
{ id: 'gemini:extract_response', platform: 'gemini', name: 'Extract Response' },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
async function getCustomActions(): Promise<ActionDef[]> {
|
|
31
|
+
const dir = join(process.cwd(), '.monomind', 'actions');
|
|
32
|
+
if (!existsSync(dir)) return [];
|
|
33
|
+
const files = (await readdir(dir)).filter(f => f.endsWith('.json'));
|
|
34
|
+
const results: ActionDef[] = [];
|
|
35
|
+
for (const f of files) {
|
|
36
|
+
try {
|
|
37
|
+
results.push(await readAction(join(dir, f)));
|
|
38
|
+
} catch {
|
|
39
|
+
// skip malformed action files
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return results;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function createActionCommand(): Command {
|
|
46
|
+
const cmd = new Command('action').description('Manage browser actions');
|
|
47
|
+
|
|
48
|
+
cmd
|
|
49
|
+
.command('build')
|
|
50
|
+
.description('AI-powered: analyze a page and generate an action definition')
|
|
51
|
+
.requiredOption('--url <url>', 'URL to analyze')
|
|
52
|
+
.requiredOption('--task <description>', 'What the action should do')
|
|
53
|
+
.option('--output <file>', 'Output file path (default: .monomind/actions/<id>.json)')
|
|
54
|
+
.action(async (opts: { url: string; task: string; output?: string }) => {
|
|
55
|
+
console.log(`Analyzing ${opts.url} for task: "${opts.task}"`);
|
|
56
|
+
console.log('Opening browser...');
|
|
57
|
+
|
|
58
|
+
let actionDef: ActionDef;
|
|
59
|
+
try {
|
|
60
|
+
// Dynamic import to avoid crashing if CDP is unavailable
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
|
+
const mod = await (import('@monoes/monobrowse' as string) as Promise<any>).catch(() => null);
|
|
63
|
+
const createBrowserPage = mod?.createBrowserPage as ((url: string) => Promise<AnalyzerPage>) | null;
|
|
64
|
+
if (!createBrowserPage) {
|
|
65
|
+
throw new Error('Browser CDP client not available. Ensure Chrome is running with --remote-debugging-port=9222');
|
|
66
|
+
}
|
|
67
|
+
const page = await createBrowserPage(opts.url);
|
|
68
|
+
actionDef = await analyzePageForAction(page, opts.task);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.error(`Action build failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const dir = join(process.cwd(), '.monomind', 'actions');
|
|
75
|
+
await mkdir(dir, { recursive: true });
|
|
76
|
+
const outputPath = opts.output ?? join(dir, `${actionDef.id.replace(':', '-')}.json`);
|
|
77
|
+
await writeFile(outputPath, JSON.stringify(actionDef, null, 2));
|
|
78
|
+
console.log(`\nGenerated action: ${outputPath}`);
|
|
79
|
+
console.log(`Action ID: ${actionDef.id}`);
|
|
80
|
+
console.log(`Steps: ${actionDef.steps.length}`);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
cmd
|
|
84
|
+
.command('run <action-id>')
|
|
85
|
+
.description('Run a single action')
|
|
86
|
+
.requiredOption('--account <user>', 'Account username to use')
|
|
87
|
+
.option('--params <pairs...>', 'Key=value params e.g. --params post_url=https://... text=hello')
|
|
88
|
+
.action(async (actionId: string, opts: { account: string; params?: string[] }) => {
|
|
89
|
+
const params: Record<string, string> = {};
|
|
90
|
+
for (const pair of opts.params ?? []) {
|
|
91
|
+
const eq = pair.indexOf('=');
|
|
92
|
+
if (eq > 0) params[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
93
|
+
}
|
|
94
|
+
console.log(`Running action: ${actionId} with account: ${opts.account}`);
|
|
95
|
+
console.log('Params:', params);
|
|
96
|
+
console.log('(Action runner not yet implemented — use browse playbook run for full execution)');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
cmd
|
|
100
|
+
.command('list')
|
|
101
|
+
.description('List available actions (built-in + custom)')
|
|
102
|
+
.option('--platform <platform>', 'Filter by platform')
|
|
103
|
+
.action(async (opts: { platform?: string }) => {
|
|
104
|
+
const custom = await getCustomActions();
|
|
105
|
+
const all = [
|
|
106
|
+
...BUILTIN_ACTIONS.map(a => ({ ...a, source: 'built-in' })),
|
|
107
|
+
...custom.map(a => ({ id: a.id, platform: a.platform, name: a.name, source: 'custom' })),
|
|
108
|
+
];
|
|
109
|
+
const filtered = opts.platform ? all.filter(a => a.platform === opts.platform) : all;
|
|
110
|
+
if (filtered.length === 0) {
|
|
111
|
+
console.log('No actions found.');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
console.log(`\n${'ID'.padEnd(40)} ${'PLATFORM'.padEnd(12)} ${'NAME'.padEnd(30)} SOURCE`);
|
|
115
|
+
console.log('─'.repeat(90));
|
|
116
|
+
for (const a of filtered) {
|
|
117
|
+
console.log(`${a.id.padEnd(40)} ${a.platform.padEnd(12)} ${a.name.padEnd(30)} ${a.source}`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
cmd
|
|
122
|
+
.command('show <action-id>')
|
|
123
|
+
.description('Print the action definition JSON')
|
|
124
|
+
.action(async (actionId: string) => {
|
|
125
|
+
// Check custom actions first
|
|
126
|
+
const dir = join(process.cwd(), '.monomind', 'actions');
|
|
127
|
+
const fileName = actionId.replace(':', '-') + '.json';
|
|
128
|
+
const customPath = join(dir, fileName);
|
|
129
|
+
if (existsSync(customPath)) {
|
|
130
|
+
const def = await readAction(customPath);
|
|
131
|
+
console.log(JSON.stringify(def, null, 2));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// Check built-ins
|
|
135
|
+
const builtin = BUILTIN_ACTIONS.find(a => a.id === actionId);
|
|
136
|
+
if (builtin) {
|
|
137
|
+
console.log(JSON.stringify({ ...builtin, note: 'Built-in action — steps defined in browser/adapters/' }, null, 2));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
console.error(`Action not found: ${actionId}`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return cmd;
|
|
145
|
+
}
|