@qwen-code/arena-agent 0.0.9-dev.2 → 0.0.9-dev.8
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/.env.example +29 -0
- package/README.md +77 -7
- package/dist/agent.d.ts +3 -1
- package/dist/agent.js +34 -11
- package/dist/agent.js.map +1 -1
- package/dist/ask-user.d.ts +20 -0
- package/dist/ask-user.js +388 -0
- package/dist/ask-user.js.map +1 -0
- package/dist/canonical-data.d.ts +1 -0
- package/dist/canonical-data.js +1 -0
- package/dist/canonical-data.js.map +1 -1
- package/dist/cli.js +29 -10
- package/dist/cli.js.map +1 -1
- package/dist/code-cli.d.ts +2 -0
- package/dist/code-cli.js +12 -0
- package/dist/code-cli.js.map +1 -0
- package/dist/code-tools.d.ts +73 -0
- package/dist/code-tools.js +2106 -0
- package/dist/code-tools.js.map +1 -0
- package/dist/config.d.ts +6 -1
- package/dist/config.js +50 -3
- package/dist/config.js.map +1 -1
- package/dist/document-reader.js +9 -0
- package/dist/document-reader.js.map +1 -1
- package/dist/fetch-page.d.ts +2 -0
- package/dist/fetch-page.js +50 -21
- package/dist/fetch-page.js.map +1 -1
- package/dist/history.d.ts +2 -0
- package/dist/history.js +1 -0
- package/dist/history.js.map +1 -1
- package/dist/mode.d.ts +6 -0
- package/dist/mode.js +33 -0
- package/dist/mode.js.map +1 -0
- package/dist/sdk.d.ts +26 -1
- package/dist/sdk.js +1 -0
- package/dist/sdk.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.js +11 -2
- package/dist/server.js.map +1 -1
- package/dist/spec.d.ts +11 -8
- package/dist/spec.js +105 -13
- package/dist/spec.js.map +1 -1
- package/dist/tools.d.ts +10 -27
- package/dist/tools.js +52 -11
- package/dist/tools.js.map +1 -1
- package/dist/tui.d.ts +2 -0
- package/dist/tui.js +8 -2
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +6 -1
- package/dist/workspace.d.ts +12 -0
- package/dist/workspace.js +165 -0
- package/dist/workspace.js.map +1 -0
- package/docs/BINARY_DISTRIBUTION.md +224 -0
- package/docs/MODES_AND_RELEASES.md +119 -0
- package/modes/code-arena/full-stack/system-prompt.txt +77 -0
- package/modes/code-arena/full-stack/template/.env +1 -0
- package/modes/code-arena/full-stack/template/drizzle.config.json +7 -0
- package/modes/code-arena/full-stack/template/eslint.config.mjs +9 -0
- package/modes/code-arena/full-stack/template/next.config.ts +5 -0
- package/modes/code-arena/full-stack/template/package.json +32 -0
- package/modes/code-arena/full-stack/template/postcss.config.mjs +7 -0
- package/modes/code-arena/full-stack/template/src/app/api/health/route.ts +13 -0
- package/modes/code-arena/full-stack/template/src/app/globals.css +1 -0
- package/modes/code-arena/full-stack/template/src/app/layout.tsx +16 -0
- package/modes/code-arena/full-stack/template/src/app/page.tsx +22 -0
- package/modes/code-arena/full-stack/template/src/db/index.ts +24 -0
- package/modes/code-arena/full-stack/template/src/db/schema.ts +3 -0
- package/modes/code-arena/full-stack/template/tsconfig.json +24 -0
- package/modes/code-arena/full-stack/tools.json +446 -0
- package/modes/code-arena/html/system-prompt.txt +36 -0
- package/modes/code-arena/html/tools.json +284 -0
- package/modes/code-arena/model.json +10 -0
- package/modes/code-arena/react/system-prompt.txt +33 -0
- package/modes/code-arena/react/template/index.html +12 -0
- package/modes/code-arena/react/template/package.json +28 -0
- package/modes/code-arena/react/template/src/App.tsx +28 -0
- package/modes/code-arena/react/template/src/index.css +1 -0
- package/modes/code-arena/react/template/src/main.tsx +10 -0
- package/modes/code-arena/react/template/src/utils/cn.ts +6 -0
- package/modes/code-arena/react/template/tsconfig.json +25 -0
- package/modes/code-arena/react/template/vite.config.ts +18 -0
- package/modes/code-arena/react/tools.json +410 -0
- package/package.json +18 -3
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { constants as fsConstants } from "node:fs";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { access, appendFile, copyFile, mkdir, readFile, readdir, rm, writeFile, } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { embeddedAsset } from "./runtime-assets.js";
|
|
7
|
+
import { projectRoot } from "./spec.js";
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
const dependencyInstallTimeoutMs = 5 * 60_000;
|
|
10
|
+
export const reactTemplateFiles = [
|
|
11
|
+
"src/utils/cn.ts",
|
|
12
|
+
"src/index.css",
|
|
13
|
+
"src/main.tsx",
|
|
14
|
+
"src/App.tsx",
|
|
15
|
+
"vite.config.ts",
|
|
16
|
+
"tsconfig.json",
|
|
17
|
+
"package.json",
|
|
18
|
+
"index.html",
|
|
19
|
+
];
|
|
20
|
+
export const fullStackTemplateFiles = [
|
|
21
|
+
"postcss.config.mjs",
|
|
22
|
+
"eslint.config.mjs",
|
|
23
|
+
"next.config.ts",
|
|
24
|
+
"tsconfig.json",
|
|
25
|
+
"package.json",
|
|
26
|
+
"drizzle.config.json",
|
|
27
|
+
".env",
|
|
28
|
+
"src/db/schema.ts",
|
|
29
|
+
"src/db/index.ts",
|
|
30
|
+
"src/app/api/health/route.ts",
|
|
31
|
+
"src/app/page.tsx",
|
|
32
|
+
"src/app/globals.css",
|
|
33
|
+
"src/app/layout.tsx",
|
|
34
|
+
];
|
|
35
|
+
function ignoredEmptyWorkspaceEntry(name) {
|
|
36
|
+
return (name === ".DS_Store" ||
|
|
37
|
+
name === ".arena" ||
|
|
38
|
+
name === ".code-harness" ||
|
|
39
|
+
name === ".env" ||
|
|
40
|
+
name.startsWith(".env."));
|
|
41
|
+
}
|
|
42
|
+
async function readManifest(workspace) {
|
|
43
|
+
try {
|
|
44
|
+
return JSON.parse(await readFile(path.join(workspace, "package.json"), "utf8"));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function isCapturedWorkspace(workspace, mode) {
|
|
51
|
+
if (mode === "html")
|
|
52
|
+
return false;
|
|
53
|
+
const manifest = await readManifest(workspace);
|
|
54
|
+
if (mode === "react") {
|
|
55
|
+
return (manifest.name === "react-vite-tailwind" &&
|
|
56
|
+
manifest.scripts?.build === "vite build" &&
|
|
57
|
+
typeof manifest.dependencies?.react === "string" &&
|
|
58
|
+
typeof manifest.dependencies?.["react-dom"] === "string");
|
|
59
|
+
}
|
|
60
|
+
return (manifest.name === "nextjs-postgresql-template" &&
|
|
61
|
+
manifest.scripts?.build === "next build" &&
|
|
62
|
+
typeof manifest.dependencies?.next === "string" &&
|
|
63
|
+
typeof manifest.dependencies?.["drizzle-orm"] === "string" &&
|
|
64
|
+
typeof manifest.dependencies?.pg === "string");
|
|
65
|
+
}
|
|
66
|
+
async function prepareDependencies(workspace, mode) {
|
|
67
|
+
const npmCli = process.env.CODE_HARNESS_NPM_CLI_JS;
|
|
68
|
+
const command = npmCli ? process.execPath : "npm";
|
|
69
|
+
const args = [
|
|
70
|
+
...(npmCli ? [npmCli] : []),
|
|
71
|
+
"install",
|
|
72
|
+
"--package-lock=false",
|
|
73
|
+
"--ignore-scripts",
|
|
74
|
+
"--no-audit",
|
|
75
|
+
"--no-fund",
|
|
76
|
+
];
|
|
77
|
+
try {
|
|
78
|
+
await execFileAsync(command, args, {
|
|
79
|
+
cwd: workspace,
|
|
80
|
+
env: { ...process.env, npm_config_package_lock: "false" },
|
|
81
|
+
timeout: dependencyInstallTimeoutMs,
|
|
82
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
const detail = error && typeof error === "object" && "stderr" in error
|
|
87
|
+
? String(error.stderr || "").trim()
|
|
88
|
+
: "";
|
|
89
|
+
throw new Error(`Failed to prepare ${mode === "react" ? "React" : "Full Stack"} workspace dependencies${detail ? `: ${detail}` : ""}`, { cause: error });
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
// Both captured scaffolds start with installed dependencies but no lockfile.
|
|
93
|
+
await rm(path.join(workspace, "package-lock.json"), { force: true });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function ensureFullStackDatabaseUrl(workspace) {
|
|
97
|
+
const envPath = path.join(workspace, ".env");
|
|
98
|
+
let source = "";
|
|
99
|
+
try {
|
|
100
|
+
source = await readFile(envPath, "utf8");
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (error.code !== "ENOENT")
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
if (/^\s*DATABASE_URL\s*=/m.test(source))
|
|
107
|
+
return;
|
|
108
|
+
const prefix = source.length > 0 && !source.endsWith("\n") ? "\n" : "";
|
|
109
|
+
await appendFile(envPath, `${prefix}DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:5432/app_db\n`, "utf8");
|
|
110
|
+
}
|
|
111
|
+
/** Materialize the captured scaffold for the selected Code Arena mode. */
|
|
112
|
+
export async function initializeWorkspace(workspace, mode) {
|
|
113
|
+
const targetRoot = path.resolve(workspace);
|
|
114
|
+
await mkdir(targetRoot, { recursive: true });
|
|
115
|
+
const entries = await readdir(targetRoot);
|
|
116
|
+
const hasProjectEntries = entries.some((entry) => !ignoredEmptyWorkspaceEntry(entry));
|
|
117
|
+
// The single-HTML sandbox is intentionally empty. Existing HTML projects
|
|
118
|
+
// are therefore also left untouched.
|
|
119
|
+
if (mode === "html")
|
|
120
|
+
return { initialized: false, files: [] };
|
|
121
|
+
if (hasProjectEntries && !(await isCapturedWorkspace(targetRoot, mode))) {
|
|
122
|
+
return { initialized: false, files: [] };
|
|
123
|
+
}
|
|
124
|
+
const files = mode === "react" ? reactTemplateFiles : fullStackTemplateFiles;
|
|
125
|
+
const sourceRoot = path.join(projectRoot(), "modes", "code-arena", mode, "template");
|
|
126
|
+
const copied = [];
|
|
127
|
+
if (!hasProjectEntries) {
|
|
128
|
+
for (const relative of files) {
|
|
129
|
+
const source = path.join(sourceRoot, relative);
|
|
130
|
+
const target = path.join(targetRoot, relative);
|
|
131
|
+
await mkdir(path.dirname(target), { recursive: true });
|
|
132
|
+
try {
|
|
133
|
+
const assetName = `modes/code-arena/${mode}/template/${relative}`;
|
|
134
|
+
const embedded = embeddedAsset(assetName);
|
|
135
|
+
if (embedded) {
|
|
136
|
+
await writeFile(target, embedded, { flag: "wx" });
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
await copyFile(source, target, fsConstants.COPYFILE_EXCL);
|
|
140
|
+
}
|
|
141
|
+
copied.push(relative);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
if (error.code !== "EEXIST")
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (mode === "full-stack")
|
|
150
|
+
await ensureFullStackDatabaseUrl(targetRoot);
|
|
151
|
+
const binary = mode === "react" ? "vite" : "next";
|
|
152
|
+
try {
|
|
153
|
+
await access(path.join(targetRoot, "node_modules", ".bin", binary));
|
|
154
|
+
await rm(path.join(targetRoot, "package-lock.json"), { force: true });
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
await prepareDependencies(targetRoot, mode);
|
|
158
|
+
}
|
|
159
|
+
return { initialized: copied.length > 0, files: copied };
|
|
160
|
+
}
|
|
161
|
+
/** Backward-compatible React-only entrypoint. */
|
|
162
|
+
export async function initializeReactWorkspace(workspace) {
|
|
163
|
+
return initializeWorkspace(workspace, "react");
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Arena 多平台单文件二进制
|
|
2
|
+
|
|
3
|
+
Arena 可以使用 Node.js Single Executable Applications(SEA)构建为一个包含
|
|
4
|
+
Node.js 运行时、应用代码和静态资源的可执行文件。目标机器不需要安装 Node.js。
|
|
5
|
+
|
|
6
|
+
如果业务机只是受安装权限或 Node.js 版本管理限制,这种方式可以绕过安装步骤;
|
|
7
|
+
如果业务机的操作系统本身无法运行 Node.js 20+(例如 glibc 太旧),同一运行时
|
|
8
|
+
封装进二进制后仍然无法运行,需要针对该系统选择兼容的构建机和 Node.js 发行版。
|
|
9
|
+
|
|
10
|
+
## npm 安装(业务机有 Node.js 18)
|
|
11
|
+
|
|
12
|
+
推荐业务方安装统一入口包:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g @qwen-code/arena-cli
|
|
16
|
+
arena --version
|
|
17
|
+
code-harness --version
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`@qwen-code/arena-cli` 是一个兼容 Node.js 18 的小型启动器。npm 会通过
|
|
21
|
+
`optionalDependencies` 安装当前系统对应的平台包,启动器检测操作系统、CPU 和
|
|
22
|
+
Linux libc 后运行其中的同一个 SEA 文件。`arena` 默认选择 Arena 模式,
|
|
23
|
+
`code-harness` 默认选择 React 模式;二者都可用 `--mode` 选择四种模式。
|
|
24
|
+
Harness 本身使用 SEA 内嵌的 Node.js 运行时,
|
|
25
|
+
业务机不需要 Node.js 20+。
|
|
26
|
+
|
|
27
|
+
不要使用 `--omit=optional` 安装入口包;否则需要显式安装对应的平台包。
|
|
28
|
+
|
|
29
|
+
现有的 `@qwen-code/arena-agent` 继续提供 JavaScript CLI 和 SDK,并同时暴露
|
|
30
|
+
`arena`、`code-harness` 两个命令,仍要求 Node.js 20.16+。它与平台包是两种
|
|
31
|
+
分发形式,不是两套模式实现。
|
|
32
|
+
|
|
33
|
+
## 直接安装(业务机没有 Node.js)
|
|
34
|
+
|
|
35
|
+
npm 命令本身需要 Node.js。如果业务机连 Node.js 18 也没有,macOS/Linux 可以
|
|
36
|
+
直接安装最新稳定版:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
curl -fsSL https://cdn.jsdelivr.net/npm/@qwen-code/arena-cli@latest/install.sh | sh
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
指定预发布版本或安装目录:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
curl -fsSL https://cdn.jsdelivr.net/npm/@qwen-code/arena-cli@dev/install.sh \
|
|
46
|
+
| sh -s -- --version 0.0.10-dev.1 --install-dir "$HOME/bin"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
安装脚本检测 macOS/Linux、x64/arm64 与 Linux glibc/musl,从 npm 下载对应平台包,
|
|
50
|
+
校验 tarball checksum,并把 `arena` 安装到 `~/.local/bin`。如果该目录不在 PATH,
|
|
51
|
+
脚本会幂等更新当前 shell 的 profile;设置 `ARENA_NO_MODIFY_PATH=1` 可以关闭。
|
|
52
|
+
|
|
53
|
+
也可以从平台包中取出 `bin/arena`(Windows 为 `bin/arena.exe`),直接复制运行。
|
|
54
|
+
|
|
55
|
+
macOS / Linux:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
chmod +x arena
|
|
59
|
+
./arena --version
|
|
60
|
+
./arena -p "分析当前项目"
|
|
61
|
+
./arena --mode full-stack -p "创建一个应用"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Windows:
|
|
65
|
+
|
|
66
|
+
```powershell
|
|
67
|
+
.\arena.exe --version
|
|
68
|
+
.\arena.exe -p "分析当前项目"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
模型地址、密钥和其他配置仍通过 `.env` 或环境变量提供。
|
|
72
|
+
|
|
73
|
+
## npm 平台包矩阵
|
|
74
|
+
|
|
75
|
+
所有包必须使用与仓库根 `package.json` 完全相同的版本号。
|
|
76
|
+
|
|
77
|
+
| 目标 | npm 包 |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| macOS arm64 | `@qwen-code/arena-darwin-arm64` |
|
|
80
|
+
| macOS x64 | `@qwen-code/arena-darwin-x64` |
|
|
81
|
+
| Linux arm64 glibc | `@qwen-code/arena-linux-arm64` |
|
|
82
|
+
| Linux arm64 musl | `@qwen-code/arena-linux-arm64-musl` |
|
|
83
|
+
| Linux x64 glibc | `@qwen-code/arena-linux-x64` |
|
|
84
|
+
| Linux x64 musl | `@qwen-code/arena-linux-x64-musl` |
|
|
85
|
+
| Windows x64 | `@qwen-code/arena-win32-x64` |
|
|
86
|
+
|
|
87
|
+
Node SEA 使用 Node 官方运行时,不需要像部分 Bun 二进制那样再拆 AVX2 与 baseline。
|
|
88
|
+
如果以后引入有额外 CPU 指令要求的原生依赖,再扩展目标矩阵。
|
|
89
|
+
|
|
90
|
+
## 在各平台构建
|
|
91
|
+
|
|
92
|
+
构建机要求 Node.js 20.16+。面向旧业务系统的正式发布建议固定使用 Node.js 20.x,
|
|
93
|
+
不要因为构建 runner 自动升级而无意中嵌入 Node.js 22/24:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm ci
|
|
97
|
+
npm run package:binary
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
默认命令构建当前 runner 的系统、CPU 和 libc。CI 还支持在 Linux x64 上按 Node
|
|
101
|
+
SEA 跨平台流程生成 `darwin-x64` 和 `linux-x64-musl`。前者下载完全相同版本的
|
|
102
|
+
官方 macOS x64 Runtime,后者下载 Node.js unofficial-builds 的 musl Runtime;
|
|
103
|
+
两者都通过 Aone 可访问的 npmmirror 二进制镜像下载,并校验对应的
|
|
104
|
+
`SHASUMS256.txt`,关闭 code cache/snapshot 后注入 SEA blob。
|
|
105
|
+
macOS 产物再使用固定版本和 checksum 的 `rcodesign` 做 ad-hoc 签名。Aone 从仓库的
|
|
106
|
+
`toolchains/apple-codesign-0.29.0` 工具链分支拉取固定 commit,避免构建时依赖 GitHub
|
|
107
|
+
Release 的网络可用性;本地构建未指定 `ARENA_RCODESIGN_ARCHIVE` 时仍会从官方
|
|
108
|
+
Release 下载。产物包括:
|
|
109
|
+
|
|
110
|
+
- SEA 文件:macOS / Linux 为 `build/sea/arena`,Windows 为
|
|
111
|
+
`build/sea/arena.exe`
|
|
112
|
+
- 待发布包目录:`build/npm/packages/<target>` 与 `build/npm/packages/cli`
|
|
113
|
+
- npm tarball:`build/npm/tarballs/*.tgz`
|
|
114
|
+
|
|
115
|
+
`build/sea` 最终只保留需要交付的可执行文件。构建脚本会自动运行一次
|
|
116
|
+
`arena --version` 冒烟检查。
|
|
117
|
+
|
|
118
|
+
Code Arena 的 prompt/tool contract 会编译进 bundle;React 与 Full Stack
|
|
119
|
+
scaffold 会作为 SEA assets 一起嵌入。四种模式只构建一次,不为每个模式重复平台
|
|
120
|
+
矩阵。
|
|
121
|
+
|
|
122
|
+
如果已经有另一个 runner 产生的二进制,也可以只组装指定平台包:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
node scripts/package-binaries.mjs \
|
|
126
|
+
--target linux-x64 \
|
|
127
|
+
--binary artifacts/linux-x64/arena \
|
|
128
|
+
--skip-cli
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
CI 应构建并汇总 `build/npm/packages/<target>`。原生 Runtime 通常应在对应环境中
|
|
132
|
+
构建;禁用 SEA snapshot/code cache 后,`darwin-x64` 和 `linux-x64-musl` 也可以在
|
|
133
|
+
Linux x64 Runner 上使用经过校验的目标 Node Runtime 交叉组装。
|
|
134
|
+
|
|
135
|
+
本仓库使用 Aone CI,流水线定义在
|
|
136
|
+
[`/.aoneci/arena-binaries.yaml`](../.aoneci/arena-binaries.yaml)。当前项目没有关联
|
|
137
|
+
自托管 Runner 组,因此流水线优先使用 Aone 托管的 Linux amd64 资源构建
|
|
138
|
+
`linux-x64`,并交叉构建 `linux-x64-musl` 和 `darwin-x64`。推送与根
|
|
139
|
+
`package.json` 版本完全一致的 `v<semver>` Tag 时会自动运行,并在同一批次
|
|
140
|
+
发布这三个关键平台包、`@qwen-code/arena-agent` 和
|
|
141
|
+
`@qwen-code/arena-cli`;后两个包都包含四种模式和两个命令入口。普通分支 push
|
|
142
|
+
不触发,手动运行只构建、不发布。发布前
|
|
143
|
+
需要在“设置 → 持续集成 → 变量管理”中添加名为 `NPM_TOKEN` 的 Secret。
|
|
144
|
+
|
|
145
|
+
例如,预发布版自动使用 npm `dev` tag:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npm version 0.0.10-dev.1 --no-git-tag-version
|
|
149
|
+
git add package.json package-lock.json
|
|
150
|
+
git commit -m "chore: release 0.0.10-dev.1"
|
|
151
|
+
git push origin master
|
|
152
|
+
git tag v0.0.10-dev.1
|
|
153
|
+
git push origin v0.0.10-dev.1
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
正式版同理,例如 `package.json` 为 `0.0.10` 时推送 `v0.0.10`,发布脚本会自动
|
|
157
|
+
使用 npm `latest` tag。Tag 名与版本不一致时发布步骤会直接失败,避免把错误版本
|
|
158
|
+
发布到 npm。
|
|
159
|
+
|
|
160
|
+
Aone 官方不提供 Windows/macOS 托管资源;`darwin-x64` 已通过上述交叉构建覆盖。
|
|
161
|
+
Linux arm64 的两个平台包暂不参与自动发布,以免非关键 ARM64 Job 阻塞 x64
|
|
162
|
+
发布。发布 `darwin-arm64` 和 Windows 包前,仍需要关联对应的 self-hosted Runner
|
|
163
|
+
组。
|
|
164
|
+
|
|
165
|
+
## 发布
|
|
166
|
+
|
|
167
|
+
汇总全部 7 个平台包目录后,重新生成一次入口包并进行发布前检查:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npm run package:binary:cli
|
|
171
|
+
npm run publish:binaries -- --dry-run --tag dev
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
确认后去掉 `--dry-run`,按需传入 registry:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm run publish:binaries -- \
|
|
178
|
+
--tag dev \
|
|
179
|
+
--registry https://registry.example.com
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
发布脚本会校验 7 个平台包和入口包的名称、版本、依赖是否一致,并严格依次发布
|
|
183
|
+
平台包、`@qwen-code/arena-agent`,最后发布 `@qwen-code/arena-cli`。失败后重跑会
|
|
184
|
+
跳过 npm 上已经存在的同版本包。预发布版本默认使用 `dev` tag,稳定版本默认使用
|
|
185
|
+
`latest` tag,也可以显式用 `--tag` 覆盖。
|
|
186
|
+
|
|
187
|
+
入口包必须最后发布;否则用户可能在平台包尚未可用时安装到一个缺少二进制的版本。
|
|
188
|
+
|
|
189
|
+
## 平台与兼容性
|
|
190
|
+
|
|
191
|
+
SEA 产物内含构建机当前的 Node.js 可执行文件,因此需要为每种目标分别构建:
|
|
192
|
+
|
|
193
|
+
- macOS arm64 与 x64
|
|
194
|
+
- Linux arm64/x64 的 glibc 与 musl
|
|
195
|
+
- Windows x64
|
|
196
|
+
|
|
197
|
+
除流水线已覆盖的 Linux x64 → macOS x64、Linux x64 glibc → musl SEA 交叉构建
|
|
198
|
+
外,其他目标应在对应操作系统和 CPU 架构的构建机或 CI runner 上执行。
|
|
199
|
+
|
|
200
|
+
“业务机不需要 Node.js 20+”不等于“二进制不受 Node.js 20 的系统要求影响”。
|
|
201
|
+
SEA 把 Node.js 可执行文件放进 Arena,运行时仍由操作系统加载这个内嵌运行时:
|
|
202
|
+
|
|
203
|
+
- glibc 包只能运行在满足该 Node.js 可执行文件最低 glibc 要求的系统上;
|
|
204
|
+
- musl 包用于 Alpine 等 musl 系统,不能代替 glibc 包;
|
|
205
|
+
- 在较新的 Linux 上打包,不能自动获得对更老 glibc 的兼容性。
|
|
206
|
+
|
|
207
|
+
因此,业务机只有 Node.js 18 通常不是问题;真正需要确认的是它的操作系统、CPU
|
|
208
|
+
架构和 `ldd --version`。如果业务机的 glibc 低于所选 Node.js 发行版的要求,必须
|
|
209
|
+
使用面向旧 glibc 编译的 Node.js 运行时重新制作该平台包,或升级业务系统。仅仅在
|
|
210
|
+
“更老的 Docker 镜像”里复制同一个官方 Node.js 二进制并不能降低其 glibc 下限。
|
|
211
|
+
|
|
212
|
+
单文件只消除了目标机器安装 Node.js 的要求,并不会内嵌所有外部程序:
|
|
213
|
+
|
|
214
|
+
- `bash` 工具仍要求 `/bin/bash`。
|
|
215
|
+
- Git 仓库识别仍需要系统提供 `git`。
|
|
216
|
+
- 旧版 `.doc`、`.ppt`、`.xls` 转换仍需要 LibreOffice;现代 Office 文档和 PDF
|
|
217
|
+
读取已包含在二进制中。
|
|
218
|
+
|
|
219
|
+
macOS 构建会进行 ad-hoc 签名。对外分发时,建议在构建完成后使用正式开发者证书
|
|
220
|
+
重新签名并按组织要求完成 notarization。Windows 也可以在构建后使用组织证书签名。
|
|
221
|
+
|
|
222
|
+
实现基于 [Node.js SEA 官方文档](https://nodejs.org/api/single-executable-applications.html)、
|
|
223
|
+
[Node.js unofficial-builds](https://github.com/nodejs/unofficial-builds) 和
|
|
224
|
+
[rcodesign 文档](https://gregoryszorc.com/docs/apple-codesign/stable/)。
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# 四模式架构与发包方案
|
|
2
|
+
|
|
3
|
+
## 结论
|
|
4
|
+
|
|
5
|
+
本仓库采用“一个核心包、四种运行模式”,不改成 monorepo。
|
|
6
|
+
|
|
7
|
+
- `arena`、`react`、`html`、`full-stack` 共用当前仓库的配置、provider、
|
|
8
|
+
agent loop、compaction、history、metrics、CLI/TUI/server 和 SDK。
|
|
9
|
+
- 模式边界只包含 system prompt、工具 schema/实现以及可选 scaffold。
|
|
10
|
+
- 四种模式使用同一个版本号一起演进,避免两份 agent loop 再次漂移。
|
|
11
|
+
- JavaScript/SDK 包与 SEA 二进制包是两种分发形式,可以按需要分别发布;
|
|
12
|
+
它们不是两套产品源码,也不要求 npm workspaces。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
src/
|
|
18
|
+
agent.ts # 唯一 agent loop
|
|
19
|
+
config.ts # 唯一配置入口
|
|
20
|
+
tools.ts # mode-aware facade + Arena tools
|
|
21
|
+
code-tools.ts # 三种 Code Arena 工具语义
|
|
22
|
+
mode.ts # 四模式名称、别名与默认 step limit
|
|
23
|
+
workspace.ts # React/Full Stack scaffold 初始化
|
|
24
|
+
|
|
25
|
+
spec/ # Arena 生产 fixtures(保持原路径)
|
|
26
|
+
modes/code-arena/
|
|
27
|
+
model.json # 三种 Code Arena 共用模型参数
|
|
28
|
+
react/
|
|
29
|
+
system-prompt.txt
|
|
30
|
+
tools.json
|
|
31
|
+
template/
|
|
32
|
+
html/
|
|
33
|
+
system-prompt.txt
|
|
34
|
+
tools.json
|
|
35
|
+
full-stack/
|
|
36
|
+
system-prompt.txt
|
|
37
|
+
tools.json
|
|
38
|
+
template/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`scripts/generate-canonical-data.mjs` 将 Arena fixtures 和三种 Code Arena
|
|
42
|
+
contract 一起编译到 `src/canonical-data.ts`。正常 npm 运行不读取 prompt/schema
|
|
43
|
+
源文件;scaffold 仍作为包资源保留,SEA 构建时则作为 assets 嵌入二进制。
|
|
44
|
+
|
|
45
|
+
## 模式选择
|
|
46
|
+
|
|
47
|
+
统一 CLI 使用显式参数:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
arena --mode arena -p '...'
|
|
51
|
+
arena --mode react -p '...'
|
|
52
|
+
arena --mode html -p '...'
|
|
53
|
+
arena --mode full-stack -p '...'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
兼容命令 `code-harness` 进入同一 CLI,缺省模式为 `react`。环境变量优先级为:
|
|
57
|
+
|
|
58
|
+
1. CLI `--mode`
|
|
59
|
+
2. `ARENA_HARNESS_MODE`
|
|
60
|
+
3. `CODE_HARNESS_MODE`(兼容)
|
|
61
|
+
4. `ARENA_MODE`(兼容)
|
|
62
|
+
5. `arena` 命令默认 `arena`;`code-harness` 命令默认 `react`
|
|
63
|
+
|
|
64
|
+
历史记录会保存 `mode`,system prompt 的 canonical 校验会阻止用错误模式续跑
|
|
65
|
+
同一轨迹。Code Arena 模式不启用 Arena 的自动 repo prompt;即使工作区位于 Git
|
|
66
|
+
仓库中,也仍使用所选的 Code Arena prompt。
|
|
67
|
+
|
|
68
|
+
## npm 与二进制
|
|
69
|
+
|
|
70
|
+
### JavaScript/SDK 包
|
|
71
|
+
|
|
72
|
+
`@qwen-code/arena-agent` 同时发布:
|
|
73
|
+
|
|
74
|
+
- `arena -> dist/cli.js`
|
|
75
|
+
- `code-harness -> dist/code-cli.js`
|
|
76
|
+
- SDK 的 Arena 名称与 Code Harness 兼容别名
|
|
77
|
+
- 四种模式所需的 scaffold
|
|
78
|
+
|
|
79
|
+
这是日常源码安装和 SDK 消费的发布单元,要求 Node.js 20.16+。
|
|
80
|
+
|
|
81
|
+
### 单文件二进制
|
|
82
|
+
|
|
83
|
+
`@qwen-code/arena-cli` 是兼容 Node.js 18 的平台选择器,同时提供 `arena` 和
|
|
84
|
+
`code-harness` 两个命令。它们启动同一个 SEA 文件;`code-harness` launcher
|
|
85
|
+
只负责注入默认 `react` 模式。平台包继续使用 `@qwen-code/arena-<platform>`
|
|
86
|
+
命名,无需为四种模式复制一套平台矩阵。
|
|
87
|
+
|
|
88
|
+
因此一次平台构建包含全部四种模式,版本和校验和天然一致。
|
|
89
|
+
|
|
90
|
+
## 发布节奏
|
|
91
|
+
|
|
92
|
+
可以只发布 JavaScript/SDK 包,也可以在随后完成 7 个平台的 SEA 包和 launcher;
|
|
93
|
+
但不建议单独发布某一个模式。推荐顺序:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm run typecheck
|
|
97
|
+
npm test
|
|
98
|
+
npm pack --dry-run
|
|
99
|
+
|
|
100
|
+
# 每个平台 runner
|
|
101
|
+
npm run package:binary:platform
|
|
102
|
+
|
|
103
|
+
# 汇总平台产物后
|
|
104
|
+
npm run package:binary:cli
|
|
105
|
+
npm run publish:binaries -- --dry-run
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
平台包必须先于 `@qwen-code/arena-cli` 发布。完整矩阵见
|
|
109
|
+
[`BINARY_DISTRIBUTION.md`](BINARY_DISTRIBUTION.md)。
|
|
110
|
+
|
|
111
|
+
## 原 Code Harness 的迁移边界
|
|
112
|
+
|
|
113
|
+
迁入的是三种模式的运行时 contract、工具行为、scaffold 和必要的验证;没有
|
|
114
|
+
迁入旧仓库中已经落后的 agent loop、配置、server、SDK、Web UI 副本,也没有
|
|
115
|
+
把大量 replay/实验产物复制进运行包。需要保留的数据集可以后续独立放在
|
|
116
|
+
`tasks/code-arena/`,但不应成为第二套 runtime。
|
|
117
|
+
|
|
118
|
+
只有在两组模式确实需要独立版本、独立依赖或不同发布权限时,才值得增加两个
|
|
119
|
+
很薄的入口包;即便如此,共享核心仍应留在本仓库,而不是复制实现。
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
You are an expert fullstack developer building web applications with Next.js (App Router) and PostgreSQL via Drizzle ORM. You will use the provided tools to view, create, and edit files in the project.
|
|
2
|
+
For any user prompt, always try to generate a working fullstack web application. Always just update the code instead of asking the user to confirm details.
|
|
3
|
+
|
|
4
|
+
## Critical File Operations
|
|
5
|
+
|
|
6
|
+
All file operations must be done exclusively through the provided tools. After using a tool, provide only a brief summary of what you did - DO NOT output the actual code content in your response text.
|
|
7
|
+
You can use 'list_files', 'grep_files', 'glob_files', and 'bash' to explore the project, search file contents by regex, and discover files by name pattern.
|
|
8
|
+
|
|
9
|
+
## Web Research
|
|
10
|
+
|
|
11
|
+
You have access to 'web_search' and 'web_fetch' tools for researching information on the internet.
|
|
12
|
+
- Use 'web_search' to find documentation, API references, examples, or any facts you need. This is especially useful when the user asks you to integrate a third-party API or library you're not fully familiar with.
|
|
13
|
+
- Use 'web_fetch' to read the content of a specific web page, such as documentation or API reference pages found via search.
|
|
14
|
+
- When the user's request involves a specific API, service, or library, proactively search for its documentation to ensure you use the correct endpoints, parameters, and authentication methods rather than guessing.
|
|
15
|
+
|
|
16
|
+
## Task Planning
|
|
17
|
+
|
|
18
|
+
You have a maximum of 50 sequential tool-calling steps to complete the task. Plan your approach carefully and prioritize the most critical changes first to work within this limit.
|
|
19
|
+
|
|
20
|
+
For each file you create or edit, you must first explain what you are about to do, then call the tool, then confirm the result.
|
|
21
|
+
|
|
22
|
+
Do not ask me for anything. Go with your recommendation.
|
|
23
|
+
|
|
24
|
+
## Database
|
|
25
|
+
|
|
26
|
+
The project connects to a local PostgreSQL instance via Drizzle ORM.
|
|
27
|
+
- The database connection is configured in `src/db/index.ts` and reads `DATABASE_URL` from the `.env` file.
|
|
28
|
+
- Use Drizzle ORM for all database interactions. Import the `db` client from `@/db`.
|
|
29
|
+
- Tailwind CSS is already installed and wired through `src/app/globals.css`, so you can use Tailwind utility classes immediately.
|
|
30
|
+
- When defining new tables, edit `src/db/schema.ts` and use `drizzle-orm/pg-core`.
|
|
31
|
+
- If you need to apply schema changes in a fresh sandbox, call `build_and_start` first so the environment is bootstrapped and dependencies are installed.
|
|
32
|
+
- After `build_and_start` has prepared the environment, you may use the `bash` tool to run `npx drizzle-kit push` to apply schema changes directly without migration files.
|
|
33
|
+
- If you apply schema changes after a previously passing validation run, rerun the full validation sequence and end with `build_and_start` again.
|
|
34
|
+
- You can also run raw SQL via the bash tool: `psql postgresql://postgres:postgres@127.0.0.1:5432/app_db -c "YOUR SQL"`
|
|
35
|
+
|
|
36
|
+
## Requirements
|
|
37
|
+
|
|
38
|
+
The platform builds and starts the preview after your tool calls complete.
|
|
39
|
+
Do not assume there is a running app server while you edit files.
|
|
40
|
+
Do not leave behind long-lived `next dev` or `next start` processes unless you are debugging a blocker.
|
|
41
|
+
ALWAYS create complete, functional fullstack web applications.
|
|
42
|
+
NEVER edit package.json directly. Use the 'install_npm_packages' tool to install new packages.
|
|
43
|
+
|
|
44
|
+
## Final Validation
|
|
45
|
+
|
|
46
|
+
Before you finish, you MUST use the `bash` tool to run all of these commands from the project root:
|
|
47
|
+
- `bash -lc 'set -o pipefail; npx next typegen 2>&1 | tee /tmp/next-typegen.log'`
|
|
48
|
+
- `bash -lc 'set -o pipefail; npm exec tsc -- --noEmit --pretty false 2>&1 | tee /tmp/tsc.log'`
|
|
49
|
+
- `bash -lc 'set -o pipefail; npm run build 2>&1 | tee /tmp/build.log'`
|
|
50
|
+
|
|
51
|
+
After those commands pass, you MUST call the `build_and_start` tool. This tool bootstraps the database, builds the app, starts the production server, and verifies `/api/health`.
|
|
52
|
+
|
|
53
|
+
Do not run `npm run start` or `next start` directly via `bash` as your final validation step.
|
|
54
|
+
Do not finish until type generation, TypeScript, production build, and `build_and_start` all pass.
|
|
55
|
+
Do not treat `npm run typecheck` as sufficient final validation.
|
|
56
|
+
If any validation command fails, immediately inspect the matching log before fixing the code:
|
|
57
|
+
- `cat /tmp/next-typegen.log`
|
|
58
|
+
- `cat /tmp/tsc.log`
|
|
59
|
+
- `cat /tmp/build.log`
|
|
60
|
+
If `build_and_start` fails, carefully inspect the returned `stage` and `logTail` before fixing the code.
|
|
61
|
+
If any validation step fails, keep fixing the project and do not finish yet.
|
|
62
|
+
If you make any code, package, or schema change after a passing validation run, rerun the full validation sequence before finishing.
|
|
63
|
+
Do not rely on the platform's post-turn preview build as proof the task is done; you must confirm the build yourself during the turn.
|
|
64
|
+
|
|
65
|
+
## Environment Variables
|
|
66
|
+
|
|
67
|
+
The user may have configured environment variable secrets (API keys, tokens, etc.) for this sandbox.
|
|
68
|
+
- Server-side code (API routes, server components, route handlers): access via `process.env.KEY_NAME`
|
|
69
|
+
- Client-side code: only `NEXT_PUBLIC_*` prefixed vars are exposed to the browser bundle
|
|
70
|
+
- For external API calls that require secrets, create an API route under `app/api/` that reads `process.env.KEY_NAME` and proxies the request — this keeps secrets server-side
|
|
71
|
+
- Do NOT hardcode API keys or secrets — always read from `process.env`
|
|
72
|
+
|
|
73
|
+
## Remember
|
|
74
|
+
|
|
75
|
+
Use tools for all file creation and editing. Never output code directly in your response text.
|
|
76
|
+
Feel free to use multiple files in your implementation.
|
|
77
|
+
The preview is rebuilt and restarted after you finish your edits for the turn.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
DATABASE_URL=postgresql://postgres:postgres@127.0.0.1:5432/app_db
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineConfig, globalIgnores } from "eslint/config";
|
|
2
|
+
import nextVitals from "eslint-config-next/core-web-vitals";
|
|
3
|
+
import nextTs from "eslint-config-next/typescript";
|
|
4
|
+
|
|
5
|
+
export default defineConfig([
|
|
6
|
+
...nextVitals,
|
|
7
|
+
...nextTs,
|
|
8
|
+
globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts"]),
|
|
9
|
+
]);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nextjs-postgresql-template",
|
|
3
|
+
"private": true,
|
|
4
|
+
"scripts": {
|
|
5
|
+
"dev": "next dev",
|
|
6
|
+
"build": "next build",
|
|
7
|
+
"start": "next start",
|
|
8
|
+
"lint": "eslint .",
|
|
9
|
+
"typecheck": "tsc --noEmit"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"dotenv": "17.3.1",
|
|
13
|
+
"drizzle-orm": "0.45.2",
|
|
14
|
+
"next": "16.2.6",
|
|
15
|
+
"pg": "8.20.0",
|
|
16
|
+
"react": "19.2.6",
|
|
17
|
+
"react-dom": "19.2.6"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@tailwindcss/postcss": "4.1.17",
|
|
21
|
+
"@types/node": "22.19.15",
|
|
22
|
+
"@types/pg": "8.18.0",
|
|
23
|
+
"@types/react": "19.2.14",
|
|
24
|
+
"@types/react-dom": "19.2.3",
|
|
25
|
+
"drizzle-kit": "0.31.10",
|
|
26
|
+
"eslint": "9.39.4",
|
|
27
|
+
"eslint-config-next": "16.2.6",
|
|
28
|
+
"postcss": "8.5.8",
|
|
29
|
+
"tailwindcss": "4.1.17",
|
|
30
|
+
"typescript": "5.9.3"
|
|
31
|
+
}
|
|
32
|
+
}
|