heroshot 0.17.0 → 0.19.0

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,319 @@
1
+ #!/usr/bin/env node
2
+ import { _ as loadConfig, b as screenshotSchema, g as getConfigPath, i as filterScreenshots, r as sync, t as generateSnippets, v as saveConfig, x as generateUid } from "./snippet-ZcZmuryj.js";
3
+ import { z } from "zod";
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ //#region src/mcp/schemas/add.ts
7
+ /**
8
+ * Add tool input schema.
9
+ * Wraps the existing screenshotSchema from heroshot.
10
+ */
11
+ const screenshotInputSchema = screenshotSchema.omit({ id: true });
12
+ const addOptionsSchema = z.object({
13
+ configPath: z.string().optional().describe("Path to config file (default: .heroshot/config.json in cwd)"),
14
+ screenshot: screenshotInputSchema.describe("Screenshot definition to add")
15
+ });
16
+ //#endregion
17
+ //#region src/mcp/schemas/list.ts
18
+ /**
19
+ * List tool input schema.
20
+ */
21
+ const listOptionsSchema = z.object({
22
+ configPath: z.string().optional().describe("Path to config file (default: .heroshot/config.json in cwd)"),
23
+ filter: z.string().optional().describe("Filter screenshots by id, name, or filename (case-insensitive substring match)")
24
+ });
25
+ //#endregion
26
+ //#region src/mcp/schemas/remove.ts
27
+ /**
28
+ * Remove tool input schema.
29
+ */
30
+ const removeOptionsSchema = z.object({
31
+ configPath: z.string().optional().describe("Path to config file (default: .heroshot/config.json in cwd)"),
32
+ id: z.string().min(1).describe("ID of the screenshot to remove")
33
+ });
34
+ //#endregion
35
+ //#region src/mcp/schemas/snippet.ts
36
+ /**
37
+ * Snippet tool input schema.
38
+ */
39
+ const snippetOptionsSchema = z.object({
40
+ configPath: z.string().optional().describe("Path to config file (default: .heroshot/config.json in cwd)"),
41
+ filter: z.string().optional().describe("Filter screenshots by id, name, or filename (case-insensitive substring match)"),
42
+ pathPrefix: z.string().optional().describe("Custom path prefix for images (default: ./heroshots/)")
43
+ });
44
+ //#endregion
45
+ //#region src/mcp/schemas/sync.ts
46
+ /**
47
+ * Sync tool input schema.
48
+ */
49
+ const syncOptionsSchema = z.object({
50
+ configPath: z.string().optional().describe("Path to config file (default: .heroshot/config.json in cwd)"),
51
+ filter: z.string().optional().describe("Filter screenshots by id, name, or filename (case-insensitive substring match)"),
52
+ clean: z.boolean().optional().describe("Delete stale files in output directory"),
53
+ workers: z.number().int().min(1).optional().describe("Number of parallel capture workers"),
54
+ sessionKey: z.string().optional().describe("Encrypted session key for authenticated screenshots")
55
+ });
56
+ //#endregion
57
+ //#region src/mcp/tools/add.ts
58
+ /**
59
+ * Add tool handler.
60
+ * Adds a new screenshot definition to config.
61
+ */
62
+ function addHandler(input) {
63
+ try {
64
+ const configPath = input.configPath ?? getConfigPath();
65
+ const config = loadConfig(configPath);
66
+ const screenshotInput = {
67
+ ...input.screenshot,
68
+ id: generateUid()
69
+ };
70
+ const screenshot = screenshotSchema.parse(screenshotInput);
71
+ const existingByName = config.screenshots.find((s) => s.name.toLowerCase() === screenshot.name.toLowerCase());
72
+ if (existingByName) return {
73
+ success: false,
74
+ error: `Screenshot with name "${screenshot.name}" already exists (id: ${existingByName.id})`
75
+ };
76
+ config.screenshots.push(screenshot);
77
+ saveConfig(configPath, config);
78
+ return {
79
+ success: true,
80
+ id: screenshot.id,
81
+ screenshot: {
82
+ id: screenshot.id,
83
+ name: screenshot.name,
84
+ url: screenshot.url
85
+ }
86
+ };
87
+ } catch (error) {
88
+ return {
89
+ success: false,
90
+ error: error instanceof Error ? error.message : String(error)
91
+ };
92
+ }
93
+ }
94
+ //#endregion
95
+ //#region src/mcp/tools/list.ts
96
+ /**
97
+ * List tool handler.
98
+ * Lists screenshots defined in config.
99
+ */
100
+ function listHandler(input) {
101
+ try {
102
+ const screenshots = filterScreenshots(loadConfig(input.configPath ?? getConfigPath()).screenshots, input.filter);
103
+ return {
104
+ success: true,
105
+ count: screenshots.length,
106
+ screenshots: screenshots.map((s) => ({
107
+ id: s.id,
108
+ name: s.name,
109
+ url: s.url,
110
+ selector: s.selector
111
+ }))
112
+ };
113
+ } catch {
114
+ return {
115
+ success: false,
116
+ count: 0,
117
+ screenshots: [],
118
+ error: "Failed to load config"
119
+ };
120
+ }
121
+ }
122
+ //#endregion
123
+ //#region src/mcp/tools/remove.ts
124
+ /**
125
+ * Remove tool handler.
126
+ * Removes a screenshot definition from config.
127
+ */
128
+ function removeHandler(input) {
129
+ try {
130
+ const configPath = input.configPath ?? getConfigPath();
131
+ const config = loadConfig(configPath);
132
+ const index = config.screenshots.findIndex((s) => s.id === input.id);
133
+ if (index === -1) return {
134
+ success: false,
135
+ error: `Screenshot with id "${input.id}" not found`
136
+ };
137
+ const [removed] = config.screenshots.splice(index, 1);
138
+ if (!removed) return {
139
+ success: false,
140
+ error: `Screenshot with id "${input.id}" not found`
141
+ };
142
+ saveConfig(configPath, config);
143
+ return {
144
+ success: true,
145
+ removed: {
146
+ id: removed.id,
147
+ name: removed.name
148
+ }
149
+ };
150
+ } catch (error) {
151
+ return {
152
+ success: false,
153
+ error: error instanceof Error ? error.message : String(error)
154
+ };
155
+ }
156
+ }
157
+ //#endregion
158
+ //#region src/mcp/tools/snippet.ts
159
+ /**
160
+ * Snippet tool handler.
161
+ * Generates markdown/HTML snippets for screenshots.
162
+ */
163
+ function snippetHandler(input) {
164
+ try {
165
+ const results = generateSnippets(loadConfig(input.configPath ?? getConfigPath()), input.filter, { pathPrefix: input.pathPrefix });
166
+ return {
167
+ success: true,
168
+ count: results.length,
169
+ snippets: results.map((r) => ({
170
+ id: r.screenshot.id,
171
+ name: r.screenshot.name,
172
+ snippet: r.snippet
173
+ }))
174
+ };
175
+ } catch (error) {
176
+ return {
177
+ success: false,
178
+ count: 0,
179
+ snippets: [],
180
+ error: error instanceof Error ? error.message : String(error)
181
+ };
182
+ }
183
+ }
184
+ //#endregion
185
+ //#region src/mcp/tools/sync.ts
186
+ /**
187
+ * Sync tool handler.
188
+ * Captures screenshots defined in config.
189
+ */
190
+ function resolveSessionKey(input) {
191
+ return input.sessionKey ?? process.env["HEROSHOT_SESSION_KEY"];
192
+ }
193
+ async function syncHandler(input) {
194
+ try {
195
+ const configPath = input.configPath ?? getConfigPath();
196
+ const sessionKey = resolveSessionKey(input);
197
+ const result = await sync({
198
+ configPath,
199
+ filter: input.filter,
200
+ clean: input.clean,
201
+ workers: input.workers,
202
+ sessionKey
203
+ });
204
+ return {
205
+ success: result.failed === 0,
206
+ total: result.total,
207
+ captured: result.success,
208
+ failed: result.failed,
209
+ results: result.results,
210
+ staleFiles: result.staleFiles,
211
+ deletedFiles: result.deletedFiles
212
+ };
213
+ } catch (error) {
214
+ return {
215
+ success: false,
216
+ total: 0,
217
+ captured: 0,
218
+ failed: 0,
219
+ results: [],
220
+ error: error instanceof Error ? error.message : String(error)
221
+ };
222
+ }
223
+ }
224
+ //#endregion
225
+ //#region src/mcp/tools/definitions.ts
226
+ function formatResult(result) {
227
+ return {
228
+ content: [{
229
+ type: "text",
230
+ text: JSON.stringify(result, null, 2)
231
+ }],
232
+ isError: !result.success
233
+ };
234
+ }
235
+ async function syncToolHandler(input) {
236
+ return formatResult(await syncHandler(input));
237
+ }
238
+ async function addToolHandler(input) {
239
+ return formatResult(addHandler(input));
240
+ }
241
+ async function listToolHandler(input) {
242
+ return formatResult(listHandler(input));
243
+ }
244
+ async function snippetToolHandler(input) {
245
+ return formatResult(snippetHandler(input));
246
+ }
247
+ async function removeToolHandler(input) {
248
+ return formatResult(removeHandler(input));
249
+ }
250
+ const tools = [
251
+ {
252
+ name: "heroshot_sync",
253
+ description: "Capture all screenshots defined in the heroshot config. Optionally filter by id/name/filename pattern, delete stale files, or run with multiple workers.",
254
+ inputSchema: syncOptionsSchema,
255
+ handler: syncToolHandler
256
+ },
257
+ {
258
+ name: "heroshot_add",
259
+ description: "Add a new screenshot definition to the heroshot config. Requires at least name and url. Optional: selector for element capture, actions for pre-capture steps.",
260
+ inputSchema: addOptionsSchema,
261
+ handler: addToolHandler
262
+ },
263
+ {
264
+ name: "heroshot_list",
265
+ description: "List all screenshots defined in the heroshot config. Returns id, name, url, and selector for each screenshot.",
266
+ inputSchema: listOptionsSchema,
267
+ handler: listToolHandler
268
+ },
269
+ {
270
+ name: "heroshot_snippet",
271
+ description: "Generate markdown/HTML snippets for embedding screenshots in documentation. Supports light/dark mode with <picture> elements.",
272
+ inputSchema: snippetOptionsSchema,
273
+ handler: snippetToolHandler
274
+ },
275
+ {
276
+ name: "heroshot_remove",
277
+ description: "Remove a screenshot definition from the heroshot config by its ID.",
278
+ inputSchema: removeOptionsSchema,
279
+ handler: removeToolHandler
280
+ }
281
+ ];
282
+ //#endregion
283
+ //#region src/mcp/utils/zodToMcp.ts
284
+ /**
285
+ * Utilities for converting Zod schemas to MCP tool definitions.
286
+ */
287
+ /**
288
+ * Convert a ToolDefinition to MCP tool format.
289
+ * Uses z.toJSONSchema() for automatic schema conversion.
290
+ */
291
+ function toMcpTool(definition) {
292
+ return {
293
+ name: definition.name,
294
+ description: definition.description,
295
+ inputSchema: z.toJSONSchema(definition.inputSchema)
296
+ };
297
+ }
298
+ //#endregion
299
+ //#region src/mcp/server.ts
300
+ /**
301
+ * Heroshot MCP Server
302
+ *
303
+ * MCP server for screenshot automation. Tools are auto-derived from Zod schemas
304
+ * using z.toJSONSchema() for low maintenance.
305
+ */
306
+ async function startMcpServer() {
307
+ const server = new McpServer({
308
+ name: "heroshot",
309
+ version: "0.1.0"
310
+ });
311
+ for (const tool of tools) {
312
+ const mcpTool = toMcpTool(tool);
313
+ server.registerTool(tool.name, mcpTool.inputSchema, async (input) => tool.handler(input));
314
+ }
315
+ const transport = new StdioServerTransport();
316
+ await server.connect(transport);
317
+ }
318
+ //#endregion
319
+ export { startMcpServer as t };
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { t as startMcpServer } from "./server-BklhdmjN.js";
3
+ export { startMcpServer };