mcpField
S
settings

settings

github.com/donchitos开发31.1k166 次安装2 周前更新
代码仓库

关于 settings

settings 是一项用于查看或修改 CCGS 项目配置的技能,可处理团队共享的 project.yaml 和个人覆盖文件 project.local.yaml。它按配置模式读取、校验并展示设置,也会在写入前检查键和值及审批要求。

主要功能

  1. 01查看全部或单项配置
  2. 02设置共享或本地 YAML 值
  3. 03解析配置来源与有效值
  4. 04校验枚举并检查已知键
  5. 05按自动化模式执行写入审批

适用场景

  1. 01查看项目当前生效配置
  2. 02修改个人本地覆盖项
  3. 03调整团队共享设置并确认写入
  4. 04识别无效或未被读取的配置键

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/donchitos/claude-code-game-studios --skill settings

安装后在 Claude Code 中输入/settings确认已加载。

详细介绍

/settings — 查看或更改项目配置

管理 project.yaml(团队范围的配置,会提交到版本控制)和 project.local.yaml (每位开发者的覆盖配置,会被 git 忽略)。使用此技能检查当前设置或更改设置,无需手动编辑 YAML。

自动化模式:解析 modes.automation(project.local.yaml → project.yaml → 默认值 collaborative)。Phase 4 和 Phase 5 中的审批关卡遵循 .claude/docs/automation-modes.md 中的模式。注意: 写入 project.yaml 属于 schema_changes 决策(默认 automation_always_ask 类别),因此即使处于 autonomous 模式,/settings 也会确认配置写入, 除非用户已将 schema_changes 从其始终询问列表中移除。

Phase 0:解析参数

确定用户调用的是以下四种形式中的哪一种:

形式模式
/settings(无参数)查看全部(Phase 2)
/settings <key>(单个参数,不含 =)查看一项(Phase 3)
/settings <key>=<value>(含 = 的单个参数)设置 YAML(Phase 4)
/settings --local <key>=<value>(--local 前缀)设置本地配置(Phase 5)

对于“设置 YAML”和“设置本地配置”,<key> 是点分隔的 YAML 路径(例如 modes.review_mode、testing.strict.logic),而 <value> 是新值。

**空操作数验证:**按 = 拆分 key=value 操作数后,如果 <key> 或 <value> 为空,则格式错误——转到 Phase 6(用法说明),而不是尝试写入。此规则适用于“设置 YAML”和“设置本地配置”两种路由:对于 --local,先去掉 --local 标记, 再以相同方式检查剩余操作数(因此,/settings --local =foo 和 /settings --local key= 都会转到 Phase 6)。

任何其他不符合上述四种形式的输入 → Phase 6(用法说明)。

Phase 1:加载辅助脚本

所有四个子命令都需要 yaml-helper.sh。将每次辅助函数调用作为独立的普通命令运行:

bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" <helper call>

<helper call> 是下方各阶段指定的函数,例如 resolve_setting modes.review_mode 或 validate_yaml_enum project.yaml。辅助脚本会自行切换到项目根目录,因此即使会话是在子文件夹中启动的,project.yaml 和 project.local.yaml 参数也能正确解析,并且会保留函数的退出状态。is_locally_overridable 也会输出 0 或 1。请严格按所示方式运行调用:不要 source 文件,不要用 cd ... && 包装,也不要追加 ; echo $?。此技能仅预先批准普通形式,复合命令每次都会询问用户。

如果缺少 .claude/hooks/yaml-helper.sh,说明这不是 CCGS 项目。 报告错误并退出。

阶段 1b:保留设置检测

有些设置有完整文档且可以设置,但没有任何技能或钩子会读取它们——设置它们不会产生任何变化。**本技能必须明确说明这一点。**如果返回普通的成功信息,用户完全有理由相信设置描述的行为已经生效——无障碍等级正是促使我们处理此问题的情况。(此处有意不点明该键;请参阅下方说明。)提示仅存在于 .claude/docs/effects-map.md 中,而配置项目的人永远不会打开这个文件。毫无作用的设置绝不能看起来和有效设置一模一样——这是 .claude/rules/skill-authoring.md 中义务 3 的要求。

推导这个集合;不要硬编码(义务 5):

grep -B14 '^> ### RESERVED' .claude/docs/effects-map.md | grep -E '^## '

匹配提示标题(> ### RESERVED),绝不要只匹配单词 “RESERVED”。 platform.cert_tier 的章节在说明文字中提到了该提示,用来记录它曾经带有此提示,后来则变成了有效设置。更宽泛的匹配会再次将一个有效设置报告为无效——这会低估框架的功能,也是无效设置检查需要验证两个方向的原因。

一个标题可能会用 “ and ” 连接两个键——按此分隔符拆分,确保两个键都被捕获,否则第二个键会悄悄漏出集合。将结果记为 RESERVED_SET。

此处刻意不点明这些键。无效设置检查会断言允许列表中的设置没有读取方,并统计任何写出该键的技能文件。在这里点名说明如何拆分,会让 /settings 看起来像是读取了两个实际上无人读取的设置,从而导致检查失败——而且这是正确的。在解释为何不该使用某条路径时写出无效路径,也会触发同样的检查。请改写,而不是添加豁免:严格执行正是目的,因此不要为了让示例更清楚而再次写出这些字面名称。

绝不要拒绝对保留键的写入。存储用户想要的值是合理的;缺陷在于悄无声息地存储它。

阶段 2:查看全部模式

(未提供参数时)

  1. 确认 project.yaml 存在。如果缺失,请报告:

    “未找到 project.yaml——请运行 /start 创建文件。” 然后退出。

  2. 检查 project.local.yaml 是否存在。

  3. 运行 validate_yaml_enum project.yaml 并捕获所有错误。 如果 project.local.yaml 存在,也运行 validate_yaml_enum project.local.yaml。 为每个错误标注其来源文件,以便用户区分。

  4. **枚举叶节点。**使用 Read 工具将两个 YAML 文件作为文本读取。遍历每个文件的结构,收集所有叶键,组成去重后的点分路径列表。叶节点是值非空的 key: value 行(标量或内联数组),不是引入嵌套映射的父级块。保持每个文件中的插入顺序;合并时,将 project.local.yaml 中尚未出现在 project.yaml 里的叶节点追加到列表。所得列表即为要显示的叶节点集合。

    然后追加严谨度系列设置——modes.rigor、modes.workflow、docs.density、qa.level、modes.story_granularity、modes.review_mode、team.size——若这七项中的任一项尚未包含在合并列表中,就将其追加。这些设置通常不是任一文件中的叶节点:modes.rigor 有终端默认值,另外六项由严谨度扩展提供(设置为本地值时,modes.review_mode 和 team.size 也可能作为文件叶节点出现,但仍必须追加,以显示其派生值)。只枚举文件叶节点会隐藏用户刚刚选择的设置,而这恰恰是唯一一个旨在展示这些设置的视图。

  5. 对每个叶子项,执行三次读取和一次检查:

    • resolve_setting <path> → <value>、TAB、<source>。此操作会遍历 整条链路(project.local.yaml → project.yaml → 旧版文件 → rigor 展开 → 默认值),因此只有它能报告派生值或指出值的来源。
    • get_yaml_key project.yaml <path> → 仅 YAML 值(仅当需要显示本地覆盖项所遮蔽的值时才需要)
    • is_locally_overridable <path> → 0(可覆盖)或 1(锁定)

    根据 <source> 计算来源标注:

    <source>标注
    project.local.yaml,仅 YAML 值非空(LOCAL OVERRIDE — yaml has: <yamlvalue>)
    project.local.yaml,仅 YAML 值为空(project.local.yaml)
    project.yaml(project.yaml)
    旧版文件路径(例如 production/review-mode.txt)(<path>, legacy)
    rigor:<level>(derived from rigor: <level>)
    default(default)
    unset跳过此叶子项(不要打印未设置的键)

    当 is_locally_overridable 返回 1 时,在标注后追加 , locked。

    如果叶子项属于 RESERVED_SET(阶段 1b),则追加 , reserved,并在代码块下方打印这一行图例:

    reserved = stored, but nothing reads it. Setting it changes
    no behaviour today.
    

    四个阶段都必须标记 reserved — 单项视图、全部视图,以及两种写入路径。 如果标记了单项视图和写入路径,却漏掉全部视图 — 这是此技能最常用的形式 — 那么设置了保留键的用户就会看到它与正常设置并列,且只带有普通的 (project.yaml) 标注,出现在大多数人实际使用的视图中。四处都要防护:单项视图和全部视图完全相同,就像两种写入路径一样。

  6. 按顶层分组打印(framework、modes、 engine 等),顺序按叶子项首次出现的顺序排列。分组由点分路径决定,而不是由叶子项来自哪个文件决定 — 例如,即使只有 project.local.yaml 定义了 modes.automation,它也应归入 modes:。每个分组内的叶子项缩进 2 个空格;子块进一步缩进(例如 testing.strict.*)。 输出示例:

project.yaml: present
project.local.yaml: present

Schema validation: ok

Effective config:

framework:
  version: 1.2.0            (project.yaml, locked)

modes:
  review_mode: lean         (project.yaml)
  automation: autonomous    (LOCAL OVERRIDE — yaml has: collaborative)
  rigor: full               (project.yaml, locked)
  workflow: full            (derived from rigor: full, locked)
  story_granularity: fine   (derived from rigor: full, locked)

docs:
  density: terse            (project.yaml, locked)

qa:
  level: full               (derived from rigor: full, locked)

engine:
  name: Godot               (project.yaml, locked)
  version: 4.7              (project.yaml, locked)

testing:
  strict:
    logic: false            (LOCAL OVERRIDE — yaml has: true)
    integration: true       (project.yaml)

locked = cannot be overridden in project.local.yaml (project-wide setting).
It does NOT mean fixed: a derived value can still be set explicitly with
/settings <key>=<value>, and an explicit value wins over rigor.

只要任何已渲染的行带有 locked,就应在配置块之后打印这两行图例。否则,用户会把 locked 理解为“不可变”,并得出由 rigor 派生的选项无法更改的结论 — 这与阶段 3 的单项视图对同一选项的说明(“显式值优先于 rigor”)正好相反。两个视图不能让用户对同一选项是否可变产生矛盾的印象。

上方的 docs.density 行体现了优先级规则:显式设置的 project.yaml 值会继续优先于 rigor 原本会派生出的值,因此仍可表达“全面但简洁”。

如果存在 schema 错误,请按以下格式在有效配置块之前打印:

Schema validation: ERRORS
  [project.yaml] modes.review_mode: 'chaotic' is not a valid value (expected: full|lean|solo)
  [project.local.yaml] engine.name: 'Pygame' is not a valid value (expected: Godot|Unity|Unreal)

阶段 3:查看单个模式

(仅有一个参数时,不含 =)

如果 <key> 在 RESERVED_SET 中,请在值块之前打印此内容——放在上方, 不要放在下方。在一个有效设置的值下方添加注意事项,会被视为脚注:

<key> 已保留——没有任何内容会读取它。 下方的值已存储,但 当前不会改变任何行为。

将参数记为 <key>。执行四次读取:

  1. resolve_setting <key> → <value>、TAB、<source>(有效值 + 来源信息)
  2. get_yaml_key project.yaml <key> → 仅 YAML 值
  3. get_yaml_key project.local.yaml <key> → 仅本地值(文件不存在时跳过)
  4. is_locally_overridable <key> → 0(可覆盖)或 1(锁定)

根据 <source> 确定来源(与阶段 2 第 5 步使用相同的表), 并确定本地覆盖状态:

  • 如果仅本地值非空,则为 yes
  • 否则为 no

打印:

<key>

  Effective value: <effective-value or "(not set)" if <source> is unset>
  Source: <project.yaml | project.local.yaml | project.local.yaml (overrides project.yaml) | derived from rigor: <level> | default>
  Locally overridden: <yes | no>
  Whitelist: <"can be locally overridden" if is_locally_overridable returned 0, else "locked — project-wide">

如果两个文件都设置了此键(即本地覆盖情况),请在“来源”下方再添加两行:

  project.yaml value: <yamlvalue>
  project.local.yaml value: <localvalue>

当 <source> 为 rigor:<level> 时,请在“来源”下方添加一行,让用户 知道该值可以设置,以及如何设置:

  Set explicitly with: /settings <key>=<value>   (an explicit value wins over rigor)

当有效值为空(该键在任何地方都未设置)时,仅打印:

<key>

  Effective value: (not set)
  Locally overridden: no
  Whitelist: <"can be locally overridden" | "locked — project-wide">

阶段 4:Set-yaml 模式

(当使用 <key>=<value> 且不带 --local 时)

  1. 架构验证:调用 validate_enum_value <key> <value>。如果 返回 1,则将 stderr 行原样展示给用户 (Invalid value '<value>' for '<key>'. Allowed: ...),技能 随即退出,不进行写入。如果返回 0,则该值有效,或该键没有枚举约束——继续。

1b. 已知键检查:按照阶段 1 中的方式,从项目根目录运行 bash .claude/scripts/config-set.sh <key> <value> --dry-run,并读取其 known 行。如果显示 yes,则继续。如果显示 no,说明 CCGS 中没有任何内容会读取 该键,因此写入不会产生任何变化;这通常是拼写错误。暂时不要 写入:说明这一点,并通过 AskUserQuestion 询问,选项为 Use <nearest> instead(仅当该行以 nearest: <key> 结尾时显示)、 Write <key> anyway、Cancel。只有用户明确选择后才继续;如果跳过或 答案为空,则取消。选择 Use <nearest> instead 时,使用该键重新开始本阶段。

  1. 保留键警告:如果 <key> 在 RESERVED_SET(阶段 1b)中,请在审批提示 之前打印:

    "注意:<key> 是 RESERVED——没有技能或钩子会读取它,因此设置它不会 改变任何行为。无论如何,你的值都会被存储。"

    然后像往常一样继续审批关卡。阶段 5 会显示完全相同的 警告。一个写入路径显示警告,而另一个不显示,会留下通往相同结果的静默路径, 这正是此检查要防止的问题。

  2. 覆盖警告:读取 get_yaml_key project.local.yaml <key>。如果 返回非空值,请在审批提示之前打印:

    "注意:此设置当前在 project.local.yaml 中被本地覆盖(值:<localvalue>)。写入 project.yaml 不会改变你的有效值。"

  3. 审批关卡:使用 AskUserQuestion:

    • 提示:Set `<key>=<value>` in `project.yaml`?
    • 选项:[A] Yes, write / [B] No, cancel
  4. 使用 Edit 工具写入。编辑策略取决于 project.yaml 中 已有的内容:

    情况 A — 键已存在:读取 project.yaml。定位 <lastsegment>: <oldvalue> 这一行,以及它正上方引入其父级块的那一行(例如, modes.review_mode 的 modes:)。 构造 Edit,使 old_string 同时包含父级 块行和叶节点行,这样即使 <lastsegment>: <oldvalue> 出现在其他位置, 匹配也具有唯一性。modes.review_mode=full 的示例:

    old_string:
      modes:
        review_mode: lean
    new_string:
      modes:
        review_mode: full
    

    情况 B — 父级块存在,叶节点不存在:找到父级块的最后一行。 使用 Edit,在正确的缩进级别追加新的叶节点行,并使用 最后一个现有叶节点作为 old_string 锚点。

    情况 C — 父级块不存在:在文件末尾追加新的顶级 块(确定性操作——始终追加到文件末尾,绝不插入块与块之间)。使用 Edit, 将文件中最后一个非空行作为 old_string,并在其后追加新块。

    情况 D — 文件结构异常(存在同名注释键、嵌套关系不明确、YAML 格式错误):停止并通过 AskUserQuestion 询问:

    "无法在 project.yaml 中为 <key> 找到合适的插入位置。请告诉我该怎么做。"

  5. 确认:Set `<key>=<value>` in `project.yaml`.

    当 <key> 为 modes.rigor 时,此次写入还会调整其他六项配置,因此请打印它们现在解析出的值——对每项重新调用 resolve_setting,而不要照抄展开表,因为其中任何一项都可能带有优先级更高的显式值:

    Set modes.rigor=full in project.yaml. It now supplies:
      modes.workflow: full            (derived from rigor: full)
      docs.density: terse             (project.yaml — explicit, unchanged)
      qa.level: full                  (derived from rigor: full)
      modes.story_granularity: fine   (derived from rigor: full)
      modes.review_mode: full         (derived from rigor: full)
      team.size: studio               (derived from rigor: full)
    

第 5 阶段:本地模式

(当使用 --local <key>=<value> 时)

  1. 白名单检查:调用 is_locally_overridable <key>。

    • 如果返回 1(已锁定),打印一行:

      <key> 不能在本地覆盖——它是项目级设置。使用 `/settings <key>=<value>`(不带 `--local`)来为整个团队更改此设置。

    • 不写入并退出。
  2. 架构验证:调用 validate_enum_value <key> <value>。如果 返回 1,原样显示 stderr 消息,并且不写入就退出。

2a. 已知键检查:与第 4 阶段步骤 1b 相同,在 <key> 前加上 --local:如果 known 行显示 no,写入前先询问;如果该行提供了 nearest: 键,则提供该键。

2b. 保留键警告:如果 <key> 在 RESERVED_SET(第 1b 阶段)中,请在 确认提示前打印:

"注意:<key> 是 RESERVED——没有技能或 hook 会读取它,因此设置它 不会改变任何行为。无论如何,你的值都会被保存。"

与第 4 阶段步骤 2 相同,这是有意为之。两种写入路径都会将用户意图写入 同一个记录文件;如果只在一种路径中警告,--local 就会成为 不提示用户的途径。

  1. 基础文件检查:如果 project.yaml 不存在:

    "无法创建 project.local.yaml——缺少 project.yaml。请先运行 /start 创建该文件。" 退出。(根据规范,本地覆盖需要基础文件。)

  2. 确认关卡:使用 AskUserQuestion:

    • 提示:在 `project.local.yaml` 中设置 `<key>=<value>`(你的个人覆盖,已加入 gitignore)?
    • 选项:[A] 是,写入 / [B] 否,取消
  3. 写入:

    • 如果 project.local.yaml 不存在,使用 Write 创建该文件, 并将新设置置于其父级块中。--local modes.automation=autonomous 的最简 示例:
      # project.local.yaml — 每位开发者的覆盖设置(已加入 gitignore)
      modes:
        automation: autonomous
      
    • 如果文件存在,使用 Edit,并采用 第 4 阶段步骤 4 中相同的 Case A/B/C 策略。
  4. 确认:已在 `project.local.yaml` 中设置 `<key>=<value>`(你的覆盖设置)。

第 6 阶段:用法

当参数与四种有效形式都不匹配(或操作数为空)时,打印:

Usage:
  /settings                          — view all effective config
  /settings <key>                    — view a single setting
  /settings <key>=<value>            — change a setting (project.yaml)
  /settings --local <key>=<value>    — change a setting locally
                                       (project.local.yaml, gitignored)

Examples:
  /settings modes.review_mode
  /settings modes.review_mode=full
  /settings --local modes.automation=autonomous

说明

  • 所有 YAML 写入都通过 Edit(已有键/块)或 Write (新文件)完成。此技能不依赖 yq 或任何外部 YAML 库。
  • 白名单由 yaml-helper.sh (is_locally_overridable 函数)强制执行。要扩展白名单,请编辑 _yaml_helper_locally_overridable 常量——不要在此重复列出。
  • 派生值不会存储在任何地方。 modes.workflow、docs.density、 qa.level、modes.story_granularity、modes.review_mode 和 team.size 都没有 终端默认值;如果没有文件设置它们,其值将来自 yaml-helper.sh 中的 modes.rigor 展开逻辑(_yaml_helper_rigor_expansion)。使用 resolve_setting 报告它们——get_yaml_key 读取结果为空,会将其显示为“(未设置)”,但实际上每项技能都在依据真实值运行。
  • 架构验证所用的枚举常量位于 yaml-helper.sh (_yaml_helper_enums)。validate_enum_value 是用于待写入值的单键 验证器;validate_yaml_enum 用于验证整个文件(由 session-start.sh 使用)。
  • project.local.yaml 已加入 gitignore。这些 覆盖设置不会传播给队友。
  • 对于特定游戏类型或情境应选择哪个值,以及何时 建议更改设置,请参阅 .claude/docs/settings-guidance.md(建议预设值
    • 更改触发条件)。effects-map.md 说明各项设置的作用;该文档说明 应选择哪项设置。

评论

支持 Markdown