Skip to content

fix: eliminate code duplication with shared modules and composite actions - #652

Merged
keito4 merged 2 commits into
mainfrom
fix/refactor-dedup-shared-modules
Mar 30, 2026
Merged

fix: eliminate code duplication with shared modules and composite actions#652
keito4 merged 2 commits into
mainfrom
fix/refactor-dedup-shared-modules

Conversation

@keito4

@keito4 keito4 commented Mar 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • hooks/common.py: 11 hookファイルの共通コード(JSON入力パース、出力フォーマット、Git操作、PM検出)を共通モジュールに抽出
  • lib/config.sh: 8つのコピペ import/export 関数を2つのジェネリック関数に統合(-190行)
  • シェルスクリプト×10: カラー定義・ログ関数の重複を lib/output.sh の source 化で排除
  • GitHub Actions: setup-node-ci composite action を作成し、ci.yml / security.yml / update-libraries.yml の Node.js セットアップを一元化
  • テスト: credential-filtering.test.js の ittest 統一

28ファイル変更、純削減 -54行(457追加 / 511削除)

Test plan

  • Jest 全95テスト合格(5 suites)
  • Python 12 hookファイル全コンパイル成功
  • Hook動作テスト(block_dangerous_commands, block_git_no_verify, block_config_edit)
  • pre-commit hooks(format:check, lint, test)全パス
  • CI ワークフロー実行確認

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor

    • Consolidated shared utilities for hook scripts to standardize input parsing, command detection, Git and package-manager helpers, and uniform output formatting.
    • Centralized shell script output/logging and config import/export logic for consistent behavior.
  • New Features

    • Added a composite GitHub Action to set up Node.js and enable npm caching.
  • Tests

    • Broadened CI workflow tests and updated test syntax/assertions for compatibility.

…ions

Extract duplicated patterns across hooks, shell scripts, and workflows:
- Create hooks/common.py shared module (JSON parsing, output formatting, git ops)
- Consolidate lib/config.sh 8 copy-paste functions into 2 generic functions
- Replace color/log definitions in 10 shell scripts with lib/output.sh sourcing
- Create .github/actions/setup-node-ci composite action for 3 workflows
- Standardize test assertion style (it -> test) in credential-filtering tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 877cfbe1-cf4d-48a8-baa5-5235afae10be

📥 Commits

Reviewing files that changed from the base of the PR and between 0732b23 and 039b000.

📒 Files selected for processing (2)
  • test/integration/e2e-scenarios.bats
  • test/integration/workflows.bats

📝 Walkthrough

Walkthrough

Refactors multiple .claude hook scripts to use a new shared .claude/hooks/common.py for input, command parsing, git/package helpers, and standardized stderr output; adds a composite GitHub Action for Node/npm setup and updates workflows; many shell scripts now source a shared script/lib/output.sh; script/lib/config.sh is generalized.

Changes

Cohort / File(s) Summary
Hook common utilities & refactors
./.claude/hooks/common.py, ./.claude/hooks/block_config_edit.py, ./.claude/hooks/block_dangerous_commands.py, ./.claude/hooks/block_git_no_verify.py, ./.claude/hooks/post_commit_adr_reminder.py, ./.claude/hooks/post_edit_auto_lint.py, ./.claude/hooks/post_git_push_ci.py, ./.claude/hooks/post_pr_ai_review.py, ./.claude/hooks/post_pr_ci_watch.py, ./.claude/hooks/pre_exit_plan_ai_review.py, ./.claude/hooks/pre_git_quality_gates.py
Added common.py with load_hook_input, parsing, command helpers, git/package detection, output formatting, and PR URL extraction; updated hooks to call these helpers instead of parsing stdin/JSON and duplicating logic.
Git/package helpers used by test hook
./.claude/hooks/stop_test_verification.py
Replaced inline git-root discovery and package-manager detection with get_git_root() and detect_package_manager() from common.py.
GitHub Actions composite
./.github/actions/setup-node-ci/action.yml
New composite action to set Node using .node-version and optionally run npm ci with caching.
Workflows updated to use composite
./.github/workflows/ci.yml, ./.github/workflows/security.yml, ./.github/workflows/update-libraries.yml
Replaced repeated actions/setup-node + npm ci steps with the local ./.github/actions/setup-node-ci composite action in several workflows.
Shell scripts source shared output lib
script/branch-cleanup.sh, script/changelog-generator.sh, script/code-complexity-check.sh, script/container-health.sh, script/dependency-health-check.sh, script/pre-pr-checklist.sh, script/security-credential-scan.sh, script/test-coverage-trend.sh, script/update-actions.sh, script/update-all.sh
Scripts now attempt to source script/lib/output.sh for color constants and logging helpers, with inline fallback definitions when sourcing fails.
Config library generalization
script/lib/config.sh
Introduced generic config::_import_tool / config::_export_tool and refactored per-tool wrappers to delegate to them, reducing duplication in import/export logic.
Tests & CI assertions
test/credential-filtering.test.js, test/integration/e2e-scenarios.bats, test/integration/workflows.bats
Switched test declarations from it(...) to test(...); broadened CI workflow checks to accept setup-node-ci composite action or npm ci and updated corresponding assertions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

released, size/S

Poem

🐰 I hopped through hooks and workflow lanes,
Collected echoes, folded plains,
Shared helpers stitched each lonely script,
Colors sourced, and tests equipped —
A tiny rabbit tidies up the trains.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of the pull request: eliminating code duplication through shared modules and composite actions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/refactor-dedup-shared-modules

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@keito4

keito4 commented Mar 30, 2026

Copy link
Copy Markdown
Owner Author

🔍 AI Code Review (Local Hook)

Models: Codex (default) / Gemini (default)

🤖 Codex Review

指摘事項
なし。

判定
patch is correct — 変更は共通化と出力整備が中心で、機能要件や既存の挙動を壊すリスクは見当たりませんでした。信頼度 0.72


🤖 Generated by post_pr_ai_review.py hook

@keito4 keito4 self-assigned this Mar 30, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0732b232a4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread script/update-all.sh
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Source shared output library (provides log_info, log_success, log_warn, color vars)
# shellcheck source=/dev/null
source "$SCRIPT_DIR/lib/output.sh" 2>/dev/null || {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Define log_error on the sourced output-lib path

This refactor makes source "$SCRIPT_DIR/lib/output.sh" the default path, but output.sh does not provide log_error, and log_error is now only defined inside the fallback block. When any error path is taken (for example invalid args at --bogus or a failed sub-step), the script crashes with log_error: command not found instead of reporting the intended error and continuing its failure handling.

Useful? React with 👍 / 👎.

Comment thread script/update-actions.sh
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Source shared output library (provides log_info, log_success, log_warn, color vars)
# shellcheck source=/dev/null
source "$SCRIPT_DIR/lib/output.sh" 2>/dev/null || {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep log_error available after sourcing output helpers

In the normal execution path where lib/output.sh is successfully sourced, log_error is undefined (that helper file exports log_info/log_success/log_warn only), so the required-command check now fails with command not found when gh is missing. This breaks the script's explicit dependency error handling and produces an opaque failure instead of the intended actionable message.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (5)
.github/workflows/ci.yml (1)

164-164: Consider whether npm dependencies are needed for integration tests.

The integration-test job runs .bats files that validate npm command availability and check for npm usage in workflow files (via grep patterns), but don't execute npm packages directly. If install: 'false' is passed, Node.js setup still provides the npm command, allowing tests like command_exists npm to pass while skipping the slower npm ci step.

💡 Potential optimization if npm package installation isn't needed
       - uses: ./.github/actions/setup-node-ci
+        with:
+          install: 'false'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yml at line 164, The integration-test job currently
invokes the custom action setup-node-ci which installs npm packages; if the
.bats integration tests only need the npm binary (not installed packages),
update the job to skip npm package installation by providing the action input to
disable install (e.g., pass install: 'false' to the setup-node-ci action) or
remove the action entirely and only ensure Node/npm is available; locate
references to the integration-test job and the uses:
./.github/actions/setup-node-ci entry and change the action invocation to pass
the install flag so npm is available but npm ci is skipped.
.claude/hooks/common.py (2)

47-49: Minor: -h substring match may have false positives.

The current check "-h" in command could match substrings in paths or other flags (e.g., --http, /path-here/). Since this is used for early-exit optimization, false positives are safe but may skip processing unnecessarily.

♻️ Optional: Use word boundary matching
+import re
+
 def is_help_command(command: str) -> bool:
     """Check if command is a help/dry-run command."""
-    return "--help" in command or "-h" in command
+    return bool(re.search(r'--help\b', command) or re.search(r'\s-h\b', command))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/hooks/common.py around lines 47 - 49, The is_help_command function
currently uses substring checks which cause false positives (e.g., matching "-h"
inside paths or other flags); change it to detect standalone help flags by
parsing the command into arguments or using word-boundary regex checks so only
an exact "-h" or "--help" token triggers true (update is_help_command to split
the command into args or apply regex like token boundaries and return True only
when "-h" or "--help" appears as a separate token).

1-16: Add unit tests for this shared module.

This module provides critical utilities (input parsing, command extraction, Git operations) used by 11 hook files. The existing test suite only validates syntax and basic structure; specific tests for these utility functions would prevent regressions across dependent hooks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/hooks/common.py around lines 1 - 16, Add focused unit tests for the
shared utilities in .claude/hooks/common.py: write tests that (1) validate JSON
input parsing from stdin (simulate sys.stdin to exercise the parse function that
reads JSON), (2) exercise tool context extraction (call the function that
extracts tool/context fields from input objects and assert expected outputs and
error handling), (3) verify output formatting helpers (headers, sections, status
functions produce expected strings), (4) stub subprocess/git interactions to
test Git operation helpers (e.g., the function that runs git commands returns
expected output and handles failures), and (5) test package manager detection
(feed different filesystem/project layouts or mocked Path.exists to assert
detection logic). Use pytest with fixtures and monkeypatch to simulate stdin,
subprocess, and filesystem, and include edge cases and error paths for each
referenced function to prevent regressions across the 11 dependent hooks.
script/test-coverage-trend.sh (1)

9-12: Consider removing the SC2034 disable for consistency.

This file includes # shellcheck disable=SC2034 (line 10) inside the fallback block, but the other 7 scripts using this same pattern do not. All color variables (RED, GREEN, YELLOW, BLUE, NC) are actually used in this script, so the suppression appears unnecessary.

For consistency across the refactored scripts, consider removing the extra directive:

♻️ Suggested diff
 # shellcheck source=/dev/null
 source "$SCRIPT_DIR/lib/output.sh" 2>/dev/null || {
-  # shellcheck disable=SC2034
   readonly RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m'
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@script/test-coverage-trend.sh` around lines 9 - 12, Remove the unnecessary
shellcheck suppression: delete the comment "# shellcheck disable=SC2034" from
the fallback block so the linter runs normally, leaving the readonly color
variable declarations (RED, GREEN, YELLOW, BLUE, NC) intact; this keeps the
readonly assignments in the fallback while matching the pattern used in the
other scripts.
script/lib/config.sh (1)

211-223: Clarify Gemini's "warning only" intent with an explicit directory check.

The || return 0 pattern catches both missing source directory and other failures from the helper function. While the helper already handles missing directories gracefully, the wrapper's broad exception clause masks other potential errors. An explicit pre-check for the directory keeps the "warning only" case visible and lets actual helper failures propagate normally.

Note: script/lib/config.sh is listed in script/.shellcheck-exclude, so no static validation is enforced on this file.

💡 Suggested refactor
 config::import_gemini() {
+  local source_dir="${1:?Source directory required}"
+  local target_dir="${2:-$HOME/.gemini}"
+
+  if [[ ! -d "$source_dir" ]]; then
+    echo "⚠️  Gemini設定ディレクトリが見つかりません: $source_dir"
+    return 0
+  fi
+
   config::_import_tool "Gemini" \
-    "${1:?Source directory required}" \
-    "${2:-$HOME/.gemini}" \
-    CONFIG_GEMINI_SHARED_FILES || return 0  # Gemini: warning only
+    "$source_dir" \
+    "$target_dir" \
+    CONFIG_GEMINI_SHARED_FILES
 }
 
 config::export_gemini() {
+  local source_dir="${1:-$HOME/.gemini}"
+  local target_dir="${2:?Target directory required}"
+
+  if [[ ! -d "$source_dir" ]]; then
+    echo "⚠️  Gemini設定ディレクトリが見つかりません: $source_dir"
+    return 0
+  fi
+
   config::_export_tool "Gemini" \
-    "${1:-$HOME/.gemini}" \
-    "${2:?Target directory required}" \
-    CONFIG_GEMINI_SHARED_FILES || return 0  # Gemini: warning only
+    "$source_dir" \
+    "$target_dir" \
+    CONFIG_GEMINI_SHARED_FILES
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@script/lib/config.sh` around lines 211 - 223, The wrapper functions
config::import_gemini and config::export_gemini should perform an explicit
directory existence check for the source/target path before calling
config::_import_tool / config::_export_tool: test the respective directory
argument (the first arg for import, the second arg for export, using the same
default expansion as currently present) and if it does not exist return 0
(preserving the "warning only" behavior); remove the trailing "|| return 0" so
that any real failure from config::_import_tool or config::_export_tool
(referencing CONFIG_GEMINI_SHARED_FILES) will propagate normally.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/hooks/block_config_edit.py:
- Around line 11-15: Remove the unused import of the json module: delete the
line importing json at the top of .claude/hooks/block_config_edit.py since the
code now uses load_hook_input() (function referenced as load_hook_input) and no
other code uses json; keep the import of load_hook_input and the existing data =
load_hook_input() line intact.

In @.claude/hooks/block_dangerous_commands.py:
- Around line 8-14: Remove the unused json import from the top-level imports;
edit the import block so it only imports sys, re, and the common helpers (remove
the line "import json"), leaving load_hook_input and get_command usage unchanged
(symbols to check: load_hook_input, get_command, data, cmd).

In @.claude/hooks/block_git_no_verify.py:
- Around line 2-8: Remove the unused json import from the top of the file;
locate the import line that currently reads "import json" alongside "import sys"
and "import shlex" and delete it so only required modules remain, since
load_hook_input() and get_command() are used and json is no longer referenced.

In `@script/lib/config.sh`:
- Around line 78-79: Replace the fragile import copy and suppressed errors:
instead of cp -r "$source_dir/$dir"/* "$target_dir/$dir/" 2>/dev/null || true,
use cp -R "$source_dir/$dir"/. "$target_dir/$dir/" and allow failures to
propagate (or guard with && for the success echo), e.g. cp -R
"$source_dir/$dir"/. "$target_dir/$dir/" && echo "✅ Imported $display_name";
likewise update the corresponding export copy that used the wildcard pattern to
use cp -R "$export_source"/. "$export_target"/ (remove the 2>/dev/null || true
suppression) so hidden files are copied and real errors are reported; reference
the variables source_dir, dir, target_dir, display_name (and the export
source/target vars) when making the changes.

In `@script/update-all.sh`:
- Around line 11-19: The fallback aliases in the shared output library are
missing the log_error alias, so add a log_error wrapper alongside
log_info/log_success/log_warn that forwards all arguments to output::error
(i.e., implement a log_error function that calls output::error with the received
args) in the same block where log_info/log_success/log_warn are defined so calls
to log_error in update-all.sh succeed.

---

Nitpick comments:
In @.claude/hooks/common.py:
- Around line 47-49: The is_help_command function currently uses substring
checks which cause false positives (e.g., matching "-h" inside paths or other
flags); change it to detect standalone help flags by parsing the command into
arguments or using word-boundary regex checks so only an exact "-h" or "--help"
token triggers true (update is_help_command to split the command into args or
apply regex like token boundaries and return True only when "-h" or "--help"
appears as a separate token).
- Around line 1-16: Add focused unit tests for the shared utilities in
.claude/hooks/common.py: write tests that (1) validate JSON input parsing from
stdin (simulate sys.stdin to exercise the parse function that reads JSON), (2)
exercise tool context extraction (call the function that extracts tool/context
fields from input objects and assert expected outputs and error handling), (3)
verify output formatting helpers (headers, sections, status functions produce
expected strings), (4) stub subprocess/git interactions to test Git operation
helpers (e.g., the function that runs git commands returns expected output and
handles failures), and (5) test package manager detection (feed different
filesystem/project layouts or mocked Path.exists to assert detection logic). Use
pytest with fixtures and monkeypatch to simulate stdin, subprocess, and
filesystem, and include edge cases and error paths for each referenced function
to prevent regressions across the 11 dependent hooks.

In @.github/workflows/ci.yml:
- Line 164: The integration-test job currently invokes the custom action
setup-node-ci which installs npm packages; if the .bats integration tests only
need the npm binary (not installed packages), update the job to skip npm package
installation by providing the action input to disable install (e.g., pass
install: 'false' to the setup-node-ci action) or remove the action entirely and
only ensure Node/npm is available; locate references to the integration-test job
and the uses: ./.github/actions/setup-node-ci entry and change the action
invocation to pass the install flag so npm is available but npm ci is skipped.

In `@script/lib/config.sh`:
- Around line 211-223: The wrapper functions config::import_gemini and
config::export_gemini should perform an explicit directory existence check for
the source/target path before calling config::_import_tool /
config::_export_tool: test the respective directory argument (the first arg for
import, the second arg for export, using the same default expansion as currently
present) and if it does not exist return 0 (preserving the "warning only"
behavior); remove the trailing "|| return 0" so that any real failure from
config::_import_tool or config::_export_tool (referencing
CONFIG_GEMINI_SHARED_FILES) will propagate normally.

In `@script/test-coverage-trend.sh`:
- Around line 9-12: Remove the unnecessary shellcheck suppression: delete the
comment "# shellcheck disable=SC2034" from the fallback block so the linter runs
normally, leaving the readonly color variable declarations (RED, GREEN, YELLOW,
BLUE, NC) intact; this keeps the readonly assignments in the fallback while
matching the pattern used in the other scripts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8fab8024-93f5-4630-9b1f-f83a59acffd9

📥 Commits

Reviewing files that changed from the base of the PR and between 83a5146 and 0732b23.

📒 Files selected for processing (28)
  • .claude/hooks/block_config_edit.py
  • .claude/hooks/block_dangerous_commands.py
  • .claude/hooks/block_git_no_verify.py
  • .claude/hooks/common.py
  • .claude/hooks/post_commit_adr_reminder.py
  • .claude/hooks/post_edit_auto_lint.py
  • .claude/hooks/post_git_push_ci.py
  • .claude/hooks/post_pr_ai_review.py
  • .claude/hooks/post_pr_ci_watch.py
  • .claude/hooks/pre_exit_plan_ai_review.py
  • .claude/hooks/pre_git_quality_gates.py
  • .claude/hooks/stop_test_verification.py
  • .github/actions/setup-node-ci/action.yml
  • .github/workflows/ci.yml
  • .github/workflows/security.yml
  • .github/workflows/update-libraries.yml
  • script/branch-cleanup.sh
  • script/changelog-generator.sh
  • script/code-complexity-check.sh
  • script/container-health.sh
  • script/dependency-health-check.sh
  • script/lib/config.sh
  • script/pre-pr-checklist.sh
  • script/security-credential-scan.sh
  • script/test-coverage-trend.sh
  • script/update-actions.sh
  • script/update-all.sh
  • test/credential-filtering.test.js

Comment on lines 11 to +15
import sys
import json
from common import load_hook_input

data = json.load(sys.stdin)
data = load_hook_input()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused json import.

The json module is imported but no longer used after refactoring to use load_hook_input().

🧹 Proposed fix
 import sys
-import json
 from common import load_hook_input
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/hooks/block_config_edit.py around lines 11 - 15, Remove the unused
import of the json module: delete the line importing json at the top of
.claude/hooks/block_config_edit.py since the code now uses load_hook_input()
(function referenced as load_hook_input) and no other code uses json; keep the
import of load_hook_input and the existing data = load_hook_input() line intact.

Comment on lines 8 to +14
import sys
import json
import re
from common import load_hook_input, get_command

data = json.load(sys.stdin)
cmd = (data.get("tool_input", {}) or {}).get("command") or ""
data = load_hook_input()
cmd = get_command(data)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused json import.

The json module is imported but no longer used after refactoring to use load_hook_input() from common.

🧹 Proposed fix
 import sys
-import json
 import re
 from common import load_hook_input, get_command
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import sys
import json
import re
from common import load_hook_input, get_command
data = json.load(sys.stdin)
cmd = (data.get("tool_input", {}) or {}).get("command") or ""
data = load_hook_input()
cmd = get_command(data)
import sys
import re
from common import load_hook_input, get_command
data = load_hook_input()
cmd = get_command(data)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/hooks/block_dangerous_commands.py around lines 8 - 14, Remove the
unused json import from the top-level imports; edit the import block so it only
imports sys, re, and the common helpers (remove the line "import json"), leaving
load_hook_input and get_command usage unchanged (symbols to check:
load_hook_input, get_command, data, cmd).

Comment on lines 2 to +8
import sys
import json
import shlex
from common import load_hook_input, get_command

# Read input from Claude
data = json.load(sys.stdin)
cmd = (data.get("tool_input", {}) or {}).get("command") or ""
data = load_hook_input()
cmd = get_command(data)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused json import.

The json module is imported but no longer used after refactoring to use load_hook_input() and get_command().

🧹 Proposed fix
 import sys
-import json
 import shlex
 from common import load_hook_input, get_command
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import sys
import json
import shlex
from common import load_hook_input, get_command
# Read input from Claude
data = json.load(sys.stdin)
cmd = (data.get("tool_input", {}) or {}).get("command") or ""
data = load_hook_input()
cmd = get_command(data)
import sys
import shlex
from common import load_hook_input, get_command
data = load_hook_input()
cmd = get_command(data)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/hooks/block_git_no_verify.py around lines 2 - 8, Remove the unused
json import from the top of the file; locate the import line that currently
reads "import json" alongside "import sys" and "import shlex" and delete it so
only required modules remain, since load_hook_input() and get_command() are used
and json is no longer referenced.

Comment thread script/lib/config.sh
Comment on lines +78 to +79
cp -r "$source_dir/$dir"/* "$target_dir/$dir/" 2>/dev/null || true
echo "✅ Imported $display_name"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

command -v zsh >/dev/null || { echo "zsh not installed"; exit 1; }

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT
export CODERABBIT_TMPDIR="$tmpdir"

zsh <<'ZSH'
set -euo pipefail

tmpdir="$CODERABBIT_TMPDIR"

mkdir -p "$tmpdir/src/dir" "$tmpdir/dst/dir"
touch "$tmpdir/src/dir/visible" "$tmpdir/src/dir/.hidden"

cp -r "$tmpdir/src/dir"/* "$tmpdir/dst/dir/" 2>/dev/null || true

print '--- destination after current pattern ---'
ls -la "$tmpdir/dst/dir"

mkdir -p "$tmpdir/src2/dir" "$tmpdir/dst2/dir"
touch "$tmpdir/src2/dir/visible"
chmod 500 "$tmpdir/dst2/dir"

if (cp -r "$tmpdir/src2/dir"/* "$tmpdir/dst2/dir/" 2>/dev/null || true); then
  print "masked_failure=true"
fi
ZSH

Repository: keito4/config

Length of output: 74


🏁 Script executed:

# Check the file and context around lines 78-79
head -n 85 script/lib/config.sh | tail -n +70

Repository: keito4/config

Length of output: 550


🏁 Script executed:

# Check if there's a shellcheck exclude file
cat script/.shellcheck-exclude 2>/dev/null || echo "No exclude file found"

Repository: keito4/config

Length of output: 213


🏁 Script executed:

# Check if shellcheck is available and can validate the script
command -v shellcheck >/dev/null && echo "shellcheck found" || echo "shellcheck not found"

Repository: keito4/config

Length of output: 73


🏁 Script executed:

# Verify glob behavior with bash (since zsh not available)
# Test if * glob skips dotfiles
bash -c '
mkdir -p /tmp/test_src /tmp/test_dst
touch /tmp/test_src/visible /tmp/test_src/.hidden
echo "Source contents:"
ls -la /tmp/test_src/
echo ""
echo "Testing glob expansion:"
cd /tmp/test_src
for file in *; do
  echo "  Matched: $file"
done
echo ""
echo "After cp -r /tmp/test_src/* /tmp/test_dst/:"
cp -r /tmp/test_src/* /tmp/test_dst/ 2>/dev/null || true
ls -la /tmp/test_dst/
rm -rf /tmp/test_src /tmp/test_dst
'

Repository: keito4/config

Length of output: 548


🏁 Script executed:

# Get broader context around the import function
sed -n '60,85p' script/lib/config.sh

Repository: keito4/config

Length of output: 820


🏁 Script executed:

# Check the export function at lines 137-139
sed -n '130,145p' script/lib/config.sh

Repository: keito4/config

Length of output: 639


🏁 Script executed:

# Check what CONFIG_GEMINI_SHARED_DIRS contains
grep -n "CONFIG_GEMINI_SHARED_DIRS\|SHARED_DIRS" script/lib/config.sh | head -20

Repository: keito4/config

Length of output: 475


🏁 Script executed:

# Check if these directories exist and if they contain any dotfiles
for dir in commands agents hooks prompts rules; do
  if fd -H "^\." --base-directory "$dir" 2>/dev/null | head -5; then
    echo "Found dotfiles in $dir"
  fi
done

Repository: keito4/config

Length of output: 182


🏁 Script executed:

# Also check in common tool config directories for these patterns
fd -H "^\." --base-directory . --type f -x grep -l "commands\|agents\|hooks\|prompts\|rules" {} \; 2>/dev/null | head -10

Repository: keito4/config

Length of output: 102


🏁 Script executed:

# Show what dotfiles exist in each of these directories
for dir in commands agents hooks prompts rules; do
  echo "=== Dotfiles in $dir ==="
  fd -H "^\." --base-directory "$dir" --type f 2>/dev/null | head -10
done

Repository: keito4/config

Length of output: 192


🏁 Script executed:

# Test the proposed fix to ensure it works correctly
bash -c '
mkdir -p /tmp/fix_test_src /tmp/fix_test_dst
touch /tmp/fix_test_src/visible /tmp/fix_test_src/.hidden /tmp/fix_test_src/.gitkeep
echo "Source:"
ls -la /tmp/fix_test_src/

echo ""
echo "Testing proposed fix: cp -R /tmp/fix_test_src/. /tmp/fix_test_dst/"
cp -R /tmp/fix_test_src/. /tmp/fix_test_dst/

echo "Destination:"
ls -la /tmp/fix_test_dst/

rm -rf /tmp/fix_test_src /tmp/fix_test_dst
'

Repository: keito4/config

Length of output: 701


Use cp -R with dot-slash syntax to copy directory contents including hidden files and report copy failures.

The pattern "$source_dir/$dir"/* skips dotfiles, and error handling with || true / && ... || ... masks real failures. Use cp -R "$source_dir/$dir"/. "$target_dir/$dir/" instead to copy all files (including hidden ones) and let failures propagate.

Suggested fix for import (lines 78-79)
          mkdir -p "$target_dir/$dir"
-         cp -r "$source_dir/$dir"/* "$target_dir/$dir/" 2>/dev/null || true
+         cp -R "$source_dir/$dir"/. "$target_dir/$dir/"
          echo "✅ Imported $display_name"
Suggested fix for export (lines 137-139)
         mkdir -p "$target_dir/$dir"
-        cp -r "$source_dir/$dir"/* "$target_dir/$dir/" 2>/dev/null && \
-          echo "✅ Exported ${label:+$label/}$dir/" || \
-          echo "⚠️  No ${label:+$label/}$dir found"
+        cp -R "$source_dir/$dir"/. "$target_dir/$dir/"
+        echo "✅ Exported ${label:+$label/}$dir/"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cp -r "$source_dir/$dir"/* "$target_dir/$dir/" 2>/dev/null || true
echo "✅ Imported $display_name"
cp -R "$source_dir/$dir"/. "$target_dir/$dir/"
echo "✅ Imported $display_name"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@script/lib/config.sh` around lines 78 - 79, Replace the fragile import copy
and suppressed errors: instead of cp -r "$source_dir/$dir"/* "$target_dir/$dir/"
2>/dev/null || true, use cp -R "$source_dir/$dir"/. "$target_dir/$dir/" and
allow failures to propagate (or guard with && for the success echo), e.g. cp -R
"$source_dir/$dir"/. "$target_dir/$dir/" && echo "✅ Imported $display_name";
likewise update the corresponding export copy that used the wildcard pattern to
use cp -R "$export_source"/. "$export_target"/ (remove the 2>/dev/null || true
suppression) so hidden files are copied and real errors are reported; reference
the variables source_dir, dir, target_dir, display_name (and the export
source/target vars) when making the changes.

Comment thread script/update-all.sh
Comment on lines +11 to +19
# Source shared output library (provides log_info, log_success, log_warn, color vars)
# shellcheck source=/dev/null
source "$SCRIPT_DIR/lib/output.sh" 2>/dev/null || {
GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' RED='\033[0;31m' NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify the shared output API exports log_error alias
rg -n '^\s*(output::log_error|log_error)\s*\(' script/lib/output.sh

# Verify affected call sites that require log_error
rg -n '\blog_error\s*\(' script/update-all.sh script/update-actions.sh

Repository: keito4/config

Length of output: 39


🏁 Script executed:

# Check if files exist and their contents
echo "=== Checking script/lib/output.sh ===" 
if [ -f script/lib/output.sh ]; then
  echo "File exists. Contents:"
  cat -n script/lib/output.sh
else
  echo "File does not exist"
fi

echo ""
echo "=== Checking script/update-all.sh for log_error calls ===" 
if [ -f script/update-all.sh ]; then
  echo "File exists. Searching for log_error:"
  grep -n "log_error" script/update-all.sh || echo "No matches found"
else
  echo "File does not exist"
fi

echo ""
echo "=== Checking script/update-actions.sh ===" 
if [ -f script/update-actions.sh ]; then
  echo "File exists. Searching for log_error:"
  grep -n "log_error" script/update-actions.sh || echo "No matches found"
else
  echo "File does not exist"
fi

Repository: keito4/config

Length of output: 6833


log_error is missing from the backward compatibility aliases in script/lib/output.sh

The file defines log_info, log_success, and log_warn aliases (lines 138-140) but omits log_error. When script/update-all.sh sources the library successfully, it skips the fallback block (lines 11-19) that defines log_error, causing calls to log_error at lines 42, 68, 87, 106, and 126 to fail with "command not found".

Add the missing alias to script/lib/output.sh:

log_error() { output::error "$@"; }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@script/update-all.sh` around lines 11 - 19, The fallback aliases in the
shared output library are missing the log_error alias, so add a log_error
wrapper alongside log_info/log_success/log_warn that forwards all arguments to
output::error (i.e., implement a log_error function that calls output::error
with the received args) in the same block where log_info/log_success/log_warn
are defined so calls to log_error in update-all.sh succeed.

Integration tests grepped for "npm ci" and "actions/setup-node@" directly
in ci.yml, which now delegates to .github/actions/setup-node-ci composite
action. Update patterns to match either direct or composite action usage.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@keito4
keito4 merged commit 06e43a7 into main Mar 30, 2026
14 of 15 checks passed
@keito4
keito4 deleted the fix/refactor-dedup-shared-modules branch March 30, 2026 13:21
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.107.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@github-actions github-actions Bot added the released リリース済み label Mar 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released リリース済み

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant