@bf-meishijian/aip 0.0.31 → 0.0.32

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.
Files changed (98) hide show
  1. package/README.md +16 -18
  2. package/dist/aip-submit-outcome/SKILL.md +20 -47
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +3 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/coding-run-manager.d.ts +2 -3
  7. package/dist/coding-run-manager.d.ts.map +1 -1
  8. package/dist/coding-run-manager.js +52 -49
  9. package/dist/coding-run-manager.js.map +1 -1
  10. package/dist/daemon.d.ts.map +1 -1
  11. package/dist/daemon.js +8 -3
  12. package/dist/daemon.js.map +1 -1
  13. package/dist/delivery-tools.d.ts.map +1 -1
  14. package/dist/delivery-tools.js +2 -0
  15. package/dist/delivery-tools.js.map +1 -1
  16. package/dist/diagnostics.d.ts +1 -1
  17. package/dist/diagnostics.d.ts.map +1 -1
  18. package/dist/diagnostics.js +1 -1
  19. package/dist/diagnostics.js.map +1 -1
  20. package/dist/general-run-client.d.ts.map +1 -1
  21. package/dist/general-run-manager.d.ts.map +1 -1
  22. package/dist/general-run-manager.js +0 -1
  23. package/dist/general-run-manager.js.map +1 -1
  24. package/dist/general-run-tools.d.ts +1 -1
  25. package/dist/general-run-tools.d.ts.map +1 -1
  26. package/dist/general-run-tools.js +1 -1
  27. package/dist/general-run-tools.js.map +1 -1
  28. package/dist/generated/qa-schemas.js +1123 -0
  29. package/dist/handoff-cli.d.ts +2 -0
  30. package/dist/handoff-cli.d.ts.map +1 -0
  31. package/dist/handoff-cli.js +86 -0
  32. package/dist/handoff-cli.js.map +1 -0
  33. package/dist/host-log.d.ts +2 -0
  34. package/dist/host-log.d.ts.map +1 -1
  35. package/dist/host-log.js +5 -2
  36. package/dist/host-log.js.map +1 -1
  37. package/dist/host-shell.d.ts +2 -0
  38. package/dist/host-shell.d.ts.map +1 -0
  39. package/dist/host-shell.js +11 -0
  40. package/dist/host-shell.js.map +1 -0
  41. package/dist/host-status.d.ts.map +1 -1
  42. package/dist/live-employee.js +2 -2
  43. package/dist/live-employee.js.map +1 -1
  44. package/dist/local-employee-runtime.d.ts +1 -1
  45. package/dist/local-employee-runtime.d.ts.map +1 -1
  46. package/dist/local-employee-runtime.js +1 -1
  47. package/dist/local-employee-runtime.js.map +1 -1
  48. package/dist/local-handoff-workspace.d.ts +8 -1
  49. package/dist/local-handoff-workspace.d.ts.map +1 -1
  50. package/dist/local-handoff-workspace.js +14 -34
  51. package/dist/local-handoff-workspace.js.map +1 -1
  52. package/dist/outcome-cli.d.ts +1 -0
  53. package/dist/outcome-cli.d.ts.map +1 -1
  54. package/dist/outcome-cli.js +43 -54
  55. package/dist/outcome-cli.js.map +1 -1
  56. package/dist/pi-message-queue.d.ts +5 -0
  57. package/dist/pi-message-queue.d.ts.map +1 -1
  58. package/dist/pi-message-queue.js +21 -0
  59. package/dist/pi-message-queue.js.map +1 -1
  60. package/dist/pi-model-service.d.ts.map +1 -1
  61. package/dist/platform-client.d.ts +6 -0
  62. package/dist/platform-client.d.ts.map +1 -1
  63. package/dist/platform-client.js +18 -2
  64. package/dist/platform-client.js.map +1 -1
  65. package/dist/project-facts.d.ts.map +1 -1
  66. package/dist/project-facts.js +5 -0
  67. package/dist/project-facts.js.map +1 -1
  68. package/dist/qa-ajv.js +9 -0
  69. package/dist/qa-contract.d.ts +1 -1
  70. package/dist/qa-contract.d.ts.map +1 -1
  71. package/dist/qa-contract.js +18 -90
  72. package/dist/qa-contract.js.map +1 -1
  73. package/dist/qa-http-validation.js +5 -133
  74. package/dist/qa-project-checkout.d.ts +6 -2
  75. package/dist/qa-project-checkout.d.ts.map +1 -1
  76. package/dist/qa-project-checkout.js +19 -12
  77. package/dist/qa-project-checkout.js.map +1 -1
  78. package/dist/qa-session-manager.d.ts +3 -6
  79. package/dist/qa-session-manager.d.ts.map +1 -1
  80. package/dist/qa-session-manager.js +116 -90
  81. package/dist/qa-session-manager.js.map +1 -1
  82. package/dist/qa-tool-arguments.js +336 -0
  83. package/dist/stage-delivery.js +5 -3
  84. package/dist/state.d.ts +2 -2
  85. package/dist/state.js +2 -2
  86. package/dist/test-cli.d.ts.map +1 -1
  87. package/dist/test-cli.js +1 -3
  88. package/dist/test-cli.js.map +1 -1
  89. package/dist/test-executor.d.ts +2 -2
  90. package/dist/test-executor.d.ts.map +1 -1
  91. package/dist/test-executor.js +14 -9
  92. package/dist/test-executor.js.map +1 -1
  93. package/dist/test-reports.d.ts +13 -1
  94. package/dist/test-reports.d.ts.map +1 -1
  95. package/dist/tool-dispatch.d.ts.map +1 -1
  96. package/dist/tool-dispatch.js +3 -0
  97. package/dist/tool-dispatch.js.map +1 -1
  98. package/package.json +5 -4
@@ -1,107 +1,8 @@
1
- import { Ajv } from "ajv";
1
+ import { qaEvidenceReferencesSchema, qaHttpExchangeSchema } from "./generated/qa-schemas.js";
2
+ import { createQaAjv } from "./qa-ajv.js";
2
3
 
3
- export const qaHttpExchangeSchema = {
4
- type: "object",
5
- additionalProperties: false,
6
- properties: {
7
- step: { type: "string", minLength: 1 },
8
- id: {
9
- type: "string",
10
- },
11
- sequence: {
12
- type: "integer",
13
- minimum: 1,
14
- },
15
- startedAt: {
16
- type: "string",
17
- },
18
- durationMs: {
19
- type: "integer",
20
- minimum: 0,
21
- },
22
- request: {
23
- type: "object",
24
- additionalProperties: false,
25
- properties: {
26
- method: {
27
- type: "string",
28
- },
29
- url: {
30
- type: "string",
31
- },
32
- headers: {
33
- type: "object",
34
- additionalProperties: {
35
- type: "array",
36
- items: {
37
- type: "string",
38
- },
39
- },
40
- },
41
- body: {
42
- anyOf: [
43
- {
44
- type: "string",
45
- },
46
- {
47
- type: "null",
48
- },
49
- ],
50
- },
51
- bodyAttachment: {
52
- type: "string",
53
- },
54
- },
55
- required: ["method", "url", "headers", "body"],
56
- },
57
- response: {
58
- anyOf: [
59
- {
60
- type: "object",
61
- additionalProperties: false,
62
- properties: {
63
- status: {
64
- type: "integer",
65
- minimum: 100,
66
- maximum: 599,
67
- },
68
- headers: {
69
- type: "object",
70
- additionalProperties: {
71
- type: "array",
72
- items: {
73
- type: "string",
74
- },
75
- },
76
- },
77
- body: {
78
- anyOf: [
79
- {
80
- type: "string",
81
- },
82
- {
83
- type: "null",
84
- },
85
- ],
86
- },
87
- bodyAttachment: {
88
- type: "string",
89
- },
90
- },
91
- required: ["status", "headers", "body"],
92
- },
93
- {
94
- type: "null",
95
- },
96
- ],
97
- },
98
- error: {
99
- type: "string",
100
- },
101
- },
102
- required: ["id", "sequence", "startedAt", "durationMs", "request", "response"],
103
- } ;
104
- const ajv = new Ajv({ allErrors: true, strict: false });
4
+ export { qaEvidenceReferencesSchema, qaHttpExchangeSchema } from "./generated/qa-schemas.js";
5
+ const ajv = createQaAjv();
105
6
  const validate = ajv.compile(qaHttpExchangeSchema);
106
7
  export function parseQaHttpExchange(value ) {
107
8
  if (!validate(value))
@@ -109,36 +10,7 @@ export function parseQaHttpExchange(value ) {
109
10
  return value ;
110
11
  }
111
12
 
112
- export const qaEvidenceReferencesSchema = {
113
- type: "array",
114
- items: {
115
- oneOf: [
116
- {
117
- type: "object",
118
- additionalProperties: false,
119
- required: ["kind", "exchangeId", "side", "label"],
120
- properties: {
121
- kind: { const: "http" },
122
- exchangeId: { type: "string", minLength: 1 },
123
- side: { enum: ["request", "response"] },
124
- label: { type: "string" },
125
- },
126
- },
127
- {
128
- type: "object",
129
- additionalProperties: false,
130
- required: ["kind", "filename", "label"],
131
- properties: {
132
- kind: { const: "attachment" },
133
- filename: { type: "string", minLength: 1 },
134
- label: { type: "string" },
135
- },
136
- },
137
- ],
138
- },
139
- } ;
140
-
141
- const validateReferences = new Ajv({ strict: false }).compile(qaEvidenceReferencesSchema);
13
+ const validateReferences = createQaAjv().compile(qaEvidenceReferencesSchema);
142
14
  export function parseQaEvidenceReferences(value ) {
143
15
  if (!validateReferences(value)) throw new Error("QA_EVIDENCE_REFERENCES_INVALID");
144
16
  return value ;
@@ -1,12 +1,16 @@
1
1
  import type { QaHostCommandPayload } from "@ai-platform/api-contracts";
2
2
  type Project = Omit<NonNullable<QaHostCommandPayload["project"]>, "mainBranch">;
3
3
  export declare function qaProjectDirectory(project: Project): string;
4
- export declare function gitQa(args: string[], cwd?: string): Promise<string>;
4
+ /** QA 检出复用平台受控 Git 执行器:超时、中断清理与输出上限同公共实现,不自动重试。 */
5
+ export declare function gitQa(args: string[], cwd?: string, signal?: AbortSignal): Promise<string>;
5
6
  /** 同一 Host 的同项目任务排队;文件锁同时保护 CLI 与 daemon。 */
6
7
  export declare function withQaProject<T>(project: Project, work: () => Promise<T>): Promise<T>;
7
8
  /** 仅更新 Host 专用检出,不接触开发者工作目录。调用期间必须持有项目锁。 */
8
9
  export declare function prepareQaCheckout({ project }: {
9
10
  project: Project;
10
- }): Promise<string>;
11
+ }): Promise<{
12
+ directory: string;
13
+ commitSha: string;
14
+ }>;
11
15
  export {};
12
16
  //# sourceMappingURL=qa-project-checkout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"qa-project-checkout.d.ts","sourceRoot":"","sources":["../src/qa-project-checkout.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAKvE,KAAK,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AAGhF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,UAGlD;AACD,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,mBAIvD;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAoB3F;AAED,4CAA4C;AAC5C,wBAAsB,iBAAiB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,mBAyBxE"}
1
+ {"version":3,"file":"qa-project-checkout.d.ts","sourceRoot":"","sources":["../src/qa-project-checkout.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAOvE,KAAK,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AAEhF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,UAGlD;AACD,mDAAmD;AACnD,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,mBAe7E;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAoB3F;AAED,4CAA4C;AAC5C,wBAAsB,iBAAiB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE;;;GAqBxE"}
@@ -1,19 +1,30 @@
1
- import { execFile } from "node:child_process";
2
1
  import { access, mkdir, realpath } from "node:fs/promises";
3
2
  import { join, resolve } from "node:path";
4
- import { promisify } from "node:util";
5
3
  import lockfile from "proper-lockfile";
4
+ import { execGitFile, GitProcessError, gitFailure } from "./git-process.js";
6
5
  import { ensureSshOrigin, gitTransportUrl } from "./git-transport.js";
6
+ import { sanitizeGitOutput } from "./host-log.js";
7
7
  import { paths } from "./paths.js";
8
- const exec = promisify(execFile);
9
8
  const pending = new Map();
10
9
  export function qaProjectDirectory(project) {
11
10
  if (!/^[a-zA-Z0-9_-]+$/u.test(project.id))
12
11
  throw new Error("QA_PROJECT_ID_INVALID");
13
12
  return join(paths().workspaceRoot, "qa-projects", project.id);
14
13
  }
15
- export async function gitQa(args, cwd) {
16
- return (await exec("git", args, { cwd, encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 60_000 })).stdout.trim();
14
+ /** QA 检出复用平台受控 Git 执行器:超时、中断清理与输出上限同公共实现,不自动重试。 */
15
+ export async function gitQa(args, cwd, signal) {
16
+ try {
17
+ const { stdout } = await execGitFile("git", args, {
18
+ ...(cwd ? { cwd } : {}),
19
+ ...(signal ? { signal } : {}),
20
+ });
21
+ return stdout.trim();
22
+ }
23
+ catch (error) {
24
+ // 失败信息保留脱敏后的 Git 输出,只带子命令名,不回显参数或仓库地址。
25
+ const stderr = error instanceof GitProcessError ? sanitizeGitOutput(error.stderr).trim() : "";
26
+ throw gitFailure(`QA_REPOSITORY_GIT_FAILED(git ${args[0] ?? ""})${stderr ? `:${stderr.slice(-2000)}` : ""}`, error);
27
+ }
17
28
  }
18
29
  /** 同一 Host 的同项目任务排队;文件锁同时保护 CLI 与 daemon。 */
19
30
  export async function withQaProject(project, work) {
@@ -42,8 +53,6 @@ export async function withQaProject(project, work) {
42
53
  }
43
54
  /** 仅更新 Host 专用检出,不接触开发者工作目录。调用期间必须持有项目锁。 */
44
55
  export async function prepareQaCheckout({ project }) {
45
- if (!project.commitSha || !/^[a-f\d]{40}$/iu.test(project.commitSha))
46
- throw new Error("QA_COMMIT_REQUIRED");
47
56
  if (!project.remoteUrl || project.remoteUrl.startsWith("-"))
48
57
  throw new Error("QA_REMOTE_INVALID");
49
58
  const transport = gitTransportUrl(project.remoteUrl, project.sshRemoteUrl);
@@ -62,12 +71,10 @@ export async function prepareQaCheckout({ project }) {
62
71
  if ((await realpath(resolve(repository, common))) !== (await realpath(join(repository, ".git"))))
63
72
  throw new Error("QA_REPOSITORY_NOT_ISOLATED");
64
73
  await ensureSshOrigin(repository, project.remoteUrl, project.sshRemoteUrl);
65
- await gitQa(["fetch", "--no-tags", "origin", project.commitSha], repository);
74
+ await gitQa(["fetch", "--no-tags", "origin", `refs/heads/${project.branch}`], repository);
66
75
  // 上一次报告已独立保存;清理专用仓库内产物,避免将旧结果当成本次结果。
67
76
  await gitQa(["clean", "-ffdx"], repository);
68
- await gitQa(["checkout", "--detach", "--force", project.commitSha], repository);
69
- if ((await gitQa(["rev-parse", "HEAD"], repository)) !== project.commitSha.toLowerCase())
70
- throw new Error("QA_CHECKOUT_MISMATCH");
71
- return repository;
77
+ await gitQa(["checkout", "--detach", "--force", "FETCH_HEAD"], repository);
78
+ return { directory: repository, commitSha: await gitQa(["rev-parse", "HEAD"], repository) };
72
79
  }
73
80
  //# sourceMappingURL=qa-project-checkout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"qa-project-checkout.js","sourceRoot":"","sources":["../src/qa-project-checkout.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"qa-project-checkout.js","sourceRoot":"","sources":["../src/qa-project-checkout.ts"],"names":[],"mappings":"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"}
@@ -43,6 +43,8 @@ export interface QaSessionClient {
43
43
  contentBase64: string;
44
44
  }): Promise<QaAttachmentView>;
45
45
  qaSubmitVerification: PlatformClient["qaSubmitVerification"];
46
+ qaReuseVerification: PlatformClient["qaReuseVerification"];
47
+ qaRequestWaiver: PlatformClient["qaRequestWaiver"];
46
48
  qaSubmitConclusion: PlatformClient["qaSubmitConclusion"];
47
49
  }
48
50
  export declare class QaSessionManager {
@@ -66,13 +68,8 @@ export declare function readQaAssetState(cwd: string, remoteUrl: string, expecte
66
68
  sourceCommitSha: string;
67
69
  mainCommitSha: string;
68
70
  hasChanges: boolean;
71
+ hasLocalChanges: boolean;
69
72
  }>;
70
- export declare function verifyQaAssetMerge(cwd: string, remoteUrl: string, expectedBranch: string, mainBranch: string, sshRemoteUrl?: string | null): Promise<{
71
- sourceCommitSha: string;
72
- mainCommitSha: string;
73
- }>;
74
- /** 对照批准内容及实际合入结果;主分支其他文件的并行改动不属于本次 QA。 */
75
- export declare function qaAssetContentChanged(cwd: string, approvedSource: string, approvedMain: string, source: string, main: string): Promise<boolean>;
76
73
  export declare function readQaScreenshot(cwd: string, filename: string): Promise<{
77
74
  filename: string;
78
75
  mediaType: string;
@@ -1 +1 @@
1
- {"version":3,"file":"qa-session-manager.d.ts","sourceRoot":"","sources":["../src/qa-session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"qa-session-manager.d.ts","sourceRoot":"","sources":["../src/qa-session-manager.ts"],"names":[],"mappings":"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"}
@@ -2,13 +2,14 @@ import { execFile } from "node:child_process";
2
2
  import { createHash, randomUUID } from "node:crypto";
3
3
  import { constants } from "node:fs";
4
4
  import { mkdir, open, realpath, stat } from "node:fs/promises";
5
- import { basename, isAbsolute, join, relative, resolve } from "node:path";
5
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
6
6
  import { promisify } from "node:util";
7
7
  import { openPiSession, prepareDeploymentProjects, redactHostText } from "./coding-run-manager.js";
8
8
  import { ensureSshOrigin, gitTransportUrl, matchesRepository, SSH_ACCESS_HINT, } from "./git-transport.js";
9
9
  import { logGitPreparationFailure, logHostEvent } from "./host-log.js";
10
10
  import { liveEmployee } from "./live-employee.js";
11
11
  import { localModelUsage } from "./local-model-usage.js";
12
+ import { prepareMergeRequest } from "./merge-requests.js";
12
13
  import { paths } from "./paths.js";
13
14
  import { PiMessageQueue } from "./pi-message-queue.js";
14
15
  import { PlatformClientError } from "./platform-client.js";
@@ -97,11 +98,22 @@ export class QaSessionManager {
97
98
  return;
98
99
  }
99
100
  if (previous.session && !previous.session.isIdle && previous.queue) {
100
- await previous.emit?.("MESSAGE_QUEUE_UPDATED", "", {
101
- messageId: input.message.id,
102
- deliveryStatus: "QUEUED",
103
- });
104
- await previous.queue.submit(input.message.id, input.message.mode, input.message.contentMarkdown);
101
+ const queue = previous.queue;
102
+ const mode = input.message.mode;
103
+ const submission = (async () => {
104
+ await previous.emit?.("MESSAGE_QUEUE_UPDATED", "", {
105
+ messageId: input.message.id,
106
+ deliveryStatus: "QUEUED",
107
+ });
108
+ await queue.submit(input.message.id, mode, input.message.contentMarkdown);
109
+ })();
110
+ previous.submissions.add(submission);
111
+ try {
112
+ await submission;
113
+ }
114
+ finally {
115
+ previous.submissions.delete(submission);
116
+ }
105
117
  return;
106
118
  }
107
119
  await previous.done;
@@ -112,6 +124,7 @@ export class QaSessionManager {
112
124
  });
113
125
  const active = {
114
126
  stopping: false,
127
+ submissions: new Set(),
115
128
  done: Promise.resolve(),
116
129
  ready,
117
130
  markReady,
@@ -187,7 +200,7 @@ export class QaSessionManager {
187
200
  const live = liveEmployee({
188
201
  employeeConfig: client.qaEmployeeConfig.bind(client),
189
202
  employeeTool: client.qaEmployeeTool.bind(client),
190
- }, id, employeeBinding, initial, cwd, false, false, "DEVELOPMENT", () => active.stopping, () => `工单:${workItem.key} ${workItem.title}\n验证方式:${input.verificationMode ?? "AUTO"}\n测试仓库:${preparedWorkspace.testProject?.projectName ?? "未准备;当前目录用于工单证据"}\n当前目录:${cwd}\n业务源码参考(测试分支独立副本,不代表部署环境的运行版本):\n${preparedWorkspace.sourceProjects.map((p) => `${p.projectName}:${p.directory},分支 ${p.branch},提交 ${p.commitSha}`).join("\n") || "未配置业务项目"}`, () => { }, {});
203
+ }, id, employeeBinding, initial, cwd, false, false, "DEVELOPMENT", () => active.stopping, () => `工单:${workItem.key} ${workItem.title}\n当前任务:${input.releaseAssetTask ? `上线准备,仅处理测试资产 ${input.releaseAssetTask.sourceBranch} → ${input.releaseAssetTask.targetBranch},通过 report_qa_asset_merge 提交 MR;不启动 QA 测试。` : "QA 验证"}\n验证方式:${input.verificationMode ?? "AUTO"}\n测试仓库:${preparedWorkspace.testProject?.projectName ?? "未准备;当前目录用于工单证据"}\n当前目录:${cwd}\n业务源码参考(测试分支独立副本,不代表部署环境的运行版本):\n${preparedWorkspace.sourceProjects.map((p) => `${p.projectName}:${p.directory},分支 ${p.branch},提交 ${p.commitSha}`).join("\n") || "未配置业务项目"}`, () => { }, {});
191
204
  const opened = await openPiSession({
192
205
  cwd,
193
206
  sessionDir: join(paths().piSessions, "qa"),
@@ -275,6 +288,23 @@ export class QaSessionManager {
275
288
  const prompted = opened.session.prompt(message.contentMarkdown);
276
289
  active.markReady();
277
290
  await prompted;
291
+ // Pi 1.4.0 只在本次运行收尾前续跑已入队消息;运行中判定后才入队的补充消息会留在
292
+ // 空闲会话队列里。按空闲会话的既有处理方式由同一 QA 继续处理,不取消、不另建队列。
293
+ for (;;) {
294
+ await Promise.allSettled([...active.submissions]);
295
+ const unread = active.stopping ? [] : (active.queue?.takeUnread() ?? []);
296
+ if (!unread.length)
297
+ break;
298
+ for (const item of unread) {
299
+ if (active.stopping)
300
+ break;
301
+ await emit("MESSAGE_QUEUE_UPDATED", "", {
302
+ messageId: item.id,
303
+ deliveryStatus: "READ",
304
+ });
305
+ await opened.session.prompt(item.text);
306
+ }
307
+ }
278
308
  }
279
309
  await pending;
280
310
  if (modelError && !active.stopping)
@@ -286,6 +316,8 @@ export class QaSessionManager {
286
316
  throw error;
287
317
  }
288
318
  finally {
319
+ // 停止或失败时在途补充消息也须先进入 Pi,再如实标记未执行,不遗留为已排队。
320
+ await Promise.allSettled([...active.submissions]);
289
321
  for (const messageId of active.queue?.recall() ?? [])
290
322
  await emit("MESSAGE_QUEUE_UPDATED", "", { messageId, deliveryStatus: "CANCELLED" }).catch(() => undefined);
291
323
  unsubscribe?.();
@@ -342,15 +374,15 @@ export async function prepareQaProject(input) {
342
374
  workspaceId: input.workspaceId,
343
375
  workItemId: input.workItem.id,
344
376
  });
345
- const cwd = join(workRoot, input.project && input.verificationMode !== "AGENT" ? qaProjectName(input.project) : "evidence");
377
+ const cwd = join(workRoot, input.project ? qaProjectName(input.project) : "evidence");
346
378
  await claimQaDirectory(cwd, {
347
- projectId: input.project && input.verificationMode !== "AGENT" ? input.project.id : "evidence",
379
+ projectId: input.project ? input.project.id : "evidence",
348
380
  });
349
- if (!input.project || input.verificationMode === "AGENT") {
381
+ if (!input.project) {
350
382
  await mkdir(cwd, { recursive: true, mode: 0o700 });
351
383
  return cwd;
352
384
  }
353
- const branch = `qa/${input.workItem.key}`;
385
+ const branch = `aip/${input.workItem.key}`;
354
386
  await git("git", ["check-ref-format", "--branch", branch]);
355
387
  if (!input.project.mainBranch)
356
388
  throw new Error("QA_MAIN_BRANCH_REQUIRED");
@@ -419,7 +451,7 @@ export async function prepareQaWorkspace(input, cwd) {
419
451
  sourceProjects.push(await readPreparedProject(project.id, project.name, directory));
420
452
  }
421
453
  return {
422
- testProject: input.project && input.verificationMode !== "AGENT"
454
+ testProject: input.project
423
455
  ? await readPreparedProject(input.project.id, input.project.name, cwd)
424
456
  : null,
425
457
  sourceProjects,
@@ -465,47 +497,26 @@ export async function readQaAssetState(cwd, remoteUrl, expectedBranch, mainBranc
465
497
  const sourceCommitSha = source.trim();
466
498
  const mainCommitSha = main.trim();
467
499
  const remoteSource = remote.trim().split(/\s+/)[0];
468
- let hasChanges = Boolean(status.trim()) || remoteSource !== sourceCommitSha;
469
- if (!hasChanges) {
470
- try {
471
- await git("git", ["merge-base", "--is-ancestor", sourceCommitSha, mainCommitSha], { cwd });
472
- }
473
- catch (error) {
474
- if (error.code !== 1)
475
- throw error;
476
- hasChanges = true;
477
- }
500
+ let hasChanges = false;
501
+ try {
502
+ await git("git", ["merge-base", "--is-ancestor", sourceCommitSha, mainCommitSha], { cwd });
478
503
  }
479
- return { sourceCommitSha, mainCommitSha, hasChanges };
480
- }
481
- export async function verifyQaAssetMerge(cwd, remoteUrl, expectedBranch, mainBranch, sshRemoteUrl) {
482
- const { hasChanges, ...commits } = await readQaAssetState(cwd, remoteUrl, expectedBranch, mainBranch, sshRemoteUrl);
483
- if (hasChanges)
484
- throw new Error("QA_TEST_ASSET_NOT_MERGED:存在未提交、未推送或远端主分支尚未包含的测试资产");
485
- return commits;
486
- }
487
- /** 对照批准内容及实际合入结果;主分支其他文件的并行改动不属于本次 QA。 */
488
- export async function qaAssetContentChanged(cwd, approvedSource, approvedMain, source, main) {
489
- async function differs(from, to, files = []) {
504
+ catch (error) {
505
+ if (error.code !== 1)
506
+ throw error;
490
507
  try {
491
- await git("git", ["--literal-pathspecs", "diff", "--quiet", from, to, "--", ...files], {
492
- cwd,
493
- });
494
- return false;
508
+ await git("git", ["diff", "--quiet", `${mainCommitSha}...${sourceCommitSha}`, "--"], { cwd });
495
509
  }
496
510
  catch (error) {
497
511
  if (error.code !== 1)
498
512
  throw error;
499
- return true;
513
+ hasChanges = true;
500
514
  }
501
515
  }
502
- if (await differs(approvedSource, source))
503
- return true;
504
- const { stdout: base } = await git("git", ["merge-base", approvedSource, approvedMain], { cwd });
505
- // 禁用 rename 检测,保留旧路径和新路径;-z 与 literal pathspec 避免特殊文件名变成模式。
506
- const { stdout } = await git("git", ["diff", "--name-only", "--no-renames", "-z", base.trim(), approvedSource, "--"], { cwd });
507
- const files = stdout.split("\0").filter(Boolean);
508
- return files.length > 0 && (await differs(approvedSource, main, files));
516
+ const hasLocalChanges = Boolean(status.trim()) ||
517
+ Boolean(remoteSource && remoteSource !== sourceCommitSha) ||
518
+ (!remoteSource && hasChanges);
519
+ return { sourceCommitSha, mainCommitSha, hasChanges, hasLocalChanges };
509
520
  }
510
521
  export async function readQaScreenshot(cwd, filename) {
511
522
  const root = await realpath(cwd), path = await realpath(resolve(cwd, filename));
@@ -541,7 +552,7 @@ export function qaTools(client, input, binding, cwd, definitions) {
541
552
  throw new Error("QA_SESSION_COMMAND_INVALID");
542
553
  const workItem = input.workItem;
543
554
  const requireTestProject = () => {
544
- if (!input.project || input.verificationMode === "AGENT")
555
+ if (!input.project)
545
556
  throw new Error("QA_TEST_PROJECT_REQUIRED:当前会话未准备测试项目,请补齐配置后继续");
546
557
  return cwd;
547
558
  };
@@ -594,45 +605,47 @@ export function qaTools(client, input, binding, cwd, definitions) {
594
605
  }));
595
606
  }, api));
596
607
  api.registerTool(bindHostTool(definitions, "submit_qa_verification", async (callId, args) => {
597
- if (args.sourceVerificationId)
598
- return result(await client.qaSubmitVerification(id, {
599
- ...binding,
600
- toolCallId: callId,
601
- sourceVerificationId: args.sourceVerificationId,
602
- testItemIds: args.testItemIds,
603
- ...(args.content === undefined ? {} : { content: args.content }),
604
- }));
605
- if (!args.content?.trim() || !args.conclusion)
606
- throw new Error("QA_VERIFICATION_INVALID:请填写真实验证说明与结论,或引用 sourceVerificationId");
607
608
  if (args.conclusion === "UNVERIFIABLE" && !args.unverifiableReason?.trim())
608
- throw new Error("QA_VERIFICATION_DETAILS_REQUIRED:无法验证时须填写真实原因");
609
- if (args.conclusion === "WAIVER_REQUESTED" &&
610
- (!args.waiverReason?.trim() || !args.waiverRisk?.trim() || !args.waiverScope?.trim()))
611
- throw new Error("QA_WAIVER_DETAILS_REQUIRED:申请豁免须说明理由、未覆盖风险和影响范围");
609
+ throw new Error("QA_VERIFICATION_DETAILS_REQUIRED:unverifiableReason 无法验证时须填写真实原因");
610
+ const screenshots = [];
611
+ for (const [index, file] of args.screenshots.entries()) {
612
+ try {
613
+ screenshots.push(await readQaScreenshot(cwd, file));
614
+ }
615
+ catch (error) {
616
+ const code = error.code ?? error.message;
617
+ const feedback = {
618
+ ENOENT: "文件不存在,请确认截图已保存并填写当前工作目录中的真实路径。",
619
+ EACCES: "文件不可读,请检查当前 Host 的文件读取权限。",
620
+ EPERM: "文件不可读,请检查当前 Host 的文件读取权限。",
621
+ QA_SCREENSHOT_OUTSIDE_WORKSPACE: "路径不在当前工作目录中,请先将真实截图保存在当前工作目录内。",
622
+ QA_SCREENSHOT_TYPE_INVALID: "文件类型不支持,请提供 PNG、JPEG 或 WebP 截图。",
623
+ QA_SCREENSHOT_SIZE_INVALID: "不是普通文件或超过 10 MiB,请提供符合大小限制的截图文件。",
624
+ };
625
+ if (code && feedback[code])
626
+ throw new Error(`QA_SCREENSHOT_INVALID:screenshots[${index}] ${feedback[code]}`);
627
+ throw error;
628
+ }
629
+ }
612
630
  const attachmentIds = [];
613
- for (const file of args.screenshots ?? [])
614
- attachmentIds.push((await client.qaUploadSessionAttachment(id, {
615
- ...binding,
616
- ...(await readQaScreenshot(cwd, file)),
617
- })).id);
631
+ for (const screenshot of screenshots)
632
+ attachmentIds.push((await client.qaUploadSessionAttachment(id, { ...binding, ...screenshot })).id);
618
633
  return result(await client.qaSubmitVerification(id, {
619
634
  ...binding,
620
635
  toolCallId: callId,
621
- content: args.content,
636
+ ...(args.content === undefined ? {} : { content: args.content }),
622
637
  testItemIds: args.testItemIds,
623
- ...(args.expected === undefined ? {} : { expected: args.expected }),
624
- ...(args.actual === undefined ? {} : { actual: args.actual }),
638
+ expected: args.expected,
639
+ actual: args.actual,
625
640
  ...(args.checkpoints === undefined ? {} : { checkpoints: args.checkpoints }),
626
- ...(args.waiverReason === undefined ? {} : { waiverReason: args.waiverReason }),
627
- ...(args.waiverRisk === undefined ? {} : { waiverRisk: args.waiverRisk }),
628
- ...(args.waiverScope === undefined ? {} : { waiverScope: args.waiverScope }),
629
641
  ...(args.unverifiableReason ? { unverifiableReason: args.unverifiableReason } : {}),
630
- ...(args.steps === undefined ? {} : { steps: args.steps }),
642
+ steps: args.steps,
631
643
  conclusion: args.conclusion,
632
644
  attachmentIds,
633
- ...(args.ac ? { ac: args.ac } : {}),
634
645
  }));
635
646
  }, api));
647
+ api.registerTool(bindHostTool(definitions, "reuse_qa_verification", async (callId, args) => result(await client.qaReuseVerification(id, { ...args, ...binding, toolCallId: callId })), api));
648
+ api.registerTool(bindHostTool(definitions, "request_qa_waiver", async (callId, args) => result(await client.qaRequestWaiver(id, { ...args, ...binding, toolCallId: callId })), api));
636
649
  api.registerTool(bindHostTool(definitions, "report_qa_defects", async (callId, args) => {
637
650
  return result(await client.qaReportDefects(id, {
638
651
  defects: args.defects,
@@ -657,9 +670,9 @@ export function qaTools(client, input, binding, cwd, definitions) {
657
670
  api.registerTool(bindHostTool(definitions, "complete_qa_review", async (callId, args) => {
658
671
  return result(await client.qaCompleteReview(id, {
659
672
  summary: args.summary,
660
- ...(input.project && input.verificationMode !== "AGENT"
673
+ ...(input.project
661
674
  ? {
662
- assetState: await readQaAssetState(cwd, input.project.remoteUrl, `qa/${workItem.key}`, requireQaMainBranch(input), input.project.sshRemoteUrl),
675
+ assetState: await readQaAssetState(cwd, input.project.remoteUrl, `aip/${workItem.key}`, requireQaMainBranch(input), input.project.sshRemoteUrl),
663
676
  }
664
677
  : {}),
665
678
  ...binding,
@@ -667,26 +680,39 @@ export function qaTools(client, input, binding, cwd, definitions) {
667
680
  }));
668
681
  }, api));
669
682
  api.registerTool(bindHostTool(definitions, "report_qa_asset_merge", async (callId, args) => {
670
- if (!input.acceptanceDeliveryId)
671
- throw new Error("QA_ACCEPTANCE_CONFIRMATION_REQUIRED");
672
683
  requireTestProject();
673
- if (!input.project)
674
- throw new Error("QA_TEST_PROJECT_REQUIRED");
675
- const commits = args.status === "SUCCEEDED"
676
- ? await verifyQaAssetMerge(cwd, input.project.remoteUrl, `qa/${workItem.key}`, requireQaMainBranch(input), input.project.sshRemoteUrl)
677
- : null;
678
- let contentChanged = false;
679
- if (commits) {
680
- if (!input.approvedSourceCommitSha || !input.approvedMainCommitSha)
681
- throw new Error("QA_ACCEPTANCE_SOURCE_REQUIRED");
682
- contentChanged = await qaAssetContentChanged(cwd, input.approvedSourceCommitSha, input.approvedMainCommitSha, commits.sourceCommitSha, commits.mainCommitSha);
684
+ const task = input.releaseAssetTask;
685
+ if (!input.project || !task)
686
+ throw new Error("QA_RELEASE_TASK_REQUIRED:当前没有测试资产上线准备任务");
687
+ if (task.projectId !== input.project.id)
688
+ throw new Error("QA_RELEASE_PROJECT_MISMATCH");
689
+ let mergeRequest;
690
+ if (args.status === "SUCCEEDED") {
691
+ const status = await git("git", ["status", "--porcelain", "--untracked-files=all"], {
692
+ cwd,
693
+ });
694
+ if (status.stdout.trim())
695
+ throw new Error("QA_RELEASE_WORKTREE_DIRTY:请提交测试资产修改后再准备 MR");
696
+ mergeRequest = await prepareMergeRequest({
697
+ project: {
698
+ id: task.projectId,
699
+ name: input.project.name,
700
+ repositoryUrl: input.project.remoteUrl,
701
+ devBranch: task.sourceBranch,
702
+ baselineBranch: task.targetBranch,
703
+ },
704
+ cwd,
705
+ title: args.title ?? `${workItem.key} 测试资产`,
706
+ description: args.description ?? args.summary,
707
+ updateExisting: args.updateExisting === true,
708
+ pendingFile: join(dirname(cwd), `release-mr-${task.id}.json`),
709
+ });
683
710
  }
684
711
  return result(await client.qaReportAssetMerge(id, {
685
- deliveryId: input.acceptanceDeliveryId,
686
- ...(args.status === "SUCCEEDED" ? { contentChanged } : {}),
712
+ releaseAssetTaskId: task.id,
687
713
  status: args.status,
688
714
  summary: args.summary,
689
- ...commits,
715
+ ...(mergeRequest ? { mergeRequest } : {}),
690
716
  ...binding,
691
717
  toolCallId: callId,
692
718
  }));