Claude Skill

knit-rmd-html

Knit/render R Markdown (.Rmd) to HTML reliably in this repo (auto-bootstrap pandoc, set correct knit_root_dir, and run rmarkdown::render via a Python wrapper).

LLM Mart · 0 points · 17 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download huangwb8-skills-skills_beta_knit-rmd-html-dd1fab8.zip · 8 KB
Part of huangwb8/skills — 22 skills

Install

skills CLI npx skills add https://github.com/huangwb8/skills/tree/main/skills/beta/knit-rmd-html
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install huangwb8-skills@llmmart
Git git clone https://github.com/huangwb8/skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole huangwb8/skills collection as a plugin from our marketplace. Git is the plain clone.

README

Knit Rmd HTML

当前版本:0.1.1。

这个 skill 用来把 .Rmd 文件稳定地渲染成 HTML,适合仓库里的高频 R Markdown 报告输出;如果你想生成 PDF、Word 或处理普通 Markdown,就不该直接用它。

用法

最推荐用法

请使用 knit-rmd-html skill 将这个 R Markdown 文件渲染成 HTML。
输入:`/path/to/report.Rmd`
输出:对应的 `.html` 文件,默认输出到同目录

进阶用法

请使用 knit-rmd-html skill 渲染这个 R Markdown 文件。
输入:`/path/to/report.Rmd`
输出:指定输出位置的 HTML 文件
另外,还有下列参数约束:
- 输出路径:`/path/to/out/report.html`
- 缺少 pandoc 时允许自动安装:是
- 日志尽量安静:是

能做什么

  • 使用 Python 包装层调用 rmarkdown::render(),减少环境差异带来的失败。
  • 缺少 pandoc 时可自动引导安装。
  • Windows 下兼容 Pandoc ZIP 的根目录与 bin/ 两类布局,并识别 pandoc.exe。
  • Rscript 输出固定按 UTF-8 解码,不依赖中文控制台的 GBK locale。
  • 通过正确设置 knit_root_dir,让 Rmd 内相对路径更稳定。
  • 适合本仓库内“把 Rmd 可靠地 knit 成 HTML”的固定场景。
  • 不适合替代通用报告系统或其它输出格式转换器。

使用示例

示例 1:渲染单个 Rmd

请使用 knit-rmd-html skill 将这个 R Markdown 文件渲染成 HTML。
输入:`analysis/report.Rmd`
输出:`analysis/report.html`

示例 2:指定输出文件

请使用 knit-rmd-html skill 渲染这个文件。
输入:`analysis/report.Rmd`
输出:`./outputs/report-final.html`

示例 3:要求失败即报错

请使用 knit-rmd-html skill 渲染这个 Rmd。
输入:`report.Rmd`
输出:HTML 文件
另外,还有下列参数约束:
- 不自动安装依赖:是
- 输出日志:简洁

输出

  • 默认输出:与输入 .Rmd 同目录下的同名 .html。
  • 可以通过参数显式指定输出路径。
  • 缺少 pandoc 时可自动补齐到本地用户目录。
  • 需要 Rscript 可用;否则无法真正执行渲染。

配置

  • 版本号由 config.yaml:skill_info.version 统一管理,高频设置通过命令行参数控制。
  • 最常用参数:
    • -o / --output
    • --pandoc-version
    • --no-install
    • --quiet

备选用法(脚本/硬编码)

如果你已经在仓库里,直接运行脚本通常是最稳定的方式。

基础渲染

python3 knit-rmd-html/scripts/knit_rmd_html.py report.Rmd

指定输出文件

python3 knit-rmd-html/scripts/knit_rmd_html.py \
  report.Rmd \
  -o outputs/report.html

控制依赖安装与日志

python3 knit-rmd-html/scripts/knit_rmd_html.py \
  report.Rmd \
  --no-install \
  --quiet

常见问题

Q:为什么这个 skill 不直接让我写 R 命令?

A:因为它的价值之一就是帮你把环境检测、pandoc 补齐和稳定渲染流程包装好。

Q:会自动安装什么?

A:主要是缺失的 pandoc。真正的渲染仍然依赖本地 Rscript 和 rmarkdown 运行环境。

Q:为什么输出默认在原文件旁边?

A:这是最符合直觉、也最不容易弄丢结果的默认行为。

Q:它能生成 PDF 吗?

A:这个 skill 的职责是 .Rmd -> HTML。如果你要别的格式,应该走其他专门技能或工具链。

Skill manifest

Knit Rmd → HTML(项目高频场景)

目标

Knit/render R Markdown (.Rmd) to HTML reliably in this repo (auto-bootstrap pandoc, set correct knit_root_dir, and run rmarkdown::render via a Python wrapper).

当用户说"knit 出 html / render Rmd / 生成 HTML 报告"时使用本 skill。

版本由 config.yaml:skill_info.version 统一管理。

流程

输入

输入为待渲染的 .Rmd 路径;可选输入包括项目根目录、输出文件路径、Pandoc 版本/下载选项和 rmarkdown::render 参数。渲染前需确认项目 knit_root_dir、R 和必要模板资源可用。

执行步骤

直接用法

  • 在仓库根目录执行:
    • python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd
    • 输出默认写到 <input>.Rmd 同目录:<input>.html

常用参数

  • 指定输出文件:
    • python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd -o <output>.html
  • 指定 pandoc 版本(默认 3.8.3):
    • python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd --pandoc-version 3.8.3
  • 不自动安装依赖(只做检测;缺什么就报错):
    • python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd --no-install
  • 静默渲染输出:
    • python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd --quiet

设计要点(为何这样做)

  • 不依赖 R 写脚本:外层用 Python 做编排与环境自检;真正的 knit 仍由 rmarkdown::render() 执行。
  • 自动补齐 pandoc:若系统无 pandoc,自动下载安装到 ~/.local/pandoc/ 并将 ~/.local/bin 放到子进程 PATH 前面。
  • 兼容 Windows ZIP:安全解压后递归寻找唯一的 pandoc / pandoc.exe,兼容根目录与 bin/ 布局并拒绝歧义结果。
  • 输出编码稳定:Rscript 日志始终按 UTF-8 解码并保留真实退出码,不依赖 Windows 控制台 locale。
  • 相对路径更稳:用 knit_root_dir=dirname(input),确保 Rmd 内 source("xxx.R") 等相对路径在 knit 时仍可用。

工作原理

  1. 环境检测:检查 pandoc 和 Rscript 是否在 PATH 中
  2. 自动安装:若缺少 pandoc,根据平台自动下载对应版本到 ~/.local/pandoc/
  3. 渲染执行:通过 R 的 rmarkdown::render() 执行 knit
  4. 输出定位:默认输出到输入文件同目录,可通过 -o 参数指定

输出

成功时在同级目录生成与 Rmd 同名的 HTML,或写入由 -o 指定的输出文件路径;同时保留渲染日志、Pandoc/依赖诊断和任务工作区中的临时产物,不改变输入 Rmd。

输出管理

BenszAPI 任务工作区

校验

校验 Rmd 路径和项目根目录、Pandoc/R 依赖、knit_root_dir 与输出 HTML 存在性;渲染退出码为 0 且 HTML 可读取时才报告成功。

失败与恢复

Pandoc/R 缺失、引导下载失败、路径越界、渲染超时或 rmarkdown::render 返回非零时,保留日志和诊断输出并报告可复现命令;若产生部分输出,由用户按需清理或隔离后再修复依赖/参数重试。

约束

公共硬约束

本块由 docs/templates/skill-common-constraints.md 统一维护;每个 SKILL.md 的 ## 约束 必须逐字同步本块,不得在副本中改写公共规则。

  • 任务需要落盘时,使用唯一的 ./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/ 根目录;共享材料放入 shared/,Skill 专属材料放入该 Skill 的 input/、output/、log/。
  • 正式交付物、源代码和正式计划按项目约定保存,不写入任务工作区;未经授权不覆盖、删除、迁移或远程写入。
  • 项目维护变更检查 BAC 可用性并记录需求、AI 产出、工具结果、文件改动和验证摘要;BAC 只做过程审计,不替代署名、责任或合规判断。
  • 不记录 API Key、访问令牌、密码、Cookie、环境/凭据文件、私有 Prompt、身份信息、本地用户名、主机名或不必要的大体积原始数据。
  • 文件路径必须规范化并限制在授权项目范围内;外部 URL、子进程和网络访问遵循最小权限,防止路径遍历、SSRF 和命令注入。
  • Skill 版本唯一记录在自身 config.yaml:skill_info.version;公开 API、协议、目录或配置变更同步文档与 CHANGELOG.md。
  • bensz-collect-bugs 是一个 Agent Skill;仅将 Bensz Agent Skill 或 Bensz 基础设施本身的设计缺陷交给它。先脱敏写入 ~/.bensz-skills/bugs/,当前任务不中断,只有用户明确要求才公开上报,禁止直接修改用户已安装的 Skill 源码。
Files (skills)
  • scripts
    • knit_rmd_html.py 8.3 KB
      #!/usr/bin/env python3
      import argparse
      import json
      import os
      import platform
      import shutil
      import subprocess
      import sys
      import tempfile
      import urllib.request
      import zipfile
      
      
      def _run(cmd, *, env=None, cwd=None):
          proc = subprocess.run(
              cmd,
              env=env,
              cwd=cwd,
              stdout=subprocess.PIPE,
              stderr=subprocess.STDOUT,
              text=True,
              encoding="utf-8",
              errors="replace",
          )
          return proc.returncode, proc.stdout
      
      
      def _which(cmd, env):
          return shutil.which(cmd, path=env.get("PATH"))
      
      
      def _ensure_dir(path):
          os.makedirs(path, exist_ok=True)
      
      
      def _detect_pandoc(env):
          pandoc = _which("pandoc", env)
          if not pandoc:
              return None, None
          code, out = _run([pandoc, "--version"], env=env)
          if code != 0:
              return pandoc, None
          first = out.splitlines()[0].strip() if out else None
          return pandoc, first
      
      
      def _github_latest_pandoc_tag(env):
          url = "https://api.github.com/repos/jgm/pandoc/releases/latest"
          req = urllib.request.Request(url, headers={"Accept": "application/vnd.github+json", "User-Agent": "knit-rmd-html-skill"})
          with urllib.request.urlopen(req, timeout=30) as resp:
              data = json.loads(resp.read().decode("utf-8"))
          return data.get("tag_name")
      
      
      def _pandoc_asset_name(version, system, machine):
          system = system.lower()
          machine = machine.lower()
          if system == "darwin":
              if machine in ("arm64", "aarch64"):
                  return f"pandoc-{version}-arm64-macOS.zip"
              if machine in ("x86_64", "amd64"):
                  return f"pandoc-{version}-x86_64-macOS.zip"
              raise RuntimeError(f"Unsupported macOS arch: {machine}")
          if system == "linux":
              if machine in ("x86_64", "amd64"):
                  return f"pandoc-{version}-linux-amd64.tar.gz"
              if machine in ("arm64", "aarch64"):
                  return f"pandoc-{version}-linux-arm64.tar.gz"
              raise RuntimeError(f"Unsupported linux arch: {machine}")
          if system == "windows":
              if machine in ("x86_64", "amd64"):
                  return f"pandoc-{version}-windows-x86_64.zip"
              if machine in ("arm64", "aarch64"):
                  return f"pandoc-{version}-windows-arm64.zip"
              raise RuntimeError(f"Unsupported windows arch: {machine}")
          raise RuntimeError(f"Unsupported OS: {system}")
      
      
      def _install_pandoc_zip(zip_path, install_root):
          install_root = os.path.abspath(install_root)
          with zipfile.ZipFile(zip_path) as zf:
              for member in zf.infolist():
                  target = os.path.abspath(os.path.join(install_root, member.filename))
                  if os.path.commonpath([install_root, target]) != install_root:
                      raise RuntimeError(f"Unsafe path in Pandoc zip: {member.filename}")
              zf.extractall(install_root)
      
          candidates = []
          for root, _, filenames in os.walk(install_root):
              for filename in filenames:
                  if filename.lower() in {"pandoc", "pandoc.exe"}:
                      candidates.append(os.path.join(root, filename))
          candidates.sort()
          if not candidates:
              raise RuntimeError("Pandoc zip extracted but no pandoc or pandoc.exe executable was found.")
          if len(candidates) > 1:
              relative = [os.path.relpath(path, install_root) for path in candidates]
              raise RuntimeError(f"Pandoc zip contains ambiguous executables: {', '.join(relative)}")
          return candidates[0]
      
      
      def _ensure_pandoc(env, *, version, no_install):
          pandoc, verline = _detect_pandoc(env)
          if pandoc:
              return pandoc, verline
          if no_install:
              raise RuntimeError("pandoc not found in PATH, and --no-install is set.")
      
          system = platform.system()
          machine = platform.machine()
          asset = _pandoc_asset_name(version, system, machine)
          url = f"https://github.com/jgm/pandoc/releases/download/{version}/{asset}"
      
          home = os.path.expanduser("~")
          pandoc_root = os.path.join(home, ".local", "pandoc")
          bin_root = os.path.join(home, ".local", "bin")
          _ensure_dir(pandoc_root)
          _ensure_dir(bin_root)
      
          zip_path = os.path.join(pandoc_root, asset)
          if not os.path.exists(zip_path):
              with urllib.request.urlopen(url, timeout=120) as resp, open(zip_path, "wb") as f:
                  f.write(resp.read())
      
          if not asset.endswith(".zip"):
              raise RuntimeError(
                  f"Auto-install currently supports zip assets only (got {asset}). "
                  f"Please install pandoc manually or use a zip-capable platform."
              )
      
          # Extract into a versioned folder to keep installs reproducible
          install_root = os.path.join(pandoc_root, f"pandoc-{version}")
          if os.path.exists(install_root):
              shutil.rmtree(install_root)
          _ensure_dir(install_root)
      
          pandoc_bin = _install_pandoc_zip(zip_path, install_root)
          if not os.path.exists(pandoc_bin):
              raise RuntimeError("pandoc binary not found after installation.")
          try:
              os.chmod(pandoc_bin, 0o755)
          except OSError:
              pass
      
          link_name = "pandoc.exe" if pandoc_bin.lower().endswith(".exe") else "pandoc"
          link_path = os.path.join(bin_root, link_name)
          try:
              if os.path.islink(link_path) or os.path.exists(link_path):
                  os.remove(link_path)
              os.symlink(pandoc_bin, link_path)
          except OSError:
              shutil.copy2(pandoc_bin, link_path)
              try:
                  os.chmod(link_path, 0o755)
              except OSError:
                  pass
      
          # Prepend ~/.local/bin to PATH for the current process & downstream
          env2 = dict(env)
          env2["PATH"] = os.pathsep.join([bin_root, env.get("PATH", "")])
          pandoc, verline = _detect_pandoc(env2)
          if not pandoc:
              raise RuntimeError("pandoc installation finished but still not detectable.")
          return pandoc, verline
      
      
      def _ensure_rscript(env):
          rscript = _which("Rscript", env)
          if not rscript:
              raise RuntimeError("Rscript not found in PATH. Please install R first.")
          return rscript
      
      
      def main():
          ap = argparse.ArgumentParser(description="Render a .Rmd to HTML (auto-bootstrap pandoc) via a Python wrapper.")
          ap.add_argument("input", help="Path to .Rmd")
          ap.add_argument("-o", "--output", default=None, help="Output HTML path (default: alongside input)")
          ap.add_argument("--pandoc-version", default="3.8.3", help="Pandoc version to auto-install when missing")
          ap.add_argument("--no-install", action="store_true", help="Do not auto-install pandoc / R packages; fail fast")
          ap.add_argument("--quiet", action="store_true", help="Quiet render output")
          args = ap.parse_args()
      
          inp = os.path.abspath(args.input)
          if not os.path.exists(inp):
              raise SystemExit(f"Input not found: {inp}")
          if not inp.lower().endswith(".rmd"):
              raise SystemExit("Input must be a .Rmd file.")
      
          out = args.output
          if out is None:
              base, _ = os.path.splitext(inp)
              out = base + ".html"
          out = os.path.abspath(out)
      
          env = dict(os.environ)
      
          try:
              pandoc, verline = _ensure_pandoc(env, version=args.pandoc_version, no_install=args.no_install)
          except Exception as e:
              raise SystemExit(f"[pandoc] {e}")
      
          # Make sure downstream R can see pandoc if installed into ~/.local/bin
          home = os.path.expanduser("~")
          env["PATH"] = os.pathsep.join([os.path.join(home, ".local", "bin"), env.get("PATH", "")])
      
          try:
              rscript = _ensure_rscript(env)
          except Exception as e:
              raise SystemExit(f"[R] {e}")
      
          knit_root = os.path.dirname(inp)
      
          # Render via rmarkdown. Keep the R snippet minimal; orchestration is in Python.
          ensure_rmarkdown = (
              "if (!requireNamespace('rmarkdown', quietly=TRUE)) {"
              + (
                  "stop('Package rmarkdown is required but missing (use --no-install to fail fast).', call.=FALSE);"
                  if args.no_install
                  else "install.packages('rmarkdown', repos='https://cloud.r-project.org');"
              )
              + "}"
          )
          render_call = (
              "rmarkdown::render("
              f"input={json.dumps(inp)}, "
              f"output_file={json.dumps(out)}, "
              f"knit_root_dir={json.dumps(knit_root)}, "
              f"quiet={str(bool(args.quiet)).upper()}"
              ")"
          )
          r_expr = ensure_rmarkdown + ";" + render_call
      
          code, outlog = _run([rscript, "-e", r_expr], env=env, cwd=knit_root)
          if code != 0:
              sys.stdout.write(outlog)
              raise SystemExit(f"[render] Failed (exit={code}).")
      
          if not args.quiet and outlog.strip():
              sys.stdout.write(outlog)
          print(f"[render] OK: {out}")
      
      
      if __name__ == "__main__":
          main()
      
  • CHANGELOG.md 726 B
    # knit-rmd-html - 变更日志
    
    遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 与语义化版本规范。
    
    ## [Unreleased]
    
    ### Fixed(修复)
    
    - 修复 Windows Pandoc ZIP 布局并不固定为 `bin/pandoc` 的问题:解压后递归发现唯一的 `pandoc` / `pandoc.exe`,拒绝路径穿越、缺失和歧义结果,并保留 `.exe` 文件名供 Windows `PATH` 发现。
    - 修复 Windows 中文 locale 下 Rscript 的 UTF-8 输出被按 GBK 解码的问题:子进程输出统一使用 UTF-8 并以 replacement 策略保留返回码和可读日志。
    
    ## [0.1.0]
    
    ### Added(新增)
    
    - 初始化 R Markdown 到 HTML 的 Python 渲染入口,并支持缺少 Pandoc 时按固定版本安装。
    
  • config.yaml 183 B
    skill_info:
      name: knit-rmd-html
      version: 0.1.1
      description: 可靠地将 R Markdown 渲染为 HTML,并按需引导安装 Pandoc
      author: "Bensz Conan"
      category: R Markdown
    
  • README.md 3.4 KB
    # Knit Rmd HTML
    
    当前版本:`0.1.1`。
    
    这个 skill 用来把 `.Rmd` 文件稳定地渲染成 HTML,适合仓库里的高频 R Markdown 报告输出;如果你想生成 PDF、Word 或处理普通 Markdown,就不该直接用它。
    
    ## 用法
    
    ### 最推荐用法
    
    ```text
    请使用 knit-rmd-html skill 将这个 R Markdown 文件渲染成 HTML。
    输入:`/path/to/report.Rmd`
    输出:对应的 `.html` 文件,默认输出到同目录
    ```
    
    ### 进阶用法
    
    ```text
    请使用 knit-rmd-html skill 渲染这个 R Markdown 文件。
    输入:`/path/to/report.Rmd`
    输出:指定输出位置的 HTML 文件
    另外,还有下列参数约束:
    - 输出路径:`/path/to/out/report.html`
    - 缺少 pandoc 时允许自动安装:是
    - 日志尽量安静:是
    ```
    
    ## 能做什么
    
    - 使用 Python 包装层调用 `rmarkdown::render()`,减少环境差异带来的失败。
    - 缺少 `pandoc` 时可自动引导安装。
    - Windows 下兼容 Pandoc ZIP 的根目录与 `bin/` 两类布局,并识别 `pandoc.exe`。
    - Rscript 输出固定按 UTF-8 解码,不依赖中文控制台的 GBK locale。
    - 通过正确设置 `knit_root_dir`,让 Rmd 内相对路径更稳定。
    - 适合本仓库内“把 Rmd 可靠地 knit 成 HTML”的固定场景。
    - 不适合替代通用报告系统或其它输出格式转换器。
    
    ## 使用示例
    
    ### 示例 1:渲染单个 Rmd
    
    ```text
    请使用 knit-rmd-html skill 将这个 R Markdown 文件渲染成 HTML。
    输入:`analysis/report.Rmd`
    输出:`analysis/report.html`
    ```
    
    ### 示例 2:指定输出文件
    
    ```text
    请使用 knit-rmd-html skill 渲染这个文件。
    输入:`analysis/report.Rmd`
    输出:`./outputs/report-final.html`
    ```
    
    ### 示例 3:要求失败即报错
    
    ```text
    请使用 knit-rmd-html skill 渲染这个 Rmd。
    输入:`report.Rmd`
    输出:HTML 文件
    另外,还有下列参数约束:
    - 不自动安装依赖:是
    - 输出日志:简洁
    ```
    
    ## 输出
    
    - 默认输出:与输入 `.Rmd` 同目录下的同名 `.html`。
    - 可以通过参数显式指定输出路径。
    - 缺少 `pandoc` 时可自动补齐到本地用户目录。
    - 需要 `Rscript` 可用;否则无法真正执行渲染。
    
    ## 配置
    
    - 版本号由 `config.yaml:skill_info.version` 统一管理,高频设置通过命令行参数控制。
    - 最常用参数:
      - `-o` / `--output`
      - `--pandoc-version`
      - `--no-install`
      - `--quiet`
    
    ## 备选用法(脚本/硬编码)
    
    如果你已经在仓库里,直接运行脚本通常是最稳定的方式。
    
    ### 基础渲染
    
    ```bash
    python3 knit-rmd-html/scripts/knit_rmd_html.py report.Rmd
    ```
    
    ### 指定输出文件
    
    ```bash
    python3 knit-rmd-html/scripts/knit_rmd_html.py \
      report.Rmd \
      -o outputs/report.html
    ```
    
    ### 控制依赖安装与日志
    
    ```bash
    python3 knit-rmd-html/scripts/knit_rmd_html.py \
      report.Rmd \
      --no-install \
      --quiet
    ```
    
    ## 常见问题
    
    ### Q:为什么这个 skill 不直接让我写 R 命令?
    
    A:因为它的价值之一就是帮你把环境检测、`pandoc` 补齐和稳定渲染流程包装好。
    
    ### Q:会自动安装什么?
    
    A:主要是缺失的 `pandoc`。真正的渲染仍然依赖本地 `Rscript` 和 `rmarkdown` 运行环境。
    
    ### Q:为什么输出默认在原文件旁边?
    
    A:这是最符合直觉、也最不容易弄丢结果的默认行为。
    
    ### Q:它能生成 PDF 吗?
    
    A:这个 skill 的职责是 `.Rmd -> HTML`。如果你要别的格式,应该走其他专门技能或工具链。
    
  • SKILL.md 5.1 KB
    ---
    name: knit-rmd-html
    description: Knit/render R Markdown (.Rmd) to HTML reliably in this repo (auto-bootstrap pandoc, set correct knit_root_dir, and run rmarkdown::render via a Python wrapper).
    metadata:
      author: Bensz Conan
      keywords:
        - knit-rmd-html
    ---
    
    # Knit Rmd → HTML(项目高频场景)
    
    ## 目标
    
    Knit/render R Markdown (.Rmd) to HTML reliably in this repo (auto-bootstrap pandoc, set correct knit_root_dir, and run rmarkdown::render via a Python wrapper).
    
    当用户说"knit 出 html / render Rmd / 生成 HTML 报告"时使用本 skill。
    
    版本由 `config.yaml:skill_info.version` 统一管理。
    
    ## 流程
    
    ### 输入
    
    输入为待渲染的 `.Rmd` 路径;可选输入包括项目根目录、输出文件路径、Pandoc 版本/下载选项和 `rmarkdown::render` 参数。渲染前需确认项目 `knit_root_dir`、R 和必要模板资源可用。
    
    ### 执行步骤
    
    #### 直接用法
    
    - 在仓库根目录执行:
      - `python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd`
      - 输出默认写到 `<input>.Rmd` 同目录:`<input>.html`
    
    #### 常用参数
    
    - 指定输出文件:
      - `python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd -o <output>.html`
    - 指定 pandoc 版本(默认 `3.8.3`):
      - `python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd --pandoc-version 3.8.3`
    - 不自动安装依赖(只做检测;缺什么就报错):
      - `python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd --no-install`
    - 静默渲染输出:
      - `python3 skills/knit-rmd-html/scripts/knit_rmd_html.py <input>.Rmd --quiet`
    
    #### 设计要点(为何这样做)
    
    - **不依赖 R 写脚本**:外层用 Python 做编排与环境自检;真正的 knit 仍由 `rmarkdown::render()` 执行。
    - **自动补齐 pandoc**:若系统无 `pandoc`,自动下载安装到 `~/.local/pandoc/` 并将 `~/.local/bin` 放到子进程 `PATH` 前面。
    - **兼容 Windows ZIP**:安全解压后递归寻找唯一的 `pandoc` / `pandoc.exe`,兼容根目录与 `bin/` 布局并拒绝歧义结果。
    - **输出编码稳定**:Rscript 日志始终按 UTF-8 解码并保留真实退出码,不依赖 Windows 控制台 locale。
    - **相对路径更稳**:用 `knit_root_dir=dirname(input)`,确保 Rmd 内 `source("xxx.R")` 等相对路径在 knit 时仍可用。
    
    #### 工作原理
    
    1. **环境检测**:检查 `pandoc` 和 `Rscript` 是否在 PATH 中
    2. **自动安装**:若缺少 pandoc,根据平台自动下载对应版本到 `~/.local/pandoc/`
    3. **渲染执行**:通过 R 的 `rmarkdown::render()` 执行 knit
    4. **输出定位**:默认输出到输入文件同目录,可通过 `-o` 参数指定
    
    ### 输出
    
    成功时在同级目录生成与 Rmd 同名的 HTML,或写入由 `-o` 指定的输出文件路径;同时保留渲染日志、Pandoc/依赖诊断和任务工作区中的临时产物,不改变输入 Rmd。
    
    ### 输出管理
    
    #### BenszAPI 任务工作区
    
    
    ### 校验
    
    校验 Rmd 路径和项目根目录、Pandoc/R 依赖、`knit_root_dir` 与输出 HTML 存在性;渲染退出码为 0 且 HTML 可读取时才报告成功。
    
    ### 失败与恢复
    
    Pandoc/R 缺失、引导下载失败、路径越界、渲染超时或 `rmarkdown::render` 返回非零时,保留日志和诊断输出并报告可复现命令;若产生部分输出,由用户按需清理或隔离后再修复依赖/参数重试。
    
    
    ## 约束
    
    <!-- BEGIN COMMON CONSTRAINTS -->
    <!-- Source-Hash: sha256:15120201e9e0c7569517261d57ecefb63ac279c26ed13876f8e95b6dc35854d3 -->
    <!-- Template-ID: skill-common-constraints; Template-Version: 1; Sync-Policy: exact-block -->
    
    ### 公共硬约束
    
    本块由 `docs/templates/skill-common-constraints.md` 统一维护;每个 `SKILL.md` 的 `## 约束` 必须逐字同步本块,不得在副本中改写公共规则。
    
    - 任务需要落盘时,使用唯一的 `./.bensz-api/task-{yyyymmdd-hhmm}-{简短描述}/` 根目录;共享材料放入 `shared/`,Skill 专属材料放入该 Skill 的 `input/`、`output/`、`log/`。
    - 正式交付物、源代码和正式计划按项目约定保存,不写入任务工作区;未经授权不覆盖、删除、迁移或远程写入。
    - 项目维护变更检查 BAC 可用性并记录需求、AI 产出、工具结果、文件改动和验证摘要;BAC 只做过程审计,不替代署名、责任或合规判断。
    - 不记录 API Key、访问令牌、密码、Cookie、环境/凭据文件、私有 Prompt、身份信息、本地用户名、主机名或不必要的大体积原始数据。
    - 文件路径必须规范化并限制在授权项目范围内;外部 URL、子进程和网络访问遵循最小权限,防止路径遍历、SSRF 和命令注入。
    - Skill 版本唯一记录在自身 `config.yaml:skill_info.version`;公开 API、协议、目录或配置变更同步文档与 `CHANGELOG.md`。
    - `bensz-collect-bugs` 是一个 Agent Skill;仅将 Bensz Agent Skill 或 Bensz 基础设施本身的设计缺陷交给它。先脱敏写入 `~/.bensz-skills/bugs/`,当前任务不中断,只有用户明确要求才公开上报,禁止直接修改用户已安装的 Skill 源码。
    
    <!-- End of canonical common constraints. -->
    <!-- END COMMON CONSTRAINTS -->
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related