@1aboveio/skills 1.0.16 → 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 +178 -150
- 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 -10
- package/skills/app-dev/android-development/references/diagnosis.md +4 -6
- package/skills/app-dev/android-development/references/feature-work.md +3 -2
- package/skills/app-dev/android-development/references/gotchas.md +7 -0
- package/skills/app-dev/android-development/references/init.md +5 -2
- package/skills/app-dev/android-development/references/setup.md +9 -5
- package/skills/app-dev/android-development/references/ui-journeys.md +12 -55
- 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 +46 -12
- package/skills/engineering/harness-runtime/contracts.md +1 -1
- package/skills/engineering/resolve-issues/SKILL.md +11 -9
- package/skills/engineering/resolve-issues/references/exploration.md +60 -18
- package/skills/engineering/resolve-issues/references/implementation.md +1 -1
- package/skills/engineering/resolve-issues/references/preflight.md +47 -22
- package/skills/engineering/resolve-issues/references/review.md +2 -1
- package/skills/engineering/resolve-issues/references/shared-modules.md +58 -4
- package/skills/engineering/resolve-issues/references/task-plan.md +30 -10
- package/skills/engineering/resolve-issues/scripts/findings-reuse.mjs +1 -1
- package/skills/engineering/resolve-issues/scripts/next-actions.mjs +7 -7
- package/skills/engineering/resolve-issues/scripts/plan-sync.mjs +1 -1
- package/skills/engineering/resolve-issues/scripts/size-check.mjs +6 -5
- 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,13 +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
|
-
|
|
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.
|
|
70
74
|
|
|
71
75
|
## Validation ladder
|
|
72
76
|
|
|
@@ -149,6 +153,6 @@ higher levels still pending rather than claiming acceptance.
|
|
|
149
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 |
|
|
150
154
|
| Feature/fix validation and handoff | [feature-work.md](references/feature-work.md) |
|
|
151
155
|
| Device failure record and evidence capture | [diagnosis.md](references/diagnosis.md#record-the-failed-device-case) |
|
|
152
|
-
|
|
|
156
|
+
| Maestro journeys, UI-driver migration and evidence conversion | `{maestro baseDir}/SKILL.md` |
|
|
153
157
|
| Failure reproduction and correction | [diagnosis.md](references/diagnosis.md), then the relevant [gotcha](references/gotchas.md) |
|
|
154
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
|
|
|
@@ -173,8 +173,9 @@ at L2. Required CI and L3 obligations remain assigned, not silently waived or ma
|
|
|
173
173
|
rule for unreproduced or intermittent failures; report uncertainty until evidence
|
|
174
174
|
supports the cause.
|
|
175
175
|
- Report source SHA, commands, results and remaining gaps at review handoff. For device
|
|
176
|
-
checks, include the selected scenarios, `PASS` markers
|
|
177
|
-
|
|
176
|
+
checks, include the selected scenarios, per-scenario results (`PASS` markers or the
|
|
177
|
+
journey tool's report) and cleanup exit. For a failure, name the earliest failing
|
|
178
|
+
checkpoint and link retained evidence; preserve failed attempts.
|
|
178
179
|
Separate build duration, device-check duration and total worker time when discussing cost.
|
|
179
180
|
Reuse existing logs to distinguish cold/warm builds, build count, ABI, test packaging,
|
|
180
181
|
runtime startup and edit-to-feedback time. Do not infer a task's cost from total job time,
|
|
@@ -20,8 +20,10 @@ 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 another UI client holds registration: read `{maestro baseDir}/references/diagnosis.md` |
|
|
23
24
|
| Journey harness | a wait right after a navigation times out while the destination is on screen |
|
|
24
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
|
+
| Journey adapter | an offscreen target stays hidden while scrolls move away from it |
|
|
25
27
|
| Product assertion | a screen or state mismatch with a screenshot |
|
|
26
28
|
|
|
27
29
|
Then match the signal against [gotchas.md](gotchas.md). If nothing
|
|
@@ -143,6 +145,11 @@ matches, [confirm the suspected cause](#confirm-a-suspected-cause) before changi
|
|
|
143
145
|
|
|
144
146
|
## Journey harness
|
|
145
147
|
|
|
148
|
+
### A scroll adapter moves away from the target
|
|
149
|
+
|
|
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.
|
|
152
|
+
|
|
146
153
|
### A navigation check passes on the previous screen
|
|
147
154
|
|
|
148
155
|
- **Signal:** intermittently, a wait right after the next tap times out even though the
|
|
@@ -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.
|
|
@@ -228,9 +228,12 @@ does not stop that server: use a verified private endpoint on a shared host and
|
|
|
228
228
|
through the caller's owner. Capture the command's exit status, the final summary line and,
|
|
229
229
|
when the journey failed, the `NATIVE_FAILURE` line and its `failure.json`.
|
|
230
230
|
|
|
231
|
-
Expect every selected scenario's `PASS` marker
|
|
232
|
-
|
|
233
|
-
|
|
231
|
+
Expect every selected scenario's result (`PASS` marker or the journey tool's report),
|
|
232
|
+
required screenshots, and backend and Metro logs when the selected variant uses those
|
|
233
|
+
services. For Maestro's result, screenshot and non-competing capture rules, read
|
|
234
|
+
`{maestro baseDir}/references/evidence.md` before executing its journey.
|
|
235
|
+
Preserve the failed checkpoint's evidence before cleanup. A release build with embedded
|
|
236
|
+
assets does not require Metro by default.
|
|
234
237
|
|
|
235
238
|
## Owned development session
|
|
236
239
|
|
|
@@ -385,8 +388,9 @@ For setup proof only. Record:
|
|
|
385
388
|
- Each stage's exit status and duration.
|
|
386
389
|
- The APK's SHA-256 (`shasum -a 256` or `sha256sum`) and its per-ABI `lib/` entries
|
|
387
390
|
(`unzip -l`), checked on the APK itself rather than inferred from Gradle flags.
|
|
388
|
-
- The journey's `PASS` markers
|
|
389
|
-
|
|
391
|
+
- The journey's per-scenario results (`PASS` markers or the journey tool's report) and
|
|
392
|
+
cleanup results: database dropped, emulator exited, container removed, no listeners
|
|
393
|
+
left on the backend or Metro ports.
|
|
390
394
|
- Earlier failed or incomplete attempts. A later pass does not erase them.
|
|
391
395
|
|
|
392
396
|
State what the run does not prove: tablet, accessibility (TalkBack), physical devices,
|
|
@@ -1,58 +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 | Keep the harness. Add Maestro flows for new journeys alongside it; do not migrate existing cases. |
|
|
12
|
-
| Coordinated multi-device case | Keep the custom harness. Maestro sharding runs independent flows, and a shard cannot depend on another. |
|
|
13
|
-
|
|
14
|
-
## Device ownership
|
|
15
|
-
|
|
16
|
-
Run against the emulator the session owns and name it, so Maestro never starts or picks its
|
|
17
|
-
own device:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
maestro --device "$ANDROID_SERIAL" test --test-output-dir "$LOG_DIR" ./maestro-flows
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Each session installs and starts Maestro's driver packages (`dev.mobile.maestro`,
|
|
24
|
-
`dev.mobile.maestro.test`) through `am instrument`. That cost lands on the session's first
|
|
25
|
-
flow, not on every step, so run every flow of the case in one session instead of one session
|
|
26
|
-
per flow.
|
|
27
|
-
|
|
28
|
-
## Evidence
|
|
29
|
-
|
|
30
|
-
`--test-output-dir` receives one session folder holding one self-contained folder per flow:
|
|
31
|
-
`manifest.json`, `commands.json` (one entry per executed step), the failing step's
|
|
32
|
-
`screenshots/` image and `screen-hierarchy/` JSON, and `logs/device-logcat.txt`. Convert that
|
|
33
|
-
into the [device failure record](diagnosis.md#record-the-failed-device-case) instead of
|
|
34
|
-
adding the journey helper:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
python3 <skill-base-dir>/scripts/maestro_failure.py --maestro-dir "$LOG_DIR/2026-07-31_173617" \
|
|
38
|
-
--evidence-dir "$LOG_DIR" --case "$DEVICE_CASE"
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
It takes the session folder or one flow folder, writes `failure.json` into `--evidence-dir`
|
|
42
|
-
(the flow folder by default) and prints the one `NATIVE_FAILURE` line for the first failed
|
|
43
|
-
step. A passing flow writes nothing, and an existing record is never replaced. The artifact
|
|
44
|
-
fields name the Maestro files (`screenshots/…`, `screen-hierarchy/…`, `logs/…`) rather than
|
|
45
|
-
copying them into the adb names, so the failing frame and its hierarchy stay paired.
|
|
46
|
-
|
|
47
|
-
## Agents
|
|
48
|
-
|
|
49
|
-
`maestro mcp` gives an agent `list_devices`, `inspect_screen`, `take_screenshot` and `run`.
|
|
50
|
-
Explore the screen and draft a flow with it; the committed YAML flow is the proof, not the
|
|
51
|
-
MCP session that found the selectors.
|
|
52
|
-
|
|
53
|
-
## Limits
|
|
54
|
-
|
|
55
|
-
- Coordinated multi-device cases, exact data or payment proofs, and process-death checks stay
|
|
56
|
-
on custom harness code.
|
|
57
|
-
- Authentication codes still come from the harness's disposable database, passed into a flow
|
|
58
|
-
with `maestro test -e` or resolved by its `runScript`; do not add a second fixture path.
|
|
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 }
|