diff --git a/bun.lock b/bun.lock index 72b46b8..5bedb3f 100644 --- a/bun.lock +++ b/bun.lock @@ -35,7 +35,7 @@ }, "packages/core": { "name": "@google/jules-sdk", - "version": "0.1.0", + "version": "0.2.0", "dependencies": { "yaml": "^2.8.2", "zod": "^3.25.76", @@ -52,6 +52,16 @@ "vitest": "^3.2.4", }, }, + "packages/core/examples/cloudflare-workers": { + "name": "cloudflare-workers", + "version": "1.0.0", + "dependencies": { + "@google/jules-sdk": "workspace:*", + }, + "devDependencies": { + "bun-types": "^1.1.8", + }, + }, "packages/core/examples/github-actions": { "name": "jules-github-actions-example", "version": "1.0.0", @@ -79,7 +89,7 @@ }, "packages/fleet": { "name": "@google/jules-fleet", - "version": "0.0.1-experimental.31", + "version": "0.0.1-experimental.32", "bin": { "jules-fleet": "dist/cli/index.mjs", }, @@ -105,7 +115,7 @@ }, "packages/mcp": { "name": "@google/jules-mcp", - "version": "0.1.0", + "version": "0.2.0", "bin": { "jules-mcp": "./dist/cli.mjs", }, @@ -575,6 +585,8 @@ "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "cloudflare-workers": ["cloudflare-workers@workspace:packages/core/examples/cloudflare-workers"], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], @@ -1145,8 +1157,14 @@ "@google/jules-fleet/@google/jules-merge": ["@google/jules-merge@0.0.2", "", { "dependencies": { "@google/jules-sdk": "^0.1.0", "@octokit/auth-app": "^8.2.0", "@octokit/rest": "^21.0.0", "citty": "^0.1.6", "zod": "^3.25.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.1" }, "optionalPeers": ["@modelcontextprotocol/sdk"], "bin": { "jules-merge": "dist/cli/index.mjs" } }, "sha512-VPpbdBt48AbmFByg5RGztv2sQPPJ5fFJARXTvX41lY/b9M+qdyZPp19+ay3qfxEHgj1EvnRMwf/HFOrMMXZ7vQ=="], + "@google/jules-fleet/@google/jules-sdk": ["@google/jules-sdk@0.1.0", "", { "dependencies": { "yaml": "^2.8.2", "zod": "^3.25.76" } }, "sha512-DBVhFOsLfWaVtO0miEeX+zQoazB55EYmK5/0VJSX/YHdeheZqNuPlKRV1vrnd9uSQAtU6ACRicQssMbnvJM6ng=="], + "@google/jules-fleet/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "@google/jules-mcp/@google/jules-sdk": ["@google/jules-sdk@0.1.0", "", { "dependencies": { "yaml": "^2.8.2", "zod": "^3.25.76" } }, "sha512-DBVhFOsLfWaVtO0miEeX+zQoazB55EYmK5/0VJSX/YHdeheZqNuPlKRV1vrnd9uSQAtU6ACRicQssMbnvJM6ng=="], + + "@google/jules-merge/@google/jules-sdk": ["@google/jules-sdk@0.1.0", "", { "dependencies": { "yaml": "^2.8.2", "zod": "^3.25.76" } }, "sha512-DBVhFOsLfWaVtO0miEeX+zQoazB55EYmK5/0VJSX/YHdeheZqNuPlKRV1vrnd9uSQAtU6ACRicQssMbnvJM6ng=="], + "@microsoft/api-extractor/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], "@microsoft/api-extractor/typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], @@ -1251,6 +1269,8 @@ "@actions/github/@octokit/request-error/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + "@google/jules-fleet/@google/jules-merge/@google/jules-sdk": ["@google/jules-sdk@workspace:packages/core"], + "@google/jules-fleet/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], "@google/jules-fleet/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], diff --git a/packages/core/README.md b/packages/core/README.md index c3d32e7..c41cc58 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -7,6 +7,7 @@ Orchestrate complex, long-running coding tasks to an ephemeral cloud environment ## Examples - [Basic Session](./examples/basic-session/README.md) +- [Cloudflare Workers](./examples/cloudflare-workers/README.md) - [Advanced Session](./examples/advanced-session/README.md) - [Agent Workflow](./examples/agent/README.md) - [Webhook Integration](./examples/webhook/README.md) diff --git a/packages/core/examples/cloudflare-workers/README.md b/packages/core/examples/cloudflare-workers/README.md new file mode 100644 index 0000000..c98c10c --- /dev/null +++ b/packages/core/examples/cloudflare-workers/README.md @@ -0,0 +1,34 @@ +# Cloudflare Workers Example + +This example demonstrates how to use the Jules SDK within a Cloudflare Worker environment. By intercepting incoming HTTP `POST` requests, the worker can automatically trigger and orchestrate a new coding session through the `@google/jules-sdk`. + +This is especially useful for edge-based event processing (e.g., handling incoming webhooks from external services like Stripe or GitHub directly at the edge) and kicking off agent workflows globally without dedicated infrastructure. + +## Prerequisites + +- Ensure you have [Bun](https://bun.sh/) installed, or another compatible runtime like Node.js. +- Ensure your `JULES_API_KEY` is set as an environment variable in your local shell or your Cloudflare environment bindings. + +## Running the Example Locally + +The example uses a mocked entry point for the Cloudflare worker module via `index.ts`. To ensure it builds and can run basic checks in the monorepo context: + +1. Build the module: + + ```bash + bun run build + ``` + +2. To run the handler script as a standard Bun process (noting it simulates the Worker `fetch` function structure): + + ```bash + bun run start + ``` + +*(Note: While `bun run start` simply executes `index.ts`, a true worker testing environment typically requires `wrangler` and a test server setup. This simple repository example demonstrates the SDK's structural integration.)* + +## Notes + +- In a real-world Cloudflare deployment, the `JULES_API_KEY` should be set via Cloudflare secrets using `wrangler secret put JULES_API_KEY`. It would be available on the `env` object inside the `fetch` handler. +- If your environment provides the API key via `env.JULES_API_KEY` rather than the global `process.env`, you can customize the instantiation using `jules.with({ apiKey: env.JULES_API_KEY })`. +- Make sure to modify the target `source` in `index.ts` to match the specific GitHub repository or branching strategy your worker intends to automate. diff --git a/packages/core/examples/cloudflare-workers/index.ts b/packages/core/examples/cloudflare-workers/index.ts new file mode 100644 index 0000000..fae8cd8 --- /dev/null +++ b/packages/core/examples/cloudflare-workers/index.ts @@ -0,0 +1,64 @@ +import { jules } from '@google/jules-sdk'; + +/** + * Cloudflare Worker Example + * + * This example demonstrates how to use the Jules SDK within a Cloudflare Worker environment. + * The worker intercepts incoming HTTP POST requests (e.g., a webhook or custom event trigger) + * and starts a new Jules coding session. + */ +export default { + async fetch(request: Request, env: any, ctx: any): Promise { + // Only accept POST requests for this example + if (request.method !== 'POST') { + return new Response('Method Not Allowed. Please send a POST request.', { status: 405 }); + } + + try { + // Parse the incoming JSON payload + const payload = await request.json().catch(() => ({})); + console.log('Received payload:', payload); + + // We can use the global `jules` object since JULES_API_KEY should be passed as an environment variable + // or configured globally in the environment (e.g. via .env in local dev or Cloudflare bindings). + // Note: If JULES_API_KEY is not available globally, you can construct a custom instance + // of Jules SDK using `jules.with({ apiKey: env.JULES_API_KEY })`. + + // Construct a prompt dynamically from the payload + const promptText = `Process this event triggered from a Cloudflare Worker: ${JSON.stringify(payload)}`; + + // Start a Jules session + const session = await jules.session({ + prompt: promptText, + // Define a target source context (replace with your repository/branch as needed) + source: { github: 'davideast/dataprompt', baseBranch: 'main' }, + }); + + console.log(`Successfully created Jules session: ${session.id}`); + + // Return a successful JSON response with the created session ID + return new Response(JSON.stringify({ + success: true, + message: 'Cloudflare Worker processed event and created a session.', + sessionId: session.id, + }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + }, + }); + + } catch (error) { + console.error('Error creating session:', error); + + return new Response(JSON.stringify({ + success: false, + message: 'Internal Server Error while creating Jules session', + error: error instanceof Error ? error.message : String(error) + }), { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }); + } + }, +}; diff --git a/packages/core/examples/cloudflare-workers/package.json b/packages/core/examples/cloudflare-workers/package.json new file mode 100644 index 0000000..b0bd7ca --- /dev/null +++ b/packages/core/examples/cloudflare-workers/package.json @@ -0,0 +1,16 @@ +{ + "name": "cloudflare-workers", + "version": "1.0.0", + "description": "Example demonstrating how to use the Jules SDK within a Cloudflare Worker.", + "main": "index.ts", + "scripts": { + "build": "bun build index.ts --target=node", + "start": "bun run index.ts" + }, + "dependencies": { + "@google/jules-sdk": "workspace:*" + }, + "devDependencies": { + "bun-types": "^1.1.8" + } +} \ No newline at end of file