@kafitra/lynx-cli
v0.2.2
Published
Developer workflow CLI for Lynx Native Modules — autolink, run, prebuild, dev, doctor
Maintainers
Readme
@kafitra/lynx-cli
Developer workflow CLI for Lynx Native Modules.
From project generation to device launch — one tool for the full Android/iOS dev cycle.Repository: github.com/kafitramarna/kafitra-lynx-native
Overview
lynx doctor ← check your environment
lynx prebuild ← generate Android host project
lynx link ← wire native modules into Gradle
lynx run android ← build + install + launch on device
lynx dev ← start JS dev server
lynx run ios ← build + launch on iOS simulator (macOS)Installation
pnpm add -D @kafitra/lynx-cli
# or
npm install --save-dev @kafitra/lynx-cliAdd to package.json scripts:
{
"scripts": {
"android": "lynx run android --android-dir android-host",
"dev": "lynx dev",
"doctor": "lynx doctor"
}
}Commands
lynx doctor
Check your development environment before you start.
npx @kafitra/lynx-cli doctor| Check | Required | Description |
| ---------------- | -------- | -------------------------------- |
| Node.js ≥ 18 | critical | Runtime version |
| Java (JDK) ≥ 17 | critical | Android build toolchain |
| adb | critical | Android Debug Bridge |
| ANDROID_HOME | warning | Android SDK root |
| Gradle wrapper | critical | gradlew + gradle-wrapper.jar |
| Connected device | warning | At least one device/emulator |
Exits with code 1 if any critical check fails.
lynx prebuild
Generate a minimal clean Android host project from template.
npx @kafitra/lynx-cli prebuild --package com.example.myapp| Option | Default | Description |
| ----------------------- | --------- | ------------------------------------------ |
| --package <id> | — | Required. Java package / applicationId |
| --android-dir <path> | android | Output directory name |
| --project-root <path> | cwd | Project root |
| --force | off | Overwrite existing directory |
Generates:
android/
├── settings.gradle
├── build.gradle
├── gradlew / gradlew.bat
├── gradle/wrapper/gradle-wrapper.properties
└── app/
├── build.gradle ← Lynx 3.6.0 deps pre-configured
├── proguard-rules.pro
└── src/main/
├── AndroidManifest.xml
├── assets/ ← put main.lynx.bundle here
└── java/com/example/myapp/
├── LynxApplication.java
├── MainActivity.java
├── LynxTemplateProvider.java
└── LynxAutolinkRegistry.javaAuto-runs lynx link after generation to wire up any installed modules.
Note:
gradle-wrapper.jaris auto-downloaded from GitHub if missing — no manual step needed.
Note: Generated
MainActivityextendsAppCompatActivity— required for CameraX lifecycle binding and runtime permission dialogs.
lynx link
Scan node_modules, generate LynxAutolinkRegistry.java, and patch settings.gradle,
app/build.gradle, and AndroidManifest.xml.
npx @kafitra/lynx-cli link [options]| Option | Default | Description |
| ----------------------- | ----------------------------- | ----------------------------------------------------- |
| --project-root <path> | cwd | Root of the host project (where node_modules lives) |
| --android-dir <path> | android | Android directory name |
| --java-package <name> | inferred from applicationId | Java package for the registry class |
All patch operations are idempotent — running the command twice produces the same result.
Steps performed:
- Scan
node_modulesforlynx.module.jsonpackages - Generate
LynxAutolinkRegistry.java - Inject
settings.gradleproject includes - Inject
app/build.gradledependencies - Inject
AndroidManifest.xml<uses-permission>entries (from each module'spermissionsfield)
One-time Application class setup:
private void initLynxEnv() {
LynxEnv.inst().init(this, null, null, null);
LynxAutolinkRegistry.registerAll(); // ← call once
}lynx run android
Auto-link → build APK → install → launch. One command replaces all manual steps. `
npx @kafitra/lynx-cli run android [options]| Option | Default | Description |
| ----------------------- | ------------ | ----------------------------- |
| --project-root <path> | cwd | Root of the host project |
| --android-dir <path> | android | Android directory name |
| --device <serial> | first device | Target specific device serial |
| --no-link | off | Skip auto-running lynx link |
What it does:
- Runs
lynx link(unless--no-link) - Checks if dev server is running on port 3000; starts it in a new terminal if not
- Detects connected devices via
adb devices; auto-launches AVD if none found - Copies
dist/main.lynx.bundle→ assets (if missing), then runsgradlew installDebug - Sets up
adb reverse tcp:3000 tcp:3000 - Launches app via
adb shell am start
Examples:
# Standard
npx @kafitra/lynx-cli run android
# Custom android dir (monorepo)
npx @kafitra/lynx-cli run android --android-dir android-host
# From repo root
npx @kafitra/lynx-cli run android --project-root apps/demo --android-dir android-host
# Target specific device
npx @kafitra/lynx-cli run android --device emulator-5554lynx dev
Start the JS dev server and display bundle URLs for all network interfaces.
npx @kafitra/lynx-cli dev [options]| Option | Default | Description |
| ----------------------- | ------- | -------------------------------------- |
| --project-root <path> | cwd | Project root containing package.json |
| --port <number> | 3000 | Dev server port |
Auto-detects package manager (pnpm, yarn, or npm) and spawns run dev.
Prints all bundle URLs for localhost and LAN. Ctrl+C shuts down cleanly.
→ Starting dev server…
ℹ Bundle URLs:
ℹ Local: http://localhost:3000/main.lynx.bundle
ℹ Network: http://192.168.1.42:3000/main.lynx.bundle
ℹ Android port forwarding:
ℹ adb reverse tcp:3000 tcp:3000lynx run ios
Build and launch on iOS simulator. macOS only.
npx @kafitra/lynx-cli run ios --bundle-id com.example.myapp| Option | Default | Description |
| ----------------------- | ------- | -------------------------------------------- |
| --project-root <path> | cwd | Root of the host project |
| --ios-dir <path> | ios | iOS directory name |
| --bundle-id <id> | — | iOS bundle identifier (for simulator launch) |
| --no-pod-install | off | Skip pod install |
What it does:
- Guards non-macOS systems
- Validates
ios/*.xcworkspaceexists - Runs
pod install - Builds via
xcodebuild -sdk iphonesimulator - Launches on booted simulator via
xcrun simctl launch
Monorepo usage
# From repo root, targeting a specific app
npx @kafitra/lynx-cli run android \
--project-root apps/demo \
--android-dir android-host
# Or via workspace script
pnpm --filter @your/demo run androidHow a module declares itself
Each Lynx Native Module must include a lynx.module.json at its package root:
{
"name": "LynxDeviceInfo",
"android": {
"moduleClass": "com.kafitra.lynxdeviceinfo.LynxDeviceInfoModule",
"sourceDir": "android"
}
}See @kafitra/lynx-autolink for the full schema reference.
Troubleshooting
No Android devices or emulators found
→ Connect a device with USB debugging enabled, or start an AVD emulator.
Gradle wrapper not found
→ Run lynx prebuild --package <id> to generate the project, or
→ Run gradle wrapper --gradle-version 8.2 inside your Android directory.
pod install failed: CocoaPods not found
→ sudo gem install cocoapods
adb: command not found
→ Install Android SDK Platform-Tools and add to PATH.
ANDROID_HOME not set
→ Set it to your SDK path. Run lynx doctor for exact instructions.
Build fails with AbstractMethodError
→ Do not register LynxHttpService — it is incompatible with lynx:3.6.0 core.
Other flags
lynx --version # print CLI version
lynx --help # print usageRequirements
- Node.js ≥ 18
- JDK ≥ 17 (for Android builds)
- Android SDK +
adbin PATH - AGP ≥ 7.x, Gradle ≥ 8.x
- Each Lynx Native Module must have
lynx.module.json
License
MIT
