@kvasar/google-stitch 0.1.12 → 0.1.14

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-google-stitch",
3
3
  "name": "Google Stitch MCP",
4
- "version": "0.1.12",
4
+ "version": "0.1.14",
5
5
  "description": "Integrates Google Stitch MCP services into OpenClaw",
6
6
  "skills": ["skills"],
7
7
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kvasar/google-stitch",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "OpenClaw plugin for Google Stitch UI generation, screen design, variants, and design systems",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -74,4 +74,19 @@ export class StitchMCPClient {
74
74
  },
75
75
  });
76
76
  }
77
+
78
+ async listProjects(filter?: string) {
79
+ return this.request("list_projects", {
80
+ ...(filter ? { filter } : {}),
81
+ });
82
+ }
83
+
84
+ async request(toolName: string, params?: Record<string, any>) {
85
+ await this.connect();
86
+
87
+ return this.client.callTool({
88
+ name: toolName,
89
+ arguments: params ?? {},
90
+ });
91
+ }
77
92
  }
@@ -93,22 +93,32 @@ export function generateScreenFromTextTool(client: StitchMCPClient) {
93
93
  const screen = result.screen;
94
94
  const firstComponent = result.output_components?.[0];
95
95
 
96
+ // Extract model's conversational text and suggestion
97
+ const modelText = firstComponent?.text;
98
+ const suggestion = firstComponent?.suggestion;
99
+
100
+ // Try image URL response
96
101
  const imageUrl =
97
102
  screen?.screenshot?.url ||
98
103
  firstComponent?.design?.screenshot?.url;
99
104
 
100
105
  if (imageUrl) {
101
- return {
102
- content: [
103
- {
104
- type: "image",
105
- url: imageUrl,
106
- caption: screen?.title || "Generated by Google Stitch"
107
- }
108
- ]
109
- };
106
+ const content: Array<{ type: string; [key: string]: any }> = [];
107
+ if (modelText) {
108
+ content.push({ type: "text", text: modelText });
109
+ }
110
+ content.push({
111
+ type: "image",
112
+ url: imageUrl,
113
+ caption: screen?.title || "Generated by Google Stitch"
114
+ });
115
+ if (suggestion) {
116
+ content.push({ type: "text", text: suggestion });
117
+ }
118
+ return { content };
110
119
  }
111
120
 
121
+ // Try image bytes response
112
122
  const imageBytes =
113
123
  screen?.screenshot?.bytes ||
114
124
  firstComponent?.design?.screenshot?.bytes;
@@ -124,33 +134,41 @@ export function generateScreenFromTextTool(client: StitchMCPClient) {
124
134
  Buffer.from(imageBytes, "base64")
125
135
  );
126
136
 
127
- return {
128
- content: [
129
- {
130
- type: "image",
131
- path: tempFilePath,
132
- caption: screen?.title || "Generated by Google Stitch"
133
- }
134
- ]
135
- };
137
+ const content: Array<{ type: string; [key: string]: any }> = [];
138
+ if (modelText) {
139
+ content.push({ type: "text", text: modelText });
140
+ }
141
+ content.push({
142
+ type: "image",
143
+ path: tempFilePath,
144
+ caption: screen?.title || "Generated by Google Stitch"
145
+ });
146
+ if (suggestion) {
147
+ content.push({ type: "text", text: suggestion });
148
+ }
149
+ return { content };
136
150
  }
137
151
 
138
- const html =
152
+ // HTML fallback (either provided or minimal placeholder)
153
+ let html =
139
154
  screen?.htmlCode?.content ||
140
- firstComponent?.design?.htmlCode?.content ||
141
- `<div style="padding:16px">
155
+ firstComponent?.design?.htmlCode?.content;
156
+
157
+ if (!html) {
158
+ html = `<div style="padding:16px">
142
159
  <h3>${escapeHtml(screen?.title || "Generated screen")}</h3>
143
- <p>${escapeHtml(firstComponent?.text || "")}</p>
144
160
  </div>`;
161
+ }
145
162
 
146
- return {
147
- content: [
148
- {
149
- type: "html",
150
- html
151
- }
152
- ]
153
- };
163
+ const content: Array<{ type: string; [key: string]: any }> = [];
164
+ if (modelText) {
165
+ content.push({ type: "text", text: modelText });
166
+ }
167
+ content.push({ type: "html", html });
168
+ if (suggestion) {
169
+ content.push({ type: "text", text: suggestion });
170
+ }
171
+ return { content };
154
172
  }
155
173
  };
156
174
  }
@@ -1,7 +1,36 @@
1
- export const listProjectsTool = (client:any) => ({
2
- name: "list_projects",
3
- description: "list projects",
4
- async execute(_: string, params: any) {
5
- return await client.request?.("list_projects", params);
6
- },
7
- });
1
+ import { Type } from "@sinclair/typebox";
2
+ import { StitchMCPClient } from "../services/stitch-mcp-client.js";
3
+
4
+ export interface ListProjectsParams {
5
+ filter?: string;
6
+ }
7
+
8
+ export function listProjectsTool(client: StitchMCPClient) {
9
+ return {
10
+ name: "list_projects" as const,
11
+ description:
12
+ "Lists all Stitch projects accessible to the user. By default, it lists projects owned by the user.",
13
+
14
+ parameters: Type.Object({
15
+ filter: Type.Optional(
16
+ Type.String({
17
+ description:
18
+ "Optional. AIP-160 filter on `view` field. Supported: `view=owned` (default), `view=shared`.",
19
+ })
20
+ ),
21
+ }),
22
+
23
+ async execute(_id: string, params: ListProjectsParams) {
24
+ const result = await client.listProjects(params?.filter);
25
+
26
+ return {
27
+ content: [
28
+ {
29
+ type: "text" as const,
30
+ text: JSON.stringify(result, null, 2),
31
+ },
32
+ ],
33
+ };
34
+ },
35
+ };
36
+ }