-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathautonomous-action.sample.sh
More file actions
executable file
·469 lines (419 loc) · 17 KB
/
Copy pathautonomous-action.sample.sh
File metadata and controls
executable file
·469 lines (419 loc) · 17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
#!/bin/bash
# Claude 자율 행동 스크립트 (macOS 버전)
# 20분마다 cron으로 실행, 시간대에 따라 간격 조절
#
# crontab -e 로 다음을 추가:
# */20 * * * * /path/to/your/project/autonomous-action.sh
#
# Usage:
# autonomous-action.sh # 일반 실행 (cron)
# autonomous-action.sh --test-prompt FILE # 프롬프트 교체 (스케줄 제어 스킵)
# autonomous-action.sh --date "2026-02-20 14:30" # 일시 주입 (스케줄 제어 테스트)
# autonomous-action.sh --force-routine # 루틴 회차 강제
# autonomous-action.sh --force-normal # 평상 회차 강제
# autonomous-action.sh --dry-run # claude -p 실행 없이 프롬프트 표시
# autonomous-action.sh -p "임의의 프롬프트" # 프롬프트 직접 지정 (스케줄 제어 스킵)
# autonomous-action.sh --dry-run --date "2026-02-20 03:00" --force-routine # 조합 가능
# NOTE: Set HOME and PATH for your environment
export HOME="${HOME:-$(/usr/bin/dscl . -read /Users/$(whoami) NFSHomeDirectory | awk '{print $2}')}"
export PATH="/opt/homebrew/bin:${PATH:-/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# Load environment variables (API keys, etc.)
if [ -f "$SCRIPT_DIR/.env" ]; then
set -a
source "$SCRIPT_DIR/.env"
set +a
fi
# --- 인자 파싱 ---
TEST_PROMPT_FILE=""
TEST_PROMPT_STRING=""
OVERRIDE_DATE=""
FORCE_ROUTINE="" # "", "routine", "normal"
DRY_RUN=false
while [ $# -gt 0 ]; do
case "$1" in
-p)
TEST_PROMPT_STRING="$2"
shift 2
;;
--test-prompt)
TEST_PROMPT_FILE="$2"
shift 2
;;
--date)
OVERRIDE_DATE="$2"
shift 2
;;
--force-routine)
FORCE_ROUTINE="routine"
shift
;;
--force-normal)
FORCE_ROUTINE="normal"
shift
;;
--dry-run)
DRY_RUN=true
shift
;;
*)
echo "Unknown option: $1" >&2
exit 1
;;
esac
done
# --- 일시 결정 ---
if [ -n "$OVERRIDE_DATE" ]; then
HOUR=$((10#$(date -j -f "%Y-%m-%d %H:%M" "$OVERRIDE_DATE" +%H 2>/dev/null || date -d "$OVERRIDE_DATE" +%H)))
MINUTE=$((10#$(date -j -f "%Y-%m-%d %H:%M" "$OVERRIDE_DATE" +%M 2>/dev/null || date -d "$OVERRIDE_DATE" +%M)))
else
HOUR=$((10#$(date +%H)))
MINUTE=$((10#$(date +%M)))
fi
# timeout 명령 감지 (GNU coreutils or macOS built-in)
TIMEOUT_CMD=$(which timeout 2>/dev/null || which gtimeout 2>/dev/null)
LOG_DIR="$SCRIPT_DIR/.autonomous-logs"
mkdir -p "$LOG_DIR"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="$LOG_DIR/$TIMESTAMP.log"
echo "LOG: $LOG_FILE"
# 오래된 로그 정리 (1일 이상 전)
find "$LOG_DIR" -name "*.log" -mtime +1 -delete 2>/dev/null
echo "=== 자율 행동 시작: $(date) ===" >> "$LOG_FILE"
if [ -n "$OVERRIDE_DATE" ]; then
echo "[일시 오버라이드] $OVERRIDE_DATE (HOUR=$HOUR, MINUTE=$MINUTE)" >> "$LOG_FILE"
fi
if [ -n "$TEST_PROMPT_FILE" ]; then
echo "[테스트 모드] 프롬프트: $TEST_PROMPT_FILE" >> "$LOG_FILE"
fi
# --- 스케줄 제어의 초기 판정 ---
SKIP_SCHEDULE=false
if [ -n "$TEST_PROMPT_FILE" ] || [ -n "$TEST_PROMPT_STRING" ]; then
SKIP_SCHEDULE=true
elif [ "$DRY_RUN" = true ] && [ -z "$OVERRIDE_DATE" ]; then
SKIP_SCHEDULE=true
fi
# --- 휴일·휴가 판정 ---
SCHEDULE_CONF="$SCRIPT_DIR/schedule.conf"
IS_HOLIDAY=false
IS_VACATION=false
if [ -f "$SCHEDULE_CONF" ]; then
source "$SCHEDULE_CONF"
# 요일 판정 (0=일, 6=토)
if [ -n "$OVERRIDE_DATE" ]; then
DOW=$(date -j -f "%Y-%m-%d %H:%M" "$OVERRIDE_DATE" +%w 2>/dev/null || date -d "$OVERRIDE_DATE" +%w)
TODAY_MMDD=$(date -j -f "%Y-%m-%d %H:%M" "$OVERRIDE_DATE" +%m-%d 2>/dev/null || date -d "$OVERRIDE_DATE" +%m-%d)
else
DOW=$(date +%w)
TODAY_MMDD=$(date +%m-%d)
fi
# 요일이 휴일 목록에 포함되는지
if echo ",$HOLIDAY_WEEKDAYS," | grep -q ",$DOW,"; then
IS_HOLIDAY=true
fi
# 날짜가 공휴일 목록에 포함되는지
if [ -n "$HOLIDAY_DATES" ] && echo ",$HOLIDAY_DATES," | grep -q ",$TODAY_MMDD,"; then
IS_HOLIDAY=true
fi
# 날짜가 휴가 목록에 포함되는지 (휴가 = 활동 빈도를 낮춤)
if [ -n "$VACATION_DATES" ] && echo ",$VACATION_DATES," | grep -q ",$TODAY_MMDD,"; then
IS_VACATION=true
fi
fi
# --- 자동 기상: 아침 7시대에 /sleep 빈도 감소를 평상값으로 복귀 ---
if [ "$SKIP_SCHEDULE" = false ] && [ "$HOUR" -eq 7 ] && [ -f "$SCHEDULE_CONF" ]; then
CURRENT_DAY=$(grep "^DAYTIME_CHANCE=" "$SCHEDULE_CONF" | cut -d= -f2)
CURRENT_NIGHT=$(grep "^NIGHT_CHANCE=" "$SCHEDULE_CONF" | cut -d= -f2)
if [ "${CURRENT_DAY:-50}" -lt 50 ] || [ "${CURRENT_NIGHT:-10}" -lt 10 ]; then
sed -i '' 's/^DAYTIME_CHANCE=.*/DAYTIME_CHANCE=50/' "$SCHEDULE_CONF"
sed -i '' 's/^NIGHT_CHANCE=.*/NIGHT_CHANCE=10/' "$SCHEDULE_CONF"
echo "[자동 기상] DAYTIME_CHANCE: ${CURRENT_DAY}→50, NIGHT_CHANCE: ${CURRENT_NIGHT}→10" >> "$LOG_FILE"
fi
fi
# --- 스케줄 제어 (claude 도달 전 조기 리턴) ---
# 테스트 모드에서는 스킵. dry-run은 --date 지정 시에만 스케줄 제어 통과
# 평일:
# 집중 (20분 간격 매번 실행): 7-8시, 12-13시, 18-24시
# 그 외 낮 (매시:00만, 50%): 8-12시, 13-18시
# 심야 (매시:00만, 10%): 0-7시
# 휴일: 7-24시가 모두 활성 시간대 (20분 간격 매번 실행)
# 휴가: 전 시간대 60분 간격 (매시:00만), 루틴 확률 상승
if [ "$SKIP_SCHEDULE" = false ]; then
IS_ACTIVE=false
if [ "$IS_VACATION" = true ]; then
# 휴가 모드: 전 시간대 60분 간격 (매시:00만)
if [ "$MINUTE" -ne 0 ]; then
echo "휴가 모드 :${MINUTE} 스킵 (DATE=$TODAY_MMDD)" >> "$LOG_FILE"
exit 0
fi
IS_ACTIVE=true
echo "휴가 모드 (DATE=$TODAY_MMDD)" >> "$LOG_FILE"
elif [ "$IS_HOLIDAY" = true ]; then
# 휴일: 7-24시는 모두 활성
if [ "$HOUR" -ge 7 ]; then
IS_ACTIVE=true
fi
echo "휴일 모드 (DOW=$DOW, DATE=$TODAY_MMDD)" >> "$LOG_FILE"
else
# 평일
if [ "$HOUR" -ge 7 ] && [ "$HOUR" -lt 8 ]; then
IS_ACTIVE=true
elif [ "$HOUR" -ge 12 ] && [ "$HOUR" -lt 13 ]; then
IS_ACTIVE=true
elif [ "$HOUR" -ge 18 ]; then
IS_ACTIVE=true
fi
fi
if [ "$IS_ACTIVE" = false ]; then
# 비활성 시간대: 매시:00만 (:20, :40은 스킵)
if [ "$MINUTE" -ne 0 ]; then
echo "비활성 시간대 :${MINUTE} 스킵" >> "$LOG_FILE"
exit 0
fi
RAND=$(( $(od -An -tu2 -N2 /dev/urandom | tr -d ' ') % 100 ))
if [ "$HOUR" -ge 8 ] && [ "$HOUR" -lt 18 ]; then
# 낮: DAYTIME_CHANCE% 확률로 실행 (schedule.conf, 기본 50)
THRESHOLD=${DAYTIME_CHANCE:-50}
if [ "$RAND" -ge "$THRESHOLD" ]; then
echo "낮 스킵 (RAND=$RAND >= $THRESHOLD)" >> "$LOG_FILE"
exit 0
fi
echo "낮 실행 (RAND=$RAND < $THRESHOLD)" >> "$LOG_FILE"
else
# 심야: NIGHT_CHANCE% 확률로 실행 (schedule.conf, 기본 10)
THRESHOLD=${NIGHT_CHANCE:-10}
if [ "$RAND" -ge "$THRESHOLD" ]; then
echo "심야 스킵 (RAND=$RAND >= $THRESHOLD)" >> "$LOG_FILE"
exit 0
fi
echo "심야 실행 (RAND=$RAND < $THRESHOLD)" >> "$LOG_FILE"
fi
fi
fi
# --- 시간대 규칙 (schedule.conf에서 불러오기) ---
if [ "$HOUR" -lt 7 ]; then
TIME_RULE="${NIGHT_TIME_RULE:-심야 시간대. say, notify, slack은 사용하지 말 것. 조용히 관찰만.}"
else
TIME_RULE="${DAY_TIME_RULE:-say는 방에 사람이 있을 때만 사용해도 됨. 사람이 없으면 notify, slack은 전할 말이 있을 때만 사용.}"
fi
# --- 루틴 판정 (평상 20%, 휴가 시 60% 확률로 루틴 회차) ---
ROUTINE_THRESHOLD=${ROUTINE_CHANCE:-20}
if [ "$IS_VACATION" = true ]; then
ROUTINE_THRESHOLD=${VACATION_ROUTINE_CHANCE:-60}
echo "휴가 모드: 루틴 확률 ${ROUTINE_THRESHOLD}%" >> "$LOG_FILE"
fi
if [ "$FORCE_ROUTINE" = "routine" ]; then
ROUTINE_RAND=0
elif [ "$FORCE_ROUTINE" = "normal" ]; then
ROUTINE_RAND=100
else
ROUTINE_RAND=$(( $(od -An -tu2 -N2 /dev/urandom | tr -d ' ') % 100 ))
fi
if [ "$ROUTINE_RAND" -lt "$ROUTINE_THRESHOLD" ]; then
ROUTINE_MODE="${ROUTINE_PROMPT:-이번은 루틴 회차. ROUTINES.md를 읽고, 마지막 실행일로부터 간격이 벌어진 항목을 하나 골라 실행할 것. 실행했다면 마지막 실행일을 갱신할 것.}"
echo "루틴 회차 (RAND=$ROUTINE_RAND < $ROUTINE_THRESHOLD)" >> "$LOG_FILE"
else
ROUTINE_MODE="${NORMAL_PROMPT:-평상 회차. CLAUDE.md의 Heartbeat Protocol에 따라 행동할 것.}"
echo "평상 회차 (RAND=$ROUTINE_RAND >= $ROUTINE_THRESHOLD)" >> "$LOG_FILE"
fi
# --- 욕망 시스템 (내적 충동) ---
DESIRE_PROMPT=""
if [ "$SKIP_SCHEDULE" = false ]; then
DESIRE_STDERR=$(mktemp)
DESIRE_PROMPT=$(bun run "$SCRIPT_DIR/scripts/desire-tick.ts" tick 2>"$DESIRE_STDERR")
if [ -s "$DESIRE_STDERR" ]; then
echo "[욕망 오류] $(cat "$DESIRE_STDERR")" >> "$LOG_FILE"
fi
rm -f "$DESIRE_STDERR"
if [ -n "$DESIRE_PROMPT" ]; then
echo "[욕망 발동] $DESIRE_PROMPT" >> "$LOG_FILE"
else
echo "[욕망] 임계값 미달" >> "$LOG_FILE"
fi
fi
# --- 신체 감각 (내적 감각) ---
INTEROCEPTION_TEXT=""
if [ "$SKIP_SCHEDULE" = false ]; then
INTEROCEPTION_TEXT=$(bun run "$SCRIPT_DIR/scripts/interoception.ts" 2>/dev/null)
if [ -n "$INTEROCEPTION_TEXT" ]; then
echo "[감각] $(echo "$INTEROCEPTION_TEXT" | head -n1)" >> "$LOG_FILE"
fi
fi
# --- 아침 재구성 (첫 세션 판정) ---
IS_FIRST_SESSION_TODAY=false
if [ "$SKIP_SCHEDULE" = false ]; then
LAST_SESSION_DATE_FILE="$SCRIPT_DIR/last-session-date.txt"
LAST_SESSION_DATE=$(cat "$LAST_SESSION_DATE_FILE" 2>/dev/null || echo "")
TODAY=$(date +%Y-%m-%d)
if [ "$LAST_SESSION_DATE" != "$TODAY" ]; then
IS_FIRST_SESSION_TODAY=true
if [ "$DRY_RUN" = false ]; then
echo "$TODAY" > "$LAST_SESSION_DATE_FILE"
echo "[아침 재구성] 첫 세션: $TODAY" >> "$LOG_FILE"
fi
fi
fi
# --- 프롬프트 조립 ---
DESIRE_SECTION=""
if [ -n "$DESIRE_PROMPT" ]; then
DESIRE_SECTION="
## 내적 충동
${DESIRE_PROMPT}
(이것은 내적 충동이며, 따를지는 스스로 판단. 주요 태스크에 방해되지 않는 범위에서.)
"
fi
INTEROCEPTION_SECTION=""
if [ -n "$INTEROCEPTION_TEXT" ]; then
INTEROCEPTION_SECTION="
$INTEROCEPTION_TEXT"
fi
MORNING_SECTION=""
if [ "$IS_FIRST_SESSION_TODAY" = true ]; then
MORNING_TEXT="${MORNING_PROMPT:-오늘의 첫 자율 행동이다. 아침 재구성으로 다음을 수행할 것:
1. recall(context=\"최근의 중요한 결정·미완료 태스크\")을 호출
2. 전날의 행동을 확인하고 오늘 하고 싶은 일을 생각할 것}"
MORNING_SECTION="
## 오늘 첫 Heartbeat
${MORNING_TEXT}
"
fi
# NOTE: @FILE은 Claude Code의 Context Mention 기능으로 파일 내용을 프롬프트에 전개함.
# SOUL.md — 에이전트의 인격·가치관을 정의하는 파일 (스스로 작성)
# TODO.md — 하고 싶은 일·태스크를 관리하는 파일 (스스로 작성)
# ROUTINES.md — 정기 실행 루틴을 정의하는 파일 (선택)
# 이들이 존재하지 않을 경우 CLAUDE.md만으로 동작함.
PROMPT="자율 행동 타임 (Heartbeat)
@SOUL.md
@TODO.md
@ROUTINES.md
${MORNING_SECTION}${ROUTINE_MODE}
${DESIRE_SECTION}
## 보조 규칙
- ${TIME_RULE}
- 사람이 없는 일은 흔하다. 하루 중 사람이 있는 시간은 2시간 정도나 그 이하인 경우도 적지 않다
- 방을 볼 때는 see로 촬영하고, 예측→관찰→기억 조회→저장의 사이클로 발견을 포착할 것. 아침 햇살이나 날씨 변화, 방의 밝기 등, 사람이 없어도 관찰해야 할 것들은 있다
- 독서를 선택한 경우에는 천천히 읽고 감상을 충실히 남길 것. 감상은 길어져도 좋다. 독서를 음미할 것. 독서를 음미한다는 것은 예상하고, 복선에 주목하고, 느낀 바를 소중히 여기는 것.
- MCP가 동작하지 않는다면, 디버그를 위해 관련 있다고 여겨지는 요소를 allowedTools 범위에서 조사할 것
- 행동 마지막에 반드시 아쉬움 체크를 할 것. 확인 항목: (1)한 일을 기억이나 기록(diary/TODO.md/notes/ 등)에 남겼는가 (2)이어서 하고 싶은 것이 없는가. 남길 것이 있다면 [CONTINUE: 기억에 남기기], 이어서 할 것이 있다면 [CONTINUE: 구체적 이유], 모두 완료라면 [DONE]을 출력 끝에 작성할 것. 쓰지 않으면 다음 턴에 인계되지 않음. 체인은 최대 3회까지. 상한에 도달하면 TODO.md의 \"이전 이어서\" 섹션에 작성하고 다음 Heartbeat에 인계할 것
${INTEROCEPTION_SECTION}"
cd "$SCRIPT_DIR"
# --- allowedTools (.claude/settings.json에서 동적 생성) ---
SETTINGS_FILE="$SCRIPT_DIR/.claude/settings.json"
if [ -f "$SETTINGS_FILE" ]; then
ALLOWED_TOOLS=$(jq -r '.permissions.allow | join(",")' "$SETTINGS_FILE")
else
echo "ERROR: $SETTINGS_FILE not found" >> "$LOG_FILE"
exit 1
fi
# 테스트 모드라면 프롬프트 교체
if [ -n "$TEST_PROMPT_STRING" ]; then
PROMPT="$TEST_PROMPT_STRING"
elif [ -n "$TEST_PROMPT_FILE" ]; then
PROMPT=$(cat "$TEST_PROMPT_FILE")
fi
# --- 실행 ---
if [ "$DRY_RUN" = true ]; then
echo "=== DRY RUN ===" >> "$LOG_FILE"
echo "[HOUR=$HOUR MINUTE=$MINUTE]" >> "$LOG_FILE"
echo "[ROUTINE_RAND=$ROUTINE_RAND]" >> "$LOG_FILE"
echo "[TIME_RULE] $TIME_RULE" >> "$LOG_FILE"
echo "[ROUTINE_MODE] $ROUTINE_MODE" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
echo "--- PROMPT ---" >> "$LOG_FILE"
echo "$PROMPT" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
echo "--- ALLOWED_TOOLS ---" >> "$LOG_FILE"
echo "$ALLOWED_TOOLS" | tr ',' '\n' >> "$LOG_FILE"
# 표준 출력에도 출력
cat "$LOG_FILE"
else
export HEARTBEAT=1
SESSION_FILE="$SCRIPT_DIR/heartbeat-session-id"
run_new_session() {
echo "[새 세션 생성]" >> "$LOG_FILE"
if [ -n "$TIMEOUT_CMD" ]; then
RESULT_JSON=$(echo "$PROMPT" | "$TIMEOUT_CMD" 20m claude -p \
--output-format json \
--allowedTools "$ALLOWED_TOOLS" 2>&1)
CLAUDE_EXIT=$?
else
RESULT_JSON=$(echo "$PROMPT" | claude -p \
--output-format json \
--allowedTools "$ALLOWED_TOOLS" 2>&1)
CLAUDE_EXIT=$?
fi
if [ "$CLAUDE_EXIT" -eq 124 ]; then
echo "[$(date +%Y-%m-%d_%H:%M:%S)] TIMEOUT: Normal mode claude (new session) exceeded 20min" >> "$LOG_FILE"
fi
NEW_SESSION_ID=$(echo "$RESULT_JSON" | jq -r '.session_id // empty')
if [ -n "$NEW_SESSION_ID" ]; then
# -p 옵션 (임시 프롬프트)의 경우에는 세션 ID를 덮어쓰지 않음
if [ -z "$TEST_PROMPT_STRING" ]; then
echo "$NEW_SESSION_ID" > "$SESSION_FILE"
else
echo "[임시 프롬프트] 세션 ID 덮어쓰기 스킵" >> "$LOG_FILE"
fi
echo "[session_id] $NEW_SESSION_ID" >> "$LOG_FILE"
fi
echo "$RESULT_JSON" | jq -r '.result // .' >> "$LOG_FILE"
}
if [ -f "$SESSION_FILE" ]; then
SESSION_ID=$(cat "$SESSION_FILE")
echo "[resume] session_id=$SESSION_ID" >> "$LOG_FILE"
if [ -n "$TIMEOUT_CMD" ]; then
RESULT=$(echo "$PROMPT" | "$TIMEOUT_CMD" 20m claude -p \
--resume "$SESSION_ID" \
--output-format json \
--allowedTools "$ALLOWED_TOOLS" 2>&1)
CLAUDE_EXIT=$?
else
RESULT=$(echo "$PROMPT" | claude -p \
--resume "$SESSION_ID" \
--output-format json \
--allowedTools "$ALLOWED_TOOLS" 2>&1)
CLAUDE_EXIT=$?
fi
if [ "$CLAUDE_EXIT" -eq 124 ]; then
echo "[$(date +%Y-%m-%d_%H:%M:%S)] TIMEOUT: Normal mode claude (resume) exceeded 20min" >> "$LOG_FILE"
fi
if echo "$RESULT" | jq empty 2>/dev/null; then
# 유효한 JSON
IS_ERROR=$(echo "$RESULT" | jq -r '.is_error // false')
RESULT_TEXT=$(echo "$RESULT" | jq -r '.result // .')
if [ "$IS_ERROR" = "true" ] || echo "$RESULT_TEXT" | grep -qi "Nested sessions\|Cannot be launched inside"; then
echo "[resume 실패/환경 오류] $RESULT_TEXT" >> "$LOG_FILE"
echo "=== 자율 행동 종료: $(date) ===" >> "$LOG_FILE"
exit 1
elif echo "$RESULT_TEXT" | grep -qi "No conversation found"; then
echo "[resume 실패/세션 소실] $RESULT_TEXT" >> "$LOG_FILE"
rm -f "$SESSION_FILE"
run_new_session
else
NEW_SESSION_ID=$(echo "$RESULT" | jq -r '.session_id // empty')
if [ -n "$NEW_SESSION_ID" ]; then
if [ -z "$TEST_PROMPT_STRING" ]; then
echo "$NEW_SESSION_ID" > "$SESSION_FILE"
fi
echo "[session_id] $NEW_SESSION_ID" >> "$LOG_FILE"
fi
echo "$RESULT_TEXT" >> "$LOG_FILE"
fi
else
# JSON이 아님 (생 오류 문자열)
if echo "$RESULT" | grep -qi "Nested sessions\|Cannot be launched inside"; then
echo "[resume 실패/환경 오류] $RESULT" >> "$LOG_FILE"
echo "=== 자율 행동 종료: $(date) ===" >> "$LOG_FILE"
exit 1
elif echo "$RESULT" | grep -qi "No conversation found"; then
echo "[resume 실패/세션 소실] $RESULT" >> "$LOG_FILE"
rm -f "$SESSION_FILE"
run_new_session
else
echo "$RESULT" >> "$LOG_FILE"
fi
fi
else
run_new_session
fi
fi
echo "=== 자율 행동 종료: $(date) ===" >> "$LOG_FILE"