Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 20 additions & 23 deletions .claude/commands/update-claude-code.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Update Claude Code

Claude Code の最新バージョンをチェックして更新します
Claude Code の最新バージョンに更新します(ネイティブインストーラー使用)

## 実行内容

1. npm/global.json から現在の `@anthropic-ai/claude-code` のバージョンを取得
2. npm registry から最新バージョンを取得
3. バージョンを比較して、更新が必要な場合は global.json を更新
1. 現在のClaude Codeバージョンを確認
2. `claude update` コマンドで最新版に更新
3. 更新に失敗した場合は再インストールを試行
4. リリースノートのURLを表示

## 使用方法
Expand All @@ -25,33 +25,30 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"

# 環境変数を設定して自動更新を有効化
export AUTO_UPDATE=true
export CI=true

# Claude Code更新スクリプトを実行
if [[ -f "${PROJECT_ROOT}/script/update-claude-code.sh" ]]; then
bash "${PROJECT_ROOT}/script/update-claude-code.sh"
else
echo "Error: update-claude-code.sh が見つかりません"
exit 1
fi

# 更新があった場合の後処理
if git diff --quiet npm/global.json; then
echo "✓ Claude Code は既に最新です"
else
echo ""
echo "更新が完了しました。変更をコミットしてください:"
echo " git add npm/global.json"
echo " git commit -m 'chore: update Claude Code to latest version'"
echo ""
git diff npm/global.json
fi
```

## 注意事項

- このコマンドは config リポジトリ内で実行する必要があります
- 更新後は手動でコミットとプッシュが必要です
- CI環境では自動的に更新されます(確認プロンプトなし)
- このコマンドは Claude Code がインストールされている環境で実行する必要があります
- ネイティブインストーラーを使用しているため、npm は不要です
- 自動更新が有効な場合、手動更新は不要な場合があります

## インストール方法

Claude Code が未インストールの場合:

```bash
curl -fsSL https://claude.ai/install.sh | bash
```

## 参考リンク

- [Claude Code Getting Started](https://docs.anthropic.com/en/docs/claude-code/getting-started)
- [Claude Code Releases](https://github.com/anthropics/claude-code/releases)
38 changes: 21 additions & 17 deletions .claude/hooks/post_pr_ai_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,17 @@
print("⚠️ AIレビューツール(Codex/Gemini)がインストールされていません。スキップします。", file=sys.stderr)
sys.exit(0)

# レビュープロンプト
review_prompt = """You are acting as a reviewer for a proposed code change made by another engineer.
Focus on issues that impact correctness, performance, security, maintainability, or developer experience.
Flag only actionable issues introduced by the change.
When you flag an issue, provide a short, direct explanation and cite the affected file and line range.
Prioritize severe issues and avoid nit-level comments unless they block understanding of the diff.
After listing findings, produce an overall correctness verdict ('patch is correct' or 'patch is incorrect') with a concise justification and a confidence score between 0 and 1.
Review the current branch against origin/main.
Use git merge-base to find the merge base, then review the diff from that merge base to HEAD."""
# レビュープロンプト(日本語で出力)
review_prompt = """あなたは他のエンジニアが作成したコード変更のレビュアーとして行動してください。
正確性、パフォーマンス、セキュリティ、保守性、開発者体験に影響する問題に焦点を当ててください。
変更によって導入されたアクション可能な問題のみを指摘してください。
問題を指摘する際は、簡潔で直接的な説明と、影響を受けるファイルと行範囲を記載してください。
重大な問題を優先し、diffの理解を妨げない限りは細かい指摘は避けてください。
発見事項をリストした後、全体的な正確性の判定('patch is correct' または 'patch is incorrect')を簡潔な理由と0から1の信頼度スコアとともに出力してください。
現在のブランチをorigin/mainと比較してレビューしてください。
git merge-baseを使用してマージベースを見つけ、そのマージベースからHEADまでのdiffをレビューしてください。

**重要: 必ず日本語で回答してください。**"""

print("", file=sys.stderr)
print("=" * 60, file=sys.stderr)
Expand Down Expand Up @@ -156,15 +158,17 @@ def run_gemini_review():
print("⚠️ diffが空です", file=sys.stderr)
return None

# Gemini用のプロンプト(diffを含める)
gemini_prompt = f"""You are acting as a reviewer for a proposed code change.
Focus on issues that impact correctness, performance, security, maintainability, or developer experience.
Flag only actionable issues introduced by the change.
When you flag an issue, provide a short, direct explanation and cite the affected file and line range.
Prioritize severe issues and avoid nit-level comments unless they block understanding of the diff.
After listing findings, produce an overall correctness verdict ('patch is correct' or 'patch is incorrect') with a concise justification and a confidence score between 0 and 1.
# Gemini用のプロンプト(diffを含める、日本語で出力
gemini_prompt = f"""あなたはコード変更のレビュアーとして行動してください。
正確性、パフォーマンス、セキュリティ、保守性、開発者体験に影響する問題に焦点を当ててください。
変更によって導入されたアクション可能な問題のみを指摘してください。
問題を指摘する際は、簡潔で直接的な説明と、影響を受けるファイルと行範囲を記載してください。
重大な問題を優先し、diffの理解を妨げない限りは細かい指摘は避けてください。
発見事項をリストした後、全体的な正確性の判定('patch is correct' または 'patch is incorrect')を簡潔な理由と0から1の信頼度スコアとともに出力してください。

## Git Diff to Review:
**重要: 必ず日本語で回答してください。**

## レビュー対象のGit Diff:

{diff_content[:50000]}"""

Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/codex-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ PR作成後、OpenAI Codexによるコードレビューを実行します。
以下のコマンドでCodexレビューを実行:

```bash
codex exec --sandbox read-only "You are acting as a reviewer for a proposed code change made by another engineer. Focus on issues that impact correctness, performance, security, maintainability, or developer experience. Flag only actionable issues introduced by the change. When you flag an issue, provide a short, direct explanation and cite the affected file and line range. Prioritize severe issues and avoid nit-level comments unless they block understanding of the diff. After listing findings, produce an overall correctness verdict ('patch is correct' or 'patch is incorrect') with a concise justification and a confidence score between 0 and 1. Review the current branch against origin/main. Use git merge-base to find the merge base, then review the diff from that merge base to HEAD."
codex exec --sandbox read-only "あなたは他のエンジニアが作成したコード変更のレビュアーとして行動してください。正確性、パフォーマンス、セキュリティ、保守性、開発者体験に影響する問題に焦点を当ててください。変更によって導入されたアクション可能な問題のみを指摘してください。問題を指摘する際は、簡潔で直接的な説明と、影響を受けるファイルと行範囲を記載してください。重大な問題を優先し、diffの理解を妨げない限りは細かい指摘は避けてください。発見事項をリストした後、全体的な正確性の判定('patch is correct' または 'patch is incorrect')を簡潔な理由と0から1の信頼度スコアとともに出力してください。現在のブランチをorigin/mainと比較してレビューしてください。git merge-baseを使用してマージベースを見つけ、そのマージベースからHEADまでのdiffをレビューしてください。必ず日本語で回答してください。"
```

## レビュー結果の対応
Expand Down
9 changes: 6 additions & 3 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
FROM mcr.microsoft.com/devcontainers/base:ubuntu

# Build arguments for Claude Code authentication
ARG CLAUDE_CODE_OAUTH_TOKEN

Check warning on line 4 in .devcontainer/Dockerfile

View workflow job for this annotation

GitHub Actions / Generate SBOM

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "CLAUDE_CODE_OAUTH_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 4 in .devcontainer/Dockerfile

View workflow job for this annotation

GitHub Actions / Trivy Container Scan

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "CLAUDE_CODE_OAUTH_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
ARG ANTHROPIC_API_KEY

Check warning on line 5 in .devcontainer/Dockerfile

View workflow job for this annotation

GitHub Actions / Generate SBOM

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "ANTHROPIC_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 5 in .devcontainer/Dockerfile

View workflow job for this annotation

GitHub Actions / Trivy Container Scan

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ARG "ANTHROPIC_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

# Install dependencies and Node.js using official binaries
RUN apt-get update && apt-get install -y \
Expand Down Expand Up @@ -65,14 +65,17 @@

COPY npm/global.json /tmp/npm-global.json

RUN CLAUDE_CODE_VERSION=$(node -pe "require('/tmp/npm-global.json').dependencies['@anthropic-ai/claude-code'].version") \
&& CODEX_VERSION=$(node -pe "require('/tmp/npm-global.json').dependencies['@openai/codex'].version") \
# Install Claude Code using native installer (npm installation deprecated)
RUN curl -fsSL https://claude.ai/install.sh | bash \
&& echo 'export PATH="$HOME/.claude/local/bin:$PATH"' >> /home/vscode/.bashrc

Comment on lines +68 to +71

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

🌐 Web query:

Claude Code native installer install.sh behavior root vs non-root HOME directory

💡 Result:

Claude Code’s native installer script (the curl …/install.sh | bash flow) installs into the invoking user’s home directory—it is **not a system-wide (/usr/local) installer.

  • The script “adds a symlink to the installation at ~/.local/bin/claude”. That ~ resolves from $HOME of the user running the script. So:

    • Run normally (non-root): installs under your user’s home, e.g. ~/.local/bin/claude. [1]
    • Run with sudo / as root: installs under root’s home, e.g. /root/.local/bin/claude, and your normal user won’t see it in their ~/.local/bin (unless you also adjust PATH). (This is the direct consequence of the installer targeting ~/.local/bin.) [1]
  • The installer may print setup notes about adding ~/.local/bin to PATH; issues have been reported around the exact PATH snippet it prints, reinforcing that it’s managing a per-user ~/.local/bin install rather than a global one. [2]

If you accidentally installed as root and want it under a specific user, rerun it as that user (or use something like sudo -u <user> -H bash -c 'curl -fsSL https://claude.ai/install.sh | bash' so HOME is the target user’s home).

Sources:
[1] Claude Code troubleshooting docs (native installer symlink location ~/.local/bin/claude, and local migration notes)
[2] GitHub issue reporting the installer’s PATH guidance for ~/.local/bin (shows installer’s per-user PATH expectations)


Install Claude Code as vscode to avoid HOME/path mismatch.

The installer runs as root, but the PATH is appended for /home/vscode. The native installer installs to ~/.local/bin (resolved from the invoking user's $HOME), so running it as root installs to /root/.local/bin. This binary is inaccessible to the vscode user. Additionally, the PATH variable in the original code ($HOME/.claude/local/bin) doesn't match the installer's actual output location ($HOME/.local/bin).

Proposed fix
 # Install Claude Code using native installer (npm installation deprecated)
+USER vscode
 RUN curl -fsSL https://claude.ai/install.sh | bash \
  && echo 'export PATH="$HOME/.local/bin:$PATH"' >> /home/vscode/.bashrc
+USER root
🤖 Prompt for AI Agents
In @.devcontainer/Dockerfile around lines 68 - 71, The installer is run as root
so Claude is installed into /root/.local/bin and the PATH appended points to the
wrong directory; run the installer as the vscode user (or set HOME=/home/vscode
when invoking the installer) so the binary installs to /home/vscode/.local/bin,
then append the correct PATH entry ($HOME/.local/bin) to the vscode user's shell
rc (use /home/vscode/.bashrc) and ensure ownership of installed files is vscode;
look for the RUN curl...| bash invocation and the echo 'export
PATH=...'/home/vscode/.bashrc to update invocation user, HOME, PATH target, and
file ownership (chown) accordingly.

# Install other global npm packages
RUN CODEX_VERSION=$(node -pe "require('/tmp/npm-global.json').dependencies['@openai/codex'].version") \
&& VERCEL_VERSION=$(node -pe "require('/tmp/npm-global.json').dependencies['vercel'].version") \
&& GEMINI_CLI_VERSION=$(node -pe "require('/tmp/npm-global.json').dependencies['@google/gemini-cli'].version") \
&& npm install -g eslint \
typescript \
typescript-language-server \
@anthropic-ai/claude-code@${CLAUDE_CODE_VERSION} \
@openai/codex@${CODEX_VERSION} \
vercel@${VERCEL_VERSION} \
@google/gemini-cli@${GEMINI_CLI_VERSION}
Expand Down
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Config Base Container",
"image": "ghcr.io/keito4/config-base:1.62.1",
"image": "ghcr.io/keito4/config-base:1.62.2",
"features": {
"ghcr.io/devcontainers-extra/features/homebrew-package:1": {},
"ghcr.io/eitsupi/devcontainer-features/jq-likes:2": {},
Expand Down
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,20 +281,27 @@ The script performs the following actions:

#### Update Claude Code Only

- Run `npm run update:claude` (wrapper for `script/update-claude-code.sh`) to check and update **only** the `@anthropic-ai/claude-code` package to the latest version.
- The script compares the current version in `npm/global.json` with the latest available version on npm registry.
- If a newer version is available, it automatically updates `npm/global.json` and displays the release notes URL.
- Run `npm run update:claude` (wrapper for `script/update-claude-code.sh`) to update Claude Code to the latest version.
- Claude Code uses the **native installer** (npm installation is deprecated).
- The script runs `claude update` command to update to the latest version.
- Use `/update-claude-code` Claude command for interactive update within Claude Code sessions.
- Claude Code supports automatic updates - manual updates may not be necessary if auto-update is enabled.

**Installation (if not already installed):**

```bash
curl -fsSL https://claude.ai/install.sh | bash
```

#### Commit Requirements

- Commits that touch release-critical files (`package*.json`, `npm/global.json`, `.devcontainer/codex*`, `.codex/**`) **must** use a release-triggering Conventional Commit type (`feat`, `fix`, `perf`, `revert`, or `docs`). Commitlint enforces this so semantic-release can publish automatically when tooling versions change.

#### Global CLI version source of truth

- `npm/global.json` is the single source of truth for both `@openai/codex` and `@anthropic-ai/claude-code` versions.
- The DevContainer Dockerfile copies this file into the build context and reads the versions at build time, guaranteeing that `npm install -g ...` pins to the same versions used by local setups.
- When bumping either CLI, update the version in `npm/global.json` (or run `npm run update:libs`) and rebuild the DevContainer image. No manual edits in `.devcontainer/Dockerfile` are required anymore.
- `npm/global.json` is the single source of truth for `@openai/codex` and other npm-installed global packages.
- **Note:** Claude Code is no longer managed via npm. It uses the native installer (`curl -fsSL https://claude.ai/install.sh | bash`) and updates via `claude update`.
- The DevContainer Dockerfile copies `npm/global.json` into the build context and reads the versions at build time for npm-installed packages.
- Rebuild the DevContainer image after updating CLI versions to ensure consistency across environments.

### Configuration Setup
Expand Down
4 changes: 0 additions & 4 deletions npm/global.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
{
"name": "lib",
"dependencies": {
"@anthropic-ai/claude-code": {
"version": "2.1.22",
"overridden": false
},
"@commitlint/cli": {
"version": "20.3.1",
"overridden": false
Expand Down
81 changes: 23 additions & 58 deletions script/update-claude-code.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# ============================================================================
# Claude Code Version Update Script
# @anthropic-ai/claude-code の最新バージョンをチェックして更新します
# Claude Code の最新バージョンに更新します(ネイティブインストーラー使用)
# ============================================================================

set -euo pipefail
Expand All @@ -18,75 +18,40 @@ log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# スクリプトのディレクトリを取得
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

GLOBAL_FILE="${PROJECT_ROOT}/npm/global.json"
PACKAGE="@anthropic-ai/claude-code"

log_info "Claude Code バージョン更新を開始します..."

# jqの存在確認
if ! command -v jq &> /dev/null; then
log_error "jq が必要です。インストールしてください: brew install jq"
exit 1
fi

# npmの存在確認
if ! command -v npm &> /dev/null; then
log_error "npm が必要です。"
exit 1
fi

# global.jsonの存在確認
if [[ ! -f "$GLOBAL_FILE" ]]; then
log_error "global.json が見つかりません: ${GLOBAL_FILE}"
# claudeコマンドの存在確認
if ! command -v claude &> /dev/null; then
log_error "Claude CLI が見つかりません。"
log_info "インストール方法: curl -fsSL https://claude.ai/install.sh | bash"
exit 1
fi

# 現在のバージョンを取得
current_version=$(jq -r ".dependencies[\"${PACKAGE}\"].version" "$GLOBAL_FILE")
current_version=$(claude --version 2>/dev/null | head -1 || echo "unknown")
log_info "現在のバージョン: ${current_version}"

# 最新バージョンを取得
log_info "最新バージョンを確認中..."
latest_version=$(npm view "$PACKAGE" version 2>/dev/null)

if [[ -z "$latest_version" ]]; then
log_error "最新バージョンの取得に失敗しました"
exit 1
fi

log_info "最新バージョン: ${latest_version}"

# バージョン比較
if [[ "$current_version" == "$latest_version" ]]; then
log_success "Claude Code は既に最新バージョンです (${current_version})"
exit 0
fi
# 更新を実行
log_info "Claude Code を更新中..."

log_warn "バージョンが異なります: ${current_version} → ${latest_version}"

# 更新するかどうかを確認(CI環境では自動的に更新)
if [[ "${CI:-false}" != "true" ]] && [[ "${AUTO_UPDATE:-false}" != "true" ]]; then
read -p "更新しますか? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "更新をキャンセルしました"
exit 0
if claude update; then
new_version=$(claude --version 2>/dev/null | head -1 || echo "unknown")
if [[ "$current_version" == "$new_version" ]]; then
log_success "Claude Code は既に最新バージョンです (${current_version})"
else
log_success "Claude Code を ${current_version} → ${new_version} に更新しました"
fi
else
log_warn "claude update に失敗しました。再インストールを試みます..."
if curl -fsSL https://claude.ai/install.sh | bash; then
new_version=$(claude --version 2>/dev/null | head -1 || echo "unknown")
log_success "Claude Code を再インストールしました (${new_version})"
else
log_error "Claude Code の更新に失敗しました"
exit 1
fi
Comment on lines +23 to 52

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

🌐 Web query:

claude update exit code behavior already up to date

💡 Result:

Anthropic’s docs confirm claude update exists (and is the recommended manual update path when auto-updates fail), but they do not document any “exit code contract” for the command—specifically, there’s no guarantee spelled out for what exit code you get when it reports “already up to date.” [1] [2]

Practical workaround (don’t rely on the exit code):

  • Treat “already up to date” as a successful outcome in your wrapper script, and verify via version comparison.

Example (bash):

set -euo pipefail

before="$(claude --version | head -n1)"
out="$(claude update 2>&1 || true)"
after="$(claude --version | head -n1)"

if grep -qiE 'already up to date|no updates' <<<"$out"; then
  exit 0
fi

# If it changed, also success
if [[ "$before" != "$after" ]]; then
  exit 0
fi

# Otherwise treat as failure (unexpected state)
echo "$out" >&2
exit 1

If you’re seeing “update available” prompts but Homebrew says everything is already up to date, that mismatch is a known/recurring packaging sync issue (brew lagging behind other release channels), so version-checking is especially important. [3]

Sources

  1. Claude Code docs (“Set up Claude Code” → manual update: claude update). [1]
  2. Claude Code troubleshooting (“Auto-updater issues” → “Update manually: Run claude update”). [2]
  3. GitHub issue: Claude indicates an update via brew, but brew upgrade reports already up to date. [3]

The script's reliance on claude update exit code is unreliable.

Anthropic does not document the exit code contract for claude update, so there is no guarantee what exit code is returned when already up to date. If claude update returns non-zero when already at the latest version (undocumented behavior), the script will incorrectly fall into the else block and trigger an unnecessary reinstallation. Compare versions before branching on the exit code, or capture the output and check for "already up to date" messages to avoid relying on the undocumented exit code behavior.

🤖 Prompt for AI Agents
In `@script/update-claude-code.sh` around lines 23 - 52, Do not rely on the exit
code of claude update; instead capture versions and compare them to decide
whether an update/reinstall is needed: record current_version using the existing
current_version command, run claude update (but ignore its exit code), then
fetch new_version with the same claude --version call and compare
current_version vs new_version to determine success or whether to reinstall;
optionally capture the stdout/stderr of the claude update invocation to include
in log_warn/log_info messages but never branch solely on the exit status of
claude update.

fi

# global.jsonを更新
log_info "global.json を更新中..."
tmp_file=$(mktemp)
jq --arg version "$latest_version" \
".dependencies[\"${PACKAGE}\"].version = \$version" "$GLOBAL_FILE" > "$tmp_file"
mv "$tmp_file" "$GLOBAL_FILE"

log_success "Claude Code を ${current_version} → ${latest_version} に更新しました"

# リリースノートのURLを表示
log_info "リリースノート: https://github.com/anthropics/claude-code/releases"

Expand Down
Loading