From 221f0178b119ff4fe28f6d00852eb94734b03b4e Mon Sep 17 00:00:00 2001 From: KeyInfo Bot Date: Fri, 11 Sep 2026 07:43:18 +0800 Subject: [PATCH] Sync third-party and MCP marketplace plugins Constraint: Public skills are published only by explicit administrator action unless they are tracked third-party market sources. Confidence: high Scope-risk: narrow Directive: Keep private/internal skills out of the public marketplace and preserve normal incremental market Git history. Tested: Marketplace validation passed. --- config/external-sources.lock.json | 36 +-- .../.codex-plugin/plugin.json | 2 +- .../THIRD_PARTY_SOURCE.json | 6 +- .../skills/etunel-role-collaboration/SKILL.md | 2 +- .../references/dingtalk-progress-reporting.md | 14 +- .../references/dingtalk-script-usage.md | 81 +++--- .../references/hub-workflow.md | 1 + .../plugins/mcp-playwright/MCP_SOURCE.json | 2 +- .../next-skills/THIRD_PARTY_SOURCE.json | 4 +- .../next-cache-components-adoption/SKILL.md | 29 ++- .../next-cache-components-optimizer/SKILL.md | 21 +- .../rig-template.md | 244 +++++++++++------- .../SKILL.md | 4 +- .../rig-template.md | 8 +- .../SKILL.md | 229 ++++++++++++++++ .../reference/red-test-robustness.md | 132 ++++++++++ .../rig-template.md | 174 +++++++++++++ .../ppt-master/THIRD_PARTY_SOURCE.json | 4 +- .../ppt-master/skills/ppt-master/SKILL.md | 2 +- .../ppt-master/references/animations.md | 2 +- .../ppt-master/references/executor-base.md | 10 +- .../ppt-master/references/executor-chart.md | 2 + .../ppt-master/references/image-generator.md | 11 +- .../references/image-layout-spec.md | 2 +- .../references/native-data-interface.md | 2 +- .../references/native-shape-authoring.md | 2 +- .../skills/ppt-master/references/plan-core.md | 2 +- .../references/shared-standards-core.md | 2 +- .../ppt-master/references/strategist-image.md | 2 +- .../ppt-master/references/strategist.md | 2 +- .../ppt-master/references/svg-effects.md | 12 +- .../references/visual-styles/blueprint.md | 2 +- .../references/visual-styles/swiss-minimal.md | 2 +- .../ppt-master/scripts/confirm_ui/server.py | 15 ++ .../ppt-master/scripts/docs/conversion.md | 3 + .../skills/ppt-master/scripts/docs/image.md | 6 +- .../ppt-master/scripts/docs/narration.md | 2 +- .../ppt-master/scripts/docs/native-data.md | 8 +- .../ppt-master/scripts/docs/svg-pipeline.md | 4 +- .../skills/ppt-master/scripts/image_gen.py | 6 + .../skills/ppt-master/scripts/image_treat.py | 24 +- .../scripts/prompt_audit_manifest.json | 2 +- .../skills/ppt-master/scripts/slice_images.py | 138 ++++++++-- .../scripts/source_to_md/web_to_md.py | 81 +++++- .../ppt-master/scripts/svg_editor/server.py | 15 ++ .../scripts/svg_editor/static/app.js | 29 ++- .../scripts/svg_finalize/flatten_tspan.py | 5 +- .../scripts/svg_position_calculator.py | 65 +++-- .../ppt-master/scripts/svg_quality/checker.py | 67 ++++- .../scripts/svg_to_pptx/animation_config.py | 26 +- .../svg_to_pptx/native_objects/chart_data.py | 6 + .../svg_to_pptx/native_objects/chart_style.py | 30 ++- .../tests/test_local_server_security.py | 85 ++++++ .../scripts/tests/test_minimax_subtitles.py | 96 +++++++ .../tests/test_native_chart_fidelity.py | 75 ++++++ .../scripts/tests/test_slice_images.py | 144 +++++++++++ .../scripts/tests/test_svg_quality_checker.py | 48 ++++ .../scripts/tests/test_text_measure.py | 35 +++ .../scripts/tests/test_web_to_md_security.py | 168 ++++++++++++ .../skills/ppt-master/scripts/text_measure.py | 76 ++++-- .../scripts/tts_backends/backend_minimax.py | 25 +- .../ppt-master/scripts/workflow_transcript.py | 24 +- .../duty-manual/templates/design_spec.md | 114 ++++---- .../templates/styles/styles_index.json | 12 +- .../ppt-master/workflows/generate-pptx.md | 8 +- .../stages/apply-template-workspace.md | 4 +- .../workflows/stages/customize-animations.md | 6 +- .../workflows/stages/topic-research.md | 6 +- .../workflows/stages/verify-charts.md | 4 +- plugins/codex/plugins/ui-ux-pro-max/README.md | 29 +++ .../ui-ux-pro-max/THIRD_PARTY_SOURCE.json | 4 +- 71 files changed, 2144 insertions(+), 401 deletions(-) create mode 100644 plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/SKILL.md create mode 100644 plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/reference/red-test-robustness.md create mode 100644 plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/rig-template.md create mode 100644 plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/tests/test_local_server_security.py create mode 100644 plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/tests/test_minimax_subtitles.py create mode 100644 plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/tests/test_web_to_md_security.py diff --git a/config/external-sources.lock.json b/config/external-sources.lock.json index 546b928e..a1a20e7f 100644 --- a/config/external-sources.lock.json +++ b/config/external-sources.lock.json @@ -42,8 +42,17 @@ "repo": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git", "ref": "main", "adapter": "claude-skill", - "commit": "4aad0584d92131626b16d4ff4d77f0455385013c", - "syncedAt": "2026-09-06T15:59:59Z" + "commit": "7f69fed6a2717900085f1bc3b263721f8ba025e2", + "syncedAt": "2026-09-10T23:40:59Z" + }, + { + "id": "caveman", + "pluginName": "caveman", + "repo": "https://github.com/JuliusBrussee/caveman.git", + "ref": "main", + "adapter": "codex-plugin", + "commit": "15581d14007fd01fb3f132016741962f34936ca2", + "syncedAt": "2026-09-10T23:13:42Z" }, { "id": "taste-skill", @@ -96,8 +105,8 @@ "repo": "https://github.com/hugohe3/ppt-master.git", "ref": "main", "adapter": "claude-skill", - "commit": "64b65839c7f8096a534c872c03d688a2b2491c8f", - "syncedAt": "2026-09-09T16:00:00Z" + "commit": "09ad58f0d58decc9d30799ca83374ff2604ef16b", + "syncedAt": "2026-09-10T23:40:59Z" }, { "id": "grill-me", @@ -121,10 +130,10 @@ "id": "etunel-role-collaboration", "pluginName": "etunel-role-collaboration", "repo": "https://git.playones.com/chenmingxuan/EP-Hub-Skill.git", - "ref": "v1.0.2", + "ref": "v1.0.3", "adapter": "claude-skill", - "commit": "a08cfd6a3b4bfa38a3b3ac3a5b56bbd56502a514", - "syncedAt": "2026-09-09T04:01:45Z" + "commit": "20c0de9b3829534685d1f931dc0b574c988eec6b", + "syncedAt": "2026-09-10T23:40:59Z" }, { "id": "next-skills", @@ -132,8 +141,8 @@ "repo": "https://github.com/vercel/next.js.git", "ref": "canary", "adapter": "skill-collection", - "commit": "e0966df11438b1f82e06d6f650a2a044b84457c3", - "syncedAt": "2026-09-09T16:00:00Z" + "commit": "ccef3db535aa163a883f6ac000bdceb16b13e5e5", + "syncedAt": "2026-09-10T23:40:59Z" }, { "id": "shuorenhua", @@ -143,15 +152,6 @@ "adapter": "claude-skill", "commit": "d2d0ce27da295581c3cf87a30ab65deb7d0ddfb8", "syncedAt": "2026-09-03T02:45:43Z" - }, - { - "id": "caveman", - "pluginName": "caveman", - "repo": "https://github.com/JuliusBrussee/caveman.git", - "ref": "main", - "adapter": "codex-plugin", - "commit": "15581d14007fd01fb3f132016741962f34936ca2", - "syncedAt": "2026-09-10T23:13:42Z" } ] } diff --git a/plugins/codex/plugins/etunel-role-collaboration/.codex-plugin/plugin.json b/plugins/codex/plugins/etunel-role-collaboration/.codex-plugin/plugin.json index 0c7c9c7f..646eea18 100644 --- a/plugins/codex/plugins/etunel-role-collaboration/.codex-plugin/plugin.json +++ b/plugins/codex/plugins/etunel-role-collaboration/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "etunel-role-collaboration", - "version": "1.0.2", + "version": "1.0.3", "description": "Etunel 多 Agent 项目的角色识别、Hub 中介、依赖任务波次、成果交接和消息流程协作规范。", "author": { "name": "chenmingxuan", diff --git a/plugins/codex/plugins/etunel-role-collaboration/THIRD_PARTY_SOURCE.json b/plugins/codex/plugins/etunel-role-collaboration/THIRD_PARTY_SOURCE.json index ab61c0c0..edbd654c 100644 --- a/plugins/codex/plugins/etunel-role-collaboration/THIRD_PARTY_SOURCE.json +++ b/plugins/codex/plugins/etunel-role-collaboration/THIRD_PARTY_SOURCE.json @@ -1,9 +1,9 @@ { "sourceId": "etunel-role-collaboration", "repo": "https://git.playones.com/chenmingxuan/EP-Hub-Skill.git", - "ref": "v1.0.2", - "commit": "a08cfd6a3b4bfa38a3b3ac3a5b56bbd56502a514", + "ref": "v1.0.3", + "commit": "20c0de9b3829534685d1f931dc0b574c988eec6b", "adapter": "claude-skill", "sourcePath": "etunel-role-collaboration", - "syncedAt": "2026-09-09T04:01:45Z" + "syncedAt": "2026-09-10T23:40:59Z" } diff --git a/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/SKILL.md b/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/SKILL.md index a271dfbe..c41a387f 100644 --- a/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/SKILL.md +++ b/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/SKILL.md @@ -59,7 +59,7 @@ Etunel 负责当前角色和会话绑定。不要向负责人询问或复述 rol - 缺信息、资料冲突、查询无新线索、旧任务收尾、错投、阻塞、超时升级、会议决定、返工、变更、流程跳转或模拟:读 [异常与协调](references/exceptions-and-coordination.md)。 - 编写给负责人、角色或群组的任务、提问、结果和状态消息:读 [人类可读沟通](references/human-readable-communication.md)。 - 创建项目资料目录、保存成员清单、归档成果、更新进度或阶段记录:读 [项目文件与进度留档](references/project-files-and-progress.md)。 -- 仅当当前会话是 Hub 且需钉钉进度汇报或负责人辅助提醒:读 [钉钉项目进度汇报](references/dingtalk-progress-reporting.md),实际调用再读其中的脚本用法。 +- 仅当当前会话是 Hub 且需初始化个人 DWS 通知、钉钉进度汇报或负责人辅助提醒:读 [钉钉项目进度汇报](references/dingtalk-progress-reporting.md),实际调用再读其中的脚本用法。 - 测试角色仅在任务类型匹配时,按 [测试职责](references/roles/testing.md) 中的二级链接读取更深细则。 不要为“全面了解”一次加载全部引用或全部角色文件。Etunel Hook 源文件独立配置,不属于本 Skill 的渐进式发现树。 diff --git a/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/dingtalk-progress-reporting.md b/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/dingtalk-progress-reporting.md index b72f082c..110f4f21 100644 --- a/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/dingtalk-progress-reporting.md +++ b/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/dingtalk-progress-reporting.md @@ -5,12 +5,12 @@ ## 权限与封装入口 - 只有 Hub/主 Agent 可以发送;成员 Agent 只把成果、状态或阻塞交给 Hub。 -- 项目配置为启用时视为持续发送授权,不需每条消息再次询问。 -- 只用项目封装:`dingtalk-progress` 处理五类项目事件,`dingtalk-bot-message` 处理自定义中文摘要或负责人提醒;二者共用 `scripts/dingtalk_notify.py`。Windows、macOS/Linux 的命令及文件正文、人员提醒用法见 [通知脚本用法](dingtalk-script-usage.md),实际调用前按需读取。 +- 项目首次初始化时,由 Hub 查询可用个人 DWS 账号和群,以姓名、组织和群名向负责人确认自动通知范围,再调用 `init` 创建配置;不让人填写编号或密钥。确认并启用后,范围内通知不需每条再次询问,变更账号或群须重新确认。 +- 只用项目封装:`dingtalk-progress` 处理五类项目事件,`dingtalk-message` 处理自定义中文摘要或负责人提醒;二者共用 `scripts/dingtalk_notify.py`,统一使用确认的个人 DWS 账号。初始化、跨平台入口及 @ 用法见 [通知脚本用法](dingtalk-script-usage.md)。 - Agent 不得直接调用底层 OpenAPI、`dws api` 或其他消息入口绕过封装脚本。 -- Agent 不自行打开、展示或修改真实配置,不请求负责人在会话中提供密钥和内部标识;由封装在本地读取 `config.env` 中的 `DINGTALK_PROGRESS_CLIENT_SECRET` 并完成认证,不再使用环境变量或钥匙串取密钥。 -- Skill 与消息正文不得硬编码项目 Client ID、robotCode、openConversationId、Client Secret 或群名;项目差异只由 `.dingtalk/config.env` 和封装脚本处理。 +- 配置只保存开关、固定账号、项目群和项目名称;Hub 可在已确认范围内创建或更新,登录凭据由 DWS 管理,不索取、读取或输出 Token、密码与应用密钥。旧机器人配置须重新初始化,不静默切换发送身份。 +- 不在 Skill 或群消息里硬编码账号、群或人员标识;标识从同一账号的真实工具结果取得,仅用于本地配置和工具参数。不因默认账号切换而更换发送人,不退回机器人或 Webhook。 ## 汇报单位与顺序 @@ -58,6 +58,8 @@ Hub 必须先确认进展真实有效,并完成成果文件、成果索引和 使用中文 Markdown 自然排版,可以使用标题、短段落和列表,不要求固定模板,也不要把全部内容挤成一行。像项目负责人向团队说明进展,不像日志转储。 +保留个人消息的 AI 标识和自动汇报说明,让群成员知道这是 Hub 自动通知,不是负责人本人新增批准、验收或承诺。 + 根据事件选择必要内容:项目名称、当前阶段、已验证进展、关键成果、下一步和责任角色;阻塞时再说明问题、影响以及需要谁采取什么动作。通常保持一屏内可读。 不在正文中写运行时 ID、英文成果名、机器状态码或内部字段。只写已验证结论,不得包含密钥、Token、个人数据、客户敏感信息、大段日志、完整内部对话或未经验证的根因推断。 @@ -68,8 +70,8 @@ Hub 必须先确认进展真实有效,并完成成果文件、成果索引和 1. Hub 判断事件并形成中文 Markdown 摘要。 2. 调用封装脚本一次;脚本自行处理配置检查、发送和有限重试。 -3. 只有真实发送响应包含非空 `processQueryKey`,才表示钉钉服务端已经接受;不证明群成员已读。 -4. 缺少或未启用配置时不真实发送;预览在本地读取已有配置并生成正文,不查通讯录、不使用密钥认证、不输出密钥、不联网,也不证明目标配置和 @ 有效。 +3. 只有真实个人发送响应成功且含非空 `openTaskId`,才表示请求已经接受;不证明已投递、已读或接收端 @ 提醒成功。必要时按脚本用法查询投递状态,不把任务回执当消息编号。 +4. 缺少或未启用配置时不真实发送;显式 `--dry-run` 仅在本地生成正文,不查通讯录、不联网,也不证明目标配置和 @ 有效。配置仍为旧格式时停止并请求重新初始化。 5. 只有明确的域名解析失败才自动重试,总计最多 3 次,间隔 10 秒;首次收到有效回执立即停止。认证、权限或未知错误不自动重试;超时、连接中断或缺少回执可能已发出,不盲目重发。单次命令最长等待 60 秒。 6. 有效回执优先于命令退出码,不因退出异常重复发送。发送停止或结果未知时,Etunel 主任务继续;Hub 在本地结果中向负责人说明一次,不递归发送新的阻塞或失败通知,不自动补发历史事件。 diff --git a/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/dingtalk-script-usage.md b/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/dingtalk-script-usage.md index eb7539df..ec53781d 100644 --- a/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/dingtalk-script-usage.md +++ b/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/dingtalk-script-usage.md @@ -1,61 +1,52 @@ -# Hub 通知脚本用法 +# Hub 个人 DWS 通知用法 -仅在 Hub 已按 [通知规则](dingtalk-progress-reporting.md) 判断需要通知、准备调用脚本时读取。脚本须由部署负责人放在目标 Hub 项目的 `scripts/`;安装 Skill 本身不会部署脚本、配置或凭据。找不到入口时说明未部署并继续主任务,不猜绝对路径、不临时绕过封装。 +仅在 Hub 初始化通知或按 [通知规则](dingtalk-progress-reporting.md) 准备发送时读取。脚本放在实际 Hub 项目的 `scripts/`,配置位于同项目 `.dingtalk/config.env`;安装 Skill 不会自动部署脚本。缺少入口时说明并继续主任务,不猜路径或绕过封装。 -## 选一个入口,不重复调用 +## 项目首次初始化 -共用实现为 `scripts/dingtalk_notify.py`,依赖 Python 3.9+;真实发送还需原生 `dws`。相对命令从目标项目根目录执行。 +1. 用 `dws profile list --format json` 查询账号,向负责人显示姓名与组织;未登录请负责人完成 DWS 登录,不索取凭据。 +2. 在选定账号下,用 `dws chat +chat-search --query "负责人提供的群名称" --page-all --profile "实际账号标识" --format json` 查群。账号或群有歧义、结果不完整时先澄清,不猜编号、不选第一项。 +3. 一次确认发送账号、项目群及是否允许自动进度和必要 @ 提醒。人只确认名字与用途,不负责找编号。 +4. Hub 将真实查询结果传入 `python scripts/dingtalk_notify.py init --profile "实际账号标识" --group "实际群标识" --project "项目名称" --yes`。这是参数结构示例;值必须替换为同一账号的实际结果。脚本创建仅含开关、账号、群和项目名的配置,不存机器人密钥或登录凭据,不发测试消息。 -所有系统由封装统一从目标项目 `.dingtalk/config.env` 的 `DINGTALK_PROGRESS_CLIENT_SECRET` 读取机器人密钥,不回退到环境变量或钥匙串。配置由部署负责人本地维护;Hub 不打开或展示真实配置、不在会话索取密钥。普通发送不需要 DWS 用户登录,按姓名提醒才额外需要同组织的已登录账号配置。 +已有有效配置直接沿用;变更发送账号或群须重新确认,初始化时加 `--replace`。旧机器人配置必须重新初始化,不能静默转换发送身份。账号、群选择与查询由 Hub 完成;`init` 校验账号登录,不替代负责人对目标群的确认。暂停通知可由 Hub 按负责人要求将 `DINGTALK_PROGRESS_ENABLED` 改为 `0`。配置和标识只用于本地工具,不粘贴到群或普通回复,不提交真实配置。 -| 环境 | 项目事件 | 中文摘要/负责人提醒 | -| --- | --- | --- | -| 通用 Python | `python scripts/dingtalk_notify.py progress ...` | `python scripts/dingtalk_notify.py message ...` | -| Windows PowerShell 7.3+ | `./scripts/dingtalk-progress.ps1 ...` | `./scripts/dingtalk-bot-message.ps1 ...` | -| macOS/Linux | `sh scripts/dingtalk-progress ...` | `sh scripts/dingtalk-bot-message ...` | +初始化时同时确认目标项目的 Git 忽略规则包含 `.dingtalk/config.env`,不把本机通知配置提交到仓库。 -Python 在 macOS/Linux 通常叫 `python3`;Windows 也可用 `py -3`。这是同一实现的不同入口,不是失败后依次尝试的备选发送渠道。原有 `./scripts/dingtalk-progress` 调用仍可使用,前提是该文件有执行权限。 +## 选择本机入口 -## 项目事件通知 +共用实现依赖 Python 3.9+ 和已登录的原生 DWS。相对命令从目标项目根目录执行。 + +| 环境 | 初始化/检查 | 项目事件 | 摘要/提醒 | +| --- | --- | --- | --- | +| 通用 Python | `python scripts/dingtalk_notify.py init ...`/`check ...` | 同入口 `progress ...` | 同入口 `message ...` | +| Windows PowerShell 7.3+ | `./scripts/dingtalk-python.ps1 init ...`/`check ...` | `./scripts/dingtalk-progress.ps1 ...` | `./scripts/dingtalk-message.ps1 ...` | +| macOS/Linux | 通常用 `python3` 执行共用入口 | `sh scripts/dingtalk-progress ...` | `sh scripts/dingtalk-message ...` | + +Windows 优先用 `.ps1`,须同时部署共用启动器 `dingtalk-python.ps1`,它选择独立 Python,不使用可能隔离 DWS 登录的商店版;必要时用 `DINGTALK_PYTHON` 指定解释器。各系统均通过 PATH 查找原生 DWS,不再设置机器人相关参数。这些入口是同一实现,不能重复调用。 + +## 日常发送 ```text -python scripts/dingtalk_notify.py progress milestone "**已完成**:本阶段成果已确认并归档。下一步安排联调。" +python scripts/dingtalk_notify.py progress milestone "**已完成**:阶段成果已确认并归档。下一步安排联调。" +python scripts/dingtalk_notify.py progress blocked "缺少接口说明,请补充后回自己的角色会话同步。" --at "完整姓名" +python scripts/dingtalk_notify.py message --title "资料补充提醒" --text "请补齐已约定资料,并回自己的角色会话确认。" --at "完整姓名" ``` -事件仍只有 `start`、`milestone`、`blocked`、`complete`、`failed`。脚本自动加项目名、中文状态和本机带时区时间;不自动判断项目阶段或完成状态。 +事件仍只有 `start`、`milestone`、`blocked`、`complete`、`failed`。脚本增加项目名、中文标题、带时区时间和自动汇报说明,不替 Hub 判断阶段。保留 DWS 的 AI 标识,不能冒充负责人本人批准或承诺。 -多行 Markdown 可直接作为一个参数传入。较长或含引号的摘要优先保存为 UTF-8 正文文件,再用 `--file`;不要把大段成果或日志当通知: +- 多行中文 Markdown 作为一个参数传入;较长摘要可先保存成 UTF-8 文件,再用 `--file "实际正文文件路径"` 替代摘要或 `--text`。文件须实际存在,路径相对工作目录;这是正文,不是上传附件,不发送大段成果或日志。 +- `progress` 和 `message` 均支持 `--at`,多个姓名可逗号分隔或重复传入。负责人姓名来自 Etunel 已绑定的 `member_alias`,不把角色名称当姓名;人员查询和发送固定使用初始化账号,不跟随默认账号切换。 +- 脚本只接受唯一姓名匹配,自动构造个人消息所需的 `openDingTalkId` 和提及标记。查不到、重名或权限不足时停止,不让负责人手填编号,不删掉 @ 降级发送。 +- 默认且仅发配置的项目群。同一事项合成一条,事件通知可直接 @ 人,不额外重复提醒。提醒讨论结果回各自角色会话,不在群里另派任务或批准。 -```text -python scripts/dingtalk_notify.py progress milestone --file "项目资料/00-项目管理/通知摘要.md" -``` +## 检查与结果 -这里的路径是调用示例,须先在实际项目中生成相应摘要,不能假定文件存在。文件路径相对当前工作目录解析;`--file` 是读取消息正文,不是上传附件。进度摘要和 `--file` 二选一。 +排障可用 `python scripts/dingtalk_notify.py check --at "完整姓名"`,省略 `--at` 只查登录;它联网但不发送,不是每轮必做。两个发送入口加 `--dry-run` 可完全离线预览,不查人、不验证目标或 @ 效果。 -## 自定义摘要与负责人提醒 +- `initialized`:已创建经确认的个人通知配置,未发送。 +- `accepted`:真实个人发送响应成功且含非空 `openTaskId`,请求已接受,不等于已投递、已读或接收端提醒成功。保留回执供排障,面向负责人只说中文结果。 +- `checked`/`preview`/`skipped`:分别为只读检查、离线预览、未配置或未启用;都没发送。 +- `error`:本次停止,按说明区分失败与未知,不自行补发。错误退出码为 1,参数错误可能为 2,不能只凭退出码 0 判断已发。 -```text -python scripts/dingtalk_notify.py message --title "联调需补充接口说明" --text "缺少接口返回值说明,联调暂时无法继续。请负责该接口的人补齐,并在自己的角色会话中同步结果。" -``` - -这个入口允许自定义标题,但不新增项目状态,不替代应该记录的阻塞事件。需要 @ 已知负责人时追加 `--at "完整姓名"`;多个姓名用逗号分隔或重复传入 `--at`。正文也可用 `--file` 代替 `--text`。 - -- 负责人称呼来自 Etunel 已绑定的 `member_alias`,不要把角色名称 `display_name` 当人员姓名,也不要让人每轮确认身份。 -- 按姓名查找由封装执行,只使用部署时配置的同组织账号。没有配置账号、查不到、重名或返回无法识别时,本条不发送;请负责人澄清姓名或让部署负责人修正映射,不选择第一个、不换组织碰运气。 -- `--at-id "姓名=userId"` 仅兼容已有且同组织的有效映射,由真实工具结果或部署负责人提供;不从 Etunel 角色标识推导,不主动索要人员编号。 -- 默认发项目配置群。`--group` 仅保留给用户明确指定其他目标群的情形,不由 AI 猜群或扩大通知范围。 -- 同一事项只形成一条合并通知。已经由事件通知说明清楚时,不额外发一遍提醒;没有变化时不循环催促。 -- 通知必须指向实际下一步。负责人在线下讨论后回自己的角色会话补充结果,由角色完成原任务并经 Etunel 返回 Hub;群里已读或口头回复都不自动完成任务。 - -## 预览与结果 - -两个入口均支持 `--dry-run`;项目配置的预览开关也同时约束两者。预览不要求安装 `dws` 或填写密钥;会读取已有配置,但不使用密钥认证、不输出密钥、不查人员、不发送,只显示本地正文,@ 对象及目标配置未验证。 - -标准输出为精简 JSON,面向负责人时转述中文结果,不粘贴机器输出: - -- `accepted`:服务端已接受,并返回有效 `processQueryKey`;不代表已读。 -- `preview`:只有预览,未发送。 -- `skipped`:未配置或未启用,未发送。 -- `error`:本次停止;按说明区分失败和结果未知,不声称已发送或自行补发。 - -前三种退出码为 0,错误为 1;错误参数可能返回 2,因此不能只凭退出码 0 宣布已发送。封装内部处理有限重试,不要在脚本外再套重试。缺配置、凭据、权限或安装问题交部署负责人处理;通知失败不影响 Etunel 主流程。 +需要进一步核实投递时,按发送回执在同一账号下调用 `dws chat +messages-query-send-status --open-task-id "真实回执值" --profile "配置账号" --format json` 只读查询;按实际结果判断,不把 `openTaskId` 当消息 ID。脚本只在明确 DNS 失败时最多尝试 3 次、间隔 10 秒;其余失败或未知结果不重发,Agent 不追加外层重试。登录失效交负责人恢复,不换身份或渠道;通知异常不阻塞主任务,也不递归发送异常通知。 diff --git a/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/hub-workflow.md b/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/hub-workflow.md index 031d323b..206fdb8b 100644 --- a/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/hub-workflow.md +++ b/plugins/codex/plugins/etunel-role-collaboration/skills/etunel-role-collaboration/references/hub-workflow.md @@ -23,6 +23,7 @@ Hub 只检查角色、必填内容、成果、版本、证据、负责人确认 5. 从《项目概览》读取当前项目已经确认的特殊规则;只登记有权负责人明确确认的内容,并持续沿用到同一决定权人修改或取消,不在每项任务中重复询问。 6. 在途项目继续使用已登记流程基线,除非取得明确迁移决定。 7. 有权业务负责人发起的正式项目即使资料不齐也可接收,但缺口、责任和风险必须如实记录,不能把未知写成已确认。 +8. 首次使用钉钉通知时,按 [通知初始化](dingtalk-script-usage.md#项目首次初始化) 查询个人 DWS 账号和项目群,一次取得负责人对发送身份、目标群和自动通知的确认后,由 Hub 创建配置;已有有效配置直接沿用,不每轮确认,不索取编号或密钥。配置暂未完成不阻塞 Etunel 主任务。 ## 启动阶段并明确完成约定 diff --git a/plugins/codex/plugins/mcp-playwright/MCP_SOURCE.json b/plugins/codex/plugins/mcp-playwright/MCP_SOURCE.json index 85066871..f5c88e96 100644 --- a/plugins/codex/plugins/mcp-playwright/MCP_SOURCE.json +++ b/plugins/codex/plugins/mcp-playwright/MCP_SOURCE.json @@ -3,5 +3,5 @@ "name": "playwright浏览器自动化操作", "version": "20260605", "keySource": "none", - "syncedAt": "2026-09-09T16:03:05Z" + "syncedAt": "2026-09-10T23:43:18Z" } diff --git a/plugins/codex/plugins/next-skills/THIRD_PARTY_SOURCE.json b/plugins/codex/plugins/next-skills/THIRD_PARTY_SOURCE.json index 8ad6cfc8..bb958250 100644 --- a/plugins/codex/plugins/next-skills/THIRD_PARTY_SOURCE.json +++ b/plugins/codex/plugins/next-skills/THIRD_PARTY_SOURCE.json @@ -2,8 +2,8 @@ "sourceId": "next-skills", "repo": "https://github.com/vercel/next.js.git", "ref": "canary", - "commit": "e0966df11438b1f82e06d6f650a2a044b84457c3", + "commit": "ccef3db535aa163a883f6ac000bdceb16b13e5e5", "adapter": "skill-collection", "sourcePath": "skills", - "syncedAt": "2026-09-09T16:00:00Z" + "syncedAt": "2026-09-10T23:40:59Z" } diff --git a/plugins/codex/plugins/next-skills/skills/next-cache-components-adoption/SKILL.md b/plugins/codex/plugins/next-skills/skills/next-cache-components-adoption/SKILL.md index e157460a..d33c2b74 100644 --- a/plugins/codex/plugins/next-skills/skills/next-cache-components-adoption/SKILL.md +++ b/plugins/codex/plugins/next-skills/skills/next-cache-components-adoption/SKILL.md @@ -19,7 +19,7 @@ Enable Cache Components on an app and walk it to a passing build. This skill seq - `npx @next/codemod@latest upgrade latest` to apply the version-to-version codemods. - Read the relevant [version upgrade guide](https://nextjs.org/docs/app/guides/upgrading) (e.g. [Version 16](https://nextjs.org/docs/app/guides/upgrading/version-16)) for what the codemod doesn't cover. -- **No incompatible config keys.** `cacheComponents: true` errors on any file that still exports `dynamic`, `revalidate`, or `fetchCache`. **Translate, don't delete.** Each export encodes behavior the route needs to keep doing; migrate each one to its Cache Components equivalent via the [migration guide's per-key sections](https://nextjs.org/docs/app/guides/migrating-to-cache-components#enable-cache-components). The exception is `dynamic = 'force-dynamic'`: under Cache Components every route is already dynamic by default, so the migration guide removes it outright rather than translating it — don't overthink a batch of identical `force-dynamic` deletions. `revalidate` and `fetchCache` still need real translation. If a value can't be cleanly translated yet, leave a `// TODO: Cache Components adoption — restore revalidate = 3600` comment so the loop picks it up. The `cache-components-instant-false` codemod does not touch these. +- **No incompatible config keys.** `cacheComponents: true` errors on any file that still exports `dynamic`, `revalidate`, or `fetchCache`. Inventory these exports before running the codemod, then follow the [migration guide's per-key sections](https://nextjs.org/docs/app/guides/migrating-to-cache-components). The guide is the source of truth for translating each value. The `cache-components-instant-false` codemod does not remove these configs. - **`experimental.dynamicIO` is fatal.** It was renamed to top-level `cacheComponents` and the old key now aborts before any build can run — remove it (or replace with `cacheComponents: true`) first. `experimental.useCache` is still accepted as a deprecated alias; redundant once `cacheComponents: true` is set, so remove it for clarity. @@ -27,6 +27,8 @@ Enable Cache Components on an app and walk it to a passing build. This skill seq - **No passing baseline before the flag.** If the app already uses `"use cache"`, the pre-flag build errors with `please enable the feature flag cacheComponents`. Enabling the flag is the first thing you do (in Incremental, before the codemod; in Direct, before fixing routes) — not a thing to do _after_ getting a passing build. Note this in your starting summary so it doesn't read as a regression. +- **Existing caches can stay.** Follow the migration guide's [`fetch` and `unstable_cache` sections](https://nextjs.org/docs/app/guides/migrating-to-cache-components#fetch-cache-options). Do not rewrite them solely to enable Cache Components. + - **Offline docs.** Guide links have offline copies under `node_modules/next/dist/docs/` (bundled since Next.js 16.2), with the directory layout numbered for ordering (e.g. `node_modules/next/dist/docs/01-app/02-guides/migrating-to-cache-components.md`). If you can't predict the numbered prefix, `find node_modules/next/dist/docs -name '.md'` resolves it. The `/docs/messages/*` error pages are not bundled. - **Older versions without bundled docs.** Suggest `npx @next/codemod@latest agents-md` to the user before starting: it downloads a version-matched copy to `.next-docs/` and writes an index into `AGENTS.md` / `CLAUDE.md`. It touches files in their repo, so ask first and run it only if they want it. @@ -37,7 +39,7 @@ There's one loop: walk the route tree top-down, one feature at a time, adopting The choice in step 1 is whether to opt every route out of validation first or fix routes as you go. Either way the loop is the same: -- **With a quiet pre-step (Incremental).** Run the codemod to opt every page and layout out of validation. Once you've also fixed what the codemod can't (sync-IO calls, leftover `revalidate`/`dynamic`/`fetchCache` exports), the build passes; you ship that as its own PR and then start the loop — removing one opt-out at a time and adopting that route. This splits the work into small, reviewable PRs. +- **With a quiet pre-step (Incremental).** Run the codemod, fix what it can't, and fully migrate routes that previously required static rendering. Other routes keep their opt-outs for follow-up PRs. - **Without (Direct).** Enable `cacheComponents` and start the loop on whatever the build flags first. Same loop, but every fix sits on one branch until adoption is complete. In both, the per-route success bar is the same: **dev loop reports no errors AND `next build` passes**. Check in with the user after every feature, and suggest a commit but never make one without their confirmation. Expect to spend most of the time in the loop, not in the pre-step. @@ -46,7 +48,7 @@ In both, the per-route success bar is the same: **dev loop reports no errors AND `cacheComponents: true` requires every route to be prerenderable. A route that reads request-time data outside `` is "blocking" and fails the build. `export const instant = false` marks a route as allowed to block, which clears it in both dev and build; on a layout it covers the whole subtree during the build, but client navigations still validate each descendant segment on its own. Reads wrapped in a [`"use cache"`](https://nextjs.org/docs/app/api-reference/directives/use-cache) function count as cache boundaries, not blocking reads. -When a fix introduces `"use cache"`, follow the Caching guide for [choosing a data-level or UI-level boundary and setting its lifetime](https://nextjs.org/docs/app/getting-started/caching#usage). Use the [`use cache` cache-key reference](https://nextjs.org/docs/app/api-reference/directives/use-cache#cache-keys) when the result varies by arguments or captured values. +When a fix introduces `"use cache"`, follow the Caching guide for [choosing a data-level or UI-level boundary and setting its lifetime](https://nextjs.org/docs/app/getting-started/caching#usage) and [revalidating after mutations](https://nextjs.org/docs/app/getting-started/revalidating). Use the [`use cache` cache-key reference](https://nextjs.org/docs/app/api-reference/directives/use-cache#cache-keys) when the result varies by arguments or captured values. Three classes of blocker come up, usually in this order: @@ -99,14 +101,14 @@ Ask the user, in terms of the PRs they want, not the size of the job. Never use If there's no user to ask, default to **Incremental** and document the choice. +Honor an explicit choice in the request. If the user asks to migrate incrementally and also asks you to complete the migration, establish and verify the incremental checkpoint before continuing to the remaining routes in the same task. “Complete” sets the stopping point; it does not change the chosen strategy. + - **Incremental** — quiet pre-step + the loop. Run the codemod to opt every page and layout out of validation, get the build passing, stop and check in with the user (see [end of the pre-step](#end-of-the-pre-step-check-in)), then enter [step 2's loop](#step-2-the-inner-loop-remove-opt-outs-one-feature-at-a-time) and ship each feature as a follow-up PR. - **Direct** — skip the pre-step. Enable `cacheComponents` and go straight to [step 2's loop](#step-2-the-inner-loop-remove-opt-outs-one-feature-at-a-time); the build's blocking routes are the work queue. ### incremental -Before invoking the codemod, fix the blocker that does not require build feedback. - -1. **Incompatible segment configs.** Grep for `^export const (revalidate|dynamic|fetchCache)` across the app directory and translate per the `requires` note above. The codemod does not touch them; leaving them in place fails the build after the codemod. +Before invoking the codemod, grep for `^export const (revalidate|dynamic|fetchCache)` across the app directory and follow the migration guide for every match. Mark routes that use `dynamic = 'force-static'` or `dynamic = 'error'` for full migration in this PR. The codemod does not remove incompatible configs. The codemod refuses to run on a dirty working tree. Commit or stash unrelated work first, or pass `--force` to let its edits land alongside your WIP. Common false positive: if you recently upgraded Next.js, `package.json` and the lockfile will already be dirty — commit those first. @@ -130,6 +132,8 @@ The codemod opts every segment out, not only the root, on purpose. Resolution is Because the highest opt-out wins, remove them top-down (root layout first, then descend). Removing a leaf's opt-out does nothing while an ancestor still holds one. +Remove the opt-outs from the previously static routes and any shared segments that mask their validation. Resolve their errors and confirm they still prerender. A cached data call alone does not prove the route remains static. + Next, run `next build` to surface blockers the codemod could not handle. The build is the proof, not the codemod run — a shared layout that calls `new Date()` / `Math.random()` directly still fails regardless of the opt-out (see [background](#background)). If the normal build reports a sync-IO error without locating the call, rerun that route with `next build --debug-prerender --debug-build-paths="app/path/to/page.tsx"`. For each sync-IO error it reports: 1. **Sync-IO at module/render time.** Use the route, originating file and line, and `/docs/messages/` link in the build output to locate the error. If needed, grep the whole repo for `new Date()`, `Date.now()`, `Math.random()`, and `crypto.randomUUID()` (not only `app/**/layout.{js,jsx,ts,tsx}` — the read might live in any component imported by a layout). Do not change unreported matches. Apply the appropriate option from the linked error page, then add this comment above a temporary boundary introduced only to unblock the build: @@ -142,20 +146,20 @@ Next, run `next build` to surface blockers the codemod could not handle. The bui After each fix, rerun the scoped build when available, then run `next build` again to find the next blocker. Repeat until the normal build passes. -After the build passes, confirm the root layout got an opt-out (`grep -n "export const instant" /layout.*`). The root layout renders every route, including framework routes like `/_not-found`, so if it was missed, add `export const instant = false` to it by hand. +After the build passes, confirm every deferred route is still covered by an opt-out and no shared opt-out covers a previously static route. If the app has no previously static routes and the root layout remains deferred, confirm it got an opt-out (`grep -n "export const instant" /layout.*`). The root layout renders every route, including framework routes like `/_not-found`, so if it was missed, add `export const instant = false` to it by hand. Synthetic routes like `/_not-found` have no user file — when they block, fix the root layout's opt-out, not the synthetic route. Client Components (`"use client"`) get no opt-out (it's a build error to export `instant` from them), but they are not a rare blocker. The high-frequency case is a client component in the root layout's nav or header calling `usePathname()`/`useSearchParams()`: it blocks _every_ dynamic route with `blocking-prerender-client-hook`, and static routes pass (the pathname is known at prerender), which masks it until you reach a dynamic segment. It's not an ancestor-data fix — follow the [error's docs page](https://nextjs.org/docs/messages/blocking-prerender-client-hook) for the `` recipe. Only when a client route blocks on _server_ data do you fix that data in its ancestor. ### end of the pre-step: check in -Incremental only. Stop here before starting step 2 — the pre-step is the shippable PR. Talk to the user in their language; don't say "Incremental" or other internal labels; talk about adoption, PRs, and what the app does now. Tell them: +Incremental only. The pre-step is the shippable PR. Record the passing checkpoint before starting step 2. Unless the user already asked you to continue through the full migration in the same task, stop and check in. Talk to the user in their language; don't say "Incremental" or other internal labels; talk about adoption, PRs, and what the app does now. Tell them: -- What you did: turned on Cache Components, ran the codemod that opts every page and layout out of the new validation (or did it by hand), fixed any blockers the codemod can't (list them), confirmed the build passes. -- What changed: every page and layout in the app directory now exports `instant = false` with a `// TODO: Cache Components adoption` comment, except client components and any that already had an `instant` export. -- What to sanity-check: the diff is mostly mechanical (new exports + comments). The build passes. Routes still behave exactly as they did before — the opt-outs preserve current behavior; no rendering changes yet. +- What you did: turned on Cache Components, ran the codemod, migrated the previously static routes, fixed the remaining blockers, and confirmed the build passes. +- What changed: the previously static routes still prerender. Other pages and layouts keep a `// TODO: Cache Components adoption` opt-out. +- What to sanity-check: the previously static routes stay fully prerendered and prefetchable, and request-specific data on the deferred routes remains request-specific. - The question: "Want to open this as its own PR before we start adopting Cache Components route by route? Or keep going on this branch?" Wait for the answer. -Moving to step 2 without checking in defeats the point of taking the incremental path. +If the user already asked you to complete the migration, continue after recording this checkpoint instead of asking the same question again. ### direct @@ -209,6 +213,7 @@ Checklist before checking in with the user: - `next build` completes without blocking-route errors. - No bare TODOs in the feature: `grep -rn "TODO: Cache Components adoption"` finds both the codemod's opt-out comments and the sync-IO unblocks from the pre-step. Any `instant = false` left behind is a deliberate, documented Block — comment rewritten to a reason (see [references/per-page-decisions.md](./references/per-page-decisions.md) → "when to leave a Block in place"). Any `await io()` or `await connection()` left behind has been reviewed and kept on purpose, not left over from the pre-step. - Each route visited in the browser: confirm the static shell renders first and every `` fallback resolves to its real content. Capture both states if you can — the fallback (mid-stream) and the final paint — so you have a streaming-experience demo to show the user. Throttle the network in the browser if streaming is too fast to observe. +- After populating any new cache whose data can be updated, a mutation check confirms the next read returns the expected data. - If runtime verification fails, reproduce the same route on the pre-adoption branch or with its opt-out restored. A failure that already exists is an environment or data problem, not an adoption regression. Then check in with the user. Same rule as the pre-step: speak their language. Don't say "feature-by-feature loop" or other internal labels; talk about the feature you adopted and what the user will see. diff --git a/plugins/codex/plugins/next-skills/skills/next-cache-components-optimizer/SKILL.md b/plugins/codex/plugins/next-skills/skills/next-cache-components-optimizer/SKILL.md index 415b3ba9..e9820e9a 100644 --- a/plugins/codex/plugins/next-skills/skills/next-cache-components-optimizer/SKILL.md +++ b/plugins/codex/plugins/next-skills/skills/next-cache-components-optimizer/SKILL.md @@ -157,9 +157,8 @@ yours. On first use in a repository, discover how the project builds, deploys, authenticates, and tests (inspect the repository first, and ask the user only what it cannot answer), then write the answers to a committed `instant-nav.rig.md`. Every later run reads that file instead of -rediscovering. The six questions (BUILD / EXPOSE / RUN / TEST USER / DRIFT / -LOOP), the file template, and filled examples (local-only, generic CI + -container, preview deploy) are in **`rig-template.md`**. +rediscovering. The required build, test context, navigation contracts, +iteration loop, and file template are in **`rig-template.md`**. If the repo has no Playwright e2e harness yet, standing up a minimal one (`@next/playwright`, a config with `baseURL`, one authenticated path) is part @@ -196,12 +195,12 @@ every platform: The rig is any production-like build that exposes the testing API: a local `next build && next start`, a CI/staging container, and a preview deploy are all equally valid; the verdict comes from the build, not the platform. See -`rig-template.md` for filled examples. +`rig-template.md` for the setup requirements. For any deployed or remote build, poll the rig's LIVENESS probe to confirm the artifact contains `HEAD` before trusting a verdict (a stale deploy reads as a false RED or GREEN); a local `next build && next start` needs none. The probe -mechanism is in `rig-template.md` (question 6). +mechanism is in `rig-template.md`. ## B. BASELINE (unlocked): development scaffold, do not ship @@ -357,6 +356,10 @@ this gate is as machine-checkable as the others. Detail: > under the lock on the production-build rig**, not when the code compiles. That > GREEN is the deterministic stop for the fix loop; proceed to E. +If the optimization adds or expands a cache boundary, follow +[Revalidating](https://nextjs.org/docs/app/getting-started/revalidating). +A passing `instant()` test proves shell readiness, not mutation freshness. + **When URL data can't be pushed down** (for example, the whole page depends on `params`, `searchParams`, or the full URL), there may be no meaningful static shell to grow. Don't force one. Per-link prefetching can make the soft @@ -404,6 +407,9 @@ PR-specific items: - [ ] **Differential shown**: RED without the fix, GREEN with it, runs linked. - [ ] **Parity confirmed (E)**: same content, redirects, and state. +- [ ] **Mutations verified when applicable**: after populating any cache whose + data can be updated, a mutation test confirms the next read returns the + expected data. - [ ] **Existing loading UI reused (D1)**: no new page-mirroring skeleton. - [ ] **Shell matches the real render at desktop and mobile widths (D2)**. - [ ] **Baseline removed**: only the locked test from C remains. @@ -425,9 +431,8 @@ three hold, you are not done. ## Files -- `rig-template.md`: phase 0, the six-question rig discovery, the - `instant-nav.rig.md` template, and filled examples (local-only, generic CI, - preview deploy). +- `rig-template.md`: phase 0 production build, test context, navigation + contract, and unattended loop discovery. - `test-template.md`: the shipped `instant()` specs for both navigation types (phase C), and the delete-before-PR baseline scaffold (phase B). - `reference/red-test-robustness.md`: the C-gate and phase F. The taxonomy of diff --git a/plugins/codex/plugins/next-skills/skills/next-cache-components-optimizer/rig-template.md b/plugins/codex/plugins/next-skills/skills/next-cache-components-optimizer/rig-template.md index c19c0ba5..e2a6ff42 100644 --- a/plugins/codex/plugins/next-skills/skills/next-cache-components-optimizer/rig-template.md +++ b/plugins/codex/plugins/next-skills/skills/next-cache-components-optimizer/rig-template.md @@ -1,111 +1,173 @@ -# Rig discovery: generate this project's `instant-nav.rig.md` +# Production `instant()` rig -The skill's principles are environment-independent. Your build, deploy, auth, -and test infrastructure are not. This phase converts the principles into THIS -project's concrete workflow: run discovery once per repo, write the answers to -a committed `instant-nav.rig.md` (repo root, or next to your e2e config), and -every later run reads that file instead of rediscovering. +The optimizer suite needs a production build that exposes the Next.js testing +API, a stable URL for that build, and a Playwright command that can drive the +initial loads or client navigations being optimized. Discover this setup once, +record it in `instant-nav.rig.md`, and reuse it across optimization runs. -The skill is deliberately opinionated about **what** the rig must provide, and -deliberately unopinionated about **how** your stack provides it. +Read an existing `instant-nav.rig.md` before creating one. Inspect the +repository before asking the user: -## How to discover +- `package.json` scripts for build, start, and end-to-end tests +- `playwright.config.*` for `baseURL`, `webServer`, projects, and authentication +- `next.config.*` for existing `experimental` options +- CI, preview deployment, container, and hosting configuration +- test helpers for login, `storageState`, fixtures, flags, and seeded data -Inspect before asking. Most answers are already in the repo: +Ask only for details the repository cannot answer, such as unavailable +credentials or which remote environment may expose the testing API. -- `package.json` scripts (`build`, `start`, `test:e2e`) -- the e2e config (`playwright.config.*`: `baseURL`, `webServer`, projects) -- CI config (`.github/workflows/`, `vercel.json`, GitLab/Circle files, - Dockerfiles) -- `next.config.*` (existing `experimental` flags) -- existing e2e auth helpers (grep for `login`, `storageState`, `session`) +## What the rig must define -Ask the user only what the repo can't answer. Typically that means: which -deploy target counts as "preview", which account the suite runs as in CI, and -whether an agent is allowed to push and wait on CI unattended. +### Production build and server -## The six questions (all must have answers), plus two derived fields +Use `next build` followed by `next start`, or a remote artifact produced by the +same production build. Development can help diagnose a route, but the final +RED and GREEN must come from a production build. -The six questions below must all have answers. The rig file template adds two -more fields the discovery feeds rather than asks directly: **LIVENESS** (the -SHA-echoing probe, derived from the LOOP answer) and **WALLS** (project-specific -build/run obstacles, accumulated as you first hit them). +Record separate build and start commands. For a local rig, record the port, +stop any previous server before starting, fail on `EADDRINUSE`, and confirm the +new process owns the port before running Playwright. `next start` can fork a +`next-server` child, so the launcher process ID may not own the port. Start the +server in a process group that the rig can stop as a unit, or discover and stop +the process listening on the recorded port before the next build. -1. **BUILD**: how is a production build of this app produced and served? - A per-push preview deploy, a staging container, or bare - `next build && next start`. Anything but `next dev`. -2. **EXPOSE**: what condition turns on - `experimental.exposeTestingApiInProductionBuild` for every measured build, - and never for real production? Spellings: an explicit - `EXPOSE_TESTING_API=1` for local production builds; `process.env.DEPLOY_ENV -=== 'staging'` for a generic CI/staging env var; `process.env.VERCEL_ENV === -'preview'` on Vercel. Set the condition during `next build`, not only - `next start`. Otherwise `instant()` may not acquire the testing cookie - before the test times out; rebuild the artifact before debugging the - assertion. -3. **RUN**: how is the Playwright suite invoked, and against which - `BASE_URL`? -4. **TEST USER**: which account does the suite run as, and how does login - happen (helper, `storageState`, API token)? What flags / plan / role / data - does that account have? -5. **DRIFT**: enumerate everything that can differ between the author's own - session and the test user's environment (feature flags, plans and - entitlements, roles, seeded vs empty data, locale, A/B buckets). Every item - is a way a RED can become untrustworthy; this list feeds the C-gate - (`reference/red-test-robustness.md`). -6. **LOOP**: the unattended iteration for your rig. Push → build → e2e - against the artifact → read the failure → fix → push (CI), or build → start - → e2e (local). Note anything an agent cannot do alone (deploy approvals, - secrets, protected branches). Include the **liveness probe**: the endpoint - or response header that echoes the deployed commit SHA (e.g. a `/healthz` - route or an `x-deployed-sha` header), so a CI run can confirm the build - under test matches `HEAD` before trusting a verdict (SKILL.md phase A). If - the platform exposes no SHA-echoing endpoint or header, add one: surface a - build-time commit var (`VERCEL_GIT_COMMIT_SHA`, a CI commit variable) on a - `/healthz` route or a response header, or fall back to polling the deploy - platform's API for the deployment whose `commitSha === HEAD`. Record the - chosen mechanism. For a local `build && start` rig the artifact is the one - freshly built, so no SHA probe is needed. Record the port, stop the previous - server before starting, fail the loop on `EADDRINUSE`, and verify the newly - started process owns the port before running the test. `next start` can fork - a `next-server` child, so the launcher process ID may not own the port. Start - the server in a process group that the rig can stop as a unit, or discover - and stop the process listening on the recorded port before the next build. +### Testing API -## The file: copy, fill, commit as `instant-nav.rig.md` +An `instant()` test against a production build requires +`experimental.exposeTestingApiInProductionBuild`. Gate it so real production +builds do not expose the API: + +```ts filename="next.config.ts" highlight={3,8-10} +import type { NextConfig } from 'next' + +const exposeTestingApi = process.env.EXPOSE_TESTING_API === '1' + +const nextConfig: NextConfig = { + cacheComponents: true, + experimental: { + exposeTestingApiInProductionBuild: exposeTestingApi, + }, +} + +export default nextConfig +``` + +Merge the option into an existing `experimental` object instead of replacing +the project's other experimental options. + +Set the condition while running `next build`. Setting it only for `next start` +is too late because the testing API is compiled into the production artifact. +When the artifact was built without it, Next.js does not activate the +navigation lock, so the test cannot distinguish shell content from streamed +dynamic content. Rebuild with the condition enabled before interpreting the +results. Use the project's existing environment naming when it already +distinguishes test, staging, preview, and production builds. + +### Test command and base URL + +Record the exact Playwright command and how it receives the measured build's +URL. Reuse the project's package manager, Playwright configuration, projects, +and reporters. The suite must import `instant()` from `@next/playwright`. If +the dependencies are absent, install `@next/playwright` on the same release +line as the project's `next`, alongside `@playwright/test`. + +For a local rig, a typical sequence is: + +```bash filename="Terminal" +EXPOSE_TESTING_API=1 pnpm build +pnpm start --port 3000 +BASE_URL=http://localhost:3000 pnpm playwright test tests/static-shell.spec.ts +``` + +Adapt the script names and port to the project. Keep the production server +running while the test command executes. Follow the public +[`instant()` testing pattern](https://nextjs.org/docs/app/guides/instant-navigation#prevent-regressions-with-e2e-tests): use `page.goto()` for an initial-load +contract and click the real `` for a client-navigation contract. + +### Test context + +Record the state required to reach the target route and shell marker: + +- Use `public; no authentication` when the route is public. +- Otherwise record the test account and login mechanism, including a fixture, + `storageState`, API login, or seeded session. +- Record flags, plan, role, locale, seeded data, and other state that can change + which shell the test sees. + +A test user is not required. The field exists to make authenticated and +state-dependent tests reproducible when the app needs one. + +### Drift + +List differences between the state used to choose the shell contract and the +state used by Playwright. Feature flags, permissions, empty test data, and +locale differences can make an assertion fail because the target is +unreachable, not because its shell blocks. Write `none known` +only after checking the test context. + +### Iteration loop + +Record the complete loop the agent can repeat without rediscovering commands: + +- Local: build with the testing API, start the new artifact, run the focused + suite, stop the server, edit, and repeat. +- Remote: push, wait for the measured artifact, verify it matches `HEAD`, run + the focused suite against its URL, edit, and repeat. + +Note any step the agent cannot perform without the user, including deployment +approval, protected branches, secrets, or multi-factor authentication. + +### Artifact liveness + +For a remote rig, record how the test proves the deployment matches `HEAD`. +Prefer an endpoint or response header that exposes the deployed commit SHA. If +the app has neither, use the deployment provider's API to select the artifact +whose commit SHA matches `HEAD`. + +A freshly completed local `build` followed by `start` does not need a SHA +probe. Record `n/a; local build and start`. + +### Walls + +Record build and run obstacles with their working resolution, such as required +environment variables, server-only imports that fail during prerendering, +unavailable credentials, or a process that keeps reclaiming the test port. +Reuse these notes on the next iteration. + +## Write `instant-nav.rig.md` + +Place this file at the repository root or next to the end-to-end configuration: ```md # instant-nav rig: -- BUILD: -- EXPOSE: -- RUN: against -- TEST USER: via ; flags/plan/role/data: <...> -- DRIFT: -- LOOP: ; agent limits: <...> -- LIVENESS: -- WALLS: +- BUILD: +- EXPOSE: +- RUN: +- TEST USER: ; state: +- DRIFT: +- CONTRACTS: +- LOOP: ; agent limits: <...> +- LIVENESS: +- WALLS: ``` -Real apps rarely build for production cleanly on the first attempt: missing -secrets, server-only imports that fail prerender, ports held by respawning -servers. Record each wall and its workaround the first time you hit it. `WALLS` -accumulates the project-specific build/run obstacles that the other fields -cannot capture. +`CONTRACTS` may list more than one focused navigation, but each route and +navigation type needs its own test. Every field needs a concrete value. `n/a` +is valid only with a reason, such as `TEST USER: public; no authentication` or +`LIVENESS: n/a; local build and start`. -## Filled examples +## Check the rig before writing the baseline -**No CI / local-only.** BUILD: `EXPOSE_TESTING_API=1 next build && next -start`. EXPOSE: that env var. RUN: `BASE_URL=http://localhost:3000 playwright -test`. LOOP: build → start → test on one machine; fully agent-drivable, with -nothing to push, no secrets, and no deploy wait. +Before recording the static-shell contract: -**Generic CI + container.** BUILD: the pipeline builds an image and deploys it -to a staging namespace. EXPOSE: `process.env.DEPLOY_ENV === 'staging'`. RUN: a -CI job runs Playwright against the staging URL. LOOP: push → pipeline → e2e; -fully agent-drivable once the pipeline is wired. +1. Build with the testing API condition enabled. +2. Start or locate that exact artifact and confirm the base URL responds. +3. Run one focused `instant()` smoke test using the intended navigation type. +4. Confirm the test can reach the route and eventual destination UI in the + recorded test context. -**Vercel preview deploys.** BUILD: every push builds a preview. EXPOSE: -`process.env.VERCEL_ENV === 'preview'`. RUN: `playwright test` with -`BASE_URL=`. LOOP: push → preview → e2e; fully agent-drivable -once the preview deploy and `VERCEL_ENV` gating are in place. +Fix the rig before interpreting an optimizer failure. A missing testing API, +stale deployment, unreachable target, or wrong test state is an environment +failure rather than evidence that the shell blocks. diff --git a/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-adoption/SKILL.md b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-adoption/SKILL.md index aa11cd07..dcc2b5fb 100644 --- a/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-adoption/SKILL.md +++ b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-adoption/SKILL.md @@ -112,7 +112,7 @@ Use that exact prefix so step 7 can grep them back. Do not select new target UI For test-backed preservation, rerun the affected **unchanged** tests after each destination changes and treat failures as the work queue. Run the complete suite and record its passing exit status before enabling the global flag. For manual preservation, compare the adopted production navigation with the selected target and document anything not yet restored. Apply the guide's matching preservation pattern for caching and Link-prop changes, and ask the user before making an unclear freshness or caching decision. New URL-data candidates marked above wait for step 7. -When restoring the target changes caching or invalidation, follow the project's existing verification approach. Reuse or extend an applicable suite for the affected lifecycle, such as freshness after mutations, cache scope, or generated values. If the project doesn't test this type of behavior, do not introduce new test infrastructure during adoption; verify it manually in production and record the expected and observed results. A green `instant()` test proves readiness, not cache correctness. Ask the user only when the intended behavior is unclear. +When restoring the target changes caching or invalidation, follow the project's existing verification approach and the [Revalidating](https://nextjs.org/docs/app/getting-started/revalidating) guide. Reuse or extend an applicable suite for the affected lifecycle. If the project doesn't test this type of behavior, do not introduce new test infrastructure during adoption; verify it manually in production and record the expected and observed results. A green `instant()` test proves readiness, not cache correctness. Ask the user only when the intended behavior is unclear. > **If you add `use cache`, verify under `next start`, not only the build.** A `cookies()`/`headers()`/session read anywhere in the cached call tree throws at request time while `next build` passes clean. See [`use cache`](https://nextjs.org/docs/app/api-reference/directives/use-cache). @@ -153,7 +153,7 @@ Checklist before checking in with the user: - The App Shells are real: for each route you changed, confirm the first paint after a navigation shows the intended shared content, not an empty shell or a stuck fallback. A `` around the whole page body passes validation with an empty shell, which defeats the point. - The insights validate shell _structure_, not that a prefetch actually happened. Confirm on the production run (automatic prefetching runs only in production) that navigating a changed link lands on the shared shell instantly. - For test-backed preservation, every locked `instant()` test for an audited `` passes against the production run. For manual preservation, the before/after inventory and any deferred test follow-ups are recorded. -- Any caching or invalidation changed to preserve the target is verified through an applicable existing test suite or a recorded manual check when the project has no such coverage. +- After populating any new or expanded cache whose data can be updated, a mutation check verifies the next read through an applicable existing test suite or a recorded manual check when the project has no such coverage. - **If the app prefetches imperatively**, the insight sweep does not cover it, so an empty sweep is not proof the prefetch survived the flag. Verify the call under `next start`: compare the `_rsc` prefetch response or resource timing before/after, and make sure any intentionally preserved full prefetch still carries the data the old call was warming. If it now returns only the App Shell, migrate that call site using the same decision as the nearest `` destination — cache the data, or move per-link-prefetch behavior to a docs-supported ``. - **Before blaming a broken route on the flag, reproduce it with `partialPrefetching` off** (or on the pre-flag branch). The flag surfaces existing issues — a fragile request-time auth gate, a rewrite, deployment skew — earlier and more visibly, but rarely causes them. If it breaks flag-off too, it isn't a Partial Prefetching problem; fix it there, not here. - `next build` still passes. diff --git a/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-adoption/rig-template.md b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-adoption/rig-template.md index bbfa4c7e..647d19d3 100644 --- a/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-adoption/rig-template.md +++ b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-adoption/rig-template.md @@ -148,14 +148,16 @@ Place this file at the repository root or next to the end-to-end configuration: - RUN: - TEST USER: ; state: - DRIFT: +- CONTRACTS: - LOOP: ; agent limits: <...> - LIVENESS: - WALLS: ``` -Every field needs a concrete value. `n/a` is valid only with a reason, such as -`TEST USER: public; no authentication` or `LIVENESS: n/a; local build and -start`. +`CONTRACTS` may list more than one audited navigation, but each contract needs +its own test. Every field needs a concrete value. `n/a` is valid only with a +reason, such as `TEST USER: public; no authentication` or +`LIVENESS: n/a; local build and start`. ## Check the rig before writing the baseline diff --git a/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/SKILL.md b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/SKILL.md new file mode 100644 index 00000000..f33dbc67 --- /dev/null +++ b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/SKILL.md @@ -0,0 +1,229 @@ +--- +name: next-partial-prefetching-optimizer +description: > + Optimize what selected Next.js client navigations include before the click + under Partial Prefetching. Use after Cache Components and Partial Prefetching + are adopted when the user wants selected URL-specific UI to be instant, + wants reusable content to wait for navigation, or needs to choose between + default, viewport, and intent prefetching. Requires Next.js 16.3+. +--- + +# Partial Prefetching optimizer + +Optimize each requested source link and destination as its own contract. Turn +the requested prefetched UI, navigation-only UI, and trigger into a production +[`instant()`](https://nextjs.org/docs/app/guides/instant-navigation#prevent-regressions-with-e2e-tests) +test. Record the current behavior, make the smallest optimization, verify the +differential, and keep the passing test as regression coverage. + +Before making framework changes, read the bundled Optimizing prefetching guide +at +`node_modules/next/dist/docs/01-app/02-guides/optimizing-prefetching.md`. If the +bundled guide is unavailable, use the [online +guide](https://nextjs.org/docs/app/guides/optimizing-prefetching). It is the +source of truth for prefetch stages, `prefetch={true}`, session-specific UI, +and cost trade-offs. + +When the work changes what belongs in the App Shell, follow the +[Instant navigation](https://nextjs.org/docs/app/guides/instant-navigation) and +[Caching](https://nextjs.org/docs/app/getting-started/caching) docs for cache +placement, Suspense boundaries, loading UI, and authorization. + +The guides own framework behavior and implementation patterns. This skill owns +the navigation contract, production rig, trustworthy RED-to-GREEN loop, parity +check, differential, and report. + +This is not an adoption skill. If Cache Components or Partial Prefetching are +not adopted, use their adoption skills and return to this workflow. If the App +Shell itself cannot commit under `instant()`, use +`next-cache-components-optimizer` first, then resume the selected navigation. + +Run the workflow unattended. Resolve the contract from the request and the +existing application. Stop for user input only when a product decision is +genuinely blocked and cannot be inferred safely without changing cost, +freshness, authorization, or user-visible behavior. + +## Reporting to the user + +This loop runs unattended, so do not stop between implementation steps. Finish +the navigations the user named, then check in. The rig, lock, RED/GREEN loop, +and stage names are internal scaffolding; report the product behavior instead. + +- **Speak their language.** Describe the source link and result in terms of + what the user sees before and after the click, not the validation mechanics. +- **Show, don't tell.** Drive the exact link in a production browser so the user + sees which content is already available and which content streams after the + click. If a live demonstration is unavailable, attach before/after captures. +- **Give them a concise click-through list, not a technical results table.** Use + one line per navigation with the source URL, link to click, UI ready before + the click, UI that waits for navigation, and whether prefetching starts in the + viewport or after intent. +- **Only surface a question for a genuine fork.** Ask when the choice changes + cost, freshness, authorization, or visible behavior. If the user already + requested a PR or named every navigation, finish that scope without asking + again. + +## Define the contract + +Inspect the source route, the exact link or interaction, the destination's +Suspense boundaries, its data reads, existing prefetch policy, and any existing +`instant()` test. Record: + +- which destination UI should be ready before the click; +- which reusable UI should wait for navigation; +- whether per-link prefetching should start in the viewport or only after + intent. + +The trigger is part of the contract. Two links to the same URL may use +different prefetch policies and need separate tests. + +Use the guide's cost model when the trigger is not already specified. Do not +silently increase the number of links that can invoke the server or cache data +whose freshness contract is unknown. + +## Reuse the production rig + +Read an existing `instant-nav.rig.md`. Cache Components optimization, Partial +Prefetching adoption, and this optimizer share the same build, auth, data, and +Playwright contract. Add the exact source link, destination markers, and +prefetch budget instead of creating another rig. + +If the project has no rig, use [`rig-template.md`](rig-template.md) to discover +and record one. The measured run must be a production build or +preview where `experimental.exposeTestingApiInProductionBuild` is enabled only +for testing. Development can help diagnose a route, but automatic link +prefetching is production-only. + +## Prove the current behavior + +Search for an existing `instant()` test for the exact source link and +destination. Extend it when it already covers the same behavior. Otherwise, +add a focused click-driven test using the guide's +[prefetched and deferred content testing](https://nextjs.org/docs/app/guides/optimizing-prefetching#test-prefetched-and-deferred-content) +pattern. + +Keep one production browser test per source-link, destination, and trigger +contract. Do not loop over several destinations or collect their readiness +results in one test. Focused tests can still run serially in one browser worker. + +First, run an unlocked scaffold that proves the link reaches the exact pathname +and query and that the selected UI eventually renders for the test user. Do not +ship this scaffold. + +Then run the same interaction inside `instant()`. The existing App Shell must +stay visible, while the guide's positive and negative assertions capture the +prefetched result. After the lock releases, every selected region must +eventually render. + +Read [`reference/red-test-robustness.md`](reference/red-test-robustness.md) +before treating this failure as RED. A timeout before the URL changes, a +missing App Shell, a redirect, missing data, or a stale preview indicates a rig +or route problem. It does not justify changing prefetching. + +If the complete desired contract already passes under the lock, stop. Never +add `prefetch={false}` merely to manufacture a RED. + +Only test files and the configuration needed to expose the testing API may +change before these runs finish. Run builds and tests in the foreground. If the +harness moves one into the background, wait for it to exit and continue the +loop in the same task. A written test or a build still in progress is not +verification. + +## Make the smallest optimization + +Follow the Optimizing prefetching guide for stage and link policy. If the +contract also requires changing cache placement, Suspense, or loading UI, +follow the static-shell documentation used by +`next-cache-components-optimizer`. Preserve the existing freshness and +authorization behavior. Change only what the selected contract requires. + +When reusable UI should wait for navigation, follow the +[`unstable_navigation()`](https://nextjs.org/docs/app/api-reference/functions/navigation) +reference, including its comparison with `connection()`. Then verify both +properties independently. The `instant()` assertion proves that the UI is +absent from the prefetch; it does not prove that the underlying work stayed +reusable. Verify that reusable work remains cached below the stage boundary. + +When the contract needs an explicit runtime stage, follow the API references +for [`unstable_prefetch()`](https://nextjs.org/docs/app/api-reference/functions/prefetch) +and +[`unstable_navigation()`](https://nextjs.org/docs/app/api-reference/functions/navigation). + +Work one accepted navigation to GREEN before moving to another. Do not create +an app-wide Link or cache abstraction from a single case. + +If the optimization adds or expands a cache boundary, follow +[Revalidating](https://nextjs.org/docs/app/getting-started/revalidating). +When a writer can change that cached data, test the complete lifecycle: populate +the cache, perform the mutation, then read the data again and verify the updated +value. A passing `instant()` test proves prefetched readiness, not mutation +freshness. + +## Verify and ship + +Keep the passing locked test for the real source link as regression coverage. +Preserve the loaded page's content, ordering, empty and error states, +authorization, freshness, redirects, and direct-load behavior. + +Finally, remove only the optimization and rerun the test: + +- the App Shell stays GREEN; +- the selected prefetch contract returns RED. + +Reapply the optimization and require GREEN again. This differential proves the +test guards the exact link policy instead of unrelated cached state. Ship only +the final positive test. + +Report the verified result using the user-facing format above. Be precise that +prefetching is best-effort; the App Shell remains the fallback when it has not +completed. + +Treat request counts, transferred bytes, and cache behavior as measurements, +not as part of the `instant()` contract. Do not classify requests using private +RSC URLs or internal headers such as `next-router-prefetch`. The public testing +API verifies the rendered result, not the protocol stage that produced each +request. + +## Completion checklist + +- [ ] Cache Components and Partial Prefetching were already adopted. +- [ ] The target UI, trigger, freshness, and authorization constraints were + resolved from the request and existing application. +- [ ] The test clicks the exact source link and verifies the exact destination. +- [ ] Each source-link, destination, and trigger contract has its own test. +- [ ] The unlocked baseline and locked RED used the same production artifact. +- [ ] The App Shell stayed visible throughout the RED/GREEN loop. +- [ ] The selected UI is present and navigation-only UI is absent under lock. +- [ ] Reusable navigation-only work remains cached below its navigation stage. +- [ ] After populating any new cache whose data can be updated, a mutation test + confirms the next read returns the expected data. +- [ ] Loaded content, freshness, authorization, and direct visits are unchanged. +- [ ] Removing only the optimization returns the contract to RED. +- [ ] The final positive `instant()` regression test ships. + +## Handoff + +Finish every navigation named in the request. If Cache Components or Partial +Prefetching are not adopted, use `next-cache-components-adoption` or +`next-partial-prefetching-adoption`, then return to this workflow. If the App +Shell cannot commit under `instant()`, use `next-cache-components-optimizer` +and resume the selected navigation afterward. Do not leave a build or test for +the user to monitor. + +Report additional optimization candidates without changing them unless they +are already in scope. Do not broaden a selected per-link policy into an app-wide +Link or cache abstraction. + +## Files + +- `rig-template.md`: production build, test context, navigation contract, and + unattended loop discovery for projects without an existing + `instant-nav.rig.md`. +- `reference/red-test-robustness.md`: trustworthy RED and differential checks. + +## Further reading + +- [Optimizing prefetching](https://nextjs.org/docs/app/guides/optimizing-prefetching) +- [Instant navigation](https://nextjs.org/docs/app/guides/instant-navigation) +- [Caching](https://nextjs.org/docs/app/getting-started/caching) +- [Prefetching](https://nextjs.org/docs/app/guides/prefetching) diff --git a/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/reference/red-test-robustness.md b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/reference/red-test-robustness.md new file mode 100644 index 00000000..dc707d9b --- /dev/null +++ b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/reference/red-test-robustness.md @@ -0,0 +1,132 @@ +# Trustworthy RED and differential + +Change the implementation only after the RED proves a genuine prefetch-contract +gap for one exact link. A failing assertion alone is not enough. + +## Verification gate + +Require this sequence on the same production artifact and as the same test +user: + +1. **Unlocked:** click the exact source link; exact pathname/query, shell, and + expected URL-derived target content all render. +2. **Locked diagnostic:** click the same link; destination URL changes, + `SHELL_MARKER` is visible, and the current result differs from the selected + target/navigation-only contract. +3. **After release:** every marker selected from the loaded page is visible. + +Only then restore the selected contract assertions and change the +implementation. + +## What each signal rules out + +- **Destination URL wait** rules out matching the source page or clicking a + nested element that never navigates. Match relevant search params too, not + only `pathname`. +- **Shell visible under lock** proves the route already has an App Shell and is + not wholly blocking. +- **Target visible unlocked** rules out auth, flags, empty data, typoed + selectors, and redirects hiding the region. +- **Target absent locked, visible after release** proves it is outside the + prefetched result rather than absent altogether. + +## The trigger is part of the test + +Do not replace the real link with `router.push`, `page.goto`, or another link +to the same URL. The testing lock reenacts the clicked link's fetch strategy. +It intentionally restricts a default Partial Prefetching link to the App Shell +even if a sibling `prefetch={true}` link already warmed a concrete-param cache +entry. + +For an intent policy, hover or focus the exact link inside `instant()` before +clicking. Click without a fixed delay and assert the prefetched UI after the +destination URL changes. Do not warm outside the scope or inspect private +request headers to decide when the prefetch is ready. For viewport policy, do +not hover: the test should prove the link's declared eager strategy. + +Reusing a browser worker does not require aggregating several contracts into +one test. Separate tests prevent navigation cache and interaction state from +leaking between routes, and their failures identify the exact contract that +regressed. + +## Common false REDs + +- The target is URL-specific but the test user's record/query returns empty. +- The target is behind a flag, role, plan, locale, or experiment absent in CI. +- Auth redirects to a page where the shell selector happens to exist. +- A shared selector matches the source before the destination commits. +- The test clicks a default link while the code change modified a different + link to the same URL. +- Session-only UI was assumed to need a per-link prefetch without proving the + default/per-link exact-link differential. +- The pathname matches but the query or parameter-derived content is wrong. +- The production build does not have the testing API exposed. +- A remote test ran against a stale deployment. +- A local start failed with `EADDRINUSE` and the test hit the previous build. + +## Contract already GREEN + +Run the locked diagnostic against the exact link as it exists. If the shell and +target are visible, navigation-only markers are absent, and the lock is +engaged, the current link already meets the contract. It is not an optimizer +candidate, even if setting `prefetch={false}` would make it RED. Never add that +prop as a test control; the optimizer compares automatic prefetching with no +prop against `prefetch={true}`. + +## Lock engagement + +`experimental.exposeTestingApiInProductionBuild` must be true on the measured +artifact. A marker that is absent under lock and visible after release is the +in-band proof that the lock engaged. A vacuous no-op cannot satisfy both +halves. + +Never enable this flag for real production traffic. For a remote rig, verify +the deployed commit before trusting RED or GREEN. + +## What `instant()` can verify + +See: [`instant()`](https://nextjs.org/docs/app/guides/instant-navigation#prevent-regressions-with-e2e-tests). + +The public helper accepts a page, callback, and optional `baseURL`: + +```ts +instant(page, callback, { baseURL? }) +``` + +It does not accept a requested stage such as `shell` or `max`. A failed test +also does not identify the data read where the prefetch stopped. Compare the +same exact link before and after the optimization: + +- existing exact-link policy -> current committed UI; +- accepted policy change -> the selected prefetch stages may commit. + +If the optimization does not change the locked result, inspect `params`, +`searchParams`, Suspense boundaries, and cache directives using the +[Optimizing prefetching guide](https://nextjs.org/docs/app/guides/optimizing-prefetching). +Do not compensate with timing. + +`instant()` does not expose a public request classifier for App Shell, +per-link, and navigation requests. Internal request headers and segment URLs +can change between Next.js versions, so do not use them as product regression +assertions. Use `instant()` for the visible contract and record network or +platform cost data separately when the task calls for it. + +## Differential + +After the test passes: + +1. Record the build/commit under test. +2. Remove only the stage, per-link prefetch trigger, and cache boundary + introduced for the contract. +3. Rebuild and rerun. The shell should stay available, but the selected + prefetch contract should fail. +4. Reapply the optimization, rebuild, and rerun. The complete contract should + pass again. +5. Confirm the unlocked loaded page is identical in both versions. + +If removing the optimization also removes the shell, the change mixed Cache +Components work into this loop. Split it. If the contract remains GREEN, +another policy still controls the clicked link or the changed boundary does +not own the asserted content; the test does not guard the intended +optimization. Do not replace the unchanged automatic policy with +`prefetch={false}` to force this step RED. diff --git a/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/rig-template.md b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/rig-template.md new file mode 100644 index 00000000..2f6ad9e6 --- /dev/null +++ b/plugins/codex/plugins/next-skills/skills/next-partial-prefetching-optimizer/rig-template.md @@ -0,0 +1,174 @@ +# Production `instant()` rig + +The optimizer suite needs a production build that exposes the Next.js +testing API, a stable URL for that build, and a Playwright command that can +drive the selected source Links. Discover this setup once, record it in +`instant-nav.rig.md`, and reuse it across optimization runs. + +Read an existing `instant-nav.rig.md` before creating one. Inspect the +repository before asking the user: + +- `package.json` scripts for build, start, and end-to-end tests +- `playwright.config.*` for `baseURL`, `webServer`, projects, and authentication +- `next.config.*` for existing `experimental` options +- CI, preview deployment, container, and hosting configuration +- test helpers for login, `storageState`, fixtures, flags, and seeded data + +Ask only for details the repository cannot answer, such as unavailable +credentials or which remote environment may expose the testing API. + +## What the rig must define + +### Production build and server + +Use `next build` followed by `next start`, or a remote artifact produced by the +same production build. Automatic prefetching does not run in `next dev`, so a +development server cannot verify the prefetched result. + +Record separate build and start commands. For a local rig, record the port, +stop any previous server before starting, fail on `EADDRINUSE`, and confirm the +new process owns the port before running Playwright. `next start` can fork a +`next-server` child, so the launcher process ID may not own the port. Start the +server in a process group that the rig can stop as a unit, or discover and stop +the process listening on the recorded port before the next build. + +### Testing API + +An `instant()` test against a production build requires +`experimental.exposeTestingApiInProductionBuild`. Gate it so real production +builds do not expose the API: + +```ts filename="next.config.ts" highlight={3,8-10} +import type { NextConfig } from 'next' + +const exposeTestingApi = process.env.EXPOSE_TESTING_API === '1' + +const nextConfig: NextConfig = { + cacheComponents: true, + experimental: { + exposeTestingApiInProductionBuild: exposeTestingApi, + }, +} + +export default nextConfig +``` + +Merge the option into an existing `experimental` object instead of replacing +the project's other experimental options. + +Set the condition while running `next build`. Setting it only for `next start` +is too late because the testing API is compiled into the production artifact. +When the artifact was built without it, Next.js does not activate the +navigation lock, so the test cannot distinguish prefetched UI from streamed +dynamic content. Rebuild with the condition enabled before interpreting the +results. Use the project's existing environment naming when it already +distinguishes test, staging, preview, and production builds. + +### Test command and base URL + +Record the exact Playwright command and how it receives the measured build's +URL. Reuse the project's package manager, Playwright configuration, projects, +and reporters. The suite must import `instant()` from `@next/playwright`. If +the dependencies are absent, install `@next/playwright` on the same release +line as the project's `next`, alongside `@playwright/test`. + +For a local rig, a typical sequence is: + +```bash filename="Terminal" +EXPOSE_TESTING_API=1 pnpm build +pnpm start --port 3000 +BASE_URL=http://localhost:3000 pnpm playwright test tests/prefetch-optimization.spec.ts +``` + +Adapt the script names and port to the project. Keep the production server +running while the test command executes. Follow the public +[client-navigation test](https://nextjs.org/docs/app/guides/instant-navigation#prevent-regressions-with-e2e-tests): load the source route, confirm the real +Link is visible, then enter `instant()`, click, wait for the destination URL, +and assert the prefetched UI. + +### Test context + +Record the state required to reach the selected source Link and destination UI: + +- Use `public; no authentication` when the navigation is public. +- Otherwise record the test account and login mechanism, including a fixture, + `storageState`, API login, or seeded session. +- Record flags, plan, role, locale, seeded data, and other state that can change + which UI the test sees. + +A test user is not required. The field exists to make authenticated and +state-dependent tests reproducible when the app needs one. + +### Drift + +List differences between the state used to choose the navigation contract and +the state used by Playwright. Feature flags, permissions, empty test data, and +locale differences can make an assertion fail because the target is +unreachable, not because Partial Prefetching removed it. Write `none known` +only after checking the test context. + +### Iteration loop + +Record the complete loop the agent can repeat without rediscovering commands: + +- Local: build with the testing API, start the new artifact, run the focused + suite, stop the server, edit, and repeat. +- Remote: push, wait for the measured artifact, verify it matches `HEAD`, run + the focused suite against its URL, edit, and repeat. + +Note any step the agent cannot perform without the user, including deployment +approval, protected branches, secrets, or multi-factor authentication. + +### Artifact liveness + +For a remote rig, record how the test proves the deployment matches `HEAD`. +Prefer an endpoint or response header that exposes the deployed commit SHA. If +the app has neither, use the deployment provider's API to select the artifact +whose commit SHA matches `HEAD`. + +A freshly completed local `build` followed by `start` does not need a SHA +probe. Record `n/a; local build and start`. + +### Walls + +Record build and run obstacles with their working resolution, such as required +environment variables, server-only imports that fail during prerendering, +unavailable credentials, or a process that keeps reclaiming the test port. +Reuse these notes on the next iteration. + +## Write `instant-nav.rig.md` + +Place this file at the repository root or next to the end-to-end configuration: + +```md +# instant-nav rig: + +- BUILD: +- EXPOSE: +- RUN: +- TEST USER: ; state: +- DRIFT: +- CONTRACTS: +- LOOP: ; agent limits: <...> +- LIVENESS: +- WALLS: +``` + +`CONTRACTS` may list more than one focused navigation, but each contract needs +its own test. Every field needs a concrete value. `n/a` is valid only with a +reason, such as `TEST USER: public; no authentication` or +`LIVENESS: n/a; local build and start`. + +## Check the rig before writing the baseline + +Before recording the prefetch contract: + +1. Build with the testing API condition enabled. +2. Start or locate that exact artifact and confirm the base URL responds. +3. Run one focused `instant()` smoke test through a real `` navigation. +4. Confirm the test can reach its source Link and eventual destination UI in + the recorded test context. + +Fix the rig before interpreting an optimizer failure. A missing testing API, +stale deployment, unreachable target, or wrong test state is an environment +failure rather than evidence that the optimization changed the prefetched UI. diff --git a/plugins/codex/plugins/ppt-master/THIRD_PARTY_SOURCE.json b/plugins/codex/plugins/ppt-master/THIRD_PARTY_SOURCE.json index 3f993b19..c26aec66 100644 --- a/plugins/codex/plugins/ppt-master/THIRD_PARTY_SOURCE.json +++ b/plugins/codex/plugins/ppt-master/THIRD_PARTY_SOURCE.json @@ -2,8 +2,8 @@ "sourceId": "ppt-master", "repo": "https://github.com/hugohe3/ppt-master.git", "ref": "main", - "commit": "64b65839c7f8096a534c872c03d688a2b2491c8f", + "commit": "09ad58f0d58decc9d30799ca83374ff2604ef16b", "adapter": "claude-skill", "sourcePath": "skills/ppt-master", - "syncedAt": "2026-09-09T16:00:00Z" + "syncedAt": "2026-09-10T23:40:59Z" } diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/SKILL.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/SKILL.md index 1058f759..28cfd4a3 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/SKILL.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/SKILL.md @@ -2,7 +2,7 @@ name: ppt-master description: "多格式源文档到高质量 SVG 页面再导出 PPTX 的多阶段演示文稿生成工作流。" metadata: - version: "6.3.1" + version: "6.3.2" copyright: "Copyright (c) 2025-2026 Hugo He" license: "MIT" official_repository: "https://github.com/hugohe3/ppt-master" diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/animations.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/animations.md index 4b450db0..61ea3c37 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/animations.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/animations.md @@ -234,7 +234,7 @@ Animations anchor on unique top-level `` content groups (`cover-title`, `c **Hard rule — existing groups are not custom-animation intent**: during the custom stage derive one group per logical motion unit from claims, comparisons, sequence, causality, and narration — splitting coarse wrappers and merging fragments without changing appearance, never to hit a count — and run `list-groups` only after that rewrite. -**Chrome stays static by default**: a `data-pptx-layer` group is structural and never animates, and a full-canvas background rect becomes the slide background, which cannot animate either. A static role/placeholder marker or a chrome-name id (background, header/footer, decor, watermark, page number, nav, logo, rule) keeps a group out of automatic animation and the scaffold; a sidecar entry that names it animates it — a background field panning (§4.1), a cover band sliding in — judged per page, never by category. Wrap logical sections in `` ([`shared-standards-core.md`](./shared-standards-core.md) §4.3); a root with no top-level group falls back to a bounded primitive set ([`svg-pipeline.md`](../scripts/docs/svg-pipeline.md)). +**Chrome stays static by default**: a `data-pptx-layer` group is structural and never animates, and a full-canvas background rect becomes the slide background, which cannot animate either. A static role/placeholder marker or a chrome-name id (background, header/footer, decor, watermark, page number, nav, logo, or a bare `rule` / decorative-line `hairline-rule`; a content group such as `commit-rule` is not chrome) keeps a group out of automatic animation and the scaffold; a sidecar entry that names it animates it — a background field panning (§4.1), a cover band sliding in — judged per page, never by category. Wrap logical sections in `` ([`shared-standards-core.md`](./shared-standards-core.md) §4.3); a root with no top-level group falls back to a bounded primitive set ([`svg-pipeline.md`](../scripts/docs/svg-pipeline.md)). --- diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/executor-base.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/executor-base.md index 912ef9f2..dd6345dc 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/executor-base.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/executor-base.md @@ -15,7 +15,7 @@ Always-loaded Executor authority for flat SVG page authoring, shared by Default | A page's contour reaches beyond rectangle, rounded rectangle, circle, ellipse, and line — an inflected carrier (snipped or one-sided rounded rectangle, plaque, bevel, polygon, pie / arc / donut, frame, corner, folded corner, trapezoid, parallelogram) as much as a relationship symbol (block arrow, chevron, callout, flowchart node, banner, star, bracket, connector) — or needs a Boolean / freeform decision | [`native-shape-authoring.md`](./native-shape-authoring.md), read completely (the preset vocabulary is already resident) | | A page's visual job reaches beyond the everyday block below — faux glass, constructed styles (hand-drawn, ink, riso, pixel, halftone, paper-cut, facets, gradient ribbon), gradient stroke, text picture/texture fill, gauge / sunburst / explicit arc geometry, freeform curves, transforms beyond rotate, or an unsupported effect needing a native-safe alternative | [`svg-effects.md`](./svg-effects.md) | | Any image | [`executor-image.md`](./executor-image.md) + [`image-layout-spec.md`](./image-layout-spec.md) + [`image-layout-patterns.md`](./image-layout-patterns.md) + [`svg-image-embedding.md`](./svg-image-embedding.md) | -| Any nontrivial mathematical expression | [`native-formula.md`](./native-formula.md) | +| Structural notation — a fraction, radical, n-ary operator, matrix, or delimiter pair (flat arithmetic, percentages, and `O(n log n)`-style tokens stay ordinary text) | [`native-formula.md`](./native-formula.md) | | Any external or same-deck click hyperlink | [`native-hyperlinks.md`](./native-hyperlinks.md) | | Any placed image is `Status: Sourced` or its filename has an `image_sources.json` record | [`executor-web-image.md`](./executor-web-image.md), after `executor-image.md` | | Effective Speaker Notes outcome is enabled after all SVG pages pass | [`executor-notes.md`](./executor-notes.md) | @@ -71,7 +71,7 @@ Read this before §1: the expression vocabulary every page draws from — what e | Elevated primary object | The one card, image, or CTA that sits above the page | `softShadow` at resting opacity on that object; peers stay flat | | Duotone or brand-wash image | A photo that must join the deck palette instead of fighting it | Wash gradient over the picture, or a prepared duotone derivative ([`svg-effects.md`](./svg-effects.md) §6.5 / §6.12) | -**Reference — layout structures (starting points; proportion follows information weight)**: 16:9 values for 1280×720 — safe area 1200×640 with 40 px margins; title band ≈ 100 px, content field ≈ 500 px, footer ≈ 40 px. +**Reference — layout structures (starting points; proportion follows information weight)**: 16:9 values for 1280×720 — safe area 1200×640 with 40 px margins; title band ≈ 100 px, content field ≈ 500 px, footer ≈ 40 px. 4:3 values for 1024×768 — safe area 944×688 with 40 px margins; title band ≈ 90 px, content field ≈ 540 px, footer ≈ 40 px; the field is 256 px narrower than 16:9, so a text column beside an image needs ≥ 520 px or the page stacks top/bottom. A4 portrait values for 1240×1754 (`a4`, print) — 80 px margins, a running masthead band ≈ 100 px, body field 1080×1490, footer band ≈ 60 px; regions stack, an evidence margin of ≈ 330 px beside a ≥ 700 px argument column reads as a document, and a chart takes the full measure. | Content relationship | Useful starting structure | Starting geometry | |---|---|---| @@ -164,7 +164,7 @@ Repeating symmetric card grids without a page job is the failure mode these stru | Activation | Only an explicit user motion instruction, an enabled Custom Animations outcome, or an existing `animations.json`; a §IX Motion suggestion alone does not activate it | | Missing state | A deck exported without both states cannot gain the motion by a flag | | Extra page | Adding a page is a §IX roster change and returns to Strategist | -| Endpoint id | Fix the first endpoint's direct-root `` when that page is drawn and record the intended partner id in `notes/total.md`; the next page reuses it, so no endpoint is renamed after both pages exist (a rename reruns the gate) | +| Endpoint id | Fix the first endpoint's direct-root `` when that page is drawn and record the intended partner id with `workflow_log.py` (never in `notes/total.md`, which is read verbatim by TTS); the next page reuses it, so no endpoint is renamed after both pages exist (a rename reruns the gate) | --- @@ -280,7 +280,7 @@ Mechanical repetition comes from reusing one carrier and topology without a page **Checkpoints**: - **Phased generation** (recommended): - 1. **Visual Construction Phase**: generate all pages sequentially, applying every triggered branch while drawing. **MUST embed one object-scoped plot-area marker** per §IX-named or Quick-promoted value-driven chart object ([`executor-chart.md`](./executor-chart.md) §2); calibration follows in [`verify-charts`](../workflows/stages/verify-charts.md). Write every `=yes` native marker plus JSON metadata atomically ([`native-data-interface.md`](./native-data-interface.md) §2) and stamp its baseline before the page's gate — `python3 ${SKILL_DIR}/scripts/stamp_native_fallbacks.py /svg_output/.svg --write`, rerun after any visible edit inside the marker group. **Reach for native presets** per §3.0 as you draw, decided by the object's intent, never by scanning finished paths; several presets for one page go through one `preset_shape_svg.py render-batch --input -` round (gradient/pattern paint stays ordinary SVG; a justified §6.4 shadow/glow stays on the helper-authored shape). + 1. **Visual Construction Phase**: generate all pages sequentially, applying every triggered branch while drawing. **MUST embed one object-scoped plot-area marker** per §IX-named or Quick-promoted value-driven chart object ([`executor-chart.md`](./executor-chart.md) §2); calibration follows in [`verify-charts`](../workflows/stages/verify-charts.md). Write every `=yes` native marker plus JSON metadata atomically ([`native-data-interface.md`](./native-data-interface.md) §2) and stamp its baseline before the page's gate — `python3 ${SKILL_DIR}/scripts/stamp_native_fallbacks.py /svg_output/.svg --write`, rerun after any visible edit inside the marker group, a `compact_svg_styles.py --inplace` rewrite included. **Reach for native presets** per §3.0 as you draw, decided by the object's intent, never by scanning finished paths; several presets for one page go through one `preset_shape_svg.py render-batch --input -` round (gradient/pattern paint stays ordinary SVG; a justified §6.4 shadow/glow stays on the helper-authored shape). 2. **Quality gates**: the gate points and their commands are the route's — [`generate-pptx.md`](../workflows/generate-pptx.md) Step 6 or [`quick-generate.md`](../workflows/profiles/quick-generate.md) §3–4. The repair discipline at every gate is the same: run the checker unfiltered, review the complete issue set, fix every error plus the selected warnings in one consolidated pass, verify once. Never check between individual fixes, never `cat` a passing report, never defer errors past `finalize_svg.py` (it rewrites SVG and masks violations). Every `warning` is advisory. 3. **Logic Construction Phase (conditional)**: after the gates pass, generate speaker notes for narrative continuity only when the effective Speaker Notes outcome is enabled. @@ -293,7 +293,7 @@ Mechanical repetition comes from reusing one carrier and topology without a page | A primary image reduced to a minor frame | Restore its planned share | | Unrelated page jobs collapsing into one neutral construction | Vary the construction by job | - **Absence needs a reason.** Each of these receipt facts needs one written line — what carries that job instead, and why that serves the reader better: a deck-wide `Presets: (none)`; `inline emphasis 0`, `gradients 0`, or `filters 0` on the `Effects:` line; fewer pages carrying a preset or connector than pages whose relationship line (Default: §IX `Relationships`; Quick: the transient relationship statement) names `order` / `link` / `parent` / `membership`; a `Presets:` line naming no carrier-and-field contour. Answer per family the presets serve, not for arrows alone: + **Absence needs a reason.** Each of these receipt facts needs one written line — what carries that job instead, and why that serves the reader better: a deck-wide `Presets: (none)`; `inline emphasis 0`, `gradients 0`, or `filters 0` on the `Effects:` line; fewer pages carrying a preset or connector than pages whose relationship line (Default: §IX `Relationships`; Quick: the transient relationship statement) names `order` / `link` / `parent` / `membership`; a `Presets:` line naming no carrier-and-field contour; `icons: 0` while §VI (Quick: the prepared pool) registered an icon pool. Answer per family the presets serve, not for arrows alone: | Family | Members | |---|---| diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/executor-chart.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/executor-chart.md index 2356aa02..a857428e 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/executor-chart.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/executor-chart.md @@ -69,6 +69,8 @@ After each page containing verified charts: `rg -n "chart-plot-area" /images/illus_sheet.png --grid 2x3 \ --names team,product,customer,growth,risk,vision --trim --alpha \ --bg "${SHEET_KEY_HEX}" --strict-alpha +# Generated sheets arrive through JPEG, so the ground is never exactly the pure +# key: the first run usually fails with a measured border line — rerun with the +# --bg / --tolerance it names (the measured ground, which skips despill). ``` `--names` count equals `rows*cols`; `--strict-alpha` writes nothing on an incomplete cut. Three quality constraints: | Constraint | Rule | |---|---| -| **Strict key recovery** | Measure the smallest channel distance from any element pixel to the key first; raise `--tolerance` only enough to absorb measured flat-field drift and keep it below that distance, `--inset` for an isolated outer gutter or for grid lines the model drew between cells (its most frequent use — trim the gutter, never an element), and regenerate or enlarge when an effect reaches an edge. A `1x1` lettering sheet whose glyph touches the outer key border fails the same gate: pad the sheet with a key-colored border (about 10%) before slicing, or regenerate with more margin | +| **Strict key recovery** | Measure the smallest channel distance from any element pixel to the key first; raise `--tolerance` only enough to absorb measured flat-field drift and keep it below that distance, `--inset` for an isolated outer gutter or for grid lines the model drew between cells (its most frequent use — trim the gutter, never an element; wide lettering bands take `--inset 0.01,0.03` style H,V values so the horizontal line goes without cutting into the glyphs), and regenerate or enlarge when an effect reaches an edge. A `1x1` lettering sheet whose glyph touches the outer key border fails the same gate: pad the sheet with a key-colored border (about 10%) before slicing, or regenerate with more margin | | **Clean isolated cells** | Fused cells, scene backgrounds, or flourishes crossing a cell make the sheet unusable; re-rolls follow only a strict keying failure or user/preview evidence, never taste | | **Enough source pixels** | Each cell at least 1.5–2× its display size (`1K` small accents, `2K` medium, `4K` large or enlarged) | diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/image-layout-spec.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/image-layout-spec.md index 0eb32f09..9c51b400 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/image-layout-spec.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/image-layout-spec.md @@ -39,7 +39,7 @@ x = x0 - ax × overflow_x; y = y0 - ay × overflow_y ### 2.3 Mode selection -**Reference — narrative intent before geometry**: decide whether the image is the page (hero / full-bleed: image fills the canvas or dominant zone, title floats over a gradient or scrim — covers, dividers, breathing pages), a backdrop (atmosphere: low-contrast image behind text), a coequal block (side-by-side: image and text read together — most content pages), or an accent (small image beside related text, no ratio matching); do not default every image page to side-by-side. For side-by-side, the source ratio shapes the item inside its region (§2–§3), not the page split; on portrait canvases (Xiaohongshu, Story) side columns become narrow, so stacked regions usually serve better. +**Reference — narrative intent before geometry**: decide whether the image is the page (hero / full-bleed: image fills the canvas or dominant zone, title floats over a gradient or scrim — covers, dividers, breathing pages), a backdrop (atmosphere: low-contrast image behind text), a coequal block (side-by-side: image and text read together — most content pages), or an accent (small image beside related text, no ratio matching); do not default every image page to side-by-side. For side-by-side, the source ratio shapes the item inside its region (§2–§3), not the page split; on portrait canvases (Xiaohongshu, Story, A4) and on 4:3 (`ppt43`, 256 px narrower than 16:9) side columns become narrow, so stacked regions usually serve better. Complete source, evidence, or edge content → contain; region coverage with a focal-safe crop → fill; complete source plus a detail view → one contain placement plus a separately justified crop; irregular or repeated source windows → the selected region math first, then the owning crop/shape reference. diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/native-data-interface.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/native-data-interface.md index 415157ee..386abef1 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/native-data-interface.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/native-data-interface.md @@ -29,7 +29,7 @@ Both keep the JSON inside the SVG; `native_payloads.json.gz` is for opaque shape **Hard rule — selected-object authoring**: write the marker and JSON for every supported chart and pure text-grid table in the same edit — both are native-ready by default, and an unactivated marker changes no export, so never skip an eligible object. Default reads the key from §IX `Native-ready: =yes|no; …`; Quick assigns the same page-local `kebab-case` key before drawing; the key is the marker group `id` and metadata `name`. A catalog `family/key`, §VII row, numeric content, or another ready object never implies eligibility; `=no` entries and incidental microvisuals stay on the fallback route; a legacy bare `Native-ready: yes|no` maps only to the page's sole eligible object. **MUST — atomic authoring**: one object's visible fallback, `data-pptx-replace-with` marker, and single JSON `` child are one authoring unit written while the data is in context, never deferred to `verify-charts`, the final gate, or export. Then stamp SVG-first objects: ```bash -python3 skills/ppt-master/scripts/stamp_native_fallbacks.py "" --write # read-only without --write; skips JSON-first +python3 ${SKILL_DIR}/scripts/stamp_native_fallbacks.py "" --write # read-only without --write; skips JSON-first ``` The hash is a synchronization receipt, not proof of semantic equivalence; never stamp stale JSON to satisfy validation. diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/native-shape-authoring.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/native-shape-authoring.md index 0080b1b6..6f530509 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/native-shape-authoring.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/native-shape-authoring.md @@ -38,7 +38,7 @@ python3 ${SKILL_DIR}/scripts/shape_boolean_svg.py render \ |---|---| | Mirror/preserve input already owns native-shape metadata | Keep the object and metadata; never reselect its preset | | One exact non-Connector stock contour | Ordinary SVG primitive only when the exporter maps it to that same contour; otherwise `render` and insert the fragment | -| A stock `bentConnector*` / `curvedConnector*` contour expresses a bend or curve with no endpoint attachment | `render --object-kind connector`; an unconnected native Connector | +| A stock `bentConnector*` / `curvedConnector*` contour expresses a bend or curve with no endpoint attachment | `render --object-kind connector`; an unconnected native Connector with no line-end markers (the fragment accepts none), so an arrowed edge stays a `` with a §1.1 marker | | A straight relationship, divider, or leader | ``, with a §1.1 marker only when direction is meaningful | | A boundary that needs no filled surface | The exact form with `fill="none"` and a visible stroke; content stays an independent sibling | | Two or more native contours form the construction without needing one contour | Independent siblings in one semantic group, composed under §2.1 | diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/plan-core.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/plan-core.md index 3fe71525..71c31075 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/plan-core.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/plan-core.md @@ -139,7 +139,7 @@ python3 skills/ppt-master/scripts/visualization_recall.py validate \ / [/ ...] ``` -**Native-ready boundary**: give every independent data chart and pure text-grid table a unique page-local `kebab-case` key and a `=yes|no` native-ready decision — `yes` by default, `no` only when [`native-data-interface.md`](./native-data-interface.md) §2 cannot express the object; qualitative compositions and incidental microvisuals stay unlisted. Default writes §VII and the `Native-ready` map; Quick keeps the key and decision in context. +**Native-ready boundary**: give every independent data chart and pure text-grid table a unique page-local `kebab-case` key and a `=yes|no` native-ready decision — `yes` by default, `no` when [`native-data-interface.md`](./native-data-interface.md) §2 cannot express the object — `yes` presumes the family has a native `type` there (dumbbell, bullet, gantt, heatmap, sankey, and word clouds have none and stay `no`); qualitative compositions and incidental microvisuals stay unlisted. Default writes §VII and the `Native-ready` map; Quick keeps the key and decision in context. --- diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/shared-standards-core.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/shared-standards-core.md index 29d41f52..cefc6cbb 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/shared-standards-core.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/shared-standards-core.md @@ -189,7 +189,7 @@ These forms are needed only when the stated PPT behavior matters: **Hard rule — root groups protect body-text layout**: every visible direct root `` except a compact helper-authored preset atom declares positive root-coordinate `data-pptx-bounds="x y width height"` sized as the intended module zone. On flat pages, maximize ordinary zones within canvas/sibling space without overlap; the checker fails root-group overlap beyond `1px`, warns on module text overflow through `5%` and fails above it, and fails any larger root-`viewBox` text overflow. Bounds do not clip or reflow. A native plate, caption, or label laid over a picture belongs inside that picture's root group, so it takes no separate zone and creates no root-group overlap, and a clipped picture's zone is its visible region; shrinking the picture to free a text zone is not the repair. Structured slots, structural-role groups, and a wholly off-canvas Morph endpoint marked `data-pptx-morph-staging="true"` are overlap-exempt only; thresholds and estimator: [`svg-contract.md`](../scripts/docs/svg-contract.md) §4. -Wrap each logical Slide-local body unit in one descriptive top-level ``; group count follows the page's semantic units, and each group becomes one stable animation target when animation is enabled. Nested implementation groups may remain anonymous, need no bounds, and create no animation step; use them only when internal subunits (icon + title, value + label, repeated rows) are useful to edit — there is no default nesting pattern, depth, or quota. Titles, direct atomic Master/Layout elements, and canvas-level static framing — background images and full-canvas scrim/decoration rectangles — may remain root primitives; on flat pages give such framing a stable `id` plus `data-pptx-role="background"` / `"decoration"` and never add a `` solely to silence an ungrouped-element advisory; a `` that carries the role is still a root group and declares `data-pptx-bounds` — only a root primitive is exempt. +Wrap each logical Slide-local body unit in one descriptive top-level ``; group count follows the page's semantic units, and each group becomes one stable animation target when animation is enabled. Nested implementation groups may remain anonymous, need no bounds, and create no animation step; use them only when internal subunits (icon + title, value + label, repeated rows) are useful to edit — there is no default nesting pattern, depth, or quota. The page title is one top-level `` of its own (an animation and Morph target like any unit); direct atomic Master/Layout elements and canvas-level static framing — background images and full-canvas scrim/decoration rectangles — may remain root primitives; on flat pages give such framing a stable `id` plus `data-pptx-role="background"` / `"decoration"` and never add a `` solely to silence an ungrouped-element advisory; a `` that carries the role is still a root group and declares `data-pptx-bounds` — only a root primitive is exempt. **Structural atoms and slots are excluded automatically.** `data-pptx-layer` and `data-pptx-placeholder` semantics are read first; otherwise explicit `data-pptx-role` values (`background`, `decoration`, `header`, `footer`, `chrome`, `watermark`, `page-number`, `logo`) mark Slide-local static framing (§4.1, [`semantic-svg.md`](semantic-svg.md)). A normal slot group has exactly one direct compatible carrier; several drawing atoms require the explicit composite `object` proxy fallback. Native chart/table carrier groups retain their specialized [`native-data-interface.md`](./native-data-interface.md) contract. diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/strategist-image.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/strategist-image.md index e59cf404..81943078 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/strategist-image.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/strategist-image.md @@ -42,4 +42,4 @@ For specialized or regulated paper-figure subjects keep the prompt depth of [`im **Image pattern** (one non-empty value per placed row, required by the checker): preferred expression in ordinary words, not locked geometry (an id from [`image-layout-patterns.md`](./image-layout-patterns.md) only when already known; Executor loads that catalog); Executor adjusts it freely as a Reference while keeping resource identity, must-use status, crop/content, and explicit constraints (layout-only changes need no upstream rewrite). A useful entry names the job the image does for the content or the page's shapes — the catalog is recall, an uncatalogued technique answers a job equally, plain split and full bleed stay valid, and a `no-crop` or supporting row keeps one concise suggestion. Choose narrative intent before dimensions, then derive `Dimensions` / `Ratio` from the intended region of the confirmed canvas (placement geometry itself is Executor's [`image-layout-spec.md`](./image-layout-spec.md)); a cutout, blurred crop, or desaturated copy requires that prepared asset. -**Crop policy**: `no-crop` whenever cropping could remove required pixels, labels, evidence, identity, or edge content (screenshots, charts, certificates, dense diagrams, logos, product markings are common triggers); otherwise `adaptive` — Executor may use complete display or a focal-safe crop, and the value never commands cropping. Judge `text_policy` per AI row under [`image-generator.md`](./image-generator.md) §5.3; paper figures, schematics, panel comparisons, data-axis graphics, and stable lettering are triggers to reconsider an all-`none` plan. Step 5 dispatches pending `ai` / `slice` rows to Image_Generator and `web` rows to Image_Searcher. +**Crop policy**: `no-crop` whenever cropping could remove required pixels, labels, evidence, identity, or edge content (screenshots, charts, certificates, dense diagrams, logos, product markings are common triggers); otherwise `adaptive` — Executor may use complete display or a focal-safe crop, and the value never commands cropping; artwork that will be clipped into a carrier shape (poster frame, device screen, lightbox, window) is `adaptive`, because `no-crop` forbids `clip-path` and nested-`` crops on every instance. Judge `text_policy` per AI row under [`image-generator.md`](./image-generator.md) §5.3; paper figures, schematics, panel comparisons, data-axis graphics, and stable lettering are triggers to reconsider an all-`none` plan. Step 5 dispatches pending `ai` / `slice` rows to Image_Generator and `web` rows to Image_Searcher. diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/strategist.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/strategist.md index 7f6deb78..f54468c8 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/strategist.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/strategist.md @@ -92,7 +92,7 @@ Seed the six contract fields of [`plan-core.md`](./plan-core.md) §1 as open-pro **Hard rule — top-down direction construction**: author three complete, project-fit solution intents from the confirmed contract and source before touching any catalog basis. The three mode/style/rendering indexes are the only basis selectors. Freeze each direction's exact reference ids from the index summaries, read once only the deduplicated union of those detail files, then write the behaviors. Never force safe / shifted / bold archetypes, glob a catalog, read an unselected sibling, or write bespoke prose as an enum value. -**Direction serialization**: every direction serializes `mode: custom`, `visual_style: custom`, and `image_strategy.rendering: custom`, each with visible non-empty behavior prose. A custom may use catalog material in any way or none; one preset carried unchanged is valid. References record only actual sources, each owning a distinct executable contribution, never a decorative second basis. +**Direction serialization**: every direction serializes `mode: custom`, `visual_style: custom`, and `image_strategy.rendering: custom`, each with visible non-empty behavior prose. A custom may use catalog material in any way or none; one preset carried unchanged is valid; a layer the user or an installed template already fixed to a catalog preset locks that preset id instead of `custom`. References record only actual sources, each owning a distinct executable contribution, never a decorative second basis. **Three plainly different designs**: the three directions differ as designs *before* any field is written. Whichever components a design requires carry the difference; mode, style, rendering, bases, color, type, and icons are each free to coincide. A different name, note, or reference count alone is no difference, and identical projections are not three solutions. Where authoritative truth fixes components, the open ones carry the difference. Where nothing is open, keep the projections identical and state that boundary. diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/svg-effects.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/svg-effects.md index a54b8c9e..2e2a3a35 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/svg-effects.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/svg-effects.md @@ -147,7 +147,11 @@ material, or texture inside editable glyphs, fill the `` (or a non-positional ``) with a registered single-image `` marked `data-pptx-text-image-fill="stretch"` or `"tile"`. It exports as a PowerPoint run picture fill (`stretch` `Native-normalized`; `tile` needs visual review), -not as a general SVG pattern; the text stays editable. +not as a general SVG pattern; the text stays editable. The glyphs are the +only thing showing the image, so the fill must read as one value against the +ground — a near-uniform texture or material, not a scene, gradient, or +anything with its own light and dark regions, which breaks the letterforms +into unreadable patches (a 2026-09-10 cover title was lost this way). ```xml @@ -251,7 +255,11 @@ alone. A clip disables `meet` frame-fit, so match the box to the source ratio or use `slice`; put a §6.4 filter directly on an unclipped image, and for a clipped one on an exact outer `` whose sole visual child is that image — never both on the same ``. A nested `` is only the exact -single-image crop wrapper the crop parser accepts, not a general viewport. +single-image crop wrapper the crop parser accepts, not a general viewport; +its required form (outer `preserveAspectRatio="none"` + `overflow="hidden"` ++ unit-space `viewBox`, child `` at `0 0 1 1`) is in +[`svg-contract.md`](../scripts/docs/svg-contract.md) under "Nested SVG is +picture-crop transport". | Overlay | Construction | Typical stops / alpha | |---|---|---| diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/visual-styles/blueprint.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/visual-styles/blueprint.md index 9872a1b7..13998b69 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/visual-styles/blueprint.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/visual-styles/blueprint.md @@ -31,7 +31,7 @@ Engineering schematic — thin line work on dark blueprint paper, isometric proj ## 5. Paired image-rendering -`blueprint` — lock it so AI imagery shares the schematic line-drawing aesthetic. +`blueprint` — one coherence candidate for AI imagery that shares the schematic line-drawing aesthetic; the resolved rendering decision owns the choice. ## 6. Illustration propensity diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/visual-styles/swiss-minimal.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/visual-styles/swiss-minimal.md index 482cbc27..e6ce2d1f 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/references/visual-styles/swiss-minimal.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/references/visual-styles/swiss-minimal.md @@ -32,7 +32,7 @@ Strict Swiss-grid discipline. Modular grid, sharp geometry, aggressive whitespac ## 5. Paired image-rendering -`minimalist-swiss` — lock it for AI images so illustrations share the grid-austere aesthetic. +`minimalist-swiss` — one coherence candidate for AI images that shares the grid-austere aesthetic; the resolved rendering decision owns the choice. ## 6. Illustration propensity diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/confirm_ui/server.py b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/confirm_ui/server.py index 26680465..48705956 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/confirm_ui/server.py +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/confirm_ui/server.py @@ -44,6 +44,7 @@ import sys import threading import time import urllib.error +import urllib.parse import urllib.request import webbrowser from pathlib import Path @@ -2526,6 +2527,20 @@ def create_app( @app.before_request def _update_activity(): + allowed_hosts = {PUBLIC_HOST, 'localhost', '::1', '[::1]'} + host = request.headers.get('Host', '').lower() + if host.startswith('[') or host.count(':') == 1: + host = re.sub(r':\d+$', '', host) + if host not in allowed_hosts: + return jsonify({'error': 'Forbidden Host header'}), 403 + origin = request.headers.get('Origin') + if origin is not None: + try: + origin_host = urllib.parse.urlsplit(origin).hostname + except ValueError: + origin_host = None + if origin_host not in allowed_hosts: + return jsonify({'error': 'Forbidden Origin header'}), 403 app.config['LAST_REQUEST_TIME'] = time.time() def _exit_with_lock_release(code: int = 0) -> None: diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/conversion.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/conversion.md index 2af14d0e..cd2b29bd 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/conversion.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/conversion.md @@ -621,6 +621,9 @@ Error: PPTX-to-SVG conversion failed: Invalid DrawingML sRGB color structure Convert web pages to Markdown and download images locally by default. Use `--no-images` to retain remote image links without downloading their files. +Pages, images, and redirect targets must be public HTTP(S) hosts with valid +TLS; `--insecure` skips certificate checks, `--allow-private-hosts` admits +intranet and loopback addresses. ```bash python3 scripts/source_to_md/web_to_md.py https://example.com/article diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/image.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/image.md index e03b19e8..6db8f609 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/image.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/image.md @@ -49,6 +49,8 @@ python3 scripts/image_gen.py --list-backends Backends are grouped into Core / Extended / Experimental tiers. Run `python3 scripts/image_gen.py --list-backends` for the current list. +Each backend accepts its own subset of `--aspect_ratio` values; the authority is the `VALID_ASPECT_RATIOS` constant in its `scripts/image_backends/backend_.py`, and `--manifest` rejects an unsupported ratio before any request. Gemini 3.1 image models take `1:1 1:4 1:8 2:3 3:2 3:4 4:1 4:3 4:5 5:4 8:1 9:16 16:9 21:9` (no `3:1`); the `gemini-2.5-flash-image` models take only `1:1 2:3 3:2 3:4 4:3 4:5 5:4 9:16 16:9 21:9` at `1K`. + Backend selection: ```bash @@ -187,7 +189,9 @@ sources are rejected rather than reduced to one frame, while a camera multi-picture JPEG (MPO) contributes its primary frame. Both input and output are bare filenames directly under `images/`; output must -be a new `.png` file. The tool keeps the EXIF-corrected display dimensions, +be a new `.png` file, or a new `.jpg` file when the source is opaque (a +photograph downscaled with `--fit` keeps its weight in check that way; a +source with transparency is refused for `.jpg`). The tool keeps the EXIF-corrected display dimensions, leaves any alpha mask unchanged, and never overwrites the source or an existing derivative. If `images/image_sources.json` contains the source filename, the new record inherits that legal provenance and records `derived_from` plus the diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/narration.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/narration.md index a7ddd6e9..54c00a20 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/narration.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/narration.md @@ -24,7 +24,7 @@ python3 skills/ppt-master/scripts/notes_to_audio.py --provider co - **Outputs**: one `audio/.` per note plus `audio/.srt` on provider-timed paths (edge, ElevenLabs, MiniMax, timestamp-capable CosyVoice); Qwen and explicit `--cosyvoice-audio-only` write audio only. The flat `audio/` directory is the single active set — no provider subdirectories unless the user asks to keep variants. Stale `audio/manifest.json` and `audio/total.srt` are removed before generation; a successful audio-only run also removes same-stem stale SRT; the manifest (provider/model, formats, voice settings, SHA-256 voice fingerprint — no per-slide inventory, hashes, or keys) is published atomically only after the complete roster succeeds. - **Formats**: PowerPoint-reliable audio is `m4a` (AAC), `mp3`, or `wav`; edge defaults to `mp3`; provider `pcm` / `opus` / `flac` output must be transcoded before embedding. - **Edge SRT**: MP3 and page SRT come from the same `edge-tts` stream using `WordBoundary` timing. Sentence-ending punctuation always closes a cue; text over the 20-visible-character default (`--subtitle-max-chars`) splits at commas, semicolons, or colons, then at the nearest word boundary. Adjacent overlap up to 100 ms moves the later cue start to the previous end; larger overlap fails. Each SRT uses a page-local timeline starting at `00:00:00,000` including leading silence. Default concurrency is three slide pairs (`--concurrency 1` for serial troubleshooting); cloud providers stay serial. -- **Provider timing**: MiniMax reads word timing from its synchronous subtitle file; ElevenLabs uses `/with-timestamps` with original-text character alignment; CosyVoice enables HTTP streaming plus `word_timestamp_enabled` and uses the final audio URL and word timing — unsupported model/voice pairs fail without replacing the prior pair unless `--cosyvoice-audio-only` was explicit (model and voice families must match; cloned voices need a supported v3.5/v3/v2 model or a timestamp-supported system voice); Qwen exposes no timing and never gets estimated SRT. Provider-timed paths share punctuation-first, `--subtitle-max-chars`-bounded regrouping, exact-text validation, and rollback-safe pair publication. +- **Provider timing**: MiniMax reads word timing from its synchronous subtitle file (a normalized number such as `42` comes back as one row per spoken syllable sharing one original-text span; the adapter merges rows by that span, never by text alone); ElevenLabs uses `/with-timestamps` with original-text character alignment; CosyVoice enables HTTP streaming plus `word_timestamp_enabled` and uses the final audio URL and word timing — unsupported model/voice pairs fail without replacing the prior pair unless `--cosyvoice-audio-only` was explicit (model and voice families must match; cloned voices need a supported v3.5/v3/v2 model or a timestamp-supported system voice); Qwen exposes no timing and never gets estimated SRT. Provider-timed paths share punctuation-first, `--subtitle-max-chars`-bounded regrouping, exact-text validation, and rollback-safe pair publication. ## `narration_sync.py` diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/native-data.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/native-data.md index 69888ab8..4f0811ff 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/native-data.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/docs/native-data.md @@ -21,20 +21,20 @@ one child `` (attribute `data-pptx-json` is re Every payload carries that exact `schema`. Native tables are rectangular grids: `columns` for the optional header row, `rows` for body rows (shorter rows padded unless `strict_grid: true`; at most 1000 resolved rows and columns); `column_widths` / `row_heights` are finite non-negative relative weights matching the grid with one positive value (`row_heights` counts the header row when `columns` is present) (a row's top and bottom padding shrink to what its resolved height can hold beside the text line, since PowerPoint would otherwise grow the row past the drawn one); `header_rows` is an integer in range; `strict_grid`, `style.band_row`, and `bold` are JSON booleans. Exact repetition may be factored into `defaults.cell` / `defaults.paragraph` / `defaults.run` and kebab-case `cell_styles` selected by `cell_style` (precedence: cell defaults → named style → cell fields; object-valued `padding` merges, everything else replaces; `Page' + b'

Content

', + headers={'Content-Type': 'text/html; charset=utf-8'}, + ) + for unsafe_image in (False, True): + blocked = Mock(url='http://169.254.169.254/secret') + responses = [page, blocked] if unsafe_image else [blocked] + with self.subTest(image=unsafe_image), \ + patch.object(web_to_md, 'curl_requests', None), \ + patch.object(web_to_md.requests, 'get', side_effect=responses), \ + patch.object(web_to_md.os, 'makedirs'), \ + patch('builtins.open') as write, redirect_stdout(io.StringIO()): + result = web_to_md.process_url(PUBLIC_URL, '/unused/result.md') + self.assertFalse(result[0]) + self.assertIn('non-public', result[2]) + write.assert_not_called() + blocked.close.assert_called_once_with() + + +class TlsVerificationTests(unittest.TestCase): + def test_both_http_backends_verify_by_default_and_honor_explicit_opt_out(self) -> None: + for use_curl in (False, True): + for kwargs, expected in (({}, True), ({'verify': False}, False)): + backend = Mock() + backend.get.return_value = Mock(url=PUBLIC_URL) + with self.subTest(curl=use_curl, kwargs=kwargs), \ + patch.object(web_to_md, 'curl_requests', backend if use_curl else None), \ + patch.object(web_to_md.requests, 'get', backend.get): + web_to_md._http_get(PUBLIC_URL, **kwargs) + self.assertIs(backend.get.call_args.kwargs['verify'], expected) + if use_curl: + self.assertEqual(backend.get.call_args.kwargs['impersonate'], web_to_md._CURL_IMPERSONATE) + + def test_pages_and_images_share_the_insecure_config(self) -> None: + response = Mock(url=PUBLIC_URL, content=b'page', headers={'Content-Type': 'text/plain; charset=utf-8'}) + for insecure in (False, True): + with self.subTest(insecure=insecure), patch.dict(web_to_md.CONFIG, insecure=insecure): + with patch.object(web_to_md, '_http_get', return_value=response) as fetch: + web_to_md.fetch_url(PUBLIC_URL) + self.assertIs(fetch.call_args.kwargs['verify'], not insecure) + content = web_to_md.BeautifulSoup('', 'html.parser') + with patch.object(web_to_md, '_http_get', side_effect=web_to_md._UnsafeUrlError('blocked')) as fetch, \ + patch.object(web_to_md.os, 'makedirs'): + with self.assertRaises(web_to_md._UnsafeUrlError): + web_to_md.download_and_rewrite_images(content, PUBLIC_URL, '/unused/images', 'images') + self.assertIs(fetch.call_args.kwargs['verify'], not insecure) + + def test_cli_insecure_is_opt_in_and_warns(self) -> None: + with patch.dict(web_to_md.CONFIG), \ + patch.object(web_to_md, 'process_url', return_value=(True, PUBLIC_URL, None, None)), \ + redirect_stdout(io.StringIO()), redirect_stderr(io.StringIO()) as errors: + self.assertEqual(web_to_md.main([PUBLIC_URL, '--insecure']), 0) + self.assertIs(web_to_md.CONFIG['insecure'], True) + self.assertIn('TLS certificate verification disabled', errors.getvalue()) + self.assertEqual(web_to_md.main([PUBLIC_URL]), 0) + self.assertIs(web_to_md.CONFIG['insecure'], False) + + def test_dispatcher_forwards_insecure_to_web_backend(self) -> None: + args, unknown = source_to_md.build_parser().parse_known_args([PUBLIC_URL, '--insecure']) + with patch.object(source_to_md, 'run_backend', return_value=1) as run: + self.assertEqual(source_to_md.dispatch_single(PUBLIC_URL, 'web', '/unused/result.md', args, unknown), 1) + command, script_name = run.call_args.args + self.assertEqual(script_name, 'web_to_md.py') + self.assertEqual(command.count('--insecure'), 1) diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/text_measure.py b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/text_measure.py index d80e2ab9..13ed505b 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/text_measure.py +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/text_measure.py @@ -44,11 +44,15 @@ _PREFERRED_BREAK_PUNCTUATION = frozenset(',。;:') # visibly short line, so the greedy fill wins. _PREFERRED_BREAK_MIN_FILL = 0.75 _LATIN_TOKEN_CONNECTORS = frozenset("'’._:/+%@#-") +# A unit-like sign glued to a number stays with it: never break "71" | "%". +_NUMBER_SUFFIXES = frozenset("%‰°") _WEIGHTS = ('normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900') _CALIBRATION_CJK_SAMPLE = '天地玄黄宇宙洪荒日月盈昃辰宿列张寒来暑往' _CALIBRATION_LATIN_SAMPLE = 'Clear Slides Make Big Ideas Easy to See.' _CALIBRATION_CAPS_SAMPLE = 'CLEAR SLIDES MAKE BIG IDEAS EASY TO SEE.' _CALIBRATION_DIGITS_SAMPLE = '0123456789' +# A source line: dataset ids, years, brackets and caps mixed into prose. +_CALIBRATION_CITATION_SAMPLE = 'NYC DOE, dataset sgsi-66kk (2018-19 to 2022-23), v2.1' _CORE_CALIBRATION_ROLES = ('body', 'title', 'subtitle', 'annotation') _SLIDE_HEADING_RE = re.compile( r'^#{3,6}[ \t]+Slide[ \t]+([0-9]+|NN)\b.*$', @@ -153,6 +157,9 @@ def _lexical_units(text: str) -> list[str]: ): end += 2 continue + if next_cluster in _NUMBER_SUFFIXES and clusters[end - 1].isdigit(): + end += 1 + continue break prefix = ' ' if pending_space else '' @@ -276,12 +283,16 @@ def text_box( return dict(x=left, y=top, width=width, height=bottom - top, top=top, bottom=bottom) -def _role_argument(value: str) -> tuple[str, str, float]: +def _role_argument(value: str) -> tuple[str, str, float, str]: + weight = 'normal' + parts = value.rsplit(':', 1) + if len(parts) == 2 and parts[1].strip().casefold() in _ROLE_WEIGHTS: + value, weight = parts[0], parts[1].strip().casefold() try: name_and_family, raw_size = value.rsplit(':', 1) name, family = name_and_family.split(':', 1) except ValueError as exc: - raise argparse.ArgumentTypeError('expected NAME:FAMILY:SIZE') from exc + raise argparse.ArgumentTypeError('expected NAME:FAMILY:SIZE[:bold]') from exc name, family = name.strip().casefold(), family.strip() if not name or not family: raise argparse.ArgumentTypeError('expected non-empty NAME and FAMILY') @@ -289,7 +300,10 @@ def _role_argument(value: str) -> tuple[str, str, float]: size = _positive_float(raw_size) except (argparse.ArgumentTypeError, ValueError) as exc: raise argparse.ArgumentTypeError('SIZE must be a positive finite number') from exc - return name, family, size + return name, family, size, weight + + +_ROLE_WEIGHTS = frozenset({'normal', 'bold'}) def _ordered_roles(roles: dict[str, tuple[str, float]]) -> list[tuple[str, str, float]]: @@ -301,6 +315,7 @@ def _ordered_roles(roles: dict[str, tuple[str, float]]) -> list[tuple[str, str, def _roles_from_spec_lock( lock_path: Path, fallbacks: dict[str, str] | None = None, + weights: dict[str, str] | None = None, ) -> dict[str, tuple[str, float]]: lock = parse_spec_lock(lock_path, report_duplicate_fields=True) typography = next( @@ -451,7 +466,9 @@ def _truncate_planned_line(text: str, limit: int = 40) -> str: def _longest_planned_lines( project_path: Path, roles: list[tuple[str, str, float]], + weights: dict[str, str] | None = None, ) -> dict[str, dict[str, object] | None]: + weights = weights or {} candidates = _outline_candidates( project_path / 'design_spec.md', {name for name, _family, _size in roles}, @@ -460,7 +477,10 @@ def _longest_planned_lines( for name, family, size in roles: best: tuple[float, str, str] | None = None for slide, planned_line in candidates[name]: - width = measure_text(planned_line, size=size, family=family) + width = measure_text( + planned_line, size=size, family=family, + weight=weights.get(name, 'normal'), + ) if best is None or width > best[0]: best = (width, slide, planned_line) longest[name] = None if best is None else { @@ -477,28 +497,36 @@ def _calibration_payload( project_path: Path, source: str, include_outline: bool, + weights: dict[str, str] | None = None, ) -> dict[str, object]: + weights = weights or {} longest = ( - _longest_planned_lines(project_path, roles) + _longest_planned_lines(project_path, roles, weights) if include_outline else {name: None for name, _family, _size in roles} ) cjk_length = len(split_project_text_clusters(_CALIBRATION_CJK_SAMPLE)) latin_length = len(split_project_text_clusters(_CALIBRATION_LATIN_SAMPLE)) digits_length = len(split_project_text_clusters(_CALIBRATION_DIGITS_SAMPLE)) + citation_length = len(split_project_text_clusters(_CALIBRATION_CITATION_SAMPLE)) role_rows = {} for name, family, size in roles: - cjk_width = measure_text(_CALIBRATION_CJK_SAMPLE, size=size, family=family) - latin_width = measure_text(_CALIBRATION_LATIN_SAMPLE, size=size, family=family) - caps_width = measure_text(_CALIBRATION_CAPS_SAMPLE, size=size, family=family) - digits_width = measure_text(_CALIBRATION_DIGITS_SAMPLE, size=size, family=family) + weight = weights.get(name, 'normal') + style = dict(size=size, family=family, weight=weight) + cjk_width = measure_text(_CALIBRATION_CJK_SAMPLE, **style) + latin_width = measure_text(_CALIBRATION_LATIN_SAMPLE, **style) + caps_width = measure_text(_CALIBRATION_CAPS_SAMPLE, **style) + digits_width = measure_text(_CALIBRATION_DIGITS_SAMPLE, **style) + citation_width = measure_text(_CALIBRATION_CITATION_SAMPLE, **style) role_rows[name] = { 'family': family, 'size': size, + 'weight': weight, 'cjk_chars_per_100px': round(100.0 * cjk_length / cjk_width, 1), 'latin_chars_per_100px': round(100.0 * latin_length / latin_width, 1), 'caps_chars_per_100px': round(100.0 * latin_length / caps_width, 1), 'digits_chars_per_100px': round(100.0 * digits_length / digits_width, 1), + 'citation_chars_per_100px': round(100.0 * citation_length / citation_width, 1), 'longest_planned_line': longest[name], } return { @@ -533,7 +561,7 @@ def _fallback_notes( def _render_calibration_table(payload: dict[str, object], *, include_outline: bool) -> str: role_rows = payload['roles'] assert isinstance(role_rows, dict) - headers = ['role', 'family', 'size', 'CJK ≈chars/100px', 'Latin ≈chars/100px', 'CAPS ≈chars/100px', 'DIGITS ≈chars/100px'] + headers = ['role', 'family', 'size', 'CJK ≈chars/100px', 'Latin ≈chars/100px', 'CAPS ≈chars/100px', 'DIGITS ≈chars/100px', 'CITE ≈chars/100px'] if include_outline: headers.append('longest planned line (px, slide, text)') lines = [ @@ -551,6 +579,7 @@ def _render_calibration_table(payload: dict[str, object], *, include_outline: bo f'{raw_row["latin_chars_per_100px"]:.1f}', f'{raw_row["caps_chars_per_100px"]:.1f}', f'{raw_row["digits_chars_per_100px"]:.1f}', + f'{raw_row.get("citation_chars_per_100px", 0.0):.1f}', ] if include_outline: planned = raw_row['longest_planned_line'] @@ -573,12 +602,18 @@ def _render_calibration_table(payload: dict[str, object], *, include_outline: bo 'while authoring (an expanded title, a longer label) is re-estimated ' 'with the rates — the outline column does not cover it.' ) + lines.append( + '[NOTE] measure and wrap take one --weight for the whole string: a line ' + 'with a bold run (an inline emphasis lead) is measured piecewise per ' + 'weight and summed, or the bold clause takes its own line.' + ) lines.append( '[NOTE] rates are sample averages measured with the checker\'s ' 'estimator (headroom included); the checker measures each real line ' 'glyph by glyph, so capital-heavy words (WebGPU, GDP), digits (1935, ' '83.2%) and wide letters run wider than the Latin rate — use the CAPS ' - 'rate for acronyms and uppercase, the DIGITS rate for numbers, and keep ' + 'rate for acronyms and uppercase, the DIGITS rate for numbers, the CITE ' + 'rate for source lines (dataset ids, years, brackets), and keep ' 'about 5% below any bounds width.' ) return '\n'.join(lines) + '\n' @@ -595,19 +630,21 @@ def _run_calibrate(args: argparse.Namespace) -> int: lock_path = project_path / 'spec_lock.md' if not lock_path.is_file() and not args.role: print( - 'Calibration requires spec_lock.md or at least one --role NAME:FAMILY:SIZE entry.', + 'Calibration requires spec_lock.md or at least one --role NAME:FAMILY:SIZE[:bold] entry.', file=sys.stderr, ) return 2 try: fallbacks: dict[str, str] = {} + weights: dict[str, str] = {} roles = ( - _roles_from_spec_lock(lock_path, fallbacks) + _roles_from_spec_lock(lock_path, fallbacks, weights) if lock_path.is_file() else {} ) - for name, family, size in args.role: + for name, family, size, weight in args.role: roles[name] = (family, size) + weights[name] = weight fallbacks.pop(name, None) ordered_roles = _ordered_roles(roles) if not ordered_roles: @@ -618,8 +655,17 @@ def _run_calibrate(args: argparse.Namespace) -> int: project_path=project_path, source=source, include_outline=args.outline, + weights=weights, ) payload['notes'] = _fallback_notes(roles, fallbacks) + bold_roles = sorted(name for name, weight in weights.items() if weight == 'bold') + payload['notes'].append( + 'rates for ' + ', '.join(bold_roles) + ' are measured at bold weight' + if bold_roles else + 'every role is measured at normal weight; recalibrate a role ' + 'realized as bold deck-wide with --role NAME:FAMILY:SIZE:bold, ' + 'since bold runs about 7% wider' + ) output_path = project_path / 'validation' / 'text_calibration.json' output_path.parent.mkdir(parents=True, exist_ok=True) if args.role and output_path.is_file(): @@ -695,7 +741,7 @@ def build_parser() -> argparse.ArgumentParser: action='append', type=_role_argument, default=[], - metavar='NAME:FAMILY:SIZE', + metavar='NAME:FAMILY:SIZE[:bold]', help='Typography role to calibrate when spec_lock.md is absent, e.g. ' 'body:"Microsoft YaHei":20; repeatable.', ) diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/tts_backends/backend_minimax.py b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/tts_backends/backend_minimax.py index 46b7dd65..a8f75cba 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/tts_backends/backend_minimax.py +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/tts_backends/backend_minimax.py @@ -63,12 +63,14 @@ def _word_boundaries(raw: object) -> list[dict]: raise RuntimeError("MiniMax subtitle response contains no sentence blocks") boundaries: list[dict] = [] + previous_start = -1 for sentence in raw: if not isinstance(sentence, dict): raise RuntimeError("MiniMax subtitle sentence block is not an object") words = sentence.get("timestamped_words") if not isinstance(words, list) or not words: raise RuntimeError("MiniMax subtitle sentence block contains no word timings") + previous_span = None for item in words: if not isinstance(item, dict): raise RuntimeError("MiniMax subtitle word timing is not an object") @@ -81,8 +83,29 @@ def _word_boundaries(raw: object) -> list[dict]: raise RuntimeError( "MiniMax subtitle response contains an invalid word interval" ) - if boundaries and start < boundaries[-1]["offset"]: + if start < previous_start: raise RuntimeError("MiniMax subtitle words are not in chronological order") + previous_start = start + word_begin, word_end = item.get("word_begin"), item.get("word_end") + span = ( + (word_begin, word_end) + if type(word_begin) is int + and type(word_end) is int + and 0 <= word_begin < word_end + else None + ) + # Normalized numbers can emit one row per spoken syllable, all + # pointing at the same original-text span (e.g. "42" three times). + # The span is the merge key; the text match is a guard — a same-span + # row with a different word falls through and the shared alignment + # check reports it instead of merging it silently. + if span is not None and span == previous_span and boundaries[-1]["text"] == word: + previous = boundaries[-1] + previous["duration"] = max( + previous["duration"], end - previous["offset"] + ) + continue + previous_span = span boundaries.append( { "text": word, diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/workflow_transcript.py b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/workflow_transcript.py index 6fb846d0..2602c2e9 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/workflow_transcript.py +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/scripts/workflow_transcript.py @@ -64,18 +64,22 @@ def _candidate_directory(value: str) -> Path | None: return None try: raw_path = Path(value) + # A long positional string (a paragraph handed to text_measure.py) + # is not a path; stat-ing it raises ENAMETOOLONG on most filesystems. + if any(len(part.encode("utf-8", "surrogateescape")) > 255 for part in raw_path.parts): + return None + if not raw_path.exists() and raw_path.parent == Path("."): + return None + path = raw_path + if not path.is_absolute(): + path = Path.cwd() / path + while not path.exists() and path != path.parent: + path = path.parent + if path.is_file(): + path = path.parent + return path.resolve() except (OSError, ValueError): return None - if not raw_path.exists() and raw_path.parent == Path("."): - return None - path = raw_path - if not path.is_absolute(): - path = Path.cwd() / path - while not path.exists() and path != path.parent: - path = path.parent - if path.is_file(): - path = path.parent - return path.resolve() def _find_project_root(argv: list[str]) -> Path | None: diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/templates/styles/duty-manual/templates/design_spec.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/templates/styles/duty-manual/templates/design_spec.md index dbc7da7b..3f69d758 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/templates/styles/duty-manual/templates/design_spec.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/templates/styles/duty-manual/templates/design_spec.md @@ -1,11 +1,11 @@ --- style_id: duty-manual kind: style -summary: 把散落规则收敛到一条判断主轴上的技术手册方法,暗场栅格、机制先行、每条规则可追回其机制页 -keywords: [技术手册, 暗场栅格, 机制先行, 判断主轴, 线稿图解] +summary: Technical-manual method that gathers scattered rules onto one judgment axis — dark-field grid, mechanism before rule, every rule traceable to its mechanism page. +keywords: [technical-manual, dark-field-grid, mechanism-first, judgment-axis, line-drawing] --- -# 勤务手册 — Style Specification +# Duty Manual — Style Specification > Method and design defaults only. No project communication contract, brand identity, page structure, or SVG prototypes. @@ -13,97 +13,97 @@ keywords: [技术手册, 暗场栅格, 机制先行, 判断主轴, 线稿图解] | Property | Value | |---|---| -| Style Name | 勤务手册 | -| Best Fit | 需要把散落在多份材料里的规则、规范、操作条目收敛到一条可推导主轴上的技术材料、训练课件、作业规范讲解与内部技术分享;受众要能据此在现场自行判断,而不是背条文 | -| Reusable Intent | 标题写成可判断的句子;机制先于规则;每一条规则都能追回它所依据的机制页;读者随时知道自己在主轴的哪个位置 | -| Sources | 从一份已完成的技术分享材料提炼的方法与视觉默认;基底参考 instructional / pyramid(方法)、swiss-minimal / blueprint / dark-tech(视觉)、blueprint / vector-illustration / digital-dashboard(图像) | +| Style Name | Duty Manual (勤务手册) | +| Best Fit | Technical material, training courseware, operating-standard walkthroughs, and internal technical sharing that must gather rules, standards, and procedure items scattered across many documents onto one derivable axis; the audience must be able to judge on site from it rather than recite clauses | +| Reusable Intent | Titles written as judgeable sentences; mechanism before rule; every rule traceable to the mechanism page it rests on; the reader always knows where on the axis they stand | +| Sources | Method and visual defaults distilled from one finished technical-sharing deck; base references instructional / pyramid (method), swiss-minimal / blueprint / dark-tech (visual), blueprint / vector-illustration / digital-dashboard (image) | ## II. Communication Method - **Preferred Mode**: custom - **Mode References**: instructional, pyramid -- **Mode Behavior**: 每一段开头先给判断句结论,再以「分解—展开—应用」三拍讲透机制:先给这一条的定义与代价,再给触发变化的条件,最后落到它所需的配置、器材与动作。全篇维持一条纵轴,任何一页都能回答「现在在哪一级、哪一步」。 -- **Argument Flow**: 先用可外部核验的规模事实确立「为什么值得重讲一次」,再分两段建立认知(对象的客观性质、对象的时间性),第三段给出贯穿全篇的判断主轴,其后各段是这条主轴的展开与保障,末段把规则收回到已讲过的机制。段落之间以「这条机制决定了下一段的顺序」这类因果句衔接,不用「接下来我们看」这类过场语。 -- **Page Message Discipline**: 一页一个可判断的主张,写在标题里;副标题承担该主张的一句话理由;正文只提供支撑这一主张的证据与限制。标题写成判断句而非名词短语——「入水是最后的手段」而不是「入水救援」。 -- **Claim Discipline**: 规则不以条文形式独立出现,必须先有承载它的机制页;引用规则时标出它追回的机制页码。凡是外部事实都写明来源与口径年份;本材料自建的框架、分级或归类要标明是整理而非来源原文。相互冲突的表述并列呈现并说明取舍依据,不静默择一。 +- **Mode Behavior**: Open every section with a judgment-sentence conclusion, then explain the mechanism in three beats — break down, expand, apply: first the item's definition and cost, then the conditions that trigger change, finally the configuration, equipment, and actions it requires. Keep one vertical axis through the whole deck so any page can answer "which level, which step are we at now". +- **Argument Flow**: First establish "why this deserves retelling" with externally verifiable scale facts, then build understanding in two sections (the object's objective nature, the object's behavior over time), then give the judgment axis that runs through the whole deck in the third section; later sections expand and safeguard that axis, and the closing section folds the rules back onto the mechanisms already taught. Link sections with causal sentences such as "this mechanism decides the order of the next section", never with filler transitions like "next let us look at". +- **Page Message Discipline**: One judgeable claim per page, written in the title; the subtitle carries that claim's one-sentence reason; the body supplies only the evidence and limits that support the claim. Write titles as judgment sentences rather than noun phrases — "Entering the water is the last resort", not "In-water rescue". +- **Claim Discipline**: A rule never appears as a free-standing clause; the mechanism page that carries it must come first, and any citation of a rule marks the mechanism page it traces to. Every external fact names its source and reference year; frameworks, gradings, or classifications built for this material are marked as compiled rather than quoted from a source. Conflicting statements are presented side by side with the basis for the choice, never silently resolved. ## III. Page Role Vocabulary | Role | Communication Job | Evidence Obligation | Composition Tendency | |---|---|---|---| -| 冲击开篇 | 用规模事实确立议题值得重讲 | 每个数字带来源与口径年份;不采用无出处的流传数字 | 少量大字号数字占据主区,其余大面积留白,底部一句翻转认知的结论 | -| 段落章节页 | 标出进入哪一段、本段要回答什么 | 列出本段条目但不承诺顺序与页数 | 满版影像压深色蒙版,超大段落编号与判断句并置 | -| 机制页 | 讲透一条机制,使后续规则可被推导 | 因果链完整;给出行动含义而不只是现象 | 图解与文字左右或上下分置,图解占近半幅,文字给判断句与含义 | -| 主轴总览 | 一次性给出贯穿全篇的判断顺序 | 每一级的定义,以及随级递增的两条代价 | 主视觉占半幅,另半幅为分级索引与国际对应框架 | -| 轴上分级页 | 讲清这一级的定义、代价与升级触发 | 适用条件、禁忌、升级触发三者齐全 | 标题旁与页面左缘同时标出当前位置 | -| 技术展开页 | 展开一项具体做法并标明它属于主轴哪一级 | 注意要点与适用范围成对出现 | 图解与要点分置,页面右上以标牌标出所属级别 | -| 清单表页 | 让读者逐项对照 | 每项写出它挡住的风险或支撑的级别,而非只有名称 | 表格占主区,前提项以底色区分,整体形象图置于侧栏 | -| 岗位配置表页 | 说明岗位、人数与职责 | 人数门槛与岗位职责成对出现,门槛写明是成立条件 | 表格加人数徽记,关键岗位以文字色强调 | -| 程序序列页 | 给出不可调换的步骤顺序 | 每步的核心动作与它为何不能后置 | 序列纵向排列,实景影像锚定其中一步 | -| 反例页 | 指认一个越出主轴的常见做法并拆解其失败机制 | 至少两条机制加一次对前文数据的回指,并给出替代做法 | 单一主视觉压禁止标记,左缘指示条整体转为警示色 | -| 收束规范页 | 把规则收回到已讲过的机制 | 每条规则可追回其机制页;标出反复回到的那几条 | 多列密排,回指项以强调色标出 | +| Impact opener | Establish with scale facts that the topic deserves retelling | Every number carries a source and reference year; no unsourced folklore figures | A few large-size numbers occupy the main zone with generous white space elsewhere; one perception-flipping conclusion at the bottom | +| Section divider | Mark which section begins and what it answers | List the section's items without promising order or page count | Full-bleed image under a dark scrim; an oversized section number beside the judgment sentence | +| Mechanism page | Explain one mechanism fully so later rules can be derived | Complete causal chain; state the implication for action, not only the phenomenon | Diagram and text split left/right or top/bottom, the diagram near half the page, the text giving the judgment sentence and its implication | +| Axis overview | Give the judgment order that runs through the deck in one view | Each level's definition plus the two costs that rise with level | Main visual on one half; on the other half the level index and the corresponding international framework | +| Level page | Explain one level's definition, cost, and escalation trigger | Applicability, contraindications, and escalation trigger all present | Current position marked both beside the title and on the page's left edge | +| Technique page | Expand one concrete practice and mark which axis level it belongs to | Cautions and scope of application appear as a pair | Diagram and key points split; a plate at the top right names the level | +| Checklist table page | Let the reader verify item by item | Each item states the risk it blocks or the level it supports, not only its name | Table in the main zone, prerequisite rows tinted, an overall image in the side column | +| Staffing table page | State posts, headcount, and responsibilities | Headcount thresholds and post duties appear as pairs; thresholds are stated as conditions of validity | Table with headcount badges; key posts emphasized through text color | +| Procedure sequence page | Give a step order that cannot be reshuffled | Each step's core action and why it cannot come later | Steps stacked vertically, a real photograph anchoring one of them | +| Counterexample page | Name one common practice that leaves the axis and dissect why it fails | At least two mechanisms plus one callback to earlier data, with the replacement practice | A single main visual under a prohibition mark; the left-edge indicator bar turns wholly to the warning color | +| Closing standards page | Fold the rules back onto the mechanisms already taught | Every rule traces to its mechanism page; the few mechanisms returned to repeatedly are marked | Dense multi-column layout, callback items in the emphasis color | ## IV. Evidence & Data Expression -- **Argument Trace**: 规范条目页与机制页之间保持双向可追:机制页在页脚写出它支撑哪条规则,规范页在条目旁标出它追回的机制页码。读者可以从任一端走到另一端。 -- **Charts**: 量级差异悬殊的序列不要压进同一坐标轴——把可比的序列画进图,把量级远大的那一项拆成独立数值块并注明倍数关系,信息不丢而图仍可读。数据点按刻度精确计算,不目测。非线性关系在标题里直接说出结论(「翻一倍,翻四倍」)。 -- **Tables**: 用横向行线而非满格线;表头以底色与字重区分,关键行用文字色而非底色强调,避免与表头混淆。数值右对齐、单位一致。深色底材料的原生表格必须显式声明单元格底色,否则导出后会变成白底浅字。 -- **Sources**: 数据页页脚写来源名与口径年份;同一指标存在多个口径时并列写出并说明采用哪一个。流传广但查无出处的数字宁可不用,并在备注里说明为何不用。 -- **Native Editability**: 清单、岗位配置、对照矩阵这类会被下游修改的表格优先做成原生可编辑对象;纯装饰性的微型图示不必如此。数据对象的可见回退与元数据同时书写,保持一致。 +- **Argument Trace**: Keep standards pages and mechanism pages traceable both ways: a mechanism page's footer names the rule it supports, and a standards page marks the mechanism page each item traces to. The reader can walk from either end to the other. +- **Charts**: Never force series of wildly different magnitude onto one axis — chart the comparable series, pull the far larger item into a separate numeric block with its multiple stated, so nothing is lost and the chart stays readable. Compute data points exactly from the scale, never by eye. State the conclusion of a non-linear relationship directly in the title ("double it, and it quadruples"). +- **Tables**: Horizontal row rules rather than full grids; distinguish the header by fill and weight, emphasize key rows through text color rather than fill so they are not confused with the header. Right-align numbers and keep units consistent. A native table on a dark deck must declare its cell fills explicitly, or it exports as light text on a white ground. +- **Sources**: Data pages carry the source name and reference year in the footer; when one indicator has several definitions, list them together and say which is used. A widely circulated figure with no traceable source is left out, with a note explaining why. +- **Native Editability**: Tables that downstream readers will edit — checklists, staffing tables, comparison matrices — are native editable objects first; purely decorative micro-diagrams need not be. Write a data object's visible fallback and its metadata together and keep them consistent. ## V. Visual System Defaults - **Preferred Visual Style**: custom - **Visual Style References**: swiss-minimal, blueprint, dark-tech -- **Visual Style Behavior**: 暗场上的严格栅格手册。swiss-minimal 负责基准栏、左对齐硬边与大留白;blueprint 负责发丝网格、引出线标注与技术剖面式的图解排版;dark-tech 负责暗场上的荧光强调与几何精度。容器一律细描边直角方框,圆角为零,不用投影与柔光。页面左缘固定一条分段进度指示条,当前段以强调色点亮,越界内容整条转为警示色。 -- **Composition**: 内容区以左上起手:左缘指示条先回答「现在在哪」,标题横贯上部给出判断句,证据与图解向右下展开,页面底部收一句可执行结论。图文分置在相邻页之间左右交替,形成阅读节奏。 -- **Density**: 机制页与表格页密排,段落章节页与反例页留白;每一段之内至少有一页明显低密度,作为呼吸。密度服从信息重量,不为填满版面而增加条目。 -- **Decoration**: 装饰即标注——发丝网格、引出线、刻度、指示条本身就是信息载体。不使用与信息无关的图形点缀、渐变色块与柔光。 -- **Color Behavior**: 大面积暗场底,结构线与次级标题用一个冷色,两个强调色分工固定——一个承担关键量与正确做法,另一个承担危险、禁止与最高风险级,两者不互换、不并用于同一语义。强调色只出现在关键数字与结论词上,不铺面。 -- **Typography Character**: 中性无衬线承担全部结构文本,让判断句本身产生力度;数字与级别标记用一款极重的无衬线取得重量对比;表格与图表数值用等线字保证数字对齐。标题不使用装饰字体与文字特效。 +- **Visual Style Behavior**: A strict-grid manual on a dark field. swiss-minimal owns the baseline columns, hard left-aligned edges, and generous space; blueprint owns the hairline grid, leader-line callouts, and cross-section-style diagram layout; dark-tech owns the fluorescent emphasis and geometric precision on the dark ground. Containers are hairline-stroked square boxes with zero corner radius and no drop shadow or glow. A section progress indicator bar sits fixed on the page's left edge, the current section lit in the emphasis color; on off-axis content the whole bar turns to the warning color. +- **Composition**: The content zone starts at the top left: the left-edge indicator answers "where are we" first, the title runs across the top with the judgment sentence, evidence and diagrams unfold toward the bottom right, and the page closes with one actionable conclusion at the bottom. Image and text swap sides between adjacent pages to give the reading a rhythm. +- **Density**: Mechanism and table pages are dense; section dividers and counterexample pages breathe; every section holds at least one visibly low-density page as a rest. Density follows information weight; never add items to fill a page. +- **Decoration**: Decoration is annotation — the hairline grid, leader lines, tick marks, and the indicator bar are themselves information carriers. No ornament unrelated to the information, no gradient blocks, no soft glow. +- **Color Behavior**: A large dark-field ground; structure lines and secondary headings in one cool color; two accents with a fixed division of labor — one carries key quantities and correct practice, the other carries danger, prohibition, and the highest risk level — never swapped and never used together for one meaning. Accents appear only on key numbers and conclusion words, never as fills across areas. +- **Typography Character**: A neutral sans-serif carries all structural text so the judgment sentences supply the force themselves; numbers and level marks use one very heavy sans-serif for weight contrast; table and chart values use a monospaced-figure face so digits align. Titles use no display faces and no text effects. ### Fallback Color Scheme | Role | HEX | Purpose | |---|---|---| -| background | #0E1B2E | 全篇暗场底 | -| secondary_bg | #1A2C46 | 面板、表头、图解衬底 | -| primary | #4A9FD8 | 结构线、次级标题、图表主序列 | -| accent | #D8F04A | 关键量、当前级别、正确做法 | -| secondary_accent | #E85D2B | 危险、禁止、最高风险级 | -| body_text | #DCE6F0 | 正文与主要标签 | -| secondary_text | #8FA3BC | 图注、脚注、来源行 | -| divider | #2A3F5C | 分隔线与容器描边 | +| background | #0E1B2E | Dark field across the deck | +| secondary_bg | #1A2C46 | Panels, table headers, diagram backing | +| primary | #4A9FD8 | Structure lines, secondary headings, main chart series | +| accent | #D8F04A | Key quantities, current level, correct practice | +| secondary_accent | #E85D2B | Danger, prohibition, highest risk level | +| body_text | #DCE6F0 | Body text and main labels | +| secondary_text | #8FA3BC | Captions, footnotes, source lines | +| divider | #2A3F5C | Rules and container strokes | ### Fallback Typography | Role | Primary | Fallback Tail | Character | |---|---|---|---| -| title | Microsoft YaHei | Arial, sans-serif | 中性无衬线,方正精确,由判断句本身承担力度 | -| body | Microsoft YaHei | Arial, sans-serif | 与标题同族,长段机制说明不疲劳 | -| display | Arial Black | sans-serif | 极重无衬线,承担段落编号、级别标记与冲击数字 | -| data | Arial | Microsoft YaHei, sans-serif | 等线数字,表格与图表内数值等宽等高 | +| title | Microsoft YaHei | Arial, sans-serif | Neutral sans-serif, square and precise; the judgment sentence carries the force | +| body | Microsoft YaHei | Arial, sans-serif | Same family as the title; long mechanism passages read without fatigue | +| display | Arial Black | sans-serif | Very heavy sans-serif for section numbers, level marks, and impact numbers | +| data | Arial | Microsoft YaHei, sans-serif | Lining figures; table and chart values align in width and height | -供给的 Brand 或 Deck 身份会整体替换以上兜底配色与字体,方法与版面规则不受影响。 +A supplied Brand or Deck identity replaces this fallback palette and typography wholesale; the method and layout rules are unaffected. ## VI. Image & Icon Direction - **Preferred Image Rendering**: custom - **Image Rendering References**: blueprint, vector-illustration, digital-dashboard -- **Image Rendering Behavior**: 实底上的等宽白线技术线稿。blueprint 负责单线、引出线与剖面式取景;vector-illustration 负责干净的平面主体与无渐变填色;digital-dashboard 负责荧光标注色与刻度式数值呈现。主体以均匀细线勾勒不作填色,流动以平行流线与箭头表示,只用两个强调色分别承担关键量与危险,无渐变、无阴影、无景深、图内无文字。 -- **Image Usage**: 机制类页面由线稿图解承担机制本身,实景影像承担证据与场景锚定,两者不互相替代——讲清原理用图解,证明确有其事用实拍。段落章节页用满版实景压蒙版建立段落边界。 -- **Image Treatment**: 实景一律硬边直角嵌入,不做羽化、圆形裁切与倾斜;需要文字压在影像上时用方向性蒙版而非整幅均匀压暗。同一批线稿图解保持同一渲染,新增图必须能与既有图并排而看不出批次差异——这条优先于单张图的表现力。 -- **Icon Treatment**: 细线描边图标,与线稿图解同族;只用于分类与状态提示,不承担机制解释;投影与打印场景线宽不低于 2。 +- **Image Rendering Behavior**: Uniform-weight white technical line drawings on a solid ground. blueprint owns the single line, leader lines, and cross-section framing; vector-illustration owns clean flat subjects and gradient-free fills; digital-dashboard owns the fluorescent annotation colors and scale-style numeric display. Subjects are outlined in even thin lines without fill, flow is shown with parallel streamlines and arrows, only the two accents are used — one for key quantities, one for danger — with no gradient, no shadow, no depth of field, and no text inside the image. +- **Image Usage**: Mechanism pages carry the mechanism through line diagrams; real photographs carry evidence and scene anchoring; neither replaces the other — explain a principle with a diagram, prove it happened with a photograph. Section dividers use a full-bleed photograph under a scrim to set the section boundary. +- **Image Treatment**: Photographs are always inset hard-edged and square-cornered, never feathered, circle-cropped, or tilted; where text must sit over an image use a directional scrim rather than dimming the whole frame evenly. One batch of line diagrams keeps one rendering; a new diagram must sit beside the existing ones without a visible batch difference — this outranks the expressiveness of any single image. +- **Icon Treatment**: Thin-stroke icons of the same family as the line diagrams; used only for category and status cues, never to explain a mechanism; stroke width no thinner than 2 for projection and print. ## VII. Review Focus > Apply only after the user explicitly activates visual review. It never triggers that stage. -- 标题是否为可判断的句子,而不是名词短语 -- 每条规则条目是否能追回它所依据的机制页 -- 左缘进度指示条的当前位置是否与页面内容一致,越界内容是否已转为警示色 -- 两个强调色的语义分工是否被守住,是否出现互换或同页混用 -- 深色底的原生表格是否显式声明了单元格底色 -- 量级悬殊的数据是否被压进同一坐标轴而导致小量级序列不可读 -- 新增线稿图解与既有图解并排时是否存在批次差异 +- Titles are judgeable sentences rather than noun phrases +- Every rule item traces back to the mechanism page it rests on +- The left-edge progress indicator's current position matches the page content, and off-axis content has turned it to the warning color +- The two accents keep their semantic division, with no swap and no mixing on one page +- Native tables on the dark ground declare their cell fills explicitly +- Data of very different magnitude is not forced onto one axis so that the small series becomes unreadable +- A new line diagram placed beside the existing ones shows no batch difference diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/templates/styles/styles_index.json b/plugins/codex/plugins/ppt-master/skills/ppt-master/templates/styles/styles_index.json index 4033c9d8..8b89985b 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/templates/styles/styles_index.json +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/templates/styles/styles_index.json @@ -30,13 +30,13 @@ ] }, "duty-manual": { - "summary": "把散落规则收敛到一条判断主轴上的技术手册方法,暗场栅格、机制先行、每条规则可追回其机制页", + "summary": "Technical-manual method that gathers scattered rules onto one judgment axis — dark-field grid, mechanism before rule, every rule traceable to its mechanism page.", "keywords": [ - "技术手册", - "暗场栅格", - "机制先行", - "判断主轴", - "线稿图解" + "technical-manual", + "dark-field-grid", + "mechanism-first", + "judgment-axis", + "line-drawing" ] }, "incident-postmortem": { diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/generate-pptx.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/generate-pptx.md index 8fac863a..62716341 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/generate-pptx.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/generate-pptx.md @@ -63,7 +63,7 @@ python3 ${SKILL_DIR}/scripts/project_manager.py import-sources /validation/workflow.log`; later project-scoped Python tools record their command envelopes there automatically (prefix `PPT_MASTER_PROJECT_PATH=""` when a helper's arguments do not identify the project). Append one concise note with `python3 ${SKILL_DIR}/scripts/workflow_log.py ""` only for a material handoff, rework reason, approved exception, or manual recovery with no owning command output. The log is cold audit evidence, never read during generation. -**Import rules**: pass the source path once when Step 1 wrote Markdown beside it, both locations when `-o` wrote it elsewhere, and only the research pair when Topic Research ran (its facts JSON is imported as a file; no URL is fetched). Copy/move semantics, bitmap archiving, and the PPTX intake bundle it writes under `analysis/` (`.identity.json`, `.slide_library.json`, `source_profile.json`) are [`project.md`](../scripts/docs/project.md). Those artifacts are source facts and recommendation candidates, not replica constraints; Beautify stays single-deck. +**Import rules**: pass the source path together with the Markdown Step 1 wrote beside it (a same-stem Markdown suppresses re-conversion and is imported with its sidecar and assets; the source alone is archived and converted again), both locations when `-o` wrote it elsewhere, and only the research pair when Topic Research ran (its facts JSON is imported as a file; no URL is fetched). Copy/move semantics, bitmap archiving, and the PPTX intake bundle it writes under `analysis/` (`.identity.json`, `.slide_library.json`, `source_profile.json`) are [`project.md`](../scripts/docs/project.md). Those artifacts are source facts and recommendation candidates, not replica constraints; Beautify stays single-deck. **✅ Checkpoint** — project created, `sources/` complete, converted materials ready. `import-sources` exits 0 when any input converts: read the printed `skipped` reasons and treat those inputs as absent. Proceed to Step 3. @@ -196,7 +196,7 @@ Read ${SKILL_DIR}/references/image-base.md # always | Row | Additional reference | Run | |---|---|---| | Prepared derivative | `image-generator.md` §4.4 only for registered layers | after its canonical source is terminal: `python3 ${SKILL_DIR}/scripts/image_treat.py ...` for blur, desaturation/grayscale, duotone, brightness, contrast, or `--fit WxH` downscaling to the planned size, or the §4.4 preparation path | -| `ai` | `image-generator.md` | write `images/image_prompts.json`, render `image_prompts.md` with `image_gen.py --render-md`, then follow §7 Path Selection — `image_gen.py --manifest` is Path A only, `host-native` is Path B and skips `--manifest`, `manual` writes prompts and stops; the recorded `design_spec.md §I` path wins over `IMAGE_BACKEND` | +| `ai` | `image-generator.md` | write `images/image_prompts.json`, render `image_prompts.md` with `image_gen.py --render-md images/image_prompts.json`, then follow §7 Path Selection — `image_gen.py --manifest` is Path A only, `host-native` is Path B and skips `--manifest`, `manual` writes prompts and stops; the recorded `design_spec.md §I` path wins over `IMAGE_BACKEND` | | `web` | `image-searcher.md` | `python3 ${SKILL_DIR}/scripts/image_search.py ...`; with ≥2 rows write `images/image_queries.json` and run `--batch` once | | `slice` | `image-generator.md` §4.3 | after the parent sheet is `Generated`: `python3 ${SKILL_DIR}/scripts/slice_images.py /images/.png --grid RxC --names ... --trim --alpha --bg KEY_HEX_FROM_PROMPT --strict-alpha` | | `user` / `placeholder` | — | skip | @@ -259,7 +259,7 @@ Read the core as one batch with the exact detail files named by the retained `sp python3 ${SKILL_DIR}/scripts/svg_editor/server.py --live --daemon ``` -Default first free port from `6060` (`--port N` binds strictly); read the URL from output or `/live_preview/lock.json` and report it — or the launch failure — before the first SVG. It is a side process: never wait for it or for user confirmation, and keep it running until the user clicks **Exit preview** or asks in chat. Do not read or apply submitted annotations during generation; that window opens after Step 7 ([`live-preview.md`](stages/live-preview.md), which also describes staged direct edits). +Default first free port from `6060` (`--port N` binds strictly); read the URL from output or `/live_preview/lock.json` and report it — or the launch failure, or that the user or run instructions forbade starting it — before the first SVG. It is a side process: never wait for it or for user confirmation, and keep it running until the user clicks **Exit preview** or asks in chat. Do not read or apply submitted annotations during generation; that window opens after Step 7 ([`live-preview.md`](stages/live-preview.md), which also describes staged direct edits). **Cadence (Mandatory)**: P01–P05 → early gate (a planned roster of six or fewer pages skips it) → remaining pages → final gate, in one context. Every checker invocation follows one of two events: a gate point whose covered pages all exist, or the end of one consolidated repair pass. A run with neither predecessor is a pacing violation; validating an authoring pattern early is not a reason, because the same issues surface at the gate and are fixed in the same pass. Reload under Context validity above after context invalidation. @@ -279,7 +279,7 @@ python3 ${SKILL_DIR}/scripts/svg_quality_checker.py \ --canonical-authoring --stage early --json ``` -`--json` writes the report file (`validation/svg_quality_early_report.json`); stdout stays the human-readable summary and is never parsed as JSON. The stage checks every authored page so far under the partial-roster rules. Repair under the consolidated-pass discipline in [`executor-base.md`](../references/executor-base.md) §3; a still-failing verification is the next batch. If terminal output is truncated, read only the issue arrays from `validation/svg_quality_early_report.json`. The gate validates the method, not just the pages — emit one line before editing: +`--json` writes the report file (`validation/svg_quality_early_report.json`); stdout stays the human-readable summary and is never parsed as JSON. The stage checks every authored page so far under the partial-roster rules. Repair under the consolidated-pass discipline in [`executor-base.md`](../references/executor-base.md) §3; a still-failing verification is the next batch. If terminal output is truncated, extract only `categories.blocking.issues` (and `categories.introduced.issues` when needed) from `validation/svg_quality_early_report.json`. The gate validates the method, not just the pages — emit one line before editing (in the conversation, not to a file): ``` gate-signal: method= | page-local= | not-exercised= diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/apply-template-workspace.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/apply-template-workspace.md index ca244b09..4b846a49 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/apply-template-workspace.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/apply-template-workspace.md @@ -44,7 +44,7 @@ Read [`templates/README.md`](../../templates/README.md), then only the README fo A Layout created with `mirror` stays eligible only when its source is brand-neutral and application-neutral; keep a branded or application-bearing source as a Deck or re-author it through `standard` / `fidelity`. Before mapping any workspace, run the shared package validator from its root — Brand/Style are roster-free, the active structure validates its roster, a shadowed Deck still validates its contract; any error blocks installation: ```bash -python3 skills/ppt-master/scripts/svg_quality_checker.py "/templates" --template-mode --canonical-authoring +python3 ${SKILL_DIR}/scripts/svg_quality_checker.py "/templates" --template-mode --canonical-authoring ``` ## 3. Structured Preflight @@ -71,7 +71,7 @@ Validate each normalized root once. The effective structural owner is Layout whe **Command**: the mapping, provenance line, asset copy, collision and duplicate-kind refusal, and completion receipt below are one run of the install tool (add `--dry-run` to review the mapping first; `--skip-validation` only when the §2 checker already ran on that root in this turn); [`template-tools.md`](../../scripts/docs/template-tools.md#apply_templatepy) owns its behavior: ```bash -python3 skills/ppt-master/scripts/apply_template.py --root [--root ...] +python3 ${SKILL_DIR}/scripts/apply_template.py --root [--root ...] ``` **Atomic install preflight**: resolve every source and destination path; enumerate the union mapping across all roots and across `templates/`, `images/`, `icons/`, mapping each source file at most once; resolve Layout-over-Deck precedence before building the map so the shadowed roster never enters it; reject every destination collision and duplicate kind before writing; write the accepted mapping once — never recursive copy as an implicit conflict policy. An input equal to the target project is consumed in place; if a selected Layout supersedes its in-place Deck roster, stage the mapping and replace the roster atomically. diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/customize-animations.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/customize-animations.md index a3ba148d..52fb067a 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/customize-animations.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/customize-animations.md @@ -38,7 +38,7 @@ Before editing `animations.json`, read every semantic file that exists — `desi | Sidecar with no new instruction | Validate and preserve unchanged; repair an invalid sidecar/group reference before export | | Ambiguous request | Default asks regenerate-or-modify; Quick decides from the request, SVG, and sidecar | -Unless an all-motion disable bypasses it, validate an existing sidecar first: `python3 skills/ppt-master/scripts/animation_config.py validate `. +Unless an all-motion disable bypasses it, validate an existing sidecar first: `python3 ${SKILL_DIR}/scripts/animation_config.py validate `. **Hard rule**: semantic files determine motion intent and unit boundaries; the current `svg_output/*.svg` supplies visible content and implementation structure, and its existing `` hierarchy is never accepted as the plan merely because it exists. @@ -103,13 +103,13 @@ Only after visual transition, lifecycle, effect, order, and timing are complete, ## 5. Validate and Return to Generate Export -When `animations.json` was created or changed after §1, run `python3 skills/ppt-master/scripts/animation_config.py validate `, then return to the owning export path — Default [`generate-pptx.md`](../generate-pptx.md) Step 7.1; Quick [`quick-generate.md`](../profiles/quick-generate.md) §4 — both of which read the sidecar automatically. If §2 changed `svg_output/`, complete the owning route's final SVG rerun before returning; never finalize or export from this stage. +When `animations.json` was created or changed after §1, run `python3 ${SKILL_DIR}/scripts/animation_config.py validate `, then return to the owning export path — Default [`generate-pptx.md`](../generate-pptx.md) Step 7.1; Quick [`quick-generate.md`](../profiles/quick-generate.md) §4 — both of which read the sidecar automatically. If §2 changed `svg_output/`, complete the owning route's final SVG rerun before returning; never finalize or export from this stage. **Validation**: every invalid field, target, or Morph pair fails rather than falling back ([`pptx-animations.md`](../../scripts/docs/pptx-animations.md) §6). A passing sidecar and read-back prove the PPTX configuration, not an exported MP4 audio track. ### 5.1 Optional Video Motion Handoff -When a downstream renderer will enhance the deck, have Step 7.3 append `--conversion-trace`, then derive the plan from the final resolved trace (the `--recorded-narration` trace for narrated output): `python3 skills/ppt-master/scripts/video_motion_plan.py /validation/.trace.json -o /validation/video_motion_plan.json --style adaptive --force`. The plan locks identity, effect, direction, order, bounds, and timing and may refine renderer parameters only ([`video-motion-plan.md`](../../scripts/docs/video-motion-plan.md)). With resolved sound cues on the native-export branch, the same final trace and narrated PPTX feed `video_sound_mix.py`; an explicit slideshow capture records native cue playback and uses no trace for mixing. +When a downstream renderer will enhance the deck, have Step 7.3 append `--conversion-trace`, then derive the plan from the final resolved trace (the `--recorded-narration` trace for narrated output): `python3 ${SKILL_DIR}/scripts/video_motion_plan.py /validation/.trace.json -o /validation/video_motion_plan.json --style adaptive --force`. The plan locks identity, effect, direction, order, bounds, and timing and may refine renderer parameters only ([`video-motion-plan.md`](../../scripts/docs/video-motion-plan.md)). With resolved sound cues on the native-export branch, the same final trace and narrated PPTX feed `video_sound_mix.py`; an explicit slideshow capture records native cue playback and uses no trace for mixing. --- diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/topic-research.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/topic-research.md index 307cdaca..4b998279 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/topic-research.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/topic-research.md @@ -49,9 +49,9 @@ Default bundles only genuinely missing scope or research-boundary decisions into ## Step 2: Gather factual sources -Use the search and fetch tools available in the research context; an isolated worker without them returns `blocked: web-tools-unavailable`. With no usable search/fetch context, pause and ask the user for authoritative URLs covering the gaps, then fetch each with `web_to_md.py -o projects/_web_sources/.md --no-images` (remote image links stay in the Markdown; nothing is downloaded). +Use the search and fetch tools available in the research context; an isolated worker without them returns `blocked: web-tools-unavailable`. With no usable search/fetch context, pause and ask the user for authoritative URLs covering the gaps, then fetch each with `python3 ${SKILL_DIR}/scripts/source_to_md/web_to_md.py -o projects/_web_sources/.md --no-images` (remote image links stay in the Markdown; nothing is downloaded). -Orient (map authoritative sources to the gaps) → deep fetch (read the highest-signal primary pages in full) → targeted fill (search only for gaps still unsupported). Prefer primary sources, official sites, institutional releases, standards, and original research; then authoritative reference works and academic sources; then reputable reporting; avoid unsourced reposts, unverifiable summaries, and stock-aggregator pages. +Orient (map authoritative sources to the gaps) → deep fetch (read the highest-signal primary pages in full) → targeted fill (search only for gaps still unsupported). Prefer primary sources (an encyclopedia page is a pointer — chase its claim one level to the source it cites and record that source), official sites, institutional releases, standards, and original research; then authoritative reference works and academic sources; then reputable reporting; avoid unsourced reposts, unverifiable summaries, and stock-aggregator pages. **Adopted webpage boundary**: record a URL only in the matching fact's `source_url`, and only when it materially supports that fact — never because its images may be useful, and never from unopened search results or a separate image-search pass. Stop when every declared gap has enough sourced evidence for the content owner to decide inclusion; do not add overview/history/outlook sections to look complete. @@ -92,7 +92,7 @@ python3 ${SKILL_DIR}/scripts/project_manager.py import-sources projects/" -o /sources/.md`, review the companion `_files/` package, and copy only accepted images into `/images/` — never pass the URL to `import-sources`, which would promote every companion image into the pool. Fetch another page only after the current package has no usable image; without vision, retain `Needs-Manual`. +**Single-page image fallback**: only after normal web-image providers, ranked thumbnail pages, and materially different queries fail may an image owner with visual capability select one relevant `source_url` from the facts JSON and fetch that one page package with `python3 ${SKILL_DIR}/scripts/source_to_md/web_to_md.py "" -o /sources/.md`, review the companion `_files/` package, and copy only accepted images into `/images/` — never pass the URL to `import-sources`, which would promote every companion image into the pool. Fetch another page only after the current package has no usable image; without vision, retain `Needs-Manual`. ```markdown ## ✅ Topic Research Complete diff --git a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/verify-charts.md b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/verify-charts.md index 4ec1ca41..054de09e 100644 --- a/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/verify-charts.md +++ b/plugins/codex/plugins/ppt-master/skills/ppt-master/workflows/stages/verify-charts.md @@ -55,13 +55,13 @@ If the list is empty, output `verify-charts: active profile declares no data-dri 5. Run the matching command (see the [calculator documentation](../../scripts/docs/svg-pipeline.md#svg_position_calculatorpy) and recipes for decomposable, partial, formula, and manual modes): ```bash - python3 skills/ppt-master/scripts/svg_position_calculator.py calc bar --data "L1:V1,L2:V2" --area "x_min,y_min,x_max,y_max" --bar-width 120 --value-range=0,axis_max + python3 skills/ppt-master/scripts/svg_position_calculator.py calc bar --data "L1:V1,L2:V2" --area "x_min,y_min,x_max,y_max" --bar-width 120 --value-range=0,axis_max # a Native-ready bar/column passes --gap-width instead of --bar-width so the category axis follows the PowerPoint slot model the parity gate checks python3 skills/ppt-master/scripts/svg_position_calculator.py calc line --data "x1:y1,x2:y2" --area "x_min,y_min,x_max,y_max" --y-range=0,max python3 skills/ppt-master/scripts/svg_position_calculator.py calc pie --data "S1:V1,S2:V2" --center "cx,cy" --radius 200 [--inner-radius 120] --start-angle -90 python3 skills/ppt-master/scripts/svg_position_calculator.py calc radar --data "D1:V1,D2:V2,D3:V3" --center "cx,cy" --radius 200 --max-value 100 ``` -6. **Scale-aware comparison**: before declaring a mismatch, confirm every invocation used the axis range, plot area, center/radius, start angle, or size scale the SVG visually declares — for `calc bar` the header must show `Value scale: axis ticks (...)` when the SVG has ticks; `auto (max*1.1)` means go back to step 3. Never update the SVG with mismatched-scale output. When the scale matches and coordinates genuinely differ, update by hand — no regex or bulk replacement. +6. **Scale-aware comparison**: before declaring a mismatch, confirm every invocation used the axis range, plot area, center/radius, start angle, or size scale the SVG visually declares — for `calc bar` the header must show `Value scale: axis ticks (...)` when the SVG has ticks; `auto (max*1.1)` means go back to step 3. Never update the SVG with mismatched-scale output. When the scale matches and coordinates genuinely differ, update by hand — no regex or bulk replacement. On a signed bar chart the calculator starts every bar at the axis minimum, so compare `x_min + width` against the drawn far edge from the zero baseline rather than its `X`. After updating any page, follow the profile's checker order. Default reruns `svg_quality_checker.py --canonical-authoring --stage final --json`, which writes the current `final` report Step 7.3 requires. Quick completes every chart comparison/repair first, then returns to `quick-generate.md` §4 for its one lockless final checker — no checker call between chart pages. diff --git a/plugins/codex/plugins/ui-ux-pro-max/README.md b/plugins/codex/plugins/ui-ux-pro-max/README.md index a9368937..da6fb6cf 100755 --- a/plugins/codex/plugins/ui-ux-pro-max/README.md +++ b/plugins/codex/plugins/ui-ux-pro-max/README.md @@ -41,6 +41,35 @@ An AI skill that provides design intelligence for building professional UI/UX ac NextLevelBuilder.io | GoClaw.sh | AgentKit.best | TOSE.sh

+--- + +

+ Check Out Our New Skill: +
+ + + + 3Dviz Pro Max + + +

+ +

Turn an idea into a 3D scene worth exploring.

+ +

+ Harness Village: a fantasy village with camera navigation and animated creatures +

+ +

+ Visual inspiration, not a benchmark. An author-supplied project recorded before this skill existed; its UI contains Vietnamese. Historical footage, not an English demo or a runtime test of the skill — see media provenance. +

+ +

+ 🤌 Website: https://3dviz.dev/ +

+ +--- + ## What's New in v2.0 ### Intelligent Design System Generation diff --git a/plugins/codex/plugins/ui-ux-pro-max/THIRD_PARTY_SOURCE.json b/plugins/codex/plugins/ui-ux-pro-max/THIRD_PARTY_SOURCE.json index 6412951f..8899e900 100644 --- a/plugins/codex/plugins/ui-ux-pro-max/THIRD_PARTY_SOURCE.json +++ b/plugins/codex/plugins/ui-ux-pro-max/THIRD_PARTY_SOURCE.json @@ -2,8 +2,8 @@ "sourceId": "ui-ux-pro-max", "repo": "https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git", "ref": "main", - "commit": "4aad0584d92131626b16d4ff4d77f0455385013c", + "commit": "7f69fed6a2717900085f1bc3b263721f8ba025e2", "adapter": "claude-skill", "sourcePath": ".claude/skills/ui-ux-pro-max", - "syncedAt": "2026-09-06T15:59:59Z" + "syncedAt": "2026-09-10T23:40:59Z" }