mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-10-16 15:34:08 +08:00
fix: unblock v1.138.0 release pipelines
This commit is contained in:
@@ -174,11 +174,11 @@ std::string readElement(IUIAutomationElement* element,
|
||||
if (SUCCEEDED(element->get_CurrentProcessId(&processId))) {
|
||||
object << "\"processId\":" << processId << ",";
|
||||
}
|
||||
int nativeWindowHandle = 0;
|
||||
UIA_HWND nativeWindowHandle = nullptr;
|
||||
if (SUCCEEDED(element->get_CurrentNativeWindowHandle(&nativeWindowHandle)) &&
|
||||
nativeWindowHandle) {
|
||||
object << "\"nativeWindowHandle\":"
|
||||
<< static_cast<uintptr_t>(nativeWindowHandle) << ",";
|
||||
<< reinterpret_cast<uintptr_t>(nativeWindowHandle) << ",";
|
||||
}
|
||||
RECT rect{};
|
||||
if (SUCCEEDED(element->get_CurrentBoundingRectangle(&rect))) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Lime v1.138.0 发布执行计划
|
||||
|
||||
状态:`second-follow-up-ready / Windows CI verification pending`
|
||||
状态:`third-follow-up-ready / Windows UIA SDK contract verification pending`
|
||||
日期:2026-09-01
|
||||
目标版本:`1.138.0`
|
||||
目标 tag:`v1.138.0`
|
||||
@@ -39,6 +39,9 @@
|
||||
- 首次 follow-up commit `ba9dbdaae` 已推送并重建 `v1.138.0` tag。Quality run `33521136350` 中 Bridge、GUI Smoke、Integrity、Rust Full 均通过;Release run `33521150327` 中 macOS arm64/x64 均通过,但发布资产因 Windows job 失败未进入聚合上传。
|
||||
- 第二轮失败根因已由任务日志确认:Windows native host 在 `get_CurrentNativeWindowHandle` 传入 `HWND*`,而 Windows SDK 接口要求 `int*`;Windows Quality 的 PowerShell 命中系统 `tar` 并对 `.tar.bz2` 超时;Frontend Full 的 `electron/systemUtilityHost.test.ts` 在 Linux runner 硬编码了 macOS Accessibility 状态。
|
||||
- 第二轮修复:native window handle 改为 SDK 契约的 `int` 后再安全提升为 `uintptr_t`;Windows 7-Zip 解出中间 `.tar` 后用同一 7-Zip 解第二层,继续保留 tar 兜底;环境预览测试按真实宿主平台断言 Accessibility。定向回归 `24/24` 通过,仍待 commit/tag 更新后由 Windows runner 证明 MSVC build、Squirrel、CodeMode Gate B 与 native host Gate B。
|
||||
- 第二轮 follow-up commit `1ac3364de` 已证明 sherpa 双层解压通过、GUI Smoke 通过,但 Release run `33569593531` 的 Windows MSVC 编译仍在 `get_CurrentNativeWindowHandle` 失败。Windows SDK 事实源显示 `typedef void *UIA_HWND`,接口参数为 `UIA_HWND *`;此前 `HWND` 和 `int` 均不匹配。第三轮修复改为直接使用 `UIA_HWND`,并让 `cl` 继承 CI 标准输出,后续失败不再退化为不可读 Buffer 字节数组。
|
||||
- Quality run `33569587544` 的 Frontend Full 在第 32/119 批出现 5 个 DeepSWE 失败。根因不是 `PATH` 并发污染:默认测试直接依赖被 `.gitignore` 排除的 `.lime/benchmark/sources/deep-swe` 本地 cache,干净 CI 中 source cwd 不存在,Node 启动 `git` 因此报 `spawnSync git ENOENT`,其余断言随 task metadata 缺失级联失败。默认测试现改用临时自包含 source fixture,production preflight 仍默认执行真实 `git rev-parse` 并校验固定 commit;无 live 授权路径也在读取外部 task cache 前 fail closed。
|
||||
- 第三轮本地验证:Windows/sherpa/Electron 定向回归 `31/31`;DeepSWE adapter/benchmark `29/29`;对应 smart runner 完整并行批次 `108/108`;真实本地 DeepSWE Release 20 preflight `205/205`;受影响 ESLint、`npm run typecheck`、`npm run test:contracts`、`npm run verify:app-version`、脚本治理和 `git diff --check` 全部通过。仍待 follow-up commit/tag 更新后由 `windows-2022` 证明 MSVC、Squirrel、安装态 CodeMode/native host Gate B,并由干净 Linux runner 复验 Frontend Full。
|
||||
|
||||
已通过:
|
||||
|
||||
|
||||
@@ -208,11 +208,12 @@ export function preflightSelectedTasks({
|
||||
sourceRoot,
|
||||
sliceName = "release-20",
|
||||
manifestPath = DEEPSWE_MANIFEST_PATH,
|
||||
resolveSourceCommit = (root) => runGit(root, ["rev-parse", "HEAD"]),
|
||||
}) {
|
||||
const checks = [];
|
||||
const add = (name, passed, detail) => checks.push({ name, passed, detail });
|
||||
const { manifest } = loadSliceManifest(repoRoot, manifestPath);
|
||||
const sourceHead = runGit(sourceRoot, ["rev-parse", "HEAD"]);
|
||||
const sourceHead = resolveSourceCommit(sourceRoot);
|
||||
add(
|
||||
"source-commit",
|
||||
sourceHead === manifest.source.commit &&
|
||||
|
||||
@@ -246,6 +246,11 @@ async function main() {
|
||||
throw new Error("--verifier-only requires --run-dir");
|
||||
}
|
||||
}
|
||||
if (!options.verifierOnly && !options.allowLiveProvider) {
|
||||
throw new Error(
|
||||
"real DeepSWE execution requires --allow-live-provider; preflight remains offline",
|
||||
);
|
||||
}
|
||||
const taskId = options.verifierOnly
|
||||
? verifierTaskIdForRun({
|
||||
runDir: options.runDir,
|
||||
@@ -330,11 +335,6 @@ async function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!options.allowLiveProvider) {
|
||||
throw new Error(
|
||||
"real DeepSWE execution requires --allow-live-provider; preflight remains offline",
|
||||
);
|
||||
}
|
||||
const runId = `${timestampId()}-${task.id}`;
|
||||
const runDir = path.join(options.runsRoot, runId);
|
||||
const { workspaceRoot, workspaceDir } = createTaskWorkspaceLocation({
|
||||
|
||||
@@ -25,10 +25,11 @@ import {
|
||||
verifierCompletionStatus,
|
||||
verifierTaskIdForRun,
|
||||
} from "./deepswe-adapter-core.mjs";
|
||||
import { createDeepSweSourceFixture } from "./fixtures/deepswe-source.mjs";
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const sourceRoot = path.join(repoRoot, ".lime/benchmark/sources/deep-swe");
|
||||
const temporaryRoots = [];
|
||||
let sourceFixture = null;
|
||||
|
||||
function temporaryRoot() {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "deepswe-adapter-test-"));
|
||||
@@ -36,6 +37,14 @@ function temporaryRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
function deepSweSourceFixture() {
|
||||
if (!sourceFixture) {
|
||||
sourceFixture = createDeepSweSourceFixture({ repoRoot });
|
||||
temporaryRoots.push(sourceFixture.sourceRoot);
|
||||
}
|
||||
return sourceFixture;
|
||||
}
|
||||
|
||||
function git(cwd, args) {
|
||||
return execFileSync("git", args, { cwd, encoding: "utf8" }).trim();
|
||||
}
|
||||
@@ -56,6 +65,7 @@ afterEach(() => {
|
||||
for (const root of temporaryRoots.splice(0)) {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
sourceFixture = null;
|
||||
});
|
||||
|
||||
describe("DeepSWE current-chain adapter", () => {
|
||||
@@ -171,10 +181,12 @@ describe("DeepSWE current-chain adapter", () => {
|
||||
});
|
||||
|
||||
it("validates all selected Release 20 tasks against the pinned source", () => {
|
||||
const fixture = deepSweSourceFixture();
|
||||
const result = preflightSelectedTasks({
|
||||
repoRoot,
|
||||
sourceRoot,
|
||||
sourceRoot: fixture.sourceRoot,
|
||||
sliceName: "release-20",
|
||||
resolveSourceCommit: () => fixture.sourceCommit,
|
||||
});
|
||||
|
||||
expect(result.status).toBe("pass");
|
||||
@@ -194,17 +206,22 @@ describe("DeepSWE current-chain adapter", () => {
|
||||
}, 20_000);
|
||||
|
||||
it("loads task metadata with TOML semantics instead of ad hoc line parsing", () => {
|
||||
const fixture = deepSweSourceFixture();
|
||||
const task = loadTaskDefinition({
|
||||
repoRoot,
|
||||
sourceRoot,
|
||||
sourceRoot: fixture.sourceRoot,
|
||||
taskId: "happy-dom-abort-pending-body-reads",
|
||||
});
|
||||
const fixtureTask = fixture.tasks.get(
|
||||
"happy-dom-abort-pending-body-reads",
|
||||
);
|
||||
|
||||
expect(task).toMatchObject({
|
||||
id: "happy-dom-abort-pending-body-reads",
|
||||
schemaVersion: "1.3",
|
||||
repository: "capricorn86/happy-dom",
|
||||
baseCommit: "82a0888cb2c87a6123e05424b528f8e8c9b3e426",
|
||||
repositoryUrl: fixtureTask.repositoryUrl,
|
||||
baseCommit: fixtureTask.baseCommit,
|
||||
artifacts: ["/logs/artifacts/model.patch"],
|
||||
agent: { networkMode: "no-network", timeoutSec: 5400 },
|
||||
verifier: {
|
||||
@@ -213,14 +230,14 @@ describe("DeepSWE current-chain adapter", () => {
|
||||
collect: [
|
||||
{
|
||||
command: expect.stringContaining(
|
||||
"git diff --binary 82a0888cb2c87a6123e05424b528f8e8c9b3e426 HEAD",
|
||||
`git diff --binary ${fixtureTask.baseCommit} HEAD`,
|
||||
),
|
||||
timeoutSec: 300,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(task.instruction).toContain("AbortError");
|
||||
expect(task.instruction).toBe(fixtureTask.instruction);
|
||||
});
|
||||
|
||||
it("prepares an isolated branch and captures committed plus uncommitted changes", () => {
|
||||
@@ -1079,6 +1096,7 @@ fs.writeFileSync(path.join(verifierDir, "test-stdout.txt"), "passed");
|
||||
|
||||
it("records verifier prerequisite blockers without overwriting product failure evidence", () => {
|
||||
const root = temporaryRoot();
|
||||
const fixture = deepSweSourceFixture();
|
||||
const runDir = path.join(root, "existing-run");
|
||||
fs.mkdirSync(runDir);
|
||||
fs.writeFileSync(
|
||||
@@ -1108,6 +1126,8 @@ fs.writeFileSync(path.join(verifierDir, "test-stdout.txt"), "passed");
|
||||
"--verifier-only",
|
||||
"--run-dir",
|
||||
runDir,
|
||||
"--source-root",
|
||||
fixture.sourceRoot,
|
||||
"--pier-bin",
|
||||
path.join(root, "missing-pier"),
|
||||
"--container-bin",
|
||||
|
||||
@@ -164,6 +164,7 @@ export function createBatchPlan({
|
||||
sourceRoot = path.resolve(root, ".lime/benchmark/sources/deep-swe"),
|
||||
sliceName = "release-20",
|
||||
trials = 1,
|
||||
resolveSourceCommit,
|
||||
} = {}) {
|
||||
const { manifest } = loadSliceManifest(root, manifestPath);
|
||||
const taskIds = taskIdsForSlice(manifest, sliceName);
|
||||
@@ -172,6 +173,7 @@ export function createBatchPlan({
|
||||
sourceRoot,
|
||||
sliceName,
|
||||
manifestPath,
|
||||
...(resolveSourceCommit ? { resolveSourceCommit } : {}),
|
||||
});
|
||||
const tasks = taskIds.flatMap((taskId) =>
|
||||
Array.from({ length: trials }, (_, index) => ({
|
||||
|
||||
@@ -9,35 +9,46 @@ import {
|
||||
createBatchPlan,
|
||||
parseArgs,
|
||||
} from "./deepswe-benchmark.mjs";
|
||||
import { createDeepSweSourceFixture } from "./fixtures/deepswe-source.mjs";
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
|
||||
describe("DeepSWE Core batch benchmark", () => {
|
||||
it("plans Smoke 10 and Release 20 with explicit trial counts", () => {
|
||||
const smoke = createBatchPlan({
|
||||
const fixture = createDeepSweSourceFixture({ repoRoot });
|
||||
const options = {
|
||||
repoRoot,
|
||||
sliceName: "smoke-10",
|
||||
trials: 1,
|
||||
});
|
||||
const release = createBatchPlan({
|
||||
repoRoot,
|
||||
sliceName: "release-20",
|
||||
trials: 3,
|
||||
});
|
||||
sourceRoot: fixture.sourceRoot,
|
||||
resolveSourceCommit: () => fixture.sourceCommit,
|
||||
};
|
||||
try {
|
||||
const smoke = createBatchPlan({
|
||||
...options,
|
||||
sliceName: "smoke-10",
|
||||
trials: 1,
|
||||
});
|
||||
const release = createBatchPlan({
|
||||
...options,
|
||||
sliceName: "release-20",
|
||||
trials: 3,
|
||||
});
|
||||
|
||||
expect(smoke).toMatchObject({
|
||||
status: "ready",
|
||||
taskCount: 10,
|
||||
expectedTrialCount: 10,
|
||||
trialsPerTask: 1,
|
||||
});
|
||||
expect(release).toMatchObject({
|
||||
status: "ready",
|
||||
taskCount: 20,
|
||||
expectedTrialCount: 60,
|
||||
trialsPerTask: 3,
|
||||
});
|
||||
expect(new Set(release.tasks.map((task) => task.trialKey)).size).toBe(60);
|
||||
expect(smoke).toMatchObject({
|
||||
status: "ready",
|
||||
taskCount: 10,
|
||||
expectedTrialCount: 10,
|
||||
trialsPerTask: 1,
|
||||
});
|
||||
expect(release).toMatchObject({
|
||||
status: "ready",
|
||||
taskCount: 20,
|
||||
expectedTrialCount: 60,
|
||||
trialsPerTask: 3,
|
||||
});
|
||||
expect(new Set(release.tasks.map((task) => task.trialKey)).size).toBe(60);
|
||||
} finally {
|
||||
fs.rmSync(fixture.sourceRoot, { recursive: true, force: true });
|
||||
}
|
||||
}, 60_000);
|
||||
|
||||
it("rejects ambiguous modes and non-release trial counts", () => {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
export function createDeepSweSourceFixture({
|
||||
repoRoot,
|
||||
manifestPath = "internal/test/deepswe-coding-slice-v2.json",
|
||||
} = {}) {
|
||||
const manifest = JSON.parse(
|
||||
fs.readFileSync(path.resolve(repoRoot, manifestPath), "utf8"),
|
||||
);
|
||||
const sourceRoot = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), "lime-deepswe-source-test-"),
|
||||
);
|
||||
const tasksRoot = path.join(sourceRoot, "tasks");
|
||||
const tasks = new Map();
|
||||
|
||||
fs.mkdirSync(tasksRoot, { recursive: true });
|
||||
fs.writeFileSync(path.join(sourceRoot, "LICENSE"), "Apache-2.0\n", "utf8");
|
||||
fs.writeFileSync(
|
||||
path.join(sourceRoot, "PROVENANCE.md"),
|
||||
"# Test fixture provenance\n",
|
||||
"utf8",
|
||||
);
|
||||
|
||||
for (const task of manifest.tasks) {
|
||||
const taskDir = path.join(tasksRoot, task.id);
|
||||
const baseCommit = createHash("sha1").update(task.id).digest("hex");
|
||||
const repositoryUrl = `https://github.com/${task.repository}.git`;
|
||||
const instruction = `Fix the ${task.id} regression.`;
|
||||
|
||||
fs.mkdirSync(taskDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(taskDir, "instruction.md"), instruction, "utf8");
|
||||
fs.writeFileSync(
|
||||
path.join(taskDir, "task.toml"),
|
||||
`schema_version = "${manifest.source.taskSchemaVersion}"
|
||||
artifacts = ["/logs/artifacts/model.patch"]
|
||||
|
||||
[metadata]
|
||||
repository_url = "${repositoryUrl}"
|
||||
base_commit_hash = "${baseCommit}"
|
||||
|
||||
[agent]
|
||||
network_mode = "no-network"
|
||||
timeout_sec = 5400
|
||||
|
||||
[environment]
|
||||
docker_image = "lime/deepswe-test:latest"
|
||||
cpus = 2
|
||||
memory_mb = 4096
|
||||
storage_mb = 8192
|
||||
|
||||
[verifier]
|
||||
network_mode = "no-network"
|
||||
environment_mode = "separate"
|
||||
timeout_sec = 600
|
||||
|
||||
[[verifier.collect]]
|
||||
command = "git diff --binary ${baseCommit} HEAD > /logs/artifacts/model.patch"
|
||||
timeout_sec = 300
|
||||
`,
|
||||
"utf8",
|
||||
);
|
||||
tasks.set(task.id, { baseCommit, instruction, repositoryUrl });
|
||||
}
|
||||
|
||||
return {
|
||||
sourceRoot,
|
||||
sourceCommit: manifest.source.commit,
|
||||
tasks,
|
||||
};
|
||||
}
|
||||
@@ -442,7 +442,7 @@ function compileWindowsNativeHost({
|
||||
"-o",
|
||||
outputPath,
|
||||
];
|
||||
execFileSyncImpl(compiler, args, { stdio: "pipe" });
|
||||
execFileSyncImpl(compiler, args, { stdio: "inherit" });
|
||||
chmodSync(outputPath, 0o755);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,19 @@ function createWindowsPackage() {
|
||||
}
|
||||
|
||||
describe("electron desktop resource manifest", () => {
|
||||
it("Windows native host 使用 SDK UIA_HWND 类型接收窗口句柄", () => {
|
||||
const source = readFileSync(
|
||||
"electron/native/windows/windows-native-host.cpp",
|
||||
"utf8",
|
||||
);
|
||||
|
||||
expect(source).toContain("UIA_HWND nativeWindowHandle = nullptr;");
|
||||
expect(source).not.toContain("int nativeWindowHandle = 0;");
|
||||
expect(source).not.toMatch(
|
||||
/^\s*HWND nativeWindowHandle = nullptr;\s*$/mu,
|
||||
);
|
||||
});
|
||||
|
||||
it("按平台和架构生成稳定的资源清单", () => {
|
||||
expect(desktopResourcePlatformKey("darwin", "arm64")).toBe("darwin-arm64");
|
||||
expect(desktopResourcePlatformKey("win32", "x64")).toBe("win32-x64");
|
||||
|
||||
Reference in New Issue
Block a user