feat(live): P25 Live 증분 동기화 체계 구현 (PD님 직접 지시)
세션 중 반영 불가 파일 9종의 변경을 즉시 반영하는 체계: - .claude/live/ 파일별 더미 + 증분 읽기 - live_inject.sh: UserPromptSubmit hook (추가분만 주입, 변경 없으면 토큰 0) - live_session_load.sh: SessionStart hook (전량 1회 로드) - P25 코어룰 명문화 + P21-2 세션 공유에 Live 비우기 편입 - settings.json hook 등록 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d6bf349b20
commit
5b6cfe3342
|
|
@ -57,6 +57,10 @@
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "bash scripts/change_digest.sh 2>/dev/null || true"
|
"command": "bash scripts/change_digest.sh 2>/dev/null || true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash scripts/live_session_load.sh 2>/dev/null || true"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +76,10 @@
|
||||||
{
|
{
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "bash scripts/hold_watch.sh 2>/dev/null || true"
|
"command": "bash scripts/hold_watch.sh 2>/dev/null || true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash scripts/live_inject.sh 2>/dev/null || true"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -733,10 +733,12 @@ PD님이 **"세션 갱신"**이라고 지시하면, PM 단일 세션 에이전
|
||||||
PD님이 **"세션 공유"**라고 지시하면, 현재 세션의 모든 변경사항을 **즉시 git commit + push**하여 다른 세션에서 접근 가능하게 만든다. PD님에게 추가 확인을 요청하지 않는다.
|
PD님이 **"세션 공유"**라고 지시하면, 현재 세션의 모든 변경사항을 **즉시 git commit + push**하여 다른 세션에서 접근 가능하게 만든다. PD님에게 추가 확인을 요청하지 않는다.
|
||||||
|
|
||||||
### 수행 절차
|
### 수행 절차
|
||||||
1. `git add -A`
|
1. `.claude/live/` 더미 파일 내용을 원본에 반영 (아직 미반영분이 있다면)
|
||||||
2. `git commit` (변경 내용 요약 메시지 자동 생성)
|
2. `.claude/live/` 더미 파일 비우기 (README.md 제외)
|
||||||
3. `git push origin main`
|
3. `git add -A`
|
||||||
4. 완료 보고 (1줄)
|
4. `git commit` (변경 내용 요약 메시지 자동 생성)
|
||||||
|
5. `git push origin main`
|
||||||
|
6. 완료 보고 (1줄)
|
||||||
|
|
||||||
### 트리거 표현
|
### 트리거 표현
|
||||||
- "세션 공유"
|
- "세션 공유"
|
||||||
|
|
@ -877,6 +879,43 @@ grep -r "기각안" 공유/대화로그/ # 기각 이유 추적
|
||||||
| **P24 (대화로그)** | "논의 맥락·경위·기각 이유" | 상위 근거 |
|
| **P24 (대화로그)** | "논의 맥락·경위·기각 이유" | 상위 근거 |
|
||||||
| ~~P20 (일일보고)~~ | 폐기 — P24로 대체 | - |
|
| ~~P20 (일일보고)~~ | 폐기 — P24로 대체 | - |
|
||||||
|
|
||||||
|
## P25. Live 증분 동기화 체계 (2026-04-16 PD님 직접 지시)
|
||||||
|
|
||||||
|
> 세션 시작 후 변경된 설정·규칙·에이전트 정의를 **세션 갱신 없이 즉시 반영**하기 위한 임시 더미 파일 체계. 원본 수정 + 더미 기록의 이중 반영으로, 현재 세션은 hook이 즉시 주입하고 다음 세션은 원본이 이미 최신.
|
||||||
|
|
||||||
|
### 대상 (세션 중 반영 불가 9종)
|
||||||
|
CLAUDE.md, CLAUDE.local.md, .claude/settings.json, settings.local.json, .claude/skills/*/SKILL.md, .claude/agents/*.md, .claude/rules/*.md, .claude/commands/*.md, .mcp.json
|
||||||
|
|
||||||
|
### 더미 파일 위치
|
||||||
|
`.claude/live/` — 원본과 동일 파일명으로 **변경분(diff)만** 기록.
|
||||||
|
|
||||||
|
### 변경 발생 시 절차
|
||||||
|
1. **원본 파일 즉시 수정** (다음 세션·다른 PC를 위해)
|
||||||
|
2. **`.claude/live/{파일명}`에 변경 요지 append** (현재 세션 즉시 반영용)
|
||||||
|
3. UserPromptSubmit hook(`live_inject.sh`)이 증분 감지 → 추가분만 컨텍스트 주입
|
||||||
|
|
||||||
|
### 증분 읽기 원리
|
||||||
|
- hook이 파일별 "마지막 읽은 줄 번호" 기록
|
||||||
|
- 다음 턴에 추가된 줄만 stdout 출력 → 에이전트 컨텍스트 주입
|
||||||
|
- 변경 없으면 출력 없음 (토큰 비용 0)
|
||||||
|
|
||||||
|
### 서브에이전트 의무
|
||||||
|
모든 에이전트는 작업 착수 전 `.claude/live/` 디렉토리에 더미 파일이 존재하는지 확인하고, 존재하면 Read하여 변경사항을 인지한다.
|
||||||
|
|
||||||
|
### Write 권한
|
||||||
|
- **PM만 Write** (서브에이전트는 Read 전용)
|
||||||
|
- 각 더미 파일 최대 8,000자
|
||||||
|
|
||||||
|
### "세션 공유" 시 동기화 (P21-2 연계)
|
||||||
|
1. 더미 내용이 원본에 이미 반영되어 있는지 확인
|
||||||
|
2. `.claude/live/` 더미 파일 비우기 (README.md 제외)
|
||||||
|
3. commit + push
|
||||||
|
|
||||||
|
### C14 준수
|
||||||
|
- 변경 없는 턴: 토큰 비용 0 (해시 비교만)
|
||||||
|
- 변경 감지 턴: 추가분만 주입 (전체 재읽기 없음)
|
||||||
|
- 세션 시작 시: SessionStart hook이 전량 1회 로드
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 교훈 및 노하우
|
## 교훈 및 노하우
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# UserPromptSubmit hook — .claude/live/ 증분 읽기 + 컨텍스트 주입
|
||||||
|
# 세션 중 반영 불가 파일의 변경분을 실시간 주입
|
||||||
|
# 증분 방식: 마지막 읽은 줄 이후 추가분만 출력
|
||||||
|
|
||||||
|
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||||
|
[ -z "$REPO_ROOT" ] && exit 0
|
||||||
|
|
||||||
|
LIVE_DIR="$REPO_ROOT/.claude/live"
|
||||||
|
[ ! -d "$LIVE_DIR" ] && exit 0
|
||||||
|
|
||||||
|
THROTTLE_DIR="$HOME/.claude/.nerdnavis_throttle"
|
||||||
|
mkdir -p "$THROTTLE_DIR" 2>/dev/null
|
||||||
|
|
||||||
|
OUTPUT=""
|
||||||
|
TOTAL_CHARS=0
|
||||||
|
MAX_CHARS=8000 # 10,000자 한도에서 기존 hook 여유분 확보
|
||||||
|
|
||||||
|
for LIVE_FILE in "$LIVE_DIR"/*.md "$LIVE_DIR"/*.json; do
|
||||||
|
[ ! -f "$LIVE_FILE" ] && continue
|
||||||
|
BASENAME=$(basename "$LIVE_FILE")
|
||||||
|
[ "$BASENAME" = "README.md" ] && continue # README는 스킵
|
||||||
|
|
||||||
|
# 파일별 마지막 읽은 줄 번호 추적
|
||||||
|
FILE_HASH=$(echo "$LIVE_FILE" | sha1sum 2>/dev/null | cut -d' ' -f1)
|
||||||
|
LAST_LINE_FILE="$THROTTLE_DIR/live_lastline_$FILE_HASH"
|
||||||
|
LAST_LINE=$(cat "$LAST_LINE_FILE" 2>/dev/null || echo 0)
|
||||||
|
TOTAL_LINES=$(wc -l < "$LIVE_FILE" 2>/dev/null || echo 0)
|
||||||
|
|
||||||
|
# 새 줄이 추가된 경우에만 출력
|
||||||
|
if [ "$TOTAL_LINES" -gt "$LAST_LINE" ]; then
|
||||||
|
NEW_CONTENT=$(tail -n +$((LAST_LINE + 1)) "$LIVE_FILE" 2>/dev/null)
|
||||||
|
NEW_CHARS=${#NEW_CONTENT}
|
||||||
|
|
||||||
|
# 한도 체크
|
||||||
|
if [ $((TOTAL_CHARS + NEW_CHARS)) -lt $MAX_CHARS ]; then
|
||||||
|
OUTPUT="$OUTPUT
|
||||||
|
[LIVE:$BASENAME] 변경분 (${LAST_LINE}줄 이후):
|
||||||
|
$NEW_CONTENT
|
||||||
|
"
|
||||||
|
TOTAL_CHARS=$((TOTAL_CHARS + NEW_CHARS + 50)) # 헤더 여유
|
||||||
|
echo "$TOTAL_LINES" > "$LAST_LINE_FILE"
|
||||||
|
else
|
||||||
|
OUTPUT="$OUTPUT
|
||||||
|
[LIVE:$BASENAME] ⚠️ 증분 크기 초과 — Read 도구로 직접 확인 필요
|
||||||
|
"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 출력이 있을 때만 주입
|
||||||
|
if [ -n "$OUTPUT" ] && [ "$TOTAL_CHARS" -gt 0 ]; then
|
||||||
|
echo "📝 [Live 증분 동기화]$OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# SessionStart hook — .claude/live/ 전량 로드 (세션 시작 시)
|
||||||
|
# 세션 시작 시점에 모든 live 더미 파일을 읽어서 컨텍스트에 주입
|
||||||
|
# 증분 카운터도 리셋하여 다음 턴부터 증분 추적 시작
|
||||||
|
|
||||||
|
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
||||||
|
[ -z "$REPO_ROOT" ] && exit 0
|
||||||
|
|
||||||
|
LIVE_DIR="$REPO_ROOT/.claude/live"
|
||||||
|
[ ! -d "$LIVE_DIR" ] && exit 0
|
||||||
|
|
||||||
|
THROTTLE_DIR="$HOME/.claude/.nerdnavis_throttle"
|
||||||
|
mkdir -p "$THROTTLE_DIR" 2>/dev/null
|
||||||
|
|
||||||
|
OUTPUT=""
|
||||||
|
TOTAL_CHARS=0
|
||||||
|
MAX_CHARS=8000
|
||||||
|
FILE_COUNT=0
|
||||||
|
|
||||||
|
for LIVE_FILE in "$LIVE_DIR"/*.md "$LIVE_DIR"/*.json; do
|
||||||
|
[ ! -f "$LIVE_FILE" ] && continue
|
||||||
|
BASENAME=$(basename "$LIVE_FILE")
|
||||||
|
[ "$BASENAME" = "README.md" ] && continue
|
||||||
|
|
||||||
|
CONTENT=$(head -c $MAX_CHARS "$LIVE_FILE" 2>/dev/null)
|
||||||
|
CHARS=${#CONTENT}
|
||||||
|
|
||||||
|
if [ "$CHARS" -gt 0 ] && [ $((TOTAL_CHARS + CHARS)) -lt $MAX_CHARS ]; then
|
||||||
|
OUTPUT="$OUTPUT
|
||||||
|
[LIVE:$BASENAME]
|
||||||
|
$CONTENT
|
||||||
|
"
|
||||||
|
TOTAL_CHARS=$((TOTAL_CHARS + CHARS + 30))
|
||||||
|
FILE_COUNT=$((FILE_COUNT + 1))
|
||||||
|
|
||||||
|
# 증분 카운터를 현재 줄 수로 설정 (다음 턴부터 증분 추적)
|
||||||
|
FILE_HASH=$(echo "$LIVE_FILE" | sha1sum 2>/dev/null | cut -d' ' -f1)
|
||||||
|
TOTAL_LINES=$(wc -l < "$LIVE_FILE" 2>/dev/null || echo 0)
|
||||||
|
echo "$TOTAL_LINES" > "$THROTTLE_DIR/live_lastline_$FILE_HASH"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$FILE_COUNT" -gt 0 ]; then
|
||||||
|
echo "📝 [Live 세션 로드] ${FILE_COUNT}개 더미 파일:$OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
Loading…
Reference in New Issue