From 52752a92bf504510e882220dded15f69867e916c Mon Sep 17 00:00:00 2001 From: Dorian Date: Sun, 15 Mar 2026 12:34:16 +0000 Subject: [PATCH] chore: remove duplicated archy skills and redundant hooks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wrong archy-specific skills (harden, refactor, test, ux-review, lint, add-app, pwa-icon-cache-fix) removed — these referenced Archipelago infrastructure irrelevant to botfights. Redundant hooks (block-risky-bash, protect-files, post-deploy-check, post-push-progress) removed since global hooks provide superset protection. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/hooks/block-risky-bash.sh | 76 --------------- .claude/hooks/post-deploy-check.sh | 43 --------- .claude/hooks/post-push-progress.sh | 75 --------------- .claude/hooks/protect-files.sh | 82 ----------------- .claude/settings.json | 21 +---- .claude/skills/add-app/SKILL.md | 49 ---------- .claude/skills/harden/SKILL.md | 49 ---------- .claude/skills/lint/SKILL.md | 52 ----------- .claude/skills/pwa-icon-cache-fix/SKILL.md | 102 --------------------- .claude/skills/refactor/SKILL.md | 41 --------- .claude/skills/test/SKILL.md | 59 ------------ .claude/skills/ux-review/SKILL.md | 90 ------------------ 12 files changed, 1 insertion(+), 738 deletions(-) delete mode 100755 .claude/hooks/block-risky-bash.sh delete mode 100755 .claude/hooks/post-deploy-check.sh delete mode 100755 .claude/hooks/post-push-progress.sh delete mode 100755 .claude/hooks/protect-files.sh delete mode 100644 .claude/skills/add-app/SKILL.md delete mode 100644 .claude/skills/harden/SKILL.md delete mode 100644 .claude/skills/lint/SKILL.md delete mode 100644 .claude/skills/pwa-icon-cache-fix/SKILL.md delete mode 100644 .claude/skills/refactor/SKILL.md delete mode 100644 .claude/skills/test/SKILL.md delete mode 100644 .claude/skills/ux-review/SKILL.md diff --git a/.claude/hooks/block-risky-bash.sh b/.claude/hooks/block-risky-bash.sh deleted file mode 100755 index 0a68d6b..0000000 --- a/.claude/hooks/block-risky-bash.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash -# PreToolUse Bash guard: block dangerous shell commands. -# Denies: rm -rf, git reset --hard, git push -f, git clean -fd, chmod -R 777, -# fork bombs, block device overwrites, mkfs, building Rust on macOS for Linux. -set -euo pipefail - -INPUT=$(cat) -CMD=$(python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('tool_input', {}).get('command', '')) -except: pass -" <<< "$INPUT") -BASE="${CLAUDE_PROJECT_DIR:-}" -[[ -z "$BASE" ]] && BASE=$(python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('cwd', '')) -except: pass -" <<< "$INPUT") -[[ -z "$BASE" ]] && BASE="$(pwd)" - -# Normalize: collapse whitespace, strip leading/trailing -CMD_NORM=$(echo "$CMD" | tr -s '[:space:]' ' ' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') - -deny() { - local reason="$1" - python3 -c " -import json -print(json.dumps({ - 'hookSpecificOutput': { - 'hookEventName': 'PreToolUse', - 'permissionDecision': 'deny', - 'permissionDecisionReason': '$reason' - } -})) -" - exit 0 -} - -# Dangerous patterns -case "$CMD_NORM" in - *"rm -rf"*|*"rm -fr"*|*"rm -f -r"*|*"rm -r -f"*) deny "Destructive rm -rf blocked by security hook" ;; - *"git reset --hard"*) deny "git reset --hard would lose uncommitted work" ;; - *"git push --force"*|*"git push -f"*|*"git push -f "*) deny "git push --force would rewrite history" ;; - *"git clean -fd"*|*"git clean -f -d"*) deny "git clean -fd deletes untracked files" ;; - *"chmod -R 777"*|*"chmod -R 0777"*) deny "chmod -R 777 is a security risk" ;; - *":(){ :"*"};:"*) deny "Fork bomb pattern blocked" ;; - *"> /dev/sd"*|*">/dev/sd"*) deny "Block device overwrite blocked" ;; - *"mkfs "*|*"mkfs."*) deny "Disk format command blocked" ;; -esac - -# Block building Rust locally on macOS (should always build on dev server) -if [[ "$(uname)" == "Darwin" ]]; then - if echo "$CMD_NORM" | grep -qE '^\s*cargo\s+build'; then - # Allow if it's clearly an SSH command (building on remote) - if ! echo "$CMD_NORM" | grep -qE 'ssh|sshpass'; then - deny "NEVER build Rust on macOS — use ./scripts/deploy-to-target.sh --live or build on dev server via SSH" - fi - fi -fi - -# Check for path traversal escaping project root -if [[ -n "$BASE" ]] && [[ -d "$BASE" ]]; then - if echo "$CMD_NORM" | grep -qE '\.\./|/\.\.'; then - if echo "$CMD_NORM" | grep -qE '(rm|mv|cp|cat|chmod|chown)\s+.*\.\.'; then - if echo "$CMD_NORM" | grep -qE '\brm\b.*\.\.'; then - deny "Path traversal with rm blocked" - fi - fi - fi -fi - -exit 0 diff --git a/.claude/hooks/post-deploy-check.sh b/.claude/hooks/post-deploy-check.sh deleted file mode 100755 index ea49b0a..0000000 --- a/.claude/hooks/post-deploy-check.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -# PostToolUse Bash hook: detect deploy commands and remind to test. -# Triggers after deploy-to-target.sh runs. -set -euo pipefail - -INPUT=$(cat) - -CMD=$(python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('tool_input', {}).get('command', '')) -except: pass -" <<< "$INPUT") - -# Only trigger on deploy commands or git push -if ! echo "$CMD" | grep -qE 'deploy-to-target|git\s+push'; then - exit 0 -fi - -TIMESTAMP=$(date '+%Y-%m-%d %H:%M') - -python3 -c " -import json - -message = '''Deploy detected at $TIMESTAMP. - -Post-deploy checklist: -1. Test the web UI at http://192.168.1.228 -2. Verify modified apps load correctly -3. Check backend logs: sudo journalctl -u archipelago -n 20 -4. Check nginx: sudo tail -f /var/log/nginx/error.log -5. If building ISO, sync system configs to image-recipe/configs/ -6. Update CHANGELOG.md if this is a notable change''' - -output = { - 'hookSpecificOutput': { - 'hookEventName': 'PostToolUse', - 'deployReminder': message - } -} -print(json.dumps(output)) -" diff --git a/.claude/hooks/post-push-progress.sh b/.claude/hooks/post-push-progress.sh deleted file mode 100755 index fa90935..0000000 --- a/.claude/hooks/post-push-progress.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env bash -# PostToolUse Bash hook: detect git push/commit and prompt Claude to update PROGRESS.md. -# Returns structured feedback with recent commits so Claude can write a session log entry. -# Uses python3 instead of jq for JSON (guaranteed on macOS). -set -euo pipefail - -INPUT=$(cat) - -# Extract command from JSON using python3 -CMD=$(python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('tool_input', {}).get('command', '')) -except: pass -" <<< "$INPUT") - -# Only trigger on git push or git commit commands -if ! echo "$CMD" | grep -qE '\bgit\s+(push|commit)\b'; then - exit 0 -fi - -# Gather context for the progress update -BASE="${CLAUDE_PROJECT_DIR:-$(pwd)}" -BRANCH=$(git -C "$BASE" branch --show-current 2>/dev/null || echo "unknown") -PROGRESS_FILE="$BASE/PROGRESS.md" -TIMESTAMP=$(date '+%Y-%m-%d %H:%M') - -# Get recent commits (branch vs main, or last 10) -if git -C "$BASE" rev-parse --verify main &>/dev/null; then - COMMITS=$(git -C "$BASE" log --oneline main..HEAD 2>/dev/null | head -15) - if [ -z "$COMMITS" ]; then - COMMITS=$(git -C "$BASE" log --oneline -10 2>/dev/null) - fi -else - COMMITS=$(git -C "$BASE" log --oneline -10 2>/dev/null) -fi - -# Get changed files in recent commits -CHANGED_FILES=$(git -C "$BASE" diff --name-only main..HEAD 2>/dev/null | head -20 || \ - git -C "$BASE" diff --name-only HEAD~5..HEAD 2>/dev/null | head -20 || \ - echo "unknown") - -# Build the feedback message and output as JSON using python3 -python3 -c " -import json, sys - -message = '''Progress Update Needed - -A git push/commit was detected on branch \`$BRANCH\` at $TIMESTAMP. - -Recent commits: -\`\`\` -$COMMITS -\`\`\` - -Changed files: -\`\`\` -$CHANGED_FILES -\`\`\` - -Please update PROGRESS.md: -1. Add a session log entry under '## Session Log' with format: ### $TIMESTAMP — $BRANCH -2. Summarize what was accomplished (2-4 bullet points based on the commits above) -3. Update any roadmap checkboxes if tasks were completed -4. Commit the PROGRESS.md update''' - -output = { - 'hookSpecificOutput': { - 'hookEventName': 'PostToolUse', - 'progressUpdate': message - } -} -print(json.dumps(output)) -" diff --git a/.claude/hooks/protect-files.sh b/.claude/hooks/protect-files.sh deleted file mode 100755 index 3ff5453..0000000 --- a/.claude/hooks/protect-files.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env bash -# PreToolUse Edit|Write guard: block edits outside project and to protected paths. -# Denies: paths outside project, .git/, .env*, lockfiles, node_modules/, deploy-config.sh -set -euo pipefail - -INPUT=$(cat) -FILE_PATH=$(python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('tool_input', {}).get('file_path', '')) -except: pass -" <<< "$INPUT") -BASE="${CLAUDE_PROJECT_DIR:-}" -[[ -z "$BASE" ]] && BASE=$(python3 -c " -import json, sys -try: - data = json.loads(sys.stdin.read()) - print(data.get('cwd', '')) -except: pass -" <<< "$INPUT") -[[ -z "$BASE" ]] && BASE="$(pwd)" - -# Resolve to absolute path -if [[ -z "$FILE_PATH" ]]; then - exit 0 -fi -ABS_BASE=$(cd "$BASE" 2>/dev/null && pwd) || true -[[ -z "$ABS_BASE" ]] && ABS_BASE=$(python3 -c "import os,sys; print(os.path.abspath(os.path.normpath(sys.argv[1])))" "$BASE" 2>/dev/null) || true -[[ -z "$ABS_BASE" ]] && ABS_BASE="$BASE" -[[ "$ABS_BASE" != */ ]] && ABS_BASE="${ABS_BASE}/" -if [[ "$FILE_PATH" != /* ]]; then - ABS_PATH="$ABS_BASE${FILE_PATH#./}" -else - ABS_PATH="$FILE_PATH" -fi -ABS_PATH=$(python3 -c "import os,sys; print(os.path.abspath(os.path.normpath(sys.argv[1])))" "$ABS_PATH" 2>/dev/null) || true -[[ -z "$ABS_PATH" ]] && ABS_PATH="$ABS_BASE${FILE_PATH#./}" - -deny() { - local reason="$1" - echo "Blocked: $ABS_PATH — $reason" >&2 - python3 -c " -import json -print(json.dumps({ - 'hookSpecificOutput': { - 'hookEventName': 'PreToolUse', - 'permissionDecision': 'deny', - 'permissionDecisionReason': '$reason' - } -})) -" - exit 0 -} - -# Protected patterns -PROTECTED_PATTERNS=( - ".git/" - ".env" - ".env.local" - "node_modules/" - "package-lock.json" - "scripts/deploy-config.sh" -) - -for pattern in "${PROTECTED_PATTERNS[@]}"; do - if [[ "$ABS_PATH" == *"$pattern"* ]] || [[ "$ABS_PATH" == *"/$pattern" ]]; then - deny "Edit blocked: path matches protected pattern ($pattern)" - fi -done - -# .env.*.local -if [[ "$ABS_PATH" =~ \.env\..*\.local$ ]]; then - deny "Edit blocked: .env.*.local files contain secrets" -fi - -# Ensure path is under project root -if [[ "$ABS_PATH" != "$ABS_BASE"* ]] && [[ "$ABS_PATH" != "$BASE"* ]]; then - deny "Edit blocked: path is outside project directory" -fi - -exit 0 diff --git a/.claude/settings.json b/.claude/settings.json index d7d8d16..83428d9 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,25 +1,6 @@ { "hooks": { - "PreToolUse": [ - { - "matcher": "Bash", - "hooks": [ - { - "type": "command", - "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-risky-bash.sh" - } - ] - }, - { - "matcher": "Edit|Write", - "hooks": [ - { - "type": "command", - "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh" - } - ] - } - ], + "PreToolUse": [], "PostToolUse": [] } } diff --git a/.claude/skills/add-app/SKILL.md b/.claude/skills/add-app/SKILL.md deleted file mode 100644 index b47b64f..0000000 --- a/.claude/skills/add-app/SKILL.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: add-app -description: Step-by-step guide for adding a new containerized app to Archipelago -disable-model-invocation: true -allowed-tools: Bash, Read, Write, Edit, Glob, Grep -argument-hint: "[app-name]" ---- - -Add a new containerized app ($ARGUMENTS) to Archipelago. - -## Steps - -### 1. Create the manifest - -Create `apps/{app-id}/manifest.yml` following the spec in `docs/app-manifest-spec.md`: -- `app.id` (kebab-case), `app.name`, `app.version` (SemVer) -- `container.image` (pinned version, **NEVER** `latest`) -- `security`: readonly_root, dropped capabilities, non-root UID > 1000 -- `health_check`, `dependencies` - -### 2. Add app icon - -Place icon at `neode-ui/public/assets/img/app-icons/{app-id}.{png|webp|svg}` - -### 3. Create status UI (if no native web UI) - -For apps without their own web interface, create a UI container in `docker/{app-id}-ui/` following the patterns in `.cursor/rules/APP-UI-STANDARDS.md`. - -Reference implementations: -- Bitcoin UI: `docker/bitcoin-ui/` -- LND UI: `docker/lnd-ui/` - -### 4. Update backend - -- Add port mapping in `core/archipelago/src/container/docker_packages.rs` -- Add env vars in `get_app_config()` in `core/archipelago/src/api/rpc.rs` - -### 5. Deploy and test - -- Deploy: `./scripts/deploy-to-target.sh --live` -- Install from marketplace UI at http://192.168.1.228 -- Verify it launches and auto-connects to dependencies -- Check logs: `sudo podman logs {container-name}` - -### 6. Security review - -- Verify readonly root, dropped caps, non-root user -- Check network isolation -- No hardcoded secrets diff --git a/.claude/skills/harden/SKILL.md b/.claude/skills/harden/SKILL.md deleted file mode 100644 index 6736cec..0000000 --- a/.claude/skills/harden/SKILL.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: harden -description: Security hardening review and fixes for Archipelago code and infrastructure -disable-model-invocation: true -allowed-tools: Read, Edit, Write, Glob, Grep, Bash -argument-hint: "[area: backend|frontend|containers|scripts|all]" ---- - -Perform a security hardening pass on $ARGUMENTS (default: all). - -## Backend Hardening (Rust) - -- [ ] No hardcoded credentials — check for Base64-encoded auth strings, passwords in source -- [ ] Secrets use `core/security/secrets_manager.rs` — verify encryption is implemented (not plaintext) -- [ ] All RPC endpoints validate inputs before processing -- [ ] No `unwrap()` on user-supplied data — handle errors gracefully -- [ ] Rate limiting on auth endpoints (login, password change) -- [ ] Session tokens have proper expiry and rotation -- [ ] File permissions: keys at 0o600, dirs at 0o700 -- [ ] Tracing never logs secrets, passwords, keys, or tokens - -## Frontend Hardening (Vue/TypeScript) - -- [ ] No secrets in source (API keys, passwords, tokens) -- [ ] No `eval()` or `innerHTML` with untrusted content -- [ ] XSS prevention — sanitize all user inputs -- [ ] CSRF protection on state-changing requests -- [ ] Credentials use `credentials: 'include'` not localStorage tokens -- [ ] No sensitive data in console.log statements - -## Container Hardening - -- [ ] All manifests: `readonly_root: true` (unless documented exception) -- [ ] All manifests: capabilities dropped, only required ones added -- [ ] All manifests: non-root user (UID > 1000) -- [ ] All manifests: `no-new-privileges: true` -- [ ] All images pinned to specific versions (no `:latest`) -- [ ] Network isolation — no `host` network unless required and documented -- [ ] AppArmor profiles defined and enforced - -## Script Hardening - -- [ ] All scripts use `set -euo pipefail` -- [ ] No hardcoded passwords (use deploy-config.sh or env vars) -- [ ] SSH uses proper key-based auth where possible -- [ ] No `chmod 777` or overly permissive permissions -- [ ] Temp files use `mktemp` not predictable paths - -Report all findings with file paths and line numbers. Fix issues directly where safe to do so. Flag anything that needs discussion. diff --git a/.claude/skills/lint/SKILL.md b/.claude/skills/lint/SKILL.md deleted file mode 100644 index d684f64..0000000 --- a/.claude/skills/lint/SKILL.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -name: lint -description: Run all linters and type checks for the Archipelago project -allowed-tools: Bash, Read, Grep -argument-hint: "[backend|frontend|all]" ---- - -Run linters and type-checks for $ARGUMENTS (default: all). - -## Frontend Linting - -```bash -cd neode-ui - -# Type check -npm run type-check 2>&1 - -# Check for any `any` types (should be zero) -grep -rn ': any' src/ --include='*.ts' --include='*.vue' | grep -v node_modules | grep -v '.d.ts' - -# Check for inline Tailwind violations (long class strings) -grep -rn 'class="[^"]\{100,\}"' src/ --include='*.vue' - -# Check for TODO/FIXME -grep -rn 'TODO\|FIXME' src/ --include='*.ts' --include='*.vue' - -# Check for console.log (should be cleaned before production) -grep -rn 'console\.\(log\|warn\|error\)' src/ --include='*.ts' --include='*.vue' | wc -l -``` - -## Backend Linting (on dev server) - -```bash -sshpass -p 'EwPDR8q45l0Upx@' ssh -o StrictHostKeyChecking=no archipelago@192.168.1.228 \ - 'source ~/.cargo/env && cd ~/archy/core && cargo clippy --all-targets --all-features 2>&1 && cargo fmt --all -- --check 2>&1' -``` - -## Script Linting - -```bash -# Check for scripts missing set -e -for f in scripts/*.sh; do - if ! head -5 "$f" | grep -q 'set -e'; then - echo "MISSING set -e: $f" - fi -done - -# Check for hardcoded IPs (should use variables) -grep -rn '192\.168\.1\.' scripts/ --include='*.sh' | grep -v deploy-config -``` - -Report all issues found with severity (critical/warning/info). diff --git a/.claude/skills/pwa-icon-cache-fix/SKILL.md b/.claude/skills/pwa-icon-cache-fix/SKILL.md deleted file mode 100644 index dbc65f8..0000000 --- a/.claude/skills/pwa-icon-cache-fix/SKILL.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -name: pwa-icon-cache-fix -description: Use when the user reports a PWA icon not updating, stale PWA icon, wrong icon after install, or any PWA caching issue. Also applies when changing PWA icons in a Vite + vite-plugin-pwa project. -version: 2.0.0 ---- - -# PWA Icon Cache Fix - -## Problem - -PWA icons are cached at FOUR independent layers: -1. **Service worker cache** (Workbox precache) -2. **Browser HTTP cache** -3. **Browser manifest resources** (Chromium stores resized icons in its profile data, keyed by a permanent extension ID tied to the origin — NEVER re-fetched even after uninstall/reinstall) -4. **macOS .app bundle** (`.icns` file baked into the `.app` in `~/Applications/`) - -Query string cache busting (`?v=2`) and uninstall/reinstall do NOT fix this. Chromium reuses the same extension ID for the same origin, so it keeps the old cached icons. - -## Fix Steps - -### 1. Verify icon files on disk and server are correct - -```bash -# Visual check -Read packages/app/public/pwa-192x192.png -Read packages/app/public/pwa-512x512.png - -# Hash match check -curl -s http://localhost:5173/pwa-192x192.png | md5 -md5 -q packages/app/public/pwa-192x192.png -``` - -### 2. Find the PWA's Chromium extension ID - -Read the installed `.app` bundle's `Info.plist` to get the `CrAppModeShortcutID`: - -```bash -plutil -p "~/Applications/Brave Browser Apps.localized/AIUI.app/Contents/Info.plist" | grep CrAppModeShortcutID -``` - -This returns an ID like `idemibpphagihbobmgmaojhjfidlfpdl`. - -### 3. Overwrite the cached icons in browser profile - -Chromium stores resized icons at: -`~/Library/Application Support/BraveSoftware/Brave-Browser/Default/Web Applications/Manifest Resources/{ID}/Icons/` - -Overwrite every size using `sips`: - -```bash -ICON_DIR="~/Library/Application Support/BraveSoftware/Brave-Browser/Default/Web Applications/Manifest Resources/{ID}/Icons" -SRC="packages/app/public/pwa-512x512.png" -for size in 32 48 64 96 128 192 256 512; do - sips -z $size $size "$SRC" --out "${ICON_DIR}/${size}.png" -done -``` - -### 4. Rebuild the macOS .icns in the .app bundle - -```bash -ICONSET="/tmp/aiui.iconset" -mkdir -p "$ICONSET" -SRC="packages/app/public/pwa-512x512.png" -sips -z 16 16 "$SRC" --out "$ICONSET/icon_16x16.png" -sips -z 32 32 "$SRC" --out "$ICONSET/icon_16x16@2x.png" -sips -z 32 32 "$SRC" --out "$ICONSET/icon_32x32.png" -sips -z 64 64 "$SRC" --out "$ICONSET/icon_32x32@2x.png" -sips -z 128 128 "$SRC" --out "$ICONSET/icon_128x128.png" -sips -z 256 256 "$SRC" --out "$ICONSET/icon_128x128@2x.png" -sips -z 256 256 "$SRC" --out "$ICONSET/icon_256x256.png" -sips -z 512 512 "$SRC" --out "$ICONSET/icon_256x256@2x.png" -sips -z 512 512 "$SRC" --out "$ICONSET/icon_512x512.png" -cp "$SRC" "$ICONSET/icon_512x512@2x.png" -iconutil -c icns "$ICONSET" -o "~/Applications/Brave Browser Apps.localized/AIUI.app/Contents/Resources/app.icns" -``` - -### 5. Flush macOS icon cache - -```bash -touch "~/Applications/Brave Browser Apps.localized/AIUI.app" -killall Finder -killall Dock -``` - -### 6. Bump PWA_CACHE_VERSION in main.ts - -Increment the `PWA_CACHE_VERSION` constant — this nukes all SW caches on next page load for web-layer caching. - -### 7. Delete stale build artifacts - -Remove old `dist/` and `dev-dist/` SW/manifest files. - -## Browser-Specific Paths - -- **Brave**: `~/Library/Application Support/BraveSoftware/Brave-Browser/Default/Web Applications/` -- **Chrome**: `~/Library/Application Support/Google/Chrome/Default/Web Applications/` -- **PWA apps (Brave)**: `~/Applications/Brave Browser Apps.localized/` -- **PWA apps (Chrome)**: `~/Applications/Chrome Apps.localized/` - -## Key Insight - -Chromium assigns a permanent extension ID per origin (e.g., `localhost:5173`). This ID persists across uninstall/reinstall. The icon cache in `Manifest Resources/{ID}/Icons/` is populated ONCE and never refreshed from the manifest. The only fix is to overwrite the files directly on disk. diff --git a/.claude/skills/refactor/SKILL.md b/.claude/skills/refactor/SKILL.md deleted file mode 100644 index 8c0e036..0000000 --- a/.claude/skills/refactor/SKILL.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -name: refactor -description: Refactor code for quality, maintainability, and adherence to project standards -disable-model-invocation: true -allowed-tools: Read, Edit, Write, Glob, Grep, Bash -argument-hint: "[file-or-area]" ---- - -Refactor the specified code ($ARGUMENTS) following Archipelago coding standards. - -## Checklist - -### Rust Backend -- [ ] No `unwrap()` or `expect()` — use `?` operator with context -- [ ] Replace `#[allow(dead_code)]` — either use it or remove it -- [ ] Functions under 50 lines, single responsibility -- [ ] Custom error types per module with `thiserror` -- [ ] `tracing` for logging — no `println!` or secrets in logs -- [ ] Split files over 500 lines into focused modules -- [ ] Run `cargo clippy --all-targets --all-features` mentally and fix issues - -### Vue Frontend -- [ ] Extract ALL inline Tailwind to global classes in `neode-ui/src/style.css` -- [ ] Use semantic class names: `.glass-card`, `.info-card`, `.glass-button`, `.path-option-card` -- [ ] Replace ALL `.gradient-button` with `.glass-button` (gradient buttons are BANNED) -- [ ] Replace ALL `.gradient-card` / `.gradient-card-dark` with `.glass-card` or `.path-option-card` -- [ ] Settings.vue is the gold standard — all screens should match its patterns -- [ ] Replace `any` types with proper interfaces or `unknown` -- [ ] Ensure `