Files
Templated-PPT-Master/references/project-workspace.md
T

14 KiB
Raw Blame History

可移动的 PPT 消费工程

接口版本:ppt-project/v1。内容日期:2026-10-10。实现为 ppt_project.py,基础模板接口仍以 template-interface.md 为准。本接口不改变 template_ref.py,不安装全局工具,不初始化 Git,不提交或发布。

工程把正文、页面源、数据、素材、模板源、必要工具和依赖说明放在同一目录。Git 可追踪这些输入;设备相关绝对路径、缓存和导出物在运行时重建。一次工程固定一个 template 版本和一个 theme,页面顺序由 pages 数组表达,重排页面无需更换页面 ID。

用户要求使用本Skill时,必须使用本工程工具创建可构建项目,或继续使用已有的有效工程;单页、小样重建和修改任务也适用,不以需要Git协作或跨设备迁移为前提。选定template/theme后先初始化工程,再在其中维护页面源和真实builder。禁止绕过Skill编译器手拼PPT、临时拼接PPTX/XML/ZIP,或给已手拼的成品补一个空工程。交付PPTX必须由声明的工程入口从当前输入成功构建,并保留对应工程。

复刻已确认小样时,可按C27在工程自有共享样式/版式中调整内容区字号与几何,记录适用范围、单位和取值步长,并由真实builder/renderer消费。把所需样式与配方文件列入build.inputs,作为作者输入锁定;不能只记录数值而不应用,也不修改锁定的vendor/template、已安装模板或冻结包。每次调整后重建,检查内容容器及整页溢出、裁切、遮挡与层次;共享样式变化覆盖受影响页面。此处不新增自动识别的样式叠加schema或模板重锁入口。

初始化与作者工作流

解析和工程管理要求 Python 3.10+,只用标准库;实际 builder 的依赖由工程自行声明。消费方明确逐页制作时,保留 interactive-page,不要因建立工程而自动批量创作。

python3 /path/to/skill/scripts/ppt_project.py init \
  --project /path/to/report \
  --manifest /path/to/released-template/manifest.json \
  --theme chosen-theme --title '报告标题' --project-id example-report \
  --route native --workflow interactive-page

--project 对六个命令均必需。init 另要求 --manifest、--theme、--title;--project-id 默认生成合法 UUID,显式值为小写字母/数字及单连字符组成的 ID。路线默认为 native,另支持 image-rebuild;工作流默认为 interactive-page,另支持 batch。统一的 --theme 在消费 v1 清单时映射为其 mode,不改变基础解析器的 v1 CLI。

目标必须不存在或为空目录。初始化在相邻临时目录完成验证后整体重命名,失败不会把半成品合并入已有目录;非空目标保留。模板包根目录为选中 manifest 的父目录,按相对路径复制到 vendor/template/,排除所有 exports/、缓存、虚拟环境、Git 和本地配置。遇到复制范围内的 symlink 拒绝且不跟随。源清单一般命名为 manifest.json;选择其他文件名时保留原文件并添加相同字节的 manifest.json,有冲突则拒绝。

初始工程是诚实骨架:没有页面,build.entrypoint 为 null。check 可以通过并返回 build_ready: false;build 明确拒绝,不生成占位 PPTX。作者加入页面、数据与真实 builder 后执行:

采用本包原生编译器时,可先运行 python3 /path/to/skill/scripts/prepare_native_project.py --project /path/to/report。它只接受没有 builder、依赖/字体/工具声明为空的已锁定骨架,复制项目内 compiler/wrapper,写入 tools/native_builder.py 和环境声明,并保留旧作者锁。审阅这些改动后显式 lock;不覆盖已有 builder 或已配置环境,不改变工程 schema 1。完整行为见 运行库与出处。

该通用 builder 读取各页已完成的 SVG 和 Markdown 讲稿;content.json/data 仍是锁定作者输入,不会自动绑定到 SVG。需要数据驱动生成的消费方应提供自己的明确绑定或预处理步骤。

自定义预处理/builder仍须通过本Skill的相应编译路线生成最终PPTX,并声明真实输入,不能成为手拼成品的旁路。空骨架、build_ready: false、仅通过check或已有导出物都不算完成可构建项目;必须对当前获准页面实际执行build成功。若所选路线或环境暂时无法构建,完成可独立进行的源工作并说明具体缺口,不用手拼结果冒充工程交付。生产修复回写源后重建,PowerPoint内的临时编辑测试在独立副本中进行。

python3 tools/ppt_project.py lock --project .
python3 tools/ppt_project.py check --project .
python3 tools/ppt_project.py resolve --project .
python3 tools/ppt_project.py build --project .
python3 tools/ppt_project.py pack --project . --out /outside/report-source.zip

resolve 是可选的制作准备步骤,build 会自动执行。check 只读且不运行 builder;resolve 只生成运行时记录且不运行 builder。所有命令输出 JSON,输入错误返回退出码 2 和 stderr JSON。初始化和移动工程时均不复用另一台机器的选择记录。

目录与字段

report/
  project.json
  project.lock.json
  template.lock.json
  environment.json
  README.md
  .gitignore
  .gitattributes
  pages/<stable-id>/source.svg
  pages/<stable-id>/content.json
  pages/<stable-id>/notes.md
  data/
  assets/
  tools/template_ref.py
  tools/ppt_project.py
  tools/build_deck.py              # 作者提供并声明的可选入口
  vendor/template/manifest.json
  build/local/                    # 可丢弃的本机绝对路径记录
  build/tmp/                      # 本次唯一临时产物
  exports/deck.pptx                # 可丢弃的构建结果

project.json 的固定基础字段如下;示例中页面和 builder 由作者加入,初始值为 pages: []、entrypoint: null。data、assets、inputs 即便为空也保留数组。所有路径字段为相对于工程根的 POSIX 路径。

{
  "schema_version": 1,
  "project_id": "example-report",
  "title": "报告标题",
  "template": {
    "manifest": "vendor/template/manifest.json",
    "theme": "chosen-theme",
    "lock": "template.lock.json"
  },
  "authoring": {"route": "native", "workflow": "interactive-page"},
  "environment": "environment.json",
  "pages": [
    {
      "id": "opening",
      "layout": "declared-layout-id",
      "source": "pages/opening/source.svg",
      "content": "pages/opening/content.json",
      "notes": "pages/opening/notes.md",
      "data": ["data/observations.json"],
      "assets": ["assets/figure.svg"]
    }
  ],
  "build": {
    "entrypoint": "tools/build_deck.py",
    "output": "exports/deck.pptx",
    "inputs": ["tools/helper.py"]
  }
}

页面 ID 必须稳定且唯一,layout 必须在模板 manifest 中声明。三项页面文件名固定为 pages/<id>/source.svg、content.json、notes.md。数据文件可用 JSON 数组等合法 JSON 值;页面内容结构由 builder 定义。工具拒绝重复 JSON 键和非标准 NaN/Infinity。

声明文件必须存在。路径字段拒绝绝对路径、..、反斜杠、URL/盘符形式以及 symlink,包括仍指向工程内部的 symlink。SVG href 和 CSS url(...) 的本地资源、Markdown 行内及引用式链接递归纳入作者输入;相对于源文件解析,允许 ../../assets/... 等仍在工程内的引用,拒绝逃逸、绝对路径和缺文件。SVG 允许 #id 与内嵌 data:;Markdown 允许 HTTP(S)/mailto 来源链接和 #anchor。这不是完整的 HTML/JavaScript/Python 依赖分析器:builder 导入的辅助文件、动态读取的数据和自定义格式资源仍须在 build.inputs、页面 data/assets 中显式声明。

vendor/ 下的第三方 Markdown 说明作为固定字节锁定,不递归跟随其工作流或参考文档链接;裁剪后的编译器快照可以保留完整归属说明而无需携带无关文档库。实际构建所需文件仍须显式列入 build.inputs。工程 README、页面讲稿及其本地引用继续检查;此例外不豁免 SVG 素材引用。

environment.json 初始内容为:

{
  "schema_version": 1,
  "python": {"minimum": "3.10"},
  "packages": {},
  "fonts": [],
  "tools": []
}

作者应补充实际 Python/包版本、可重建的安装说明、外部工具与字体名称、版本、来源及许可。check 校验此文件的基本结构、存在与锁定,不探测所有平台的字体和工具,不自动下载或安装依赖。字体不会因写入清单而获得分发许可;工程只纳入确有许可的字体文件,并显式列入输入。设备设置写入被忽略的 environment.local.json,不要把用户名、绝对路径、凭据、私有配置写入受版本管理的清单。

两层锁与协作

template.lock.json 使用 schema_version: 1,包含 template_id、version、theme、工程相对 manifest 和有序 inputs。每个 input 为 {"path": "vendor/template/...", "sha256": "..."}。复用模板解析器验证 released 状态、路线、工作区和选择后,锁定全部复制的模板源,包括未激活 theme;不把 review exports/ 当源。模板新增、删除、字节变化,或改变 template/theme 选择均使验证失败。

project.lock.json 使用 schema_version: 1、project_id 和相同形式的有序 inputs,包括 project.json、环境说明、页面 source/content/notes/data/assets、本地资源闭包、builder 与 build.inputs、随包两脚本,以及 README/Git 元数据。运行输出不进入锁。

lock 先验证模板锁未变,再校验作者输入和引用,原子更新作者锁。它不会修改模板锁、自动接受升级或掩盖缺文件。模板需要升级时,新建显式选择新版本的工程,审阅接口变化后迁移作者输入;不要通过反复 lock 接受发布模板漂移。

协作者一起审阅 source、data、project 与锁差异。多人编辑不同稳定页面时仍由工程负责人整合 project.json 页序与锁;不要把生成的绝对路径收据作为可移植状态提交。生成的 .gitignore 忽略 build/、exports/、.venv/、node_modules/、__pycache__/、*.pyc 和 environment.local.json,不忽略正文、数据、素材或讲稿;.gitattributes 为 JSON/Python/Markdown/SVG/CSV/TSV 声明 UTF-8/LF,为 PPTX/PDF/PNG 等声明二进制。

构建与移动重建

resolve 先 check,在 build/local/ 写入本次唯一 ID 的 selection/style JSON。每页使用对应 layout;空骨架生成工程级记录。记录的绝对路径只对当前工程位置有效,v1 模板仅生成 selection。它们不进入 Git 或 pack。

builder 必须是工程内 .py 文件。执行前审阅入口代码及依赖;build 意味着运行作者声明的工程 Python 代码,不是沙箱。工具先验证锁并生成新收据,再使用当前 sys.executable、shell=False、工程根为 cwd,固定调用:

python /absolute/project/tools/build_deck.py \
  --project /absolute/project \
  --output /absolute/project/build/tmp/<new-unique-id>.pptx

入口只能通过固定的 --project、--output 接收工程位置与本次输出位置,不接受 shell 字符串配置;退出 0 后必须实际产生新文件,最长运行 600 秒。工具检查 ZIP 成员、CRC、必要 XML 根和 slide 数量/presentation 页表,重新验证输入锁,然后原子替换 build.output。输出必须位于 exports/ 且扩展名为 .pptx。builder 失败、超时、缺输出、无效 ZIP 或输入被修改时,旧产物保留;不能用已有 exports 推断本次成功。成功 JSON 返回本次输出的 SHA-256。

pack --out 必需,必须是工程外 .zip 路径。既有 ZIP 或同名 .zip.sha256.json 均拒绝覆盖。包仅包含已锁作者输入、模板源、两层锁和必要元数据;未声明文件、build、exports、Git、虚拟环境、缓存及本地配置不进入包。固定路径排序、ZIP 时间与权限,同一输入在同一压缩环境下得到相同 ZIP 字节;不同 Python/zlib 版本未保证逐字节压缩结果相同。另写 JSON SHA-256 收据,收据 archive 字段只存文件名。

移动整个源工程或解压 ZIP 后,先配置 environment.json 记录的依赖与有许可的字体,再运行工程随包的 tools/ppt_project.py check 和 build。不需要访问原模板目录、原 Skill 安装路径、原工作区或旧 exports。缺少外部工具时,由 destination 环境提供,不用旧输出冒充重建。

证据与限制

维护仓库的工程专项检查使用合成 released 模板与两页工程,覆盖锁定、路径/资源/symlink 拒绝、作者及模板漂移、失败保留旧产物、确定性源码包、缓存排除,并在原路径不存在时用解压后的工具实际生成新的基本 PPTX;修改数据后再次构建并检查 slide XML 的新数据。Skill 0.5 的独立编译器检查另覆盖原生导出、字体身份、素材边界、项目内 runtime 和移动重建;安装包不要求维护仓库的检查脚本在运行时存在。

这些证据证明本机新路径下的源码可移动与构建接口行为,不代表已在另一台物理设备执行,也不代替渲染、字体一致性、完整 OOXML 关系图、PowerPoint 打开/实际编辑或投影可读性验收。按实际作者路线另外完成原生结构、逐页渲染和产品验收。

For page assignments, write boundaries, packets and serial integration, use page collaboration. A plan is portable source metadata, not a second ownership/history service.