Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
51 changes: 51 additions & 0 deletions packages/sdk/examples/stitch-cli/README.md
Original file line number Diff line number Diff line change
@@ -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"}'
```
48 changes: 48 additions & 0 deletions packages/sdk/examples/stitch-cli/SKILL.md
Original file line number Diff line number Diff line change
@@ -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 <command>`
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 '<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 '<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 '<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 <command>` if you are unsure of the required fields.
- Make sure to properly escape your JSON input string on the command line.
231 changes: 231 additions & 0 deletions packages/sdk/examples/stitch-cli/src/cli.ts
Original file line number Diff line number Diff line change
@@ -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 <command> [options]

Commands:
schema <cmd> 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(/<script id="tailwind-config">([\s\S]*?)<\/script>/);

let theme = null;
if (configMatch && configMatch[1]) {
theme = configMatch[1].trim();
}

console.log(
JSON.stringify(
{
theme,
success: true,
},
null,
2,
),
);
} catch (error: any) {
console.error(
JSON.stringify({ error: "Failed to extract theme: " + error.message, success: false })
);
process.exit(1);
}
return;
}

if (command === "export") {
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 || !payload.format) {
console.error(
JSON.stringify({
error: "Missing projectId, screenId, or format in JSON.",
}),
);
process.exit(1);
}

const project = stitch.project(payload.projectId);
let screen;
try {
screen = await project.getScreen(payload.screenId);
} catch (e) {
console.error(JSON.stringify({ error: "Screen ID not found or invalid." }));
process.exit(1);
}

let url: string | undefined;
if (payload.format === "html") {
url = await screen.getHtml();
} else if (payload.format === "image") {
url = await screen.getImage();
} else {
console.error(
JSON.stringify({ error: "Invalid format. Use 'html' or 'image'." }),
);
process.exit(1);
}

console.log(
JSON.stringify(
{
url,
success: true,
},
null,
2,
),
);
return;
}

console.error(`Unknown command: ${command}`);
process.exit(1);
} catch (error: any) {
console.error(
JSON.stringify({
error: error.message || "An unknown error occurred",
success: false,
}),
);
process.exit(1);
}
}

main();
Loading