html2pptx-local-mcp 1.1.37 → 1.1.38

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.
@@ -170,17 +170,20 @@ const SKILL_INSTALL_COMMAND_EN = `# Choose the command for your agent
170
170
  # Claude Code
171
171
  npx skills add https://html2pptx.app -a claude-code
172
172
 
173
+ # Grok Build
174
+ npx --yes --package html2pptx-local-mcp@latest html2pptx-install-skills grok
175
+
173
176
  # Codex
174
177
  npx skills add https://html2pptx.app -a codex
175
178
 
176
179
  # Cursor
177
180
  npx skills add https://html2pptx.app -a cursor
178
181
 
179
- # Windsurf
180
- npx skills add https://html2pptx.app -a windsurf
182
+ # VS Code (GitHub Copilot)
183
+ npx skills add https://html2pptx.app -a github-copilot
181
184
 
182
- # Grok Build
183
- npx --yes --package html2pptx-local-mcp@latest html2pptx-install-skills grok
185
+ # Antigravity
186
+ npx skills add https://html2pptx.app -a antigravity
184
187
 
185
188
  # Preview published skills without installing
186
189
  npx skills add https://html2pptx.app --list
@@ -197,17 +200,20 @@ const SKILL_INSTALL_COMMAND_JA = `# 使うエージェントのコマンドを
197
200
  # Claude Code
198
201
  npx skills add https://html2pptx.app -a claude-code
199
202
 
203
+ # Grok Build
204
+ npx --yes --package html2pptx-local-mcp@latest html2pptx-install-skills grok
205
+
200
206
  # Codex
201
207
  npx skills add https://html2pptx.app -a codex
202
208
 
203
209
  # Cursor
204
210
  npx skills add https://html2pptx.app -a cursor
205
211
 
206
- # Windsurf
207
- npx skills add https://html2pptx.app -a windsurf
212
+ # VS Code (GitHub Copilot)
213
+ npx skills add https://html2pptx.app -a github-copilot
208
214
 
209
- # Grok Build
210
- npx --yes --package html2pptx-local-mcp@latest html2pptx-install-skills grok
215
+ # Antigravity
216
+ npx skills add https://html2pptx.app -a antigravity
211
217
 
212
218
  # インストールせずに公開Skillを確認
213
219
  npx skills add https://html2pptx.app --list
@@ -432,44 +438,54 @@ export const DOCS_COPY = {
432
438
  'Comprehensive documentation for html2pptx.app: the only API that converts HTML/CSS to fully editable PowerPoint files. REST API, Skills integration, MCP protocol, quickstart guides, and the HTML contract for reliable PowerPoint generation.',
433
439
 
434
440
  navSections: [
435
- { id: 'overview', label: 'Service Overview', children: [
441
+ { id: 'overview', label: 'Service Overview', desc: 'What html2pptx is, architecture, channels, comparison, and CSS support.', children: [
436
442
  { id: 'overview-channels', label: 'Channels' },
437
443
  { id: 'overview-comparison', label: 'Comparison' },
438
444
  { id: 'overview-css', label: 'CSS Support' },
439
445
  ]},
440
- { id: 'quickstart', label: 'Quick Start' },
441
- { id: 'api-reference', label: 'API Reference', children: [
446
+ { id: 'quickstart', label: 'Quick Start', desc: 'Your first authenticated HTML-to-PPTX export in four steps.' },
447
+ { id: 'api-reference', label: 'API Reference', desc: 'REST endpoints, supported and forbidden HTML elements, and response headers.', children: [
442
448
  { id: 'api-html-elements', label: 'HTML Elements' },
443
449
  { id: 'api-html-forbidden', label: 'Forbidden' },
444
450
  ]},
445
- { id: 'skills', label: 'Skills Integration', children: [
451
+ { id: 'skills', label: 'Skills Integration', desc: 'Use the html2pptx skill inside Claude Code and Codex agents.', children: [
446
452
  { id: 'skills-setup', label: 'Setup' },
447
453
  { id: 'skills-local-editor', label: 'Local Visual Editor' },
448
454
  { id: 'skills-capabilities', label: 'Capabilities' },
449
455
  ]},
450
- { id: 'mcp', label: 'MCP Integration', children: [
456
+ { id: 'mcp', label: 'MCP Integration', desc: 'Connect AI agents via the Model Context Protocol — remote and local.', children: [
451
457
  { id: 'mcp-setup', label: 'Setup' },
452
458
  { id: 'mcp-auth', label: 'Authentication' },
453
459
  { id: 'mcp-tools', label: 'Tools' },
454
460
  { id: 'mcp-example', label: 'Example' },
455
461
  ]},
456
- { id: 'cli', label: 'CLI Tool', children: [
462
+ { id: 'cli', label: 'CLI Tool', desc: 'Install and run the command-line tool for exports.', children: [
457
463
  { id: 'cli-install', label: 'Installation' },
458
464
  { id: 'cli-commands', label: 'Commands' },
459
465
  { id: 'cli-examples', label: 'Examples' },
460
466
  ]},
461
- { id: 'use-cases', label: 'Use Cases' },
462
- { id: 'plans', label: 'Plans & Pricing', children: [
467
+ { id: 'use-cases', label: 'Use Cases', desc: 'Common ways teams use html2pptx in production.' },
468
+ { id: 'plans', label: 'Plans & Pricing', desc: 'Subscription tiers, pricing, and per-plan rate limits.', children: [
463
469
  { id: 'plans-rate-limits', label: 'Rate Limits' },
464
470
  ]},
465
- { id: 'security', label: 'Security & Limits', children: [
471
+ { id: 'security', label: 'Security & Limits', desc: 'Security model, limits, and the pre-publish checklist.', children: [
466
472
  { id: 'security-checklist', label: 'Checklist' },
467
473
  ]},
468
- { id: 'faq', label: 'FAQ', children: [
474
+ { id: 'faq', label: 'FAQ', desc: 'Frequently asked questions and troubleshooting.', children: [
469
475
  { id: 'faq-troubleshoot', label: 'Troubleshoot' },
470
476
  ]},
471
477
  ],
472
478
 
479
+ searchCopy: {
480
+ rootCrumb: 'Docs',
481
+ buttonLabel: 'Search docs…',
482
+ placeholder: 'Search documentation…',
483
+ noResults: 'No results found',
484
+ hintNavigate: 'navigate',
485
+ hintSelect: 'select',
486
+ hintClose: 'close',
487
+ },
488
+
473
489
  /* --- Section 1: Service Overview --- */
474
490
  overviewTitle: 'Service Overview',
475
491
  overviewSubtitle: 'What is html2pptx.app',
@@ -842,7 +858,7 @@ html2pptx edit ./html2pptx/slides.html --no-open`,
842
858
  { issue: 'Another tab is read-only', fix: 'The editor uses a local tab lock to avoid two tabs writing to the same file. Use the active tab or click the transfer edit control.' },
843
859
  ],
844
860
  skillsSetupTitle: 'Setup',
845
- skillsSetupLead: 'Pick the agent you actually use and run the matching command. The skills CLI handles Claude Code, Codex, Cursor, and Windsurf; Grok Build uses its own installer.',
861
+ skillsSetupLead: 'Pick the agent you actually use and run the matching command. The skills CLI handles Claude Code, Codex, Cursor, VS Code (GitHub Copilot), and Antigravity; Grok Build uses its own installer. The tab list mirrors the MCP setup tabs below so the same agent appears in the same place in both sections.',
846
862
  skillsEditorTabs: [
847
863
  {
848
864
  id: 'claude-code',
@@ -881,28 +897,30 @@ html2pptx edit ./html2pptx/slides.html --no-open`,
881
897
  ],
882
898
  },
883
899
  {
884
- id: 'windsurf',
885
- label: 'Windsurf',
886
- icon: 'https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/windsurf/default.svg',
900
+ id: 'vscode',
901
+ label: 'VS Code',
902
+ icon: 'https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/visual-studio-code/default.svg',
887
903
  steps: [
888
- { title: 'Install the html2pptx skill', body: 'Register the published html2pptx skills into Windsurf via the skills CLI.', code: `npx skills add https://html2pptx.app -a windsurf` },
904
+ { title: 'Install the html2pptx skill', body: 'Register the published html2pptx skills into VS Code (GitHub Copilot) via the skills CLI. Skills land under `~/.copilot/skills/`.', code: `npx skills add https://html2pptx.app -a github-copilot` },
889
905
  ],
906
+ tip: 'The skills CLI agent ID is `github-copilot`; the GitHub Copilot extension inside VS Code picks the skill up after a reload.',
890
907
  },
891
908
  {
892
- id: 'others',
893
- label: 'Other agents',
909
+ id: 'antigravity',
910
+ label: 'Antigravity',
911
+ icon: 'https://cdn.jsdelivr.net/npm/@lobehub/icons-static-svg/icons/antigravity-color.svg',
894
912
  steps: [
895
- { title: 'Use the interactive selector', body: 'For any other supported agent, or to install into multiple targets at once, run the CLI without `-a` and choose interactively.', code: `npx skills add https://html2pptx.app` },
913
+ { title: 'Install the html2pptx skill', body: 'Register the published html2pptx skills into Antigravity via the skills CLI. Skills land under `~/.gemini/antigravity/skills/`.', code: `npx skills add https://html2pptx.app -a antigravity` },
896
914
  ],
897
- tip: 'Avoid `--yes` unless you intentionally want to install into every detected agent directory.',
915
+ tip: 'Antigravity (Google) shares the same skills CLI flow as Claude Code restart Antigravity after installing so the IDE picks up the new skill.',
898
916
  },
899
917
  ],
900
918
  skillsSetupSteps: [
901
919
  {
902
920
  step: '1',
903
921
  title: 'Install MCP + Skill',
904
- icons: ['claude-code', 'codex', 'cursor'],
905
- body: 'Choose the command for the agent you actually use: Claude Code, Codex, or Cursor. For Grok Build, use the Grok-specific installer. For other supported agents or multiple targets, use the interactive selector. Avoid --yes unless you intentionally want to install into every detected agent directory.',
922
+ icons: ['claude-code', 'grok-build', 'codex', 'cursor', 'vscode', 'antigravity'],
923
+ body: 'Pick the command for the agent you actually use: Claude Code, Codex, Cursor, VS Code (GitHub Copilot), or Antigravity. For Grok Build, use the Grok-specific installer. For other supported agents or multiple targets, drop the `-a` flag and use the interactive selector. Avoid `--yes` unless you intentionally want to install into every detected agent directory.',
906
924
  code: SKILL_INSTALL_COMMAND_EN,
907
925
  },
908
926
  {
@@ -1359,44 +1377,54 @@ echo 'HTML2PPTX_API_KEY=sk_live_xxxx' >> .env`,
1359
1377
  'html2pptx.app の包括的なドキュメント。HTML/CSSを完全に編集可能なPowerPointファイルに変換する唯一のAPI。REST API、Skills統合、MCPプロトコル、クイックスタートガイド、HTML変換契約を網羅しています。',
1360
1378
 
1361
1379
  navSections: [
1362
- { id: 'overview', label: 'サービス概要', children: [
1380
+ { id: 'overview', label: 'サービス概要', desc: 'html2pptxの概要・アーキテクチャ・チャネル・比較・CSS対応。', children: [
1363
1381
  { id: 'overview-channels', label: 'チャネル' },
1364
1382
  { id: 'overview-comparison', label: '比較' },
1365
1383
  { id: 'overview-css', label: 'CSS対応' },
1366
1384
  ]},
1367
- { id: 'quickstart', label: 'クイックスタート' },
1368
- { id: 'api-reference', label: 'APIリファレンス', children: [
1385
+ { id: 'quickstart', label: 'クイックスタート', desc: '認証付きでHTMLをPPTXに変換する最初の4ステップ。' },
1386
+ { id: 'api-reference', label: 'APIリファレンス', desc: 'RESTエンドポイント、対応/禁止HTML要素、レスポンスヘッダー。', children: [
1369
1387
  { id: 'api-html-elements', label: '対応HTML要素' },
1370
1388
  { id: 'api-html-forbidden', label: '使用禁止要素' },
1371
1389
  ]},
1372
- { id: 'skills', label: 'Skills統合', children: [
1390
+ { id: 'skills', label: 'Skills統合', desc: 'Claude Code や Codex エージェントで html2pptx skill を使う。', children: [
1373
1391
  { id: 'skills-setup', label: 'セットアップ' },
1374
1392
  { id: 'skills-local-editor', label: 'ローカル編集' },
1375
1393
  { id: 'skills-capabilities', label: '機能一覧' },
1376
1394
  ]},
1377
- { id: 'mcp', label: 'MCP統合', children: [
1395
+ { id: 'mcp', label: 'MCP統合', desc: 'Model Context Protocol でAIエージェントと連携(リモート/ローカル)。', children: [
1378
1396
  { id: 'mcp-setup', label: 'セットアップ' },
1379
1397
  { id: 'mcp-auth', label: '認証方法' },
1380
1398
  { id: 'mcp-tools', label: 'ツール一覧' },
1381
1399
  { id: 'mcp-example', label: '使用例' },
1382
1400
  ]},
1383
- { id: 'cli', label: 'CLIツール', children: [
1401
+ { id: 'cli', label: 'CLIツール', desc: 'エクスポート用のコマンドラインツールの導入と実行。', children: [
1384
1402
  { id: 'cli-install', label: 'インストール' },
1385
1403
  { id: 'cli-commands', label: 'コマンド' },
1386
1404
  { id: 'cli-examples', label: '使用例' },
1387
1405
  ]},
1388
- { id: 'use-cases', label: '活用事例' },
1389
- { id: 'plans', label: 'プラン・料金', children: [
1406
+ { id: 'use-cases', label: '活用事例', desc: '本番環境での html2pptx の代表的な活用方法。' },
1407
+ { id: 'plans', label: 'プラン・料金', desc: 'サブスクプラン、料金、プランごとのレート制限。', children: [
1390
1408
  { id: 'plans-rate-limits', label: 'レート制限' },
1391
1409
  ]},
1392
- { id: 'security', label: 'セキュリティ・制限', children: [
1410
+ { id: 'security', label: 'セキュリティ・制限', desc: 'セキュリティモデル・制限・公開前チェックリスト。', children: [
1393
1411
  { id: 'security-checklist', label: 'チェックリスト' },
1394
1412
  ]},
1395
- { id: 'faq', label: 'FAQ', children: [
1413
+ { id: 'faq', label: 'FAQ', desc: 'よくある質問とトラブルシューティング。', children: [
1396
1414
  { id: 'faq-troubleshoot', label: 'トラブルシュート' },
1397
1415
  ]},
1398
1416
  ],
1399
1417
 
1418
+ searchCopy: {
1419
+ rootCrumb: 'ドキュメント',
1420
+ buttonLabel: 'ドキュメントを検索…',
1421
+ placeholder: 'ドキュメントを検索…',
1422
+ noResults: '結果が見つかりません',
1423
+ hintNavigate: '移動',
1424
+ hintSelect: '選択',
1425
+ hintClose: '閉じる',
1426
+ },
1427
+
1400
1428
  /* --- Section 1: サービス概要 --- */
1401
1429
  overviewTitle: 'サービス概要',
1402
1430
  overviewSubtitle: 'html2pptx.app とは',
@@ -1768,7 +1796,7 @@ html2pptx edit ./html2pptx/slides.html --no-open`,
1768
1796
  { issue: '別タブが読み取り専用になる', fix: '同じHTMLを複数タブで編集して競合しないよう、エディタはタブロックを使います。編集権限のあるタブを使うか、画面上の移譲操作を行ってください。' },
1769
1797
  ],
1770
1798
  skillsSetupTitle: 'セットアップ',
1771
- skillsSetupLead: '実際に使うエージェントのタブを開き、そのコマンドだけ実行してください。skills CLI は Claude Code / Codex / Cursor / Windsurf に対応し、Grok Build のみ Grok 専用 installer を使います。',
1799
+ skillsSetupLead: '実際に使うエージェントのタブを開き、そのコマンドだけ実行してください。skills CLI は Claude Code / Codex / Cursor / VS Code (GitHub Copilot) / Antigravity に対応し、Grok Build のみ Grok 専用 installer を使います。タブの並びは下の MCP セットアップと同じ順序にしてあるので、同じエージェントは両セクションの同じ位置にあります。',
1772
1800
  skillsEditorTabs: [
1773
1801
  {
1774
1802
  id: 'claude-code',
@@ -1807,28 +1835,30 @@ html2pptx edit ./html2pptx/slides.html --no-open`,
1807
1835
  ],
1808
1836
  },
1809
1837
  {
1810
- id: 'windsurf',
1811
- label: 'Windsurf',
1812
- icon: 'https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/windsurf/default.svg',
1838
+ id: 'vscode',
1839
+ label: 'VS Code',
1840
+ icon: 'https://cdn.jsdelivr.net/gh/glincker/thesvg@main/public/icons/visual-studio-code/default.svg',
1813
1841
  steps: [
1814
- { title: 'html2pptx Skill をインストール', body: '公開済みの html2pptx skills を skills CLI から Windsurf に登録します。', code: `npx skills add https://html2pptx.app -a windsurf` },
1842
+ { title: 'html2pptx Skill をインストール', body: '公開済みの html2pptx skills を skills CLI から VS Code (GitHub Copilot) に登録します。skills は `~/.copilot/skills/` に配置されます。', code: `npx skills add https://html2pptx.app -a github-copilot` },
1815
1843
  ],
1844
+ tip: 'skills CLI でのエージェント ID は `github-copilot` です。インストール後、VS Code の GitHub Copilot 拡張を再読み込みすると skill が認識されます。',
1816
1845
  },
1817
1846
  {
1818
- id: 'others',
1819
- label: 'その他のエージェント',
1847
+ id: 'antigravity',
1848
+ label: 'Antigravity',
1849
+ icon: 'https://cdn.jsdelivr.net/npm/@lobehub/icons-static-svg/icons/antigravity-color.svg',
1820
1850
  steps: [
1821
- { title: '対話形式で選択', body: 'その他の対応エージェントや、複数のエージェントへ一度にインストールする場合は `-a` を付けずに対話形式で選択します。', code: `npx skills add https://html2pptx.app` },
1851
+ { title: 'html2pptx Skill をインストール', body: '公開済みの html2pptx skills を skills CLI から Antigravity に登録します。skills は `~/.gemini/antigravity/skills/` に配置されます。', code: `npx skills add https://html2pptx.app -a antigravity` },
1822
1852
  ],
1823
- tip: '`--yes` は検出された全エージェントのディレクトリへ入るため、全対応が必要な場合以外は使わないでください。',
1853
+ tip: 'Antigravity (Google) は Claude Code と同じく skills CLI でそのまま導入できます。インストール後に Antigravity を再起動すると skill が読み込まれます。',
1824
1854
  },
1825
1855
  ],
1826
1856
  skillsSetupSteps: [
1827
1857
  {
1828
1858
  step: '1',
1829
1859
  title: 'MCP + スキルをインストール',
1830
- icons: ['claude-code', 'codex', 'cursor'],
1831
- body: 'Claude CodeCodexCursor のうち、実際に使うエージェントのコマンドを選んで実行してください。Grok Build Grok 専用 installer を使います。その他の対応エージェントや複数指定の場合は対話形式で選択します。--yes は検出された全エージェントのディレクトリへ入るため、全対応が必要な場合以外は使わないでください。',
1860
+ icons: ['claude-code', 'grok-build', 'codex', 'cursor', 'vscode', 'antigravity'],
1861
+ body: 'Claude Code / Codex / Cursor / VS Code (GitHub Copilot) / Antigravity のうち、実際に使うエージェントのコマンドを選んで実行してください。Grok Build のみ Grok 専用 installer を使います。その他の対応エージェントや複数指定の場合は `-a` を付けずに対話形式で選択します。`--yes` は検出された全エージェントのディレクトリへ入るため、全対応が必要な場合以外は使わないでください。',
1832
1862
  code: SKILL_INSTALL_COMMAND_JA,
1833
1863
  },
1834
1864
  {
@@ -18,7 +18,7 @@ declare function normalizeBaseUrl(raw: string): URL;
18
18
  declare function readRegisteredEditorBaseUrl(root: string): Promise<string | null>;
19
19
  declare function resolveEditorBaseUrl(root: string, explicitBaseUrl: string | undefined): Promise<URL>;
20
20
  declare function buildEditorUrl(baseUrl: URL, rel: string, bridgeUrl: string, sessionToken: string): URL;
21
- declare function createBridgeServer(ctx: BridgeContext): import("http").Server<typeof IncomingMessage, typeof ServerResponse>;
21
+ declare function createBridgeServer(ctx: BridgeContext): import("node:http").Server<typeof IncomingMessage, typeof ServerResponse>;
22
22
  declare function listen(server: ReturnType<typeof createBridgeServer>, requestedPort: number): Promise<number>;
23
23
  export declare function editCommand(input: string | undefined, options?: EditOptions): Promise<void>;
24
24
  export declare const editCommandInternalsForTest: {
@@ -8,11 +8,13 @@ import * as p from "@clack/prompts";
8
8
  import pc from "picocolors";
9
9
  const AUTO_PORT = 0;
10
10
  const MAX_WRITE_BYTES = 5 * 1024 * 1024;
11
- const MAX_ASSET_BYTES = 8 * 1024 * 1024;
11
+ const MAX_ASSET_BYTES = 64 * 1024 * 1024;
12
12
  const ALLOWED_EXTENSIONS = [".html", ".htm"];
13
13
  const ALLOWED_EXT = new Set(ALLOWED_EXTENSIONS);
14
14
  const ASSET_IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".avif"];
15
- const ASSET_IMAGE_EXT = new Set(ASSET_IMAGE_EXTENSIONS);
15
+ const ASSET_VIDEO_EXTENSIONS = [".mp4", ".webm", ".mov", ".m4v", ".ogv"];
16
+ const ASSET_VIDEO_EXT = new Set(ASSET_VIDEO_EXTENSIONS);
17
+ const ASSET_MEDIA_EXT = new Set([...ASSET_IMAGE_EXTENSIONS, ...ASSET_VIDEO_EXTENSIONS]);
16
18
  const ASSET_CONTENT_TYPES = {
17
19
  ".png": "image/png",
18
20
  ".jpg": "image/jpeg",
@@ -21,6 +23,11 @@ const ASSET_CONTENT_TYPES = {
21
23
  ".webp": "image/webp",
22
24
  ".svg": "image/svg+xml",
23
25
  ".avif": "image/avif",
26
+ ".mp4": "video/mp4",
27
+ ".webm": "video/webm",
28
+ ".mov": "video/quicktime",
29
+ ".m4v": "video/x-m4v",
30
+ ".ogv": "video/ogg",
24
31
  };
25
32
  const ASSET_CONTENT_TYPE_EXT = {
26
33
  "image/png": ".png",
@@ -29,6 +36,11 @@ const ASSET_CONTENT_TYPE_EXT = {
29
36
  "image/webp": ".webp",
30
37
  "image/svg+xml": ".svg",
31
38
  "image/avif": ".avif",
39
+ "video/mp4": ".mp4",
40
+ "video/webm": ".webm",
41
+ "video/quicktime": ".mov",
42
+ "video/x-m4v": ".m4v",
43
+ "video/ogg": ".ogv",
32
44
  };
33
45
  const DISALLOWED_TOP_DIRECTORIES = [
34
46
  "public",
@@ -460,8 +472,8 @@ async function safeAssetPath(ctx, rel) {
460
472
  throw new Error("path escape");
461
473
  }
462
474
  const ext = extname(abs).toLowerCase();
463
- if (!ASSET_IMAGE_EXT.has(ext)) {
464
- throw new Error("only image files are allowed");
475
+ if (!ASSET_MEDIA_EXT.has(ext)) {
476
+ throw new Error("only image, GIF, and video files are allowed");
465
477
  }
466
478
  const real = await resolveReal(abs);
467
479
  if (real !== ctx.root && !real.startsWith(ctx.root + sep)) {
@@ -477,18 +489,21 @@ async function safeAssetPath(ctx, rel) {
477
489
  }
478
490
  function assetExt(name, contentType) {
479
491
  const fromName = extname(String(name || "")).toLowerCase();
480
- if (ASSET_IMAGE_EXT.has(fromName))
492
+ if (ASSET_MEDIA_EXT.has(fromName))
481
493
  return fromName;
482
494
  return ASSET_CONTENT_TYPE_EXT[String(contentType || "").toLowerCase()] || "";
483
495
  }
484
496
  function assetSlug(name) {
485
- const base = String(name || "image").replace(/\.[^.]+$/, "");
497
+ const base = String(name || "asset").replace(/\.[^.]+$/, "");
486
498
  const slug = base
487
499
  .normalize("NFKD")
488
500
  .replace(/[^\w.-]+/g, "-")
489
501
  .replace(/^[-.]+|[-.]+$/g, "")
490
502
  .toLowerCase();
491
- return slug || "image";
503
+ return slug || "asset";
504
+ }
505
+ function assetKind(ext) {
506
+ return ASSET_VIDEO_EXT.has(ext) ? "video" : "image";
492
507
  }
493
508
  function assetDirRel(scope, htmlDirRel) {
494
509
  if (scope === "global")
@@ -530,10 +545,11 @@ async function handleAssetGet(ctx, req, reqUrl, res) {
530
545
  if (absDir === ctx.root || absDir.startsWith(ctx.root + sep)) {
531
546
  const names = await readdir(absDir);
532
547
  assets = names
533
- .filter((name) => ASSET_IMAGE_EXT.has(extname(name).toLowerCase()))
548
+ .filter((name) => ASSET_MEDIA_EXT.has(extname(name).toLowerCase()))
534
549
  .map((name) => ({
535
550
  name,
536
551
  src: toPosixPath(relative(htmlDirAbs, join(absDir, name))),
552
+ kind: assetKind(extname(name).toLowerCase()),
537
553
  }));
538
554
  }
539
555
  }
@@ -576,21 +592,21 @@ async function handleAssetPost(ctx, req, res) {
576
592
  }
577
593
  const { file, scope: rawScope, name, contentType, dataBase64 } = body || {};
578
594
  if (typeof dataBase64 !== "string" || !dataBase64) {
579
- sendJson(res, 400, { error: "missing image data" });
595
+ sendJson(res, 400, { error: "missing asset data" });
580
596
  return;
581
597
  }
582
598
  const buf = Buffer.from(dataBase64, "base64");
583
599
  if (!buf.length) {
584
- sendJson(res, 400, { error: "empty image data" });
600
+ sendJson(res, 400, { error: "empty asset data" });
585
601
  return;
586
602
  }
587
603
  if (buf.length > MAX_ASSET_BYTES) {
588
- sendJson(res, 413, { error: "image too large (>8MB)" });
604
+ sendJson(res, 413, { error: "asset too large (>64MB)" });
589
605
  return;
590
606
  }
591
607
  const ext = assetExt(name, contentType);
592
- if (!ASSET_IMAGE_EXT.has(ext)) {
593
- sendJson(res, 400, { error: "unsupported image type" });
608
+ if (!ASSET_MEDIA_EXT.has(ext)) {
609
+ sendJson(res, 400, { error: "unsupported asset type" });
594
610
  return;
595
611
  }
596
612
  const scope = rawScope === "global" ? "global" : "project";
@@ -617,6 +633,7 @@ async function handleAssetPost(ctx, req, res) {
617
633
  name: fileName,
618
634
  path: toPosixPath(relative(ctx.root, absTarget)),
619
635
  src: toPosixPath(relative(htmlDirAbs, absTarget)),
636
+ kind: assetKind(ext),
620
637
  bytes: buf.length,
621
638
  reused: alreadyIdentical,
622
639
  policy: buildPolicy(ctx),
package/cli/dist/index.js CHANGED
File without changes
@@ -4228,6 +4228,15 @@ ${slidesArg.join('\n\n')}
4228
4228
  {text.layers}
4229
4229
  </button>
4230
4230
  <span className="cv-inspector__zoom">{Math.round(viewScale * 100)}%</span>
4231
+ <button
4232
+ type="button"
4233
+ className="cv-inspector__close"
4234
+ onClick={exitFocus}
4235
+ aria-label={text.panel?.closeEditPanel || 'Close'}
4236
+ title={text.overview || 'Overview'}
4237
+ >
4238
+ <X size={19} strokeWidth={2.25} />
4239
+ </button>
4231
4240
  </div>
4232
4241
  <div className="cv-inspector__ctx">
4233
4242
  <span className="cv-inspector__tag">&lt;{selection.element?.tagName?.toLowerCase?.() || 'node'}&gt;</span>
@@ -4255,7 +4264,7 @@ ${slidesArg.join('\n\n')}
4255
4264
  key={`${selection.key || selection.selector || selection.element?.tagName || 'selection'}:${inspectorNonce}`}
4256
4265
  selector={selection.selector}
4257
4266
  element={selection.element}
4258
- onClose={clearSelection}
4267
+ onClose={exitFocus}
4259
4268
  onChange={onPanelChange}
4260
4269
  labels={text.panel}
4261
4270
  assetTools={{
@@ -4506,11 +4515,13 @@ ${slidesArg.join('\n\n')}
4506
4515
  .cv-zoomhud { position: absolute; bottom: 16px; right: 16px; display: flex; align-items: center; gap: 2px; padding: 5px 8px; border-radius: 10px; background: rgba(255,255,255,0.96); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); border: 1px solid #e6e6e6; box-shadow: 0 4px 16px rgba(0,0,0,0.1); z-index: 8; }
4507
4516
  .cv-zoomhud__label { min-width: 44px; text-align: center; font-size: 12px; font-weight: 600; color: #3a3a3a; font-variant-numeric: tabular-nums; }
4508
4517
 
4509
- .cv-inspector { width: 280px; flex: 0 0 280px; display: flex; flex-direction: column; background: #ffffff; border-left: 1px solid #e6e6e6; overflow-x: hidden; overflow-y: auto; min-height: 0; scrollbar-gutter: stable; }
4518
+ .cv-inspector { order: -1; width: 280px; flex: 0 0 280px; display: flex; flex-direction: column; background: #ffffff; border-right: 1px solid #e6e6e6; overflow-x: hidden; overflow-y: auto; min-height: 0; scrollbar-gutter: stable; }
4510
4519
  .cv-inspector__tabs { display: flex; align-items: center; gap: 2px; padding: 8px 10px; border-bottom: 1px solid #ececec; flex: 0 0 auto; }
4511
4520
  .cv-inspector__tabs button { border: none; background: transparent; font-size: 12.5px; font-weight: 600; color: #9a9a9a; padding: 5px 10px; border-radius: 6px; cursor: pointer; }
4512
4521
  .cv-inspector__tabs button.is-active { color: #1a1a1a; background: #f0f0f0; }
4513
4522
  .cv-inspector__zoom { margin-left: auto; font-size: 11px; color: #9a9a9a; font-variant-numeric: tabular-nums; padding-right: 4px; }
4523
+ .cv-inspector__close { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; margin-left: 2px; border: none; background: transparent; color: #6a6a6a; border-radius: 8px; cursor: pointer; flex: 0 0 auto; }
4524
+ .cv-inspector__close:hover { background: #ececec; color: #111; }
4514
4525
  .cv-inspector__ctx { display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-bottom: 1px solid #ececec; flex: 0 0 auto; }
4515
4526
  .cv-inspector__tag { font-family: ui-monospace, monospace; font-size: 11px; font-weight: 600; color: var(--cv-sel); background: var(--cv-sel-soft); padding: 2px 7px; border-radius: 5px; white-space: nowrap; }
4516
4527
  .cv-inspector__sel { font-size: 11px; color: #9a9a9a; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@@ -4540,7 +4551,8 @@ ${slidesArg.join('\n\n')}
4540
4551
 
4541
4552
  @keyframes cv-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
4542
4553
 
4543
- .cv-main:not(:has(.cv-inspector)) .cv-lp-section--layers {
4554
+ /* While editing an element the inspector replaces the slide/layer list on the left */
4555
+ .cv-main:has(.cv-inspector) .cv-leftpanel {
4544
4556
  display: none;
4545
4557
  }
4546
4558
 
@@ -4576,6 +4588,7 @@ ${slidesArg.join('\n\n')}
4576
4588
  }
4577
4589
 
4578
4590
  .cv-main:has(.cv-inspector) .cv-leftpanel {
4591
+ display: flex;
4579
4592
  grid-column: 1;
4580
4593
  }
4581
4594
 
@@ -4613,6 +4626,8 @@ ${slidesArg.join('\n\n')}
4613
4626
  width: 248px;
4614
4627
  min-width: 0;
4615
4628
  flex: none;
4629
+ border-left: 1px solid #e6e6e6;
4630
+ border-right: 0;
4616
4631
  }
4617
4632
 
4618
4633
  .cv-lp-section--slides .cv-lp-pages {
@@ -4691,6 +4706,7 @@ ${slidesArg.join('\n\n')}
4691
4706
 
4692
4707
  .cv-leftpanel,
4693
4708
  .cv-main:has(.cv-inspector) .cv-leftpanel {
4709
+ display: flex;
4694
4710
  grid-column: 1;
4695
4711
  grid-row: 2;
4696
4712
  }
@@ -4707,6 +4723,7 @@ ${slidesArg.join('\n\n')}
4707
4723
  max-width: none;
4708
4724
  border-top: 1px solid #e6e6e6;
4709
4725
  border-left: 0;
4726
+ border-right: 0;
4710
4727
  }
4711
4728
 
4712
4729
  .cv-lp-section--slides .cv-lp-pages {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "html2pptx-local-mcp",
3
- "version": "1.1.37",
3
+ "version": "1.1.38",
4
4
  "type": "module",
5
5
  "description": "Local stdio MCP server for opening html2pptx slide HTML in the local edit-slide editor.",
6
6
  "bin": {
@@ -420,6 +420,10 @@ Extract the download URL from the `Download:` text block in the response. Then o
420
420
 
421
421
  Do NOT ask the user to manually download — always automate the full flow.
422
422
 
423
+ #### Step 9: Open the local editor (mandatory)
424
+
425
+ After the PPTX is downloaded and opened, immediately perform the mandatory editor handoff (see "Mandatory editor handoff after HTML generation"). This is not optional and must run even when the user only asked for a PPTX export — do not stop at the PPTX/HTML and do not ask whether to open the editor.
426
+
423
427
  ### Output directory structure
424
428
 
425
429
  All generated files MUST be saved under `./html2pptx/`:
@@ -575,6 +579,8 @@ If the user clicks Export PPTX inside the local editor, the browser must only sh
575
579
 
576
580
  Whenever this skill finishes generating or materially updating a slide HTML file, always hand it off to the local visual editor. Prefer `html2pptx_open_local_slide_editor` because it starts the loopback UI and bridge together; do not use hosted edit-slide as a fallback. Do this even if the user did not separately ask for preview.
577
581
 
582
+ This handoff is unconditional and applies to EVERY slide generation path, including when the user only asked for a PPTX export. Do not merely offer it, and do not ask "shall I open the editor?" — open it. The only thing that ever requires asking first is adding the local stdio MCP config when it is not yet present (see below); the act of opening the editor itself is never gated on user confirmation. Treat "stopped at HTML/PPTX without opening the editor" as a skill failure.
583
+
578
584
  Required behavior:
579
585
 
580
586
  1. Save the deck under `./html2pptx/<fileName>.html`.