Dock 과 앱
Dock 은 2단이에요. 1단에는 기기와, 자주 써서 1단에 따로 고정한 앱이 있어요. 기기를 누르면 그 기기의 앱이 2단으로 펼쳐져요. 사람도 AI 에이전트도 “어느 기기에서 → 어떤 앱” 순서로 생각하게 돼요. 같은 앱이 두 기기에 있어도 헷갈리지 않고, 기기가 늘어도 1단이 넘치지 않아요.
┌─ 2단: pixel (android) ─────────────────┐ │ 📌 설정 📌 카메라 │ 모든 앱 ▸ │ └──────────────────────────────▲─────────┘ 1단: [research-box · linux] [web · chrome] [pixel · android] [내 폰 · android] [설정 ⤒] └──────────── virtual ────────────┘ └─ virtual ─┘ └── actual ──┘ └ 1단에 고정한 앱 ┘| 단 | 무엇 | 저장 |
|---|---|---|
| 1단 | Device(actual·virtual 모두)와 1단에도 고정한 App | GET·PUT /stations/{id}/dock 의 순서 있는 목록 (최대 30칸) |
| 2단 | 그 Device 의 App 전부 + android 면 “모든 앱”(설치된 앱 목록) | GET /devices/{id}/apps |
Device 를 만들면 1단 끝에 붙어요 — virtual 은 pin_to_dock(기본 true), actual 은 등록할 때. 내가 연결한 폰도 클라우드에 띄운 기기와 똑같이 1단 항목으로 저장돼요.
1단 읽기와 바꾸기
섹션 제목: “1단 읽기와 바꾸기”curl -s $OS/api/v1/stations/$STN/dock -H "Authorization: Bearer $TOKEN" \ | jq '.data.items[] | {type, label, kind, device_type, compute_status, online}'항목마다 type(device·app)·device_id·app_id·label·kind·device_type(actual·virtual)·compute_status·online·icon_data_url 이 채워져 있어서, 화면은 이것 하나로 1단의 아이콘과 실행 중 표시를 그려요. app 항목의 device_id 는 그 앱이 있는 기기예요.
1단은 PUT /stations/{id}/dock 으로 통째로 바꿔요 — 순서 바꾸기, 1단에 넣기, 1단에서 빼기가 모두 이것이에요:
{ "items": [ { "type": "device", "device_id": "res_…" }, { "type": "app", "app_id": "app_…" } ] }1단에서 빼도 Device·App 은 지워지지 않아요 — App 은 그 기기의 2단에 그대로 남아요. 없는·남의·지워진 항목이거나 같은 항목이 두 번이면 422 DOCK_ITEM_INVALID (details.index) 이고 Dock 은 그대로예요. 바뀔 때마다 dock.changed 이벤트가 나가요.
App — 기기에 저장한 앱
섹션 제목: “App — 기기에 저장한 앱”App 은 기기 안의 앱(android 패키지)을 저장한 것이에요(app_). Device 를 가리키기 때문에(device_id + package), 클라우드에 띄운 android 와 내가 연결한 폰이 같은 방식이에요.
- App 은 그 기기의 2단에 늘 있어요.
pinned가 true 면 1단에도 있어요 (Dock 항목이 있다는 뜻).
# 1. 설치된 앱 목록 (android 만) — 2단의 "모든 앱"curl -s $OS/api/v1/devices/$DEV/installed-apps -H "Authorization: Bearer $TOKEN" | jq '.data[] | {package, label, app_id}'
# 2. 기기에 저장 (2단에만) — pin_to_dock 기본 falseexport APP=$(curl -s -X POST $OS/api/v1/devices/$DEV/apps \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ -d '{"package":"com.android.settings","label":"설정"}' | jq -r .data.app_id)
# 3. 1단에도 고정curl -s -X PATCH $OS/api/v1/apps/$APP \ -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d '{"pinned":true}'
# 4. 열기 — 그 기기에서 앱이 열려요curl -s -X POST $OS/api/v1/apps/$APP/launch -H "Authorization: Bearer $TOKEN" | jq .data.statusPOST /devices/{id}/apps{package, label?, icon_data_url?, pin_to_dock?}→ 201.pin_to_dock의 기본값은 false — 2단에만 둬요. 만들 때 true 면 1단 끝에도 붙어요.icon_data_url에는 설치된 앱 목록의 아이콘을 그대로 넘겨요 (16 KiB 까지).- 같은 기기의 같은
package로 다시 만들면 새로 만들지 않고 있는 것을 200 으로 돌려줘요. Station 당 100개 (409APP_LIMIT_REACHED). PATCH /apps/{id}{label?, pinned?}— 이름을 바꾸거나 1단에 고정·해제해요.pinned: false여도 2단에는 남아요.DELETE /apps/{id}는 저장한 앱을 지워요 — 2단에서, 1단에 있었으면 1단에서도 빠져요. 기기 안의 앱은 그대로예요.GET /stations/{id}/apps— Station 의 저장한 앱 전부.- 실행은 그 기기에
app_launch {package}명령을 보내요. 10초 안에 끝나지 않으면dispatched로 답하고, 명령 기록에 사용자 행동으로 남아요. 명령의 오류를 그대로 돌려줘요 — 기기가 오프라인이면 409RESOURCE_OFFLINE, 잔액이 0 이하면 402INSUFFICIENT_CREDITS. - 기기를 지우면 그 기기의 App 도 지워져요.
Dock 을 누를 때 (데스크톱 화면의 동작)
섹션 제목: “Dock 을 누를 때 (데스크톱 화면의 동작)”- 1단의 기기 — 2단이 있으면(android 이거나 저장한 앱이 있으면) 그 기기의 2단을 펼쳐요. 2단의 “화면 열기”, 또는 2단이 없는 기기(chrome·linux)는 기기 창을 열어요. virtual 기기가
running이 아니면 먼저POST /devices/{id}/start를 보내고device.status_changed(running)을 기다려요. - 2단에서 — 📌 는 설치된 앱을 그 기기에 저장하고(App 만들기), ⤒ 는 App 을 1단에 올리거나 내려요(
pinned). 오른쪽 클릭 메뉴도 같은 일을 해요. - App(1단·2단 모두) —
POST /apps/{id}/launch후 기기 앱 창을 열고 화면을 따라가요. 그 기기가 virtual 이고 멈춰 있으면 화면이 먼저 기기를 시작해요.