AGENTS and sync-pictures script for linux
This commit is contained in:
174
AGENTS.md
Normal file
174
AGENTS.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# schmeeve-toolz — Agent Guide
|
||||
|
||||
Personal macOS automation toolkit deployed to `~/Dropbox/bin/`. Mostly shell scripts for power management, network, and system automation, triggered by Keyboard Maestro and cron.
|
||||
|
||||
## Commands
|
||||
|
||||
No build/test/deploy infrastructure exists. Scripts run directly:
|
||||
|
||||
```sh
|
||||
./scriptname # run any script directly
|
||||
chmod +x scriptname # scripts should already be executable
|
||||
```
|
||||
|
||||
Scripts are deployed by copying (or symlinking) to `~/Dropbox/bin/`. There is no install step.
|
||||
|
||||
Check shebang (`#!/bin/sh` or `#!/bin/bash`) before running — some use bashisms like `[[ ]]` and arrays.
|
||||
|
||||
## Language & Style
|
||||
|
||||
| Aspect | Convention |
|
||||
|---|---|
|
||||
| **Shell** | `#!/bin/bash` for complex scripts, `#!/bin/sh` for simple one-liners. Mix of both. |
|
||||
| **Python** | `#!/usr/bin/python3` for mail helpers. Hardcoded SMTP config block at top. |
|
||||
| **AppleScript** | Compiled `.scpt` files (binary — cannot view as text). Shell scripts invoke via `/usr/bin/osascript`. |
|
||||
| **Indentation** | Inconsistent across codebase. 2-space dominant but no enforced standard. |
|
||||
| **Naming** | `lowercase-with-hyphens` for scripts. `UPPER_CASE` for config constants, `lower_case` for locals. |
|
||||
| **Functions** | `name() {` syntax (rarely used). |
|
||||
| **Quoting** | Inconsistent. Many older scripts use bare `$var`. Newer scripts use `"${var}"`. Assume unquoted vars will break on spaces. |
|
||||
|
||||
## Architecture
|
||||
|
||||
### What it is
|
||||
|
||||
A flat collection of ~60+ standalone scripts organized by function, NOT a structured project. No packages, no modules, no dependencies file.
|
||||
|
||||
### How scripts relate
|
||||
|
||||
```
|
||||
presleep ──→ presleep_quitapps ──→ send_quitbrowsers_mail3.py
|
||||
│ │
|
||||
└──── send_sleep_mail3.py (sends email)
|
||||
|
||||
idlecheck ──→ idlecheck_tasks ──→ idlecheck_quitvideowake
|
||||
│ ──→ idlecheck_quitaudioprevent
|
||||
└──── idlecheck_caffeinatestuck
|
||||
|
||||
wakenotify ──→ wakelogstart / wakelogend
|
||||
|
||||
sleep ──→ idlecheck_caffeinatestuck
|
||||
|
||||
pull-all ──→ iterates repos in ~/git/ matching *schmeeve* remote
|
||||
checkin-all ──→ iterates repos in ~/git/ matching *schmeeve* remote
|
||||
```
|
||||
|
||||
Sub-scripts are invoked via `/bin/bash` or `/bin/sh`, never sourced.
|
||||
|
||||
### Trigger chain
|
||||
|
||||
1. **Keyboard Maestro** (macros) — most common trigger. Evidence: `$KMINFO_MacroName` env var used in email subjects, `dactoggle` bound to hotkey.
|
||||
2. **cron/launchd** — likely for `checkin-all`, `pull-all`, maintenance scripts.
|
||||
3. **pmset schedule** — `wakenotify` and `maintwakes` are scheduled via `pmset repeat`.
|
||||
|
||||
### Power management flow
|
||||
|
||||
```
|
||||
[Keyboard Maestro / cron / pmset schedule]
|
||||
│
|
||||
▼
|
||||
presleep / sleep / idlecheck / shutdown_safe / wakenotify
|
||||
│
|
||||
├── pmset (sleep, assertions, schedule)
|
||||
├── osascript (quit apps, shutdown)
|
||||
├── HomeKit URL scheme (smart home)
|
||||
└── Python mailer (status email via SMTP)
|
||||
```
|
||||
|
||||
## Gotchas & Non-Obvious
|
||||
|
||||
### Hardcoded paths
|
||||
|
||||
- `/Users/shughey/Dropbox/bin/` is hardcoded in many scripts (`sleep`, `presleep`, `wakenotify`, `idlecheck_tasks`, `maintwakes`). Will break on a different user's machine. Use `$HOME` when adding references.
|
||||
- `/Users/shughey/git/` is hardcoded in `checkin-all` and `pull-all`.
|
||||
- `/Usres/shughey/` (typo) exists in `Angus/tdarr-bounce` — affects the `Angus` machine only.
|
||||
|
||||
### Machine-specific branching
|
||||
|
||||
Several scripts branch on `scutil --get ComputerName` output:
|
||||
- `dactoggle` — branches on `Angus` vs `Petula` vs `Callum` for HomeKit tokens.
|
||||
- `presleep_quitapps` — same pattern.
|
||||
|
||||
Add new branches when adding machine-specific behavior.
|
||||
|
||||
### Authentication tokens in scripts
|
||||
|
||||
HomeKit x-callback-url tokens are **hardcoded** in `dactoggle` and `presleep_quitapps`. These are auth tokens for homecontrol.d27n.com. Do not commit to public repos.
|
||||
|
||||
### Email pipeline
|
||||
|
||||
All mail scripts:
|
||||
1. Read `$ESUBJ` env var for subject (set by Keyboard Maestro)
|
||||
2. Compute `CNAME` from `platform.node()` (Python) or `scutil --get ComputerName` (shell)
|
||||
3. Send via `emailz.d27n.com:587` with hardcoded credentials
|
||||
|
||||
### Deprecated patterns to avoid
|
||||
|
||||
- `` `backtick command substitution` `` — use `$( )` instead
|
||||
- `$[ arithmetic ]` — use `$(( ))` instead
|
||||
- Bare `$var` without quotes — use `"${var}"`
|
||||
- `export PATH=$PATH:/usr/bin/local` — `/usr/bin/local` doesn't exist on standard macOS (typo for `/usr/local/bin`)
|
||||
|
||||
### Risk zones (pmset)
|
||||
|
||||
These commands are **destructive** if run unintentionally:
|
||||
- `pmset schedule cancelall` — wipes all scheduled sleep/wake events
|
||||
- `pmset repeat cancel` — wipes recurring schedule
|
||||
- `osascript -e 'tell application "System Events" to shut down'` — immediate shutdown
|
||||
- `pmset sleepnow` / `pmset displaysleepnow` — immediate sleep
|
||||
|
||||
### Cloud sync artifacts
|
||||
|
||||
Conflicted copies from iCloud/Google Drive exist throughout the repo (`displaycount (Callum.local's conflicted copy YYYY-MM-DD).scpt`, `main (host's conflicted copy).scpt` inside `.app` bundles). These are stale and can be cleaned up.
|
||||
|
||||
### sudo requirements
|
||||
|
||||
Some scripts reference `sudo pmset ...` which requires `NOPASSWD` in sudoers (e.g., `/etc/sudoers.d/shughey`). Not portable.
|
||||
|
||||
### macOS-specific commands
|
||||
|
||||
All scripts depend on macOS-only commands:
|
||||
- `pmset` — power management
|
||||
- `scutil` — system config (ComputerName)
|
||||
- `sw_vers` — macOS version
|
||||
- `osascript` — AppleScript bridge
|
||||
- `log show --style syslog` — unified logging
|
||||
- `diskutil` — disk management
|
||||
- `networksetup` — network config
|
||||
- `sips` / `iconutil` — image processing (makeicns)
|
||||
- `hdiutil` — disk images (bootableBigSur)
|
||||
|
||||
### arc-export subproject
|
||||
|
||||
`arc-export/` is a vendored third-party tool (from [ivnvxd/arc-export](https://github.com/ivnvxd/arc-export)) — converts Arc Browser pinned tabs to HTML bookmarks. Has its own MIT license. Don't modify unless fixing bugs.
|
||||
|
||||
### Test data files
|
||||
|
||||
- `wakemaints.txt` — maintenance window config (read by `maintwakes`)
|
||||
- `test-caffeinate.txt` — test data for caffeinate detection
|
||||
- `test.sh` — sanity check/test script
|
||||
- `.nova/Configuration.json` — Nova editor config (sets default syntax to shell)
|
||||
|
||||
## .app Bundles
|
||||
|
||||
Two AppleScript `.app` bundles follow this structure:
|
||||
|
||||
```
|
||||
*.app/
|
||||
Contents/
|
||||
Info.plist # CFBundleExecutable=applet, CFBundlePackageType=APPL
|
||||
PkgInfo # "APPLaplt"
|
||||
MacOS/applet # Compiled runtime binary
|
||||
Resources/
|
||||
applet.icns # Icon
|
||||
applet.rsrc # Resource fork
|
||||
Scripts/main.scpt # The actual AppleScript (compiled binary)
|
||||
_CodeSignature/ # (unmount-cli only)
|
||||
```
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- Don't add comments to scripts unless the user asks. Many scripts have minimal or no comments.
|
||||
- Don't fix inconsistent quoting/indentation across the codebase — it's a personal toolkit, not a shared project.
|
||||
- Don't assume `set -euo pipefail` exists — only `checkin-all` and `pull-all` use it.
|
||||
- Don't run `pmset schedule cancelall` or `pmset repeat cancel` unless explicitly asked.
|
||||
- Don't commit changes without user confirmation (per agent rules).
|
||||
59
sync-pictures
Executable file
59
sync-pictures
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Sync ~/Pictures to a NAS share, then run neatcli organize on both ends.
|
||||
#
|
||||
# Uses mount -t cifs with sudo (prompts for password if no credentials file).
|
||||
# Create ~/.smb/mini.nas to avoid the password prompt each time:
|
||||
# echo -e "username=schmeeve\npassword=yourpass" > ~/.smb/mini.nas
|
||||
# chmod 600 ~/.smb/mini.nas
|
||||
#
|
||||
# Adjust SHARE and SUBPATH to match your environment.
|
||||
|
||||
SHARE="//mini.nas/miniShare1"
|
||||
SUBPATH="Pictures"
|
||||
MOUNTPOINT="/mnt/miniShare1"
|
||||
CREDENTIALS="${HOME}/.smb/mini.nas"
|
||||
SOURCE="${HOME}/Pictures"
|
||||
START="$(date +%s)"
|
||||
|
||||
echo "[sync-pictures] Starting at $(date)"
|
||||
|
||||
# 1. Create mountpoint and mount if not already mounted
|
||||
if mount | grep -q "${MOUNTPOINT}"; then
|
||||
echo "[sync-pictures] Already mounted at ${MOUNTPOINT}"
|
||||
else
|
||||
echo "[sync-pictures] Mounting ${SHARE} → ${MOUNTPOINT}"
|
||||
mkdir -p "${MOUNTPOINT}"
|
||||
OPTS="username=schmeeve,uid=$(id -u),gid=$(id -g),forceuid,forcegid,nounix,serverino"
|
||||
if [ -f "${CREDENTIALS}" ]; then
|
||||
OPTS="${OPTS},credentials=${CREDENTIALS}"
|
||||
fi
|
||||
sudo mount -t cifs "${SHARE}" "${MOUNTPOINT}" -o "${OPTS}"
|
||||
if ! mount | grep -q "${MOUNTPOINT}"; then
|
||||
echo "[sync-pictures] ERROR: Failed to mount ${SHARE}"
|
||||
exit 1
|
||||
fi
|
||||
echo "[sync-pictures] Mounted at ${MOUNTPOINT}"
|
||||
fi
|
||||
|
||||
# 2. One-way rsync contents of ~/Pictures → share subpath
|
||||
MP="${MOUNTPOINT}/${SUBPATH}"
|
||||
echo "[sync-pictures] Syncing ${SOURCE}/ → ${MP}/"
|
||||
rsync -vrau \
|
||||
"${SOURCE}/" \
|
||||
"${MP}/" \
|
||||
--progress --stats \
|
||||
--exclude=".DS_Store"
|
||||
|
||||
# 3. Run neatcli organize on both source and dest
|
||||
if command -v neatcli &>/dev/null; then
|
||||
echo "[sync-pictures] Organizing source: ${SOURCE}"
|
||||
neatcli organize --execute "${SOURCE}"
|
||||
echo "[sync-pictures] Organizing dest: ${MP}"
|
||||
neatcli organize --execute "${MP}"
|
||||
else
|
||||
echo "[sync-pictures] WARNING: neatcli not found in PATH, skipping organize step"
|
||||
fi
|
||||
|
||||
DURATION=$(( $(date +%s) - START ))
|
||||
echo "[sync-pictures] Done in ${DURATION}s at $(date)"
|
||||
Reference in New Issue
Block a user