agent-reader 1.1.3 → 1.1.4
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/CHANGELOG.md +22 -0
- package/README.md +3 -2
- package/SKILL.md +10 -1
- package/bin/agent-reader.js +1 -1
- package/openclaw-skill/SKILL.md +10 -1
- package/openclaw-skill/schema.json +68 -0
- package/package.json +1 -1
- package/src/core/renderer.js +9 -1
- package/src/mcp/server.js +109 -1
- package/src/mcp/toolSchemas.js +9 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.1.3 - 2026-03-14
|
|
4
|
+
|
|
5
|
+
- Fixed slideshow landscape PDF crash by removing unstable in-page canvas recompression.
|
|
6
|
+
- Improved custom theme error message (`theme not found`) for better novice UX.
|
|
7
|
+
- Added MCP `export_slideshow` tool to export image directories directly to HTML/PDF.
|
|
8
|
+
- Expanded OpenClaw skill docs/schema to include slideshow export tool and parameter hints.
|
|
9
|
+
|
|
10
|
+
## 1.1.2 - 2026-03-14
|
|
11
|
+
|
|
12
|
+
- Added auto fallback retry (`--no-sandbox`) for PDF export in `sandbox=auto` mode.
|
|
13
|
+
|
|
14
|
+
## 1.1.1 - 2026-03-14
|
|
15
|
+
|
|
16
|
+
- Fixed PDF export stability (`networkidle0` to `domcontentloaded` + font/image readiness wait).
|
|
17
|
+
- Registered `mcp` command in CLI.
|
|
18
|
+
- Fixed stdin TTY handling.
|
|
19
|
+
|
|
20
|
+
## 1.1.0 - 2026-03-14
|
|
21
|
+
|
|
22
|
+
- Implemented v2 plan: sandbox modes, DOCX fallback quality upgrades, path guard, skill/schema packaging, tests, and docs updates.
|
package/README.md
CHANGED
|
@@ -193,13 +193,14 @@ Claude Desktop 配置(`claude_desktop_config.json`):
|
|
|
193
193
|
}
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
提供
|
|
196
|
+
提供 7 个工具:
|
|
197
197
|
|
|
198
198
|
| 工具 | 功能 |
|
|
199
199
|
|------|------|
|
|
200
200
|
| `render_markdown` | Markdown → 网页预览 |
|
|
201
201
|
| `export_document` | Markdown → PDF / Word |
|
|
202
202
|
| `create_slideshow` | 图片目录 → 幻灯片 |
|
|
203
|
+
| `export_slideshow` | 图片目录 → 幻灯片 HTML / PDF |
|
|
203
204
|
| `open_file` | 智能打开(按偏好自动选格式) |
|
|
204
205
|
| `configure_user_preferences` | 设置默认偏好 |
|
|
205
206
|
| `get_user_preferences` | 读取当前偏好 |
|
|
@@ -226,7 +227,7 @@ Claude Desktop 配置(`claude_desktop_config.json`):
|
|
|
226
227
|
| 依赖 | 必需? | 用途 |
|
|
227
228
|
|------|--------|------|
|
|
228
229
|
| Node.js 18+ | 是 | 运行环境 |
|
|
229
|
-
| Puppeteer |
|
|
230
|
+
| Puppeteer | 否(按需) | PDF 导出(可选依赖;未安装时仅影响 PDF) |
|
|
230
231
|
| Pandoc | 否 | Word 导出更好看(没有会自动降级为纯 JS 方案) |
|
|
231
232
|
|
|
232
233
|
## 云环境部署
|
package/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ description: 把 Markdown 渲染成漂亮网页、导出 Word/PDF、图片做幻
|
|
|
9
9
|
|
|
10
10
|
- Markdown 渲染为可阅读网页(目录、代码高亮、表格样式)
|
|
11
11
|
- 导出 PDF / DOCX 文档
|
|
12
|
-
-
|
|
12
|
+
- 图片目录生成幻灯片并支持直接导出 PDF
|
|
13
13
|
|
|
14
14
|
## 触发条件
|
|
15
15
|
|
|
@@ -31,8 +31,17 @@ agent-reader slides ./images --auto 5
|
|
|
31
31
|
- `render_markdown`
|
|
32
32
|
- `export_document`
|
|
33
33
|
- `create_slideshow`
|
|
34
|
+
- `export_slideshow`
|
|
34
35
|
- `open_file`
|
|
35
36
|
|
|
37
|
+
### MCP 参数速查
|
|
38
|
+
|
|
39
|
+
- `render_markdown`: `content`(必填), `source_path`, `theme`, `return_content`
|
|
40
|
+
- `export_document`: `content`(必填), `format`=`pdf|docx`(必填), `source_path`, `return_content`
|
|
41
|
+
- `create_slideshow`: `image_dir`(必填), `auto_play`, `return_content`
|
|
42
|
+
- `export_slideshow`: `image_dir`(必填), `format`=`pdf|html`, `auto_play`, `return_content`
|
|
43
|
+
- `open_file`: `file_path`(必填), `open_as`=`auto|web|word|pdf|ppt`, `theme`, `auto_play`, `return_content`
|
|
44
|
+
|
|
36
45
|
## 安装
|
|
37
46
|
|
|
38
47
|
```bash
|
package/bin/agent-reader.js
CHANGED
package/openclaw-skill/SKILL.md
CHANGED
|
@@ -9,7 +9,7 @@ description: 把 Markdown 渲染成漂亮网页、导出 Word/PDF、图片做幻
|
|
|
9
9
|
|
|
10
10
|
- Markdown 渲染为可阅读网页(目录、代码高亮、表格样式)
|
|
11
11
|
- 导出 PDF / DOCX 文档
|
|
12
|
-
-
|
|
12
|
+
- 图片目录生成幻灯片并支持直接导出 PDF
|
|
13
13
|
|
|
14
14
|
## 触发条件
|
|
15
15
|
|
|
@@ -31,8 +31,17 @@ agent-reader slides ./images --auto 5
|
|
|
31
31
|
- `render_markdown`
|
|
32
32
|
- `export_document`
|
|
33
33
|
- `create_slideshow`
|
|
34
|
+
- `export_slideshow`
|
|
34
35
|
- `open_file`
|
|
35
36
|
|
|
37
|
+
### MCP 参数速查
|
|
38
|
+
|
|
39
|
+
- `render_markdown`: `content`(必填), `source_path`, `theme`, `return_content`
|
|
40
|
+
- `export_document`: `content`(必填), `format`=`pdf|docx`(必填), `source_path`, `return_content`
|
|
41
|
+
- `create_slideshow`: `image_dir`(必填), `auto_play`, `return_content`
|
|
42
|
+
- `export_slideshow`: `image_dir`(必填), `format`=`pdf|html`, `auto_play`, `return_content`
|
|
43
|
+
- `open_file`: `file_path`(必填), `open_as`=`auto|web|word|pdf|ppt`, `theme`, `auto_play`, `return_content`
|
|
44
|
+
|
|
36
45
|
## 安装
|
|
37
46
|
|
|
38
47
|
```bash
|
|
@@ -192,6 +192,74 @@
|
|
|
192
192
|
],
|
|
193
193
|
"additionalProperties": true
|
|
194
194
|
}
|
|
195
|
+
},
|
|
196
|
+
"export_slideshow": {
|
|
197
|
+
"description": "Export slideshow from an image directory into HTML or PDF",
|
|
198
|
+
"input": {
|
|
199
|
+
"type": "object",
|
|
200
|
+
"properties": {
|
|
201
|
+
"image_dir": {
|
|
202
|
+
"type": "string",
|
|
203
|
+
"description": "Absolute or relative image directory path"
|
|
204
|
+
},
|
|
205
|
+
"format": {
|
|
206
|
+
"type": "string",
|
|
207
|
+
"enum": [
|
|
208
|
+
"html",
|
|
209
|
+
"pdf"
|
|
210
|
+
],
|
|
211
|
+
"description": "Export format, default pdf"
|
|
212
|
+
},
|
|
213
|
+
"auto_play": {
|
|
214
|
+
"type": "number",
|
|
215
|
+
"description": "Autoplay interval in seconds"
|
|
216
|
+
},
|
|
217
|
+
"return_content": {
|
|
218
|
+
"type": "boolean",
|
|
219
|
+
"description": "Return file content directly"
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
"required": [
|
|
223
|
+
"image_dir"
|
|
224
|
+
],
|
|
225
|
+
"additionalProperties": false
|
|
226
|
+
},
|
|
227
|
+
"output": {
|
|
228
|
+
"type": "object",
|
|
229
|
+
"properties": {
|
|
230
|
+
"file_path": {
|
|
231
|
+
"type": "string"
|
|
232
|
+
},
|
|
233
|
+
"content_data": {
|
|
234
|
+
"type": "string"
|
|
235
|
+
},
|
|
236
|
+
"format": {
|
|
237
|
+
"type": "string",
|
|
238
|
+
"enum": [
|
|
239
|
+
"html",
|
|
240
|
+
"pdf"
|
|
241
|
+
]
|
|
242
|
+
},
|
|
243
|
+
"size": {
|
|
244
|
+
"type": "number"
|
|
245
|
+
},
|
|
246
|
+
"warnings": {
|
|
247
|
+
"type": "array",
|
|
248
|
+
"items": {
|
|
249
|
+
"type": "string"
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"image_count": {
|
|
253
|
+
"type": "number"
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
"required": [
|
|
257
|
+
"format",
|
|
258
|
+
"size",
|
|
259
|
+
"warnings"
|
|
260
|
+
],
|
|
261
|
+
"additionalProperties": true
|
|
262
|
+
}
|
|
195
263
|
}
|
|
196
264
|
}
|
|
197
265
|
}
|
package/package.json
CHANGED
package/src/core/renderer.js
CHANGED
|
@@ -173,12 +173,20 @@ async function loadStyles(theme) {
|
|
|
173
173
|
: path.resolve(themeName);
|
|
174
174
|
|
|
175
175
|
const highlightCssPath = themeName === 'dark' ? HIGHLIGHT_CSS_DARK : HIGHLIGHT_CSS_LIGHT;
|
|
176
|
+
const customThemePromise = customThemePath
|
|
177
|
+
? fs.readFile(customThemePath, 'utf8').catch((error) => {
|
|
178
|
+
if (error && error.code === 'ENOENT') {
|
|
179
|
+
throw new Error(`theme not found: ${themeName}. Use "light", "dark", or a valid CSS file path.`);
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
})
|
|
183
|
+
: Promise.resolve('');
|
|
176
184
|
|
|
177
185
|
const [builtInTheme, githubCss, highlightCss, customTheme = ''] = await Promise.all([
|
|
178
186
|
fs.readFile(builtInThemePath, 'utf8'),
|
|
179
187
|
fs.readFile(GITHUB_MARKDOWN_CSS_PATH, 'utf8'),
|
|
180
188
|
fs.readFile(highlightCssPath, 'utf8'),
|
|
181
|
-
|
|
189
|
+
customThemePromise,
|
|
182
190
|
]);
|
|
183
191
|
|
|
184
192
|
const mergedCss = `${githubCss}\n${highlightCss}\n${builtInTheme}\n${TOC_BASE_CSS}\n${customTheme}`;
|
package/src/mcp/server.js
CHANGED
|
@@ -63,6 +63,10 @@ function maybeTooLargePayload(textOrBase64) {
|
|
|
63
63
|
return byteLengthOfString(textOrBase64) > MAX_CONTENT_BYTES;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
function uniqueWarnings(warnings = []) {
|
|
67
|
+
return [...new Set(warnings)];
|
|
68
|
+
}
|
|
69
|
+
|
|
66
70
|
async function saveHtmlResult(html, outputDir, name = 'output') {
|
|
67
71
|
const htmlPath = path.join(outputDir, `${name}.html`);
|
|
68
72
|
await fs.writeFile(htmlPath, html, 'utf8');
|
|
@@ -72,7 +76,7 @@ async function saveHtmlResult(html, outputDir, name = 'output') {
|
|
|
72
76
|
|
|
73
77
|
const server = new McpServer({
|
|
74
78
|
name: 'agent-reader',
|
|
75
|
-
version: '1.1.
|
|
79
|
+
version: '1.1.4',
|
|
76
80
|
});
|
|
77
81
|
|
|
78
82
|
server.registerTool(
|
|
@@ -253,6 +257,110 @@ server.registerTool(
|
|
|
253
257
|
},
|
|
254
258
|
);
|
|
255
259
|
|
|
260
|
+
server.registerTool(
|
|
261
|
+
'export_slideshow',
|
|
262
|
+
MCP_TOOL_SCHEMAS.export_slideshow,
|
|
263
|
+
async ({
|
|
264
|
+
image_dir,
|
|
265
|
+
format = 'pdf',
|
|
266
|
+
auto_play,
|
|
267
|
+
return_content,
|
|
268
|
+
}) => {
|
|
269
|
+
try {
|
|
270
|
+
const outputDir = await createOutputDir('export-slideshow');
|
|
271
|
+
const wantsContent = Boolean(return_content);
|
|
272
|
+
const targetFormat = format === 'html' ? 'html' : 'pdf';
|
|
273
|
+
const slideshow = await createSlideshow(image_dir, {
|
|
274
|
+
autoPlay: auto_play,
|
|
275
|
+
inlineAll: wantsContent || targetFormat === 'pdf',
|
|
276
|
+
outDir: outputDir,
|
|
277
|
+
});
|
|
278
|
+
const warnings = [...(slideshow.warnings || [])];
|
|
279
|
+
|
|
280
|
+
if (targetFormat === 'html') {
|
|
281
|
+
const htmlPath = path.join(outputDir, 'slideshow.html');
|
|
282
|
+
await fs.writeFile(htmlPath, slideshow.html, 'utf8');
|
|
283
|
+
const fileSize = (await fs.stat(htmlPath)).size;
|
|
284
|
+
|
|
285
|
+
if (wantsContent) {
|
|
286
|
+
if (!maybeTooLargePayload(slideshow.html)) {
|
|
287
|
+
return toTextResult({
|
|
288
|
+
content_data: slideshow.html,
|
|
289
|
+
format: 'html',
|
|
290
|
+
size: byteLengthOfString(slideshow.html),
|
|
291
|
+
warnings: uniqueWarnings(warnings),
|
|
292
|
+
image_count: slideshow.imageCount,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return toTextResult({
|
|
297
|
+
file_path: htmlPath,
|
|
298
|
+
format: 'html',
|
|
299
|
+
size: fileSize,
|
|
300
|
+
warnings: uniqueWarnings([...warnings, 'content_too_large']),
|
|
301
|
+
image_count: slideshow.imageCount,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return toTextResult({
|
|
306
|
+
file_path: htmlPath,
|
|
307
|
+
format: 'html',
|
|
308
|
+
size: fileSize,
|
|
309
|
+
warnings: uniqueWarnings(warnings),
|
|
310
|
+
image_count: slideshow.imageCount,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const dirName = path.basename(path.resolve(image_dir));
|
|
315
|
+
const printHtmlPath = path.join(outputDir, '_print.html');
|
|
316
|
+
await fs.writeFile(printHtmlPath, slideshow.printHtml, 'utf8');
|
|
317
|
+
|
|
318
|
+
const pdf = await exportPDF(slideshow.printHtml, {
|
|
319
|
+
pageSize: 'A4',
|
|
320
|
+
landscape: true,
|
|
321
|
+
outDir: outputDir,
|
|
322
|
+
fileName: `${dirName}.pdf`,
|
|
323
|
+
htmlPath: printHtmlPath,
|
|
324
|
+
sandbox: MCP_SANDBOX_MODE,
|
|
325
|
+
});
|
|
326
|
+
warnings.push(...(pdf.warnings || []));
|
|
327
|
+
|
|
328
|
+
if (wantsContent) {
|
|
329
|
+
const fileBuffer = await fs.readFile(pdf.pdfPath);
|
|
330
|
+
const fileSize = fileBuffer.byteLength;
|
|
331
|
+
const base64 = fileBuffer.toString('base64');
|
|
332
|
+
if (!maybeTooLargePayload(base64)) {
|
|
333
|
+
return toTextResult({
|
|
334
|
+
content_data: base64,
|
|
335
|
+
format: 'pdf',
|
|
336
|
+
size: fileSize,
|
|
337
|
+
warnings: uniqueWarnings(warnings),
|
|
338
|
+
image_count: slideshow.imageCount,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return toTextResult({
|
|
343
|
+
file_path: pdf.pdfPath,
|
|
344
|
+
format: 'pdf',
|
|
345
|
+
size: fileSize,
|
|
346
|
+
warnings: uniqueWarnings([...warnings, 'content_too_large']),
|
|
347
|
+
image_count: slideshow.imageCount,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return toTextResult({
|
|
352
|
+
file_path: pdf.pdfPath,
|
|
353
|
+
format: 'pdf',
|
|
354
|
+
size: pdf.size,
|
|
355
|
+
warnings: uniqueWarnings(warnings),
|
|
356
|
+
image_count: slideshow.imageCount,
|
|
357
|
+
});
|
|
358
|
+
} catch (error) {
|
|
359
|
+
return toErrorResult(error, 'slideshow_export_failed');
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
);
|
|
363
|
+
|
|
256
364
|
server.registerTool(
|
|
257
365
|
'open_file',
|
|
258
366
|
MCP_TOOL_SCHEMAS.open_file,
|
package/src/mcp/toolSchemas.js
CHANGED
|
@@ -29,6 +29,15 @@ export const MCP_TOOL_SCHEMAS = {
|
|
|
29
29
|
return_content: z.boolean().optional().describe('Return inline HTML content directly'),
|
|
30
30
|
},
|
|
31
31
|
},
|
|
32
|
+
export_slideshow: {
|
|
33
|
+
description: 'Export slideshow from an image directory into HTML or PDF',
|
|
34
|
+
inputSchema: {
|
|
35
|
+
image_dir: z.string().describe('Absolute or relative image directory path'),
|
|
36
|
+
format: z.enum(['html', 'pdf']).optional().describe('Export format, default pdf'),
|
|
37
|
+
auto_play: z.number().optional().describe('Autoplay interval in seconds'),
|
|
38
|
+
return_content: z.boolean().optional().describe('Return file content directly'),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
32
41
|
open_file: {
|
|
33
42
|
description: 'Open a local file/path using user preference or explicit mode: web/word/pdf/ppt',
|
|
34
43
|
inputSchema: {
|