opencodekit 0.18.25 → 0.18.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,307 @@
1
+ /**
2
+ * Stitch Plugin — Google Stitch UI generation as native OpenCode tools.
3
+ *
4
+ * Replaces the MCP subprocess (`npx @_davideast/stitch-mcp proxy`) with
5
+ * direct HTTP via `@google/stitch-sdk`'s `StitchToolClient`.
6
+ *
7
+ * Tools: stitch_create_project, stitch_get_project, stitch_list_projects,
8
+ * stitch_list_screens, stitch_get_screen, stitch_generate_screen,
9
+ * stitch_edit_screens, stitch_generate_variants
10
+ *
11
+ * Auth: Set STITCH_API_KEY env var (API key) or STITCH_ACCESS_TOKEN (OAuth).
12
+ */
13
+
14
+ import { StitchError, StitchToolClient } from "@google/stitch-sdk";
15
+ import type { Plugin } from "@opencode-ai/plugin";
16
+ import { tool } from "@opencode-ai/plugin/tool";
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Shared
20
+ // ---------------------------------------------------------------------------
21
+
22
+ let client: StitchToolClient | null = null;
23
+
24
+ const getClient = (): StitchToolClient => {
25
+ if (!client) {
26
+ client = new StitchToolClient();
27
+ }
28
+ return client;
29
+ };
30
+
31
+ /** Call a Stitch MCP tool and return the result as a JSON string. */
32
+ const callTool = async (
33
+ name: string,
34
+ args: Record<string, unknown>,
35
+ ): Promise<string> => {
36
+ try {
37
+ const result = await getClient().callTool(name, args);
38
+ return JSON.stringify(result, null, 2);
39
+ } catch (err: unknown) {
40
+ if (err instanceof StitchError) {
41
+ return JSON.stringify({
42
+ error: err.code,
43
+ message: err.message,
44
+ ...(err.suggestion ? { suggestion: err.suggestion } : {}),
45
+ recoverable: err.recoverable,
46
+ tool: name,
47
+ });
48
+ }
49
+ return JSON.stringify({
50
+ error: "UNKNOWN_ERROR",
51
+ message: err instanceof Error ? err.message : String(err),
52
+ tool: name,
53
+ });
54
+ }
55
+ };
56
+
57
+ // ---------------------------------------------------------------------------
58
+ // Enums (for agent guidance — not strict validation)
59
+ // ---------------------------------------------------------------------------
60
+
61
+ const DEVICE_TYPES = [
62
+ "DEVICE_TYPE_UNSPECIFIED",
63
+ "MOBILE",
64
+ "DESKTOP",
65
+ "TABLET",
66
+ "AGNOSTIC",
67
+ ] as const;
68
+
69
+ const MODEL_IDS = [
70
+ "MODEL_ID_UNSPECIFIED",
71
+ "GEMINI_3_PRO",
72
+ "GEMINI_3_FLASH",
73
+ ] as const;
74
+
75
+ // ---------------------------------------------------------------------------
76
+ // Plugin
77
+ // ---------------------------------------------------------------------------
78
+
79
+ export const StitchPlugin: Plugin = async () => {
80
+ return {
81
+ tool: {
82
+ // ---------------------------------------------------------------
83
+ // Projects
84
+ // ---------------------------------------------------------------
85
+
86
+ stitch_create_project: tool({
87
+ description:
88
+ "Create a new Google Stitch project.\n\nOptionally provide a title.",
89
+ args: {
90
+ title: tool.schema
91
+ .string()
92
+ .optional()
93
+ .describe("Project title (optional)"),
94
+ },
95
+ async execute(args: { title?: string }) {
96
+ return callTool("create_project", args);
97
+ },
98
+ }),
99
+
100
+ stitch_get_project: tool({
101
+ description:
102
+ "Get details of a Stitch project by resource name.\n\nFormat: projects/{projectId}",
103
+ args: {
104
+ name: tool.schema
105
+ .string()
106
+ .describe(
107
+ "Project resource name (e.g. projects/abc123). Required.",
108
+ ),
109
+ },
110
+ async execute(args: { name: string }) {
111
+ return callTool("get_project", args);
112
+ },
113
+ }),
114
+
115
+ stitch_list_projects: tool({
116
+ description: "List all Stitch projects. Optionally filter by keyword.",
117
+ args: {
118
+ filter: tool.schema
119
+ .string()
120
+ .optional()
121
+ .describe("Filter string (optional)"),
122
+ },
123
+ async execute(args: { filter?: string }) {
124
+ return callTool("list_projects", args);
125
+ },
126
+ }),
127
+
128
+ // ---------------------------------------------------------------
129
+ // Screens
130
+ // ---------------------------------------------------------------
131
+
132
+ stitch_list_screens: tool({
133
+ description:
134
+ "List all screens in a Stitch project.\n\nRequires projectId.",
135
+ args: {
136
+ projectId: tool.schema.string().describe("Project ID. Required."),
137
+ },
138
+ async execute(args: { projectId: string }) {
139
+ return callTool("list_screens", args);
140
+ },
141
+ }),
142
+
143
+ stitch_get_screen: tool({
144
+ description:
145
+ "Get screen details including HTML code.\n\nProvide the screen resource name (format: projects/{projectId}/screens/{screenId}).",
146
+ args: {
147
+ name: tool.schema
148
+ .string()
149
+ .describe(
150
+ "Screen resource name (e.g. projects/abc/screens/xyz). Required.",
151
+ ),
152
+ },
153
+ async execute(args: { name: string }) {
154
+ return callTool("get_screen", args);
155
+ },
156
+ }),
157
+
158
+ // ---------------------------------------------------------------
159
+ // Generation
160
+ // ---------------------------------------------------------------
161
+
162
+ stitch_generate_screen: tool({
163
+ description: `Generate a UI screen from a text prompt.
164
+
165
+ Device types: ${DEVICE_TYPES.join(", ")}
166
+ Model IDs: ${MODEL_IDS.join(", ")}`,
167
+ args: {
168
+ projectId: tool.schema.string().describe("Project ID. Required."),
169
+ prompt: tool.schema
170
+ .string()
171
+ .describe("Text description of the UI to generate. Required."),
172
+ deviceType: tool.schema
173
+ .string()
174
+ .optional()
175
+ .describe(
176
+ `Device type: ${DEVICE_TYPES.join(" | ")} (default: MOBILE)`,
177
+ ),
178
+ modelId: tool.schema
179
+ .string()
180
+ .optional()
181
+ .describe(
182
+ `Model: ${MODEL_IDS.join(" | ")} (default: GEMINI_3_FLASH)`,
183
+ ),
184
+ },
185
+ async execute(args: {
186
+ projectId: string;
187
+ prompt: string;
188
+ deviceType?: string;
189
+ modelId?: string;
190
+ }) {
191
+ return callTool("generate_screen_from_text", args);
192
+ },
193
+ }),
194
+
195
+ stitch_edit_screens: tool({
196
+ description: `Edit existing screens with a text prompt.
197
+
198
+ Device types: ${DEVICE_TYPES.join(", ")}
199
+ Model IDs: ${MODEL_IDS.join(", ")}`,
200
+ args: {
201
+ projectId: tool.schema.string().describe("Project ID. Required."),
202
+ selectedScreenIds: tool.schema
203
+ .array(tool.schema.string())
204
+ .describe("Screen IDs to edit. Required."),
205
+ prompt: tool.schema.string().describe("Edit instructions. Required."),
206
+ deviceType: tool.schema
207
+ .string()
208
+ .optional()
209
+ .describe(
210
+ `Device type: ${DEVICE_TYPES.join(" | ")} (default: MOBILE)`,
211
+ ),
212
+ modelId: tool.schema
213
+ .string()
214
+ .optional()
215
+ .describe(
216
+ `Model: ${MODEL_IDS.join(" | ")} (default: GEMINI_3_FLASH)`,
217
+ ),
218
+ },
219
+ async execute(args: {
220
+ projectId: string;
221
+ selectedScreenIds: string[];
222
+ prompt: string;
223
+ deviceType?: string;
224
+ modelId?: string;
225
+ }) {
226
+ return callTool("edit_screens", args);
227
+ },
228
+ }),
229
+
230
+ stitch_generate_variants: tool({
231
+ description: `Generate design variants of existing screens.
232
+
233
+ variantOptions:
234
+ - variantCount: number of variants (1-10)
235
+ - creativeRange: LOW, MEDIUM, HIGH (how different from original)
236
+ - aspects: optional comma-separated aspects to vary (e.g. "color,layout")
237
+
238
+ Device types: ${DEVICE_TYPES.join(", ")}
239
+ Model IDs: ${MODEL_IDS.join(", ")}`,
240
+ args: {
241
+ projectId: tool.schema.string().describe("Project ID. Required."),
242
+ selectedScreenIds: tool.schema
243
+ .array(tool.schema.string())
244
+ .describe("Screen IDs to create variants of. Required."),
245
+ prompt: tool.schema
246
+ .string()
247
+ .describe("Prompt describing desired variations. Required."),
248
+ variantCount: tool.schema
249
+ .number()
250
+ .optional()
251
+ .describe("Number of variants to generate (1-10, default: 3)"),
252
+ creativeRange: tool.schema
253
+ .string()
254
+ .optional()
255
+ .describe("Creative range: LOW | MEDIUM | HIGH (default: MEDIUM)"),
256
+ aspects: tool.schema
257
+ .string()
258
+ .optional()
259
+ .describe(
260
+ "Comma-separated aspects to vary (e.g. 'color,layout'). Optional.",
261
+ ),
262
+ deviceType: tool.schema
263
+ .string()
264
+ .optional()
265
+ .describe(
266
+ `Device type: ${DEVICE_TYPES.join(" | ")} (default: MOBILE)`,
267
+ ),
268
+ modelId: tool.schema
269
+ .string()
270
+ .optional()
271
+ .describe(
272
+ `Model: ${MODEL_IDS.join(" | ")} (default: GEMINI_3_FLASH)`,
273
+ ),
274
+ },
275
+ async execute(args: {
276
+ projectId: string;
277
+ selectedScreenIds: string[];
278
+ prompt: string;
279
+ variantCount?: number;
280
+ creativeRange?: string;
281
+ aspects?: string;
282
+ deviceType?: string;
283
+ modelId?: string;
284
+ }) {
285
+ // Build variantOptions object from flat args
286
+ const variantOptions: Record<string, unknown> = {};
287
+ if (args.variantCount != null)
288
+ variantOptions.variantCount = args.variantCount;
289
+ if (args.creativeRange)
290
+ variantOptions.creativeRange = args.creativeRange;
291
+ if (args.aspects) variantOptions.aspects = args.aspects;
292
+
293
+ return callTool("generate_variants", {
294
+ projectId: args.projectId,
295
+ selectedScreenIds: args.selectedScreenIds,
296
+ prompt: args.prompt,
297
+ variantOptions,
298
+ ...(args.deviceType ? { deviceType: args.deviceType } : {}),
299
+ ...(args.modelId ? { modelId: args.modelId } : {}),
300
+ });
301
+ },
302
+ }),
303
+ },
304
+ };
305
+ };
306
+
307
+ export default StitchPlugin;
@@ -1,31 +1,24 @@
1
1
  ---
2
2
  name: stitch
3
- description: Google Stitch MCP for AI-powered UI design. Extract design context, generate code from designs, and create screens from descriptions. Use when working with Stitch designs and UI generation.
4
- version: 1.0.0
5
- tags: [design, mcp, ui]
3
+ description: Google Stitch UI generation via native plugin. Generate screens from text, edit designs, create variants. Use when working with Stitch designs and UI generation.
4
+ version: 2.0.0
5
+ tags: [design, ui, stitch]
6
6
  dependencies: []
7
7
  ---
8
8
 
9
- # Google Stitch MCP
9
+ # Google Stitch Plugin
10
10
 
11
11
  ## When to Use
12
12
 
13
- - When you need to generate or inspect Google Stitch UI designs via MCP.
13
+ - When you need to generate or inspect Google Stitch UI designs.
14
14
 
15
15
  ## When NOT to Use
16
16
 
17
17
  - When you don't have Stitch access or don't need Stitch-generated UI.
18
18
 
19
-
20
19
  ## Overview
21
20
 
22
- Stitch MCP is Google's official Model Context Protocol server for interacting with Google Stitch designs. It allows AI agents to extract design context (colors, typography, spacing), generate production-ready code from designs, and create new designs from text descriptions.
23
-
24
- ## Endpoint
25
-
26
- **MCP Server URL**: `https://stitch.googleapis.com/mcp`
27
-
28
- **Authentication**: Google Cloud credentials with Bearer token and project ID header
21
+ Stitch tools are registered as native OpenCode tools via the Stitch plugin (`.opencode/plugin/stitch.ts`), using `@google/stitch-sdk` for direct HTTP to `stitch.googleapis.com/mcp`. No MCP subprocess needed.
29
22
 
30
23
  ## Prerequisites
31
24
 
@@ -40,49 +33,41 @@ Stitch MCP is Google's official Model Context Protocol server for interacting wi
40
33
  ### 1. Enable Stitch API in Google Cloud
41
34
 
42
35
  ```bash
43
- # Set your Google Cloud project
44
36
  gcloud config set project PROJECT_ID
45
-
46
- # Enable the Stitch MCP service
47
37
  gcloud beta services mcp enable stitch.googleapis.com --project=PROJECT_ID
48
38
  ```
49
39
 
50
- ### 2. Get Your Access Token
40
+ ### 2. Set Environment Variables
51
41
 
52
- ```bash
53
- # Authenticate with Google Cloud
54
- gcloud auth login
42
+ **API Key auth** (recommended):
55
43
 
56
- # Get your access token
57
- gcloud auth print-access-token
44
+ ```bash
45
+ export STITCH_API_KEY="your-api-key"
58
46
  ```
59
47
 
60
- ### 3. Set Environment Variables
48
+ **Or OAuth auth**:
61
49
 
62
50
  ```bash
63
- # Set your Google Cloud project ID
64
- export GOOGLE_CLOUD_PROJECT="your-project-id"
65
-
66
- # Get and set your access token
67
51
  export STITCH_ACCESS_TOKEN=$(gcloud auth print-access-token)
52
+ export GOOGLE_CLOUD_PROJECT="your-project-id"
68
53
  ```
69
54
 
70
- ### 4. Configuration
55
+ ### 3. Restart OpenCode
71
56
 
72
- Stitch MCP is pre-configured in `opencode.json` as a default MCP server. Once environment variables are set, restart OpenCode and the tools will be available.
57
+ Tools are available immediately after env vars are set and OpenCode restarts.
73
58
 
74
59
  ## Available Tools
75
60
 
76
- Once configured, the Stitch MCP exposes the following tools:
77
-
78
- | Tool | Description |
79
- | ---------------------------------- | --------------------------------- |
80
- | `stitch_list_projects` | List all your Stitch projects |
81
- | `stitch_create_project` | Create a new UI design project |
82
- | `stitch_get_project` | Get project details |
83
- | `stitch_list_screens` | List screens in a project |
84
- | `stitch_get_screen` | Get screen details with HTML code |
85
- | `stitch_generate_screen_from_text` | Generate UI from text prompt |
61
+ | Tool | Description |
62
+ | -------------------------- | ------------------------------------ |
63
+ | `stitch_create_project` | Create a new Stitch project |
64
+ | `stitch_get_project` | Get project details by resource name |
65
+ | `stitch_list_projects` | List all projects (optional filter) |
66
+ | `stitch_list_screens` | List screens in a project |
67
+ | `stitch_get_screen` | Get screen details with HTML code |
68
+ | `stitch_generate_screen` | Generate UI from text prompt |
69
+ | `stitch_edit_screens` | Edit existing screens with a prompt |
70
+ | `stitch_generate_variants` | Generate design variants of screens |
86
71
 
87
72
  ## Usage Examples
88
73
 
@@ -95,15 +80,13 @@ stitch_list_projects({});
95
80
  ### Create a Project
96
81
 
97
82
  ```typescript
98
- stitch_create_project({
99
- title: "My E-commerce App",
100
- });
83
+ stitch_create_project({ title: "My E-commerce App" });
101
84
  ```
102
85
 
103
86
  ### Generate Screen from Text
104
87
 
105
88
  ```typescript
106
- stitch_generate_screen_from_text({
89
+ stitch_generate_screen({
107
90
  projectId: "my-project-123",
108
91
  prompt:
109
92
  "Create a modern login page with email and password fields, social login buttons, and a forgot password link",
@@ -111,37 +94,71 @@ stitch_generate_screen_from_text({
111
94
  });
112
95
  ```
113
96
 
114
- ## Troubleshooting
97
+ ### Edit Existing Screens
115
98
 
116
- ### "Stitch API not enabled"
99
+ ```typescript
100
+ stitch_edit_screens({
101
+ projectId: "my-project-123",
102
+ selectedScreenIds: ["screen-abc"],
103
+ prompt: "Make the login button larger and change the color scheme to dark mode",
104
+ });
105
+ ```
117
106
 
118
- ```bash
119
- gcloud beta services mcp enable stitch.googleapis.com --project=YOUR_PROJECT_ID
107
+ ### Generate Design Variants
108
+
109
+ ```typescript
110
+ stitch_generate_variants({
111
+ projectId: "my-project-123",
112
+ selectedScreenIds: ["screen-abc"],
113
+ prompt: "Create variants with different color schemes",
114
+ variantCount: 3,
115
+ creativeRange: "MEDIUM",
116
+ });
120
117
  ```
121
118
 
122
- ### "Authentication failed"
119
+ ## Parameters
120
+
121
+ ### Device Types
122
+
123
+ `DEVICE_TYPE_UNSPECIFIED` | `MOBILE` | `DESKTOP` | `TABLET` | `AGNOSTIC`
124
+
125
+ ### Model IDs
126
+
127
+ `MODEL_ID_UNSPECIFIED` | `GEMINI_3_PRO` | `GEMINI_3_FLASH`
128
+
129
+ ### Variant Options
130
+
131
+ - `variantCount`: Number of variants (1-10)
132
+ - `creativeRange`: `LOW` | `MEDIUM` | `HIGH`
133
+ - `aspects`: Comma-separated aspects to vary (e.g. "color,layout")
134
+
135
+ ## Troubleshooting
136
+
137
+ ### "AUTH_FAILED"
123
138
 
124
139
  ```bash
125
- # Refresh your access token (expires after ~1 hour)
140
+ # API key auth
141
+ export STITCH_API_KEY="your-key"
142
+
143
+ # Or OAuth (token expires after ~1 hour)
126
144
  export STITCH_ACCESS_TOKEN=$(gcloud auth print-access-token)
127
- # Restart OpenCode
128
145
  ```
129
146
 
130
- ### "Project not set"
147
+ ### "Stitch API not enabled"
131
148
 
132
149
  ```bash
133
- gcloud config set project YOUR_PROJECT_ID
134
- export GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID
150
+ gcloud beta services mcp enable stitch.googleapis.com --project=YOUR_PROJECT_ID
135
151
  ```
136
152
 
137
153
  ## Documentation
138
154
 
139
155
  - [Google Stitch](https://stitch.withgoogle.com)
156
+ - [Stitch SDK](https://github.com/google-labs-code/stitch-sdk)
140
157
  - [Stitch MCP Setup](https://stitch.withgoogle.com/docs/mcp/setup)
141
- - [Google Cloud MCP Overview](https://docs.cloud.google.com/mcp/overview)
142
158
 
143
159
  ## Tips
144
160
 
145
- - Access tokens expire after ~1 hour, refresh with `gcloud auth print-access-token`
146
- - Use descriptive prompts for better UI generation results
161
+ - API key auth is simpler than OAuth (no token refresh)
162
+ - Use descriptive prompts for better UI generation
163
+ - `GEMINI_3_PRO` produces higher quality; `GEMINI_3_FLASH` is faster
147
164
  - Test generated code in your target framework before production use
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencodekit",
3
- "version": "0.18.25",
3
+ "version": "0.18.27",
4
4
  "description": "CLI tool for bootstrapping and managing OpenCodeKit projects",
5
5
  "keywords": [
6
6
  "agents",
@@ -1,9 +0,0 @@
1
- {
2
- "stitch": {
3
- "serverUrl": "https://stitch.googleapis.com/mcp",
4
- "headers": {
5
- "Authorization": "Bearer ${STITCH_ACCESS_TOKEN}",
6
- "X-Goog-User-Project": "${GOOGLE_CLOUD_PROJECT}"
7
- }
8
- }
9
- }