Skip to content

Commit 1645bae

Browse files
author
CodeBuddy Attribution Bot
committed
fix(attribution): envDomainManagement 输出消息与实际生效时间不一致,且缺少结构化轮询引导 (issue_mock71a7_3s4jto)
1 parent 36f1dc1 commit 1645bae

2 files changed

Lines changed: 135 additions & 10 deletions

File tree

mcp/src/tools/env.test.ts

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,13 +1181,17 @@ describe("env tools - envQuery", () => {
11811181
});
11821182
});
11831183

1184-
it("envDomainManagement(create) should return structured polling guidance", async () => {
1184+
it("envDomainManagement(create) should return PENDING with polling guidance when domain not yet ENABLE", async () => {
11851185
const createEnvDomain = vi.fn().mockResolvedValue({
11861186
RequestId: "req-create-domain",
11871187
});
1188+
const getEnvAuthDomains = vi.fn().mockResolvedValue({
1189+
Domains: [],
1190+
});
11881191
mockGetCloudBaseManager.mockResolvedValue({
11891192
env: {
11901193
createEnvDomain,
1194+
getEnvAuthDomains,
11911195
},
11921196
});
11931197

@@ -1202,6 +1206,7 @@ describe("env tools - envQuery", () => {
12021206
);
12031207

12041208
expect(createEnvDomain).toHaveBeenCalledWith(["integration.example.com"]);
1209+
expect(getEnvAuthDomains).toHaveBeenCalled();
12051210
expect(payload).toMatchObject({
12061211
ok: true,
12071212
code: "DOMAIN_UPDATE_PENDING",
@@ -1213,7 +1218,7 @@ describe("env tools - envQuery", () => {
12131218
pollTool: "envQuery",
12141219
pollAction: "domains",
12151220
pollIntervalSuggestionSeconds: 10,
1216-
timeoutSuggestionSeconds: 600,
1221+
timeoutSuggestionSeconds: 300,
12171222
},
12181223
next_step: {
12191224
tool: "envQuery",
@@ -1226,13 +1231,84 @@ describe("env tools - envQuery", () => {
12261231
expect(payload.message).toContain("继续轮询 envQuery(action=\"domains\")");
12271232
});
12281233

1234+
it("envDomainManagement(create) should return COMPLETED when domain is already ENABLE", async () => {
1235+
const createEnvDomain = vi.fn().mockResolvedValue({
1236+
RequestId: "req-create-domain",
1237+
});
1238+
const getEnvAuthDomains = vi.fn().mockResolvedValue({
1239+
Domains: [
1240+
{ Domain: "integration.example.com", Status: "ENABLE", Type: "USER" },
1241+
],
1242+
});
1243+
mockGetCloudBaseManager.mockResolvedValue({
1244+
env: {
1245+
createEnvDomain,
1246+
getEnvAuthDomains,
1247+
},
1248+
});
1249+
1250+
const { tools } = createMockServer();
1251+
const payload = JSON.parse(
1252+
(
1253+
await tools.envDomainManagement.handler({
1254+
action: "create",
1255+
domains: ["integration.example.com"],
1256+
})
1257+
).content[0].text,
1258+
);
1259+
1260+
expect(createEnvDomain).toHaveBeenCalledWith(["integration.example.com"]);
1261+
expect(getEnvAuthDomains).toHaveBeenCalled();
1262+
expect(payload).toMatchObject({
1263+
ok: true,
1264+
code: "DOMAIN_UPDATE_COMPLETED",
1265+
operation: "create",
1266+
targetDomains: ["integration.example.com"],
1267+
asyncState: "COMPLETED",
1268+
});
1269+
expect(payload.message).toContain("立即生效");
1270+
expect(payload.propagation).toBeUndefined();
1271+
});
1272+
1273+
it("envDomainManagement(create) should return PENDING when verification fails", async () => {
1274+
const createEnvDomain = vi.fn().mockResolvedValue({
1275+
RequestId: "req-create-domain",
1276+
});
1277+
const getEnvAuthDomains = vi.fn().mockRejectedValue(new Error("verify failed"));
1278+
mockGetCloudBaseManager.mockResolvedValue({
1279+
env: {
1280+
createEnvDomain,
1281+
getEnvAuthDomains,
1282+
},
1283+
});
1284+
1285+
const { tools } = createMockServer();
1286+
const payload = JSON.parse(
1287+
(
1288+
await tools.envDomainManagement.handler({
1289+
action: "create",
1290+
domains: ["integration.example.com"],
1291+
})
1292+
).content[0].text,
1293+
);
1294+
1295+
expect(payload).toMatchObject({
1296+
ok: true,
1297+
code: "DOMAIN_UPDATE_PENDING",
1298+
asyncState: "PENDING",
1299+
});
1300+
expect(payload.propagation).toBeDefined();
1301+
expect(payload.message).toContain("继续轮询");
1302+
});
1303+
12291304
it("envDomainManagement(delete) should return structured polling guidance", async () => {
12301305
const deleteEnvDomain = vi.fn().mockResolvedValue({
12311306
RequestId: "req-delete-domain",
12321307
});
12331308
mockGetCloudBaseManager.mockResolvedValue({
12341309
env: {
12351310
deleteEnvDomain,
1311+
getEnvAuthDomains: vi.fn().mockResolvedValue({ Domains: [] }),
12361312
},
12371313
});
12381314

@@ -1257,6 +1333,7 @@ describe("env tools - envQuery", () => {
12571333
requiresPolling: true,
12581334
pollTool: "envQuery",
12591335
pollAction: "domains",
1336+
timeoutSuggestionSeconds: 300,
12601337
},
12611338
next_step: {
12621339
tool: "envQuery",

mcp/src/tools/env.ts

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -195,29 +195,56 @@ function buildEnvDomainManagementResult(params: {
195195
action: "create" | "delete";
196196
domains: string[];
197197
result: unknown;
198+
domainVerifiedStatus?: { enabled: boolean; details?: Array<{ domain: string; status: string }> };
198199
}) {
199-
const { action, domains, result } = params;
200+
const { action, domains, result, domainVerifiedStatus } = params;
200201
const rawResult =
201202
result && typeof result === "object" && !Array.isArray(result)
202203
? (result as Record<string, unknown>)
203204
: { result };
204205

205206
if (action === "create") {
206-
return {
207+
const allEnabled = domainVerifiedStatus?.enabled === true;
208+
const asyncState = allEnabled ? "COMPLETED" as const : "PENDING" as const;
209+
const code = allEnabled ? "DOMAIN_UPDATE_COMPLETED" : "DOMAIN_UPDATE_PENDING";
210+
211+
const base: Record<string, unknown> = {
207212
...rawResult,
208213
ok: true,
209-
code: "DOMAIN_UPDATE_PENDING",
214+
code,
210215
operation: action,
211216
targetDomains: domains,
212-
asyncState: "PENDING",
217+
asyncState,
218+
};
219+
220+
if (allEnabled) {
221+
return {
222+
...base,
223+
message:
224+
'安全域名已添加并立即生效。目标域名状态已确认为 ENABLE,无需轮询。',
225+
verifiedStatus: domainVerifiedStatus?.details,
226+
next_step: {
227+
tool: "envQuery",
228+
action: "domains",
229+
suggested_args: {
230+
action: "domains",
231+
},
232+
note: "域名已生效,如需再次确认可随时查询。",
233+
},
234+
};
235+
}
236+
237+
return {
238+
...base,
213239
message:
214-
'安全域名已提交添加请求。该变更通常需要约 10 分钟传播,请继续轮询 envQuery(action="domains"),直到目标域名状态为 ENABLE。',
240+
'安全域名已提交添加请求。该变更可能需要数分钟传播,请继续轮询 envQuery(action="domains"),直到目标域名状态为 ENABLE。',
241+
verifiedStatus: domainVerifiedStatus?.details,
215242
propagation: {
216243
requiresPolling: true,
217244
pollTool: "envQuery",
218245
pollAction: "domains",
219246
pollIntervalSuggestionSeconds: 10,
220-
timeoutSuggestionSeconds: 600,
247+
timeoutSuggestionSeconds: 300,
221248
successCondition:
222249
'目标域名出现在 envQuery(action="domains") 返回中,且 Status 为 ENABLE。',
223250
},
@@ -245,7 +272,7 @@ function buildEnvDomainManagementResult(params: {
245272
pollTool: "envQuery",
246273
pollAction: "domains",
247274
pollIntervalSuggestionSeconds: 10,
248-
timeoutSuggestionSeconds: 600,
275+
timeoutSuggestionSeconds: 300,
249276
successCondition:
250277
'目标域名不再出现在 envQuery(action="domains") 返回中。',
251278
},
@@ -1482,7 +1509,7 @@ export function registerEnvTools(server: ExtendedMcpServer) {
14821509
{
14831510
title: "环境域名管理",
14841511
description:
1485-
"管理云开发环境的安全域名,支持添加和删除操作。(原工具名:createEnvDomain/deleteEnvDomain,为兼容旧AI规则可继续使用这些名称)当浏览器 Web 应用需要从本地 Vite / dev server 或自定义域名直接访问 CloudBase 资源时,应先用 envQuery(action=domains) 检查当前实际浏览器 origin 对应的 host:port 是否已在白名单中,再按该实际值添加。新增或删除后通常需要继续轮询 envQuery(action=domains) 确认状态收敛;安全域名一般约 10 分钟生效。",
1512+
"管理云开发环境的安全域名,支持添加和删除操作。(原工具名:createEnvDomain/deleteEnvDomain,为兼容旧AI规则可继续使用这些名称)当浏览器 Web 应用需要从本地 Vite / dev server 或自定义域名直接访问 CloudBase 资源时,应先用 envQuery(action=domains) 检查当前实际浏览器 origin 对应的 host:port 是否已在白名单中,再按该实际值添加。创建后会自动验证域名状态:若已生效则返回 asyncState=COMPLETED,否则返回 asyncState=PENDING 并附带轮询指引,请按指引轮询 envQuery(action=domains) 直到域名状态为 ENABLE。",
14861513
inputSchema: {
14871514
action: z
14881515
.enum(["create", "delete"])
@@ -1507,11 +1534,31 @@ export function registerEnvTools(server: ExtendedMcpServer) {
15071534
try {
15081535
const cloudbase = await getManager();
15091536
let result;
1537+
let domainVerifiedStatus: { enabled: boolean; details?: Array<{ domain: string; status: string }> } | undefined;
15101538

15111539
switch (action) {
15121540
case "create":
15131541
result = await cloudbase.env.createEnvDomain(domains);
15141542
logCloudBaseResult(server.logger, result);
1543+
// Immediately verify domain status after creation
1544+
try {
1545+
const verifyResult = await cloudbase.env.getEnvAuthDomains();
1546+
logCloudBaseResult(server.logger, verifyResult);
1547+
const allDomains = Array.isArray(verifyResult?.Domains) ? verifyResult.Domains : [];
1548+
const details = domains.map((d) => {
1549+
const match = allDomains.find(
1550+
(entry: any) => String(entry?.Domain ?? "").toLowerCase() === d.toLowerCase(),
1551+
);
1552+
return { domain: d, status: match?.Status ?? "UNKNOWN" };
1553+
});
1554+
const allEnabled = details.every((d) => d.status === "ENABLE");
1555+
domainVerifiedStatus = { enabled: allEnabled, details };
1556+
} catch (verifyError) {
1557+
debug("Domain verification after create failed, returning PENDING", {
1558+
error: verifyError,
1559+
});
1560+
domainVerifiedStatus = undefined;
1561+
}
15151562
break;
15161563

15171564
case "delete":
@@ -1528,6 +1575,7 @@ export function registerEnvTools(server: ExtendedMcpServer) {
15281575
action,
15291576
domains,
15301577
result,
1578+
domainVerifiedStatus,
15311579
}),
15321580
);
15331581
} catch (error) {

0 commit comments

Comments
 (0)