CrownyAI 집사 — 페이지 스크리닝 Q&A (N15)
개요
사장님 지시("브라우저 안 내용 뚫고 다니게 하기") 대응 — CrownyAI 신셸 집사(CAButlerDock)에
"현재 페이지에 대해 물어보면 본문을 읽고 답한다" 기능(N15)을 배선. 활성 탭 WKWebView 가
집사에 연결돼 있지 않던 미배선 상태(
setActiveTabWebView:urlString: 호출부 없음)를
탭 전환·네비 이벤트마다 자동 주입되도록 완성.
무엇을 했는지
1. 활성 웹뷰 배선 (main.m + content.m)
crowny-ai-content.m: CAContentController에 caActiveWebView(WKWebView*)/caActiveURLString
게터 추가 —
activeTab.isApp이면 nil(네이티브 앱탭·설정탭 제외). 클래스 익스텐션(538-546행
근방)에 선언,
activeTab 접근자 직후 구현.
crowny-ai-main.m: onTabsChanged:/onAddressChanged: 말미에 caSyncButlerActiveTab 호출
추가 —
self.butler와(있으면)
self.butlerWindowDock 양쪽에
setActiveTabWebView:urlString: 주입.
CAContentController (CAAIExtras)/`CAButlerDock
(CAAIPageAskWire)` 카테고리 재선언으로 크로스 파일 접근(crowny-ai.h 무수정, 기존
CAAutosaveForward/CADocListForward와 동일 관용구).
2. 라우터 + 액션 (butler.m)
cbButlerRespond:에 "요약" 규칙보다 앞서 페이지질의 규칙 추가: "이 페이지"/"현재 페이지"/
"페이지에"/"이 글"/"이 문서"/"화면에" + 물음 성격(?, 뭐, 알려, 설명, 어때, 찾아, 있어)이
함께 있고 요약/summarize 키워드가 없으면
pageask|<원문>|현재 페이지를 읽고 답합니다.
cbExecuteButlerAction:에 pageask 분기 → cbPageAsk:.
cbPageAsk:: activeWebView 없으면 안내, 있으면 document.body.innerText 8000자 캡 →
NFC 정규화 후
/tmp/crownyai_pageask_<pid>.txt(첫 줄 질문, 빈 줄, 본문)에 기록 → NSTask
--file <경로>만 인자로 브릿지 호출(한글 NFD 함정 회피, argv/env 미사용). 선로그
"[옴] 현재 페이지를 읽는 중…(N자)".
cbRunLocalCLIWithFile:은
cbRunLocalCLI: 관용구
(120s 타임아웃·env 4키 주입·main큐 logAppend) 그대로 답습. 응답 who=
집사·페이지.
3. 브릿지 --file 모드 (집사CLI브릿지.sh)
$1 == "--file" $2=<경로> 분기 추가. 파일없음/빈경로→exit 2, CLI없음→exit 3,
타임아웃→exit 4, 비정상종료→exit 5, 성공→exit 0(
[출처: claude_CLI_페이지]).
- brainq 조회 생략(페이지 문맥 질의는 항상 LLM). 프롬프트는 stdin 파이프로 전달:
cat 파일 | ctimeout 100 claude -p "<지시문>" --model haiku — 실측 확인 완료(아래 검증 참조).
- 로그 psv에 출처
claude_CLI_페이지로 기록(기존 5열 포맷 그대로, log_line() 재사용).
4. 한선 동반 (집사CLI브릿지.한선)
파일라우팅(경로) 함수 추가: 4상(타=빈경로/파일없음, 옴=위임). 파일존재() VM 함정
(항상 -1) 회피 —
읽기()의 글자수로 존재 판정.
메인()에
CROWNY_BUTLER_FILE env 분기
추가(설정 시
파일라우팅 우선, 없으면 기존
CROWNY_BUTLER_Q 경로).
- 컴파일+실행 게이트 통과(아래 검증). learn add 완료(
intent=집사CLI브릿지_페이지질의).
검증 (실측)
cc -fsyntax-only -fobjc-arc -DCROWNY_VM_WEBKIT -DCROWNY_HYBRID 3개 파일(butler/content/main.m)
모두 exit 0, 경고/에러 없음.
- 브릿지
.sh --file 실측: 테스트 파일(질문 "이 페이지의 주제는?" + 크라우니 생태계 설명 3문장)
→ 실답변("이 페이지의 주제는 크라우니 생태계입니다...") +
[출처: claude_CLI_페이지] +
exit 0. 로그 psv에
claude_CLI_페이지|15|OK|이 페이지의 주제는? 기록 확인.
- 없는 파일 경로 →
[집사CLI오류] 파일 없음: ... + exit 2. 빈 경로도 동일 exit 2.
.한선 컴파일: hanseonc_high 6416 큐브 생성, 에러 없음. crownyc run 실행 — 파일없음
경로에서
타|파일없음:..., 파일있음 경로에서 실제 claude 위임 성공(
옴|...본문 근거 답변...)
두 4상 분기 모두 라이브 확인.
crownycode-learn.sh add 집사CLI브릿지_페이지질의 학습 완료.
관련 파일
- /Users/ef/CrownyBrowser/native/crowny-ai-butler.m (라우터 규칙 + cbPageAsk: + cbRunLocalCLIWithFile:)
- /Users/ef/CrownyBrowser/native/crowny-ai-content.m (caActiveWebView/caActiveURLString)
- /Users/ef/CrownyBrowser/native/crowny-ai-main.m (caSyncButlerActiveTab, onTabsChanged:/onAddressChanged: 배선)
- /Users/ef/CrownyBrowser/tools/집사CLI브릿지.sh (--file 모드)
- /Users/ef/CrownyBrowser/tools/집사CLI브릿지.한선 (파일라우팅 4상 정본)
잔여 이슈
- GUI 실측(실제 CrownyAI 앱에서 페이지 열고 "이 페이지 뭐에 관한 거야?" 질문 → 응답 확인)은
이번 작업 범위 밖 — 오케스트레이터/사용자가
make ai 빌드 후 라이브 확인 필요(작업 지시에
따라
make ai 금지, syntax-only만 수행함).
crowny-ai-chrome.m은 오케스트레이터가 병행 수정 중이라 접촉하지 않음 — 병합 후 전체 링크
회귀(otool/실행)는 오케스트레이터 쪽에서 확인 필요.
- 라우터 규칙 순서상 "이 페이지에서 XX 찾아줘"처럼 "찾아"만 물음 단서로 쓰인 문장은 더 앞선
기존
찾 단일 키워드 규칙(find 액션)에 먼저 걸릴 수 있음(사소한 edge case, 요약 규칙과의
우선순위만 명시적으로 처리함 — 스펙 요구사항 그대로).