mcp-ghost-optimized 1.0.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.
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Ghost Optimized - Entry Point
4
+ *
5
+ * This MCP server provides Ghost Admin API tools with field projection
6
+ * for significant token reduction compared to standard Ghost MCP.
7
+ *
8
+ * Environment variables required:
9
+ * - GHOST_URL: Ghost site URL (e.g., https://your-blog.ghost.io)
10
+ * - GHOST_ADMIN_API_KEY: Admin API key in format "id:secret"
11
+ */
12
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
+ import { createServer } from "./server.js";
14
+ async function main() {
15
+ try {
16
+ const server = createServer();
17
+ const transport = new StdioServerTransport();
18
+ await server.connect(transport);
19
+ // Log to stderr (stdout is reserved for MCP protocol)
20
+ console.error("MCP Ghost Optimized server running on stdio");
21
+ }
22
+ catch (error) {
23
+ console.error("Failed to start MCP server:", error);
24
+ process.exit(1);
25
+ }
26
+ }
27
+ main();
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhC,sDAAsD;QACtD,OAAO,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * MCP Ghost Optimized Server
3
+ *
4
+ * Provides Ghost Admin API tools with field projection for token efficiency.
5
+ */
6
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ export declare function createServer(): McpServer;
8
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsDpE,wBAAgB,YAAY,IAAI,SAAS,CA2cxC"}
package/dist/server.js ADDED
@@ -0,0 +1,378 @@
1
+ /**
2
+ * MCP Ghost Optimized Server
3
+ *
4
+ * Provides Ghost Admin API tools with field projection for token efficiency.
5
+ */
6
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
7
+ import { z } from "zod";
8
+ import { GhostClient } from "./api/client.js";
9
+ import { POST_FIELDS, TAG_FIELDS } from "./utils/fields.js";
10
+ import { htmlToPlaintext } from "./utils/html.js";
11
+ export function createServer() {
12
+ const server = new McpServer({
13
+ name: "ghost-optimized",
14
+ version: "1.0.0",
15
+ });
16
+ // Get config from environment
17
+ const ghostUrl = process.env.GHOST_URL;
18
+ const ghostKey = process.env.GHOST_ADMIN_API_KEY;
19
+ const defaultTemplate = process.env.GHOST_DEFAULT_TEMPLATE;
20
+ if (!ghostUrl || !ghostKey) {
21
+ throw new Error("GHOST_URL and GHOST_ADMIN_API_KEY environment variables must be set");
22
+ }
23
+ const client = new GhostClient({ url: ghostUrl, apiKey: ghostKey });
24
+ // ============================================================
25
+ // POSTS TOOLS
26
+ // ============================================================
27
+ /**
28
+ * posts_browse - List posts with optimized field projection
29
+ */
30
+ server.tool("posts_browse", "List posts with optimized field projection. Returns minimal data to save tokens.", {
31
+ status: z
32
+ .enum(["draft", "published", "scheduled", "all"])
33
+ .default("all")
34
+ .describe("Filter by post status"),
35
+ limit: z
36
+ .number()
37
+ .min(1)
38
+ .max(100)
39
+ .default(15)
40
+ .describe("Number of posts to return"),
41
+ page: z.number().min(1).default(1).describe("Page number for pagination"),
42
+ order: z
43
+ .enum(["published_at desc", "updated_at desc", "title asc"])
44
+ .default("updated_at desc")
45
+ .describe("Sort order"),
46
+ mode: z
47
+ .enum(["minimal", "compact", "standard"])
48
+ .default("compact")
49
+ .describe("Response detail level: minimal (~15 tokens/post), compact (~50), standard (~150)"),
50
+ filter: z
51
+ .string()
52
+ .optional()
53
+ .describe("NQL filter (e.g., 'tag:finance+status:published', 'author:matthieu'). Overrides status parameter if provided."),
54
+ }, async ({ status, limit, page, order, mode, filter: nqlFilter }) => {
55
+ // User-provided NQL filter takes precedence
56
+ let filter = nqlFilter;
57
+ // If no NQL filter, build from status
58
+ if (!filter && status !== "all") {
59
+ filter = `status:${status}`;
60
+ }
61
+ const fields = [...POST_FIELDS[mode]];
62
+ const result = await client.browse("posts", {
63
+ fields,
64
+ filter,
65
+ limit,
66
+ page,
67
+ order,
68
+ include: mode === "standard" ? ["tags"] : undefined,
69
+ });
70
+ return {
71
+ content: [
72
+ {
73
+ type: "text",
74
+ text: JSON.stringify(result, null, 2),
75
+ },
76
+ ],
77
+ };
78
+ });
79
+ /**
80
+ * posts_read - Read a single post by ID or slug
81
+ */
82
+ server.tool("posts_read", "Read a single post. Use 'metadata' mode for info only, 'content' for readable text, 'full' for HTML.", {
83
+ id: z.string().optional().describe("Post ID"),
84
+ slug: z.string().optional().describe("Post slug (alternative to ID)"),
85
+ mode: z
86
+ .enum(["metadata", "content", "full"])
87
+ .default("content")
88
+ .describe("Response mode: metadata (~200 tokens), content (plaintext, ~500-2000), full (HTML, ~500-3000)"),
89
+ }, async ({ id, slug, mode }) => {
90
+ if (!id && !slug) {
91
+ throw new Error("Either id or slug must be provided");
92
+ }
93
+ const fields = [...POST_FIELDS[mode]];
94
+ const postId = id || `slug/${slug}`;
95
+ // Ghost requires formats=html to return HTML content
96
+ const needsHtml = mode === "content" || mode === "full";
97
+ const result = await client.read("posts", postId, {
98
+ fields,
99
+ include: ["tags"],
100
+ formats: needsHtml ? ["html"] : undefined,
101
+ });
102
+ // Convert HTML to plaintext if mode is 'content'
103
+ if (mode === "content" && result.posts?.[0]?.html) {
104
+ result.posts[0].plaintext = htmlToPlaintext(result.posts[0].html);
105
+ delete result.posts[0].html;
106
+ }
107
+ return {
108
+ content: [
109
+ {
110
+ type: "text",
111
+ text: JSON.stringify(result, null, 2),
112
+ },
113
+ ],
114
+ };
115
+ });
116
+ /**
117
+ * posts_add - Create a new post
118
+ */
119
+ server.tool("posts_add", "Create a new post. Returns minimal response with ID and URL.", {
120
+ title: z.string().min(1).describe("Post title"),
121
+ html: z.string().optional().describe("Post content as HTML"),
122
+ status: z
123
+ .enum(["draft", "published", "scheduled"])
124
+ .default("draft")
125
+ .describe("Post status"),
126
+ slug: z
127
+ .string()
128
+ .optional()
129
+ .describe("URL slug (auto-generated if not provided)"),
130
+ custom_excerpt: z
131
+ .string()
132
+ .optional()
133
+ .describe("Custom excerpt for SEO (replaces auto-generated)"),
134
+ custom_template: z
135
+ .string()
136
+ .optional()
137
+ .describe("Custom template name (e.g., 'custom-template-perso')"),
138
+ tags: z
139
+ .array(z.string())
140
+ .optional()
141
+ .describe("Array of tag slugs to assign"),
142
+ feature_image: z.string().url().optional().describe("Feature image URL"),
143
+ published_at: z
144
+ .string()
145
+ .datetime()
146
+ .optional()
147
+ .describe("Publication date (required for scheduled posts)"),
148
+ }, async (data) => {
149
+ const postData = {
150
+ title: data.title,
151
+ status: data.status,
152
+ };
153
+ if (data.html)
154
+ postData.html = data.html;
155
+ if (data.slug)
156
+ postData.slug = data.slug;
157
+ if (data.custom_excerpt)
158
+ postData.custom_excerpt = data.custom_excerpt;
159
+ // Use provided template or fall back to default from env
160
+ const template = data.custom_template ?? defaultTemplate;
161
+ if (template)
162
+ postData.custom_template = template;
163
+ if (data.feature_image)
164
+ postData.feature_image = data.feature_image;
165
+ if (data.published_at)
166
+ postData.published_at = data.published_at;
167
+ if (data.tags) {
168
+ postData.tags = data.tags.map((slug) => ({ slug }));
169
+ }
170
+ const result = await client.add("posts", postData);
171
+ // Return minimal response
172
+ const post = result.posts[0];
173
+ return {
174
+ content: [
175
+ {
176
+ type: "text",
177
+ text: JSON.stringify({
178
+ id: post.id,
179
+ title: post.title,
180
+ slug: post.slug,
181
+ status: post.status,
182
+ url: post.url,
183
+ }, null, 2),
184
+ },
185
+ ],
186
+ };
187
+ });
188
+ /**
189
+ * posts_edit - Update an existing post
190
+ */
191
+ server.tool("posts_edit", "Update a post. Automatically handles updated_at for optimistic locking.", {
192
+ id: z.string().describe("Post ID to update"),
193
+ title: z.string().optional().describe("New title"),
194
+ html: z.string().optional().describe("New content as HTML"),
195
+ status: z
196
+ .enum(["draft", "published", "scheduled"])
197
+ .optional()
198
+ .describe("New status"),
199
+ slug: z.string().optional().describe("New URL slug"),
200
+ custom_excerpt: z
201
+ .string()
202
+ .optional()
203
+ .describe("New custom excerpt (null to use auto-generated)"),
204
+ custom_template: z
205
+ .string()
206
+ .optional()
207
+ .describe("Custom template name (null to use default)"),
208
+ tags: z
209
+ .array(z.string())
210
+ .optional()
211
+ .describe("New tags (replaces existing). Array of tag slugs."),
212
+ feature_image: z
213
+ .string()
214
+ .url()
215
+ .nullable()
216
+ .optional()
217
+ .describe("New feature image URL (null to remove)"),
218
+ }, async ({ id, ...data }) => {
219
+ const updateData = {};
220
+ if (data.title !== undefined)
221
+ updateData.title = data.title;
222
+ if (data.html !== undefined)
223
+ updateData.html = data.html;
224
+ if (data.status !== undefined)
225
+ updateData.status = data.status;
226
+ if (data.slug !== undefined)
227
+ updateData.slug = data.slug;
228
+ if (data.custom_excerpt !== undefined)
229
+ updateData.custom_excerpt = data.custom_excerpt;
230
+ if (data.custom_template !== undefined)
231
+ updateData.custom_template = data.custom_template;
232
+ if (data.feature_image !== undefined)
233
+ updateData.feature_image = data.feature_image;
234
+ if (data.tags !== undefined) {
235
+ updateData.tags = data.tags.map((slug) => ({ slug }));
236
+ }
237
+ const result = await client.edit("posts", id, updateData);
238
+ const post = result.posts[0];
239
+ return {
240
+ content: [
241
+ {
242
+ type: "text",
243
+ text: JSON.stringify({
244
+ id: post.id,
245
+ title: post.title,
246
+ slug: post.slug,
247
+ status: post.status,
248
+ updated_at: post.updated_at,
249
+ }, null, 2),
250
+ },
251
+ ],
252
+ };
253
+ });
254
+ /**
255
+ * posts_delete - Delete a post
256
+ */
257
+ server.tool("posts_delete", "Permanently delete a post. This cannot be undone. CRITICAL: You MUST ask the user for explicit confirmation before calling this tool. Never call this tool without user approval first.", {
258
+ id: z.string().describe("Post ID to delete"),
259
+ title: z.string().describe("Post title (for confirmation display)"),
260
+ confirm: z.literal(true).describe("Must be true to confirm deletion"),
261
+ }, async ({ id, title }) => {
262
+ await client.delete("posts", id);
263
+ return {
264
+ content: [
265
+ {
266
+ type: "text",
267
+ text: JSON.stringify({ success: true, deleted_id: id, title }),
268
+ },
269
+ ],
270
+ };
271
+ });
272
+ // ============================================================
273
+ // TAGS TOOLS
274
+ // ============================================================
275
+ /**
276
+ * tags_browse - List all tags
277
+ */
278
+ server.tool("tags_browse", "List all tags with optimized field projection.", {
279
+ limit: z
280
+ .number()
281
+ .min(1)
282
+ .max(100)
283
+ .default(50)
284
+ .describe("Number of tags to return"),
285
+ mode: z
286
+ .enum(["minimal", "standard"])
287
+ .default("minimal")
288
+ .describe("Response detail level: minimal (~15 tokens/tag), standard (~40)"),
289
+ }, async ({ limit, mode }) => {
290
+ const fields = [...TAG_FIELDS[mode]];
291
+ const result = await client.browse("tags", {
292
+ fields,
293
+ limit,
294
+ });
295
+ return {
296
+ content: [
297
+ {
298
+ type: "text",
299
+ text: JSON.stringify(result, null, 2),
300
+ },
301
+ ],
302
+ };
303
+ });
304
+ /**
305
+ * tags_read - Read a single tag
306
+ */
307
+ server.tool("tags_read", "Read a single tag by ID or slug.", {
308
+ id: z.string().optional().describe("Tag ID"),
309
+ slug: z.string().optional().describe("Tag slug (alternative to ID)"),
310
+ }, async ({ id, slug }) => {
311
+ if (!id && !slug) {
312
+ throw new Error("Either id or slug must be provided");
313
+ }
314
+ const tagId = id || `slug/${slug}`;
315
+ const result = await client.read("tags", tagId, {
316
+ fields: [...TAG_FIELDS.standard],
317
+ });
318
+ return {
319
+ content: [
320
+ {
321
+ type: "text",
322
+ text: JSON.stringify(result, null, 2),
323
+ },
324
+ ],
325
+ };
326
+ });
327
+ // ============================================================
328
+ // IMAGES TOOLS
329
+ // ============================================================
330
+ /**
331
+ * images_upload - Upload an image to Ghost from local file or URL
332
+ */
333
+ server.tool("images_upload", "Upload an image to Ghost storage from a local file or URL. Returns the URL that can be used for feature_image or in post content.", {
334
+ file_path: z
335
+ .string()
336
+ .optional()
337
+ .describe("Absolute path to local image file (e.g., '/tmp/image.jpg')"),
338
+ url: z
339
+ .string()
340
+ .url()
341
+ .optional()
342
+ .describe("URL to download and upload (e.g., 'https://example.com/image.jpg')"),
343
+ filename: z
344
+ .string()
345
+ .optional()
346
+ .describe("Filename with extension (inferred from path/url if absent)"),
347
+ }, async ({ file_path, url: imageUrl, filename }) => {
348
+ if (!file_path && !imageUrl) {
349
+ throw new Error("Either file_path or url must be provided");
350
+ }
351
+ let resultUrl;
352
+ if (file_path) {
353
+ // Upload from local file
354
+ resultUrl = await client.uploadImageFromPath(file_path);
355
+ }
356
+ else if (imageUrl) {
357
+ // Upload from URL - filename is required
358
+ const inferredFilename = filename || imageUrl.split("/").pop() || "image.jpg";
359
+ if (!inferredFilename.includes(".")) {
360
+ throw new Error("Could not infer filename from URL. Please provide filename parameter.");
361
+ }
362
+ resultUrl = await client.uploadImageFromUrl(imageUrl, inferredFilename);
363
+ }
364
+ else {
365
+ throw new Error("Either file_path or url must be provided");
366
+ }
367
+ return {
368
+ content: [
369
+ {
370
+ type: "text",
371
+ text: JSON.stringify({ url: resultUrl }, null, 2),
372
+ },
373
+ ],
374
+ };
375
+ });
376
+ return server;
377
+ }
378
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Field presets for different response modes
3
+ *
4
+ * These presets control which fields are requested from Ghost API,
5
+ * enabling significant token reduction compared to full responses.
6
+ */
7
+ /**
8
+ * Post field presets by response mode
9
+ *
10
+ * Token estimates per post:
11
+ * - minimal: ~15 tokens
12
+ * - compact: ~50 tokens
13
+ * - standard: ~150 tokens
14
+ * - metadata: ~200 tokens
15
+ * - content: ~500-2000 tokens (depends on article length)
16
+ * - full: ~500-3000 tokens
17
+ */
18
+ export declare const POST_FIELDS: {
19
+ /** Bare minimum for listing - just identification and status */
20
+ readonly minimal: readonly ["id", "title", "status"];
21
+ /** Good for listing with actionable info */
22
+ readonly compact: readonly ["id", "title", "slug", "status", "published_at", "updated_at", "reading_time"];
23
+ /** For listing with preview info */
24
+ readonly standard: readonly ["id", "title", "slug", "status", "published_at", "updated_at", "reading_time", "excerpt", "feature_image"];
25
+ /** For reading post info without content */
26
+ readonly metadata: readonly ["id", "title", "slug", "status", "published_at", "updated_at", "reading_time", "excerpt", "feature_image"];
27
+ /** For reading post with content (HTML will be converted to plaintext) */
28
+ readonly content: readonly ["id", "title", "slug", "status", "published_at", "updated_at", "reading_time", "excerpt", "html"];
29
+ /** For reading post with full HTML */
30
+ readonly full: readonly ["id", "title", "slug", "status", "published_at", "updated_at", "reading_time", "excerpt", "feature_image", "html"];
31
+ };
32
+ /**
33
+ * Tag field presets by response mode
34
+ *
35
+ * Token estimates per tag:
36
+ * - minimal: ~15 tokens
37
+ * - standard: ~40 tokens
38
+ */
39
+ export declare const TAG_FIELDS: {
40
+ /** Just identification */
41
+ readonly minimal: readonly ["id", "name", "slug"];
42
+ /** With description */
43
+ readonly standard: readonly ["id", "name", "slug", "description"];
44
+ };
45
+ /**
46
+ * Member field presets (if implementing members tools)
47
+ */
48
+ export declare const MEMBER_FIELDS: {
49
+ readonly minimal: readonly ["id", "email", "name"];
50
+ readonly standard: readonly ["id", "email", "name", "status", "created_at"];
51
+ };
52
+ export type PostFieldMode = keyof typeof POST_FIELDS;
53
+ export type TagFieldMode = keyof typeof TAG_FIELDS;
54
+ export type MemberFieldMode = keyof typeof MEMBER_FIELDS;
55
+ //# sourceMappingURL=fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/utils/fields.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW;IACtB,gEAAgE;;IAGhE,4CAA4C;;IAW5C,oCAAoC;;IAapC,4CAA4C;;IAa5C,0EAA0E;;IAa1E,sCAAsC;;CAa9B,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,UAAU;IACrB,0BAA0B;;IAG1B,uBAAuB;;CAEf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,aAAa;;;CAGhB,CAAC;AAGX,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,WAAW,CAAC;AACrD,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,UAAU,CAAC;AACnD,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,aAAa,CAAC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Field presets for different response modes
3
+ *
4
+ * These presets control which fields are requested from Ghost API,
5
+ * enabling significant token reduction compared to full responses.
6
+ */
7
+ /**
8
+ * Post field presets by response mode
9
+ *
10
+ * Token estimates per post:
11
+ * - minimal: ~15 tokens
12
+ * - compact: ~50 tokens
13
+ * - standard: ~150 tokens
14
+ * - metadata: ~200 tokens
15
+ * - content: ~500-2000 tokens (depends on article length)
16
+ * - full: ~500-3000 tokens
17
+ */
18
+ export const POST_FIELDS = {
19
+ /** Bare minimum for listing - just identification and status */
20
+ minimal: ["id", "title", "status"],
21
+ /** Good for listing with actionable info */
22
+ compact: [
23
+ "id",
24
+ "title",
25
+ "slug",
26
+ "status",
27
+ "published_at",
28
+ "updated_at",
29
+ "reading_time",
30
+ ],
31
+ /** For listing with preview info */
32
+ standard: [
33
+ "id",
34
+ "title",
35
+ "slug",
36
+ "status",
37
+ "published_at",
38
+ "updated_at",
39
+ "reading_time",
40
+ "excerpt",
41
+ "feature_image",
42
+ ],
43
+ /** For reading post info without content */
44
+ metadata: [
45
+ "id",
46
+ "title",
47
+ "slug",
48
+ "status",
49
+ "published_at",
50
+ "updated_at",
51
+ "reading_time",
52
+ "excerpt",
53
+ "feature_image",
54
+ ],
55
+ /** For reading post with content (HTML will be converted to plaintext) */
56
+ content: [
57
+ "id",
58
+ "title",
59
+ "slug",
60
+ "status",
61
+ "published_at",
62
+ "updated_at",
63
+ "reading_time",
64
+ "excerpt",
65
+ "html",
66
+ ],
67
+ /** For reading post with full HTML */
68
+ full: [
69
+ "id",
70
+ "title",
71
+ "slug",
72
+ "status",
73
+ "published_at",
74
+ "updated_at",
75
+ "reading_time",
76
+ "excerpt",
77
+ "feature_image",
78
+ "html",
79
+ ],
80
+ };
81
+ /**
82
+ * Tag field presets by response mode
83
+ *
84
+ * Token estimates per tag:
85
+ * - minimal: ~15 tokens
86
+ * - standard: ~40 tokens
87
+ */
88
+ export const TAG_FIELDS = {
89
+ /** Just identification */
90
+ minimal: ["id", "name", "slug"],
91
+ /** With description */
92
+ standard: ["id", "name", "slug", "description"],
93
+ };
94
+ /**
95
+ * Member field presets (if implementing members tools)
96
+ */
97
+ export const MEMBER_FIELDS = {
98
+ minimal: ["id", "email", "name"],
99
+ standard: ["id", "email", "name", "status", "created_at"],
100
+ };
101
+ //# sourceMappingURL=fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fields.js","sourceRoot":"","sources":["../../src/utils/fields.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,gEAAgE;IAChE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC;IAElC,4CAA4C;IAC5C,OAAO,EAAE;QACP,IAAI;QACJ,OAAO;QACP,MAAM;QACN,QAAQ;QACR,cAAc;QACd,YAAY;QACZ,cAAc;KACf;IAED,oCAAoC;IACpC,QAAQ,EAAE;QACR,IAAI;QACJ,OAAO;QACP,MAAM;QACN,QAAQ;QACR,cAAc;QACd,YAAY;QACZ,cAAc;QACd,SAAS;QACT,eAAe;KAChB;IAED,4CAA4C;IAC5C,QAAQ,EAAE;QACR,IAAI;QACJ,OAAO;QACP,MAAM;QACN,QAAQ;QACR,cAAc;QACd,YAAY;QACZ,cAAc;QACd,SAAS;QACT,eAAe;KAChB;IAED,0EAA0E;IAC1E,OAAO,EAAE;QACP,IAAI;QACJ,OAAO;QACP,MAAM;QACN,QAAQ;QACR,cAAc;QACd,YAAY;QACZ,cAAc;QACd,SAAS;QACT,MAAM;KACP;IAED,sCAAsC;IACtC,IAAI,EAAE;QACJ,IAAI;QACJ,OAAO;QACP,MAAM;QACN,QAAQ;QACR,cAAc;QACd,YAAY;QACZ,cAAc;QACd,SAAS;QACT,eAAe;QACf,MAAM;KACP;CACO,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,0BAA0B;IAC1B,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC;IAE/B,uBAAuB;IACvB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC;CACvC,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC;IAChC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC;CACjD,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * HTML to plaintext conversion utilities
3
+ *
4
+ * Ghost stores content as HTML (or Lexical JSON internally).
5
+ * For LLM consumption, plaintext is more token-efficient.
6
+ */
7
+ /**
8
+ * Convert HTML to plaintext
9
+ *
10
+ * Removes all HTML tags, scripts, styles, and normalizes whitespace.
11
+ * Also decodes common HTML entities.
12
+ *
13
+ * @param html - HTML string to convert
14
+ * @returns Clean plaintext
15
+ */
16
+ export declare function htmlToPlaintext(html: string): string;
17
+ /**
18
+ * Truncate text to a maximum length, preserving word boundaries
19
+ *
20
+ * @param text - Text to truncate
21
+ * @param maxLength - Maximum character length
22
+ * @param suffix - Suffix to add if truncated (default: "...")
23
+ * @returns Truncated text
24
+ */
25
+ export declare function truncateText(text: string, maxLength: number, suffix?: string): string;
26
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/utils/html.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkCpD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAAc,GACrB,MAAM,CAcR"}