@_deep4wee/agent-lens 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +141 -31
  2. package/dist/cli.d.mts +2 -1
  3. package/dist/cli.d.ts +2 -1
  4. package/dist/cli.js +1169 -957
  5. package/dist/cli.js.map +1 -1
  6. package/dist/cli.mjs +1268 -974
  7. package/dist/cli.mjs.map +1 -1
  8. package/dist/dsl-BIjVN1M0.d.mts +204 -0
  9. package/dist/dsl-BIjVN1M0.d.ts +204 -0
  10. package/dist/index.d.mts +131 -155
  11. package/dist/index.d.ts +131 -155
  12. package/dist/index.js +1506 -8
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +1479 -3
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/plugins/a11y-tree/index.d.mts +11 -0
  17. package/dist/plugins/a11y-tree/index.d.ts +11 -0
  18. package/dist/plugins/a11y-tree/index.js +190 -0
  19. package/dist/plugins/a11y-tree/index.js.map +1 -0
  20. package/dist/plugins/a11y-tree/index.mjs +155 -0
  21. package/dist/plugins/a11y-tree/index.mjs.map +1 -0
  22. package/dist/plugins/desktop-webview2/index.d.mts +14 -0
  23. package/dist/plugins/desktop-webview2/index.d.ts +14 -0
  24. package/dist/plugins/desktop-webview2/index.js +258 -0
  25. package/dist/plugins/desktop-webview2/index.js.map +1 -0
  26. package/dist/plugins/desktop-webview2/index.mjs +221 -0
  27. package/dist/plugins/desktop-webview2/index.mjs.map +1 -0
  28. package/dist/plugins/live-controller/index.d.mts +35 -0
  29. package/dist/plugins/live-controller/index.d.ts +35 -0
  30. package/dist/plugins/live-controller/index.js +303 -0
  31. package/dist/plugins/live-controller/index.js.map +1 -0
  32. package/dist/plugins/live-controller/index.mjs +261 -0
  33. package/dist/plugins/live-controller/index.mjs.map +1 -0
  34. package/dist/plugins/mock-ipc/index.d.mts +30 -0
  35. package/dist/plugins/mock-ipc/index.d.ts +30 -0
  36. package/dist/plugins/mock-ipc/index.js +210 -0
  37. package/dist/plugins/mock-ipc/index.js.map +1 -0
  38. package/dist/plugins/mock-ipc/index.mjs +181 -0
  39. package/dist/plugins/mock-ipc/index.mjs.map +1 -0
  40. package/dist/plugins/visual-diff/index.d.mts +30 -0
  41. package/dist/plugins/visual-diff/index.d.ts +30 -0
  42. package/dist/plugins/visual-diff/index.js +163 -0
  43. package/dist/plugins/visual-diff/index.js.map +1 -0
  44. package/dist/plugins/visual-diff/index.mjs +127 -0
  45. package/dist/plugins/visual-diff/index.mjs.map +1 -0
  46. package/docs/plugins.md +415 -0
  47. package/package.json +40 -2
  48. package/skills/agent-lens/SKILL.md +142 -37
  49. package/skills/agent-lens/examples/06-state-testing-with-mock-ipc.md +13 -12
  50. package/skills/agent-lens/examples/07-live-controller-interactive-loop.md +108 -0
  51. package/skills/agent-lens/examples/08-accessibility-semantic-inspection.md +80 -0
  52. package/skills/agent-lens/examples/09-visual-regression-and-pixel-diffing.md +66 -0
  53. package/skills/agent-lens/examples/10-authoring-custom-agent-plugins.md +85 -0
  54. package/skills/agent-lens/references/plugin-development.md +165 -0
@@ -0,0 +1,221 @@
1
+ // src/shared/api/plugin.ts
2
+ function definePlugin(plugin) {
3
+ return plugin;
4
+ }
5
+
6
+ // src/plugins/desktop-webview2/driver.ts
7
+ import { spawn } from "child_process";
8
+ import http from "http";
9
+ import path from "path";
10
+ import fs from "fs";
11
+
12
+ // src/shared/lib/playwrightLoader.ts
13
+ import { chromium as baseChromium } from "playwright";
14
+ var chromium = new Proxy(baseChromium, {
15
+ get(target, prop, receiver) {
16
+ if (prop === "launch") {
17
+ return async (...args) => {
18
+ try {
19
+ return await target.launch(...args);
20
+ } catch (err) {
21
+ if (err.message?.includes("Executable doesn't exist") || err.message?.includes("playwright install") || err.message?.includes("browser has not been downloaded")) {
22
+ console.error("\n\u274C [AgentLens] Playwright Chromium browser binary is missing!");
23
+ console.error("\u{1F449} Please install it by running: npx playwright install chromium\n");
24
+ }
25
+ throw err;
26
+ }
27
+ };
28
+ }
29
+ const val = Reflect.get(target, prop, receiver);
30
+ return typeof val === "function" ? val.bind(target) : val;
31
+ }
32
+ });
33
+
34
+ // src/plugins/desktop-webview2/driver.ts
35
+ import treeKill from "tree-kill";
36
+ var DesktopDriver = class {
37
+ port;
38
+ executablePath;
39
+ autoLaunch;
40
+ args;
41
+ env;
42
+ cwd;
43
+ childProcess = null;
44
+ browser = null;
45
+ context = null;
46
+ page = null;
47
+ processStderr = "";
48
+ processExited = false;
49
+ exitCode = null;
50
+ constructor(options) {
51
+ this.port = options?.port || 9222;
52
+ this.autoLaunch = options?.autoLaunch ?? true;
53
+ this.executablePath = options?.executablePath;
54
+ this.args = options?.args || [];
55
+ this.env = options?.env || {};
56
+ this.cwd = options?.cwd;
57
+ }
58
+ async isPortAvailable() {
59
+ return new Promise((resolve) => {
60
+ const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
61
+ resolve(res.statusCode === 200);
62
+ });
63
+ req.on("error", () => resolve(false));
64
+ req.setTimeout(800, () => {
65
+ req.destroy();
66
+ resolve(false);
67
+ });
68
+ });
69
+ }
70
+ async waitForPort(timeoutMs = 25e3) {
71
+ const startTime = Date.now();
72
+ while (Date.now() - startTime < timeoutMs) {
73
+ if (this.processExited) {
74
+ throw new Error(
75
+ `[DesktopDriver] Process terminated prematurely with exit code ${this.exitCode}.
76
+ Stderr: ${this.processStderr.trim() || "(none)"}`
77
+ );
78
+ }
79
+ if (await this.isPortAvailable()) {
80
+ return;
81
+ }
82
+ await new Promise((r) => setTimeout(r, 400));
83
+ }
84
+ throw new Error(
85
+ `Timeout waiting for WebView2/Chromium CDP port ${this.port}. Last stderr:
86
+ ${this.processStderr.trim() || "(no stderr output)"}`
87
+ );
88
+ }
89
+ async start(initialViewport = { width: 1200, height: 800 }) {
90
+ const alreadyRunning = await this.isPortAvailable();
91
+ if (!alreadyRunning) {
92
+ if (!this.autoLaunch) {
93
+ throw new Error(
94
+ `App is not running on port ${this.port} and autoLaunch is false. Start app with WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=${this.port}`
95
+ );
96
+ }
97
+ if (!this.executablePath) {
98
+ throw new Error(
99
+ `[DesktopDriver] No executablePath provided and nothing is running on port ${this.port}. Specify --exe=<path> in CLI or executablePath in config.`
100
+ );
101
+ }
102
+ const resolvedExe = path.resolve(process.cwd(), this.executablePath);
103
+ if (!fs.existsSync(resolvedExe)) {
104
+ throw new Error(
105
+ `[DesktopDriver] Desktop executable not found at: ${resolvedExe}. Please build your native project first.`
106
+ );
107
+ }
108
+ console.log(`\u{1F680} [DesktopDriver] Launching: ${resolvedExe}`);
109
+ const finalArgs = [...this.args];
110
+ const hasDebugPort = finalArgs.some((a) => a.startsWith("--remote-debugging-port="));
111
+ if (!hasDebugPort) {
112
+ finalArgs.push(`--remote-debugging-port=${this.port}`);
113
+ }
114
+ const mergedEnv = {
115
+ ...process.env,
116
+ ...this.env,
117
+ WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS: `--remote-debugging-port=${this.port}`
118
+ };
119
+ this.processStderr = "";
120
+ this.processExited = false;
121
+ this.exitCode = null;
122
+ this.childProcess = spawn(resolvedExe, finalArgs, {
123
+ env: mergedEnv,
124
+ cwd: this.cwd || path.dirname(resolvedExe),
125
+ stdio: ["ignore", "ignore", "pipe"],
126
+ detached: false
127
+ });
128
+ this.childProcess.stderr?.on("data", (chunk) => {
129
+ this.processStderr += chunk.toString();
130
+ });
131
+ this.childProcess.on("exit", (code) => {
132
+ this.processExited = true;
133
+ this.exitCode = code;
134
+ });
135
+ this.childProcess.on("error", (err) => {
136
+ console.error("[DesktopDriver] Failed to spawn process:", err);
137
+ });
138
+ console.log(`\u23F3 [DesktopDriver] Waiting for CDP debugging port on ${this.port}...`);
139
+ await this.waitForPort();
140
+ } else {
141
+ console.log(`\u{1F50C} [DesktopDriver] Attached to already running process on port ${this.port}`);
142
+ }
143
+ console.log(`\u{1F310} [DesktopDriver] Connecting Playwright CDP to http://127.0.0.1:${this.port}...`);
144
+ this.browser = await chromium.connectOverCDP(`http://127.0.0.1:${this.port}`);
145
+ const contexts = this.browser.contexts();
146
+ this.context = contexts[0] || await this.browser.newContext();
147
+ const pages = this.context.pages();
148
+ if (pages.length > 0) {
149
+ this.page = pages[0];
150
+ } else {
151
+ this.page = await this.context.waitForEvent("page", { timeout: 1e4 });
152
+ }
153
+ if (initialViewport) {
154
+ await this.page.setViewportSize(initialViewport).catch(() => {
155
+ });
156
+ }
157
+ return { page: this.page, context: this.context, browser: this.browser };
158
+ }
159
+ async stop() {
160
+ if (this.browser) {
161
+ await this.browser.close().catch(() => {
162
+ });
163
+ this.browser = null;
164
+ }
165
+ if (this.childProcess && !this.childProcess.killed && this.childProcess.pid) {
166
+ console.log("\u{1F6D1} [DesktopDriver] Terminating spawned desktop process tree...");
167
+ const pid = this.childProcess.pid;
168
+ await new Promise((resolve) => {
169
+ treeKill(pid, "SIGTERM", () => resolve());
170
+ });
171
+ this.childProcess = null;
172
+ }
173
+ }
174
+ };
175
+
176
+ // src/plugins/desktop-webview2/index.ts
177
+ var activeDriver = null;
178
+ var desktopWebview2Plugin = definePlugin({
179
+ name: "desktop-webview2",
180
+ version: "1.0.0",
181
+ launchSession: async (options, hookContext) => {
182
+ const cliOpts = hookContext.cliOptions || {};
183
+ const isDesktopMode = hookContext.targetMode === "desktop";
184
+ const hasExe = Boolean(cliOpts.executablePath || cliOpts.exe);
185
+ if (!isDesktopMode && !hasExe) {
186
+ return void 0;
187
+ }
188
+ console.log(`\u{1F50C} [Plugin:desktop-webview2] Initializing native desktop bridge...`);
189
+ const driver = new DesktopDriver({
190
+ executablePath: typeof cliOpts.executablePath === "string" ? cliOpts.executablePath : typeof cliOpts.exe === "string" ? cliOpts.exe : void 0,
191
+ port: typeof cliOpts.port === "number" ? cliOpts.port : 9222,
192
+ autoLaunch: typeof cliOpts.autoLaunchDesktop === "boolean" ? cliOpts.autoLaunchDesktop : true,
193
+ args: Array.isArray(cliOpts.desktopArgs) ? cliOpts.desktopArgs : void 0,
194
+ env: cliOpts.desktopEnv || void 0,
195
+ cwd: typeof cliOpts.startCwd === "string" ? cliOpts.startCwd : void 0
196
+ });
197
+ activeDriver = driver;
198
+ const session = await driver.start(options.currentViewport);
199
+ return {
200
+ page: session.page,
201
+ context: session.context,
202
+ browser: session.browser,
203
+ stop: async () => {
204
+ await driver.stop();
205
+ activeDriver = null;
206
+ }
207
+ };
208
+ },
209
+ teardown: async () => {
210
+ if (activeDriver) {
211
+ await activeDriver.stop();
212
+ activeDriver = null;
213
+ }
214
+ }
215
+ });
216
+ var desktop_webview2_default = desktopWebview2Plugin;
217
+ export {
218
+ desktop_webview2_default as default,
219
+ desktopWebview2Plugin
220
+ };
221
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/shared/api/plugin.ts","../../../src/plugins/desktop-webview2/driver.ts","../../../src/shared/lib/playwrightLoader.ts","../../../src/plugins/desktop-webview2/index.ts"],"sourcesContent":["import type { Page, BrowserContext, Browser } from 'playwright';\nimport type { TestContext, VisualScenario } from './dsl';\nimport type { ReportData } from '../types/report';\n\nexport interface DriverLaunchResult {\n page: Page;\n context: BrowserContext;\n browser?: Browser;\n stop?: () => Promise<void>;\n}\n\nexport interface PluginHookContext {\n scenario?: VisualScenario;\n targetMode: 'desktop' | 'preview' | string;\n artifactsDir: string;\n cliOptions?: Record<string, unknown>;\n state: Map<string, unknown>;\n}\n\nexport interface AgentLensPlugin {\n /** Unique plugin identifier (e.g. 'desktop-webview2', 'live-controller', 'mock-ipc') */\n name: string;\n version?: string;\n\n /** Lifecycle hook: initial setup before drivers and scenarios start */\n setup?: (context: PluginHookContext) => Promise<void> | void;\n\n /**\n * Microkernel driver hook: allows a plugin to provide a custom browser/page session\n * (e.g., desktop WebView2 CDP connection, custom remote browser).\n */\n launchSession?: (\n options: { currentViewport: { width: number; height: number }; headed?: boolean },\n hookContext: PluginHookContext\n ) => Promise<DriverLaunchResult | undefined>;\n\n /** Lifecycle hook: called when browser context is ready */\n onContextCreated?: (context: BrowserContext, hookContext: PluginHookContext) => Promise<void> | void;\n\n /** Lifecycle hook: called when the test page is created/navigated */\n onPageCreated?: (page: Page, context: BrowserContext, hookContext: PluginHookContext) => Promise<void> | void;\n\n /**\n * Context extension: inject custom methods or properties directly into TestContext (ctx)\n */\n extendContext?: (\n ctx: TestContext,\n page: Page,\n hookContext: PluginHookContext\n ) => Record<string, any> | Promise<Record<string, any>>;\n\n /** Lifecycle hook: called after scenario runs and report data is calculated */\n onAfterRun?: (reportData: ReportData, hookContext: PluginHookContext) => Promise<void> | void;\n\n /** Lifecycle hook: teardown and cleanup guaranteed to run */\n teardown?: (hookContext: PluginHookContext) => Promise<void> | void;\n}\n\nexport function definePlugin(plugin: AgentLensPlugin): AgentLensPlugin {\n return plugin;\n}","import { spawn, type ChildProcess } from 'child_process';\nimport http from 'http';\nimport path from 'path';\nimport fs from 'fs';\nimport type { Browser, BrowserContext, Page } from 'playwright';\nimport { chromium } from '../../shared/lib/playwrightLoader';\nimport treeKill from 'tree-kill';\n\nexport interface DesktopDriverOptions {\n port?: number;\n executablePath?: string;\n autoLaunch?: boolean;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\n\nexport class DesktopDriver {\n private port: number;\n private executablePath?: string;\n private autoLaunch: boolean;\n private args: string[];\n private env: Record<string, string>;\n private cwd?: string;\n\n private childProcess: ChildProcess | null = null;\n private browser: Browser | null = null;\n private context: BrowserContext | null = null;\n private page: Page | null = null;\n private processStderr: string = '';\n private processExited: boolean = false;\n private exitCode: number | null = null;\n\n constructor(options?: DesktopDriverOptions) {\n this.port = options?.port || 9222;\n this.autoLaunch = options?.autoLaunch ?? true;\n this.executablePath = options?.executablePath;\n this.args = options?.args || [];\n this.env = options?.env || {};\n this.cwd = options?.cwd;\n }\n\n private async isPortAvailable(): Promise<boolean> {\n return new Promise((resolve) => {\n const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {\n resolve(res.statusCode === 200);\n });\n req.on('error', () => resolve(false));\n req.setTimeout(800, () => {\n req.destroy();\n resolve(false);\n });\n });\n }\n\n private async waitForPort(timeoutMs: number = 25000): Promise<void> {\n const startTime = Date.now();\n while (Date.now() - startTime < timeoutMs) {\n if (this.processExited) {\n throw new Error(\n `[DesktopDriver] Process terminated prematurely with exit code ${this.exitCode}.\\nStderr: ${this.processStderr.trim() || '(none)'}`\n );\n }\n\n if (await this.isPortAvailable()) {\n return;\n }\n await new Promise((r) => setTimeout(r, 400));\n }\n throw new Error(\n `Timeout waiting for WebView2/Chromium CDP port ${this.port}. Last stderr:\\n${this.processStderr.trim() || '(no stderr output)'}`\n );\n }\n\n public async start(initialViewport = { width: 1200, height: 800 }): Promise<{ page: Page; context: BrowserContext; browser: Browser }> {\n const alreadyRunning = await this.isPortAvailable();\n\n if (!alreadyRunning) {\n if (!this.autoLaunch) {\n throw new Error(\n `App is not running on port ${this.port} and autoLaunch is false. Start app with WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=${this.port}`\n );\n }\n\n if (!this.executablePath) {\n throw new Error(\n `[DesktopDriver] No executablePath provided and nothing is running on port ${this.port}. Specify --exe=<path> in CLI or executablePath in config.`\n );\n }\n\n const resolvedExe = path.resolve(process.cwd(), this.executablePath);\n if (!fs.existsSync(resolvedExe)) {\n throw new Error(\n `[DesktopDriver] Desktop executable not found at: ${resolvedExe}. Please build your native project first.`\n );\n }\n\n console.log(`🚀 [DesktopDriver] Launching: ${resolvedExe}`);\n\n const finalArgs = [...this.args];\n const hasDebugPort = finalArgs.some((a) => a.startsWith('--remote-debugging-port='));\n if (!hasDebugPort) {\n finalArgs.push(`--remote-debugging-port=${this.port}`);\n }\n\n const mergedEnv = {\n ...process.env,\n ...this.env,\n WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS: `--remote-debugging-port=${this.port}`\n };\n\n this.processStderr = '';\n this.processExited = false;\n this.exitCode = null;\n\n this.childProcess = spawn(resolvedExe, finalArgs, {\n env: mergedEnv,\n cwd: this.cwd || path.dirname(resolvedExe),\n stdio: ['ignore', 'ignore', 'pipe'],\n detached: false\n });\n\n this.childProcess.stderr?.on('data', (chunk) => {\n this.processStderr += chunk.toString();\n });\n\n this.childProcess.on('exit', (code) => {\n this.processExited = true;\n this.exitCode = code;\n });\n\n this.childProcess.on('error', (err) => {\n console.error('[DesktopDriver] Failed to spawn process:', err);\n });\n\n console.log(`⏳ [DesktopDriver] Waiting for CDP debugging port on ${this.port}...`);\n await this.waitForPort();\n } else {\n console.log(`🔌 [DesktopDriver] Attached to already running process on port ${this.port}`);\n }\n\n console.log(`🌐 [DesktopDriver] Connecting Playwright CDP to http://127.0.0.1:${this.port}...`);\n this.browser = await chromium.connectOverCDP(`http://127.0.0.1:${this.port}`);\n\n const contexts = this.browser.contexts();\n this.context = contexts[0] || (await this.browser.newContext());\n\n const pages = this.context.pages();\n if (pages.length > 0) {\n this.page = pages[0];\n } else {\n this.page = await this.context.waitForEvent('page', { timeout: 10000 });\n }\n\n if (initialViewport) {\n await this.page.setViewportSize(initialViewport).catch(() => {});\n }\n\n return { page: this.page, context: this.context, browser: this.browser };\n }\n\n public async stop(): Promise<void> {\n if (this.browser) {\n await this.browser.close().catch(() => {});\n this.browser = null;\n }\n\n if (this.childProcess && !this.childProcess.killed && this.childProcess.pid) {\n console.log('🛑 [DesktopDriver] Terminating spawned desktop process tree...');\n const pid = this.childProcess.pid;\n await new Promise<void>((resolve) => {\n treeKill(pid, 'SIGTERM', () => resolve());\n });\n this.childProcess = null;\n }\n }\n}\n","import { chromium as baseChromium, type ChromiumBrowser, type BrowserType } from 'playwright';\r\n\r\n/**\r\n * Safe Playwright Chromium loader that wraps browser initialization with helpful diagnostic messages.\r\n */\r\nexport const chromium: BrowserType<ChromiumBrowser> = new Proxy(baseChromium, {\r\n get(target, prop, receiver) {\r\n if (prop === 'launch') {\r\n return async (...args: Parameters<typeof baseChromium.launch>) => {\r\n try {\r\n return await target.launch(...args);\r\n } catch (err: any) {\r\n if (\r\n err.message?.includes(\"Executable doesn't exist\") ||\r\n err.message?.includes('playwright install') ||\r\n err.message?.includes('browser has not been downloaded')\r\n ) {\r\n console.error(\"\\n❌ [AgentLens] Playwright Chromium browser binary is missing!\");\r\n console.error(\"👉 Please install it by running: npx playwright install chromium\\n\");\r\n }\r\n throw err;\r\n }\r\n };\r\n }\r\n const val = Reflect.get(target, prop, receiver);\r\n return typeof val === 'function' ? val.bind(target) : val;\r\n }\r\n});","import { definePlugin, type AgentLensPlugin } from '../../shared/api/plugin';\nimport { DesktopDriver } from './driver';\n\nexport interface DesktopPluginOptions {\n executablePath?: string;\n port?: number;\n autoLaunch?: boolean;\n args?: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\n\nlet activeDriver: DesktopDriver | null = null;\n\nexport const desktopWebview2Plugin: AgentLensPlugin = definePlugin({\n name: 'desktop-webview2',\n version: '1.0.0',\n\n launchSession: async (options, hookContext) => {\n // Only intercept if targetMode is desktop or an executable is explicitly provided\n const cliOpts = hookContext.cliOptions || {};\n const isDesktopMode = hookContext.targetMode === 'desktop';\n const hasExe = Boolean(cliOpts.executablePath || cliOpts.exe);\n\n if (!isDesktopMode && !hasExe) {\n return undefined;\n }\n\n console.log(`🔌 [Plugin:desktop-webview2] Initializing native desktop bridge...`);\n\n const driver = new DesktopDriver({\n executablePath: typeof cliOpts.executablePath === 'string'\n ? cliOpts.executablePath\n : typeof cliOpts.exe === 'string'\n ? cliOpts.exe\n : undefined,\n port: typeof cliOpts.port === 'number' ? cliOpts.port : 9222,\n autoLaunch: typeof cliOpts.autoLaunchDesktop === 'boolean' ? cliOpts.autoLaunchDesktop : true,\n args: Array.isArray(cliOpts.desktopArgs) ? (cliOpts.desktopArgs as string[]) : undefined,\n env: (cliOpts.desktopEnv as Record<string, string>) || undefined,\n cwd: typeof cliOpts.startCwd === 'string' ? cliOpts.startCwd : undefined\n });\n\n activeDriver = driver;\n const session = await driver.start(options.currentViewport);\n\n return {\n page: session.page,\n context: session.context,\n browser: session.browser,\n stop: async () => {\n await driver.stop();\n activeDriver = null;\n }\n };\n },\n\n teardown: async () => {\n if (activeDriver) {\n await activeDriver.stop();\n activeDriver = null;\n }\n }\n});\n\nexport default desktopWebview2Plugin;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,35 @@
1
+ import { A as AgentLensPlugin } from '../../dsl-BIjVN1M0.mjs';
2
+ import { Page } from 'playwright';
3
+
4
+ interface SnapLiveOptions {
5
+ name?: string;
6
+ fullPage?: boolean;
7
+ selector?: string;
8
+ }
9
+ /**
10
+ * Click at physical pixel coordinates on the page (for Vision AI models).
11
+ */
12
+ declare function clickCoords(page: Page, x: number, y: number, options?: {
13
+ button?: 'left' | 'right' | 'middle';
14
+ clickCount?: number;
15
+ }): Promise<void>;
16
+ /**
17
+ * Drag and drop from (fromX, fromY) to (toX, toY).
18
+ */
19
+ declare function dragAndDrop(page: Page, fromX: number, fromY: number, toX: number, toY: number, steps?: number): Promise<void>;
20
+ /**
21
+ * Scroll page by percentage (0 to 100).
22
+ */
23
+ declare function scrollPercent(page: Page, percent: number): Promise<void>;
24
+ /**
25
+ * Capture a live snapshot with optional fullPage (--full) support.
26
+ */
27
+ declare function snapLive(page: Page, options?: SnapLiveOptions): Promise<string>;
28
+ /**
29
+ * Handle CLI commands: live start, click, type, snap, stop
30
+ */
31
+ declare function handleLiveCli(argv: string[]): Promise<boolean>;
32
+
33
+ declare const liveControllerPlugin: AgentLensPlugin;
34
+
35
+ export { type SnapLiveOptions, clickCoords, liveControllerPlugin as default, dragAndDrop, handleLiveCli, liveControllerPlugin, scrollPercent, snapLive };
@@ -0,0 +1,35 @@
1
+ import { A as AgentLensPlugin } from '../../dsl-BIjVN1M0.js';
2
+ import { Page } from 'playwright';
3
+
4
+ interface SnapLiveOptions {
5
+ name?: string;
6
+ fullPage?: boolean;
7
+ selector?: string;
8
+ }
9
+ /**
10
+ * Click at physical pixel coordinates on the page (for Vision AI models).
11
+ */
12
+ declare function clickCoords(page: Page, x: number, y: number, options?: {
13
+ button?: 'left' | 'right' | 'middle';
14
+ clickCount?: number;
15
+ }): Promise<void>;
16
+ /**
17
+ * Drag and drop from (fromX, fromY) to (toX, toY).
18
+ */
19
+ declare function dragAndDrop(page: Page, fromX: number, fromY: number, toX: number, toY: number, steps?: number): Promise<void>;
20
+ /**
21
+ * Scroll page by percentage (0 to 100).
22
+ */
23
+ declare function scrollPercent(page: Page, percent: number): Promise<void>;
24
+ /**
25
+ * Capture a live snapshot with optional fullPage (--full) support.
26
+ */
27
+ declare function snapLive(page: Page, options?: SnapLiveOptions): Promise<string>;
28
+ /**
29
+ * Handle CLI commands: live start, click, type, snap, stop
30
+ */
31
+ declare function handleLiveCli(argv: string[]): Promise<boolean>;
32
+
33
+ declare const liveControllerPlugin: AgentLensPlugin;
34
+
35
+ export { type SnapLiveOptions, clickCoords, liveControllerPlugin as default, dragAndDrop, handleLiveCli, liveControllerPlugin, scrollPercent, snapLive };
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/plugins/live-controller/index.ts
31
+ var live_controller_exports = {};
32
+ __export(live_controller_exports, {
33
+ clickCoords: () => clickCoords,
34
+ default: () => live_controller_default,
35
+ dragAndDrop: () => dragAndDrop,
36
+ handleLiveCli: () => handleLiveCli,
37
+ liveControllerPlugin: () => liveControllerPlugin,
38
+ scrollPercent: () => scrollPercent,
39
+ snapLive: () => snapLive
40
+ });
41
+ module.exports = __toCommonJS(live_controller_exports);
42
+
43
+ // src/shared/api/plugin.ts
44
+ function definePlugin(plugin) {
45
+ return plugin;
46
+ }
47
+
48
+ // src/plugins/live-controller/actions.ts
49
+ var import_path2 = __toESM(require("path"));
50
+
51
+ // src/plugins/live-controller/session.ts
52
+ var import_fs = __toESM(require("fs"));
53
+ var import_path = __toESM(require("path"));
54
+
55
+ // src/shared/lib/playwrightLoader.ts
56
+ var import_playwright = require("playwright");
57
+ var chromium = new Proxy(import_playwright.chromium, {
58
+ get(target, prop, receiver) {
59
+ if (prop === "launch") {
60
+ return async (...args) => {
61
+ try {
62
+ return await target.launch(...args);
63
+ } catch (err) {
64
+ if (err.message?.includes("Executable doesn't exist") || err.message?.includes("playwright install") || err.message?.includes("browser has not been downloaded")) {
65
+ console.error("\n\u274C [AgentLens] Playwright Chromium browser binary is missing!");
66
+ console.error("\u{1F449} Please install it by running: npx playwright install chromium\n");
67
+ }
68
+ throw err;
69
+ }
70
+ };
71
+ }
72
+ const val = Reflect.get(target, prop, receiver);
73
+ return typeof val === "function" ? val.bind(target) : val;
74
+ }
75
+ });
76
+
77
+ // src/plugins/live-controller/session.ts
78
+ var import_tree_kill = __toESM(require("tree-kill"));
79
+ var SESSION_DIR = import_path.default.resolve(process.cwd(), ".agent-lens");
80
+ var SESSION_FILE = import_path.default.join(SESSION_DIR, "live-session.json");
81
+ var LIVE_ARTIFACTS_DIR = import_path.default.resolve(process.cwd(), "artifacts", "live");
82
+ function getLiveArtifactsDir() {
83
+ if (!import_fs.default.existsSync(LIVE_ARTIFACTS_DIR)) {
84
+ import_fs.default.mkdirSync(LIVE_ARTIFACTS_DIR, { recursive: true });
85
+ }
86
+ return LIVE_ARTIFACTS_DIR;
87
+ }
88
+ function readLiveSession() {
89
+ if (!import_fs.default.existsSync(SESSION_FILE)) return null;
90
+ try {
91
+ return JSON.parse(import_fs.default.readFileSync(SESSION_FILE, "utf-8"));
92
+ } catch {
93
+ return null;
94
+ }
95
+ }
96
+ function saveLiveSession(info) {
97
+ if (!import_fs.default.existsSync(SESSION_DIR)) {
98
+ import_fs.default.mkdirSync(SESSION_DIR, { recursive: true });
99
+ }
100
+ import_fs.default.writeFileSync(SESSION_FILE, JSON.stringify(info, null, 2), "utf-8");
101
+ }
102
+ function clearLiveSession() {
103
+ if (import_fs.default.existsSync(SESSION_FILE)) {
104
+ try {
105
+ import_fs.default.unlinkSync(SESSION_FILE);
106
+ } catch {
107
+ }
108
+ }
109
+ }
110
+ async function connectToLiveSession() {
111
+ const session = readLiveSession();
112
+ if (!session) {
113
+ throw new Error(
114
+ `No active live session found. Start one with: npx agent-lens live start --url=http://localhost:5173`
115
+ );
116
+ }
117
+ const browser = await chromium.connectOverCDP(`http://127.0.0.1:${session.port}`);
118
+ const contexts = browser.contexts();
119
+ const context = contexts[0] || await browser.newContext();
120
+ const pages = context.pages();
121
+ const page = pages[0] || await context.waitForEvent("page", { timeout: 5e3 });
122
+ return { browser, context, page };
123
+ }
124
+ async function stopLiveSession() {
125
+ const session = readLiveSession();
126
+ if (!session) {
127
+ console.log(`\u2139\uFE0F [Live] No active session to stop.`);
128
+ return false;
129
+ }
130
+ try {
131
+ const { browser } = await connectToLiveSession();
132
+ await browser.close().catch(() => {
133
+ });
134
+ } catch {
135
+ }
136
+ if (session.pid) {
137
+ await new Promise((resolve) => {
138
+ (0, import_tree_kill.default)(session.pid, "SIGTERM", () => resolve());
139
+ });
140
+ }
141
+ clearLiveSession();
142
+ console.log(`\u{1F6D1} [Live] Session stopped and cleaned up.`);
143
+ return true;
144
+ }
145
+
146
+ // src/plugins/live-controller/actions.ts
147
+ async function clickCoords(page, x, y, options) {
148
+ console.log(`\u{1F5B1}\uFE0F [LiveController] Clicking coordinates: (${x}, ${y})`);
149
+ await page.mouse.click(x, y, options);
150
+ await page.waitForTimeout(200);
151
+ }
152
+ async function dragAndDrop(page, fromX, fromY, toX, toY, steps = 10) {
153
+ console.log(`\u{1F590}\uFE0F [LiveController] Dragging from (${fromX}, ${fromY}) to (${toX}, ${toY}) in ${steps} steps`);
154
+ await page.mouse.move(fromX, fromY);
155
+ await page.mouse.down();
156
+ await page.mouse.move(toX, toY, { steps });
157
+ await page.mouse.up();
158
+ await page.waitForTimeout(200);
159
+ }
160
+ async function scrollPercent(page, percent) {
161
+ const clamped = Math.max(0, Math.min(100, percent));
162
+ console.log(`\u{1F4DC} [LiveController] Scrolling to ${clamped}% of page height`);
163
+ await page.evaluate((pct) => {
164
+ const totalHeight = document.documentElement.scrollHeight - window.innerHeight;
165
+ const targetY = totalHeight * pct / 100;
166
+ window.scrollTo({ top: targetY, behavior: "smooth" });
167
+ }, clamped);
168
+ await page.waitForTimeout(300);
169
+ }
170
+ async function snapLive(page, options) {
171
+ const artifactsDir = getLiveArtifactsDir();
172
+ const fileName = options?.name ? `${options.name}.png` : "current.png";
173
+ const filePath = import_path2.default.join(artifactsDir, fileName);
174
+ if (options?.selector) {
175
+ const el = await page.waitForSelector(options.selector, { timeout: 5e3 });
176
+ await el.screenshot({ path: filePath });
177
+ } else {
178
+ await page.screenshot({ path: filePath, fullPage: options?.fullPage ?? false });
179
+ }
180
+ console.log(`\u{1F4F8} [LiveController] Snapshot saved: ${filePath}${options?.fullPage ? " (Full Page)" : ""}`);
181
+ return filePath;
182
+ }
183
+ async function handleLiveCli(argv) {
184
+ const action = argv[0]?.toLowerCase();
185
+ switch (action) {
186
+ case "start": {
187
+ const urlArg = argv.find((a) => a.startsWith("--url="))?.split("=")[1] || "http://localhost:5173";
188
+ const portArg = parseInt(argv.find((a) => a.startsWith("--port="))?.split("=")[1] || "9223", 10);
189
+ const isHeaded = argv.includes("--headed");
190
+ console.log(`\u{1F680} [Live] Starting background browser for ${urlArg} on CDP port ${portArg}...`);
191
+ const browser = await chromium.launch({
192
+ headless: !isHeaded,
193
+ args: [`--remote-debugging-port=${portArg}`, "--no-sandbox"]
194
+ });
195
+ const context = await browser.newContext({ viewport: { width: 1200, height: 800 } });
196
+ const page = await context.newPage();
197
+ await page.goto(urlArg, { waitUntil: "domcontentloaded" });
198
+ await page.waitForTimeout(500);
199
+ saveLiveSession({
200
+ port: portArg,
201
+ url: urlArg,
202
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
203
+ });
204
+ await snapLive(page, { name: "current" });
205
+ console.log(`\u2705 [Live] Session active! You can now send live commands:
206
+ `);
207
+ console.log(` npx agent-lens live click 450 120`);
208
+ console.log(` npx agent-lens live type "input" "hello"`);
209
+ console.log(` npx agent-lens live snap --full`);
210
+ console.log(` npx agent-lens live stop
211
+ `);
212
+ return true;
213
+ }
214
+ case "click": {
215
+ const { page, browser } = await connectToLiveSession();
216
+ const firstArg = argv[1];
217
+ const secondArg = argv[2];
218
+ const x = parseInt(firstArg, 10);
219
+ const y = parseInt(secondArg, 10);
220
+ if (!isNaN(x) && !isNaN(y)) {
221
+ await clickCoords(page, x, y);
222
+ } else if (firstArg) {
223
+ console.log(`\u{1F5B1}\uFE0F [Live] Clicking selector: "${firstArg}"`);
224
+ await page.click(firstArg);
225
+ } else {
226
+ console.error(`\u274C Usage: npx agent-lens live click <x> <y> OR npx agent-lens live click <selector>`);
227
+ await browser.close();
228
+ return false;
229
+ }
230
+ await snapLive(page, { name: "current" });
231
+ return true;
232
+ }
233
+ case "type": {
234
+ const { page, browser } = await connectToLiveSession();
235
+ const selector = argv[1];
236
+ const text = argv[2];
237
+ if (!selector || text === void 0) {
238
+ console.error(`\u274C Usage: npx agent-lens live type <selector> <text>`);
239
+ await browser.close();
240
+ return false;
241
+ }
242
+ console.log(`\u2328\uFE0F [Live] Typing into "${selector}": "${text}"`);
243
+ await page.fill(selector, text);
244
+ await snapLive(page, { name: "current" });
245
+ return true;
246
+ }
247
+ case "snap": {
248
+ const { page } = await connectToLiveSession();
249
+ const isFull = argv.includes("--full");
250
+ const nameArg = argv.find((a) => !a.startsWith("--") && a !== "snap");
251
+ await snapLive(page, { name: nameArg || "current", fullPage: isFull });
252
+ return true;
253
+ }
254
+ case "stop": {
255
+ return await stopLiveSession();
256
+ }
257
+ default: {
258
+ console.log(`
259
+ \u2139\uFE0F AgentLens Live Controller:
260
+ npx agent-lens live start --url=<url> Start background live session
261
+ npx agent-lens live click <x> <y> Click at pixel coordinates
262
+ npx agent-lens live click <selector> Click CSS selector
263
+ npx agent-lens live type <sel> <text> Fill input field
264
+ npx agent-lens live snap [name] [--full] Capture current or full-page screenshot
265
+ npx agent-lens live stop Close live browser and finish
266
+ `);
267
+ return true;
268
+ }
269
+ }
270
+ }
271
+
272
+ // src/plugins/live-controller/index.ts
273
+ var liveControllerPlugin = definePlugin({
274
+ name: "live-controller",
275
+ version: "1.0.0",
276
+ extendContext: (_ctx, page) => {
277
+ return {
278
+ clickCoords: async (x, y, options) => {
279
+ await clickCoords(page, x, y, options);
280
+ },
281
+ dragAndDrop: async (fromX, fromY, toX, toY, steps) => {
282
+ await dragAndDrop(page, fromX, fromY, toX, toY, steps);
283
+ },
284
+ scrollPercent: async (percent) => {
285
+ await scrollPercent(page, percent);
286
+ },
287
+ snapLive: async (options) => {
288
+ return await snapLive(page, options);
289
+ }
290
+ };
291
+ }
292
+ });
293
+ var live_controller_default = liveControllerPlugin;
294
+ // Annotate the CommonJS export names for ESM import in node:
295
+ 0 && (module.exports = {
296
+ clickCoords,
297
+ dragAndDrop,
298
+ handleLiveCli,
299
+ liveControllerPlugin,
300
+ scrollPercent,
301
+ snapLive
302
+ });
303
+ //# sourceMappingURL=index.js.map