Add Object B and self-growth canons with Cursor ledger rules; refresh connectivity and VPN runbooks.
Track day metrics/anamnesis HARD rules under .cursor/rules and personal docs so each screening updates days/{KIN}, dynamics, and big-data ledger.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
39
docs/apps/joplin/scripts/joplin-ensure-sync.sh
Executable file
39
docs/apps/joplin/scripts/joplin-ensure-sync.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
# Подготовить Mac к синку Joplin с телефона (одна команда).
|
||||
# ./joplin-ensure-sync.sh
|
||||
#
|
||||
# Mac = клиент Wi‑Fi хотспота телефона. Primary IP *.100 (не alias).
|
||||
|
||||
set -e
|
||||
|
||||
ROOT="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
|
||||
|
||||
echo "=== Joplin: подготовка синка ==="
|
||||
|
||||
if ! pgrep -f "rclone serve webdav" >/dev/null 2>&1; then
|
||||
echo "→ запуск WebDAV..."
|
||||
"$ROOT/joplin-webdav-serve.sh"
|
||||
else
|
||||
echo "→ WebDAV уже запущен"
|
||||
fi
|
||||
|
||||
if [ -x "$ROOT/joplin-hotspot-alias.sh" ]; then
|
||||
if ! "$ROOT/joplin-hotspot-alias.sh" repair 2>/dev/null; then
|
||||
if ! "$ROOT/joplin-hotspot-alias.sh" ensure 2>/dev/null; then
|
||||
echo ""
|
||||
echo "⚠ Нужен sudo один раз:"
|
||||
echo " ./docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh"
|
||||
echo " ./docs/apps/joplin/scripts/joplin-hotspot-alias.sh repair"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
"$ROOT/joplin-webdav-status.sh"
|
||||
|
||||
echo ""
|
||||
echo "=== На телефоне ==="
|
||||
echo "1. Mac должен быть на Wi‑Fi хотспота этого телефона (не домашний Wi‑Fi)"
|
||||
echo "2. Joplin → WebDAV → URL из блока выше (*.100)"
|
||||
echo "3. Браузер на телефоне → тот же URL → логин за 2–3 сек"
|
||||
echo "4. Синхронизировать"
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Одноразово: passwordless sudo только для joplin-hotspot-alias.sh ensure
|
||||
# Одноразово: passwordless sudo для joplin-hotspot-alias.sh (setmanual *.100, dhcp)
|
||||
set -e
|
||||
|
||||
SCRIPT="$(CDPATH= cd -- "$(dirname "$0")" && pwd)/joplin-hotspot-alias.sh"
|
||||
@@ -12,8 +12,8 @@ TMP="$(mktemp)"
|
||||
trap 'rm -f "$TMP"' EXIT
|
||||
|
||||
cat >"$TMP" <<EOF
|
||||
# Joplin WebDAV: alias *.100 на en0 после reconnect хотспота (только этот скрипт)
|
||||
${USER_NAME} ALL=(ALL) NOPASSWD: ${SCRIPT} ensure
|
||||
# Joplin WebDAV: primary *.100 на Wi-Fi (setmanual) + dhcp (только этот скрипт)
|
||||
${USER_NAME} ALL=(ALL) NOPASSWD: ${SCRIPT}, ${SCRIPT} ensure, ${SCRIPT} ensure --force, ${SCRIPT} repair, ${SCRIPT} dhcp
|
||||
EOF
|
||||
|
||||
echo "Будет создан $DEST:"
|
||||
@@ -22,4 +22,4 @@ echo ""
|
||||
sudo cp "$TMP" "$DEST"
|
||||
sudo chmod 440 "$DEST"
|
||||
sudo visudo -c -f "$DEST"
|
||||
echo "OK. LaunchAgent сможет поднимать alias без пароля."
|
||||
echo "OK. LaunchAgent сможет выставлять *.100 без пароля."
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# LaunchAgent: каждые 60 с проверять alias *.100 (нужен joplin-hotspot-alias-install-sudo.sh).
|
||||
# LaunchAgent: каждые 60 с проверять primary *.100 (нужен joplin-hotspot-alias-install-sudo.sh).
|
||||
set -e
|
||||
|
||||
ROOT="$(CDPATH= cd -- "$(dirname "$0")" && pwd)"
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#!/bin/sh
|
||||
# Стабильный URL для Joplin на телефоне при Android-хотспоте: http://<подсеть>.100:8080
|
||||
# Alias *.100 на en0 (DHCP primary не трогаем). LaunchAgent поднимает alias после reconnect.
|
||||
# Стабильный URL для Joplin: http://<подсеть>.100:8080
|
||||
# Primary IP *.100 через networksetup (Android видит primary, alias — часто нет).
|
||||
#
|
||||
# ./joplin-hotspot-alias.sh status
|
||||
# ./joplin-hotspot-alias.sh ensure
|
||||
# ./joplin-hotspot-alias.sh ensure|repair
|
||||
# ./joplin-hotspot-alias.sh dhcp # вернуть DHCP (перед домашним Wi‑Fi)
|
||||
#
|
||||
# Passwordless: ./joplin-hotspot-alias-install-sudo.sh
|
||||
|
||||
@@ -11,8 +12,10 @@ set -e
|
||||
|
||||
CONFIG="${JOPLIN_WEBDAV_CONFIG:-$HOME/.config/joplin-webdav/env}"
|
||||
WIFI_DEV="${WIFI_DEVICE:-en0}"
|
||||
WIFI_SERVICE="${WIFI_SERVICE:-Wi-Fi}"
|
||||
PORT="${JOPLIN_WEBDAV_PORT:-8080}"
|
||||
LOG="$HOME/Library/Logs/joplin-webdav/alias.log"
|
||||
NS="/usr/sbin/networksetup"
|
||||
|
||||
ipv4_subnet() {
|
||||
printf '%s\n' "$1" | awk -F. '{print $1"."$2"."$3}'
|
||||
@@ -59,19 +62,34 @@ has_ip_on_dev() {
|
||||
ifconfig "$dev" 2>/dev/null | grep -q "inet ${ip} "
|
||||
}
|
||||
|
||||
# Убрать *.100 alias с других подсетей (после смены хотспота / Wi‑Fi)
|
||||
prune_stale_aliases() {
|
||||
target="$1"
|
||||
dev="$2"
|
||||
ifconfig "$dev" 2>/dev/null | awk '/inet / {print $2}' | while read -r ip; do
|
||||
case "$ip" in
|
||||
*.*.*.100)
|
||||
[ "$ip" = "$target" ] && continue
|
||||
ifconfig "$dev" -alias "$ip" 2>/dev/null || true
|
||||
log_msg "removed stale alias $ip"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
is_android_hotspot_gw() {
|
||||
gw="$1"
|
||||
case "$gw" in
|
||||
10.*|172.20.10.*|192.168.43.*|192.168.44.*|192.168.49.*) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
log_msg() {
|
||||
mkdir -p "$(dirname "$LOG")"
|
||||
printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >>"$LOG"
|
||||
}
|
||||
|
||||
run_priv() {
|
||||
if [ "$(id -u)" -eq 0 ]; then
|
||||
"$@"
|
||||
else
|
||||
sudo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
write_phone_url_env() {
|
||||
url="$(phone_url 2>/dev/null || true)"
|
||||
[ -n "$url" ] && [ -f "$CONFIG" ] || return 0
|
||||
@@ -90,31 +108,45 @@ cmd_status() {
|
||||
gw="$(default_gateway 2>/dev/null || true)"
|
||||
url="$(phone_url 2>/dev/null || true)"
|
||||
|
||||
echo "mode: Android-хотспот (alias *.100)"
|
||||
echo "mode: static primary *.100 ($WIFI_SERVICE)"
|
||||
echo "device: $WIFI_DEV"
|
||||
echo "primary: ${primary:-(none)}"
|
||||
echo "gateway: ${gw:-(none)}"
|
||||
echo "joplin IP: ${target:-(no gateway)}"
|
||||
|
||||
if [ -n "$target" ] && has_ip_on_dev "$target" "$WIFI_DEV"; then
|
||||
echo "alias: OK"
|
||||
elif [ -n "$target" ] && [ "$primary" = "$target" ]; then
|
||||
echo "alias: OK (primary)"
|
||||
if [ -n "$gw" ] && ! is_android_hotspot_gw "$gw"; then
|
||||
echo "network: домашний/роутер Wi‑Fi (не Android-хотспот)"
|
||||
echo " → телефон должен быть в той же Wi‑Fi сети, что Mac"
|
||||
else
|
||||
echo "network: похоже на Android-хотспот"
|
||||
fi
|
||||
|
||||
if [ -n "$target" ]; then
|
||||
ifconfig "$WIFI_DEV" 2>/dev/null | awk -v t="$target" '/inet / { if ($2 ~ /\.100$/ && $2 != t) print "stale ifconfig: " $2 " (repair)" }'
|
||||
fi
|
||||
|
||||
if [ -n "$target" ] && [ "$primary" = "$target" ]; then
|
||||
echo "static IP: OK (primary = $target)"
|
||||
elif [ -n "$target" ]; then
|
||||
echo "alias: MISSING — телефон не достучится"
|
||||
echo " fix: $0 ensure"
|
||||
echo "static IP: MISSING (primary $primary, нужен $target)"
|
||||
echo " fix: $0 repair"
|
||||
fi
|
||||
|
||||
if [ -n "$url" ]; then
|
||||
echo ""
|
||||
echo "URL на телефоне (работает с Android-хотспота):"
|
||||
echo "URL на телефоне:"
|
||||
echo " $url"
|
||||
echo ""
|
||||
echo "Проверка: браузер НА ТЕЛЕФОНЕ → URL → запрос логина за 2–3 сек"
|
||||
echo "Если браузер висит — телефон не видит Mac (не Joplin)"
|
||||
echo ""
|
||||
echo "⚠ http://*.local:8080 с телефона НЕ работает (Android не резолвит mDNS клиентов хотспота)"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_ensure() {
|
||||
force=0
|
||||
[ "${1:-}" = --force ] && force=1
|
||||
target="$(joplin_phone_ip 2>/dev/null || true)"
|
||||
if [ -z "$target" ]; then
|
||||
log_msg "skip: no gateway"
|
||||
@@ -125,25 +157,56 @@ cmd_ensure() {
|
||||
log_msg "skip: no primary IP"
|
||||
exit 0
|
||||
fi
|
||||
if [ "$primary" = "$target" ] || has_ip_on_dev "$target" "$WIFI_DEV"; then
|
||||
write_phone_url_env
|
||||
if [ "$primary" = "$target" ] && [ "$force" -eq 0 ]; then
|
||||
[ "$(id -u)" -ne 0 ] && write_phone_url_env
|
||||
exit 0
|
||||
fi
|
||||
log_msg "add alias $target on $WIFI_DEV (primary $primary)"
|
||||
run_priv ifconfig "$WIFI_DEV" inet "$target" netmask 255.255.255.0 alias
|
||||
write_phone_url_env
|
||||
echo "alias OK: $target"
|
||||
echo "URL на телефоне: $(phone_url)"
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
log_msg "setmanual $target (was $primary)"
|
||||
sudo_arg=ensure
|
||||
[ "$force" -eq 1 ] && sudo_arg="ensure --force"
|
||||
# shellcheck disable=SC2086
|
||||
if ! sudo -n "$0" $sudo_arg; then
|
||||
echo "static IP FAILED: нужен sudo." >&2
|
||||
echo " один раз: ./docs/apps/joplin/scripts/joplin-hotspot-alias-install-sudo.sh" >&2
|
||||
echo " затем: $0 repair" >&2
|
||||
exit 1
|
||||
fi
|
||||
write_phone_url_env
|
||||
echo "static IP OK: $target"
|
||||
echo "URL на телефоне: $(phone_url)"
|
||||
exit 0
|
||||
fi
|
||||
gw="$(default_gateway 2>/dev/null || true)"
|
||||
[ -n "$gw" ] || { log_msg "skip: no gateway"; exit 1; }
|
||||
prune_stale_aliases "$target" "$WIFI_DEV"
|
||||
log_msg "networksetup -setmanual $target gw $gw [root]"
|
||||
"$NS" -setmanual "$WIFI_SERVICE" "$target" "255.255.255.255.0" "$gw"
|
||||
}
|
||||
|
||||
cmd_dhcp() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
if ! sudo -n "$0" dhcp; then
|
||||
echo "Нужен sudo: sudo $NS -setdhcp \"$WIFI_SERVICE\"" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Wi‑Fi → DHCP"
|
||||
exit 0
|
||||
fi
|
||||
"$NS" -setdhcp "$WIFI_SERVICE"
|
||||
log_msg "setdhcp $WIFI_SERVICE"
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "Usage: $(basename "$0") status|ensure" >&2
|
||||
echo "Usage: $(basename "$0") status|ensure|repair|dhcp" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
case "${1:-ensure}" in
|
||||
status) cmd_status ;;
|
||||
ensure) cmd_ensure ;;
|
||||
ensure) cmd_ensure "${2:-}" ;;
|
||||
repair) "$0" ensure --force ;;
|
||||
dhcp) cmd_dhcp ;;
|
||||
-h|--help) usage ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
|
||||
@@ -56,16 +56,52 @@ if [ -f "$settings" ]; then
|
||||
| while read -r u; do echo "settings.json: $u"; done
|
||||
fi
|
||||
|
||||
log="$HOME/Library/Logs/joplin-webdav/rclone.log"
|
||||
|
||||
echo ""
|
||||
echo "=== Сеть: Mac и телефон в одной LAN? ==="
|
||||
gw=$(route -n get default 2>/dev/null | awk '/gateway:/{print $2; exit}')
|
||||
ip=$(ipconfig getifaddr en0 2>/dev/null || true)
|
||||
case "$gw" in
|
||||
192.168.1.*|192.168.0.*)
|
||||
peers=$(arp -an 2>/dev/null | grep "$gw" | awk '{print $2}' | tr -d '()' | grep -vE "^${gw%.*}\.(1|255)$|^$ip$" | head -3)
|
||||
if [ -z "$peers" ]; then
|
||||
echo "⚠ Mac на домашнем Wi‑Fi ($ip), других устройств в LAN не видно"
|
||||
echo " Телефон, скорее всего, НЕ в этой Wi‑Fi → синк невозможен"
|
||||
echo " Вариант A: Mac подключить к хотспоту телефона"
|
||||
echo " Вариант B: телефон подключить к той же Wi‑Fi, что Mac"
|
||||
else
|
||||
echo "Mac на Wi‑Fi роутера ($ip). Телефон должен быть в той же Wi‑Fi."
|
||||
fi
|
||||
;;
|
||||
10.*|172.20.10.*|192.168.43.*|192.168.44.*)
|
||||
echo "Mac на хотспоте ($ip). URL на телефоне — из блока выше (*.100)."
|
||||
if [ -n "$gw" ] && [ -f "$log" ] && ! grep -q "from ${gw}:" "$log" 2>/dev/null; then
|
||||
echo "⚠ В логе rclone ещё не было запросов с телефона ($gw)"
|
||||
echo " Проверьте URL в браузере НА ТЕЛЕФОНЕ (не только в Joplin)"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
[ -n "$gw" ] && echo "gateway: $gw, Mac: ${ip:-?}"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "=== rclone (запросы с телефона?) ==="
|
||||
log="$HOME/Library/Logs/joplin-webdav/rclone.log"
|
||||
gw=$(route -n get default 2>/dev/null | awk '/gateway:/{print $2; exit}')
|
||||
if [ -f "$log" ]; then
|
||||
phone_lines=$(grep -E 'from 10\.|from 192\.168\.' "$log" 2>/dev/null | tail -3)
|
||||
if [ -n "$phone_lines" ]; then
|
||||
phone_lines=$(grep -E 'from 10\.|from 192\.168\.' "$log" 2>/dev/null | grep -v '127.0.0.1' | tail -5)
|
||||
if [ -n "$gw" ] && grep -q "from ${gw}:" "$log" 2>/dev/null; then
|
||||
echo "OK: в логе есть запросы с телефона/шлюза ($gw)"
|
||||
grep "from ${gw}:" "$log" 2>/dev/null | tail -2
|
||||
elif [ -n "$phone_lines" ]; then
|
||||
echo "$phone_lines"
|
||||
echo "⚠ нет запросов с шлюза ${gw:-?} — возможно только тесты с Mac"
|
||||
else
|
||||
echo "нет запросов с LAN (только 127.0.0.1?) — телефон не достучался"
|
||||
echo "нет запросов с LAN — телефон не достучался до rclone"
|
||||
fi
|
||||
echo ""
|
||||
echo "Смотреть live: tail -f $log | grep -v 127.0.0.1"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user