opencode-skills-collection 3.0.41 → 3.0.43
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 +10 -0
- package/bundled-skills/.antigravity-install-manifest.json +3 -1
- package/bundled-skills/2slides-ppt-generator/SKILL.md +8 -18
- package/bundled-skills/accesslint-diff/SKILL.md +5 -2
- package/bundled-skills/android-dev/SKILL.md +524 -0
- package/bundled-skills/android-dev/references/flutter.md +269 -0
- package/bundled-skills/android-dev/references/hybrid.md +158 -0
- package/bundled-skills/android-dev/references/java-android.md +586 -0
- package/bundled-skills/android-dev/references/kmm.md +206 -0
- package/bundled-skills/android-dev/references/native-android.md +239 -0
- package/bundled-skills/android-dev/references/react-native.md +242 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +1 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/event-staffing-ordering/SKILL.md +2 -17
- package/bundled-skills/unship/SKILL.md +138 -0
- package/package.json +1 -1
- package/skills_index.json +44 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# Flutter Reference (Dart)
|
|
2
|
+
|
|
3
|
+
## Project Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
lib/
|
|
7
|
+
├── main.dart # Entry point
|
|
8
|
+
├── app/
|
|
9
|
+
│ ├── app.dart # MaterialApp + router setup
|
|
10
|
+
│ ├── theme/ # ThemeData, colors, typography, spacing
|
|
11
|
+
│ └── router/ # go_router config, guards
|
|
12
|
+
├── features/
|
|
13
|
+
│ └── home/
|
|
14
|
+
│ ├── data/
|
|
15
|
+
│ │ ├── datasource/ # Remote + local data sources
|
|
16
|
+
│ │ ├── dto/ # JSON models (freezed)
|
|
17
|
+
│ │ └── repository/ # Repo implementations
|
|
18
|
+
│ ├── domain/
|
|
19
|
+
│ │ ├── model/ # Domain models (freezed)
|
|
20
|
+
│ │ ├── repository/ # Abstract repo interfaces
|
|
21
|
+
│ │ └── usecase/ # Use cases
|
|
22
|
+
│ └── presentation/
|
|
23
|
+
│ ├── bloc/ # Bloc/Cubit + state + event
|
|
24
|
+
│ └── screen/ # Widgets + page files
|
|
25
|
+
├── core/
|
|
26
|
+
│ ├── network/ # Dio client, interceptors
|
|
27
|
+
│ ├── database/ # Drift DB setup
|
|
28
|
+
│ ├── widgets/ # Shared design system widgets
|
|
29
|
+
│ └── error/ # Failure types, error handling
|
|
30
|
+
└── injection.dart # GetIt service locator setup
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## State Management (BLoC)
|
|
34
|
+
|
|
35
|
+
```dart
|
|
36
|
+
// States
|
|
37
|
+
@freezed
|
|
38
|
+
class HomeState with _$HomeState {
|
|
39
|
+
const factory HomeState.initial() = _Initial;
|
|
40
|
+
const factory HomeState.loading() = _Loading;
|
|
41
|
+
const factory HomeState.success(List<Item> items) = _Success;
|
|
42
|
+
const factory HomeState.failure(String message) = _Failure;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Events
|
|
46
|
+
@freezed
|
|
47
|
+
class HomeEvent with _$HomeEvent {
|
|
48
|
+
const factory HomeEvent.loadItems() = _LoadItems;
|
|
49
|
+
const factory HomeEvent.refreshItems() = _RefreshItems;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Bloc
|
|
53
|
+
class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
|
54
|
+
final GetItemsUseCase _getItems;
|
|
55
|
+
|
|
56
|
+
HomeBloc(this._getItems) : super(const HomeState.initial()) {
|
|
57
|
+
on<_LoadItems>(_onLoad);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Future<void> _onLoad(_LoadItems event, Emitter<HomeState> emit) async {
|
|
61
|
+
emit(const HomeState.loading());
|
|
62
|
+
final result = await _getItems();
|
|
63
|
+
result.fold(
|
|
64
|
+
(failure) => emit(HomeState.failure(failure.message)),
|
|
65
|
+
(items) => emit(HomeState.success(items)),
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## State Management (Riverpod — alternative)
|
|
72
|
+
|
|
73
|
+
```dart
|
|
74
|
+
@riverpod
|
|
75
|
+
class HomeNotifier extends _$HomeNotifier {
|
|
76
|
+
@override
|
|
77
|
+
FutureOr<List<Item>> build() => _load();
|
|
78
|
+
|
|
79
|
+
Future<List<Item>> _load() async {
|
|
80
|
+
final repo = ref.read(itemRepositoryProvider);
|
|
81
|
+
return repo.getItems().getOrThrow();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
Future<void> refresh() async {
|
|
85
|
+
state = const AsyncLoading();
|
|
86
|
+
state = await AsyncValue.guard(_load);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Screen Widget Pattern
|
|
92
|
+
|
|
93
|
+
```dart
|
|
94
|
+
class HomeScreen extends StatelessWidget {
|
|
95
|
+
const HomeScreen({super.key});
|
|
96
|
+
|
|
97
|
+
@override
|
|
98
|
+
Widget build(BuildContext context) {
|
|
99
|
+
return BlocProvider(
|
|
100
|
+
create: (ctx) => sl<HomeBloc>()..add(const HomeEvent.loadItems()),
|
|
101
|
+
child: const _HomeView(),
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
class _HomeView extends StatelessWidget {
|
|
107
|
+
const _HomeView();
|
|
108
|
+
|
|
109
|
+
@override
|
|
110
|
+
Widget build(BuildContext context) {
|
|
111
|
+
return Scaffold(
|
|
112
|
+
body: BlocConsumer<HomeBloc, HomeState>(
|
|
113
|
+
listener: (ctx, state) {
|
|
114
|
+
state.maybeWhen(
|
|
115
|
+
failure: (msg) => ScaffoldMessenger.of(ctx)
|
|
116
|
+
.showSnackBar(SnackBar(content: Text(msg))),
|
|
117
|
+
orElse: () {},
|
|
118
|
+
);
|
|
119
|
+
},
|
|
120
|
+
builder: (ctx, state) => state.when(
|
|
121
|
+
initial: () => const SizedBox(),
|
|
122
|
+
loading: () => const Center(child: CircularProgressIndicator()),
|
|
123
|
+
success: (items) => _ItemList(items: items),
|
|
124
|
+
failure: (msg) => ErrorView(message: msg,
|
|
125
|
+
onRetry: () => ctx.read<HomeBloc>().add(
|
|
126
|
+
const HomeEvent.loadItems())),
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## go_router Setup
|
|
135
|
+
|
|
136
|
+
```dart
|
|
137
|
+
final router = GoRouter(
|
|
138
|
+
initialLocation: '/home',
|
|
139
|
+
redirect: (context, state) {
|
|
140
|
+
final isLoggedIn = ref.read(authStateProvider).isLoggedIn;
|
|
141
|
+
if (!isLoggedIn && !state.matchedLocation.startsWith('/auth')) {
|
|
142
|
+
return '/auth/login';
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
},
|
|
146
|
+
routes: [
|
|
147
|
+
GoRoute(
|
|
148
|
+
path: '/home',
|
|
149
|
+
name: AppRoutes.home,
|
|
150
|
+
builder: (ctx, state) => const HomeScreen(),
|
|
151
|
+
routes: [
|
|
152
|
+
GoRoute(
|
|
153
|
+
path: 'detail/:id',
|
|
154
|
+
builder: (ctx, state) =>
|
|
155
|
+
DetailScreen(id: state.pathParameters['id']!),
|
|
156
|
+
),
|
|
157
|
+
],
|
|
158
|
+
),
|
|
159
|
+
],
|
|
160
|
+
);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Drift Database
|
|
164
|
+
|
|
165
|
+
```dart
|
|
166
|
+
@DriftDatabase(tables: [Items])
|
|
167
|
+
class AppDatabase extends _$AppDatabase {
|
|
168
|
+
AppDatabase(QueryExecutor e) : super(e);
|
|
169
|
+
|
|
170
|
+
@override
|
|
171
|
+
int get schemaVersion => 1;
|
|
172
|
+
|
|
173
|
+
Stream<List<Item>> watchAllItems() =>
|
|
174
|
+
(select(items)..orderBy([(t) => OrderingTerm.desc(t.updatedAt)])).watch();
|
|
175
|
+
|
|
176
|
+
Future<void> upsertItems(List<ItemsCompanion> rows) =>
|
|
177
|
+
batch((b) => b.insertAllOnConflictUpdate(items, rows));
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Key pubspec.yaml Dependencies
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
dependencies:
|
|
185
|
+
flutter_bloc: ^8.1.5
|
|
186
|
+
freezed_annotation: ^2.4.1
|
|
187
|
+
riverpod: ^2.5.1 # alternative to bloc
|
|
188
|
+
flutter_riverpod: ^2.5.1
|
|
189
|
+
go_router: ^14.1.0
|
|
190
|
+
dio: ^5.4.3
|
|
191
|
+
drift: ^2.18.0
|
|
192
|
+
sqflite: ^2.3.3
|
|
193
|
+
get_it: ^7.7.0
|
|
194
|
+
injectable: ^2.4.1
|
|
195
|
+
dartz: ^0.10.1 # Either/Option for FP error handling
|
|
196
|
+
json_annotation: ^4.9.0
|
|
197
|
+
|
|
198
|
+
dev_dependencies:
|
|
199
|
+
build_runner: ^2.4.9
|
|
200
|
+
freezed: ^2.5.2
|
|
201
|
+
json_serializable: ^6.8.0
|
|
202
|
+
drift_dev: ^2.18.0
|
|
203
|
+
mocktail: ^1.0.3
|
|
204
|
+
bloc_test: ^9.1.7
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Error Handling (Either/Failure pattern)
|
|
208
|
+
|
|
209
|
+
```dart
|
|
210
|
+
abstract class Failure {
|
|
211
|
+
final String message;
|
|
212
|
+
const Failure(this.message);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
class NetworkFailure extends Failure {
|
|
216
|
+
const NetworkFailure([super.message = 'Network error occurred']);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
class CacheFailure extends Failure {
|
|
220
|
+
const CacheFailure([super.message = 'Cache error occurred']);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Repository
|
|
224
|
+
Future<Either<Failure, List<Item>>> getItems() async {
|
|
225
|
+
try {
|
|
226
|
+
final remote = await _remoteSource.fetchItems();
|
|
227
|
+
await _localSource.saveItems(remote);
|
|
228
|
+
return Right(remote.map(_mapper.toDomain).toList());
|
|
229
|
+
} on DioException catch (e) {
|
|
230
|
+
return Left(NetworkFailure(e.message ?? 'Network error'));
|
|
231
|
+
} on Exception {
|
|
232
|
+
return const Left(CacheFailure());
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Testing
|
|
238
|
+
|
|
239
|
+
```dart
|
|
240
|
+
void main() {
|
|
241
|
+
group('HomeBloc', () {
|
|
242
|
+
late HomeBloc bloc;
|
|
243
|
+
late MockGetItemsUseCase mockUseCase;
|
|
244
|
+
|
|
245
|
+
setUp(() {
|
|
246
|
+
mockUseCase = MockGetItemsUseCase();
|
|
247
|
+
bloc = HomeBloc(mockUseCase);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
tearDown(() => bloc.close());
|
|
251
|
+
|
|
252
|
+
blocTest<HomeBloc, HomeState>(
|
|
253
|
+
'emits [loading, success] when loadItems succeeds',
|
|
254
|
+
build: () {
|
|
255
|
+
when(() => mockUseCase()).thenAnswer(
|
|
256
|
+
(_) async => Right([Item(id: '1', title: 'Test')]),
|
|
257
|
+
);
|
|
258
|
+
return bloc;
|
|
259
|
+
},
|
|
260
|
+
act: (b) => b.add(const HomeEvent.loadItems()),
|
|
261
|
+
expect: () => [
|
|
262
|
+
const HomeState.loading(),
|
|
263
|
+
isA<HomeState>().having((s) => s, 'success',
|
|
264
|
+
const HomeState.success([Item(id: '1', title: 'Test')])),
|
|
265
|
+
],
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
```
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Hybrid Android Reference (Capacitor + Ionic / React)
|
|
2
|
+
|
|
3
|
+
## When to Use Hybrid
|
|
4
|
+
|
|
5
|
+
✅ Good fit:
|
|
6
|
+
- Web team building a companion Android app
|
|
7
|
+
- Content-heavy apps (news, docs, forms)
|
|
8
|
+
- PWA upgrade to installable app
|
|
9
|
+
- Rapid prototyping
|
|
10
|
+
|
|
11
|
+
❌ Avoid for:
|
|
12
|
+
- Real-time games / heavy animations
|
|
13
|
+
- Deep native sensor / hardware access
|
|
14
|
+
- Apps requiring 60fps custom animations
|
|
15
|
+
- Bluetooth/NFC intensive apps (use plugins, but complex)
|
|
16
|
+
|
|
17
|
+
## Stack Options
|
|
18
|
+
|
|
19
|
+
| Option | UI Framework | Best For |
|
|
20
|
+
|--------|-------------|---------|
|
|
21
|
+
| Capacitor + Ionic | Ionic components | Full mobile-optimized UI |
|
|
22
|
+
| Capacitor + React | React + Tailwind | Web team reuse |
|
|
23
|
+
| Capacitor + Vue | Vue + Ionic | Vue teams |
|
|
24
|
+
| Capacitor + Angular | Angular + Ionic | Enterprise Angular teams |
|
|
25
|
+
|
|
26
|
+
## Project Structure (Capacitor + React)
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
src/
|
|
30
|
+
├── App.tsx
|
|
31
|
+
├── pages/ # Screen components
|
|
32
|
+
├── components/ # Shared UI components
|
|
33
|
+
├── hooks/ # Business logic hooks
|
|
34
|
+
├── services/ # API, storage services
|
|
35
|
+
└── store/ # State management
|
|
36
|
+
android/ # Native Android project (generated)
|
|
37
|
+
├── app/src/main/
|
|
38
|
+
│ ├── AndroidManifest.xml
|
|
39
|
+
│ └── java/.../MainActivity.kt
|
|
40
|
+
capacitor.config.ts # Capacitor configuration
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Capacitor Config
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// capacitor.config.ts
|
|
47
|
+
import { CapacitorConfig } from '@capacitor/cli';
|
|
48
|
+
|
|
49
|
+
const config: CapacitorConfig = {
|
|
50
|
+
appId: 'com.example.app',
|
|
51
|
+
appName: 'My App',
|
|
52
|
+
webDir: 'dist',
|
|
53
|
+
server: {
|
|
54
|
+
androidScheme: 'https',
|
|
55
|
+
},
|
|
56
|
+
android: {
|
|
57
|
+
buildOptions: {
|
|
58
|
+
releaseType: 'APK', // or AAB for Play Store
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
plugins: {
|
|
62
|
+
SplashScreen: {
|
|
63
|
+
launchShowDuration: 0,
|
|
64
|
+
backgroundColor: '#FFFFFF',
|
|
65
|
+
},
|
|
66
|
+
PushNotifications: {
|
|
67
|
+
presentationOptions: ['badge', 'sound', 'alert'],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Native Plugin Usage
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { Camera, CameraResultType } from '@capacitor/camera';
|
|
77
|
+
import { Preferences } from '@capacitor/preferences';
|
|
78
|
+
import { PushNotifications } from '@capacitor/push-notifications';
|
|
79
|
+
import { Geolocation } from '@capacitor/geolocation';
|
|
80
|
+
|
|
81
|
+
// Camera
|
|
82
|
+
const takePhoto = async () => {
|
|
83
|
+
const photo = await Camera.getPhoto({
|
|
84
|
+
quality: 90,
|
|
85
|
+
allowEditing: false,
|
|
86
|
+
resultType: CameraResultType.Uri,
|
|
87
|
+
});
|
|
88
|
+
return photo.webPath;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// Secure storage
|
|
92
|
+
const saveToken = async (token: string) => {
|
|
93
|
+
await Preferences.set({ key: 'auth_token', value: token });
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const getToken = async (): Promise<string | null> => {
|
|
97
|
+
const { value } = await Preferences.get({ key: 'auth_token' });
|
|
98
|
+
return value;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Push notifications
|
|
102
|
+
const initPush = async () => {
|
|
103
|
+
const permission = await PushNotifications.requestPermissions();
|
|
104
|
+
if (permission.receive === 'granted') {
|
|
105
|
+
await PushNotifications.register();
|
|
106
|
+
}
|
|
107
|
+
PushNotifications.addListener('registration', ({ value: token }) => {
|
|
108
|
+
console.log('FCM Token:', token);
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Performance Best Practices
|
|
114
|
+
|
|
115
|
+
- Ensure hardware acceleration is enabled for the application in AndroidManifest.xml (default in Capacitor)
|
|
116
|
+
- Enable HTTP caching in Android WebView settings
|
|
117
|
+
- Lazy-load routes with React.lazy / dynamic imports
|
|
118
|
+
- Avoid `setTimeout`/`setInterval` for animations; use CSS transitions
|
|
119
|
+
- Use `@ionic/react` components — they handle mobile-specific touch handling
|
|
120
|
+
- Ionic virtual scroll for long lists
|
|
121
|
+
|
|
122
|
+
## Build & Deploy
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Build web assets
|
|
126
|
+
npm run build
|
|
127
|
+
|
|
128
|
+
# Sync to native
|
|
129
|
+
npx cap sync android
|
|
130
|
+
|
|
131
|
+
# Open in Android Studio
|
|
132
|
+
npx cap open android
|
|
133
|
+
|
|
134
|
+
# Build release APK/AAB via Android Studio or:
|
|
135
|
+
cd android && ./gradlew bundleRelease
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Custom Native Plugin (when built-in plugins don't cover it)
|
|
139
|
+
|
|
140
|
+
```kotlin
|
|
141
|
+
// android/app/src/main/java/.../MyPlugin.kt
|
|
142
|
+
@CapacitorPlugin(name = "MyPlugin")
|
|
143
|
+
class MyPlugin : Plugin() {
|
|
144
|
+
@PluginMethod
|
|
145
|
+
fun doNativeWork(call: PluginCall) {
|
|
146
|
+
val value = call.getString("input") ?: return call.reject("No input")
|
|
147
|
+
// Do native work
|
|
148
|
+
val result = JSObject()
|
|
149
|
+
result.put("output", "processed: $value")
|
|
150
|
+
call.resolve(result)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// TypeScript usage
|
|
155
|
+
import { registerPlugin } from '@capacitor/core';
|
|
156
|
+
const MyPlugin = registerPlugin<{ doNativeWork: (opts: { input: string }) => Promise<{ output: string }> }>('MyPlugin');
|
|
157
|
+
const result = await MyPlugin.doNativeWork({ input: 'hello' });
|
|
158
|
+
```
|