From 9eb97125f4c5473745a196dc51091ef251863f08 Mon Sep 17 00:00:00 2001 From: okash1n <48118431+okash1n@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:29:31 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20ultracode=20=E9=80=9A=E3=81=97=E3=83=AC?= =?UTF-8?q?=E3=83=93=E3=83=A5=E3=83=BC=E3=81=AE=E3=83=95=E3=82=A9=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=82=A2=E3=83=83=E3=83=97=20=E2=80=94=20custom=20upd?= =?UTF-8?q?ate=20=E3=81=AE=20agent-teams=20=E6=AC=A0=E8=90=BD=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E3=81=BB=E3=81=8B=EF=BC=88#138=E3=80=81v0.71.0?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - custom プロファイル update で agent-teams env が消える問題を修正(後発キーのデフォルト補完) - doc-blocker 拡張子ゲートの case-insensitive 化(SUMMARY.MD バイパス解消) - _strip_retired_hook_entries を /.claude/hooks/ にアンカー強化(ユーザー同名ディレクトリ保護) - agent-teams をウィザード・--hooks で切替可能に(#120 ギャップ)、GA トラッキング #139 起票 - effortLevel merge 2 ケース・spec-kit ゲート・retired 4 feature のテスト追加(unit 348) - CLAUDE.md 注入を delete モード化 + partial 区切り空行(体裁改善) - README ja/en・CLAUDE.md・hooks-reference・standard.conf のドキュメント残骸を掃除 Closes #138 --- CHANGELOG.md | 18 ++++++++ CLAUDE.md | 4 +- README.en.md | 12 ++--- README.md | 8 ++-- docs/GUIDES/hooks-reference.md | 5 +-- features/codex-plugin/CLAUDE.md.partial.en | 1 + features/codex-plugin/CLAUDE.md.partial.ja | 1 + .../doc-blocker/scripts/check-doc-write.sh | 2 +- i18n/en/CLAUDE.md.base | 1 - i18n/en/partials/spec-kit.md | 1 + i18n/en/partials/web-content-extraction.md | 1 + i18n/en/strings.sh | 1 + i18n/ja/CLAUDE.md.base | 1 - i18n/ja/partials/spec-kit.md | 1 + i18n/ja/partials/web-content-extraction.md | 1 + i18n/ja/strings.sh | 1 + lib/deploy.sh | 5 ++- lib/update.sh | 8 ++-- profiles/standard.conf | 2 +- tests/unit/test-merge.sh | 41 +++++++++++++++++ tests/unit/test-retired-hooks.sh | 45 +++++++++++++++++++ tests/unit/test-web-content-extraction.sh | 19 ++++++++ wizard/registry.sh | 3 ++ wizard/wizard.sh | 6 +++ 24 files changed, 163 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9975e95..f6dd432 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,24 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/). +## [0.71.0] - 2026-06-12 + +v0.57.0〜v0.70.0 の累積差分に対する multi-agent 通しレビュー(8 次元 + 14 Issue 受け入れ照合 + 敵対的検証)のフォローアップ(#138)。 + +### Fixed +- **custom プロファイルの update で agent-teams env が無言で削除される問題を修正(#138)**: update 経路は非対話デフォルト補完を通らず、custom プロファイルには conf ファイルが無いため、`ENABLE_AGENT_TEAMS` が空のまま fragment 不注入 → 3-way merge でキー削除となっていた。`_restore_config_from_manifest` に後発キーのデフォルト補完を追加 +- **doc-blocker の拡張子ゲートを case-insensitive 化(#138)**: `SUMMARY.MD` / `NOTES.TXT` のような大文字拡張子が ask 確認をバイパスしていた(slop 名判定は nocasematch 済みだったが外側の拡張子ゲートが case-sensitive だった) +- **`_strip_retired_hook_entries` のマッチを `/.claude/hooks//` にアンカー強化(#138)**: 廃止 feature と同名のディレクトリ配下にあるユーザー自作 hook(例: `~/dotfiles/hooks/memory-persistence/`)を誤って除去し得た非アンカー substring マッチを修正(回帰テスト付き) + +### Added +- **agent-teams をウィザード・`--hooks` CSV で切替可能に(#138、#120 の受け入れギャップ解消)**: `HOOK_KEYS` / `HOOK_TOKENS`(トークン `agent-teams`)/ `HOOK_LABELS` に登録し、custom プロファイルや `--hooks` 指定でオフにできるようにした。README の `--hooks` 例にも追加(`--hooks` は明示列挙のため、リストに含めない場合は無効化される点に注意) +- agent teams GA 時の env フラグ除去トラッキング Issue #139 を起票(#120 の受け入れギャップ解消) +- **テスト追加**: effortLevel ピン解除の merge 挙動 2 ケース(未変更→キー削除 / 上書き済み→値保持)、spec-kit partial の `INSTALL_COMMANDS` ゲート回帰テスト、retired 4 feature の一括 strip + ユーザー同名ディレクトリ保護のテスト(unit 計 348) + +### Changed +- **CLAUDE.md 注入の体裁改善(#138)**: 無効 feature のマーカー行を空行で残す replace モードから行ごと削除する delete モードに変更(minimal プロファイルの連続空行を解消)。各 partial 先頭に区切り空行を追加し、partial 同士の密着を解消 +- **ドキュメント残骸の掃除(#138)**: README ja のプロファイル比較表(メモリ行・旧フック数)・フック節見出し「15個」→「11個」・エディタ注記の廃止 hook 言及、README en のプロファイル表 Memory 列、profiles/standard.conf ヘッダコメント、リポジトリ CLAUDE.md(Inline hooks 例・Doc Size Guard 記述)、docs/GUIDES/hooks-reference.md の Compaction 節、lib/deploy.sh の spec-kit 注入ブロックの誤コメント + ## [0.70.0] - 2026-06-12 LLM 性能監査(#121)の最終弾(#120)。配布設定の世代依存ピンを整理した。これで監査計画 P1-P4 の全 14 Issue(#107〜#120)が完了。 diff --git a/CLAUDE.md b/CLAUDE.md index dc2d0cf..8aa4021 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -124,7 +124,7 @@ Each feature in `features/*/` has a `hooks.json` containing Claude Code hook def **IMPORTANT: Hook types (`SessionStart`, `SessionEnd`, `PreToolUse`, `PostToolUse`, `PreCompact`, `PostCompact`, `Stop`, `Notification`) MUST be nested inside a `"hooks"` key in hooks.json.** Claude Code reads hooks from `settings.json.hooks.*`, not from the top level. Top-level settings keys (`env`, `statusLine`, etc.) remain at the root. Three fragment styles exist: -- **Inline hooks**: bash commands embedded as escaped JSON strings in `hooks.json` `"command"` fields, nested inside `"hooks"` (e.g., `features/tmux-hooks/hooks.json`) +- **Inline hooks**: bash commands embedded as escaped JSON strings in `hooks.json` `"command"` fields, nested inside `"hooks"` (e.g., `features/pre-compact-commit/hooks.json`) - **External script hooks**: `hooks.json` references a script path with `__HOME__` token inside `"hooks"`, (e.g., `"hooks": {"PostToolUse": [{"hooks": [{"command": "__HOME__/.claude/hooks/doc-size-guard/check-doc-size.sh"}]}]}`). These scripts are deployed by `deploy_hook_scripts()` to `~/.claude/hooks//` with `chmod +x`. Both `.sh` and `.py` scripts are supported. - **Top-level settings**: `hooks.json` can contain any top-level settings key alongside `"hooks"`. The jq deep-merge applies at root level, so `{"statusLine": {...}}` and `{"env": {...}}` merge correctly (e.g., `features/statusline/hooks.json`, `features/safety-net/hooks.json`). @@ -262,7 +262,7 @@ Multiple features can safely use the same hook type (e.g., `PreCompact`, `PostCo - **Safety Net**: `cc-safety-net` PreToolUse hook blocks destructive shell/git operations and sets both canonical and legacy strict env names for fail-closed compatibility. - **Auto Update**: async SessionStart/SessionEnd update checks with lock/status files; older Claude versions use the legacy cache hook. - **Status Line**: Python statusLine command showing model, context usage, and 5h/7d rate limits. -- **Doc Size Guard**: validates CLAUDE.md/AGENTS.md line counts and broken path references after Write. +- **Doc Size Guard**: non-blocking size-hygiene warning when CLAUDE.md/AGENTS.md exceeds line targets after Write. - **Feature Recommendation**: writes pending feature names and notifies via SessionStart for enabled profiles. ## Platform Detection diff --git a/README.en.md b/README.en.md index bad6a86..0b1f065 100644 --- a/README.en.md +++ b/README.en.md @@ -164,11 +164,11 @@ Other supported editors: [Cursor](https://www.cursor.com/) (AI-native), [Zed](ht ## Profiles -| Profile | Agents | Rules | Commands | Skills | Hooks | Memory | Plugins | Codex Plugin | Ghostty | -|---------|--------|-------|----------|--------|-------|--------|---------|-----------|---------| -| Minimal | Yes | Yes | - | - | - | - | - | - | - | -| Standard (Recommended) | Yes | Yes | Yes | Yes | Core | Yes | 5 | Optional | - | -| Full | Yes | Yes | Yes | Yes | All | Yes | 14 | Yes | macOS only | +| Profile | Agents | Rules | Commands | Skills | Hooks | Plugins | Codex Plugin | Ghostty | +|---|---|---|---|---|---|---|---|---| +| Minimal | Yes | Yes | - | - | - | - | - | - | +| Standard (Recommended) | Yes | Yes | Yes | Yes | Core | 5 | Optional | - | +| Full | Yes | Yes | Yes | Yes | All | 14 | Yes | macOS only | - **Minimal**: Lightweight start with just agents and rules - **Standard**: Best for most teams. Includes commands, skills, and core hooks @@ -327,7 +327,7 @@ NONINTERACTIVE=1 bash -c "$(curl -fsSL https://raw.githubusercontent.com/cloudna --new-init=true \ --codex-plugin=false \ --commit-attribution=false \ - --hooks=safety-net,auto-update,tmux,prettier,pr-log,pre-commit \ + --hooks=safety-net,auto-update,tmux,prettier,pr-log,pre-commit,agent-teams \ --plugins=security-guidance,commit-commands,pr-review-toolkit,document-skills@anthropic-agent-skills # Reuse a saved config diff --git a/README.md b/README.md index 893f3cb..72c74b4 100644 --- a/README.md +++ b/README.md @@ -366,7 +366,6 @@ cd claude-code-starter-kit > **エディタの質問について**: ステップ 5 で「どのエディタを使っていますか?」と聞かれます。 > これは使用しているエディタを記録するための設定です(現在この選択で挙動が変わる機能はありません)。 -> エディタの起動や差分表示は行いません。「なし」を選ぶとこのフックは追加されません。 > **エディタをインストールしていない場合や、わからない場合は「5) なし」を選んでください。** Claude Code の動作には影響しません。 > エディタの詳細は「[エディタ(コードエディタ)とは?](#エディタコードエディタとは)」をご覧ください。 @@ -404,8 +403,7 @@ cd claude-code-starter-kit | ルール(コーディング規約) | ✅ | ✅ | ✅ | | コマンド(ショートカット) | - | ✅ | ✅ | | スキル(専門知識) | - | ✅ | ✅ | -| フック(安全装置) | - | 主要(11個) | 全部(14個) | -| メモリ(記憶の永続化) | - | ✅ | ✅ | +| フック(安全装置) | - | 主要 | 全部 | | プラグイン(拡張機能) | - | 5個 | 14個 | | フォント(IBM Plex Mono / HackGen NF) | - | ✅ | ✅ | | Codex Plugin(外部 AI 連携) | - | 任意 | ✅ | @@ -462,7 +460,7 @@ URL・公式ドキュメント・ブログ・ニュース・OSS ページを読 - **セキュリティ**: SSRF 多層防御(http(s) 限定・内部/プライベート IP 拒否・接続 IP pin・リダイレクト各ホップ検査)、非フェッチ DOM(外部サブリソース取得・スクリプト実行なし)、PDF は CJK 対応・解凍爆弾対策付き。開発時のみ `ALLOW_PRIVATE_URLS=true` で内部 URL を許可。 - **依存の自動更新(opt-in)**: `web-content-update` フックが SessionStart でスキルの依存(defuddle/jsdom/pdfjs-dist)を更新(24h スロットル・テストゲート+ロールバック)。**Full のみ既定有効**、Standard では opt-in。手動更新は `npm run update:deps`。 -### 🪝 フック(安全装置・15個) +### 🪝 フック(安全装置・11個) フックは **自動で動作する安全装置** です。コードを書いたり保存したりしたときに、自動でチェックが走ります。 @@ -853,7 +851,7 @@ NONINTERACTIVE=1 bash -c "$(curl -fsSL https://raw.githubusercontent.com/cloudna --codex-plugin=false \ --commit-attribution=false \ --ghostty=true \ - --hooks=safety-net,auto-update,tmux,prettier,pr-log,pre-commit \ + --hooks=safety-net,auto-update,tmux,prettier,pr-log,pre-commit,agent-teams \ --plugins=security-guidance,commit-commands,pr-review-toolkit,document-skills@anthropic-agent-skills ``` diff --git a/docs/GUIDES/hooks-reference.md b/docs/GUIDES/hooks-reference.md index 5d761da..c66115a 100644 --- a/docs/GUIDES/hooks-reference.md +++ b/docs/GUIDES/hooks-reference.md @@ -21,6 +21,5 @@ ## Compaction 前後の流れ(関連機能が有効な場合) -- `PreCompact`: compaction でコンテキストが要約される前に走る(例: pre-compact-commit のスナップショット) -- `PostCompact`: compaction 完了直後に走る -- `SessionStart`: 次セッション開始時の復元・通知に使う +- `PreCompact`: compaction でコンテキストが要約される前に走る(例: pre-compact-commit の stash スナップショット。opt-in) +- セッション状態の保存・復元はキットの hook では行わない — Claude Code ネイティブの auto-memory / checkpoint・rewind / --resume に委譲している diff --git a/features/codex-plugin/CLAUDE.md.partial.en b/features/codex-plugin/CLAUDE.md.partial.en index 1837b22..b9f86f4 100644 --- a/features/codex-plugin/CLAUDE.md.partial.en +++ b/features/codex-plugin/CLAUDE.md.partial.en @@ -1,3 +1,4 @@ + --- # Codex Plugin diff --git a/features/codex-plugin/CLAUDE.md.partial.ja b/features/codex-plugin/CLAUDE.md.partial.ja index d2ffb0f..f30c61c 100644 --- a/features/codex-plugin/CLAUDE.md.partial.ja +++ b/features/codex-plugin/CLAUDE.md.partial.ja @@ -1,3 +1,4 @@ + --- # Codex プラグイン diff --git a/features/doc-blocker/scripts/check-doc-write.sh b/features/doc-blocker/scripts/check-doc-write.sh index f37f850..f12b01a 100755 --- a/features/doc-blocker/scripts/check-doc-write.sh +++ b/features/doc-blocker/scripts/check-doc-write.sh @@ -35,7 +35,7 @@ _doc_blocker_slop_name() { return "$matched" } -if [[ "$file_path" =~ \.(md|txt)$ ]] && ! _doc_blocker_allowed_path "$file_path"; then +if [[ "$file_path" =~ \.([Mm][Dd]|[Tt][Xx][Tt])$ ]] && ! _doc_blocker_allowed_path "$file_path"; then base="$(basename "$file_path")" if _doc_blocker_slop_name "$base"; then jq -cn --arg path "$file_path" '{ diff --git a/i18n/en/CLAUDE.md.base b/i18n/en/CLAUDE.md.base index 7d59349..da3cb68 100644 --- a/i18n/en/CLAUDE.md.base +++ b/i18n/en/CLAUDE.md.base @@ -3,7 +3,6 @@ ## Basic Principles - Follow the repository's existing commit style; use Conventional Commits format (feat: / fix: / refactor: / test: / docs: / chore:) when no convention exists - {{FEATURE:spec-kit}} {{FEATURE:web-content-extraction}} {{FEATURE:codex-plugin}} diff --git a/i18n/en/partials/spec-kit.md b/i18n/en/partials/spec-kit.md index 22bb682..98769c6 100644 --- a/i18n/en/partials/spec-kit.md +++ b/i18n/en/partials/spec-kit.md @@ -1,2 +1,3 @@ + ## Optional: GitHub Spec Kit - Run `/spec-kit-init` inside a project to bootstrap spec-driven development with GitHub Spec Kit (details, marker rules, and constitution precedence are documented in the command). diff --git a/i18n/en/partials/web-content-extraction.md b/i18n/en/partials/web-content-extraction.md index 0dcd399..d6cdc85 100644 --- a/i18n/en/partials/web-content-extraction.md +++ b/i18n/en/partials/web-content-extraction.md @@ -1,3 +1,4 @@ + ## Web Fetch / URL Analysis - When reading a web page, URL, official doc, blog post, news article, or OSS page, extract the main content with the `web-content-extraction` skill first (do not summarize or analyze raw HTML directly). diff --git a/i18n/en/strings.sh b/i18n/en/strings.sh index f3d1b73..e372f02 100644 --- a/i18n/en/strings.sh +++ b/i18n/en/strings.sh @@ -92,6 +92,7 @@ STR_HOOKS_BIOME="Biome Auto-format - Format and lint JS/TS files after edits" STR_HOOKS_PR_LOG="PR Creation Log - Log PR URL after creation" STR_HOOKS_PRE_COMMIT="Pre-compact Snapshot - Stash tracked changes before context compaction (opt-in)" STR_HOOKS_DOC_SIZE="Doc Size Guard - Warn when CLAUDE.md/AGENTS.md is too large" +STR_HOOKS_AGENT_TEAMS="Agent Teams (experimental) - Enable Claude Code agent teams (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS)" STR_HOOKS_FEATURE_RECOMMENDATION="Feature Recommendation - Notify about new features on session start" # web-content-extraction skill dependency install (deploy-time messages) diff --git a/i18n/ja/CLAUDE.md.base b/i18n/ja/CLAUDE.md.base index cfb4bb3..b275fa8 100644 --- a/i18n/ja/CLAUDE.md.base +++ b/i18n/ja/CLAUDE.md.base @@ -3,7 +3,6 @@ ## 基本方針 - リポジトリに既存のコミット規約がある場合はそれに従い、ない場合は Conventional Commits 形式(feat: / fix: / refactor: / test: / docs: / chore:)を使う - {{FEATURE:spec-kit}} {{FEATURE:web-content-extraction}} {{FEATURE:codex-plugin}} diff --git a/i18n/ja/partials/spec-kit.md b/i18n/ja/partials/spec-kit.md index 8049598..3f1286f 100644 --- a/i18n/ja/partials/spec-kit.md +++ b/i18n/ja/partials/spec-kit.md @@ -1,2 +1,3 @@ + ## オプション: GitHub Spec Kit - プロジェクト内で `/spec-kit-init` を実行すると GitHub Spec Kit による仕様駆動開発を導入できる(詳細・マーカー規則・constitution の優先順位はコマンド側に記載)。 diff --git a/i18n/ja/partials/web-content-extraction.md b/i18n/ja/partials/web-content-extraction.md index ed2a455..49f1aa1 100644 --- a/i18n/ja/partials/web-content-extraction.md +++ b/i18n/ja/partials/web-content-extraction.md @@ -1,3 +1,4 @@ + ## Web取得・URL解析 - Webページ・URL・公式Doc・ブログ・ニュース・OSSページを読むときは、`web-content-extraction` skill で本文を抽出してから読む(生HTMLをそのまま要約・分析しない)。 diff --git a/i18n/ja/strings.sh b/i18n/ja/strings.sh index 58e8da3..98f4d82 100644 --- a/i18n/ja/strings.sh +++ b/i18n/ja/strings.sh @@ -90,6 +90,7 @@ STR_HOOKS_BIOME="Biome 自動フォーマット - JS/TS ファイルを編集後 STR_HOOKS_PR_LOG="PR 作成ログ - PR 作成後に URL をログ" STR_HOOKS_PRE_COMMIT="コンパクト前スナップショット - compact 前に tracked 変更を git stash に退避(opt-in)" STR_HOOKS_DOC_SIZE="ドキュメントサイズガード - CLAUDE.md/AGENTS.md の肥大化を警告" +STR_HOOKS_AGENT_TEAMS="Agent Teams(実験的) - Claude Code の agent teams を有効化(CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS)" STR_HOOKS_FEATURE_RECOMMENDATION="機能レコメンド - セッション開始時に新機能を通知" # web-content-extraction skill dependency install (deploy-time messages) diff --git a/lib/deploy.sh b/lib/deploy.sh index 0610404..160aeb8 100644 --- a/lib/deploy.sh +++ b/lib/deploy.sh @@ -509,12 +509,13 @@ build_claude_md_to_file() { cp -a "$base" "$out" - # Web content extraction standard rule — only when the skill is installed + # Spec Kit pointer — only when commands (incl. /spec-kit-init) are installed if is_true "${INSTALL_COMMANDS:-false}"; then local sk_partial="$PROJECT_DIR/i18n/${lang}/partials/spec-kit.md" inject_feature "$out" "spec-kit" "$sk_partial" fi + # Web content extraction standard rule — only when the skill is installed if is_true "${INSTALL_SKILLS:-false}"; then local wce_partial="$PROJECT_DIR/i18n/${lang}/partials/web-content-extraction.md" inject_feature "$out" "web-content-extraction" "$wce_partial" @@ -525,7 +526,7 @@ build_claude_md_to_file() { inject_feature "$out" "codex-plugin" "$partial" fi - remove_unresolved "$out" + remove_unresolved "$out" "delete" } # --------------------------------------------------------------------------- diff --git a/lib/update.sh b/lib/update.sh index f9118fa..ccc2705 100644 --- a/lib/update.sh +++ b/lib/update.sh @@ -550,18 +550,20 @@ _RETIRED_HOOK_FEATURES=(memory-persistence strategic-compact console-log-guard g # _strip_retired_hook_entries - Remove hook commands referencing retired # feature script dirs (~/.claude/hooks//) from settings.json, then -# drop matchers/events left empty. +# drop matchers/events left empty. The pattern is anchored on "/.claude/" so +# a user script that merely lives under a directory named after a retired +# feature (e.g. ~/dotfiles/hooks/memory-persistence/) never matches. _strip_retired_hook_entries() { local settings_file="$1" [[ -f "$settings_file" ]] || return 0 local feature tmp changed=false for feature in "${_RETIRED_HOOK_FEATURES[@]}"; do - jq -e --arg p "/hooks/${feature}/" ' + jq -e --arg p "/.claude/hooks/${feature}/" ' [(.hooks // {}) | to_entries[] | .value[]?.hooks[]? | (.command // "")] | any(contains($p)) ' "$settings_file" >/dev/null 2>&1 || continue tmp="$(mktemp)" - if jq --arg p "/hooks/${feature}/" ' + if jq --arg p "/.claude/hooks/${feature}/" ' if .hooks then .hooks |= (to_entries | map(.value |= (map((.hooks //= []) | .hooks |= map(select((.command // "") | contains($p) | not))) diff --git a/profiles/standard.conf b/profiles/standard.conf index 377fc37..f5f4299 100644 --- a/profiles/standard.conf +++ b/profiles/standard.conf @@ -1,5 +1,5 @@ # Standard profile: Recommended for most users -# Agents + Rules + Commands + Skills + Core hooks + Memory +# Agents + Rules + Commands + Skills + Core hooks ENABLE_NEW_INIT=true diff --git a/tests/unit/test-merge.sh b/tests/unit/test-merge.sh index 726f438..73cd610 100644 --- a/tests/unit/test-merge.sh +++ b/tests/unit/test-merge.sh @@ -762,3 +762,44 @@ _write_json() { rm -f "$snapshot" "$current" "$new_kit" "$output" unset _prev_interactive } + +# --------------------------------------------------------------------------- +# effortLevel pin removal (#120/#138): kit-removed key is deleted for +# unchanged users and preserved for users who overrode it +# --------------------------------------------------------------------------- +{ + test_name="3way: kit-removed effortLevel is deleted when user never changed it" + snapshot="$(_write_json '{"effortLevel": "high", "language": "en"}')" + current="$(_write_json '{"effortLevel": "high", "language": "en"}')" + new_kit="$(_write_json '{"language": "en"}')" + output="$(mktemp)" + + run_func merge_settings_3way "$snapshot" "$current" "$new_kit" "$output" + + if [[ "$_RF_RC" -eq 0 ]] \ + && [[ "$(jq 'has("effortLevel")' "$output")" == "false" ]] \ + && assert_json_field "$output" '.language' "en"; then + pass "$test_name" + else + fail "$test_name" + fi + rm -f "$snapshot" "$current" "$new_kit" "$output" +} + +{ + test_name="3way: kit-removed effortLevel is preserved when user overrode it" + snapshot="$(_write_json '{"effortLevel": "high", "language": "en"}')" + current="$(_write_json '{"effortLevel": "max", "language": "en"}')" + new_kit="$(_write_json '{"language": "en"}')" + output="$(mktemp)" + + run_func merge_settings_3way "$snapshot" "$current" "$new_kit" "$output" + + if [[ "$_RF_RC" -eq 0 ]] \ + && assert_json_field "$output" '.effortLevel' "max"; then + pass "$test_name" + else + fail "$test_name" + fi + rm -f "$snapshot" "$current" "$new_kit" "$output" +} diff --git a/tests/unit/test-retired-hooks.sh b/tests/unit/test-retired-hooks.sh index f27e217..4ed2bee 100644 --- a/tests/unit/test-retired-hooks.sh +++ b/tests/unit/test-retired-hooks.sh @@ -15,6 +15,51 @@ _rh_run() { ' } +{ + test_name="retired-hooks: all retired feature entries are stripped in one pass" + _rh_all="$_rh_tmp/all-retired.json" + cat > "$_rh_all" <<'JSON' +{ + "hooks": { + "PreToolUse": [ + {"matcher": "*", "hooks": [ + {"type": "command", "command": "/home/u/.claude/hooks/strategic-compact/suggest-compact.sh"}, + {"type": "command", "command": "/home/u/.claude/hooks/git-push-review/remind.sh"} + ]} + ], + "PostToolUse": [ + {"matcher": "Edit|Write", "hooks": [ + {"type": "command", "command": "/home/u/.claude/hooks/console-log-guard/check-file.sh"} + ]} + ], + "SessionStart": [ + {"matcher": "*", "hooks": [ + {"type": "command", "command": "/home/u/.claude/hooks/memory-persistence/session-start.sh"} + ]} + ] + } +} +JSON + _rh_run "$_rh_all" >/dev/null 2>&1 + if [[ "$(jq -r '.hooks | length' "$_rh_all")" == "0" ]]; then + pass "$test_name" + else + fail "$test_name" + fi +} + +{ + test_name="retired-hooks: user script under a same-named dir outside ~/.claude is kept" + _rh_user="$_rh_tmp/user-dir.json" + printf '{"hooks":{"PreCompact":[{"matcher":"*","hooks":[{"type":"command","command":"/home/u/dotfiles/hooks/memory-persistence/mine.sh"}]}]}}\n' > "$_rh_user" + _rh_run "$_rh_user" >/dev/null 2>&1 + if [[ "$(jq -r '.hooks.PreCompact[0].hooks | length' "$_rh_user")" == "1" ]]; then + pass "$test_name" + else + fail "$test_name" + fi +} + { test_name="retired-hooks: memory-persistence entries are stripped, others kept" _rh_settings="$_rh_tmp/settings.json" diff --git a/tests/unit/test-web-content-extraction.sh b/tests/unit/test-web-content-extraction.sh index 2ee09fc..188296d 100644 --- a/tests/unit/test-web-content-extraction.sh +++ b/tests/unit/test-web-content-extraction.sh @@ -146,6 +146,25 @@ else fail "web-content-extraction: CLAUDE.md rule gating/markers incorrect" fi + +# --- spec-kit partial: gated on INSTALL_COMMANDS (mirror of the wce gate) --- +_wce_reset_flags +INSTALL_COMMANDS="true" +CLAUDE_DIR="$_wce_tmp/cmds-on"; mkdir -p "$CLAUDE_DIR" +build_claude_md >/dev/null 2>&1 || true +_wce_reset_flags +INSTALL_COMMANDS="false" +CLAUDE_DIR="$_wce_tmp/cmds-off"; mkdir -p "$CLAUDE_DIR" +build_claude_md >/dev/null 2>&1 || true +if grep -q "spec-kit-init" "$_wce_tmp/cmds-on/CLAUDE.md" \ + && ! grep -q "spec-kit-init" "$_wce_tmp/cmds-off/CLAUDE.md" \ + && ! grep -q "{{FEATURE:" "$_wce_tmp/cmds-on/CLAUDE.md" \ + && ! grep -q "{{FEATURE:" "$_wce_tmp/cmds-off/CLAUDE.md"; then + pass "spec-kit: CLAUDE.md pointer gated on INSTALL_COMMANDS, no stray markers" +else + fail "spec-kit: CLAUDE.md pointer gating/markers incorrect" +fi + # --- 8. Syntax check skill scripts when Node is available --- if command -v node >/dev/null 2>&1; then _wce_check_ok=true diff --git a/wizard/registry.sh b/wizard/registry.sh index 4e3d6ae..11be049 100644 --- a/wizard/registry.sh +++ b/wizard/registry.sh @@ -177,6 +177,7 @@ HOOK_KEYS=( "ENABLE_PRE_COMPACT_COMMIT" "ENABLE_DOC_SIZE_GUARD" "ENABLE_FEATURE_RECOMMENDATION" + "ENABLE_AGENT_TEAMS" ) HOOK_TOKENS=( @@ -191,6 +192,7 @@ HOOK_TOKENS=( "pre-commit" "doc-size" "feature-rec" + "agent-teams" ) HOOK_LABELS=() @@ -208,6 +210,7 @@ _init_hook_labels() { "${STR_HOOKS_PRE_COMMIT:-Pre-compact Snapshot}" "${STR_HOOKS_DOC_SIZE:-Doc Size Guard - Warn when CLAUDE.md/AGENTS.md is too large}" "${STR_HOOKS_FEATURE_RECOMMENDATION:-Feature Recommendation - Notify about new features on session start}" + "${STR_HOOKS_AGENT_TEAMS:-Agent Teams (experimental) - Enable Claude Code agent teams}" ) } diff --git a/wizard/wizard.sh b/wizard/wizard.sh index 2459355..ec098af 100755 --- a/wizard/wizard.sh +++ b/wizard/wizard.sh @@ -399,6 +399,12 @@ _restore_config_from_manifest() { ENABLE_CODEX_PLUGIN="$manifest_codex_plugin" fi + # Keys introduced after older installs get their intended default here. + # Profile conf covers minimal/standard/full, but custom has no conf file, + # so without this fill a custom-profile update would silently drop the + # agent-teams env fragment (3-way merge would then delete the key). + [[ -z "${ENABLE_AGENT_TEAMS:-}" ]] && ENABLE_AGENT_TEAMS="true" + _normalize_formatter_hooks _normalize_codex_state load_strings "$LANGUAGE"