mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-30 15:10:41 +00:00
fix(skills): support direct invocation of the skill packager (#6938)
Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
parent
2488ba7c27
commit
d8d0830e16
@ -1774,6 +1774,8 @@ Discovery follows operator-managed directory symlinks, but skips links back to a
|
||||
|
||||
Skill Markdown and bundled text resources use UTF-8. Skill-creator CLI and review utilities read and write text explicitly as UTF-8 so localized skills behave consistently across operating systems.
|
||||
|
||||
For standalone skill exports, the bundled skill creator's `scripts/package_skill.py` can be run by file path from any directory, or as `python -m scripts.package_skill` from the skill-creator directory. Both entry points validate the skill before writing a `.skill` archive.
|
||||
|
||||
Custom-skill writes and security-scan staging preserve submitted line endings
|
||||
on every platform, so the scanner checks the bytes that will be stored.
|
||||
|
||||
|
||||
@ -3,18 +3,22 @@
|
||||
Skill Packager - Creates a distributable .skill file of a skill folder
|
||||
|
||||
Usage:
|
||||
python utils/package_skill.py <path/to/skill-folder> [output-directory]
|
||||
python scripts/package_skill.py <path/to/skill-folder> [output-directory]
|
||||
|
||||
Example:
|
||||
python utils/package_skill.py skills/public/my-skill
|
||||
python utils/package_skill.py skills/public/my-skill ./dist
|
||||
python scripts/package_skill.py skills/public/my-skill
|
||||
python scripts/package_skill.py skills/public/my-skill ./dist
|
||||
"""
|
||||
|
||||
import fnmatch
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from scripts.quick_validate import validate_skill
|
||||
|
||||
if __name__ == "__main__" and not __package__:
|
||||
from quick_validate import validate_skill
|
||||
else:
|
||||
from scripts.quick_validate import validate_skill
|
||||
|
||||
# Patterns to exclude when packaging skills.
|
||||
EXCLUDE_DIRS = {"__pycache__", "node_modules"}
|
||||
@ -88,9 +92,9 @@ def package_skill(skill_path, output_dir=None):
|
||||
|
||||
# Create the .skill file (zip format)
|
||||
try:
|
||||
with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||||
with zipfile.ZipFile(skill_filename, "w", zipfile.ZIP_DEFLATED) as zipf:
|
||||
# Walk through the skill directory, excluding build artifacts
|
||||
for file_path in skill_path.rglob('*'):
|
||||
for file_path in skill_path.rglob("*"):
|
||||
if not file_path.is_file():
|
||||
continue
|
||||
arcname = file_path.relative_to(skill_path.parent)
|
||||
@ -110,10 +114,10 @@ def package_skill(skill_path, output_dir=None):
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
|
||||
print("Usage: python scripts/package_skill.py <path/to/skill-folder> [output-directory]")
|
||||
print("\nExample:")
|
||||
print(" python utils/package_skill.py skills/public/my-skill")
|
||||
print(" python utils/package_skill.py skills/public/my-skill ./dist")
|
||||
print(" python scripts/package_skill.py skills/public/my-skill")
|
||||
print(" python scripts/package_skill.py skills/public/my-skill ./dist")
|
||||
sys.exit(1)
|
||||
|
||||
skill_path = sys.argv[1]
|
||||
|
||||
50
tests/skills/test_skill_packager_cli.py
Normal file
50
tests/skills/test_skill_packager_cli.py
Normal file
@ -0,0 +1,50 @@
|
||||
"""Exercise the skill packager through its standalone and module entry points."""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
SKILL_CREATOR = Path(__file__).resolve().parents[2] / "skills/public/skill-creator"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("entrypoint", ["script", "module"])
|
||||
@pytest.mark.parametrize("valid", [True, False], ids=["valid", "invalid"])
|
||||
def test_packager_cli(tmp_path, entrypoint, valid):
|
||||
skill = tmp_path / "example-skill"
|
||||
skill.mkdir()
|
||||
content = "---\nname: example-skill\ndescription: Example skill.\n---\n"
|
||||
if not valid:
|
||||
content = "# Missing frontmatter\n"
|
||||
(skill / "SKILL.md").write_text(content, encoding="utf-8", newline="\n")
|
||||
output = tmp_path / "dist"
|
||||
if entrypoint == "script":
|
||||
command = [str(SKILL_CREATOR / "scripts/package_skill.py")]
|
||||
cwd = tmp_path
|
||||
else:
|
||||
command = ["-m", "scripts.package_skill"]
|
||||
cwd = SKILL_CREATOR
|
||||
env = {**os.environ, "PYTHONIOENCODING": "utf-8"}
|
||||
env.pop("PYTHONPATH", None)
|
||||
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-B", *command, str(skill), str(output)],
|
||||
cwd=cwd,
|
||||
env=env,
|
||||
capture_output=True,
|
||||
encoding="utf-8",
|
||||
timeout=15,
|
||||
)
|
||||
|
||||
assert result.returncode == (0 if valid else 1), result.stdout + result.stderr
|
||||
assert "Traceback" not in result.stderr
|
||||
archive = output / "example-skill.skill"
|
||||
if valid:
|
||||
with zipfile.ZipFile(archive) as package:
|
||||
assert package.read("example-skill/SKILL.md").decode("utf-8") == content
|
||||
else:
|
||||
assert "No YAML frontmatter found" in result.stdout
|
||||
assert not archive.exists()
|
||||
Loading…
x
Reference in New Issue
Block a user