ai-scaffold-pro 1.1.1
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/bin/cli.js +86 -0
- package/hooks/check-review-needed.sh +28 -0
- package/hooks/post-edit-tracker.sh +21 -0
- package/i18n/en.json +536 -0
- package/i18n/index.js +27 -0
- package/i18n/zh.json +536 -0
- package/package.json +29 -0
- package/scripts/gen_references.py +877 -0
- package/src/detect.js +320 -0
- package/src/platforms/android.js +206 -0
- package/src/platforms/default.js +26 -0
- package/src/platforms/flutter.js +278 -0
- package/src/platforms/harmonyos.js +26 -0
- package/src/platforms/index.js +40 -0
- package/src/platforms/ios.js +252 -0
- package/src/platforms/react-native.js +26 -0
- package/src/prompts.js +191 -0
- package/src/render.js +459 -0
- package/templates/CHANGELOG.md +21 -0
- package/templates/agents/arch-review.md +78 -0
- package/templates/agents/cpp-memory-review.md +84 -0
- package/templates/agents/proactive-correction.md +204 -0
- package/templates/agents/resource-sync.md +34 -0
- package/templates/rules/conflict_resolution.md +39 -0
- package/templates/rules/project_rule.md +210 -0
- package/templates/settings.json +27 -0
- package/templates/settings.local.json +5 -0
- package/templates/skills/code_review/SKILL.md +117 -0
- package/templates/skills/plan_mode/SKILL.md +92 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const strings = {
|
|
2
|
+
zh: {
|
|
3
|
+
PLATFORM_RULES_SUMMARY: 'React Native: TurboModules桥接, StyleSheet, React Navigation, Hermes, JS/UI线程分离',
|
|
4
|
+
PLATFORM_SPECIFIC_RULES: `### 5.1 原生桥接(Bridge / JSI)\n\n- 新架构项目必须使用 TurboModules 替代旧版 NativeModules\n- TurboModule 注册使用 \`codegenNativeComponent\` 和 \`TurboModuleRegistry.get\`\n- Bridge 通信规则:\n - 禁止通过 Bridge 传递大量数据(>100KB),应使用共享内存或 ArrayBuffer\n - Bridge 调用是异步的,禁止依赖同步返回值\n - 原生模块方法参数必须是可序列化的 JSON 类型\n- JSI(JavaScript Interface)用于需要同步调用的场景,但应谨慎使用\n- Fabric 渲染器(新架构)替代旧版 UIManager,渲染指令直接在 JS 线程执行\n\n### 5.2 平台特定代码\n\n- 平台特定文件使用命名约定:\`Component.ios.js\` / \`Component.android.js\`\n- 运行时平台判断使用 \`Platform.OS === 'ios' / 'android'\`\n- 平台特定样式使用 \`Platform.select({ ios: {...}, android: {...} })\`\n- 原生模块放置在对应平台目录:\n - iOS: \`ios/\` 目录下的 Swift/ObjC 文件\n - Android: \`android/app/src/main/java/\` 下的 Kotlin/Java 文件\n- 禁止在同一文件中通过大量 if/else 区分平台逻辑,应拆分为平台特定文件\n\n### 5.3 样式规范\n\n- **必须**使用 \`StyleSheet.create()\` 创建样式,禁止行内样式对象\n- 布局使用 Flexbox(默认 \`flexDirection: 'column'\`,与 Web 相反)\n- 尺寸使用 \`Dimensions\` API 或 \`useWindowDimensions\` hook\n- 禁止在样式中使用魔法数字,应定义为常量\n- 平台特定样式使用 \`Platform.select()\`\n- 字体和颜色统一定义在 \`constants/theme.js\`\n\n### 5.4 路由导航\n\n- 使用 React Navigation(@react-navigation/native)进行路由管理\n- 导航器类型:\n - \`createStackNavigator\`:页面栈导航\n - \`createBottomTabNavigator\`:底部标签导航\n - \`createDrawerNavigator\`:侧边抽屉导航\n- 页面配置通过 \`screenOptions\` 和 \`options\` 设置\n- 深度链接通过 \`linking\` 配置实现\n- 认证流程通过条件渲染导航器实现(AuthStack vs AppStack)\n- 禁止使用 \`navigation.navigate\` 传递大对象,应使用全局状态或路由参数\n\n### 5.5 性能优化\n\n- **Hermes 引擎**:必须启用,优化启动时间和内存占用\n- **列表渲染**:\n - 长列表必须使用 \`FlatList\` 或 \`SectionList\`,禁止使用 \`ScrollView\` + \`map\`\n - 实现 \`getItemLayout\` 跳过动态测量\n - 使用 \`keyExtractor\` 提供稳定 key\n - 配置 \`initialNumToRender\`、\`maxToRenderPerBatch\`、\`windowSize\` 优化\n- **图片优化**:\n - 使用 \`resizeMethod="resize"\` 和 \`resizeMode\` 控制内存\n - 本地图片使用适当分辨率(避免超大图片)\n - 网络图片使用缓存库(如 react-native-fast-image)\n- **RAM Bundle**:大型应用启用 RAM Bundle + inline requires\n- **重计算延后**:使用 \`InteractionManager.runAfterInteractions\` 延后非关键任务\n\n### 5.6 线程模型\n\n- RN 运行在多个线程上:\n - **JS 线程**:执行 JavaScript 代码、处理业务逻辑\n - **UI 线程(Main)**:处理原生渲染、手势响应\n - **Shadow 线程**:计算 Flexbox 布局\n- 优化规则:\n - 禁止在 JS 线程执行耗时同步操作(会阻塞动画和交互)\n - 动画使用 \`Animated\` 的 \`useNativeDriver: true\`,在 UI 线程执行\n - 复杂计算使用 \`Web Worker\` 或原生模块在后台线程执行\n - \`InteractionManager.runAfterInteractions\` 用于延后非关键 JS 任务`,
|
|
5
|
+
PLATFORM_FATAL_CHECKS: `- 通过 Bridge 传递大量数据(>100KB)\n- 缺少错误边界(ErrorBoundary)组件\n- Native Module 中未处理的 Promise rejection\n- 事件监听器在组件卸载时未清理(内存泄漏)\n- 在未挂载组件上调用 \`setState\`\n- ScrollView + map 渲染长列表(应用 FlatList)`,
|
|
6
|
+
PLATFORM_WARNING_CHECKS: `- 使用行内样式而非 \`StyleSheet.create()\`\n- 长列表未使用虚拟化(FlatList/SectionList)\n- 列表渲染缺少 \`key\` / \`keyExtractor\`\n- 同步 Bridge 调用可以改为异步\n- 存在未使用的平台特定文件(.ios.js / .android.js)\n- 动画未使用 \`useNativeDriver: true\``,
|
|
7
|
+
PLATFORM_SUGGESTION_CHECKS: `- 检查 Hermes 引擎优化机会\n- 纯组件使用 \`React.memo\` 包装\n- 高频回调使用 \`useCallback\` / \`useMemo\` 优化\n- 图片资源检查平台特定分辨率变体\n- 使用 \`InteractionManager.runAfterInteractions\` 延后非关键任务`,
|
|
8
|
+
PLATFORM_SELF_CHECK_ITEMS: `| RN1 | 所有样式使用 StyleSheet.create()? |\n| RN2 | ErrorBoundary 错误边界已部署? |\n| RN3 | 事件监听器在 useEffect cleanup 中已清理? |\n| RN4 | 平台特定代码通过 .ios.js/.android.js 或 Platform.select() 处理? |\n| RN5 | 长列表使用 FlatList 而非 ScrollView + map? |\n| RN6 | Hermes 引擎已启用? |\n| RN7 | 动画使用 useNativeDriver: true? |\n| RN8 | Bridge 传递数据量 < 100KB? |`,
|
|
9
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: `#### React Native 资源同步检查\n\n- 图片资源 @2x/@3x 变体齐全(iOS 要求)\n- Android 密度桶资源(mdpi/hdpi/xhdpi/xxhdpi/xxxhdpi)齐全\n- \`react-native.config.js\` 资源链接配置正确\n- 原生资源目录(iOS: xcassets, Android: res)文件完整\n- 字体文件在 \`react-native.config.js\` 中正确配置`,
|
|
10
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: `#### React Native 任务模板\n\n**新增页面**:\n1. 创建 Screen 组件\n2. 在 React Navigation 中注册路由\n3. 配置 header / screenOptions\n4. 如需,添加深度链接配置\n\n**新增原生模块**:\n1. 创建 Native Module(iOS: Swift/ObjC, Android: Kotlin/Java)\n2. 创建 JS 桥接层 + TypeScript 类型定义\n3. 注册 TurboModule(新架构)或 NativeModule(旧架构)\n4. 添加到 index 文件导出\n\n**添加平台特定 UI**:\n1. 创建 \`Component.ios.js\` 和 \`Component.android.js\`\n2. 或使用 \`Platform.select()\` 在单一文件中处理\n3. 在统一入口文件中导出`,
|
|
11
|
+
},
|
|
12
|
+
en: {
|
|
13
|
+
PLATFORM_RULES_SUMMARY: 'React Native: TurboModules bridge, StyleSheet, React Navigation, Hermes, JS/UI thread separation',
|
|
14
|
+
PLATFORM_SPECIFIC_RULES: `### 5.1 Native Bridge (Bridge / JSI)\n\n- New architecture projects must use TurboModules instead of legacy NativeModules\n- TurboModule registration uses \`codegenNativeComponent\` and \`TurboModuleRegistry.get\`\n- Bridge communication rules:\n - Do NOT pass large data (>100KB) through the Bridge; use shared memory or ArrayBuffer\n - Bridge calls are async; do NOT rely on synchronous return values\n - Native module method parameters must be serializable JSON types\n- JSI (JavaScript Interface) for synchronous call scenarios; use sparingly\n- Fabric renderer (new architecture) replaces legacy UIManager; rendering commands execute directly on JS thread\n\n### 5.2 Platform-Specific Code\n\n- Platform-specific files use naming convention: \`Component.ios.js\` / \`Component.android.js\`\n- Runtime platform detection: \`Platform.OS === 'ios' / 'android'\`\n- Platform-specific styles: \`Platform.select({ ios: {...}, android: {...} })\`\n- Native modules placed in platform directories:\n - iOS: Swift/ObjC files under \`ios/\` directory\n - Android: Kotlin/Java files under \`android/app/src/main/java/\`\n- Large if/else blocks for platform logic in the same file are prohibited; split into platform-specific files\n\n### 5.3 Style Standards\n\n- **Must** use \`StyleSheet.create()\` to create styles; inline style objects are prohibited\n- Layout uses Flexbox (default \`flexDirection: 'column'\`, opposite of Web)\n- Dimensions use \`Dimensions\` API or \`useWindowDimensions\` hook\n- Magic numbers in styles are prohibited; define as constants\n- Platform-specific styles use \`Platform.select()\`\n- Fonts and colors unified in \`constants/theme.js\`\n\n### 5.4 Router Navigation\n\n- Use React Navigation (@react-navigation/native) for routing\n- Navigator types:\n - \`createStackNavigator\`: Stack navigation\n - \`createBottomTabNavigator\`: Bottom tab navigation\n - \`createDrawerNavigator\`: Drawer navigation\n- Screen configuration via \`screenOptions\` and \`options\`\n- Deep linking via \`linking\` configuration\n- Auth flow via conditional navigator rendering (AuthStack vs AppStack)\n- Passing large objects via \`navigation.navigate\` is prohibited; use global state or route params\n\n### 5.5 Performance Optimization\n\n- **Hermes engine**: Must be enabled for optimized startup time and memory\n- **List rendering**:\n - Long lists must use \`FlatList\` or \`SectionList\`; \`ScrollView\` + \`map\` is prohibited\n - Implement \`getItemLayout\` to skip dynamic measurement\n - Use \`keyExtractor\` for stable keys\n - Configure \`initialNumToRender\`, \`maxToRenderPerBatch\`, \`windowSize\` for optimization\n- **Image optimization**:\n - Use \`resizeMethod="resize"\` and \`resizeMode\` for memory control\n - Local images use appropriate resolution (avoid oversized images)\n - Network images use caching library (e.g., react-native-fast-image)\n- **RAM Bundle**: Enable RAM Bundle + inline requires for large apps\n- **Deferred computation**: Use \`InteractionManager.runAfterInteractions\` for non-critical tasks\n\n### 5.6 Threading Model\n\n- RN runs on multiple threads:\n - **JS thread**: Executes JavaScript code, handles business logic\n - **UI thread (Main)**: Handles native rendering, gesture response\n - **Shadow thread**: Calculates Flexbox layout\n- Optimization rules:\n - Do NOT execute heavy sync operations on the JS thread (blocks animation and interaction)\n - Animations use \`Animated\` with \`useNativeDriver: true\`, executing on UI thread\n - Complex computation uses \`Web Worker\` or native modules on background threads\n - \`InteractionManager.runAfterInteractions\` for deferring non-critical JS tasks`,
|
|
15
|
+
PLATFORM_FATAL_CHECKS: `- Passing large data (>100KB) through the Bridge\n- Missing ErrorBoundary components\n- Unhandled Promise rejections in Native Modules\n- Event listeners not cleaned up on component unmount (memory leak)\n- \`setState\` called on unmounted components\n- ScrollView + map rendering long lists (should use FlatList)`,
|
|
16
|
+
PLATFORM_WARNING_CHECKS: `- Inline styles instead of \`StyleSheet.create()\`\n- Long lists not virtualized (FlatList/SectionList)\n- List rendering missing \`key\` / \`keyExtractor\`\n- Synchronous Bridge calls that could be async\n- Unused platform-specific files (.ios.js / .android.js)\n- Animations without \`useNativeDriver: true\``,
|
|
17
|
+
PLATFORM_SUGGESTION_CHECKS: `- Check Hermes engine optimization opportunities\n- Pure components wrapped with \`React.memo\`\n- High-frequency callbacks optimized with \`useCallback\` / \`useMemo\`\n- Image resources checked for platform-specific resolution variants\n- Use \`InteractionManager.runAfterInteractions\` to defer non-critical tasks`,
|
|
18
|
+
PLATFORM_SELF_CHECK_ITEMS: `| RN1 | All styles use StyleSheet.create()? |\n| RN2 | ErrorBoundary components in place? |\n| RN3 | Event listeners cleaned up in useEffect cleanup? |\n| RN4 | Platform-specific code handled via .ios.js/.android.js or Platform.select()? |\n| RN5 | Long lists use FlatList instead of ScrollView + map? |\n| RN6 | Hermes engine enabled? |\n| RN7 | Animations use useNativeDriver: true? |\n| RN8 | Bridge data transfer < 100KB? |`,
|
|
19
|
+
PLATFORM_RESOURCE_SYNC_CONTENT: `#### React Native Resource Sync Checks\n\n- Image resource @2x/@3x variants complete (iOS requirement)\n- Android density bucket resources (mdpi/hdpi/xhdpi/xxhdpi/xxxhdpi) complete\n- \`react-native.config.js\` asset linking configuration correct\n- Native resource directories (iOS: xcassets, Android: res) files complete\n- Font files correctly configured in \`react-native.config.js\``,
|
|
20
|
+
PLATFORM_SPECIFIC_TASK_TEMPLATES: `#### React Native Task Templates\n\n**Add new screen**:\n1. Create Screen component\n2. Register route in React Navigation\n3. Configure header / screenOptions\n4. Add deep linking configuration if needed\n\n**Add native module**:\n1. Create Native Module (iOS: Swift/ObjC, Android: Kotlin/Java)\n2. Create JS bridge layer + TypeScript type definitions\n3. Register TurboModule (new arch) or NativeModule (legacy arch)\n4. Add to index file exports\n\n**Add platform-specific UI**:\n1. Create \`Component.ios.js\` and \`Component.android.js\`\n2. Or use \`Platform.select()\` in a single file\n3. Export from unified entry file`,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default function getPlatformVars(lang) {
|
|
25
|
+
return strings[lang] || strings.en;
|
|
26
|
+
}
|
package/src/prompts.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
|
|
3
|
+
export async function promptConfig(detection) {
|
|
4
|
+
const answers = {};
|
|
5
|
+
|
|
6
|
+
// Phase 0: Language selection
|
|
7
|
+
const { lang } = await inquirer.prompt([
|
|
8
|
+
{
|
|
9
|
+
type: 'list',
|
|
10
|
+
name: 'lang',
|
|
11
|
+
message: 'Generated files language / 生成文件使用哪种语言?',
|
|
12
|
+
choices: [
|
|
13
|
+
{ name: '中文 (Chinese)', value: 'zh' },
|
|
14
|
+
{ name: 'English', value: 'en' },
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
]);
|
|
18
|
+
answers.lang = lang;
|
|
19
|
+
|
|
20
|
+
const isZh = lang === 'zh';
|
|
21
|
+
|
|
22
|
+
// Phase 0: AI tool selection
|
|
23
|
+
const toolChoices = [
|
|
24
|
+
{ name: 'Claude Code', value: 'claude' },
|
|
25
|
+
{ name: 'Qoder', value: 'qoder' },
|
|
26
|
+
{ name: 'Codex', value: 'codex' },
|
|
27
|
+
{ name: 'OpenCode', value: 'opencode' },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
if (detection.existingTool) {
|
|
31
|
+
const { useDetected } = await inquirer.prompt([
|
|
32
|
+
{
|
|
33
|
+
type: 'confirm',
|
|
34
|
+
name: 'useDetected',
|
|
35
|
+
message: isZh
|
|
36
|
+
? `检测到已有 ${detection.existingTool.target} 体系,使用它吗?`
|
|
37
|
+
: `Detected existing ${detection.existingTool.target} setup. Use it?`,
|
|
38
|
+
default: true,
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
if (useDetected) {
|
|
42
|
+
answers.target = detection.existingTool.target;
|
|
43
|
+
answers.dir = detection.existingTool.dir;
|
|
44
|
+
answers.entry = detection.existingTool.entry;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!answers.target) {
|
|
49
|
+
const { target } = await inquirer.prompt([
|
|
50
|
+
{
|
|
51
|
+
type: 'list',
|
|
52
|
+
name: 'target',
|
|
53
|
+
message: isZh ? '选择 AI 工具' : 'Select AI tool',
|
|
54
|
+
choices: toolChoices,
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
answers.target = target;
|
|
58
|
+
answers.dir = target === 'claude' ? '.claude' : `.${target}`;
|
|
59
|
+
answers.entry = 'AGENTS.md';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Phase 1.5: CodeGraph detection and prompt
|
|
63
|
+
if (detection.hasCodeGraph) {
|
|
64
|
+
answers.hasCodeGraph = true;
|
|
65
|
+
} else {
|
|
66
|
+
const { installCodeGraph } = await inquirer.prompt([
|
|
67
|
+
{
|
|
68
|
+
type: 'confirm',
|
|
69
|
+
name: 'installCodeGraph',
|
|
70
|
+
message: isZh
|
|
71
|
+
? '检测到项目未安装 CodeGraph(代码关系图工具,可提升 AI 对代码库的理解能力)。是否安装?'
|
|
72
|
+
: 'CodeGraph (code relationship graph tool for improved AI codebase understanding) is not installed. Install it?',
|
|
73
|
+
default: true,
|
|
74
|
+
},
|
|
75
|
+
]);
|
|
76
|
+
answers.installCodeGraph = installCodeGraph;
|
|
77
|
+
answers.hasCodeGraph = false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Phase 2: Configuration questions
|
|
81
|
+
const configPrompts = [
|
|
82
|
+
{
|
|
83
|
+
type: 'input',
|
|
84
|
+
name: 'projectName',
|
|
85
|
+
message: isZh ? '项目名称' : 'Project name',
|
|
86
|
+
default: 'MyProject',
|
|
87
|
+
validate: v => {
|
|
88
|
+
if (!v || v.trim().length === 0) {
|
|
89
|
+
return isZh ? '项目名不能为空' : 'Project name cannot be empty';
|
|
90
|
+
}
|
|
91
|
+
if (v.length > 50) {
|
|
92
|
+
return isZh ? '项目名不能超过 50 个字符' : 'Project name cannot exceed 50 characters';
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
type: 'input',
|
|
99
|
+
name: 'projectDescription',
|
|
100
|
+
message: isZh ? '项目描述(一句话)' : 'Project description (one sentence)',
|
|
101
|
+
default: isZh ? '一个项目' : 'A project',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
type: 'input',
|
|
105
|
+
name: 'packageName',
|
|
106
|
+
message: isZh ? '主包名' : 'Main package name',
|
|
107
|
+
default: 'com.example.app',
|
|
108
|
+
validate: v => {
|
|
109
|
+
if (!v) return true;
|
|
110
|
+
if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$/.test(v)) {
|
|
111
|
+
return isZh ? '请输入有效的包名格式 (如 com.example.app)' : 'Please enter a valid package name (e.g. com.example.app)';
|
|
112
|
+
}
|
|
113
|
+
return true;
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'input',
|
|
118
|
+
name: 'aiName',
|
|
119
|
+
message: isZh ? 'AI 助手名称' : 'AI assistant name',
|
|
120
|
+
default: 'AI Assistant',
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: 'input',
|
|
124
|
+
name: 'buildDebug',
|
|
125
|
+
message: isZh ? 'Debug 构建命令' : 'Debug build command',
|
|
126
|
+
default: detection.platform === 'Android' ? './gradlew assembleDebug' : 'npm run build',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'input',
|
|
130
|
+
name: 'buildRelease',
|
|
131
|
+
message: isZh ? 'Release 构建命令' : 'Release build command',
|
|
132
|
+
default: detection.platform === 'Android' ? './gradlew assembleRelease' : 'npm run build:prod',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: 'confirm',
|
|
136
|
+
name: 'hasTests',
|
|
137
|
+
message: isZh ? '项目有自动化测试吗?' : 'Does the project have automated tests?',
|
|
138
|
+
default: true,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
type: 'input',
|
|
142
|
+
name: 'reviewThreshold',
|
|
143
|
+
message: isZh ? '修改几个文件触发代码审查?' : 'How many files modified triggers code review?',
|
|
144
|
+
default: '2',
|
|
145
|
+
validate: v => {
|
|
146
|
+
const n = parseInt(v);
|
|
147
|
+
if (isNaN(n) || n < 1 || n > 100) {
|
|
148
|
+
return isZh ? '请输入 1-100 之间的数字' : 'Please enter a number between 1 and 100';
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
},
|
|
152
|
+
filter: v => parseInt(v),
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
type: 'input',
|
|
156
|
+
name: 'archThreshold',
|
|
157
|
+
message: isZh ? '修改几个模块触发架构审查?' : 'How many modules modified triggers architecture review?',
|
|
158
|
+
default: '3',
|
|
159
|
+
validate: v => !isNaN(v) || 'Please enter a number',
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
const config = await inquirer.prompt(configPrompts);
|
|
164
|
+
Object.assign(answers, config);
|
|
165
|
+
|
|
166
|
+
// NDK questions
|
|
167
|
+
if (detection.hasNdk) {
|
|
168
|
+
const ndkConfig = await inquirer.prompt([
|
|
169
|
+
{
|
|
170
|
+
type: 'list',
|
|
171
|
+
name: 'ndkBuildSystem',
|
|
172
|
+
message: isZh ? 'NDK 构建系统' : 'NDK build system',
|
|
173
|
+
choices: ['ndk-build', 'CMake'],
|
|
174
|
+
default: 'ndk-build',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
type: 'list',
|
|
178
|
+
name: 'jniMethod',
|
|
179
|
+
message: isZh ? 'JNI native 方法注册方式' : 'JNI native method registration',
|
|
180
|
+
choices: [
|
|
181
|
+
{ name: isZh ? '动态注册 (RegisterNatives)' : 'Dynamic (RegisterNatives)', value: 'dynamic' },
|
|
182
|
+
{ name: isZh ? '静态绑定' : 'Static binding', value: 'static' },
|
|
183
|
+
],
|
|
184
|
+
default: 'dynamic',
|
|
185
|
+
},
|
|
186
|
+
]);
|
|
187
|
+
Object.assign(answers, ndkConfig);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return answers;
|
|
191
|
+
}
|