@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.
Files changed (102) hide show
  1. package/.codex-plugin/plugin.json +1 -1
  2. package/.codex-plugin/resources.json +178 -150
  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 -10
  7. package/skills/app-dev/android-development/references/diagnosis.md +4 -6
  8. package/skills/app-dev/android-development/references/feature-work.md +3 -2
  9. package/skills/app-dev/android-development/references/gotchas.md +7 -0
  10. package/skills/app-dev/android-development/references/init.md +5 -2
  11. package/skills/app-dev/android-development/references/setup.md +9 -5
  12. package/skills/app-dev/android-development/references/ui-journeys.md +12 -55
  13. package/skills/app-dev/android-development/scripts/failure_capture.py +23 -84
  14. package/skills/app-dev/android-development/scripts/init.mjs +2 -1
  15. package/skills/app-dev/android-development/scripts/maestro_failure.py +43 -387
  16. package/skills/app-dev/android-development/scripts/test_maestro_failure.py +113 -424
  17. package/skills/app-dev/app-debug/SKILL.md +1 -1
  18. package/skills/app-dev/better-auth/SKILL.md +1 -1
  19. package/skills/app-dev/data-catalog/SKILL.md +1 -1
  20. package/skills/app-dev/data-quality/SKILL.md +1 -1
  21. package/skills/app-dev/ios-foundation/SKILL.md +1 -1
  22. package/skills/app-dev/maestro/LICENSE +3 -0
  23. package/skills/app-dev/maestro/SKILL.md +112 -0
  24. package/skills/app-dev/maestro/references/android-connection.md +54 -0
  25. package/skills/app-dev/maestro/references/authoring.md +113 -0
  26. package/skills/app-dev/maestro/references/diagnosis.md +50 -0
  27. package/skills/app-dev/maestro/references/evidence.md +74 -0
  28. package/skills/app-dev/maestro/references/journeys.md +100 -0
  29. package/skills/app-dev/maestro/references/migration.md +35 -0
  30. package/skills/app-dev/maestro/release-check.mjs +95 -0
  31. package/skills/app-dev/maestro/scripts/failure_record.py +110 -0
  32. package/skills/app-dev/maestro/scripts/maestro_failure.py +481 -0
  33. package/skills/app-dev/maestro/scripts/test_maestro_failure.py +710 -0
  34. package/skills/app-dev/monorepo/SKILL.md +1 -1
  35. package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
  36. package/skills/app-dev/prisma-setup/SKILL.md +1 -1
  37. package/skills/app-dev/pyspark/SKILL.md +1 -1
  38. package/skills/app-dev/python-backend/SKILL.md +1 -1
  39. package/skills/app-dev/shadcn/SKILL.md +1 -1
  40. package/skills/app-dev/zod-v4/SKILL.md +1 -1
  41. package/skills/cicd/cloud-build/SKILL.md +1 -1
  42. package/skills/cicd/cloud-debug/SKILL.md +1 -1
  43. package/skills/cicd/cloud-deploy/SKILL.md +1 -1
  44. package/skills/cicd/docker/SKILL.md +1 -1
  45. package/skills/cicd/github-actions/SKILL.md +1 -1
  46. package/skills/cicd/github-flow/SKILL.md +1 -1
  47. package/skills/cicd/google-cloud/SKILL.md +1 -1
  48. package/skills/cicd/mergify/SKILL.md +1 -1
  49. package/skills/cicd/podman/SKILL.md +1 -1
  50. package/skills/content/article-review/SKILL.md +1 -1
  51. package/skills/content/article-to-image/SKILL.md +1 -1
  52. package/skills/content/flowchart-svg/SKILL.md +1 -1
  53. package/skills/content/image-gen/SKILL.md +1 -1
  54. package/skills/content/mermaid/SKILL.md +1 -1
  55. package/skills/content/wechat-article-writer/SKILL.md +1 -1
  56. package/skills/content/wechat-publisher/SKILL.md +1 -1
  57. package/skills/content/wechat-search/SKILL.md +1 -1
  58. package/skills/content/xai-search/SKILL.md +1 -1
  59. package/skills/core/distill-writing/SKILL.md +1 -1
  60. package/skills/core/doc-to-md/SKILL.md +1 -1
  61. package/skills/core/editorial-review/SKILL.md +1 -1
  62. package/skills/core/house-style/SKILL.md +1 -1
  63. package/skills/core/plain-language/SKILL.md +1 -1
  64. package/skills/core/polish-cn/SKILL.md +1 -1
  65. package/skills/core/reg-parser/SKILL.md +1 -1
  66. package/skills/core/terminology/SKILL.md +1 -1
  67. package/skills/core/write-doc/SKILL.md +1 -1
  68. package/skills/core/write-report/SKILL.md +1 -1
  69. package/skills/engineering/better-review/SKILL.md +1 -1
  70. package/skills/engineering/e2e-test/SKILL.md +1 -1
  71. package/skills/engineering/engineering/SKILL.md +1 -1
  72. package/skills/engineering/engineering-runtime/SKILL.md +1 -1
  73. package/skills/engineering/engineering-runtime/coherence/workflow.json +13 -13
  74. package/skills/engineering/ensure-coverage/SKILL.md +1 -1
  75. package/skills/engineering/golden-path/SKILL.md +1 -1
  76. package/skills/engineering/harness-runtime/SKILL.md +1 -1
  77. package/skills/engineering/harness-runtime/agent-catalog.mjs +46 -12
  78. package/skills/engineering/harness-runtime/contracts.md +1 -1
  79. package/skills/engineering/resolve-issues/SKILL.md +11 -9
  80. package/skills/engineering/resolve-issues/references/exploration.md +60 -18
  81. package/skills/engineering/resolve-issues/references/implementation.md +1 -1
  82. package/skills/engineering/resolve-issues/references/preflight.md +47 -22
  83. package/skills/engineering/resolve-issues/references/review.md +2 -1
  84. package/skills/engineering/resolve-issues/references/shared-modules.md +58 -4
  85. package/skills/engineering/resolve-issues/references/task-plan.md +30 -10
  86. package/skills/engineering/resolve-issues/scripts/findings-reuse.mjs +1 -1
  87. package/skills/engineering/resolve-issues/scripts/next-actions.mjs +7 -7
  88. package/skills/engineering/resolve-issues/scripts/plan-sync.mjs +1 -1
  89. package/skills/engineering/resolve-issues/scripts/size-check.mjs +6 -5
  90. package/skills/engineering/resolve-release/SKILL.md +1 -1
  91. package/skills/engineering/rush-issues/SKILL.md +1 -1
  92. package/skills/engineering/rush-release/SKILL.md +1 -1
  93. package/skills/engineering/test-quality/SKILL.md +1 -1
  94. package/skills/risk-compliance/compliance-audit/SKILL.md +1 -1
  95. package/skills/risk-compliance/contract-compare/SKILL.md +1 -1
  96. package/skills/risk-compliance/contract-review/SKILL.md +1 -1
  97. package/skills/risk-compliance/doc-authenticity/SKILL.md +1 -1
  98. package/skills/risk-compliance/fraud-detection/SKILL.md +1 -1
  99. package/skills/risk-compliance/payment-analysis/SKILL.md +1 -1
  100. package/skills/risk-compliance/portfolio-payment-analysis/SKILL.md +1 -1
  101. package/skills/risk-compliance/similar-domain/SKILL.md +1 -1
  102. 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.16",
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": "efea727f2b53be74c1dad921e4d976e9a4bf22054a5461217bea9a5983de48cc",
32
- "releaseIdentity": "357a73a8819a5c43f9e6d935ece7e5efc38519d0b83e0984798677c4cb9dfc0d"
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": "26eb35331224e4dd2e0e8ef13bafd6383af21ae416bcf9e5acc28e68c6b45221"
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.48.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, 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.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
- The skill references Maestro; it does not bundle or install it. A repo with no journey tool
64
- is offered Maestro for new single-device journeys; a repo with a working harness keeps it
65
- and adds Maestro flows alongside. Run it on the session's own emulator
66
- (`maestro --device <serial>`) and convert its output with
67
- [maestro_failure.py](scripts/maestro_failure.py), which writes the record above. Read
68
- [UI journeys](references/ui-journeys.md) for the device-ownership cost, evidence layout, MCP
69
- use and the cases that 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.
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
- | 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` |
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: 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
 
@@ -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 and cleanup exit. For a failure,
177
- name the earliest failing checkpoint and link retained evidence; preserve failed attempts.
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`: 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.
@@ -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, screenshots, and backend and Metro logs
232
- when the selected variant uses those services. Preserve the failed checkpoint's evidence
233
- before cleanup. A release build with embedded assets does not require Metro by default.
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 and the cleanup results: database dropped, emulator exited,
389
- container removed, no listeners left on the backend or Metro ports.
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 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 | 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
- 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 }