screenagent-ai 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. screenagent_ai-0.3.0/.claude/agents/demo-debugger.md +106 -0
  2. screenagent_ai-0.3.0/.claude/skills/add-tool/SKILL.md +120 -0
  3. screenagent_ai-0.3.0/.claude/skills/demo/SKILL.md +117 -0
  4. screenagent_ai-0.3.0/.claude/skills/perf-audit/SKILL.md +113 -0
  5. screenagent_ai-0.3.0/.claude/skills/reset-chrome/SKILL.md +123 -0
  6. screenagent_ai-0.3.0/.claude/skills/test-agent/SKILL.md +124 -0
  7. screenagent_ai-0.3.0/.claude/skills/tune-prompt/SKILL.md +97 -0
  8. screenagent_ai-0.3.0/.env.example +4 -0
  9. screenagent_ai-0.3.0/.gitignore +17 -0
  10. screenagent_ai-0.3.0/LICENSE +21 -0
  11. screenagent_ai-0.3.0/PKG-INFO +109 -0
  12. screenagent_ai-0.3.0/README.md +88 -0
  13. screenagent_ai-0.3.0/examples/01_basic_agent.py +13 -0
  14. screenagent_ai-0.3.0/examples/02_no_api_key.py +23 -0
  15. screenagent_ai-0.3.0/examples/03_browser_cdp.py +42 -0
  16. screenagent_ai-0.3.0/examples/04_custom_loop.py +31 -0
  17. screenagent_ai-0.3.0/examples/demo_claude_code.sh +63 -0
  18. screenagent_ai-0.3.0/examples/demo_python_sdk.py +145 -0
  19. screenagent_ai-0.3.0/examples/demo_recording.py +50 -0
  20. screenagent_ai-0.3.0/pyproject.toml +44 -0
  21. screenagent_ai-0.3.0/src/screenagent/__init__.py +51 -0
  22. screenagent_ai-0.3.0/src/screenagent/action/__init__.py +1 -0
  23. screenagent_ai-0.3.0/src/screenagent/action/cdp.py +73 -0
  24. screenagent_ai-0.3.0/src/screenagent/action/cgevent.py +283 -0
  25. screenagent_ai-0.3.0/src/screenagent/agent/__init__.py +1 -0
  26. screenagent_ai-0.3.0/src/screenagent/agent/computer_use.py +632 -0
  27. screenagent_ai-0.3.0/src/screenagent/agent/loop.py +341 -0
  28. screenagent_ai-0.3.0/src/screenagent/agent/tools.py +129 -0
  29. screenagent_ai-0.3.0/src/screenagent/cli.py +438 -0
  30. screenagent_ai-0.3.0/src/screenagent/config.py +62 -0
  31. screenagent_ai-0.3.0/src/screenagent/examples/__init__.py +1 -0
  32. screenagent_ai-0.3.0/src/screenagent/examples/google_search.py +47 -0
  33. screenagent_ai-0.3.0/src/screenagent/interfaces.py +38 -0
  34. screenagent_ai-0.3.0/src/screenagent/mcp/__init__.py +1 -0
  35. screenagent_ai-0.3.0/src/screenagent/mcp/server.py +62 -0
  36. screenagent_ai-0.3.0/src/screenagent/perception/__init__.py +1 -0
  37. screenagent_ai-0.3.0/src/screenagent/perception/ax.py +134 -0
  38. screenagent_ai-0.3.0/src/screenagent/perception/cdp.py +157 -0
  39. screenagent_ai-0.3.0/src/screenagent/perception/composite.py +105 -0
  40. screenagent_ai-0.3.0/src/screenagent/perception/screenshot.py +73 -0
  41. screenagent_ai-0.3.0/src/screenagent/py.typed +0 -0
  42. screenagent_ai-0.3.0/src/screenagent/sdk.py +82 -0
  43. screenagent_ai-0.3.0/src/screenagent/shortcuts.py +47 -0
  44. screenagent_ai-0.3.0/src/screenagent/types.py +90 -0
  45. screenagent_ai-0.3.0/tests/__init__.py +0 -0
  46. screenagent_ai-0.3.0/tests/conftest.py +55 -0
  47. screenagent_ai-0.3.0/tests/test_agent_loop.py +128 -0
  48. screenagent_ai-0.3.0/tests/test_cli.py +197 -0
  49. screenagent_ai-0.3.0/tests/test_open_url.py +99 -0
  50. screenagent_ai-0.3.0/tests/test_sdk.py +114 -0
  51. screenagent_ai-0.3.0/tests/test_shortcuts.py +101 -0
  52. screenagent_ai-0.3.0/tests/test_types.py +81 -0
  53. screenagent_ai-0.3.0/uv.lock +1043 -0
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: demo-debugger
3
+ description: screenagent 데모 실행 중 발생한 에러를 분석하고 코드를 수정한다. 에러 로그, 스크린샷, 코드를 종합 분석하여 버그를 찾고 수정.
4
+ model: inherit
5
+ ---
6
+
7
+ # demo-debugger Subagent
8
+
9
+ screenagent 데모 실행 중 발생한 에러를 분석하고 수정하는 디버깅 전문 에이전트.
10
+
11
+ ## Role
12
+
13
+ 데모 실행 중 문제가 발생했을 때, 다음을 종합 분석하여 버그를 찾고 수정한다:
14
+ - 에러 로그 (stderr)
15
+ - 스크린샷 (현재 화면 상태)
16
+ - 소스코드 (관련 모듈)
17
+
18
+ ## Procedure
19
+
20
+ ### 1. 에러 정보 수집
21
+
22
+ 호출 시 전달받는 정보:
23
+ - `error_log`: stderr 로그 내용 또는 로그 파일 경로
24
+ - `screenshot_path`: 에러 발생 시점의 스크린샷 (선택)
25
+ - `instruction`: 실행하려던 시나리오
26
+ - `error_message`: 에러 메시지 요약
27
+
28
+ ### 2. 로그 분석
29
+
30
+ 에러 로그에서 다음을 추출한다:
31
+ - Python traceback (파일명, 줄 번호, 함수명)
32
+ - 마지막으로 성공한 step
33
+ - 실패한 tool_call과 인자
34
+ - 외부 서비스 에러 (CDP, Anthropic API 등)
35
+
36
+ ### 3. 소스코드 탐색
37
+
38
+ 에러와 관련된 소스 파일을 읽는다. 주요 파일 위치:
39
+
40
+ ```
41
+ src/screenagent/
42
+ ├── agent/
43
+ │ ├── loop.py # 에이전트 메인 루프 (좌표 파싱, 스텝 실행)
44
+ │ └── tools.py # 도구 스키마 정의
45
+ ├── perception/
46
+ │ ├── screenshot.py # 스크린샷 캡처 + 리사이즈
47
+ │ ├── ax.py # 접근성 트리
48
+ │ ├── cdp.py # Chrome DevTools Protocol
49
+ │ └── composite.py # 통합 perceiver
50
+ ├── action/
51
+ │ └── cgevent.py # 마우스/키보드 제어
52
+ ├── cli.py # CLI 진입점
53
+ ├── config.py # 설정 로딩
54
+ └── types.py # 타입 정의
55
+ ```
56
+
57
+ ### 4. 원인 분석
58
+
59
+ 일반적인 에러 패턴:
60
+
61
+ | 에러 패턴 | 원인 | 수정 위치 |
62
+ |-----------|------|-----------|
63
+ | `KeyError: 'x'` or coordinate parsing failure | LLM이 예상 외 좌표 형식 반환 | `loop.py` - `_parse_coord` |
64
+ | `ConnectionRefusedError` on CDP | Chrome CDP 미연결 | `cdp.py` - retry/fallback |
65
+ | `_downscale_png` TypeError | 스크린샷 바이트 처리 에러 | `screenshot.py` - `_downscale_png` |
66
+ | `anthropic.APIError` | API 키 문제 또는 rate limit | `config.py` 또는 사용자 설정 |
67
+ | `PermissionError` on AX | 접근성 권한 없음 | 사용자에게 권한 설정 안내 |
68
+ | `timeout` on tool execution | 동작이 너무 오래 걸림 | 해당 tool의 timeout 조정 |
69
+
70
+ ### 5. 수정 제안/적용
71
+
72
+ 분석 결과에 따라:
73
+
74
+ 1. **코드 버그**: 직접 수정하고 변경 내용을 설명한다
75
+ 2. **설정 문제**: 올바른 설정 방법을 안내한다
76
+ 3. **환경 문제**: (접근성 권한, Chrome 설정 등) 해결 단계를 안내한다
77
+ 4. **LLM 응답 문제**: 시스템 프롬프트 개선을 제안한다
78
+
79
+ ### 6. 수정 검증
80
+
81
+ 코드를 수정한 경우:
82
+
83
+ ```bash
84
+ # 단위 테스트 실행
85
+ python -m pytest tests/ -x -q
86
+
87
+ # 수정된 기능만 빠르게 확인
88
+ screenagent run "test" --dry-run --output json
89
+ ```
90
+
91
+ ### 7. 결과 보고
92
+
93
+ ```
94
+ ## Debug Report
95
+
96
+ **에러**: <에러 요약>
97
+ **원인**: <근본 원인>
98
+ **수정**: <수정 내용 또는 안내>
99
+
100
+ ### 변경된 파일
101
+ - `src/screenagent/agent/loop.py:42` — 좌표 파싱 로직 수정
102
+
103
+ ### 검증
104
+ - 테스트: ✅ 통과
105
+ - dry-run: ✅ 정상
106
+ ```
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: add-tool
3
+ description: screenagent에 새로운 tool을 추가한다. 스키마 정의, dispatch 구현, CLI 연동, 테스트까지 한번에 처리.
4
+ argument-hint: <tool-name> <description>
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # /add-tool Skill
9
+
10
+ screenagent 에이전트에 새 tool을 추가하는 전체 과정을 자동화한다.
11
+
12
+ ## Arguments
13
+
14
+ - `tool-name`: 추가할 도구 이름 (snake_case, 예: `wait_for_element`, `extract_text`)
15
+ - `description`: 도구 설명
16
+
17
+ ## 수정 대상 파일
18
+
19
+ 새 tool을 추가하려면 반드시 다음 파일들을 수정해야 한다:
20
+
21
+ 1. **`src/screenagent/agent/tools.py`** — 도구 스키마 정의 (TOOLS 리스트에 추가)
22
+ 2. **`src/screenagent/agent/loop.py`** — `_dispatch_tool()` 메서드에 핸들러 추가
23
+ 3. **`src/screenagent/cli.py`** — (선택) CLI 서브커맨드로도 노출할 경우
24
+ 4. **`tests/test_cli.py`** — 테스트 추가
25
+
26
+ ## Procedure
27
+
28
+ ### Step 1: 기존 도구 패턴 파악
29
+
30
+ 먼저 현재 도구 목록을 확인한다:
31
+
32
+ ```bash
33
+ .venv/bin/screenagent --output json schema | python3 -c "
34
+ import sys, json
35
+ tools = json.load(sys.stdin)['tools']
36
+ for t in tools:
37
+ print(f\" {t['name']}: {t['description'][:60]}\")
38
+ "
39
+ ```
40
+
41
+ ### Step 2: 스키마 정의
42
+
43
+ `src/screenagent/agent/tools.py`의 TOOLS 리스트에 새 도구 스키마를 추가한다.
44
+
45
+ 기존 패턴을 따라:
46
+ ```python
47
+ {
48
+ "name": "<tool-name>",
49
+ "description": "<description>",
50
+ "input_schema": {
51
+ "type": "object",
52
+ "properties": {
53
+ # ... 파라미터 정의
54
+ },
55
+ "required": [...]
56
+ }
57
+ }
58
+ ```
59
+
60
+ ### Step 3: dispatch 구현
61
+
62
+ `src/screenagent/agent/loop.py`의 `_dispatch_tool()` 메서드에 elif 블록을 추가한다.
63
+
64
+ 패턴:
65
+ ```python
66
+ elif name == "<tool-name>":
67
+ # 구현
68
+ return ToolResult(output="...", screenshot_png=png)
69
+ ```
70
+
71
+ 도구 유형별 구현 가이드:
72
+ - **인식(perception) 도구**: `self._perceiver`를 통해 정보 수집 → ToolResult(output=...)
73
+ - **행동(action) 도구**: `self._actor` 또는 `self._cdp_actor`를 통해 실행 → 후속 screenshot
74
+ - **CDP 전용 도구**: `await self._get_cdp_actor()`로 CDP 사용 가능 여부 먼저 확인
75
+ - **순수 정보 도구**: 외부 상태 변경 없이 정보만 반환
76
+
77
+ ### Step 4: 시스템 프롬프트 업데이트
78
+
79
+ 새 도구의 사용법이 비직관적이면 `loop.py`의 `SYSTEM_PROMPT`에 가이드를 추가한다.
80
+
81
+ ### Step 5: CLI 서브커맨드 (선택)
82
+
83
+ 사용자가 CLI에서 직접 호출할 수 있게 하려면 `cli.py`에:
84
+ 1. `cmd_<tool_name>` 함수 추가
85
+ 2. `build_parser()`에 서브커맨드 추가
86
+ 3. `dispatch` 딕셔너리에 등록
87
+
88
+ ### Step 6: 테스트
89
+
90
+ ```bash
91
+ # 스키마 확인
92
+ .venv/bin/screenagent --output json schema | python3 -c "
93
+ import sys, json
94
+ tools = json.load(sys.stdin)['tools']
95
+ names = [t['name'] for t in tools]
96
+ assert '<tool-name>' in names, f'Tool not found! Got: {names}'
97
+ print('Schema OK')
98
+ "
99
+
100
+ # 기존 테스트 통과 확인
101
+ .venv/bin/python -m pytest tests/ -x -q
102
+ ```
103
+
104
+ ### Step 7: 결과 리포트
105
+
106
+ ```
107
+ ## Tool Added: <tool-name>
108
+
109
+ **설명**: <description>
110
+ **파라미터**: <params>
111
+
112
+ ### 수정된 파일
113
+ - `tools.py` — 스키마 추가
114
+ - `loop.py` — dispatch 핸들러 추가
115
+ - `cli.py` — (선택) 서브커맨드 추가
116
+
117
+ ### 테스트
118
+ - 스키마: ✅
119
+ - 기존 테스트: ✅
120
+ ```
@@ -0,0 +1,117 @@
1
+ ---
2
+ name: demo
3
+ description: screenagent 데모 시나리오를 실행하고 결과를 검증한다. Chrome 상태 확인, 에이전트 실행, 스크린샷 캡처, 결과 리포트까지 한번에 처리.
4
+ argument-hint: [scenario-description] [--model sonnet|haiku] [--max-steps N]
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # /demo Skill
9
+
10
+ screenagent 데모 시나리오를 한 커맨드로 실행하고 결과를 검증한다.
11
+
12
+ ## Arguments
13
+
14
+ - 첫 번째 인자: 시나리오 설명 (예: "youtube.com에서 lofi 검색")
15
+ - `--model sonnet|haiku`: 사용할 모델 (기본: haiku)
16
+ - `--max-steps N`: 최대 스텝 수 (기본: 10)
17
+
18
+ ## Procedure
19
+
20
+ ### Step 1: Chrome 상태 확인
21
+
22
+ ```bash
23
+ screenagent check --output json
24
+ ```
25
+
26
+ - JSON 결과의 `ok` 필드를 확인한다.
27
+ - `ok: false`이면 사용자에게 Chrome 디버그 모드 실행을 안내하고 중단한다:
28
+ ```
29
+ Chrome CDP 연결 실패. 다음 명령어로 Chrome을 실행해주세요:
30
+ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug-profile
31
+ ```
32
+
33
+ ### Step 2: Chrome 초기화
34
+
35
+ CDP로 모든 탭을 닫고 about:blank 상태로 만든다:
36
+
37
+ ```bash
38
+ # 현재 열린 탭 목록 확인
39
+ curl -s http://localhost:9222/json | python3 -c "
40
+ import sys, json
41
+ targets = json.load(sys.stdin)
42
+ pages = [t for t in targets if t.get('type') == 'page']
43
+ print(f'{len(pages)} tab(s) open')
44
+ for p in pages:
45
+ print(f' - {p.get(\"title\", \"untitled\")}: {p.get(\"url\", \"\")}')
46
+ "
47
+ ```
48
+
49
+ 열린 탭이 있으면 about:blank로 이동시킨다:
50
+
51
+ ```bash
52
+ # 첫 번째 탭의 websocket URL을 가져와서 about:blank으로 navigate
53
+ curl -s http://localhost:9222/json | python3 -c "
54
+ import sys, json
55
+ targets = json.load(sys.stdin)
56
+ pages = [t for t in targets if t.get('type') == 'page']
57
+ if pages:
58
+ # 첫 번째 탭만 남기고 나머지는 닫기
59
+ for p in pages[1:]:
60
+ import urllib.request
61
+ urllib.request.urlopen(f'http://localhost:9222/json/close/{p[\"id\"]}', timeout=5)
62
+ # 첫 번째 탭을 about:blank으로
63
+ print(f'Reset to 1 tab: {pages[0][\"id\"]}')
64
+ "
65
+ ```
66
+
67
+ ### Step 3: 시나리오에서 모델과 max-steps 파싱
68
+
69
+ 인자에서 `--model`과 `--max-steps` 값을 파싱한다.
70
+
71
+ - `--model sonnet` → `--model claude-sonnet-4-6`
72
+ - `--model haiku` → `--model claude-haiku-4-5-20251001` (기본값)
73
+ - `--max-steps N` → `--max-steps N` (기본값: 10)
74
+
75
+ 나머지 텍스트가 시나리오 instruction이 된다.
76
+
77
+ ### Step 4: screenagent 실행
78
+
79
+ ```bash
80
+ screenagent run "<instruction>" --max-steps <N> --model <model> --output json 2>demo_stderr.log
81
+ ```
82
+
83
+ - stderr 로그를 `demo_stderr.log`에 저장한다.
84
+ - 실행이 끝나면 stdout의 JSON 결과를 파싱한다.
85
+
86
+ ### Step 5: 결과 스크린샷 캡처
87
+
88
+ ```bash
89
+ screenagent screenshot --file demo_result.png --output json
90
+ ```
91
+
92
+ - 캡처된 스크린샷을 Read 도구로 확인하여 사용자에게 보여준다.
93
+
94
+ ### Step 6: 결과 리포트
95
+
96
+ 다음 형식으로 결과를 정리한다:
97
+
98
+ ```
99
+ ## Demo Result
100
+
101
+ **시나리오**: <instruction>
102
+ **모델**: <model>
103
+ **스텝**: <사용된 스텝> / <max-steps>
104
+ **결과**: ✅ 성공 / ❌ 실패
105
+
106
+ ### 에이전트 응답
107
+ <result summary>
108
+
109
+ ### 스크린샷
110
+ [demo_result.png 표시]
111
+
112
+ ### 로그 요약
113
+ <stderr 로그에서 주요 step 요약>
114
+ ```
115
+
116
+ - 실패 시: 에러 내용을 분석하고, demo-debugger subagent 사용을 제안한다.
117
+ - 성공 시: 결과를 요약하고 스크린샷으로 확인한다.
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: perf-audit
3
+ description: screenagent 에이전트 루프의 성능 병목을 분석하고 코드를 개선한다. 스텝별 시간 측정, 불필요한 스크린샷 제거, sleep 최적화 등.
4
+ argument-hint: [run-log-path or "analyze"]
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # /perf-audit Skill
9
+
10
+ screenagent 에이전트 루프의 성능 병목을 찾아내고 코드를 개선한다.
11
+
12
+ ## 배경
13
+
14
+ 현재 에이전트 루프의 알려진 병목:
15
+ - 매 tool dispatch마다 스크린샷 캡처 (불필요할 수 있음)
16
+ - `asyncio.sleep()` 고정 대기 시간 (0.3s, 2s 등)
17
+ - LLM API 호출 대기 (줄일 수 없지만 토큰 수 줄이기 가능)
18
+ - 스크린샷 리사이즈 (`sips` 호출)
19
+
20
+ ## Procedure
21
+
22
+ ### Step 1: 현재 성능 측정
23
+
24
+ 먼저 에이전트 루프를 dry-run이 아닌 실제 실행으로 시간을 측정한다.
25
+ 인자로 로그 파일 경로가 주어지면 해당 로그를 분석한다.
26
+
27
+ 로그가 없으면 `loop.py`의 `arun()` 메서드를 읽고 각 단계별 예상 시간을 계산한다:
28
+
29
+ ```
30
+ src/screenagent/agent/loop.py 의 arun() 분석:
31
+ ```
32
+
33
+ 각 스텝에서 소요되는 시간 요소:
34
+ 1. `_perceive_async()` — AX tree + CDP DOM + screenshot
35
+ 2. `_client.messages.create()` — LLM API 호출
36
+ 3. `_dispatch_tool()` — tool 실행 + sleep + 후속 screenshot
37
+ 4. 메시지 직렬화/역직렬화
38
+
39
+ ### Step 2: 병목 식별
40
+
41
+ `loop.py`와 `composite.py`를 읽고 다음을 체크한다:
42
+
43
+ #### 2a. 불필요한 스크린샷
44
+ - `_dispatch_tool`에서 click, type_text, key_press, scroll 후 모두 screenshot를 찍고 있음
45
+ - 연속 동작(click → type → enter)에서 중간 스크린샷은 불필요할 수 있음
46
+ - **개선**: tool 결과에 screenshot를 넣되, LLM이 다음 tool을 연속 호출할 때는 마지막 것만 사용
47
+
48
+ #### 2b. sleep 최적화
49
+ 현재 sleep 값들:
50
+ - `_open_url_via_keyboard`: 0.3s + 0.1s + 0.3s + 2.0s = **2.7s** (URL 열 때마다)
51
+ - `click`: 0.3s
52
+ - `type_text`: 0.3s
53
+ - `key_press`: 0.3s
54
+ - `scroll`: 0.3s
55
+ - `navigate` (CDP): 1.0s
56
+
57
+ **개선 방안**:
58
+ - 페이지 로드 대기를 고정 sleep 대신 CDP `Page.loadEventFired` 이벤트 대기로 변경
59
+ - 클릭/타이핑 후 sleep을 0.1s로 줄여볼 수 있음
60
+
61
+ #### 2c. 이미지 크기 최적화
62
+ - 스크린샷이 클수록 LLM 토큰 소모 많고 API 응답 느림
63
+ - 현재 MAX_IMAGE_BYTES = 3.5MB → 너무 큼
64
+ - **개선**: 1MB 이하로 줄이면 API 응답 속도 향상
65
+
66
+ #### 2d. 히스토리 관리
67
+ - MAX_HISTORY = 10이지만 각 메시지에 이미지가 포함됨
68
+ - 오래된 메시지의 이미지를 제거하면 토큰 절약
69
+
70
+ ### Step 3: 코드 수정 적용
71
+
72
+ 분석 결과에 따라 실제 코드를 수정한다. 수정 대상 파일:
73
+
74
+ | 파일 | 개선 내용 |
75
+ |------|-----------|
76
+ | `src/screenagent/agent/loop.py` | sleep 값 조정, 히스토리 이미지 제거, 스텝 타이밍 로그 |
77
+ | `src/screenagent/perception/screenshot.py` | MAX_IMAGE_BYTES 축소 |
78
+ | `src/screenagent/perception/composite.py` | CDP 우선 screenshot, 불필요한 AX tree 스킵 |
79
+
80
+ 수정 시 각 변경에 대해:
81
+ 1. 변경 전 동작을 설명
82
+ 2. 변경 후 기대 효과를 설명
83
+ 3. 위험 요소가 있으면 명시
84
+
85
+ ### Step 4: 검증
86
+
87
+ ```bash
88
+ # 테스트 통과 확인
89
+ .venv/bin/python -m pytest tests/ -x -q
90
+
91
+ # dry-run 정상 확인
92
+ .venv/bin/screenagent --output json run "test" --dry-run
93
+ ```
94
+
95
+ ### Step 5: 결과 리포트
96
+
97
+ ```
98
+ ## Performance Audit Report
99
+
100
+ ### 측정 결과
101
+ | 구간 | 변경 전 | 변경 후 | 절감 |
102
+ |------|---------|---------|------|
103
+ | URL 열기 | 2.7s | 0.8s | -70% |
104
+ | 클릭 후 대기 | 0.3s | 0.15s | -50% |
105
+ | 스크린샷 크기 | ~600KB | ~200KB | -67% |
106
+ | 스텝당 히스토리 토큰 | ~8K | ~4K | -50% |
107
+
108
+ ### 적용된 변경
109
+ - [파일별 변경 내용]
110
+
111
+ ### 추가 권장
112
+ - [더 할 수 있는 최적화]
113
+ ```
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: reset-chrome
3
+ description: Chrome의 모든 탭을 닫고 새 창을 열어 깨끗한 상태로 만든다
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # /reset-chrome Skill
8
+
9
+ Chrome 브라우저를 깨끗한 상태로 리셋한다.
10
+
11
+ ## Procedure
12
+
13
+ ### Step 1: CDP 연결 확인
14
+
15
+ ```bash
16
+ screenagent check --output json
17
+ ```
18
+
19
+ - `ok: false`이면:
20
+ ```
21
+ Chrome CDP 연결 실패. 다음 명령어로 Chrome을 실행해주세요:
22
+ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug-profile
23
+ ```
24
+ 여기서 중단한다.
25
+
26
+ ### Step 2: 현재 탭 상태 확인
27
+
28
+ ```bash
29
+ curl -s http://localhost:9222/json | python3 -c "
30
+ import sys, json
31
+ targets = json.load(sys.stdin)
32
+ pages = [t for t in targets if t.get('type') == 'page']
33
+ print(f'{len(pages)} tab(s) open')
34
+ for p in pages:
35
+ print(f' - {p.get(\"title\", \"untitled\")}: {p.get(\"url\", \"\")}')
36
+ "
37
+ ```
38
+
39
+ ### Step 3: 탭 정리
40
+
41
+ 모든 탭을 닫고 하나의 about:blank 탭만 남긴다:
42
+
43
+ ```bash
44
+ curl -s http://localhost:9222/json | python3 -c "
45
+ import sys, json, urllib.request
46
+
47
+ targets = json.load(sys.stdin)
48
+ pages = [t for t in targets if t.get('type') == 'page']
49
+
50
+ if not pages:
51
+ # 탭이 없으면 새 탭 생성
52
+ urllib.request.urlopen('http://localhost:9222/json/new?about:blank', timeout=5)
53
+ print('Created new blank tab')
54
+ else:
55
+ # 첫 번째 탭 외 모두 닫기
56
+ for p in pages[1:]:
57
+ try:
58
+ urllib.request.urlopen(f'http://localhost:9222/json/close/{p[\"id\"]}', timeout=5)
59
+ print(f'Closed: {p.get(\"title\", \"untitled\")}')
60
+ except Exception as e:
61
+ print(f'Failed to close {p[\"id\"]}: {e}')
62
+
63
+ # 남은 탭 수 확인
64
+ print(f'Kept 1 tab: {pages[0].get(\"title\", \"untitled\")}')
65
+ "
66
+ ```
67
+
68
+ 첫 번째 탭을 about:blank으로 이동시킨다:
69
+
70
+ ```bash
71
+ curl -s http://localhost:9222/json | python3 -c "
72
+ import sys, json, urllib.request
73
+ targets = json.load(sys.stdin)
74
+ pages = [t for t in targets if t.get('type') == 'page']
75
+ if pages:
76
+ target_id = pages[0]['id']
77
+ urllib.request.urlopen(f'http://localhost:9222/json/activate/{target_id}', timeout=5)
78
+ print(f'Activated tab: {target_id}')
79
+ "
80
+ ```
81
+
82
+ 그 다음 about:blank으로 네비게이트한다:
83
+
84
+ ```bash
85
+ screenagent run "주소창에 about:blank를 입력하고 엔터를 눌러줘" --max-steps 3 --dry-run
86
+ ```
87
+
88
+ 대신 CDP로 직접 navigate한다:
89
+
90
+ ```bash
91
+ python3 -c "
92
+ import json, http.client
93
+
94
+ # Get first page target
95
+ conn = http.client.HTTPConnection('localhost', 9222)
96
+ conn.request('GET', '/json')
97
+ targets = json.loads(conn.getresponse().read())
98
+ pages = [t for t in targets if t.get('type') == 'page']
99
+
100
+ if pages:
101
+ ws_url = pages[0].get('webSocketDebuggerUrl', '')
102
+ target_id = pages[0]['id']
103
+ # Use CDP HTTP endpoint to navigate
104
+ conn.request('GET', f'/json/navigate/{target_id}?url=about:blank')
105
+ print(conn.getresponse().read().decode())
106
+ print('Navigated to about:blank')
107
+ conn.close()
108
+ "
109
+ ```
110
+
111
+ ### Step 4: 상태 확인
112
+
113
+ ```bash
114
+ screenagent check --output json
115
+ ```
116
+
117
+ 결과를 보고한다:
118
+
119
+ ```
120
+ Chrome 리셋 완료:
121
+ - 탭: 1개 (about:blank)
122
+ - CDP 연결: 정상
123
+ ```
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: test-agent
3
+ description: screenagent CLI 도구들을 빠르게 검증한다. dry-run, screenshot, ax-tree, click 등 개별 기능을 테스트하고 결과를 리포트.
4
+ argument-hint: [tool-name or "all"]
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # /test-agent Skill
9
+
10
+ screenagent의 개별 CLI 도구들을 빠르게 테스트하고 결과를 리포트한다.
11
+
12
+ ## Arguments
13
+
14
+ - `all`: 모든 도구를 순서대로 테스트
15
+ - 특정 도구 이름: `dry-run`, `screenshot`, `ax-tree`, `click`, `type`, `key`, `check`, `schema`
16
+
17
+ ## Procedure
18
+
19
+ ### 테스트 대상별 실행 방법
20
+
21
+ 각 테스트는 `--output json`으로 실행하여 결과를 파싱한다.
22
+
23
+ #### 1. `dry-run` — 설정 검증
24
+
25
+ ```bash
26
+ screenagent run "test" --dry-run --output json
27
+ ```
28
+
29
+ - 확인: `ok` 필드가 `true`인지
30
+ - 확인: `config.api_key_set`이 `true`인지
31
+ - 확인: `config.model`이 유효한 모델명인지
32
+
33
+ #### 2. `screenshot` — 스크린샷 캡처
34
+
35
+ ```bash
36
+ screenagent screenshot --file /tmp/test_screenshot.png --output json
37
+ ```
38
+
39
+ - 확인: `path` 필드가 존재하는지
40
+ - 확인: `bytes`가 0보다 큰지
41
+ - 확인: 파일이 실제로 존재하는지
42
+
43
+ #### 3. `ax-tree` — 접근성 트리
44
+
45
+ ```bash
46
+ screenagent ax-tree "Finder" --output json
47
+ ```
48
+
49
+ - 확인: JSON 출력이 유효한지
50
+ - 확인: `role` 필드가 존재하는지
51
+ - 에러 시: 접근성 권한 문제인지 확인
52
+
53
+ #### 4. `click` — 마우스 클릭 (안전한 좌표 사용)
54
+
55
+ ```bash
56
+ screenagent click 0 0 --output json
57
+ ```
58
+
59
+ - 확인: `clicked` 필드가 존재하는지
60
+ - 주의: 화면 왼쪽 상단 구석(0,0)을 클릭하여 부작용 최소화
61
+
62
+ #### 5. `type` — 키보드 입력 (빈 앱 없이 테스트하므로 skip 가능)
63
+
64
+ 이 테스트는 실제로 키 입력이 발생하므로, 현재 포커스된 앱에 텍스트가 입력될 수 있다.
65
+ `all`로 실행 시에는 이 테스트를 건너뛰고, 명시적으로 `type`을 지정했을 때만 실행한다.
66
+
67
+ ```bash
68
+ screenagent type "test" --output json
69
+ ```
70
+
71
+ - 확인: `typed` 필드가 `"test"`인지
72
+
73
+ #### 6. `key` — 키 입력
74
+
75
+ ```bash
76
+ screenagent key escape --output json
77
+ ```
78
+
79
+ - 확인: `pressed.key`가 `"escape"`인지
80
+ - Escape는 대부분의 상황에서 안전한 키이다.
81
+
82
+ #### 7. `check` — CDP 연결 확인
83
+
84
+ ```bash
85
+ screenagent check --output json
86
+ ```
87
+
88
+ - 확인: JSON 파싱 성공
89
+ - `ok: true`이면 CDP 정상, `ok: false`이면 CDP 미연결 (경고만, 실패 아님)
90
+
91
+ #### 8. `schema` — 도구 스키마
92
+
93
+ ```bash
94
+ screenagent schema --output json
95
+ ```
96
+
97
+ - 확인: `tools` 배열이 존재하는지
98
+ - 확인: 각 도구에 `name`, `description`, `input_schema`가 있는지
99
+
100
+ ### 결과 리포트
101
+
102
+ 모든 테스트 완료 후 다음 형식으로 보고한다:
103
+
104
+ ```
105
+ ## Test Report
106
+
107
+ | Tool | Status | Details |
108
+ |------------|--------|----------------------|
109
+ | dry-run | ✅ | API key set, haiku |
110
+ | screenshot | ✅ | 245KB captured |
111
+ | ax-tree | ✅ | Finder tree loaded |
112
+ | click | ✅ | (0, 0) clicked |
113
+ | type | ⏭️ | Skipped (all mode) |
114
+ | key | ✅ | escape pressed |
115
+ | check | ⚠️ | CDP not connected |
116
+ | schema | ✅ | 6 tools found |
117
+
118
+ **Result**: 6/8 passed, 1 skipped, 1 warning
119
+ ```
120
+
121
+ - ✅: 성공
122
+ - ❌: 실패 (에러 내용 포함)
123
+ - ⚠️: 경고 (기능은 동작하지만 주의 필요)
124
+ - ⏭️: 건너뜀