diff --git a/README.md b/README.md index f4d42e6..55b0798 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Follow @rfgarcia

-A CLI tool to create the scaffolding for a new Kernel applications. This tool helps you get started with building browser automation applications using Kernel's platform. +A CLI tool to create the scaffolding for a new Kernel applications. This tool helps you get started with building browser automation applications using Kernel's platform. ## Features @@ -52,30 +52,36 @@ create-kernel-app [app-name] [options] ### Examples Create a TypeScript application with a sample app: + ```bash npx @onkernel/create-kernel-app my-app --language typescript --template sample-app ``` Create a Typescript application with Stagehand template: + ```bash npx @onkernel/create-kernel-app my-app --language typescript --template stagehand ``` Create a Typescript application with Computer Use template: + ```bash npx @onkernel/create-kernel-app my-app --language typescript --template computer-use ``` Create a Python application with a sample app: + ```bash npx @onkernel/create-kernel-app my-app --language python --template sample-app ``` Create a Python application with Browser Use template: + ```bash npx @onkernel/create-kernel-app my-app --language python --template browser-use ``` -``` + +```` ## Next Steps @@ -84,18 +90,21 @@ After creating your application: 1. Navigate to your project directory: ```bash cd my-app -``` +```` 2. Set up your environment: + - For TypeScript: `npm install` - For Python: `uv venv && source .venv/bin/activate && uv sync` 3. Set your Kernel API key: + ```bash -export KERNEL_API_KEY= +kernel login # or: export KERNEL_API_KEY= ``` 4. Deploy your application: + ```bash # Typscript kernel deploy index.ts # --env OPENAI_API_KEY=XXX if Stagehand; --env ANTHROPIC_API_KEY=XXX if Computer Use @@ -107,6 +116,7 @@ kernel deploy main.py # --env OPENAI_API_KEY=XXX if Browser Use If deploying an app that requires environment variables, make sure to [set them](https://docs.onkernel.com/launch/deploy#environment-variables) when you `deploy`. 5. Invoke your application: + ```bash # Typescript + Sample App kernel invoke ts-basic get-page-title --payload '{"url": "https://www.google.com"}' @@ -134,18 +144,19 @@ kernel invoke python-cua cua-task --payload '{"task": "Get current market price These are the sample apps currently available when you run `npx @onkernel/create-kernel-app`: -| Template | Description | Framework | Query Parameters | -|----------|-------------|-----------|------------------| -| **sample-app** | Returns the page title of a specified URL | Playwright | `{ url }` | -| **browser-use** | Completes a specified task | Browser Use | `{ task }` | -| **stagehand** | Returns the first result of a specified Google search | Stagehand | `{ query }` | -| **advanced-sample** | Implements sample apps using advanced Kernel configs | n/a | -| **computer-use** | Implements a prompt loop | Anthropic Computer Use API | `{ query }` | -| **cua** | Implements the OpenAI Computer Using Agent (CUA) | OpenAI CUA | `{ task }` | +| Template | Description | Framework | Query Parameters | +| ------------------- | ----------------------------------------------------- | -------------------------- | ---------------- | +| **sample-app** | Returns the page title of a specified URL | Playwright | `{ url }` | +| **browser-use** | Completes a specified task | Browser Use | `{ task }` | +| **stagehand** | Returns the first result of a specified Google search | Stagehand | `{ query }` | +| **advanced-sample** | Implements sample apps using advanced Kernel configs | n/a | +| **computer-use** | Implements a prompt loop | Anthropic Computer Use API | `{ query }` | +| **cua** | Implements the OpenAI Computer Using Agent (CUA) | OpenAI CUA | `{ task }` | ## Documentation For more information about Kernel and its features, visit: + - [Kernel Documentation](https://docs.onkernel.com/quickstart) - [Kernel Homepage](https://onkernel.com) @@ -156,4 +167,3 @@ Contributions are welcome! Please feel free to submit a pull request. See [Contr ## License MIT © [Kernel](https://onkernel.com) - diff --git a/index.ts b/index.ts index b4d51f5..0beacdc 100644 --- a/index.ts +++ b/index.ts @@ -66,8 +66,7 @@ const TEMPLATES: Record = { }, [TEMPLATE_ADVANCED_SAMPLE]: { name: "Advanced Samples", - description: - "Implements sample actions with advanced Kernel configs", + description: "Implements sample actions with advanced Kernel configs", languages: [LANGUAGE_TYPESCRIPT, LANGUAGE_PYTHON], }, [TEMPLATE_COMPUTER_USE]: { @@ -91,8 +90,7 @@ const INVOKE_SAMPLES: Record< 'kernel invoke ts-basic get-page-title --payload \'{"url": "https://www.google.com"}\'', [TEMPLATE_STAGEHAND]: 'kernel invoke ts-stagehand stagehand-task --payload \'{"query": "Best wired earbuds"}\'', - [TEMPLATE_ADVANCED_SAMPLE]: - 'kernel invoke ts-advanced test-captcha-solver', + [TEMPLATE_ADVANCED_SAMPLE]: "kernel invoke ts-advanced test-captcha-solver", [TEMPLATE_COMPUTER_USE]: 'kernel invoke ts-cu cu-task --payload \'{"query": "Return the first url of a search result for NYC restaurant reviews Pete Wells"}\'', [TEMPLATE_CUA]: @@ -104,7 +102,7 @@ const INVOKE_SAMPLES: Record< [TEMPLATE_BROWSER_USE]: 'kernel invoke python-bu bu-task --payload \'{"task": "Compare the price of gpt-4o and DeepSeek-V3"}\'', [TEMPLATE_ADVANCED_SAMPLE]: - 'kernel invoke python-advanced test-captcha-solver', + "kernel invoke python-advanced test-captcha-solver", [TEMPLATE_COMPUTER_USE]: 'kernel invoke python-cu cu-task --payload \'{"query": "Return the first url of a search result for NYC restaurant reviews Pete Wells"}\'', [TEMPLATE_CUA]: @@ -117,28 +115,18 @@ const REGISTERED_APP_NAMES: Record< Partial> > = { [LANGUAGE_TYPESCRIPT]: { - [TEMPLATE_SAMPLE_APP]: - 'ts-basic', - [TEMPLATE_STAGEHAND]: - 'ts-stagehand', - [TEMPLATE_ADVANCED_SAMPLE]: - 'ts-advanced', - [TEMPLATE_COMPUTER_USE]: - 'ts-cu', - [TEMPLATE_CUA]: - 'ts-cua', + [TEMPLATE_SAMPLE_APP]: "ts-basic", + [TEMPLATE_STAGEHAND]: "ts-stagehand", + [TEMPLATE_ADVANCED_SAMPLE]: "ts-advanced", + [TEMPLATE_COMPUTER_USE]: "ts-cu", + [TEMPLATE_CUA]: "ts-cua", }, [LANGUAGE_PYTHON]: { - [TEMPLATE_SAMPLE_APP]: - 'python-basic', - [TEMPLATE_BROWSER_USE]: - 'python-bu', - [TEMPLATE_ADVANCED_SAMPLE]: - 'python-advanced', - [TEMPLATE_COMPUTER_USE]: - 'python-cu', - [TEMPLATE_CUA]: - 'python-cua', + [TEMPLATE_SAMPLE_APP]: "python-basic", + [TEMPLATE_BROWSER_USE]: "python-bu", + [TEMPLATE_ADVANCED_SAMPLE]: "python-advanced", + [TEMPLATE_COMPUTER_USE]: "python-cu", + [TEMPLATE_CUA]: "python-cua", }, }; @@ -311,14 +299,14 @@ function copyTemplateFiles( fs.copySync(templatePath, appPath, { filter: (src, dest) => { const filename = path.basename(src); - if (filename === '_gitignore') { + if (filename === "_gitignore") { fs.copyFileSync(src, dest); // Rename it to .gitignore - fs.renameSync(dest, path.join(path.dirname(dest), '.gitignore')); + fs.renameSync(dest, path.join(path.dirname(dest), ".gitignore")); return false; // Skip the original copy since we handled it } return true; // Copy all other files normally - } + }, }); } @@ -363,7 +351,8 @@ function printNextSteps( ): void { // Determine which sample command to show based on language and template const deployCommand = - language === LANGUAGE_TYPESCRIPT && (template === TEMPLATE_SAMPLE_APP || template === TEMPLATE_ADVANCED_SAMPLE) + language === LANGUAGE_TYPESCRIPT && + (template === TEMPLATE_SAMPLE_APP || template === TEMPLATE_ADVANCED_SAMPLE) ? "kernel deploy index.ts" : language === LANGUAGE_TYPESCRIPT && template === TEMPLATE_STAGEHAND ? "kernel deploy index.ts --env OPENAI_API_KEY=XXX" @@ -371,7 +360,9 @@ function printNextSteps( ? "kernel deploy index.ts --env ANTHROPIC_API_KEY=XXX" : language === LANGUAGE_TYPESCRIPT && template === TEMPLATE_CUA ? "kernel deploy index.ts --env OPENAI_API_KEY=XXX" - : language === LANGUAGE_PYTHON && (template === TEMPLATE_SAMPLE_APP || template === TEMPLATE_ADVANCED_SAMPLE) + : language === LANGUAGE_PYTHON && + (template === TEMPLATE_SAMPLE_APP || + template === TEMPLATE_ADVANCED_SAMPLE) ? "kernel deploy main.py" : language === LANGUAGE_PYTHON && template === TEMPLATE_BROWSER_USE ? "kernel deploy main.py --env OPENAI_API_KEY=XXX" @@ -388,11 +379,11 @@ function printNextSteps( Next steps: brew install onkernel/tap/kernel cd ${appName} - export KERNEL_API_KEY= + kernel login # or: export KERNEL_API_KEY= ${deployCommand} ${INVOKE_SAMPLES[language][template]} # Do this in a separate tab - export KERNEL_API_KEY= + kernel login # or: export KERNEL_API_KEY= kernel logs ${REGISTERED_APP_NAMES[language][template]} --follow `) ); diff --git a/templates/python/advanced-sample/main.py b/templates/python/advanced-sample/main.py index 92d8b50..17994cc 100644 --- a/templates/python/advanced-sample/main.py +++ b/templates/python/advanced-sample/main.py @@ -15,7 +15,7 @@ None Invoke this via CLI: - export KERNEL_API_KEY= + kernel login # or: export KERNEL_API_KEY= kernel deploy main.py # If you haven't already deployed this app kernel invoke py-advanced test_captcha_solver kernel logs py-advanced -f # Open in separate tab @@ -36,7 +36,7 @@ async def test_captcha_solver(ctx: kernel.KernelContext) -> None: page = context.pages[0] if context.pages else await context.new_page() # Access the live view. Retrieve this live_view_url from the Kernel logs in your CLI: - # export KERNEL_API_KEY= + # kernel login # or: export KERNEL_API_KEY= # kernel logs py-advanced --follow print("Kernel browser live view url: ", kernel_browser.browser_live_view_url) diff --git a/templates/python/cua/main.py b/templates/python/cua/main.py index 6ec301a..d6f0872 100644 --- a/templates/python/cua/main.py +++ b/templates/python/cua/main.py @@ -15,7 +15,7 @@ Returns: An answer to the task, elapsed time and optionally the messages stack Invoke this via CLI: - export KERNEL_API_KEY= + kernel login # or: export KERNEL_API_KEY= kernel deploy main.py -e OPENAI_API_KEY=XXXXX --force kernel invoke python-cua cua-task -p '{"task":"go to https://news.ycombinator.com and list top 5 articles"}' kernel logs python-cua -f # Open in separate tab diff --git a/templates/python/sample-app/main.py b/templates/python/sample-app/main.py index e27a4c0..6ba3d73 100644 --- a/templates/python/sample-app/main.py +++ b/templates/python/sample-app/main.py @@ -17,7 +17,7 @@ Returns: A dictionary containing the page title Invoke this via CLI: - export KERNEL_API_KEY= + kernel login # or: export KERNEL_API_KEY= kernel deploy main.py # If you haven't already deployed this app kernel invoke python-basic get-page-title -p '{"url": "https://www.google.com"}' kernel logs python-basic -f # Open in separate tab @@ -74,7 +74,7 @@ async def get_page_title(ctx: kernel.KernelContext, input_data: PageTitleInput) Returns: A dictionary containing the browser live view url Invoke this via CLI: - export KERNEL_API_KEY= + kernel login # or: export KERNEL_API_KEY= kernel deploy main.py # If you haven't already deployed this app kernel invoke python-basic create-persisted-browser kernel logs python-basic -f # Open in separate tab diff --git a/templates/typescript/advanced-sample/index.ts b/templates/typescript/advanced-sample/index.ts index c213431..86bd531 100644 --- a/templates/typescript/advanced-sample/index.ts +++ b/templates/typescript/advanced-sample/index.ts @@ -8,20 +8,19 @@ const app = kernel.app("ts-advanced"); /** * Example showing Kernel's auto-CAPTCHA solver * Visit the live view url to see the Kernel browser auto-solve the CAPTCHA on the site - * + * * Args: * ctx: Kernel context containing invocation information * Returns: * None - * + * * Invoke this via CLI: - * export KERNEL_API_KEY= + * kernel login # or: export KERNEL_API_KEY= * kernel deploy index.ts # If you haven't already deployed this app * kernel invoke ts-advanced test-captcha-solver * kernel logs ts-advanced -f # Open in separate tab */ -app.action("test-captcha-solver", async(ctx: KernelContext): Promise => { - +app.action("test-captcha-solver", async (ctx: KernelContext): Promise => { const kernelBrowser = await kernel.browsers.create({ invocation_id: ctx.invocation_id, stealth: true, @@ -32,15 +31,18 @@ app.action("test-captcha-solver", async(ctx: KernelContext): Promise => { const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url); // Access the live view. Retrieve this live_view_url from the Kernel logs in your CLI: - // export KERNEL_API_KEY= + // kernel login # or: export KERNEL_API_KEY= // kernel logs ts-advanced --follow - console.log("Kernel browser live view url: ", kernelBrowser.browser_live_view_url); + console.log( + "Kernel browser live view url: ", + kernelBrowser.browser_live_view_url + ); // Navigate to a site with a CAPTCHA - const context = await browser.contexts()[0] || (await browser.newContext()); - const page = await context.pages()[0] || (await context.newPage()); + const context = browser.contexts()[0] || (await browser.newContext()); + const page = context.pages()[0] || (await context.newPage()); await page.waitForTimeout(10000); // Add a delay to give you time to visit the live view url await page.goto("https://www.google.com/recaptcha/api2/demo"); // Watch Kernel auto-solve the CAPTCHA! await browser.close(); -}); \ No newline at end of file +}); diff --git a/templates/typescript/cua/index.ts b/templates/typescript/cua/index.ts index 4b01c69..b4fc803 100644 --- a/templates/typescript/cua/index.ts +++ b/templates/typescript/cua/index.ts @@ -28,7 +28,7 @@ if (!process.env.OPENAI_API_KEY) { * Returns: * An answer to the task, elapsed time and optionally the messages stack * Invoke this via CLI: - * export KERNEL_API_KEY= + * kernel login # or: export KERNEL_API_KEY= * kernel deploy index.ts -e OPENAI_API_KEY=XXXXX --force * kernel invoke ts-cua cua-task -p "{\"task\":\"current market price range for a used dreamcast\"}" * kernel logs ts-cua -f # Open in separate tab diff --git a/templates/typescript/sample-app/index.ts b/templates/typescript/sample-app/index.ts index 30b9688..c62df63 100644 --- a/templates/typescript/sample-app/index.ts +++ b/templates/typescript/sample-app/index.ts @@ -1,9 +1,9 @@ -import { Kernel, type KernelContext } from '@onkernel/sdk'; -import { chromium } from 'playwright'; +import { Kernel, type KernelContext } from "@onkernel/sdk"; +import { chromium } from "playwright"; const kernel = new Kernel(); -const app = kernel.app('ts-basic'); +const app = kernel.app("ts-basic"); /** * Example app that extracts the title of a webpage @@ -13,7 +13,7 @@ const app = kernel.app('ts-basic'); * Returns: * A dictionary containing the page title * Invoke this via CLI: - * export KERNEL_API_KEY= + * kernel login # or: export KERNEL_API_KEY= * kernel deploy index.ts # If you haven't already deployed this app * kernel invoke ts-basic get-page-title -p '{"url": "https://www.google.com"}' * kernel logs ts-basic -f # Open in separate tab @@ -26,13 +26,19 @@ interface PageTitleOutput { title: string; } app.action( - 'get-page-title', - async (ctx: KernelContext, payload?: PageTitleInput): Promise => { + "get-page-title", + async ( + ctx: KernelContext, + payload?: PageTitleInput + ): Promise => { if (!payload?.url) { - throw new Error('URL is required'); + throw new Error("URL is required"); } - - if (!payload.url.startsWith('http://') && !payload.url.startsWith('https://')) { + + if ( + !payload.url.startsWith("http://") && + !payload.url.startsWith("https://") + ) { payload.url = `https://${payload.url}`; } @@ -47,11 +53,14 @@ app.action( invocation_id: ctx.invocation_id, }); - console.log("Kernel browser live view url: ", kernelBrowser.browser_live_view_url); + console.log( + "Kernel browser live view url: ", + kernelBrowser.browser_live_view_url + ); const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url); - const context = await browser.contexts()[0] || (await browser.newContext()); - const page = await context.pages()[0] || (await context.newPage()); + const context = browser.contexts()[0] || (await browser.newContext()); + const page = context.pages()[0] || (await context.newPage()); try { ////////////////////////////////////// @@ -63,7 +72,7 @@ app.action( } finally { await browser.close(); } - }, + } ); /** @@ -75,7 +84,7 @@ app.action( * Returns: * A dictionary containing the browser live view url * Invoke this via CLI: - * export KERNEL_API_KEY= + * kernel login # or: export KERNEL_API_KEY= * kernel deploy index.ts # If you haven't already deployed this app * kernel invoke ts-basic create-persisted-browser * kernel logs ts-basic -f # Open in separate tab @@ -83,9 +92,9 @@ app.action( interface CreatePersistedBrowserOutput { browser_live_view_url: string; } -app.action("create-persisted-browser", +app.action( + "create-persisted-browser", async (ctx: KernelContext): Promise => { - const kernelBrowser = await kernel.browsers.create({ invocation_id: ctx.invocation_id, persistence: { @@ -98,4 +107,4 @@ app.action("create-persisted-browser", browser_live_view_url: kernelBrowser.browser_live_view_url, }; } -); \ No newline at end of file +);