story-setup:网文写作工具集基础设施部署
你是写作基础设施部署器。将网文写作工具集部署到用户项目目录:已适配的 CLI 走专用 hooks/agents/config;NarraFork、Web AI、自定义 Agent 等环境走通用文件模式。
执行铁律:不覆盖用户已有配置,合并而非替换。
交互工具兼容门:本 Skill 中的 AskUserQuestion 表示“必须让用户做选择”,不表示必须存在同名工具。当前运行时未暴露该工具时(包括部分 TRAE Code、WorkBuddy / CodeBuddy Code、Web AI 会话),主 Agent 必须在当前主对话中直接提出同一个简短问题并等待回答;不得因工具缺失跳过确认、伪造已选结果或让子 Agent 代替提问。
Phase 1:检测项目状态
先自检参考目录:以正在执行的本 SKILL.md 所在目录为准,列出与它同级的 references/ 下的子目录,核对下面 10 个名字是否都在且都非空——agent-references、templates、opencode、codex、zcode、trae、workbuddy、openclaw、reasonix、generic;同级 scripts/merge-claude-settings.py、scripts/merge-codex-hooks.py、scripts/merge-trae-hooks.py、scripts/trae-core-ownership.py、scripts/merge-workbuddy-settings.py 与 scripts/copy-path-safety.py 也必须存在(Claude/Codex/TRAE/WorkBuddy hooks 合并、shared-core 归属验证与递归复制安全预检依赖它们)。有缺即 skill 包没装全,立即停止,不写任何部署文件,报告里区分「缺目录」和「目录为空」,并给修复指令:「story-setup 参考资料包不完整,缺 {目录名}。按你的安装方式重装 oh-story-claudecode(命令行装的重跑 npx skills add https://github.com/qin1473692580-ux/oh-story-claudecode/releases/latest/download/oh-story-release.zip -y -g,marketplace / Plugin Management 装的在面板里重装),再执行 /story-setup。」
判据是「有没有
SKILL.md」:只看正在执行的SKILL.md同级的references/。项目内.claude/skills/story-setup/、.codex/skills/story-setup/和 OpenCode 的skills/story-setup/只有references/agent-references/、不含SKILL.md,不会是执行目录,也不要拿它们核对。ZCode / TRAE Code / WorkBuddy / CodeBuddy Code / OpenClaw / Reasonix / generic 的项目副本是整份 skill 拷贝、自带SKILL.md,10 个子目录本就齐全,照常核对即可。
- 检查当前目录是否已部署过(存在
.story-deployed)agents_version缺失、非整数或小于39→ 标记为待更新,继续执行当前部署agents_version: 39→ 使用 AskUserQuestion 确认是否重新部署;提示里写明重新部署只用当前本地 skill 包刷新项目文件,要拿 skill 本身的新版本得先用固定 GitHub Release 资产重跑npx skills add https://github.com/qin1473692580-ux/oh-story-claudecode/releases/latest/download/oh-story-release.zip -y -g,再回来重跑agents_version大于39→ 当前 story-setup 比项目部署旧;停止以避免降级覆盖,提示先更新 oh-story-claudecode,不写任何部署文件- 同时读
target_cli字段。已部署项目以 sentinel 里的值为准:非空时(逗号分隔的多端组合原样保留)跳过下面第 5-14 步的环境探测与选择,直接按这些端重新部署。只有字段缺失或为空,才回落到探测。用户明确要求增删目标端时,用 AskUserQuestion 在现有值基础上改,改完的值写回 sentinel。
- 检查是否有书名目录(包含
追踪/子目录的目录,或用户自定义结构)- 有 → 识别为长篇项目,显示当前项目信息
- 无 → 识别为新项目或短篇项目
- 检查
.claude/settings.local.json是否存在- 存在 → 读取现有配置,后续合并
- 不存在 → 后续创建新文件
- 检查
.active-book文件是否存在- 存在 → 显示当前活跃书目
- 不存在 → 跳过
- 检查
opencode.json或.opencode/是否存在- 存在 → 识别为 opencode 项目,
target_cli = opencode - 不存在 → 跳过
- 存在 → 识别为 opencode 项目,
- 检查
.codex/、.codex/config.toml、.codex/agents/、.codex/hooks.json、AGENTS.md中的 Codex 段- 存在 → 识别为 Codex 项目,
target_cli = codex - 不存在 → 跳过
- 存在 → 识别为 Codex 项目,
- 检查
.zcode/、.zcode/config.json、zcode.json、.zcode/skills/、.zcode/commands/、AGENTS.md中的 ZCode 段- 存在 → 识别为 ZCode 项目,
target_cli = zcode - 不存在 → 跳过
- 存在 → 识别为 ZCode 项目,
- 检查
.trae/、.trae/hooks.json、.trae/skills/、.trae/agents/、.trae/commands/、.trae/rules/,或AGENTS.md中的 TRAE 段(标题行含网文写作工具集(TRAE Code))- 存在 → 识别为 TRAE Code 项目,
target_cli = trae - 不存在 → 跳过
- 存在 → 识别为 TRAE Code 项目,
- 检查
.codebuddy/、.codebuddy/settings.json、.codebuddy/skills/、.codebuddy/agents/、.codebuddy/commands/、.codebuddy/rules/,或.codebuddy/CODEBUDDY.md/ 根CODEBUDDY.md/ 根AGENTS.md中的 oh-story WorkBuddy 管理段- 存在 → 识别为 WorkBuddy / CodeBuddy Code 项目,
target_cli = workbuddy - 不存在 → 跳过
- 存在 → 识别为 WorkBuddy / CodeBuddy Code 项目,
- 检查
openclaw.json、.openclaw/,或AGENTS.md中的 OpenClaw 段(标题行含网文写作工具集(OpenClaw))
- 存在 → 识别为 OpenClaw 项目,
target_cli = openclaw - 不存在 → 跳过
- 检查
.reasonix/、reasonix-plugin.json、REASONIX.md,或AGENTS.md中的 Reasonix 段(标题行含网文写作工具集(Reasonix))
- 存在 → 识别为 Reasonix 项目,
target_cli = reasonix - 不存在 → 跳过
- 检查
AGENTS.md中的通用段(标题行含网文写作工具集(通用 Agent / Web AI))
- 存在 → 识别为通用 Web AI 项目,
target_cli = generic - 不存在 → 跳过
第 8-12 步只认各端互斥的标记。
skills/*/SKILL.md的metadata.openclaw不作 OpenClaw 信号:canonical 中文主包 Skill 都带这个字段,而 OpenClaw / Reasonix / generic 三条 skills-only 路径部署出的skills/长得一样,用它判定会把后两者一律误认成 OpenClaw。.agents/skills/同理由 Codex 与 Reasonix 共用,也不单独作准。TRAE 只认.trae/或 TRAE 专用标题行;WorkBuddy 只认.codebuddy/或其 CODEBUDDY 管理段;skills-only 三端真正的分辨点是各自AGENTS.md模板的标题行。
- 如
.claude/或CLAUDE.md、OpenCode、Codex、ZCode、TRAE Code、WorkBuddy / CodeBuddy Code、OpenClaw、Reasonix、generic 标记同时存在 → 使用 AskUserQuestion 让用户选择目标环境(选项:Claude Code / OpenCode / Codex / ZCode / TRAE Code / WorkBuddy / CodeBuddy Code / OpenClaw / Reasonix / 通用 Web AI 或其他 Agent / 任意组合) - 如九类标记都不存在(全新项目)→ 使用 AskUserQuestion 让用户选择目标环境
- 用户选择 opencode →
target_cli = opencode,部署时创建opencode.json和.opencode/ - 用户选择 claude-code → 按现有逻辑处理
- 用户选择 codex →
target_cli = codex,部署时创建.codex/ - 用户选择 zcode →
target_cli = zcode,部署时创建.zcode/、合并根AGENTS.md,不创建项目 custom agents - 用户选择 TRAE Code →
target_cli = trae,部署时创建.trae/并合并根AGENTS.md、.trae/hooks.json,部署原生 Skills / Subagents / Commands / Rules / Hooks - 用户选择 WorkBuddy / CodeBuddy Code →
target_cli = workbuddy,部署时创建.codebuddy/,按「WorkBuddy memory 合并策略」选择唯一 memory 文件并合并.codebuddy/settings.json,部署原生 Skills / Agents / Commands / Rules / Hooks - 用户选择 openclaw →
target_cli = openclaw,部署时复制 OpenClaw 兼容 skills 到项目skills/ - 用户选择 reasonix →
target_cli = reasonix,部署时复制 skills 到项目skills/、写入 Reasonix 版AGENTS.md,不创建项目 custom agents/hooks - 用户选择通用 Web AI / 其他 Agent →
target_cli = generic,部署通用AGENTS.md与项目本地skills/;不写平台专属 hooks/agents - 用户选择多端 →
target_cli = claude-code,opencode,codex,zcode,trae,workbuddy,openclaw,reasonix,generic的子集(仅包含用户选择的端)
Phase 2:部署基础设施
使用 AskUserQuestion 确认部署位置后,依次执行。
整个 Phase 2 幂等:目录复制、文件写入和下表各合并算法重复执行结果一致。因环境原因(工具不可用、权限被拒、网络失败)中途失败时,直接从头重跑本 Phase,不需要先清理半成品;create only if absent 的用户状态文件(见下表 Owner class)不会被二次覆盖。
Step 1:部署清单(机械可检查)
递归复制安全预检(先于任何目录 replace/copy):先把 Source path 解析为“正在执行的 story-setup skill 包”内的绝对路径,把 Target path 解析为用户项目内绝对路径,再用可用的 python3/python/py 运行 scripts/copy-path-safety.py <source> <target>。读取它的 JSON 结果:
status=safe:路径互不包含,才允许继续该项复制。status=same:源、目标经 realpath/samefile 指向同一对象;把该项记录为幂等 no-op,不得再递归复制。status=unsafe:目标位于源内,或源位于目标内;立即停止整个 Phase 2,不执行删除/覆盖,报告reason与两条 realpath。status=error:源缺失或路径解析失败;按部署包不完整处理,立即停止。
不得用字符串前缀、未展开的相对路径或“看起来不是同一个目录”代替此预检;symlink/别名必须按 realpath 判定。文件级 replace 可继续按原有原子写入规则;所有递归目录复制都必须逐项过这一关。
TRAE 归属与备份门(target_cli 含 trae 时):在改动任何已存在的 .trae/ 文件前,先将本次会改动的原文件按相对路径备份到 .trae/.oh-story-backups/<UTC时间戳>/;目录备份本身也要先跑 copy-path-safety.py。只允许替换带 oh-story-managed 标记的 canonical 中文主包 skill / command / agent / rule / AGENTS 管理块、头注释明确为 oh-story TRAE adapter 的 story_trae_hook.js,以及满足下列任一归属证据的 story_hook_core.js:含通用标记 oh-story-managed: shared-hook-core;用 scripts/trae-core-ownership.py 校验后 sha256 命中唯一权威 references/trae/legacy-managed-sha256.json;或与已验证的同项目 Claude/OpenCode/ZCode oh-story shared core 字节一致。Skill 目录的归属证据是 SKILL.md 的 metadata.openclaw.source 指向本仓库,或精确标记 <!-- oh-story-managed: skill/{name} -->。同名但无归属证据的用户文件必须保留并报告冲突,不得覆盖。.trae/hooks.json 始终用 helper 按稳定 command 身份合并,绝不整文件替换。新创建的产物必须写入对应管理标记,以保证下次可安全升级。
TRAE 与 Claude Hook 去重门:TRAE 会兼容读取项目 .claude/settings*.json。Claude settings 命令保持跨平台可执行的直接 bash ... 形式,不内嵌 POSIX if;所有 Claude shell 入口在 source lib/common.sh 后由共用库检测 TRAE_PROJECT_DIR 并成功、静默退出。在 Claude 中照常执行,在 TRAE 进程中由 .trae/hooks.json 独占执行。部署后用两端合成输入验证同一事件只有一套 oh-story 输出,不能把“双份提示看起来一样”当作可接受。
WorkBuddy 归属与 Hook 互斥门(target_cli 含 workbuddy 时):只替换带 oh-story-managed 标记的 canonical 中文主包 skill / command / agent / rule / CODEBUDDY(或 AGENTS)管理块,以及带适配器头注释或通用 shared-core 标记的 hook 文件;Skill 目录使用与 TRAE 相同的仓库 metadata / <!-- oh-story-managed: skill/{name} --> 双证据。同名用户文件保留并报告冲突。.codebuddy/settings.json 只通过 merge-workbuddy-settings.py 合并。若当前 skill 来自已启用的 oh-story CodeBuddy plugin(实际执行路径位于插件安装根,或当前会话 registry / codebuddy plugin list 明确显示 oh-story 已启用),plugin hooks 会自动加载,此时必须用空模板移除项目内旧的 oh-story-managed hook 注册,不能再合并 project-hooks.json;只有 project-local skills 模式才写项目 hooks,防止同一事件双触发。仓库里存在 .codebuddy-plugin/plugin.json 或插件曾经安装过都不算“当前已启用”的证据。
WorkBuddy 命名空间门:plugin 模式只由 .codebuddy-plugin/plugin.json 暴露 Skills、Agents 与 Hooks;不得同时在 manifest 暴露与 Skills 同名的 Commands,否则 /oh-story:story-* 会发生组件名竞争。plugin 模式调用 /oh-story:story、/oh-story:story-long-write 等命名空间化 Skill;运行 story-setup 后的项目模式才由 .codebuddy/commands/ 暴露 /story、/story-long-write 等裸命令。两种模式必须在安装报告中分开写,不能把裸命令说成 plugin 命令。
| Source path | Target path | Owner class | Merge mode | Validation check |
|---|---|---|---|---|
skills/story-setup/references/templates/CLAUDE.md.tmpl |
CLAUDE.md |
user+managed | marker/section merge | contains story skill routing sections |
skills/story-setup/references/templates/hooks/ |
.claude/hooks/ |
story-setup managed | recursive replace | session-*.sh, detect-story-gaps.sh, validate-story-commit.sh, guard-outline-before-prose.sh, check-prose-after-write.sh, story_hook_core.js, story_hook_cli.js, lib/common.sh, lib/sentinel.sh exist;story_hook_core.js 与 OpenCode/ZCode 副本字节一致 |
skills/story-setup/references/templates/rules/*.md |
.claude/rules/*.md |
story-setup managed | replace | every rule contains paths frontmatter |
skills/story-setup/references/templates/agents/*.md |
.claude/agents/*.md |
story-setup managed | replace | 8 agent files exist |
skills/story-setup/references/agent-references/*.md |
.claude/skills/story-setup/references/agent-references/*.md |
story-setup managed | replace | every story-setup/references/agent-references/*.md reference resolves |
skills/story-setup/references/templates/settings-hooks.json |
.claude/settings.local.json |
user+managed | replace managed registrations by stable hook identity | hook JSON valid;旧 matcher 注册已迁移、当前模板命令各一份、用户 hook 保留 |
skills/story-setup/scripts/merge-claude-settings.py |
部署时执行,不复制到项目 | story-setup helper | execute | 替换已知 story hook 注册、保留用户 hooks/顶层字段,历史 matcher 迁移与重复执行幂等 |
skills/story-setup/references/templates/质检进度.md.tmpl |
{书名}/追踪/质检进度.md |
user state | create only if absent | never overwrite existing progress table |
| generated sentinel | .story-deployed |
story-setup managed | replace | contains agents_version, setup_skill_version, target_cli, resolver_strategy, references_dir |
skills/story-setup/references/opencode/AGENTS.md.tmpl |
AGENTS.md |
user+managed | marker/section merge | contains story skill routing sections |
skills/story-setup/references/opencode/agents/ |
.opencode/agents/ |
story-setup managed | replace | 8 agent files exist(replace 前按「配置 OpenCode Agent 模型」中的「保留已有模型配置」缓存现有 model:,避免覆盖用户已配模型) |
skills/story-setup/references/opencode/plugin.ts |
.opencode/plugins/story-hooks.ts |
story-setup managed | replace | TypeScript plugin file exists |
skills/story-setup/references/opencode/story_hook_core.js |
.opencode/plugins/lib/story_hook_core.js |
story-setup managed | replace | Node syntax valid;与 ZCode 副本字节一致;被 story-hooks.ts import |
skills/story-setup/references/opencode/commands/ |
.opencode/commands/ |
story-setup managed | replace | command 数量与当前 OpenCode 模板清单一致 |
skills/story-setup/references/opencode/opencode.json.patch |
merge into opencode.json |
user+managed | merge by plugin/permission key | plugin entry registered |
skills/story-setup/references/agent-references/ |
skills/story-setup/references/agent-references/ |
story-setup managed | replace | every reference resolves |
skills/story-setup/references/opencode/pre-commit.sh |
.git/hooks/pre-commit |
user+managed | append or create | file exists and is executable;含 marker 块则替换块内容,不含则检测 exit 0 位置智能插入 |
skills/story-setup/references/codex/AGENTS.md.tmpl |
AGENTS.md |
user+managed | marker/section merge | contains Codex story skill routing sections |
skills/story-setup/references/codex/agents/ |
.codex/agents/ |
story-setup managed | replace | 8 TOML agent files parse and contain name/description/developer_instructions |
skills/story-setup/references/codex/hooks/hooks.json |
.codex/hooks.json |
user+managed | replace managed registrations by stable hook identity | hook JSON valid; all stale direct/launcher registrations removed, current 6 registrations present exactly once |
skills/story-setup/references/codex/hooks/{story_codex_hook.py,run-story-hook.sh,run-story-hook.cmd} |
.codex/hooks/ 同名文件 |
story-setup managed | replace | Python/shell/cmd launcher 文件齐全 |
skills/story-setup/scripts/merge-codex-hooks.py |
部署时执行,不复制到项目 | story-setup helper | execute | 替换已知管理注册、保留用户 hooks 与未知顶层字段,结果幂等 |
skills/story-setup/scripts/copy-path-safety.py |
每次递归目录复制前执行,不复制到项目 | story-setup helper | execute | same=no-op;祖先/后代嵌套=阻断;仅 safe 可复制 |
skills/story-setup/references/agent-references/ |
.codex/skills/story-setup/references/agent-references/ |
story-setup managed | replace | every reference resolves |
skills/story-setup/references/zcode/AGENTS.md.tmpl |
AGENTS.md |
user+managed | marker/section merge | contains ZCode $story-* routing and solo fallback |
canonical repository skills/{browser-cdp,story*}/ |
.zcode/skills/{browser-cdp,story*}/ |
story-setup managed for 18 known skill names | replace known skill dirs only | SKILL.md 名字集与中文主包 18 Skill 清单一致并满足 ZCode frontmatter 限制 |
skills/story-setup/references/zcode/commands/ |
.zcode/commands/ |
story-setup managed for 18 known command names | replace known command files only | commands have valid names/frontmatter and cover the canonical skill list |
skills/story-setup/references/zcode/hooks/story_zcode_hook.js |
.zcode/hooks/story_zcode_hook.js |
story-setup managed | replace | Node syntax valid; hook contract tests pass |
skills/story-setup/references/zcode/hooks/story_hook_core.js |
.zcode/hooks/story_hook_core.js |
story-setup managed | replace | Node syntax valid; hook contract tests pass |
skills/story-setup/references/zcode/config.json.patch |
merge into .zcode/config.json |
user+managed | merge by event+matcher+process args | JSON valid; 按「ZCode 部署算法」第 4 步 hooks 互斥分支校验——未装 oh-story 插件时 hooks.enabled=true、only supported events;已装插件时校验 .zcode/config.json 不含(或已移除)这批 oh-story hooks 注册 |
skills/story-setup/references/trae/AGENTS.md.tmpl |
AGENTS.md |
user+managed | marker/section merge | contains TRAE Code story routing and fallback contract |
canonical repository skills/{browser-cdp,story*}/ |
.trae/skills/{skill-name}/ |
story-setup managed for the fixed 18 source names | backup + replace managed dirs only | 目标 SKILL.md 数量/名字与中文主包 18 Skill 清单一致;源目标同一则 no-op |
skills/story-setup/references/trae/commands/ |
.trae/commands/{skill-name}.md |
story-setup managed by oh-story-managed marker |
backup + replace 18 managed files only | 每个 canonical skill 恰有一个同名 command,frontmatter 含 name / description |
skills/story-setup/references/trae/agents/ |
.trae/agents/ |
story-setup managed by oh-story-managed marker |
backup + replace 精确通用名册(8 张) | 名字集精确为 chapter-extractor, character-designer, consistency-checker, narrative-writer, revision-governor, story-architect, story-explorer, story-researcher;TRAE frontmatter 可解析 |
repository skills/story-data-analyze/agents/trae/ |
.trae/agents/ |
story-setup managed by oh-story-managed marker |
backup + replace 精确数据名册(5 张) | 名字集精确为 story-data-fetcher, story-data-method-validator, story-data-metrics-analyst, story-data-supervisor, story-data-text-improvement-planner;与通用角色无重名 |
skills/story-setup/references/trae/rules/ |
.trae/rules/ |
story-setup managed by oh-story-managed marker |
backup + replace managed files only | rules frontmatter 含 alwaysApply / globs |
skills/story-setup/references/trae/hooks/{story_trae_hook.js,story_hook_core.js} |
.trae/hooks/ 同名文件 |
runner by adapter header; core by fixed name + packaged hash | backup + replace managed files only | Node syntax valid;shared core 与其他 adapter 副本一致 |
skills/story-setup/references/trae/hooks/hooks.json |
.trae/hooks.json |
user+managed | replace managed registrations by stable hook command identity | version: 1;仅含 TRAE 支持事件;用户 hook/顶层字段保留 |
skills/story-setup/scripts/merge-trae-hooks.py |
部署时执行,不复制到项目 | story-setup helper | execute | 迁移旧 matcher/command、保留用户配置,重复执行字节幂等 |
skills/story-setup/scripts/trae-core-ownership.py + references/trae/legacy-managed-sha256.json |
部署时执行,不复制到项目 | story-setup ownership helper/registry | classify before replace | marker / legacy SHA 判 managed;unknown/error 保留并报告 |
skills/story-setup/references/workbuddy/CODEBUDDY.md.tmpl |
既有 CODEBUDDY.md / .codebuddy/CODEBUDDY.md,或无两者时的 AGENTS.md / .codebuddy/CODEBUDDY.md |
user+managed | 按「WorkBuddy memory 合并策略」只合并 marker block | 无遮蔽已有 AGENTS;条件导入占位已解析;管理块唯一 |
canonical repository skills/{browser-cdp,story*}/ |
.codebuddy/skills/{skill-name}/ |
story-setup managed for the fixed 18 source names | replace managed dirs only | SKILL.md 名字集与中文主包 18 Skill 清单一致;源目标同一则 no-op |
skills/story-setup/references/workbuddy/commands/ |
.codebuddy/commands/{skill-name}.md |
story-setup managed by oh-story-managed marker |
replace 18 managed files only | commands 与 canonical skill 一一对应,frontmatter 仅用 CodeBuddy 支持字段 |
skills/story-setup/references/workbuddy/agents/ |
.codebuddy/agents/ |
story-setup managed by marker | replace 精确通用名册(8 张) | 名字集精确为 chapter-extractor, character-designer, consistency-checker, narrative-writer, revision-governor, story-architect, story-explorer, story-researcher;WorkBuddy frontmatter 合法,项目 Agent 名不带 plugin namespace |
repository skills/story-data-analyze/agents/workbuddy/ |
.codebuddy/agents/ |
story-setup managed by marker | replace 精确数据物理名册(2 张) | 名字集精确为 story-data-fetcher, story-data-readonly-runner;4 张逻辑角色卡留在 Skill references |
skills/story-setup/references/workbuddy/rules/ |
.codebuddy/rules/ |
story-setup managed by marker | replace managed files only | alwaysApply 可解析;用户 rules 保留 |
skills/story-setup/references/workbuddy/hooks/{story_workbuddy_hook.js,story_hook_core.js} |
.codebuddy/hooks/ 同名文件 |
story-setup managed | replace managed files only | Node syntax valid;shared core byte-parity |
skills/story-setup/references/workbuddy/hooks/project-hooks.json |
merge into .codebuddy/settings.json |
user+managed | merge or remove by plugin mutex | 只有 project-local 模式各注册一次;plugin 模式为零;用户设置与 hooks 保留 |
skills/story-setup/scripts/merge-workbuddy-settings.py |
部署时执行,不复制到项目 | story-setup helper | execute | 稳定 runner 身份去旧、合并/移除幂等 |
skills/story-setup/references/openclaw/AGENTS.md.tmpl |
AGENTS.md |
user+managed | marker/section merge | contains OpenClaw story skill routing sections |
skills/story-setup/references/generic/AGENTS.md.tmpl |
AGENTS.md |
user+managed | marker/section merge | contains generic story skill routing sections |
skills/story-setup/references/reasonix/AGENTS.md.tmpl |
AGENTS.md |
user+managed | marker/section merge | contains Reasonix story skill routing sections and solo/direct fallback |
canonical repository skills/{browser-cdp,story*}/ |
skills/{browser-cdp,story*}/ |
story-setup managed for 18 known skill names | replace known skill dirs only | SKILL.md 名字集与中文主包 18 Skill 清单一致;OpenClaw 分支校验兼容 frontmatter |
skills/story-setup/references/agent-references/ |
skills/story-setup/references/agent-references/ |
story-setup managed | replace via full skill copy | every reference resolves |
opencode.json 合并算法
部署 opencode.json.patch 时按以下规则合并:
- 读取现有
opencode.json(如存在),解析 JSON - 合并
plugin数组:将./.opencode/plugins/story-hooks.ts加入数组,去重 - 保留用户已有的其他配置字段(
permission、model、provider等),不覆盖 - 写入合并后的
opencode.json
Step 2:部署 CLAUDE.md
- 读取
skills/story-setup/references/templates/CLAUDE.md.tmpl - 替换占位符(见下方「模板占位符」段)
- 写入项目根目录
CLAUDE.md(如已存在,按「CLAUDE.md 合并策略」处理)
Step 3:部署 Hooks
- 递归复制完整目录树:将
skills/story-setup/references/templates/hooks/复制到用户项目.claude/hooks/ - 必须保留子目录
lib/,其中:lib/common.sh提供project_root、discover_active_book、discover_all_bookslib/sentinel.sh提供.story-deployed字段读取
- 只需对
.claude/hooks/*.sh设置执行权限(chmod +x);lib/*.sh由 hooksource,不要求可执行位
Step 4:部署 Rules
- 读取
skills/story-setup/references/templates/rules/下所有.md文件 - 复制到用户项目的
.claude/rules/目录
Step 5:部署 Agents
- 读取
skills/story-setup/references/templates/agents/下所有.md文件 - 复制到用户项目的
.claude/agents/目录 - Agent 文件属于 story-setup 管理文件,可安全覆盖;版本升级时按
UPGRADING.md的版本检测结果重新部署 target_cli含 opencode 时,覆盖.opencode/agents/之前先执行下面「配置 OpenCode Agent 模型」的 Step 1 缓存现有model:。那一步写在本节后面,但必须先跑——照顺序读到哪做到哪会先覆盖再缓存,用户已配的模型就没了。- 部署后必须新开会话:agent 只在会话启动时注册;原因与必须输出的报告文案见「验证安装」中的「输出安装报告」。
Agent 兼容性处理
- Agent frontmatter 以 Claude Code 为主;OpenCode 的
.opencode/agents/*.md、Codex 的.codex/agents/*.toml、TRAE 的.trae/agents/*.md和 WorkBuddy 的.codebuddy/agents/*.md均使用对应 adapter 下的预生成产物,不得直接复制别端 frontmatter。TRAE 通用角色的唯一来源是references/trae/agents/,数据分析角色的唯一来源是skills/story-data-analyze/agents/trae/;WorkBuddy 对应来源为references/workbuddy/agents/与skills/story-data-analyze/agents/workbuddy/。不把 Claude 模型别名或某一端的专有字段机械带入另一端。OpenCode/Codex/WorkBuddy 预生成产物由仓库维护脚本生成;这些脚本不随 story-setup 下发,部署时只复制已提交产物。 - ZCode 3.3.4 不部署项目 agents:其自定义子智能体只支持用户级
~/.zcode/agents/,plugin manifest 中的agents当前不执行。不要创建.zcode/agents/或修改用户 home;相关 Skill 必须直接 solo/direct 并报告 fallback。 - OpenClaw Phase 1 不部署 agents:OpenClaw 只部署 skills,agent 协作相关 skill 必须按既有 fallback 规则降级 solo/direct,不要把 Claude/OpenCode agent frontmatter 直接复制成 OpenClaw agent。
- 部署到项目后,agent 内引用的参考资料必须走
story-setup/references/agent-references/*.md这一本 skill 内复制路径;不要跨 skill 引用其他 skill 的 references。各 adapter 只使用当前规范前缀:Claude Code 为.claude/skills/,OpenCode / OpenClaw / Reasonix / generic 为skills/,Codex 为.codex/skills/,ZCode 为.zcode/skills/,TRAE Code 为.trae/skills/,WorkBuddy / CodeBuddy Code 为.codebuddy/skills/;插件模式可用由平台内联的${CODEBUDDY_PLUGIN_ROOT}/skills/。不在运行时遍历历史备选路径。
部署 Agent References
- 将
skills/story-setup/references/agent-references/下所有.md复制到项目内.claude/skills/story-setup/references/agent-references/ - 校验:凡 agent 或 reference 中出现
story-setup/references/agent-references/<file>.md,源包与目标包都必须存在<file>.md
部署 Codex Agents(target_cli 含 codex 时)
- 读取
skills/story-setup/references/codex/agents/下所有.toml文件,复制到用户项目.codex/agents/ - Agent 文件属于 story-setup 管理文件,可安全覆盖;
references/codex/agents/里的 TOML 由仓库根的scripts/generate-codex-agents.py从 Claude agent 模板确定性生成后提交入库,部署只做复制 - 校验每个 TOML 都能解析,且包含 Codex 必需字段:
name、description、developer_instructions - 只读职责 agent(
chapter-extractor、consistency-checker、revision-governor、story-explorer)必须保留sandbox_mode = "read-only" - 部署后必须 trust + 新开 Codex 会话(报告文案与 fallback 规则见「验证 Codex 部署」);若运行时返回
unknown agent_type,调用方必须降级 solo/direct 并报告 fallback。 - 将
skills/story-setup/references/agent-references/同步复制到.codex/skills/story-setup/references/agent-references/,作为 Codex agent 的项目内参考资料主路径
部署 TRAE Agents(target_cli 含 trae 时)
- 先校验
references/trae/agents/的名字集精确为chapter-extractor,character-designer,consistency-checker,narrative-writer,revision-governor,story-architect,story-explorer,story-researcher(8 张通用卡),再校验 canonicalstory-data-analyze/agents/trae/的名字集精确为story-data-fetcher,story-data-method-validator,story-data-metrics-analyst,story-data-supervisor,story-data-text-improvement-planner(5 张数据卡)。两组必须无重名,合并后名册精确为 13 张;任一必需目录缺失、为空、名字集不等、重名或 frontmatter 不可解析时停止 TRAE 分支,不进行半套部署。 - 依次写入
.trae/agents/,只新建或替换带<!-- oh-story-managed: agent/<agent-name> -->标记的同名文件;无标记同名文件保留并报告。不删除用户其他 agents。 - TRAE frontmatter 只用其原生字段:
name、description、逗号字符串形式的tools/disallowedTools以及可选的 TRAE 内置model;禁止自动把 Claude 模型别名写入。 - 部署后提示新开 TRAE 会话并确认 Subagents Beta 功能可用。若当前 TRAE 版本/会话不支持原生 Agent,必须按各 skill 契约降级
solo/direct,报告Fallback: TRAE subagent unavailable -> solo/direct;不得声称 full/lean 多 Agent 已生效。
部署 WorkBuddy Agents(target_cli 含 workbuddy 时)
- 先校验
references/workbuddy/agents/的名字集精确为chapter-extractor,character-designer,consistency-checker,narrative-writer,revision-governor,story-architect,story-explorer,story-researcher(8 张通用卡);再校验skills/story-data-analyze/agents/workbuddy/的物理名字集精确为story-data-fetcher,story-data-readonly-runner(2 张数据卡),且四张只读逻辑角色卡完整留在该 Skill 的 WorkBuddy role-card references。全部物理名必须无重复,合并后中文主包物理名册精确为 10 张。 - CodeBuddy 当前会在
agenticregistry 查询阶段把 内置 + 项目 Subagent 总数硬截为 20。本节列出的 WorkBuddy 精确 10 张物理卡低于平台上限;部署器不向该名册注入项目扩展卡,不靠排序或截断隐藏容量问题。 - 每个 Markdown 必须有合法 YAML frontmatter,
name与文件名一致,description非空,tools/disallowedTools为逗号字符串且只使用当前 CodeBuddy 工具名。plugin agent 禁止hooks、mcpServers、permissionMode;项目 agent 也不依赖这些字段。 - 只新建或替换带
<!-- oh-story-managed: agent/<name> -->标记的.codebuddy/agents/<name>.md;无标记同名文件保留并报告冲突。项目定义优先级高于 plugin/user agent,项目模式统一用裸名称和Agent(subagent_type: "<name>")。 - pooled runner 的逻辑角色卡留在所属 Skill 内,不能复制进
.codebuddy/agents/。主协调器必须按该 Skill 的运行时映射选择 runner,并在 prompt 中传入logical_role、角色卡绝对路径、项目根、输入隔离合同和任务正文;runner 必须完整读取且核对角色卡后执行。 - plugin-only 模式的 UI 名为
oh-story:<name>;只有当前 registry 确实暴露该名称时才用它。未运行 story-setup 时不得凭磁盘 manifest 猜测 registry 已加载;调用失败立即按 Skill 合同降级。完成项目部署后统一使用.codebuddy/agents/的裸名称,避免命名空间分歧。 - 部署后新开 WorkBuddy / CodeBuddy 会话,用
/agents或当前 registry 确认本节列出的精确 10 张物理卡全部可见;再分别冒烟一个通用 Agent 和一个 pooled runner 逻辑角色。子 Agent 不得递归 spawn。
配置 OpenCode Agent 模型
仅当
target_cli含opencode时执行。OpenCode 子代理不指定模型时继承主模型,导致低成本 Agent 也消耗主模型额度。此步骤自动检测用户模型并写入model:字段。
Step 1:保留已有模型配置(必须在 .opencode/agents/ 的 replace 之前执行)
OpenCode agents 部署是 replace,会覆盖上次写入的 model:。所以在执行该 replace 之前先扫描现有 .opencode/agents/*.md,缓存每个 agent 的 model:(agent 名 → 模型 ID)。后续检测失败/超时、或用户跳过某一级时,用缓存值回填,避免把用户上次配好的低成本模型抹成主模型。若 replace 已先发生、缓存为空,则按全新部署处理,并在安装报告中提示"未能保留上次模型配置"。
Step 2:获取模型列表
优先执行 opencode models --verbose,它输出含 cost(input/output/cache 单价)、context、capabilities 的 metadata;不可用或解析失败时回退到 opencode models 纯文本(每行 provider/model)。两者都用 60000ms(60 秒)超时,因为首次运行需加载 models.dev 缓存。
- 成功 → 进入「模型分级」
- 超时 → 重试一次(缓存可能未预热);仍然超时则按「保留已有模型配置」缓存回填已有
model:、跳过自动配置,在安装报告中输出手动配置指南 - 失败(命令不存在、输出为空等)→ 同上:回填「保留已有模型配置」缓存、跳过自动配置、输出手动配置指南
Step 3:模型分级
优先按成本分级(有 --verbose 时):按每模型实际 cost 从低到高分档——低端取最便宜/免费档、中端取中价档、高端取最贵或上下文/能力最强档。免费模型按真实 cost=0 归低端,不按名字里的营销词(如 nemotron-3-ultra-free 名含 ultra 但 cost=0,应归低端)。无 cost 数据的模型也据此进入候选,不被丢弃。
回退按关键词分级(无 --verbose 或无 cost 时):按模型 ID 中最后一个 / 之后的模型名按 -、.、_ 分割为段,逐段精确匹配关键词(不区分大小写)。例如 minimax-m3 拆为 [minimax, m3],不匹配 mini 也不匹配 max;claude-haiku-4.5 拆为 [claude, haiku, 4, 5],匹配 haiku。关键词分级是启发式,安装报告中标注 分级依据:关键词(heuristic)。
| 等级 | 匹配关键词 | 对应 Agent |
|---|---|---|
| 低端 | haiku, flash, mini, nano, lite |
chapter-extractor, consistency-checker, story-explorer |
| 中端 | sonnet, plus |
story-researcher, narrative-writer, character-designer, revision-governor |
| 高端 | opus, pro, ultra, max |
story-architect |
- 一个模型可能匹配多个等级的关键词,取最高等级
- 关键词回退下未匹配任何关键词的模型仍列入候选附加建议(按成本分级则一律纳入),并在安装报告列出,提示"可通过自定义输入使用"
- 同一等级内,如果包含多个模型供应商,优先列出知名供应商(anthropic、openai、google、deepseek)的模型
Step 4:逐级交互选择
按 低端 → 中端 → 高端 顺序,每级用 AskUserQuestion 让用户选择。
低端选项结构:
问题:"为低成本 Agent(chapter-extractor, consistency-checker, story-explorer)选择模型:"
选项:
- provider/model-id
- provider/model-id
- 自定义输入(手动输入完整模型 ID,ID 拼写错误要到运行时才会暴露)
- 跳过,使用主模型(成本可能较高)
中端选项结构:
问题:"为写作质量关键 Agent(narrative-writer, character-designer, story-researcher, revision-governor)选择模型:"
选项:
- provider/model-id
- provider/model-id
- 自定义输入(请勿使用低端模型,会影响正文质量;ID 拼写错误要到运行时才会暴露)
- 跳过,使用主模型(主模型质量通常足够)
高端选项结构:
问题:"为总指挥 Agent(story-architect)选择模型:"
选项:
- provider/model-id
- provider/model-id
- 自定义输入(手动输入完整模型 ID,ID 拼写错误要到运行时才会暴露)
- 跳过,使用主模型(成本可能较高)
规则:
- 候选最多显示 5 个,超过则截断并提示"更多模型请使用自定义输入"。每一级无论候选数是否为 0 都用 AskUserQuestion 弹出,选项至少含:候选模型(如有)、
自定义输入、保留现有模型(「保留已有模型配置」缓存到该 agent 的 model,无则不显示此项)、跳过,用主模型。候选为 0 时仍弹窗,并在问题说明里给出对应警告 + 列出未分级/未入档模型供参考——不再静默跳过交互(否则用户够不到自定义输入)。 自定义输入:用户输入provider/model-id完整 ID;写入前校验为单行、无控制字符、匹配^[A-Za-z0-9._-]+/[A-Za-z0-9._:+-]+$,不符则提示重输或改选跳过。保留现有模型:写回「保留已有模型配置」缓存的该 agent model(重新部署时保住用户上次配置),不算"跳过"。跳过,用主模型:显式清除——不写该 agent 的model:,agent 继承主模型。想保留上次配置请选保留现有模型。- 各级候选为 0 时在问题说明里给出提示:
- 低端:"未检测到低成本模型,这 3 个 agent 将使用主模型,成本可能较高"
- 中端:"未检测到匹配的中端模型。narrative-writer、character-designer、story-researcher 将使用主模型。如主模型质量足够此配置合理;如需降本,请用自定义输入指定不低于主模型质量的中端模型,或从下方未分级模型里选。"
- 高端:"未检测到高端模型,story-architect 将使用主模型"
Step 5:写入 model 字段
对应用户选择的 agent 文件(.opencode/agents/*.md,由部署清单中 OpenCode agents 部署步骤在此步骤之前已部署),在 frontmatter 末尾、closing --- 之前,以零缩进的顶层字段插入 model:(不要插进 permission: 等多行 map 的缩进块内部)。值含 YAML 特殊字符时加引号,确保不破坏 frontmatter:
---
description: ...
mode: subagent
permission:
read: allow
edit: deny
steps: 12
model: provider/model-id
---
- 如果 agent 文件已有
model:字段(重新部署场景),替换该顶层model:的值,不新增重复键 保留现有模型:写回「保留已有模型配置」缓存的该 agent model跳过,用主模型:不写入model:字段- 检测失败/超时、没走到本步骤的等级:用「保留已有模型配置」缓存回填
model:,避免 replace 抹掉用户上次配置
Step 6:部署质检进度模板
追踪/上下文.md不再由本步部署。它已改为_tracking-state.json的派生视图,由写作 skill 自带的追踪事务工具在提交时渲染,story-setup 不再创建也不再覆盖它- 读取
skills/story-setup/references/templates/质检进度.md.tmpl - 仅当已识别为长篇书目且
{书名}/追踪/已存在时,创建缺失的{书名}/追踪/质检进度.md - 如果目标文件已存在,不覆盖;短篇项目不得因此创建
追踪/目录。这张表是 Phase 5 硬性必须项(consistency-checker、去AI味独立审查)的可机械核对记录,不能因为项目已在写而缺失
Step 7:合并 Hooks 注册到 settings.local.json
- 按现有跨平台规则探测 Python:
for PYBIN in python3 python py; do "$PYBIN" -c "" 2>/dev/null && break; done;无可用解释器时停止,不手写或简化合并。 - 调用
"$PYBIN" "{story-setup skill目录}/scripts/merge-claude-settings.py" --existing "{项目}/.claude/settings.local.json" --template "{story-setup skill目录}/references/templates/settings-hooks.json" --output "{项目}/.claude/settings.local.json"。 - helper 会移除所有已知 story-setup hook 的历史注册,再追加当前模板;因此 matcher、timeout、if 能随版本升级,同时混在旧 block 中的用户 hook 与未知顶层字段原样保留。写后解析 JSON,验证模板命令各一份、用户配置仍在,再复跑 helper 比较文件字节确认幂等。
Codex hooks.json 合并算法(target_cli 含 codex 时)
Codex 项目 hooks 部署到 .codex/hooks.json;运行脚本部署到 .codex/hooks/story_codex_hook.py、run-story-hook.sh、run-story-hook.cmd。JSON 只负责定位项目根与传递 event,解释器探测由平台 launcher 统一处理。
- 定位当前 story-setup skill 目录,读取
references/codex/hooks/hooks.json作为唯一当前模板,读取项目.codex/hooks.json(不存在时视为空对象)。 - 按现有跨平台规则探测可用 Python:
for PYBIN in python3 python py; do "$PYBIN" -c "" 2>/dev/null && break; done;无可用解释器时停止,不手写或简化 JSON 合并。 - 调用
"$PYBIN" "{story-setup skill目录}/scripts/merge-codex-hooks.py" --existing "{项目}/.codex/hooks.json" --template "{story-setup skill目录}/references/codex/hooks/hooks.json" --output "{项目}/.codex/hooks.json"。该 helper 会识别旧直调story_codex_hook.py、当前run-story-hook.sh和run-story-hook.cmd三类管理身份,先移除所有已知管理注册,再追加当前模板。 - 保留用户已有的非 story-setup hooks、matcher 块与未知顶层字段。重复执行必须幂等;禁止再按原始
command字符串追加去重,否则 v17 直调命令会与 v18 launcher 双重注册。 - 写入后解析 JSON 验证:旧直调
story_codex_hook.py命令数为 0,当前模板 6 个注册各存在且仅存在一次,用户 hook 与未知顶层字段仍在。然后提示用户:项目.codex/层需要被 Codex trust,非 managed command hooks 还需要在/hooks中 review/trust 后才会运行;Windows 下走commandWindows,launcher 从当前目录向上定位项目.codex/hooks/,与 POSIX 路径的嵌套目录行为一致。
部署源解析(防项目旧副本自复制)
- 记下当前正在执行的
story-setup目录与其上一级 skills 根,称为bootstrap_root。如果它位于目标项目的.trae/skills/、.codebuddy/skills/、.zcode/skills/、.codex/skills/、.claude/skills/或根skills/下,它只是“已部署快照”,不得一概当成升级权威源。 - 已部署项目另外枚举这些可验证候选:当前已启用 plugin 的
${CODEBUDDY_PLUGIN_ROOT}/skills/story-setup、~/.agents/skills/story-setup、~/.claude/skills/story-setup、~/.codex/skills/story-setup,以及用户本次显式给出的本地安装目录。不搜索整个磁盘,不从网页或浮动仓库直接执行未验证内容。 - 候选只有在以下条件全部成立时才有效:
SKILL.mdfrontmatter 的name=story-setup、version为可比较的三段数字 SemVer、metadata.openclaw.source指向本 oh-story 仓库,且 Phase 1 列出的 references 与 helper 自检全部通过。无效候选只报告,不读其他内容。 - 在有效候选与
bootstrap_root中按 SemVer 选最新完整包为canonical_root;版本相同时优先项目外的安装包,版本较低的外部包不得反向降级项目。安装报告必须写出bootstrap_root、canonical_root、各自版本/用途与选择原因。 - 后续模板、helper 与 18 个中文主包 Skill 全部从
canonical_root读取;项目自定义 Skill 不进入 TRAE/WorkBuddy 本轮适配部署源,已有用户 Skill 保留不动。 copy-path-safety.py的status=same只让当前那一个 source/target 项 no-op;不得因项目内story-setup副本指向自身,就跳过从canonical_root刷新其他 Skills、Commands、Agents、Rules 和 Hooks。
canonical 中文主包 Skill 清单(所有 skills 复制分支共用)
canonical_root/skills/必须精确包含这 18 个可部署 Skill:browser-cdp、story、story-cover、story-data-analyze、story-deslop、story-explore、story-import、story-long-analyze、story-long-scan、story-long-write、story-publish、story-release-package、story-research、story-review、story-setup、story-short-analyze、story-short-scan、story-short-write。- 按上述固定名字集读取每个
SKILL.mdfrontmatter 的name/description;任一缺失、目录名与name不一致或重名时停止部署。不因项目根出现额外story*目录而扩张主包。 - 对每个源 Skill 目录与对应目标目录逐项执行
copy-path-safety.py;same记录为 no-op,unsafe/error停止,仅safe可复制。不对整个用户 skills 根目录做删除或整体替换。
TRAE / WorkBuddy 固定 Agent 名册
- 两端共用通用名册精确为 8 张:
chapter-extractor,character-designer,consistency-checker,narrative-writer,revision-governor,story-architect,story-explorer,story-researcher。 - TRAE 数据名册精确为 5 张:
story-data-fetcher,story-data-method-validator,story-data-metrics-analyst,story-data-supervisor,story-data-text-improvement-planner。TRAE 物理名册必须精确等于前述 8 张通用卡与这 5 张数据卡的并集,共 13 张。 - WorkBuddy 数据物理名册精确为 2 张:
story-data-fetcher,story-data-readonly-runner。WorkBuddy 物理名册必须精确等于前述 8 张通用卡与这 2 张数据卡的并集,共 10 张。四个只读逻辑角色卡随数据分析 Skill 自身部署,由其运行时映射定位,不作物理 Agent 注册。 - 两端都只备份/替换上述精确 marker 卡,保留用户 Agent;上次受管但本次不在对应精确名字集的卡走「管理资产收敛」备份后删除。
ZCode 部署算法(target_cli 含 zcode 时)
ZCode 首版部署 Skills、Commands、AGENTS.md 和支持事件内的 Hooks;不部署 .zcode/agents 或 .zcode/rules。
- 按「canonical 中文主包 Skill 清单」复制到
.zcode/skills/{skill-name}/;仅替换这 18 个已知目录,保留用户其他 Skills。 - 复制
references/zcode/commands/*.md到.zcode/commands/;仅替换与 canonical skill 同名的管理命令,保留用户其他 Commands。若主包某个 skill 缺预生成模板,视为包不完整并停止,不临时为项目扩展生成 command。 - 复制
references/zcode/hooks/story_zcode_hook.js和references/zcode/hooks/story_hook_core.js到.zcode/hooks/。 - 读取
references/zcode/config.json.patch和现有.zcode/config.json(如只有根zcode.json,仍创建.zcode/config.json承载 oh-story 项目 Hooks,不改写根文件):- 保留用户所有未知字段、MCP、plugins、skills/commands disable overrides;
- hooks 互斥(避免双触发):若本项目经已安装的 oh-story 插件运行(marketplace 安装,仓库根
.zcode-plugin/plugin.json的hooks.json已全局注册 SessionStart/PreToolUse/PostToolUse),则跳过下面把config.json.patch的hooks块合并进.zcode/config.json——插件 manifest 已注册这批 hooks,再合并会让同一事件跑两遍(PreToolUse 拦两次、PostToolUse 注入两次)。只有未装插件(直接克隆 / 手动导入 references)时才合并 hooks。不确定时以「ZCode 是否已通过本插件注册这套 hooks」为准;skills/commands/hook 文件/AGENTS 与 config 的非 hook 字段两条路径都照常部署。 - 合并 hooks(仅未装插件时):设置
hooks.enabled: true;用户已有更大的timeoutMs时保留,否则取模板值;对hooks.events的 SessionStart、PreToolUse、PostToolUse 按event + matcher + process command + args去重追加;不复制 ZCode 不支持的 PreCompact、PostCompact、SessionEnd、SubagentStop、Notification。
- 将
references/zcode/AGENTS.md.tmpl按「AGENTS.md 合并策略」写入根AGENTS.md。 .story-deployed的target_cli写入zcode或多端组合,references_dir写.zcode/skills/story-setup/references/agent-references。- 安装报告明确说明:ZCode 3.3.4 的项目/plugin custom agents 不执行,所有专业角色走 solo/direct;系统需要可用的
node命令运行项目 Hook。
Plugin 安装不经过本算法:仓库根 .zcode-plugin/plugin.json 直接暴露同一组 Skills/Commands/Hooks。Plugin Skills 优先级低于 workspace .zcode/skills;两者同时存在时项目快照优先,升级项目快照需重新运行 $story-setup。Hooks 只能注册一份:插件 manifest 与 workspace .zcode/config.json 注册的是同一批事件,装了插件就不要再把 config.json.patch 的 hooks 合并进 .zcode/config.json(见上算法第 4 步的 hooks 互斥),否则 PreToolUse/PostToolUse 会双触发;插件在场时以插件 manifest 为 hooks 唯一注册源。
TRAE hooks.json 合并算法(target_cli 含 trae 时)
- 读取
references/trae/hooks/hooks.json作为唯一当前模板,读取项目.trae/hooks.json(不存在时视为空对象)。TRAE 合法 schema 是顶层{ "version": 1, "hooks": {...} },事件值为 matcher group 数组,group 内是matcher+hooks,每个 hook 仅使用{ "type": "command", "command": "<单一 shell command 字符串>", "timeout": <秒> }。 - 按跨平台规则探测
python3/python/py;无可用解释器时停止 TRAE 分支,不手写或整体覆盖 JSON。 - 调用
"$PYBIN" "{story-setup skill目录}/scripts/merge-trae-hooks.py" --existing "{项目}/.trae/hooks.json" --template "{story-setup skill目录}/references/trae/hooks/hooks.json" --output "{项目}/.trae/hooks.json"。helper 只把 command 中包含.trae/hooks/story_trae_hook.js的注册识别为 oh-story 管理项:先从历史 event/matcher 块移除它们,再追加当前模板。同一 matcher 块中的用户 hook、其他事件、未知顶层字段全部保留。 - 写后校验
version == 1;事件名只能来自 TRAE 支持集SessionStart、UserPromptSubmit、PreToolUse、PostToolUse、Stop、Notification,当前模板不得出现SessionEnd、PreCompact、PostCompact、SubagentStop;hook 内不得出现 ZCode 的process/args/timeoutMs或 Claude 的if。正文工具 matcher 覆盖 TRAE 原生RunCommand|Write|Edit,commit advisory 覆盖RunCommand。 - 统计模板中每个 oh-story command 身份在结果中恰好一份,用户 hook/顶层字段仍在;再次运行 helper,必须与上次输出字节一致。
TRAE Code 原生部署算法(target_cli 含 trae 时)
TRAE 分支部署原生 Skills / Subagents / Commands / Rules / Hooks,不走 generic skills-only 降级模式。
- 按「canonical 中文主包 Skill 清单」确认固定 18 个 Skill。在任何写入前,按「TRAE 归属与备份门」为本次将改动的已存管理资产建立带 UTC 时间戳的备份;遇到无
oh-story-managed标记的同名文件则保留、记录冲突并停止该资产写入。 - 逐项过
copy-path-safety.py后,把 18 个 canonical Skill 复制到.trae/skills/{skill-name}/。目标缺失则创建;已是 oh-story skill(SKILL.md的metadata.openclaw.source指向本仓库,或含精确标记<!-- oh-story-managed: skill/{skill-name} -->)才可备份后替换。现有 sentinel 不能代替单个 Skill 的归属证据;无证据则保留并报告。status=same的 Skill 只验证,不复制进自身。 - 对 18 个 canonical 名字逐一部署
references/trae/commands/{name}.md;任一模板缺失即按部署包不完整停止,不为项目额外 Skill 生成 fallback command。只替换带相同管理标记的文件。 - 按「部署 TRAE Agents」与「TRAE / WorkBuddy 固定 Agent 名册」把通用 8 名与 TRAE 数据 5 名的精确并集(13 张)部署到
.trae/agents/。仅 Agent 内置 Agent 才能调用子 Agent;skill 流程遇到子 Agent 不可用必须走已定义的solo/directfallback。 - 将
references/trae/rules/*.md写入.trae/rules/,只替换带<!-- oh-story-managed: rule/... -->标记的文件;TRAE rule frontmatter 使用alwaysApply: false和globs,不复制 Claudepathsfrontmatter。将references/trae/AGENTS.md.tmpl按「AGENTS.md 合并策略」写入根AGENTS.md,只替换<!-- BEGIN oh-story-managed: trae -->与<!-- END oh-story-managed: trae -->之间的块,保留用户其他段落。 - 将
references/trae/hooks/story_trae_hook.js与story_hook_core.js写入.trae/hooks/;runner 只替换头注释证明为 oh-story TRAE adapter 的同名文件。既有 shared core 必须先运行trae-core-ownership.py --candidate <文件> --registry references/trae/legacy-managed-sha256.json,或证明与同项目受信 sibling core 字节一致;退出 3(unmanaged)/2(registry error)都保留并报告,不覆盖。替换后执行node --check与跨 adapter byte-parity 校验,再按「TRAE hooks.json 合并算法」合并.trae/hooks.json;禁止用模板整体覆盖用户配置。 Windows 的原生RunCommand由 PowerShell 提供,runner 必须同时覆盖已测试的静态Set-Content、Add-Content、Out-File、Copy-Item、Move-Item、New-Item写盘形式;动态表达式、splatting、.NETAPI 和未识别外部程序仍由 Skill 自检与写后门兜底,不得声称全部 PowerShell 写入都能在 PreToolUse 硬拦。 - 校验
.trae/skills/与.trae/commands/的受管名字集都精确等于 canonical 18,受管 Ag
…(truncated)