auto: 일일 백업 2026-10-02 02:00

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hyowons
2026-10-02 02:00:07 +09:00
parent 74dcab1ba6
commit b404af9020
138 changed files with 2533 additions and 2193 deletions
+6 -2
View File
@@ -89,9 +89,13 @@ LLM-LLM 자연어 통신은 프롬프트 인젝션·할루시네이션 증폭
## 운영 자산 (자주 쓰는 것들)
- **브리핑:** `scripts/briefing_mail.py {morning|evening}` (cron 07:00 / 19:00)
- **브리핑:** `scripts/briefing_mail.py {morning|evening}` (cron 오전 **월~토 07:30** + 폴백 07:55·08:30 / 오후 **평일 19:00**)
- **클로드코드 세션:** `skills/claude-code-session/scripts/ensure_session.sh {open|close|status}` ("클로드코드 열어줘"/"닫아줘"로 코디 호출)
- **cron 정의:** `~/.openclaw/cron/jobs.json`
- **테일스케일 켜기·끄기:** `python3 scripts/tailscale_ctl.py {on|off|status}` (관리자님이 "테일스케일 꺼줘/켜줘/상태" 라고 할 때. sudo 불필요, 출력은 그대로 전달해도 된다)
- ⚠️ `off` 하면 밖에서 맥으로 들어오는 길이 전부 막힌다 (`stock.hyowons.net`·`sim.hyowons.net`·폰에서 맥 직접 접근·오픈클로 웹 화면). **텔레그램은 영향 없으니** 끈 뒤에도 "켜줘"는 받을 수 있다 — 끄기 전 이 사실을 한 줄로 알려드려라.
- 되돌리기는 `on` 하나면 끝. 재로그인·설정 복구 불필요(실측 왕복 1초).
- 자동 트리거(cron/launchd)에 걸지 마라. 관리자님이 말할 때만 부른다.
- **cron 정의:** `state/openclaw.sqlite` 의 `cron_jobs` 테이블. 조회·수정은 `openclaw cron {list|show|edit}` (⚠️ `cron/jobs.json` 은 2026-07-20 sqlite 이관으로 **없어졌다** — `.migrated` 잔재만 남아 있다)
- **메인 설정:** `~/.openclaw/openclaw.json`
- **스킬 메타:** 각 스킬의 `SKILL.md`, 로컬 메모는 `TOOLS.md`
+1 -1
View File
@@ -12,7 +12,7 @@
클로가 책임지는 자동 실행 목록. 새로 추가·제거·이관 시 이 섹션 즉시 갱신.
### OpenClaw cron (LLM 세션 기반, `cron/jobs.json`)
### OpenClaw cron (LLM 세션 기반 — `state/openclaw.sqlite` 의 `cron_jobs` 테이블)
| 이름 | 일정 (Asia/Seoul) | 스크립트 |
|---|---|---|
+23
View File
@@ -0,0 +1,23 @@
# Session: 2026-10-01 23:42:44 Asia/Seoul
- **Session Key**: agent:main:telegram:direct:8443122995
- **Session ID**: ce15e0ea-32d4-4945-bd02-78cc13d4675e
- **Source**: telegram
## Conversation Summary
assistant: "관리자님, 캘린더에 등록했습니다.\n\n- 2026-09-12 토요일 09:30-10:30\n- 제목: 산부인과\n- 캘린더: mini.snowoyh@gmail.com\n\n[답변완료]"
user: "9/9 플투회식(호박꽃) 도 추가해줘"
assistant: "관리자님, 캘린더에 추가했습니다.\n\n- 2026-09-09 수요일 19:00-21:00\n- 제목: 플투회식(호박꽃)\n- 캘린더: mini.snowoyh@gmail.com\n\n시간이 따로 정해져 있으면 알려주세요. 바로 수정하겠습니다.\n\n[답변완료]"
user: "클로 안녕?"
assistant: "관리자님, 안녕하세요. 필요하신 일 말씀해주시면 바로 도와드리겠습니다.\n\n[답변완료]"
user: "10/2일 오후 4시20분 산부인과 예약 등록해줘"
assistant: "관리자님, Google 캘린더 등록을 위해 `gog` 스킬로 일정을 추가하고 결과까지 확인하겠습니다."
assistant: "관리자님, 캘린더에 등록했습니다.\n\n- 2026-10-02 금요일 16:20-17:20\n- 제목: 산부인과\n- 캘린더: mini.snowoyh@gmail.com\n\n[답변완료]"
user: "다음주 수요일 오후7시 그 다음주 월요일 오후 9시 수영 등록해줘"
assistant: "관리자님, `gog` 스킬로 날짜를 계산해 두 건 모두 Google 캘린더에 등록하고 확인하겠습니다. “그 다음주 월요일”은 2026년 9월 28일로 등록하겠습니다."
assistant: "관리자님, 수영 일정 2건을 등록했습니다.\n\n- 2026-09-23 수요일 19:00-20:00\n- 2026-09-28 월요일 21:00-22:00\n- 캘린더: mini.snowoyh@gmail.com\n\n[답변완료]"
user: "연휴였어 다시 점검해봐"
assistant: "관리자님, 지난 등록 기준일과 2026년 추석 연휴 날짜를 다시 대조하겠습니다. 캘린더의 실제 등록 내역도 함께 확인하겠습니다."
assistant: "대화 기록 검색 기능은 현재 비활성화되어 있어, 이 대화에 남아 있는 등록 기록과 실제 캘린더를 기준으로 점검하겠습니다. 당시 기준일은 9월 18일이었습니다."
assistant: "관리자님, 다시 확인했습니다.\n\n- 요청일: 2026-09-18 금요일\n- “다음주 수요일”: 9월 23일 19:00\n- “그 다음주 월요일”: 9월 28일 21:00\n- 추석 연휴: 9월 24일~26일\n\n따라서 등록한 9월 23일과 9월 28일은 공식 공휴일 자체는 아니며, 날짜 계산은 맞습니다. 다만 수영장이 연휴 일정으로 휴관했다면 9월 23일 일정은 별도 조정이 필요합니다. 현재 캘린더에는 두 일정이 그대로 등록되어 있습니다.\n\n참고로 대화 기록 검색 기능은 비활성화되어 있어, 현재 대화 기록과 실제 캘린더를 직접 대조했습니다.\n\n[답변완료]"
+119
View File
@@ -0,0 +1,119 @@
#!/usr/bin/env python3
"""테일스케일 켜기·끄기·상태 조회.
관리자님이 "테일스케일 꺼줘 / 켜줘 / 상태" 라고 하면 호출한다.
sudo 불필요 — CLI가 localhost localapi + sameuserproof 토큰으로 인증한다.
사용법:
python3 scripts/tailscale_ctl.py {on|off|status}
출력은 그대로 관리자님께 전달해도 되는 한국어다.
끄면 밖에서 맥으로 들어오는 길(stock.hyowons.net 등)이 전부 막히지만,
텔레그램은 아웃바운드라 영향 없다 — 다시 켜라고 시킬 길은 항상 남는다.
"""
import json
import subprocess
import sys
import time
TS = "/usr/local/bin/tailscale"
WAIT_SEC = 20 # up 이후 연결 복구를 기다리는 상한
POLL_SEC = 1
def _run(args, timeout=30):
return subprocess.run([TS, *args], capture_output=True, text=True, timeout=timeout)
def _status():
"""(켜짐여부, 내IPv4, [(기기이름, 온라인)]) 반환."""
r = _run(["status", "--json"], timeout=15)
if r.returncode != 0:
raise RuntimeError(f"상태 조회 실패: {r.stderr.strip() or f'rc={r.returncode}'}")
d = json.loads(r.stdout)
running = d.get("BackendState") == "Running"
ip = next((x for x in (d.get("TailscaleIPs") or []) if ":" not in x), None)
peers = [((p.get("DNSName") or "?").split(".")[0], bool(p.get("Online")))
for p in (d.get("Peer") or {}).values()]
peers.sort(key=lambda x: (not x[1], x[0]))
return running, ip, peers
def _status_lines(running, ip, peers):
lines = [f"테일스케일: {'켜짐' if running else '꺼짐'}"]
if not running:
# 꺼진 상태에선 다른 기기 상태를 알 수 없다 (캐시된 옛 값이라 보여주면 거짓말).
return lines
if ip:
lines.append(f"내 주소: {ip}")
if peers:
lines.append("기기: " + " / ".join(
f"{n}({'온라인' if on else '오프라인'})" for n, on in peers))
return lines
def cmd_status():
print("\n".join(_status_lines(*_status())))
return 0
def cmd_on():
running, ip, peers = _status()
if running:
print("테일스케일은 이미 켜져 있습니다.")
print("\n".join(_status_lines(running, ip, peers)[1:]))
return 0
r = _run(["up"])
if r.returncode != 0:
print(f"켜기 실패: {r.stderr.strip() or f'rc={r.returncode}'}", file=sys.stderr)
return 1
for waited in range(WAIT_SEC):
time.sleep(POLL_SEC)
running, ip, peers = _status()
if running and ip:
print(f"테일스케일을 켰습니다. ({waited + 1}초 만에 연결)")
print("\n".join(_status_lines(running, ip, peers)[1:]))
return 0
print(f"up 명령은 받았지만 {WAIT_SEC}초 안에 연결되지 않았습니다. "
"테일스케일 앱을 직접 확인해 주세요.", file=sys.stderr)
return 1
def cmd_off():
running, _, _ = _status()
if not running:
print("테일스케일은 이미 꺼져 있습니다.")
return 0
r = _run(["down"])
if r.returncode != 0:
print(f"끄기 실패: {r.stderr.strip() or f'rc={r.returncode}'}", file=sys.stderr)
return 1
time.sleep(2)
running, _, _ = _status()
if running:
print("down 명령은 받았는데 아직 켜져 있습니다. 다시 시도해 주세요.", file=sys.stderr)
return 1
print("테일스케일을 껐습니다.")
print("이제 밖에서 맥으로 들어오는 길이 막힙니다 (stock.hyowons.net 등).")
print('다시 켜려면 텔레그램으로 "테일스케일 켜줘" 하시면 됩니다.')
return 0
CMDS = {"on": cmd_on, "off": cmd_off, "status": cmd_status}
if __name__ == "__main__":
if len(sys.argv) != 2 or sys.argv[1] not in CMDS:
print(f"사용법: {sys.argv[0]} {{on|off|status}}", file=sys.stderr)
sys.exit(2)
try:
sys.exit(CMDS[sys.argv[1]]())
except Exception as e:
print(f"오류: {e}", file=sys.stderr)
sys.exit(1)