@1aboveio/skills 1.0.17 → 1.0.19

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 (99) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/.codex-plugin/resources.json +175 -141
  3. package/README.md +1 -1
  4. package/package.json +5 -4
  5. package/skills/app-dev/airflow/SKILL.md +1 -1
  6. package/skills/app-dev/android-development/SKILL.md +14 -12
  7. package/skills/app-dev/android-development/references/diagnosis.md +4 -6
  8. package/skills/app-dev/android-development/references/gotchas.md +3 -9
  9. package/skills/app-dev/android-development/references/init.md +5 -2
  10. package/skills/app-dev/android-development/references/setup.md +2 -1
  11. package/skills/app-dev/android-development/references/ui-journeys.md +12 -127
  12. package/skills/app-dev/android-development/scripts/failure_capture.py +23 -84
  13. package/skills/app-dev/android-development/scripts/init.mjs +2 -1
  14. package/skills/app-dev/android-development/scripts/maestro_failure.py +43 -387
  15. package/skills/app-dev/android-development/scripts/test_maestro_failure.py +113 -424
  16. package/skills/app-dev/app-debug/SKILL.md +1 -1
  17. package/skills/app-dev/better-auth/SKILL.md +1 -1
  18. package/skills/app-dev/data-catalog/SKILL.md +1 -1
  19. package/skills/app-dev/data-quality/SKILL.md +1 -1
  20. package/skills/app-dev/ios-foundation/SKILL.md +1 -1
  21. package/skills/app-dev/maestro/LICENSE +3 -0
  22. package/skills/app-dev/maestro/SKILL.md +112 -0
  23. package/skills/app-dev/maestro/references/android-connection.md +54 -0
  24. package/skills/app-dev/maestro/references/authoring.md +113 -0
  25. package/skills/app-dev/maestro/references/diagnosis.md +50 -0
  26. package/skills/app-dev/maestro/references/evidence.md +74 -0
  27. package/skills/app-dev/maestro/references/journeys.md +100 -0
  28. package/skills/app-dev/maestro/references/migration.md +35 -0
  29. package/skills/app-dev/maestro/release-check.mjs +95 -0
  30. package/skills/app-dev/maestro/scripts/failure_record.py +110 -0
  31. package/skills/app-dev/maestro/scripts/maestro_failure.py +481 -0
  32. package/skills/app-dev/maestro/scripts/test_maestro_failure.py +710 -0
  33. package/skills/app-dev/monorepo/SKILL.md +1 -1
  34. package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
  35. package/skills/app-dev/prisma-setup/SKILL.md +1 -1
  36. package/skills/app-dev/pyspark/SKILL.md +1 -1
  37. package/skills/app-dev/python-backend/SKILL.md +1 -1
  38. package/skills/app-dev/shadcn/SKILL.md +1 -1
  39. package/skills/app-dev/zod-v4/SKILL.md +1 -1
  40. package/skills/cicd/cloud-build/SKILL.md +1 -1
  41. package/skills/cicd/cloud-debug/SKILL.md +1 -1
  42. package/skills/cicd/cloud-deploy/SKILL.md +1 -1
  43. package/skills/cicd/docker/SKILL.md +1 -1
  44. package/skills/cicd/github-actions/SKILL.md +1 -1
  45. package/skills/cicd/github-flow/SKILL.md +1 -1
  46. package/skills/cicd/google-cloud/SKILL.md +1 -1
  47. package/skills/cicd/mergify/SKILL.md +1 -1
  48. package/skills/cicd/podman/SKILL.md +1 -1
  49. package/skills/content/article-review/SKILL.md +1 -1
  50. package/skills/content/article-to-image/SKILL.md +1 -1
  51. package/skills/content/flowchart-svg/SKILL.md +1 -1
  52. package/skills/content/image-gen/SKILL.md +1 -1
  53. package/skills/content/mermaid/SKILL.md +1 -1
  54. package/skills/content/wechat-article-writer/SKILL.md +1 -1
  55. package/skills/content/wechat-publisher/SKILL.md +1 -1
  56. package/skills/content/wechat-search/SKILL.md +1 -1
  57. package/skills/content/xai-search/SKILL.md +1 -1
  58. package/skills/core/distill-writing/SKILL.md +1 -1
  59. package/skills/core/doc-to-md/SKILL.md +1 -1
  60. package/skills/core/editorial-review/SKILL.md +1 -1
  61. package/skills/core/house-style/SKILL.md +1 -1
  62. package/skills/core/plain-language/SKILL.md +1 -1
  63. package/skills/core/polish-cn/SKILL.md +1 -1
  64. package/skills/core/reg-parser/SKILL.md +1 -1
  65. package/skills/core/terminology/SKILL.md +1 -1
  66. package/skills/core/write-doc/SKILL.md +1 -1
  67. package/skills/core/write-report/SKILL.md +1 -1
  68. package/skills/engineering/better-review/SKILL.md +1 -1
  69. package/skills/engineering/e2e-test/SKILL.md +1 -1
  70. package/skills/engineering/engineering/SKILL.md +1 -1
  71. package/skills/engineering/engineering-runtime/SKILL.md +1 -1
  72. package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
  73. package/skills/engineering/ensure-coverage/SKILL.md +1 -1
  74. package/skills/engineering/golden-path/SKILL.md +1 -1
  75. package/skills/engineering/harness-runtime/SKILL.md +1 -1
  76. package/skills/engineering/harness-runtime/agent-catalog.mjs +44 -11
  77. package/skills/engineering/harness-runtime/contracts.md +1 -1
  78. package/skills/engineering/resolve-issues/SKILL.md +4 -2
  79. package/skills/engineering/resolve-issues/references/preflight.md +17 -3
  80. package/skills/engineering/resolve-issues/references/retention.md +162 -0
  81. package/skills/engineering/resolve-issues/references/workspaces.md +40 -10
  82. package/skills/engineering/resolve-issues/scripts/daily-cleanup.mjs +169 -0
  83. package/skills/engineering/resolve-issues/scripts/resource-formats.mjs +625 -0
  84. package/skills/engineering/resolve-issues/scripts/retention-lock.mjs +548 -0
  85. package/skills/engineering/resolve-issues/scripts/retention-plans.mjs +57 -0
  86. package/skills/engineering/resolve-issues/scripts/retention.mjs +2314 -0
  87. package/skills/engineering/resolve-release/SKILL.md +1 -1
  88. package/skills/engineering/rush-issues/SKILL.md +1 -1
  89. package/skills/engineering/rush-release/SKILL.md +1 -1
  90. package/skills/engineering/test-quality/SKILL.md +1 -1
  91. package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
  92. package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
  93. package/skills/risk-compliance/contract-review/SKILL.md +1 -1
  94. package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
  95. package/skills/risk-compliance/fraud-detection/SKILL.md +1 -1
  96. package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
  97. package/skills/risk-compliance/portfolio-payment-analysis/SKILL.md +1 -1
  98. package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
  99. package/skills/risk-compliance/tld-detection/SKILL.md +1 -1
package/README.md CHANGED
@@ -52,7 +52,7 @@ See https://github.com/1aboveio/ai/blob/main/docs/native-codex.md for prerequisi
52
52
  | `core` | `@1aboveio/core-skills` | distill-writing, doc-to-md, editorial-review, house-style, plain-language, polish-cn, reg-parser, terminology, write-doc, write-report |
53
53
  | `engineering` | `@1aboveio/engineering-skills` | better-review, e2e-test, engineering, engineering-runtime, ensure-coverage, golden-path, harness-runtime, resolve-issues, resolve-release, rush-issues, rush-release, test-quality |
54
54
  | `cicd` | `@1aboveio/cicd-skills` | cloud-build, cloud-debug, cloud-deploy, docker, github-actions, github-flow, google-cloud, mergify, podman |
55
- | `app-dev` | `@1aboveio/app-dev-skills` | airflow, android-development, app-debug, better-auth, data-catalog, data-quality, ios-foundation, monorepo, nextjs-fullstack, prisma-setup, pyspark, python-backend, shadcn, zod-v4 |
55
+ | `app-dev` | `@1aboveio/app-dev-skills` | airflow, android-development, app-debug, better-auth, data-catalog, data-quality, ios-foundation, maestro, monorepo, nextjs-fullstack, prisma-setup, pyspark, python-backend, shadcn, zod-v4 |
56
56
  | `risk-compliance` | `@1aboveio/risk-compliance-skills` | compliance-audit, contract-compare, contract-review, doc-authenticity, fraud-detection, payment-analysis, portfolio-payment-analysis, similar-domain, tld-detection |
57
57
  | `content` | `@1aboveio/content-skills` | article-review, article-to-image, flowchart-svg, image-gen, mermaid, wechat-article-writer, wechat-publisher, wechat-search, xai-search |
58
58
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1aboveio/skills",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "description": "Every 1aboveio skill package in one: install once, then choose which packages Pi loads with npx @1aboveio/skills select.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -28,8 +28,8 @@
28
28
  "nativeCodex": {
29
29
  "schemaVersion": 1,
30
30
  "metadataPath": ".codex-plugin/resources.json",
31
- "metadataDigest": "4ae04aa79316f8a7cc9df45582d19e332321316012dac6843be1eb21d2b1a385",
32
- "releaseIdentity": "d4a51368dcc414b3136d3b6f51a6aeeeea77429a101eb65f36f7878e00032494"
31
+ "metadataDigest": "5214fae69e2323b56ca56e3e09a4d6d21dfb408ae7834a560b65cac2efbb51f3",
32
+ "releaseIdentity": "6f7be7f9699ae9d9480689971e5cb8ea88e5d8f460618fe153a4ca8b7ad4347a"
33
33
  },
34
34
  "pi": {
35
35
  "skills": [
@@ -110,6 +110,7 @@
110
110
  "data-catalog",
111
111
  "data-quality",
112
112
  "ios-foundation",
113
+ "maestro",
113
114
  "monorepo",
114
115
  "nextjs-fullstack",
115
116
  "prisma-setup",
@@ -260,7 +261,7 @@
260
261
  ]
261
262
  }
262
263
  ],
263
- "digest": "ae9b2ca5b33484b68e892b41976bcc054562385ef7dc7db94bf86ab42e369d0d"
264
+ "digest": "8cfe81576dedf61b5ecafa0141e615cc570630469837e7da251de0c4a40b92cf"
264
265
  },
265
266
  "publishConfig": {
266
267
  "registry": "https://registry.npmjs.org/",
@@ -2,7 +2,7 @@
2
2
  name: airflow
3
3
  description: Airflow DAG architecture and conventions. Use when designing, writing, reviewing, testing, or debugging Airflow DAGs and tasks, including TaskGroups, data intervals, timezone-aware date parameters, CLI validation, environment-based scheduling, and pytest integrity tests.
4
4
  user-invocable: true
5
- release-version: 0.48.1
5
+ release-version: 0.49.1
6
6
  ---
7
7
  **Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
8
8
  # Airflow DAG Development Patterns
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: android-development
3
- description: "Prove and debug Expo / React Native apps on an owned Android emulator. Use for Android startup/rendering failures, Metro or ADB problems, UiAutomator/harness failures, APK builds, SDK/NDK/JDK workspace setup, native journey validation, and choosing Kotlin/Compose versus React Native for Android flows. Reproduce failed Android CI checkpoints off CI before fixing and redispatching. Standalone invocation offers Project or Session; init persists repo conventions. NOT for workflow YAML, CI speed or runners (github-actions), browser tests (e2e-test), iOS (ios-foundation), plain Jest tests, or signing/store release."
4
- release-version: 0.48.1
3
+ description: "Prove and debug Expo / React Native apps on an owned Android emulator. Use for Android startup/rendering failures, Metro or ADB problems, native harness failures, APK builds, SDK/NDK/JDK workspace setup, native journey validation, and choosing Kotlin/Compose versus React Native for Android flows. Reproduce failed Android CI checkpoints off CI before fixing and redispatching. Standalone invocation offers Project or Session; init persists repo conventions. Maestro journey authoring, UI-driver migration and flow diagnosis belong to maestro. NOT for workflow YAML, CI speed or runners (github-actions), browser tests (e2e-test), iOS (ios-foundation), plain Jest tests, or signing/store release."
4
+ release-version: 0.49.1
5
5
  ---
6
6
  **Updates:** Once/session run `node <skill-base-dir>/release-check.mjs`.
7
7
  # Android development
@@ -60,15 +60,17 @@ The contract, other languages and the Maestro/Detox mapping are in
60
60
 
61
61
  ## UI journey tool
62
62
 
63
- The skill references Maestro; it does not bundle or install it. Offer Maestro for new
64
- single-device journeys when the repo has no journey tool. Keep an existing sufficient
65
- harness; adding Maestro needs a concrete benefit and repo authorization, not just an
66
- installed CLI. Maestro uses the same work loop and validation ladder. Run it on the
67
- session's own emulator (`maestro --device <serial>`) and convert its output with
68
- [maestro_failure.py](scripts/maestro_failure.py), which writes the record above. Read
69
- [UI journeys](references/ui-journeys.md) before selecting or running Maestro flows, for
70
- starting state, permissions, device ownership, execution evidence and the cases that
71
- stay custom.
63
+ Before selecting, authoring, running, debugging or migrating Maestro journeys, read and
64
+ apply `{maestro baseDir}/SKILL.md`. That skill owns complete UI flows, the split between
65
+ UI/backend/native proof, exclusive UI-driver execution and Maestro evidence conversion.
66
+ It is a required companion; report it missing rather than improvising or installing it.
67
+
68
+ Keep Android workspace, emulator/ADB, build/install, Metro and cleanup ownership here.
69
+ Pass the existing owned device and identity contract to Maestro; it does not create a
70
+ second runtime. Offer Maestro for new journeys without a tool, but an existing harness
71
+ migration still needs task/repo authorization. Preserve this validation ladder and all
72
+ assigned native assertions. The [journey routing note](references/ui-journeys.md) keeps
73
+ the old reference location discoverable without duplicating Maestro's procedure.
72
74
 
73
75
  ## Validation ladder
74
76
 
@@ -151,6 +153,6 @@ higher levels still pending rather than claiming acceptance.
151
153
  | Builds, provisioning, device execution, cleanup and setup proof | [setup.md](references/setup.md); use [device-run.sh](scripts/device-run.sh) only without an existing resource owner |
152
154
  | Feature/fix validation and handoff | [feature-work.md](references/feature-work.md) |
153
155
  | Device failure record and evidence capture | [diagnosis.md](references/diagnosis.md#record-the-failed-device-case) |
154
- | UI journey tool (Maestro) and its evidence converter | [UI journeys](references/ui-journeys.md) |
156
+ | Maestro journeys, UI-driver migration and evidence conversion | `{maestro baseDir}/SKILL.md` |
155
157
  | Failure reproduction and correction | [diagnosis.md](references/diagnosis.md), then the relevant [gotcha](references/gotchas.md) |
156
158
  | CI integration | [ci.md](references/ci.md), [template](assets/android-ci-job.yml), and `github-actions` |
@@ -137,12 +137,10 @@ and prints `NATIVE_FAILURE`. Its `original_stage_exit=<n> cleanup_exit=<n>` line
137
137
  status are unchanged, and a record the journey already wrote is left untouched.
138
138
 
139
139
  A repo that already runs Maestro or Detox maps its failing artifacts to this record instead
140
- of adding the helper: Maestro's failing-step screenshot, view hierarchy and logcat plus its
141
- `commands.json` step, and Detox's `failing` artifact preset output. For Maestro, run
142
- [maestro_failure.py](../scripts/maestro_failure.py) over the flow folder or the session folder
143
- it sits in; it writes the record and prints the line, and [UI journeys](ui-journeys.md#evidence)
144
- has the evidence layout. A record is written even when the source is the framework's artifact
145
- set, and the printed line still has the four fields.
140
+ of adding the helper. For Maestro, read `{maestro baseDir}/references/evidence.md` and use
141
+ its converter and non-competing capture path. The old local converter entry point forwards
142
+ to that companion. Detox uses its `failing` artifact preset output. Preserve the same
143
+ record fields and printed line rather than adding another failure format.
146
144
 
147
145
  ## Bound work and distinguish progress from waiting
148
146
 
@@ -20,7 +20,7 @@ the product.
20
20
  | Backend tool, CI only | a Backend-backed step gets a 5xx in CI only; the log names a missing program (`Browser was not found at the configured executablePath`) |
21
21
  | adb transport, mid-journey | `connection terminated: read failed` in the adb trace after boot, then lost `adb reverse`: usually guest RAM |
22
22
  | UiAutomator server | `RemoteDisconnected` while the adb transport stays up: the on-device server was relaunched |
23
- | Maestro driver | driver readiness fails while a setup uiautomator2 process is still alive: see [device ownership](ui-journeys.md#device-ownership) |
23
+ | Maestro driver | driver readiness fails while another UI client holds registration: read `{maestro baseDir}/references/diagnosis.md` |
24
24
  | Journey harness | a wait right after a navigation times out while the destination is on screen |
25
25
  | Journey harness, short screen | a wait for a label times out only on a short or landscape screen, which shows the content above it |
26
26
  | Journey adapter | an offscreen target stays hidden while scrolls move away from it |
@@ -147,14 +147,8 @@ matches, [confirm the suspected cause](#confirm-a-suspected-cause) before changi
147
147
 
148
148
  ### A scroll adapter moves away from the target
149
149
 
150
- - **Signal:** a custom comparison adapter times out on an offscreen target even though it
151
- sends scroll gestures; a fake UI that exposes all targets can still pass.
152
- - **Cause:** Maestro's requested scroll direction describes the content to reach, not the
153
- finger movement. Mapping `DOWN` to a downward finger swipe reverses the intended scroll.
154
- - **Fix:** for `DOWN` toward later content, swipe the finger up; for `UP` toward earlier
155
- content, swipe the finger down. In the adapter test, keep the target offscreen until the
156
- correct gesture moves it into view. Wrong-direction gestures must not reveal it merely
157
- because a gesture count was reached. Check both directions where the adapter supports them.
150
+ For the Maestro/custom-adapter direction mismatch and its offscreen regression case,
151
+ read `{maestro baseDir}/references/diagnosis.md`. Maestro-specific diagnosis has one owner.
158
152
 
159
153
  ### A navigation check passes on the previous screen
160
154
 
@@ -31,7 +31,7 @@ to a newly created Android section; report unresolved commands instead of guessi
31
31
  | --- | --- |
32
32
  | `CONTRIBUTING.md` | The `## Android development` section, wrapped in `<!-- conventions:android:start -->` / `<!-- conventions:android:end -->`, with `references/android-conventions.md` as its body. |
33
33
  | `AGENTS.md` | An `Android task entry` skill-loading block between `conventions:android-task-entry` markers, plus a pointer to the selected `CONTRIBUTING.md` when missing. Check these independently: a contributor-guide link alone is not a skill loader. |
34
- | `<dir>/device-run.sh`, `<dir>/failure_capture.py` | Only with `--install-scripts`: the generic layer copied with a version header. |
34
+ | `<dir>/device-run.sh`, `<dir>/failure_capture.py`, `<dir>/failure_record.py` | Only with `--install-scripts`: capture/runner scripts and their record dependency copied with version headers. |
35
35
 
36
36
  Each file is created only when it is absent. The helper never edits `CLAUDE.md`, never writes into
37
37
  a parent project, a home directory or global agent configuration, and never reaches outside the
@@ -113,7 +113,10 @@ Existing guidance wins over the template:
113
113
  ## Skill scripts: reference or copy
114
114
 
115
115
  `device-run.sh` and `failure_capture.py` are referenced from the installed skill by
116
- default: nothing is copied, and the run reads them from the skill directory. Copy them
116
+ default: nothing is copied, and the run reads them from the skill directory, with the
117
+ record module supplied by the required `maestro` companion. Explicit copies also include
118
+ that dependency as `failure_record.py` beside `failure_capture.py`, so they run without
119
+ installed skills. Copy them
117
120
  into the repo only on an explicit request, with `--install-scripts` (default target
118
121
  `scripts/android/`) or `--install-scripts <dir>` for another relative directory inside
119
122
  the project.
@@ -230,7 +230,8 @@ when the journey failed, the `NATIVE_FAILURE` line and its `failure.json`.
230
230
 
231
231
  Expect every selected scenario's result (`PASS` marker or the journey tool's report),
232
232
  required screenshots, and backend and Metro logs when the selected variant uses those
233
- services. For Maestro's result and screenshot rules, read [UI journeys](ui-journeys.md#evidence).
233
+ services. For Maestro's result, screenshot and non-competing capture rules, read
234
+ `{maestro baseDir}/references/evidence.md` before executing its journey.
234
235
  Preserve the failed checkpoint's evidence before cleanup. A release build with embedded
235
236
  assets does not require Metro by default.
236
237
 
@@ -1,130 +1,15 @@
1
- # UI journey tool: Maestro
1
+ # Mobile UI journey routing
2
2
 
3
- Maestro writes a single-device UI flow as YAML and records per-step failure evidence. The
4
- skill references it; it does not bundle or install it, and adding it is the repo's decision.
3
+ Maestro instructions moved to the required companion skill. Before selecting, authoring,
4
+ running, debugging or migrating Maestro flows, read `{maestro baseDir}/SKILL.md` and its
5
+ task-specific references. Resolve that path from the installed skill, not the working
6
+ directory. Report a missing companion; discovery does not authorize installation.
5
7
 
6
- ## When to use it
8
+ `maestro` owns UI/backend/native test splitting, flow structure, state and permissions,
9
+ exclusive UI-driver execution, diagnosis and the Maestro failure converter. This skill
10
+ still owns Android runtime setup, workspace/device identity, the validation ladder and
11
+ cleanup. Reuse its existing owner and required gates; a UI-driver change is not another
12
+ emulator or fixture lifecycle.
7
13
 
8
- | Situation | Recommendation |
9
- | --- | --- |
10
- | Repo has no UI journey tool | Offer Maestro for new single-device journeys. It replaces hand-written adb/UiAutomator launch, poll, capture and assertion code. |
11
- | Repo has a working harness | Reuse it when sufficient. Add Maestro only for a concrete benefit with repo authorization; an installed CLI alone is not a reason to add or migrate journeys. |
12
- | Coordinated multi-device case | Keep the custom harness. Maestro sharding runs independent flows, and a shard cannot depend on another. |
13
-
14
- Maestro changes the UI journey driver, not the [work loop or validation ladder](../SKILL.md#work-loop).
15
- Use focused flows at the applicable L0/L1 check, candidate-APK journeys at L2, and assigned
16
- acceptance journeys at L3. Source tests and required backend/native checks keep their roles.
17
-
18
- ## Starting state and permissions
19
-
20
- Declare each flow's intended starting app state and permissions in its YAML or owned
21
- fixture setup, and check included subflows and hooks for resets:
22
-
23
- - For a warm-runtime check, keep the running app or use `launchApp: {stopApp: false}`
24
- to foreground it. Plain `launchApp` stops and relaunches the app by default, so it
25
- cannot preserve the process whose state the check needs.
26
- - For restart, upgrade or fresh-install checks, use the checkpoint's required setup.
27
- `clearState: true` and `clearState` clear Android app data; they do not install the
28
- candidate APK or prove a fresh installation or upgrade. Clear only authorized disposable
29
- state. If a reset removes debug endpoint preferences, restore them through the existing
30
- owner and verify the app's actual code source before continuing.
31
- - Set permissions for permission-sensitive journeys. `launchApp` allows all permissions
32
- by default; use the required denied or unset state to exercise denial or prompts.
33
- An auto-granted run does not prove the permission-request journey.
34
-
35
- ## Device ownership
36
-
37
- Run against the emulator the session owns and name it with `maestro --device <serial>`.
38
- Use the status handling under [Evidence](#evidence) inside the existing journey owner.
39
-
40
- Each session installs and starts Maestro's driver packages (`dev.mobile.maestro`,
41
- `dev.mobile.maestro.test`) through `am instrument`. That cost lands on the session's first
42
- flow, not on every step, so run every flow of the case in one session instead of one session
43
- per flow.
44
-
45
- Keep mutating checks exclusive on that device, including existing harness and Maestro
46
- runs. Reuse the existing runtime owner; Maestro is not a second emulator, backend or
47
- cleanup owner.
48
-
49
- If setup started a `setupUiAutomator` uiautomator2 process, have its owner verify ownership,
50
- stop it and wait for it to exit before starting Maestro; a live setup driver can block
51
- Maestro driver readiness. Restart that setup driver only after Maestro has fully exited,
52
- if it is still needed. Never stop a peer's process; coordinate with its owner instead.
53
-
54
- When comparing a custom journey adapter with Maestro, check scroll direction and prove
55
- offscreen targets with the [scroll-direction gotcha](gotchas.md#a-scroll-adapter-moves-away-from-the-target).
56
-
57
- ## Evidence
58
-
59
- Record the selected flows, executed assertions, run exit status, app/source identity and
60
- cleanup outcome. Accept the harness's `PASS` markers or Maestro's per-flow results/JUnit
61
- report as scenario results; a zero exit with no selected flows is not a pass. For JUnit,
62
- use `--format junit --output <owned-report-path>`; the report is separate from
63
- `--test-output-dir`. Capture successful checkpoints with `takeScreenshot` when the
64
- assignment requires visual evidence; normal passing flows have no automatic screenshots.
65
-
66
- `--test-output-dir` receives one session folder holding one self-contained folder per flow:
67
- `manifest.json`, `commands.json` (one entry per executed step), the failing step's
68
- `screenshots/` image and `screen-hierarchy/` JSON, and `logs/device-logcat.txt`. Convert that
69
- into the [device failure record](diagnosis.md#record-the-failed-device-case) instead of
70
- adding the journey helper:
71
-
72
- Give each case/attempt a new owned `LOG_DIR`, shared with its existing launcher so its
73
- partial-record fallback looks in the same directory. Retain earlier attempts separately;
74
- reusing a runtime does not mean reusing a failure-record destination. Confirm the pinned
75
- Maestro supports these flags and output layout before using the example.
76
-
77
- Run this body as the existing owner's journey command. Guard both commands so `set -e`
78
- cannot skip conversion or cleanup after a failure. The owner retains its bounded cleanup
79
- after the journey exits; this is not a new launcher or an acceptance checker.
80
-
81
- ```bash
82
- maestro_status=0
83
- maestro --device "$ANDROID_SERIAL" test --test-output-dir "$LOG_DIR/maestro" \
84
- --format junit --output "$LOG_DIR/report.xml" ./maestro-flows || maestro_status=$?
85
- conversion_status=0
86
- python3 <skill-base-dir>/scripts/maestro_failure.py --maestro-dir "$LOG_DIR/maestro" \
87
- --evidence-dir "$LOG_DIR" --case "$DEVICE_CASE" || conversion_status=$?
88
- printf 'maestro_exit=%s conversion_exit=%s\n' "$maestro_status" "$conversion_status"
89
- if [ "$maestro_status" -ne 0 ]; then
90
- exit "$maestro_status"
91
- fi
92
- exit "$conversion_status"
93
- ```
94
-
95
- Convert this invocation's finalized output before teardown. If startup or driver failure
96
- left no usable failed-step output, retain raw CLI logs and the original status and use
97
- the existing owner's partial-record fallback before cleanup. Conversion errors are
98
- evidence-processing failures, not replacements for the original test failure.
99
-
100
- It takes the session folder or one flow folder, writes `failure.json` into `--evidence-dir`
101
- (the flow folder by default) and prints the one `NATIVE_FAILURE` line for the first failed
102
- step. A passing flow writes nothing, and an existing record is never replaced. The artifact
103
- fields name the Maestro files (`screenshots/…`, `screen-hierarchy/…`, `logs/…`) rather than
104
- copying them into the adb names, so the failing frame and its hierarchy stay paired.
105
-
106
- Converter exit zero means processing completed, not that tests passed: a recorded failure
107
- also returns zero, and empty or incomplete step output may produce no record. Establish
108
- success from the executed assertions and per-flow results above, never from the converter
109
- or absence of `NATIVE_FAILURE`.
110
-
111
- ## Agents
112
-
113
- `maestro mcp` gives an agent `list_devices`, `inspect_screen`, `take_screenshot` and `run`.
114
- Explore the screen and draft a repeatable YAML flow with it. Proof comes from executing
115
- the flow against the identified candidate with assertions that establish the claimed
116
- behavior and retained results. Committing YAML or finding selectors in MCP does not prove
117
- the journey passed.
118
-
119
- ## Limits
120
-
121
- - Coordinated multi-device cases, exact data or payment proofs, and process-death checks stay
122
- on custom harness code.
123
- - Authentication codes still come from the harness's disposable database, passed into a flow
124
- with `maestro test -e` or resolved by its `runScript`; do not add a second fixture path.
125
-
126
- ## Sources
127
-
128
- - [Launch state and permissions](https://docs.maestro.dev/reference/commands-available/launchapp)
129
- - [Android state clearing](https://docs.maestro.dev/reference/commands-available/clearstate)
130
- - [Reports and artifacts](https://docs.maestro.dev/maestro-flows/workspace-management/test-reports-and-artifacts)
14
+ The old `scripts/maestro_failure.py` entry point forwards to the companion for callers
15
+ already using it. New commands use `{maestro baseDir}/scripts/maestro_failure.py`.
@@ -21,6 +21,10 @@ adapters described in ``references/diagnosis.md``:
21
21
 
22
22
  case, step, error, screenshot, uiDump, logcatTail, evidenceDir, cleanupErrors
23
23
 
24
+ The record model, its constants and the ``failure.json`` read and write live in the
25
+ sibling ``maestro`` skill (``scripts/failure_record.py``) and are re-exported here, so
26
+ the Maestro converter writes the same record without this module or a device.
27
+
24
28
  ``screenshot``, ``uiDump`` and ``logcatTail`` are file names relative to
25
29
  ``evidenceDir`` and are ``null`` when that capture failed; the reason goes to
26
30
  ``cleanupErrors`` and never replaces the original ``error``. A record is written
@@ -39,32 +43,35 @@ always propagates unchanged.
39
43
  from __future__ import annotations
40
44
 
41
45
  import contextlib
42
- import json
43
46
  import os
44
47
  import subprocess
45
48
  import sys
46
49
  import tempfile
47
- from dataclasses import dataclass, field
48
50
 
49
- RECORD_NAME = "failure.json"
50
- NATIVE_FAILURE_PREFIX = "NATIVE_FAILURE "
51
+ # Explicit project copies carry the record module beside this file. Installed skills
52
+ # use the declared Maestro sibling dependency; neither route depends on the caller's cwd.
53
+ _SCRIPTS = os.path.dirname(os.path.abspath(__file__))
54
+ _RECORD_SCRIPTS = _SCRIPTS if os.path.isfile(os.path.join(_SCRIPTS, "failure_record.py")) else (
55
+ os.path.normpath(os.path.join(_SCRIPTS, "..", "..", "maestro", "scripts"))
56
+ )
57
+ if _RECORD_SCRIPTS not in sys.path:
58
+ sys.path.insert(0, _RECORD_SCRIPTS)
59
+
60
+ from failure_record import ( # noqa: E402
61
+ NATIVE_FAILURE_KEYS,
62
+ NATIVE_FAILURE_PREFIX,
63
+ RECORD_KEYS,
64
+ RECORD_NAME,
65
+ Failure,
66
+ read_record,
67
+ write_record,
68
+ )
69
+
51
70
  SCREENSHOT_NAME = "screenshot.png"
52
71
  UI_DUMP_NAME = "ui-dump.xml"
53
72
  LOGCAT_NAME = "logcat-tail.txt"
54
73
  UI_DUMP_REMOTE = "/sdcard/failure-capture.xml"
55
74
 
56
- RECORD_KEYS = (
57
- "case",
58
- "step",
59
- "error",
60
- "screenshot",
61
- "uiDump",
62
- "logcatTail",
63
- "evidenceDir",
64
- "cleanupErrors",
65
- )
66
- NATIVE_FAILURE_KEYS = ("case", "step", "error", "evidenceDir")
67
-
68
75
 
69
76
  class CaptureError(RuntimeError):
70
77
  """A bounded capture command failed, timed out or returned no usable output."""
@@ -152,74 +159,6 @@ class AdbClient:
152
159
  _write_bytes(destination, payload)
153
160
 
154
161
 
155
- @dataclass
156
- class Failure:
157
- """One failed device case; also the payload of `failure.json`."""
158
-
159
- case: str = None
160
- step: str = None
161
- error: str = ""
162
- screenshot: str = None
163
- uiDump: str = None
164
- logcatTail: str = None
165
- evidenceDir: str = None
166
- cleanupErrors: list = field(default_factory=list)
167
-
168
- def as_dict(self):
169
- return {key: getattr(self, key) for key in RECORD_KEYS}
170
-
171
- def native_failure_line(self):
172
- compact = {key: getattr(self, key) for key in NATIVE_FAILURE_KEYS}
173
- return NATIVE_FAILURE_PREFIX + json.dumps(compact, separators=(",", ":"))
174
-
175
- @classmethod
176
- def from_dict(cls, payload):
177
- values = {key: payload[key] for key in RECORD_KEYS if key in payload}
178
- errors = values.get("cleanupErrors")
179
- values["cleanupErrors"] = list(errors) if isinstance(errors, list) else []
180
- return cls(**values)
181
-
182
-
183
- def read_record(evidence_dir):
184
- """The record already in `evidence_dir`, or None when there is no usable one."""
185
- path = os.path.join(evidence_dir, RECORD_NAME)
186
- try:
187
- with open(path, "r", encoding="utf-8") as stream:
188
- payload = json.load(stream)
189
- except (OSError, ValueError):
190
- return None
191
- if not isinstance(payload, dict) or "error" not in payload:
192
- return None
193
- return Failure.from_dict(payload)
194
-
195
-
196
- def write_record(failure, evidence_dir):
197
- """Store `failure` unless a record already exists; return the record on disk.
198
-
199
- A valid earlier record wins, so a cleanup error or a second failing step cannot
200
- replace the first failure. An unreadable file is not a record and is replaced,
201
- with the replacement noted on the returned record's `cleanupErrors`.
202
- """
203
- os.makedirs(evidence_dir, exist_ok=True)
204
- existing = read_record(evidence_dir)
205
- if existing is not None:
206
- return existing
207
- path = os.path.join(evidence_dir, RECORD_NAME)
208
- if os.path.exists(path):
209
- failure.cleanupErrors.append("%s: replaced an unreadable record" % RECORD_NAME)
210
- payload = json.dumps(failure.as_dict(), indent=2) + "\n"
211
- handle, temporary = tempfile.mkstemp(dir=evidence_dir, prefix=".failure-", suffix=".json")
212
- try:
213
- with os.fdopen(handle, "w", encoding="utf-8") as stream:
214
- stream.write(payload)
215
- os.replace(temporary, path)
216
- except BaseException:
217
- if os.path.exists(temporary):
218
- os.unlink(temporary)
219
- raise
220
- return failure
221
-
222
-
223
162
  class FailureRecorder:
224
163
  """Capture the first failing step of one device case.
225
164
 
@@ -22,6 +22,7 @@ const defaultScriptsDir = 'scripts/android'
22
22
  const installableScripts = [
23
23
  { name: 'device-run.sh', mode: 0o755 },
24
24
  { name: 'failure_capture.py', mode: 0o644 },
25
+ { name: 'failure_record.py', source: '../../maestro/scripts/failure_record.py', mode: 0o644 },
25
26
  ]
26
27
  const scriptHeaderPattern = /^# android-development skill (\S+) sha256:([0-9a-f]{64}) (\S+)$/
27
28
 
@@ -516,7 +517,7 @@ function scriptPlan(root, requested) {
516
517
  return installableScripts.map(script => {
517
518
  const file = path.join(root, target, script.name)
518
519
  assertScriptDirectory(root, file)
519
- const source = scriptSource(script.name)
520
+ const source = scriptSource(script.source ?? script.name)
520
521
  const next = withHeader(source, scriptHeader(script.name, version, source))
521
522
  const entry = readGuidance(resolveTarget(root, path.posix.join(target, script.name)))
522
523
  const base = { ...entry, mode: script.mode, script: script.name }