Skip to content

Commit bc67c8d

Browse files
ToraDadyclaude
andcommitted
fix(careful): hook 発火経路と output format を Claude Code 仕様に合わせる + 日本語化 + BSD sed 互換性
PR #24(step 28)の実機 integration テストで判明した問題を 4 件修正: 1. hook command path:`${CLAUDE_SKILL_DIR}` は Claude Code 公式 env var ではなく gstack 独自拡張だった(Claude Code は提供しない)。Claude Code 公式 `$CLAUDE_PROJECT_DIR` ベースの絶対 path に置換 → `$CLAUDE_PROJECT_DIR/.claude/skills/careful/bin/check-careful.sh`。これにより hook がそもそも script を見つけられない問題(`bash: /bin/check-careful.sh: No such file or directory`)を解消 2. hook output JSON format:gstack の `{"permissionDecision":"ask","message":"..."}` は旧 format。現行 Claude Code は `hookSpecificOutput` で wrap した format を要求 → `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask","permissionDecisionReason":"..."}}`。これにより hook は呼ばれるが警告が UI に表示されない問題を解消 3. WARN メッセージ 8 種を日本語化:「Destructive: ...」→「危険: ...」(uzustack の言語感に整合、SKILL.md.tmpl は日本語、statusMessage も日本語、warning だけ英語は不整合) 4. BSD sed 互換性:sed regex の `\s+` を `[[:space:]]+` に置換。macOS の BSD sed は `\s` 未対応で safe exception の RM_ARGS strip が失敗、結果として `rm -rf node_modules` が安全例外として通らなかった。POSIX の `[[:space:]]+` に置換して macOS / Linux 両対応に これらの finding は Phase 4(freeze + investigate hook 復活)翻訳でも再利用される設計知見として [[未決-16 hook 機構の発動経路の検証]] に記録予定。 実機検証済み(Mode A、uzustack repo 内 Claude Code): - destructive コマンド → `[careful] 危険: 再帰削除 (rm -r)。ファイルを永続的に削除します。` 警告発火 - 安全例外(`./fake_dir/node_modules`) → `{}` 返却で標準 prompt - git reset --hard → `[careful] 危険: git reset --hard は未コミットの変更をすべて破棄します。` 警告 - 非 destructive → `{}` 返却 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 39fdec6 commit bc67c8d

3 files changed

Lines changed: 13 additions & 13 deletions

File tree

careful/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ hooks:
2222
- matcher: "Bash"
2323
hooks:
2424
- type: command
25-
command: "bash ${CLAUDE_SKILL_DIR}/bin/check-careful.sh"
25+
command: "bash $CLAUDE_PROJECT_DIR/.claude/skills/careful/bin/check-careful.sh"
2626
statusMessage: "危険コマンドをチェック中..."
2727
sensitive: true
2828
---

careful/SKILL.md.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ hooks:
2222
- matcher: "Bash"
2323
hooks:
2424
- type: command
25-
command: "bash ${CLAUDE_SKILL_DIR}/bin/check-careful.sh"
25+
command: "bash $CLAUDE_PROJECT_DIR/.claude/skills/careful/bin/check-careful.sh"
2626
statusMessage: "危険コマンドをチェック中..."
2727
sensitive: true
2828
---

careful/bin/check-careful.sh

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env bash
22
# check-careful.sh — PreToolUse hook for /careful skill
33
# Reads JSON from stdin, checks Bash command for destructive patterns.
4-
# Returns {"permissionDecision":"ask","message":"..."} to warn, or {} to allow.
4+
# Returns hookSpecificOutput permissionDecision: "ask" to warn, or {} to allow.
55
set -euo pipefail
66

77
# Read stdin (JSON with tool_input)
@@ -28,7 +28,7 @@ CMD_LOWER=$(printf '%s' "$CMD" | tr '[:upper:]' '[:lower:]')
2828
# --- Check for safe exceptions (rm -rf of build artifacts) ---
2929
if printf '%s' "$CMD" | grep -qE 'rm\s+(-[a-zA-Z]*r[a-zA-Z]*\s+|--recursive\s+)' 2>/dev/null; then
3030
SAFE_ONLY=true
31-
RM_ARGS=$(printf '%s' "$CMD" | sed -E 's/.*rm\s+(-[a-zA-Z]+\s+)*//;s/--recursive\s*//')
31+
RM_ARGS=$(printf '%s' "$CMD" | sed -E 's/.*rm[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*//;s/--recursive[[:space:]]*//')
3232
for target in $RM_ARGS; do
3333
case "$target" in
3434
*/node_modules|node_modules|*/\.next|\.next|*/dist|dist|*/__pycache__|__pycache__|*/\.cache|\.cache|*/build|build|*/\.turbo|\.turbo|*/coverage|coverage)
@@ -53,56 +53,56 @@ PATTERN=""
5353

5454
# rm -rf / rm -r / rm --recursive
5555
if printf '%s' "$CMD" | grep -qE 'rm\s+(-[a-zA-Z]*r|--recursive)' 2>/dev/null; then
56-
WARN="Destructive: recursive delete (rm -r). This permanently removes files."
56+
WARN="危険: 再帰削除 (rm -r)。ファイルを永続的に削除します。"
5757
PATTERN="rm_recursive"
5858
fi
5959

6060
# DROP TABLE / DROP DATABASE
6161
if [ -z "$WARN" ] && printf '%s' "$CMD_LOWER" | grep -qE 'drop\s+(table|database)' 2>/dev/null; then
62-
WARN="Destructive: SQL DROP detected. This permanently deletes database objects."
62+
WARN="危険: SQL DROP を検出。データベースオブジェクトを永続的に削除します。"
6363
PATTERN="drop_table"
6464
fi
6565

6666
# TRUNCATE
6767
if [ -z "$WARN" ] && printf '%s' "$CMD_LOWER" | grep -qE '\btruncate\b' 2>/dev/null; then
68-
WARN="Destructive: SQL TRUNCATE detected. This deletes all rows from a table."
68+
WARN="危険: SQL TRUNCATE を検出。テーブルの全行を削除します。"
6969
PATTERN="truncate"
7070
fi
7171

7272
# git push --force / git push -f
7373
if [ -z "$WARN" ] && printf '%s' "$CMD" | grep -qE 'git\s+push\s+.*(-f\b|--force)' 2>/dev/null; then
74-
WARN="Destructive: git force-push rewrites remote history. Other contributors may lose work."
74+
WARN="危険: git force-push remote の履歴を書き換えます。他の contributor の作業が失われる可能性があります。"
7575
PATTERN="git_force_push"
7676
fi
7777

7878
# git reset --hard
7979
if [ -z "$WARN" ] && printf '%s' "$CMD" | grep -qE 'git\s+reset\s+--hard' 2>/dev/null; then
80-
WARN="Destructive: git reset --hard discards all uncommitted changes."
80+
WARN="危険: git reset --hard は未コミットの変更をすべて破棄します。"
8181
PATTERN="git_reset_hard"
8282
fi
8383

8484
# git checkout . / git restore .
8585
if [ -z "$WARN" ] && printf '%s' "$CMD" | grep -qE 'git\s+(checkout|restore)\s+\.' 2>/dev/null; then
86-
WARN="Destructive: discards all uncommitted changes in the working tree."
86+
WARN="危険: ワーキングツリーの未コミット変更をすべて破棄します。"
8787
PATTERN="git_discard"
8888
fi
8989

9090
# kubectl delete
9191
if [ -z "$WARN" ] && printf '%s' "$CMD" | grep -qE 'kubectl\s+delete' 2>/dev/null; then
92-
WARN="Destructive: kubectl delete removes Kubernetes resources. May impact production."
92+
WARN="危険: kubectl delete Kubernetes リソースを削除します。プロダクションへの影響可能性あり。"
9393
PATTERN="kubectl_delete"
9494
fi
9595

9696
# docker rm -f / docker system prune
9797
if [ -z "$WARN" ] && printf '%s' "$CMD" | grep -qE 'docker\s+(rm\s+-f|system\s+prune)' 2>/dev/null; then
98-
WARN="Destructive: Docker force-remove or prune. May delete running containers or cached images."
98+
WARN="危険: Docker force-remove または prune。実行中のコンテナや cached image を削除する可能性があります。"
9999
PATTERN="docker_destructive"
100100
fi
101101

102102
# --- Output ---
103103
if [ -n "$WARN" ]; then
104104
WARN_ESCAPED=$(printf '%s' "$WARN" | sed 's/"/\\"/g')
105-
printf '{"permissionDecision":"ask","message":"[careful] %s"}\n' "$WARN_ESCAPED"
105+
printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask","permissionDecisionReason":"[careful] %s"}}\n' "$WARN_ESCAPED"
106106
else
107107
echo '{}'
108108
fi

0 commit comments

Comments
 (0)