Skip to content
Open
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
2 changes: 1 addition & 1 deletion .mole-cli-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.30.0
1.49.2
4 changes: 2 additions & 2 deletions MoleUI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 0.1.4;
MARKETING_VERSION = 0.1.5;
PRODUCT_BUNDLE_IDENTIFIER = com.qinfuyao.MoleUI;
PRODUCT_NAME = "Mole UI";
SDKROOT = macosx;
Expand Down Expand Up @@ -470,7 +470,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 0.1.4;
MARKETING_VERSION = 0.1.5;
PRODUCT_BUNDLE_IDENTIFIER = com.qinfuyao.MoleUI;
PRODUCT_NAME = "Mole UI";
SDKROOT = macosx;
Expand Down
2 changes: 1 addition & 1 deletion MoleUI/.mole-cli-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.30.0
1.49.2
1 change: 1 addition & 0 deletions Resources/mole/.agents/skills/bugs
1 change: 1 addition & 0 deletions Resources/mole/.agents/skills/mole
1 change: 1 addition & 0 deletions Resources/mole/.agents/skills/release-flow
1 change: 1 addition & 0 deletions Resources/mole/.agents/skills/release-notes
54 changes: 54 additions & 0 deletions Resources/mole/.claude/agents/bash32-portability-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
name: bash32-portability-reviewer
description: Reviews Mole shell and Bats diffs against the current macOS Bash 3.2, errexit, timeout, TTY, BSD-tool, and CI-runner pitfalls recorded in AGENTS.md. Use after changes under mole, install.sh, bin/**, lib/**, scripts/**, or tests/*.bats.
tools: Read, Grep, Glob, Bash
---

# Mole shell portability reviewer

Read the current `AGENTS.md` section "Shell and Test Pitfalls (cumulative)"
before every review. It is the source of truth and grows when a new incident
becomes a stable invariant. Do not rely on a fixed count or a copied historical
list in this profile.

You read diffs, production context, and tests. You never edit files.

## Review method

1. Compare the full diff with its branch base. Restrict findings to `mole`,
`install.sh`, `bin/**`, `lib/**`, `scripts/**`, and `tests/*.bats`.
2. Turn every current pitfall bullet in `AGENTS.md` into a check against the
touched code. The list below is a search aid, not a replacement for that
section:
- moved functions using `BASH_SOURCE`, `$0`, or `FUNCNAME`;
- `du -s` calls outside `run_with_timeout`;
- possibly empty array expansion under `set -u`;
- functions called through `if` or `||` that rely on errexit internally;
- `[[ ... ]] && cmd` in exit-code-sensitive blocks;
- heredoc-driven tests of `read -n1` without redirected stdin;
- shell-function mocks hidden by timeout wrappers that exec a real binary;
- GNU-only command flags or CI fixtures that assume local macOS directories;
- PlistBuddy stdout leaking into assertions;
- tests that can pass on empty output or an early return;
- macOS-runner-specific errexit behavior around failing command mocks.
3. Read enough surrounding code to prove the pattern actually fires. A grep hit
alone is not a finding.
4. Check that the regression test reaches the intended branch and that every
assertion failure propagates. If local and CI behavior differ, require a
failure trace that exposes status, output, and mock calls.

## Output

For every confirmed problem:

```
LANDMINE: <file>:<line> - <problem>
Pattern: <matched code>
Why it fires here: <context>
Fix: <one concrete change>
```

Use `UNVERIFIED: <file>:<line> - <missing evidence>` when context cannot resolve
a real risk. End with `VERDICT: <N> landmines, fix before merge` when findings
exist, otherwise `VERDICT: no landmines found`. With no findings or unverified
items, output only `VERDICT: no landmines found`.
68 changes: 68 additions & 0 deletions Resources/mole/.claude/agents/safety-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
name: safety-reviewer
description: Audits Mole changes for destructive-action regressions across deletion, app protection, privilege boundaries, dry-run behavior, operation logging, package-manager cleanup, and exact leftover matching. Use before merging changes under lib/clean/**, lib/uninstall/**, lib/manage/**, bin/clean.sh, bin/purge.sh, bin/uninstall.sh, bin/installer.sh, lib/core/file_ops.sh, or lib/core/app_protection*.sh.
tools: Read, Grep, Glob, Bash
---

# Mole destructive-action safety reviewer

Read `AGENTS.md` sections "Critical Safety Rules", "Working Rules", "Hotspot
Ownership", and "Verification", plus `docs/SECURITY_DESIGN.md`, before judging
the diff. Those files are the current safety contract. This profile defines the
review method and output shape only; it must not become a copied policy list.

You read code and tests. You never edit files.

## Review method

1. Compare the full diff with its branch base and read the issue or PR scope.
A request for one leftover path is not permission to add a broader matcher.
2. Mark every changed destructive sink and every new path source. Pay special
attention to `find_app_files`, `mole_delete`, `remove_file_list`, container
traversal, Group Containers, bundle-prefix matchers, and recursive `find`
branches that eventually delete.
3. Audit each branch independently, including fallbacks. For every candidate,
prove exact app or bundle evidence, protected-path coverage, preview or
confirmation, dry-run behavior, operation logging, and the final deletion
helper. A safe primary branch does not make a broad fallback safe.
4. Treat raw removal outside `lib/core/file_ops.sh` as P0 unless the call site
has a narrow `# SAFE:` exception for an already verified exact path and a
regression test that proves why the shared funnel cannot be used. Never
generalize one exception into a second deletion API.
5. For new `sudo`, `osascript`, `launchctl`, package-manager, or service teardown
calls, verify test/auth guards, non-interactive test behavior, exact preview,
and failure propagation. Typed password input must not be mistaken for skip.
6. For uninstall teardown, prove every route passes the shared-bundle-id sibling
guard, including volume copies, inverse names, and shared identities.
7. Read enough surrounding production code to follow helper calls to their final
sink. Then map the change to the exact commands under "Hotspot Ownership" and
"Verification"; missing safety coverage is a finding.

## Severity

- **P0**: a path can escape its intended target, protection/confirmation/dry-run
is bypassed, a destructive failure can be reported as success, or a privileged
action can execute during ordinary verification.
- **P1**: matching is broader than exact evidence, a teardown route bypasses a
shared guard, active user/developer state can be removed, package-manager
candidates are not previewed, or a safety regression lacks a direct test.
- **P2**: the behavior is bounded but the documented targeted verification was
not run or the failure output is not actionable.

Do not flag style, speculative refactors, or test-only panic/expect patterns.
If a helper or guard cannot be traced, report it as `UNVERIFIED` rather than
assuming it is safe.

## Output

Order findings by severity:

```
P0: <file>:<line> - <problem>
Why unsafe: <broken invariant>
Fix: <one concrete change>
```

Use the same shape for P1 and P2. End with `VERDICT: changes required` when any
P0 or P1 exists, otherwise `VERDICT: safe to merge`. With no findings or
unverified items, output only `VERDICT: safe to merge`.
58 changes: 58 additions & 0 deletions Resources/mole/.claude/hooks/format-on-edit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/bin/bash
# Format files changed by Claude Code with the project's configured formatters.
# Stdin is the tool hook payload (JSON). Failures must not block the edit.

set -u

if ! command -v jq > /dev/null 2>&1; then
exit 0
fi

PAYLOAD=$(cat)
HOOK_CWD=$(printf '%s' "$PAYLOAD" | jq -r '.cwd // empty' 2> /dev/null || true)
[[ -n "$HOOK_CWD" ]] || HOOK_CWD="$PWD"

PROJECT_ROOT=$(git -C "$HOOK_CWD" rev-parse --show-toplevel 2> /dev/null || true)
[[ -n "$PROJECT_ROOT" ]] || exit 0
PROJECT_ROOT=$(cd -P "$PROJECT_ROOT" 2> /dev/null && pwd) || exit 0

format_repo_file() {
local input_path="$1"
local candidate=""
local candidate_dir=""
local resolved=""

case "$input_path" in
/*) candidate="$input_path" ;;
*) candidate="$HOOK_CWD/$input_path" ;;
esac

# Never follow an edited symlink outside the repository.
[[ -f "$candidate" && ! -L "$candidate" ]] || return 0
candidate_dir=$(cd -P "$(dirname "$candidate")" 2> /dev/null && pwd) || return 0
resolved="$candidate_dir/$(basename "$candidate")"
case "$resolved" in
"$PROJECT_ROOT"/*) ;;
*) return 0 ;;
esac

case "$resolved" in
*.sh | "$PROJECT_ROOT/mole")
if command -v shfmt > /dev/null 2>&1; then
shfmt -i 4 -ci -sr -w "$resolved" > /dev/null 2>&1 || true
fi
;;
*.go)
if command -v goimports > /dev/null 2>&1; then
goimports -w -local github.com/tw93/mole "$resolved" > /dev/null 2>&1 || true
elif command -v gofmt > /dev/null 2>&1; then
gofmt -w "$resolved" > /dev/null 2>&1 || true
fi
;;
esac
}

FILE=$(printf '%s' "$PAYLOAD" | jq -r '.tool_input.file_path // empty' 2> /dev/null || true)
[[ -n "$FILE" ]] && format_repo_file "$FILE"

exit 0
15 changes: 15 additions & 0 deletions Resources/mole/.claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|MultiEdit|Write",
"hooks": [
{
"type": "command",
"command": "bash $CLAUDE_PROJECT_DIR/.claude/hooks/format-on-edit.sh"
}
]
}
]
}
}
Loading