From ccad9f69aae7465c4ad4ea169d273f61ffac1eb5 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Fri, 18 Sep 2026 10:38:09 -0700 Subject: [PATCH] Use T3 Device panel for mobile testing (#12414) --- .agents/skills/ios-debugger-agent/LICENSE | 21 -- .agents/skills/ios-debugger-agent/SKILL.md | 66 ------ .../ios-debugger-agent/agents/openai.yaml | 9 - .agents/skills/ios-simulator-browser/LICENSE | 21 -- .agents/skills/ios-simulator-browser/SKILL.md | 51 ----- .../ios-simulator-browser/agents/openai.yaml | 4 - .agents/skills/test-t3-app/SKILL.md | 105 +++------ .agents/skills/test-t3-app/agents/openai.yaml | 4 +- .agents/skills/test-t3-mobile/SKILL.md | 203 ++++-------------- .../skills/test-t3-mobile/agents/openai.yaml | 4 +- .../test-t3-mobile/scripts/pair-client.sh | 49 ++--- .codex/config.toml | 9 - .mcp.json | 11 - 13 files changed, 86 insertions(+), 471 deletions(-) delete mode 100644 .agents/skills/ios-debugger-agent/LICENSE delete mode 100644 .agents/skills/ios-debugger-agent/SKILL.md delete mode 100644 .agents/skills/ios-debugger-agent/agents/openai.yaml delete mode 100644 .agents/skills/ios-simulator-browser/LICENSE delete mode 100644 .agents/skills/ios-simulator-browser/SKILL.md delete mode 100644 .agents/skills/ios-simulator-browser/agents/openai.yaml delete mode 100644 .codex/config.toml delete mode 100644 .mcp.json diff --git a/.agents/skills/ios-debugger-agent/LICENSE b/.agents/skills/ios-debugger-agent/LICENSE deleted file mode 100644 index 0d193abe04f2d20e76d96762ecb6b4c432c8bc06..0000000000000000000000000000000000000000 --- a/.agents/skills/ios-debugger-agent/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) OpenAI - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/.agents/skills/ios-debugger-agent/SKILL.md b/.agents/skills/ios-debugger-agent/SKILL.md deleted file mode 100644 index 8d204ff201bc57f637e639a90dc265916c078b34..0000000000000000000000000000000000000000 --- a/.agents/skills/ios-debugger-agent/SKILL.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -name: ios-debugger-agent -description: Build, launch, inspect, and drive iOS apps with the repository-configured XcodeBuildMCP server. Use on macOS for iOS Simulator builds, focused native test runs, semantic UI automation, screenshots, logs, or debugging, including T3 Code Mobile verification. ---- - -# iOS Debugger Agent - -Use the repository-configured `xcodebuildmcp` tools instead of requiring a globally installed Codex plugin. Prefer MCP tools over raw `xcodebuild`, `xcrun`, or `simctl` when the client exposes them. - -## Confirm availability - -This workflow requires macOS 14.5 or newer, Xcode 16 or newer, and Node.js 18 or newer. The repository pins XcodeBuildMCP in both `.mcp.json` for Claude Code and `.codex/config.toml` for Codex. Project MCP servers may require one-time trust or approval followed by a new session. - -If the tools are missing: - -1. Confirm the repository is trusted and its project MCP server was approved. -2. Restart or recreate the agent session after approving configuration. -3. Run `npx --yes xcodebuildmcp@2.6.2 doctor` when the server starts but simulator or UI-automation tools are unavailable. Follow its actionable Xcode or AXe setup guidance. -4. Fall back to the pinned XcodeBuildMCP CLI or native Apple CLIs only when the current agent client cannot expose project MCP tools. - -Do not ask contributors to install the OpenAI `build-ios-apps` plugin globally. - -## Establish one simulator context - -1. Call `session_show_defaults` before discovery, build, launch, or UI work. -2. Call `list_sims` and select one explicit simulator UDID. Prefer a simulator that is already booted; boot an installed simulator when verification requires it, but do not create or download runtimes without user authorization. -3. Call `session_set_defaults` with the project or workspace, scheme, Debug configuration, simulator ID, and bundle identifier when known. -4. Keep every subsequent build, launch, screenshot, log capture, and UI action pinned to that same UDID. - -Avoid generic Mac window automation for switching among Simulator windows. Explicit device identity is more reliable. - -## Choose build or launch - -For T3 Code Mobile, run `node scripts/mobile-native-client.ts ensure ios ` from the checkout on the simulator host first. It checks the local Expo native fingerprint against the installed client and builds/installs when stale, missing, or unknown. Then launch with the intended Metro bundle. Authorized verification includes native builds and installs; do not stop because the existing client is old. Use `check` instead of `ensure` only when the user explicitly prohibits rebuilding or requests a read-only check. - -- Use `build_run_sim` when native source, native dependencies, entitlements, or project configuration changed. -- Use `test_sim` for the smallest relevant native test target or test cases; do not run an entire workspace test matrix routinely. -- Use `launch_app_sim` when a compatible app is already installed and no native rebuild is needed. -- To reuse an existing build artifact, use `get_sim_app_path` or `get_app_bundle_id`, install it with `install_app_sim` when necessary, and then launch it. -- Do not run a build-only action immediately before `build_run_sim` unless the task requires both artifacts. - -After launch, call `snapshot_ui` or `screenshot` before interacting. An open Simulator window alone is not evidence that the intended app launched. - -## Drive the UI semantically - -1. Call `snapshot_ui` to obtain the current accessibility hierarchy and element references. -2. Use only current `elementRef` values whose snapshot entries list the intended action. XcodeBuildMCP `2.6.2` does not accept coordinates for `tap`; when the app exposes no actionable reference, prefer a registered deep link or another app-supported route and otherwise report the accessibility blocker. -3. Refresh with `snapshot_ui` after navigation or layout changes. Element references are snapshot-specific. -4. Use `wait_for_ui` for asynchronous transitions when available rather than fixed sleeps. -5. Capture a final `screenshot` for the state that proves the affected flow. - -Use `gesture` or scoped swipe actions when needed. If a gesture is unreliable, return to a known route or relaunch rather than switching to generic desktop automation. - -## Capture logs and debug - -- Use `start_sim_log_cap` and `stop_sim_log_cap` with the exact bundle identifier for focused runtime logs. -- Use debugger tools only when the task requires runtime diagnosis; attach to the selected simulator and app rather than an ambiguous process. -- Summarize relevant errors instead of returning unbounded logs. - -## Clean up - -Stop only log captures, debugger sessions, apps, or simulators started for the current test. Leave pre-existing simulators and unrelated sessions alone. - -## Upstream - -Adapted from OpenAI's [`build-ios-apps`](https://github.com/openai/plugins/tree/main/plugins/build-ios-apps) plugin version `0.1.2` (`ios-debugger-agent`, MIT) and aligned with XcodeBuildMCP `2.6.2` tool names. diff --git a/.agents/skills/ios-debugger-agent/agents/openai.yaml b/.agents/skills/ios-debugger-agent/agents/openai.yaml deleted file mode 100644 index 094bae6620be2702397c70c87e0ce6953385d6a7..0000000000000000000000000000000000000000 --- a/.agents/skills/ios-debugger-agent/agents/openai.yaml +++ /dev/null @@ -1,9 +0,0 @@ -interface: - display_name: "iOS Debugger Agent" - short_description: "Build and drive iOS Simulator apps" - default_prompt: "Use $ios-debugger-agent to build, launch, and inspect the current iOS app on Simulator." -dependencies: - tools: - - type: "mcp" - value: "xcodebuildmcp" - description: "Repository-configured Xcode build, simulator, logging, debugging, and semantic UI tools" diff --git a/.agents/skills/ios-simulator-browser/LICENSE b/.agents/skills/ios-simulator-browser/LICENSE deleted file mode 100644 index 0d193abe04f2d20e76d96762ecb6b4c432c8bc06..0000000000000000000000000000000000000000 --- a/.agents/skills/ios-simulator-browser/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) OpenAI - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/.agents/skills/ios-simulator-browser/SKILL.md b/.agents/skills/ios-simulator-browser/SKILL.md deleted file mode 100644 index 74b97530799c1894049df06946f66e023e3ac023..0000000000000000000000000000000000000000 --- a/.agents/skills/ios-simulator-browser/SKILL.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -name: ios-simulator-browser -description: Stream an explicit iOS Simulator through pinned serve-sim into the T3 Code in-app browser or another agent browser. Use on Apple Silicon macOS when the user should watch simulator verification live or when browser-visible simulator evidence is needed. ---- - -# iOS Simulator Browser - -Use serve-sim as the shared visual feed for an iOS Simulator. Use `ios-debugger-agent` and XcodeBuildMCP semantic UI tools to drive the app; do not treat browser-canvas coordinates as a substitute for missing app accessibility. - -## Confirm availability - -serve-sim `0.1.45` requires Apple Silicon macOS, Xcode command-line tools, and Node.js 20 or newer. If the host is unsupported, continue with XcodeBuildMCP screenshots and report that live streaming was unavailable. - -When running inside T3 Code, use its product-native browser MCP to open the stream. Other agent hosts may use their own browser or preview surface. - -Keep serve-sim on its default `127.0.0.1` binding. Do not expose its preview to a LAN or tunnel unless the user explicitly requests that access and the network is trusted; the preview includes a token-gated shell-execution route. - -## Start one owned stream - -1. Obtain the exact simulator UDID from the iOS build or launch workflow. -2. Check whether an existing serve-sim stream for that UDID belongs to another task. Reuse it only when explicitly shared; never kill another task's stream. -3. Otherwise, clear only a stale stream for that UDID and start the pinned version with scoped cleanup: - - ```bash - SIMULATOR_ID= - cleanup_serve_sim() { - npx --yes serve-sim@0.1.45 --kill "$SIMULATOR_ID" >/dev/null 2>&1 || true - } - trap cleanup_serve_sim EXIT INT TERM HUP - cleanup_serve_sim - npx --yes serve-sim@0.1.45 "$SIMULATOR_ID" - ``` - -4. Keep the terminal alive and open the exact local URL printed by serve-sim in the agent's browser. -5. Verify that a live simulator frame renders. A loaded wrapper page is not sufficient evidence. - -## Observe while driving semantically - -- Let the user watch the serve-sim stream while XcodeBuildMCP performs `snapshot_ui`, semantic taps, typing, gestures, and screenshots. -- Keep the browser and Xcode tooling pinned to the same simulator UDID. -- Do not switch to generic desktop automation or browser-canvas clicking merely because the stream is visible. - -If the in-app browser explicitly reports that previews are unavailable, do not install unrelated browser automation. Continue through XcodeBuildMCP, capture a simulator screenshot, report the unavailable live stream, and clean up the owned serve-sim process. - -## Finish - -Stop the long-running terminal and wait for its cleanup trap to finish. If it disappeared without cleanup, run `npx --yes serve-sim@0.1.45 --kill ` for that exact simulator. Never run an unscoped `--kill`. - -## Upstream - -Adapted from OpenAI's [`build-ios-apps`](https://github.com/openai/plugins/tree/main/plugins/build-ios-apps) plugin version `0.1.2` (`ios-simulator-browser`, MIT). It invokes serve-sim `0.1.45` under its Apache-2.0 license without vendoring the package. diff --git a/.agents/skills/ios-simulator-browser/agents/openai.yaml b/.agents/skills/ios-simulator-browser/agents/openai.yaml deleted file mode 100644 index 9e8cdf7a16b0294e2c61bb5f3e94328d893fa517..0000000000000000000000000000000000000000 --- a/.agents/skills/ios-simulator-browser/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "iOS Simulator Browser" - short_description: "Stream iOS Simulator in the browser" - default_prompt: "Use $ios-simulator-browser to stream the selected iOS Simulator into the T3 Code in-app browser." diff --git a/.agents/skills/test-t3-app/SKILL.md b/.agents/skills/test-t3-app/SKILL.md index 0e11b50e1c83c31194ca40db8851d69d29bbb730..06fe9867b15ae0e36b5dc8cc44a0c4d39d9cbbba 100644 --- a/.agents/skills/test-t3-app/SKILL.md +++ b/.agents/skills/test-t3-app/SKILL.md @@ -1,90 +1,41 @@ --- name: test-t3-app -description: Launch, retain, and test the T3 Code web app in isolated development environments, including first-try browser authentication with one-time pairing URLs, pairing-token recovery, worktree-safe state directories, cross-turn dev server lifecycle, and direct SQLite inspection or fixture seeding. Use when an agent needs to run T3 locally, iteratively test UI behavior with a human, recover from an expired or consumed pairing token, isolate dev state, or prepare test data in state.sqlite. +description: Test T3 Code's web and desktop UI through its built-in Browser panel against isolated development state. Use for browser verification, browser pairing recovery, and test fixtures. Use test-t3-mobile for native mobile verification. --- -# Test T3 App +# Test T3 web and desktop -Use this skill for the web client. For iOS Simulator, Android Emulator, or physical-device testing against an isolated T3 backend, use the sibling [`test-t3-mobile`](../test-t3-mobile/SKILL.md) skill. +Use T3's built-in Browser panel for verification. If its tools are absent or +the panel reports unavailable, explain the blocker and stop verification. +Do not install or switch to another automation system. For native mobile +testing, use [test-t3-mobile](../test-t3-mobile/SKILL.md). -## Start an isolated web environment +## Start the app -1. Run commands from the repository root. -2. Choose a base directory that belongs only to the current worktree or test: - - Use the repository's ignored `.t3` directory for reusable worktree-local state. - - Use `mktemp -d /tmp/t3code-test.XXXXXX` for disposable state and retain the printed absolute path. -3. Start the full web stack with `vp run dev`. Add `--share` when the user needs to open it from another tailnet device. In a linked worktree it defaults to that worktree's gitignored `.t3`; pass `--home-dir ` only when the test needs a different isolated directory. -4. Keep the terminal session alive and read the selected server port, web port, base directory, and pairing URL from its output. +Reuse this task's healthy dev server. Otherwise run `vp run dev` from the +repository root and retain its terminal session. Use the worktree's ignored +`.t3` state and read the actual ports and pairing URL from the dev-runner output. +Never run against `~/.t3/userdata` or set `VITE_HTTP_URL` or `VITE_WS_URL`. -Treat a base directory as disposable only when it was created or deliberately selected for the current test. Never delete or directly seed the shared `~/.t3` directory. Prefer starting with a new temporary base directory over clearing state of uncertain ownership. +Test with meaningful project and thread data. Read +[references/sqlite-fixtures.md](references/sqlite-fixtures.md) only when +inspecting or seeding SQLite. Stop the test server before direct fixture writes. -The worktree-local default deliberately outranks an ambient `T3CODE_HOME`; do not pass the shared home through to a worktree dev server. +## Use the Browser panel -Ports are derived from the worktree path but can shift when occupied. Always read the actual values from the `[dev-runner]` line. +Call `preview_status`, then `preview_open` if the Browser panel is +closed. Navigate to the complete startup pairing URL once with +`preview_navigate`, then use `preview_snapshot` and T3's interaction tools. +If the token was consumed or expired, run `node apps/server/src/bin.ts pair` +for a fresh one. Keep using the same tab. -Shared browser dev is single-origin: Vite proxies the backend paths, so never set `VITE_HTTP_URL` or `VITE_WS_URL` for `dev`/`dev:web`. +## Verify and retain -The dev runner disables browser auto-open by default. Do not pass `--browser` during automated testing: an automatically opened page can consume the one-time bootstrap token before the controlled browser uses it. +Exercise the affected flow and capture the state that proves it works. Keep +the server, state, and panel available while the user inspects or iterates. +An assistant turn ending is not teardown. Stop only processes you started, +using retained terminal sessions or captured PIDs. -### Verify a shared environment before human handoff - -When another person will use the printed pairing URL, first open the shared origin without the pairing path or fragment in the controlled browser and confirm the T3 Code app loads. This browser navigation is required even when curl succeeds because browsers block some otherwise reachable ports before making a network request. - -Do not open the other person's complete pairing URL during this reachability check; doing so consumes its one-time token. If the agent also needs an authenticated browser, create and consume a separate pairing token, then leave a fresh token for the other person. - -## Preserve the environment while iterating - -Treat the overall testing or implementation loop—not an assistant turn or one verification pass—as the environment lifecycle boundary. - -- Keep the dev process, base directory, selected ports, authenticated browser tab, registered projects, and seeded fixtures alive while the user may inspect the result or request follow-up changes. -- Do not stop the server merely because one verification pass completed or because you are yielding a response to the user. -- Before starting another environment, check whether the existing process and browser tab still serve the task. Reuse them when healthy instead of discarding useful state. -- On a later turn, verify that the existing process is alive and reuse its printed ports and base directory. If it exited, restart with the same base directory; create a new pairing token only when the browser session is no longer valid. -- Tell the user when a test environment remains available, including its non-secret web URL when useful. Include a pairing token only when the user still needs to pair (see below). - -## Authenticate the browser on the first navigation - -1. Wait for the server log that says authentication is required and includes a URL ending in `/pair#token=...`. -2. Use the controlled in-app browser or browser-automation surface available to the agent. Do not use a system-browser launch command during automated testing. -3. Open that complete URL exactly once as the controlled browser's first navigation. Preserve the fragment and token verbatim. -4. Wait for the pairing exchange and redirect to finish before navigating elsewhere. -5. Continue in the same browser context so its stored bearer session remains available. - -Keep pairing URLs out of screenshots, committed files, and durable logs. When the user asked for a shared environment, the deliverable IS the full pairing URL — paste it in your reply, token and all; a bare origin is useless to them. A pairing token is short-lived and single-use; opening the URL in another browser or opening it twice can consume it, so never open a URL you handed to the user. - -## Recover a consumed or expired pairing token - -Run `node apps/server/src/bin.ts pair` from the repository root. It discovers the running dev server (worktree `.t3` first, same precedence as the dev runner) and prints a fresh `Pair URL` against the server's current web origin, including a `--share` tailnet origin. Pass `--base-dir ` only when the server was started with `--home-dir`, using the identical path. - -Tokens from `pair` carry standard client scopes. The startup pairing URL carries admin scopes; if the user needs Settings → Connections management (`access:write`), restart the server and hand over the new startup URL instead. - -## Inspect or seed SQLite state - -Read [references/sqlite-fixtures.md](references/sqlite-fixtures.md) before changing the database. - -- Use `node apps/server/scripts/t3-sqlite-state.ts query` for schema discovery and read-only checks. -- Stop the dev server before using `node apps/server/scripts/t3-sqlite-state.ts exec`, then restart it with the same base directory. -- Seed projection tables only for disposable UI fixtures. Use application commands and APIs when testing business behavior or projection correctness. -- Use the auth CLI, not direct `auth_*` table edits, for pairing and sessions. - -The helper refuses to write to the shared `~/.t3` directory by default and creates a database backup before each mutation. - -## Tear down only when the testing loop is finished - -Tear down when the user explicitly asks, confirms the iteration is finished, or the overall task is genuinely complete with no pending human review. Do not infer completion from the end of an assistant turn. - -When teardown is appropriate: - -1. Stop the dev process with its terminal interrupt. -2. Preserve the isolated base directory when it contains useful reproduction evidence or state for a likely follow-up. -3. Otherwise remove only a path created for this test after resolving and verifying the exact target. - -If completion is uncertain, keep the environment alive and mention that it is retained for further iteration. A fresh isolated base directory remains the safest reset when authentication, migrations, or fixture state becomes ambiguous. - -## Troubleshoot predictably - -- If the browser shows an unauthenticated pairing screen, issue a new token instead of retrying the consumed URL. -- If the pairing URL is no longer visible, create a replacement token with both `--dev-url` and `--base-url`. -- If the replacement token is rejected, verify that the CLI and server use the identical absolute base directory and web URL. -- If the UI shows unexpected data, verify that every command uses the identical explicit base directory before editing anything. -- If ports move because another instance is running, trust the current dev-runner output rather than assuming ports `13773` and `5733`. +When sharing is requested, start with `vp run dev --share` and give the user +a fresh complete pairing URL that you have not consumed. Keep other credentials +out of screenshots, commits, and replies. diff --git a/.agents/skills/test-t3-app/agents/openai.yaml b/.agents/skills/test-t3-app/agents/openai.yaml index 0445ee4cb9ec1c2ba8838da9e9d665a27ae6dc4b..2f161a27ee0bff206e1471f093c16950f5a85adf 100644 --- a/.agents/skills/test-t3-app/agents/openai.yaml +++ b/.agents/skills/test-t3-app/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "T3 App Testing" - short_description: "Launch and retain isolated T3 test environments" - default_prompt: "Use $test-t3-app to launch an isolated T3 environment and iteratively test it in the browser while preserving state." + short_description: "Test web and desktop in T3's Browser panel" + default_prompt: "Use $test-t3-app to verify the affected web or desktop flow through T3's Browser panel." diff --git a/.agents/skills/test-t3-mobile/SKILL.md b/.agents/skills/test-t3-mobile/SKILL.md index afebcb7aa7d53b121bf86a3e90b96f45b770000d..1222449cd8a60d4dc9d3b837899d626813156b35 100644 --- a/.agents/skills/test-t3-mobile/SKILL.md +++ b/.agents/skills/test-t3-mobile/SKILL.md @@ -1,190 +1,65 @@ --- name: test-t3-mobile -description: Launch and test T3 Code Mobile on an iOS Simulator or Android Emulator against disposable local T3 environments, including Metro and dev-client reuse, native rebuild decisions, per-client pairing, seeded projects, semantic UI control, screenshots, and iOS serve-sim streaming. Use after mobile UI or native changes, when reproducing phone or tablet behavior, pairing an emulator to isolated state, or verifying mobile behavior on macOS, Linux, or Windows. +description: Test T3 Code's native iOS and Android app through its Device panel and returned AgentDevice command. Use for mobile verification, native-client builds, Metro launch, and mobile pairing against isolated development state. --- # Test T3 Mobile -Run one focused, end-to-end mobile verification pass against disposable T3 state. Use the sibling [`test-t3-app`](../test-t3-app/SKILL.md) skill as the detailed reference for pairing-token semantics and SQLite fixtures. +## Open the device -Command examples use POSIX shell syntax. On Windows, use PowerShell equivalents: set variables with `$env:NAME = "value"`, use an explicit temporary directory from `[System.IO.Path]::GetTempPath()`, and run multiline examples on one line or with PowerShell backticks. Use `$env:ANDROID_HOME\platform-tools\adb.exe` when `adb` is not already on `PATH`. +Call `device_list`, then `device_open` with the selected host and device IDs. +T3 boots the device and shows its live stream in the Device panel. Follow its +returned `quickStart`, using the exact `agentDevice.command` and all `targetArgs` +on every operation. Use `device_screenshot` to inspect the screen. -## Select a viable platform +If T3 device tools or the selected device are unavailable, report the blocker +and stop verification. Do not install or switch to another automation system. -Inspect the host and the affected code before launching processes: +## Use an isolated backend -- On macOS with Xcode, prefer one representative iOS Simulator when the change is cross-platform so the user can watch through serve-sim. Load and follow [`ios-debugger-agent`](../ios-debugger-agent/SKILL.md), and load [`ios-simulator-browser`](../ios-simulator-browser/SKILL.md) when live streaming is available. -- On macOS, Linux, or Windows with the Android SDK, use one Android Emulator when Android is the affected surface or iOS tooling is unavailable. -- When the change is platform-specific, test that platform. When neither platform is viable, report the missing SDK or emulator prerequisite rather than claiming verification. A missing development client is a build step, not a blocker. +Reuse this task's healthy backend. Otherwise run `vp run dev` from the +repository root, retain its terminal session, and read the actual backend port +from the dev-runner output. Use the worktree's ignored `.t3` state. Never run +against `~/.t3/userdata`. The Browser panel is not required for this workflow. -Do not treat unavailable iOS tooling as a blocker when Android is a valid representative target. +Test with meaningful project and thread data. Read the shared +[SQLite fixture reference](../test-t3-app/references/sqlite-fixtures.md) only +when inspecting or seeding SQLite. Stop the test server before fixture writes. -## Ensure a compatible native client +## Launch T3 Code Dev -Authorized mobile verification includes building and installing a development client. A missing, stale, or unknown native client is not a reason to skip verification or leave a PR in draft. Build and install it, then continue. Respect an explicit user instruction not to rebuild; otherwise do not ask for separate permission. - -Run this from the checkout being tested, on the machine that hosts the selected simulator or emulator. Select and boot one explicit iOS UDID or Android emulator serial first: - -```bash -node scripts/mobile-native-client.ts ensure ios -node scripts/mobile-native-client.ts ensure android -``` - -`ensure` compares the checkout's local Expo development fingerprint and the installed app's binary contents against the last successful build record. It reuses a matching client; otherwise it runs a clean prebuild, builds and installs the development app, and records the successful result. It does not start Metro. Start Metro below after it succeeds. On hosts with an `agent-job` requirement, run the entire `ensure` command through that queue. - -For a read-only decision, use `check` in place of `ensure`. Exit 0 means compatible, 2 means build required, and 1 means an operational error. An app installed outside this helper is initially unknown and gets rebuilt once. Records are local to the simulator host under `~/.cache/t3code/native-clients` and work across checkouts. Do not copy records between machines or write them manually. - -A JavaScript-only diff, bundle identifier, app version, or recent install date does not prove native compatibility. Always check the whole checkout. Expo fingerprints are computed locally with `APP_VARIANT=development`; no EAS credentials or cloud build are required. Generated `ios/` and `android/` directories are excluded by `.fingerprintignore`, so edit native source modules or config plugins rather than generated output. - -The development identity is `T3 Code Dev`, bundle/package `com.t3tools.t3code.dev`, scheme `t3code-dev`. If a build fails, investigate the build error and fix the local prerequisites. Report the concrete failure if it cannot be resolved, not “no compatible client.” - -## Start one disposable T3 environment - -Run backend commands from the repository root. Use the ignored, worktree-local `.t3` directory or create a fresh directory with the host OS's temporary-directory mechanism. An explicit base directory stores state in `/userdata`; never point testing at shared `~/.t3` state. - -Seed a small number of meaningful Git projects before starting the backend: - -```bash -node apps/server/src/bin.ts project add \ - --base-dir \ - --title -``` - -Running `project add` before the backend starts gives it exclusive offline database access. If a backend is already running, wait until it is ready so the CLI dispatches through the live server; never run offline mutations concurrently with the server. - -Use direct SQLite mutation only for disposable projection fixtures. Follow `test-t3-app` and stop the backend before writing. - -Start a headless backend after seeding: - -```bash -node apps/server/src/bin.ts serve \ - --host 127.0.0.1 \ - --port \ - --base-dir \ - --no-browser -``` - -Use these client origins: - -- iOS Simulator: `http://127.0.0.1:` -- Android Emulator: `http://10.0.2.2:` -- Physical device: bind the backend to `0.0.0.0` and use the host's reachable LAN origin - -Enter the complete `http://` origin to make the test transport explicit. Bare IP addresses default to HTTP, while bare hostnames default to HTTPS. When testing web and mobile together, run `vp run dev --home-dir --host 127.0.0.1` instead and do not launch a second backend over the same base directory. - -## Start or reuse Metro safely - -Run Metro from `apps/mobile`. - -1. Inspect any process on the intended Metro port and its `/status` response. Reuse it only when it is healthy, belongs to this worktree, and matches `APP_VARIANT=development`, `--dev-client`, and scheme `t3code-dev`. -2. Never kill another worktree's Metro. Use a free explicit port when necessary. -3. Run `vp run dev:client` on the standard port. For another port, retain the complete development identity: - - ```bash - APP_VARIANT=development vp exec expo start \ - --dev-client \ - --scheme t3code-dev \ - --lan \ - --port - ``` - - In PowerShell, set `$env:APP_VARIANT = "development"` first and then run the `vp exec expo start ...` command without the leading assignment. - -4. Open the exact development-client URL for the selected device and confirm the loaded bundle belongs to this worktree and Metro port. - -### iOS launch - -Use `ios-debugger-agent` to select one UDID and set these XcodeBuildMCP session defaults: - -- Workspace: `/apps/mobile/ios/T3CodeDev.xcworkspace` -- Scheme: `T3CodeDev` -- Configuration: `Debug` -- Simulator ID: the selected UDID -- Bundle ID: `com.t3tools.t3code.dev` - -After `ensure` succeeds, open the Metro URL: +From the checkout being tested on the selected device host, run: ```bash -xcrun simctl openurl +node scripts/mobile-native-client.ts ensure ``` -Accept the iOS confirmation prompt and dismiss the developer menu when it obscures the app. +This reuses a matching native client or builds and installs one. Authorized +mobile verification includes that build step unless the user prohibits it. -### Android launch - -Use the emulator serial already checked by `ensure`: - -```bash -adb -s reverse tcp: tcp: -adb -s shell am start -W \ - -a android.intent.action.VIEW \ - -d '' \ - com.t3tools.t3code.dev -``` +Start `vp run dev:client` from `apps/mobile`, or reuse a healthy Metro belonging +to this checkout. Open its printed development-client URL with AgentDevice +`open com.t3tools.t3code.dev ` and all returned target arguments. +The device must be able to reach both Metro and the isolated backend. -Do not start, stop, erase, or reconfigure an emulator owned by another task. Track and later stop only processes owned by this test. +## Pair and verify -## Pair each client once - -Use the bundled helper from the repository root. It issues a fresh credential against the running backend's exact base directory, opens the existing Add Environment route with the credential in an encoded query parameter, and asks that route to connect once: +Use the helper from the repository root, with the returned executable and target +arguments stored in `agent_device_command` and the Bash array +`agent_device_target_args`: ```bash .agents/skills/test-t3-mobile/scripts/pair-client.sh \ - ios - -.agents/skills/test-t3-mobile/scripts/pair-client.sh \ - android -``` - -Run only the command for the selected platform. The helper uses `http://127.0.0.1:` for iOS and `http://10.0.2.2:` for Android. Pass a fifth argument only when testing a non-development URL scheme. - -The helper opens this registered route: - -```text -t3code-dev://connections/new?pairingUrl=&autoConnect=1 + \ + "$agent_device_command" "${agent_device_target_args[@]}" ``` -The Add Environment route owns the behavior: `pairingUrl` prefills its normal host and token inputs, while `autoConnect=1` submits once in development builds and returns to Home after success. Without `autoConnect`, the same route only prefills the form for manual inspection. - -Do not enter pairing hosts or tokens through simulator keyboard automation. Xcode's semantic typer sends HID-style key events through the simulator's active keyboard state, which can corrupt uppercase tokens and punctuation even when the host Mac uses a U.S. input source. The one-shot route is the deterministic pairing path. Use the visible form only as a fallback, and paste credentials rather than typing them character by character. - -Verify the expected seeded projects appear before exercising the affected flow. - -Pairing credentials are secret, short-lived, and single-use. Create a different credential for every simulator, emulator, physical device, or browser. If an attempt fails, issue a new credential rather than retrying the old one. Do not expose tokens in screenshots, commits, or final responses. - -## Drive and observe the affected flow - -### iOS - -Use `snapshot_ui` and current element references from XcodeBuildMCP for taps and typing. Stream the same UDID through `ios-simulator-browser` so the user can watch in T3 Code when the host supports it. Use the stream as a visual feed rather than a reason to switch to fragile browser coordinates. - -### Android - -Prefer semantic Android automation exposed by the current agent host. Otherwise inspect the current hierarchy with `adb shell uiautomator dump`, target stable resource IDs, content descriptions, text, or bounds, and use scoped `adb shell input` actions. Refresh the hierarchy after navigation. Capture the final state with `adb exec-out screencap -p`. - -Android does not use serve-sim. Use a browser-compatible Android mirror when the host already provides one; otherwise return focused emulator screenshots as evidence rather than installing unrelated streaming infrastructure during verification. - -## Verify and clean up - -Exercise only the affected flow on one representative device unless the change specifically concerns platform, OS version, or screen size. Before finishing: - -1. Confirm the app connected to the intended disposable environment instead of merely rendering an empty disconnected state. -2. Capture the relevant final state. -3. Remove the disposable environment from T3 Code Dev. -4. Remove any `adb reverse` rule created for this test with `adb -s reverse --remove tcp:`. -5. Stop only the serve-sim, Metro, backend, emulator, and log processes started by this test. -6. Remove only base directories and temporary Git repositories deliberately created for this test. Preserve them when they contain useful reproduction evidence. - -Keep local verification focused. Do not turn this workflow into a full repository test run. - -## Troubleshoot predictable failures +It issues a fresh credential and opens T3 Code Dev's existing pairing route +through AgentDevice. For a backend on the device host, use +`http://127.0.0.1:` on iOS or `http://10.0.2.2:` +on Android. For a remote backend, use its reachable origin. -- **Old UI or an old error appears:** verify Metro's worktree, variant, URL, and port before diagnosing the app. -- **Metro serves stale or invalid transforms after those checks:** stop the owned Metro process and run `vp run dev:client:reset` once on the standard port. For a custom port, add `--clear` to the complete explicit `expo start` command above. -- **The environment remains empty:** verify the platform-specific HTTP origin, use a fresh token, and confirm project seeding used the identical base directory. -- **A second client cannot pair:** pairing tokens are single-use; issue another token. -- **The pairing form opens but does not connect:** confirm the deep link uses the existing `connections/new` route, includes `autoConnect=1`, and carries a freshly minted encoded `pairingUrl`. -- **Pairing text changes case or punctuation:** do not retry semantic typing. Use `scripts/pair-client.sh`; the simulator keyboard layout and HID input path are not reliable for credentials. -- **iOS semantic actions fail:** set explicit XcodeBuildMCP defaults and refresh with `snapshot_ui`. -- **Android cannot reach Metro:** verify `adb reverse` for the exact Metro port and relaunch the development-client URL. -- **Android cannot reach the backend:** use `10.0.2.2`, not `127.0.0.1`, for the Android Emulator. +Confirm the intended projects appear, exercise the affected flow, and capture +evidence. Retain the app and environment while iterating. At teardown, remove +the disposable connection, close the AgentDevice session, call `device_close`, +and stop only your backend and Metro processes. diff --git a/.agents/skills/test-t3-mobile/agents/openai.yaml b/.agents/skills/test-t3-mobile/agents/openai.yaml index e9518ce9e04ad964b4f9f67aad732709ec553843..bda3335f47e561be3e841f91a1d6401bf3d14d51 100644 --- a/.agents/skills/test-t3-mobile/agents/openai.yaml +++ b/.agents/skills/test-t3-mobile/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "Test T3 Mobile" - short_description: "Test T3 Code on iOS or Android" - default_prompt: "Use $test-t3-mobile to launch T3 Code against an isolated backend and verify the affected flow on an available simulator or emulator." + short_description: "Test iOS and Android in T3's Device panel" + default_prompt: "Use $test-t3-mobile to verify the affected native mobile flow through T3's Device panel and AgentDevice." diff --git a/.agents/skills/test-t3-mobile/scripts/pair-client.sh b/.agents/skills/test-t3-mobile/scripts/pair-client.sh index 9caa060728ec9c741dd0d891dcd5d7ea520a2dab..6eeb14844a65156b3d4d6d47d48f4869ecae95a3 100755 --- a/.agents/skills/test-t3-mobile/scripts/pair-client.sh +++ b/.agents/skills/test-t3-mobile/scripts/pair-client.sh @@ -3,29 +3,17 @@ set -euo pipefail usage() { - echo "Usage: $0 [url-scheme]" >&2 + echo "Usage: $0 " >&2 exit 2 } -[[ $# -ge 4 && $# -le 5 ]] || usage +[[ $# -ge 5 ]] || usage -platform="$1" -device_id="$2" -server_port="$3" -base_dir="$4" -url_scheme="${5:-t3code-dev}" - -case "$platform" in - ios) - mobile_origin="http://127.0.0.1:${server_port}" - ;; - android) - mobile_origin="http://10.0.2.2:${server_port}" - ;; - *) - usage - ;; -esac +server_port="$1" +base_dir="$2" +mobile_origin="$3" +agent_device_command="$4" +shift 4 repo_root="$(git rev-parse --show-toplevel)" cd "$repo_root" @@ -35,7 +23,7 @@ if ! pairing_output="$({ --base-dir "$base_dir" \ --base-url "$mobile_origin" \ --ttl 15m \ - --label "agent-mobile-${device_id:0:8}" + --label "agent-mobile" } 2>&1)"; then echo "Could not mint a mobile pairing credential." >&2 exit 1 @@ -47,26 +35,19 @@ if [[ -z "$pairing_url" ]]; then exit 1 fi -deep_link="$(PAIRING_URL="$pairing_url" URL_SCHEME="$url_scheme" node - <<'NODE' +deep_link="$(PAIRING_URL="$pairing_url" node - <<'NODE' const query = new URLSearchParams({ pairingUrl: process.env.PAIRING_URL, autoConnect: "1", }); -process.stdout.write(`${process.env.URL_SCHEME}://connections/new?${query}`); +process.stdout.write(`t3code-dev://connections/new?${query}`); NODE )" -case "$platform" in - ios) - xcrun simctl openurl "$device_id" "$deep_link" - ;; - android) - # adb shell re-joins its arguments and evaluates them through the device - # shell, so the deep link's `?`/`&` must be quoted once more for that shell. - adb -s "$device_id" shell \ - "am start -W -a android.intent.action.VIEW -d '$deep_link' com.t3tools.t3code.dev" \ - >/dev/null - ;; -esac +if ! "$agent_device_command" open com.t3tools.t3code.dev "$deep_link" "$@" \ + >/dev/null 2>&1; then + echo "AgentDevice could not open the pairing route. Check the Device panel and retry with a fresh credential." >&2 + exit 1 +fi echo "Opened the existing Add Environment route with a fresh pairing credential." diff --git a/.codex/config.toml b/.codex/config.toml deleted file mode 100644 index a6369d240fc773e5be2d72f0bade9ca1649e9b62..0000000000000000000000000000000000000000 --- a/.codex/config.toml +++ /dev/null @@ -1,9 +0,0 @@ -[mcp_servers.xcodebuildmcp] -enabled = true -required = false -command = "npx" -args = ["--yes", "xcodebuildmcp@2.6.2", "mcp"] -startup_timeout_sec = 20.0 - -[mcp_servers.xcodebuildmcp.env] -XCODEBUILDMCP_ENABLED_WORKFLOWS = "simulator,ui-automation,debugging,logging" diff --git a/.mcp.json b/.mcp.json deleted file mode 100644 index 213a64995fab64418fdac0ab827a40c7f44540e7..0000000000000000000000000000000000000000 --- a/.mcp.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "mcpServers": { - "xcodebuildmcp": { - "command": "npx", - "args": ["--yes", "xcodebuildmcp@2.6.2", "mcp"], - "env": { - "XCODEBUILDMCP_ENABLED_WORKFLOWS": "simulator,ui-automation,debugging,logging" - } - } - } -} -- 2.54.0