refactor(skills): align MPI skills with Agent Skills best practices

The skill metadata had drifted: every SKILL.md name field lacked the
mpi- prefix, contradicting the directory names and the Agent Skills
specification. Descriptions were also missing negative triggers, making
it easy for the agent to load the wrong skill.

Rewrote the pdf-to-docx skill to follow progressive disclosure: the main
SKILL.md dropped from 318 lines to 80, with detailed code examples moved
to on-demand references. Added uv run instructions and /// script PEP 723
metadata so dependencies are declared inline and installed automatically.
Fixed the pptx skill's script paths and added CLI usage messages to both
pptx scripts and the normalize script.

Removed the empty self-review directory that was superseded by the unified
translation-review skill.
This commit is contained in:
iacore
2026-07-14 23:18:55 +08:00
parent 216a7658ac
commit 894d769051
16 changed files with 371 additions and 361 deletions
+59 -45
View File
@@ -1,3 +1,11 @@
# /// script
# requires-python = ">=3.9"
# dependencies = [
# "python-pptx",
# "pyyaml",
# ]
# ///
import sys, yaml
from pptx import Presentation
from pptx.util import Pt
@@ -5,15 +13,6 @@ from pptx.enum.text import MSO_AUTO_SIZE
FONT_SCALE = 0.82 # shrink ~18%
yaml_path, src_path, out_path = sys.argv[1], sys.argv[2], sys.argv[3]
with open(yaml_path) as f:
entries = yaml.safe_load(f)
index = {}
for e in entries:
index[(e["slide"], e["shape"], e["run"])] = e["en"]
def shrink_font_tf(tf):
for para in tf.paragraphs:
@@ -26,43 +25,58 @@ def shrink_font_tf(tf):
pass
prs = Presentation(src_path)
def build(yaml_path, src_path, out_path):
with open(yaml_path) as f:
entries = yaml.safe_load(f)
for slide_num, slide in enumerate(prs.slides, 1):
for shape_idx, shape in enumerate(slide.shapes):
if shape.has_text_frame:
has_translation = False
for para_idx, para in enumerate(shape.text_frame.paragraphs):
key = (slide_num, shape_idx, para_idx)
if key in index:
has_translation = True
en = index[key]
for r in para.runs:
r.text = ""
if para.runs:
para.runs[0].text = en
else:
para.add_run().text = en
if has_translation:
shrink_font_tf(shape.text_frame)
index = {}
for e in entries:
index[(e["slide"], e["shape"], e["run"])] = e["en"]
elif shape.has_table:
num_rows = len(shape.table.rows)
for r in range(num_rows * len(shape.table.columns)):
key = (slide_num, shape_idx, r)
if key in index:
row = r % num_rows
col = r // num_rows
shape.table.cell(row, col).text = index[key]
for row in shape.table.rows:
for cell in row.cells:
shrink_font_tf(cell.text_frame)
prs = Presentation(src_path)
key = (slide_num, -1, 0)
if key in index and slide.has_notes_slide:
ns = slide.notes_slide
ns.notes_text_frame.clear()
ns.notes_text_frame.paragraphs[0].add_run().text = index[key]
for slide_num, slide in enumerate(prs.slides, 1):
for shape_idx, shape in enumerate(slide.shapes):
if shape.has_text_frame:
has_translation = False
for para_idx, para in enumerate(shape.text_frame.paragraphs):
key = (slide_num, shape_idx, para_idx)
if key in index:
has_translation = True
en = index[key]
for r in para.runs:
r.text = ""
if para.runs:
para.runs[0].text = en
else:
para.add_run().text = en
if has_translation:
shrink_font_tf(shape.text_frame)
prs.save(out_path)
print(f"Saved {out_path}")
elif shape.has_table:
num_rows = len(shape.table.rows)
for r in range(num_rows * len(shape.table.columns)):
key = (slide_num, shape_idx, r)
if key in index:
row = r % num_rows
col = r // num_rows
shape.table.cell(row, col).text = index[key]
for row in shape.table.rows:
for cell in row.cells:
shrink_font_tf(cell.text_frame)
key = (slide_num, -1, 0)
if key in index and slide.has_notes_slide:
ns = slide.notes_slide
ns.notes_text_frame.clear()
ns.notes_text_frame.paragraphs[0].add_run().text = index[key]
prs.save(out_path)
print(f"Saved {out_path}")
if __name__ == "__main__":
if len(sys.argv) != 4:
print("Usage: uv run build.py <strings.yaml> <input.pptx> <output.pptx>", file=sys.stderr)
sys.exit(1)
build(sys.argv[1], sys.argv[2], sys.argv[3])