dsh-ppt 0.5.1 → 0.6.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/CHANGELOG.md +10 -0
- package/README.en.md +52 -9
- package/README.md +67 -11
- package/docs/FEATURE-PLAN-2026-10-01.md +50 -0
- package/docs/LIBREOFFICE-INTEGRATION-2026-10-01.md +69 -0
- package/lib/execution.d.ts +8 -0
- package/lib/execution.js +41 -6
- package/lib/index.d.ts +1 -1
- package/lib/index.js +5 -5
- package/lib/tools.js +134 -12
- package/lib/types.d.ts +110 -2
- package/package.json +17 -3
- package/skills/dsh-ppt/SKILL.md +8 -3
- package/skills/dsh-ppt/package.json +11 -0
- package/skills/dsh-ppt/references/advanced.md +39 -0
- package/skills/dsh-ppt/references/syntax.md +1 -1
- package/skills/dsh-ppt/references/troubleshooting.md +6 -0
- package/skills/dsh-ppt/scripts/build-deck.mjs +56 -7
- package/skills/dsh-ppt/scripts/deck-advanced.mjs +461 -0
- package/skills/dsh-ppt/scripts/deck-core.mjs +94 -49
- package/skills/dsh-ppt/scripts/deck-media.mjs +160 -0
- package/skills/dsh-ppt/scripts/deck-render.mjs +236 -0
package/lib/tools.js
CHANGED
|
@@ -1,4 +1,30 @@
|
|
|
1
1
|
import { createPptExecutors } from './execution.js';
|
|
2
|
+
/** Harness uses disjoint oneOf branches for unions, never type arrays. */
|
|
3
|
+
function compileNode(node) {
|
|
4
|
+
if (Array.isArray(node.type)) {
|
|
5
|
+
const { type, description, properties, additionalProperties, items, required, ...shared } = node;
|
|
6
|
+
return {
|
|
7
|
+
...(description !== undefined ? { description } : {}),
|
|
8
|
+
oneOf: type.map(kind => compileNode({
|
|
9
|
+
...shared, type: kind,
|
|
10
|
+
...(kind === 'object' ? {
|
|
11
|
+
...(properties !== undefined ? { properties } : {}),
|
|
12
|
+
...(additionalProperties !== undefined ? { additionalProperties } : {}),
|
|
13
|
+
...(required !== undefined ? { required } : {}),
|
|
14
|
+
} : {}),
|
|
15
|
+
...(kind === 'array' && items !== undefined ? { items } : {}),
|
|
16
|
+
})),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const compiled = { ...node };
|
|
20
|
+
if (node.properties)
|
|
21
|
+
compiled.properties = Object.fromEntries(Object.entries(node.properties).map(([key, value]) => [key, compileNode(value)]));
|
|
22
|
+
if (node.items)
|
|
23
|
+
compiled.items = compileNode(node.items);
|
|
24
|
+
if (Array.isArray(node.oneOf))
|
|
25
|
+
compiled.oneOf = node.oneOf.map(value => compileNode(value));
|
|
26
|
+
return compiled;
|
|
27
|
+
}
|
|
2
28
|
function compileParameters(spec) {
|
|
3
29
|
const properties = {};
|
|
4
30
|
const required = [];
|
|
@@ -6,19 +32,19 @@ function compileParameters(spec) {
|
|
|
6
32
|
if (prop?.required === true)
|
|
7
33
|
required.push(key);
|
|
8
34
|
const node = {};
|
|
9
|
-
if (typeof prop?.type === 'string')
|
|
35
|
+
if (typeof prop?.type === 'string' || Array.isArray(prop?.type))
|
|
10
36
|
node.type = prop.type;
|
|
11
37
|
if (typeof prop?.description === 'string')
|
|
12
38
|
node.description = prop.description;
|
|
13
39
|
if (Array.isArray(prop?.enum))
|
|
14
40
|
node.enum = prop.enum;
|
|
15
|
-
if (prop?.type === 'array' && prop.items !== null && typeof prop.items === 'object')
|
|
16
|
-
node.items =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
properties[key] = node;
|
|
41
|
+
if (prop?.type === 'array' && prop.items !== null && typeof prop.items === 'object')
|
|
42
|
+
node.items = prop.items;
|
|
43
|
+
if (prop.properties)
|
|
44
|
+
node.properties = prop.properties;
|
|
45
|
+
if (prop.additionalProperties !== undefined)
|
|
46
|
+
node.additionalProperties = prop.additionalProperties;
|
|
47
|
+
properties[key] = compileNode(node);
|
|
22
48
|
}
|
|
23
49
|
return { type: 'object', properties, ...(required.length > 0 ? { required } : {}) };
|
|
24
50
|
}
|
|
@@ -82,12 +108,60 @@ function renderThemes(value) {
|
|
|
82
108
|
return oneText(summary + '\n\n想要并排对比:ppt_themes { preview: true, outputDir: "..." } 会生成 themes-preview.html 和每套主题的 SVG 色板卡。');
|
|
83
109
|
}
|
|
84
110
|
function renderCreate(value) {
|
|
85
|
-
return oneText('dsh-ppt 已生成 ' + value.slideCount + '
|
|
111
|
+
return oneText('dsh-ppt 已生成 ' + value.slideCount + ' 页' + (value.deliveryStatus === 'draft' ? '草稿(还有待填写内容,不能作为成品交付)' : '演示文稿') + '(主题 ' + value.theme + ',语言 ' + value.language + '):\n' +
|
|
86
112
|
'HTML 网页放映:' + value.htmlPath + '\n' +
|
|
87
113
|
'PPTX 导出:' + value.pptxPath + '\n' +
|
|
88
114
|
'Manifest:' + value.jsonPath + '\n' +
|
|
89
|
-
'HTML 双击即可放映(← → 翻页 / V 演讲者视图 / S 备注 / G 缩略图总览 / F 全屏 / P 打印 / ? 快捷键);PPTX 可用 PowerPoint / WPS / Keynote 打开。'
|
|
115
|
+
'HTML 双击即可放映(← → 翻页 / V 演讲者视图 / S 备注 / G 缩略图总览 / F 全屏 / P 打印 / ? 快捷键);PPTX 可用 PowerPoint / WPS / Keynote 打开。' +
|
|
116
|
+
(value.revision !== undefined ? '\n修订号:' + value.revision + ';可撤销修改:' + value.undoAvailable + '。用 ppt_edit 修改指定页,ppt_undo 撤销。' : '') +
|
|
117
|
+
(value.quality ? '\n\n' + qualityText(value.quality) : ''));
|
|
118
|
+
}
|
|
119
|
+
function qualityText(value) {
|
|
120
|
+
return '质量检查:' + value.errorCount + ' 个错误,' + value.warningCount + ' 个提醒。\n' +
|
|
121
|
+
value.issues.slice(0, 12).map(issue => '第 ' + issue.slide + ' 页:' + issue.message + ';' + issue.suggestion).join('\n') +
|
|
122
|
+
(value.issues.length > 12 ? '\n其余提醒请查看结构化结果。' : '') + '\n' + value.note;
|
|
90
123
|
}
|
|
124
|
+
function renderCheck(value) {
|
|
125
|
+
return oneText(qualityText(value) + '\nPPTX 渲染:' + (value.verification?.pptxRender === 'rendered' ? '已核验当前文件的渲染输出' : '尚未验证') +
|
|
126
|
+
';视觉检查:需查看实际画面。' + (value.render?.message ? '\n' + value.render.message : '') +
|
|
127
|
+
(value.render?.missingFonts?.length ? '\n缺失字体:' + value.render.missingFonts.join('、') + '。请替换为可用字体,重新生成并检查每页;解决前需标注字体问题。' : ''));
|
|
128
|
+
}
|
|
129
|
+
function renderPreview(value) {
|
|
130
|
+
if (!value.ok)
|
|
131
|
+
return oneText((value.message || 'PPTX 尚未渲染。') + (value.installationHint ? '\n' + value.installationHint : ''));
|
|
132
|
+
return oneText('PPTX 已渲染 ' + value.slideCount + ' 页(' + value.backend + '):\n' +
|
|
133
|
+
(value.pngPaths?.length ? '逐页 PNG:\n' + value.pngPaths.slice(0, 6).join('\n') + (value.pngPaths.length > 6 ? '\n其余页面见结构化结果。' : '') + '\n' : '') +
|
|
134
|
+
(value.pdfPath ? 'PDF:' + value.pdfPath + '\n' : '') + '渲染收据:' + value.receiptPath +
|
|
135
|
+
'\n缺失字体:' + (value.missingFonts?.join('、') || '引擎未报告缺失字体') +
|
|
136
|
+
(value.missingFonts?.length ? '\n请先替换为环境和目标机器可用字体,重新生成并渲染检查;解决前不能声称已验收。' : '') +
|
|
137
|
+
'\n请查看实际画面,确认文字、图片和图表后再交付。原可编辑 PPTX 保留。');
|
|
138
|
+
}
|
|
139
|
+
const imageSchema = { type: ['object', 'string', 'null'], properties: {
|
|
140
|
+
src: { type: 'string', description: 'Local PNG/JPEG path relative to the session cwd, or image data URI. Embedded into all output files.' },
|
|
141
|
+
alt: { type: 'string' }, fit: { type: 'string', enum: ['contain', 'cover'] }, caption: { type: 'string' },
|
|
142
|
+
}, additionalProperties: false };
|
|
143
|
+
const chartSchema = { type: ['object', 'null'], properties: {
|
|
144
|
+
kind: { type: 'string', enum: ['column', 'bar', 'line', 'pie'] },
|
|
145
|
+
categories: { type: 'array', items: { type: ['string', 'number'] } },
|
|
146
|
+
series: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, values: { type: 'array', items: { type: ['number', 'string'] } } }, required: ['name', 'values'], additionalProperties: false } },
|
|
147
|
+
rows: { type: 'array', items: { type: 'array', items: { type: ['string', 'number'] } }, description: 'Alternative: header row [category, series names], then category/value rows.' },
|
|
148
|
+
unit: { type: 'string' }, caption: { type: 'string' },
|
|
149
|
+
}, additionalProperties: false };
|
|
150
|
+
const brandProperties = {
|
|
151
|
+
name: { type: 'string' }, primaryColor: { type: 'string' }, backgroundColor: { type: 'string' }, textColor: { type: 'string' },
|
|
152
|
+
fontFamily: { type: 'string', description: 'One installed font family; choose a font available on the recipient computer.' },
|
|
153
|
+
logo: { type: ['string', 'null'], description: 'Local PNG/JPEG logo path; null clears logo during edit.' }, footer: { type: 'string' },
|
|
154
|
+
};
|
|
155
|
+
const slideProperties = {
|
|
156
|
+
layout: { type: 'string', enum: ['cover', 'section', 'bullets', 'statement', 'quote', 'table', 'closing', 'image', 'image-left', 'image-right', 'chart'] },
|
|
157
|
+
title: { type: 'string' }, subtitle: { type: 'string' }, kicker: { type: 'string' }, text: { type: 'string' }, notes: { type: 'string' },
|
|
158
|
+
bullets: { type: 'array', items: { type: 'string' } }, rows: { type: 'array', items: { type: 'array', items: { type: ['string', 'number'] } } },
|
|
159
|
+
image: imageSchema, chart: chartSchema,
|
|
160
|
+
};
|
|
161
|
+
const projectParameters = {
|
|
162
|
+
deckPath: { type: 'string', required: true, description: 'Path to a dsh-ppt .json project, relative to this session cwd or absolute. Arbitrary external PPTX editing is not supported.' },
|
|
163
|
+
expectedRevision: { type: 'integer', description: 'Use revision returned by ppt_create/ppt_check to prevent overwriting another edit.' },
|
|
164
|
+
};
|
|
91
165
|
/** Assemble presentation schemas, rendering and the session-aware executors. */
|
|
92
166
|
export function buildPptTools(config) {
|
|
93
167
|
const executors = createPptExecutors(config);
|
|
@@ -109,14 +183,16 @@ export function buildPptTools(config) {
|
|
|
109
183
|
},
|
|
110
184
|
{
|
|
111
185
|
name: 'ppt_create',
|
|
112
|
-
description: '
|
|
186
|
+
description: 'Generate a standalone HTML slideshow, editable 16:9 PPTX and JSON project from prepared Markdown or structured slides. Organize actual facts and content before calling; this deterministic generator does not invent missing facts or research them. Supports five themes, local images, native editable charts and shared branding. Check and visually review artifacts before delivery; template-only output is an unfilled draft. 中文:先组织事实与内容,再生成可直接放映和继续编辑的三件套;支持图片、原生图表与品牌,交付前检查成品。',
|
|
113
187
|
parameters: compileParameters({
|
|
114
188
|
title: { type: 'string', required: true, description: 'Deck title (used for the cover and file names).' },
|
|
115
189
|
content: { type: 'string', description: 'Markdown content: one sentence, a paragraph, or a full document. First # heading becomes the cover title; ## headings become slides; -/* lists become bullets; | ... | tables paginate with repeated headers (8 data rows/page, up to 8 columns and 60 characters/cell); > blockquotes become quote slides; <!-- 备注: ... --> comments become speaker notes. Required unless slides is provided.' },
|
|
116
190
|
theme: { type: 'string', description: 'Visual theme id: swiss / velvet / data / soft / bold. Default data. See ppt_themes.' },
|
|
117
191
|
lang: { type: 'string', description: 'UI language of the generated player: zh (default), en, or bilingual. Content language is whatever you write.' },
|
|
118
192
|
motion: { type: 'string', enum: ['on', 'off'], description: 'Slide transitions plus bullet entrance animations: on (default) or off for a fully static deck.' },
|
|
119
|
-
slides: { type: 'array', items: { type: 'object', additionalProperties: true }, description: '
|
|
193
|
+
slides: { type: 'array', items: { type: 'object', properties: slideProperties, additionalProperties: true }, description: 'Structured slides including image/image-left/image-right and chart. Images: {src, alt, fit: contain|cover, caption}. Charts: {kind: column|bar|line|pie, categories, series:[{name,values}]} or rows with header. Tables paginate at 8 data rows. Keep full content editable; use images only for actual photos/screenshots/logos.' },
|
|
194
|
+
template: { type: 'string', enum: ['weekly', 'defense', 'project', 'pitch'], description: 'Scenario reference from ppt_templates. Provide finished content/slides following its outline. Template alone creates a clearly marked draft with unfilled slots, never a finished presentation.' },
|
|
195
|
+
brand: { type: 'object', properties: brandProperties, additionalProperties: false, description: 'Shared brand: #RRGGBB primary/background/text colors, fontFamily, logo and footer. Applied to HTML and PPTX.' },
|
|
120
196
|
outputDir: { type: 'string', description: 'Directory to write the files into. Default: session working directory (or the plugin outputDir config).' },
|
|
121
197
|
fileName: { type: 'string', description: 'Base file name for the three artifacts. Default: sanitized deck title.' },
|
|
122
198
|
overwrite: { type: 'boolean', description: 'Replace an existing same-name HTML/PPTX/JSON trio. Default false: choose a unique numeric suffix instead.' },
|
|
@@ -127,5 +203,51 @@ export function buildPptTools(config) {
|
|
|
127
203
|
},
|
|
128
204
|
execute: executors.create,
|
|
129
205
|
},
|
|
206
|
+
{
|
|
207
|
+
name: 'ppt_templates',
|
|
208
|
+
description: 'List weekly report, thesis defense, project update and pitch scenario outlines and draft structures. Use as internal content planning references; fill actual facts before delivering a finished deck. 中文:查看周报、答辩、项目汇报和路演的结构参考,组织并填写真实内容后再调用 ppt_create 交付成品。',
|
|
209
|
+
parameters: compileParameters({ lang: { type: 'string', description: 'zh / en / bilingual, default zh.' } }),
|
|
210
|
+
output: { schema: { type: 'object', additionalProperties: true }, render: (_args, value) => oneText(JSON.stringify(value, null, 2)) },
|
|
211
|
+
execute: executors.templates,
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
name: 'ppt_edit',
|
|
215
|
+
description: 'Modify selected slides in an existing dsh-ppt JSON project, preserving other pages and stable IDs. Each edit uses a 1-based slide number or ID and a patch of changed fields. Regenerates the HTML/PPTX/JSON trio atomically, embeds new images, stores undo history. Use ppt_check first and expectedRevision. 中文:按页码或 ID 修改指定页,其他页不变,支持撤销;可同步调整品牌。',
|
|
216
|
+
parameters: compileParameters({ ...projectParameters,
|
|
217
|
+
edits: { type: 'array', items: { type: 'object', properties: { slide: { type: ['integer', 'string'], description: '1-based page number or stable slide ID' }, patch: { type: 'object', properties: slideProperties, additionalProperties: false } }, required: ['slide', 'patch'], additionalProperties: false } },
|
|
218
|
+
brand: { type: ['object', 'null'], properties: brandProperties, additionalProperties: false, description: 'Merge shared branding. null clears all branding. Empty footer clears footer; logo:null clears logo.' },
|
|
219
|
+
}),
|
|
220
|
+
output: { schema: createResultSchema, render: (_args, value) => renderCreate(value) },
|
|
221
|
+
execute: executors.edit,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'ppt_undo',
|
|
225
|
+
description: 'Undo the most recent edit in a dsh-ppt JSON project, restoring slides, charts, embedded images and branding together. Revision increases so stale edits cannot overwrite the undo. Keeps up to 20 edits. 中文:撤销最近一次修改,恢复正文、图表、图片和品牌设置。',
|
|
226
|
+
parameters: compileParameters(projectParameters),
|
|
227
|
+
output: { schema: createResultSchema, render: (_args, value) => renderCreate(value) },
|
|
228
|
+
execute: executors.undo,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: 'ppt_check',
|
|
232
|
+
description: 'Inspect a dsh-ppt JSON project without rewriting artifacts. Report revision, slide IDs, page-specific errors and warnings for dense text, estimated overflow, small table fonts, missing/low-resolution images, chart labels, contrast and unfilled template slots. Static estimates require final visual review in browser and PowerPoint/WPS. 中文:交付前检查工程,定位具体页的问题并给出修改建议,不改文件。',
|
|
233
|
+
parameters: compileParameters({ deckPath: projectParameters.deckPath,
|
|
234
|
+
renderReceipt: { type: 'string', description: 'Optional receiptPath returned by ppt_render. Rechecks current PPTX hash and every rendered output; never implies a visual pass.' },
|
|
235
|
+
}),
|
|
236
|
+
output: { schema: { type: 'object', additionalProperties: true }, render: (_args, value) => renderCheck(value) },
|
|
237
|
+
execute: executors.check,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
name: 'ppt_render',
|
|
241
|
+
description: 'Read the final PPTX and render all pages to PNG, PDF, or both using optional official @deepseek-ai/libreoffice-kit@0.1.3. Returns unavailable plus installation guidance when absent; ordinary deck creation remains usable. Retains original editable PPTX and creates a separate unique output folder and integrity receipt. Reports missing fonts. Inspect actual pages before delivery. 中文:把最终 PPTX 渲染为逐页图片和 PDF,报告缺失字体;需安装可选官方引擎,渲染成功仍需检查画面。',
|
|
242
|
+
parameters: compileParameters({
|
|
243
|
+
pptxPath: { type: 'string', required: true, description: 'Final .pptx path, absolute or relative to session cwd.' },
|
|
244
|
+
outputDir: { type: 'string', description: 'Base output folder. Existing folders are preserved; creates a unique sibling when needed. Default <deck>-render.' },
|
|
245
|
+
format: { type: 'string', enum: ['png', 'pdf', 'both'], description: 'png (default), pdf, or both.' },
|
|
246
|
+
width: { type: 'integer', description: 'PNG target width 320–3840, default 1440; scales from actual page dimensions.' },
|
|
247
|
+
timeoutMs: { type: 'integer', description: 'Whole rendering deadline in milliseconds, 1000–300000, default 120000.' },
|
|
248
|
+
}),
|
|
249
|
+
output: { schema: { type: 'object', additionalProperties: true }, render: (_args, value) => renderPreview(value) },
|
|
250
|
+
execute: executors.render,
|
|
251
|
+
},
|
|
130
252
|
];
|
|
131
253
|
}
|
package/lib/types.d.ts
CHANGED
|
@@ -1,8 +1,99 @@
|
|
|
1
1
|
/** dsh-ppt 的公共类型。 */
|
|
2
2
|
export type PptThemeId = 'swiss' | 'velvet' | 'data' | 'soft' | 'bold';
|
|
3
3
|
export type PptLanguage = 'zh' | 'en' | 'bilingual';
|
|
4
|
-
export type PptSlideLayout = 'cover' | 'section' | 'bullets' | 'statement' | 'quote' | 'table' | 'closing';
|
|
4
|
+
export type PptSlideLayout = 'cover' | 'section' | 'bullets' | 'statement' | 'quote' | 'table' | 'closing' | 'image' | 'image-left' | 'image-right' | 'chart';
|
|
5
|
+
export type PptTemplateId = 'weekly' | 'defense' | 'project' | 'pitch';
|
|
6
|
+
export interface PptImageSpec {
|
|
7
|
+
src?: string;
|
|
8
|
+
assetId?: string;
|
|
9
|
+
alt?: string;
|
|
10
|
+
fit?: 'contain' | 'cover';
|
|
11
|
+
caption?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PptChartSpec {
|
|
14
|
+
kind?: 'column' | 'bar' | 'line' | 'pie';
|
|
15
|
+
categories?: Array<string | number>;
|
|
16
|
+
series?: Array<{
|
|
17
|
+
name: string;
|
|
18
|
+
values: Array<string | number>;
|
|
19
|
+
}>;
|
|
20
|
+
rows?: Array<Array<string | number>>;
|
|
21
|
+
unit?: string;
|
|
22
|
+
caption?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface PptBrand {
|
|
25
|
+
name?: string;
|
|
26
|
+
primaryColor?: string;
|
|
27
|
+
backgroundColor?: string;
|
|
28
|
+
textColor?: string;
|
|
29
|
+
fontFamily?: string;
|
|
30
|
+
logo?: string | null;
|
|
31
|
+
footer?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface PptQualityIssue {
|
|
34
|
+
slide: number;
|
|
35
|
+
slideId?: string;
|
|
36
|
+
severity: 'warning' | 'error';
|
|
37
|
+
code: string;
|
|
38
|
+
message: string;
|
|
39
|
+
suggestion: string;
|
|
40
|
+
}
|
|
41
|
+
export interface PptQualityResult {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
slideCount: number;
|
|
44
|
+
errorCount: number;
|
|
45
|
+
warningCount: number;
|
|
46
|
+
issues: PptQualityIssue[];
|
|
47
|
+
note: string;
|
|
48
|
+
}
|
|
49
|
+
export interface PptVerification {
|
|
50
|
+
static: 'checked';
|
|
51
|
+
pptxRender: 'not-verified' | 'rendered';
|
|
52
|
+
visual: 'not-verified';
|
|
53
|
+
}
|
|
54
|
+
export interface PptRenderArgs {
|
|
55
|
+
pptxPath: string;
|
|
56
|
+
outputDir?: string;
|
|
57
|
+
format?: 'png' | 'pdf' | 'both';
|
|
58
|
+
width?: number;
|
|
59
|
+
timeoutMs?: number;
|
|
60
|
+
}
|
|
61
|
+
export interface PptRenderResult {
|
|
62
|
+
ok: boolean;
|
|
63
|
+
status: 'unavailable' | 'not-verified' | 'rendered';
|
|
64
|
+
backend?: string;
|
|
65
|
+
rendererVersion?: string;
|
|
66
|
+
sourceSha256?: string;
|
|
67
|
+
outputDir?: string;
|
|
68
|
+
reason?: string;
|
|
69
|
+
slideCount?: number;
|
|
70
|
+
pngPaths?: string[];
|
|
71
|
+
pdfPath?: string;
|
|
72
|
+
receiptPath?: string;
|
|
73
|
+
missingFonts?: string[];
|
|
74
|
+
message?: string;
|
|
75
|
+
installationHint?: string;
|
|
76
|
+
visual?: 'not-verified';
|
|
77
|
+
}
|
|
78
|
+
export interface PptCheckResult extends PptQualityResult {
|
|
79
|
+
verification: PptVerification;
|
|
80
|
+
render?: PptRenderResult;
|
|
81
|
+
}
|
|
82
|
+
export interface PptEditArgs {
|
|
83
|
+
deckPath: string;
|
|
84
|
+
edits?: Array<{
|
|
85
|
+
slide: number | string;
|
|
86
|
+
patch: Partial<Omit<PptSlideSpec, 'id'>>;
|
|
87
|
+
}>;
|
|
88
|
+
brand?: PptBrand | null;
|
|
89
|
+
expectedRevision?: number;
|
|
90
|
+
}
|
|
91
|
+
export interface PptProjectArgs {
|
|
92
|
+
deckPath: string;
|
|
93
|
+
expectedRevision?: number;
|
|
94
|
+
}
|
|
5
95
|
export interface PptSlideSpec {
|
|
96
|
+
id?: string;
|
|
6
97
|
layout?: PptSlideLayout;
|
|
7
98
|
title?: string;
|
|
8
99
|
subtitle?: string;
|
|
@@ -13,6 +104,8 @@ export interface PptSlideSpec {
|
|
|
13
104
|
rows?: Array<Array<string | number>>;
|
|
14
105
|
/** 演讲者备注;写入 HTML 备注面板与 PPTX 原生备注页。 */
|
|
15
106
|
notes?: string;
|
|
107
|
+
image?: PptImageSpec | string | null;
|
|
108
|
+
chart?: PptChartSpec | null;
|
|
16
109
|
}
|
|
17
110
|
export interface PptConfig {
|
|
18
111
|
/** 默认输出目录;调用 ppt_create 时可用 outputDir 覆盖。相对路径按会话工作目录解析。 */
|
|
@@ -38,6 +131,8 @@ export interface PptCreateArgs {
|
|
|
38
131
|
fileName?: string;
|
|
39
132
|
/** 是否覆盖同名三件套;默认 false,同名时自动选择唯一后缀。 */
|
|
40
133
|
overwrite?: boolean;
|
|
134
|
+
template?: PptTemplateId;
|
|
135
|
+
brand?: PptBrand;
|
|
41
136
|
}
|
|
42
137
|
export interface PptThemeInfo {
|
|
43
138
|
id: string;
|
|
@@ -80,9 +175,22 @@ export interface PptCreateResult {
|
|
|
80
175
|
htmlPath: string;
|
|
81
176
|
pptxPath: string;
|
|
82
177
|
jsonPath: string;
|
|
178
|
+
deckId?: string;
|
|
179
|
+
revision?: number;
|
|
180
|
+
undoAvailable?: number;
|
|
181
|
+
deliveryStatus?: 'draft' | 'ready-for-review';
|
|
182
|
+
quality?: PptQualityResult;
|
|
183
|
+
verification?: PptVerification;
|
|
83
184
|
}
|
|
84
|
-
/**
|
|
185
|
+
/** Shared generator and optional renderer exposed to the plugin. */
|
|
85
186
|
export interface DeckEngine {
|
|
187
|
+
buildDeckAsync?(options: Record<string, unknown>): Promise<PptCreateResult>;
|
|
188
|
+
listTemplates(lang?: string): unknown[];
|
|
189
|
+
editDeck(options: Record<string, unknown>): Promise<PptCreateResult>;
|
|
190
|
+
undoDeck(options: Record<string, unknown>): Promise<PptCreateResult>;
|
|
191
|
+
checkDeck(options: Record<string, unknown>): PptQualityResult;
|
|
192
|
+
checkDeckAsync?(options: Record<string, unknown>): Promise<PptCheckResult>;
|
|
193
|
+
renderDeck(options: Record<string, unknown>): Promise<PptRenderResult>;
|
|
86
194
|
buildDeck(options: Record<string, unknown>): PptCreateResult;
|
|
87
195
|
buildThemePreview(options: Record<string, unknown>): PptThemePreviewResult;
|
|
88
196
|
listThemes(lang?: string): PptThemeInfo[];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ppt",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "DSH 演示文稿插件:
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "DSH 演示文稿插件:HTML 与可编辑 PPTX、图文排版、原生图表、按页编辑撤销、质量检查与可选官方 PNG/PDF 渲染。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"./skills/*": "./skills/*",
|
|
14
14
|
"./deck-core": "./skills/dsh-ppt/scripts/deck-core.mjs",
|
|
15
|
+
"./deck-advanced": "./skills/dsh-ppt/scripts/deck-advanced.mjs",
|
|
16
|
+
"./deck-render": "./skills/dsh-ppt/scripts/deck-render.mjs",
|
|
15
17
|
"./build-deck": "./skills/dsh-ppt/scripts/build-deck.mjs",
|
|
16
18
|
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
17
19
|
"./package.json": "./package.json"
|
|
@@ -19,6 +21,7 @@
|
|
|
19
21
|
"files": [
|
|
20
22
|
"lib",
|
|
21
23
|
"skills",
|
|
24
|
+
"docs",
|
|
22
25
|
"cordis.patch.yml",
|
|
23
26
|
"README.md",
|
|
24
27
|
"README.en.md",
|
|
@@ -66,5 +69,16 @@
|
|
|
66
69
|
},
|
|
67
70
|
"homepage": "https://github.com/STARDUSTLC666/dsh-ppt#readme",
|
|
68
71
|
"author": "stardustlc",
|
|
69
|
-
"packageManager": "pnpm@11.7.0"
|
|
72
|
+
"packageManager": "pnpm@11.7.0",
|
|
73
|
+
"dependencies": {
|
|
74
|
+
"@office-kit/pptx": "0.21.0"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"@deepseek-ai/libreoffice-kit": "0.1.3"
|
|
78
|
+
},
|
|
79
|
+
"peerDependenciesMeta": {
|
|
80
|
+
"@deepseek-ai/libreoffice-kit": {
|
|
81
|
+
"optional": true
|
|
82
|
+
}
|
|
83
|
+
}
|
|
70
84
|
}
|
package/skills/dsh-ppt/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dsh-ppt
|
|
3
3
|
description: "Turn one sentence or a Markdown document into a complete, presentation-ready deck: a standalone HTML web slideshow plus an editable PPTX export, with 5 built-in visual themes (Swiss Pulse / Velvet Standard / Data Drift / Soft Signal / Maximalist Type), slide transitions + bullet entrance animations (motion, on by default), and bilingual Chinese/English support. Use when the user asks for a PPT, slides, deck, keynote, 演示文稿, 幻灯片, 汇报, 提案, 路演, 培训材料, or wants to turn a document into a presentation. 中文:把一句话或一篇文档变成完整演示文稿(HTML 网页放映 + PPTX 导出),内置 5 套视觉主题、页间转场与要点入场动画,中英双语。"
|
|
4
|
-
compatibility: "
|
|
4
|
+
compatibility: "Node ^22.19.0 or >=24.0.0. Images/charts use @office-kit/pptx@0.21.0. Optional PNG/PDF renderer: @deepseek-ai/libreoffice-kit@0.1.3. Cross-harness: copy the full directory and run npm install --ignore-scripts there."
|
|
5
5
|
allowed-tools: "Bash, Read, Write, Edit"
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -19,6 +19,8 @@ allowed-tools: "Bash, Read, Write, Edit"
|
|
|
19
19
|
- 内容语言由你撰写;`lang` 只决定界面文字。
|
|
20
20
|
- 先选主题再构建;不确定就用默认 `data`。
|
|
21
21
|
- 交付前逐项过一遍文末「质量门禁」。
|
|
22
|
+
- 目标是可用成品:先组织真实内容,再调用生成器;未填模板必须标注草稿,不编造缺失事实。
|
|
23
|
+
- 渲染报告缺失字体时,替换为环境和接收方机器可用字体,重新生成并逐页检查;未解决需标注字体问题,不能声称已验收。
|
|
22
24
|
|
|
23
25
|
## 核心流水线
|
|
24
26
|
|
|
@@ -32,7 +34,7 @@ allowed-tools: "Bash, Read, Write, Edit"
|
|
|
32
34
|
- 跨 harness:`node <skill-dir>/scripts/build-deck.mjs --title "标题" --content deck.md --theme data --lang zh --out dist`。
|
|
33
35
|
- 动效默认开(页间转场 + 要点逐条入场);严肃/打印场景传 `motion: 'off'`。
|
|
34
36
|
→ 用表格 / 金句 / 备注 / 结构化 slides 前读 `references/syntax.md`。
|
|
35
|
-
5. **Verify
|
|
37
|
+
5. **Verify 校验与修正**:调 `ppt_check` 检查具体页;在浏览器操作放映、总览和备注,查看图片/图表。若可选官方引擎可用,调 `ppt_render` 读取最终 PPTX 生成逐页 PNG/PDF,逐页看画面。修正用 `ppt_edit`,以 `expectedRevision` 防冲突;需要时 `ppt_undo`。修改后重新渲染,以收据复核当前文件。文件头/结构通过不等同于视觉验收,静态估算、渲染、视觉检查必须分开说明。
|
|
36
38
|
6. **Deliver 交付**:给用户三个绝对路径,说明 HTML 直接放映(← → 翻页 · F 全屏 · G 总览 · S 备注 · P 打印),PPTX 用 PowerPoint / WPS / Keynote 打开(备注在演示者视图可见,bullets 页放映时逐条点击出现)。
|
|
37
39
|
|
|
38
40
|
## 按需装载索引
|
|
@@ -42,6 +44,7 @@ allowed-tools: "Bash, Read, Write, Edit"
|
|
|
42
44
|
| 写大纲 / 正文前 | `references/copywriting.md` | 叙事骨架、单页规则、双语规则 |
|
|
43
45
|
| 选主题拿不准 | `references/themes.md` | 5 套主题色板 + 情绪决策树 |
|
|
44
46
|
| 用表格/金句/备注/结构化 slides | `references/syntax.md` | Markdown 解析、进阶语法、slides JSON、motion 开关 |
|
|
47
|
+
| 图片/图表/模板/品牌/编辑/渲染 | `references/advanced.md` | 参数、限制、草稿与成品、收据语义 |
|
|
45
48
|
| 交付异常 | `references/troubleshooting.md` | 症状 → 处理对照表 |
|
|
46
49
|
|
|
47
50
|
## 质量门禁(交付前逐项确认)
|
|
@@ -53,10 +56,12 @@ allowed-tools: "Bash, Read, Write, Edit"
|
|
|
53
56
|
- [ ] 中文内容无错别字;英文标题用 Title Case。
|
|
54
57
|
- [ ] 最后一页有可执行的行动号召,不只是「谢谢」。
|
|
55
58
|
- [ ] 文件已写到用户工作区,路径为绝对路径。
|
|
59
|
+
- [ ] 没有未填模板;保留真实数据来源,检查每页画面而非只检查生成成功。
|
|
60
|
+
- [ ] 图片嵌入成功,图表与原始数据一致;渲染收据匹配最终 PPTX,说明尚未验证的部分。
|
|
56
61
|
|
|
57
62
|
## 跨 harness 安装
|
|
58
63
|
|
|
59
|
-
把整个 `dsh-ppt` 技能目录复制到目标 agent
|
|
64
|
+
把整个 `dsh-ppt` 技能目录复制到目标 agent 的技能目录,使用 Node `^22.19.0 || >=24.0.0`,在该目录运行 `npm install --ignore-scripts`。纯文本可直接运行;图片/图表/品牌导出需要 Office Kit,PNG/PDF 需另外安装可选官方引擎:
|
|
60
65
|
|
|
61
66
|
| Agent | 技能目录 |
|
|
62
67
|
| --- | --- |
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-ppt-skill",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Standalone dsh-ppt skill dependencies for image/chart export",
|
|
7
|
+
"dependencies": { "@office-kit/pptx": "0.21.0" },
|
|
8
|
+
"peerDependencies": { "@deepseek-ai/libreoffice-kit": "0.1.3" },
|
|
9
|
+
"peerDependenciesMeta": { "@deepseek-ai/libreoffice-kit": { "optional": true } },
|
|
10
|
+
"engines": { "node": "^22.19.0 || >=24.0.0" }
|
|
11
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# 图文、图表、工程编辑与渲染
|
|
2
|
+
|
|
3
|
+
Agent 先准备实际内容,再生成可放映 HTML 与可编辑 PPTX。用户无需填写 JSON。以下是工具接口参考。
|
|
4
|
+
|
|
5
|
+
## 创建
|
|
6
|
+
|
|
7
|
+
`ppt_templates` 提供 weekly、defense、project、pitch 四种结构参考。`ppt_create` 的 `template` 单独使用时生成待填草稿,返回 `deliveryStatus:draft`;提供完成的 content/slides 才能开始成品验收。
|
|
8
|
+
|
|
9
|
+
`slides` 新增 image/image-left/image-right/chart 布局。图片示例:`{layout:"image-left",title:"新版流程更短",image:{src:"assets/flow.png",alt:"新版流程截图",fit:"contain"},bullets:["可直接生成","可修改指定页"]}`。PNG/JPEG 本地路径按会话 cwd 解析,亦支持 data URI;每张5MiB/3200万像素、合计32MiB。图片嵌入工程和输出,移动原文件后仍可使用。contain完整显示,cover居中裁切。外链/SVG需先由明确授权的其他工具准备,不自动下载。
|
|
10
|
+
|
|
11
|
+
图表示例:`{layout:"chart",title:"完成量逐月增加",chart:{kind:"column",categories:["七月","八月","九月"],series:[{name:"完成量",values:[3,5,9]}],unit:"项"}}`。支持 column/bar/line/pie,也可用带表头 rows。长度必须一致,值必须有限;pie仅一个非负系列、正总和。原生PPTX图表包含编辑数据工作簿,HTML有SVG与读屏数据表。
|
|
12
|
+
|
|
13
|
+
共享品牌 `brand:{primaryColor:"#2C9F87",fontFamily:"Microsoft YaHei",logo:"logo.png",footer:"产品团队 · 2026"}`。还可设背景/文字色及name。选择接收方可用字体;字体诊断不自动安装字体。
|
|
14
|
+
|
|
15
|
+
## 修改与撤销
|
|
16
|
+
|
|
17
|
+
先 `ppt_check {deckPath:"report.json"}` 取得当前revision和页面ID。修改:`ppt_edit {deckPath:"report.json",expectedRevision:0,edits:[{slide:3,patch:{title:"新标题",bullets:["事实一","行动"]}}]}`。slide为1起始页码或ID,其他页保留;重复指定页拒绝。可单独修改brand;brand:null清空品牌,logo:null清空Logo,空footer清空页脚。
|
|
18
|
+
|
|
19
|
+
编辑会原子更新整套HTML/PPTX/JSON,失败回滚。历史最多20次。`ppt_undo {deckPath:"report.json",expectedRevision:1}` 恢复上次状态,包含图片/图表/品牌;revision继续增长,旧修改不可覆盖撤销。仅编辑本插件JSON工程,不导入任意外部PPTX进行修改。编辑不能新增/删除页;表格扩大到需要分页时会要求另建文稿。
|
|
20
|
+
|
|
21
|
+
## 检查与渲染
|
|
22
|
+
|
|
23
|
+
`ppt_check` 定位页面问题,包括密度、估计溢出、7–8列表格14pt、图片缺失/损坏/分辨率、图表标签和对比度。6列以内原生表格17pt。静态估算不能保证字体或视觉布局。
|
|
24
|
+
|
|
25
|
+
可选安装 `npm install --ignore-scripts @deepseek-ai/libreoffice-kit@0.1.3`。Windows还需相应架构的VC++v14运行库。`ppt_render {pptxPath:"report.pptx",format:"both"}` 读取最终PPTX,输出PNG/PDF/收据,不改源文件。默认png,width默认1440(320–3840),timeoutMs默认120000(1000–300000);最多120页,输入64MiB、输出128MiB、单张16MP。缺失引擎返回unavailable及安装说明,普通创建仍可用。
|
|
26
|
+
|
|
27
|
+
查看每页PNG及HTML,必要时在实际PowerPoint/WPS检查编辑、备注和动画。LibreOffice不保证与Office逐像素一致,PNG/PDF不保留动画。成功渲染仍为 `visual:not-verified`,不会自动声称视觉通过。
|
|
28
|
+
|
|
29
|
+
把返回receiptPath传给 `ppt_check {deckPath:"report.json",renderReceipt:".../render-receipt.json"}`。源文件与所有输出的摘要必须匹配;修改/删除后失效,重新渲染。收据是本地完整性记录,非签名证明。
|
|
30
|
+
|
|
31
|
+
## CLI
|
|
32
|
+
|
|
33
|
+
`--slides @slides.json`、`--brand @brand.json`、`--template weekly`。
|
|
34
|
+
|
|
35
|
+
`--edit report.json --edits @edits.json --revision 0`、`--undo report.json --revision 1`。
|
|
36
|
+
|
|
37
|
+
`--check report.json`、`--render report.pptx --format both`、`--check report.json --render-receipt receipt.json`。
|
|
38
|
+
|
|
39
|
+
默认渲染目录在PPTX旁;显式 `--out` 指定基目录,已有目录追加后缀。引擎不可用/静态错误/显式收据失效返回非零退出码。
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
]
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
`layout`
|
|
40
|
+
`layout` 支持 `cover | section | bullets | statement | quote | table | closing | image | image-left | image-right | chart`;每页可选 `notes`,表格用 `rows`(首行为表头)。结构化表格自动分页,备注只放第一页。分页后超过 maxSlides 会报错,最多120页。图文、图表、品牌及按页编辑见 `advanced.md`。
|
|
41
41
|
|
|
42
42
|
## 动效(motion)
|
|
43
43
|
|
|
@@ -11,3 +11,9 @@
|
|
|
11
11
|
| 双语界面 | `lang: bilingual` 只双语化界面;内容双语由 agent 在写作阶段完成 |
|
|
12
12
|
| 放映没有动画 | `motion` 被设为 `off`;默认 `on` 时 HTML 有转场、PPTX 要点逐条点击出现 |
|
|
13
13
|
| HTML 打印要点缺失 | 打印样式已强制显示全部要点;若仍缺失检查浏览器是否屏蔽了动画样式 |
|
|
14
|
+
| 图片、图表或品牌导出缺少依赖 | 插件重新安装;独立技能目录运行 npm install --ignore-scripts 安装 Office Kit 0.21.0 |
|
|
15
|
+
| ppt_render 返回 unavailable | 在插件项目或技能目录安装可选官方 Kit 0.1.3;Windows检查相应VC++v14运行库 |
|
|
16
|
+
| 收据 not-verified | 源PPTX或输出发生变化、缺失、版本不同;用当前PPTX重新渲染,不沿用旧结论 |
|
|
17
|
+
| 修订号冲突 | 重新用ppt_check读取当前工程,再按新revision编辑 |
|
|
18
|
+
| 模板还有待填写 | 补充实际事实/依据/行动;按草稿说明,不作为成品交付 |
|
|
19
|
+
| 渲染报告缺失字体 | 替换为环境和目标机器可用字体,重新生成并逐页检查;未解决需标注字体问题,不能声称已验收 |
|