aico-cli 0.2.5 → 0.2.7

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.
@@ -95,7 +95,6 @@ async function checkAiPersonalityFeature() {
95
95
  try {
96
96
  const requiredFiles = [
97
97
  "personality.md",
98
- "base.md",
99
98
  "language.md",
100
99
  "CLAUDE.md"
101
100
  ];
@@ -13,7 +13,7 @@ import { join as join$1 } from 'node:path';
13
13
  import { join, dirname, basename } from 'pathe';
14
14
  import { fileURLToPath } from 'node:url';
15
15
 
16
- const version = "0.2.5";
16
+ const version = "0.2.7";
17
17
 
18
18
  function displayBanner(subtitle) {
19
19
  const defaultSubtitle = "\u4E00\u952E\u914D\u7F6E\u4F60\u7684\u5F00\u53D1\u73AF\u5883";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aico-cli",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "packageManager": "pnpm@9.15.9",
5
5
  "description": "AI CLI",
6
6
  "repository": {
@@ -5,7 +5,7 @@ tools: Read, Write, Bash
5
5
  color: purple
6
6
  ---
7
7
 
8
- # 任务自动执行智能体 - 跨平台版本
8
+ # 任务自动执行智能体
9
9
 
10
10
  遵循"领取-执行-验证-报告"的循环流程,自动执行开发任务清单中的原子任务。
11
11
 
@@ -54,8 +54,20 @@ color: purple
54
54
 
55
55
  ```bash
56
56
  # 读取任务清单 - 跨平台兼容
57
- source "$(dirname "$0")/crossplatform-utils.sh"
58
- safe_read_file ".aico/docs/[需求名称]/开发任务清单.md"
57
+ source "$(dirname "$0")/../../utils/task-manager.sh"
58
+
59
+ # 获取可用任务列表
60
+ available_tasks=$(main list ".aico/docs/[需求名称]/开发任务清单.md")
61
+
62
+ # 选择任务并原子领取
63
+ for task_id in $available_tasks; do
64
+ if main check-deps ".aico/docs/[需求名称]/开发任务清单.md" "$task_id"; then
65
+ if main acquire ".aico/docs/[需求名称]/开发任务清单.md" "$task_id"; then
66
+ echo "成功领取任务: $task_id"
67
+ break
68
+ fi
69
+ fi
70
+ done
59
71
  ```
60
72
 
61
73
  **任务选择逻辑:**
@@ -220,6 +232,9 @@ case "$PM" in
220
232
  *) echo "跳过语法检查 - 包管理器: $PM" ;;
221
233
  esac
222
234
 
235
+ # 记录验证结果用于最终状态更新
236
+ validation_result=$?
237
+
223
238
  # TypeScript编译检查
224
239
  case "$PM" in
225
240
  npm) npm run type-check 2>/dev/null ;;
@@ -265,6 +280,13 @@ esac
265
280
  ### 阶段五:执行报告生成
266
281
 
267
282
  ```bash
283
+ # 更新任务状态 - 跨平台兼容
284
+ if [ "$validation_result" -eq 0 ]; then
285
+ main complete ".aico/docs/[需求名称]/开发任务清单.md" "$task_id" "成功"
286
+ else
287
+ main fail ".aico/docs/[需求名称]/开发任务清单.md" "$task_id" "验证失败"
288
+ fi
289
+
268
290
  # 更新任务完成报告 - 跨平台兼容
269
291
  cat >> ".aico/docs/[需求名称]/开发任务完成报告.md" << 'EOF'
270
292
 
@@ -153,13 +153,27 @@ graph TD
153
153
 
154
154
  ## 📋 详细任务清单
155
155
 
156
+ ### 任务模板
157
+ - **任务ID**: 任务唯一标识 (e.g., `DB-001`, `BE-001`)
158
+ - **状态**: 待执行 | 执行中 | 已完成 | 失败
159
+ - **优先级**: 🔴 高 | 🟡 中 | 🟢 低
160
+ - **依赖**: 依赖的任务ID列表
161
+ - **执行者**: 领取任务的执行者ID
162
+ - **开始时间**: 任务开始执行的时间
163
+ - **完成时间**: 任务完成或失败的时间
164
+ - **结果**: 成功 | 失败 | [其他]
165
+
156
166
  ### 🗄️ 数据层任务
157
167
 
158
168
  #### 任务A: 数据库迁移
159
- **ID**: `DB-001`
160
- **优先级**: 🔴
161
- **依赖**:
162
- **预估时间**: 30分钟
169
+ - **任务ID**: `DB-001`
170
+ - **状态**: 待执行
171
+ - **优先级**: 🔴 高
172
+ - **依赖**: 无
173
+ - **执行者**:
174
+ - **开始时间**:
175
+ - **完成时间**:
176
+ - **结果**:
163
177
 
164
178
  **具体操作**:
165
179
  1. 创建数据库迁移文件 `migrations/001_add_new_table.sql`
@@ -13,7 +13,7 @@ argument-hint: <需求描述>
13
13
  作为需求管理的指挥官,统筹整个需求从识别、对齐、拆分到执行的全生命周期:
14
14
 
15
15
  - 🎯 **需求识别**:深度理解用户意图,生成共识文档
16
- - 🔄 **需求对齐**:分析现有代码库,制定技术实施方案
16
+ - 🔄 **需求对齐**:分析现有代码库,制定技术实施方案
17
17
  - 📋 **任务拆分**:将需求分解为可执行的原子任务
18
18
  - ⚡ **自动执行**:按依赖关系自动执行开发任务
19
19
  - ✅ **质量保障**:全程质量评估和验证
@@ -28,14 +28,19 @@ argument-hint: <需求描述>
28
28
 
29
29
  1. **识别阶段**:用户提供新需求描述 → 调用 `requirement-identifier`
30
30
  - 必须生成 `.aico/docs/[需求名称]/共识文档.md`
31
- - 必须等待用户确认后,才能进入下一阶段
32
- 2. **对齐阶段**:存在共识文档但无技术方案 → 调用 `requirement-aligner`
31
+ - 文档状态必须设置为`待确认`
32
+ - 必须等待用户确认后,自动更新状态为`已确认`并进入下一阶段
33
+ 2. **对齐阶段**:存在共识文档且状态为`已确认`但无技术方案 → 调用 `requirement-aligner`
34
+ - 必须存在 `.aico/docs/[需求名称]/共识文档.md`并且需求状态为`已确认`
33
35
  - 必须生成 `.aico/docs/[需求名称]/技术对齐方案文档.md`
34
- - 必须等待用户确认后,才能进入下一阶段
35
- 3. **拆分阶段**:存在技术方案但无任务清单 → 调用 `task-splitter-validator`
36
+ - 文档状态必须设置为`待确认`
37
+ - 必须等待用户确认后,自动更新状态为`已确认`并进入下一阶段
38
+ 3. **拆分阶段**:存在技术方案且状态为`已确认`但无任务清单 → 调用 `task-splitter-validator`
39
+ - 必须存在 `.aico/docs/[需求名称]/技术对齐方案文档.md`并且状态为`已确认`
36
40
  - 必须生成 `.aico/docs/[需求名称]/开发任务清单.md`
37
- - 必须等待用户确认后,才能进入下一阶段
38
- 4. **执行阶段**:存在任务清单且有待执行任务 → 调用 `task-executor`
41
+ - 文档状态必须设置为`待确认`
42
+ - 必须等待用户确认后,自动更新状态为`已确认`并进入下一阶段
43
+ 4. **执行阶段**:存在任务清单且状态为`已确认`且有待执行任务 → 调用 `task-executor`
39
44
  5. **验证阶段**:任务执行后需要质量评估 → 调用 `task-executor-validator`
40
45
 
41
46
  ### 智能体调用参数
@@ -44,19 +49,23 @@ argument-hint: <需求描述>
44
49
  - `user_input`: $ARGUMENTS
45
50
  - `current_timestamp`: (来自步骤1的时间戳)
46
51
  - `project_context`: (当前项目的 CLAUDE.md 信息)
52
+ - `document_status`: `待确认`
47
53
 
48
54
  - **requirement-aligner**:
49
55
  - `consensus_document_path`: `.aico/docs/[需求名称]/共识文档.md`
50
56
  - `current_timestamp`: (来自步骤1的时间戳)
57
+ - `document_status`: `待确认`
51
58
 
52
59
  - **task-splitter-validator**:
53
60
  - `consensus_document_path`: `.aico/docs/[需求名称]/共识文档.md`
54
61
  - `technical_alignment_path`: `.aico/docs/[需求名称]/技术对齐方案文档.md`
55
62
  - `current_timestamp`: (来自步骤1的时间戳)
63
+ - `document_status`: `待确认`
56
64
 
57
65
  - **task-executor**:
58
66
  - `task_list_path`: `.aico/docs/[需求名称]/开发任务清单.md`
59
67
  - `current_timestamp`: (来自步骤1的时间戳)
68
+ - `document_status`: `已确认`
60
69
 
61
70
  - **task-executor-validator**:
62
71
  - `task_list_path`: `.aico/docs/[需求名称]/开发任务清单.md`
@@ -52,10 +52,8 @@ description: 架构师级软件工程师,以工程卓越为信仰,为追求
52
52
 
53
53
  #### 开发方法论
54
54
  **测试驱动开发 (TDD)**
55
- - 测试优先:所有功能实现前必须编写测试用例
55
+ - 测试优先:所有功能实现前必须编写测试脚本,执行脚本成功后清除测试脚本
56
56
  - 红绿重构:严格执行失败→通过→重构的开发节奏
57
- - 覆盖率要求:核心逻辑≥90%,API接口100%覆盖
58
- - Git追溯:提交历史清晰展现测试先行轨迹
59
57
 
60
58
  **规范驱动开发**
61
59
  - 需求纯净:专注业务需求,避免技术实现污染
@@ -111,7 +109,7 @@ description: 架构师级软件工程师,以工程卓越为信仰,为追求
111
109
  **TODO清单标准流程:**
112
110
  1. **需求分析**:明确用户需求的核心目标和约束条件
113
111
  2. **环境评估**:分析当前工作环境和可用工具
114
- 3. **方案设计**:制定技术方案和实现策略
112
+ 3. **方案设计**:制定技术方案和实现策略
115
113
  4. **风险评估**:识别潜在技术难点和解决方案
116
114
  5. **执行验证**:按计划执行并验证结果
117
115
  6. **总结反馈**:输出最终解决方案和优化建议
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # 跨平台任务管理器 - 支持 Windows (Git Bash/Cygwin/WSL), Linux, macOS
4
+
5
+ set -euo pipefail
6
+
7
+ # 检测平台类型
8
+ detect_platform() {
9
+ case "$(uname -s)" in
10
+ Darwin)
11
+ echo "macos"
12
+ ;;
13
+ Linux)
14
+ if grep -q "Microsoft" /proc/version 2>/dev/null; then
15
+ echo "wsl"
16
+ else
17
+ echo "linux"
18
+ fi
19
+ ;;
20
+ CYGWIN*|MINGW*|MSYS*)
21
+ echo "windows"
22
+ ;;
23
+ *)
24
+ echo "unknown"
25
+ ;;
26
+ esac
27
+ }
28
+
29
+ # 获取临时目录(跨平台兼容)
30
+ get_temp_dir() {
31
+ local platform="$(detect_platform)"
32
+ case "$platform" in
33
+ windows|cygwin|mingw|msys)
34
+ # Windows 系统
35
+ if [ -n "${TEMP:-}" ]; then
36
+ echo "$TEMP"
37
+ elif [ -n "${TMP:-}" ]; then
38
+ echo "$TMP"
39
+ else
40
+ echo "/tmp"
41
+ fi
42
+ ;;
43
+ *)
44
+ # Unix-like 系统
45
+ echo "/tmp"
46
+ ;;
47
+ esac
48
+ }
49
+
50
+ # 安全的文件操作(跨平台兼容)
51
+ safe_file_operation() {
52
+ local operation="$1"
53
+ local file_path="$2"
54
+ local content="${3:-}"
55
+
56
+ case "$operation" in
57
+ read)
58
+ if [ -f "$file_path" ]; then
59
+ cat "$file_path" 2>/dev/null || echo ""
60
+ else
61
+ echo ""
62
+ fi
63
+ ;;
64
+ write)
65
+ mkdir -p "$(dirname "$file_path")"
66
+ echo "$content" > "$file_path"
67
+ ;;
68
+ append)
69
+ mkdir -p "$(dirname "$file_path")"
70
+ echo "$content" >> "$file_path"
71
+ ;;
72
+ lock)
73
+ # 文件锁定机制(跨平台兼容)
74
+ local lock_file="$file_path.lock"
75
+ local timeout=${4:-30}
76
+ local start_time=$(date +%s)
77
+
78
+ while [ -f "$lock_file" ]; do
79
+ local current_time=$(date +%s)
80
+ local elapsed=$((current_time - start_time))
81
+
82
+ if [ $elapsed -ge $timeout ]; then
83
+ echo "锁定超时: $file_path" >&2
84
+ return 1
85
+ fi
86
+ sleep 1
87
+ done
88
+
89
+ touch "$lock_file"
90
+ ;;
91
+ unlock)
92
+ rm -f "$file_path.lock" 2>/dev/null || true
93
+ ;;
94
+ esac
95
+ }
96
+
97
+ # 原子任务领取
98
+ task_acquire() {
99
+ local task_list_path="$1"
100
+ local task_id="$2"
101
+ local executor_id="${3:-$(hostname)-$(date +%s)}"
102
+
103
+ # 锁定任务清单文件
104
+ safe_file_operation lock "$task_list_path"
105
+
106
+ # 读取任务清单
107
+ local task_list_content="$(safe_file_operation read "$task_list_path")"
108
+
109
+ # 查找任务并检查状态
110
+ if echo "$task_list_content" | grep -q "$task_id"; then
111
+ local task_status=$(echo "$task_list_content" | awk -v id="$task_id" '
112
+ $0 ~ id {
113
+ for(i=1; i<=NF; i++) {
114
+ if ($i ~ /^状态:/) {
115
+ gsub(/状态:/, "", $i)
116
+ print $i
117
+ exit
118
+ }
119
+ }
120
+ }'
121
+ )
122
+
123
+ # 检查任务状态
124
+ if [ "$task_status" = "待执行" ]; then
125
+ # 更新任务状态为执行中
126
+ local updated_content=$(echo "$task_list_content" | awk -v id="$task_id" -v executor="$executor_id" -v timestamp="$(date +'%Y-%m-%d %H:%M:%S')" '
127
+ $0 ~ id {
128
+ gsub(/状态:待执行/, "状态:执行中")
129
+ gsub(/执行者:/, "执行者:" executor " 开始时间:" timestamp)
130
+ }
131
+ { print }
132
+ ')
133
+
134
+ safe_file_operation write "$task_list_path" "$updated_content"
135
+ echo "任务领取成功: $task_id"
136
+ return 0
137
+ else
138
+ echo "任务状态不可领取: $task_status" >&2
139
+ return 1
140
+ fi
141
+ else
142
+ echo "任务不存在: $task_id" >&2
143
+ return 1
144
+ fi
145
+
146
+ # 解锁文件
147
+ safe_file_operation unlock "$task_list_path"
148
+ }
149
+
150
+ # 原子任务完成
151
+ task_complete() {
152
+ local task_list_path="$1"
153
+ local task_id="$2"
154
+ local result="${3:-成功}"
155
+
156
+ safe_file_operation lock "$task_list_path"
157
+
158
+ local task_list_content="$(safe_file_operation read "$task_list_path")"
159
+
160
+ local updated_content=$(echo "$task_list_content" | awk -v id="$task_id" -v result="$result" -v timestamp="$(date +'%Y-%m-%d %H:%M:%S')" '
161
+ $0 ~ id {
162
+ gsub(/状态:执行中/, "状态:已完成")
163
+ gsub(/执行者:[^ ]*/, "& 完成时间:" timestamp " 结果:" result)
164
+ }
165
+ { print }
166
+ ')
167
+
168
+ safe_file_operation write "$task_list_path" "$updated_content"
169
+
170
+ safe_file_operation unlock "$task_list_path"
171
+ echo "任务完成: $task_id - $result"
172
+ }
173
+
174
+ # 原子任务失败
175
+ task_fail() {
176
+ local task_list_path="$1"
177
+ local task_id="$2"
178
+ local error_message="$3"
179
+
180
+ safe_file_operation lock "$task_list_path"
181
+
182
+ local task_list_content="$(safe_file_operation read "$task_list_path")"
183
+
184
+ local updated_content=$(echo "$task_list_content" | awk -v id="$task_id" -v error="$error_message" -v timestamp="$(date +'%Y-%m-%d %H:%M:%S')" '
185
+ $0 ~ id {
186
+ gsub(/状态:执行中/, "状态:失败")
187
+ gsub(/执行者:[^ ]*/, "& 失败时间:" timestamp " 错误:" error)
188
+ }
189
+ { print }
190
+ ')
191
+
192
+ safe_file_operation write "$task_list_path" "$updated_content"
193
+
194
+ safe_file_operation unlock "$task_list_path"
195
+ echo "任务失败: $task_id - $error_message" >&2
196
+ return 1
197
+ }
198
+
199
+ # 获取可执行任务列表
200
+ get_available_tasks() {
201
+ local task_list_path="$1"
202
+
203
+ safe_file_operation lock "$task_list_path"
204
+
205
+ local task_list_content="$(safe_file_operation read "$task_list_path")"
206
+
207
+ # 提取状态为"待执行"的任务
208
+ echo "$task_list_content" | awk '
209
+ /^#### 任务[A-Za-z0-9-]+:/ {
210
+ task_id = $2
211
+ gsub(/:/, "", task_id)
212
+ status = ""
213
+ in_task = 1
214
+ }
215
+ in_task && /^状态:/ {
216
+ status = $0
217
+ gsub(/状态:/, "", status)
218
+ gsub(/^[ \t]+|[ \t]+$/, "", status)
219
+ }
220
+ in_task && /^---$/ {
221
+ if (status == "待执行") {
222
+ print task_id
223
+ }
224
+ in_task = 0
225
+ status = ""
226
+ }
227
+ '
228
+
229
+ safe_file_operation unlock "$task_list_path"
230
+ }
231
+
232
+ # 检查任务依赖是否满足
233
+ check_task_dependencies() {
234
+ local task_list_path="$1"
235
+ local task_id="$2"
236
+
237
+ safe_file_operation lock "$task_list_path"
238
+
239
+ local task_list_content="$(safe_file_operation read "$task_list_path")"
240
+
241
+ # 提取任务的依赖
242
+ local dependencies=$(echo "$task_list_content" | awk -v id="$task_id" '
243
+ $0 ~ id {
244
+ for(i=1; i<=NF; i++) {
245
+ if ($i ~ /^依赖:/) {
246
+ # 打印依赖行并退出
247
+ print $0
248
+ exit
249
+ }
250
+ }
251
+ }
252
+ ')
253
+
254
+ # 提取依赖的任务ID
255
+ local dep_tasks=$(echo "$dependencies" | grep -oE '[A-Z]+-[0-9]+' || true)
256
+
257
+ # 检查每个依赖任务的状态
258
+ local all_deps_completed=true
259
+ for dep_task in $dep_tasks; do
260
+ local dep_status=$(echo "$task_list_content" | awk -v id="$dep_task" '
261
+ $0 ~ id {
262
+ for(i=1; i<=NF; i++) {
263
+ if ($i ~ /^状态:/) {
264
+ gsub(/状态:/, "", $i)
265
+ print $i
266
+ exit
267
+ }
268
+ }
269
+ }
270
+ ')
271
+
272
+ if [ "$dep_status" != "已完成" ]; then
273
+ echo "依赖任务未完成: $dep_task (状态: $dep_status)" >&2
274
+ all_deps_completed=false
275
+ fi
276
+ done
277
+
278
+ safe_file_operation unlock "$task_list_path"
279
+
280
+ $all_deps_completed
281
+ }
282
+
283
+ # 并行任务执行协调器
284
+ parallel_task_executor() {
285
+ local task_list_path="$1"
286
+ local max_parallel="${2:-3}"
287
+
288
+ echo "开始并行任务执行 (最大并行数: $max_parallel)"
289
+
290
+ while true; do
291
+ # 获取可用任务
292
+ local available_tasks=$(get_available_tasks "$task_list_path")
293
+
294
+ if [ -z "$available_tasks" ]; then
295
+ echo "所有任务已完成"
296
+ break
297
+ fi
298
+
299
+ local running_tasks=0
300
+ local completed_tasks=0
301
+
302
+ # 检查当前运行中的任务数
303
+ safe_file_operation lock "$task_list_path"
304
+ local task_list_content="$(safe_file_operation read "$task_list_path")"
305
+ running_tasks=$(echo "$task_list_content" | grep -c "状态:执行中" || true)
306
+ completed_tasks=$(echo "$task_list_content" | grep -c "状态:已完成" || true)
307
+ safe_file_operation unlock "$task_list_path"
308
+
309
+ # 如果还有并行空间,领取新任务
310
+ if [ $running_tasks -lt $max_parallel ]; then
311
+ for task_id in $available_tasks; do
312
+ if [ $running_tasks -ge $max_parallel ]; then
313
+ break
314
+ fi
315
+
316
+ # 检查任务依赖
317
+ if check_task_dependencies "$task_list_path" "$task_id"; then
318
+ # 尝试领取任务
319
+ if task_acquire "$task_list_path" "$task_id" 2>/dev/null; then
320
+ echo "开始执行任务: $task_id"
321
+ # 在实际使用中,这里会调用具体的任务执行逻辑
322
+ ((running_tasks++))
323
+ fi
324
+ fi
325
+ done
326
+ fi
327
+
328
+ # 等待一段时间再检查
329
+ sleep 5
330
+ done
331
+ }
332
+
333
+ # 主函数
334
+ main() {
335
+ local command="${1:-help}"
336
+ local task_list_path="${2:-}"
337
+ local task_id="${3:-}"
338
+
339
+ case "$command" in
340
+ acquire)
341
+ if [ -z "$task_list_path" ] || [ -z "$task_id" ]; then
342
+ echo "用法: $0 acquire <任务清单路径> <任务ID>" >&2
343
+ exit 1
344
+ fi
345
+ task_acquire "$task_list_path" "$task_id"
346
+ ;;
347
+ complete)
348
+ if [ -z "$task_list_path" ] || [ -z "$task_id" ]; then
349
+ echo "用法: $0 complete <任务清单路径> <任务ID> [结果]" >&2
350
+ exit 1
351
+ fi
352
+ task_complete "$task_list_path" "$task_id" "${4:-成功}"
353
+ ;;
354
+ fail)
355
+ if [ -z "$task_list_path" ] || [ -z "$task_id" ]; then
356
+ echo "用法: $0 fail <任务清单路径> <任务ID> <错误信息>" >&2
357
+ exit 1
358
+ fi
359
+ task_fail "$task_list_path" "$task_id" "$4"
360
+ ;;
361
+ list)
362
+ if [ -z "$task_list_path" ]; then
363
+ echo "用法: $0 list <任务清单路径>" >&2
364
+ exit 1
365
+ fi
366
+ get_available_tasks "$task_list_path"
367
+ ;;
368
+ parallel)
369
+ if [ -z "$task_list_path" ]; then
370
+ echo "用法: $0 parallel <任务清单路径> [最大并行数]" >&2
371
+ exit 1
372
+ fi
373
+ parallel_task_executor "$task_list_path" "${4:-3}"
374
+ ;;
375
+ check-deps)
376
+ if [ -z "$task_list_path" ] || [ -z "$task_id" ]; then
377
+ echo "用法: $0 check-deps <任务清单路径> <任务ID>" >&2
378
+ exit 1
379
+ fi
380
+ check_task_dependencies "$task_list_path" "$task_id"
381
+ ;;
382
+ *|help)
383
+ echo "跨平台任务管理器"
384
+ echo "用法: $0 <命令> [参数]"
385
+ echo ""
386
+ echo "命令:"
387
+ echo " acquire <清单路径> <任务ID> - 领取任务"
388
+ echo " complete <清单路径> <任务ID> [结果] - 标记任务完成"
389
+ echo " fail <清单路径> <任务ID> <错误> - 标记任务失败"
390
+ echo " list <清单路径> - 列出可用任务"
391
+ echo " parallel <清单路径> [并行数] - 并行执行任务"
392
+ echo " check-deps <清单路径> <任务ID> - 检查任务依赖"
393
+ echo " help - 显示帮助信息"
394
+ ;;
395
+ esac
396
+ }
397
+
398
+ # 如果是直接执行而不是被 source,则运行主函数
399
+ if [ "${BASH_SOURCE[0]}" = "$0" ]; then
400
+ main "$@"
401
+ fi