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

150 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 可移动的 PPT 消费工程
接口版本:`ppt-project/v1`。内容日期:2026-10-10。实现为 [ppt_project.py](../scripts/ppt_project.py),基础模板接口仍以 [template-interface.md](template-interface.md) 为准。本接口不改变 `template_ref.py`,不安装全局工具,不初始化 Git,不提交或发布。
工程把正文、页面源、数据、素材、模板源、必要工具和依赖说明放在同一目录。Git 可追踪这些输入;设备相关绝对路径、缓存和导出物在运行时重建。一次工程固定一个 template 版本和一个 theme,页面顺序由 `pages` 数组表达,重排页面无需更换页面 ID。
## 初始化与作者工作流
解析和工程管理要求 Python 3.10+,只用标准库;实际 builder 的依赖由工程自行声明。消费方明确逐页制作时,保留 `interactive-page`,不要因建立工程而自动批量创作。
```sh
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。完整行为见 [运行库与出处](runtime-and-provenance.md)。
该通用 builder 读取各页已完成的 SVG 和 Markdown 讲稿;`content.json`/`data` 仍是锁定作者输入,不会自动绑定到 SVG。需要数据驱动生成的消费方应提供自己的明确绑定或预处理步骤。
```sh
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。初始化和移动工程时均不复用另一台机器的选择记录。
## 目录与字段
```text
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 路径。
```json
{
"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` 初始内容为:
```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,固定调用:
```text
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 打开/实际编辑或投影可读性验收。按实际作者路线另外完成原生结构、逐页渲染和产品验收。