-
Notifications
You must be signed in to change notification settings - Fork 812
feat(cli): add TypeScript runner with AgentProxy for browser automation #1754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for midscene ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
2632609 to
4045ba2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a TypeScript runner module for the CLI package that enables direct execution of TypeScript automation scripts from the command line. The implementation provides a simplified AgentProxy interface for browser automation with support for both CDP connections and browser launches.
Key changes:
- New ts-runner module with
AgentProxyclass providing simplified browser automation APIs - CLI enhancement to detect and run TypeScript files using tsx
- Support for both imperative (top-level await) and declarative (export-based) script styles
Reviewed changes
Copilot reviewed 15 out of 18 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/cli/bin/midscene | Enhanced CLI entry point to detect and run TypeScript files via tsx |
| packages/cli/src/ts-runner/agent-proxy.ts | Core AgentProxy class implementing browser connection and AI automation methods |
| packages/cli/src/ts-runner/runner.ts | Runner module that loads user scripts and manages agent lifecycle |
| packages/cli/src/ts-runner/types.ts | Type definitions for CDP and Launch configurations |
| packages/cli/src/ts-runner/global.d.ts | Global type declarations for user scripts |
| packages/cli/src/ts-runner/index.ts | Module exports for ts-runner |
| packages/cli/package.json | Added tsx and dotenv as dependencies, configured exports |
| packages/cli/rslib.config.ts | Added build entries for ts-runner modules |
| packages/cli/tsconfig.json | Added path alias and included examples directory |
| packages/cli/examples/*.mts | Example automation scripts demonstrating usage patterns |
| packages/cli/tests/unit-test/ts-runner/*.test.ts | Comprehensive unit tests with 33 test cases |
| pnpm-lock.yaml | Updated lockfile with dotenv version consolidation |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
b986c9e to
d91da44
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 15 out of 18 changed files in this pull request and generated 10 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)
packages/cli/src/ts-runner/runner.ts:61
- The runner.ts module has side effects on import - it immediately sets up process event handlers and calls run() at lines 21-33 and 57-61. This makes the module difficult to test and import safely. The auto-execution at line 57-61 will run whenever this module is imported, even in test environments. Consider separating the side-effect code into a separate entry point or making the module purely functional with explicit initialization.
config();
const agentInstance = new AgentProxy();
(globalThis as any).agent = agentInstance;
export async function cleanup(): Promise<void> {
await agentInstance.destroy().catch(() => {});
}
process.on('beforeExit', cleanup);
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
cleanup().finally(() => process.exit(1));
});
process.on('unhandledRejection', (reason) => {
console.error('Unhandled Rejection:', reason);
cleanup().finally(() => process.exit(1));
});
export async function run(scriptPath?: string): Promise<void> {
const path = scriptPath ?? process.argv[2];
if (!path) {
console.error('Usage: midscene <script.ts>');
process.exit(1);
return; // Required for test mocking where process.exit doesn't terminate
}
const absolutePath = resolve(process.cwd(), path);
const userModule = (await import(absolutePath)) as UserScriptExports;
if (userModule.launch) {
await agentInstance.launch(userModule.launch);
} else if (userModule.cdp) {
await agentInstance.connect(userModule.cdp);
}
if (typeof userModule.run === 'function') {
await userModule.run(agentInstance);
}
}
// Auto-run when executed as entry point
run().catch((error) => {
console.error(error);
process.exit(1);
});
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 15 out of 18 changed files in this pull request and generated 10 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add a new ts-runner module that enables running TypeScript automation scripts directly from the CLI. The AgentProxy class provides a simplified interface for browser automation with CDP connection or browser launch support.
…I automation scripts
- Use synchronous event handlers with .finally() for uncaughtException and unhandledRejection to ensure cleanup completes before exit - Remove unused runnerModule variables in runner.test.ts
- Add cleanup before connect/launch to prevent connection leaks - Add WebSocket URL validation (ws:// or wss://) - Add explicit null check in createAgent instead of non-null assertion - Log errors in cleanup function instead of silent catch - Improve Chrome connection error message with documentation link - Add warning when both launch and cdp exports are present - Add test cases for URL validation and cleanup behavior
…onvention
Users can now call agent.launch() or agent.connect() directly inside
their run function, instead of exporting launch/cdp config separately.
Before:
export const launch = { headed: true };
export async function run(agent) { ... }
After:
export async function run(agent) {
await agent.launch({ headed: true });
...
}
This provides more flexibility and a cleaner API for users.
The run function now uses the global agent variable instead of receiving
it as a parameter. This unifies the API with top-level await style.
Before:
export async function run(agent: AgentProxy) {
await agent.launch({...});
}
After:
export async function run() {
await agent.launch({...}); // uses global agent
}
… scripts and improve error handling in agent connection
Simplified script-basic.mts to only use agent.aiAct() instead of accessing agent.page directly. This prevents "Cannot read properties of undefined" errors in CI when the mock agent doesn't have a page property.
a7bb2b7 to
39ce6a9
Compare
Summary
ts-runnermodule for running TypeScript automation scripts directly from CLIAgentProxyclass providing a simplified interface for browser automationTest plan
pnpm run lint- passes with no errorsmidscene run examples/ai-todo.mts