@1aboveio/skills 1.0.12 → 1.0.14
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 +151 -148
- package/README.md +1 -1
- package/package.json +5 -5
- package/skills/app-dev/airflow/SKILL.md +1 -1
- package/skills/app-dev/android-development/SKILL.md +126 -0
- package/skills/app-dev/android-development/references/android-conventions.md +117 -0
- package/skills/app-dev/{android-foundation → android-development}/references/ci.md +10 -6
- package/skills/app-dev/{android-foundation → android-development}/references/diagnosis.md +39 -15
- package/skills/app-dev/android-development/references/feature-work.md +171 -0
- package/skills/app-dev/android-development/references/framework-choice.md +88 -0
- package/skills/app-dev/{android-foundation → android-development}/references/gotchas.md +43 -6
- package/skills/app-dev/android-development/references/init.md +104 -0
- package/skills/app-dev/android-development/references/setup.md +389 -0
- package/skills/app-dev/android-development/references/workspace.md +156 -0
- package/skills/app-dev/android-development/scripts/init.mjs +380 -0
- 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 +2 -2
- 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 +9 -3
- package/skills/engineering/engineering/references/init-scope.md +7 -3
- package/skills/engineering/engineering/references/scope-management.md +9 -0
- package/skills/engineering/engineering/scripts/init.mjs +40 -17
- 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/resolve-issues/SKILL.md +4 -3
- package/skills/engineering/resolve-issues/references/ci.md +9 -3
- package/skills/engineering/resolve-issues/references/delivery-progress.md +12 -2
- package/skills/engineering/resolve-issues/references/expire.md +16 -8
- package/skills/engineering/resolve-issues/references/exploration.md +1 -1
- package/skills/engineering/resolve-issues/references/implementation.md +15 -7
- package/skills/engineering/resolve-issues/references/principles.md +5 -3
- package/skills/engineering/resolve-issues/scripts/next-actions.mjs +5 -2
- 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/skills/app-dev/android-foundation/SKILL.md +0 -248
- package/skills/app-dev/android-foundation/references/delivery-focus.md +0 -31
- package/skills/app-dev/android-foundation/references/feature-work.md +0 -50
- package/skills/app-dev/android-foundation/references/setup.md +0 -188
- package/skills/app-dev/android-foundation/references/workspace.md +0 -81
- /package/skills/app-dev/{android-foundation → android-development}/LICENSE +0 -0
- /package/skills/app-dev/{android-foundation → android-development}/assets/android-ci-job.yml +0 -0
- /package/skills/app-dev/{android-foundation → android-development}/release-check.mjs +0 -0
- /package/skills/app-dev/{android-foundation → android-development}/scripts/device-run.sh +0 -0
- /package/skills/app-dev/{android-foundation → android-development}/scripts/workspace-runtime/bin/workspaces.mjs +0 -0
- /package/skills/app-dev/{android-foundation → android-development}/scripts/workspace-runtime/native-workspace.mjs +0 -0
- /package/skills/app-dev/{android-foundation → android-development}/scripts/workspace-runtime/workspace-lifecycle.mjs +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Choose Kotlin/Compose or React Native
|
|
2
|
+
|
|
3
|
+
Choose the smallest design that preserves the required behavior and reduces demonstrated
|
|
4
|
+
coordination cost. Recommend a concrete default below; do not answer a framework decision
|
|
5
|
+
with only "it depends." Apply the product's platform requirements and existing ADRs first.
|
|
6
|
+
If one missing requirement would reverse the choice, name that requirement and ask for it.
|
|
7
|
+
|
|
8
|
+
## Choose by situation
|
|
9
|
+
|
|
10
|
+
| Situation | Recommendation | What must hold |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| Existing React Native app; delay is repeated builds, cold setup or oversized verification | Keep React Native and repair the development loop. Do not propose migration for this evidence. | JS edits use the compatible running app; native edits use the verified incremental path; required acceptance stays intact. |
|
|
13
|
+
| New flow with required Android/iOS UI reuse, mostly forms, lists and API interaction | Prefer React Native. Use platform-specific code only for demonstrated platform needs. | Verify the required native SDKs and platform behavior can be integrated without unacceptable ownership/synchronization costs. |
|
|
14
|
+
| New Android-only flow dominated by hardware/SDK interaction, IME/Back/focus, windows or Activity lifecycle | Prefer Kotlin with Jetpack Compose as the starting design. Keep the related UI state and lifecycle under one coherent native owner. | Android-only scope is confirmed; backend/security contracts and required validation remain unchanged. Kotlin is not a promise of faster builds. |
|
|
15
|
+
| Existing React Native flow repeatedly fails at demonstrated RN/native event or state coordination | First remove duplicated authority in the existing design. If that cannot meet the requirement, recommend an explicitly authorized Kotlin-owned coherent screen/flow as the next candidate, not many tiny bridged controls. | Define the boundary and its API, navigation and lifecycle responsibilities. Compare retained integration cost with the coordination being removed; preserve iOS obligations. |
|
|
16
|
+
| Product-wide migration proposed, or platform/reuse/maintenance trade-offs remain unresolved | Keep the current stack for ordinary delivery. Present the candidate decision and obtain authorization for a bounded comparison or architecture change. | No migration, standalone host, benchmark campaign or new framework is implied by an ordinary bug fix. |
|
|
17
|
+
|
|
18
|
+
Use the native-heavy recommendation for new design decisions, not as permission to rewrite
|
|
19
|
+
working React Native code. A single native SDK is not by itself a reason to migrate a whole
|
|
20
|
+
app. Conversely, shared UI is not a reason to force a platform-specific workflow through
|
|
21
|
+
multiple owners when the required behavior cannot be supported reliably.
|
|
22
|
+
|
|
23
|
+
## Compare the actual development paths
|
|
24
|
+
|
|
25
|
+
| Dimension | React Native with native modules | Kotlin with Jetpack Compose |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| UI styling and state iteration | Fast Refresh/reload can update supported JS/TS edits in an owned running debug app without a native build. | Compose Preview/Live Edit can help when the actual tooling supports them; structural changes still require compilation/deployment. |
|
|
28
|
+
| Business logic | Focused JS/TS tests and runtime debugging; native contracts still need composition proof. | Focused Kotlin/JVM tests and runtime debugging; platform/backend contracts still need composition proof. |
|
|
29
|
+
| Android APIs, hardware and SDKs | Native modules or components add a contract between JS and Android when needed. | Direct Android API/SDK integration can remove that cross-runtime adapter. |
|
|
30
|
+
| IME, Back, focus and window lifecycle | Define ownership across the React tree, native component and Android host; asynchronous events must not create competing authority. | A coherent native screen can reduce inter-framework coordination, but still needs correct state, event and lifecycle handling. |
|
|
31
|
+
| Build feedback | JS-only feedback can avoid Gradle; changed native inputs require native rebuilding. | Native changes use the supported incremental build/run path; Kotlin is not automatically a cheaper cold build. |
|
|
32
|
+
| Tests | May combine JS, JVM, instrumentation and device journeys. | May combine JVM, instrumentation and device journeys; one UI toolkit does not eliminate integration or acceptance layers. |
|
|
33
|
+
| Android/iOS reuse | Can share UI and logic, with explicit platform-specific behavior. | An Android Compose UI does not supply an iOS UI. Account for separate iOS work or an independently approved sharing strategy. |
|
|
34
|
+
|
|
35
|
+
For an agent, compare tools it can actually operate. Do not count Android Studio Preview or
|
|
36
|
+
Live Edit as available feedback in a headless CLI workflow without verifying access. Live
|
|
37
|
+
Edit has edit/runtime constraints; preview or live updates do not prove native interaction,
|
|
38
|
+
packaged startup or release behavior. Use the pinned toolchain, not assumed IDE capabilities.
|
|
39
|
+
|
|
40
|
+
## Decide where ownership belongs
|
|
41
|
+
|
|
42
|
+
For a native-heavy editor or sheet, assign one authoritative owner for draft state,
|
|
43
|
+
Apply/Cancel, IME/Back handling and focus restoration. Define who accepts the final result
|
|
44
|
+
and rejects stale events. Prefer a coherent screen/flow boundary over splitting each
|
|
45
|
+
gesture and transition across runtimes. Keep business authorization and backend authority
|
|
46
|
+
where the product contract requires them; moving UI ownership does not transfer those powers.
|
|
47
|
+
|
|
48
|
+
Do not delete process-death recovery, persistence, identity, authorization, stale-callback
|
|
49
|
+
guards or tests just because a bridge disappears. Identify which adapters become unnecessary
|
|
50
|
+
and which correctness contracts remain. More Kotlin inside a React Native host may retain
|
|
51
|
+
the boundary; it is not evidence for a pure-native architecture's cost.
|
|
52
|
+
|
|
53
|
+
## Make and report the decision
|
|
54
|
+
|
|
55
|
+
1. State the recommendation first: keep React Native, use React Native for the new flow,
|
|
56
|
+
prefer Kotlin/Compose for the new Android-only flow, or evaluate a specific native-owned
|
|
57
|
+
boundary. Name the platform and behavior facts that support it.
|
|
58
|
+
2. Fix avoidable feedback-loop costs before comparing engineering effort: no repeated cold
|
|
59
|
+
setup, unnecessary test packaging or all-ABI build for every local edit. Keep the
|
|
60
|
+
[validation ladder](../SKILL.md#validation-ladder) and required CI in both paths.
|
|
61
|
+
3. If a comparison is authorized, use the same representative behavior, backend/security
|
|
62
|
+
contracts and acceptance criteria. Compare total implementation/debug/verification effort,
|
|
63
|
+
failed iterations and their causes, plus build/startup cost using existing records.
|
|
64
|
+
Adapter lines are supporting evidence, not the decision metric. Do not invent timings,
|
|
65
|
+
a universal percentage threshold, or a new metrics service.
|
|
66
|
+
4. A standalone native host can test whether an interaction becomes simpler, but excludes
|
|
67
|
+
production integration, navigation, deployment and iOS costs. Report that scope separately;
|
|
68
|
+
do not compare its narrow success with full production acceptance as equivalent work.
|
|
69
|
+
5. Recommend adoption only for the scope supported by the evidence. Record platform/reuse
|
|
70
|
+
trade-offs, retained contracts, transition/rollback costs and unresolved proof in the
|
|
71
|
+
project's existing decision record. Ask for approval before changing an established stack
|
|
72
|
+
or launching a new experiment. Continue ordinary fixes within their authorized scope.
|
|
73
|
+
|
|
74
|
+
## Avoids
|
|
75
|
+
|
|
76
|
+
- Do not choose a framework from one slow build, a PR count or generic "excellent" ratings.
|
|
77
|
+
- Do not promise that Kotlin removes Android lifecycle or backend correctness obligations.
|
|
78
|
+
- Do not replace an optimized React Native baseline with an artificially cheap native demo.
|
|
79
|
+
- Do not turn this guide into a Kotlin-only preference, mandatory experiment or migration gate.
|
|
80
|
+
- Do not assume Android-only deployment or that cross-platform reuse has no product value.
|
|
81
|
+
|
|
82
|
+
## Public tooling references
|
|
83
|
+
|
|
84
|
+
Check behavior against the project's versions before selecting a feedback mechanism:
|
|
85
|
+
|
|
86
|
+
- [React Native 0.81 build scope and ABI selection](https://reactnative.dev/docs/0.81/build-speed)
|
|
87
|
+
- [Expo local development and Metro reuse](https://docs.expo.dev/guides/local-app-development/)
|
|
88
|
+
- [Compose iterative development and Live Edit limitations](https://developer.android.com/develop/ui/compose/tooling/iterative-development)
|
|
@@ -1,4 +1,36 @@
|
|
|
1
|
-
# Android
|
|
1
|
+
# Android development gotchas
|
|
2
|
+
|
|
3
|
+
## Triage
|
|
4
|
+
|
|
5
|
+
Name the earliest stage that failed. In CI, that is the first failed step. If the same
|
|
6
|
+
journey passed on another run of the same commit, suspect the run or the journey before
|
|
7
|
+
the product.
|
|
8
|
+
|
|
9
|
+
| Stage | Typical signal |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| Prerequisites / install | missing SDK directory, wrong JDK, lockfile drift |
|
|
12
|
+
| Harness unit tests (CI, before the APK) | a harness test fails on host state its fixture should fake (`requires 2 GiB reserve`) |
|
|
13
|
+
| Export / APK | Metro bundling error, Gradle compile or dependency-resolution error |
|
|
14
|
+
| Gradle network | Maven download or TLS-handshake errors on a cold build: fix routing, not code |
|
|
15
|
+
| Emulator boot / ADB | `sys.boot_completed` never reaches 1, device offline, exit 124 |
|
|
16
|
+
| Device to Metro | red box, "unable to load script", missing `adb reverse` mapping |
|
|
17
|
+
| Bridge passes, debug app fails to load | possible app/probe endpoint mismatch; inspect the actual request before choosing a cause ([React Native example](diagnosis.md#example-react-native-debug-app-uses-another-metro)) |
|
|
18
|
+
| Device to Metro, mid-journey | a screen's first Metro asset fails (`Unable to download asset from url: http://127.0.0.1:8081/assets/…`) while API calls still succeed |
|
|
19
|
+
| Backend / Login | backend log errors, verification code not found in the database |
|
|
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
|
+
| adb transport, mid-journey | `connection terminated: read failed` in the adb trace after boot, then lost `adb reverse`: usually guest RAM |
|
|
22
|
+
| UiAutomator server | `RemoteDisconnected` while the adb transport stays up: the on-device server was relaunched |
|
|
23
|
+
| Journey harness | a wait right after a navigation times out while the destination is on screen |
|
|
24
|
+
| Journey harness, short screen | a wait for a label times out only on a short or landscape screen, which shows the content above it |
|
|
25
|
+
| Product assertion | a screen or state mismatch with a screenshot |
|
|
26
|
+
|
|
27
|
+
Then match the signal against [gotchas.md](gotchas.md). If nothing
|
|
28
|
+
matches, [confirm the suspected cause](gotchas.md#confirm-a-suspected-cause)
|
|
29
|
+
before changing code.
|
|
30
|
+
|
|
31
|
+
Preserve the failure evidence. Do not blindly replay steps that send codes, verify sessions
|
|
32
|
+
or charge payments just to get a passing screenshot. One passing run does not prove the
|
|
33
|
+
build is reliable.
|
|
2
34
|
|
|
3
35
|
Known traps, each as signal, cause and fix. Match the signal before you dig. If none
|
|
4
36
|
matches, [confirm the suspected cause](#confirm-a-suspected-cause) before changing code.
|
|
@@ -58,10 +90,12 @@ matches, [confirm the suspected cause](#confirm-a-suspected-cause) before changi
|
|
|
58
90
|
recovers, Metro becomes unreachable, and a debug build loads assets from Metro. A
|
|
59
91
|
backend reached at `10.0.2.2` does not use adb, so it keeps working. The usual trigger is
|
|
60
92
|
an [adb transport drop](#the-adb-transport-drops-mid-journey); fix that first.
|
|
61
|
-
- **Fix:**
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
93
|
+
- **Fix:** after a transport reconnect or observed mapping loss, restore the owned reverse
|
|
94
|
+
and verify device-to-Metro loading before continuing the affected check. Preserve a
|
|
95
|
+
harness's required checkpoints, but do not reset mappings or probe every screen by
|
|
96
|
+
default in an unchanged warm session. Determine the selected variant's real asset
|
|
97
|
+
mechanism before classifying the failure; an absent mapping alone does not prove
|
|
98
|
+
that the harness rather than the app caused the disconnect.
|
|
65
99
|
|
|
66
100
|
### The adb transport drops mid-journey
|
|
67
101
|
|
|
@@ -191,7 +225,10 @@ matches, [confirm the suspected cause](#confirm-a-suspected-cause) before changi
|
|
|
191
225
|
|
|
192
226
|
- **Cause:** the slot's tool cache is empty, so the JDK or Python downloads from the
|
|
193
227
|
internet.
|
|
194
|
-
- **Fix:**
|
|
228
|
+
- **Fix:** report the cold tool cache and hand provisioning to the runner owner through
|
|
229
|
+
`github-actions` and the fleet policy. A compatible cache seed may be their remedy;
|
|
230
|
+
do not copy or mutate either slot's shared `_tool/` state during an ordinary Android
|
|
231
|
+
diagnosis without a separate provisioning assignment.
|
|
195
232
|
|
|
196
233
|
### A Backend call fails only in CI: the runner lacks a tool the app launches
|
|
197
234
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Project initialization
|
|
2
|
+
|
|
3
|
+
`android-development` persists one section of project Android guidance. This helper is the
|
|
4
|
+
deterministic writer behind that setup; `SKILL.md` owns the interactive choice that decides
|
|
5
|
+
whether anything is persisted.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
node {baseDir}/scripts/init.mjs [--repo-root <dir>] [--write]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
- Preview is the default: it prints the planned action per file and writes nothing.
|
|
14
|
+
- `--write` applies the plan. `--repo-root` selects the project; without it the nearest Git root
|
|
15
|
+
from the current directory is used, falling back to the current directory when there is none.
|
|
16
|
+
- `--help` prints the usage line.
|
|
17
|
+
- An unknown argument, an unresolvable root, a malformed marker or an unsafe target exits
|
|
18
|
+
non-zero with a message and no writes.
|
|
19
|
+
|
|
20
|
+
## Files and ownership
|
|
21
|
+
|
|
22
|
+
When Project or explicit init is selected, preview with the command above, then apply it
|
|
23
|
+
with `--write` for the authorized missing additions. Existing conflicting policy needs a
|
|
24
|
+
decision, not an overwrite. Verify the repo's actual commands and add only known bindings
|
|
25
|
+
to a newly created Android section; report unresolved commands instead of guessing them.
|
|
26
|
+
|
|
27
|
+
| File | Write |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `CONTRIBUTING.md` | The `## Android development` section, wrapped in `<!-- conventions:android:start -->` / `<!-- conventions:android:end -->`, with `references/android-conventions.md` as its body. |
|
|
30
|
+
| `AGENTS.md` | A short pointer to the selected `CONTRIBUTING.md`, added only when no correct loader link exists yet. |
|
|
31
|
+
|
|
32
|
+
Each file is created only when it is absent. The helper never edits `CLAUDE.md`, never writes into
|
|
33
|
+
a parent project, a home directory or global agent configuration, and never reaches outside the
|
|
34
|
+
selected root.
|
|
35
|
+
|
|
36
|
+
After applying authorized additions, verify that each existing supported agent entrypoint
|
|
37
|
+
reaches the Android section, directly or through its instruction chain. The helper configures
|
|
38
|
+
`AGENTS.md`; it does not certify an independent `CLAUDE.md` loader. Preserve existing chains
|
|
39
|
+
and do not edit that entrypoint under this init permission. If one does not reach the guide,
|
|
40
|
+
report the files configured and the unresolved loading path as partial setup. Obtain separate
|
|
41
|
+
authorization for any additional loader edit instead of silently claiming complete setup.
|
|
42
|
+
|
|
43
|
+
## Resolve the repo command map
|
|
44
|
+
|
|
45
|
+
The initializer, not the deterministic writer, inspects existing scripts and guidance.
|
|
46
|
+
Prefer the repo's working development route over adding another wrapper. For a new Android
|
|
47
|
+
section, persist verified bindings in that section using this compact convention:
|
|
48
|
+
|
|
49
|
+
| Lane | Working directory and command | Inputs/artifacts and owner | Verification status |
|
|
50
|
+
| --- | --- | --- | --- |
|
|
51
|
+
| L0 | Existing Metro start/reuse, focused tests and typecheck | JS delivery endpoint and owned running app | Observed or unresolved |
|
|
52
|
+
| L1 | Incremental native build/install | Actual device ABI, scoped override, Gradle graph, app vs test APKs | Observed or unresolved |
|
|
53
|
+
| L2 | Candidate startup/install and selected journey | Candidate artifact, supported selectors and disposable state owner | Observed or unresolved |
|
|
54
|
+
| L3 | Existing required CI and release checks | Required test artifacts, device/ABI matrix and acceptance owner | Existing binding requirement |
|
|
55
|
+
|
|
56
|
+
Inspect wrapper/task expansion using [feature work](feature-work.md#verify-command-expansion)
|
|
57
|
+
when the owned toolchain permits it; reading a script is not executing its graph. Record
|
|
58
|
+
what was inspected versus run and leave missing evidence unresolved. Initialization does
|
|
59
|
+
not require a cold build, emulator provisioning, CI dispatch or acceptance campaign.
|
|
60
|
+
Record native/JS invalidation triggers and [development-session ownership](workspace.md).
|
|
61
|
+
Do not invent a command, selector or flag to complete the table.
|
|
62
|
+
|
|
63
|
+
On later init runs, preserve the existing section and manual bindings without refreshing
|
|
64
|
+
them. An authorized correction to stale commands is a deliberate policy edit, not a side
|
|
65
|
+
effect of initialization or a new skill version.
|
|
66
|
+
|
|
67
|
+
## Preservation
|
|
68
|
+
|
|
69
|
+
Existing guidance wins over the template:
|
|
70
|
+
|
|
71
|
+
- An existing `## Android development` heading, marked or hand-written, is left byte-for-byte,
|
|
72
|
+
including any repository-specific commands a caller added.
|
|
73
|
+
- Every other section, hand edit and file is preserved; initialization appends and never
|
|
74
|
+
rewrites, reorders or refreshes.
|
|
75
|
+
- Repeating the same initialization leaves configured files unchanged. There is no `--force` and
|
|
76
|
+
no update path: a new skill release never replaces saved project policy.
|
|
77
|
+
- A valid symlink inside the project stays a link and its target is updated once. A dangling
|
|
78
|
+
link, a link resolving outside the selected root, a directory, unreadable or non-UTF-8 content,
|
|
79
|
+
and two targets resolving to one file are refused. Every target is validated before the first
|
|
80
|
+
write, so a refusal leaves the project untouched.
|
|
81
|
+
- Refuse a mutation of a multiply hard-linked file or of an alias to the protected
|
|
82
|
+
`CLAUDE.md` entrypoint. This includes a shared AGENTS/CLAUDE target: preserve it and
|
|
83
|
+
report the boundary rather than silently granting a new write permission.
|
|
84
|
+
- An existing pointer is reused only when its link resolves to the selected `CONTRIBUTING.md`,
|
|
85
|
+
and a new pointer is written relative to the real location of `AGENTS.md`. A link to some other
|
|
86
|
+
file, such as a nested package guide, does not count as this project's loader.
|
|
87
|
+
|
|
88
|
+
## What it does not do
|
|
89
|
+
|
|
90
|
+
Initialization is not installation or delivery. It does not install dependencies, SDK components
|
|
91
|
+
or devices, provision an emulator, generate CI, open issues, push or release. It does not
|
|
92
|
+
discover commands automatically: the initializer follows the command map above and reports
|
|
93
|
+
what it could not resolve. Adding verified repository-specific bindings to the new section is
|
|
94
|
+
part of that explicit initialization; a
|
|
95
|
+
conflicting existing rule is reported rather than overwritten.
|
|
96
|
+
|
|
97
|
+
## Scope and overrides
|
|
98
|
+
|
|
99
|
+
The section applies to the project root it was written in, for later sessions. A Session choice
|
|
100
|
+
keeps the ladder in conversation only and writes no files or configuration, including after
|
|
101
|
+
compaction; an ordinary Android task reads existing guidance and does not initialize or ask about
|
|
102
|
+
setup by itself. `SKILL.md` owns that interactive choice and its lifetime.
|
|
103
|
+
|
|
104
|
+
Initialization does not authorize a commit, push, pull request, enqueue or release.
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# Android setup and device execution
|
|
2
|
+
|
|
3
|
+
Read [setup rules](#setup-rules) and [owned-resource cleanup](#owned-resource-cleanup)
|
|
4
|
+
before these commands. All stages are for fresh setup proof; established workspaces use
|
|
5
|
+
the [validation ladder](../SKILL.md#validation-ladder) and the
|
|
6
|
+
[owned development session](#owned-development-session), and rerun only invalidated stages.
|
|
7
|
+
|
|
8
|
+
Treat the shell blocks as an Expo/pnpm/UiAutomator example, not a required stack. Use the
|
|
9
|
+
repo's verified package manager, native build, bundle/export step and existing test harness.
|
|
10
|
+
Keep ownership, installed-toolchain, deadlines, cleanup and proof requirements mandatory;
|
|
11
|
+
do not install Expo, Python automation or a new harness to make another RN project fit.
|
|
12
|
+
|
|
13
|
+
Replace each `<placeholder>` with the repo's real value. Tool shells do not keep variables,
|
|
14
|
+
functions or traps between calls: step 1 resolves the workspace and writes
|
|
15
|
+
`.cache/android-env.sh`, which also `cd`s into it; every later block starts by sourcing it by
|
|
16
|
+
absolute path, and steps 6–8 run as one command through the bundled `scripts/device-run.sh`.
|
|
17
|
+
|
|
18
|
+
## Contents
|
|
19
|
+
|
|
20
|
+
- [Fresh setup stages](#1-workspace-and-environment)
|
|
21
|
+
- [Owned development session](#owned-development-session)
|
|
22
|
+
- [Scoped ABI selection](#scoped-abi-selection)
|
|
23
|
+
- [Setup rules](#setup-rules)
|
|
24
|
+
- [Owned-resource cleanup](#owned-resource-cleanup)
|
|
25
|
+
- [Setup evidence](#evidence-record)
|
|
26
|
+
|
|
27
|
+
## 1. Workspace and environment
|
|
28
|
+
|
|
29
|
+
Workspace precedence is owned by [workspace.md](workspace.md). Do not create a worktree,
|
|
30
|
+
switch branch, fetch or reset when the caller supplied an isolated workspace.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
set -euo pipefail
|
|
34
|
+
ASSIGNED_WORKSPACE=<assigned-workspace-or-empty>
|
|
35
|
+
CANDIDATE_HEAD=<candidate-head-or-empty>
|
|
36
|
+
WORKSPACE="${ASSIGNED_WORKSPACE:?use the caller assignment or native-start result from workspace.md}"
|
|
37
|
+
test -d "$WORKSPACE"
|
|
38
|
+
git -C "$WORKSPACE" rev-parse --is-inside-work-tree >/dev/null
|
|
39
|
+
cd "$WORKSPACE"
|
|
40
|
+
actual_head="$(git rev-parse HEAD)"
|
|
41
|
+
test -z "$CANDIDATE_HEAD" || test "$actual_head" = "$(git rev-parse "$CANDIDATE_HEAD^{commit}")" || {
|
|
42
|
+
echo "workspace HEAD $actual_head != candidate $CANDIDATE_HEAD; report it; do not switch" >&2
|
|
43
|
+
exit 1
|
|
44
|
+
}
|
|
45
|
+
mkdir -p .cache
|
|
46
|
+
{ echo 'set -euo pipefail'; printf 'cd %q\n' "$PWD"; printf 'export ANDROID_SOURCE_HEAD=%q\n' "$actual_head"; } > .cache/android-env.sh
|
|
47
|
+
cat >> .cache/android-env.sh <<'ENV'
|
|
48
|
+
|
|
49
|
+
# Repo-specific names, read from the repo's journey wrapper and device harness.
|
|
50
|
+
export APP_FILTER=<android-workspace-package> # pnpm --filter target
|
|
51
|
+
export DEVICE_PYTHON_DIR=<venv-dir-the-wrapper-reads> # e.g. the default in the wrapper
|
|
52
|
+
export DB_NAME_PREFIX=<db-prefix-the-harness-accepts> # the harness rejects other names
|
|
53
|
+
export DB_URL_VAR=<harness-admin-url-variable> # e.g. SHARD_ADMIN_URL
|
|
54
|
+
export DB_NAME_VAR=<harness-db-name-variable> # e.g. SHARD_DB_NAME
|
|
55
|
+
|
|
56
|
+
# Host paths. Example values are for Apple Silicon with Android Studio.
|
|
57
|
+
export JAVA_HOME=/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home
|
|
58
|
+
export ANDROID_HOME="$HOME/Library/Android/sdk"
|
|
59
|
+
export ANDROID_SDK_ROOT="$ANDROID_HOME"
|
|
60
|
+
export SOURCE_AVD="$HOME/.android/avd/<installed-avd>.avd"
|
|
61
|
+
export SEED_GRADLE_HOME="$HOME/.gradle"
|
|
62
|
+
export PATH="$JAVA_HOME/bin:$ANDROID_HOME/platform-tools:$PATH"
|
|
63
|
+
|
|
64
|
+
# Private caches.
|
|
65
|
+
export GRADLE_USER_HOME="$PWD/.cache/gradle"
|
|
66
|
+
export ANDROID_USER_HOME="$PWD/.cache/android-user"
|
|
67
|
+
export ANDROID_AVD_HOME="$PWD/.cache/android-avd"
|
|
68
|
+
export TMPDIR="$PWD/.cache/tmp"
|
|
69
|
+
export npm_config_cache="$PWD/.cache/npm"
|
|
70
|
+
export npm_config_devdir="$PWD/.cache/node-gyp"
|
|
71
|
+
export PNPM_CONFIG_STORE_DIR="$PWD/.cache/pnpm-store"
|
|
72
|
+
export PNPM_CONFIG_CACHE_DIR="$PWD/.cache/pnpm"
|
|
73
|
+
case "${JAVA_TOOL_OPTIONS:-}" in *java.io.tmpdir*) ;; *)
|
|
74
|
+
export JAVA_TOOL_OPTIONS="${JAVA_TOOL_OPTIONS:+$JAVA_TOOL_OPTIONS }-Djava.io.tmpdir=$TMPDIR" ;; esac
|
|
75
|
+
|
|
76
|
+
# Run identifiers: an even console port in 5554-5584 (adb scans only that range),
|
|
77
|
+
# and backend/Metro ports under the names the journey wrapper reads.
|
|
78
|
+
export SETUP_AVD=<new-unique-avd-name>
|
|
79
|
+
export EMULATOR_PORT=<even-port-5554-5584>
|
|
80
|
+
export ANDROID_BACKEND_PORT=<free-port>
|
|
81
|
+
export ANDROID_METRO_PORT=<free-port>
|
|
82
|
+
# Choose the whole-journey deadline; zero disables it and is not suitable for unattended runs.
|
|
83
|
+
export JOURNEY_SECONDS=<positive-journey-timeout-seconds>
|
|
84
|
+
ENV
|
|
85
|
+
source .cache/android-env.sh
|
|
86
|
+
mkdir -p "$TMPDIR" "$npm_config_cache" "$npm_config_devdir" \
|
|
87
|
+
"$ANDROID_USER_HOME" "$ANDROID_AVD_HOME" .cache/logs
|
|
88
|
+
|
|
89
|
+
node --version; pnpm --version; java -version; python3 --version
|
|
90
|
+
adb version; "$ANDROID_HOME/emulator/emulator" -version
|
|
91
|
+
# Versions come from the repo's native config and CI preflight.
|
|
92
|
+
for component in platforms/android-<api> build-tools/<build-tools> ndk/<ndk> cmake/<cmake>; do
|
|
93
|
+
test -d "$ANDROID_HOME/$component" || { echo "Missing SDK: $component" >&2; exit 1; }
|
|
94
|
+
done
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The recorded standalone path is reused on retries; verify its lifecycle record names this
|
|
98
|
+
run, branch and base. If an assigned path is missing, is not a Git worktree, or is at another
|
|
99
|
+
revision, stop and report instead of creating another checkout. Never fall back to
|
|
100
|
+
`../<repo>-android-setup`.
|
|
101
|
+
|
|
102
|
+
If the wrapper reads ports or Python under other names, export aliases in
|
|
103
|
+
`android-env.sh` **as well as** the bundled runner's required names. For example,
|
|
104
|
+
`export APP_METRO_PORT="$ANDROID_METRO_PORT"`; both must select the same port. Adapt
|
|
105
|
+
`DB_URL_VAR` and `DB_NAME_VAR` to the actual harness, not its fallback defaults.
|
|
106
|
+
|
|
107
|
+
## 2. Install and check
|
|
108
|
+
|
|
109
|
+
Run the repo's frozen install, relevant tests and typecheck. Export/bundle using the
|
|
110
|
+
selected framework's supported command; use `expo export` only for an Expo project.
|
|
111
|
+
Create a Python venv and pin UiAutomator only when the existing harness uses them.
|
|
112
|
+
For Yarn/npm or an instrumentation-only harness, substitute its verified commands and
|
|
113
|
+
omit unused pnpm/Python environment settings; do not invent replacements or install tools.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
source <worktree>/.cache/android-env.sh
|
|
117
|
+
pnpm install --frozen-lockfile --store-dir "$PWD/.cache/pnpm-store"
|
|
118
|
+
pnpm --filter "$APP_FILTER" test
|
|
119
|
+
pnpm --filter "$APP_FILTER" typecheck
|
|
120
|
+
EXPO_PUBLIC_API_URL=https://app.invalid \
|
|
121
|
+
pnpm --filter "$APP_FILTER" exec expo export --platform android
|
|
122
|
+
python3 -m venv "$DEVICE_PYTHON_DIR"
|
|
123
|
+
"$DEVICE_PYTHON_DIR/bin/python3" -m pip install uiautomator2==<harness-pinned-version>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 3. Gradle dependencies (pick one)
|
|
127
|
+
|
|
128
|
+
Seed from a trusted Gradle home:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
source <worktree>/.cache/android-env.sh
|
|
132
|
+
mkdir -p "$GRADLE_USER_HOME/caches/modules-2/files-2.1"
|
|
133
|
+
rsync -r --ignore-existing \
|
|
134
|
+
--exclude='*.lock' --exclude='*.lck' --exclude='*.tmp' \
|
|
135
|
+
"$SEED_GRADLE_HOME/caches/modules-2/files-2.1/" \
|
|
136
|
+
"$GRADLE_USER_HOME/caches/modules-2/files-2.1/"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Or wire a trusted Maven proxy into the private Gradle home. Append the exports to
|
|
140
|
+
`android-env.sh` so the build in step 4 sees them. Route every repository the build uses,
|
|
141
|
+
JitPack included; a route left unset goes straight upstream.
|
|
142
|
+
|
|
143
|
+
If the opted-in proxy fails, stop and fix its routing; never fall back to direct
|
|
144
|
+
downloads or disable TLS checks. The proxy covers Maven repositories only. Route the
|
|
145
|
+
Gradle wrapper ZIP and pnpm as the repo's `CONTRIBUTING.md` requires. Without a seed or
|
|
146
|
+
opted-in proxy, use upstream intentionally and allow for a cold build.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
source <worktree>/.cache/android-env.sh
|
|
150
|
+
cat >> "$PWD/.cache/android-env.sh" <<'ENV'
|
|
151
|
+
export GRADLE_MAVEN_REPOSITORY=<proxy>/maven/
|
|
152
|
+
export GRADLE_GOOGLE_REPOSITORY=<proxy>/google-maven/
|
|
153
|
+
export GRADLE_PLUGIN_REPOSITORY=<proxy>/gradle-plugins/
|
|
154
|
+
export GRADLE_JITPACK_REPOSITORY=<proxy>/jitpack/
|
|
155
|
+
ENV
|
|
156
|
+
curl --fail --silent --show-error --max-time 10 <proxy-health-url>
|
|
157
|
+
install -d "$GRADLE_USER_HOME/init.d"
|
|
158
|
+
install -m 0644 <path/to/proxy.init.gradle> "$GRADLE_USER_HOME/init.d/proxy.init.gradle"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## 4. Build
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
source <worktree>/.cache/android-env.sh
|
|
165
|
+
pnpm build:android --max-workers=2 -Dorg.gradle.parallel=false \
|
|
166
|
+
-Pandroid.builder.sdkDownload=false --console=plain --info \
|
|
167
|
+
2>&1 | tee .cache/logs/gradle.log
|
|
168
|
+
APK=<path/to/app/build/outputs/apk/debug/app-debug.apk>
|
|
169
|
+
shasum -a 256 "$APK" # sha256sum on Linux
|
|
170
|
+
unzip -l "$APK" | grep -E 'lib/[^/]+/libreactnative\.so'
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 5. Owned emulator
|
|
174
|
+
|
|
175
|
+
Copy only `config.ini`, never user data or snapshots. Verify that `image.sysdir.1` is an
|
|
176
|
+
installed, host-compatible system image and that `target` matches it. Give the guest
|
|
177
|
+
4 GB to avoid mid-journey ADB drops. A hand-written config needs the hardware keys in
|
|
178
|
+
[gotchas](gotchas.md#a-hand-written-avd-misses-the-screen).
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
source <worktree>/.cache/android-env.sh
|
|
182
|
+
test -f "$SOURCE_AVD/config.ini"
|
|
183
|
+
test ! -e "$ANDROID_AVD_HOME/$SETUP_AVD.ini"
|
|
184
|
+
test ! -e "$ANDROID_AVD_HOME/$SETUP_AVD.avd"
|
|
185
|
+
grep '^image.sysdir.1' "$SOURCE_AVD/config.ini" # must be an installed, host-compatible image
|
|
186
|
+
mkdir "$ANDROID_AVD_HOME/$SETUP_AVD.avd"
|
|
187
|
+
# Copy without the source's RAM size and give the guest 4 GB (gotchas: adb transport drops).
|
|
188
|
+
grep -Ev '^hw\.ramSize[[:space:]]*=' "$SOURCE_AVD/config.ini" > "$ANDROID_AVD_HOME/$SETUP_AVD.avd/config.ini"
|
|
189
|
+
echo 'hw.ramSize=4096' >> "$ANDROID_AVD_HOME/$SETUP_AVD.avd/config.ini"
|
|
190
|
+
printf 'avd.ini.encoding=UTF-8\npath=%s\ntarget=android-<api>\n' \
|
|
191
|
+
"$ANDROID_AVD_HOME/$SETUP_AVD.avd" > "$ANDROID_AVD_HOME/$SETUP_AVD.ini"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 6–8. Cleanup, resources and journey: one command
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
source <worktree>/.cache/android-env.sh
|
|
198
|
+
bash <skill-base-dir>/scripts/device-run.sh \
|
|
199
|
+
--drop node <path/to/device-harness.mjs> drop \
|
|
200
|
+
-- bash <path/to/foundation-journey-wrapper.sh>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Pass each command as separate words, not as one quoted string. The script:
|
|
204
|
+
|
|
205
|
+
1. Registers the cleanup trap before anything starts.
|
|
206
|
+
2. Refuses an emulator port outside 5554–5584 and any busy port.
|
|
207
|
+
3. Starts the ADB server, then the emulator (its PID recorded), then `postgres` with
|
|
208
|
+
`--cidfile` on a random loopback port. Override the image with `POSTGRES_IMAGE`.
|
|
209
|
+
4. Waits for `sys.boot_completed=1` and `pg_isready`. Startup/readiness and cleanup
|
|
210
|
+
commands have a 30-second limit (`BOUNDED_SECONDS`); exit 124 is terminal. The journey
|
|
211
|
+
uses the separate `JOURNEY_SECONDS` deadline. Leave time for cleanup after that deadline.
|
|
212
|
+
5. Exports `$DB_URL_VAR`, `$DB_NAME_VAR` (`$DB_NAME_PREFIX` plus a unique suffix) and
|
|
213
|
+
`ANDROID_EMULATOR_SERIAL`, then runs the journey.
|
|
214
|
+
6. Drops the database, stops the emulator PID (`TERM`, then `KILL` after 10 seconds),
|
|
215
|
+
removes the container by its CID, and prints `original_stage_exit=<n> cleanup_exit=<n>`.
|
|
216
|
+
It exits with the journey's status if the journey failed, else the cleanup status.
|
|
217
|
+
|
|
218
|
+
The runner supervises the journey's process group. Journey children must stay in that
|
|
219
|
+
group; a wrapper that deliberately creates detached services must stop those services
|
|
220
|
+
through its own owner. Send TERM to the launcher and allow its cleanup to finish rather
|
|
221
|
+
than killing it immediately. The generic runner inherits the caller's ADB endpoint and
|
|
222
|
+
does not stop that server: use a verified private endpoint on a shared host and close it
|
|
223
|
+
through the caller's owner. Capture the command's exit status and final summary line.
|
|
224
|
+
|
|
225
|
+
Expect every selected scenario's `PASS` marker, screenshots, and backend and Metro logs
|
|
226
|
+
when the selected variant uses those services. Preserve the failed checkpoint's evidence
|
|
227
|
+
before cleanup. A release build with embedded assets does not require Metro by default.
|
|
228
|
+
|
|
229
|
+
## Owned development session
|
|
230
|
+
|
|
231
|
+
Apply the safety/proof requirements above to a new environment or invalidated setup
|
|
232
|
+
assumptions, using only the repo's applicable stages and verified tools. The example
|
|
233
|
+
commands are not universal requirements or a per-incremental-build checklist. Ordinary iteration runs against the
|
|
234
|
+
owned development session described in [workspace.md](workspace.md): one development emulator
|
|
235
|
+
and ADB endpoint, Metro, one compatible Gradle daemon on the private `GRADLE_USER_HOME`, and
|
|
236
|
+
the workspace's build outputs. Rerun only the stages whose inputs changed, and end the session
|
|
237
|
+
or hand it off before finishing.
|
|
238
|
+
|
|
239
|
+
Keep that fast path fast:
|
|
240
|
+
|
|
241
|
+
- Reuse the compatible Gradle daemon and private outputs where repo policy permits. CI or
|
|
242
|
+
one-shot verification may require `--no-daemon`; do not copy it automatically into a
|
|
243
|
+
local fast path, change global daemon settings or use shared writable caches. Preserve
|
|
244
|
+
the actual host/slot capacity limits and repo JVM constraints in every lane.
|
|
245
|
+
- Add no configuration-cache, parallel, worker or JVM tuning without a measured need. Keep
|
|
246
|
+
the repo's JVM and resource-capacity settings, and keep this recipe's own flags as written.
|
|
247
|
+
- A tracked native project that already builds and installs needs no routine `expo prebuild`
|
|
248
|
+
or `clean`, and no dependency reinstall.
|
|
249
|
+
- Do not rerun the disposable stack from stages 5–8 for an edit. Reuse the existing
|
|
250
|
+
development owner. At L2/L3, follow the gate's fresh-state requirements; an authorized
|
|
251
|
+
fresh install on an existing owned emulator need not boot another guest if data isolation
|
|
252
|
+
is sufficient. The generic runner is not a second owner for an existing session.
|
|
253
|
+
- Verify every Gradle task name against the actual task graph before using it. `assembleDebug`
|
|
254
|
+
and `installDebug` may also package instrumentation or test APKs, so do not treat either as
|
|
255
|
+
app-only proof without checking the packaged artifacts.
|
|
256
|
+
|
|
257
|
+
### Scoped ABI selection
|
|
258
|
+
|
|
259
|
+
Focused L1 work may build only the ABI of the owned device, where repo policy permits. Ask
|
|
260
|
+
the device instead of guessing, and name its serial so both commands respect the caller's ADB
|
|
261
|
+
endpoint. Give the probe a 30-second command deadline through the existing owner; do not
|
|
262
|
+
wait indefinitely on a lost transport:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
source <worktree>/.cache/android-env.sh
|
|
266
|
+
adb -s <owned-serial> shell getprop ro.product.cpu.abi | tr -d '\r'
|
|
267
|
+
# The ABIs the native build configures, e.g. the reactNativeArchitectures values.
|
|
268
|
+
grep -n 'reactNativeArchitectures' <native-gradle-properties-file>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The printed ABI must appear in that configured list; stop and report any other value. Then
|
|
272
|
+
scope one command to it, through the same build entry point as step 4, which forwards Gradle
|
|
273
|
+
arguments. Tool shells do not keep variables between calls, so restate the verified value:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
source <worktree>/.cache/android-env.sh
|
|
277
|
+
DEVICE_ABI=<verified-abi-from-the-previous-command>
|
|
278
|
+
pnpm <repo-build-entry> -PreactNativeArchitectures="$DEVICE_ABI" \
|
|
279
|
+
-Pandroid.builder.sdkDownload=false
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Verify that this entry point forwards both properties, and retain the repo's applicable
|
|
283
|
+
capacity and build-safety flags. Flags from an earlier command are not inherited.
|
|
284
|
+
|
|
285
|
+
Do not change the shared checked-in ABI defaults, persist the flag in `gradle.properties`, or
|
|
286
|
+
hardcode `x86` or `x86_64`, and keep the every-configured-ABI build as setup proof and release
|
|
287
|
+
acceptance. An emulator-ABI build proves only that ABI.
|
|
288
|
+
|
|
289
|
+
## Setup rules
|
|
290
|
+
|
|
291
|
+
- Resolve the workspace first; [workspace.md](workspace.md) owns
|
|
292
|
+
precedence: an assigned isolated workspace and candidate HEAD win, feature work, fixes and
|
|
293
|
+
diagnosis reuse the owned workspace, and standalone setup creates one managed workspace
|
|
294
|
+
only with no usable assignment. Read its actual HEAD; never substitute `origin/main`, a new
|
|
295
|
+
branch or another checkout, mutate a peer's checkout or symlink its writable `node_modules`.
|
|
296
|
+
- Tool shells keep no variables, functions or traps between calls. Write the environment
|
|
297
|
+
to `.cache/android-env.sh` once and source it at the start of every command. Use the
|
|
298
|
+
repo's existing owned-resource launcher. For a new local setup without one, use
|
|
299
|
+
`scripts/device-run.sh` for stages 6–8 in one command. Do not wrap an existing owner
|
|
300
|
+
with a second emulator/database lifecycle.
|
|
301
|
+
- Keep local writable caches private under `.cache/`: Gradle home, Android user/AVD
|
|
302
|
+
homes, temporary files, npm, node-gyp and pnpm. In CI, an already isolated runner slot
|
|
303
|
+
may provide those paths; verify its ownership contract rather than layering another
|
|
304
|
+
cache system on top. Never share writable state across concurrent owners.
|
|
305
|
+
- Read toolchain versions from the repo: the root `packageManager` and `engines`, the
|
|
306
|
+
native Gradle config, and the CI preflight. The repo is the source of truth, not this skill.
|
|
307
|
+
- Check that every required SDK component (platform, build-tools, NDK, CMake,
|
|
308
|
+
platform-tools, emulator, system image) is already installed. If one is missing, stop and
|
|
309
|
+
provision it separately. Never upgrade or install into a shared SDK during a journey;
|
|
310
|
+
build with `-Pandroid.builder.sdkDownload=false`.
|
|
311
|
+
- Install with `--frozen-lockfile`. Do not routinely run `clean`, reinstall dependencies or
|
|
312
|
+
run `expo prebuild`. The native project is tracked, and prebuild needs a reviewed native
|
|
313
|
+
change.
|
|
314
|
+
- Build every configured ABI for setup proof and release acceptance. An emulator-only
|
|
315
|
+
APK proves only that ABI. L1 focused native validation may use the emulator ABI where
|
|
316
|
+
repo policy permits, discovered from the owned device as in
|
|
317
|
+
[scoped ABI selection](#scoped-abi-selection); retain additional checks for affected ABI
|
|
318
|
+
configuration and all required native/ABI CI gates. Do not claim all-ABI proof from one
|
|
319
|
+
incremental build.
|
|
320
|
+
- Determine how the selected build loads code and assets. A typical debug build needs
|
|
321
|
+
Metro; a release build normally embeds its bundle. Do not introduce Metro or debug
|
|
322
|
+
preferences into a release failure without evidence that the build uses them.
|
|
323
|
+
A successful build does not prove execution on a device.
|
|
324
|
+
|
|
325
|
+
Ordinary edits reuse the [owned development session](#owned-development-session) instead of
|
|
326
|
+
repeating these stages. Every stop still follows the cleanup rules below.
|
|
327
|
+
|
|
328
|
+
## Owned-resource cleanup
|
|
329
|
+
|
|
330
|
+
- Clean up only what this run started: the emulator child PID, the container ID from the
|
|
331
|
+
CID file, and the named database; these are short-lived, unlike the development workspace
|
|
332
|
+
and its private caches. Signal the PID with `TERM`, wait up to 10 seconds, then `KILL`.
|
|
333
|
+
Then `wait` for it and confirm nothing is left. Count wait status 0 or 143 (ended by your
|
|
334
|
+
`TERM`) as a clean stop; count a needed `KILL` or any other status as a failure.
|
|
335
|
+
- The development runtime ends with the session, not after each check. Use its existing
|
|
336
|
+
owner's bounded shutdown, distinguishing supervised children/process groups from
|
|
337
|
+
persistent daemons. Shell `wait` and child exit codes apply only to children of that
|
|
338
|
+
shell; do not use them to attest termination of an adopted service or Gradle daemon.
|
|
339
|
+
The build client's exit does not mean its daemon exited. Record the daemon's own
|
|
340
|
+
identity and private Gradle home/version, not merely the client PID.
|
|
341
|
+
- For a supervised runtime, stop through its harness owner and verify the owned group
|
|
342
|
+
and descendants exited; a Metro wrapper exiting alone is insufficient. For Gradle or
|
|
343
|
+
another daemon, use the verified owner-specific stop with the recorded private home,
|
|
344
|
+
version and endpoint, then verify the original process identity is gone and owned
|
|
345
|
+
endpoints are released where applicable. Never use a shared/global daemon stop,
|
|
346
|
+
`adb kill-server` or a broad kill. If scope or exit cannot be verified, report the
|
|
347
|
+
retained resource and cleanup gap or arrange explicit handoff; do not signal a guessed
|
|
348
|
+
PID or report success. Preserve the bounded-stop and failure-reporting rules below.
|
|
349
|
+
- Never use broad `pkill`, `docker system prune` or a shared `adb kill-server` for cleanup.
|
|
350
|
+
Use the live child's process owner, not an ADB serial that may be reused. A numeric
|
|
351
|
+
PID can also be reused after exit; it is not durable ownership evidence.
|
|
352
|
+
- Give every startup, readiness and cleanup command a 30-second limit that kills the
|
|
353
|
+
command's whole process group. Treat exit 124 (timeout) as a terminal failure, not as
|
|
354
|
+
"not ready yet".
|
|
355
|
+
- Preserve the stage's original non-zero exit status even when cleanup succeeds. Print
|
|
356
|
+
`original_stage_exit=<n> cleanup_exit=<n>`.
|
|
357
|
+
- After SIGKILL or a host crash, verify recorded resources before recovery: process
|
|
358
|
+
start identity, command/run scope and boot identity where available, or container ID
|
|
359
|
+
and ownership labels. Never signal a numeric PID solely because an old record names
|
|
360
|
+
it. If ownership cannot be verified, leave it alone and report the gap. Keep logs.
|
|
361
|
+
- For the local setup flow, point the database URL only at its disposable loopback
|
|
362
|
+
container. An existing isolated remote test flow must use its own disposable data and
|
|
363
|
+
ownership checks. Never use development, production or another worker's database for
|
|
364
|
+
fixture writes or cleanup. A public render-only smoke needs no database.
|
|
365
|
+
- Record existing working changes before tools run. If Expo rewrites `android/tsconfig.json`
|
|
366
|
+
or deletes `android/expo-env.d.ts`, remove only unwanted changes attributable to that tool
|
|
367
|
+
execution. Preserve pre-existing and intentional task edits. If attribution is unclear,
|
|
368
|
+
retain the files and report the conflict; do not restore a whole file merely because
|
|
369
|
+
Expo touched it.
|
|
370
|
+
|
|
371
|
+
## Evidence record
|
|
372
|
+
|
|
373
|
+
For setup proof only. Record:
|
|
374
|
+
|
|
375
|
+
- Source SHA and the workspace root/path/base/branch/owner from the lifecycle record; host OS
|
|
376
|
+
and architecture, the Expo SDK, and the node, pnpm, JDK, Python and emulator versions.
|
|
377
|
+
- System image API, image type and ABI. The AVD name, serial and ports are run
|
|
378
|
+
identifiers, not shared resources.
|
|
379
|
+
- Each stage's exit status and duration.
|
|
380
|
+
- The APK's SHA-256 (`shasum -a 256` or `sha256sum`) and its per-ABI `lib/` entries
|
|
381
|
+
(`unzip -l`), checked on the APK itself rather than inferred from Gradle flags.
|
|
382
|
+
- The journey's `PASS` markers and the cleanup results: database dropped, emulator exited,
|
|
383
|
+
container removed, no listeners left on the backend or Metro ports.
|
|
384
|
+
- Earlier failed or incomplete attempts. A later pass does not erase them.
|
|
385
|
+
|
|
386
|
+
State what the run does not prove: tablet, accessibility (TalkBack), physical devices,
|
|
387
|
+
signing, distribution, and any feature acceptance beyond the journey. Publish only
|
|
388
|
+
sanitized evidence: no authentication codes, session cookies, customer data or raw
|
|
389
|
+
payment payloads.
|