| name | paper-compile-zh |
| description | Compile Chinese LaTeX paper to PDF using XeLaTeX. Use when user says "编译中文论文", "compile Chinese paper", "中文PDF", or wants to compile a Chinese academic paper. |
| argument-hint | ["paper-directory"] |
| allowed-tools | Bash(*), Read, Write, Edit, Grep, Glob |
Chinese Paper Compile: XeLaTeX → PDF
Compile a Chinese LaTeX paper: $ARGUMENTS
Constants
- ENGINE =
xelatex — Required for Chinese text
- MAX_COMPILE_ATTEMPTS = 3
- PAPER_DIR =
paper/
- MAX_PAGES — From Additional Parameters.
- PAPER_TYPE — bachelor/master/journal
Workflow
Step 1: Verify environment
if ! which xelatex 2>/dev/null; then
echo "xelatex not found, attempting install..."
if which miktex 2>/dev/null; then
miktex packages install xetex ctex xecjk gbt7714 fontspec
miktex fndb refresh
elif which initexmf 2>/dev/null; then
initexmf --set-config-value=[MPM]AutoInstall=1
fi
fi
which xelatex && which bibtex && echo "ready" || echo "xelatex/bibtex not found"
fc-list :lang=zh | head -5
kpsewhich gbt7714.sty 2>/dev/null || echo "gbt7714.sty not found (will auto-install on first compile)"
Step 2: Pre-compile cleanup
if [ -f "_utils/compile_utils.sh" ]; then
bash _utils/compile_utils.sh paper/
elif [ -f "skills/shared-scripts/compile_utils.sh" ]; then
bash skills/shared-scripts/compile_utils.sh paper/
else
echo "compile_utils.sh not found, manual cleanup needed"
fi
The script auto-handles: special chars cleanup (emoji, zero-width chars, Unicode math → LaTeX), table format fixes (single → double backslash), includegraphics path correction, hidelinks, figures/figures/ nesting, PDF existence check, math_commands conflicts, wide table resizebox wrapping, narrow table resizebox removal, light-color text fixes, on background layer removal, TikZ library injection (backgrounds + fit).
If script not found, perform these steps manually.
Step 3: Figure completeness check
mkdir -p _tmp
grep -oh '\\ref{[^}]*}' paper/sections/*.tex paper/main.tex 2>/dev/null | sort -u > _tmp/_refs.txt
grep -oh '\\label{[^}]*}' paper/sections/*.tex paper/main.tex 2>/dev/null | sort -u > _tmp/_labels.txt
comm -23 <(sed 's/\\ref/\\label/g' _tmp/_refs.txt) _tmp/_labels.txt > _tmp/_missing_labels.txt
cat _tmp/_missing_labels.txt
If labels are missing, find corresponding figure/table code in figures/*.tex and embed into the correct section file. Figure embedding is the compile step's responsibility — do not just warn, actually fix it by copying the figure/table block from figures/*.tex into the appropriate section.
Also check compile_utils.sh output for "UNEMBEDDED" warnings — each one means a figure or table from figures/ is not in any section.
MANDATORY FIX LOOP — do NOT proceed to compilation until all figures AND tables are embedded:
UNEMBED=0
for pdf in figures/*.pdf; do
[ -f "$pdf" ] || continue
bn=$(basename "$pdf")
grep -rq "$bn" paper/sections/*.tex paper/main.tex 2>/dev/null || { echo "UNEMBEDDED PDF: $bn"; UNEMBED=$((UNEMBED+1)); }
done
for tbl in figures/TABLE_*.tex; do
[ -f "$tbl" ] || continue
bn=$(basename "$tbl")
for lbl in $(grep -oh '\\label{[^}]*}' "$tbl" 2>/dev/null); do
grep -rq "$lbl" paper/sections/*.tex paper/main.tex 2>/dev/null || { echo "UNEMBEDDED TABLE: $lbl (from $bn)"; UNEMBED=$((UNEMBED+1)); }
done
done
if [ -f figures/latex_includes.tex ]; then
for lbl in $(grep -oh '\\label{[^}]*}' figures/latex_includes.tex 2>/dev/null); do
grep -rq "$lbl" paper/sections/*.tex paper/main.tex 2>/dev/null || { echo "UNEMBEDDED: $lbl"; UNEMBED=$((UNEMBED+)); }
If UNEMBED > 0, fix ALL before compiling. For each:
- PDF: copy
\begin{figure}...\end{figure} from figures/latex_includes.tex into target section
- TABLE_*.tex: paste the
\begin{table}...\end{table} block into target section
- Add lead-in text + analysis after each embedded item
- Re-run count check — repeat until UNEMBED = 0
Step 3.5: 模板完整性检查(编译前必须通过)
echo "=== main.tex 模板完整性检查(编译前)==="
FAIL=0
grep -q 'documentclass' paper/main.tex || { echo "❌ 缺少 documentclass"; FAIL=$((FAIL+1)); }
grep -q '\\input{sections/' paper/main.tex || { echo "❌ 缺少 sections input"; FAIL=$((FAIL+1)); }
grep -q 'thebibliography\|bibliography{' paper/main.tex || { echo "❌ 缺少参考文献"; FAIL=$((FAIL+1)); }
grep -q 'superscript\|\\@cite\|setcitestyle.*super' paper/main.tex || { echo "❌ 缺少上标引用"; FAIL=$((FAIL+1)); }
if grep -qi 'wuyi\|五一杯' CLAUDE.md 2>/dev/null; then
grep -q '承诺书' paper/main.tex || { echo "❌ 五一杯缺少承诺书页"; FAIL=$((FAIL+1)); }
grep -q 'image2' paper/main.tex || { echo "❌ 五一杯缺少封面logo"; FAIL=$((FAIL+1)); }
fi
[ "$FAIL" -eq 0 ] && echo "✅ 模板完整性检查通过" || echo "⛔ $FAIL 项失败 — main.tex 可能被重写了,必须从模板恢复"
⛔ 如果模板检查失败,必须从模板目录重新复制 main.tex 并只替换占位符,不要继续编译。
Step 4: Compile (manual steps, no latexmk)
cd paper/
rm -f main.aux main.blg main.log main.out main.toc main.xdv 2>/dev/null
xelatex -interaction=nonstopmode main.tex 2>&1 | tee compile_pass1.log
bibtex main 2>&1 | tee bibtex.log
xelatex -interaction=nonstopmode main.tex 2>&1 | tee compile_pass2.log
xelatex -interaction=nonstopmode main.tex 2>&1 | tee compile.log
[ -f main.pdf ] && echo "main.pdf $(wc -c < main.pdf) bytes" || echo "PDF not generated"
Step 5: Error diagnosis and fix loop (MANDATORY)
After each compilation, check main.log for CRITICAL errors. You MUST fix ALL errors before declaring compilation complete.
MATH_ERR=$(grep -c 'Bad math environment delimiter\|Missing \$ inserted\|begin{document} ended by' paper/main.log 2>/dev/null || echo 0)
LR_ERR=$(grep -c 'Not allowed in LR mode' paper/main.log 2>/dev/null || echo 0)
echo "Math errors: $MATH_ERR, LR mode errors: $LR_ERR"
[ $((MATH_ERR + LR_ERR)) -gt 0 ] && grep -B2 'Bad math\|Missing \$ inserted\|Not allowed in LR mode' paper/main.log | grep -E '^\./|^l\.' | head -20
Iterate up to MAX_COMPILE_ATTEMPTS times, each with full 4-step compilation (xelatex → bibtex → xelatex → xelatex). For each error:
- Math errors: read the error location from main.log, open the file, fix broken
$...$ delimiters individually. Do NOT use broad sed patterns.
- LR mode errors: add
\par or blank line before float environments.
- Missing packages:
tlmgr install or miktex auto-install.
- Font not found: check
fc-list.
- BibTeX failures: fix LaTeX errors first (BibTeX fails when LaTeX errors exist upstream), then recompile.
After each fix, recompile and recheck. ⛔ Do NOT proceed until MATH_ERR = 0 and LR_ERR = 0.
When fixing errors in main.tex, only fix the specific error. Do not rewrite or restructure main.tex — the template's preamble, cover page, page margins, section numbering format, and header/footer settings must remain unchanged.
Step 6: Post-compile checks
bash _utils/compile_check.sh paper/ 2>/dev/null || bash skills/shared-scripts/compile_check.sh paper/
The script checks: PDF existence/size, undefined references, overfull hbox, TOC, Chinese/English abstracts, bibliography command and entries, citation count in body, unused figures, figure stacking, TikZ diagram presence against plan.
Run compile_utils.sh post-compile checks too (items 10-13: TOC, abstracts, bibliography config, unused figures).
Step 7: Page count verification
Body pages = chapter 1 through conclusion, excluding cover/abstract/TOC/references/acknowledgments/appendix.
Body pages must be ≥ MAX_PAGES. If insufficient, return to paper-write-zh to expand content. Exceeding MAX_PAGES is allowed.
Step 8: ⛔ FINAL QUALITY GATE
echo "=========================================="
echo " FINAL QUALITY GATE"
echo "=========================================="
GATE_FAIL=0
[ -f paper/main.pdf ] && [ $(wc -c < paper/main.pdf) -gt 100000 ] && echo "✅ PDF exists" || { echo "❌ PDF missing"; GATE_FAIL=$((GATE_FAIL+1)); }
MATH_ERR=$(grep -c 'Bad math.*delimiter\|Missing \$ inserted' paper/main.log 2>/dev/null || echo 0)
LR_ERR=$(grep -c 'Not allowed in LR mode' paper/main.log 2>/dev/null || echo 0)
[ "$((MATH_ERR+LR_ERR))" -eq 0 ] && echo "✅ No LaTeX errors" || { echo "❌ $MATH_ERR math + $LR_ERR LR errors"; GATE_FAIL=$((GATE_FAIL+1)); }
BBL=$(grep -c '\\bibitem' paper/main.bbl 2>/dev/null || echo 0)
[ "$BBL" -gt 0 ] && echo "✅ Bib: $BBL entries" || { echo "❌ Bib empty"; GATE_FAIL=$((GATE_FAIL+1)); }
UNEMBED=0
for pdf in figures/*.pdf; do [ -f "$pdf" ] || continue; bn=$(basename ""); grep -rq paper/sections/*.tex paper/main.tex 2>/dev/null || UNEMBED=$((UNEMBED+));
[ -eq 0 ] && || { ; GATE_FAIL=$((GATE_FAIL+)); }
VBOX=$(grep -c paper/main.log 2>/dev/null || 0)
[ -eq 0 ] && || { ; GATE_FAIL=$((GATE_FAIL+)); }
AI_LISTS=0
f paper/sections/*.tex; [ -f ] || ; | grep -qi && ; c=$(grep -c 2>/dev/null || 0); AI_LISTS=$((AI_LISTS+c));
[ -eq 0 ] && || { ; GATE_FAIL=$((GATE_FAIL+)); }
TMPL=
t _templates/stats_main.tex _templates/cumcm_main.tex _templates/bachelor_main.tex _templates/master_main.tex _templates/journal_main.tex; [ -f ] && TMPL= && ;
[ -n ] && [ -f paper/main.tex ];
TMPL_PRE=$(sed -n | grep | )
MAIN_PRE=$(sed -n paper/main.tex | grep | )
MISSING=$( -23 <( ) <( ) 2>/dev/null | -5)
[ -z ] && || { ; | sed ; GATE_FAIL=$((GATE_FAIL+)); }
grep -q 2>/dev/null;
grep -q paper/main.tex 2>/dev/null && || { ; GATE_FAIL=$((GATE_FAIL+)); }
grep -q paper/main.tex 2>/dev/null && || { ; GATE_FAIL=$((GATE_FAIL+)); }
grep -q paper/main.tex 2>/dev/null;
; GATE_FAIL=$((GATE_FAIL+))
grep -P paper/main.tex 2>/dev/null | -1 | grep -q ;
; GATE_FAIL=$((GATE_FAIL+))
TIKZ=$(grep -rl paper/sections/*.tex 2>/dev/null | -l)
[ -gt 0 ] && || { ; GATE_FAIL=$((GATE_FAIL+)); }
CITE=$(grep -roh paper/sections/*.tex paper/main.tex 2>/dev/null | -l)
[ -gt 0 ] && || { ; GATE_FAIL=$((GATE_FAIL+)); }
PLACEHOLDERS=$(grep -rl paper/sections/*.tex paper/main.tex 2>/dev/null | -l)
[ -eq 0 ] && || { ; GATE_FAIL=$((GATE_FAIL+)); }
HBOX=$(grep -c paper/main.log 2>/dev/null || 0); [ -lt 5 ] && || { ; GATE_FAIL=$((GATE_FAIL+)); }
grep -rq paper/sections/*.tex paper/main.tex 2>/dev/null && || { ; GATE_FAIL=$((GATE_FAIL+)); }
grep -rq paper/sections/*.tex paper/main.tex 2>/dev/null && || { ; GATE_FAIL=$((GATE_FAIL+)); }
[ -f figures/all_results.json ];
python3 -c 2>/dev/null
[ $? -ne 0 ] && GATE_FAIL=$((GATE_FAIL+))
[ -f figures/all_results.json ];
python3 -c 2>/dev/null
[ -f RESULTS.md ];
grep -q RESULTS.md 2>/dev/null;
GATE_FAIL=$((GATE_FAIL+))
[ -f figures/all_results.json ];
JSON_TIME=$( -c %Y figures/all_results.json 2>/dev/null || -f %m figures/all_results.json 2>/dev/null || 0)
STALE_FIGS=0
pdf figures/*.pdf;
[ -f ] ||
PDF_TIME=$( -c %Y 2>/dev/null || -f %m 2>/dev/null || 0)
[ -gt ] && [ -gt 60 ];
STALE_FIGS=$((STALE_FIGS+))
[ -gt 0 ];
GATE_FAIL=$((GATE_FAIL+))
LONG_TABLES=0
f paper/sections/*.tex;
[ -f ] ||
| grep -qi &&
COUNT=$(grep -c 2>/dev/null || 0)
[ -gt 40 ];
HAS_TABLE=$(grep -c 2>/dev/null || 0)
[ -gt 0 ];
LONG_TABLES=$((LONG_TABLES+))
[ -eq 0 ] && || GATE_FAIL=$((GATE_FAIL+))
META=0
f paper/sections/*.tex;
[ -f ] ||
l=$(grep -ci 2>/dev/null || 0)
META=$((META+l))
[ -eq 0 ] && || { ; GATE_FAIL=$((GATE_FAIL+)); }
OC=0
f paper/sections/*.tex;
[ -f ] ||
w ;
c=$(grep -c 2>/dev/null || 0); OC=$((OC+c))
[ -eq 0 ] && ||
[ -f PAPER_PLAN.md ];
python3 -c 2>/dev/null
[ $? -ne 0 ] && GATE_FAIL=$((GATE_FAIL+))
bash _utils/compile_check.sh paper/ 2>/dev/null || bash skills/shared-scripts/compile_check.sh paper/ 2>/dev/null
bash _utils/writing_check.sh paper/ 2>/dev/null || bash skills/shared-scripts/writing_check.sh paper/ 2>/dev/null
[ -eq 0 ] && ||
⛔ If GATE_FAIL > 0, fix every ❌, recompile, re-run gate. Do NOT finish with any ❌.
Step 9: Output report
Status, PDF path, page count, compliance results, fixed errors, remaining warnings.
Key Rules
- No latexmk — manual step-by-step compilation
- Use
-interaction=nonstopmode, not -halt-on-error
- Do not delete .bbl file (bibliography data) — also do not write cleanup scripts that delete .bbl
- Figure embedding is the compile step's responsibility — fix missing labels from figures/*.tex
- Bibliography is a core validation item — final PDF must not have
[?]
- Primary output:
paper/main.pdf, compile log: paper/compile.log
- Temp files:
_tmp/ directory