@coze-arch/cli 0.0.1-alpha.ee5d83 → 0.0.1-alpha.ef0249
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/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +10 -10
- package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +2 -2
- package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +2 -2
- package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +45 -0
- package/lib/__templates__/expo/README.md +2 -0
- package/lib/__templates__/expo/client/app/_layout.tsx +14 -14
- package/lib/__templates__/expo/client/app/index.tsx +1 -1
- package/lib/__templates__/expo/client/app.config.ts +4 -3
- package/lib/__templates__/expo/client/declarations.d.ts +5 -0
- package/lib/__templates__/expo/client/eslint.config.mjs +13 -10
- package/lib/__templates__/expo/client/hooks/useTheme.ts +26 -6
- package/lib/__templates__/expo/client/screens/{home → demo}/index.tsx +1 -1
- package/lib/__templates__/expo/client/scripts/install-missing-deps.js +1 -0
- package/lib/__templates__/expo/client/utils/index.ts +22 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/index.js +9 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/names.js +2486 -0
- package/lib/__templates__/expo/eslint-plugins/fontawesome6/rule.js +155 -0
- package/lib/__templates__/expo/server/build.js +21 -0
- package/lib/__templates__/expo/server/package.json +2 -2
- package/lib/__templates__/expo/server/src/index.ts +2 -1
- package/lib/__templates__/nextjs/next.config.ts +2 -2
- package/lib/__templates__/nextjs/package.json +6 -1
- package/lib/__templates__/nextjs/pnpm-lock.yaml +1461 -1710
- package/lib/__templates__/nextjs/src/app/page.tsx +2 -2
- package/lib/__templates__/nextjs/template.config.js +5 -5
- package/lib/__templates__/vite/package.json +6 -1
- package/lib/__templates__/vite/pnpm-lock.yaml +504 -982
- package/lib/__templates__/vite/src/main.ts +1 -2
- package/lib/__templates__/vite/template.config.js +6 -4
- package/lib/cli.js +13 -6
- package/package.json +1 -1
- package/lib/__templates__/expo/client/app/home.tsx +0 -1
- /package/lib/__templates__/expo/client/screens/{home → demo}/styles.ts +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
1
|
+
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
2
2
|
PREVIEW_DIR="${COZE_PREVIEW_DIR:-/source/preview}"
|
|
3
3
|
LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
|
|
4
4
|
LOG_FILE="$LOG_DIR/app.log"
|
|
@@ -111,14 +111,14 @@ wait_port_connectable() {
|
|
|
111
111
|
start_expo() {
|
|
112
112
|
local offline="${1:-0}"
|
|
113
113
|
|
|
114
|
-
pushd
|
|
114
|
+
pushd "$ROOT_DIR/client"
|
|
115
115
|
|
|
116
116
|
if [ "$offline" = "1" ]; then
|
|
117
117
|
( EXPO_OFFLINE=1 EXPO_NO_DOCTOR=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" \
|
|
118
|
-
nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "
|
|
118
|
+
nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$ROOT_DIR/logs/client.log" ) &
|
|
119
119
|
else
|
|
120
120
|
( EXPO_NO_DOCTOR=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" \
|
|
121
|
-
nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "
|
|
121
|
+
nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$ROOT_DIR/logs/client.log" ) &
|
|
122
122
|
fi
|
|
123
123
|
EXPO_PID=$!
|
|
124
124
|
disown $EXPO_PID 2>/dev/null || true
|
|
@@ -129,7 +129,7 @@ start_expo() {
|
|
|
129
129
|
detect_expo_fetch_failed() {
|
|
130
130
|
local timeout="${1:-8}"
|
|
131
131
|
local waited=0
|
|
132
|
-
local log_file="logs/client.log"
|
|
132
|
+
local log_file="$ROOT_DIR/logs/client.log"
|
|
133
133
|
while [ "$waited" -lt "$timeout" ]; do
|
|
134
134
|
if [ -f "$log_file" ] && grep -q "TypeError: fetch failed" "$log_file" 2>/dev/null; then
|
|
135
135
|
return 0
|
|
@@ -159,15 +159,15 @@ check_command "pnpm"
|
|
|
159
159
|
check_command "lsof"
|
|
160
160
|
check_command "bash"
|
|
161
161
|
|
|
162
|
-
echo "
|
|
163
|
-
mkdir -p logs
|
|
162
|
+
echo "准备日志目录:$ROOT_DIR/logs"
|
|
163
|
+
mkdir -p "$ROOT_DIR/logs"
|
|
164
164
|
# 端口占用预检查与处理
|
|
165
165
|
ensure_port SERVER_PORT "$SERVER_PORT"
|
|
166
166
|
ensure_port EXPO_PORT "$EXPO_PORT"
|
|
167
167
|
|
|
168
168
|
echo "==================== 启动 server 服务 ===================="
|
|
169
|
-
echo "正在执行:
|
|
170
|
-
(
|
|
169
|
+
echo "正在执行:pnpm run dev (server)"
|
|
170
|
+
( pushd "$ROOT_DIR/server" > /dev/null && SERVER_PORT="$SERVER_PORT" nohup pnpm run dev; popd > /dev/null ) &
|
|
171
171
|
SERVER_PID=$!
|
|
172
172
|
disown $SERVER_PID 2>/dev/null || true
|
|
173
173
|
if [ -z "${SERVER_PID}" ]; then
|
|
@@ -181,7 +181,7 @@ start_expo 0
|
|
|
181
181
|
if detect_expo_fetch_failed 8; then
|
|
182
182
|
echo "Expo 启动检测到网络错误:TypeError: fetch failed,启用离线模式重试"
|
|
183
183
|
if [ -n "${EXPO_PID}" ]; then kill -9 "$EXPO_PID" 2>/dev/null || true; fi
|
|
184
|
-
: > logs/client.log
|
|
184
|
+
: > "$ROOT_DIR/logs/client.log"
|
|
185
185
|
start_expo 1
|
|
186
186
|
fi
|
|
187
187
|
# 输出以下环境变量,确保 Expo 项目能正确连接到 Server 服务
|
|
@@ -40,8 +40,8 @@ fi
|
|
|
40
40
|
info "==================== 依赖安装完成!====================\n"
|
|
41
41
|
|
|
42
42
|
info "==================== dist打包 ===================="
|
|
43
|
-
info "开始执行:
|
|
44
|
-
(
|
|
43
|
+
info "开始执行:pnpm run build (server)"
|
|
44
|
+
(pushd "$ROOT_DIR/server" > /dev/null && pnpm run build; popd > /dev/null) || error "dist打包失败"
|
|
45
45
|
info "==================== dist打包完成!====================\n"
|
|
46
46
|
|
|
47
47
|
info "下一步:执行 ./prod_run.sh 启动服务"
|
|
@@ -29,6 +29,6 @@ check_command() {
|
|
|
29
29
|
check_command "pnpm"
|
|
30
30
|
check_command "npm"
|
|
31
31
|
|
|
32
|
-
info "开始执行:
|
|
33
|
-
(
|
|
32
|
+
info "开始执行:pnpm run start (server)"
|
|
33
|
+
(pushd "$ROOT_DIR/server" > /dev/null && PORT="$PORT" pnpm run start; popd > /dev/null) || error "服务启动失败"
|
|
34
34
|
info "服务启动完成!\n"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
4
|
+
SERVER_DIR="$ROOT_DIR/server"
|
|
5
|
+
LOG_DIR="$ROOT_DIR/logs"
|
|
6
|
+
LOG_FILE="$LOG_DIR/server.log"
|
|
7
|
+
SERVER_PORT="${SERVER_PORT:-9091}"
|
|
8
|
+
|
|
9
|
+
mkdir -p "$LOG_DIR"
|
|
10
|
+
|
|
11
|
+
pipe_to_log() {
|
|
12
|
+
local source="${1:-SERVER}"
|
|
13
|
+
local raw_log="${2:-}"
|
|
14
|
+
local line
|
|
15
|
+
while IFS= read -r line || [ -n "$line" ]; do
|
|
16
|
+
if [ -n "$raw_log" ]; then
|
|
17
|
+
echo "$line" >> "$raw_log"
|
|
18
|
+
fi
|
|
19
|
+
line=$(echo "[$source] $line" | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\x1b\[[0-9;]*m//g')
|
|
20
|
+
echo "$line"
|
|
21
|
+
done
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
kill_old_server() {
|
|
25
|
+
if command -v lsof &> /dev/null; then
|
|
26
|
+
local pids
|
|
27
|
+
pids=$(lsof -t -i tcp:"$SERVER_PORT" -sTCP:LISTEN 2>/dev/null || true)
|
|
28
|
+
if [ -n "$pids" ]; then
|
|
29
|
+
echo "正在关闭旧的 server 进程:$pids"
|
|
30
|
+
kill -9 $pids 2>/dev/null || echo "关闭进程失败:$pids"
|
|
31
|
+
sleep 1
|
|
32
|
+
fi
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
echo "==================== Server Dev Run ===================="
|
|
37
|
+
echo "Server 目录:$SERVER_DIR"
|
|
38
|
+
echo "Server 端口:$SERVER_PORT"
|
|
39
|
+
echo "日志文件:$LOG_FILE"
|
|
40
|
+
|
|
41
|
+
kill_old_server
|
|
42
|
+
|
|
43
|
+
echo "启动 server 服务..."
|
|
44
|
+
cd "$SERVER_DIR"
|
|
45
|
+
NODE_ENV=development PORT="$SERVER_PORT" npx tsx ./src/index.ts 2>&1 | pipe_to_log "SERVER" "$LOG_FILE"
|
|
@@ -14,20 +14,20 @@ LogBox.ignoreLogs([
|
|
|
14
14
|
export default function RootLayout() {
|
|
15
15
|
return (
|
|
16
16
|
<AuthProvider>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
<GestureHandlerRootView style={{ flex: 1 }}>
|
|
18
|
+
<StatusBar style="dark"></StatusBar>
|
|
19
|
+
<Stack screenOptions={{
|
|
20
|
+
// 设置所有页面的切换动画为从右侧滑入,适用于iOS 和 Android
|
|
21
|
+
animation: 'slide_from_right',
|
|
22
|
+
gestureEnabled: true,
|
|
23
|
+
gestureDirection: 'horizontal',
|
|
24
|
+
// 隐藏自带的头部
|
|
25
|
+
headerShown: false
|
|
26
|
+
}}>
|
|
27
|
+
<Stack.Screen name="index" options={{ title: "" }} />
|
|
28
|
+
</Stack>
|
|
29
|
+
<Toast />
|
|
30
|
+
</GestureHandlerRootView>
|
|
31
31
|
</AuthProvider>
|
|
32
32
|
);
|
|
33
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from '
|
|
1
|
+
export { default } from '@/screens/demo';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ExpoConfig, ConfigContext } from 'expo/config';
|
|
2
2
|
|
|
3
|
-
const appName =
|
|
4
|
-
const
|
|
3
|
+
const appName = process.env.EXPO_PUBLIC_COZE_PROJECT_NAME || '应用';
|
|
4
|
+
const projectId = process.env.EXPO_PUBLIC_COZE_PROJECT_ID;
|
|
5
|
+
const slugAppName = projectId ? `app${projectId}` : 'myapp';
|
|
5
6
|
|
|
6
7
|
export default ({ config }: ConfigContext): ExpoConfig => {
|
|
7
8
|
return {
|
|
@@ -22,7 +23,7 @@ export default ({ config }: ConfigContext): ExpoConfig => {
|
|
|
22
23
|
"foregroundImage": "./assets/images/adaptive-icon.png",
|
|
23
24
|
"backgroundColor": "#ffffff"
|
|
24
25
|
},
|
|
25
|
-
"package":
|
|
26
|
+
"package": `com.anonymous.x${projectId || '0'}`
|
|
26
27
|
},
|
|
27
28
|
"web": {
|
|
28
29
|
"bundler": "metro",
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import js from
|
|
2
|
-
import globals from
|
|
3
|
-
import tseslint from
|
|
4
|
-
import pluginReact from
|
|
5
|
-
import reactHooks from
|
|
6
|
-
import regexp from
|
|
7
|
-
import pluginImport from
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import tseslint from 'typescript-eslint';
|
|
4
|
+
import pluginReact from 'eslint-plugin-react';
|
|
5
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
6
|
+
import regexp from 'eslint-plugin-regexp';
|
|
7
|
+
import pluginImport from 'eslint-plugin-import';
|
|
8
|
+
import fontawesome6 from '../eslint-plugins/fontawesome6/index.js';
|
|
8
9
|
|
|
9
10
|
export default [
|
|
10
11
|
{
|
|
@@ -20,14 +21,14 @@ export default [
|
|
|
20
21
|
regexp.configs["flat/recommended"],
|
|
21
22
|
js.configs.recommended,
|
|
22
23
|
...tseslint.configs.recommended,
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
// React 的推荐配置
|
|
25
26
|
pluginReact.configs.flat.recommended,
|
|
26
27
|
pluginReact.configs.flat['jsx-runtime'],
|
|
27
28
|
reactHooks.configs.flat.recommended,
|
|
28
29
|
{
|
|
29
30
|
files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
|
30
|
-
|
|
31
|
+
|
|
31
32
|
// 语言选项:设置全局变量
|
|
32
33
|
languageOptions: {
|
|
33
34
|
globals: {
|
|
@@ -52,6 +53,7 @@ export default [
|
|
|
52
53
|
|
|
53
54
|
plugins: {
|
|
54
55
|
import: pluginImport,
|
|
56
|
+
fontawesome6,
|
|
55
57
|
},
|
|
56
58
|
rules: {
|
|
57
59
|
// 关闭代码风格规则
|
|
@@ -70,6 +72,7 @@ export default [
|
|
|
70
72
|
'no-prototype-builtins': 'off',
|
|
71
73
|
'react/react-in-jsx-scope': 'off',
|
|
72
74
|
'react/jsx-uses-react': 'off',
|
|
75
|
+
'fontawesome6/valid-name': 'error',
|
|
73
76
|
},
|
|
74
77
|
},
|
|
75
78
|
|
|
@@ -91,7 +94,7 @@ export default [
|
|
|
91
94
|
// 在 .js 文件中关闭 TS 规则
|
|
92
95
|
'@typescript-eslint/no-require-imports': 'off',
|
|
93
96
|
// 在 Node.js 文件中允许 require
|
|
94
|
-
'@typescript-eslint/no-var-requires': 'off',
|
|
97
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
95
98
|
'no-undef': 'off',
|
|
96
99
|
},
|
|
97
100
|
},
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
-
import { Colors } from
|
|
2
|
-
import { useColorScheme } from
|
|
1
|
+
import { Colors } from '@/constants/theme';
|
|
2
|
+
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
enum COLOR_SCHEME_CHOICE {
|
|
5
|
+
FOLLOW_SYSTEM = 'follow-system', // 跟随系统自动变化
|
|
6
|
+
DARK = 'dark', // 固定为 dark 主题,不随系统变化
|
|
7
|
+
LIGHT = 'light', // 固定为 light 主题,不随系统变化
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const userPreferColorScheme: COLOR_SCHEME_CHOICE = COLOR_SCHEME_CHOICE.FOLLOW_SYSTEM;
|
|
11
|
+
|
|
12
|
+
function getTheme(colorScheme?: 'dark' | 'light' | null) {
|
|
13
|
+
const isDark = colorScheme === 'dark';
|
|
14
|
+
const theme = Colors[colorScheme ?? 'light'];
|
|
8
15
|
|
|
9
16
|
return {
|
|
10
17
|
theme,
|
|
11
18
|
isDark,
|
|
12
19
|
};
|
|
13
20
|
}
|
|
21
|
+
|
|
22
|
+
function useTheme() {
|
|
23
|
+
const systemColorScheme = useColorScheme()
|
|
24
|
+
const colorScheme = userPreferColorScheme === COLOR_SCHEME_CHOICE.FOLLOW_SYSTEM ?
|
|
25
|
+
systemColorScheme :
|
|
26
|
+
userPreferColorScheme;
|
|
27
|
+
|
|
28
|
+
return getTheme(colorScheme);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
useTheme,
|
|
33
|
+
}
|
|
@@ -5,7 +5,7 @@ import { useTheme } from '@/hooks/useTheme';
|
|
|
5
5
|
import { Screen } from '@/components/Screen';
|
|
6
6
|
import { styles } from './styles';
|
|
7
7
|
|
|
8
|
-
export default function
|
|
8
|
+
export default function DemoPage() {
|
|
9
9
|
const { theme, isDark } = useTheme();
|
|
10
10
|
|
|
11
11
|
return (
|
|
@@ -1,9 +1,31 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
1
2
|
import dayjs from 'dayjs';
|
|
2
3
|
import utc from 'dayjs/plugin/utc';
|
|
3
4
|
dayjs.extend(utc);
|
|
4
5
|
|
|
5
6
|
const API_BASE = (process.env.EXPO_PUBLIC_API_BASE ?? '').replace(/\/$/, '');
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* 创建跨平台兼容的文件对象,用于 FormData.append()
|
|
10
|
+
* - Web 端返回 File 对象
|
|
11
|
+
* - 移动端返回 { uri, type, name } 对象(RN fetch 会自动处理)
|
|
12
|
+
* @param fileUri Expo 媒体库(如 expo-image-picker、expo-camera)返回的 uri
|
|
13
|
+
* @param fileName 上传时的文件名,如 'photo.jpg'
|
|
14
|
+
* @param mimeType 文件 MIME 类型,如 'image/jpeg'、'audio/mpeg'
|
|
15
|
+
*/
|
|
16
|
+
export async function createFormDataFile(
|
|
17
|
+
fileUri: string,
|
|
18
|
+
fileName: string,
|
|
19
|
+
mimeType: string
|
|
20
|
+
): Promise<File | { uri: string; type: string; name: string }> {
|
|
21
|
+
if (Platform.OS === 'web') {
|
|
22
|
+
const response = await fetch(fileUri);
|
|
23
|
+
const blob = await response.blob();
|
|
24
|
+
return new File([blob], fileName, { type: mimeType });
|
|
25
|
+
}
|
|
26
|
+
return { uri: fileUri, type: mimeType, name: fileName };
|
|
27
|
+
}
|
|
28
|
+
|
|
7
29
|
/**
|
|
8
30
|
* 构建文件或图片完整的URL
|
|
9
31
|
* @param url 相对或绝对路径
|