@testin-official/xagent 0.3.12 → 0.3.14

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 (69) hide show
  1. package/README.md +98 -2
  2. package/dist/assets/contracts/app-upload.schema.json +3 -2
  3. package/dist/assets/contracts/build-create.schema.json +17 -0
  4. package/dist/assets/contracts/build-list.schema.json +18 -0
  5. package/dist/assets/contracts/build.schema.json +76 -0
  6. package/dist/assets/contracts/execution-target.schema.json +12 -4
  7. package/dist/assets/contracts/fixtures/execution-target.concurrency-twenty-one.invalid.json +4 -0
  8. package/dist/assets/contracts/fixtures/execution-target.concurrency-two.invalid.json +1 -1
  9. package/dist/assets/contracts/fixtures/execution-target.concurrency-two.valid.json +4 -0
  10. package/dist/assets/contracts/fixtures/execution-target.count-eleven.invalid.json +6 -0
  11. package/dist/assets/contracts/fixtures/execution-target.count-two.invalid.json +1 -1
  12. package/dist/assets/contracts/fixtures/execution-target.count-two.valid.json +6 -0
  13. package/dist/assets/contracts/fixtures/execution-target.multiple-devices.invalid.json +23 -1
  14. package/dist/assets/contracts/fixtures/execution-target.multiple-devices.valid.json +4 -0
  15. package/dist/assets/contracts/fixtures/execution-target.multiple-filters.invalid.json +66 -2
  16. package/dist/assets/contracts/fixtures/execution-target.multiple-filters.valid.json +7 -0
  17. package/dist/assets/contracts/fixtures/target-hash-cases.json +52 -1
  18. package/dist/assets/contracts/fixtures/target-preview.success.json +4 -1
  19. package/dist/assets/contracts/fixtures/target-preview.unavailable.json +4 -1
  20. package/dist/assets/contracts/run-create-result.schema.json +18 -0
  21. package/dist/assets/contracts/run-create-v2.schema.json +85 -19
  22. package/dist/assets/contracts/run.schema.json +179 -34
  23. package/dist/assets/contracts/target-preview.schema.json +89 -19
  24. package/dist/cli.d.ts.map +1 -1
  25. package/dist/cli.js +324 -19
  26. package/dist/cli.js.map +1 -1
  27. package/dist/core/version.d.ts +1 -1
  28. package/dist/core/version.js +1 -1
  29. package/dist/project/target-matrix.d.ts +4 -0
  30. package/dist/project/target-matrix.d.ts.map +1 -0
  31. package/dist/project/target-matrix.js +26 -0
  32. package/dist/project/target-matrix.js.map +1 -0
  33. package/dist/run/batch.d.ts +44 -0
  34. package/dist/run/batch.d.ts.map +1 -0
  35. package/dist/run/batch.js +261 -0
  36. package/dist/run/batch.js.map +1 -0
  37. package/dist/run/builds.d.ts +20 -0
  38. package/dist/run/builds.d.ts.map +1 -0
  39. package/dist/run/builds.js +70 -0
  40. package/dist/run/builds.js.map +1 -0
  41. package/dist/run/create-result.d.ts +6 -0
  42. package/dist/run/create-result.d.ts.map +1 -0
  43. package/dist/run/create-result.js +18 -0
  44. package/dist/run/create-result.js.map +1 -0
  45. package/dist/run/exit-codes.d.ts +8 -0
  46. package/dist/run/exit-codes.d.ts.map +1 -0
  47. package/dist/run/exit-codes.js +47 -0
  48. package/dist/run/exit-codes.js.map +1 -0
  49. package/dist/run/idempotency.d.ts +2 -0
  50. package/dist/run/idempotency.d.ts.map +1 -0
  51. package/dist/run/idempotency.js +13 -0
  52. package/dist/run/idempotency.js.map +1 -0
  53. package/dist/run/junit-suite.d.ts +17 -0
  54. package/dist/run/junit-suite.d.ts.map +1 -0
  55. package/dist/run/junit-suite.js +98 -0
  56. package/dist/run/junit-suite.js.map +1 -0
  57. package/dist/run/junit.d.ts +19 -0
  58. package/dist/run/junit.d.ts.map +1 -0
  59. package/dist/run/junit.js +218 -0
  60. package/dist/run/junit.js.map +1 -0
  61. package/dist/run/scripts.d.ts +9 -0
  62. package/dist/run/scripts.d.ts.map +1 -0
  63. package/dist/run/scripts.js +156 -0
  64. package/dist/run/scripts.js.map +1 -0
  65. package/dist/sdk/client.d.ts +7 -0
  66. package/dist/sdk/client.d.ts.map +1 -1
  67. package/dist/sdk/client.js +46 -0
  68. package/dist/sdk/client.js.map +1 -1
  69. package/package.json +2 -2
@@ -0,0 +1,261 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { CliError, XAgentApiError } from "../core/errors.js";
3
+ import { onInterrupt } from "../core/interrupt.js";
4
+ import { worstExitCode, exitCodeForRunStatus, exitCodeForError } from "./exit-codes.js";
5
+ import { deriveRunIdempotencyKey } from "./idempotency.js";
6
+ import { writeBuildJUnitFile } from "./junit-suite.js";
7
+ import { isTerminalRunStatus, writeRunJUnitFile } from "./junit.js";
8
+ import { inferBuildStart } from "./builds.js";
9
+ import { unwrapCreatedRuns } from "./create-result.js";
10
+ import { isMatrixTarget } from "../project/target-matrix.js";
11
+ export async function runScriptBatch(params) {
12
+ const { ctx, profile, client, scripts, options, emit } = params;
13
+ if (profile.data.expected_token_type !== "project_ci") {
14
+ throw new CliError("token_type_mismatch", "running more than one script, or using a build, requires a project_ci Profile", 3);
15
+ }
16
+ if (options.maxParallel < 1 || !Number.isInteger(options.maxParallel)) {
17
+ throw new CliError("invalid_request", "--max-parallel must be a positive integer", 2);
18
+ }
19
+ const targetForGate = await options.resolveTarget(options.targetName);
20
+ const matrixTarget = isMatrixTarget(targetForGate.definition);
21
+ if ((scripts.length > 1 || matrixTarget) && options.packageId === undefined && !(options.appUploadId && options.promote)) {
22
+ throw new CliError("invalid_request", "multiple scripts or a matrix Target require --package-id, or --app-upload-id with --promote", 2);
23
+ }
24
+ if (matrixTarget && !options.buildId && !options.buildAuto) {
25
+ throw new CliError("invalid_request", "a matrix Target requires --build-id or --build auto", 2);
26
+ }
27
+ let packageId = options.packageId;
28
+ if (options.appUploadId && options.promote) {
29
+ const promoted = await client.promoteApp(options.appUploadId);
30
+ const promotedId = Number(promoted.package_id);
31
+ if (!Number.isInteger(promotedId) || promotedId < 1) {
32
+ throw new XAgentApiError("invalid_response", "apps promote did not return a package_id");
33
+ }
34
+ packageId = promotedId;
35
+ }
36
+ if ((scripts.length > 1 || matrixTarget) && packageId === undefined) {
37
+ throw new CliError("invalid_request", "multiple scripts or a matrix Target require --package-id, or --app-upload-id with --promote", 2);
38
+ }
39
+ let buildId = options.buildId;
40
+ let openedBuild;
41
+ if (options.buildAuto) {
42
+ const inferred = inferBuildStart({ idempotencyKey: `${options.baseIdempotencyKey}:build` });
43
+ const key = inferred.idempotency_key ?? `${options.baseIdempotencyKey}:build`;
44
+ openedBuild = await client.createBuild({
45
+ schema_version: "xagent-build-create/v1",
46
+ name: inferred.name,
47
+ external_id: inferred.external_id,
48
+ source: inferred.source,
49
+ commit_sha: inferred.commit_sha,
50
+ ref: inferred.ref,
51
+ pipeline_url: inferred.pipeline_url,
52
+ }, key);
53
+ buildId = String(openedBuild.id ?? "");
54
+ if (!buildId)
55
+ throw new XAgentApiError("invalid_response", "builds start did not return a build id");
56
+ }
57
+ const target = targetForGate;
58
+ const created = [];
59
+ const createdIds = [];
60
+ const waiting = new AbortController();
61
+ let primaryError;
62
+ const waitStartedAt = Date.now();
63
+ const cancelCreated = async () => {
64
+ waiting.abort();
65
+ if (buildId && (options.buildAuto || createdIds.length > 1)) {
66
+ try {
67
+ await client.cancelBuild(buildId);
68
+ return;
69
+ }
70
+ catch (error) {
71
+ process.stderr.write(`Cancel build ${buildId} failed: ${error instanceof Error ? error.message : String(error)}\n`);
72
+ }
73
+ }
74
+ for (const id of createdIds) {
75
+ try {
76
+ await client.cancelRun(id);
77
+ }
78
+ catch (error) {
79
+ process.stderr.write(`Cancel run ${id} failed: ${error instanceof Error ? error.message : String(error)}\n`);
80
+ }
81
+ }
82
+ };
83
+ const detach = onInterrupt(async () => {
84
+ await cancelCreated();
85
+ await writeOutputs();
86
+ });
87
+ const writeOutputs = async () => {
88
+ const runs = created.map((item) => item.run).filter((item) => Boolean(item));
89
+ if (options.output && runs.length) {
90
+ const payload = { build_id: buildId, runs };
91
+ try {
92
+ await writeFile(options.output, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
93
+ }
94
+ catch (error) {
95
+ process.stderr.write(`Warning: unable to write --output ${options.output}: ${error instanceof Error ? error.message : String(error)}\n`);
96
+ }
97
+ }
98
+ if (options.junit) {
99
+ try {
100
+ if (scripts.length === 1 && runs.length === 1 && runs[0]) {
101
+ await writeRunJUnitFile(options.junit, runs[0], {
102
+ scriptName: typeof scripts[0].script.name === "string" ? scripts[0].script.name : undefined,
103
+ scriptFile: scripts[0].file,
104
+ elapsedSeconds: (Date.now() - waitStartedAt) / 1000,
105
+ incompleteReason: junitReason(runs[0]?.status, primaryError, waiting.signal.aborted),
106
+ });
107
+ }
108
+ else {
109
+ let build = openedBuild ?? (buildId ? { id: buildId } : { name: "xagent-build" });
110
+ try {
111
+ if (buildId)
112
+ build = await client.getBuild(buildId);
113
+ }
114
+ catch { }
115
+ await writeBuildJUnitFile(options.junit, build, created.map((item) => ({
116
+ run: item.run,
117
+ options: {
118
+ scriptName: typeof item.script.script.name === "string" ? item.script.script.name : undefined,
119
+ scriptFile: item.script.file,
120
+ incompleteReason: junitReason(item.run?.status, item.error ?? primaryError, waiting.signal.aborted),
121
+ },
122
+ })), { elapsedSeconds: (Date.now() - waitStartedAt) / 1000 });
123
+ }
124
+ }
125
+ catch (error) {
126
+ process.stderr.write(`Warning: unable to write --junit ${options.junit}: ${error instanceof Error ? error.message : String(error)}\n`);
127
+ }
128
+ }
129
+ };
130
+ try {
131
+ let next = 0;
132
+ const workers = Math.min(options.maxParallel, scripts.length);
133
+ const runOne = async (script) => {
134
+ const request = {
135
+ schema_version: "xagent-run-create/v2",
136
+ script: structuredClone(script.script),
137
+ target_name: target.name,
138
+ target_hash: target.targetHash,
139
+ target: target.definition,
140
+ timeout_ms: options.timeoutMs,
141
+ device_wait_timeout_ms: options.deviceWaitTimeoutMs ?? 600000,
142
+ source_hash: script.sourceHash,
143
+ };
144
+ if (packageId !== undefined)
145
+ request.package_id = packageId;
146
+ if (Object.keys(options.variables).length)
147
+ request.variables = options.variables;
148
+ if (buildId)
149
+ request.build_id = buildId;
150
+ const key = deriveRunIdempotencyKey(options.baseIdempotencyKey, script.relativePath, target.name);
151
+ const entry = { script };
152
+ created.push(entry);
153
+ try {
154
+ const payload = await client.createRun(request, key);
155
+ const unwrapped = unwrapCreatedRuns(payload);
156
+ if (unwrapped.buildId && !buildId)
157
+ buildId = unwrapped.buildId;
158
+ const createdRuns = unwrapped.runs;
159
+ if (!createdRuns.length)
160
+ throw new XAgentApiError("invalid_response", "create run did not return a Run");
161
+ entry.run = createdRuns[0];
162
+ const runId = String(createdRuns[0].id ?? "");
163
+ if (runId)
164
+ createdIds.push(runId);
165
+ const extraEntries = createdRuns.slice(1).map((run) => {
166
+ const extraId = String(run.id ?? "");
167
+ if (extraId)
168
+ createdIds.push(extraId);
169
+ return { script, run };
170
+ });
171
+ created.push(...extraEntries);
172
+ if (options.wait && !waiting.signal.aborted) {
173
+ const waitEntry = async (item) => {
174
+ const id = String(item.run?.id ?? "");
175
+ if (!id || waiting.signal.aborted)
176
+ return;
177
+ const run = await client.waitRun(id, options.waitTimeoutSeconds, options.pollIntervalSeconds, (value) => { item.run = value; }, waiting.signal);
178
+ item.run = run;
179
+ const index = createdIds.indexOf(id);
180
+ if (index >= 0 && isTerminalRunStatus(run.status))
181
+ createdIds.splice(index, 1);
182
+ };
183
+ await Promise.all([waitEntry(entry), ...extraEntries.map((item) => waitEntry(item))]);
184
+ }
185
+ }
186
+ catch (error) {
187
+ entry.error = error;
188
+ if (!primaryError)
189
+ primaryError = error;
190
+ }
191
+ };
192
+ const worker = async () => {
193
+ while (next < scripts.length && !waiting.signal.aborted) {
194
+ const index = next;
195
+ next += 1;
196
+ await runOne(scripts[index]);
197
+ }
198
+ };
199
+ await Promise.all(Array.from({ length: workers }, () => worker()));
200
+ if (options.buildAuto && buildId && !waiting.signal.aborted) {
201
+ try {
202
+ openedBuild = await client.closeBuild(buildId);
203
+ }
204
+ catch (error) {
205
+ if (!primaryError)
206
+ primaryError = error;
207
+ }
208
+ }
209
+ }
210
+ finally {
211
+ await writeOutputs();
212
+ detach();
213
+ }
214
+ const codes = [];
215
+ for (const item of created) {
216
+ const fromStatus = exitCodeForRunStatus(item.run?.status, item.run?.reason);
217
+ if (fromStatus !== undefined)
218
+ codes.push(fromStatus);
219
+ else if (item.error)
220
+ codes.push(exitFromError(item.error));
221
+ }
222
+ const exitCode = codes.length ? worstExitCode(codes) : (primaryError ? exitFromError(primaryError) : 0);
223
+ const payload = {
224
+ build_id: buildId,
225
+ runs: created.map((item) => item.run).filter(Boolean),
226
+ };
227
+ emit(payload, humanSummary(buildId, created));
228
+ if (ctx.json && exitCode) {
229
+ // Keep JSON output as the payload; the process exit code still reflects D3.
230
+ }
231
+ if (primaryError && !created.some((item) => item.run))
232
+ throw primaryError;
233
+ return exitCode;
234
+ }
235
+ export function junitReason(status, error, aborted = false) {
236
+ if (isTerminalRunStatus(status))
237
+ return undefined;
238
+ if (aborted)
239
+ return "cancelled";
240
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : undefined;
241
+ if (code === "timeout")
242
+ return "wait_timeout";
243
+ if (status)
244
+ return "incomplete";
245
+ return undefined;
246
+ }
247
+ function exitFromError(error) {
248
+ return exitCodeForError(error);
249
+ }
250
+ function humanSummary(buildId, created) {
251
+ const parts = created.map((item) => {
252
+ const name = item.script.relativePath;
253
+ if (item.run)
254
+ return `${name} ${item.run.id} ${item.run.status}`;
255
+ const message = item.error instanceof Error ? item.error.message : String(item.error ?? "failed");
256
+ return `${name} error: ${message}`;
257
+ });
258
+ const prefix = buildId ? `Build ${buildId}` : "Runs";
259
+ return `${prefix}: ${parts.join("; ")}`;
260
+ }
261
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/run/batch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export type BuildStartInput = {
2
+ name?: string;
3
+ externalId?: string;
4
+ commit?: string;
5
+ ref?: string;
6
+ source?: string;
7
+ pipelineUrl?: string;
8
+ idempotencyKey?: string;
9
+ };
10
+ export type InferredBuildStart = {
11
+ name?: string;
12
+ external_id?: string;
13
+ source?: "gitlab" | "github" | "other";
14
+ commit_sha?: string;
15
+ ref?: string;
16
+ pipeline_url?: string;
17
+ idempotency_key?: string;
18
+ };
19
+ export declare function inferBuildStart(input: BuildStartInput, env?: NodeJS.Dict<string>): InferredBuildStart;
20
+ //# sourceMappingURL=builds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builds.d.ts","sourceRoot":"","sources":["../../src/run/builds.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,wBAAgB,eAAe,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,GAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAe,GAAG,kBAAkB,CAiBlH"}
@@ -0,0 +1,70 @@
1
+ export function inferBuildStart(input, env = process.env) {
2
+ const inferred = inferFromCi(env);
3
+ const source = normalizeSource(input.source) ?? inferred.source ?? "other";
4
+ const result = { source };
5
+ const name = emptyToUndef(input.name) ?? inferred.name;
6
+ const externalId = emptyToUndef(input.externalId) ?? inferred.external_id;
7
+ const commit = emptyToUndef(input.commit) ?? inferred.commit_sha;
8
+ const ref = emptyToUndef(input.ref) ?? inferred.ref;
9
+ const pipelineUrl = emptyToUndef(input.pipelineUrl) ?? inferred.pipeline_url;
10
+ const idempotencyKey = emptyToUndef(input.idempotencyKey) ?? inferred.idempotency_key;
11
+ if (name)
12
+ result.name = name;
13
+ if (externalId)
14
+ result.external_id = externalId;
15
+ if (commit)
16
+ result.commit_sha = commit;
17
+ if (ref)
18
+ result.ref = ref;
19
+ if (pipelineUrl)
20
+ result.pipeline_url = pipelineUrl;
21
+ if (idempotencyKey)
22
+ result.idempotency_key = idempotencyKey;
23
+ return result;
24
+ }
25
+ function inferFromCi(env) {
26
+ if (env.GITLAB_CI) {
27
+ const jobId = emptyToUndef(env.CI_JOB_ID);
28
+ return {
29
+ source: "gitlab",
30
+ name: emptyToUndef(env.CI_JOB_NAME) ?? emptyToUndef(env.CI_PIPELINE_NAME) ?? "gitlab",
31
+ external_id: jobId,
32
+ commit_sha: emptyToUndef(env.CI_COMMIT_SHA),
33
+ ref: emptyToUndef(env.CI_COMMIT_REF_NAME),
34
+ pipeline_url: emptyToUndef(env.CI_PIPELINE_URL),
35
+ idempotency_key: jobId && env.CI_PROJECT_ID ? `gitlab-${env.CI_PROJECT_ID}-${jobId}` : jobId,
36
+ };
37
+ }
38
+ if (env.GITHUB_ACTIONS) {
39
+ const runId = emptyToUndef(env.GITHUB_RUN_ID);
40
+ const attempt = emptyToUndef(env.GITHUB_RUN_ATTEMPT) ?? "1";
41
+ const job = emptyToUndef(env.GITHUB_JOB);
42
+ const external = [runId, attempt, job].filter(Boolean).join("-");
43
+ const server = emptyToUndef(env.GITHUB_SERVER_URL);
44
+ const repo = emptyToUndef(env.GITHUB_REPOSITORY);
45
+ return {
46
+ source: "github",
47
+ name: emptyToUndef(env.GITHUB_WORKFLOW) ?? emptyToUndef(env.GITHUB_JOB) ?? "github",
48
+ external_id: emptyToUndef(external),
49
+ commit_sha: emptyToUndef(env.GITHUB_SHA),
50
+ ref: emptyToUndef(env.GITHUB_REF_NAME),
51
+ pipeline_url: server && repo && runId ? `${server}/${repo}/actions/runs/${runId}` : undefined,
52
+ idempotency_key: env.GITHUB_REPOSITORY_ID && runId
53
+ ? `github-${env.GITHUB_REPOSITORY_ID}-${runId}-${attempt}${job ? `-${job}` : ""}`
54
+ : undefined,
55
+ };
56
+ }
57
+ return { source: "other" };
58
+ }
59
+ function normalizeSource(value) {
60
+ if (!value)
61
+ return undefined;
62
+ if (value === "gitlab" || value === "github" || value === "other")
63
+ return value;
64
+ return "other";
65
+ }
66
+ function emptyToUndef(value) {
67
+ const text = value?.trim();
68
+ return text ? text : undefined;
69
+ }
70
+ //# sourceMappingURL=builds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builds.js","sourceRoot":"","sources":["../../src/run/builds.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const RUN_CREATE_RESULT_SCHEMA_VERSION = "xagent-run-create-result/v1";
2
+ export declare function unwrapCreatedRuns(payload: unknown): {
3
+ buildId?: string;
4
+ runs: Record<string, any>[];
5
+ };
6
+ //# sourceMappingURL=create-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-result.d.ts","sourceRoot":"","sources":["../../src/run/create-result.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gCAAgC,gCAAgC,CAAC;AAE9E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAA;CAAE,CAerG"}
@@ -0,0 +1,18 @@
1
+ export const RUN_CREATE_RESULT_SCHEMA_VERSION = "xagent-run-create-result/v1";
2
+ export function unwrapCreatedRuns(payload) {
3
+ const record = payload && typeof payload === "object" ? payload : {};
4
+ if (record.schema_version === RUN_CREATE_RESULT_SCHEMA_VERSION && Array.isArray(record.runs)) {
5
+ return {
6
+ buildId: typeof record.build_id === "string" && record.build_id ? record.build_id : undefined,
7
+ runs: record.runs.filter((item) => item && typeof item === "object"),
8
+ };
9
+ }
10
+ if (typeof record.id === "string" && record.id) {
11
+ return {
12
+ buildId: typeof record.build_id === "string" && record.build_id ? record.build_id : undefined,
13
+ runs: [record],
14
+ };
15
+ }
16
+ return { runs: [] };
17
+ }
18
+ //# sourceMappingURL=create-result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-result.js","sourceRoot":"","sources":["../../src/run/create-result.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gCAAgC,GAAG,6BAA6B,CAAC;AAE9E,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,MAAM,MAAM,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAA8B,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5F,IAAI,MAAM,CAAC,cAAc,KAAK,gCAAgC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7F,OAAO;YACL,OAAO,EAAE,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YAC7F,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAa,EAAE,EAAE,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAA0B;SACvG,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QAC/C,OAAO;YACL,OAAO,EAAE,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YAC7F,IAAI,EAAE,CAAC,MAAM,CAAC;SACf,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const API_EXIT: Record<string, number>;
2
+ export declare function exitCodeForError(error: unknown): number;
3
+ /** Confirmed D3 order: surface permission and configuration problems first. */
4
+ export declare const EXIT_CODE_PRIORITY: readonly [3, 2, 6, 1, 7, 5, 4, 0];
5
+ export declare const RUN_STATUS_EXIT_CODES: Record<string, number>;
6
+ export declare function exitCodeForRunStatus(status: unknown, reason?: unknown): number | undefined;
7
+ export declare function worstExitCode(codes: Iterable<number>): number;
8
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../../src/run/exit-codes.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO3C,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIvD;AAED,+EAA+E;AAC/E,eAAO,MAAM,kBAAkB,mCAAoC,CAAC;AAEpE,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMxD,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK1F;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAY7D"}
@@ -0,0 +1,47 @@
1
+ import { CliError, XAgentApiError } from "../core/errors.js";
2
+ export const API_EXIT = {
3
+ invalid_request: 2, schema_invalid: 2, configuration_invalid: 2, target_not_found: 2, target_invalid: 2,
4
+ target_hash_mismatch: 2, idempotency_conflict: 2, authoring_state_invalid: 2, revision_conflict: 2, action_in_progress: 2, observation_stale: 2,
5
+ attempt_in_progress: 2, authentication_required: 3, token_invalid: 3, token_expired: 3, token_revoked: 3,
6
+ token_type_mismatch: 3, permission_denied: 3, cancelled: 4, device_unavailable: 5, resource_not_found: 5,
7
+ authoring_session_expired: 5, authoring_session_not_active: 5,
8
+ test_failed: 1, infrastructure_failed: 6, invalid_response: 6, authoring_session_renewal_failed: 6, timeout: 7,
9
+ };
10
+ export function exitCodeForError(error) {
11
+ if (error instanceof CliError)
12
+ return error.exitCode;
13
+ if (error instanceof XAgentApiError)
14
+ return API_EXIT[error.code] ?? 6;
15
+ return 6;
16
+ }
17
+ /** Confirmed D3 order: surface permission and configuration problems first. */
18
+ export const EXIT_CODE_PRIORITY = [3, 2, 6, 1, 7, 5, 4, 0];
19
+ export const RUN_STATUS_EXIT_CODES = {
20
+ passed: 0,
21
+ failed: 1,
22
+ cancelled: 4,
23
+ infrastructure_failed: 6,
24
+ timed_out: 7,
25
+ };
26
+ export function exitCodeForRunStatus(status, reason) {
27
+ if (typeof status !== "string")
28
+ return undefined;
29
+ // D5: a device-wait timeout is a resource problem, not an infrastructure fault.
30
+ if (status === "infrastructure_failed" && reason === "device_wait_timeout")
31
+ return 5;
32
+ return status in RUN_STATUS_EXIT_CODES ? RUN_STATUS_EXIT_CODES[status] : undefined;
33
+ }
34
+ export function worstExitCode(codes) {
35
+ let worstIndex = EXIT_CODE_PRIORITY.length - 1;
36
+ let seen = false;
37
+ for (const code of codes) {
38
+ const index = EXIT_CODE_PRIORITY.indexOf(code);
39
+ const ranked = index === -1 ? EXIT_CODE_PRIORITY.length : index;
40
+ if (!seen || ranked < worstIndex) {
41
+ worstIndex = ranked;
42
+ seen = true;
43
+ }
44
+ }
45
+ return seen ? EXIT_CODE_PRIORITY[Math.min(worstIndex, EXIT_CODE_PRIORITY.length - 1)] : 0;
46
+ }
47
+ //# sourceMappingURL=exit-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/run/exit-codes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function deriveRunIdempotencyKey(baseKey: string, scriptPath: string, targetName: string): string;
2
+ //# sourceMappingURL=idempotency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../../src/run/idempotency.ts"],"names":[],"mappings":"AAIA,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAQvG"}
@@ -0,0 +1,13 @@
1
+ import { createHash } from "node:crypto";
2
+ const KEY_MAX_LENGTH = 255;
3
+ export function deriveRunIdempotencyKey(baseKey, scriptPath, targetName) {
4
+ const relative = scriptPath.replaceAll("\\", "/");
5
+ const suffix = `:${relative}:${targetName}`;
6
+ const combined = `${baseKey}${suffix}`;
7
+ if (combined.length <= KEY_MAX_LENGTH)
8
+ return combined;
9
+ const digest = createHash("sha256").update(suffix).digest("hex");
10
+ const hashed = `${baseKey}:${digest}`;
11
+ return hashed.length <= KEY_MAX_LENGTH ? hashed : hashed.slice(0, KEY_MAX_LENGTH);
12
+ }
13
+ //# sourceMappingURL=idempotency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idempotency.js","sourceRoot":"","sources":["../../src/run/idempotency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B,MAAM,UAAU,uBAAuB,CAAC,OAAe,EAAE,UAAkB,EAAE,UAAkB;IAC7F,MAAM,QAAQ,GAAG,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,IAAI,QAAQ,IAAI,UAAU,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAAG,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC;IACvC,IAAI,QAAQ,CAAC,MAAM,IAAI,cAAc;QAAE,OAAO,QAAQ,CAAC;IACvD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjE,MAAM,MAAM,GAAG,GAAG,OAAO,IAAI,MAAM,EAAE,CAAC;IACtC,OAAO,MAAM,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;AACpF,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type JUnitRunOptions } from "./junit.js";
2
+ export type SuiteRunInput = {
3
+ run: Record<string, any> | null | undefined;
4
+ options?: JUnitRunOptions;
5
+ };
6
+ /**
7
+ * Suite-level JUnit for a build: one testsuites, one testsuite per target,
8
+ * one testcase per script x device (a single Run). Single-run reports stay
9
+ * on renderRunJUnit() and are unchanged.
10
+ */
11
+ export declare function renderBuildJUnit(build: Record<string, any> | null | undefined, runs: SuiteRunInput[], options?: {
12
+ elapsedSeconds?: number;
13
+ }): string;
14
+ export declare function writeBuildJUnitFile(file: string, build: Record<string, any> | null | undefined, runs: SuiteRunInput[], options?: {
15
+ elapsedSeconds?: number;
16
+ }): Promise<void>;
17
+ //# sourceMappingURL=junit-suite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"junit-suite.d.ts","sourceRoot":"","sources":["../../src/run/junit-suite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,EAC7C,IAAI,EAAE,aAAa,EAAE,EACrB,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAO,GACxC,MAAM,CAgDR;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,EAC7C,IAAI,EAAE,aAAa,EAAE,EACrB,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAO,GACxC,OAAO,CAAC,IAAI,CAAC,CAGf"}
@@ -0,0 +1,98 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { renderRunJUnit } from "./junit.js";
4
+ /**
5
+ * Suite-level JUnit for a build: one testsuites, one testsuite per target,
6
+ * one testcase per script x device (a single Run). Single-run reports stay
7
+ * on renderRunJUnit() and are unchanged.
8
+ */
9
+ export function renderBuildJUnit(build, runs, options = {}) {
10
+ const record = build && typeof build === "object" ? build : {};
11
+ const groups = new Map();
12
+ let tests = 0;
13
+ let failures = 0;
14
+ let errors = 0;
15
+ let skipped = 0;
16
+ let totalTime = 0;
17
+ let sawTime = false;
18
+ for (const item of runs) {
19
+ const xml = renderRunJUnit(item.run, item.options ?? {});
20
+ const testcase = extractTestcase(xml);
21
+ const suiteName = testcase.suite;
22
+ const group = groups.get(suiteName) ?? { cases: [], failures: 0, errors: 0, skipped: 0, time: 0 };
23
+ group.cases.push(testcase.xml);
24
+ if (testcase.kind === "failure")
25
+ group.failures += 1;
26
+ else if (testcase.kind === "error")
27
+ group.errors += 1;
28
+ else if (testcase.kind === "skipped")
29
+ group.skipped += 1;
30
+ if (testcase.time !== undefined)
31
+ group.time += testcase.time;
32
+ groups.set(suiteName, group);
33
+ tests += 1;
34
+ failures += testcase.kind === "failure" ? 1 : 0;
35
+ errors += testcase.kind === "error" ? 1 : 0;
36
+ skipped += testcase.kind === "skipped" ? 1 : 0;
37
+ if (testcase.time !== undefined) {
38
+ totalTime += testcase.time;
39
+ sawTime = true;
40
+ }
41
+ }
42
+ const time = sawTime ? totalTime : options.elapsedSeconds;
43
+ const timeAttr = formatTimeAttr(time);
44
+ const name = escapeXml(asName(record));
45
+ let body = "";
46
+ for (const [suiteName, group] of groups) {
47
+ const suiteTime = formatTimeAttr(group.time || undefined);
48
+ body += ` <testsuite name="${escapeXml(suiteName)}" tests="${group.cases.length}" failures="${group.failures}" errors="${group.errors}" skipped="${group.skipped}"${suiteTime}>\n`;
49
+ body += group.cases.map((item) => ` ${item}`).join("\n");
50
+ body += `\n </testsuite>\n`;
51
+ }
52
+ if (!body) {
53
+ body = ` <testsuite name="xagent" tests="0" failures="0" errors="0" skipped="0">\n </testsuite>\n`;
54
+ }
55
+ return `<?xml version="1.0" encoding="UTF-8"?>
56
+ <testsuites name="${name}" tests="${tests}" failures="${failures}" errors="${errors}" skipped="${skipped}"${timeAttr}>
57
+ ${body}</testsuites>
58
+ `;
59
+ }
60
+ export async function writeBuildJUnitFile(file, build, runs, options = {}) {
61
+ await mkdir(dirname(file), { recursive: true });
62
+ await writeFile(file, renderBuildJUnit(build, runs, options), "utf8");
63
+ }
64
+ function extractTestcase(xml) {
65
+ const suite = xml.match(/<testsuite name="([^"]*)"/)?.[1] ?? "xagent";
66
+ const testcase = xml.match(/<testcase[\s\S]*<\/testcase>/)?.[0] ?? '<testcase name="xagent-run" classname="xagent"></testcase>';
67
+ const kind = testcase.includes("<failure") ? "failure" : testcase.includes("<error") ? "error" : testcase.includes("<skipped") ? "skipped" : undefined;
68
+ const timeMatch = testcase.match(/\stime="([0-9.]+)"/);
69
+ const time = timeMatch ? Number(timeMatch[1]) : undefined;
70
+ return { xml: testcase, suite: unescapeXml(suite), kind, time: Number.isFinite(time) ? time : undefined };
71
+ }
72
+ function asName(build) {
73
+ const name = typeof build.name === "string" && build.name.trim() ? build.name.trim() : undefined;
74
+ const id = typeof build.id === "string" && build.id.trim() ? build.id.trim() : undefined;
75
+ return name ?? id ?? "xagent-build";
76
+ }
77
+ function formatTimeAttr(seconds) {
78
+ if (seconds === undefined || !Number.isFinite(seconds) || seconds < 0)
79
+ return "";
80
+ return ` time="${(Math.round(seconds * 1000) / 1000).toFixed(3)}"`;
81
+ }
82
+ function escapeXml(value) {
83
+ return value
84
+ .replaceAll("&", "&amp;")
85
+ .replaceAll("<", "&lt;")
86
+ .replaceAll(">", "&gt;")
87
+ .replaceAll('"', "&quot;")
88
+ .replaceAll("'", "&apos;");
89
+ }
90
+ function unescapeXml(value) {
91
+ return value
92
+ .replaceAll("&apos;", "'")
93
+ .replaceAll("&quot;", '"')
94
+ .replaceAll("&gt;", ">")
95
+ .replaceAll("&lt;", "<")
96
+ .replaceAll("&amp;", "&");
97
+ }
98
+ //# sourceMappingURL=junit-suite.js.map