6981648796
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m56s
Project CI / Backend tests (pull_request) Failing after 12s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 3m48s
Project CI / Native shell tests (pull_request) Failing after 45s
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / Frontend tests (pull_request) Failing after 1m52s
Project CI / AI game creator shell web tests (pull_request) Failing after 1m42s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Failing after 6m57s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Failing after 8m1s
- 解决 refactor/split-direct-project 与 origin/master 在 App.tsx、立项策划聊天视图、Direct composer/引用输入区、styles.css、Rust direct user item 与 appSurface 用例上的冲突,按「Supervisor 永久退役」口径保留 DirectProject 独立聊天容器与 Design Agent 两条产品路径 - 采纳 master 的策划 Agent V1/V2 退役:删除 GDD 审批卡、策划输入卡、planningLane、planningSessionV2、planningSessionContract、规划展示适配与 Rust planning_*_v2 命令、模块、契约及对应用例,不保留兼容别名或双跑路径 - 把 master「折叠思考显示单行预览」的目的落到当前结构:新增共享表现 chat/components/AgentReasoning/AgentReasoning.tsx(折叠态单行纯文本预览 + 箭头、展开态安全 Markdown),DirectProject 回合与策划回合共用,删掉两处写死的 pre 折叠实现 - 把 master「策划入口可选模型 / 推理档」的目的接到当前策划输入盒:复用 ConversationModelSelect 与 ComposerReasoningEffortSelect,配置写回仍走客户端配置通道 - App.tsx 删除只服务退役 Supervisor / 策划 V2 的 state、ref、effect、回调与死参数,并删除两条读路径都退役后的 workspaceProjectKind;openWorkspace 的工程类型入参保留为未使用契约 - Rust 侧保留本分支 canonical→wire 投影、无审计 Direct 回合与 direct user item 严格校验,并入 master 的 prepare_new_web_project_at 前置复核 - 更新 ADR 与 shared-memory 决策记录:策划当前只有 Design Agent、两条路径的共享表现清单,以及本次合并的口径、代价与验证证据 - 验证:AGC 与仓库 typecheck、check:encoding、check:doc-index、git diff --check、改动文件 eslint 0 error;AGC vitest 168 个文件中除 5 个 jsdom localStorage 环境失败文件与本分支既有 resourceTagStatsRefresh 失败外全绿,appSurface 198 passed / 13 skipped;Rust 定向用例 direct_codex_user_item、skill_pack、sessions 全过(整套分片在本容器受 /sbin -> usr/bin 触发沙箱预检失败,与本合并无关)
212 lines
6.0 KiB
JavaScript
212 lines
6.0 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { test } from 'node:test';
|
|
|
|
import {
|
|
assertRequestedVersionNotBelowChannel,
|
|
buildOssutilArgs,
|
|
issueGlobalVersion,
|
|
maxVersion,
|
|
nextVersion,
|
|
previewNextGlobalVersion,
|
|
resolveSeedBaseline,
|
|
} from './agc-global-version.mjs';
|
|
|
|
function jsonResponse(payload, status = 200) {
|
|
return {
|
|
ok: status >= 200 && status < 300,
|
|
status,
|
|
json: async () => payload,
|
|
};
|
|
}
|
|
|
|
/** 以 URL 为键的假 OSS:只读 fetch + 记录写入。 */
|
|
function createFakeOss({ objects = {} } = {}) {
|
|
const state = { ...objects };
|
|
const writes = [];
|
|
return {
|
|
state,
|
|
writes,
|
|
fetchImpl: async (url) => {
|
|
const key = String(url).replace(/^https?:\/\/[^/]+\//u, '');
|
|
if (!(key in state)) return jsonResponse(null, 404);
|
|
return jsonResponse(state[key]);
|
|
},
|
|
writeImpl: (payload, options = {}) => {
|
|
writes.push({ payload, dryRun: Boolean(options.dryRun) });
|
|
if (!options.dryRun) state['agc/global-version.json'] = payload;
|
|
return { written: !options.dryRun, payload };
|
|
},
|
|
};
|
|
}
|
|
|
|
test('播种基线取仓库版本、各渠道清单与旧迁移指针的最大值', async () => {
|
|
const oss = createFakeOss({
|
|
objects: {
|
|
'agc/dev-win/latest.json': { version: '0.1.57' },
|
|
'agc/dev-mac/latest.json': { version: '0.1.12' },
|
|
'agc/latest.json': { version: '0.1.60' },
|
|
},
|
|
});
|
|
assert.equal(
|
|
await resolveSeedBaseline({
|
|
repoVersion: '0.1.48',
|
|
env: {},
|
|
fetchImpl: oss.fetchImpl,
|
|
}),
|
|
'0.1.60',
|
|
);
|
|
assert.equal(maxVersion('0.1.9', '0.1.10', null), '0.1.10');
|
|
});
|
|
|
|
test('无总号时按播种基线发首号,并把总号写回唯一事实源', async () => {
|
|
const oss = createFakeOss({
|
|
objects: {
|
|
'agc/dev-win/latest.json': { version: '0.1.57' },
|
|
'agc/dev-mac/latest.json': { version: '0.1.12' },
|
|
},
|
|
});
|
|
const issued = await issueGlobalVersion({
|
|
channel: 'dev-win',
|
|
commit: 'a'.repeat(40),
|
|
buildId: '319',
|
|
repoVersion: '0.1.48',
|
|
env: {},
|
|
fetchImpl: oss.fetchImpl,
|
|
writeImpl: oss.writeImpl,
|
|
now: () => '2026-09-20T00:00:00.000Z',
|
|
});
|
|
assert.equal(issued, '0.1.58');
|
|
assert.deepEqual(
|
|
oss.writes.map((entry) => entry.payload.version),
|
|
['0.1.58'],
|
|
);
|
|
assert.equal(oss.state['agc/global-version.json'].version, '0.1.58');
|
|
assert.equal(oss.state['agc/global-version.json'].channel, 'dev-win');
|
|
assert.equal(oss.state['agc/global-version.json'].buildId, '319');
|
|
});
|
|
|
|
test('已有总号时只递增,不再回看渠道清单', async () => {
|
|
const oss = createFakeOss({
|
|
objects: {
|
|
'agc/global-version.json': { version: '0.2.7' },
|
|
// 渠道清单被手工改小也不能把总号拉回去。
|
|
'agc/dev-win/latest.json': { version: '0.1.10' },
|
|
},
|
|
});
|
|
const issued = await issueGlobalVersion({
|
|
channel: 'dev-mac',
|
|
env: {},
|
|
fetchImpl: oss.fetchImpl,
|
|
writeImpl: oss.writeImpl,
|
|
});
|
|
assert.equal(issued, '0.2.8');
|
|
assert.equal(oss.state['agc/global-version.json'].version, '0.2.8');
|
|
});
|
|
|
|
test('dry-run 只预览下一位,不写回、不烧号', async () => {
|
|
const oss = createFakeOss({
|
|
objects: { 'agc/global-version.json': { version: '0.3.4' } },
|
|
});
|
|
const preview = await previewNextGlobalVersion({
|
|
env: {},
|
|
fetchImpl: oss.fetchImpl,
|
|
});
|
|
assert.equal(preview, '0.3.5');
|
|
assert.equal(oss.writes.length, 0);
|
|
|
|
const issued = await issueGlobalVersion({
|
|
channel: 'dev-win',
|
|
env: { AGC_RELEASE_DRY_RUN: '1' },
|
|
fetchImpl: oss.fetchImpl,
|
|
writeImpl: oss.writeImpl,
|
|
});
|
|
assert.equal(issued, '0.3.5');
|
|
assert.deepEqual(
|
|
oss.writes.map((entry) => entry.dryRun),
|
|
[true],
|
|
);
|
|
assert.equal(oss.state['agc/global-version.json'].version, '0.3.4');
|
|
});
|
|
|
|
test('传入低于本渠道清单的号时失败关闭', () => {
|
|
assert.equal(
|
|
assertRequestedVersionNotBelowChannel({
|
|
requested: '0.1.60',
|
|
channelVersion: '0.1.60',
|
|
channel: 'dev-win',
|
|
}),
|
|
'0.1.60',
|
|
);
|
|
assert.throws(
|
|
() =>
|
|
assertRequestedVersionNotBelowChannel({
|
|
requested: '0.1.59',
|
|
channelVersion: '0.1.60',
|
|
channel: 'dev-win',
|
|
}),
|
|
/低于 dev-win 渠道当前清单版本/u,
|
|
);
|
|
assert.equal(
|
|
assertRequestedVersionNotBelowChannel({
|
|
requested: '0.1.1',
|
|
channelVersion: null,
|
|
channel: 'dev-mac',
|
|
}),
|
|
'0.1.1',
|
|
);
|
|
});
|
|
|
|
test('写后回读不一致(并发发号)时失败关闭', async () => {
|
|
const oss = createFakeOss({
|
|
objects: { 'agc/global-version.json': { version: '0.5.1' } },
|
|
});
|
|
await assert.rejects(
|
|
issueGlobalVersion({
|
|
channel: 'dev-win',
|
|
env: {},
|
|
// 模拟另一个发号进程在写入后覆盖了总号。
|
|
writeImpl: (payload, options) => {
|
|
const result = oss.writeImpl(payload, options);
|
|
// 另一个发号进程紧随其后覆盖总号。
|
|
oss.state['agc/global-version.json'] = { version: '0.5.9' };
|
|
return result;
|
|
},
|
|
fetchImpl: oss.fetchImpl,
|
|
}),
|
|
/写后回读不一致/u,
|
|
);
|
|
});
|
|
|
|
test('nextVersion 只在 patch 位递增', () => {
|
|
assert.equal(nextVersion('0.1.9'), '0.1.10');
|
|
assert.equal(nextVersion('1.0.0'), '1.0.1');
|
|
assert.throws(() => nextVersion('0.1'), /不是有效的三段版本号/u);
|
|
});
|
|
|
|
test('ossutil 参数默认使用 v1 签名,并可按需带 region 与 v4', () => {
|
|
const base = {
|
|
args: [
|
|
'cp',
|
|
'--force',
|
|
'/tmp/a.json',
|
|
'oss://agc-dev/agc/global-version.json',
|
|
],
|
|
endpoint: 'oss-rg-china-mainland.aliyuncs.com',
|
|
accessKeyId: 'id',
|
|
accessKeySecret: 'secret',
|
|
env: {},
|
|
};
|
|
const v1 = buildOssutilArgs(base);
|
|
assert.equal(v1[v1.indexOf('--sign-version') + 1], 'v1');
|
|
assert.ok(!v1.includes('--region'));
|
|
assert.equal(v1[v1.indexOf('--access-key-id') + 1], 'id');
|
|
assert.equal(v1[v1.indexOf('--access-key-secret') + 1], 'secret');
|
|
|
|
const v4 = buildOssutilArgs({
|
|
...base,
|
|
env: { AGC_OSS_SIGN_VERSION: 'v4', AGC_OSS_REGION: 'cn-beijing' },
|
|
});
|
|
assert.equal(v4[v4.indexOf('--region') + 1], 'cn-beijing');
|
|
assert.equal(v4[v4.indexOf('--sign-version') + 1], 'v4');
|
|
});
|