From d6054d83e3d09b2fd8045ddbc7a641733a3febf9 Mon Sep 17 00:00:00 2001 From: davideast <4570265+davideast@users.noreply.github.com> Date: Thu, 23 Apr 2026 04:14:44 +0000 Subject: [PATCH] feat: implement Stitch CLI agent CLI example Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- packages/sdk/README.md | 7 + packages/sdk/examples/stitch-cli/README.md | 51 +++++ packages/sdk/examples/stitch-cli/SKILL.md | 48 ++++ packages/sdk/examples/stitch-cli/src/cli.ts | 231 ++++++++++++++++++++ 4 files changed, 337 insertions(+) create mode 100644 packages/sdk/examples/stitch-cli/README.md create mode 100644 packages/sdk/examples/stitch-cli/SKILL.md create mode 100644 packages/sdk/examples/stitch-cli/src/cli.ts diff --git a/packages/sdk/README.md b/packages/sdk/README.md index 06bc3b3..4a1a773 100644 --- a/packages/sdk/README.md +++ b/packages/sdk/README.md @@ -110,6 +110,13 @@ await client.close(); The client auto-connects on the first `callTool` or `listTools` call. No explicit `connect()` needed. +## Examples + +The SDK includes several practical examples in the `examples/` directory demonstrating how to use the SDK in different form factors (Scripts, Agent Skills, CLIs, MCP): + +- **[Stitch CLI (Agent CLI)](./examples/stitch-cli/README.md)** - A CLI wrapper around the SDK with `--json` schema introspection designed for LLM agents. +- Basic examples for project and screen management (`get-project.ts`, `generate-screen.ts`, `browse-designs.ts`, etc.). + ## API Reference ### `Stitch` diff --git a/packages/sdk/examples/stitch-cli/README.md b/packages/sdk/examples/stitch-cli/README.md new file mode 100644 index 0000000..d141682 --- /dev/null +++ b/packages/sdk/examples/stitch-cli/README.md @@ -0,0 +1,51 @@ +# Stitch CLI (Agent CLI) + +This example demonstrates how to build an Agent CLI around the Stitch SDK. The CLI provides `--json` inputs and outputs, making it ideal for LLM-driven agents to use programmatically. + +## Prerequisites + +Set your Stitch API key: + +```bash +export STITCH_API_KEY="your-api-key" +``` + +## Running the CLI + +You can run the CLI directly with `bun`: + +```bash +bun src/cli.ts --help +``` + +### Supported Commands + +- `generate`: Generate a new screen in an existing project. +- `export`: Export the HTML or screenshot URL of an existing screen. +- `extract-theme`: Extract the Tailwind CSS theme config from a screen. +- `schema`: Output the expected JSON input schema for agents to read. + +### Agentic Usage (`--json`) + +The CLI is designed to take structured JSON input from agents and return structured JSON output. + +**Schema Introspection:** +An agent can ask for the schema to understand what arguments are expected. +```bash +bun src/cli.ts schema generate +``` + +**Execution:** +```bash +bun src/cli.ts generate --json '{"projectId": "...", "prompt": "A modern dashboard"}' +``` + +**Extracting Theme:** +```bash +bun src/cli.ts extract-theme --json '{"projectId": "...", "screenId": "..."}' +``` + +**Exporting Results:** +```bash +bun src/cli.ts export --json '{"projectId": "...", "screenId": "...", "format": "html"}' +``` diff --git a/packages/sdk/examples/stitch-cli/SKILL.md b/packages/sdk/examples/stitch-cli/SKILL.md new file mode 100644 index 0000000..cbaa188 --- /dev/null +++ b/packages/sdk/examples/stitch-cli/SKILL.md @@ -0,0 +1,48 @@ +# Stitch CLI Skill + +This skill teaches you how to use the `stitch-cli` to interact with the Stitch API. The CLI is designed to take structured JSON input and output JSON, making it ideal for agentic usage. + +## Available Commands + +### 1. `schema ` +Outputs the expected JSON schema for a command. +- `command`: `generate`, `export`, or `extract-theme` + +Example: +```bash +bun src/cli.ts schema generate +``` + +### 2. `generate --json ''` +Generates a new screen in a project. +- Input JSON shape: `{"projectId": "string", "prompt": "string", "deviceType": "MOBILE" | "DESKTOP" | "TABLET" | "AGNOSTIC" (optional)}` +- Returns: JSON object containing the new `screenId`. + +Example: +```bash +bun src/cli.ts generate --json '{"projectId": "123", "prompt": "A simple login form"}' +``` + +### 3. `export --json ''` +Gets the download URL for a screen's HTML or screenshot image. +- Input JSON shape: `{"projectId": "string", "screenId": "string", "format": "html" | "image"}` +- Returns: JSON object containing the download `url`. + +Example: +```bash +bun src/cli.ts export --json '{"projectId": "123", "screenId": "abc", "format": "html"}' +``` + +### 4. `extract-theme --json ''` +Extracts the Tailwind config from a screen's HTML. +- Input JSON shape: `{"projectId": "string", "screenId": "string"}` +- Returns: JSON object containing the `theme` string. + +Example: +```bash +bun src/cli.ts extract-theme --json '{"projectId": "123", "screenId": "abc"}' +``` + +## Agent Best Practices +- Always check the schema using `schema ` if you are unsure of the required fields. +- Make sure to properly escape your JSON input string on the command line. diff --git a/packages/sdk/examples/stitch-cli/src/cli.ts b/packages/sdk/examples/stitch-cli/src/cli.ts new file mode 100644 index 0000000..e1bfad0 --- /dev/null +++ b/packages/sdk/examples/stitch-cli/src/cli.ts @@ -0,0 +1,231 @@ +import { stitch } from "@google/stitch-sdk"; + +async function main() { + const args = process.argv.slice(2); + if (args.length === 0 || args.includes("--help")) { + console.log(` +Stitch CLI (Agent CLI) + +Usage: + bun src/cli.ts [options] + +Commands: + schema Output the JSON schema for a command. (cmd: generate, export, extract-theme) + generate --json Generate a screen. Expects JSON string. + export --json Export a screen URL. Expects JSON string. + extract-theme --json Extract theme from a screen. Expects JSON string. + +Examples: + bun src/cli.ts schema generate + bun src/cli.ts generate --json '{"projectId": "...", "prompt": "..."}' + bun src/cli.ts export --json '{"projectId": "...", "screenId": "...", "format": "html"}' + bun src/cli.ts extract-theme --json '{"projectId": "...", "screenId": "..."}' +`); + return; + } + + const command = args[0]; + + try { + if (command === "schema") { + const subCommand = args[1]; + if (subCommand === "generate") { + console.log( + JSON.stringify( + { + type: "object", + properties: { + projectId: { type: "string" }, + prompt: { type: "string" }, + deviceType: { + type: "string", + enum: ["MOBILE", "DESKTOP", "TABLET", "AGNOSTIC"], + }, + }, + required: ["projectId", "prompt"], + }, + null, + 2, + ), + ); + } else if (subCommand === "extract-theme") { + console.log( + JSON.stringify( + { + type: "object", + properties: { + projectId: { type: "string" }, + screenId: { type: "string" }, + }, + required: ["projectId", "screenId"], + }, + null, + 2, + ), + ); + } else if (subCommand === "export") { + console.log( + JSON.stringify( + { + type: "object", + properties: { + projectId: { type: "string" }, + screenId: { type: "string" }, + format: { type: "string", enum: ["html", "image"] }, + }, + required: ["projectId", "screenId", "format"], + }, + null, + 2, + ), + ); + } else { + console.error("Unknown schema command. Try 'generate', 'export', or 'extract-theme'."); + process.exit(1); + } + return; + } + + if (command === "generate") { + const jsonIndex = args.indexOf("--json"); + if (jsonIndex === -1 || jsonIndex + 1 >= args.length) { + console.error("Missing --json argument."); + process.exit(1); + } + const payload = JSON.parse(args[jsonIndex + 1]); + if (!payload.projectId || !payload.prompt) { + console.error( + JSON.stringify({ error: "Missing projectId or prompt in JSON." }), + ); + process.exit(1); + } + + const project = stitch.project(payload.projectId); + const screen = await project.generate(payload.prompt, payload.deviceType); + + console.log( + JSON.stringify( + { + screenId: screen.id, + projectId: screen.projectId, + success: true, + }, + null, + 2, + ), + ); + return; + } + + + if (command === "extract-theme") { + const jsonIndex = args.indexOf("--json"); + if (jsonIndex === -1 || jsonIndex + 1 >= args.length) { + console.error("Missing --json argument."); + process.exit(1); + } + const payload = JSON.parse(args[jsonIndex + 1]); + if (!payload.projectId || !payload.screenId) { + console.error( + JSON.stringify({ error: "Missing projectId or screenId in JSON." }), + ); + process.exit(1); + } + + try { + const project = stitch.project(payload.projectId); + const screen = await project.getScreen(payload.screenId); + const htmlUrl = await screen.getHtml(); + + const resp = await fetch(htmlUrl); + const html = await resp.text(); + const configMatch = html.match(/