@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.
Files changed (101) hide show
  1. package/dist/package.json +75 -0
  2. package/dist/src/browser/adapters/index.d.ts.map +1 -1
  3. package/dist/src/browser/adapters/index.js +4 -0
  4. package/dist/src/browser/adapters/index.js.map +1 -1
  5. package/dist/src/browser/browser.js +2 -2
  6. package/dist/src/browser/browser.js.map +1 -1
  7. package/dist/src/browser/cdp.d.ts +6 -0
  8. package/dist/src/browser/cdp.d.ts.map +1 -1
  9. package/dist/src/browser/cdp.js +56 -1
  10. package/dist/src/browser/cdp.js.map +1 -1
  11. package/dist/src/browser/dashboard/api-types.d.ts +1 -1
  12. package/dist/src/browser/dashboard/server.d.ts +1 -1
  13. package/dist/src/browser/dashboard/server.d.ts.map +1 -1
  14. package/dist/src/browser/dashboard/server.js +204 -15
  15. package/dist/src/browser/dashboard/server.js.map +1 -1
  16. package/dist/src/browser/dashboard/ui.html +1811 -0
  17. package/dist/src/browser/playbook/browser-handlers.d.ts +3 -0
  18. package/dist/src/browser/playbook/browser-handlers.d.ts.map +1 -0
  19. package/dist/src/browser/playbook/browser-handlers.js +377 -0
  20. package/dist/src/browser/playbook/browser-handlers.js.map +1 -0
  21. package/dist/src/browser/playbook/builtin-handlers.d.ts +3 -0
  22. package/dist/src/browser/playbook/builtin-handlers.d.ts.map +1 -0
  23. package/dist/src/browser/playbook/builtin-handlers.js +364 -0
  24. package/dist/src/browser/playbook/builtin-handlers.js.map +1 -0
  25. package/dist/src/browser/playbook/index.d.ts +3 -0
  26. package/dist/src/browser/playbook/index.d.ts.map +1 -0
  27. package/dist/src/browser/playbook/index.js +3 -0
  28. package/dist/src/browser/playbook/index.js.map +1 -0
  29. package/dist/src/browser/playbook/store.d.ts +8 -0
  30. package/dist/src/browser/playbook/store.d.ts.map +1 -0
  31. package/dist/src/browser/playbook/store.js +87 -0
  32. package/dist/src/browser/playbook/store.js.map +1 -0
  33. package/dist/src/browser/screenshot.d.ts +2 -0
  34. package/dist/src/browser/screenshot.d.ts.map +1 -1
  35. package/dist/src/browser/screenshot.js +69 -2
  36. package/dist/src/browser/screenshot.js.map +1 -1
  37. package/dist/src/browser/types.d.ts.map +1 -1
  38. package/dist/src/browser/types.js +11 -0
  39. package/dist/src/browser/types.js.map +1 -1
  40. package/dist/src/cli/action.d.ts +3 -0
  41. package/dist/src/cli/action.d.ts.map +1 -0
  42. package/dist/src/cli/action.js +139 -0
  43. package/dist/src/cli/action.js.map +1 -0
  44. package/dist/src/cli/commands.d.ts +8 -0
  45. package/dist/src/cli/commands.d.ts.map +1 -0
  46. package/dist/src/cli/commands.js +3021 -0
  47. package/dist/src/cli/commands.js.map +1 -0
  48. package/dist/src/cli/output.d.ts +11 -0
  49. package/dist/src/cli/output.d.ts.map +1 -0
  50. package/dist/src/cli/output.js +33 -0
  51. package/dist/src/cli/output.js.map +1 -0
  52. package/dist/src/cli/platform.d.ts +7 -0
  53. package/dist/src/cli/platform.d.ts.map +1 -0
  54. package/dist/src/cli/platform.js +193 -0
  55. package/dist/src/cli/platform.js.map +1 -0
  56. package/dist/src/cli/playbook.d.ts +3 -0
  57. package/dist/src/cli/playbook.d.ts.map +1 -0
  58. package/dist/src/cli/playbook.js +265 -0
  59. package/dist/src/cli/playbook.js.map +1 -0
  60. package/dist/src/cli/types.d.ts +42 -0
  61. package/dist/src/cli/types.d.ts.map +1 -0
  62. package/dist/src/cli/types.js +2 -0
  63. package/dist/src/cli/types.js.map +1 -0
  64. package/dist/src/cli/workflow.d.ts +2 -0
  65. package/dist/src/cli/workflow.d.ts.map +1 -0
  66. package/dist/src/cli/workflow.js +3 -0
  67. package/dist/src/cli/workflow.js.map +1 -0
  68. package/dist/src/cli.d.ts +7 -0
  69. package/dist/src/cli.d.ts.map +1 -0
  70. package/dist/src/cli.js +187 -0
  71. package/dist/src/cli.js.map +1 -0
  72. package/dist/src/index.d.ts +5 -1
  73. package/dist/src/index.d.ts.map +1 -1
  74. package/dist/src/index.js +16 -1
  75. package/dist/src/index.js.map +1 -1
  76. package/dist/tsconfig.tsbuildinfo +1 -1
  77. package/package.json +24 -5
  78. package/src/browser/adapters/index.ts +4 -0
  79. package/src/browser/browser.ts +2 -2
  80. package/src/browser/cdp.ts +68 -1
  81. package/src/browser/dashboard/api-types.ts +1 -1
  82. package/src/browser/dashboard/server.ts +210 -17
  83. package/src/browser/dashboard/ui.html +1412 -45
  84. package/src/browser/playbook/browser-handlers.ts +449 -0
  85. package/src/browser/{workflow → playbook}/builtin-handlers.ts +35 -14
  86. package/src/browser/playbook/index.ts +2 -0
  87. package/src/browser/{workflow → playbook}/store.ts +14 -14
  88. package/src/browser/screenshot.ts +78 -3
  89. package/src/browser/types.ts +11 -0
  90. package/src/cli/action.ts +145 -0
  91. package/src/cli/commands.ts +2895 -0
  92. package/src/cli/output.ts +37 -0
  93. package/src/cli/platform.ts +211 -0
  94. package/src/cli/playbook.ts +280 -0
  95. package/src/cli/types.ts +47 -0
  96. package/src/cli.ts +208 -0
  97. package/src/index.ts +20 -1
  98. package/src/browser/workflow/engine.ts +0 -202
  99. package/src/browser/workflow/expression.ts +0 -107
  100. package/src/browser/workflow/index.ts +0 -5
  101. 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
- const result = await client.send<{ data: string }>('Page.captureScreenshot', params, sessionId);
37
- const data = result.data;
38
- const dataUrl = `data:image/${format};base64,${data}`;
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'));
@@ -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
+ }