@loadmill/droid-cua 2.24.0 → 2.26.0

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 (46) hide show
  1. package/README.md +13 -5
  2. package/build/index.js +206 -2
  3. package/build/src/cli/cloud-status-line.js +58 -26
  4. package/build/src/cli/headless-runner.js +2 -1
  5. package/build/src/cli/headless-target.js +63 -7
  6. package/build/src/cli/loadmill-cloud-credentials.js +11 -0
  7. package/build/src/cli/loadmill-cloud-usage.js +18 -0
  8. package/build/src/commands/help.js +2 -0
  9. package/build/src/commands/run.js +5 -3
  10. package/build/src/core/cua-models.js +16 -0
  11. package/build/src/core/droid-cua-run-usage.js +8 -2
  12. package/build/src/core/execution-engine.js +8 -1
  13. package/build/src/core/runtime-config.js +8 -3
  14. package/build/src/core/session.js +2 -2
  15. package/build/src/core/tool-handlers/close-keyboard.js +103 -0
  16. package/build/src/device/actions.js +7 -0
  17. package/build/src/device/android/actions.js +16 -0
  18. package/build/src/device/cloud/actions.js +27 -0
  19. package/build/src/device/cloud/aws-device-farm/upload-cache.js +1 -1
  20. package/build/src/device/cloud/cloud-appium-client.js +15 -0
  21. package/build/src/device/cloud/connection.js +18 -6
  22. package/build/src/device/cloud/loadmill-cloud/adapter.js +537 -0
  23. package/build/src/device/cloud/loadmill-cloud/artifact-downloader.js +191 -0
  24. package/build/src/device/cloud/loadmill-cloud/control-plane-client.js +423 -0
  25. package/build/src/device/cloud/loadmill-cloud/errors.js +16 -0
  26. package/build/src/device/cloud/loadmill-cloud/format-bytes.js +18 -0
  27. package/build/src/device/cloud/loadmill-cloud/timing.js +14 -0
  28. package/build/src/device/cloud/progress.js +29 -0
  29. package/build/src/device/cloud/registry.js +2 -1
  30. package/build/src/device/connection.js +8 -2
  31. package/build/src/device/factory.js +3 -0
  32. package/build/src/device/interface.js +4 -0
  33. package/build/src/device/ios/actions.js +13 -0
  34. package/build/src/device/ios/appium-client.js +16 -0
  35. package/build/src/device/keyboard.js +119 -0
  36. package/build/src/device/openai.js +20 -1
  37. package/build/src/modes/design-mode-ink.js +1 -0
  38. package/build/src/modes/design-mode.js +1 -0
  39. package/build/src/modes/execution-mode.js +88 -16
  40. package/build/src/prompts/base.js +29 -4
  41. package/build/src/prompts/execution.js +14 -3
  42. package/package.json +1 -1
  43. package/skill/droid-cua/SKILL.md +6 -3
  44. package/skill/droid-cua/agents/openai.yaml +1 -1
  45. package/skill/droid-cua/references/project-and-auth.md +16 -13
  46. package/skill/droid-cua/references/running-and-healing.md +45 -5
@@ -1,4 +1,5 @@
1
1
  import { DEFAULT_AIM_ASSIST_MODE } from "../core/aim-assist.js";
2
+ import { CUA_CONVERSATION_POLICIES, resolveConversationPolicy } from "../core/cua-models.js";
2
3
  import { normalizeSecretKeys } from "../core/secrets.js";
3
4
  import { appendCustomSections, buildBaseSystemPrompt, isBrowserTarget } from "./base.js";
4
5
  export function buildAppContextSection(text) {
@@ -43,10 +44,14 @@ export function buildExecutionModePrompt(deviceInfo, customInstructions = {}, ap
43
44
  const testDataContextSection = buildTestDataContextSection(options.testDataContext);
44
45
  const secretKeysContextSection = buildSecretKeysContextSection(options.availableSecretKeys);
45
46
  const browserTarget = isBrowserTarget(deviceInfo);
47
+ const conversationPolicy = resolveConversationPolicy(options.cuaModel);
48
+ const instructionContextRule = conversationPolicy === CUA_CONVERSATION_POLICIES.ISOLATED
49
+ ? "This model starts each instruction without prior model history. Execute only the current instruction and stop when it is complete."
50
+ : "Instructions are sequential parts of one scenario. Use prior instructions and outcomes to resolve references in the current instruction, but execute only the current instruction. Preserve expected values established earlier; never replace them with the observed state merely to produce a pass.";
46
51
  const prompt = `${basePrompt}
47
52
 
48
53
  EXECUTION MODE - Critical Behavior:
49
- You are executing test script commands one at a time. This is NOT a conversation.
54
+ You are executing test script commands one at a time. This is an automated test run, not a chat with the user.
50
55
 
51
56
  CRITICAL RULES:
52
57
  - DO NOT generate conversational text or narration
@@ -70,14 +75,20 @@ Your process:
70
75
  - Before calling \`assert\`, make sure the current screen contains the evidence needed to validate the condition. If needed, perform only minimal preparation first, such as taking a screenshot, waiting briefly, closing the keyboard, scrolling within the relevant view, or opening the relevant menu.
71
76
  - Once you call \`assert\`, validation is read-only. The assertion tool will not click, type, wait, scroll, request screenshots, or change the device state.
72
77
  - Use \`navigate\` for direct browser navigation instead of trying to manipulate the address bar
78
+ ${browserTarget ? "" : ` - Every \`type\` action must end its computer-action batch so you can inspect the post-type screenshot
79
+ - Call \`close_keyboard\` next when a full software keyboard is visible, or after typing into an iOS secure field even when its keyboard is hidden
80
+ - Do not complete the current instruction while that required \`close_keyboard\` action is pending
81
+ - Otherwise, including when only a slim hardware-keyboard toolbar or suggestions are visible, continue without \`close_keyboard\`
82
+ - Apply the same dismissal decision after \`type_sensitive_text\`
83
+ `}
73
84
  - Use the \`loadmill\` tool whenever the instruction explicitly references running or using a Loadmill flow. Pass the requested flow name/intent and parameters as the command; the tool will search Loadmill, select the best matching flow, run it, and wait for completion. Do not handle Loadmill by typing in the app UI.
74
85
  3. Execute the required actions
75
- 4. Before tapping a mutating action, dismiss the keyboard if it is open and not needed
86
+ 4. ${browserTarget ? "Before tapping a mutating action, dismiss the keyboard if it is open and not needed" : "Use `close_keyboard` before any later interaction when the post-type dismissal rules require it"}
76
87
  5. After a mutating action, inspect the resulting screen for success cues such as cleared fields, reset buttons, changed status, refreshed content, or navigation
77
88
  6. Stop as soon as success is visible
78
89
  7. Stop immediately - no commentary, no questions
79
90
 
80
- Each instruction is independent. Do not reference previous instructions or ask about next steps.
91
+ ${instructionContextRule}
81
92
  ${appContextSection ? `\n\n${appContextSection}` : ""}${testDataContextSection ? `\n\n${testDataContextSection}` : ""}${secretKeysContextSection ? `\n\n${secretKeysContextSection}` : ""}`;
82
93
  return appendCustomSections(prompt, [
83
94
  { title: "Base Prompt Instructions", text: customInstructions.basePromptInstructions },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loadmill/droid-cua",
3
- "version": "2.24.0",
3
+ "version": "2.26.0",
4
4
  "description": "AI-powered Android testing agent using OpenAI's computer-use model and ADB",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: droid-cua
3
- description: Write, run, monitor, and troubleshoot Droid CUA mobile and web tests. Use when an agent needs to onboard @loadmill/droid-cua, configure Loadmill authentication, discover Android devices or AVDs, prepare iOS simulators or local browsers, author or revise .dcua tests and project context, run tests locally or on supported cloud devices, analyze reports and debug artifacts, distinguish test failures from product bugs, or perform guarded test healing.
3
+ description: Operate Droid CUA `.dcua` test projects. Use when the user explicitly names Droid CUA or @loadmill/droid-cua, or asks to author, configure, run, or diagnose `.dcua` tests with the Droid CUA CLI or desktop app. Do not use for general web browsing, website development, browser automation, generic mobile work, or non-Droid test tasks.
4
4
  ---
5
5
 
6
6
  # Droid CUA
@@ -13,13 +13,16 @@ Use the existing `droid-cua` CLI and repository files. Do not invent commands, f
13
13
  2. Determine the requested platform and target from the task or project. Ask the user only when the choice is unclear.
14
14
  3. Check authentication and environment readiness before the first run. Read [project-and-auth.md](references/project-and-auth.md) for project boundaries and token handling. Read [onboarding-and-troubleshooting.md](references/onboarding-and-troubleshooting.md) when setup, dependency, device, simulator, browser, or connection work is needed.
15
15
  4. Author or update the smallest useful test. Read [authoring-tests.md](references/authoring-tests.md) before changing `.dcua`, context, test data, secrets, or config.
16
- 5. Run the narrowest relevant test and monitor it to completion. Read [running-and-healing.md](references/running-and-healing.md) for commands, targets, artifacts, failure classification, and guarded healing.
17
- 6. Report the outcome, evidence paths, changes made, and whether the failure belongs to the test, environment, or product.
16
+ 5. Before execution, present the proposed tests and target to the user, resolve any questions, and get their confirmation. Read [running-and-healing.md](references/running-and-healing.md) for the required pre-run check.
17
+ 6. Run the confirmed, narrowest relevant test and monitor it to completion. Keep the user oriented during the run by surfacing meaningful live screenshots, not just terminal output.
18
+ 7. Report the outcome, evidence paths, changes made, and whether the failure belongs to the test, environment, or product.
18
19
 
19
20
  ## Safety
20
21
 
21
22
  - Never print, open, or echo secret values. Check only whether required keys are configured.
22
23
  - Never search for credentials outside the active test project or source another project's `.env` file.
24
+ - Use Loadmill for every run unless the user explicitly asks to use their own OpenAI API key. A discovered OpenAI key is never permission to switch providers.
25
+ - Never use credentials from another project, a skill, an agent configuration, or the user's home directory. Configure credentials only in the active test project's `.env` (or an explicitly supplied CI secret).
23
26
  - Get approval before installing dependencies, running `sudo`, accepting licenses, or changing system configuration.
24
27
  - During setup, do not create or edit user tests. Rerun only the failed readiness check, then resume the original task.
25
28
  - During healing, edit only `.dcua`, `context.md`, `test-data.md`, or Droid CUA config. Never modify application code under the guise of healing a test.
@@ -1,6 +1,6 @@
1
1
  interface:
2
2
  display_name: "Droid Cua"
3
- short_description: "Write, run, monitor, and troubleshoot Droid CUA tests"
3
+ short_description: "Operate Droid CUA .dcua test projects"
4
4
  icon_small: "./assets/droid-cua-app-icon.png"
5
5
  icon_large: "./assets/droid-cua-app-icon.png"
6
6
  brand_color: "#1895F7"
@@ -15,24 +15,27 @@ Keep `.env` and `.secrets` out of version control. Use `git check-ignore -q .env
15
15
 
16
16
  ## Loadmill authentication
17
17
 
18
- Loadmill is the default LLM provider. Before a run, check only for presence:
18
+ Loadmill is the required default LLM provider. Use it unless the user explicitly asks to use their own OpenAI API key. Never switch to OpenAI because a Loadmill token is missing or because an OpenAI key happens to be available.
19
+
20
+ Before a run, check only for the presence of a Loadmill token in the active test project's `.env` or explicitly supplied CI secret:
19
21
 
20
22
  ```sh
21
- test -n "${LOADMILL_API_TOKEN:-}" || grep -Eq '^LOADMILL_API_TOKEN=.+$' .env 2>/dev/null
23
+ grep -Eq '^LOADMILL_API_TOKEN=.+$' .env 2>/dev/null
22
24
  ```
23
25
 
24
- Run this check from the active test project's working directory. Do not print the variable, run `env`, open `.env`, or ask the user to paste the token. Do not search parent directories, sibling repositories, the user's home directory, or the Droid CUA source repository for credentials.
26
+ Run this check from the active test project's working directory. Do not print the variable, run `env`, open `.env`, or inspect inherited environment variables. Do not search parent directories, sibling repositories, the user's home directory, agent skills/configuration, or the Droid CUA source repository for credentials.
27
+
28
+ If it is missing, explain that Droid CUA uses a Loadmill token by default and guide the user to:
29
+
30
+ 1. Sign in, then open [Loadmill Settings → Security](https://app.loadmill.com/app/user/settings/security).
31
+ 2. Create an API token with a description such as `Droid CUA CLI`.
32
+ 3. Copy it when shown; Loadmill shows it once.
25
33
 
26
- If it is missing, instruct the user to:
34
+ Offer exactly these two choices, then wait for the user's selection:
27
35
 
28
- 1. Sign in at <https://app.loadmill.com>.
29
- 2. Open **Settings → Security**.
30
- 3. Create an API token with a description such as `Droid CUA CLI`.
31
- 4. Copy it when shown; Loadmill shows it once.
32
- 5. Ensure `.env` is ignored by version control before storing a project token; add `.env` to `.gitignore` if needed.
33
- 6. Save it as `LOADMILL_API_TOKEN=...` in the active test project's `.env`, a shell environment variable, or a CI secret.
34
- 7. Confirm when configuration is complete, without sharing the value.
36
+ 1. **Use it once:** The user provides the token through the agent's secret-input mechanism and asks to use it for this run only. Pass it only to that command through a secret-safe mechanism; do not write it to `.env`, a shell profile, or any other file.
37
+ 2. **Save it for this project:** The user provides the token through the agent's secret-input mechanism and approves saving it. Create the active project's `.env` if needed or add/update only its `LOADMILL_API_TOKEN` entry. First ensure `.env` is ignored by version control; add `.env` to the active project's `.gitignore` when needed.
35
38
 
36
- Do not create or populate the token value for the user. Do not copy a token from another file or source another project's `.env`. Sourcing an unrelated file can import development endpoints, proxy settings, and unrelated secrets. When the active project's `.env` contains the key, run `droid-cua` normally from that project; the CLI loads that file automatically.
39
+ Use a secret-safe mechanism that does not print or expose the value in commands, logs, or responses. Verify only that the key is present. Never copy a token from another file, a shell profile, another project, an agent skill/configuration, or any other location. Do not inspect inherited environment variables to discover a token. When the active project's `.env` contains the key, run `droid-cua` normally from that project; the CLI loads that file automatically.
37
40
 
38
- If the user explicitly selects direct OpenAI access, use `--llm-provider openai` with one of the supported OpenAI CUA models: `gpt-5.6-terra`, `gpt-5.6-luna`, or `gpt-5.4`. Check only for the presence of `OPENAI_API_KEY`. If it is missing, instruct the user to create an API key in their OpenAI account and save it in the active project's gitignored `.env`, their shell environment, or a CI secret. Apply the same secret-handling rules: never request, print, inspect, copy, or source the key. Do not silently switch providers to bypass missing Loadmill authentication.
41
+ Only when the user explicitly selects direct OpenAI access, use `--llm-provider openai` with one of the supported OpenAI CUA models: `gpt-5.6-terra`, `gpt-5.6-luna`, or `gpt-5.4`. Check only the active project's `.env` for `OPENAI_API_KEY`; do not use one found elsewhere. If it is missing, guide the user to create and configure their own key in the same project using the same secret-safe process. Do not silently switch providers to bypass missing Loadmill authentication.
@@ -2,19 +2,19 @@
2
2
 
3
3
  ## Construct the run
4
4
 
5
- Prefer a single test before a directory or scenario run. Preserve an existing provider/model choice in `ci/droid-cua.json`; otherwise use the Loadmill provider. Use Loadmill Smart as the recommended default, or Loadmill Beacon when the user prioritizes faster, lower-cost execution:
5
+ Prefer a single test before a directory or scenario run. Preserve an existing provider/model choice in `ci/droid-cua.json`; otherwise use the Loadmill provider. Use Loadmill Smart as the recommended default, or Loadmill Pulse when the user prioritizes faster, lower-cost execution:
6
6
 
7
7
  ```sh
8
8
  # Recommended default
9
9
  --llm-provider loadmill --cua-model loadmill-smart
10
10
 
11
11
  # Faster, lower-cost option
12
- --llm-provider loadmill --cua-model loadmill-beacon
12
+ --llm-provider loadmill --cua-model loadmill-pulse
13
13
  ```
14
14
 
15
- Both Loadmill models require `LOADMILL_API_TOKEN`. Do not switch between Smart and Beacon silently; preserve the project's model or explain the speed/cost tradeoff and follow the user's choice. If the user chooses direct OpenAI access instead, require `OPENAI_API_KEY` and use `--llm-provider openai` with one of `gpt-5.6-terra`, `gpt-5.6-luna`, or `gpt-5.4`. Do not mix a provider with another provider's model, silently switch providers, or override an existing project choice without explaining it.
15
+ All Loadmill models require `LOADMILL_API_TOKEN`. Do not switch between Smart, Pulse, and Beacon silently; preserve the project's model or explain the capability, speed, and experimental tradeoffs and follow the user's choice. If the user chooses direct OpenAI access instead, require `OPENAI_API_KEY` and use `--llm-provider openai` with one of `gpt-5.6-terra`, `gpt-5.6-luna`, or `gpt-5.4`. Do not mix a provider with another provider's model, silently switch providers, or override an existing project choice without explaining it.
16
16
 
17
- Include `--report reports/<test-name>.html` for normal test runs unless the user opts out. Prefer an explicit filename over a directory so the result is easy to locate. Add `--debug` when diagnosis may be needed.
17
+ Include `--report reports/<test-name>.html` for normal test runs unless the user opts out. Prefer an explicit filename over a directory so the result is easy to locate. Add `--debug` for every agent-observed run: it writes the screenshots needed for live progress updates as well as diagnosis.
18
18
 
19
19
  ```sh
20
20
  # Attached Android device or running emulator
@@ -41,9 +41,49 @@ droid-cua --llm-provider openai --cua-model gpt-5.4 --avd adb:<serial> --instruc
41
41
 
42
42
  Use `.ipa` and `--platform ios` for supported cloud iOS runs. Preserve existing config flags rather than replacing them with defaults.
43
43
 
44
+ ## Confirm the run with the user
45
+
46
+ Before starting any test command, send the user a short, plain-language run plan and wait for explicit confirmation. Treat this as a product conversation, not a command preview. Do not infer that a request to run a test also confirms an automatically selected device, browser, or batch of tests.
47
+
48
+ The run plan should briefly state:
49
+
50
+ - What behavior or flow will be checked, and whether one test or several will run. Mention the test filename only when it helps identify the test.
51
+ - Where it will run: the chosen device, simulator, or browser. If more than one viable target is available, present the human-readable choices and ask the user to choose.
52
+ - Any user-visible consequence, such as launching an emulator, resetting a fresh browser session, or starting a metered cloud-device session.
53
+ - That the agent will share progress screenshots and provide a report afterward.
54
+
55
+ Do not include CLI flags, commands, provider or model names, credential/key names, config/context filenames, or internal log/report paths unless the user asks or one changes a decision they need to make. Do not paste the test source into the confirmation.
56
+
57
+ Ask the user about every unresolved or ambiguous choice before running. If the plan is complete, ask for a clear go-ahead (for example, `Ready to run this?`). Start only after they confirm. If they change the tests, target, or other material run detail, show the revised plan and confirm it again.
58
+
59
+ For example: `I’m ready to run the Chrome smoke test in a fresh local Chrome window. It will check that Chrome opens and then closes. I’ll share screenshots as it progresses and provide a report at the end. Ready to run this?`
60
+
44
61
  ## Monitor and collect evidence
45
62
 
46
- Remain attached until the command exits and cloud cleanup finishes. Read terminal progress as it appears; do not treat a long model step as success or failure before completion.
63
+ Remain attached until the command exits and cloud cleanup finishes. Run the command through an interactive/pollable terminal mechanism so progress and new artifacts can be observed before it exits. Read terminal progress as it appears; do not treat a long model step as success or failure before completion.
64
+
65
+ ## Show live visual progress
66
+
67
+ Use the screenshots already captured by `--debug` to make the run understandable while it is happening. This is a required user-facing behavior, not merely an artifact to inspect after the run. After the CLI prints `Debug logging enabled: <logs/execution-...>.jsonl`, new PNGs appear in that log file's sibling directory. Keep the CLI running in a pollable/background session and poll that directory while the test is running.
68
+
69
+ For agents whose chat UI renders local Markdown images (including Cursor and Codex), send a separate progress message containing an absolute-path image, for example:
70
+
71
+ ```md
72
+ Step 2/4: add the item to the cart
73
+
74
+ ![Live test progress](/absolute/path/to/logs/execution-.../0004_....png)
75
+ ```
76
+
77
+ Do not put this Markdown only in a terminal command, tool argument, or hidden reasoning: it must be an actual user-visible chat update. Do not replace it by opening the final report.
78
+
79
+ - After every completed executable instruction, send exactly one short progress update with that instruction and its screenshot (for example, `Step 2/4 complete: add the item to the cart`). An image path alone is not a visual update.
80
+ - Screenshot filenames include `instruction-001`, `instruction-002`, and so on. Select the latest safe PNG for the completed instruction; prefer an end-of-turn or assertion screenshot over an input or click-preview frame. This connects each user-visible update to the matching script step even when the model took several actions to finish it.
81
+ - Also show a frame immediately when the run is retrying, reconnecting, or fails. Do not stream every model action or repeat visually identical frames.
82
+ - Do not show `preview_click` / aim-assist annotations unless they help explain an issue.
83
+ - If the latest frame visibly exposes a secret or other sensitive user data, do not render it; provide a text-only progress update and wait for a safe frame.
84
+ - Do not delay the test to collect screenshots. If no new frame exists during a long model call, report the current stage in text and keep polling.
85
+
86
+ When the command completes, show the final safe screenshot in addition to the result summary, then provide a clickable link to the HTML report (or its absolute path when local links are unavailable). The report is the final artifact; the interim frames are progress updates, not a substitute for it.
47
87
 
48
88
  - Exit `0`: all requested tests passed.
49
89
  - Exit `1`: configuration, connection, execution, or assertion failure.