Skip to content

feat: open Limrun uploaded apps - #2110

Open
thymikee wants to merge 3 commits into
mainfrom
feat/limrun-uploaded-apps
Open

feat: open Limrun uploaded apps#2110
thymikee wants to merge 3 commits into
mainfrom
feat/limrun-uploaded-apps

Conversation

@thymikee

@thymikee thymikee commented Aug 27, 2026

Copy link
Copy Markdown
Member

Summary

Let Limrun users discover and launch previously uploaded app assets through the existing app workflow without adding a provider-specific flag or public API.

  • connect limrun remains handshake-only and does not allocate an instance
  • before allocation, agent-device apps lists compatible uploaded assets for the selected platform
  • agent-device open <exact-uploaded-asset-name> allocates with Limrun initialAssets, resolves an exact installed identity, and launches it
  • ambiguous, partial-only, or unrelated foreground identities fail closed
  • after allocation, apps keeps its existing installed-app behavior; unmatched open targets preserve the existing path
  • Android accepts APK assets; iOS accepts IPA, ZIP, TAR, TAR.GZ, and TGZ assets
  • sessionless catalog requests retain daemon cancellation through Limrun I/O

The implementation keeps authenticated asset discovery, preinstallation, and identity mapping in the Limrun owner while reusing the normal CLI, daemon, lifecycle, and JavaScript command paths.

Size rationale

Exact-head Size CI measures +6.1 kB npm unpacked (+5.8 kB raw JS, +2.8 kB gzip, +2.4 kB tarball). The packed growth is split across:

  • about 3.4 kB raw in two lazy provider-owned feature chunks: asset filtering/exact lookup (app-catalog.js, 1.4 kB) and allocation plus fail-closed installed-identity resolution (session-allocation.js, 2.0 kB)
  • about 2.7 kB net across the provider catalog contract, sessionless apps daemon route, capability-driven deferred selection, provider-owned app-reference resolution, CLI help, and declarations

The largest per-file movements are chunk relocation rather than additive feature size: device-session.js appears at +10.8 kB while src.js falls 10.7 kB. The +6.1 kB aggregate is the authoritative net result after those moves.

A counterfactual size audit tested broader coalescing: one Limrun app chunk would save only another 403 raw bytes over the chosen layout while making pre-allocation apps load a 17.4 kB allocation/platform chunk. Keeping catalog lookup separate avoids that runtime regression. The remaining Limrun modules are loaded lazily, preserving the provider runtime's 29-module eager closure. A smaller device-inventory seam was rejected because installed-app inventory requires allocation and cannot represent uploaded assets; resolving in the CLI would duplicate provider authentication and asset semantics outside their owner. A new Limrun-only command or flag was also avoided so local and remote app discovery keep the same workflow.

Validation

Live Limrun verification at behavior head 265259cc62:

  • both connect calls verified access while reporting leaseAllocated: false; pre-allocation apps listed uploaded filenames without creating an instance
  • Android opened com.callstack.agentdevicelab.apk as com.callstack.agentdevicelab in 6.15s wall time, returned a healthy android-helper 0.20.11-dev snapshot, clicked the Catalog ref, and verified the Catalog screen
  • iOS opened easagentdevice.app.zip as dev.expo.easagentdevice in 4.64s wall time, returned the Development Build snapshot, clicked INFO, and verified the information screen
  • Limrun's three-minute inactivity expiry won the Android close race and returned typed LEASE_NOT_FOUND; both exact instance IDs were then queried directly and returned 404, and both local connection profiles were disconnected

Current-head local validation (32309bb5a3):

  • focused catalog, provider runtime, and eager-closure suites: 387/387 passed
  • planted-red proofs: the collision test selected the wrong app under the old partial matcher; the unrelated-foreground test failed to reject under the old Android fallback
  • exact coverage ratchets: 29/29 passed; cli-config.test.ts is back at its pinned 1,282 lines and Limrun retains its 29-module eager closure
  • pnpm check:affected --run passed, including format, lint, typecheck, layering, build, and 3,756 tests across 493 files
  • exact-head Size CI passed; remaining exact-head GitHub jobs are running

This touches 37 files. Scope spans the existing apps command, Limrun provider runtime, shared provider contracts, daemon routing, tests, and CLI help; it does not add a command family, public API, or flag.

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 2.48 MB 2.49 MB +5.8 kB
JS gzip 835.0 kB 837.8 kB +2.8 kB
npm tarball 958.5 kB 960.9 kB +2.4 kB
npm unpacked 3.32 MB 3.33 MB +6.1 kB

npm unpacked components

Component Base Current Diff
JS / dist source 2.64 MB 2.65 MB +6.1 kB
Apple runner source/project 581.1 kB 581.1 kB 0 B
macOS helper source 54.8 kB 54.8 kB 0 B
Android helper artifacts 0 B 0 B 0 B
Other package files 45.4 kB 45.4 kB 0 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 29.3 ms 29.6 ms +0.3 ms
CLI --help 81.5 ms 82.7 ms +1.2 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/session2.js +438 B +123 B
dist/src/registry.js +191 B +68 B
dist/src/cli-help.js +183 B +67 B
dist/src/sdk-batch-runner.js +163 B +37 B
dist/src/internal/daemon.js +119 B +32 B

Top changed packed files

Packed file Base Current Diff
dist/src/device-session.js 0 B 10.8 kB +10.8 kB
dist/src/src.js 19.2 kB 8.5 kB -10.7 kB
dist/src/session-allocation.js 0 B 2.0 kB +2.0 kB
dist/src/app-catalog.js 0 B 1.4 kB +1.4 kB
dist/src/session2.js 216.3 kB 216.7 kB +438 B
dist/src/connection.js 23.0 kB 23.4 kB +347 B
dist/src/application-lifecycle-interaction.js 4.6 kB 4.9 kB +317 B
dist/src/connection-runtime.js 19.4 kB 19.7 kB +308 B
dist/src/limrun.d.ts 10.2 kB 10.4 kB +256 B
dist/src/provider-device-runtime.js 2.8 kB 3.0 kB +200 B

@thymikee

Copy link
Copy Markdown
Member Author

Not ready.

[P1] Fail closed when mapping an uploaded asset to the installed app. resolveInstalledAppIdForAsset accepts a unique partial containment match, then Android falls back to whichever user-installed app is foreground. Either can bind the exact uploaded asset name to and launch the wrong installed app. Obtain an authoritative identifier from Limrun, or derive it from a strong provider-owned/before-after signal and fail otherwise. Add planted-red collision and unrelated-foreground cases.

[P2] Preserve request cancellation through sessionless catalog lookup. ProviderAppCatalog accepts an AbortSignal and Limrun uses it, but resolveProviderAppCatalogResponse invokes it without the daemon request signal, so a cancelled/timed-out apps request can leave provider I/O running. Thread the request signal and test abort.

Exact-head Coverage has two owner-action failures: cli-config.test.ts grew 1282→1383 past its ratchet (extract the Limrun cases), and provider-limrun eager closure grew 29→32. Android smoke is red on the recurring native-alert timeout and needs rerun/base evidence. Remove the new narration docblocks. Size evidence crosses the +3 kB unpacked scrutiny trigger (+3.8 kB), so itemize justified packed growth and why a smaller seam was rejected. The live Limrun Android/iOS evidence and cleanup are otherwise strong.

@thymikee
thymikee force-pushed the feat/limrun-uploaded-apps branch from 82cb7cb to dbfa651 Compare August 28, 2026 06:37
@thymikee

Copy link
Copy Markdown
Member Author

Addressed in dbfa651 after rebasing onto current main:

  • removed partial/single-app/foreground fallback matching; uploaded assets now resolve only through an unambiguous exact normalized ID, terminal ID, or app name
  • added planted-red collision and unrelated-foreground regressions
  • threaded the daemon request signal into sessionless provider catalog lookup and added an in-flight abort test
  • split Limrun CLI cases into cli-config-limrun.test.ts, restoring cli-config.test.ts to its 1,282-line pin
  • lazily loaded the three Limrun allocation/catalog modules, restoring the eager closure to 29
  • removed the added narration docblocks
  • itemized package growth and the rejected smaller seams in the PR body

Local static gates and exact ratchets pass. The affected suite produced changing unrelated load failures across two runs; all 3,753 tests passed on the first run before teardown noise, and the second run's two timed-out interaction-contract files passed 16/16 immediately in isolation. Fresh exact-head CI is running.

@thymikee
thymikee force-pushed the feat/limrun-uploaded-apps branch from dbfa651 to 24bdcd0 Compare August 28, 2026 06:45
@thymikee

Copy link
Copy Markdown
Member Author

Re-reviewed 265259cc. I found no code defect in the strict exact-ID mapping, Android fallback removal, cancellation propagation, or lazy provider loading; the planted-red coverage is meaningful.

It is not merge-ready yet:

  1. Live Limrun Android and iOS apps → open <uploaded filename> → snapshot/click evidence is stamped only at 82cb7cb1, before the identity/fallback changes. Repeat it at this exact head and record cleanup.
  2. Update the size rationale from +3.8 kB to the current Size CI result, +6.3 kB npm unpacked, with the current itemization.
  3. iOS Smoke was still running at review time.

Main compatibility is clean.

@thymikee

Copy link
Copy Markdown
Member Author

Addressed at exact head 265259cc62.

Live Limrun evidence:

  • Android connect verified access with leaseAllocated: false; apps listed com.callstack.agentdevicelab.apk; open resolved it to com.callstack.agentdevicelab in 6.15s wall time. snapshot -i --json reported the expected bundle, healthy android-helper backend, and helper version 0.20.11-dev. Clicking the Catalog ref succeeded and the next snapshot showed Catalog, 12 results.
  • iOS connect verified access with leaseAllocated: false; apps listed easagentdevice.app.zip; open resolved it to dev.expo.easagentdevice in 4.64s wall time. The snapshot showed Development Build; clicking INFO succeeded and the next snapshot showed the development-build instructions.
  • Cleanup: Limrun's three-minute inactivity expiry won the Android close race and returned typed LEASE_NOT_FOUND. Direct get calls for both exact instance IDs returned 404, confirming termination. Both local connection profiles were disconnected.

Size rationale is updated in the PR body for exact-head Size CI: +6.3 kB npm unpacked (+6.0 kB raw JS, +3.3 kB gzip, +2.4 kB tarball), entirely under JS/dist. About 3.4 kB raw is the three lazy provider-owned feature chunks (app-catalog, session-allocation, app-preinstall); the remaining ~2.9 kB net covers the neutral catalog/daemon/capability/lifecycle/help/declaration seams. The apparent ios.js +9.4 kB is chunk relocation paired with src.js -10.7 kB, not additive growth. The body also retains why device inventory, CLI-owned resolution, and a provider-specific command/flag were rejected as smaller-looking but incorrect seams.

Exact-head CI is now fully green, including iOS Smoke.

@thymikee

Copy link
Copy Markdown
Member Author

Follow-up size audit at 32309bb5a3 found one safe simplification: the shallow 37-line app-preinstall.ts module now lives with session allocation, removing one dynamic import/chunk while preserving the 29-module eager closure. Exact-head Size CI moved from +6.3 kB to +6.1 kB npm unpacked (+5.8 kB raw JS, +2.8 kB gzip, +2.4 kB tarball).\n\nI also measured the more aggressive counterfactual. Coalescing catalog, identity resolution, and allocation saves only another 403 raw bytes, but makes pre-allocation apps load a 17.4 kB allocation/platform chunk. I rejected that trade: it optimizes package accounting by less than half a kilobyte while making the non-allocating catalog path materially heavier. File moves alone do not reduce the metric because Size CI sums all emitted JS; only eliminated wrappers/duplication or changed tree-shaking count.\n\nThe PR body now contains the exact-head itemization and this rejection rationale. Locally, focused catalog/runtime/closure tests passed 387/387 and pnpm check:affected --run passed all 3,756 tests plus format, lint, typecheck, layering, and build.

@thymikee

Copy link
Copy Markdown
Member Author

Reviewed exact head 32309bb: clean and ready for human review. The delta from the live-tested behavior head is a behavior-preserving relocation of the two app-preinstall functions into session-allocation; exact-head checks are fully green. Discovery remains allocation-free, exact uploaded-name selection precedes allocation, identity resolution fails closed, and cancellation is threaded. Size rationale and planted-red coverage are sufficient. Residual: live Limrun evidence is stamped at 265259c, but the current byte-equivalent relocation plus exact-head package/platform CI does not warrant a device rerun.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant