@coze-arch/cli 0.0.1-alpha.f9be02 → 0.0.1-alpha.fd3d56

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.
Files changed (84) hide show
  1. package/lib/__templates__/expo/.coze +1 -1
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +19 -82
  3. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +75 -86
  4. package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +2 -2
  5. package/lib/__templates__/expo/.cozeproj/scripts/prod_run.sh +2 -2
  6. package/lib/__templates__/expo/.cozeproj/scripts/server_dev_run.sh +45 -0
  7. package/lib/__templates__/expo/README.md +68 -7
  8. package/lib/__templates__/expo/client/app/+not-found.tsx +30 -0
  9. package/lib/__templates__/expo/client/{src/app → app}/_layout.tsx +15 -12
  10. package/lib/__templates__/expo/client/app/index.tsx +1 -0
  11. package/lib/__templates__/expo/client/app.config.ts +65 -60
  12. package/lib/__templates__/expo/client/{src/components → components}/Screen.tsx +1 -17
  13. package/lib/__templates__/expo/client/{src/components → components}/ThemedView.tsx +1 -2
  14. package/lib/__templates__/expo/client/constants/theme.ts +177 -0
  15. package/lib/__templates__/expo/client/declarations.d.ts +5 -0
  16. package/lib/__templates__/expo/client/eslint.config.mjs +30 -10
  17. package/lib/__templates__/expo/client/hooks/useColorScheme.tsx +48 -0
  18. package/lib/__templates__/expo/client/hooks/useSafeRouter.ts +152 -0
  19. package/lib/__templates__/expo/client/hooks/useTheme.ts +33 -0
  20. package/lib/__templates__/expo/client/package.json +6 -3
  21. package/lib/__templates__/expo/client/screens/demo/index.tsx +25 -0
  22. package/lib/__templates__/expo/client/screens/demo/styles.ts +28 -0
  23. package/lib/__templates__/expo/client/scripts/install-missing-deps.js +1 -0
  24. package/lib/__templates__/expo/client/tsconfig.json +1 -1
  25. package/lib/__templates__/expo/client/{src/utils → utils}/index.ts +22 -0
  26. package/lib/__templates__/expo/eslint-plugins/fontawesome6/index.js +9 -0
  27. package/lib/__templates__/expo/eslint-plugins/fontawesome6/names.js +1889 -0
  28. package/lib/__templates__/expo/eslint-plugins/fontawesome6/rule.js +174 -0
  29. package/lib/__templates__/expo/eslint-plugins/fontawesome6/v5-only-names.js +388 -0
  30. package/lib/__templates__/expo/eslint-plugins/reanimated/index.js +9 -0
  31. package/lib/__templates__/expo/eslint-plugins/reanimated/rule.js +88 -0
  32. package/lib/__templates__/expo/package.json +7 -98
  33. package/lib/__templates__/expo/patches/expo@54.0.32.patch +44 -0
  34. package/lib/__templates__/expo/pnpm-lock.yaml +2001 -2124
  35. package/lib/__templates__/expo/server/build.js +21 -0
  36. package/lib/__templates__/expo/server/package.json +19 -4
  37. package/lib/__templates__/expo/server/src/index.ts +9 -2
  38. package/lib/__templates__/expo/server/tsconfig.json +24 -0
  39. package/lib/__templates__/expo/template.config.js +1 -0
  40. package/lib/__templates__/nextjs/.babelrc +15 -0
  41. package/lib/__templates__/nextjs/.coze +1 -0
  42. package/lib/__templates__/nextjs/_npmrc +1 -0
  43. package/lib/__templates__/nextjs/next.config.ts +12 -0
  44. package/lib/__templates__/nextjs/package.json +10 -11
  45. package/lib/__templates__/nextjs/pnpm-lock.yaml +2543 -1747
  46. package/lib/__templates__/nextjs/scripts/prepare.sh +9 -0
  47. package/lib/__templates__/nextjs/src/app/globals.css +10 -2
  48. package/lib/__templates__/nextjs/src/app/layout.tsx +5 -14
  49. package/lib/__templates__/nextjs/src/app/page.tsx +35 -23
  50. package/lib/__templates__/nextjs/src/components/ui/resizable.tsx +29 -22
  51. package/lib/__templates__/nextjs/src/components/ui/sidebar.tsx +228 -230
  52. package/lib/__templates__/nextjs/template.config.js +30 -0
  53. package/lib/__templates__/templates.json +61 -43
  54. package/lib/__templates__/vite/.coze +1 -0
  55. package/lib/__templates__/vite/_npmrc +1 -0
  56. package/lib/__templates__/vite/eslint.config.mjs +9 -0
  57. package/lib/__templates__/vite/package.json +10 -1
  58. package/lib/__templates__/vite/pnpm-lock.yaml +3115 -126
  59. package/lib/__templates__/vite/scripts/prepare.sh +9 -0
  60. package/lib/__templates__/vite/src/main.ts +1 -2
  61. package/lib/__templates__/vite/template.config.js +30 -4
  62. package/lib/cli.js +691 -130
  63. package/package.json +5 -3
  64. package/lib/__templates__/expo/client/src/app/index.ts +0 -1
  65. package/lib/__templates__/expo/client/src/constants/theme.ts +0 -850
  66. package/lib/__templates__/expo/client/src/hooks/useColorScheme.ts +0 -1
  67. package/lib/__templates__/expo/client/src/hooks/useTheme.ts +0 -13
  68. package/lib/__templates__/expo/client/src/screens/home/index.tsx +0 -50
  69. package/lib/__templates__/expo/client/src/screens/home/styles.ts +0 -60
  70. package/lib/__templates__/nextjs/.vscode/settings.json +0 -121
  71. package/lib/__templates__/vite/.vscode/settings.json +0 -7
  72. /package/lib/__templates__/expo/client/{src/assets → assets}/fonts/SpaceMono-Regular.ttf +0 -0
  73. /package/lib/__templates__/expo/client/{src/assets → assets}/images/adaptive-icon.png +0 -0
  74. /package/lib/__templates__/expo/client/{src/assets → assets}/images/default-avatar.png +0 -0
  75. /package/lib/__templates__/expo/client/{src/assets → assets}/images/favicon.png +0 -0
  76. /package/lib/__templates__/expo/client/{src/assets → assets}/images/icon.png +0 -0
  77. /package/lib/__templates__/expo/client/{src/assets → assets}/images/partial-react-logo.png +0 -0
  78. /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo.png +0 -0
  79. /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo@2x.png +0 -0
  80. /package/lib/__templates__/expo/client/{src/assets → assets}/images/react-logo@3x.png +0 -0
  81. /package/lib/__templates__/expo/client/{src/assets → assets}/images/splash-icon.png +0 -0
  82. /package/lib/__templates__/expo/client/{src/components → components}/SmartDateInput.tsx +0 -0
  83. /package/lib/__templates__/expo/client/{src/components → components}/ThemedText.tsx +0 -0
  84. /package/lib/__templates__/expo/client/{src/contexts → contexts}/AuthContext.tsx +0 -0
@@ -9,4 +9,4 @@ run = ["bash", ".cozeproj/scripts/dev_run.sh"]
9
9
  [deploy]
10
10
  build = ["bash", ".cozeproj/scripts/prod_build.sh"]
11
11
  run = ["bash", ".cozeproj/scripts/prod_run.sh"]
12
- build_app_dir = "."
12
+ build_app_dir = "./client"
@@ -2,108 +2,45 @@
2
2
  if [ -z "${BASH_VERSION:-}" ]; then exec /usr/bin/env bash "$0" "$@"; fi
3
3
  set -euo pipefail
4
4
  ROOT_DIR="$(pwd)"
5
- PREVIEW_DIR="${COZE_PREVIEW_DIR:-$ROOT_DIR}"
6
- LOG_DIR="${COZE_LOG_DIR:-$ROOT_DIR/logs}"
7
- LOG_FILE="$LOG_DIR/app.log"
8
- mkdir -p "$LOG_DIR"
5
+ PREVIEW_DIR="${COZE_PREVIEW_DIR:-/source/preview}"
9
6
 
10
7
  # ==================== 配置项 ====================
11
8
  SERVER_DIR="app"
12
9
  EXPO_DIR="expo"
13
10
  CHECK_HASH_SCRIPT="$ROOT_DIR/check_hash.py"
14
- # ==================== 工具函数 ====================
15
- info() {
16
- echo -e "\033[32m[INFO] $1\033[0m"
17
- }
18
- warn() {
19
- echo -e "\033[33m[WARN] $1\033[0m"
20
- }
21
- error() {
22
- echo -e "\033[31m[ERROR] $1\033[0m"
23
- exit 1
24
- }
11
+
25
12
  check_command() {
26
13
  if ! command -v "$1" &> /dev/null; then
27
- error "命令 $1 未找到,请先安装"
14
+ echo "error:命令 $1 未找到,请先安装"
28
15
  fi
29
16
  }
30
- write_log() {
31
- local level="${1:-INFO}"
32
- local msg="${2:-}"
33
- node -e '
34
- const fs=require("fs");
35
- const path=process.argv[1];
36
- const level=(process.argv[2]||"").toUpperCase();
37
- let msg=String(process.argv[3]||"");
38
- const ts=Date.now();
39
- const dt=new Date();
40
- const parts=new Intl.DateTimeFormat("en-GB",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false}).formatToParts(dt);
41
- const o={};
42
- for(const p of parts){o[p.type]=p.value}
43
- const dt_str=`${o.year}-${o.month}-${o.day} ${o.hour}:${o.minute}:${o.second}`;
44
- msg=msg.replace(/\\n/g,"\n");
45
- msg=`${dt_str} [${level}] ${msg}`;
46
- const record=JSON.stringify({level, message: msg, timestamp: ts},null,0);
47
- const fd=fs.openSync(path,"a");
48
- fs.writeSync(fd, record+"\n", null, "utf8");
49
- fs.fsyncSync(fd);
50
- fs.closeSync(fd);
51
- ' "$LOG_FILE" "$level" "$msg"
52
- }
53
17
 
54
- # ==================== 前置检查 ====================
55
- write_log "INFO" "==================== 开始构建 ===================="
18
+ echo "==================== 开始构建 ===================="
56
19
 
57
- write_log "INFO" "检查根目录 pre_install.py"
20
+ echo "检查根目录 pre_install.py"
58
21
  if [ -f "$PREVIEW_DIR/pre_install.py" ]; then
59
- write_log "INFO" "执行:python $PREVIEW_DIR/pre_install.py"
60
- python "$PREVIEW_DIR/pre_install.py" || write_log "ERROR" "pre_install.py 执行失败"
22
+ echo "执行:python $PREVIEW_DIR/pre_install.py"
23
+ python "$PREVIEW_DIR/pre_install.py" || echo "pre_install.py 执行失败"
61
24
  fi
62
25
 
63
- write_log "INFO" "开始执行构建脚本(build_dev.sh)..."
64
- write_log "INFO" "正在检查依赖命令是否存在..."
26
+ echo "开始执行构建脚本(build_dev.sh)..."
27
+ echo "正在检查依赖命令是否存在..."
65
28
  # 检查核心命令
66
- # check_command "pip"
67
- # check_command "python"
68
29
  check_command "pnpm"
69
30
  check_command "npm"
70
31
 
71
- # ==================== 步骤 1:安装项目依赖 ====================
72
- write_log "INFO" "==================== 安装项目依赖 ===================="
32
+ echo "==================== 安装项目依赖 ===================="
73
33
  if [ ! -f "package.json" ]; then
74
- write_log "ERROR" "项目目录下无 package.json,不是合法的 Node.js 项目"
75
- fi
76
- # 步骤 2.1/2.2:安装 Expo 项目依赖(按哈希变化执行)
77
- if [ -f "$CHECK_HASH_SCRIPT" ]; then
78
- write_log "INFO" "检测 package.json 哈希是否变化"
79
- set +e
80
- python "$CHECK_HASH_SCRIPT" --config "package.json" --check
81
- rc_node=$?
82
- set -e
83
- if [ $rc_node -eq 1 ]; then
84
- write_log "INFO" "依赖哈希已变化,执行:pnpm install"
85
- pnpm install --registry=https://registry.npmmirror.com || write_log "ERROR" "Expo 项目依赖安装失败(pnpm 执行出错)"
86
-
87
- write_log "INFO" "依赖哈希已变化,执行:npm run install-missing"
88
- npm run install-missing || write_log "ERROR" "npm run install-missing 执行失败,请检查 package.json 中的脚本配置"
89
-
90
- set +e
91
- python "$CHECK_HASH_SCRIPT" --config "package.json" --update
92
- set -e
93
- else
94
- write_log "INFO" "跳过 pnpm install 与 npm run install-missing"
95
- fi
96
- else
97
- write_log "WARN" "未找到 check_hash.py,默认执行:pnpm install 与 npm run install-missing"
98
- pnpm install --registry=https://registry.npmmirror.com || write_log "ERROR" "Expo 项目依赖安装失败(pnpm 执行出错)"
99
- npm run install-missing || write_log "ERROR" "npm run install-missing 执行失败,请检查 package.json 中的脚本配置"
34
+ echo "项目目录下无 package.json,不是合法的 Node.js 项目"
100
35
  fi
36
+ # 步骤 2.1/2.2:安装项目依赖
37
+ pnpm install --registry=https://registry.npmmirror.com || echo "Expo 项目依赖安装失败(pnpm 执行出错)"
101
38
 
102
- write_log "INFO" "检查根目录 post_install.py"
103
- if [ -f "$ROOT_DIR/post_install.py" ]; then
104
- write_log "INFO" "执行:python $ROOT_DIR/post_install.py"
105
- python "$ROOT_DIR/post_install.py" || write_log "ERROR" "post_install.py 执行失败"
39
+ echo "检查根目录 post_install.py"
40
+ if [ -f "$PREVIEW_DIR/post_install.py" ]; then
41
+ echo "执行:python $PREVIEW_DIR/post_install.py"
42
+ python "$PREVIEW_DIR/post_install.py" || echo "post_install.py 执行失败"
106
43
  fi
107
44
 
108
- write_log "INFO" "==================== 依赖安装完成!====================\n"
109
- write_log "INFO" "下一步:执行 ./deploy_run.sh 启动服务"
45
+ echo "==================== 依赖安装完成!====================\n"
46
+ echo "下一步:执行 ./deploy_run.sh 启动服务"
@@ -1,5 +1,5 @@
1
- ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
2
- PREVIEW_DIR="${COZE_PREVIEW_DIR:-$ROOT_DIR}"
1
+ ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
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"
5
5
  mkdir -p "$LOG_DIR"
@@ -15,27 +15,18 @@ EXPO_PORT="5000"
15
15
  WEB_URL="${COZE_PROJECT_DOMAIN_DEFAULT:-http://127.0.0.1:${SERVER_PORT}}"
16
16
  ASSUME_YES="1"
17
17
  EXPO_PUBLIC_BACKEND_BASE_URL="${EXPO_PUBLIC_BACKEND_BASE_URL:-$WEB_URL}"
18
-
18
+ EXPO_PUBLIC_COZE_PROJECT_ID="${COZE_PROJECT_ID:-}"
19
19
 
20
20
  EXPO_PACKAGER_PROXY_URL="${EXPO_PUBLIC_BACKEND_BASE_URL}"
21
- export EXPO_PUBLIC_BACKEND_BASE_URL EXPO_PACKAGER_PROXY_URL
21
+ export EXPO_PUBLIC_BACKEND_BASE_URL EXPO_PACKAGER_PROXY_URL EXPO_PUBLIC_COZE_PROJECT_ID
22
22
  # 运行时变量(为避免 set -u 的未绑定错误,预置为空)
23
23
  SERVER_PID=""
24
24
  EXPO_PID=""
25
+
25
26
  # ==================== 工具函数 ====================
26
- info() {
27
- echo -e "\033[32m[INFO] $1\033[0m"
28
- }
29
- warn() {
30
- echo -e "\033[33m[WARN] $1\033[0m"
31
- }
32
- error() {
33
- echo -e "\033[31m[ERROR] $1\033[0m"
34
- exit 1
35
- }
36
27
  check_command() {
37
28
  if ! command -v "$1" &> /dev/null; then
38
- error "命令 $1 未找到,请先安装"
29
+ echo "error:命令 $1 未找到,请先安装"
39
30
  fi
40
31
  }
41
32
  while [ $# -gt 0 ]; do
@@ -64,10 +55,10 @@ ensure_port() {
64
55
  local var_name=$1
65
56
  local port_val=$2
66
57
  if is_port_free "$port_val"; then
67
- info "端口未占用:$port_val"
58
+ echo "端口未占用:$port_val"
68
59
  eval "$var_name=$port_val"
69
60
  else
70
- warn "端口已占用:$port_val"
61
+ echo "端口已占用:$port_val"
71
62
  local choice
72
63
  if [ "$ASSUME_YES" = "1" ]; then choice="Y"; else read -r -p "是否关闭该端口的进程?[Y/n] " choice || choice="Y"; fi
73
64
  if [ -z "$choice" ] || [ "$choice" = "y" ] || [ "$choice" = "Y" ]; then
@@ -75,15 +66,15 @@ ensure_port() {
75
66
  local pids
76
67
  pids=$(lsof -t -i tcp:"$port_val" -sTCP:LISTEN 2>/dev/null || true)
77
68
  if [ -n "$pids" ]; then
78
- info "正在关闭进程:$pids"
79
- kill -9 $pids 2>/dev/null || warn "关闭进程失败:$pids"
69
+ echo "正在关闭进程:$pids"
70
+ kill -9 $pids 2>/dev/null || echo "关闭进程失败:$pids"
80
71
  eval "$var_name=$port_val"
81
72
  else
82
- warn "未获取到占用该端口的进程"
73
+ echo "未获取到占用该端口的进程"
83
74
  eval "$var_name=$port_val"
84
75
  fi
85
76
  else
86
- warn "缺少 lsof,无法自动关闭进程"
77
+ echo "缺少 lsof,无法自动关闭进程"
87
78
  eval "$var_name=$port_val"
88
79
  fi
89
80
  else
@@ -95,28 +86,18 @@ ensure_port() {
95
86
  fi
96
87
  }
97
88
 
98
- write_log() {
99
- local level="${1:-INFO}"
100
- local msg="${2:-}"
101
- node -e '
102
- const fs=require("fs");
103
- const path=process.argv[1];
104
- const level=(process.argv[2]||"").toUpperCase();
105
- let msg=String(process.argv[3]||"");
106
- const ts=Date.now();
107
- msg=msg.replace(/\\n/g,"\n");
108
- const dt=new Date();
109
- const parts=new Intl.DateTimeFormat("en-GB",{timeZone:"Asia/Shanghai",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:false}).formatToParts(dt);
110
- const o={};
111
- for(const p of parts){o[p.type]=p.value}
112
- const dt_str=`${o.year}-${o.month}-${o.day} ${o.hour}:${o.minute}:${o.second}`;
113
- msg=`${dt_str} [${level}] ${msg}`;
114
- const record=JSON.stringify({level, message: msg, timestamp: ts},null,0);
115
- const fd=fs.openSync(path,"a");
116
- fs.writeSync(fd, record+"\n", null, "utf8");
117
- fs.fsyncSync(fd);
118
- fs.closeSync(fd);
119
- ' "$LOG_FILE" "$level" "$msg"
89
+ pipe_to_log() {
90
+ local source="${1:-CLIENT}"
91
+ local raw_log="${2:-}"
92
+ local line timestamp ts msg record
93
+ while IFS= read -r line || [ -n "$line" ]; do
94
+ if [ -n "$raw_log" ]; then
95
+ echo "$line" >> "$raw_log"
96
+ fi
97
+ line=$(echo "[$source] $line" | sed 's/\x1b\[[0-9;]*[a-zA-Z]//g; s/\x1b\[[0-9;]*m//g')
98
+ msg="${line}"
99
+ echo "$msg"
100
+ done
120
101
  }
121
102
 
122
103
  wait_port_connectable() {
@@ -131,15 +112,17 @@ wait_port_connectable() {
131
112
  start_expo() {
132
113
  local offline="${1:-0}"
133
114
 
134
- pushd ./client
115
+ pushd "$ROOT_DIR/client"
135
116
 
136
117
  if [ "$offline" = "1" ]; then
137
- 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" nohup npx expo start --port "$EXPO_PORT" > ../logs/expo.log 2>&1 &
118
+ ( EXPO_OFFLINE=1 EXPO_NO_DEPENDENCY_VALIDATION=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" EXPO_PUBLIC_COZE_PROJECT_ID="$EXPO_PUBLIC_COZE_PROJECT_ID" \
119
+ nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$ROOT_DIR/logs/client.log" ) &
138
120
  else
139
- EXPO_NO_DOCTOR=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" nohup npx expo start --port "$EXPO_PORT" > ../logs/expo.log 2>&1 &
121
+ ( EXPO_NO_DEPENDENCY_VALIDATION=1 EXPO_PUBLIC_BACKEND_BASE_URL="$EXPO_PUBLIC_BACKEND_BASE_URL" EXPO_PACKAGER_PROXY_URL="$EXPO_PACKAGER_PROXY_URL" EXPO_PUBLIC_COZE_PROJECT_ID="$EXPO_PUBLIC_COZE_PROJECT_ID" \
122
+ nohup npx expo start --clear --port "$EXPO_PORT" 2>&1 | pipe_to_log "CLIENT" "$ROOT_DIR/logs/client.log" ) &
140
123
  fi
141
124
  EXPO_PID=$!
142
- echo "$EXPO_PID"
125
+ disown $EXPO_PID 2>/dev/null || true
143
126
 
144
127
  popd
145
128
  }
@@ -147,7 +130,7 @@ start_expo() {
147
130
  detect_expo_fetch_failed() {
148
131
  local timeout="${1:-8}"
149
132
  local waited=0
150
- local log_file="logs/expo.log"
133
+ local log_file="$ROOT_DIR/logs/client.log"
151
134
  while [ "$waited" -lt "$timeout" ]; do
152
135
  if [ -f "$log_file" ] && grep -q "TypeError: fetch failed" "$log_file" 2>/dev/null; then
153
136
  return 0
@@ -162,78 +145,84 @@ detect_expo_fetch_failed() {
162
145
  # 关掉nginx进程
163
146
  ps -ef | grep nginx | grep -v grep | awk '{print $2}' | xargs -r kill -9
164
147
 
165
- write_log "INFO" "检查根目录 pre_install.py"
148
+ echo "检查根目录 pre_install.py"
166
149
  if [ -f "$PREVIEW_DIR/pre_install.py" ]; then
167
- write_log "INFO" "执行:python $PREVIEW_DIR/pre_install.py"
168
- python "$PREVIEW_DIR/pre_install.py" || write_log "ERROR" "pre_install.py 执行失败"
150
+ echo "执行:python $PREVIEW_DIR/pre_install.py"
151
+ python "$PREVIEW_DIR/pre_install.py" || echo "pre_install.py 执行失败"
152
+ fi
153
+
154
+ echo "检查根目录 post_install.py"
155
+ if [ -f "$PREVIEW_DIR/post_install.py" ]; then
156
+ echo "执行:python $PREVIEW_DIR/post_install.py"
157
+ python "$PREVIEW_DIR/post_install.py" || echo "post_install.py 执行失败"
169
158
  fi
170
159
 
171
- write_log "INFO" "==================== 开始启动 ===================="
172
- write_log "INFO" "开始执行服务启动脚本(start_dev.sh)..."
173
- write_log "INFO" "正在检查依赖命令和目录是否存在..."
160
+ echo "==================== 开始启动 ===================="
161
+ echo "开始执行服务启动脚本(start_dev.sh)..."
162
+ echo "正在检查依赖命令和目录是否存在..."
174
163
  # 检查核心命令
175
- # check_command "python"
176
164
  check_command "npm"
177
165
  check_command "pnpm"
178
166
  check_command "lsof"
179
167
  check_command "bash"
180
168
 
181
- info "准备日志目录:logs"
182
- mkdir -p logs
169
+ echo "准备日志目录:$ROOT_DIR/logs"
170
+ mkdir -p "$ROOT_DIR/logs"
183
171
  # 端口占用预检查与处理
184
172
  ensure_port SERVER_PORT "$SERVER_PORT"
185
173
  ensure_port EXPO_PORT "$EXPO_PORT"
186
174
 
187
- # ==================== 启动 Server 服务 ====================
188
- write_log "INFO" "==================== 启动 server 服务 ===================="
189
- write_log "INFO" "正在执行:npm run dev"
190
- PORT="$SERVER_PORT" nohup npm run dev --prefix ./server > logs/app.log 2>&1 &
175
+ echo "==================== 启动 server 服务 ===================="
176
+ echo "正在执行:pnpm run dev (server)"
177
+ ( pushd "$ROOT_DIR/server" > /dev/null && SERVER_PORT="$SERVER_PORT" nohup pnpm run dev; popd > /dev/null ) &
191
178
  SERVER_PID=$!
179
+ disown $SERVER_PID 2>/dev/null || true
192
180
  if [ -z "${SERVER_PID}" ]; then
193
- write_log "ERROR" "无法获取 server 后台进程 PID"
181
+ echo "无法获取 server 后台进程 PID"
194
182
  fi
195
- write_log "INFO" "server 服务已启动,进程 ID:${SERVER_PID:-unknown}"
183
+ echo "server 服务已启动,进程 ID:${SERVER_PID:-unknown}"
196
184
 
197
- write_log "INFO" "==================== 启动 Expo 项目 ===================="
198
- write_log "INFO" "开始启动 Expo 服务,端口 ${EXPO_PORT}"
199
- EXPO_PID=$(start_expo 0)
185
+ echo "==================== 启动 Expo 项目 ===================="
186
+ echo "开始启动 Expo 服务,端口 ${EXPO_PORT}"
187
+ start_expo 0
200
188
  if detect_expo_fetch_failed 8; then
201
- write_log "WARN" "Expo 启动检测到网络错误:TypeError: fetch failed,启用离线模式重试"
189
+ echo "Expo 启动检测到网络错误:TypeError: fetch failed,启用离线模式重试"
202
190
  if [ -n "${EXPO_PID}" ]; then kill -9 "$EXPO_PID" 2>/dev/null || true; fi
203
- : > logs/expo.log
204
- EXPO_PID=$(start_expo 1)
191
+ : > "$ROOT_DIR/logs/client.log"
192
+ start_expo 1
205
193
  fi
206
194
  # 输出以下环境变量,确保 Expo 项目能正确连接到 Server 服务
207
- write_log "INFO" "Expo 环境变量配置:"
208
- write_log "INFO" "EXPO_PUBLIC_BACKEND_BASE_URL=${EXPO_PUBLIC_BACKEND_BASE_URL}"
209
- write_log "INFO" "EXPO_PACKAGER_PROXY_URL=${EXPO_PACKAGER_PROXY_URL}"
195
+ echo "Expo 环境变量配置:"
196
+ echo "EXPO_PUBLIC_BACKEND_BASE_URL=${EXPO_PUBLIC_BACKEND_BASE_URL}"
197
+ echo "EXPO_PACKAGER_PROXY_URL=${EXPO_PACKAGER_PROXY_URL}"
198
+ echo "EXPO_PUBLIC_COZE_PROJECT_ID=${EXPO_PUBLIC_COZE_PROJECT_ID}"
210
199
  if [ -z "${EXPO_PID}" ]; then
211
- write_log "ERROR" "无法获取 Expo 后台进程 PID"
200
+ echo "无法获取 Expo 后台进程 PID"
212
201
  fi
213
202
 
214
- write_log "INFO" "所有服务已启动。Server PID: ${SERVER_PID}, Expo PID: ${EXPO_PID}"
203
+ echo "所有服务已启动。Server PID: ${SERVER_PID}, Expo PID: ${EXPO_PID}"
215
204
 
216
- write_log "INFO" "检查 Server 服务端口:$SERVER_HOST:$SERVER_PORT"
205
+ echo "检查 Server 服务端口:$SERVER_HOST:$SERVER_PORT"
217
206
  if wait_port_connectable "$SERVER_HOST" "$SERVER_PORT" 10 2; then
218
- write_log "INFO" "端口可连接:$SERVER_HOST:$SERVER_PORT"
207
+ echo "端口可连接:$SERVER_HOST:$SERVER_PORT"
219
208
  else
220
- write_log "WARN" "端口不可连接:$SERVER_HOST:$SERVER_PORT 10 次)"
209
+ echo "端口不可连接:$SERVER_HOST:$SERVER_PORT 10 次)"
221
210
  fi
222
211
 
223
- write_log "INFO" "检查 Expo 服务端口:$EXPO_HOST:$EXPO_PORT"
212
+ echo "检查 Expo 服务端口:$EXPO_HOST:$EXPO_PORT"
224
213
  if wait_port_connectable "$EXPO_HOST" "$EXPO_PORT" 10 2; then
225
- write_log "INFO" "端口可连接:$EXPO_HOST:$EXPO_PORT"
214
+ echo "端口可连接:$EXPO_HOST:$EXPO_PORT"
226
215
  else
227
- write_log "WARN" "端口不可连接:$EXPO_HOST:$EXPO_PORT(已尝试 10 次)"
216
+ echo "端口不可连接:$EXPO_HOST:$EXPO_PORT(已尝试 10 次)"
228
217
  fi
229
218
 
230
- write_log "INFO" "服务端口检查完成"
219
+ echo "服务端口检查完成"
231
220
 
232
- write_log "INFO" "检查根目录 post_run.py"
221
+ echo "检查根目录 post_run.py"
233
222
  if [ -f "$ROOT_DIR/post_run.py" ]; then
234
- write_log "INFO" "启动检查中"
235
- python "$ROOT_DIR/post_run.py" --port "$EXPO_PORT" || write_log "ERROR" "post_run.py 执行失败"
236
- write_log "INFO" "启动检查结束"
223
+ echo "启动检查中"
224
+ python "$ROOT_DIR/post_run.py" --port "$EXPO_PORT" || echo "post_run.py 执行失败"
225
+ echo "启动检查结束"
237
226
  fi
238
227
 
239
- write_log "INFO" "==================== 服务启动完成 ===================="
228
+ echo "==================== 服务启动完成 ===================="
@@ -40,8 +40,8 @@ fi
40
40
  info "==================== 依赖安装完成!====================\n"
41
41
 
42
42
  info "==================== dist打包 ===================="
43
- info "开始执行:npm run build --prefix server"
44
- (cd "$ROOT_DIR" && npm run build --prefix ./server) || error "dist打包失败"
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 "开始执行:npm run start"
33
- (cd "$ROOT_DIR" && PORT="$PORT" npm run start --prefix ./server) || error "服务启动失败"
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"
@@ -1,13 +1,74 @@
1
- # Expo App Template
1
+ # Expo App + Express.js
2
+
3
+ ## 目录结构规范(严格遵循)
4
+
5
+ 当前仓库是一个 monorepo(基于 pnpm 的 workspace)
6
+
7
+ - Expo 代码在 client 目录,Express.js 代码在 server 目录
8
+ - 本模板默认无 Tab Bar,可按需改造
9
+
10
+ 目录结构说明
11
+
12
+ ├── server/ # 服务端代码根目录 (Express.js)
13
+ | ├── src/
14
+ │ │ └── index.ts # Express 入口文件
15
+ | └── package.json # 服务端 package.json
16
+ ├── client/ # React Native 前端代码
17
+ │ ├── app/ # Expo Router 路由目录(仅路由配置)
18
+ │ │ ├── _layout.tsx # 根布局文件(必需,务必阅读)
19
+ │ │ ├── home.tsx # 首页
20
+ │ │ └── index.tsx # re-export home.tsx
21
+ │ ├── screens/ # 页面实现目录(与 app/ 路由对应)
22
+ │ │ └── demo/ # demo 示例页面
23
+ │ │ ├── index.tsx # 页面组件实现
24
+ │ │ └── styles.ts # 页面样式
25
+ │ ├── components/ # 可复用组件
26
+ │ │ └── Screen.tsx # 页面容器组件(必用)
27
+ │ ├── hooks/ # 自定义 Hooks
28
+ │ ├── contexts/ # React Context 代码
29
+ │ ├── constants/ # 常量定义(如主题配置)
30
+ │ ├── utils/ # 工具函数
31
+ │ ├── assets/ # 静态资源
32
+ | └── package.json # Expo 应用 package.json
33
+ ├── package.json
34
+ ├── .cozeproj # 预置脚手架脚本(禁止修改)
35
+ └── .coze # 配置文件(禁止修改)
36
+
2
37
  ## 安装依赖
38
+
39
+ ### 命令
40
+
3
41
  ```bash
4
- pnpm install
42
+ pnpm i
5
43
  ```
6
- ## 启动 Metro 服务
7
- ```bash
8
- npx expo start
44
+
45
+ ### 新增依赖约束
46
+
47
+ 如果需要新增依赖,需在 client 和 server 各自的目录添加(原因:隔离前后端的依赖),禁止在根目录直接安装依赖
48
+
49
+ ### 新增依赖标准流程
50
+
51
+ - 编辑 `client/package.json` 或 `server/package.json`
52
+ - 在根目录执行 `pnpm i`
53
+
54
+ ## Expo 开发规范
55
+
56
+ ### 路径别名
57
+
58
+ Expo 配置了 `@/` 路径别名指向 `client/` 目录:
59
+
60
+ ```tsx
61
+ // 正确
62
+ import { Screen } from '@/components/Screen';
63
+
64
+ // 避免相对路径
65
+ import { Screen } from '../../../components/Screen';
9
66
  ```
10
- ## 启动 Node 服务器
67
+
68
+ ## 本地开发
69
+
70
+ 运行 coze dev 可以同时启动前端和后端服务,如果端口已占用,该命令会先杀掉占用端口的进程再启动,也可以用来重启前端和后端服务
71
+
11
72
  ```bash
12
- npm run server
73
+ coze dev
13
74
  ```
@@ -0,0 +1,30 @@
1
+ import { View, Text, StyleSheet } from 'react-native';
2
+ import { Link } from 'expo-router';
3
+ import { useTheme } from '@/hooks/useTheme';
4
+ import { Spacing } from '@/constants/theme';
5
+
6
+ export default function NotFoundScreen() {
7
+ const { theme } = useTheme();
8
+
9
+ return (
10
+ <View style={[styles.container, { backgroundColor: theme.backgroundRoot }]}>
11
+ <Text>
12
+ 页面不存在
13
+ </Text>
14
+ <Link href="/" style={[styles.gohome]}>
15
+ 返回首页
16
+ </Link>
17
+ </View>
18
+ );
19
+ }
20
+
21
+ const styles = StyleSheet.create({
22
+ container: {
23
+ flex: 1,
24
+ justifyContent: 'center',
25
+ alignItems: 'center',
26
+ },
27
+ gohome: {
28
+ marginTop: Spacing['2xl'],
29
+ },
30
+ });
@@ -5,6 +5,7 @@ import { StatusBar } from 'expo-status-bar';
5
5
  import { LogBox } from 'react-native';
6
6
  import Toast from 'react-native-toast-message';
7
7
  import { AuthProvider } from "@/contexts/AuthContext";
8
+ import { ColorSchemeProvider } from '@/hooks/useColorScheme';
8
9
 
9
10
  LogBox.ignoreLogs([
10
11
  "TurboModuleRegistry.getEnforcing(...): 'RNMapsAirModule' could not be found",
@@ -14,20 +15,22 @@ LogBox.ignoreLogs([
14
15
  export default function RootLayout() {
15
16
  return (
16
17
  <AuthProvider>
18
+ <ColorSchemeProvider>
17
19
  <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="(tabs)" options={{ title: "" }} />
28
- </Stack>
29
- <Toast />
20
+ <StatusBar style="dark"></StatusBar>
21
+ <Stack screenOptions={{
22
+ // 设置所有页面的切换动画为从右侧滑入,适用于iOS 和 Android
23
+ animation: 'slide_from_right',
24
+ gestureEnabled: true,
25
+ gestureDirection: 'horizontal',
26
+ // 隐藏自带的头部
27
+ headerShown: false
28
+ }}>
29
+ <Stack.Screen name="index" options={{ title: "" }} />
30
+ </Stack>
31
+ <Toast />
30
32
  </GestureHandlerRootView>
33
+ </ColorSchemeProvider>
31
34
  </AuthProvider>
32
35
  );
33
36
  }
@@ -0,0 +1 @@
1
+ export { default } from '@/screens/demo';