@coze-arch/cli 0.1.3 → 0.1.4-alpha.0e7259

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 (57) hide show
  1. package/lib/__templates__/expo/.coze +3 -0
  2. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.ps1 +10 -0
  3. package/lib/__templates__/expo/.cozeproj/scripts/dev_build.sh +3 -3
  4. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.ps1 +74 -0
  5. package/lib/__templates__/expo/.cozeproj/scripts/dev_run.sh +2 -0
  6. package/lib/__templates__/expo/.cozeproj/scripts/prepare-node-modules.sh +149 -0
  7. package/lib/__templates__/expo/.cozeproj/scripts/prod_build.sh +3 -3
  8. package/lib/__templates__/expo/.cozeproj/scripts/validate.ps1 +7 -0
  9. package/lib/__templates__/expo/client/components/Screen.tsx +65 -25
  10. package/lib/__templates__/expo/client/heroui/components/toast/toast.tsx +6 -2
  11. package/lib/__templates__/expo/client/heroui/helpers/internal/hooks/use-controllable-state.ts +1 -1
  12. package/lib/__templates__/expo/pnpm-lock.yaml +5 -5
  13. package/lib/__templates__/expo/server/package.json +1 -1
  14. package/lib/__templates__/nextjs/eslint.config.mjs +11 -5
  15. package/lib/__templates__/nextjs/next.config.ts +10 -0
  16. package/lib/__templates__/nextjs/package.json +3 -6
  17. package/lib/__templates__/nextjs/pnpm-lock.yaml +19 -950
  18. package/lib/__templates__/nextjs/scripts/build.ps1 +1 -1
  19. package/lib/__templates__/nextjs/scripts/build.sh +3 -2
  20. package/lib/__templates__/nextjs/scripts/dev.ps1 +2 -2
  21. package/lib/__templates__/nextjs/scripts/dev.sh +10 -5
  22. package/lib/__templates__/nextjs/scripts/prepare-next-output.sh +62 -0
  23. package/lib/__templates__/nextjs/scripts/prepare-node-modules.sh +149 -0
  24. package/lib/__templates__/nextjs/scripts/prepare.sh +1 -4
  25. package/lib/__templates__/nextjs/src/app/layout.tsx +0 -4
  26. package/lib/__templates__/nextjs/src/server.ts +1 -1
  27. package/lib/__templates__/nextjs/template.config.js +0 -59
  28. package/lib/__templates__/nuxt-vue/package.json +1 -1
  29. package/lib/__templates__/nuxt-vue/pnpm-lock.yaml +5 -5
  30. package/lib/__templates__/nuxt-vue/scripts/build.sh +1 -1
  31. package/lib/__templates__/nuxt-vue/scripts/dev.sh +2 -0
  32. package/lib/__templates__/nuxt-vue/scripts/prepare-node-modules.sh +149 -0
  33. package/lib/__templates__/nuxt-vue/scripts/prepare.sh +1 -4
  34. package/lib/__templates__/pi-agent/package.json +1 -1
  35. package/lib/__templates__/pi-agent/pnpm-lock.yaml +5 -5
  36. package/lib/__templates__/taro/.coze +4 -0
  37. package/lib/__templates__/taro/.cozeproj/scripts/deploy_build.sh +3 -2
  38. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.ps1 +3 -0
  39. package/lib/__templates__/taro/.cozeproj/scripts/dev_build.sh +3 -0
  40. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.ps1 +62 -0
  41. package/lib/__templates__/taro/.cozeproj/scripts/dev_run.sh +3 -1
  42. package/lib/__templates__/taro/.cozeproj/scripts/pack.ps1 +7 -0
  43. package/lib/__templates__/taro/.cozeproj/scripts/prepare-node-modules.sh +149 -0
  44. package/lib/__templates__/taro/.cozeproj/scripts/validate.ps1 +7 -0
  45. package/lib/__templates__/taro/pnpm-lock.yaml +5 -5
  46. package/lib/__templates__/taro/server/package.json +1 -1
  47. package/lib/__templates__/vite/package.json +1 -1
  48. package/lib/__templates__/vite/pnpm-lock.yaml +5 -5
  49. package/lib/__templates__/vite/scripts/build.sh +1 -1
  50. package/lib/__templates__/vite/scripts/dev.sh +2 -0
  51. package/lib/__templates__/vite/scripts/prepare-node-modules.sh +149 -0
  52. package/lib/__templates__/vite/scripts/prepare.sh +1 -4
  53. package/lib/__templates__/vite/template.config.js +0 -59
  54. package/lib/cli.js +38 -13
  55. package/lib/deploy/package-project.js +4 -1
  56. package/package.json +1 -1
  57. package/lib/__templates__/nextjs/.babelrc +0 -15
@@ -5,8 +5,11 @@ project_type = "app"
5
5
 
6
6
  [dev]
7
7
  build = ["bash", ".cozeproj/scripts/dev_build.sh"]
8
+ build_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", ".cozeproj/scripts/dev_build.ps1"]
8
9
  run = ["bash", ".cozeproj/scripts/dev_run.sh"]
10
+ run_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", ".cozeproj/scripts/dev_run.ps1"]
9
11
  validate = ["bash", ".cozeproj/scripts/validate.sh"]
12
+ validate_win = ["powershell.exe", "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", ".cozeproj/scripts/validate.ps1"]
10
13
 
11
14
  [deploy]
12
15
  build = ["bash", ".cozeproj/scripts/prod_build.sh"]
@@ -0,0 +1,10 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ Set-Location $workspace
5
+
6
+ Write-Host "Installing Expo project dependencies..."
7
+ & pnpm install --registry=https://registry.npmmirror.com
8
+ if ($LASTEXITCODE -ne 0) {
9
+ Write-Warning "Expo 项目依赖安装失败"
10
+ }
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
  if [ -z "${BASH_VERSION:-}" ]; then exec /usr/bin/env bash "$0" "$@"; fi
3
3
  set -euo pipefail
4
- ROOT_DIR="$(pwd)"
4
+ ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
5
5
  PREVIEW_DIR="/source/preview"
6
6
  SOURCE_DIR="/source"
7
7
 
@@ -34,8 +34,8 @@ echo "==================== 安装项目依赖 ===================="
34
34
  if [ ! -f "package.json" ]; then
35
35
  echo "项目目录下无 package.json,不是合法的 Node.js 项目"
36
36
  fi
37
- # 步骤 2.1/2.2:安装项目依赖
38
- pnpm install --registry=https://registry.npmmirror.com || echo "Expo 项目依赖安装失败(pnpm 执行出错)"
37
+ # 步骤 2.1/2.2:通过受管入口安装项目依赖
38
+ bash "$ROOT_DIR/.cozeproj/scripts/prepare-node-modules.sh" --registry=https://registry.npmmirror.com
39
39
 
40
40
  echo "检查根目录 post_install.py"
41
41
  if [ -f "$PREVIEW_DIR/post_install.py" ]; then
@@ -0,0 +1,74 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ function Stop-ProcessTree([int] $processId) {
4
+ if ($processId -gt 0 -and (Get-Process -Id $processId -ErrorAction SilentlyContinue)) {
5
+ & taskkill.exe /PID $processId /T /F *> $null
6
+ }
7
+ }
8
+
9
+ function Stop-ListeningProcess([int] $port) {
10
+ Get-NetTCPConnection -LocalPort $port -State Listen -ErrorAction SilentlyContinue |
11
+ Select-Object -ExpandProperty OwningProcess -Unique |
12
+ ForEach-Object { Stop-ProcessTree $_ }
13
+ }
14
+
15
+ function Start-LoggedProcess([string] $workingDirectory, [string] $logFile, [string[]] $arguments, [hashtable] $environment) {
16
+ $previousEnvironment = @{}
17
+ foreach ($key in $environment.Keys) {
18
+ $previousEnvironment[$key] = [Environment]::GetEnvironmentVariable($key, 'Process')
19
+ [Environment]::SetEnvironmentVariable($key, $environment[$key], 'Process')
20
+ }
21
+
22
+ try {
23
+ return Start-Process -FilePath "pnpm.cmd" -ArgumentList $arguments -WorkingDirectory $workingDirectory -RedirectStandardOutput $logFile -RedirectStandardError "$logFile.error" -PassThru
24
+ } finally {
25
+ foreach ($key in $environment.Keys) {
26
+ [Environment]::SetEnvironmentVariable($key, $previousEnvironment[$key], 'Process')
27
+ }
28
+ }
29
+ }
30
+
31
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
32
+ $serverPort = if ($env:SERVER_PORT) { [int] $env:SERVER_PORT } else { <%= serverPort %> }
33
+ $expoPort = if ($env:DEPLOY_RUN_PORT) { [int] $env:DEPLOY_RUN_PORT } elseif ($env:EXPO_PORT) { [int] $env:EXPO_PORT } else { <%= port %> }
34
+ $logDirectory = if ($env:COZE_LOG_DIR) { $env:COZE_LOG_DIR } else { Join-Path $workspace "logs" }
35
+ $serverLog = Join-Path $logDirectory "server.log"
36
+ $clientLog = Join-Path $logDirectory "client.log"
37
+ New-Item -ItemType Directory -Force -Path $logDirectory | Out-Null
38
+
39
+ Stop-ListeningProcess $serverPort
40
+ Stop-ListeningProcess $expoPort
41
+
42
+ $webUrl = if ($env:COZE_PROJECT_DOMAIN_DEFAULT) {
43
+ $env:COZE_PROJECT_DOMAIN_DEFAULT
44
+ } elseif ($env:COZE_HARDWARE_DID) {
45
+ "https://cozedaemon-$($env:COZE_HARDWARE_DID)-$expoPort.dev.coze.site"
46
+ } else {
47
+ "http://127.0.0.1:$serverPort"
48
+ }
49
+
50
+ $sharedEnvironment = @{
51
+ EXPO_PUBLIC_BACKEND_BASE_URL = $webUrl
52
+ EXPO_PACKAGER_PROXY_URL = $webUrl
53
+ EXPO_PUBLIC_COZE_PROJECT_ID = $env:COZE_PROJECT_ID
54
+ }
55
+
56
+ Write-Host "Starting server on port $serverPort..."
57
+ $server = Start-LoggedProcess (Join-Path $workspace "server") $serverLog @("exec", "tsx", "watch", "./src/index.ts") (@{ NODE_ENV = "development"; PORT = "$serverPort" })
58
+
59
+ Write-Host "Starting Expo on port $expoPort..."
60
+ $expoEnvironment = @{}
61
+ $sharedEnvironment.GetEnumerator() | ForEach-Object { $expoEnvironment[$_.Key] = $_.Value }
62
+ $expoEnvironment.EXPO_NO_DEPENDENCY_VALIDATION = "1"
63
+ $expo = Start-LoggedProcess (Join-Path $workspace "client") $clientLog @("exec", "expo", "start", "--web", "--clear", "--port", "$expoPort") $expoEnvironment
64
+
65
+ Start-Sleep -Seconds 8
66
+ if ((Test-Path $clientLog) -and (Select-String -Path $clientLog -Pattern "TypeError: fetch failed" -Quiet)) {
67
+ Write-Host "Expo 启动检测到网络错误,启用离线模式重试"
68
+ Stop-ProcessTree $expo.Id
69
+ $expoEnvironment.EXPO_OFFLINE = "1"
70
+ $expo = Start-LoggedProcess (Join-Path $workspace "client") $clientLog @("exec", "expo", "start", "--web", "--clear", "--port", "$expoPort") $expoEnvironment
71
+ }
72
+
73
+ Write-Host "服务已启动。Server PID: $($server.Id), Expo PID: $($expo.Id)"
74
+ Write-Host "EXPO_PUBLIC_BACKEND_BASE_URL=$webUrl"
@@ -135,6 +135,7 @@ shift
135
135
  child_pid=$!
136
136
 
137
137
  # 先忽略 TERM,才能在向整组发 TERM(自己也在组里)之后存活下来补一发 KILL。
138
+ if [[ -z "${COZE_EVAL:-}" && -z "${COZE_PROJECT_TYPE:-}" ]]; then
138
139
  ( trap "" TERM
139
140
  sleep "${timeout_seconds}"
140
141
  echo "[dev] 后台进程运行超过 ${timeout_seconds}s,回收进程组 $$。"
@@ -142,6 +143,7 @@ child_pid=$!
142
143
  sleep 5
143
144
  kill -KILL -- "-$$" 2>/dev/null || true
144
145
  ) &
146
+ fi
145
147
 
146
148
  wait "${child_pid}"
147
149
  kill -KILL -- "-$$" 2>/dev/null || true
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env bash
2
+ # Install dependencies on local disk and expose them to the source tree by symlink.
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
6
+ if [ "$(basename "$(dirname "$SCRIPT_DIR")")" = ".cozeproj" ]; then
7
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd -P)"
8
+ else
9
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
10
+ fi
11
+
12
+ command -v pnpm >/dev/null 2>&1 || {
13
+ echo "[node_modules] pnpm is required" >&2
14
+ exit 1
15
+ }
16
+
17
+ DRIVE_ROOT="${COZE_DRIVE_ROOT:-/Coze/Drive}"
18
+ if [ -d "$DRIVE_ROOT" ]; then
19
+ DRIVE_ROOT="$(cd "$DRIVE_ROOT" && pwd -P)"
20
+ else
21
+ DRIVE_ROOT="${DRIVE_ROOT%/}"
22
+ fi
23
+ case "$PROJECT_ROOT" in
24
+ "$DRIVE_ROOT"|"$DRIVE_ROOT"/*) ;;
25
+ *)
26
+ (cd "$PROJECT_ROOT" && pnpm install "$@")
27
+ exit 0
28
+ ;;
29
+ esac
30
+
31
+ NM_ROOT="/tmp/nm"
32
+ PROJECT_ID="$(basename "$PROJECT_ROOT")-$(printf '%s' "$PROJECT_ROOT" | cksum | awk '{print $1}')"
33
+ mkdir -p "$NM_ROOT"
34
+ WORK_DIR="$NM_ROOT/$PROJECT_ID"
35
+ case "$WORK_DIR" in
36
+ "$DRIVE_ROOT"|"$DRIVE_ROOT"/*)
37
+ echo "[node_modules] local dependency directory must not be on Coze Drive: $WORK_DIR" >&2
38
+ exit 1
39
+ ;;
40
+ esac
41
+
42
+ LOCK_DIR="$NM_ROOT/$PROJECT_ID.lock"
43
+ while ! mkdir "$LOCK_DIR" 2>/dev/null; do
44
+ echo "[node_modules] Waiting for another dependency preparation for this project..."
45
+ sleep 1
46
+ done
47
+ trap 'rmdir "$LOCK_DIR" 2>/dev/null || true' EXIT
48
+
49
+ mkdir -p "$WORK_DIR"
50
+
51
+ # Previous versions mirrored the whole project into WORK_DIR. That gives pnpm
52
+ # and framework dev servers two paths for the same source tree, which breaks
53
+ # file watching and on-demand compilation. Keep only managed local outputs.
54
+ cleanup_legacy_workspace() {
55
+ local workspace_dir="$1" entry name
56
+ if [ -L "$workspace_dir" ] || { [ -e "$workspace_dir" ] && [ ! -d "$workspace_dir" ]; }; then
57
+ rm -rf "$workspace_dir"
58
+ return
59
+ fi
60
+ if [ ! -d "$workspace_dir" ]; then
61
+ return 0
62
+ fi
63
+
64
+ while IFS= read -r -d '' entry; do
65
+ name="$(basename "$entry")"
66
+ [ "$name" = "node_modules" ] || rm -rf "$entry"
67
+ done < <(find "$workspace_dir" -mindepth 1 -maxdepth 1 -print0)
68
+ }
69
+
70
+ cleanup_legacy_shadow_project() {
71
+ local entry name
72
+ while IFS= read -r -d '' entry; do
73
+ name="$(basename "$entry")"
74
+ case "$name" in
75
+ node_modules|.next|client|server) continue ;;
76
+ esac
77
+ rm -rf "$entry"
78
+ done < <(find "$WORK_DIR" -mindepth 1 -maxdepth 1 -print0)
79
+
80
+ for workspace in client server; do
81
+ cleanup_legacy_workspace "$WORK_DIR/$workspace"
82
+ done
83
+ }
84
+
85
+ copy_install_metadata() {
86
+ local filename source_file target_file workspace
87
+ for filename in package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc; do
88
+ source_file="$PROJECT_ROOT/$filename"
89
+ target_file="$WORK_DIR/$filename"
90
+ rm -f "$target_file"
91
+ if [ -f "$source_file" ]; then
92
+ cp "$source_file" "$target_file"
93
+ fi
94
+ done
95
+
96
+ for workspace in client server; do
97
+ if [ -f "$PROJECT_ROOT/$workspace/package.json" ]; then
98
+ mkdir -p "$WORK_DIR/$workspace"
99
+ rm -f "$WORK_DIR/$workspace/package.json"
100
+ cp "$PROJECT_ROOT/$workspace/package.json" "$WORK_DIR/$workspace/package.json"
101
+ else
102
+ rm -rf "$WORK_DIR/$workspace"
103
+ fi
104
+ done
105
+ }
106
+
107
+ link_node_modules() {
108
+ local source_dir="$1" target_dir="$2"
109
+ local current=""
110
+ mkdir -p "$target_dir"
111
+ if [ -L "$source_dir/node_modules" ]; then
112
+ current="$(readlink "$source_dir/node_modules")"
113
+ case "$current" in
114
+ "$NM_ROOT"/*/node_modules|"$NM_ROOT"/*/*/node_modules) ;;
115
+ *)
116
+ echo "[node_modules] refusing to replace unmanaged symlink: $source_dir/node_modules" >&2
117
+ exit 1
118
+ ;;
119
+ esac
120
+ rm "$source_dir/node_modules"
121
+ elif [ -e "$source_dir/node_modules" ]; then
122
+ rm -rf "$source_dir/node_modules"
123
+ fi
124
+ ln -s "$target_dir" "$source_dir/node_modules"
125
+ }
126
+
127
+ cleanup_legacy_shadow_project
128
+ copy_install_metadata
129
+
130
+ echo "[node_modules] Installing dependencies in $WORK_DIR"
131
+ if ! (cd "$WORK_DIR" && pnpm install "$@"); then
132
+ exit 1
133
+ fi
134
+
135
+ if [ -f "$WORK_DIR/pnpm-lock.yaml" ]; then
136
+ temporary_lockfile="$(mktemp "$PROJECT_ROOT/.pnpm-lock.yaml.XXXXXX")"
137
+ cp "$WORK_DIR/pnpm-lock.yaml" "$temporary_lockfile"
138
+ chmod 0644 "$temporary_lockfile"
139
+ mv -f "$temporary_lockfile" "$PROJECT_ROOT/pnpm-lock.yaml"
140
+ fi
141
+
142
+ link_node_modules "$PROJECT_ROOT" "$WORK_DIR/node_modules"
143
+ for workspace in client server; do
144
+ if [ -f "$PROJECT_ROOT/$workspace/package.json" ]; then
145
+ link_node_modules "$PROJECT_ROOT/$workspace" "$WORK_DIR/$workspace/node_modules"
146
+ fi
147
+ done
148
+
149
+ echo "[node_modules] Dependencies ready"
@@ -1,7 +1,7 @@
1
1
  #!/bin/bash
2
2
  if [ -z "${BASH_VERSION:-}" ]; then exec /usr/bin/env bash "$0" "$@"; fi
3
3
  set -euo pipefail
4
- ROOT_DIR="$(pwd)"
4
+ ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
5
5
 
6
6
  # ==================== 工具函数 ====================
7
7
  info() {
@@ -32,8 +32,8 @@ info "==================== 安装 Node 依赖 ===================="
32
32
  info "开始安装 Node 依赖"
33
33
  if [ -f "$ROOT_DIR/package.json" ]; then
34
34
  info "进入目录:$ROOT_DIR"
35
- info "正在执行:pnpm install"
36
- (cd "$ROOT_DIR" && pnpm install --registry=https://registry.npmmirror.com) || error "Node 依赖安装失败"
35
+ info "正在执行受管依赖准备入口"
36
+ bash "$ROOT_DIR/.cozeproj/scripts/prepare-node-modules.sh" --registry=https://registry.npmmirror.com || error "Node 依赖安装失败"
37
37
  else
38
38
  warn "未找到 $ROOT_DIR/package.json 文件,请检查路径是否正确"
39
39
  fi
@@ -0,0 +1,7 @@
1
+ $ErrorActionPreference = "Stop"
2
+
3
+ $workspace = if ($env:COZE_WORKSPACE_PATH) { $env:COZE_WORKSPACE_PATH } else { (Get-Location).Path }
4
+ Set-Location $workspace
5
+
6
+ & pnpm validate
7
+ exit $LASTEXITCODE
@@ -6,13 +6,19 @@ import {
6
6
  View,
7
7
  TouchableWithoutFeedback,
8
8
  Keyboard,
9
- ViewStyle,
9
+ type ViewStyle,
10
10
  FlatList,
11
+ type FlatListProps,
11
12
  SectionList,
13
+ type SectionListProps,
14
+ type ScrollViewProps,
12
15
  Modal,
13
16
  } from 'react-native';
14
17
  import { withUniwind } from 'uniwind';
15
- import { useSafeAreaInsets, Edge } from 'react-native-safe-area-context';
18
+ import {
19
+ useSafeAreaInsets,
20
+ type Edge,
21
+ } from 'react-native-safe-area-context';
16
22
  import { StatusBar } from 'expo-status-bar';
17
23
  // 引入 KeyboardAware 系列组件
18
24
  import {
@@ -86,58 +92,92 @@ type KeyboardAwareProps = {
86
92
  contentInsetBehaviorIOS: 'automatic' | 'never';
87
93
  };
88
94
 
95
+ type NativeScrollableProps = Pick<
96
+ ScrollViewProps,
97
+ | 'contentContainerStyle'
98
+ | 'keyboardShouldPersistTaps'
99
+ | 'keyboardDismissMode'
100
+ | 'contentInsetAdjustmentBehavior'
101
+ >;
102
+
89
103
  const KeyboardAwareScrollable = ({
90
104
  element,
91
105
  extraPadding,
92
106
  contentInsetBehaviorIOS,
93
107
  }: KeyboardAwareProps) => {
94
- // 获取原始组件的 props
95
- const childAttrs = ((element as React.ReactElement).props ?? {}) as Record<string, unknown>;
96
- const originStyle = childAttrs['contentContainerStyle'];
97
- const styleArray = Array.isArray(originStyle) ? originStyle : originStyle ? [originStyle] : [];
98
- const merged = Object.assign({}, ...styleArray);
99
- const currentPB = typeof merged.paddingBottom === 'number' ? merged.paddingBottom : 0;
108
+ const createEnhancedContentStyle = (
109
+ contentContainerStyle: ScrollViewProps['contentContainerStyle'],
110
+ ) => {
111
+ const mergedStyle = StyleSheet.flatten(contentContainerStyle) ?? {};
112
+ const currentPaddingBottom =
113
+ typeof mergedStyle.paddingBottom === 'number'
114
+ ? mergedStyle.paddingBottom
115
+ : 0;
100
116
 
101
- // 合并 paddingBottom (安全区 + 额外留白)
102
- const enhancedContentStyle = [{ ...merged, paddingBottom: currentPB + extraPadding }];
117
+ return [
118
+ {
119
+ ...mergedStyle,
120
+ paddingBottom: currentPaddingBottom + extraPadding,
121
+ },
122
+ ];
123
+ };
103
124
 
104
- // 基础配置 props,用于传递给 KeyboardAware 组件
105
- const commonProps = {
106
- ...childAttrs,
107
- contentContainerStyle: enhancedContentStyle,
108
- keyboardShouldPersistTaps: childAttrs['keyboardShouldPersistTaps'] ?? 'handled',
109
- keyboardDismissMode: childAttrs['keyboardDismissMode'] ?? 'on-drag',
125
+ const createKeyboardAwareProps = <Props extends NativeScrollableProps>(
126
+ childProps: Props,
127
+ ) => ({
128
+ ...childProps,
129
+ contentContainerStyle: createEnhancedContentStyle(
130
+ childProps.contentContainerStyle,
131
+ ),
132
+ keyboardShouldPersistTaps:
133
+ childProps.keyboardShouldPersistTaps ?? 'handled',
134
+ keyboardDismissMode: childProps.keyboardDismissMode ?? 'on-drag',
110
135
  enableOnAndroid: true,
111
136
  // 类似于原代码中的 setTimeout/scrollToEnd 逻辑,这里设置额外的滚动高度确保输入框可见
112
137
  extraHeight: 100,
113
138
  // 禁用自带的 ScrollView 自动 inset,由外部 padding 控制
114
139
  enableAutomaticScroll: true,
115
140
  ...(Platform.OS === 'ios'
116
- ? { contentInsetAdjustmentBehavior: childAttrs['contentInsetAdjustmentBehavior'] ?? contentInsetBehaviorIOS }
141
+ ? {
142
+ contentInsetAdjustmentBehavior:
143
+ childProps.contentInsetAdjustmentBehavior ??
144
+ contentInsetBehaviorIOS,
145
+ }
117
146
  : {}),
118
- };
147
+ });
119
148
 
120
- const t = (element as React.ReactElement).type;
149
+ const t = element.type;
121
150
 
122
151
  // 根据组件类型返回对应的 KeyboardAware 版本
123
152
  // 注意:不再使用 KeyboardAvoidingView,直接替换为增强版 ScrollView
124
153
  if (t === ScrollView) {
125
- return <KeyboardAwareScrollView {...commonProps} />;
154
+ const childProps = element.props as ScrollViewProps;
155
+ return (
156
+ <KeyboardAwareScrollView {...createKeyboardAwareProps(childProps)} />
157
+ );
126
158
  }
127
159
 
128
160
  if (t === FlatList) {
129
- return <KeyboardAwareFlatList {...commonProps} />;
161
+ const childProps = element.props as FlatListProps<unknown>;
162
+ return <KeyboardAwareFlatList {...createKeyboardAwareProps(childProps)} />;
130
163
  }
131
164
 
132
165
  if (t === SectionList) {
133
- return <KeyboardAwareSectionList {...commonProps} />;
166
+ const childProps = element.props as SectionListProps<unknown>;
167
+ return (
168
+ <KeyboardAwareSectionList {...createKeyboardAwareProps(childProps)} />
169
+ );
134
170
  }
135
171
 
136
172
  // 理论上不应运行到这里,如果是非标准组件则原样返回,仅修改样式
173
+ const childProps = element.props as NativeScrollableProps;
137
174
  return React.cloneElement(element, {
138
- contentContainerStyle: enhancedContentStyle,
139
- keyboardShouldPersistTaps: childAttrs['keyboardShouldPersistTaps'] ?? 'handled',
140
- keyboardDismissMode: childAttrs['keyboardDismissMode'] ?? 'on-drag',
175
+ contentContainerStyle: createEnhancedContentStyle(
176
+ childProps.contentContainerStyle,
177
+ ),
178
+ keyboardShouldPersistTaps:
179
+ childProps.keyboardShouldPersistTaps ?? 'handled',
180
+ keyboardDismissMode: childProps.keyboardDismissMode ?? 'on-drag',
141
181
  });
142
182
  };
143
183
 
@@ -1,5 +1,9 @@
1
1
  import React, { forwardRef, useMemo } from 'react';
2
- import { View, Text as RNText } from 'react-native';
2
+ import {
3
+ type GestureResponderEvent,
4
+ View,
5
+ Text as RNText,
6
+ } from 'react-native';
3
7
  import { GestureDetector } from 'react-native-gesture-handler';
4
8
  import Animated from 'react-native-reanimated';
5
9
  import { useThemeColor } from '../../helpers/external/hooks';
@@ -339,7 +343,7 @@ const ToastClose = forwardRef<View, ToastCloseProps>((props, ref) => {
339
343
  * If hide and id are available from context, use them to hide the toast
340
344
  * Otherwise, use the provided onPress handler
341
345
  */
342
- const handlePress = (event: Parameters<NonNullable<React.ComponentProps<typeof Button>['onPress']>>[0]) => {
346
+ const handlePress = (event: GestureResponderEvent) => {
343
347
  if (hide && id) {
344
348
  hide(id);
345
349
  }
@@ -108,7 +108,7 @@ function useUncontrolledState<T>({
108
108
  * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a
109
109
  * prop or avoid re-executing effects when passed as a dependency
110
110
  */
111
- function useCallbackRef<T extends (...args: unknown[]) => unknown>(
111
+ function useCallbackRef<T extends (...args: never[]) => unknown>(
112
112
  callback: T | undefined
113
113
  ): T {
114
114
  const callbackRef = useRef(callback);
@@ -269,8 +269,8 @@ importers:
269
269
  specifier: ^2.8.5
270
270
  version: 2.8.6
271
271
  coze-coding-dev-sdk:
272
- specifier: ^0.7.25
273
- version: 0.7.25(openai@6.16.0(ws@8.19.0)(zod@4.3.6))(ws@8.19.0)
272
+ specifier: ^0.7.28
273
+ version: 0.7.28(openai@6.16.0(ws@8.19.0)(zod@4.3.6))(ws@8.19.0)
274
274
  dayjs:
275
275
  specifier: ^1.11.20
276
276
  version: 1.11.20
@@ -2643,8 +2643,8 @@ packages:
2643
2643
  resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
2644
2644
  engines: {node: '>=10'}
2645
2645
 
2646
- coze-coding-dev-sdk@0.7.25:
2647
- resolution: {integrity: sha512-5683ngikMdsRW0slGTE2OAZ1Fyj0lhkC4fGNOwsqKc35e68/gtg9KmmtK9CK9SZ+5/oIn/4wLoHXFB0gHJtO2A==}
2646
+ coze-coding-dev-sdk@0.7.28:
2647
+ resolution: {integrity: sha512-ku7AiVWUmgCrUuMT1m2iTmHIwG39EfmcAhPASd8M7XyKxIC6A1cjIIe/3YpStRsj8pMF9LU+pxHWxisf+F44oQ==}
2648
2648
  engines: {node: '>=18.0.0'}
2649
2649
  hasBin: true
2650
2650
 
@@ -9088,7 +9088,7 @@ snapshots:
9088
9088
  path-type: 4.0.0
9089
9089
  yaml: 1.10.2
9090
9090
 
9091
- coze-coding-dev-sdk@0.7.25(openai@6.16.0(ws@8.19.0)(zod@4.3.6))(ws@8.19.0):
9091
+ coze-coding-dev-sdk@0.7.28(openai@6.16.0(ws@8.19.0)(zod@4.3.6))(ws@8.19.0):
9092
9092
  dependencies:
9093
9093
  '@langchain/core': 1.1.17(openai@6.16.0(ws@8.19.0)(zod@4.3.6))
9094
9094
  '@langchain/openai': 1.2.3(@langchain/core@1.1.17(openai@6.16.0(ws@8.19.0)(zod@4.3.6)))(ws@8.19.0)
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "@supabase/supabase-js": "2.95.3",
14
14
  "cors": "^2.8.5",
15
- "coze-coding-dev-sdk": "^0.7.25",
15
+ "coze-coding-dev-sdk": "^0.7.28",
16
16
  "dayjs": "^1.11.20",
17
17
  "dotenv": "^17.2.3",
18
18
  "drizzle-orm": "^0.45.1",
@@ -23,6 +23,11 @@ const eslintConfig = defineConfig([
23
23
  ...nextVitals,
24
24
  ...nextTs,
25
25
  {
26
+ settings: {
27
+ // node_modules 里的 barrel 包(lucide-react 等)不参与 ExportMap 构建,
28
+ // import/no-cycle 只需要项目源码的依赖图。
29
+ 'import/ignore': ['/node_modules/'],
30
+ },
26
31
  rules: {
27
32
  'import/no-cycle': ['error', { ignoreExternal: true }],
28
33
  'react-hooks/set-state-in-effect': 'off',
@@ -37,14 +42,15 @@ const eslintConfig = defineConfig([
37
42
  },
38
43
  // Override default ignores of eslint-config-next.
39
44
  globalIgnores([
40
- // Default ignores of eslint-config-next:
41
- '.next/**',
42
- 'out/**',
43
- 'build/**',
45
+ // Default ignores of eslint-config-next (trailing slash prunes the whole
46
+ // directory instead of walking into it):
47
+ '.next/',
48
+ 'out/',
49
+ 'build/',
44
50
  'next-env.d.ts',
45
51
  // Build artifacts:
46
52
  'server.js',
47
- 'dist/**',
53
+ 'dist/',
48
54
  // Script files (CommonJS):
49
55
  'scripts/**/*.js',
50
56
  ]),
@@ -1,8 +1,18 @@
1
1
  import type { NextConfig } from 'next';
2
+ import path from 'path';
2
3
 
3
4
  const nextConfig: NextConfig = {
4
5
  // outputFileTracingRoot: path.resolve(__dirname, '../../'), // Uncomment and add 'import path from "path"' if needed
5
6
  /* config options here */
7
+ serverExternalPackages: ['coze-coding-dev-sdk'],
8
+ webpack: (config, { dev }) => {
9
+ if (dev && config.cache && config.cache.type === 'filesystem') {
10
+ config.cache.cacheDirectory = path.resolve(
11
+ 'node_modules/.cache/next-webpack',
12
+ );
13
+ }
14
+ return config;
15
+ },
6
16
  allowedDevOrigins: ['*.dev.coze.site'],
7
17
  images: {
8
18
  remotePatterns: [
@@ -6,7 +6,7 @@
6
6
  "build": "bash ./scripts/build.sh",
7
7
  "dev": "bash ./scripts/dev.sh",
8
8
  "preinstall": "npx only-allow pnpm",
9
- "lint": "eslint",
9
+ "lint": "eslint --cache --cache-location node_modules/.cache/eslint/",
10
10
  "lint:build": "eslint . --quiet",
11
11
  "lint:style": "stylelint \"src/**/*.css\"",
12
12
  "start": "bash ./scripts/start.sh",
@@ -47,7 +47,7 @@
47
47
  "class-variance-authority": "^0.7.1",
48
48
  "clsx": "^2.1.1",
49
49
  "cmdk": "^1.1.1",
50
- "coze-coding-dev-sdk": "^0.7.25",
50
+ "coze-coding-dev-sdk": "^0.7.28",
51
51
  "date-fns": "^4.1.0",
52
52
  "dotenv": "^17.2.3",
53
53
  "drizzle-kit": "^0.31.8",
@@ -73,17 +73,14 @@
73
73
  "zod": "^4.3.5"
74
74
  },
75
75
  "devDependencies": {
76
- "@react-dev-inspector/babel-plugin": "^2.0.1",
77
- "@react-dev-inspector/middleware": "^2.0.1",
78
76
  "@tailwindcss/postcss": "^4",
79
77
  "@types/node": "^20",
80
78
  "@types/pg": "^8.16.0",
81
79
  "@types/react": "^19",
82
80
  "@types/react-dom": "^19",
83
81
  "eslint": "^9",
84
- "eslint-config-next": "16.3.3",
82
+ "eslint-config-next": "16.1.1",
85
83
  "only-allow": "^1.2.2",
86
- "react-dev-inspector": "^2.0.1",
87
84
  "shadcn": "latest",
88
85
  "stylelint": "^16.4.0",
89
86
  "stylelint-config-standard": "^38.0.0",