@1aboveio/skills 1.0.17 → 1.0.18
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.
- package/.codex-plugin/plugin.json +1 -1
- package/.codex-plugin/resources.json +167 -139
- package/README.md +1 -1
- package/package.json +5 -4
- package/skills/app-dev/airflow/SKILL.md +1 -1
- package/skills/app-dev/android-development/SKILL.md +14 -12
- package/skills/app-dev/android-development/references/diagnosis.md +4 -6
- package/skills/app-dev/android-development/references/gotchas.md +3 -9
- package/skills/app-dev/android-development/references/init.md +5 -2
- package/skills/app-dev/android-development/references/setup.md +2 -1
- package/skills/app-dev/android-development/references/ui-journeys.md +12 -127
- package/skills/app-dev/android-development/scripts/failure_capture.py +23 -84
- package/skills/app-dev/android-development/scripts/init.mjs +2 -1
- package/skills/app-dev/android-development/scripts/maestro_failure.py +43 -387
- package/skills/app-dev/android-development/scripts/test_maestro_failure.py +113 -424
- package/skills/app-dev/app-debug/SKILL.md +1 -1
- package/skills/app-dev/better-auth/SKILL.md +1 -1
- package/skills/app-dev/data-catalog/SKILL.md +1 -1
- package/skills/app-dev/data-quality/SKILL.md +1 -1
- package/skills/app-dev/ios-foundation/SKILL.md +1 -1
- package/skills/app-dev/maestro/LICENSE +3 -0
- package/skills/app-dev/maestro/SKILL.md +112 -0
- package/skills/app-dev/maestro/references/android-connection.md +54 -0
- package/skills/app-dev/maestro/references/authoring.md +113 -0
- package/skills/app-dev/maestro/references/diagnosis.md +50 -0
- package/skills/app-dev/maestro/references/evidence.md +74 -0
- package/skills/app-dev/maestro/references/journeys.md +100 -0
- package/skills/app-dev/maestro/references/migration.md +35 -0
- package/skills/app-dev/maestro/release-check.mjs +95 -0
- package/skills/app-dev/maestro/scripts/failure_record.py +110 -0
- package/skills/app-dev/maestro/scripts/maestro_failure.py +481 -0
- package/skills/app-dev/maestro/scripts/test_maestro_failure.py +710 -0
- package/skills/app-dev/monorepo/SKILL.md +1 -1
- package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
- package/skills/app-dev/prisma-setup/SKILL.md +1 -1
- package/skills/app-dev/pyspark/SKILL.md +1 -1
- package/skills/app-dev/python-backend/SKILL.md +1 -1
- package/skills/app-dev/shadcn/SKILL.md +1 -1
- package/skills/app-dev/zod-v4/SKILL.md +1 -1
- package/skills/cicd/cloud-build/SKILL.md +1 -1
- package/skills/cicd/cloud-debug/SKILL.md +1 -1
- package/skills/cicd/cloud-deploy/SKILL.md +1 -1
- package/skills/cicd/docker/SKILL.md +1 -1
- package/skills/cicd/github-actions/SKILL.md +1 -1
- package/skills/cicd/github-flow/SKILL.md +1 -1
- package/skills/cicd/google-cloud/SKILL.md +1 -1
- package/skills/cicd/mergify/SKILL.md +1 -1
- package/skills/cicd/podman/SKILL.md +1 -1
- package/skills/content/article-review/SKILL.md +1 -1
- package/skills/content/article-to-image/SKILL.md +1 -1
- package/skills/content/flowchart-svg/SKILL.md +1 -1
- package/skills/content/image-gen/SKILL.md +1 -1
- package/skills/content/mermaid/SKILL.md +1 -1
- package/skills/content/wechat-article-writer/SKILL.md +1 -1
- package/skills/content/wechat-publisher/SKILL.md +1 -1
- package/skills/content/wechat-search/SKILL.md +1 -1
- package/skills/content/xai-search/SKILL.md +1 -1
- package/skills/core/distill-writing/SKILL.md +1 -1
- package/skills/core/doc-to-md/SKILL.md +1 -1
- package/skills/core/editorial-review/SKILL.md +1 -1
- package/skills/core/house-style/SKILL.md +1 -1
- package/skills/core/plain-language/SKILL.md +1 -1
- package/skills/core/polish-cn/SKILL.md +1 -1
- package/skills/core/reg-parser/SKILL.md +1 -1
- package/skills/core/terminology/SKILL.md +1 -1
- package/skills/core/write-doc/SKILL.md +1 -1
- package/skills/core/write-report/SKILL.md +1 -1
- package/skills/engineering/better-review/SKILL.md +1 -1
- package/skills/engineering/e2e-test/SKILL.md +1 -1
- package/skills/engineering/engineering/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
- package/skills/engineering/ensure-coverage/SKILL.md +1 -1
- package/skills/engineering/golden-path/SKILL.md +1 -1
- package/skills/engineering/harness-runtime/SKILL.md +1 -1
- package/skills/engineering/harness-runtime/agent-catalog.mjs +44 -11
- package/skills/engineering/harness-runtime/contracts.md +1 -1
- package/skills/engineering/resolve-issues/SKILL.md +1 -1
- package/skills/engineering/resolve-release/SKILL.md +1 -1
- package/skills/engineering/rush-issues/SKILL.md +1 -1
- package/skills/engineering/rush-release/SKILL.md +1 -1
- package/skills/engineering/test-quality/SKILL.md +1 -1
- package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
- package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
- package/skills/risk-compliance/contract-review/SKILL.md +1 -1
- package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
- package/skills/risk-compliance/fraud-detection/SKILL.md +1 -1
- package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
- package/skills/risk-compliance/portfolio-payment-analysis/SKILL.md +1 -1
- package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
- 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.
|
|
3
|
+
"version": "1.0.18",
|
|
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": "
|
|
32
|
-
"releaseIdentity": "
|
|
31
|
+
"metadataDigest": "df95a008c88708ef577ba4b6f7653e24705322ed24ecae12b77e1c07b557ecdd",
|
|
32
|
+
"releaseIdentity": "9de073de5cc2dd8be4429305b357f5a84e711be2abc33164b265e92e2e467ea5"
|
|
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": "
|
|
264
|
+
"digest": "8998d462290ef5cf1ccfc7b8644987344d80183d06478a08601f5ea4fed689e2"
|
|
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.
|
|
5
|
+
release-version: 0.49.0
|
|
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,
|
|
4
|
-
release-version: 0.
|
|
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.0
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
|
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
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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
|
|
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
|
-
|
|
151
|
-
|
|
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`:
|
|
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
|
|
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
|
|
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
|
|
1
|
+
# Mobile UI journey routing
|
|
2
2
|
|
|
3
|
-
Maestro
|
|
4
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
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 }
|