← 목록
AI 2026-07-17 5KB 읽기 6분

CrownyAI 집사 — 페이지 스크리닝 Q&A (N15)

개요

사장님 지시("브라우저 안 내용 뚫고 다니게 하기") 대응 — CrownyAI 신셸 집사(CAButlerDock)에 "현재 페이지에 대해 물어보면 본문을 읽고 답한다" 기능(N15)을 배선. 활성 탭 WKWebView 가 집사에 연결돼 있지 않던 미배선 상태(setActiveTabWebView:urlString: 호출부 없음)를 탭 전환·네비 이벤트마다 자동 주입되도록 완성.

무엇을 했는지

1. 활성 웹뷰 배선 (main.m + content.m)

  • crowny-ai-content.m: CAContentControllercaActiveWebView(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, 요약 규칙과의 우선순위만 명시적으로 처리함 — 스펙 요구사항 그대로).