dsh-ppt-studio 1.1.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/LICENSE +21 -0
- package/README.md +480 -0
- package/agent-presets/ppt/agent.cordis.yml +308 -0
- package/agent-presets/ppt/preset.yml +3 -0
- package/cordis.patch.yml +29 -0
- package/docs/00-/350/256/276/350/256/241/346/272/220.md +537 -0
- package/docs/01-/351/234/200/346/261/202/344/270/216/347/233/256/346/240/207.md +136 -0
- package/docs/02-/346/212/200/346/234/257/346/212/245/345/221/212.md +483 -0
- package/docs/03-/346/233/264/346/226/260/346/227/245/345/277/227.md +2898 -0
- package/docs/04-/350/267/257/347/272/277/345/233/276/344/270/216/351/207/214/347/250/213/347/242/221.md +113 -0
- package/docs/05-/350/277/255/344/273/243/346/265/201/347/250/213.md +210 -0
- package/docs/06-/350/257/204/345/256/241/344/270/216/346/265/213/350/257/225.md +296 -0
- package/docs/fidelity-report.md +225 -0
- package/examples/fx/fx-mini/deck.yaml +39 -0
- package/examples/fx/fx-mini/pages/01.yaml +6 -0
- package/examples/fx/fx-mini/pages/02.yaml +2 -0
- package/examples/fx/fx-mini/pages/03.yaml +6 -0
- package/examples/fx/fx-pro/deck.yaml +48 -0
- package/examples/fx/fx-pro/pages/01_cover.yaml +40 -0
- package/examples/fx/fx-pro/pages/02_arch.yaml +55 -0
- package/examples/fx/fx-pro/pages/03_table.yaml +20 -0
- package/examples/fx/fx-pro/pages/04_chart.yaml +40 -0
- package/examples/fx/fx-pro/pages/05_timeline.yaml +71 -0
- package/examples/fx/fx-pro/pages/06_longtext.yaml +13 -0
- package/examples/fx/fx-pro/pages/07_safearea.yaml +33 -0
- package/examples/fx/fx-pro/pages/08_contrast.yaml +22 -0
- package/examples/fx/fx-pro/pages/09_custgeom.yaml +32 -0
- package/examples/fx/fx-pro/pages/10_numbers.yaml +25 -0
- package/examples/fx/fx-pro/pages/11_section.yaml +20 -0
- package/examples/fx/fx-pro/pages/12_summary.yaml +57 -0
- package/examples/fx/fx-pro/preview/01_pages_01_cover.html +1 -0
- package/examples/fx/fx-pro/preview/02_pages_02_arch.html +3 -0
- package/examples/fx/fx-pro/preview/03_pages_03_table.html +1 -0
- package/examples/fx/fx-pro/preview/04_pages_04_chart.html +3 -0
- package/examples/fx/fx-pro/preview/05_pages_05_timeline.html +2 -0
- package/examples/fx/fx-pro/preview/06_pages_06_longtext.html +4 -0
- package/examples/fx/fx-pro/preview/07_pages_07_safearea.html +2 -0
- package/examples/fx/fx-pro/preview/08_pages_08_contrast.html +1 -0
- package/examples/fx/fx-pro/preview/09_pages_09_custgeom.html +1 -0
- package/examples/fx/fx-pro/preview/10_pages_10_numbers.html +1 -0
- package/examples/fx/fx-pro/preview/11_pages_11_section.html +1 -0
- package/examples/fx/fx-pro/preview/12_pages_12_summary.html +1 -0
- package/examples/fx/fx-pro/preview/deck.html +10 -0
- package/examples/fx/fx-pro/preview/layout.json +2325 -0
- package/examples/fx/fx-pro/preview/measured.json +814 -0
- package/examples/fx/fx-pro.pptx +0 -0
- package/examples/fx/ren-single/01.png +0 -0
- package/examples/fx/ren-spliced/01.png +0 -0
- package/examples/fx/ren-spliced/03.png +0 -0
- package/examples/fx/seed.pptx +0 -0
- package/examples/fx/single.pptx +0 -0
- package/examples/fx/spliced.pptx +0 -0
- package/examples/smoke/deck.yaml +26 -0
- package/examples/smoke/imported/deck.yaml +30 -0
- package/examples/smoke/imported/import-styles.json +126 -0
- package/examples/smoke/imported/pages/slide_01.yaml +31 -0
- package/examples/smoke/imported/pages/slide_02.yaml +38 -0
- package/examples/smoke/imported/pages/slide_03.yaml +55 -0
- package/examples/smoke/imported/preview-rt/01_pages_slide_01.html +1 -0
- package/examples/smoke/imported/preview-rt/02_pages_slide_02.html +1 -0
- package/examples/smoke/imported/preview-rt/03_pages_slide_03.html +1 -0
- package/examples/smoke/imported/preview-rt/deck.html +1 -0
- package/examples/smoke/imported/preview-rt/layout.json +434 -0
- package/examples/smoke/imported/reference/previews/01.png +0 -0
- package/examples/smoke/imported/reference/previews/02.png +0 -0
- package/examples/smoke/imported/reference/previews/03.png +0 -0
- package/examples/smoke/imported/source.pptx +0 -0
- package/examples/smoke/media-test.png +0 -0
- package/examples/smoke/out-smoke.pptx +0 -0
- package/examples/smoke/pages/01_cover.yaml +27 -0
- package/examples/smoke/pages/02_content.yaml +42 -0
- package/examples/smoke/pages/03_chart.yaml +35 -0
- package/examples/smoke/preview/01_pages_01_cover.html +1 -0
- package/examples/smoke/preview/02_pages_02_content.html +1 -0
- package/examples/smoke/preview/03_pages_03_chart.html +1 -0
- package/examples/smoke/preview/deck.html +1 -0
- package/examples/smoke/preview/layout.json +378 -0
- package/lib/autodeclare.js +40 -0
- package/lib/commands.js +161 -0
- package/lib/crosscheck.js +300 -0
- package/lib/imgmeta.js +55 -0
- package/lib/index.js +239 -0
- package/lib/measurement.js +209 -0
- package/lib/msrender.js +123 -0
- package/lib/pptd/export-pptx.js +686 -0
- package/lib/pptd/import-pptx.js +774 -0
- package/lib/pptd/layout.js +209 -0
- package/lib/pptd/render-html.js +254 -0
- package/lib/pptd/schema.js +518 -0
- package/lib/pptd/svgCharts.js +147 -0
- package/lib/pptxPy.js +205 -0
- package/lib/preset-delivery.js +195 -0
- package/lib/preview-server.js +164 -0
- package/lib/router.js +165 -0
- package/lib/scaffold.js +315 -0
- package/lib/skill.js +174 -0
- package/lib/splice.js +219 -0
- package/lib/state.js +88 -0
- package/lib/surgical.js +369 -0
- package/lib/templates.js +400 -0
- package/lib/tools.js +955 -0
- package/lib/verify.js +828 -0
- package/lib/xmljs.js +112 -0
- package/lib/zips.js +117 -0
- package/package.json +81 -0
- package/scripts/audit-manual-facts.mjs +294 -0
- package/scripts/audit-template-fidelity.mjs +162 -0
- package/scripts/bench-m2.mjs +48 -0
- package/scripts/build-templates.mjs +63 -0
- package/scripts/build.mjs +14 -0
- package/scripts/build.sh +7 -0
- package/scripts/check-lib-freshness.mjs +70 -0
- package/scripts/check-preset.mjs +189 -0
- package/scripts/check-tracked-lf.mjs +84 -0
- package/scripts/dbg-import.mjs +13 -0
- package/scripts/dbg-media.mjs +10 -0
- package/scripts/dbg-tpl-inventory.mjs +23 -0
- package/scripts/dump-workflow-baseline.mjs +38 -0
- package/scripts/e2e-1.0.mjs +129 -0
- package/scripts/eval-skills-blind.mjs +91 -0
- package/scripts/eval-skills-score.mjs +129 -0
- package/scripts/export-orig-templates.ps1 +17 -0
- package/scripts/fixtures/workflow-baseline.json +300 -0
- package/scripts/fixtures.mjs +501 -0
- package/scripts/import-user-templates.mjs +60 -0
- package/scripts/install-desktop.mjs +312 -0
- package/scripts/install.mjs +209 -0
- package/scripts/migrate-templates-dualtrack.mjs +71 -0
- package/scripts/preflight-1.0.mjs +198 -0
- package/scripts/probe-asset-freshness.mjs +57 -0
- package/scripts/probe-effect-semantics.mjs +69 -0
- package/scripts/probe-reparse-safety.mjs +32 -0
- package/scripts/rebuild-templates-c11.mjs +69 -0
- package/scripts/regression-real.mjs +84 -0
- package/scripts/release-sync.mjs +425 -0
- package/scripts/shot-templates.mjs +49 -0
- package/scripts/smoke.mjs +2512 -0
- package/scripts/verify-bundle-install.mjs +281 -0
- package/scripts/verify-fresh-install.mjs +260 -0
- package/skills/ppt-studio-copy/SKILL.md +139 -0
- package/skills/ppt-studio-craft/SKILL.md +171 -0
- package/skills/ppt-studio-data/SKILL.md +173 -0
- package/skills/ppt-studio-manual/SKILL.md +104 -0
- package/templates/academic-white/deck.yaml +24 -0
- package/templates/academic-white/pages/_chart.yaml +43 -0
- package/templates/academic-white/pages/_compare.yaml +37 -0
- package/templates/academic-white/pages/_content.yaml +35 -0
- package/templates/academic-white/pages/_cover.yaml +28 -0
- package/templates/academic-white/pages/_ending.yaml +28 -0
- package/templates/academic-white/pages/_flow.yaml +61 -0
- package/templates/academic-white/preview.png +0 -0
- package/templates/academic-white/template.yaml +14 -0
- package/templates/business-blue/deck.yaml +28 -0
- package/templates/business-blue/pages/_chart.yaml +36 -0
- package/templates/business-blue/pages/_compare.yaml +45 -0
- package/templates/business-blue/pages/_content.yaml +80 -0
- package/templates/business-blue/pages/_cover.yaml +39 -0
- package/templates/business-blue/pages/_ending.yaml +32 -0
- package/templates/business-blue/pages/_flow.yaml +87 -0
- package/templates/business-blue/preview.png +0 -0
- package/templates/business-blue/template.yaml +14 -0
- package/templates/pitch-bold/deck.yaml +23 -0
- package/templates/pitch-bold/pages/_chart.yaml +32 -0
- package/templates/pitch-bold/pages/_compare.yaml +36 -0
- package/templates/pitch-bold/pages/_content.yaml +58 -0
- package/templates/pitch-bold/pages/_cover.yaml +31 -0
- package/templates/pitch-bold/pages/_ending.yaml +27 -0
- package/templates/pitch-bold/pages/_flow.yaml +46 -0
- package/templates/pitch-bold/preview.png +0 -0
- package/templates/pitch-bold/template.yaml +14 -0
- package/templates/tech-dark/deck.yaml +24 -0
- package/templates/tech-dark/pages/_chart.yaml +27 -0
- package/templates/tech-dark/pages/_compare.yaml +38 -0
- package/templates/tech-dark/pages/_content.yaml +51 -0
- package/templates/tech-dark/pages/_cover.yaml +30 -0
- package/templates/tech-dark/pages/_ending.yaml +25 -0
- package/templates/tech-dark/pages/_flow.yaml +80 -0
- package/templates/tech-dark/preview.png +0 -0
- package/templates/tech-dark/template.yaml +14 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
{
|
|
2
|
+
"size": {
|
|
3
|
+
"width": 960,
|
|
4
|
+
"height": 540
|
|
5
|
+
},
|
|
6
|
+
"theme": {
|
|
7
|
+
"colors": {
|
|
8
|
+
"primary": "#2563EB",
|
|
9
|
+
"accent": "#F59E0B",
|
|
10
|
+
"text": "#1F2937",
|
|
11
|
+
"bg": "#F8FAFC"
|
|
12
|
+
},
|
|
13
|
+
"textStyles": {
|
|
14
|
+
"title": {
|
|
15
|
+
"fontSize": 40,
|
|
16
|
+
"color": "$text",
|
|
17
|
+
"bold": true
|
|
18
|
+
},
|
|
19
|
+
"body": {
|
|
20
|
+
"fontSize": 18,
|
|
21
|
+
"color": "$text",
|
|
22
|
+
"lineHeight": 1.5
|
|
23
|
+
},
|
|
24
|
+
"caption": {
|
|
25
|
+
"fontSize": 12,
|
|
26
|
+
"color": "#64748B"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"grid": {
|
|
30
|
+
"base": 8
|
|
31
|
+
},
|
|
32
|
+
"safeArea": null,
|
|
33
|
+
"minFontSize": null,
|
|
34
|
+
"themeConformance": "strict"
|
|
35
|
+
},
|
|
36
|
+
"pages": [
|
|
37
|
+
{
|
|
38
|
+
"index": 0,
|
|
39
|
+
"pageNo": 1,
|
|
40
|
+
"file": "pages/01_cover.yaml",
|
|
41
|
+
"name": "pages/01_cover",
|
|
42
|
+
"background": {
|
|
43
|
+
"type": "solid",
|
|
44
|
+
"color": "#F8FAFC"
|
|
45
|
+
},
|
|
46
|
+
"safeArea": {
|
|
47
|
+
"top": 0,
|
|
48
|
+
"bottom": 0,
|
|
49
|
+
"left": 0,
|
|
50
|
+
"right": 0
|
|
51
|
+
},
|
|
52
|
+
"expectedOverlaps": [],
|
|
53
|
+
"expectedOutOfSafeArea": [],
|
|
54
|
+
"contrastExempt": [],
|
|
55
|
+
"overlapMode": "declared",
|
|
56
|
+
"elements": [
|
|
57
|
+
{
|
|
58
|
+
"id": "hero-rect",
|
|
59
|
+
"kind": "shape",
|
|
60
|
+
"bounds": {
|
|
61
|
+
"x": 0,
|
|
62
|
+
"y": 0,
|
|
63
|
+
"w": 960,
|
|
64
|
+
"h": 120
|
|
65
|
+
},
|
|
66
|
+
"shape": "rect",
|
|
67
|
+
"fill": "#2563EB",
|
|
68
|
+
"rotation": 0
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": "title",
|
|
72
|
+
"kind": "text",
|
|
73
|
+
"bounds": {
|
|
74
|
+
"x": 80,
|
|
75
|
+
"y": 180,
|
|
76
|
+
"w": 700,
|
|
77
|
+
"h": 90
|
|
78
|
+
},
|
|
79
|
+
"style": {
|
|
80
|
+
"fontSize": 40,
|
|
81
|
+
"color": "#1F2937",
|
|
82
|
+
"bold": true,
|
|
83
|
+
"lineHeight": 1.2,
|
|
84
|
+
"wrap": true
|
|
85
|
+
},
|
|
86
|
+
"metrics": {
|
|
87
|
+
"textW": 508.79999999999995,
|
|
88
|
+
"textH": 48,
|
|
89
|
+
"lines": 1,
|
|
90
|
+
"lineWidths": [
|
|
91
|
+
508.79999999999995
|
|
92
|
+
],
|
|
93
|
+
"overflowY": 0,
|
|
94
|
+
"overflowX": 0
|
|
95
|
+
},
|
|
96
|
+
"text": "季度复盘:增长引擎与风险"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"id": "subtitle",
|
|
100
|
+
"kind": "text",
|
|
101
|
+
"bounds": {
|
|
102
|
+
"x": 80,
|
|
103
|
+
"y": 290,
|
|
104
|
+
"w": 600,
|
|
105
|
+
"h": 60
|
|
106
|
+
},
|
|
107
|
+
"style": {
|
|
108
|
+
"fontSize": 18,
|
|
109
|
+
"color": "#F59E0B",
|
|
110
|
+
"lineHeight": 1.5,
|
|
111
|
+
"wrap": true
|
|
112
|
+
},
|
|
113
|
+
"metrics": {
|
|
114
|
+
"textW": 170.10000000000002,
|
|
115
|
+
"textH": 27,
|
|
116
|
+
"lines": 1,
|
|
117
|
+
"lineWidths": [
|
|
118
|
+
148.5
|
|
119
|
+
],
|
|
120
|
+
"overflowY": 0,
|
|
121
|
+
"overflowX": 0
|
|
122
|
+
},
|
|
123
|
+
"text": "2026 Q3 · 内部汇报"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
"id": "deco",
|
|
127
|
+
"kind": "shape",
|
|
128
|
+
"bounds": {
|
|
129
|
+
"x": 780,
|
|
130
|
+
"y": 360,
|
|
131
|
+
"w": 120,
|
|
132
|
+
"h": 120
|
|
133
|
+
},
|
|
134
|
+
"shape": "ellipse",
|
|
135
|
+
"fill": "#F59E0B",
|
|
136
|
+
"rotation": 0
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"index": 1,
|
|
142
|
+
"pageNo": 2,
|
|
143
|
+
"file": "pages/02_content.yaml",
|
|
144
|
+
"name": "pages/02_content",
|
|
145
|
+
"background": {
|
|
146
|
+
"type": "solid",
|
|
147
|
+
"color": "#F8FAFC"
|
|
148
|
+
},
|
|
149
|
+
"safeArea": {
|
|
150
|
+
"top": 0,
|
|
151
|
+
"bottom": 0,
|
|
152
|
+
"left": 0,
|
|
153
|
+
"right": 0
|
|
154
|
+
},
|
|
155
|
+
"expectedOverlaps": [
|
|
156
|
+
{
|
|
157
|
+
"pair": [
|
|
158
|
+
"metric-rect",
|
|
159
|
+
"metric"
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"expectedOutOfSafeArea": [],
|
|
164
|
+
"contrastExempt": [],
|
|
165
|
+
"overlapMode": "declared",
|
|
166
|
+
"elements": [
|
|
167
|
+
{
|
|
168
|
+
"id": "page-title",
|
|
169
|
+
"kind": "text",
|
|
170
|
+
"bounds": {
|
|
171
|
+
"x": 60,
|
|
172
|
+
"y": 40,
|
|
173
|
+
"w": 840,
|
|
174
|
+
"h": 50
|
|
175
|
+
},
|
|
176
|
+
"style": {
|
|
177
|
+
"fontSize": 28,
|
|
178
|
+
"color": "#1F2937",
|
|
179
|
+
"bold": true,
|
|
180
|
+
"lineHeight": 1.2,
|
|
181
|
+
"wrap": true
|
|
182
|
+
},
|
|
183
|
+
"metrics": {
|
|
184
|
+
"textW": 118.72,
|
|
185
|
+
"textH": 33.6,
|
|
186
|
+
"lines": 1,
|
|
187
|
+
"lineWidths": [
|
|
188
|
+
118.72
|
|
189
|
+
],
|
|
190
|
+
"overflowY": 0,
|
|
191
|
+
"overflowX": 0
|
|
192
|
+
},
|
|
193
|
+
"text": "关键进展"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"id": "body-a",
|
|
197
|
+
"kind": "text",
|
|
198
|
+
"bounds": {
|
|
199
|
+
"x": 60,
|
|
200
|
+
"y": 130,
|
|
201
|
+
"w": 420,
|
|
202
|
+
"h": 200
|
|
203
|
+
},
|
|
204
|
+
"style": {
|
|
205
|
+
"fontSize": 18,
|
|
206
|
+
"color": "#1F2937",
|
|
207
|
+
"lineHeight": 1.5,
|
|
208
|
+
"wrap": true
|
|
209
|
+
},
|
|
210
|
+
"metrics": {
|
|
211
|
+
"textW": 816.3000000000001,
|
|
212
|
+
"textH": 54,
|
|
213
|
+
"lines": 2,
|
|
214
|
+
"lineWidths": [
|
|
215
|
+
429.3,
|
|
216
|
+
343.8
|
|
217
|
+
],
|
|
218
|
+
"overflowY": 0,
|
|
219
|
+
"overflowX": 396
|
|
220
|
+
},
|
|
221
|
+
"text": "线上增长 34%,主要来自新渠道投放;NPS 提升 12 分;复购率升至 41%。供应链成本环比下降 8%。"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"id": "metric-rect",
|
|
225
|
+
"kind": "shape",
|
|
226
|
+
"bounds": {
|
|
227
|
+
"x": 540,
|
|
228
|
+
"y": 130,
|
|
229
|
+
"w": 360,
|
|
230
|
+
"h": 80
|
|
231
|
+
},
|
|
232
|
+
"shape": "rect",
|
|
233
|
+
"fill": "#2563EB",
|
|
234
|
+
"rotation": 0
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"id": "metric",
|
|
238
|
+
"kind": "text",
|
|
239
|
+
"bounds": {
|
|
240
|
+
"x": 540,
|
|
241
|
+
"y": 150,
|
|
242
|
+
"w": 360,
|
|
243
|
+
"h": 40
|
|
244
|
+
},
|
|
245
|
+
"style": {
|
|
246
|
+
"fontSize": 22,
|
|
247
|
+
"color": "#FFFFFF",
|
|
248
|
+
"bold": true,
|
|
249
|
+
"align": "center",
|
|
250
|
+
"lineHeight": 1.2,
|
|
251
|
+
"wrap": true
|
|
252
|
+
},
|
|
253
|
+
"metrics": {
|
|
254
|
+
"textW": 112.19999999999999,
|
|
255
|
+
"textH": 26.4,
|
|
256
|
+
"lines": 1,
|
|
257
|
+
"lineWidths": [
|
|
258
|
+
103.4
|
|
259
|
+
],
|
|
260
|
+
"overflowY": 0,
|
|
261
|
+
"overflowX": 0
|
|
262
|
+
},
|
|
263
|
+
"text": "+34% 增长"
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"id": "table-b",
|
|
267
|
+
"kind": "table",
|
|
268
|
+
"bounds": {
|
|
269
|
+
"x": 60,
|
|
270
|
+
"y": 380,
|
|
271
|
+
"w": 840,
|
|
272
|
+
"h": 120
|
|
273
|
+
},
|
|
274
|
+
"cols": 4,
|
|
275
|
+
"rows": 3,
|
|
276
|
+
"fontPt": 11,
|
|
277
|
+
"metrics": {
|
|
278
|
+
"overflowY": -52.8,
|
|
279
|
+
"lines": 4,
|
|
280
|
+
"textH": 67
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
"index": 2,
|
|
287
|
+
"pageNo": 3,
|
|
288
|
+
"file": "pages/03_chart.yaml",
|
|
289
|
+
"name": "pages/03_chart",
|
|
290
|
+
"background": {
|
|
291
|
+
"type": "solid",
|
|
292
|
+
"color": "#F8FAFC"
|
|
293
|
+
},
|
|
294
|
+
"safeArea": {
|
|
295
|
+
"top": 0,
|
|
296
|
+
"bottom": 0,
|
|
297
|
+
"left": 0,
|
|
298
|
+
"right": 0
|
|
299
|
+
},
|
|
300
|
+
"expectedOverlaps": [],
|
|
301
|
+
"expectedOutOfSafeArea": [],
|
|
302
|
+
"contrastExempt": [],
|
|
303
|
+
"overlapMode": "declared",
|
|
304
|
+
"elements": [
|
|
305
|
+
{
|
|
306
|
+
"id": "page-title",
|
|
307
|
+
"kind": "text",
|
|
308
|
+
"bounds": {
|
|
309
|
+
"x": 60,
|
|
310
|
+
"y": 40,
|
|
311
|
+
"w": 840,
|
|
312
|
+
"h": 50
|
|
313
|
+
},
|
|
314
|
+
"style": {
|
|
315
|
+
"fontSize": 28,
|
|
316
|
+
"color": "#1F2937",
|
|
317
|
+
"bold": true,
|
|
318
|
+
"lineHeight": 1.2,
|
|
319
|
+
"wrap": true
|
|
320
|
+
},
|
|
321
|
+
"metrics": {
|
|
322
|
+
"textW": 194.04000000000002,
|
|
323
|
+
"textH": 33.6,
|
|
324
|
+
"lines": 1,
|
|
325
|
+
"lineWidths": [
|
|
326
|
+
171.64000000000001
|
|
327
|
+
],
|
|
328
|
+
"overflowY": 0,
|
|
329
|
+
"overflowX": 0
|
|
330
|
+
},
|
|
331
|
+
"text": "渠道 GMV 走势"
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"id": "chart-c",
|
|
335
|
+
"kind": "chart",
|
|
336
|
+
"bounds": {
|
|
337
|
+
"x": 60,
|
|
338
|
+
"y": 130,
|
|
339
|
+
"w": 840,
|
|
340
|
+
"h": 330
|
|
341
|
+
},
|
|
342
|
+
"chartType": "bar",
|
|
343
|
+
"colors": [
|
|
344
|
+
"#2563EB",
|
|
345
|
+
"#F59E0B"
|
|
346
|
+
]
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"id": "caption",
|
|
350
|
+
"kind": "text",
|
|
351
|
+
"bounds": {
|
|
352
|
+
"x": 60,
|
|
353
|
+
"y": 480,
|
|
354
|
+
"w": 840,
|
|
355
|
+
"h": 30
|
|
356
|
+
},
|
|
357
|
+
"style": {
|
|
358
|
+
"fontSize": 12,
|
|
359
|
+
"color": "#64748B",
|
|
360
|
+
"lineHeight": 1.2,
|
|
361
|
+
"wrap": true
|
|
362
|
+
},
|
|
363
|
+
"metrics": {
|
|
364
|
+
"textW": 235.79999999999995,
|
|
365
|
+
"textH": 14.399999999999999,
|
|
366
|
+
"lines": 1,
|
|
367
|
+
"lineWidths": [
|
|
368
|
+
231
|
|
369
|
+
],
|
|
370
|
+
"overflowY": 0,
|
|
371
|
+
"overflowX": 0
|
|
372
|
+
},
|
|
373
|
+
"text": "数据来源:内部经营报表(2026-09 月报)"
|
|
374
|
+
}
|
|
375
|
+
]
|
|
376
|
+
}
|
|
377
|
+
]
|
|
378
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 一键声明(反馈 D2 ★★):把警告级未声明重叠对写入页面 expectedOverlaps。
|
|
3
|
+
* - 保留源文件注释(parseDocument + setIn,不重排全文件)。
|
|
4
|
+
* - 内容互压(content-collision)不会出现在 collectDeclarable 中,必须手工修复。
|
|
5
|
+
*/
|
|
6
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
7
|
+
import YAML from 'yaml'
|
|
8
|
+
import { collectDeclarable } from './verify.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param ctx resolveDeck 结果(pages[].file 为页面 yaml 绝对路径)
|
|
12
|
+
* @param layout renderDeck 的 layout(pages[] 含 elements/expectedOverlaps/size)
|
|
13
|
+
* @returns [{ page, added }]
|
|
14
|
+
*/
|
|
15
|
+
export async function applyAutoDeclare(ctx, layout) {
|
|
16
|
+
const added = []
|
|
17
|
+
for (const pageL of layout.pages) {
|
|
18
|
+
const pairs = collectDeclarable(pageL, layout.size)
|
|
19
|
+
if (!pairs.length) continue
|
|
20
|
+
const file = ctx.pages[pageL.index].file
|
|
21
|
+
const text = await readFile(file, 'utf8')
|
|
22
|
+
const doc = YAML.parseDocument(text)
|
|
23
|
+
// yaml@2 的 doc.get() 返回 AST 节点(YAMLSeq,无 .map);其 toJS() 裸调用还会抛
|
|
24
|
+
// "A document argument is required"(需要 doc 上下文)→ 统一走 doc.toJS()(Document 级,纯 JS 值)
|
|
25
|
+
const data = doc.toJS() ?? {}
|
|
26
|
+
const list = Array.isArray(data.expectedOverlaps) ? data.expectedOverlaps : []
|
|
27
|
+
const existing = list.map((p) => ({
|
|
28
|
+
pair: [String(p?.pair?.[0]), String(p?.pair?.[1])],
|
|
29
|
+
}))
|
|
30
|
+
const exSet = new Set(existing.map((p) => [p.pair[0], p.pair[1]].sort().join('×')))
|
|
31
|
+
const add = pairs
|
|
32
|
+
.filter(([a, b]) => !exSet.has([a, b].sort().join('×')))
|
|
33
|
+
.map(([a, b]) => ({ pair: [a, b] }))
|
|
34
|
+
if (!add.length) continue
|
|
35
|
+
doc.setIn(['expectedOverlaps'], doc.createNode([...existing, ...add], { keepScalarTypes: true }))
|
|
36
|
+
await writeFile(file, String(doc))
|
|
37
|
+
added.push({ page: pageL.index + 1, added: add.length, file })
|
|
38
|
+
}
|
|
39
|
+
return added
|
|
40
|
+
}
|
package/lib/commands.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /ppt 斜杠命令面(命令 > 语义;命令写入会话/项目状态)。
|
|
3
|
+
* /ppt → 状态查询
|
|
4
|
+
* /ppt on|off → 强制进入/退出工作流
|
|
5
|
+
* /ppt free|mid|strict → 强制协作模式
|
|
6
|
+
* /ppt fidelity strict|auto|free [--page N / --dir D]
|
|
7
|
+
* /ppt review none|points|every
|
|
8
|
+
* /ppt engine pptd|python-pptx|pptxgenjs
|
|
9
|
+
* /ppt quality quick|standard|audit
|
|
10
|
+
* /ppt pause-after outline|layout|pages|overall [--dir D]
|
|
11
|
+
* /ppt help
|
|
12
|
+
*/
|
|
13
|
+
import { loadSession, saveSession, loadProject, saveProject } from './state.js'
|
|
14
|
+
|
|
15
|
+
export function registerCommands(ctx) {
|
|
16
|
+
ctx.commands.register({
|
|
17
|
+
name: 'ppt',
|
|
18
|
+
description: 'PPT 工作流控制:进入/退出、快速模式、协作模式、引擎、质量、暂停点',
|
|
19
|
+
input: { hint: '[on|off|quick|normal|free|mid|strict|fidelity <v>|review <v>|engine <v>|quality <v>|pause-after <v>|help]' },
|
|
20
|
+
handler: (invocation) => handle(invocation),
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function handle(invocation) {
|
|
25
|
+
const sessionId = invocation.agent.session?.id ?? 'default'
|
|
26
|
+
const input = invocation.rawInput.trim()
|
|
27
|
+
const state = await loadSession(sessionId)
|
|
28
|
+
const [cmdRaw, ...rest] = input.split(/\s+/)
|
|
29
|
+
const cmd = (cmdRaw ?? '').toLowerCase()
|
|
30
|
+
const args = rest.join(' ').trim()
|
|
31
|
+
const dir = argValue(args, '--dir')
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (cmd === '' || cmd === 'status') return textStatus(state, dir, await projectSummary(dir))
|
|
35
|
+
if (cmd === 'help') {
|
|
36
|
+
return ok('PPT 工作流命令:/ppt [on|off|free|mid|strict|fidelity <v>|review <v>|engine <v>|quality <v>|pause-after <v>|help]。语义检测自动进入;命令强制优先。')
|
|
37
|
+
}
|
|
38
|
+
if (cmd === 'on') { state.routing = 'on'; state.workflowActive = true; await save(); return ok('✓ PPT 工作流已强制进入(语义退出已屏蔽)') }
|
|
39
|
+
if (cmd === 'off') {
|
|
40
|
+
state.routing = 'off'; state.workflowActive = false
|
|
41
|
+
await save()
|
|
42
|
+
return ok('✓ PPT 工作流已退出(PPT 任务将按标准模式能力处理)')
|
|
43
|
+
}
|
|
44
|
+
if (cmd === 'free' || cmd === 'mid' || cmd === 'strict') {
|
|
45
|
+
state.mode = cmd
|
|
46
|
+
await save()
|
|
47
|
+
return ok(`✓ 协作模式=${cmd}(下次任务生效;free 可跳过询问环节)`)
|
|
48
|
+
}
|
|
49
|
+
if (cmd === 'quick') {
|
|
50
|
+
state.quick = true
|
|
51
|
+
await save()
|
|
52
|
+
return ok('✓ 快速模式已开启:低 token 快交付——跳过视觉定调/素材搜索/视觉审阅迭代;数字门禁照跑;回完整模式用 /ppt normal')
|
|
53
|
+
}
|
|
54
|
+
if (cmd === 'normal') {
|
|
55
|
+
state.quick = false
|
|
56
|
+
await save()
|
|
57
|
+
return ok('✓ 已回到完整模式(视觉定调/素材/审阅迭代恢复)')
|
|
58
|
+
}
|
|
59
|
+
if (cmd === 'fidelity') {
|
|
60
|
+
const v = (args.split(' ')[0] ?? '').toLowerCase()
|
|
61
|
+
if (!['strict', 'auto', 'free'].includes(v)) return err('fidelity 取值 strict|auto|free')
|
|
62
|
+
state.fidelity = v
|
|
63
|
+
await save()
|
|
64
|
+
const pageN = argValue(args, '--page')
|
|
65
|
+
if (pageN && dir) {
|
|
66
|
+
const proj = await loadProject(dir)
|
|
67
|
+
proj.spec = proj.spec ?? {}
|
|
68
|
+
const idx = Number(pageN) - 1
|
|
69
|
+
for (const p of (proj.spec.pages ?? [])) { void p }
|
|
70
|
+
await saveProject(dir, proj)
|
|
71
|
+
return ok(`✓ 会话忠实度=${v}${pageN ? `(--page ${pageN} 已记录,页面级 fidelity 由模型写入 spec.pages)` : ''}`)
|
|
72
|
+
}
|
|
73
|
+
return ok(`✓ 内容忠实度=${v}`)
|
|
74
|
+
}
|
|
75
|
+
if (cmd === 'review') {
|
|
76
|
+
const v = (args.split(' ')[0] ?? '').toLowerCase()
|
|
77
|
+
if (!['none', 'points', 'every'].includes(v)) return err('review 取值 none|points|every')
|
|
78
|
+
state.review = v
|
|
79
|
+
await save()
|
|
80
|
+
return ok(`✓ 审阅频率=${v}`)
|
|
81
|
+
}
|
|
82
|
+
if (cmd === 'engine') {
|
|
83
|
+
const v = (args.split(' ')[0] ?? '').toLowerCase()
|
|
84
|
+
// pptxgenjs **未实现**(v1.0 前按计划不动)。旧实现把它收下、回执"已记录(待接入)"并写进会话状态,
|
|
85
|
+
// 而导出侧根本不认它 ⇒ 用户以为选了引擎,实际静默按 pptd 跑。未实现就明确拒绝,不装作成功。
|
|
86
|
+
if (v === 'pptxgenjs') return err('pptxgenjs 第三引擎**未实现**(v1.0 前按计划不动,见 docs/04)——不会静默切到 pptd。可用:auto|pptd|python-pptx')
|
|
87
|
+
if (!['auto', 'pptd', 'python-pptx'].includes(v)) return err('engine 取值 auto|pptd|python-pptx')
|
|
88
|
+
state.engine = v
|
|
89
|
+
await save()
|
|
90
|
+
return ok(`✓ 引擎=${v}(auto = pptd 主引擎 + 硬失败时兜底 python-pptx;此设置会被 ppt_export 采纳)`)
|
|
91
|
+
}
|
|
92
|
+
if (cmd === 'quality') {
|
|
93
|
+
const v = (args.split(' ')[0] ?? '').toLowerCase()
|
|
94
|
+
if (!['quick', 'standard', 'audit'].includes(v)) return err('quality 取值 quick|standard|audit')
|
|
95
|
+
state.quality = v
|
|
96
|
+
await save()
|
|
97
|
+
if (dir) { const proj = await loadProject(dir); proj.quality = v; await saveProject(dir, proj) }
|
|
98
|
+
return ok(`✓ 质量模式=${v}`)
|
|
99
|
+
}
|
|
100
|
+
if (cmd === 'template') {
|
|
101
|
+
const v = (args.split(' ')[0] ?? '').trim()
|
|
102
|
+
if (!v) {
|
|
103
|
+
const { listTemplates } = await import('./templates.js')
|
|
104
|
+
const list = await listTemplates()
|
|
105
|
+
if (!list.length) return err('模板库为空(templates/ 缺失)')
|
|
106
|
+
state.template = undefined
|
|
107
|
+
await save()
|
|
108
|
+
return ok(`可用模板(${list.length} 套):${list.map((t) => `${t.id}=${t.name}`).join('、')}\n用法:/ppt template <id>(记录本会话默认模板;用 ppt_templates 看完整清单与预览图)`)
|
|
109
|
+
}
|
|
110
|
+
const { templateWorkspace } = await import('./templates.js')
|
|
111
|
+
try {
|
|
112
|
+
const t = await templateWorkspace(v)
|
|
113
|
+
state.template = v
|
|
114
|
+
await save()
|
|
115
|
+
return ok(`✓ 本会话默认模板=${t.meta.name ?? v}(${v})——S0/S2 优先使用;新建工作区:ppt_new dir=<目录> template=${v}`)
|
|
116
|
+
} catch (e) {
|
|
117
|
+
return err(String(e?.message ?? e))
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (cmd === 'pause-after') {
|
|
121
|
+
const v = (args.split(' ')[0] ?? '').toLowerCase()
|
|
122
|
+
if (!['outline', 'layout', 'pages', 'overall', 'none'].includes(v)) return err('pause-after 取值 outline|layout|pages|overall|none')
|
|
123
|
+
if (v === 'none') state.pauseAfter = []
|
|
124
|
+
else state.pauseAfter = [...new Set([...state.pauseAfter, v])]
|
|
125
|
+
await save()
|
|
126
|
+
if (dir) { const proj = await loadProject(dir); proj.pauseAfter = state.pauseAfter; await saveProject(dir, proj) }
|
|
127
|
+
return ok(`✓ 暂停点=${state.pauseAfter.join('、') || '无'}`)
|
|
128
|
+
}
|
|
129
|
+
return err(`未知子命令 "${cmd}";/ppt help 查看用法`)
|
|
130
|
+
} catch (error) {
|
|
131
|
+
return { kind: 'error', text: `ppt 命令失败:${error?.message ?? error}` }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function save() { await saveSession(sessionId, state) }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function projectSummary(dir) {
|
|
138
|
+
if (!dir) return []
|
|
139
|
+
const proj = await loadProject(dir)
|
|
140
|
+
return [`项目(${dir}): 任务 ${proj.taskType ?? '—'}|阶段 ${proj.stage ?? '—'}|质量 ${proj.quality}`]
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function textStatus(state, dir, extra) {
|
|
144
|
+
const lines = [
|
|
145
|
+
`PPT 工作流:${state.workflowActive ? '✓ 激活中' : '未激活'}(routing=${state.routing},语义自动/命令强制)`,
|
|
146
|
+
`快速模式=${state.quick ? 'on(跳过定调/素材/视觉审阅迭代)' : 'off'}|协作模式=${state.mode}|忠实度=${state.fidelity}|审阅=${state.review}|质量=${state.quality}|引擎=${state.engine}(auto=pptd)`,
|
|
147
|
+
`暂停点=${state.pauseAfter.length ? state.pauseAfter.join('、') : '无'}${state.template ? `|模板=${state.template}` : ''}`,
|
|
148
|
+
...extra,
|
|
149
|
+
'',
|
|
150
|
+
'/ppt [on|off|quick|normal|free|mid|strict|fidelity <v>|review <v>|engine <v>|quality <v>|template <id>|pause-after <v>|help]',
|
|
151
|
+
]
|
|
152
|
+
return ok(lines.join('\n'))
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function argValue(input, name) {
|
|
156
|
+
const m = input.match(new RegExp(`${name}\\s+(\"[^\"]+\"|'[^']+'|\\S+)`))
|
|
157
|
+
return m ? m[1].replace(/^["']|["']$/g, '') : null
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function ok(text) { return { kind: 'success', text } }
|
|
161
|
+
function err(text) { return { kind: 'error', text } }
|