@dyyz1993/agent-browser 0.9.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/LICENSE +202 -0
- package/README.md +907 -0
- package/bin/agent-browser-darwin-arm64 +0 -0
- package/bin/agent-browser.js +120 -0
- package/dist/__tests__/e2e/utils/test-helpers.d.ts +5 -0
- package/dist/__tests__/e2e/utils/test-helpers.d.ts.map +1 -0
- package/dist/__tests__/e2e/utils/test-helpers.js +22 -0
- package/dist/__tests__/e2e/utils/test-helpers.js.map +1 -0
- package/dist/__tests__/test-iframe.d.ts +2 -0
- package/dist/__tests__/test-iframe.d.ts.map +1 -0
- package/dist/__tests__/test-iframe.js +52 -0
- package/dist/__tests__/test-iframe.js.map +1 -0
- package/dist/__tests__/utils/parseCli.d.ts +20 -0
- package/dist/__tests__/utils/parseCli.d.ts.map +1 -0
- package/dist/__tests__/utils/parseCli.js +1086 -0
- package/dist/__tests__/utils/parseCli.js.map +1 -0
- package/dist/actions.d.ts +50 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +2164 -0
- package/dist/actions.js.map +1 -0
- package/dist/browser.d.ts +556 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +2599 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli/commands.d.ts +8 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +1038 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/connection.d.ts +50 -0
- package/dist/cli/connection.d.ts.map +1 -0
- package/dist/cli/connection.js +595 -0
- package/dist/cli/connection.js.map +1 -0
- package/dist/cli/flags.d.ts +36 -0
- package/dist/cli/flags.d.ts.map +1 -0
- package/dist/cli/flags.js +206 -0
- package/dist/cli/flags.js.map +1 -0
- package/dist/cli/help.d.ts +4 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +1024 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/output.d.ts +14 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +456 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli-new.d.ts +3 -0
- package/dist/cli-new.d.ts.map +1 -0
- package/dist/cli-new.js +308 -0
- package/dist/cli-new.js.map +1 -0
- package/dist/cli-old.d.ts +3 -0
- package/dist/cli-old.d.ts.map +1 -0
- package/dist/cli-old.js +1101 -0
- package/dist/cli-old.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +403 -0
- package/dist/cli.js.map +1 -0
- package/dist/content-detection.d.ts +18 -0
- package/dist/content-detection.d.ts.map +1 -0
- package/dist/content-detection.js +68 -0
- package/dist/content-detection.js.map +1 -0
- package/dist/daemon.d.ts +55 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +426 -0
- package/dist/daemon.js.map +1 -0
- package/dist/diff.d.ts +42 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +166 -0
- package/dist/diff.js.map +1 -0
- package/dist/human-mouse.d.ts +31 -0
- package/dist/human-mouse.d.ts.map +1 -0
- package/dist/human-mouse.js +184 -0
- package/dist/human-mouse.js.map +1 -0
- package/dist/ios-actions.d.ts +11 -0
- package/dist/ios-actions.d.ts.map +1 -0
- package/dist/ios-actions.js +228 -0
- package/dist/ios-actions.js.map +1 -0
- package/dist/ios-manager.d.ts +266 -0
- package/dist/ios-manager.d.ts.map +1 -0
- package/dist/ios-manager.js +1076 -0
- package/dist/ios-manager.js.map +1 -0
- package/dist/message-bridge.d.ts +10 -0
- package/dist/message-bridge.d.ts.map +1 -0
- package/dist/message-bridge.js +60 -0
- package/dist/message-bridge.js.map +1 -0
- package/dist/protocol.d.ts +26 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +912 -0
- package/dist/protocol.js.map +1 -0
- package/dist/recorder/binding.d.ts +24 -0
- package/dist/recorder/binding.d.ts.map +1 -0
- package/dist/recorder/binding.js +215 -0
- package/dist/recorder/binding.js.map +1 -0
- package/dist/recorder/index.d.ts +4 -0
- package/dist/recorder/index.d.ts.map +1 -0
- package/dist/recorder/index.js +4 -0
- package/dist/recorder/index.js.map +1 -0
- package/dist/recorder/inject.js +1913 -0
- package/dist/recorder/recorder.d.ts +19 -0
- package/dist/recorder/recorder.d.ts.map +1 -0
- package/dist/recorder/recorder.js +101 -0
- package/dist/recorder/recorder.js.map +1 -0
- package/dist/recorder/store.d.ts +22 -0
- package/dist/recorder/store.d.ts.map +1 -0
- package/dist/recorder/store.js +150 -0
- package/dist/recorder/store.js.map +1 -0
- package/dist/recorder/types.d.ts +73 -0
- package/dist/recorder/types.d.ts.map +1 -0
- package/dist/recorder/types.js +5 -0
- package/dist/recorder/types.js.map +1 -0
- package/dist/snapshot.d.ts +81 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +1348 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/stream-server-standalone.d.ts +38 -0
- package/dist/stream-server-standalone.d.ts.map +1 -0
- package/dist/stream-server-standalone.js +494 -0
- package/dist/stream-server-standalone.js.map +1 -0
- package/dist/stream-server.d.ts +214 -0
- package/dist/stream-server.d.ts.map +1 -0
- package/dist/stream-server.js +811 -0
- package/dist/stream-server.js.map +1 -0
- package/dist/types.d.ts +914 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/viewer-html.d.ts +2 -0
- package/dist/viewer-html.d.ts.map +1 -0
- package/dist/viewer-html.js +185 -0
- package/dist/viewer-html.js.map +1 -0
- package/dist/viewer-script.d.ts +47 -0
- package/dist/viewer-script.d.ts.map +1 -0
- package/dist/viewer-script.js +586 -0
- package/dist/viewer-script.js.map +1 -0
- package/package.json +86 -0
- package/scripts/build-all-platforms.sh +68 -0
- package/scripts/check-version-sync.js +39 -0
- package/scripts/check_goods_container.js +35 -0
- package/scripts/check_page_content.js +36 -0
- package/scripts/click_applause_rate.js +30 -0
- package/scripts/copy-native.js +36 -0
- package/scripts/copy-recorder.js +21 -0
- package/scripts/e2e-test-recorder.ts +584 -0
- package/scripts/explore_jd_page.js +31 -0
- package/scripts/extract_all_jd_data.js +80 -0
- package/scripts/extract_jd_product_detail.js +62 -0
- package/scripts/extract_jd_products_correct_links.js +78 -0
- package/scripts/extract_jd_products_final.js +80 -0
- package/scripts/extract_jd_reviews.js +48 -0
- package/scripts/extract_jd_seafood_final.js +78 -0
- package/scripts/extract_multiple_products.js +77 -0
- package/scripts/extract_products_no_scroll.js +68 -0
- package/scripts/extract_products_simple.js +68 -0
- package/scripts/find_applause_rate.js +26 -0
- package/scripts/find_jd_links.js +28 -0
- package/scripts/find_main_content.js +20 -0
- package/scripts/find_product_cards.js +38 -0
- package/scripts/find_root_content.js +26 -0
- package/scripts/find_unique_products.js +55 -0
- package/scripts/get_jd_product_detail.js +16 -0
- package/scripts/get_jd_products.js +23 -0
- package/scripts/get_jd_seafood_products.js +44 -0
- package/scripts/get_product_details_from_images.js +54 -0
- package/scripts/postinstall.js +235 -0
- package/scripts/scroll_and_get_products.js +47 -0
- package/scripts/scroll_deep_and_find.js +45 -0
- package/scripts/sync-version.js +69 -0
- package/scripts/verify-baidu-enter.ts +116 -0
- package/skills/agent-browser/SKILL.md +310 -0
- package/skills/agent-browser/references/authentication.md +198 -0
- package/skills/agent-browser/references/commands.md +471 -0
- package/skills/agent-browser/references/data-extraction.md +377 -0
- package/skills/agent-browser/references/proxy-support.md +188 -0
- package/skills/agent-browser/references/session-management.md +197 -0
- package/skills/agent-browser/references/snapshot-refs.md +379 -0
- package/skills/agent-browser/references/video-recording.md +173 -0
- package/skills/agent-browser/templates/api-interception.sh +53 -0
- package/skills/agent-browser/templates/authenticated-session.sh +97 -0
- package/skills/agent-browser/templates/capture-workflow.sh +69 -0
- package/skills/agent-browser/templates/data-extraction.sh +210 -0
- package/skills/agent-browser/templates/form-automation.sh +62 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +356 -0
- package/skills/skill-creator/references/output-patterns.md +82 -0
- package/skills/skill-creator/references/workflows.md +28 -0
- package/skills/skill-creator/scripts/init_skill.py +303 -0
- package/skills/skill-creator/scripts/package_skill.py +113 -0
- package/skills/skill-creator/scripts/quick_validate.py +95 -0
package/dist/daemon.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Set the current session
|
|
3
|
+
*/
|
|
4
|
+
export declare function setSession(session: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Get the current session
|
|
7
|
+
*/
|
|
8
|
+
export declare function getSession(): string;
|
|
9
|
+
/**
|
|
10
|
+
* Get the current instance ID
|
|
11
|
+
*/
|
|
12
|
+
export declare function getInstanceId(): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get the base directory for socket/pid files.
|
|
15
|
+
* Priority: AGENT_BROWSER_SOCKET_DIR > XDG_RUNTIME_DIR > ~/.agent-browser > tmpdir
|
|
16
|
+
*/
|
|
17
|
+
export declare function getAppDir(): string;
|
|
18
|
+
export declare function getSocketDir(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Get the socket path for the current session (Unix) or port (Windows)
|
|
21
|
+
*/
|
|
22
|
+
export declare function getSocketPath(session?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get the port file path for Windows (stores the port number)
|
|
25
|
+
*/
|
|
26
|
+
export declare function getPortFile(session?: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Get the PID file path for the current session
|
|
29
|
+
*/
|
|
30
|
+
export declare function getPidFile(session?: string): string;
|
|
31
|
+
/**
|
|
32
|
+
* Check if daemon is running for the current session
|
|
33
|
+
*/
|
|
34
|
+
export declare function isDaemonRunning(session?: string): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Get connection info for the current session
|
|
37
|
+
* Returns { type: 'unix', path: string } or { type: 'tcp', port: number }
|
|
38
|
+
*/
|
|
39
|
+
export declare function getConnectionInfo(session?: string): {
|
|
40
|
+
type: 'unix';
|
|
41
|
+
path: string;
|
|
42
|
+
} | {
|
|
43
|
+
type: 'tcp';
|
|
44
|
+
port: number;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Clean up socket and PID file for the current session
|
|
48
|
+
*/
|
|
49
|
+
export declare function cleanupSocket(session?: string): void;
|
|
50
|
+
export declare function getStreamPortFile(session?: string): string;
|
|
51
|
+
export declare function getStreamServerPidFile(): string;
|
|
52
|
+
export declare function startDaemon(options?: {
|
|
53
|
+
provider?: string;
|
|
54
|
+
}): Promise<void>;
|
|
55
|
+
//# sourceMappingURL=daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAuBA;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAgBD;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAclC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAMrC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAMtD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAGnD;AAqCD;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAqBzD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,CAAC,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAMhE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAgBpD;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgQhF"}
|
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import * as net from 'net';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
6
|
+
import { BrowserManager } from './browser.js';
|
|
7
|
+
import { IOSManager } from './ios-manager.js';
|
|
8
|
+
import { parseCommand, serializeResponse, errorResponse } from './protocol.js';
|
|
9
|
+
import { executeCommand } from './actions.js';
|
|
10
|
+
import { executeIOSCommand } from './ios-actions.js';
|
|
11
|
+
import { StreamServerProxy, getStreamServerIpcPath } from './stream-server.js';
|
|
12
|
+
const isWindows = process.platform === 'win32';
|
|
13
|
+
let currentSession = process.env.AGENT_BROWSER_SESSION || 'default';
|
|
14
|
+
let currentInstanceId = randomUUID().substring(0, 8);
|
|
15
|
+
let streamServerProxy = null;
|
|
16
|
+
const STREAM_SERVER_PID_FILE = 'stream-server.pid';
|
|
17
|
+
/**
|
|
18
|
+
* Set the current session
|
|
19
|
+
*/
|
|
20
|
+
export function setSession(session) {
|
|
21
|
+
currentSession = session;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get the current session
|
|
25
|
+
*/
|
|
26
|
+
export function getSession() {
|
|
27
|
+
return currentSession;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the current instance ID
|
|
31
|
+
*/
|
|
32
|
+
export function getInstanceId() {
|
|
33
|
+
return currentInstanceId;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get port number for TCP mode (Windows)
|
|
37
|
+
* Uses a hash of the session name to get a consistent port
|
|
38
|
+
*/
|
|
39
|
+
function getPortForSession(session) {
|
|
40
|
+
let hash = 0;
|
|
41
|
+
for (let i = 0; i < session.length; i++) {
|
|
42
|
+
hash = (hash << 5) - hash + session.charCodeAt(i);
|
|
43
|
+
hash |= 0;
|
|
44
|
+
}
|
|
45
|
+
// Port range 49152-65535 (dynamic/private ports)
|
|
46
|
+
return 49152 + (Math.abs(hash) % 16383);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the base directory for socket/pid files.
|
|
50
|
+
* Priority: AGENT_BROWSER_SOCKET_DIR > XDG_RUNTIME_DIR > ~/.agent-browser > tmpdir
|
|
51
|
+
*/
|
|
52
|
+
export function getAppDir() {
|
|
53
|
+
// 1. XDG_RUNTIME_DIR (Linux standard)
|
|
54
|
+
if (process.env.XDG_RUNTIME_DIR) {
|
|
55
|
+
return path.join(process.env.XDG_RUNTIME_DIR, 'agent-browser');
|
|
56
|
+
}
|
|
57
|
+
// 2. Home directory fallback (like Docker Desktop's ~/.docker/run/)
|
|
58
|
+
const homeDir = os.homedir();
|
|
59
|
+
if (homeDir) {
|
|
60
|
+
return path.join(homeDir, '.agent-browser');
|
|
61
|
+
}
|
|
62
|
+
// 3. Last resort: temp dir
|
|
63
|
+
return path.join(os.tmpdir(), 'agent-browser');
|
|
64
|
+
}
|
|
65
|
+
export function getSocketDir() {
|
|
66
|
+
// Allow explicit override for socket directory
|
|
67
|
+
if (process.env.AGENT_BROWSER_SOCKET_DIR) {
|
|
68
|
+
return process.env.AGENT_BROWSER_SOCKET_DIR;
|
|
69
|
+
}
|
|
70
|
+
return getAppDir();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get the socket path for the current session (Unix) or port (Windows)
|
|
74
|
+
*/
|
|
75
|
+
export function getSocketPath(session) {
|
|
76
|
+
const sess = session ?? currentSession;
|
|
77
|
+
if (isWindows) {
|
|
78
|
+
return String(getPortForSession(sess));
|
|
79
|
+
}
|
|
80
|
+
return path.join(getSocketDir(), `${sess}.sock`);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get the port file path for Windows (stores the port number)
|
|
84
|
+
*/
|
|
85
|
+
export function getPortFile(session) {
|
|
86
|
+
const sess = session ?? currentSession;
|
|
87
|
+
return path.join(getSocketDir(), `${sess}.port`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get the PID file path for the current session
|
|
91
|
+
*/
|
|
92
|
+
export function getPidFile(session) {
|
|
93
|
+
const sess = session ?? currentSession;
|
|
94
|
+
return path.join(getSocketDir(), `${sess}.pid`);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Check if daemon socket is ready to accept connections
|
|
98
|
+
*/
|
|
99
|
+
function isDaemonReady(session) {
|
|
100
|
+
const connectionInfo = getConnectionInfo(session);
|
|
101
|
+
try {
|
|
102
|
+
const socket = connectionInfo.type === 'unix'
|
|
103
|
+
? net.createConnection({ path: connectionInfo.path })
|
|
104
|
+
: net.createConnection({ port: connectionInfo.port, host: '127.0.0.1' });
|
|
105
|
+
let connected = false;
|
|
106
|
+
socket.on('connect', () => {
|
|
107
|
+
connected = true;
|
|
108
|
+
socket.destroy();
|
|
109
|
+
});
|
|
110
|
+
socket.on('error', () => {
|
|
111
|
+
socket.destroy();
|
|
112
|
+
});
|
|
113
|
+
// Synchronous check with timeout
|
|
114
|
+
const start = Date.now();
|
|
115
|
+
while (!connected && Date.now() - start < 100) {
|
|
116
|
+
// Wait for connection
|
|
117
|
+
}
|
|
118
|
+
return connected;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Check if daemon is running for the current session
|
|
126
|
+
*/
|
|
127
|
+
export function isDaemonRunning(session) {
|
|
128
|
+
const pidFile = getPidFile(session);
|
|
129
|
+
if (!fs.existsSync(pidFile))
|
|
130
|
+
return false;
|
|
131
|
+
try {
|
|
132
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10);
|
|
133
|
+
// Check if process exists (works on both Unix and Windows)
|
|
134
|
+
process.kill(pid, 0);
|
|
135
|
+
// Also check if socket is actually ready
|
|
136
|
+
if (!isDaemonReady(session)) {
|
|
137
|
+
cleanupSocket(session);
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Process doesn't exist, clean up stale files
|
|
144
|
+
cleanupSocket(session);
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get connection info for the current session
|
|
150
|
+
* Returns { type: 'unix', path: string } or { type: 'tcp', port: number }
|
|
151
|
+
*/
|
|
152
|
+
export function getConnectionInfo(session) {
|
|
153
|
+
const sess = session ?? currentSession;
|
|
154
|
+
if (isWindows) {
|
|
155
|
+
return { type: 'tcp', port: getPortForSession(sess) };
|
|
156
|
+
}
|
|
157
|
+
return { type: 'unix', path: path.join(getSocketDir(), `${sess}.sock`) };
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Clean up socket and PID file for the current session
|
|
161
|
+
*/
|
|
162
|
+
export function cleanupSocket(session) {
|
|
163
|
+
const pidFile = getPidFile(session);
|
|
164
|
+
const streamPortFile = getStreamPortFile(session);
|
|
165
|
+
try {
|
|
166
|
+
if (fs.existsSync(pidFile))
|
|
167
|
+
fs.unlinkSync(pidFile);
|
|
168
|
+
if (fs.existsSync(streamPortFile))
|
|
169
|
+
fs.unlinkSync(streamPortFile);
|
|
170
|
+
if (isWindows) {
|
|
171
|
+
const portFile = getPortFile(session);
|
|
172
|
+
if (fs.existsSync(portFile))
|
|
173
|
+
fs.unlinkSync(portFile);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
const socketPath = getSocketPath(session);
|
|
177
|
+
if (fs.existsSync(socketPath))
|
|
178
|
+
fs.unlinkSync(socketPath);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Ignore cleanup errors
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
export function getStreamPortFile(session) {
|
|
186
|
+
const sess = session ?? currentSession;
|
|
187
|
+
return path.join(getSocketDir(), `${sess}.stream`);
|
|
188
|
+
}
|
|
189
|
+
export function getStreamServerPidFile() {
|
|
190
|
+
return path.join(getSocketDir(), STREAM_SERVER_PID_FILE);
|
|
191
|
+
}
|
|
192
|
+
export async function startDaemon(options) {
|
|
193
|
+
const socketDir = getSocketDir();
|
|
194
|
+
if (!fs.existsSync(socketDir)) {
|
|
195
|
+
fs.mkdirSync(socketDir, { recursive: true });
|
|
196
|
+
}
|
|
197
|
+
cleanupSocket();
|
|
198
|
+
const provider = options?.provider ?? process.env.AGENT_BROWSER_PROVIDER;
|
|
199
|
+
const isIOS = provider === 'ios';
|
|
200
|
+
const manager = isIOS ? new IOSManager() : new BrowserManager();
|
|
201
|
+
let shuttingDown = false;
|
|
202
|
+
if (!isIOS && manager instanceof BrowserManager) {
|
|
203
|
+
const ipcPath = getStreamServerIpcPath();
|
|
204
|
+
if (fs.existsSync(ipcPath)) {
|
|
205
|
+
streamServerProxy = new StreamServerProxy(manager);
|
|
206
|
+
try {
|
|
207
|
+
await streamServerProxy.connect();
|
|
208
|
+
console.log('[Daemon] Connected to Stream Server');
|
|
209
|
+
}
|
|
210
|
+
catch (err) {
|
|
211
|
+
console.error('[Daemon] Failed to connect to Stream Server:', err);
|
|
212
|
+
streamServerProxy = null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
console.log('[Daemon] Stream Server not running, viewer will be unavailable');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const server = net.createServer((socket) => {
|
|
220
|
+
let buffer = '';
|
|
221
|
+
let httpChecked = false;
|
|
222
|
+
socket.on('data', async (data) => {
|
|
223
|
+
buffer += data.toString();
|
|
224
|
+
// Security: Detect and reject HTTP requests to prevent cross-origin attacks.
|
|
225
|
+
// Browsers using fetch() must send HTTP headers (e.g., "POST / HTTP/1.1"),
|
|
226
|
+
// while legitimate clients send raw JSON starting with "{".
|
|
227
|
+
if (!httpChecked) {
|
|
228
|
+
httpChecked = true;
|
|
229
|
+
const trimmed = buffer.trimStart();
|
|
230
|
+
if (/^(GET|POST|PUT|DELETE|HEAD|OPTIONS|PATCH|CONNECT|TRACE)\s/i.test(trimmed)) {
|
|
231
|
+
socket.destroy();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Process complete lines
|
|
236
|
+
while (buffer.includes('\n')) {
|
|
237
|
+
const newlineIdx = buffer.indexOf('\n');
|
|
238
|
+
const line = buffer.substring(0, newlineIdx);
|
|
239
|
+
buffer = buffer.substring(newlineIdx + 1);
|
|
240
|
+
if (!line.trim())
|
|
241
|
+
continue;
|
|
242
|
+
try {
|
|
243
|
+
const parseResult = parseCommand(line);
|
|
244
|
+
if (!parseResult.success) {
|
|
245
|
+
const resp = errorResponse(parseResult.id ?? 'unknown', parseResult.error);
|
|
246
|
+
socket.write(serializeResponse(resp) + '\n');
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
// Handle device_list specially - it works without a session and always uses IOSManager
|
|
250
|
+
if (parseResult.command.action === 'device_list') {
|
|
251
|
+
const iosManager = new IOSManager();
|
|
252
|
+
try {
|
|
253
|
+
const devices = await iosManager.listAllDevices();
|
|
254
|
+
const response = {
|
|
255
|
+
id: parseResult.command.id,
|
|
256
|
+
success: true,
|
|
257
|
+
data: { devices },
|
|
258
|
+
};
|
|
259
|
+
socket.write(serializeResponse(response) + '\n');
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
263
|
+
socket.write(serializeResponse(errorResponse(parseResult.command.id, message)) + '\n');
|
|
264
|
+
}
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
// Auto-launch if not already launched and this isn't a launch/close command
|
|
268
|
+
if (!manager.isLaunched() &&
|
|
269
|
+
parseResult.command.action !== 'launch' &&
|
|
270
|
+
parseResult.command.action !== 'close') {
|
|
271
|
+
if (isIOS && manager instanceof IOSManager) {
|
|
272
|
+
// Auto-launch iOS Safari
|
|
273
|
+
// Check for device in command first (for reused daemons), then fall back to env vars
|
|
274
|
+
const cmd = parseResult.command;
|
|
275
|
+
const iosDevice = cmd.iosDevice || process.env.AGENT_BROWSER_IOS_DEVICE;
|
|
276
|
+
await manager.launch({
|
|
277
|
+
device: iosDevice,
|
|
278
|
+
udid: process.env.AGENT_BROWSER_IOS_UDID,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
else if (manager instanceof BrowserManager) {
|
|
282
|
+
// Auto-launch desktop browser
|
|
283
|
+
const extensions = process.env.AGENT_BROWSER_EXTENSIONS
|
|
284
|
+
? process.env.AGENT_BROWSER_EXTENSIONS.split(',')
|
|
285
|
+
.map((p) => p.trim())
|
|
286
|
+
.filter(Boolean)
|
|
287
|
+
: undefined;
|
|
288
|
+
// Parse args from env (comma or newline separated)
|
|
289
|
+
const argsEnv = process.env.AGENT_BROWSER_ARGS;
|
|
290
|
+
const args = argsEnv
|
|
291
|
+
? argsEnv
|
|
292
|
+
.split(/[,\n]/)
|
|
293
|
+
.map((a) => a.trim())
|
|
294
|
+
.filter((a) => a.length > 0)
|
|
295
|
+
: undefined;
|
|
296
|
+
// Parse proxy from env
|
|
297
|
+
const proxyServer = process.env.AGENT_BROWSER_PROXY;
|
|
298
|
+
const proxyBypass = process.env.AGENT_BROWSER_PROXY_BYPASS;
|
|
299
|
+
const proxy = proxyServer
|
|
300
|
+
? {
|
|
301
|
+
server: proxyServer,
|
|
302
|
+
...(proxyBypass && { bypass: proxyBypass }),
|
|
303
|
+
}
|
|
304
|
+
: undefined;
|
|
305
|
+
const ignoreHTTPSErrors = process.env.AGENT_BROWSER_IGNORE_HTTPS_ERRORS === '1';
|
|
306
|
+
const allowFileAccess = process.env.AGENT_BROWSER_ALLOW_FILE_ACCESS === '1';
|
|
307
|
+
await manager.launch({
|
|
308
|
+
id: 'auto',
|
|
309
|
+
action: 'launch',
|
|
310
|
+
headless: process.env.AGENT_BROWSER_HEADED !== '1',
|
|
311
|
+
executablePath: process.env.AGENT_BROWSER_EXECUTABLE_PATH,
|
|
312
|
+
extensions: extensions,
|
|
313
|
+
profile: process.env.AGENT_BROWSER_PROFILE,
|
|
314
|
+
storageState: process.env.AGENT_BROWSER_STATE,
|
|
315
|
+
args,
|
|
316
|
+
userAgent: process.env.AGENT_BROWSER_USER_AGENT,
|
|
317
|
+
proxy,
|
|
318
|
+
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
|
319
|
+
allowFileAccess: allowFileAccess,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// Handle close command specially - shuts down daemon
|
|
324
|
+
if (parseResult.command.action === 'close') {
|
|
325
|
+
const response = isIOS && manager instanceof IOSManager
|
|
326
|
+
? await executeIOSCommand(parseResult.command, manager)
|
|
327
|
+
: await executeCommand(parseResult.command, manager);
|
|
328
|
+
socket.write(serializeResponse(response) + '\n');
|
|
329
|
+
if (!shuttingDown) {
|
|
330
|
+
shuttingDown = true;
|
|
331
|
+
// 先断开 StreamServer 连接,发送 unregister 消息
|
|
332
|
+
if (streamServerProxy) {
|
|
333
|
+
await streamServerProxy.disconnect();
|
|
334
|
+
streamServerProxy = null;
|
|
335
|
+
}
|
|
336
|
+
setTimeout(() => {
|
|
337
|
+
server.close();
|
|
338
|
+
cleanupSocket();
|
|
339
|
+
process.exit(0);
|
|
340
|
+
}, 100);
|
|
341
|
+
}
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
// Execute command with appropriate handler
|
|
345
|
+
const response = isIOS && manager instanceof IOSManager
|
|
346
|
+
? await executeIOSCommand(parseResult.command, manager)
|
|
347
|
+
: await executeCommand(parseResult.command, manager);
|
|
348
|
+
socket.write(serializeResponse(response) + '\n');
|
|
349
|
+
}
|
|
350
|
+
catch (err) {
|
|
351
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
352
|
+
socket.write(serializeResponse(errorResponse('error', message)) + '\n');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
socket.on('error', () => {
|
|
357
|
+
// Client disconnected, ignore
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
const pidFile = getPidFile();
|
|
361
|
+
// Write PID file before listening
|
|
362
|
+
fs.writeFileSync(pidFile, process.pid.toString());
|
|
363
|
+
if (isWindows) {
|
|
364
|
+
// Windows: use TCP socket on localhost
|
|
365
|
+
const port = getPortForSession(currentSession);
|
|
366
|
+
const portFile = getPortFile();
|
|
367
|
+
fs.writeFileSync(portFile, port.toString());
|
|
368
|
+
server.listen(port, '127.0.0.1', () => {
|
|
369
|
+
// Daemon is ready on TCP port
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
// Unix: use Unix domain socket
|
|
374
|
+
const socketPath = getSocketPath();
|
|
375
|
+
server.listen(socketPath, () => {
|
|
376
|
+
// Daemon is ready
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
server.on('error', (err) => {
|
|
380
|
+
console.error('Server error:', err);
|
|
381
|
+
cleanupSocket();
|
|
382
|
+
process.exit(1);
|
|
383
|
+
});
|
|
384
|
+
const shutdown = async () => {
|
|
385
|
+
if (shuttingDown)
|
|
386
|
+
return;
|
|
387
|
+
shuttingDown = true;
|
|
388
|
+
if (streamServerProxy) {
|
|
389
|
+
await streamServerProxy.disconnect();
|
|
390
|
+
streamServerProxy = null;
|
|
391
|
+
}
|
|
392
|
+
await manager.close();
|
|
393
|
+
server.close();
|
|
394
|
+
cleanupSocket();
|
|
395
|
+
process.exit(0);
|
|
396
|
+
};
|
|
397
|
+
process.on('SIGINT', shutdown);
|
|
398
|
+
process.on('SIGTERM', shutdown);
|
|
399
|
+
process.on('SIGHUP', shutdown);
|
|
400
|
+
// Handle unexpected errors - always cleanup
|
|
401
|
+
process.on('uncaughtException', (err) => {
|
|
402
|
+
console.error('Uncaught exception:', err);
|
|
403
|
+
cleanupSocket();
|
|
404
|
+
process.exit(1);
|
|
405
|
+
});
|
|
406
|
+
process.on('unhandledRejection', (reason) => {
|
|
407
|
+
console.error('Unhandled rejection:', reason);
|
|
408
|
+
cleanupSocket();
|
|
409
|
+
process.exit(1);
|
|
410
|
+
});
|
|
411
|
+
// Cleanup on normal exit
|
|
412
|
+
process.on('exit', () => {
|
|
413
|
+
cleanupSocket();
|
|
414
|
+
});
|
|
415
|
+
// Keep process alive
|
|
416
|
+
process.stdin.resume();
|
|
417
|
+
}
|
|
418
|
+
// Run daemon if this is the entry point
|
|
419
|
+
if (process.argv[1]?.endsWith('daemon.js') || process.env.AGENT_BROWSER_DAEMON === '1') {
|
|
420
|
+
startDaemon().catch((err) => {
|
|
421
|
+
console.error('Daemon error:', err);
|
|
422
|
+
cleanupSocket();
|
|
423
|
+
process.exit(1);
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
package/dist/diff.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Locator, Page, Frame, FrameLocator } from 'playwright-core';
|
|
2
|
+
import type { DiffScope } from './types.js';
|
|
3
|
+
export interface SnapshotDiff {
|
|
4
|
+
added: ElementInfo[];
|
|
5
|
+
removed: ElementInfo[];
|
|
6
|
+
changed: ElementChange[];
|
|
7
|
+
scope: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ElementInfo {
|
|
10
|
+
role: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
value?: string;
|
|
13
|
+
ref?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ElementChange {
|
|
16
|
+
role: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
ref?: string;
|
|
19
|
+
before: {
|
|
20
|
+
value?: string;
|
|
21
|
+
name?: string;
|
|
22
|
+
};
|
|
23
|
+
after: {
|
|
24
|
+
value?: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export interface DiffResult {
|
|
29
|
+
diff: SnapshotDiff;
|
|
30
|
+
output: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function getDiffTarget(locator: Locator, scope: DiffScope): Promise<{
|
|
33
|
+
target: Page | Frame | FrameLocator;
|
|
34
|
+
description: string;
|
|
35
|
+
}>;
|
|
36
|
+
export declare function getSnapshotText(target: Page | Frame | FrameLocator): Promise<string>;
|
|
37
|
+
export declare function parseSnapshot(text: string): Map<number, ElementInfo>;
|
|
38
|
+
export declare function elementsMatch(a: ElementInfo, b: ElementInfo): boolean;
|
|
39
|
+
export declare function computeDiff(beforeText: string, afterText: string): SnapshotDiff;
|
|
40
|
+
export declare function formatDiff(diff: SnapshotDiff): string;
|
|
41
|
+
export declare function performDiff(locator: Locator, scope: DiffScope | undefined, action: () => Promise<void>): Promise<DiffResult | undefined>;
|
|
42
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../src/diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,KAAK,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC;IAAE,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,YAAY,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAUvE;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,IAAI,GAAG,KAAK,GAAG,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1F;AAkCD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAcpE;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,OAAO,CAIrE;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,CAiD/E;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAuCrD;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,SAAS,GAAG,SAAS,EAC5B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAC1B,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CA6BjC"}
|