Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
569 commits
Select commit Hold shift + click to select a range
d29b217
native_build: cross-compile project NIFs for both Android ABIs
GenericJam May 14, 2026
20ab225
bump: erlang 29.0-rc3 → 29.0, elixir 1.20.0-rc.4 → 1.20.0-rc.5
GenericJam May 14, 2026
5be5152
Merge mob_dev-android-armv7 — split :android into :android_arm64/_arm32
GenericJam May 14, 2026
ceccf78
mob.doctor: warn when rustup targets for Android aren't installed
GenericJam May 14, 2026
531ec77
Use Task-based timeout instead of GNU timeout for adb calls
May 9, 2026
9e07b87
release: bump OTP runtime to hash 550d7b78 — OTP 29.0 final
GenericJam May 14, 2026
373e080
test: derive ERTS version from manifest in bundled_runtime_test helper
GenericJam May 14, 2026
a154a66
lint: mix format pass
GenericJam May 14, 2026
0ceba59
0.5.0
GenericJam May 14, 2026
ec4e473
mob.add_nif --type rustler: embed Android dlsym patch in Cargo.toml
GenericJam May 14, 2026
ed95501
guides/nifs.md: per-backend contract for C, Rustler, Zigler, Pythonx
GenericJam May 14, 2026
5a92ea6
mob.enable: rename `python` → `pythonx`, keep old name as deprecated …
GenericJam May 14, 2026
9dea16a
mob.enable: drop the `python` alias outright
GenericJam May 14, 2026
f246463
guides/nifs.md: add "Bringing in an existing Rust crate" section
GenericJam May 14, 2026
45e2430
0.5.1
GenericJam May 14, 2026
175524c
Add NxEigen Nx backend cross-compile + `mix mob.enable nxeigen`
GenericJam May 15, 2026
de84e3e
Enable EMLX Metal GPU on iOS device
GenericJam May 15, 2026
576627f
Merge pull request #5 from GenericJam/cpp-nif-support
GenericJam May 15, 2026
0f73382
0.5.2
GenericJam May 15, 2026
d2c2f46
guides/nifs.md: rewrite Nx-backends-on-mobile section for current state
GenericJam May 15, 2026
77eeaa7
guides/nifs.md: lead with Rustler maintainer's preferred shape
GenericJam May 15, 2026
bdbbbed
0.5.3
GenericJam May 16, 2026
bdeaaac
ci+docs: add tests + release workflows, CHANGELOG.md, fix HexDocs sou…
GenericJam May 16, 2026
036f9e1
release.yml: add hex_publish job gated on HEX_API_KEY secret
GenericJam May 16, 2026
b66b5a7
0.5.4
GenericJam May 16, 2026
246fa50
native_build: convert @doc + @doc false sandwich to # comments
GenericJam May 16, 2026
3f3d57a
format: wrap long assert message in native_build_test
GenericJam May 16, 2026
11b86f7
credo: clear the seven --strict findings
GenericJam May 16, 2026
10b4131
native_build: thread project_root through stage_empty_priv_otp_lib
GenericJam May 16, 2026
991f64b
ci: pre-build :dev tree + skip macOS-only tests on Linux runners
GenericJam May 16, 2026
31a062d
ci: two more shared-state hazards — NativeBuildTest async + Zig dep
GenericJam May 16, 2026
10c3221
release.yml: fix tag pattern — glob, not regex
GenericJam May 16, 2026
54dcb06
release.yml: drive from mix.exs version, drop the manual tag step
GenericJam May 16, 2026
dcbdb00
ci: per-step idempotency so re-runs back-fill missing pieces
GenericJam May 16, 2026
1838cac
Bump to 0.5.5 — 16KB-aligned OTP tarballs for Android 15
GenericJam May 16, 2026
db3c546
Release flow standardisation: link to mob/RELEASE.md + pre-push hook
GenericJam May 16, 2026
fc5e095
Bump to 0.5.6 — release-flow docs link + pre-push hook
GenericJam May 16, 2026
f38940a
Tidy 1.20-flagged dead clauses + boolean redundancy
GenericJam May 17, 2026
bbfa993
Bump to 0.5.7 — mix mob.enable tflite (TFLite NIF wiring building blo…
GenericJam May 17, 2026
158ccba
NativeBuild + runtime-lib wiring for mob.enable tflite
GenericJam May 17, 2026
93a5a42
iOS deploy fixes for TFLite — framework binaries are MH_OBJECT, not M…
GenericJam May 17, 2026
b3baa09
Add tests for the new NativeBuild TFLite plumbing
GenericJam May 17, 2026
91c75a7
Merge: TFLite NIF integration (mix mob.enable tflite, end-to-end)
GenericJam May 17, 2026
058c9e9
Bump to 0.5.8 — full mix mob.enable tflite end-to-end
GenericJam May 17, 2026
6a25515
mlx_downloader: TODO to switch upstream once cocoa-xu publishes iOS
GenericJam May 18, 2026
433d148
Bump to 0.5.9 — mix mob.enable tflite uses Hex dep
GenericJam May 18, 2026
ef642b2
mob.deploy --dist-port + --node-suffix: manual override path
GenericJam May 18, 2026
e90ebf3
Bump to 0.5.10 — mob.deploy --dist-port + --node-suffix flags
GenericJam May 18, 2026
fd53d73
fix: formatter — blank lines around inline if in deploy_android
GenericJam May 19, 2026
0ea9977
fix: drop weak struct-field-presence tests flagged by credo
GenericJam May 19, 2026
78426e8
Support project iOS Swift sources
dl-alexandre May 20, 2026
514add7
docs: CHANGELOG entry for :ios_swift_sources
GenericJam May 20, 2026
624182d
refactor: rename :ios_swift_sources → :project_swift_sources for nami…
GenericJam May 20, 2026
af25ebe
Bump to 0.5.11 — :project_swift_sources mob.exs key
GenericJam May 20, 2026
0ccbe8b
fix: start IEx before connect handoff
dl-alexandre May 22, 2026
3a2e71a
feat: support Android x86_64 OTP runtime
dl-alexandre May 22, 2026
1c4bcfa
docs: add decision log (decisions/ seed)
GenericJam May 25, 2026
4b132b0
release: real crypto+ssl on device, keep :compiler, iOS link fixes
GenericJam May 26, 2026
c01c170
Warn on build vs device-runtime Elixir minor-version skew
GenericJam May 26, 2026
daaa537
iOS release build: glob $MOB_DIR/ios/*.swift instead of listing files
GenericJam May 27, 2026
6b3e997
Merge pull request #13 from GenericJam/ios-swift-glob
GenericJam May 27, 2026
1ce1d12
Add MobDev.Plugin.host_config/3 stub (plugin epic Phase 0)
GenericJam May 27, 2026
9266bc5
Add plugin manifest engine + mix mob.plugins (Phase 1 foundation)
GenericJam May 27, 2026
31dfe86
Add plugin validation layer: validator + mix mob.validate_plugin
GenericJam May 27, 2026
09b7f15
Native merge: contribution gathering + plugin NIFs into driver table
GenericJam May 27, 2026
74754dc
Native merge part 2: compile plugin C NIFs into the Android build
GenericJam May 28, 2026
268ae51
Add mix mob.new_plugin scaffold for tiers 0–2
GenericJam May 28, 2026
eea2b27
plugin validator: enforce nif :module is a C-token atom
GenericJam May 28, 2026
f7cc5a6
iOS native_build: emit -Dplugin_swift_files + -Dplugin_frameworks
GenericJam May 28, 2026
e64fb62
iOS bundle: merge plugin Info.plist keys (project wins on conflict)
GenericJam May 28, 2026
7497f4b
fix(android): derive dist node name via device_node_suffix to match M…
GenericJam May 28, 2026
35a9566
Android native_build: merge plugin permissions + gradle_deps
GenericJam May 28, 2026
3ef8e57
docs: update CLAUDE.md to reflect Android node-name fix
GenericJam May 28, 2026
e4c99cd
iOS plugin bootstrap: codegen mob_register_plugins() at build time
GenericJam May 29, 2026
7863d1a
plugin validator: enforce iOS frameworks + Android permissions match …
GenericJam May 29, 2026
2d5ca3b
Add mix mob.audit_plugins: static-analysis pass over activated plugins
GenericJam May 29, 2026
a0ca5ce
mix mob.plugins: show vetting status per activated plugin
GenericJam May 29, 2026
5f724da
Plugin signing: Ed25519 TOFU trust model for activated plugins
GenericJam May 29, 2026
3419330
otp: bump @otp_hash to 7d46fdd4 (Elixir 1.20.0-rc.5 + iOS {spawn,driv…
GenericJam May 29, 2026
470d98e
Plugin system: zig NIFs + Android bridge classes (native-plugin pipel…
GenericJam May 29, 2026
45fbd96
Release 0.5.12 — OTP 7d46fdd4 (Elixir 1.20.0-rc.5 + iOS {spawn,driver…
GenericJam May 29, 2026
4c109f4
ADR: correct bt-extraction helper claim (pidToJlong et al are not bt-…
GenericJam May 30, 2026
5bb408d
Fix mix mob.plugins crash: validator args were swapped in vetting com…
GenericJam May 30, 2026
5bacc42
docs: add iOS-sim / BEAM debugging gotchas to CLAUDE.md
GenericJam May 30, 2026
3f2bebe
Release 0.5.13: iOS deploy ships the whole priv/
GenericJam May 30, 2026
4a55448
Fix intermittent plugin signature gate via envelope-atom interning
GenericJam May 31, 2026
cf3f72d
Generic plugin Activity handoff via MobActivityAware
GenericJam Jun 1, 2026
52a84d5
Merge plugin system into master (Phase 1 + Phase 2 infrastructure)
GenericJam Jun 1, 2026
306950d
iOS release: fix erl_errno shim newline + preflight the driver table …
GenericJam Jun 2, 2026
648ceae
Release 0.5.14: iOS release fixes (erl_errno newline + driver-table p…
GenericJam Jun 2, 2026
885dd0f
Release 0.5.15: honor --no-slim on Android, Apple-strip lib execs, ga…
GenericJam Jun 2, 2026
f62e566
Merge pull request #15 from GenericJam/no-slim-and-plugin-gate
GenericJam Jun 2, 2026
8cdb2b5
Release 0.5.16: gate plugin flags on the iOS device build path too
GenericJam Jun 2, 2026
7873c59
Merge pull request #16 from GenericJam/gate-ios-device-plugin-flags
GenericJam Jun 2, 2026
8cd59da
Release 0.5.17: iOS sim deploy parity with device (clean mob.deploy -…
GenericJam Jun 3, 2026
0b732b6
Merge pull request #17 from GenericJam/ios-sim-deploy-parity
GenericJam Jun 3, 2026
5d6ef08
iOS plugin C-NIF compile path + per-platform driver-table filtering
GenericJam Jun 4, 2026
49d8919
Update deps for Elixir 1.20.0
GenericJam Jun 4, 2026
05f169b
Fix order-dependent MOB_CACHE_DIR test races (async: false)
GenericJam Jun 4, 2026
518adf5
plugin: extensible permission registry — Android codegen + manifest
GenericJam Jun 5, 2026
dec8aa4
plugin: per-platform NIF source tagging (cross-platform plugin support)
GenericJam Jun 5, 2026
450c5d2
plugin: Objective-C (.m) iOS plugin-NIF support
GenericJam Jun 5, 2026
520088a
Plugin tiers 3/4 — Phase 0 foundation (validation, gatherers, runtime…
GenericJam Jun 6, 2026
52c5fa1
Plugin tier 3 — pure planners for migration/font/image build merges (…
GenericJam Jun 6, 2026
bcabbc3
Plugin tier 3 — wire migration + image build-merge into native_build
GenericJam Jun 6, 2026
27c8eaa
Custom fonts: bundle app + plugin fonts (iOS UIAppFonts, Android res/…
GenericJam Jun 6, 2026
ab5d1a2
Merge branch 'plugin-tiers-3-4'
GenericJam Jun 6, 2026
20d60dd
fix(native_build): bundle the toolchain's Elixir stdlib on version skew
GenericJam Jun 6, 2026
dedc83d
fix(plugin): iter-1 bug-hunt safe fixes (10 bugs across the plugin en…
GenericJam Jun 6, 2026
a1d0a57
Merge bughunt-iter1: plugin-system bug-hunt iteration 1 safe fixes
GenericJam Jun 6, 2026
6eb12f0
fix(plugin): high-value flagged build bugs (objc/Android, migrations,…
GenericJam Jun 7, 2026
685076d
Merge bughunt-iter1-hv: high-value flagged plugin bug fixes
GenericJam Jun 7, 2026
6426217
feat(plugin): systematic cross-plugin conflict surface + 7 new collis…
GenericJam Jun 7, 2026
2ee4666
Merge conflict-surface: systematic cross-plugin conflict detection
GenericJam Jun 7, 2026
4f39525
fix(native_build): always regenerate the runtime plugin manifest at b…
GenericJam Jun 7, 2026
b7bcbdd
Merge runtime-manifest-autoregen: auto-regen runtime plugin manifest …
GenericJam Jun 7, 2026
24d9679
test(plugin): property-based fuzzing of the cross-plugin merge layer
GenericJam Jun 7, 2026
cb311f7
Merge merge-fuzz: property-based fuzzing of cross-plugin merge
GenericJam Jun 7, 2026
bc6677b
feat(mob.new_plugin): scaffold tiers 3 (multi-screen) and 4 (sub-app)
GenericJam Jun 9, 2026
34e673b
Merge plugin-scaffold-3-4: scaffold tiers 3 and 4 in mix mob.new_plugin
GenericJam Jun 9, 2026
a8bbad9
docs(changelog): tier-3/4 scaffold, conflict detection, runtime-manif…
GenericJam Jun 9, 2026
533e54e
feat(plugin): emit `nifs` in the runtime manifest for boot-time NIF l…
GenericJam Jun 10, 2026
a30ea35
feat(mob.new_plugin): scaffold a starter test suite for every tier
GenericJam Jun 11, 2026
f907168
test(plugin): tighten weak assertions found by the QA audit
GenericJam Jun 11, 2026
f41138c
Merge plugin-scaffold-tests: scaffolded test suites + assertion tight…
GenericJam Jun 11, 2026
4ba72ba
feat(build/doctor): two Hex-gate guards from the QA audit
GenericJam Jun 11, 2026
59fbd91
feat(plugin): host_requirements manifest key, printed by every native…
GenericJam Jun 11, 2026
1ad4236
Merge plugin-hex-gate-guards: driver_tab auto-regen, doctor plugin-op…
GenericJam Jun 11, 2026
8ce6991
credo: register ExSlop as a plugin, not a check (it never ran)
GenericJam Jun 11, 2026
944c1b3
feat(plugin): generate io.mob.plugin.MobNotifyHub (mob_notify Stage 1…
GenericJam Jun 11, 2026
68b653d
Merge notify-hub: generated MobNotifyHub seam
GenericJam Jun 11, 2026
586efda
fix(regen_plugin_manifest): load the host app before running spec-v2 …
GenericJam Jun 12, 2026
b41c667
Merge regen-loads-host: spec-v2 generators may touch host modules
GenericJam Jun 12, 2026
6002a0e
feat(styles): tokens-only style packages — MobDev.Style + manifest wi…
GenericJam Jun 12, 2026
47bfafc
Merge styles-mvp: tokens-only style packages (build half)
GenericJam Jun 12, 2026
3c3ef7d
feat(plugin): honor the ui_components expand: form (pure-Elixir compo…
GenericJam Jun 12, 2026
3493778
Merge composite-manifest: expand: form honored end to end
GenericJam Jun 12, 2026
84c85f2
fix(build): dep detection via Mix.Project.deps_paths, not stale _buil…
GenericJam Jun 12, 2026
4c69c95
Merge dep-detection: MLX-404 root cause fixed
GenericJam Jun 12, 2026
cd058a1
test: dep-detection tests match the deps_paths semantics
GenericJam Jun 12, 2026
f488b62
feat: mix mob.styles — list style packages + the active default
GenericJam Jun 12, 2026
cadfe18
Merge mob-styles-task
GenericJam Jun 12, 2026
5e88c38
changelog: draft the 0.6.0 entry (unreleased, pairs with mob 0.7.0)
GenericJam Jun 12, 2026
5afbaea
release.yml: also read the version: @version module-attribute idiom
GenericJam Jun 12, 2026
e358a52
Release 0.6.0 — plugin/style build infrastructure (pairs with mob 0.7.0)
GenericJam Jun 12, 2026
001359f
Prune orphaned plugin artifacts when a plugin is removed
GenericJam Jun 15, 2026
b2f902e
Release 0.6.1 — prune orphaned plugin artifacts on removal
GenericJam Jun 15, 2026
88c4933
Release 0.6.2 — create app driver_tab when a plugin contributes NIFs
GenericJam Jun 15, 2026
9fbd86d
Release 0.6.3 — exqlite NIF symlink picks the device's actual ABI
GenericJam Jun 16, 2026
53512f4
Add 'mix setup' to activate git hooks on a fresh clone
GenericJam Jun 16, 2026
495652e
Merge #10: ensure :iex is started before the mob.connect handoff
GenericJam Jun 17, 2026
a040adf
release scripts: add Android x86_64 OTP build (issue #20 on mob)
GenericJam Jun 17, 2026
51b9bfb
Merge #11: Android x86_64 emulator support (mob issue #20)
GenericJam Jun 17, 2026
9e1801c
mob.release.otp: add android_x86_64 target
GenericJam Jun 17, 2026
fb720ec
Release 0.6.4 — Android x86_64 emulator support (mob#20)
GenericJam Jun 17, 2026
b97fd66
release: vendor the corrected x86_64 xcomp conf
GenericJam Jun 17, 2026
53519ac
Release 0.6.5 — default OTP runtime to Elixir 1.20.1 (otp-5c9c69fc)
GenericJam Jun 17, 2026
abc2d1a
Merge otp-1.20.1: default runtime Elixir 1.20.1 (0.6.5)
GenericJam Jun 17, 2026
021a378
Release 0.6.6 — skip Android ABIs the app's build.zig can't compile
GenericJam Jun 18, 2026
78e6287
Merge android-abi-skip: skip unsupported Android ABIs (0.6.6)
GenericJam Jun 18, 2026
2a11e71
Release 0.6.7 — mob.connect dist ports by device serial (fix collisions)
GenericJam Jun 18, 2026
5c594da
Merge connect-serial-ports: dist ports by serial + cleanup + diagnost…
GenericJam Jun 18, 2026
c3a2b4c
mob_dev 0.6.8: mix mob.connect --only/--device to target one phone
GenericJam Jun 19, 2026
2a6dcbc
mob_dev 0.6.9: mob.publish retries commit with changesNotSentForReview
GenericJam Jun 19, 2026
871f3be
Plugin :cpp_archive NIFs — ship a C++ static lib (e.g. an Nx backend)…
GenericJam Jun 19, 2026
05e9e08
Release 0.6.10 — plugin :cpp_archive NIFs (#18)
GenericJam Jun 19, 2026
69f8461
mob.adopt: relocate the Igniter installer from mob_new#8 into mob_dev…
GenericJam Jun 19, 2026
455e5c1
Release 0.6.11 — mix mob.adopt (relocated from mob_new#8, by @ken-kost)
GenericJam Jun 19, 2026
05657c4
native_build: fail fast when Android needs zig but it's missing (#20)
GenericJam Jun 19, 2026
34c8d31
mob_dev 0.6.12: enforce 16 KB .so page alignment at build time
GenericJam Jun 19, 2026
74bd1cd
feat(deploy): preserve app data on --native when signing key matches …
GenericJam Jun 20, 2026
c07204d
Release 0.6.13: preserve app data on --native; document fail-fast on …
GenericJam Jun 20, 2026
0714b1a
Support project extra static libs (#24)
dl-alexandre Jun 23, 2026
d697bcc
Bump to 0.6.14 — :extra_static_libs hook for project static_nifs (#24)
GenericJam Jun 23, 2026
216f9fb
Fix mob.new_plugin scaffolding mob ~> 0.6 (won't activate against mob…
GenericJam Jun 23, 2026
c709cf7
Bump to 0.6.15 — req CVE fix (req 0.6.2) (#27)
GenericJam Jun 23, 2026
353e4f7
Bump to 0.6.16 — plugins can contribute array iOS plist keys (UIBackg…
GenericJam Jun 24, 2026
5ce1a92
init
Jun 24, 2026
342dbed
Support iOS-only development on a Mac (don't crash when adb is absent)
GenericJam Jun 29, 2026
2dfbd95
Merge pull request #29 from GenericJam/fix/ios-only-no-adb
GenericJam Jun 29, 2026
6817a9b
Release 0.6.17: iOS-only development on a Mac (don't crash when adb i…
GenericJam Jun 29, 2026
37a4dd0
MOB-7: emit iOS plugin bootstrap for blank apps (fix undefined _mob_r…
GenericJam Jul 5, 2026
1016b0d
mob.provision: App Store Connect API key for headless provisioning (#31)
GenericJam Jul 5, 2026
c2c331c
Release 0.6.18: App Store Connect API key provisioning
GenericJam Jul 5, 2026
76a67bc
MOB-39: plugins can contribute AndroidManifest components + res files…
GenericJam Jul 7, 2026
8152bca
MOB-40: reversible plugin merges into host build files (managed block…
GenericJam Jul 7, 2026
bc9754c
release: extract + test select_dist_profile/3 (App Store profile pick…
GenericJam Jul 7, 2026
3700aff
Release 0.6.19: plugin manifest components + res files, reversible me…
GenericJam Jul 7, 2026
89dd5d1
iOS release: compile + link activated-plugin NIFs (#36)
GenericJam Jul 8, 2026
c40d901
Release 0.6.20: iOS release compiles + links plugin NIFs
GenericJam Jul 8, 2026
eda462c
icon: flatten iOS app icons opaque (App Store 90717); keep Android tr…
GenericJam Jul 8, 2026
f3ff896
Release 0.6.21: iOS app icons flattened opaque (App Store 90717) (#38)
GenericJam Jul 8, 2026
04869e2
iOS release: plumb ios_release_screenshot → -DMOB_ENABLE_SCREENSHOT (…
GenericJam Jul 11, 2026
f690d80
Bump to 0.6.22 — ios_release_screenshot opt-in flag
GenericJam Jul 11, 2026
e5faf75
MOB-89: cpp_archive/nx_eigen_nif NDK resolution honors ANDROID_HOME (…
GenericJam Jul 12, 2026
4caffa9
Release 0.6.23: cpp_archive NDK resolution honors ANDROID_HOME (MOB-8…
GenericJam Jul 13, 2026
3f03a63
Fix: release otp.zip poisons subsequent debug native deploys (#42)
GenericJam Jul 25, 2026
7375287
fix(deploy): preserve Android app data on native updates
dl-alexandre Aug 2, 2026
721edb1
fix(deploy): freeze Android update targets
dl-alexandre Aug 2, 2026
e8b9a05
fix(deploy): fail closed on empty native targets
dl-alexandre Aug 3, 2026
ebfc291
Merge pull request #1 from dl-alexandre/fix/native-empty-target-fail-…
dl-alexandre Aug 3, 2026
afbca65
fix deterministic plugin manifest generation
dl-alexandre Aug 3, 2026
0676249
Merge pull request #2 from dl-alexandre/agent/deterministic-plugin-ma…
dl-alexandre Aug 3, 2026
4ffc2c4
fix signing of Objective-C plugin sources
dl-alexandre Aug 3, 2026
baf77b0
Merge pull request #3 from dl-alexandre/agent/sign-objective-c-native…
dl-alexandre Aug 3, 2026
ac4bf89
version plugin signature payloads safely
dl-alexandre Aug 3, 2026
7d3bfac
Merge pull request #4 from dl-alexandre/agent/versioned-plugin-signat…
dl-alexandre Aug 3, 2026
b5cd016
add exact-set Android deploy lease recovery
dl-alexandre Aug 3, 2026
7bf64d4
Merge pull request #5 from dl-alexandre/agent/android-deploy-lock-202…
dl-alexandre Aug 3, 2026
659d5a9
fix fail-closed Android tombstone cleanup
dl-alexandre Aug 3, 2026
7d6277d
test exact nonrecursive lease tombstone cleanup
dl-alexandre Aug 3, 2026
c8d0b91
Merge pull request #6 from dl-alexandre/fix/android-lock-corrective-v…
dl-alexandre Aug 3, 2026
8886747
fence Android hot push as one transaction
dl-alexandre Aug 3, 2026
11ca8c8
fix hot push exact lease target dispatch
dl-alexandre Aug 3, 2026
faecca6
test exact HotPush lease cleanup sequence
dl-alexandre Aug 3, 2026
1b46d23
Merge pull request #7 from dl-alexandre/agent/android-hot-push-fence-…
dl-alexandre Aug 3, 2026
30bee0f
make Android deploy payloads authoritative
dl-alexandre Aug 3, 2026
4d7c8da
test exact Deployer lease cleanup sequence
dl-alexandre Aug 3, 2026
acb0669
fix immutable payload and retained filesystem failures
dl-alexandre Aug 3, 2026
b3ff343
Merge pull request #8 from dl-alexandre/agent/android-authoritative-d…
dl-alexandre Aug 3, 2026
50ffd6e
fix: require authoritative iOS restart success
dl-alexandre Aug 3, 2026
06d9fbd
fix: keep physical iOS restart app-scoped
dl-alexandre Aug 3, 2026
9eaf52f
Merge pull request #9 from dl-alexandre/agent/ios-restart-authority-v…
dl-alexandre Aug 3, 2026
4d51c07
serialize native Android authority before iOS
dl-alexandre Aug 3, 2026
d305890
fix native cleanup gate and canonical target order
dl-alexandre Aug 3, 2026
c9ae6f2
fix native prevalidation cleanup escape
dl-alexandre Aug 3, 2026
966a111
fix native primary failure and canonical runtime set
dl-alexandre Aug 3, 2026
148a658
fix authoritative native deploy status validation
dl-alexandre Aug 3, 2026
8a1d7e8
fix: fail closed on ambiguous native iOS deploys
dl-alexandre Aug 3, 2026
ed2335f
fix: freeze native iOS target before build
dl-alexandre Aug 3, 2026
6020a38
fix: require unique native iOS build target
dl-alexandre Aug 3, 2026
78c9c70
fix: reject malformed iOS simulator inventory
dl-alexandre Aug 3, 2026
96dccc4
Merge pull request #10 from dl-alexandre/agent/android-deploy-fail-cl…
dl-alexandre Aug 3, 2026
3f93dd4
fix: isolate Zigler staging per native build
dl-alexandre Aug 3, 2026
36ed329
Merge pull request #11 from dl-alexandre/agent/zigler-stage-isolation…
dl-alexandre Aug 3, 2026
2918035
fix(deploy): fail early for unmatched device platform
dl-alexandre Aug 3, 2026
3b61c98
fix(deploy): require authoritative device match
dl-alexandre Aug 3, 2026
d02e5f0
fix(deploy): reject ambiguous device matches
dl-alexandre Aug 3, 2026
c8b9295
fix(deploy): preserve WiFi ADB selectors
dl-alexandre Aug 3, 2026
228fa06
Merge pull request #12 from dl-alexandre/agent/deploy-device-prefligh…
dl-alexandre Aug 3, 2026
d099a22
fix(android): report partial native updates
dl-alexandre Aug 3, 2026
c282e66
Merge pull request #13 from dl-alexandre/agent/android-partial-update…
dl-alexandre Aug 3, 2026
d37fa44
fix(android): bound Elixir metadata verification
dl-alexandre Aug 5, 2026
f3f423d
Merge pull request #14 from dl-alexandre/fix/android-elixir-app-metad…
dl-alexandre Aug 5, 2026
a1bef7c
feat(android): fence native-ready lease recovery
dl-alexandre Aug 5, 2026
6da94cd
fix(android): retain ambiguous recovery authority
dl-alexandre Aug 5, 2026
ee037c8
feat(android): prove native-ready recovery before resume
dl-alexandre Aug 5, 2026
0ac970e
Merge pull request #15 from dl-alexandre/fix/android-proof-orchestrator
dl-alexandre Aug 5, 2026
b22556a
fix(android): classify recovery proof refusals safely
dl-alexandre Aug 5, 2026
20ed316
Merge pull request #16 from dl-alexandre/fix/android-recovery-refusal…
dl-alexandre Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 6 additions & 2 deletions .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
configs: [
%{
name: "default",
# ex_slop is a credo PLUGIN (registers its whole check bundle), not a
# check — listing it under checks.enabled was silently ignored
# ("Ignoring an undefined check: ExSlop").
plugins: [{ExSlop, []}],
files: %{
included: ["lib/", "test/"],
excluded: [~r"/_build/", ~r"/deps/"]
Expand All @@ -22,11 +26,11 @@
# jump_credo_checks — LiveView specific
{Jump.CredoChecks.AssertElementSelectorCanNeverFail, []},
{Jump.CredoChecks.AvoidSocketAssignsInTest, []},
{Jump.CredoChecks.LiveViewFormCanBeRehydrated, []},
{Jump.CredoChecks.LiveViewFormCanBeRehydrated, []}
],
disabled: [
# Pipes with single function calls are fine in this codebase
{Credo.Check.Readability.SinglePipe, []},
{Credo.Check.Readability.SinglePipe, []}
]
}
}
Expand Down
3 changes: 3 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
79 changes: 79 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
# .githooks/pre-push — Mob repo pre-push gate.
#
# Activated per-clone with: git config core.hooksPath .githooks
# See RELEASE.md for the full release flow + when this hook runs.
#
# Two tiers of check:
#
# ALWAYS (cheap, sub-10s):
# mix format --check-formatted
# mix credo --strict
# mix compile --warnings-as-errors
#
# ONLY WHEN mix.exs CHANGED IN THIS PUSH (release preflight):
# mix test --exclude macos_only --exclude requires_zig
#
# Intentionally NOT in the always-tier: the full test suite. It's a
# 30-60s wait per push and that's exactly what teaches people to reach
# for --no-verify. CI runs the suite on every push regardless; this
# hook is here to catch the 80% of breaks that the fast checks find.
set -euo pipefail

# Suppress noisy OTP-28 regex warning so the hook output is clean.
export ELIXIR_ERL_OPTIONS="-elixir ansi_enabled true"

cheap_checks() {
echo "[pre-push] format..."
mix format --check-formatted

echo "[pre-push] credo..."
mix credo --strict

echo "[pre-push] compile (--warnings-as-errors)..."
mix compile --warnings-as-errors
}

release_preflight() {
echo "[pre-push] mix.exs changed → running release preflight..."
mix test --exclude macos_only --exclude requires_zig

# mix mob.security_scan only exists in mob_dev. Gate on availability
# so the same hook script can live unchanged in mob / mob_dev / mob_new.
if mix help mob.security_scan >/dev/null 2>&1; then
echo "[pre-push] mob.security_scan..."
mix mob.security_scan
fi
}

# git invokes pre-push with no args but pipes
# <local_ref> <local_sha> <remote_ref> <remote_sha>
# on stdin, one line per ref being pushed. We diff the local sha
# against the remote sha to see what mix.exs looks like in this push.
zero=0000000000000000000000000000000000000000
mix_exs_changed=false

while read -r local_ref local_sha remote_ref remote_sha; do
# Branch deletion (local_sha all zeros) → nothing to diff.
[ "$local_sha" = "$zero" ] && continue

if [ "$remote_sha" = "$zero" ]; then
# New branch on the remote — diff against origin/master so we
# don't try to scan an open-ended commit range.
range="origin/master..$local_sha"
else
range="$remote_sha..$local_sha"
fi

if git diff --name-only "$range" 2>/dev/null | grep -qx 'mix.exs'; then
mix_exs_changed=true
fi
done

cheap_checks

if [ "$mix_exs_changed" = "true" ]; then
release_preflight
fi

echo "[pre-push] ✓ all checks passed"
156 changes: 156 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
name: release

# Trigger model: mix.exs is the source of truth for the version. Bump the
# `version: "X.Y.Z"` line, commit, push — the workflow detects the change,
# tags it, creates the GitHub Release, and publishes to Hex.
#
# Re-running manually (e.g. to back-fill a Hex publish that was skipped
# because the tag pre-existed) is via the Actions tab's "Run workflow"
# button (workflow_dispatch). Each step is independently idempotent:
# tag-already-exists, release-already-exists, and version-already-on-Hex
# are each detected per-step, so re-runs only do work that's actually
# missing.
on:
push:
branches: [master]
paths: ['mix.exs']
workflow_dispatch:

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: write # required to create the GitHub Release AND push the tag

jobs:
release:
name: Release from mix.exs
runs-on: ubuntu-latest
env:
# Reads the repo secret. Steps that need it gate on
# `env.HEX_API_KEY != ''` so a missing secret skips cleanly instead
# of failing with an auth error.
HEX_API_KEY: ${{ secrets.HEX_API_KEY }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history for changelog generation

- name: Configure git identity (for the tag push below)
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Extract version from mix.exs
id: version
run: |
# Pull the `version: "X.Y.Z"` from the project/0 keyword list.
# Tolerates leading whitespace, expects a literal double-quoted
# string (Elixir-mix convention).
version=$(grep -E '^\s*version:\s*"' mix.exs | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
if [ -z "$version" ]; then
# `version: @version` idiom — read the module attribute instead.
version=$(grep -E '^\s*@version\s+"' mix.exs | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
fi
if [ -z "$version" ]; then
echo "::error::Could not extract version from mix.exs"
exit 1
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "Detected version: $version"

# ── Tag (idempotent: skip if exists) ────────────────────────────
- name: Create + push tag (if missing)
run: |
tag="${{ steps.version.outputs.version }}"
if git rev-parse "refs/tags/$tag" >/dev/null 2>&1; then
echo "::notice::Tag $tag already exists — skipping tag creation"
else
git tag "$tag"
git push origin "$tag"
echo "Created and pushed tag $tag"
fi

# ── GitHub Release (idempotent: skip if exists) ─────────────────
- name: Check if GitHub Release exists
id: release_check
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
tag="${{ steps.version.outputs.version }}"
if gh release view "$tag" -R "${{ github.repository }}" >/dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "::notice::GitHub Release $tag already exists — skipping release creation"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi

- name: Extract CHANGELOG section
if: steps.release_check.outputs.exists == 'false'
id: changelog
run: |
if [ -f CHANGELOG.md ]; then
awk -v tag="${{ steps.version.outputs.version }}" '
$0 ~ "^## \\[" tag "\\]" || $0 ~ "^## " tag "( |$)" { in_section=1; next }
in_section && /^## / { exit }
in_section { print }
' CHANGELOG.md > /tmp/release-body.md
if [ -s /tmp/release-body.md ]; then
echo "has_body=true" >> "$GITHUB_OUTPUT"
else
echo "has_body=false" >> "$GITHUB_OUTPUT"
fi
else
echo "has_body=false" >> "$GITHUB_OUTPUT"
fi

- name: Create GitHub Release
if: steps.release_check.outputs.exists == 'false'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.version.outputs.version }}
name: ${{ steps.version.outputs.version }}
body_path: ${{ steps.changelog.outputs.has_body == 'true' && '/tmp/release-body.md' || '' }}
generate_release_notes: ${{ steps.changelog.outputs.has_body != 'true' }}

# ── Hex publish (idempotent: skip if version already on Hex) ────
- name: Set up BEAM
if: env.HEX_API_KEY != ''
uses: erlef/setup-beam@v1
with:
elixir-version: '1.19'
otp-version: '28'

- name: Check if version is already on Hex
if: env.HEX_API_KEY != ''
id: hex_check
run: |
# `mix hex.info <pkg> <vsn>` exits 0 if the version is published,
# non-zero otherwise. The package name is the project's `app:` value
# in mix.exs — same heuristic as for the version extract.
pkg=$(grep -E '^\s*app:\s*:' mix.exs | head -1 | sed 's/.*:\s*:\([a-z_][a-z0-9_]*\).*/\1/')
vsn="${{ steps.version.outputs.version }}"
if mix hex.info "$pkg" "$vsn" 2>/dev/null | grep -q "Config:"; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "::notice::Hex package $pkg $vsn already published — skipping mix hex.publish"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "package=$pkg" >> "$GITHUB_OUTPUT"
fi

- name: mix hex.publish
if: env.HEX_API_KEY != '' && steps.hex_check.outputs.exists == 'false'
# `--yes` skips the interactive confirm. `mix hex.publish` (no
# subcommand) ships both the package archive AND docs in one call.
run: |
mix deps.get
mix hex.publish --yes

- name: Skip Hex publish notice (no API key)
if: env.HEX_API_KEY == ''
run: |
echo "::notice::HEX_API_KEY secret is not set on this repository."
echo "::notice::Skipping Hex publish. Add the secret at"
echo "::notice::https://github.com/${{ github.repository }}/settings/secrets/actions"
echo "::notice::and re-run the workflow (Actions tab → Run workflow) to publish."
125 changes: 125 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
name: tests

on:
push:
branches: [master]
pull_request:
workflow_dispatch:

concurrency:
group: tests-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: Elixir ${{ matrix.elixir }} / OTP ${{ matrix.otp }}
runs-on: ubuntu-latest
env:
MIX_ENV: test
strategy:
fail-fast: false
matrix:
include:
- elixir: '1.19'
otp: '28'
steps:
- uses: actions/checkout@v4

# mob.adopt's native (--android/--ios) tests render from mob_new's
# templates — mob_new is the single source, not duplicated here. Provide
# a mob_new checkout so MobDev.Adopt.Generator resolves them via
# MOB_NEW_DIR (mirrors a user having the mob_new archive installed).
- name: Checkout mob_new (native adopt templates)
uses: actions/checkout@v4
with:
repository: GenericJam/mob_new
path: mob_new

- uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}

- name: Cache deps + _build
uses: actions/cache@v4
with:
path: |
deps
_build
key: mix-${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles('**/mix.lock') }}
restore-keys: mix-${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-

- run: mix deps.get
- run: mix deps.compile
- run: mix compile --warnings-as-errors

# Some HotPush tests inspect `_build/dev/lib/*/ebin/*.beam` to verify
# which runtime BEAMs the `mix mob.push` helper would ship to a device.
# Under MIX_ENV=test the dev tree doesn't exist; pre-populate it so
# those tests have something to look at.
- name: Compile :dev tree (for HotPush tests)
env:
MIX_ENV: dev
run: mix compile

- name: Format check
run: mix format --check-formatted

- name: Credo (strict)
run: mix credo --strict

- name: Tests
env:
# mob.adopt native tests resolve mob_new's templates from this checkout.
MOB_NEW_DIR: ${{ github.workspace }}/mob_new
# `:macos_only` — tests that shell out to /usr/libexec/PlistBuddy
# and similar macOS-bound tools.
# `:requires_zig` — the StaticNifs zig-ast-check round-trip; we
# don't install Zig in CI yet (it's a 30 MB download for one test).
# Both run by default on a maintainer's laptop; CI explicitly skips.
run: mix test --exclude macos_only --exclude requires_zig

security_scan:
name: Security scan
needs: test
runs-on: ubuntu-latest
if: always()
# Informational: a finding shouldn't block the workflow gate while we
# establish a baseline. Flip to `--strict` once we've triaged what's
# already in the dep tree.
continue-on-error: true
env:
MIX_ENV: test
steps:
- uses: actions/checkout@v4

- uses: erlef/setup-beam@v1
with:
elixir-version: '1.19'
otp-version: '28'

- name: Cache deps + _build (reuse test job's key)
uses: actions/cache@v4
with:
path: |
deps
_build
key: mix-${{ runner.os }}-1.19-28-${{ hashFiles('**/mix.lock') }}
restore-keys: mix-${{ runner.os }}-1.19-28-

- run: mix deps.get
- run: mix deps.compile

# osv-scanner is an optional external tool the scanner consumes when
# available. Missing tools are reported as soft warnings (not failures).
- name: Install osv-scanner
run: |
curl -sSfL https://github.com/google/osv-scanner/releases/latest/download/osv-scanner_linux_amd64 \
-o /usr/local/bin/osv-scanner
chmod +x /usr/local/bin/osv-scanner
osv-scanner --version

- name: mix mob.security_scan
# The hex_deps layer applies to mob_dev itself; the gradle / swift /
# bundled_runtime layers no-op (mob_dev has no native surface).
run: mix mob.security_scan
3 changes: 3 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
elixir 1.20.0-otp-29
erlang 29.0
zig 0.17.0-dev.269+ebff43698
Loading
Loading