@10play/expo-air 0.1.0
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/README.md +156 -0
- package/android/build.gradle +43 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/expo/modules/expoair/ExpoAirModule.kt +50 -0
- package/android/src/main/java/expo/modules/expoair/ExpoAirView.kt +30 -0
- package/build/ExpoAir.types.d.ts +25 -0
- package/build/ExpoAir.types.d.ts.map +1 -0
- package/build/ExpoAir.types.js +2 -0
- package/build/ExpoAir.types.js.map +1 -0
- package/build/ExpoAirModule.d.ts +17 -0
- package/build/ExpoAirModule.d.ts.map +1 -0
- package/build/ExpoAirModule.js +4 -0
- package/build/ExpoAirModule.js.map +1 -0
- package/build/ExpoAirModule.web.d.ts +10 -0
- package/build/ExpoAirModule.web.d.ts.map +1 -0
- package/build/ExpoAirModule.web.js +12 -0
- package/build/ExpoAirModule.web.js.map +1 -0
- package/build/ExpoAirView.d.ts +4 -0
- package/build/ExpoAirView.d.ts.map +1 -0
- package/build/ExpoAirView.js +7 -0
- package/build/ExpoAirView.js.map +1 -0
- package/build/ExpoAirView.web.d.ts +4 -0
- package/build/ExpoAirView.web.d.ts.map +1 -0
- package/build/ExpoAirView.web.js +7 -0
- package/build/ExpoAirView.web.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +6 -0
- package/build/index.js.map +1 -0
- package/cli/dist/bin/expo-air.d.ts +3 -0
- package/cli/dist/bin/expo-air.d.ts.map +1 -0
- package/cli/dist/bin/expo-air.js +51 -0
- package/cli/dist/bin/expo-air.js.map +1 -0
- package/cli/dist/commands/fly.d.ts +11 -0
- package/cli/dist/commands/fly.d.ts.map +1 -0
- package/cli/dist/commands/fly.js +324 -0
- package/cli/dist/commands/fly.js.map +1 -0
- package/cli/dist/commands/init.d.ts +7 -0
- package/cli/dist/commands/init.d.ts.map +1 -0
- package/cli/dist/commands/init.js +126 -0
- package/cli/dist/commands/init.js.map +1 -0
- package/cli/dist/commands/server.d.ts +7 -0
- package/cli/dist/commands/server.d.ts.map +1 -0
- package/cli/dist/commands/server.js +40 -0
- package/cli/dist/commands/server.js.map +1 -0
- package/cli/dist/commands/start.d.ts +12 -0
- package/cli/dist/commands/start.d.ts.map +1 -0
- package/cli/dist/commands/start.js +266 -0
- package/cli/dist/commands/start.js.map +1 -0
- package/cli/dist/server/promptServer.d.ts +38 -0
- package/cli/dist/server/promptServer.d.ts.map +1 -0
- package/cli/dist/server/promptServer.js +591 -0
- package/cli/dist/server/promptServer.js.map +1 -0
- package/cli/dist/tsconfig.tsbuildinfo +1 -0
- package/cli/dist/tunnel/bore.d.ts +24 -0
- package/cli/dist/tunnel/bore.d.ts.map +1 -0
- package/cli/dist/tunnel/bore.js +157 -0
- package/cli/dist/tunnel/bore.js.map +1 -0
- package/cli/dist/tunnel/cloudflare.d.ts +17 -0
- package/cli/dist/tunnel/cloudflare.d.ts.map +1 -0
- package/cli/dist/tunnel/cloudflare.js +159 -0
- package/cli/dist/tunnel/cloudflare.js.map +1 -0
- package/cli/dist/tunnel/localhost-run.d.ts +13 -0
- package/cli/dist/tunnel/localhost-run.d.ts.map +1 -0
- package/cli/dist/tunnel/localhost-run.js +65 -0
- package/cli/dist/tunnel/localhost-run.js.map +1 -0
- package/cli/dist/tunnel/localtunnel.d.ts +12 -0
- package/cli/dist/tunnel/localtunnel.d.ts.map +1 -0
- package/cli/dist/tunnel/localtunnel.js +23 -0
- package/cli/dist/tunnel/localtunnel.js.map +1 -0
- package/cli/dist/types/messages.d.ts +90 -0
- package/cli/dist/types/messages.d.ts.map +1 -0
- package/cli/dist/types/messages.js +8 -0
- package/cli/dist/types/messages.js.map +1 -0
- package/expo-module.config.json +10 -0
- package/ios/ExpoAir.podspec +34 -0
- package/ios/ExpoAirAppDelegateSubscriber.swift +85 -0
- package/ios/ExpoAirModule.swift +88 -0
- package/ios/ExpoAirView.swift +38 -0
- package/ios/FloatingBubbleManager.swift +483 -0
- package/ios/WidgetBridge.h +4 -0
- package/ios/WidgetBridge.mm +64 -0
- package/ios/WidgetRuntime.h +11 -0
- package/ios/WidgetRuntime.mm +153 -0
- package/package.json +90 -0
- package/plugin/build/index.d.ts +3 -0
- package/plugin/build/index.js +152 -0
- package/widget/BubbleContent.tsx +474 -0
- package/widget/app.json +8 -0
- package/widget/babel.config.js +6 -0
- package/widget/components/GitChangesTab.tsx +148 -0
- package/widget/components/PromptInput.tsx +150 -0
- package/widget/components/ResponseArea.tsx +253 -0
- package/widget/index.ts +5 -0
- package/widget/metro.config.js +28 -0
- package/widget/package.json +16 -0
- package/widget/services/websocket.ts +316 -0
- package/widget/tsconfig.json +4 -0
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# @10play/expo-air
|
|
2
|
+
|
|
3
|
+
Vibe Coding for React-Native - AI-powered on-device development with Claude.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Floating widget overlay on your iOS device
|
|
8
|
+
- Send prompts to Claude directly from your phone
|
|
9
|
+
- Real-time code changes via Expo Metro
|
|
10
|
+
- Git status monitoring
|
|
11
|
+
- Tunnel support for remote development
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Expo SDK 54+
|
|
16
|
+
- iOS 15.1+ (iOS only in v0)
|
|
17
|
+
- Node.js 18+
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
### 1. Install the package
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @10play/expo-air
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Initialize in your project
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx expo-air init
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This will:
|
|
34
|
+
- Create `.expo-air.json` configuration file
|
|
35
|
+
- Add the plugin to your `app.json`
|
|
36
|
+
- Update `.gitignore`
|
|
37
|
+
- Run `expo prebuild` to generate native iOS code
|
|
38
|
+
|
|
39
|
+
### 3. Start development
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx expo-air start
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This starts:
|
|
46
|
+
- Widget Metro server (port 8082)
|
|
47
|
+
- Prompt server (port 3847)
|
|
48
|
+
- App Metro server (port 8081)
|
|
49
|
+
- Cloudflare tunnels for remote access (optional)
|
|
50
|
+
|
|
51
|
+
The widget will appear automatically when your app launches in DEBUG mode.
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
### CLI Commands
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Initialize expo-air in your project
|
|
59
|
+
npx expo-air init
|
|
60
|
+
npx expo-air init --force # Overwrite existing config
|
|
61
|
+
npx expo-air init --skip-prebuild # Skip running expo prebuild
|
|
62
|
+
|
|
63
|
+
# Start the development environment
|
|
64
|
+
npx expo-air start
|
|
65
|
+
npx expo-air start --no-tunnel # Skip tunnel (local network only)
|
|
66
|
+
npx expo-air start --no-build # Skip building the app
|
|
67
|
+
npx expo-air start --no-server # Skip starting the WebSocket server
|
|
68
|
+
|
|
69
|
+
# Start only the WebSocket server
|
|
70
|
+
npx expo-air server
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Port Options
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx expo-air start \
|
|
77
|
+
--port 3847 \ # Prompt server port
|
|
78
|
+
--widget-port 8082 \ # Widget Metro port
|
|
79
|
+
--metro-port 8081 # App Metro port
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Configuration
|
|
83
|
+
|
|
84
|
+
### .expo-air.json
|
|
85
|
+
|
|
86
|
+
Configuration file created by `expo-air init`:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"autoShow": true,
|
|
91
|
+
"ui": {
|
|
92
|
+
"bubbleSize": 60,
|
|
93
|
+
"bubbleColor": "#007AFF"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
| Option | Type | Default | Description |
|
|
99
|
+
|--------|------|---------|-------------|
|
|
100
|
+
| `autoShow` | boolean | `true` | Auto-show widget on app launch |
|
|
101
|
+
| `ui.bubbleSize` | number | `60` | Size of the floating bubble |
|
|
102
|
+
| `ui.bubbleColor` | string | `"#007AFF"` | Color of the floating bubble |
|
|
103
|
+
|
|
104
|
+
### .expo-air.local.json (gitignored)
|
|
105
|
+
|
|
106
|
+
Auto-generated file containing tunnel URLs for the current session:
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"serverUrl": "wss://...",
|
|
111
|
+
"widgetMetroUrl": "https://...",
|
|
112
|
+
"appMetroUrl": "https://..."
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## How It Works
|
|
117
|
+
|
|
118
|
+
1. **App launches** - `ExpoAirAppDelegateSubscriber` triggers (DEBUG builds only)
|
|
119
|
+
2. **Config loaded** - Settings read from `Info.plist` (set by plugin during prebuild)
|
|
120
|
+
3. **Widget loads** - `FloatingBubbleManager` loads widget bundle from Metro server
|
|
121
|
+
4. **Connection established** - Widget connects to prompt server via WebSocket
|
|
122
|
+
5. **Ready to vibe** - Send prompts to Claude from your device
|
|
123
|
+
|
|
124
|
+
## Development Mode Only
|
|
125
|
+
|
|
126
|
+
The widget is designed for development only and will **never appear in production builds**. This is enforced via:
|
|
127
|
+
|
|
128
|
+
- `#if DEBUG` guards in native Swift code
|
|
129
|
+
- Widget loads from Metro dev server (no bundled JS)
|
|
130
|
+
- No impact on release builds
|
|
131
|
+
|
|
132
|
+
## Troubleshooting
|
|
133
|
+
|
|
134
|
+
### Widget not appearing
|
|
135
|
+
|
|
136
|
+
1. Ensure you're running a DEBUG build (not release/production)
|
|
137
|
+
2. Check that Metro servers are running (`npx expo-air start`)
|
|
138
|
+
3. Verify `autoShow: true` in `.expo-air.json`
|
|
139
|
+
4. Check Xcode console for `[expo-air]` logs
|
|
140
|
+
|
|
141
|
+
### Connection issues
|
|
142
|
+
|
|
143
|
+
1. For local development, ensure device is on same WiFi as your computer
|
|
144
|
+
2. For remote development, use tunnels (`npx expo-air start` enables by default)
|
|
145
|
+
3. Check that ports 3847, 8081, 8082 are not blocked
|
|
146
|
+
|
|
147
|
+
### Prebuild issues
|
|
148
|
+
|
|
149
|
+
If prebuild fails, try:
|
|
150
|
+
```bash
|
|
151
|
+
npx expo prebuild --platform ios --clean
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## License
|
|
155
|
+
|
|
156
|
+
MIT
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
|
|
3
|
+
group = 'expo.modules.expoair'
|
|
4
|
+
version = '0.1.0'
|
|
5
|
+
|
|
6
|
+
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
|
+
apply from: expoModulesCorePlugin
|
|
8
|
+
applyKotlinExpoModulesCorePlugin()
|
|
9
|
+
useCoreDependencies()
|
|
10
|
+
useExpoPublishing()
|
|
11
|
+
|
|
12
|
+
// If you want to use the managed Android SDK versions from expo-modules-core, set this to true.
|
|
13
|
+
// The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code.
|
|
14
|
+
// Most of the time, you may like to manage the Android SDK versions yourself.
|
|
15
|
+
def useManagedAndroidSdkVersions = false
|
|
16
|
+
if (useManagedAndroidSdkVersions) {
|
|
17
|
+
useDefaultAndroidSdkVersions()
|
|
18
|
+
} else {
|
|
19
|
+
buildscript {
|
|
20
|
+
// Simple helper that allows the root project to override versions declared by this library.
|
|
21
|
+
ext.safeExtGet = { prop, fallback ->
|
|
22
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
project.android {
|
|
26
|
+
compileSdkVersion safeExtGet("compileSdkVersion", 36)
|
|
27
|
+
defaultConfig {
|
|
28
|
+
minSdkVersion safeExtGet("minSdkVersion", 24)
|
|
29
|
+
targetSdkVersion safeExtGet("targetSdkVersion", 36)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
android {
|
|
35
|
+
namespace "expo.modules.expoair"
|
|
36
|
+
defaultConfig {
|
|
37
|
+
versionCode 1
|
|
38
|
+
versionName "0.1.0"
|
|
39
|
+
}
|
|
40
|
+
lintOptions {
|
|
41
|
+
abortOnError false
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package expo.modules.expoair
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.modules.Module
|
|
4
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
5
|
+
import java.net.URL
|
|
6
|
+
|
|
7
|
+
class ExpoAirModule : Module() {
|
|
8
|
+
// Each module class must implement the definition function. The definition consists of components
|
|
9
|
+
// that describes the module's functionality and behavior.
|
|
10
|
+
// See https://docs.expo.dev/modules/module-api for more details about available components.
|
|
11
|
+
override fun definition() = ModuleDefinition {
|
|
12
|
+
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
|
|
13
|
+
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
|
|
14
|
+
// The module will be accessible from `requireNativeModule('ExpoAir')` in JavaScript.
|
|
15
|
+
Name("ExpoAir")
|
|
16
|
+
|
|
17
|
+
// Defines constant property on the module.
|
|
18
|
+
Constant("PI") {
|
|
19
|
+
Math.PI
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Defines event names that the module can send to JavaScript.
|
|
23
|
+
Events("onChange")
|
|
24
|
+
|
|
25
|
+
// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
|
|
26
|
+
Function("hello") {
|
|
27
|
+
"Hello world! 👋"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Defines a JavaScript function that always returns a Promise and whose native code
|
|
31
|
+
// is by default dispatched on the different thread than the JavaScript runtime runs on.
|
|
32
|
+
AsyncFunction("setValueAsync") { value: String ->
|
|
33
|
+
// Send an event to JavaScript.
|
|
34
|
+
sendEvent("onChange", mapOf(
|
|
35
|
+
"value" to value
|
|
36
|
+
))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Enables the module to be used as a native view. Definition components that are accepted as part of
|
|
40
|
+
// the view definition: Prop, Events.
|
|
41
|
+
View(ExpoAirView::class) {
|
|
42
|
+
// Defines a setter for the `url` prop.
|
|
43
|
+
Prop("url") { view: ExpoAirView, url: URL ->
|
|
44
|
+
view.webView.loadUrl(url.toString())
|
|
45
|
+
}
|
|
46
|
+
// Defines an event that the view can send to JavaScript.
|
|
47
|
+
Events("onLoad")
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
package expo.modules.expoair
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.webkit.WebView
|
|
5
|
+
import android.webkit.WebViewClient
|
|
6
|
+
import expo.modules.kotlin.AppContext
|
|
7
|
+
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
8
|
+
import expo.modules.kotlin.views.ExpoView
|
|
9
|
+
|
|
10
|
+
class ExpoAirView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
11
|
+
// Creates and initializes an event dispatcher for the `onLoad` event.
|
|
12
|
+
// The name of the event is inferred from the value and needs to match the event name defined in the module.
|
|
13
|
+
private val onLoad by EventDispatcher()
|
|
14
|
+
|
|
15
|
+
// Defines a WebView that will be used as the root subview.
|
|
16
|
+
internal val webView = WebView(context).apply {
|
|
17
|
+
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
18
|
+
webViewClient = object : WebViewClient() {
|
|
19
|
+
override fun onPageFinished(view: WebView, url: String) {
|
|
20
|
+
// Sends an event to JavaScript. Triggers a callback defined on the view component in JavaScript.
|
|
21
|
+
onLoad(mapOf("url" to url))
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
init {
|
|
27
|
+
// Adds the WebView to the view hierarchy.
|
|
28
|
+
addView(webView)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
export type OnLoadEventPayload = {
|
|
3
|
+
url: string;
|
|
4
|
+
};
|
|
5
|
+
export type ExpoAirModuleEvents = {
|
|
6
|
+
onChange: (params: ChangeEventPayload) => void;
|
|
7
|
+
onPress: () => void;
|
|
8
|
+
onExpand: () => void;
|
|
9
|
+
onCollapse: () => void;
|
|
10
|
+
onDragEnd: (params: {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
}) => void;
|
|
14
|
+
};
|
|
15
|
+
export type ChangeEventPayload = {
|
|
16
|
+
value: string;
|
|
17
|
+
};
|
|
18
|
+
export type ExpoAirViewProps = {
|
|
19
|
+
url: string;
|
|
20
|
+
onLoad: (event: {
|
|
21
|
+
nativeEvent: OnLoadEventPayload;
|
|
22
|
+
}) => void;
|
|
23
|
+
style?: StyleProp<ViewStyle>;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=ExpoAir.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAir.types.d.ts","sourceRoot":"","sources":["../src/ExpoAir.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC/C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,SAAS,EAAE,CAAC,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,kBAAkB,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7D,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAir.types.js","sourceRoot":"","sources":["../src/ExpoAir.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { StyleProp, ViewStyle } from 'react-native';\n\nexport type OnLoadEventPayload = {\n url: string;\n};\n\nexport type ExpoAirModuleEvents = {\n onChange: (params: ChangeEventPayload) => void;\n onPress: () => void;\n onExpand: () => void;\n onCollapse: () => void;\n onDragEnd: (params: { x: number; y: number }) => void;\n};\n\nexport type ChangeEventPayload = {\n value: string;\n};\n\nexport type ExpoAirViewProps = {\n url: string;\n onLoad: (event: { nativeEvent: OnLoadEventPayload }) => void;\n style?: StyleProp<ViewStyle>;\n};\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { NativeModule } from 'expo';
|
|
2
|
+
import { ExpoAirModuleEvents } from './ExpoAir.types';
|
|
3
|
+
declare class ExpoAirModule extends NativeModule<ExpoAirModuleEvents> {
|
|
4
|
+
PI: number;
|
|
5
|
+
hello(): string;
|
|
6
|
+
setValueAsync(value: string): Promise<void>;
|
|
7
|
+
show(options?: {
|
|
8
|
+
size?: number;
|
|
9
|
+
color?: string;
|
|
10
|
+
}): void;
|
|
11
|
+
hide(): void;
|
|
12
|
+
expand(): void;
|
|
13
|
+
collapse(): void;
|
|
14
|
+
}
|
|
15
|
+
declare const _default: ExpoAirModule;
|
|
16
|
+
export default _default;
|
|
17
|
+
//# sourceMappingURL=ExpoAirModule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAirModule.d.ts","sourceRoot":"","sources":["../src/ExpoAirModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,OAAO,aAAc,SAAQ,YAAY,CAAC,mBAAmB,CAAC;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,IAAI,MAAM;IACf,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3C,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IACvD,IAAI,IAAI,IAAI;IACZ,MAAM,IAAI,IAAI;IACd,QAAQ,IAAI,IAAI;CACjB;;AAGD,wBAA6D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAirModule.js","sourceRoot":"","sources":["../src/ExpoAirModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAczD,yDAAyD;AACzD,eAAe,mBAAmB,CAAgB,SAAS,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\n\nimport { ExpoAirModuleEvents } from './ExpoAir.types';\n\ndeclare class ExpoAirModule extends NativeModule<ExpoAirModuleEvents> {\n PI: number;\n hello(): string;\n setValueAsync(value: string): Promise<void>;\n show(options?: { size?: number; color?: string }): void;\n hide(): void;\n expand(): void;\n collapse(): void;\n}\n\n// This call loads the native module object from the JSI.\nexport default requireNativeModule<ExpoAirModule>('ExpoAir');\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NativeModule } from 'expo';
|
|
2
|
+
import { ExpoAirModuleEvents } from './ExpoAir.types';
|
|
3
|
+
declare class ExpoAirModule extends NativeModule<ExpoAirModuleEvents> {
|
|
4
|
+
PI: number;
|
|
5
|
+
setValueAsync(value: string): Promise<void>;
|
|
6
|
+
hello(): string;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: typeof ExpoAirModule;
|
|
9
|
+
export default _default;
|
|
10
|
+
//# sourceMappingURL=ExpoAirModule.web.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAirModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoAirModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,YAAY,EAAE,MAAM,MAAM,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,cAAM,aAAc,SAAQ,YAAY,CAAC,mBAAmB,CAAC;IAC3D,EAAE,SAAW;IACP,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAGjD,KAAK;CAGN;;AAED,wBAAiE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { registerWebModule, NativeModule } from 'expo';
|
|
2
|
+
class ExpoAirModule extends NativeModule {
|
|
3
|
+
PI = Math.PI;
|
|
4
|
+
async setValueAsync(value) {
|
|
5
|
+
this.emit('onChange', { value });
|
|
6
|
+
}
|
|
7
|
+
hello() {
|
|
8
|
+
return 'Hello world! 👋';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export default registerWebModule(ExpoAirModule, 'ExpoAirModule');
|
|
12
|
+
//# sourceMappingURL=ExpoAirModule.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAirModule.web.js","sourceRoot":"","sources":["../src/ExpoAirModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAIvD,MAAM,aAAc,SAAQ,YAAiC;IAC3D,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;IACb,KAAK,CAAC,aAAa,CAAC,KAAa;QAC/B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,KAAK;QACH,OAAO,iBAAiB,CAAC;IAC3B,CAAC;CACF;AAED,eAAe,iBAAiB,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC","sourcesContent":["import { registerWebModule, NativeModule } from 'expo';\n\nimport { ExpoAirModuleEvents } from './ExpoAir.types';\n\nclass ExpoAirModule extends NativeModule<ExpoAirModuleEvents> {\n PI = Math.PI;\n async setValueAsync(value: string): Promise<void> {\n this.emit('onChange', { value });\n }\n hello() {\n return 'Hello world! 👋';\n }\n}\n\nexport default registerWebModule(ExpoAirModule, 'ExpoAirModule');\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAirView.d.ts","sourceRoot":"","sources":["../src/ExpoAirView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAKnD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAK,EAAE,gBAAgB,qBAE1D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAirView.js","sourceRoot":"","sources":["../src/ExpoAirView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,UAAU,GACd,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAE/B,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAuB;IACzD,OAAO,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,EAAG,CAAC;AACnC,CAAC","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\n\nimport { ExpoAirViewProps } from './ExpoAir.types';\n\nconst NativeView: React.ComponentType<ExpoAirViewProps> =\n requireNativeView('ExpoAir');\n\nexport default function ExpoAirView(props: ExpoAirViewProps) {\n return <NativeView {...props} />;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAirView.web.d.ts","sourceRoot":"","sources":["../src/ExpoAirView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAK,EAAE,gBAAgB,qBAU1D"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export default function ExpoAirView(props) {
|
|
3
|
+
return (<div>
|
|
4
|
+
<iframe style={{ flex: 1 }} src={props.url} onLoad={() => props.onLoad({ nativeEvent: { url: props.url } })}/>
|
|
5
|
+
</div>);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=ExpoAirView.web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoAirView.web.js","sourceRoot":"","sources":["../src/ExpoAirView.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,CAAC,OAAO,UAAU,WAAW,CAAC,KAAuB;IACzD,OAAO,CACL,CAAC,GAAG,CACF;MAAA,CAAC,MAAM,CACL,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CACnB,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CACf,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAEpE;IAAA,EAAE,GAAG,CAAC,CACP,CAAC;AACJ,CAAC","sourcesContent":["import * as React from 'react';\n\nimport { ExpoAirViewProps } from './ExpoAir.types';\n\nexport default function ExpoAirView(props: ExpoAirViewProps) {\n return (\n <div>\n <iframe\n style={{ flex: 1 }}\n src={props.url}\n onLoad={() => props.onLoad({ nativeEvent: { url: props.url } })}\n />\n </div>\n );\n}\n"]}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAc,iBAAiB,CAAC"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Reexport the native module. On web, it will be resolved to ExpoAirModule.web.ts
|
|
2
|
+
// and on native platforms to ExpoAirModule.ts
|
|
3
|
+
export { default } from './ExpoAirModule';
|
|
4
|
+
export { default as ExpoAirView } from './ExpoAirView';
|
|
5
|
+
export * from './ExpoAir.types';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,8CAA8C;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAc,iBAAiB,CAAC","sourcesContent":["// Reexport the native module. On web, it will be resolved to ExpoAirModule.web.ts\n// and on native platforms to ExpoAirModule.ts\nexport { default } from './ExpoAirModule';\nexport { default as ExpoAirView } from './ExpoAirView';\nexport * from './ExpoAir.types';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expo-air.d.ts","sourceRoot":"","sources":["../../bin/expo-air.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { startCommand } from "../commands/start.js";
|
|
4
|
+
import { serverCommand } from "../commands/server.js";
|
|
5
|
+
import { initCommand } from "../commands/init.js";
|
|
6
|
+
import { flyCommand } from "../commands/fly.js";
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("expo-air")
|
|
10
|
+
.description("Vibe Coding for React-Native - Mobile assistant for Claude Code")
|
|
11
|
+
.version("0.1.0");
|
|
12
|
+
program
|
|
13
|
+
.command("init")
|
|
14
|
+
.description("Initialize expo-air in your Expo project")
|
|
15
|
+
.option("-f, --force", "Overwrite existing configuration")
|
|
16
|
+
.option("--skip-prebuild", "Skip running expo prebuild")
|
|
17
|
+
.action(initCommand);
|
|
18
|
+
program
|
|
19
|
+
.command("start")
|
|
20
|
+
.description("Start the development environment")
|
|
21
|
+
.option("-p, --port <port>", "Port for prompt server", "3847")
|
|
22
|
+
.option("-w, --widget-port <port>", "Port for widget Metro server", "8082")
|
|
23
|
+
.option("-m, --metro-port <port>", "Port for main app Metro server", "8081")
|
|
24
|
+
.option("--project <path>", "Path to Expo project (where Claude makes changes)")
|
|
25
|
+
.option("--no-tunnel", "Skip tunnel (local network only)")
|
|
26
|
+
.option("--no-build", "Skip building and installing the app")
|
|
27
|
+
.option("--no-server", "Skip starting the WebSocket server")
|
|
28
|
+
.action(startCommand);
|
|
29
|
+
program
|
|
30
|
+
.command("server")
|
|
31
|
+
.description("Start only the WebSocket server (for dev mode with watch)")
|
|
32
|
+
.option("-p, --port <port>", "Port for prompt server", "3847")
|
|
33
|
+
.option("--project <path>", "Path to Expo project (where Claude makes changes)")
|
|
34
|
+
.action(serverCommand);
|
|
35
|
+
program
|
|
36
|
+
.command("fly")
|
|
37
|
+
.description("✈️ Start everything + build and install on a real iOS device")
|
|
38
|
+
.option("-p, --port <port>", "Port for prompt server", "3847")
|
|
39
|
+
.option("-w, --widget-port <port>", "Port for widget Metro server", "8082")
|
|
40
|
+
.option("-m, --metro-port <port>", "Port for main app Metro server", "8081")
|
|
41
|
+
.option("--project <path>", "Path to Expo project")
|
|
42
|
+
.option("--device <id>", "Device UDID or name to use")
|
|
43
|
+
.option("--no-tunnel", "Skip tunnel (local network only)")
|
|
44
|
+
.action(flyCommand);
|
|
45
|
+
// Default command (just running `expo-air` starts everything)
|
|
46
|
+
program
|
|
47
|
+
.action(() => {
|
|
48
|
+
program.commands.find((cmd) => cmd.name() === "start")?.parse();
|
|
49
|
+
});
|
|
50
|
+
program.parse();
|
|
51
|
+
//# sourceMappingURL=expo-air.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expo-air.js","sourceRoot":"","sources":["../../bin/expo-air.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,UAAU,CAAC;KAChB,WAAW,CAAC,iEAAiE,CAAC;KAC9E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,aAAa,EAAE,kCAAkC,CAAC;KACzD,MAAM,CAAC,iBAAiB,EAAE,4BAA4B,CAAC;KACvD,MAAM,CAAC,WAAW,CAAC,CAAC;AAEvB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,CAAC;KAC7D,MAAM,CAAC,0BAA0B,EAAE,8BAA8B,EAAE,MAAM,CAAC;KAC1E,MAAM,CAAC,yBAAyB,EAAE,gCAAgC,EAAE,MAAM,CAAC;KAC3E,MAAM,CAAC,kBAAkB,EAAE,mDAAmD,CAAC;KAC/E,MAAM,CAAC,aAAa,EAAE,kCAAkC,CAAC;KACzD,MAAM,CAAC,YAAY,EAAE,sCAAsC,CAAC;KAC5D,MAAM,CAAC,aAAa,EAAE,oCAAoC,CAAC;KAC3D,MAAM,CAAC,YAAY,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,2DAA2D,CAAC;KACxE,MAAM,CAAC,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,CAAC;KAC7D,MAAM,CAAC,kBAAkB,EAAE,mDAAmD,CAAC;KAC/E,MAAM,CAAC,aAAa,CAAC,CAAC;AAEzB,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,+DAA+D,CAAC;KAC5E,MAAM,CAAC,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,CAAC;KAC7D,MAAM,CAAC,0BAA0B,EAAE,8BAA8B,EAAE,MAAM,CAAC;KAC1E,MAAM,CAAC,yBAAyB,EAAE,gCAAgC,EAAE,MAAM,CAAC;KAC3E,MAAM,CAAC,kBAAkB,EAAE,sBAAsB,CAAC;KAClD,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC;KACrD,MAAM,CAAC,aAAa,EAAE,kCAAkC,CAAC;KACzD,MAAM,CAAC,UAAU,CAAC,CAAC;AAEtB,8DAA8D;AAC9D,OAAO;KACJ,MAAM,CAAC,GAAG,EAAE;IACX,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC;AAClE,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
interface FlyOptions {
|
|
2
|
+
port: string;
|
|
3
|
+
tunnel: boolean;
|
|
4
|
+
widgetPort?: string;
|
|
5
|
+
metroPort?: string;
|
|
6
|
+
project?: string;
|
|
7
|
+
device?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function flyCommand(options: FlyOptions): Promise<void>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=fly.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fly.d.ts","sourceRoot":"","sources":["../../commands/fly.ts"],"names":[],"mappings":"AA2IA,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA8OnE"}
|