From 37481a78ca49476a120af7a01765b443d4bd9737 Mon Sep 17 00:00:00 2001 From: KeyInfo Bot Date: Wed, 8 Jul 2026 00:01:24 +0800 Subject: [PATCH] Sync third-party and MCP marketplace plugins Constraint: Public skills are published only by explicit administrator action unless they are tracked third-party market sources. Confidence: high Scope-risk: narrow Directive: Keep private/internal skills out of the public marketplace and preserve normal incremental market Git history. Tested: Marketplace validation passed. --- .agents/plugins/marketplace.json | 34 ++--- config/external-sources.lock.json | 30 ++-- .../codex/.agents/plugins/marketplace.json | 34 ++--- .../plugins/mcp-playwright/MCP_SOURCE.json | 2 +- .../next-skills/THIRD_PARTY_SOURCE.json | 4 +- plugins/codex/plugins/ppt-master/README.md | 41 ++++++ .../ppt-master/THIRD_PARTY_SOURCE.json | 4 +- .../svg_to_pptx/drawingml/converter.py | 136 +++++++++++++++++- .../plugins/shadcn/THIRD_PARTY_SOURCE.json | 4 +- 9 files changed, 230 insertions(+), 59 deletions(-) diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 64549d3f3..b5f311a8a 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -281,22 +281,22 @@ "category": "文档处理" }, { - "name": "ppt-master", + "name": "ui-ux-pro-max", "source": { "source": "local", - "path": "./plugins/codex/plugins/ppt-master" + "path": "./plugins/codex/plugins/ui-ux-pro-max" }, "policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" }, - "category": "文档处理" + "category": "设计" }, { - "name": "ui-ux-pro-max", + "name": "taste-skill", "source": { "source": "local", - "path": "./plugins/codex/plugins/ui-ux-pro-max" + "path": "./plugins/codex/plugins/taste-skill" }, "policy": { "installation": "AVAILABLE", @@ -316,6 +316,18 @@ }, "category": "开发工具" }, + { + "name": "ppt-master", + "source": { + "source": "local", + "path": "./plugins/codex/plugins/ppt-master" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "文档处理" + }, { "name": "next-skills", "source": { @@ -339,18 +351,6 @@ "authentication": "ON_INSTALL" }, "category": "MCP" - }, - { - "name": "taste-skill", - "source": { - "source": "local", - "path": "./plugins/codex/plugins/taste-skill" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "设计" } ] } diff --git a/config/external-sources.lock.json b/config/external-sources.lock.json index 3fb45ac8d..3c3061ebe 100644 --- a/config/external-sources.lock.json +++ b/config/external-sources.lock.json @@ -36,14 +36,23 @@ "commit": "0d95a81d35a9f2d123a5e9430d1cfc43d55f1bb0", "syncedAt": "2026-07-06T02:08:42Z" }, + { + "id": "taste-skill", + "pluginName": "taste-skill", + "repo": "https://github.com/Leonxlnx/taste-skill.git", + "ref": "main", + "adapter": "skill-collection", + "commit": "b17742737e796305d829b3ad39eda3add0d79060", + "syncedAt": "2026-07-07T02:43:19Z" + }, { "id": "shadcn", "pluginName": "shadcn", "repo": "https://github.com/shadcn-ui/ui.git", "ref": "main", "adapter": "claude-skill", - "commit": "d8ace420baa5c8a1abccd75e52570f2a232f193d", - "syncedAt": "2026-07-06T16:00:00Z" + "commit": "68e1f171aa8c6ce2e38cb9a7d1463d6bcf357e91", + "syncedAt": "2026-07-07T16:00:00Z" }, { "id": "frontend-slides", @@ -78,8 +87,8 @@ "repo": "https://github.com/hugohe3/ppt-master.git", "ref": "main", "adapter": "claude-skill", - "commit": "eb9243be673d0019dc1c7998262214a9a977a7d4", - "syncedAt": "2026-07-05T16:00:01Z" + "commit": "0b3f73e5f0868171eef82baef44be660888f6c71", + "syncedAt": "2026-07-07T16:00:00Z" }, { "id": "next-skills", @@ -87,17 +96,8 @@ "repo": "https://github.com/vercel/next.js.git", "ref": "canary", "adapter": "skill-collection", - "commit": "6065bf6fcfc48484634dc3708c080a27c5684e5d", - "syncedAt": "2026-07-06T16:00:00Z" - }, - { - "id": "taste-skill", - "pluginName": "taste-skill", - "repo": "https://github.com/Leonxlnx/taste-skill.git", - "ref": "main", - "adapter": "skill-collection", - "commit": "b17742737e796305d829b3ad39eda3add0d79060", - "syncedAt": "2026-07-07T02:43:19Z" + "commit": "8b5df172e4908b68f7ef88e8ad2b98070baf9ced", + "syncedAt": "2026-07-07T16:00:00Z" } ] } diff --git a/plugins/codex/.agents/plugins/marketplace.json b/plugins/codex/.agents/plugins/marketplace.json index 9fe9066f0..fffee562b 100644 --- a/plugins/codex/.agents/plugins/marketplace.json +++ b/plugins/codex/.agents/plugins/marketplace.json @@ -281,22 +281,22 @@ "category": "文档处理" }, { - "name": "ppt-master", + "name": "ui-ux-pro-max", "source": { "source": "local", - "path": "./plugins/ppt-master" + "path": "./plugins/ui-ux-pro-max" }, "policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" }, - "category": "文档处理" + "category": "设计" }, { - "name": "ui-ux-pro-max", + "name": "taste-skill", "source": { "source": "local", - "path": "./plugins/ui-ux-pro-max" + "path": "./plugins/taste-skill" }, "policy": { "installation": "AVAILABLE", @@ -316,6 +316,18 @@ }, "category": "开发工具" }, + { + "name": "ppt-master", + "source": { + "source": "local", + "path": "./plugins/ppt-master" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "文档处理" + }, { "name": "next-skills", "source": { @@ -339,18 +351,6 @@ "authentication": "ON_INSTALL" }, "category": "MCP" - }, - { - "name": "taste-skill", - "source": { - "source": "local", - "path": "./plugins/taste-skill" - }, - "policy": { - "installation": "AVAILABLE", - "authentication": "ON_INSTALL" - }, - "category": "设计" } ] } diff --git a/plugins/codex/plugins/mcp-playwright/MCP_SOURCE.json b/plugins/codex/plugins/mcp-playwright/MCP_SOURCE.json index f5e0275fc..667d999f3 100644 --- a/plugins/codex/plugins/mcp-playwright/MCP_SOURCE.json +++ b/plugins/codex/plugins/mcp-playwright/MCP_SOURCE.json @@ -3,5 +3,5 @@ "name": "playwright浏览器自动化操作", "version": "20260605", "keySource": "none", - "syncedAt": "2026-07-06T16:01:31Z" + "syncedAt": "2026-07-07T16:01:24Z" } diff --git a/plugins/codex/plugins/next-skills/THIRD_PARTY_SOURCE.json b/plugins/codex/plugins/next-skills/THIRD_PARTY_SOURCE.json index 73a70b45c..24feb5e60 100644 --- a/plugins/codex/plugins/next-skills/THIRD_PARTY_SOURCE.json +++ b/plugins/codex/plugins/next-skills/THIRD_PARTY_SOURCE.json @@ -2,8 +2,8 @@ "sourceId": "next-skills", "repo": "https://github.com/vercel/next.js.git", "ref": "canary", - "commit": "6065bf6fcfc48484634dc3708c080a27c5684e5d", + "commit": "8b5df172e4908b68f7ef88e8ad2b98070baf9ced", "adapter": "skill-collection", "sourcePath": "skills", - "syncedAt": "2026-07-06T16:00:00Z" + "syncedAt": "2026-07-07T16:00:00Z" } diff --git a/plugins/codex/plugins/ppt-master/README.md b/plugins/codex/plugins/ppt-master/README.md index c5ff8273f..27edbb23d 100644 --- a/plugins/codex/plugins/ppt-master/README.md +++ b/plugins/codex/plugins/ppt-master/README.md @@ -127,6 +127,47 @@ Knowing how to use Python and AI agents will matter more and more, and this proj --- +## You Might Also Like + +### ResearchStudio-Reel + +> A Microsoft open-source project I recently joined — from **paper** to **talk video**, **poster**, and **blog**, automating the **last mile** of research dissemination. +> +> 📦 **Repo:** [microsoft/ResearchStudio](https://github.com/microsoft/ResearchStudio) · 📄 **Paper:** [arXiv:2607.04438](https://arxiv.org/abs/2607.04438) + + + + + + +
+ + ResearchStudio-Reel demo + + + + ResearchStudio-Reel generated poster + +
+ +
+BibTeX — if you use ResearchStudio-Reel in your research + +```bibtex +@article{xiao2026researchstudioreel, + title = {ResearchStudio-Reel: Automate the Last Mile of Research from Paper to Poster, Video, and Blog}, + author = {Lingao Xiao and Yalun Dai and Yangyu Huang and Qihao Zhao and Wenshan Wu and Hugo He and Ruishuo Chen and Jin Jiang and Qianli Ma and Jiahuan Zhang and Xin Zhang and Ying Xin and Yang Ou and Yan Xia and Scarlett Li and Longbo Huang and Zhipeng Zhang and Yang He and Yap Kim Hui and Yan Lu}, + journal = {arXiv preprint arXiv:2607.04438}, + year = {2026}, + url = {https://arxiv.org/abs/2607.04438} +} +``` + +
+ +--- + ## Quick Start ### 1. Prerequisites diff --git a/plugins/codex/plugins/ppt-master/THIRD_PARTY_SOURCE.json b/plugins/codex/plugins/ppt-master/THIRD_PARTY_SOURCE.json index b48973425..efbdda063 100644 --- a/plugins/codex/plugins/ppt-master/THIRD_PARTY_SOURCE.json +++ b/plugins/codex/plugins/ppt-master/THIRD_PARTY_SOURCE.json @@ -2,8 +2,8 @@ "sourceId": "ppt-master", "repo": "https://github.com/hugohe3/ppt-master.git", "ref": "main", - "commit": "eb9243be673d0019dc1c7998262214a9a977a7d4", + "commit": "0b3f73e5f0868171eef82baef44be660888f6c71", "adapter": "claude-skill", "sourcePath": "skills/ppt-master", - "syncedAt": "2026-07-05T16:00:01Z" + "syncedAt": "2026-07-07T16:00:00Z" } diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/svg_to_pptx/drawingml/converter.py b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/svg_to_pptx/drawingml/converter.py index e80da5661..809f39d3e 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/svg_to_pptx/drawingml/converter.py +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/svg_to_pptx/drawingml/converter.py @@ -13,10 +13,12 @@ from resource_paths import icon_search_dirs_for_svg from .context import ConvertContext, ShapeResult from .utils import ( SVG_NS, EMU_PER_PX, - _extract_inheritable_styles, parse_transform_matrix, resolve_url_id, + _extract_inheritable_styles, _f, _get_attr, parse_transform_matrix, resolve_url_id, parse_svg_length, ) -from .styles import build_effect_xml +from .styles import ( + build_effect_xml, build_fill_xml, get_fill_opacity, get_stroke_opacity, +) from .elements import ( convert_rect, convert_circle, convert_ellipse, convert_line, convert_path, @@ -361,6 +363,118 @@ _CONVERTERS = { _SUPPORTED_VISUAL_CHILD_TAGS = frozenset(('tspan',)) +def _parse_svg_canvas(root: ET.Element) -> tuple[float, float, float, float]: + """Return the SVG canvas as (x, y, width, height) in SVG units.""" + view_box = root.get('viewBox', '') + parts = re.split(r'[\s,]+', view_box.strip()) if view_box else [] + if len(parts) == 4: + try: + x, y, w, h = (float(part) for part in parts) + if w > 0 and h > 0: + return x, y, w, h + except ValueError: + pass + return 0.0, 0.0, _f(root.get('width')), _f(root.get('height')) + + +def _is_full_canvas_rect( + elem: ET.Element, + ctx: ConvertContext, + canvas: tuple[float, float, float, float], +) -> bool: + """Return whether a rect is a safe candidate for native slide background.""" + if elem.get('transform') or elem.get('filter') or elem.get('clip-path'): + return False + if _f(elem.get('rx')) > 0 or _f(elem.get('ry')) > 0: + return False + + canvas_x, canvas_y, canvas_w, canvas_h = canvas + if canvas_w <= 0 or canvas_h <= 0: + return False + + tolerance = 0.5 + if abs(_f(elem.get('x')) - canvas_x) > tolerance: + return False + if abs(_f(elem.get('y')) - canvas_y) > tolerance: + return False + if abs(_f(elem.get('width')) - canvas_w) > tolerance: + return False + if abs(_f(elem.get('height')) - canvas_h) > tolerance: + return False + + fill = _get_attr(elem, 'fill', ctx) + if fill == 'none': + return False + + stroke = _get_attr(elem, 'stroke', ctx) + stroke_width = _f(_get_attr(elem, 'stroke-width', ctx), 1.0) + stroke_opacity = get_stroke_opacity(elem, ctx) + if stroke and stroke != 'none' and stroke_width > 0 and stroke_opacity != 0: + return False + + return True + + +def _background_xml_from_rect( + elem: ET.Element, + ctx: ConvertContext, +) -> str: + """Build native ``p:bg`` XML from a full-slide SVG background rect.""" + fill_xml = build_fill_xml(elem, ctx, get_fill_opacity(elem, ctx)) + if not fill_xml or '{fill_xml}' + + +def _extract_background_candidate( + root: ET.Element, + ctx: ConvertContext, +) -> tuple[str, int | None]: + """Promote a first-layer SVG background rect to native PowerPoint bgPr. + + PowerPoint stores page background fills under ``p:cSld/p:bg/p:bgPr``. + Keeping the full-canvas SVG rect in ``p:spTree`` makes it an ordinary + selectable shape, so users hit it during bulk element selection. Only the + first visual layer is considered, matching pptx_to_svg's round-trip output + and avoiding accidental promotion of content panels. + """ + canvas = _parse_svg_canvas(root) + for child in root: + tag = child.tag.replace(f'{{{SVG_NS}}}', '') + if tag in _NON_VISUAL_TAGS: + continue + + if tag == 'rect' and _is_full_canvas_rect(child, ctx, canvas): + bg_xml = _background_xml_from_rect(child, ctx) + if bg_xml: + return bg_xml, id(child) + return '', None + + if tag != 'g': + return '', None + if child.get('transform') or child.get('filter') or child.get('clip-path'): + return '', None + style_overrides = _extract_inheritable_styles(child) + child_ctx = ctx.child(style_overrides=style_overrides) + visual_children = [ + grandchild for grandchild in child + if grandchild.tag.replace(f'{{{SVG_NS}}}', '') not in _NON_VISUAL_TAGS + ] + if len(visual_children) != 1: + return '', None + only_child = visual_children[0] + only_tag = only_child.tag.replace(f'{{{SVG_NS}}}', '') + if only_tag == 'rect' and _is_full_canvas_rect(only_child, child_ctx, canvas): + bg_xml = _background_xml_from_rect(only_child, child_ctx) + if bg_xml: + ctx.sync_from_child(child_ctx) + return bg_xml, id(child) + return '', None + return '', None + + return '', None + + def collect_defs(root: ET.Element) -> dict[str, ET.Element]: """Collect all children into an {id: element} dictionary.""" defs: dict[str, ET.Element] = {} @@ -568,6 +682,14 @@ def convert_svg_to_slide_shapes( shapes: list[str] = [] converted = 0 skipped = 0 + background_xml, background_skip_id = _extract_background_candidate(root, ctx) + promoted_backgrounds = 1 if background_xml else 0 + if background_xml and trace_events is not None: + trace_events.append({ + 'tag': 'rect', + 'decision': 'native-background', + 'reason': 'promoted-full-canvas-rect-to-bgPr', + }) # Per-element shape ids of every top-level child, used as an animation # fallback when no groups are present at the root. fallback_targets: list = [] @@ -576,6 +698,8 @@ def convert_svg_to_slide_shapes( tag = child.tag.replace(f'{{{SVG_NS}}}', '') if tag == 'defs': continue + if id(child) == background_skip_id: + continue result = convert_element(child, ctx) if result: shapes.append(result.xml) @@ -598,7 +722,11 @@ def convert_svg_to_slide_shapes( ctx.anim_targets = fallback_targets if verbose: - print(f' Converted {converted} elements, skipped {skipped}') + promoted = ( + f', promoted {promoted_backgrounds} background' + if promoted_backgrounds else '' + ) + print(f' Converted {converted} elements, skipped {skipped}{promoted}') if trace_out is not None: trace_out.append({ @@ -607,6 +735,7 @@ def convert_svg_to_slide_shapes( 'summary': { 'converted': converted, 'skipped': skipped, + 'promoted_backgrounds': promoted_backgrounds, 'media_files': len(ctx.media_files), 'package_files': len(ctx.package_files), 'relationships': len(ctx.rel_entries), @@ -623,6 +752,7 @@ def convert_svg_to_slide_shapes( xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"> +{background_xml} diff --git a/plugins/codex/plugins/shadcn/THIRD_PARTY_SOURCE.json b/plugins/codex/plugins/shadcn/THIRD_PARTY_SOURCE.json index 736890d8b..9a385e1bc 100644 --- a/plugins/codex/plugins/shadcn/THIRD_PARTY_SOURCE.json +++ b/plugins/codex/plugins/shadcn/THIRD_PARTY_SOURCE.json @@ -2,8 +2,8 @@ "sourceId": "shadcn", "repo": "https://github.com/shadcn-ui/ui.git", "ref": "main", - "commit": "d8ace420baa5c8a1abccd75e52570f2a232f193d", + "commit": "68e1f171aa8c6ce2e38cb9a7d1463d6bcf357e91", "adapter": "claude-skill", "sourcePath": "skills/shadcn", - "syncedAt": "2026-07-06T16:00:00Z" + "syncedAt": "2026-07-07T16:00:00Z" }