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.
This commit is contained in:
@@ -24,8 +24,8 @@
|
||||
"repo": "https://github.com/Yeachan-Heo/oh-my-codex.git",
|
||||
"ref": "main",
|
||||
"adapter": "codex-plugin",
|
||||
"commit": "bf497e67604f788fe4e85f0f13ec086e50857c5d",
|
||||
"syncedAt": "2026-07-31T16:00:01Z"
|
||||
"commit": "a62d5bd77bef6d2bc7df467dcae68082b8616239",
|
||||
"syncedAt": "2026-08-01T16:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "ui-ux-pro-max",
|
||||
@@ -33,8 +33,8 @@
|
||||
"repo": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git",
|
||||
"ref": "main",
|
||||
"adapter": "claude-skill",
|
||||
"commit": "ec1f2a9027e270c9a4e8e3dbc243136fa9d32505",
|
||||
"syncedAt": "2026-07-31T16:00:01Z"
|
||||
"commit": "14ddef5c05e52d7c253b8f0129de7bcd1045ae5b",
|
||||
"syncedAt": "2026-08-01T16:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "caveman",
|
||||
@@ -96,8 +96,8 @@
|
||||
"repo": "https://github.com/hugohe3/ppt-master.git",
|
||||
"ref": "main",
|
||||
"adapter": "claude-skill",
|
||||
"commit": "6b42a6a652f9d6e9fc0c81e634c9fdfe771eee10",
|
||||
"syncedAt": "2026-07-31T16:00:01Z"
|
||||
"commit": "8858c4960b870f12baf952994fbd0c76ab5ba4ec",
|
||||
"syncedAt": "2026-08-01T16:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "next-skills",
|
||||
@@ -105,8 +105,8 @@
|
||||
"repo": "https://github.com/vercel/next.js.git",
|
||||
"ref": "canary",
|
||||
"adapter": "skill-collection",
|
||||
"commit": "7612eaeda1d70daa5abaef01aa255541f8dc3fb8",
|
||||
"syncedAt": "2026-07-31T16:00:01Z"
|
||||
"commit": "ccd47cfe53c7fef5e6b7ad472a3a020605a23608",
|
||||
"syncedAt": "2026-08-01T16:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"name": "playwright浏览器自动化操作",
|
||||
"version": "20260605",
|
||||
"keySource": "none",
|
||||
"syncedAt": "2026-07-31T16:01:47Z"
|
||||
"syncedAt": "2026-08-01T16:01:45Z"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "next-skills",
|
||||
"repo": "https://github.com/vercel/next.js.git",
|
||||
"ref": "canary",
|
||||
"commit": "7612eaeda1d70daa5abaef01aa255541f8dc3fb8",
|
||||
"commit": "ccd47cfe53c7fef5e6b7ad472a3a020605a23608",
|
||||
"adapter": "skill-collection",
|
||||
"sourcePath": "skills",
|
||||
"syncedAt": "2026-07-31T16:00:01Z"
|
||||
"syncedAt": "2026-08-01T16:00:00Z"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "oh-my-codex",
|
||||
"repo": "https://github.com/Yeachan-Heo/oh-my-codex.git",
|
||||
"ref": "main",
|
||||
"commit": "bf497e67604f788fe4e85f0f13ec086e50857c5d",
|
||||
"commit": "a62d5bd77bef6d2bc7df467dcae68082b8616239",
|
||||
"adapter": "codex-plugin",
|
||||
"sourcePath": "plugins/oh-my-codex",
|
||||
"syncedAt": "2026-07-31T16:00:01Z"
|
||||
"syncedAt": "2026-08-01T16:00:00Z"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "ppt-master",
|
||||
"repo": "https://github.com/hugohe3/ppt-master.git",
|
||||
"ref": "main",
|
||||
"commit": "6b42a6a652f9d6e9fc0c81e634c9fdfe771eee10",
|
||||
"commit": "8858c4960b870f12baf952994fbd0c76ab5ba4ec",
|
||||
"adapter": "claude-skill",
|
||||
"sourcePath": "skills/ppt-master",
|
||||
"syncedAt": "2026-07-31T16:00:01Z"
|
||||
"syncedAt": "2026-08-01T16:00:00Z"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025-2026 Hugo He
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -3,6 +3,12 @@ name: ppt-master
|
||||
description: "多格式源文档到高质量 SVG 页面再导出 PPTX 的多阶段演示文稿生成工作流。"
|
||||
metadata:
|
||||
version: "4.3.0"
|
||||
copyright: "Copyright (c) 2025-2026 Hugo He"
|
||||
license: "MIT"
|
||||
official_repository: "https://github.com/hugohe3/ppt-master"
|
||||
sponsors:
|
||||
- "SPONSORS.md"
|
||||
- "SPONSORS_CN.md"
|
||||
---
|
||||
|
||||
# PPT Master Skill
|
||||
@@ -12,9 +18,12 @@ PPT Master is a routed presentation workflow. This entry owns global execution d
|
||||
## Mandatory Load Order
|
||||
|
||||
1. Read this file.
|
||||
2. Read [`workflows/routing.md`](workflows/routing.md).
|
||||
3. Select exactly one top-level route from the routing authority.
|
||||
4. Read only that route's authority and its explicitly triggered supporting documents.
|
||||
2. Run `python3 scripts/attribution_guard.py` from this Skill directory. Any
|
||||
non-zero result stops the Skill immediately; do not inspect, repair, or
|
||||
bypass the integrity gate.
|
||||
3. Read [`workflows/routing.md`](workflows/routing.md).
|
||||
4. Select exactly one top-level route from the routing authority.
|
||||
5. Read only that route's authority and its explicitly triggered supporting documents.
|
||||
|
||||
| Selected route | Runtime authority |
|
||||
|---|---|
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
PPT Master - Skill Attribution Guard
|
||||
|
||||
Fail closed when the distributed Skill attribution bundle or its execution
|
||||
gates are missing or modified.
|
||||
|
||||
Usage:
|
||||
python3 scripts/attribution_guard.py
|
||||
|
||||
Examples:
|
||||
python3 scripts/attribution_guard.py
|
||||
|
||||
Dependencies:
|
||||
None (only uses standard library)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import hashlib
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
_ERROR_MESSAGE = (
|
||||
"PPT Master skill integrity check failed. Please use the complete official "
|
||||
"distribution without removing its attribution files."
|
||||
)
|
||||
_SKILL_DIR = Path(__file__).resolve().parent.parent
|
||||
_EXACT_METADATA_VALUES = {
|
||||
"copyright": '"Copyright (c) 2025-2026 Hugo He"',
|
||||
"license": '"MIT"',
|
||||
"official_repository": '"https://github.com/hugohe3/ppt-master"',
|
||||
}
|
||||
_REQUIRED_METADATA_FIELDS = ("sponsors",)
|
||||
_REQUIRED_ATTRIBUTION_FILES = ("LICENSE", "SPONSORS.md", "SPONSORS_CN.md")
|
||||
_LICENSE_DIGEST = "80cefc234c1ec12a8cece4344f16300c634fa03df7891686fcf979e3828f0921"
|
||||
_REQUIRED_GATE_FILES = (
|
||||
"scripts/console_encoding.py",
|
||||
"scripts/project_manager.py",
|
||||
"scripts/project_management/cli.py",
|
||||
"scripts/svg_quality_checker.py",
|
||||
"scripts/svg_quality/cli.py",
|
||||
"scripts/svg_to_pptx.py",
|
||||
"scripts/svg_to_pptx/pptx_package/cli.py",
|
||||
"scripts/template_fill_pptx.py",
|
||||
"scripts/template_fill_pptx/cli.py",
|
||||
"scripts/native_enhance_pptx.py",
|
||||
"scripts/native_enhance_pptx_core.py",
|
||||
"scripts/register_template.py",
|
||||
"scripts/template_preview_pptx.py",
|
||||
)
|
||||
_SKILL_GATE_MARKER = "python3 scripts/attribution_guard.py"
|
||||
_SECONDARY_GATE_FILE = "scripts/console_encoding.py"
|
||||
_SECONDARY_GATE_NAME = "_require_official_distribution_identity"
|
||||
|
||||
|
||||
def _normalized_bytes(path: Path) -> bytes:
|
||||
"""Return UTF-8 text bytes with platform line endings normalized."""
|
||||
data = path.read_bytes()
|
||||
if data.startswith(b"\xef\xbb\xbf"):
|
||||
raise ValueError("UTF-8 BOM is not allowed")
|
||||
text = data.decode("utf-8")
|
||||
return text.replace("\r\n", "\n").replace("\r", "\n").encode("utf-8")
|
||||
|
||||
|
||||
def _frontmatter(skill_text: str) -> str:
|
||||
"""Return the opening YAML frontmatter or reject malformed input."""
|
||||
if not skill_text.startswith("---\n"):
|
||||
raise ValueError("missing frontmatter")
|
||||
end = skill_text.find("\n---\n", 4)
|
||||
if end < 0:
|
||||
raise ValueError("unterminated frontmatter")
|
||||
return skill_text[4:end]
|
||||
|
||||
|
||||
def _metadata_is_valid() -> bool:
|
||||
"""Require fixed identity values and each structural attribution field."""
|
||||
skill_text = _normalized_bytes(_SKILL_DIR / "SKILL.md").decode("utf-8")
|
||||
metadata = _frontmatter(skill_text)
|
||||
return (
|
||||
all(
|
||||
len(re.findall(
|
||||
rf"(?m)^ {re.escape(field)}\s*:\s*{re.escape(value)}\s*$",
|
||||
metadata,
|
||||
)) == 1
|
||||
for field, value in _EXACT_METADATA_VALUES.items()
|
||||
)
|
||||
and all(
|
||||
len(re.findall(rf"(?m)^ {re.escape(field)}\s*:", metadata)) == 1
|
||||
for field in _REQUIRED_METADATA_FIELDS
|
||||
)
|
||||
and skill_text.count(_SKILL_GATE_MARKER) == 1
|
||||
)
|
||||
|
||||
|
||||
def _protected_files_are_valid() -> bool:
|
||||
"""Require all attribution paths and the exact MIT license text."""
|
||||
for relative_path in _REQUIRED_ATTRIBUTION_FILES:
|
||||
path = _SKILL_DIR / relative_path
|
||||
if not path.is_file():
|
||||
return False
|
||||
license_digest = hashlib.sha256(_normalized_bytes(_SKILL_DIR / "LICENSE")).hexdigest()
|
||||
return license_digest == _LICENSE_DIGEST
|
||||
|
||||
|
||||
def _is_zero_arg_call(node: ast.stmt, function_name: str) -> bool:
|
||||
"""Return whether one statement directly invokes the named function."""
|
||||
return (
|
||||
isinstance(node, ast.Expr)
|
||||
and isinstance(node.value, ast.Call)
|
||||
and isinstance(node.value.func, ast.Name)
|
||||
and node.value.func.id == function_name
|
||||
and not node.value.args
|
||||
and not node.value.keywords
|
||||
)
|
||||
|
||||
|
||||
def _is_gate_call(node: ast.stmt) -> bool:
|
||||
"""Return whether one statement directly invokes the primary integrity gate."""
|
||||
return _is_zero_arg_call(node, "require_skill_integrity")
|
||||
|
||||
|
||||
def _execution_gate_is_valid(path: Path) -> bool:
|
||||
"""Require one live import and one live entry-point call."""
|
||||
tree = ast.parse(_normalized_bytes(path).decode("utf-8"), filename=str(path))
|
||||
has_import = any(
|
||||
isinstance(node, ast.ImportFrom)
|
||||
and node.module == "attribution_guard"
|
||||
and any(alias.name == "require_skill_integrity" for alias in node.names)
|
||||
for node in tree.body
|
||||
)
|
||||
has_entry_call = False
|
||||
for node in tree.body:
|
||||
if (
|
||||
isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
||||
and node.name in {"configure_utf8_stdio", "main"}
|
||||
):
|
||||
body = node.body[1:] if (
|
||||
node.body
|
||||
and isinstance(node.body[0], ast.Expr)
|
||||
and isinstance(node.body[0].value, ast.Constant)
|
||||
and isinstance(node.body[0].value.value, str)
|
||||
) else node.body
|
||||
has_entry_call = bool(body and _is_gate_call(body[0]))
|
||||
elif isinstance(node, ast.If) and any(_is_gate_call(statement) for statement in node.body):
|
||||
has_entry_call = True
|
||||
return has_import and has_entry_call
|
||||
|
||||
|
||||
def _execution_gates_are_valid() -> bool:
|
||||
"""Require every supported route to retain executable guard calls."""
|
||||
for relative_path in _REQUIRED_GATE_FILES:
|
||||
if not _execution_gate_is_valid(_SKILL_DIR / relative_path):
|
||||
return False
|
||||
return _secondary_execution_gate_is_valid(_SKILL_DIR / _SECONDARY_GATE_FILE)
|
||||
|
||||
|
||||
def _secondary_execution_gate_is_valid(path: Path) -> bool:
|
||||
"""Require the independent identity guard and its live bootstrap call."""
|
||||
tree = ast.parse(_normalized_bytes(path).decode("utf-8"), filename=str(path))
|
||||
has_guard = any(
|
||||
isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
||||
and node.name == _SECONDARY_GATE_NAME
|
||||
for node in tree.body
|
||||
)
|
||||
for node in tree.body:
|
||||
if not (
|
||||
isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
||||
and node.name == "configure_utf8_stdio"
|
||||
):
|
||||
continue
|
||||
body = node.body[1:] if (
|
||||
node.body
|
||||
and isinstance(node.body[0], ast.Expr)
|
||||
and isinstance(node.body[0].value, ast.Constant)
|
||||
and isinstance(node.body[0].value.value, str)
|
||||
) else node.body
|
||||
return (
|
||||
has_guard
|
||||
and len(body) >= 2
|
||||
and _is_gate_call(body[0])
|
||||
and _is_zero_arg_call(body[1], _SECONDARY_GATE_NAME)
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def _integrity_is_valid() -> bool:
|
||||
"""Validate every local attribution and execution invariant."""
|
||||
return (
|
||||
_metadata_is_valid()
|
||||
and _protected_files_are_valid()
|
||||
and _execution_gates_are_valid()
|
||||
)
|
||||
|
||||
|
||||
def require_skill_integrity() -> None:
|
||||
"""Stop the active command with one generic message on any expected failure."""
|
||||
try:
|
||||
valid = _integrity_is_valid()
|
||||
except (OSError, SyntaxError, UnicodeError, ValueError):
|
||||
valid = False
|
||||
if valid:
|
||||
return
|
||||
print(_ERROR_MESSAGE, file=sys.stderr)
|
||||
raise SystemExit(78)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Run the fail-closed Skill integrity gate."""
|
||||
require_skill_integrity()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -3,10 +3,67 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import io
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import TextIO
|
||||
|
||||
from attribution_guard import require_skill_integrity
|
||||
|
||||
|
||||
_SKILL_DIR = Path(__file__).resolve().parent.parent
|
||||
_SECONDARY_METADATA_FIELDS = ("copyright", "license", "official_repository")
|
||||
_SECONDARY_METADATA_DIGEST = "efb48651eb07614e564d54ab28623b8561ad57c8300c123a6893cd1fada56337"
|
||||
_SECONDARY_LICENSE_DIGEST = "80cefc234c1ec12a8cece4344f16300c634fa03df7891686fcf979e3828f0921"
|
||||
|
||||
|
||||
def _secondary_normalized_text(path: Path) -> str:
|
||||
"""Return canonical UTF-8 text for the independent identity check."""
|
||||
data = path.read_bytes()
|
||||
if data.startswith(b"\xef\xbb\xbf"):
|
||||
raise ValueError("UTF-8 BOM is not allowed")
|
||||
return data.decode("utf-8").replace("\r\n", "\n").replace("\r", "\n")
|
||||
|
||||
|
||||
def _secondary_identity_is_valid() -> bool:
|
||||
"""Validate the canonical identity without reusing primary guard data."""
|
||||
skill_text = _secondary_normalized_text(_SKILL_DIR / "SKILL.md")
|
||||
if not skill_text.startswith("---\n"):
|
||||
return False
|
||||
metadata_end = skill_text.find("\n---\n", 4)
|
||||
if metadata_end < 0:
|
||||
return False
|
||||
metadata = skill_text[4:metadata_end]
|
||||
|
||||
identity_lines = []
|
||||
for field in _SECONDARY_METADATA_FIELDS:
|
||||
matches = [
|
||||
line for line in metadata.splitlines()
|
||||
if line.startswith(f" {field}:")
|
||||
]
|
||||
if len(matches) != 1:
|
||||
return False
|
||||
identity_lines.append(matches[0])
|
||||
|
||||
metadata_digest = hashlib.sha256("\n".join(identity_lines).encode("utf-8")).hexdigest()
|
||||
license_text = _secondary_normalized_text(_SKILL_DIR / "LICENSE")
|
||||
license_digest = hashlib.sha256(license_text.encode("utf-8")).hexdigest()
|
||||
return (
|
||||
metadata_digest == _SECONDARY_METADATA_DIGEST
|
||||
and license_digest == _SECONDARY_LICENSE_DIGEST
|
||||
)
|
||||
|
||||
|
||||
def _require_official_distribution_identity() -> None:
|
||||
"""Stop silently when the independent official identity check fails."""
|
||||
try:
|
||||
valid = _secondary_identity_is_valid()
|
||||
except (OSError, UnicodeError, ValueError):
|
||||
valid = False
|
||||
if not valid:
|
||||
raise SystemExit(78)
|
||||
|
||||
|
||||
def _reconfigure_stream(stream: TextIO) -> TextIO:
|
||||
try:
|
||||
@@ -23,5 +80,7 @@ def _reconfigure_stream(stream: TextIO) -> TextIO:
|
||||
|
||||
def configure_utf8_stdio() -> None:
|
||||
"""Use UTF-8 for CLI stdout/stderr, including Windows non-UTF-8 locales."""
|
||||
require_skill_integrity()
|
||||
_require_official_distribution_identity()
|
||||
sys.stdout = _reconfigure_stream(sys.stdout)
|
||||
sys.stderr = _reconfigure_stream(sys.stderr)
|
||||
|
||||
@@ -30,6 +30,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from attribution_guard import require_skill_integrity # noqa: E402
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from native_enhance_pptx_core import main # noqa: E402
|
||||
|
||||
@@ -37,4 +38,5 @@ configure_utf8_stdio()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
require_skill_integrity()
|
||||
raise SystemExit(main())
|
||||
|
||||
@@ -45,6 +45,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from attribution_guard import require_skill_integrity # noqa: E402
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from pptx_delivery_check import audit_pptx_delivery # noqa: E402
|
||||
from pptx_animations import ( # noqa: E402
|
||||
@@ -2467,6 +2468,7 @@ def _record_preflight_exception(
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
require_skill_integrity()
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
|
||||
@@ -48,6 +48,11 @@ from .paths import (
|
||||
)
|
||||
from .project_specs import scaffold_project_artifact, validate_project_artifacts
|
||||
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from attribution_guard import require_skill_integrity # noqa: E402
|
||||
|
||||
try:
|
||||
from project_utils import (
|
||||
CANVAS_FORMATS,
|
||||
@@ -1141,6 +1146,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
"""Run the CLI entry point."""
|
||||
require_skill_integrity()
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
manager = ProjectManager()
|
||||
|
||||
@@ -27,6 +27,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from attribution_guard import require_skill_integrity # noqa: E402
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
@@ -75,4 +76,5 @@ __all__ = [
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
require_skill_integrity()
|
||||
raise SystemExit(main())
|
||||
|
||||
+15
-15
@@ -16,7 +16,7 @@
|
||||
},
|
||||
"file_budgets": {
|
||||
"AGENTS.md": 2400,
|
||||
"skills/ppt-master/SKILL.md": 850,
|
||||
"skills/ppt-master/SKILL.md": 950,
|
||||
"skills/ppt-master/references/executor-base.md": 8245,
|
||||
"skills/ppt-master/references/executor-structured.md": 5300,
|
||||
"skills/ppt-master/references/executor-chart.md": 3100,
|
||||
@@ -45,7 +45,7 @@
|
||||
"skills/ppt-master/SKILL.md",
|
||||
"skills/ppt-master/workflows/routing.md"
|
||||
],
|
||||
"max_tokens": 5775
|
||||
"max_tokens": 5855
|
||||
},
|
||||
"support.sponsor-recommendation.en": {
|
||||
"description": "English sponsor context for explicit user requests for model, AI image model, API/provider, or hosted-service recommendations.",
|
||||
@@ -93,7 +93,7 @@
|
||||
"skills/ppt-master/templates/README.md",
|
||||
"skills/ppt-master/templates/decks/README.md"
|
||||
],
|
||||
"max_tokens": 58325
|
||||
"max_tokens": 58421
|
||||
},
|
||||
"route.create-template.layout": {
|
||||
"description": "Create Layout path through Template_Designer, SVG core, and the structured PPTX interface.",
|
||||
@@ -111,7 +111,7 @@
|
||||
"skills/ppt-master/templates/README.md",
|
||||
"skills/ppt-master/templates/layouts/README.md"
|
||||
],
|
||||
"max_tokens": 58500
|
||||
"max_tokens": 58598
|
||||
},
|
||||
"route.enhance-native-pptx": {
|
||||
"description": "Finished-PPTX native enhancement route.",
|
||||
@@ -122,7 +122,7 @@
|
||||
"files": [
|
||||
"skills/ppt-master/workflows/native-enhance-pptx.md"
|
||||
],
|
||||
"max_tokens": 9775
|
||||
"max_tokens": 9849
|
||||
},
|
||||
"route.fill-native-pptx": {
|
||||
"description": "Raw-PPTX native fill route.",
|
||||
@@ -133,7 +133,7 @@
|
||||
"files": [
|
||||
"skills/ppt-master/workflows/template-fill-pptx.md"
|
||||
],
|
||||
"max_tokens": 11475
|
||||
"max_tokens": 11542
|
||||
},
|
||||
"route.generate.planning": {
|
||||
"description": "Generate-PPTX planning through Strategist, including reference-first whole-document authoring and representative multi-source custom mode/style synthesis; schemas and optional scaffolds are tool-consumed.",
|
||||
@@ -186,7 +186,7 @@
|
||||
"skills/ppt-master/references/svg-effects.md",
|
||||
"skills/ppt-master/references/native-shape-authoring.md"
|
||||
],
|
||||
"max_tokens": 55068
|
||||
"max_tokens": 55127
|
||||
},
|
||||
"route.generate.quick-generate.topic-research": {
|
||||
"description": "Quick Generate with gap-targeted factual research before direct resource preparation and SVG authoring.",
|
||||
@@ -196,7 +196,7 @@
|
||||
"stage.generate.topic-research"
|
||||
],
|
||||
"files": [],
|
||||
"max_tokens": 56580
|
||||
"max_tokens": 56639
|
||||
},
|
||||
"route.generate.quick-generate.icon": {
|
||||
"description": "Quick Generate with project-local bundled icon selection and synchronization.",
|
||||
@@ -207,7 +207,7 @@
|
||||
"files": [
|
||||
"skills/ppt-master/templates/icons/README.md"
|
||||
],
|
||||
"max_tokens": 56980
|
||||
"max_tokens": 57039
|
||||
},
|
||||
"route.generate.quick-generate.in-hand-image": {
|
||||
"description": "Quick Generate with supplied, extracted, or placeholder image resources prepared before SVG authoring.",
|
||||
@@ -217,7 +217,7 @@
|
||||
"stage.generate.executor.image"
|
||||
],
|
||||
"files": [],
|
||||
"max_tokens": 66734
|
||||
"max_tokens": 66789
|
||||
},
|
||||
"route.generate.quick-generate.formula": {
|
||||
"description": "Quick Generate with manifest-driven formula rendering and formula-image realization.",
|
||||
@@ -229,7 +229,7 @@
|
||||
"files": [
|
||||
"skills/ppt-master/scripts/docs/image.md"
|
||||
],
|
||||
"max_tokens": 69920
|
||||
"max_tokens": 69975
|
||||
},
|
||||
"route.generate.quick-generate.ai-two-types": {
|
||||
"description": "Quick Generate with AI resource preparation, representative rendering inputs, and two local image types.",
|
||||
@@ -240,7 +240,7 @@
|
||||
"stage.generate.executor.image"
|
||||
],
|
||||
"files": [],
|
||||
"max_tokens": 89839
|
||||
"max_tokens": 89894
|
||||
},
|
||||
"route.generate.quick-generate.web-image": {
|
||||
"description": "Quick Generate with web resource preparation, provenance, attribution, and image execution.",
|
||||
@@ -251,7 +251,7 @@
|
||||
"stage.generate.executor.web-image"
|
||||
],
|
||||
"files": [],
|
||||
"max_tokens": 74487
|
||||
"max_tokens": 74542
|
||||
},
|
||||
"route.generate.planning-image": {
|
||||
"description": "Generate-PPTX planning context after a non-none image source is proposed or confirmed, including the compact layout math and vocabulary.",
|
||||
@@ -451,7 +451,7 @@
|
||||
"stage.shared.generate-audio"
|
||||
],
|
||||
"files": [],
|
||||
"max_tokens": 15125
|
||||
"max_tokens": 15206
|
||||
},
|
||||
"route.generate.beautify-flat-no-image": {
|
||||
"description": "Generate-PPTX 1:1 beautify profile on the flat no-image path.",
|
||||
@@ -622,7 +622,7 @@
|
||||
"skills/ppt-master/workflows/stages/resume-execute.md",
|
||||
"skills/ppt-master/references/artifact-ownership.md"
|
||||
],
|
||||
"max_tokens": 68804
|
||||
"max_tokens": 68863
|
||||
},
|
||||
"stage.generate.resume-execute-image": {
|
||||
"description": "Fresh-session resume when the locked resource plan contains image rows.",
|
||||
|
||||
@@ -49,6 +49,7 @@ from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from attribution_guard import require_skill_integrity
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from config import CANVAS_FORMATS
|
||||
|
||||
@@ -705,6 +706,7 @@ def _print_completion_card(kind: str, template_id: str, entry: dict, extras: dic
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def main() -> int:
|
||||
require_skill_integrity()
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Register / refresh templates (brand / layout / deck) in the index."
|
||||
)
|
||||
|
||||
@@ -16,6 +16,7 @@ Dependencies:
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from attribution_guard import require_skill_integrity
|
||||
from slide_roster import discover_slide_svgs
|
||||
|
||||
from .checker import SVGQualityChecker
|
||||
@@ -90,6 +91,7 @@ def print_usage() -> None:
|
||||
|
||||
def main() -> None:
|
||||
"""Run the CLI entry point."""
|
||||
require_skill_integrity()
|
||||
if len(sys.argv) < 2:
|
||||
print_usage()
|
||||
sys.exit(0)
|
||||
|
||||
@@ -23,6 +23,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from attribution_guard import require_skill_integrity # noqa: E402
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
|
||||
configure_utf8_stdio()
|
||||
@@ -56,4 +57,5 @@ __all__ = [
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
require_skill_integrity()
|
||||
main()
|
||||
|
||||
@@ -12,10 +12,12 @@ from pathlib import Path
|
||||
# Ensure the scripts directory is on sys.path so the package can be found
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from attribution_guard import require_skill_integrity
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from svg_to_pptx import main
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == '__main__':
|
||||
require_skill_integrity()
|
||||
raise SystemExit(main())
|
||||
|
||||
+2
@@ -19,6 +19,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from attribution_guard import require_skill_integrity # noqa: E402
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from language_tags import ( # noqa: E402
|
||||
LanguageTagError,
|
||||
@@ -797,6 +798,7 @@ def _resolve_animation_config_source(
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
"""CLI entry point for the SVG to PPTX conversion tool."""
|
||||
require_skill_integrity()
|
||||
transition_choices = [
|
||||
'none',
|
||||
*NATIVE_TRANSITION_KEYS,
|
||||
|
||||
@@ -21,10 +21,12 @@ from pathlib import Path
|
||||
# Ensure the scripts directory is on sys.path so the package can be found.
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from attribution_guard import require_skill_integrity
|
||||
from console_encoding import configure_utf8_stdio
|
||||
from template_fill_pptx import main
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
if __name__ == "__main__":
|
||||
require_skill_integrity()
|
||||
raise SystemExit(main())
|
||||
|
||||
@@ -12,6 +12,7 @@ _SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from attribution_guard import require_skill_integrity # noqa: E402
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from pptx_transitions import ( # noqa: E402
|
||||
LEGACY_TRANSITION_KEYS,
|
||||
@@ -153,6 +154,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
require_skill_integrity()
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
|
||||
@@ -31,6 +31,7 @@ from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from attribution_guard import require_skill_integrity
|
||||
from console_encoding import configure_utf8_stdio
|
||||
|
||||
|
||||
@@ -362,6 +363,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
require_skill_integrity()
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"sourceId": "ui-ux-pro-max",
|
||||
"repo": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git",
|
||||
"ref": "main",
|
||||
"commit": "ec1f2a9027e270c9a4e8e3dbc243136fa9d32505",
|
||||
"commit": "14ddef5c05e52d7c253b8f0129de7bcd1045ae5b",
|
||||
"adapter": "claude-skill",
|
||||
"sourcePath": ".claude/skills/ui-ux-pro-max",
|
||||
"syncedAt": "2026-07-31T16:00:01Z"
|
||||
"syncedAt": "2026-08-01T16:00:00Z"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user