Skip to content
Draft
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
29 changes: 29 additions & 0 deletions .claude/hooks/block-generated-data.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# PreToolUse hook: block direct edits to generated dictionary data files.
# These files are produced by the dictionary compiler and must not be edited manually.
# Exit code 2 blocks the tool from executing.

set -euo pipefail

command -v jq >/dev/null 2>&1 || exit 0

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
Comment thread
tianjianjiang marked this conversation as resolved.

if [[ -z "$FILE_PATH" ]]; then
exit 0
fi

# Reject paths with newlines or path traversal
if [[ "$FILE_PATH" =~ $'\n' ]] || [[ "$FILE_PATH" == *".."* ]]; then
exit 2
fi
Comment thread
tianjianjiang marked this conversation as resolved.

# Block generated data files in Source/Data/ (absolute or relative paths)
case "$FILE_PATH" in
*/Source/Data/data.txt|*/Source/Data/data-plain-bpmf.txt|*/Source/Data/associated-phrases-v2.txt| \
Source/Data/data.txt|Source/Data/data-plain-bpmf.txt|Source/Data/associated-phrases-v2.txt)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: line continuation introduces leading whitespace into case patterns, silently breaking relative-path protection.

In bash, \<newline> line continuation removes the backslash and newline but keeps the indentation on the following line. So the patterns for relative paths become Source/Data/data.txt (with two leading spaces) and will never match an actual file path. Only the absolute/wildcard */... variants would fire.

Suggested change
Source/Data/data.txt|Source/Data/data-plain-bpmf.txt|Source/Data/associated-phrases-v2.txt)
# Block generated data files in Source/Data/ (absolute or relative paths)
case "$FILE_PATH" in
*/Source/Data/data.txt|\
*/Source/Data/data-plain-bpmf.txt|\
*/Source/Data/associated-phrases-v2.txt|\
Source/Data/data.txt|\
Source/Data/data-plain-bpmf.txt|\
Source/Data/associated-phrases-v2.txt)

Each alternative must start the continuation line without leading whitespace to avoid embedding spaces into the pattern.

echo "Blocked: $FILE_PATH is a generated file. Edit the source and rebuild instead." >&2
exit 2
;;
Comment thread
tianjianjiang marked this conversation as resolved.
esac
Comment thread
tianjianjiang marked this conversation as resolved.
29 changes: 29 additions & 0 deletions .claude/hooks/format-cpp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# PostToolUse hook: auto-format C++/ObjC files with clang-format after edits.
# Reads the tool input JSON from stdin to extract the edited file path.

set -euo pipefail

Comment thread
tianjianjiang marked this conversation as resolved.
command -v jq >/dev/null 2>&1 || exit 0

# Read stdin JSON and extract file_path
INPUT=$(cat)
Comment thread
tianjianjiang marked this conversation as resolved.
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

if [[ -z "$FILE_PATH" ]]; then
exit 0
fi

# Reject paths with newlines, nulls, or path traversal
if [[ "$FILE_PATH" =~ $'\n' ]] || [[ "$FILE_PATH" =~ $'\0' ]] || [[ "$FILE_PATH" == *".."* ]]; then
Comment thread
tianjianjiang marked this conversation as resolved.
exit 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Dead check: bash variables cannot contain null bytes.

$'\0' terminates a shell string; $FILE_PATH can never match it. This check is effectively unreachable and gives a false sense of security.

Suggested change
exit 0
# Reject paths with newlines or path traversal
if [[ "$FILE_PATH" =~ $'\n' ]] || [[ "$FILE_PATH" == *".."* ]]; then

Remove the null-byte check (it mirrors the guard already used in block-generated-data.sh).

fi

# Only format C++/ObjC source files
case "$FILE_PATH" in
*.cpp|*.h|*.mm|*.m)
if [[ -f "$FILE_PATH" ]]; then
xcrun clang-format -i -- "$FILE_PATH"
Comment thread
tianjianjiang marked this conversation as resolved.
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

set -e + xcrun clang-format failure will surface as a hook error on every C++ edit.

With set -euo pipefail active, if xcrun is absent or clang-format exits non-zero (e.g., parse error in a file), the PostToolUse hook exits non-zero and the agent sees an error after every edit. Consider suppressing the exit status so a formatter failure is non-fatal:

Suggested change
fi
if [[ -f "$FILE_PATH" ]]; then
xcrun clang-format -i -- "$FILE_PATH" || true
fi

;;
esac
Comment thread
tianjianjiang marked this conversation as resolved.
Comment thread
tianjianjiang marked this conversation as resolved.
26 changes: 26 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
Comment thread
tianjianjiang marked this conversation as resolved.
"type": "command",
"command": "bash .claude/hooks/format-cpp.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/block-generated-data.sh"
}
]
}
]
}
}
16 changes: 16 additions & 0 deletions .claude/skills/branch-guard/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
description: Verify branch and worktree before making edits
user-invocable: false
---

# Branch Guard

Before editing files, verify:

1. **Current branch**: Run `git rev-parse --abbrev-ref HEAD` and confirm it matches the expected branch for the current task.

2. **Worktree isolation**: Run `git rev-parse --show-toplevel` and confirm edits target the correct worktree directory.

3. **Clean state**: Run `git status --porcelain` and warn if there are uncommitted changes that might conflict.

If any check fails, stop and alert the user before proceeding.
32 changes: 32 additions & 0 deletions .claude/skills/engine-test/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
description: Build and run C++ engine tests
user-invocable: true
---

# /engine-test

Build and run the full C++ engine unit tests.

## Steps

1. Create the build directory if needed:
```bash
mkdir -p Source/Engine/build
```

2. Configure with CMake:
```bash
cd Source/Engine/build && cmake -DENABLE_TEST=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ..
```

3. Build:
```bash
cd Source/Engine/build && make -j$(sysctl -n hw.ncpu)
```

4. Run tests:
```bash
cd Source/Engine/build && ctest --output-on-failure
```

Report test results. If any tests fail, show the failing test names and output.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ xcuserdata
.vscode
__pycache__
codecov_comment.md
DerivedData
DerivedData
compile_commands.json
.cache
Loading