|
| 1 | +# Capabilities |
| 2 | + |
| 3 | +This skill talks WebDriver / Appium HTTP directly against the Kobiton hub. The capability payload sent on `POST /wd/hub/session` is rendered by `run-automation-suite/scripts/render-capabilities.js` (cross-skill reuse — both skills live in the same plugin). |
| 4 | + |
| 5 | +## Invocation |
| 6 | + |
| 7 | +```bash |
| 8 | +node ../run-automation-suite/scripts/render-capabilities.js \ |
| 9 | + --platformName "<Android | iOS>" \ |
| 10 | + --udid "<udid>" \ |
| 11 | + --deviceName "<device name>" \ |
| 12 | + --platformVersion "<version>" \ |
| 13 | + --automationName "<UiAutomator2 | XCUITest>" \ |
| 14 | + --app "<kobiton-store:vXXXXX>" \ |
| 15 | + --testingType app \ |
| 16 | + --newCommandTimeout 1800 |
| 17 | +``` |
| 18 | + |
| 19 | +The `--newCommandTimeout 1800` flag is the key addition for this skill — it tells Appium not to terminate the session if no command arrives for 30 minutes. That window covers the human-in-the-loop pauses the skill enters when it gets stuck and asks the user. |
| 20 | + |
| 21 | +The `--scriptlessCapture` flag emits `kobiton:scriptlessCapture: true`. This tells the Kobiton platform to record the session's WebDriver actions so the resulting session can be converted to a saveable test case via the `saveTestCase` MCP tool. This is the **single most important capability** for the skill — without it, the session id we return cannot be persisted as a re-runnable test case. The capability name evolved from `kobiton:scriptlessEnable` (older) to `kobiton:scriptlessCapture` (current). If you see "Session not created" errors mentioning either name, check which name the deployed Kobiton platform accepts; the skill currently emits only the new name. |
| 22 | + |
| 23 | +Output is the desired-caps JSON written to `.kobiton/sessions/<session-id>/caps.json` and fed to `scripts/appium.js create-session --caps-file <path>`. |
| 24 | + |
| 25 | +## Credentials → Hub URL |
| 26 | + |
| 27 | +`appium.js` reads `~/.kobiton/.credentials` (written by `/automate:setup`) on every invocation, so they stay out of the AI host's transcript, argv, and env. |
| 28 | + |
| 29 | +The composed hub URL is `https://{user}:{api_key}@{portal-host}/wd/hub` — for example, `https://api.kobiton.com/wd/hub`. The portal stored in `~/.kobiton/.credentials` is the API base (`https://api.kobiton.com`); the WebDriver path `/wd/hub` is appended by `appium.js`. |
| 30 | + |
| 31 | +If `/automate:setup` has never been run on this host, the skill stops in Step 1 with a message pointing the user there. The setup command fetches credentials from the authenticated MCP context (the `getCredential` tool) and writes them to the file. |
| 32 | + |
| 33 | +**Backward-compat:** `appium.js` still accepts `--hub-url <embedded-auth-url>` for callers that want to provide a pre-composed URL. The credential triple is preferred for new code. |
| 34 | + |
| 35 | +## What the capability payload looks like |
| 36 | + |
| 37 | +After `render-capabilities.js` runs: |
| 38 | + |
| 39 | +```jsonc |
| 40 | +{ |
| 41 | + "kobiton:sessionName": "Automation test session", |
| 42 | + "kobiton:sessionDescription": "", |
| 43 | + "kobiton:aiToolName": "Claude", // or Codex / Copilot / Gemini, host-detected |
| 44 | + "kobiton:deviceOrientation": "portrait", |
| 45 | + "kobiton:captureScreenshots": true, |
| 46 | + "appium:noReset": true, |
| 47 | + "appium:fullReset": false, |
| 48 | + "appium:automationName": "UiAutomator2", // platform-dependent |
| 49 | + "appium:newCommandTimeout": 1800, // KEY ADDITION for this skill |
| 50 | + "appium:app": "kobiton-store:v72116", |
| 51 | + "appium:udid": "21161FDF60051K", |
| 52 | + "appium:deviceName": "Pixel 6", |
| 53 | + "platformName": "Android", |
| 54 | + "platformVersion": "15" |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +`scripts/appium.js create-session` wraps this in W3C `{capabilities: {alwaysMatch: ...}}` automatically — both raw and wrapped shapes are accepted. |
| 59 | + |
| 60 | +## Platform cap on newCommandTimeout |
| 61 | + |
| 62 | +Kobiton's platform-side session-duration cap (org-plan dependent) is the wall-clock bound on the session — it is independent of `appium:newCommandTimeout`. The two values do different things: |
| 63 | + |
| 64 | +- `appium:newCommandTimeout: 1800` tells **Appium** not to time out the session for idleness (no WebDriver command in 30 min). |
| 65 | +- The platform-side cap tells **Kobiton** to end the session after N minutes regardless of activity. |
| 66 | + |
| 67 | +If Kobiton ever rejects a session-create with `newCommandTimeout: 1800` (HTTP 400 with a message about cap exceeded), lower the value here and update this doc. We have not observed this against Kobiton's public hub as of writing. |
| 68 | + |
| 69 | +## App reference |
| 70 | + |
| 71 | +The skill requires an `--app` value — a `kobiton-store:vXXXXX` reference uploaded ahead of time, OR a path the caller has just uploaded via the `uploadAppToStore` / `confirmAppUpload` MCP tools. The caller is responsible for ensuring an app is available before invoking the skill. |
| 72 | + |
| 73 | +For web sessions (`--testingType web`), pass `--browserName safari` or `chrome` instead of `--app`. |
0 commit comments