ai-battle 0.2.1 → 0.2.2
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/README.md +26 -2
- package/ai-battle.sh +200 -19
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -10,17 +10,41 @@
|
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="https://www.npmjs.com/package/ai-battle"><img src="https://img.shields.io/npm/v/ai-battle?style=flat-square&logo=npm&logoColor=white&color=CB3837" alt="npm version" /></a>
|
|
13
|
+
<a href="https://github.com/Alfonsxh/ai-battle/actions/workflows/publish.yml"><img src="https://img.shields.io/github/actions/workflow/status/Alfonsxh/ai-battle/publish.yml?style=flat-square&logo=githubactions&logoColor=white" alt="publish" /></a>
|
|
13
14
|
<img src="https://img.shields.io/badge/Bash-4%2B-4EAA25?style=flat-square&logo=gnubash&logoColor=white" alt="Bash 4+" />
|
|
14
15
|
<img src="https://img.shields.io/badge/Dep-jq-blue?style=flat-square" alt="jq" />
|
|
15
16
|
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow?style=flat-square" alt="MIT License" /></a>
|
|
16
17
|
</p>
|
|
17
18
|
|
|
18
19
|
<p align="center">
|
|
19
|
-
<a href="README_CN.md"
|
|
20
|
+
<a href="README_CN.md">中文</a> ·
|
|
21
|
+
<a href="https://www.npmjs.com/package/ai-battle">NPM</a> ·
|
|
22
|
+
<a href="https://github.com/Alfonsxh/ai-battle/issues">Issues</a> ·
|
|
23
|
+
<a href="https://github.com/Alfonsxh/ai-battle/pulls">PRs</a> ·
|
|
24
|
+
<a href="LICENSE">License</a>
|
|
20
25
|
</p>
|
|
21
26
|
|
|
22
27
|
---
|
|
23
28
|
|
|
29
|
+
<details>
|
|
30
|
+
<summary><b>Table of Contents</b></summary>
|
|
31
|
+
|
|
32
|
+
- [Features](#features)
|
|
33
|
+
- [Quick Start](#quick-start)
|
|
34
|
+
- [Installation](#installation)
|
|
35
|
+
- [Prerequisites](#prerequisites)
|
|
36
|
+
- [Usage](#usage)
|
|
37
|
+
- [Examples](#examples)
|
|
38
|
+
- [How It Works](#how-it-works)
|
|
39
|
+
- [Built-in Agents](#built-in-agents)
|
|
40
|
+
- [Output Structure](#output-structure)
|
|
41
|
+
- [Extend Agent](#extend-agent)
|
|
42
|
+
- [Environment Variables](#environment-variables)
|
|
43
|
+
- [Contributing](#contributing)
|
|
44
|
+
- [License](#license)
|
|
45
|
+
|
|
46
|
+
</details>
|
|
47
|
+
|
|
24
48
|
## ✨ Features
|
|
25
49
|
|
|
26
50
|
| Feature | Description |
|
|
@@ -70,7 +94,7 @@ npm install -g ai-battle
|
|
|
70
94
|
|
|
71
95
|
## 📖 Usage
|
|
72
96
|
|
|
73
|
-
```
|
|
97
|
+
```text
|
|
74
98
|
ai-battle [options]
|
|
75
99
|
ai-battle help
|
|
76
100
|
```
|
package/ai-battle.sh
CHANGED
|
@@ -23,12 +23,31 @@ if [ -f ".env" ]; then
|
|
|
23
23
|
fi
|
|
24
24
|
|
|
25
25
|
# ======================== 版本(从 package.json 读取) ========================
|
|
26
|
-
|
|
26
|
+
# 解析脚本真实路径(支持全局安装后经由软链接启动)
|
|
27
|
+
resolve_script_dir() {
|
|
28
|
+
local src="${BASH_SOURCE[0]}"
|
|
29
|
+
|
|
30
|
+
while [ -L "$src" ]; do
|
|
31
|
+
local dir target
|
|
32
|
+
dir="$(cd -P "$(dirname "$src")" && pwd)"
|
|
33
|
+
target="$(readlink "$src")"
|
|
34
|
+
if [[ "$target" != /* ]]; then
|
|
35
|
+
src="${dir}/${target}"
|
|
36
|
+
else
|
|
37
|
+
src="$target"
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
cd -P "$(dirname "$src")" && pwd
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
SCRIPT_DIR="$(resolve_script_dir)"
|
|
45
|
+
|
|
27
46
|
# 优先使用 npm/npx 注入的环境变量,fallback 到 node 读取,最后 grep 提取
|
|
28
47
|
if [ -n "${npm_package_version:-}" ]; then
|
|
29
48
|
VERSION="$npm_package_version"
|
|
30
49
|
else
|
|
31
|
-
VERSION=$(node -p "require(
|
|
50
|
+
VERSION=$(node -p "require(process.argv[1]).version" "${SCRIPT_DIR}/package.json" 2>/dev/null \
|
|
32
51
|
|| grep -o '"version": *"[^"]*"' "${SCRIPT_DIR}/package.json" 2>/dev/null | head -1 | grep -o '[0-9][^"]*' \
|
|
33
52
|
|| echo "0.0.0")
|
|
34
53
|
fi
|
|
@@ -50,6 +69,8 @@ DEFAULT_MAX_ROUNDS=10
|
|
|
50
69
|
WORK_DIR=".ai-battle"
|
|
51
70
|
PROBLEM_FILE="problem.md"
|
|
52
71
|
ROUNDS_DIR="${WORK_DIR}/rounds"
|
|
72
|
+
ORDERS_DIR="${WORK_DIR}/orders"
|
|
73
|
+
ORDER_HISTORY_FILE="${WORK_DIR}/order_history.jsonl"
|
|
53
74
|
CONSENSUS_FILE="${WORK_DIR}/consensus.md"
|
|
54
75
|
LOG_FILE="${WORK_DIR}/battle.log"
|
|
55
76
|
CONFIG_FILE="${WORK_DIR}/config.json"
|
|
@@ -566,6 +587,138 @@ agent_md_file() {
|
|
|
566
587
|
echo "${AGENTS_DIR}/${filename}"
|
|
567
588
|
}
|
|
568
589
|
|
|
590
|
+
# 查找 agent 在数组中的索引
|
|
591
|
+
# 参数: $1=目标 agent $2...=agent 列表
|
|
592
|
+
# 输出: 索引(找不到返回 -1)
|
|
593
|
+
find_agent_index() {
|
|
594
|
+
local target="$1"
|
|
595
|
+
shift
|
|
596
|
+
local agents=("$@")
|
|
597
|
+
|
|
598
|
+
for ((idx=0; idx<${#agents[@]}; idx++)); do
|
|
599
|
+
if [ "${agents[$idx]}" = "$target" ]; then
|
|
600
|
+
echo "$idx"
|
|
601
|
+
return 0
|
|
602
|
+
fi
|
|
603
|
+
done
|
|
604
|
+
|
|
605
|
+
echo "-1"
|
|
606
|
+
return 0
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
# 校验轮次顺序 CSV 是否与当前 agent 列表一一对应
|
|
610
|
+
# 参数: $1=order_csv $2...=agent 列表
|
|
611
|
+
# 返回: 0=有效, 1=无效
|
|
612
|
+
validate_round_order_csv() {
|
|
613
|
+
local order_csv="$1"
|
|
614
|
+
shift
|
|
615
|
+
local agents=("$@")
|
|
616
|
+
local order=()
|
|
617
|
+
|
|
618
|
+
[ -n "$order_csv" ] || return 1
|
|
619
|
+
IFS=',' read -ra order <<< "$order_csv"
|
|
620
|
+
|
|
621
|
+
if [ "${#order[@]}" -ne "${#agents[@]}" ]; then
|
|
622
|
+
return 1
|
|
623
|
+
fi
|
|
624
|
+
|
|
625
|
+
for ((idx=0; idx<${#order[@]}; idx++)); do
|
|
626
|
+
order[$idx]=$(echo "${order[$idx]}" | xargs)
|
|
627
|
+
done
|
|
628
|
+
|
|
629
|
+
# 每个 agent 必须且仅出现一次,避免顺序文件损坏导致错位
|
|
630
|
+
for expected in "${agents[@]}"; do
|
|
631
|
+
local count=0
|
|
632
|
+
for got in "${order[@]}"; do
|
|
633
|
+
if [ "$got" = "$expected" ]; then
|
|
634
|
+
count=$((count + 1))
|
|
635
|
+
fi
|
|
636
|
+
done
|
|
637
|
+
if [ "$count" -ne 1 ]; then
|
|
638
|
+
return 1
|
|
639
|
+
fi
|
|
640
|
+
done
|
|
641
|
+
|
|
642
|
+
return 0
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
# Fisher-Yates 洗牌,生成当前轮次的随机顺序
|
|
646
|
+
# 参数: $@=agent 列表
|
|
647
|
+
# 输出: csv 字符串(如 a,b,c)
|
|
648
|
+
shuffle_round_order_csv() {
|
|
649
|
+
local shuffled=("$@")
|
|
650
|
+
local n=${#shuffled[@]}
|
|
651
|
+
|
|
652
|
+
if [ "$n" -eq 0 ]; then
|
|
653
|
+
echo ""
|
|
654
|
+
return 0
|
|
655
|
+
fi
|
|
656
|
+
|
|
657
|
+
for ((i=n-1; i>0; i--)); do
|
|
658
|
+
local j=$((RANDOM % (i + 1)))
|
|
659
|
+
local tmp="${shuffled[$i]}"
|
|
660
|
+
shuffled[$i]="${shuffled[$j]}"
|
|
661
|
+
shuffled[$j]="$tmp"
|
|
662
|
+
done
|
|
663
|
+
|
|
664
|
+
local csv="${shuffled[0]}"
|
|
665
|
+
for ((i=1; i<n; i++)); do
|
|
666
|
+
csv+=",${shuffled[$i]}"
|
|
667
|
+
done
|
|
668
|
+
echo "$csv"
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
# 记录轮次顺序历史(jsonl),用于兜底追踪和恢复审计
|
|
672
|
+
# 参数: $1=round $2=order_csv $3=source(random|recovered)
|
|
673
|
+
record_round_order() {
|
|
674
|
+
local round="$1"
|
|
675
|
+
local order_csv="$2"
|
|
676
|
+
local source="${3:-random}"
|
|
677
|
+
local ts
|
|
678
|
+
ts=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
679
|
+
|
|
680
|
+
local order_json
|
|
681
|
+
order_json=$(printf '%s' "$order_csv" | jq -R 'split(",")')
|
|
682
|
+
|
|
683
|
+
jq -cn \
|
|
684
|
+
--arg ts "$ts" \
|
|
685
|
+
--arg source "$source" \
|
|
686
|
+
--argjson round "$round" \
|
|
687
|
+
--argjson order "$order_json" \
|
|
688
|
+
'{ts: $ts, round: $round, source: $source, order: $order}' \
|
|
689
|
+
>> "$ORDER_HISTORY_FILE"
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
# 读取或生成某一轮的顺序:
|
|
693
|
+
# 1) 若顺序文件存在且有效,复用;2) 否则随机生成并落盘
|
|
694
|
+
# 参数: $1=round $2...=agent 列表
|
|
695
|
+
# 输出: order_csv
|
|
696
|
+
resolve_round_order_csv() {
|
|
697
|
+
local round="$1"
|
|
698
|
+
shift
|
|
699
|
+
local agents=("$@")
|
|
700
|
+
local order_file="${ORDERS_DIR}/round_${round}.order"
|
|
701
|
+
local order_csv=""
|
|
702
|
+
local source="recovered"
|
|
703
|
+
|
|
704
|
+
if [ -f "$order_file" ] && [ -s "$order_file" ]; then
|
|
705
|
+
order_csv=$(tr -d '\r\n' < "$order_file")
|
|
706
|
+
if ! validate_round_order_csv "$order_csv" "${agents[@]}"; then
|
|
707
|
+
log_and_print "${YELLOW}⚠️ Round ${round} 顺序文件无效,已重新随机${NC}"
|
|
708
|
+
order_csv=""
|
|
709
|
+
fi
|
|
710
|
+
fi
|
|
711
|
+
|
|
712
|
+
if [ -z "$order_csv" ]; then
|
|
713
|
+
order_csv=$(shuffle_round_order_csv "${agents[@]}")
|
|
714
|
+
echo "$order_csv" > "$order_file"
|
|
715
|
+
source="random"
|
|
716
|
+
fi
|
|
717
|
+
|
|
718
|
+
record_round_order "$round" "$order_csv" "$source"
|
|
719
|
+
echo "$order_csv"
|
|
720
|
+
}
|
|
721
|
+
|
|
569
722
|
# 上帝视角: 等待用户输入补充信息
|
|
570
723
|
# 参数: $1=当前轮次
|
|
571
724
|
# 输出: stdout 用户输入的补充信息(可为空)
|
|
@@ -1069,8 +1222,8 @@ cmd_run() {
|
|
|
1069
1222
|
exit 1
|
|
1070
1223
|
fi
|
|
1071
1224
|
|
|
1072
|
-
#
|
|
1073
|
-
mkdir -p "$ROUNDS_DIR" "$SESSIONS_DIR" "$AGENTS_DIR"
|
|
1225
|
+
# 创建运行目录(包含顺序记录目录)
|
|
1226
|
+
mkdir -p "$ROUNDS_DIR" "$SESSIONS_DIR" "$AGENTS_DIR" "$ORDERS_DIR"
|
|
1074
1227
|
|
|
1075
1228
|
# 动态生成各 Agent 的指令文件(新建和恢复模式都需要更新)
|
|
1076
1229
|
for agent in "${available_agents[@]}"; do
|
|
@@ -1117,6 +1270,7 @@ cmd_run() {
|
|
|
1117
1270
|
log_and_print " 📝 问题: $(head -1 "$PROBLEM_FILE")"
|
|
1118
1271
|
log_and_print " 🤖 Agent: ${available_agents[*]}"
|
|
1119
1272
|
log_and_print " 🔄 最大轮次: $max_rounds"
|
|
1273
|
+
log_and_print " 🔀 发言顺序: 每轮随机(自动记录并可恢复)"
|
|
1120
1274
|
if $god_mode; then
|
|
1121
1275
|
log_and_print "${CYAN} 👁️ 上帝视角: 开启${NC}"
|
|
1122
1276
|
fi
|
|
@@ -1160,7 +1314,7 @@ cmd_run() {
|
|
|
1160
1314
|
round=$((prev_round + 1))
|
|
1161
1315
|
|
|
1162
1316
|
# 更新配置: 状态为 running,max_rounds 使用命令行参数
|
|
1163
|
-
jq --argjson m "$max_rounds" '.status = "running" | .max_rounds = $m' \
|
|
1317
|
+
jq --argjson m "$max_rounds" '.status = "running" | .max_rounds = $m | .order_mode = "round_random"' \
|
|
1164
1318
|
"$CONFIG_FILE" > "${CONFIG_FILE}.tmp" \
|
|
1165
1319
|
&& mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"
|
|
1166
1320
|
|
|
@@ -1197,7 +1351,7 @@ cmd_run() {
|
|
|
1197
1351
|
--argjson max_rounds "$max_rounds" \
|
|
1198
1352
|
--arg problem "$problem" \
|
|
1199
1353
|
'{agents: $agents, max_rounds: $max_rounds, problem: $problem,
|
|
1200
|
-
status: "running", current_round: 0}' \
|
|
1354
|
+
status: "running", current_round: 0, order_mode: "round_random", last_round_order: ""}' \
|
|
1201
1355
|
> "$CONFIG_FILE"
|
|
1202
1356
|
|
|
1203
1357
|
# 清空日志
|
|
@@ -1353,10 +1507,21 @@ ${all_responses_r1}请进行裁判总结。" "referee_round_1")
|
|
|
1353
1507
|
# 提取为函数逻辑,供主循环和追加轮次复用
|
|
1354
1508
|
while [ "$round" -le "$max_rounds" ]; do
|
|
1355
1509
|
local remaining=$((max_rounds - round))
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1510
|
+
local round_order_csv
|
|
1511
|
+
round_order_csv=$(resolve_round_order_csv "$round" "${available_agents[@]}")
|
|
1512
|
+
local round_order=()
|
|
1513
|
+
IFS=',' read -ra round_order <<< "$round_order_csv"
|
|
1514
|
+
|
|
1515
|
+
log_and_print "${CYAN}🔀 Round $round 顺序: ${round_order[*]}${NC}"
|
|
1516
|
+
|
|
1517
|
+
# 每轮默认随机顺序发言,优先复用已落盘顺序(便于恢复)
|
|
1518
|
+
for agent in "${round_order[@]}"; do
|
|
1519
|
+
local i
|
|
1520
|
+
i=$(find_agent_index "$agent" "${available_agents[@]}")
|
|
1521
|
+
if [ "$i" -lt 0 ]; then
|
|
1522
|
+
log_and_print "${YELLOW}⚠️ 跳过未知 agent: ${agent}${NC}"
|
|
1523
|
+
continue
|
|
1524
|
+
fi
|
|
1360
1525
|
local base
|
|
1361
1526
|
base=$(agent_base "$agent")
|
|
1362
1527
|
local color
|
|
@@ -1368,8 +1533,8 @@ ${all_responses_r1}请进行裁判总结。" "referee_round_1")
|
|
|
1368
1533
|
# 构建其他 agent 回复的 XML 块
|
|
1369
1534
|
local others_responses=""
|
|
1370
1535
|
for ((j=0; j<agent_count; j++)); do
|
|
1371
|
-
|
|
1372
|
-
|
|
1536
|
+
local other="${available_agents[$j]}"
|
|
1537
|
+
if [ "$other" != "$agent" ]; then
|
|
1373
1538
|
others_responses+="<${other}_response>
|
|
1374
1539
|
${responses[$j]}
|
|
1375
1540
|
</${other}_response>
|
|
@@ -1502,7 +1667,8 @@ ${all_responses}请进行裁判总结。" "referee_round_${round}")
|
|
|
1502
1667
|
fi
|
|
1503
1668
|
|
|
1504
1669
|
# 更新配置
|
|
1505
|
-
jq --argjson r "$round"
|
|
1670
|
+
jq --argjson r "$round" --arg o "$round_order_csv" \
|
|
1671
|
+
'.current_round = $r | .status = "running" | .last_round_order = $o' \
|
|
1506
1672
|
"$CONFIG_FILE" > "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"
|
|
1507
1673
|
|
|
1508
1674
|
# 上帝视角: 每轮结束后注入(裁判总结后再让 god 输入)
|
|
@@ -1554,9 +1720,20 @@ ${all_responses}请进行裁判总结。" "referee_round_${round}")
|
|
|
1554
1720
|
# 继续讨论循环(逻辑与上方 Round 2+ 完全相同)
|
|
1555
1721
|
while [ "$round" -le "$max_rounds" ]; do
|
|
1556
1722
|
local remaining=$((max_rounds - round))
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1723
|
+
local round_order_csv
|
|
1724
|
+
round_order_csv=$(resolve_round_order_csv "$round" "${available_agents[@]}")
|
|
1725
|
+
local round_order=()
|
|
1726
|
+
IFS=',' read -ra round_order <<< "$round_order_csv"
|
|
1727
|
+
|
|
1728
|
+
log_and_print "${CYAN}🔀 Round $round 顺序: ${round_order[*]}${NC}"
|
|
1729
|
+
|
|
1730
|
+
for agent in "${round_order[@]}"; do
|
|
1731
|
+
local i
|
|
1732
|
+
i=$(find_agent_index "$agent" "${available_agents[@]}")
|
|
1733
|
+
if [ "$i" -lt 0 ]; then
|
|
1734
|
+
log_and_print "${YELLOW}⚠️ 跳过未知 agent: ${agent}${NC}"
|
|
1735
|
+
continue
|
|
1736
|
+
fi
|
|
1560
1737
|
local base
|
|
1561
1738
|
base=$(agent_base "$agent")
|
|
1562
1739
|
local color
|
|
@@ -1568,8 +1745,8 @@ ${all_responses}请进行裁判总结。" "referee_round_${round}")
|
|
|
1568
1745
|
# 构建其他 agent 回复的 XML 块
|
|
1569
1746
|
local others_responses=""
|
|
1570
1747
|
for ((j=0; j<agent_count; j++)); do
|
|
1571
|
-
|
|
1572
|
-
|
|
1748
|
+
local other="${available_agents[$j]}"
|
|
1749
|
+
if [ "$other" != "$agent" ]; then
|
|
1573
1750
|
others_responses+="<${other}_response>
|
|
1574
1751
|
${responses[$j]}
|
|
1575
1752
|
</${other}_response>
|
|
@@ -1697,7 +1874,8 @@ ${all_responses}请进行裁判总结。" "referee_round_${round}")
|
|
|
1697
1874
|
fi
|
|
1698
1875
|
|
|
1699
1876
|
# 更新配置
|
|
1700
|
-
jq --argjson r "$round"
|
|
1877
|
+
jq --argjson r "$round" --arg o "$round_order_csv" \
|
|
1878
|
+
'.current_round = $r | .status = "running" | .last_round_order = $o' \
|
|
1701
1879
|
"$CONFIG_FILE" > "${CONFIG_FILE}.tmp" && mv "${CONFIG_FILE}.tmp" "$CONFIG_FILE"
|
|
1702
1880
|
|
|
1703
1881
|
# 上帝视角: 每轮结束后注入(裁判总结后再让 god 输入)
|
|
@@ -1751,6 +1929,7 @@ cmd_help() {
|
|
|
1751
1929
|
--agents, -a <a1,a2> Select participating agents (default: claude,codex)
|
|
1752
1930
|
Supports same-type agents: --agents gemini,gemini
|
|
1753
1931
|
--rounds, -r <N> Max discussion rounds (default: 10)
|
|
1932
|
+
Speaking order is randomized every round by default
|
|
1754
1933
|
--god, -g Enable god mode (inject instructions after each round)
|
|
1755
1934
|
--referee [agent] Enable referee mode (summarize each round, detect
|
|
1756
1935
|
consensus, generate final summary)
|
|
@@ -1788,6 +1967,8 @@ cmd_help() {
|
|
|
1788
1967
|
.ai-battle/rounds/ Per-round records (round_N_<agent>.md)
|
|
1789
1968
|
.ai-battle/rounds/referee_*.md Referee summaries (--referee)
|
|
1790
1969
|
.ai-battle/rounds/god_*.md God mode injections (--god)
|
|
1970
|
+
.ai-battle/orders/round_*.order Per-round speaking order (fallback/recovery)
|
|
1971
|
+
.ai-battle/order_history.jsonl Full order history (audit trail)
|
|
1791
1972
|
.ai-battle/sessions/ Raw Agent CLI output
|
|
1792
1973
|
.ai-battle/consensus.md Consensus conclusion (if reached)
|
|
1793
1974
|
.ai-battle/battle.log Full log
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-battle",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "让多个 AI Agent 对同一问题进行结构化圆桌讨论",
|
|
5
5
|
"bin": {
|
|
6
|
-
"ai-battle": "
|
|
6
|
+
"ai-battle": "ai-battle.sh"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"ai-battle.sh",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
],
|
|
23
23
|
"repository": {
|
|
24
24
|
"type": "git",
|
|
25
|
-
"url": "https://github.com/Alfonsxh/ai-battle.git"
|
|
25
|
+
"url": "git+https://github.com/Alfonsxh/ai-battle.git"
|
|
26
26
|
},
|
|
27
27
|
"author": "Alfons",
|
|
28
28
|
"license": "MIT"
|
|
29
|
-
}
|
|
29
|
+
}
|