@agent-inspect/jest 2.1.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AgentInspect contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,376 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var promises = require('fs/promises');
6
+ var path = require('path');
7
+ var reporters = require('agent-inspect/reporters');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var path__default = /*#__PURE__*/_interopDefault(path);
12
+
13
+ // packages/jest/src/index.ts
14
+ var PACKAGE_NAME = "@agent-inspect/jest";
15
+ var DEFAULT_ARTIFACT_DIR = ".agent-inspect/jest-artifacts";
16
+ var DEFAULT_SUCCESS_LIMIT = 20;
17
+ var MAX_SUCCESS_LIMIT = 100;
18
+ var MAX_TEXT = 180;
19
+ var DEFAULT_GENERATED_AT = "1970-01-01T00:00:00.000Z";
20
+ function createAgentInspectJestReporter(options = {}) {
21
+ const diagnostics = [];
22
+ const artifacts = [];
23
+ const seenKeys = /* @__PURE__ */ new Set();
24
+ const artifactNames = /* @__PURE__ */ new Map();
25
+ const successLimit = normalizeSuccessLimit(options);
26
+ let retainedSuccesses = 0;
27
+ const reporter = {
28
+ async onTestResult(_test, testResult) {
29
+ await handleFileResult(testResult);
30
+ },
31
+ async onRunComplete(_contexts, results) {
32
+ for (const fileResult of readRunResults(results)) {
33
+ await handleFileResult(fileResult);
34
+ }
35
+ await appendGithubSummary();
36
+ },
37
+ getDiagnostics() {
38
+ return diagnostics.slice();
39
+ },
40
+ getArtifacts() {
41
+ return artifacts.slice();
42
+ }
43
+ };
44
+ async function handleFileResult(testResult) {
45
+ for (const testCase of readTestCases(testResult)) {
46
+ await handleTestCase(testCase);
47
+ }
48
+ }
49
+ async function handleTestCase(testCase) {
50
+ const seenKey = `${testCase.id}:${testCase.status}`;
51
+ if (seenKeys.has(seenKey)) return;
52
+ const association = resolveAssociation(testCase, options);
53
+ if (association === void 0) return;
54
+ if (testCase.status === "passed") {
55
+ if (retainedSuccesses >= successLimit) return;
56
+ retainedSuccesses += 1;
57
+ }
58
+ seenKeys.add(seenKey);
59
+ try {
60
+ const artifact = await writeSafeArtifact({
61
+ artifactDir: options.artifactDir ?? DEFAULT_ARTIFACT_DIR,
62
+ association,
63
+ generatedAt: options.generatedAt ?? DEFAULT_GENERATED_AT,
64
+ redactionProfile: options.redactionProfile ?? "share",
65
+ reserveArtifactName,
66
+ status: testCase.status,
67
+ testCase
68
+ });
69
+ artifacts.push(artifact);
70
+ } catch (error) {
71
+ reportDiagnostic({
72
+ code: "artifact-write-failed",
73
+ message: `Could not write AgentInspect Jest artifact: ${errorMessage(error)}`,
74
+ testId: testCase.id
75
+ });
76
+ }
77
+ }
78
+ function reserveArtifactName(seed) {
79
+ const base = safeSegment(seed);
80
+ const next = (artifactNames.get(base) ?? 0) + 1;
81
+ artifactNames.set(base, next);
82
+ return next === 1 ? base : `${base}-${next}`;
83
+ }
84
+ function reportDiagnostic(diagnostic) {
85
+ diagnostics.push(diagnostic);
86
+ if (options.onDiagnostic === void 0) return;
87
+ try {
88
+ options.onDiagnostic(diagnostic);
89
+ } catch (error) {
90
+ diagnostics.push({
91
+ code: "on-diagnostic-failed",
92
+ message: `AgentInspect Jest diagnostic callback failed: ${errorMessage(error)}`,
93
+ testId: diagnostic.testId
94
+ });
95
+ }
96
+ }
97
+ async function appendGithubSummary() {
98
+ if (options.githubSummary === void 0 || artifacts.length === 0) return;
99
+ const failed = artifacts.filter((artifact) => artifact.status === "failed").length;
100
+ const passed = artifacts.filter((artifact) => artifact.status === "passed").length;
101
+ const lines = [
102
+ "",
103
+ "## AgentInspect Jest artifacts",
104
+ "",
105
+ `- Failed test artifacts: ${failed}`,
106
+ `- Passing test artifacts retained: ${passed}`,
107
+ `- Artifact directory: ${boundText(path__default.default.basename(options.artifactDir ?? DEFAULT_ARTIFACT_DIR))}`,
108
+ ""
109
+ ];
110
+ try {
111
+ await promises.writeFile(options.githubSummary, `${lines.join("\n")}
112
+ `, { flag: "a" });
113
+ } catch (error) {
114
+ reportDiagnostic({
115
+ code: "github-summary-write-failed",
116
+ message: `Could not append AgentInspect Jest summary: ${errorMessage(error)}`
117
+ });
118
+ }
119
+ }
120
+ return reporter;
121
+ }
122
+ var AgentInspectJestReporter = class {
123
+ reporter;
124
+ constructor(_globalConfig, options = {}) {
125
+ this.reporter = createAgentInspectJestReporter(options);
126
+ }
127
+ async onTestResult(test, testResult, aggregatedResult) {
128
+ await this.reporter.onTestResult(test, testResult, aggregatedResult);
129
+ }
130
+ async onRunComplete(contexts, results) {
131
+ await this.reporter.onRunComplete(contexts, results);
132
+ }
133
+ getDiagnostics() {
134
+ return this.reporter.getDiagnostics();
135
+ }
136
+ getArtifacts() {
137
+ return this.reporter.getArtifacts();
138
+ }
139
+ };
140
+ var agentInspectJestReporter = createAgentInspectJestReporter;
141
+ var index_default = AgentInspectJestReporter;
142
+ function normalizeSuccessLimit(options) {
143
+ const cap = clampCount(options.maxSuccessfulTraces, DEFAULT_SUCCESS_LIMIT);
144
+ if (options.retainSuccessful === true) return cap;
145
+ if (typeof options.retainSuccessful === "number") {
146
+ return Math.min(clampCount(options.retainSuccessful, 0), cap);
147
+ }
148
+ return 0;
149
+ }
150
+ function clampCount(value, fallback) {
151
+ if (value === void 0 || !Number.isFinite(value)) return fallback;
152
+ return Math.max(0, Math.min(MAX_SUCCESS_LIMIT, Math.floor(value)));
153
+ }
154
+ function resolveAssociation(testCase, options) {
155
+ const resolved = options.resolveTrace?.(testCase);
156
+ if (isAssociation(resolved)) return resolved;
157
+ const explicit = resolveFromAssociationMap(testCase, options.associations);
158
+ if (explicit !== void 0) return explicit;
159
+ return readAssociationFromAssertion(testCase.raw);
160
+ }
161
+ function resolveFromAssociationMap(testCase, associations) {
162
+ if (associations === void 0) return void 0;
163
+ const basename = testCase.file === void 0 ? void 0 : path__default.default.basename(testCase.file);
164
+ const candidates = [
165
+ testCase.id,
166
+ testCase.fullName,
167
+ basename === void 0 ? void 0 : `${basename}::${testCase.fullName}`
168
+ ];
169
+ for (const candidate of candidates) {
170
+ if (candidate !== void 0 && isAssociation(associations[candidate])) {
171
+ return associations[candidate];
172
+ }
173
+ }
174
+ return void 0;
175
+ }
176
+ function readAssociationFromAssertion(assertion) {
177
+ if (!isObject(assertion)) return void 0;
178
+ const direct = readProp(assertion, "agentInspect");
179
+ if (isAssociation(direct)) return direct;
180
+ const meta = readProp(assertion, "meta");
181
+ if (!isObject(meta)) return void 0;
182
+ for (const candidate of [
183
+ readProp(meta, "agentInspect"),
184
+ readProp(meta, "agent-inspect"),
185
+ readProp(meta, "trace")
186
+ ]) {
187
+ if (isAssociation(candidate)) return candidate;
188
+ }
189
+ return void 0;
190
+ }
191
+ function isAssociation(value) {
192
+ if (!isObject(value)) return false;
193
+ return readOptionalString(value, "runId") !== void 0 || readOptionalString(value, "tracePath") !== void 0 || readOptionalString(value, "artifactLabel") !== void 0;
194
+ }
195
+ function readRunResults(results) {
196
+ if (!isObject(results)) return [];
197
+ const testResults = readProp(results, "testResults");
198
+ return Array.isArray(testResults) ? testResults : [];
199
+ }
200
+ function readTestCases(testResult) {
201
+ if (!isObject(testResult)) return [];
202
+ const result = testResult;
203
+ const file = readOptionalString(result, "testFilePath");
204
+ const assertions = Array.isArray(result.testResults) ? result.testResults : Array.isArray(result.assertionResults) ? result.assertionResults : [];
205
+ const cases = [];
206
+ for (const assertion of assertions) {
207
+ if (!isObject(assertion)) continue;
208
+ const status = readStatus(assertion);
209
+ if (status === void 0 || status === "skipped") continue;
210
+ const title = readOptionalString(assertion, "title") ?? "unknown-test";
211
+ const fullName = readFullName(assertion, title);
212
+ const id = `${file ?? "unknown-file"}::${fullName}`;
213
+ cases.push({
214
+ file,
215
+ fullName: boundText(redactText(fullName)),
216
+ id: boundText(redactText(id)),
217
+ raw: assertion,
218
+ status,
219
+ title: boundText(redactText(title))
220
+ });
221
+ }
222
+ return cases;
223
+ }
224
+ function readFullName(assertion, title) {
225
+ const explicit = readOptionalString(assertion, "fullName");
226
+ if (explicit !== void 0) return explicit;
227
+ const ancestors = Array.isArray(assertion.ancestorTitles) ? assertion.ancestorTitles.filter((item) => typeof item === "string") : [];
228
+ return [...ancestors, title].join(" ");
229
+ }
230
+ function readStatus(assertion) {
231
+ const raw = readOptionalString(assertion, "status");
232
+ if (raw === void 0) return void 0;
233
+ const normalized = raw.toLowerCase();
234
+ if (normalized === "failed" || normalized === "fail") return "failed";
235
+ if (normalized === "passed" || normalized === "pass") return "passed";
236
+ if (normalized === "pending" || normalized === "todo" || normalized === "skipped" || normalized === "skip" || normalized === "disabled") {
237
+ return "skipped";
238
+ }
239
+ return void 0;
240
+ }
241
+ async function writeSafeArtifact(input) {
242
+ const artifactSeed = input.association.artifactLabel ?? input.testCase.id ?? input.testCase.fullName ?? input.status;
243
+ const artifactName = input.reserveArtifactName(artifactSeed);
244
+ const testFile = input.testCase.file === void 0 ? void 0 : path__default.default.basename(input.testCase.file);
245
+ const safeTestId = `${testFile ?? "unknown-file"}::${input.testCase.fullName}`;
246
+ const manifestPathResult = reporters.createReporterArtifactPath({
247
+ outputDir: input.artifactDir,
248
+ testId: artifactName,
249
+ name: input.testCase.fullName,
250
+ file: testFile,
251
+ kind: "report",
252
+ format: "json"
253
+ });
254
+ const summaryPathResult = reporters.createReporterArtifactPath({
255
+ outputDir: input.artifactDir,
256
+ testId: artifactName,
257
+ name: input.testCase.fullName,
258
+ file: testFile,
259
+ kind: "summary",
260
+ format: "md"
261
+ });
262
+ if (!manifestPathResult.ok || manifestPathResult.absolutePath === void 0 || manifestPathResult.relativePath === void 0) {
263
+ throw new Error(formatPathDiagnostics(manifestPathResult.diagnostics));
264
+ }
265
+ if (!summaryPathResult.ok || summaryPathResult.absolutePath === void 0 || summaryPathResult.relativePath === void 0) {
266
+ throw new Error(formatPathDiagnostics(summaryPathResult.diagnostics));
267
+ }
268
+ const directory = path__default.default.dirname(manifestPathResult.absolutePath);
269
+ await promises.mkdir(directory, { recursive: true });
270
+ const traceFile = input.association.tracePath === void 0 ? void 0 : path__default.default.basename(input.association.tracePath);
271
+ const manifestArtifact = {
272
+ kind: "report",
273
+ path: manifestPathResult.relativePath,
274
+ format: "json",
275
+ redactionProfile: input.redactionProfile
276
+ };
277
+ const summaryArtifact = {
278
+ kind: "summary",
279
+ path: summaryPathResult.relativePath,
280
+ format: "md",
281
+ redactionProfile: input.redactionProfile
282
+ };
283
+ const manifest = reporters.createTraceArtifactManifest({
284
+ framework: "jest",
285
+ generatedAt: input.generatedAt,
286
+ results: [
287
+ {
288
+ testId: safeTestId,
289
+ name: input.testCase.fullName,
290
+ ...testFile === void 0 ? {} : { file: testFile },
291
+ status: input.status,
292
+ tracePath: safeOptional(traceFile),
293
+ artifacts: [manifestArtifact, summaryArtifact],
294
+ diagnostics: []
295
+ }
296
+ ],
297
+ artifacts: [manifestArtifact, summaryArtifact],
298
+ diagnostics: []
299
+ });
300
+ const trace = {
301
+ runId: safeOptional(input.association.runId),
302
+ file: safeOptional(traceFile)
303
+ };
304
+ await promises.writeFile(
305
+ manifestPathResult.absolutePath,
306
+ `${JSON.stringify({ package: PACKAGE_NAME, manifest, trace }, null, 2)}
307
+ `
308
+ );
309
+ const summaryPath = summaryPathResult.absolutePath;
310
+ await promises.writeFile(summaryPath, renderSummary(manifest, trace), "utf-8");
311
+ return {
312
+ directory,
313
+ manifest,
314
+ manifestPath: manifestPathResult.absolutePath,
315
+ status: input.status,
316
+ summaryPath,
317
+ testId: safeTestId
318
+ };
319
+ }
320
+ function renderSummary(manifest, trace) {
321
+ const result = manifest.results[0];
322
+ return [
323
+ "# AgentInspect Jest Artifact",
324
+ "",
325
+ `- Test: ${result?.name ?? "unknown"}`,
326
+ `- Test id: ${result?.testId ?? "unknown"}`,
327
+ `- Status: ${result?.status ?? "unknown"}`,
328
+ `- File: ${result?.file ?? "unknown"}`,
329
+ `- Trace run: ${trace.runId ?? "unknown"}`,
330
+ `- Trace file: ${result?.tracePath ?? "unknown"}`,
331
+ `- Manifest schema: ${manifest.schemaVersion}`,
332
+ "",
333
+ "Trace contents are intentionally not embedded in this artifact.",
334
+ ""
335
+ ].join("\n");
336
+ }
337
+ function formatPathDiagnostics(diagnostics) {
338
+ if (diagnostics.length === 0) return "Unsafe AgentInspect Jest artifact path.";
339
+ return diagnostics.map((diagnostic) => diagnostic.message).join("; ");
340
+ }
341
+ function safeOptional(value) {
342
+ return value === void 0 ? void 0 : boundText(redactText(value));
343
+ }
344
+ function safeSegment(value) {
345
+ const sanitized = redactText(value).toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
346
+ return sanitized.length > 0 ? sanitized : "trace";
347
+ }
348
+ function boundText(value) {
349
+ const compact = value.replace(/\s+/g, " ").trim();
350
+ if (compact.length <= MAX_TEXT) return compact;
351
+ return `${compact.slice(0, MAX_TEXT - 12)}...[truncated]`;
352
+ }
353
+ function redactText(value) {
354
+ return value.replace(/\bsk-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(/\b(?:api[_-]?key|authorization|token|secret|password)\s*[:=]\s*[^,\s]+/gi, "$1=[REDACTED]");
355
+ }
356
+ function readOptionalString(value, key) {
357
+ if (!isObject(value)) return void 0;
358
+ const property = readProp(value, key);
359
+ return typeof property === "string" && property.length > 0 ? property : void 0;
360
+ }
361
+ function readProp(value, key) {
362
+ return value[key];
363
+ }
364
+ function isObject(value) {
365
+ return typeof value === "object" && value !== null;
366
+ }
367
+ function errorMessage(error) {
368
+ return error instanceof Error ? error.message : String(error);
369
+ }
370
+
371
+ exports.AgentInspectJestReporter = AgentInspectJestReporter;
372
+ exports.agentInspectJestReporter = agentInspectJestReporter;
373
+ exports.createAgentInspectJestReporter = createAgentInspectJestReporter;
374
+ exports.default = index_default;
375
+ //# sourceMappingURL=index.cjs.map
376
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":["path","writeFile","createReporterArtifactPath","mkdir","createTraceArtifactManifest"],"mappings":"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","file":"index.cjs","sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n createReporterArtifactPath,\n createTraceArtifactManifest,\n type TraceArtifact,\n type TraceArtifactManifest,\n type TraceArtifactRedactionProfile,\n type TraceReporterDiagnostic,\n} from \"agent-inspect/reporters\";\n\nexport type AgentInspectJestStatus = \"failed\" | \"passed\" | \"skipped\";\n\n/**\n * Experimental trace association read by `@agent-inspect/jest`.\n *\n * Jest does not expose Vitest-style task metadata, so the default path is an\n * explicit `associations` map keyed by test identity, or a `resolveTrace`\n * callback. The reporter never guesses by timestamps.\n */\nexport interface AgentInspectJestTraceAssociation {\n /** AgentInspect run/span identifier to show in safe artifacts. */\n readonly runId?: string;\n /** Local trace file path. Only the basename is written to artifacts. */\n readonly tracePath?: string;\n /** Optional stable label for the artifact directory. */\n readonly artifactLabel?: string;\n}\n\n/**\n * Experimental normalized view of one Jest assertion result.\n */\nexport interface AgentInspectJestTestCase {\n readonly id: string;\n readonly title: string;\n readonly fullName: string;\n readonly file?: string;\n readonly status: AgentInspectJestStatus;\n readonly raw: unknown;\n}\n\n/**\n * Experimental diagnostic emitted when reporter work cannot be completed.\n *\n * Diagnostics are reported instead of thrown so Jest's original test result\n * remains authoritative.\n */\nexport interface AgentInspectJestDiagnostic {\n readonly code:\n | \"artifact-write-failed\"\n | \"github-summary-write-failed\"\n | \"on-diagnostic-failed\";\n readonly message: string;\n readonly testId?: string;\n}\n\n/**\n * Experimental options for the AgentInspect Jest reporter.\n *\n * The reporter is local-only: it performs no network I/O and writes bounded,\n * structural artifacts without reading trace contents.\n */\nexport interface AgentInspectJestReporterOptions {\n /** Directory for safe Jest artifacts. Defaults to `.agent-inspect/jest-artifacts`. */\n readonly artifactDir?: string;\n /** Optional GitHub step-summary path. Only bounded structural lines are appended. */\n readonly githubSummary?: string;\n /**\n * Keep artifacts for passing tests. `false`/undefined keeps none; `true`\n * keeps up to `maxSuccessfulTraces`; a number keeps up to that many.\n */\n readonly retainSuccessful?: boolean | number;\n /** Upper bound for retained passing-test artifacts. Defaults to 20. */\n readonly maxSuccessfulTraces?: number;\n /** Redaction profile recorded on generated artifacts. Defaults to `share`. */\n readonly redactionProfile?: TraceArtifactRedactionProfile;\n /** Deterministic manifest timestamp. Defaults to the Unix epoch. */\n readonly generatedAt?: string;\n /** Explicit trace associations keyed by `file::fullName`, `basename::fullName`, or `fullName`. */\n readonly associations?: Record<string, AgentInspectJestTraceAssociation>;\n /** Resolve explicit test-to-trace associations from a normalized Jest case. */\n readonly resolveTrace?: (\n test: AgentInspectJestTestCase,\n ) => AgentInspectJestTraceAssociation | undefined;\n /** Observe non-fatal reporter diagnostics. */\n readonly onDiagnostic?: (diagnostic: AgentInspectJestDiagnostic) => void;\n}\n\nexport interface AgentInspectJestArtifact {\n readonly directory: string;\n readonly manifestPath: string;\n readonly summaryPath: string;\n readonly status: AgentInspectJestStatus;\n readonly testId: string;\n readonly manifest: TraceArtifactManifest;\n}\n\n/**\n * Experimental Jest reporter facade.\n *\n * The hooks mirror Jest reporter lifecycle names, while inputs stay structural\n * to avoid a runtime dependency on Jest internals.\n */\nexport interface AgentInspectJestReporterFacade {\n onTestResult(test: unknown, testResult: unknown, aggregatedResult?: unknown): Promise<void>;\n onRunComplete(contexts?: unknown, results?: unknown): Promise<void>;\n getDiagnostics(): readonly AgentInspectJestDiagnostic[];\n getArtifacts(): readonly AgentInspectJestArtifact[];\n}\n\ntype AssertionResultLike = {\n readonly ancestorTitles?: unknown;\n readonly title?: unknown;\n readonly fullName?: unknown;\n readonly status?: unknown;\n readonly meta?: unknown;\n readonly agentInspect?: unknown;\n};\n\ntype TestFileResultLike = {\n readonly testFilePath?: unknown;\n readonly testResults?: unknown;\n readonly assertionResults?: unknown;\n};\n\nconst PACKAGE_NAME = \"@agent-inspect/jest\";\nconst DEFAULT_ARTIFACT_DIR = \".agent-inspect/jest-artifacts\";\nconst DEFAULT_SUCCESS_LIMIT = 20;\nconst MAX_SUCCESS_LIMIT = 100;\nconst MAX_TEXT = 180;\nconst DEFAULT_GENERATED_AT = \"1970-01-01T00:00:00.000Z\";\n\n/**\n * Create the experimental AgentInspect Jest reporter.\n */\nexport function createAgentInspectJestReporter(\n options: AgentInspectJestReporterOptions = {},\n): AgentInspectJestReporterFacade {\n const diagnostics: AgentInspectJestDiagnostic[] = [];\n const artifacts: AgentInspectJestArtifact[] = [];\n const seenKeys = new Set<string>();\n const artifactNames = new Map<string, number>();\n const successLimit = normalizeSuccessLimit(options);\n let retainedSuccesses = 0;\n\n const reporter: AgentInspectJestReporterFacade = {\n async onTestResult(_test: unknown, testResult: unknown): Promise<void> {\n await handleFileResult(testResult);\n },\n async onRunComplete(_contexts?: unknown, results?: unknown): Promise<void> {\n for (const fileResult of readRunResults(results)) {\n await handleFileResult(fileResult);\n }\n await appendGithubSummary();\n },\n getDiagnostics(): readonly AgentInspectJestDiagnostic[] {\n return diagnostics.slice();\n },\n getArtifacts(): readonly AgentInspectJestArtifact[] {\n return artifacts.slice();\n },\n };\n\n async function handleFileResult(testResult: unknown): Promise<void> {\n for (const testCase of readTestCases(testResult)) {\n await handleTestCase(testCase);\n }\n }\n\n async function handleTestCase(testCase: AgentInspectJestTestCase): Promise<void> {\n const seenKey = `${testCase.id}:${testCase.status}`;\n if (seenKeys.has(seenKey)) return;\n\n const association = resolveAssociation(testCase, options);\n if (association === undefined) return;\n\n if (testCase.status === \"passed\") {\n if (retainedSuccesses >= successLimit) return;\n retainedSuccesses += 1;\n }\n\n seenKeys.add(seenKey);\n\n try {\n const artifact = await writeSafeArtifact({\n artifactDir: options.artifactDir ?? DEFAULT_ARTIFACT_DIR,\n association,\n generatedAt: options.generatedAt ?? DEFAULT_GENERATED_AT,\n redactionProfile: options.redactionProfile ?? \"share\",\n reserveArtifactName,\n status: testCase.status,\n testCase,\n });\n artifacts.push(artifact);\n } catch (error) {\n reportDiagnostic({\n code: \"artifact-write-failed\",\n message: `Could not write AgentInspect Jest artifact: ${errorMessage(error)}`,\n testId: testCase.id,\n });\n }\n }\n\n function reserveArtifactName(seed: string): string {\n const base = safeSegment(seed);\n const next = (artifactNames.get(base) ?? 0) + 1;\n artifactNames.set(base, next);\n return next === 1 ? base : `${base}-${next}`;\n }\n\n function reportDiagnostic(diagnostic: AgentInspectJestDiagnostic): void {\n diagnostics.push(diagnostic);\n if (options.onDiagnostic === undefined) return;\n try {\n options.onDiagnostic(diagnostic);\n } catch (error) {\n diagnostics.push({\n code: \"on-diagnostic-failed\",\n message: `AgentInspect Jest diagnostic callback failed: ${errorMessage(error)}`,\n testId: diagnostic.testId,\n });\n }\n }\n\n async function appendGithubSummary(): Promise<void> {\n if (options.githubSummary === undefined || artifacts.length === 0) return;\n const failed = artifacts.filter((artifact) => artifact.status === \"failed\").length;\n const passed = artifacts.filter((artifact) => artifact.status === \"passed\").length;\n const lines = [\n \"\",\n \"## AgentInspect Jest artifacts\",\n \"\",\n `- Failed test artifacts: ${failed}`,\n `- Passing test artifacts retained: ${passed}`,\n `- Artifact directory: ${boundText(path.basename(options.artifactDir ?? DEFAULT_ARTIFACT_DIR))}`,\n \"\",\n ];\n try {\n await writeFile(options.githubSummary, `${lines.join(\"\\n\")}\\n`, { flag: \"a\" });\n } catch (error) {\n reportDiagnostic({\n code: \"github-summary-write-failed\",\n message: `Could not append AgentInspect Jest summary: ${errorMessage(error)}`,\n });\n }\n }\n\n return reporter;\n}\n\n/**\n * Experimental Jest custom reporter class.\n */\nexport class AgentInspectJestReporter implements AgentInspectJestReporterFacade {\n private readonly reporter: AgentInspectJestReporterFacade;\n\n constructor(_globalConfig?: unknown, options: AgentInspectJestReporterOptions = {}) {\n this.reporter = createAgentInspectJestReporter(options);\n }\n\n async onTestResult(\n test: unknown,\n testResult: unknown,\n aggregatedResult?: unknown,\n ): Promise<void> {\n await this.reporter.onTestResult(test, testResult, aggregatedResult);\n }\n\n async onRunComplete(contexts?: unknown, results?: unknown): Promise<void> {\n await this.reporter.onRunComplete(contexts, results);\n }\n\n getDiagnostics(): readonly AgentInspectJestDiagnostic[] {\n return this.reporter.getDiagnostics();\n }\n\n getArtifacts(): readonly AgentInspectJestArtifact[] {\n return this.reporter.getArtifacts();\n }\n}\n\nexport const agentInspectJestReporter = createAgentInspectJestReporter;\nexport default AgentInspectJestReporter;\n\nfunction normalizeSuccessLimit(options: AgentInspectJestReporterOptions): number {\n const cap = clampCount(options.maxSuccessfulTraces, DEFAULT_SUCCESS_LIMIT);\n if (options.retainSuccessful === true) return cap;\n if (typeof options.retainSuccessful === \"number\") {\n return Math.min(clampCount(options.retainSuccessful, 0), cap);\n }\n return 0;\n}\n\nfunction clampCount(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value)) return fallback;\n return Math.max(0, Math.min(MAX_SUCCESS_LIMIT, Math.floor(value)));\n}\n\nfunction resolveAssociation(\n testCase: AgentInspectJestTestCase,\n options: AgentInspectJestReporterOptions,\n): AgentInspectJestTraceAssociation | undefined {\n const resolved = options.resolveTrace?.(testCase);\n if (isAssociation(resolved)) return resolved;\n\n const explicit = resolveFromAssociationMap(testCase, options.associations);\n if (explicit !== undefined) return explicit;\n\n return readAssociationFromAssertion(testCase.raw);\n}\n\nfunction resolveFromAssociationMap(\n testCase: AgentInspectJestTestCase,\n associations: Record<string, AgentInspectJestTraceAssociation> | undefined,\n): AgentInspectJestTraceAssociation | undefined {\n if (associations === undefined) return undefined;\n const basename = testCase.file === undefined ? undefined : path.basename(testCase.file);\n const candidates = [\n testCase.id,\n testCase.fullName,\n basename === undefined ? undefined : `${basename}::${testCase.fullName}`,\n ];\n for (const candidate of candidates) {\n if (candidate !== undefined && isAssociation(associations[candidate])) {\n return associations[candidate];\n }\n }\n return undefined;\n}\n\nfunction readAssociationFromAssertion(\n assertion: unknown,\n): AgentInspectJestTraceAssociation | undefined {\n if (!isObject(assertion)) return undefined;\n const direct = readProp(assertion, \"agentInspect\");\n if (isAssociation(direct)) return direct;\n\n const meta = readProp(assertion, \"meta\");\n if (!isObject(meta)) return undefined;\n for (const candidate of [\n readProp(meta, \"agentInspect\"),\n readProp(meta, \"agent-inspect\"),\n readProp(meta, \"trace\"),\n ]) {\n if (isAssociation(candidate)) return candidate;\n }\n return undefined;\n}\n\nfunction isAssociation(\n value: unknown,\n): value is AgentInspectJestTraceAssociation {\n if (!isObject(value)) return false;\n return (\n readOptionalString(value, \"runId\") !== undefined ||\n readOptionalString(value, \"tracePath\") !== undefined ||\n readOptionalString(value, \"artifactLabel\") !== undefined\n );\n}\n\nfunction readRunResults(results: unknown): unknown[] {\n if (!isObject(results)) return [];\n const testResults = readProp(results, \"testResults\");\n return Array.isArray(testResults) ? testResults : [];\n}\n\nfunction readTestCases(testResult: unknown): AgentInspectJestTestCase[] {\n if (!isObject(testResult)) return [];\n const result = testResult as TestFileResultLike;\n const file = readOptionalString(result, \"testFilePath\");\n const assertions = Array.isArray(result.testResults)\n ? result.testResults\n : Array.isArray(result.assertionResults)\n ? result.assertionResults\n : [];\n\n const cases: AgentInspectJestTestCase[] = [];\n for (const assertion of assertions) {\n if (!isObject(assertion)) continue;\n const status = readStatus(assertion);\n if (status === undefined || status === \"skipped\") continue;\n\n const title = readOptionalString(assertion, \"title\") ?? \"unknown-test\";\n const fullName = readFullName(assertion as AssertionResultLike, title);\n const id = `${file ?? \"unknown-file\"}::${fullName}`;\n cases.push({\n file,\n fullName: boundText(redactText(fullName)),\n id: boundText(redactText(id)),\n raw: assertion,\n status,\n title: boundText(redactText(title)),\n });\n }\n return cases;\n}\n\nfunction readFullName(assertion: AssertionResultLike, title: string): string {\n const explicit = readOptionalString(assertion, \"fullName\");\n if (explicit !== undefined) return explicit;\n\n const ancestors = Array.isArray(assertion.ancestorTitles)\n ? assertion.ancestorTitles.filter((item): item is string => typeof item === \"string\")\n : [];\n return [...ancestors, title].join(\" \");\n}\n\nfunction readStatus(assertion: object): AgentInspectJestStatus | undefined {\n const raw = readOptionalString(assertion, \"status\");\n if (raw === undefined) return undefined;\n\n const normalized = raw.toLowerCase();\n if (normalized === \"failed\" || normalized === \"fail\") return \"failed\";\n if (normalized === \"passed\" || normalized === \"pass\") return \"passed\";\n if (\n normalized === \"pending\" ||\n normalized === \"todo\" ||\n normalized === \"skipped\" ||\n normalized === \"skip\" ||\n normalized === \"disabled\"\n ) {\n return \"skipped\";\n }\n return undefined;\n}\n\nasync function writeSafeArtifact(input: {\n readonly artifactDir: string;\n readonly association: AgentInspectJestTraceAssociation;\n readonly generatedAt: string;\n readonly redactionProfile: TraceArtifactRedactionProfile;\n readonly reserveArtifactName: (seed: string) => string;\n readonly status: AgentInspectJestStatus;\n readonly testCase: AgentInspectJestTestCase;\n}): Promise<AgentInspectJestArtifact> {\n const artifactSeed =\n input.association.artifactLabel ??\n input.testCase.id ??\n input.testCase.fullName ??\n input.status;\n const artifactName = input.reserveArtifactName(artifactSeed);\n const testFile =\n input.testCase.file === undefined ? undefined : path.basename(input.testCase.file);\n const safeTestId = `${testFile ?? \"unknown-file\"}::${input.testCase.fullName}`;\n const manifestPathResult = createReporterArtifactPath({\n outputDir: input.artifactDir,\n testId: artifactName,\n name: input.testCase.fullName,\n file: testFile,\n kind: \"report\",\n format: \"json\",\n });\n const summaryPathResult = createReporterArtifactPath({\n outputDir: input.artifactDir,\n testId: artifactName,\n name: input.testCase.fullName,\n file: testFile,\n kind: \"summary\",\n format: \"md\",\n });\n\n if (\n !manifestPathResult.ok ||\n manifestPathResult.absolutePath === undefined ||\n manifestPathResult.relativePath === undefined\n ) {\n throw new Error(formatPathDiagnostics(manifestPathResult.diagnostics));\n }\n if (\n !summaryPathResult.ok ||\n summaryPathResult.absolutePath === undefined ||\n summaryPathResult.relativePath === undefined\n ) {\n throw new Error(formatPathDiagnostics(summaryPathResult.diagnostics));\n }\n\n const directory = path.dirname(manifestPathResult.absolutePath);\n await mkdir(directory, { recursive: true });\n\n const traceFile =\n input.association.tracePath === undefined\n ? undefined\n : path.basename(input.association.tracePath);\n const manifestArtifact: TraceArtifact = {\n kind: \"report\",\n path: manifestPathResult.relativePath,\n format: \"json\",\n redactionProfile: input.redactionProfile,\n };\n const summaryArtifact: TraceArtifact = {\n kind: \"summary\",\n path: summaryPathResult.relativePath,\n format: \"md\",\n redactionProfile: input.redactionProfile,\n };\n const manifest = createTraceArtifactManifest({\n framework: \"jest\",\n generatedAt: input.generatedAt,\n results: [\n {\n testId: safeTestId,\n name: input.testCase.fullName,\n ...(testFile === undefined ? {} : { file: testFile }),\n status: input.status,\n tracePath: safeOptional(traceFile),\n artifacts: [manifestArtifact, summaryArtifact],\n diagnostics: [],\n },\n ],\n artifacts: [manifestArtifact, summaryArtifact],\n diagnostics: [],\n });\n const trace = {\n runId: safeOptional(input.association.runId),\n file: safeOptional(traceFile),\n };\n\n await writeFile(\n manifestPathResult.absolutePath,\n `${JSON.stringify({ package: PACKAGE_NAME, manifest, trace }, null, 2)}\\n`,\n );\n const summaryPath = summaryPathResult.absolutePath;\n await writeFile(summaryPath, renderSummary(manifest, trace), \"utf-8\");\n\n return {\n directory,\n manifest,\n manifestPath: manifestPathResult.absolutePath,\n status: input.status,\n summaryPath,\n testId: safeTestId,\n };\n}\n\nfunction renderSummary(\n manifest: TraceArtifactManifest,\n trace: { readonly runId?: string; readonly file?: string },\n): string {\n const result = manifest.results[0];\n return [\n \"# AgentInspect Jest Artifact\",\n \"\",\n `- Test: ${result?.name ?? \"unknown\"}`,\n `- Test id: ${result?.testId ?? \"unknown\"}`,\n `- Status: ${result?.status ?? \"unknown\"}`,\n `- File: ${result?.file ?? \"unknown\"}`,\n `- Trace run: ${trace.runId ?? \"unknown\"}`,\n `- Trace file: ${result?.tracePath ?? \"unknown\"}`,\n `- Manifest schema: ${manifest.schemaVersion}`,\n \"\",\n \"Trace contents are intentionally not embedded in this artifact.\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction formatPathDiagnostics(\n diagnostics: readonly TraceReporterDiagnostic[],\n): string {\n if (diagnostics.length === 0) return \"Unsafe AgentInspect Jest artifact path.\";\n return diagnostics.map((diagnostic) => diagnostic.message).join(\"; \");\n}\n\nfunction safeOptional(value: string | undefined): string | undefined {\n return value === undefined ? undefined : boundText(redactText(value));\n}\n\nfunction safeSegment(value: string): string {\n const sanitized = redactText(value)\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 80);\n return sanitized.length > 0 ? sanitized : \"trace\";\n}\n\nfunction boundText(value: string): string {\n const compact = value.replace(/\\s+/g, \" \").trim();\n if (compact.length <= MAX_TEXT) return compact;\n return `${compact.slice(0, MAX_TEXT - 12)}...[truncated]`;\n}\n\nfunction redactText(value: string): string {\n return value\n .replace(/\\bsk-[A-Za-z0-9_-]{8,}\\b/g, \"[REDACTED]\")\n .replace(/\\b(?:api[_-]?key|authorization|token|secret|password)\\s*[:=]\\s*[^,\\s]+/gi, \"$1=[REDACTED]\");\n}\n\nfunction readOptionalString(value: unknown, key: string): string | undefined {\n if (!isObject(value)) return undefined;\n const property = readProp(value, key);\n return typeof property === \"string\" && property.length > 0 ? property : undefined;\n}\n\nfunction readProp(value: object, key: string): unknown {\n return (value as Record<string, unknown>)[key];\n}\n\nfunction isObject(value: unknown): value is object {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}
@@ -0,0 +1,158 @@
1
+ declare const TRACE_ARTIFACT_MANIFEST_SCHEMA_VERSION: "0.1";
2
+ /** Experimental reporter framework identifier for local CI artifacts. */
3
+ type TraceReporterFramework = "vitest" | "jest" | "manual";
4
+ /** Experimental reporter test status normalized across supported test runners. */
5
+ type TraceTestStatus = "passed" | "failed" | "skipped" | "todo";
6
+ /** Experimental reporter artifact kind used in artifact manifests. */
7
+ type TraceArtifactKind = "trace" | "report" | "eval" | "redaction" | "summary";
8
+ /** Experimental reporter artifact file format used in artifact manifests. */
9
+ type TraceArtifactFormat = "json" | "jsonl" | "md" | "html";
10
+ /** Experimental redaction profile marker recorded with reporter artifacts. */
11
+ type TraceArtifactRedactionProfile = "local" | "share" | "strict";
12
+ /** Experimental reporter diagnostic severity. */
13
+ type TraceReporterDiagnosticSeverity = "info" | "warning" | "error";
14
+ /** Experimental reporter diagnostic code for safe, non-throwing reporter helpers. */
15
+ type TraceReporterDiagnosticCode = "invalid_artifact_path" | "artifact_path_escape" | "artifact_path_empty" | "artifact_path_absolute" | "reporter_failure";
16
+ /** Experimental diagnostic emitted by reporter helpers instead of throwing. */
17
+ interface TraceReporterDiagnostic {
18
+ code: TraceReporterDiagnosticCode;
19
+ severity: TraceReporterDiagnosticSeverity;
20
+ message: string;
21
+ target?: string;
22
+ }
23
+ /** Experimental manifest artifact entry shared by framework reporters. */
24
+ interface TraceArtifact {
25
+ kind: TraceArtifactKind;
26
+ path: string;
27
+ format: TraceArtifactFormat;
28
+ redactionProfile: TraceArtifactRedactionProfile;
29
+ title?: string;
30
+ sizeBytes?: number;
31
+ diagnostics?: TraceReporterDiagnostic[];
32
+ }
33
+ /** Experimental normalized test result entry shared by framework reporters. */
34
+ interface TraceTestResult {
35
+ testId: string;
36
+ name: string;
37
+ file?: string;
38
+ status: TraceTestStatus;
39
+ durationMs?: number;
40
+ tracePath?: string;
41
+ artifacts?: TraceArtifact[];
42
+ diagnostics?: TraceReporterDiagnostic[];
43
+ }
44
+ /** Experimental reporter artifact manifest shared by framework reporters. */
45
+ interface TraceArtifactManifest {
46
+ schemaVersion: typeof TRACE_ARTIFACT_MANIFEST_SCHEMA_VERSION;
47
+ generatedAt: string;
48
+ framework: TraceReporterFramework;
49
+ results: TraceTestResult[];
50
+ artifacts: TraceArtifact[];
51
+ diagnostics: TraceReporterDiagnostic[];
52
+ }
53
+
54
+ type AgentInspectJestStatus = "failed" | "passed" | "skipped";
55
+ /**
56
+ * Experimental trace association read by `@agent-inspect/jest`.
57
+ *
58
+ * Jest does not expose Vitest-style task metadata, so the default path is an
59
+ * explicit `associations` map keyed by test identity, or a `resolveTrace`
60
+ * callback. The reporter never guesses by timestamps.
61
+ */
62
+ interface AgentInspectJestTraceAssociation {
63
+ /** AgentInspect run/span identifier to show in safe artifacts. */
64
+ readonly runId?: string;
65
+ /** Local trace file path. Only the basename is written to artifacts. */
66
+ readonly tracePath?: string;
67
+ /** Optional stable label for the artifact directory. */
68
+ readonly artifactLabel?: string;
69
+ }
70
+ /**
71
+ * Experimental normalized view of one Jest assertion result.
72
+ */
73
+ interface AgentInspectJestTestCase {
74
+ readonly id: string;
75
+ readonly title: string;
76
+ readonly fullName: string;
77
+ readonly file?: string;
78
+ readonly status: AgentInspectJestStatus;
79
+ readonly raw: unknown;
80
+ }
81
+ /**
82
+ * Experimental diagnostic emitted when reporter work cannot be completed.
83
+ *
84
+ * Diagnostics are reported instead of thrown so Jest's original test result
85
+ * remains authoritative.
86
+ */
87
+ interface AgentInspectJestDiagnostic {
88
+ readonly code: "artifact-write-failed" | "github-summary-write-failed" | "on-diagnostic-failed";
89
+ readonly message: string;
90
+ readonly testId?: string;
91
+ }
92
+ /**
93
+ * Experimental options for the AgentInspect Jest reporter.
94
+ *
95
+ * The reporter is local-only: it performs no network I/O and writes bounded,
96
+ * structural artifacts without reading trace contents.
97
+ */
98
+ interface AgentInspectJestReporterOptions {
99
+ /** Directory for safe Jest artifacts. Defaults to `.agent-inspect/jest-artifacts`. */
100
+ readonly artifactDir?: string;
101
+ /** Optional GitHub step-summary path. Only bounded structural lines are appended. */
102
+ readonly githubSummary?: string;
103
+ /**
104
+ * Keep artifacts for passing tests. `false`/undefined keeps none; `true`
105
+ * keeps up to `maxSuccessfulTraces`; a number keeps up to that many.
106
+ */
107
+ readonly retainSuccessful?: boolean | number;
108
+ /** Upper bound for retained passing-test artifacts. Defaults to 20. */
109
+ readonly maxSuccessfulTraces?: number;
110
+ /** Redaction profile recorded on generated artifacts. Defaults to `share`. */
111
+ readonly redactionProfile?: TraceArtifactRedactionProfile;
112
+ /** Deterministic manifest timestamp. Defaults to the Unix epoch. */
113
+ readonly generatedAt?: string;
114
+ /** Explicit trace associations keyed by `file::fullName`, `basename::fullName`, or `fullName`. */
115
+ readonly associations?: Record<string, AgentInspectJestTraceAssociation>;
116
+ /** Resolve explicit test-to-trace associations from a normalized Jest case. */
117
+ readonly resolveTrace?: (test: AgentInspectJestTestCase) => AgentInspectJestTraceAssociation | undefined;
118
+ /** Observe non-fatal reporter diagnostics. */
119
+ readonly onDiagnostic?: (diagnostic: AgentInspectJestDiagnostic) => void;
120
+ }
121
+ interface AgentInspectJestArtifact {
122
+ readonly directory: string;
123
+ readonly manifestPath: string;
124
+ readonly summaryPath: string;
125
+ readonly status: AgentInspectJestStatus;
126
+ readonly testId: string;
127
+ readonly manifest: TraceArtifactManifest;
128
+ }
129
+ /**
130
+ * Experimental Jest reporter facade.
131
+ *
132
+ * The hooks mirror Jest reporter lifecycle names, while inputs stay structural
133
+ * to avoid a runtime dependency on Jest internals.
134
+ */
135
+ interface AgentInspectJestReporterFacade {
136
+ onTestResult(test: unknown, testResult: unknown, aggregatedResult?: unknown): Promise<void>;
137
+ onRunComplete(contexts?: unknown, results?: unknown): Promise<void>;
138
+ getDiagnostics(): readonly AgentInspectJestDiagnostic[];
139
+ getArtifacts(): readonly AgentInspectJestArtifact[];
140
+ }
141
+ /**
142
+ * Create the experimental AgentInspect Jest reporter.
143
+ */
144
+ declare function createAgentInspectJestReporter(options?: AgentInspectJestReporterOptions): AgentInspectJestReporterFacade;
145
+ /**
146
+ * Experimental Jest custom reporter class.
147
+ */
148
+ declare class AgentInspectJestReporter implements AgentInspectJestReporterFacade {
149
+ private readonly reporter;
150
+ constructor(_globalConfig?: unknown, options?: AgentInspectJestReporterOptions);
151
+ onTestResult(test: unknown, testResult: unknown, aggregatedResult?: unknown): Promise<void>;
152
+ onRunComplete(contexts?: unknown, results?: unknown): Promise<void>;
153
+ getDiagnostics(): readonly AgentInspectJestDiagnostic[];
154
+ getArtifacts(): readonly AgentInspectJestArtifact[];
155
+ }
156
+ declare const agentInspectJestReporter: typeof createAgentInspectJestReporter;
157
+
158
+ export { type AgentInspectJestArtifact, type AgentInspectJestDiagnostic, AgentInspectJestReporter, type AgentInspectJestReporterFacade, type AgentInspectJestReporterOptions, type AgentInspectJestStatus, type AgentInspectJestTestCase, type AgentInspectJestTraceAssociation, agentInspectJestReporter, createAgentInspectJestReporter, AgentInspectJestReporter as default };
@@ -0,0 +1,158 @@
1
+ declare const TRACE_ARTIFACT_MANIFEST_SCHEMA_VERSION: "0.1";
2
+ /** Experimental reporter framework identifier for local CI artifacts. */
3
+ type TraceReporterFramework = "vitest" | "jest" | "manual";
4
+ /** Experimental reporter test status normalized across supported test runners. */
5
+ type TraceTestStatus = "passed" | "failed" | "skipped" | "todo";
6
+ /** Experimental reporter artifact kind used in artifact manifests. */
7
+ type TraceArtifactKind = "trace" | "report" | "eval" | "redaction" | "summary";
8
+ /** Experimental reporter artifact file format used in artifact manifests. */
9
+ type TraceArtifactFormat = "json" | "jsonl" | "md" | "html";
10
+ /** Experimental redaction profile marker recorded with reporter artifacts. */
11
+ type TraceArtifactRedactionProfile = "local" | "share" | "strict";
12
+ /** Experimental reporter diagnostic severity. */
13
+ type TraceReporterDiagnosticSeverity = "info" | "warning" | "error";
14
+ /** Experimental reporter diagnostic code for safe, non-throwing reporter helpers. */
15
+ type TraceReporterDiagnosticCode = "invalid_artifact_path" | "artifact_path_escape" | "artifact_path_empty" | "artifact_path_absolute" | "reporter_failure";
16
+ /** Experimental diagnostic emitted by reporter helpers instead of throwing. */
17
+ interface TraceReporterDiagnostic {
18
+ code: TraceReporterDiagnosticCode;
19
+ severity: TraceReporterDiagnosticSeverity;
20
+ message: string;
21
+ target?: string;
22
+ }
23
+ /** Experimental manifest artifact entry shared by framework reporters. */
24
+ interface TraceArtifact {
25
+ kind: TraceArtifactKind;
26
+ path: string;
27
+ format: TraceArtifactFormat;
28
+ redactionProfile: TraceArtifactRedactionProfile;
29
+ title?: string;
30
+ sizeBytes?: number;
31
+ diagnostics?: TraceReporterDiagnostic[];
32
+ }
33
+ /** Experimental normalized test result entry shared by framework reporters. */
34
+ interface TraceTestResult {
35
+ testId: string;
36
+ name: string;
37
+ file?: string;
38
+ status: TraceTestStatus;
39
+ durationMs?: number;
40
+ tracePath?: string;
41
+ artifacts?: TraceArtifact[];
42
+ diagnostics?: TraceReporterDiagnostic[];
43
+ }
44
+ /** Experimental reporter artifact manifest shared by framework reporters. */
45
+ interface TraceArtifactManifest {
46
+ schemaVersion: typeof TRACE_ARTIFACT_MANIFEST_SCHEMA_VERSION;
47
+ generatedAt: string;
48
+ framework: TraceReporterFramework;
49
+ results: TraceTestResult[];
50
+ artifacts: TraceArtifact[];
51
+ diagnostics: TraceReporterDiagnostic[];
52
+ }
53
+
54
+ type AgentInspectJestStatus = "failed" | "passed" | "skipped";
55
+ /**
56
+ * Experimental trace association read by `@agent-inspect/jest`.
57
+ *
58
+ * Jest does not expose Vitest-style task metadata, so the default path is an
59
+ * explicit `associations` map keyed by test identity, or a `resolveTrace`
60
+ * callback. The reporter never guesses by timestamps.
61
+ */
62
+ interface AgentInspectJestTraceAssociation {
63
+ /** AgentInspect run/span identifier to show in safe artifacts. */
64
+ readonly runId?: string;
65
+ /** Local trace file path. Only the basename is written to artifacts. */
66
+ readonly tracePath?: string;
67
+ /** Optional stable label for the artifact directory. */
68
+ readonly artifactLabel?: string;
69
+ }
70
+ /**
71
+ * Experimental normalized view of one Jest assertion result.
72
+ */
73
+ interface AgentInspectJestTestCase {
74
+ readonly id: string;
75
+ readonly title: string;
76
+ readonly fullName: string;
77
+ readonly file?: string;
78
+ readonly status: AgentInspectJestStatus;
79
+ readonly raw: unknown;
80
+ }
81
+ /**
82
+ * Experimental diagnostic emitted when reporter work cannot be completed.
83
+ *
84
+ * Diagnostics are reported instead of thrown so Jest's original test result
85
+ * remains authoritative.
86
+ */
87
+ interface AgentInspectJestDiagnostic {
88
+ readonly code: "artifact-write-failed" | "github-summary-write-failed" | "on-diagnostic-failed";
89
+ readonly message: string;
90
+ readonly testId?: string;
91
+ }
92
+ /**
93
+ * Experimental options for the AgentInspect Jest reporter.
94
+ *
95
+ * The reporter is local-only: it performs no network I/O and writes bounded,
96
+ * structural artifacts without reading trace contents.
97
+ */
98
+ interface AgentInspectJestReporterOptions {
99
+ /** Directory for safe Jest artifacts. Defaults to `.agent-inspect/jest-artifacts`. */
100
+ readonly artifactDir?: string;
101
+ /** Optional GitHub step-summary path. Only bounded structural lines are appended. */
102
+ readonly githubSummary?: string;
103
+ /**
104
+ * Keep artifacts for passing tests. `false`/undefined keeps none; `true`
105
+ * keeps up to `maxSuccessfulTraces`; a number keeps up to that many.
106
+ */
107
+ readonly retainSuccessful?: boolean | number;
108
+ /** Upper bound for retained passing-test artifacts. Defaults to 20. */
109
+ readonly maxSuccessfulTraces?: number;
110
+ /** Redaction profile recorded on generated artifacts. Defaults to `share`. */
111
+ readonly redactionProfile?: TraceArtifactRedactionProfile;
112
+ /** Deterministic manifest timestamp. Defaults to the Unix epoch. */
113
+ readonly generatedAt?: string;
114
+ /** Explicit trace associations keyed by `file::fullName`, `basename::fullName`, or `fullName`. */
115
+ readonly associations?: Record<string, AgentInspectJestTraceAssociation>;
116
+ /** Resolve explicit test-to-trace associations from a normalized Jest case. */
117
+ readonly resolveTrace?: (test: AgentInspectJestTestCase) => AgentInspectJestTraceAssociation | undefined;
118
+ /** Observe non-fatal reporter diagnostics. */
119
+ readonly onDiagnostic?: (diagnostic: AgentInspectJestDiagnostic) => void;
120
+ }
121
+ interface AgentInspectJestArtifact {
122
+ readonly directory: string;
123
+ readonly manifestPath: string;
124
+ readonly summaryPath: string;
125
+ readonly status: AgentInspectJestStatus;
126
+ readonly testId: string;
127
+ readonly manifest: TraceArtifactManifest;
128
+ }
129
+ /**
130
+ * Experimental Jest reporter facade.
131
+ *
132
+ * The hooks mirror Jest reporter lifecycle names, while inputs stay structural
133
+ * to avoid a runtime dependency on Jest internals.
134
+ */
135
+ interface AgentInspectJestReporterFacade {
136
+ onTestResult(test: unknown, testResult: unknown, aggregatedResult?: unknown): Promise<void>;
137
+ onRunComplete(contexts?: unknown, results?: unknown): Promise<void>;
138
+ getDiagnostics(): readonly AgentInspectJestDiagnostic[];
139
+ getArtifacts(): readonly AgentInspectJestArtifact[];
140
+ }
141
+ /**
142
+ * Create the experimental AgentInspect Jest reporter.
143
+ */
144
+ declare function createAgentInspectJestReporter(options?: AgentInspectJestReporterOptions): AgentInspectJestReporterFacade;
145
+ /**
146
+ * Experimental Jest custom reporter class.
147
+ */
148
+ declare class AgentInspectJestReporter implements AgentInspectJestReporterFacade {
149
+ private readonly reporter;
150
+ constructor(_globalConfig?: unknown, options?: AgentInspectJestReporterOptions);
151
+ onTestResult(test: unknown, testResult: unknown, aggregatedResult?: unknown): Promise<void>;
152
+ onRunComplete(contexts?: unknown, results?: unknown): Promise<void>;
153
+ getDiagnostics(): readonly AgentInspectJestDiagnostic[];
154
+ getArtifacts(): readonly AgentInspectJestArtifact[];
155
+ }
156
+ declare const agentInspectJestReporter: typeof createAgentInspectJestReporter;
157
+
158
+ export { type AgentInspectJestArtifact, type AgentInspectJestDiagnostic, AgentInspectJestReporter, type AgentInspectJestReporterFacade, type AgentInspectJestReporterOptions, type AgentInspectJestStatus, type AgentInspectJestTestCase, type AgentInspectJestTraceAssociation, agentInspectJestReporter, createAgentInspectJestReporter, AgentInspectJestReporter as default };
package/dist/index.mjs ADDED
@@ -0,0 +1,365 @@
1
+ import { writeFile, mkdir } from 'fs/promises';
2
+ import path from 'path';
3
+ import { createReporterArtifactPath, createTraceArtifactManifest } from 'agent-inspect/reporters';
4
+
5
+ // packages/jest/src/index.ts
6
+ var PACKAGE_NAME = "@agent-inspect/jest";
7
+ var DEFAULT_ARTIFACT_DIR = ".agent-inspect/jest-artifacts";
8
+ var DEFAULT_SUCCESS_LIMIT = 20;
9
+ var MAX_SUCCESS_LIMIT = 100;
10
+ var MAX_TEXT = 180;
11
+ var DEFAULT_GENERATED_AT = "1970-01-01T00:00:00.000Z";
12
+ function createAgentInspectJestReporter(options = {}) {
13
+ const diagnostics = [];
14
+ const artifacts = [];
15
+ const seenKeys = /* @__PURE__ */ new Set();
16
+ const artifactNames = /* @__PURE__ */ new Map();
17
+ const successLimit = normalizeSuccessLimit(options);
18
+ let retainedSuccesses = 0;
19
+ const reporter = {
20
+ async onTestResult(_test, testResult) {
21
+ await handleFileResult(testResult);
22
+ },
23
+ async onRunComplete(_contexts, results) {
24
+ for (const fileResult of readRunResults(results)) {
25
+ await handleFileResult(fileResult);
26
+ }
27
+ await appendGithubSummary();
28
+ },
29
+ getDiagnostics() {
30
+ return diagnostics.slice();
31
+ },
32
+ getArtifacts() {
33
+ return artifacts.slice();
34
+ }
35
+ };
36
+ async function handleFileResult(testResult) {
37
+ for (const testCase of readTestCases(testResult)) {
38
+ await handleTestCase(testCase);
39
+ }
40
+ }
41
+ async function handleTestCase(testCase) {
42
+ const seenKey = `${testCase.id}:${testCase.status}`;
43
+ if (seenKeys.has(seenKey)) return;
44
+ const association = resolveAssociation(testCase, options);
45
+ if (association === void 0) return;
46
+ if (testCase.status === "passed") {
47
+ if (retainedSuccesses >= successLimit) return;
48
+ retainedSuccesses += 1;
49
+ }
50
+ seenKeys.add(seenKey);
51
+ try {
52
+ const artifact = await writeSafeArtifact({
53
+ artifactDir: options.artifactDir ?? DEFAULT_ARTIFACT_DIR,
54
+ association,
55
+ generatedAt: options.generatedAt ?? DEFAULT_GENERATED_AT,
56
+ redactionProfile: options.redactionProfile ?? "share",
57
+ reserveArtifactName,
58
+ status: testCase.status,
59
+ testCase
60
+ });
61
+ artifacts.push(artifact);
62
+ } catch (error) {
63
+ reportDiagnostic({
64
+ code: "artifact-write-failed",
65
+ message: `Could not write AgentInspect Jest artifact: ${errorMessage(error)}`,
66
+ testId: testCase.id
67
+ });
68
+ }
69
+ }
70
+ function reserveArtifactName(seed) {
71
+ const base = safeSegment(seed);
72
+ const next = (artifactNames.get(base) ?? 0) + 1;
73
+ artifactNames.set(base, next);
74
+ return next === 1 ? base : `${base}-${next}`;
75
+ }
76
+ function reportDiagnostic(diagnostic) {
77
+ diagnostics.push(diagnostic);
78
+ if (options.onDiagnostic === void 0) return;
79
+ try {
80
+ options.onDiagnostic(diagnostic);
81
+ } catch (error) {
82
+ diagnostics.push({
83
+ code: "on-diagnostic-failed",
84
+ message: `AgentInspect Jest diagnostic callback failed: ${errorMessage(error)}`,
85
+ testId: diagnostic.testId
86
+ });
87
+ }
88
+ }
89
+ async function appendGithubSummary() {
90
+ if (options.githubSummary === void 0 || artifacts.length === 0) return;
91
+ const failed = artifacts.filter((artifact) => artifact.status === "failed").length;
92
+ const passed = artifacts.filter((artifact) => artifact.status === "passed").length;
93
+ const lines = [
94
+ "",
95
+ "## AgentInspect Jest artifacts",
96
+ "",
97
+ `- Failed test artifacts: ${failed}`,
98
+ `- Passing test artifacts retained: ${passed}`,
99
+ `- Artifact directory: ${boundText(path.basename(options.artifactDir ?? DEFAULT_ARTIFACT_DIR))}`,
100
+ ""
101
+ ];
102
+ try {
103
+ await writeFile(options.githubSummary, `${lines.join("\n")}
104
+ `, { flag: "a" });
105
+ } catch (error) {
106
+ reportDiagnostic({
107
+ code: "github-summary-write-failed",
108
+ message: `Could not append AgentInspect Jest summary: ${errorMessage(error)}`
109
+ });
110
+ }
111
+ }
112
+ return reporter;
113
+ }
114
+ var AgentInspectJestReporter = class {
115
+ reporter;
116
+ constructor(_globalConfig, options = {}) {
117
+ this.reporter = createAgentInspectJestReporter(options);
118
+ }
119
+ async onTestResult(test, testResult, aggregatedResult) {
120
+ await this.reporter.onTestResult(test, testResult, aggregatedResult);
121
+ }
122
+ async onRunComplete(contexts, results) {
123
+ await this.reporter.onRunComplete(contexts, results);
124
+ }
125
+ getDiagnostics() {
126
+ return this.reporter.getDiagnostics();
127
+ }
128
+ getArtifacts() {
129
+ return this.reporter.getArtifacts();
130
+ }
131
+ };
132
+ var agentInspectJestReporter = createAgentInspectJestReporter;
133
+ var index_default = AgentInspectJestReporter;
134
+ function normalizeSuccessLimit(options) {
135
+ const cap = clampCount(options.maxSuccessfulTraces, DEFAULT_SUCCESS_LIMIT);
136
+ if (options.retainSuccessful === true) return cap;
137
+ if (typeof options.retainSuccessful === "number") {
138
+ return Math.min(clampCount(options.retainSuccessful, 0), cap);
139
+ }
140
+ return 0;
141
+ }
142
+ function clampCount(value, fallback) {
143
+ if (value === void 0 || !Number.isFinite(value)) return fallback;
144
+ return Math.max(0, Math.min(MAX_SUCCESS_LIMIT, Math.floor(value)));
145
+ }
146
+ function resolveAssociation(testCase, options) {
147
+ const resolved = options.resolveTrace?.(testCase);
148
+ if (isAssociation(resolved)) return resolved;
149
+ const explicit = resolveFromAssociationMap(testCase, options.associations);
150
+ if (explicit !== void 0) return explicit;
151
+ return readAssociationFromAssertion(testCase.raw);
152
+ }
153
+ function resolveFromAssociationMap(testCase, associations) {
154
+ if (associations === void 0) return void 0;
155
+ const basename = testCase.file === void 0 ? void 0 : path.basename(testCase.file);
156
+ const candidates = [
157
+ testCase.id,
158
+ testCase.fullName,
159
+ basename === void 0 ? void 0 : `${basename}::${testCase.fullName}`
160
+ ];
161
+ for (const candidate of candidates) {
162
+ if (candidate !== void 0 && isAssociation(associations[candidate])) {
163
+ return associations[candidate];
164
+ }
165
+ }
166
+ return void 0;
167
+ }
168
+ function readAssociationFromAssertion(assertion) {
169
+ if (!isObject(assertion)) return void 0;
170
+ const direct = readProp(assertion, "agentInspect");
171
+ if (isAssociation(direct)) return direct;
172
+ const meta = readProp(assertion, "meta");
173
+ if (!isObject(meta)) return void 0;
174
+ for (const candidate of [
175
+ readProp(meta, "agentInspect"),
176
+ readProp(meta, "agent-inspect"),
177
+ readProp(meta, "trace")
178
+ ]) {
179
+ if (isAssociation(candidate)) return candidate;
180
+ }
181
+ return void 0;
182
+ }
183
+ function isAssociation(value) {
184
+ if (!isObject(value)) return false;
185
+ return readOptionalString(value, "runId") !== void 0 || readOptionalString(value, "tracePath") !== void 0 || readOptionalString(value, "artifactLabel") !== void 0;
186
+ }
187
+ function readRunResults(results) {
188
+ if (!isObject(results)) return [];
189
+ const testResults = readProp(results, "testResults");
190
+ return Array.isArray(testResults) ? testResults : [];
191
+ }
192
+ function readTestCases(testResult) {
193
+ if (!isObject(testResult)) return [];
194
+ const result = testResult;
195
+ const file = readOptionalString(result, "testFilePath");
196
+ const assertions = Array.isArray(result.testResults) ? result.testResults : Array.isArray(result.assertionResults) ? result.assertionResults : [];
197
+ const cases = [];
198
+ for (const assertion of assertions) {
199
+ if (!isObject(assertion)) continue;
200
+ const status = readStatus(assertion);
201
+ if (status === void 0 || status === "skipped") continue;
202
+ const title = readOptionalString(assertion, "title") ?? "unknown-test";
203
+ const fullName = readFullName(assertion, title);
204
+ const id = `${file ?? "unknown-file"}::${fullName}`;
205
+ cases.push({
206
+ file,
207
+ fullName: boundText(redactText(fullName)),
208
+ id: boundText(redactText(id)),
209
+ raw: assertion,
210
+ status,
211
+ title: boundText(redactText(title))
212
+ });
213
+ }
214
+ return cases;
215
+ }
216
+ function readFullName(assertion, title) {
217
+ const explicit = readOptionalString(assertion, "fullName");
218
+ if (explicit !== void 0) return explicit;
219
+ const ancestors = Array.isArray(assertion.ancestorTitles) ? assertion.ancestorTitles.filter((item) => typeof item === "string") : [];
220
+ return [...ancestors, title].join(" ");
221
+ }
222
+ function readStatus(assertion) {
223
+ const raw = readOptionalString(assertion, "status");
224
+ if (raw === void 0) return void 0;
225
+ const normalized = raw.toLowerCase();
226
+ if (normalized === "failed" || normalized === "fail") return "failed";
227
+ if (normalized === "passed" || normalized === "pass") return "passed";
228
+ if (normalized === "pending" || normalized === "todo" || normalized === "skipped" || normalized === "skip" || normalized === "disabled") {
229
+ return "skipped";
230
+ }
231
+ return void 0;
232
+ }
233
+ async function writeSafeArtifact(input) {
234
+ const artifactSeed = input.association.artifactLabel ?? input.testCase.id ?? input.testCase.fullName ?? input.status;
235
+ const artifactName = input.reserveArtifactName(artifactSeed);
236
+ const testFile = input.testCase.file === void 0 ? void 0 : path.basename(input.testCase.file);
237
+ const safeTestId = `${testFile ?? "unknown-file"}::${input.testCase.fullName}`;
238
+ const manifestPathResult = createReporterArtifactPath({
239
+ outputDir: input.artifactDir,
240
+ testId: artifactName,
241
+ name: input.testCase.fullName,
242
+ file: testFile,
243
+ kind: "report",
244
+ format: "json"
245
+ });
246
+ const summaryPathResult = createReporterArtifactPath({
247
+ outputDir: input.artifactDir,
248
+ testId: artifactName,
249
+ name: input.testCase.fullName,
250
+ file: testFile,
251
+ kind: "summary",
252
+ format: "md"
253
+ });
254
+ if (!manifestPathResult.ok || manifestPathResult.absolutePath === void 0 || manifestPathResult.relativePath === void 0) {
255
+ throw new Error(formatPathDiagnostics(manifestPathResult.diagnostics));
256
+ }
257
+ if (!summaryPathResult.ok || summaryPathResult.absolutePath === void 0 || summaryPathResult.relativePath === void 0) {
258
+ throw new Error(formatPathDiagnostics(summaryPathResult.diagnostics));
259
+ }
260
+ const directory = path.dirname(manifestPathResult.absolutePath);
261
+ await mkdir(directory, { recursive: true });
262
+ const traceFile = input.association.tracePath === void 0 ? void 0 : path.basename(input.association.tracePath);
263
+ const manifestArtifact = {
264
+ kind: "report",
265
+ path: manifestPathResult.relativePath,
266
+ format: "json",
267
+ redactionProfile: input.redactionProfile
268
+ };
269
+ const summaryArtifact = {
270
+ kind: "summary",
271
+ path: summaryPathResult.relativePath,
272
+ format: "md",
273
+ redactionProfile: input.redactionProfile
274
+ };
275
+ const manifest = createTraceArtifactManifest({
276
+ framework: "jest",
277
+ generatedAt: input.generatedAt,
278
+ results: [
279
+ {
280
+ testId: safeTestId,
281
+ name: input.testCase.fullName,
282
+ ...testFile === void 0 ? {} : { file: testFile },
283
+ status: input.status,
284
+ tracePath: safeOptional(traceFile),
285
+ artifacts: [manifestArtifact, summaryArtifact],
286
+ diagnostics: []
287
+ }
288
+ ],
289
+ artifacts: [manifestArtifact, summaryArtifact],
290
+ diagnostics: []
291
+ });
292
+ const trace = {
293
+ runId: safeOptional(input.association.runId),
294
+ file: safeOptional(traceFile)
295
+ };
296
+ await writeFile(
297
+ manifestPathResult.absolutePath,
298
+ `${JSON.stringify({ package: PACKAGE_NAME, manifest, trace }, null, 2)}
299
+ `
300
+ );
301
+ const summaryPath = summaryPathResult.absolutePath;
302
+ await writeFile(summaryPath, renderSummary(manifest, trace), "utf-8");
303
+ return {
304
+ directory,
305
+ manifest,
306
+ manifestPath: manifestPathResult.absolutePath,
307
+ status: input.status,
308
+ summaryPath,
309
+ testId: safeTestId
310
+ };
311
+ }
312
+ function renderSummary(manifest, trace) {
313
+ const result = manifest.results[0];
314
+ return [
315
+ "# AgentInspect Jest Artifact",
316
+ "",
317
+ `- Test: ${result?.name ?? "unknown"}`,
318
+ `- Test id: ${result?.testId ?? "unknown"}`,
319
+ `- Status: ${result?.status ?? "unknown"}`,
320
+ `- File: ${result?.file ?? "unknown"}`,
321
+ `- Trace run: ${trace.runId ?? "unknown"}`,
322
+ `- Trace file: ${result?.tracePath ?? "unknown"}`,
323
+ `- Manifest schema: ${manifest.schemaVersion}`,
324
+ "",
325
+ "Trace contents are intentionally not embedded in this artifact.",
326
+ ""
327
+ ].join("\n");
328
+ }
329
+ function formatPathDiagnostics(diagnostics) {
330
+ if (diagnostics.length === 0) return "Unsafe AgentInspect Jest artifact path.";
331
+ return diagnostics.map((diagnostic) => diagnostic.message).join("; ");
332
+ }
333
+ function safeOptional(value) {
334
+ return value === void 0 ? void 0 : boundText(redactText(value));
335
+ }
336
+ function safeSegment(value) {
337
+ const sanitized = redactText(value).toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
338
+ return sanitized.length > 0 ? sanitized : "trace";
339
+ }
340
+ function boundText(value) {
341
+ const compact = value.replace(/\s+/g, " ").trim();
342
+ if (compact.length <= MAX_TEXT) return compact;
343
+ return `${compact.slice(0, MAX_TEXT - 12)}...[truncated]`;
344
+ }
345
+ function redactText(value) {
346
+ return value.replace(/\bsk-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(/\b(?:api[_-]?key|authorization|token|secret|password)\s*[:=]\s*[^,\s]+/gi, "$1=[REDACTED]");
347
+ }
348
+ function readOptionalString(value, key) {
349
+ if (!isObject(value)) return void 0;
350
+ const property = readProp(value, key);
351
+ return typeof property === "string" && property.length > 0 ? property : void 0;
352
+ }
353
+ function readProp(value, key) {
354
+ return value[key];
355
+ }
356
+ function isObject(value) {
357
+ return typeof value === "object" && value !== null;
358
+ }
359
+ function errorMessage(error) {
360
+ return error instanceof Error ? error.message : String(error);
361
+ }
362
+
363
+ export { AgentInspectJestReporter, agentInspectJestReporter, createAgentInspectJestReporter, index_default as default };
364
+ //# sourceMappingURL=index.mjs.map
365
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n createReporterArtifactPath,\n createTraceArtifactManifest,\n type TraceArtifact,\n type TraceArtifactManifest,\n type TraceArtifactRedactionProfile,\n type TraceReporterDiagnostic,\n} from \"agent-inspect/reporters\";\n\nexport type AgentInspectJestStatus = \"failed\" | \"passed\" | \"skipped\";\n\n/**\n * Experimental trace association read by `@agent-inspect/jest`.\n *\n * Jest does not expose Vitest-style task metadata, so the default path is an\n * explicit `associations` map keyed by test identity, or a `resolveTrace`\n * callback. The reporter never guesses by timestamps.\n */\nexport interface AgentInspectJestTraceAssociation {\n /** AgentInspect run/span identifier to show in safe artifacts. */\n readonly runId?: string;\n /** Local trace file path. Only the basename is written to artifacts. */\n readonly tracePath?: string;\n /** Optional stable label for the artifact directory. */\n readonly artifactLabel?: string;\n}\n\n/**\n * Experimental normalized view of one Jest assertion result.\n */\nexport interface AgentInspectJestTestCase {\n readonly id: string;\n readonly title: string;\n readonly fullName: string;\n readonly file?: string;\n readonly status: AgentInspectJestStatus;\n readonly raw: unknown;\n}\n\n/**\n * Experimental diagnostic emitted when reporter work cannot be completed.\n *\n * Diagnostics are reported instead of thrown so Jest's original test result\n * remains authoritative.\n */\nexport interface AgentInspectJestDiagnostic {\n readonly code:\n | \"artifact-write-failed\"\n | \"github-summary-write-failed\"\n | \"on-diagnostic-failed\";\n readonly message: string;\n readonly testId?: string;\n}\n\n/**\n * Experimental options for the AgentInspect Jest reporter.\n *\n * The reporter is local-only: it performs no network I/O and writes bounded,\n * structural artifacts without reading trace contents.\n */\nexport interface AgentInspectJestReporterOptions {\n /** Directory for safe Jest artifacts. Defaults to `.agent-inspect/jest-artifacts`. */\n readonly artifactDir?: string;\n /** Optional GitHub step-summary path. Only bounded structural lines are appended. */\n readonly githubSummary?: string;\n /**\n * Keep artifacts for passing tests. `false`/undefined keeps none; `true`\n * keeps up to `maxSuccessfulTraces`; a number keeps up to that many.\n */\n readonly retainSuccessful?: boolean | number;\n /** Upper bound for retained passing-test artifacts. Defaults to 20. */\n readonly maxSuccessfulTraces?: number;\n /** Redaction profile recorded on generated artifacts. Defaults to `share`. */\n readonly redactionProfile?: TraceArtifactRedactionProfile;\n /** Deterministic manifest timestamp. Defaults to the Unix epoch. */\n readonly generatedAt?: string;\n /** Explicit trace associations keyed by `file::fullName`, `basename::fullName`, or `fullName`. */\n readonly associations?: Record<string, AgentInspectJestTraceAssociation>;\n /** Resolve explicit test-to-trace associations from a normalized Jest case. */\n readonly resolveTrace?: (\n test: AgentInspectJestTestCase,\n ) => AgentInspectJestTraceAssociation | undefined;\n /** Observe non-fatal reporter diagnostics. */\n readonly onDiagnostic?: (diagnostic: AgentInspectJestDiagnostic) => void;\n}\n\nexport interface AgentInspectJestArtifact {\n readonly directory: string;\n readonly manifestPath: string;\n readonly summaryPath: string;\n readonly status: AgentInspectJestStatus;\n readonly testId: string;\n readonly manifest: TraceArtifactManifest;\n}\n\n/**\n * Experimental Jest reporter facade.\n *\n * The hooks mirror Jest reporter lifecycle names, while inputs stay structural\n * to avoid a runtime dependency on Jest internals.\n */\nexport interface AgentInspectJestReporterFacade {\n onTestResult(test: unknown, testResult: unknown, aggregatedResult?: unknown): Promise<void>;\n onRunComplete(contexts?: unknown, results?: unknown): Promise<void>;\n getDiagnostics(): readonly AgentInspectJestDiagnostic[];\n getArtifacts(): readonly AgentInspectJestArtifact[];\n}\n\ntype AssertionResultLike = {\n readonly ancestorTitles?: unknown;\n readonly title?: unknown;\n readonly fullName?: unknown;\n readonly status?: unknown;\n readonly meta?: unknown;\n readonly agentInspect?: unknown;\n};\n\ntype TestFileResultLike = {\n readonly testFilePath?: unknown;\n readonly testResults?: unknown;\n readonly assertionResults?: unknown;\n};\n\nconst PACKAGE_NAME = \"@agent-inspect/jest\";\nconst DEFAULT_ARTIFACT_DIR = \".agent-inspect/jest-artifacts\";\nconst DEFAULT_SUCCESS_LIMIT = 20;\nconst MAX_SUCCESS_LIMIT = 100;\nconst MAX_TEXT = 180;\nconst DEFAULT_GENERATED_AT = \"1970-01-01T00:00:00.000Z\";\n\n/**\n * Create the experimental AgentInspect Jest reporter.\n */\nexport function createAgentInspectJestReporter(\n options: AgentInspectJestReporterOptions = {},\n): AgentInspectJestReporterFacade {\n const diagnostics: AgentInspectJestDiagnostic[] = [];\n const artifacts: AgentInspectJestArtifact[] = [];\n const seenKeys = new Set<string>();\n const artifactNames = new Map<string, number>();\n const successLimit = normalizeSuccessLimit(options);\n let retainedSuccesses = 0;\n\n const reporter: AgentInspectJestReporterFacade = {\n async onTestResult(_test: unknown, testResult: unknown): Promise<void> {\n await handleFileResult(testResult);\n },\n async onRunComplete(_contexts?: unknown, results?: unknown): Promise<void> {\n for (const fileResult of readRunResults(results)) {\n await handleFileResult(fileResult);\n }\n await appendGithubSummary();\n },\n getDiagnostics(): readonly AgentInspectJestDiagnostic[] {\n return diagnostics.slice();\n },\n getArtifacts(): readonly AgentInspectJestArtifact[] {\n return artifacts.slice();\n },\n };\n\n async function handleFileResult(testResult: unknown): Promise<void> {\n for (const testCase of readTestCases(testResult)) {\n await handleTestCase(testCase);\n }\n }\n\n async function handleTestCase(testCase: AgentInspectJestTestCase): Promise<void> {\n const seenKey = `${testCase.id}:${testCase.status}`;\n if (seenKeys.has(seenKey)) return;\n\n const association = resolveAssociation(testCase, options);\n if (association === undefined) return;\n\n if (testCase.status === \"passed\") {\n if (retainedSuccesses >= successLimit) return;\n retainedSuccesses += 1;\n }\n\n seenKeys.add(seenKey);\n\n try {\n const artifact = await writeSafeArtifact({\n artifactDir: options.artifactDir ?? DEFAULT_ARTIFACT_DIR,\n association,\n generatedAt: options.generatedAt ?? DEFAULT_GENERATED_AT,\n redactionProfile: options.redactionProfile ?? \"share\",\n reserveArtifactName,\n status: testCase.status,\n testCase,\n });\n artifacts.push(artifact);\n } catch (error) {\n reportDiagnostic({\n code: \"artifact-write-failed\",\n message: `Could not write AgentInspect Jest artifact: ${errorMessage(error)}`,\n testId: testCase.id,\n });\n }\n }\n\n function reserveArtifactName(seed: string): string {\n const base = safeSegment(seed);\n const next = (artifactNames.get(base) ?? 0) + 1;\n artifactNames.set(base, next);\n return next === 1 ? base : `${base}-${next}`;\n }\n\n function reportDiagnostic(diagnostic: AgentInspectJestDiagnostic): void {\n diagnostics.push(diagnostic);\n if (options.onDiagnostic === undefined) return;\n try {\n options.onDiagnostic(diagnostic);\n } catch (error) {\n diagnostics.push({\n code: \"on-diagnostic-failed\",\n message: `AgentInspect Jest diagnostic callback failed: ${errorMessage(error)}`,\n testId: diagnostic.testId,\n });\n }\n }\n\n async function appendGithubSummary(): Promise<void> {\n if (options.githubSummary === undefined || artifacts.length === 0) return;\n const failed = artifacts.filter((artifact) => artifact.status === \"failed\").length;\n const passed = artifacts.filter((artifact) => artifact.status === \"passed\").length;\n const lines = [\n \"\",\n \"## AgentInspect Jest artifacts\",\n \"\",\n `- Failed test artifacts: ${failed}`,\n `- Passing test artifacts retained: ${passed}`,\n `- Artifact directory: ${boundText(path.basename(options.artifactDir ?? DEFAULT_ARTIFACT_DIR))}`,\n \"\",\n ];\n try {\n await writeFile(options.githubSummary, `${lines.join(\"\\n\")}\\n`, { flag: \"a\" });\n } catch (error) {\n reportDiagnostic({\n code: \"github-summary-write-failed\",\n message: `Could not append AgentInspect Jest summary: ${errorMessage(error)}`,\n });\n }\n }\n\n return reporter;\n}\n\n/**\n * Experimental Jest custom reporter class.\n */\nexport class AgentInspectJestReporter implements AgentInspectJestReporterFacade {\n private readonly reporter: AgentInspectJestReporterFacade;\n\n constructor(_globalConfig?: unknown, options: AgentInspectJestReporterOptions = {}) {\n this.reporter = createAgentInspectJestReporter(options);\n }\n\n async onTestResult(\n test: unknown,\n testResult: unknown,\n aggregatedResult?: unknown,\n ): Promise<void> {\n await this.reporter.onTestResult(test, testResult, aggregatedResult);\n }\n\n async onRunComplete(contexts?: unknown, results?: unknown): Promise<void> {\n await this.reporter.onRunComplete(contexts, results);\n }\n\n getDiagnostics(): readonly AgentInspectJestDiagnostic[] {\n return this.reporter.getDiagnostics();\n }\n\n getArtifacts(): readonly AgentInspectJestArtifact[] {\n return this.reporter.getArtifacts();\n }\n}\n\nexport const agentInspectJestReporter = createAgentInspectJestReporter;\nexport default AgentInspectJestReporter;\n\nfunction normalizeSuccessLimit(options: AgentInspectJestReporterOptions): number {\n const cap = clampCount(options.maxSuccessfulTraces, DEFAULT_SUCCESS_LIMIT);\n if (options.retainSuccessful === true) return cap;\n if (typeof options.retainSuccessful === \"number\") {\n return Math.min(clampCount(options.retainSuccessful, 0), cap);\n }\n return 0;\n}\n\nfunction clampCount(value: number | undefined, fallback: number): number {\n if (value === undefined || !Number.isFinite(value)) return fallback;\n return Math.max(0, Math.min(MAX_SUCCESS_LIMIT, Math.floor(value)));\n}\n\nfunction resolveAssociation(\n testCase: AgentInspectJestTestCase,\n options: AgentInspectJestReporterOptions,\n): AgentInspectJestTraceAssociation | undefined {\n const resolved = options.resolveTrace?.(testCase);\n if (isAssociation(resolved)) return resolved;\n\n const explicit = resolveFromAssociationMap(testCase, options.associations);\n if (explicit !== undefined) return explicit;\n\n return readAssociationFromAssertion(testCase.raw);\n}\n\nfunction resolveFromAssociationMap(\n testCase: AgentInspectJestTestCase,\n associations: Record<string, AgentInspectJestTraceAssociation> | undefined,\n): AgentInspectJestTraceAssociation | undefined {\n if (associations === undefined) return undefined;\n const basename = testCase.file === undefined ? undefined : path.basename(testCase.file);\n const candidates = [\n testCase.id,\n testCase.fullName,\n basename === undefined ? undefined : `${basename}::${testCase.fullName}`,\n ];\n for (const candidate of candidates) {\n if (candidate !== undefined && isAssociation(associations[candidate])) {\n return associations[candidate];\n }\n }\n return undefined;\n}\n\nfunction readAssociationFromAssertion(\n assertion: unknown,\n): AgentInspectJestTraceAssociation | undefined {\n if (!isObject(assertion)) return undefined;\n const direct = readProp(assertion, \"agentInspect\");\n if (isAssociation(direct)) return direct;\n\n const meta = readProp(assertion, \"meta\");\n if (!isObject(meta)) return undefined;\n for (const candidate of [\n readProp(meta, \"agentInspect\"),\n readProp(meta, \"agent-inspect\"),\n readProp(meta, \"trace\"),\n ]) {\n if (isAssociation(candidate)) return candidate;\n }\n return undefined;\n}\n\nfunction isAssociation(\n value: unknown,\n): value is AgentInspectJestTraceAssociation {\n if (!isObject(value)) return false;\n return (\n readOptionalString(value, \"runId\") !== undefined ||\n readOptionalString(value, \"tracePath\") !== undefined ||\n readOptionalString(value, \"artifactLabel\") !== undefined\n );\n}\n\nfunction readRunResults(results: unknown): unknown[] {\n if (!isObject(results)) return [];\n const testResults = readProp(results, \"testResults\");\n return Array.isArray(testResults) ? testResults : [];\n}\n\nfunction readTestCases(testResult: unknown): AgentInspectJestTestCase[] {\n if (!isObject(testResult)) return [];\n const result = testResult as TestFileResultLike;\n const file = readOptionalString(result, \"testFilePath\");\n const assertions = Array.isArray(result.testResults)\n ? result.testResults\n : Array.isArray(result.assertionResults)\n ? result.assertionResults\n : [];\n\n const cases: AgentInspectJestTestCase[] = [];\n for (const assertion of assertions) {\n if (!isObject(assertion)) continue;\n const status = readStatus(assertion);\n if (status === undefined || status === \"skipped\") continue;\n\n const title = readOptionalString(assertion, \"title\") ?? \"unknown-test\";\n const fullName = readFullName(assertion as AssertionResultLike, title);\n const id = `${file ?? \"unknown-file\"}::${fullName}`;\n cases.push({\n file,\n fullName: boundText(redactText(fullName)),\n id: boundText(redactText(id)),\n raw: assertion,\n status,\n title: boundText(redactText(title)),\n });\n }\n return cases;\n}\n\nfunction readFullName(assertion: AssertionResultLike, title: string): string {\n const explicit = readOptionalString(assertion, \"fullName\");\n if (explicit !== undefined) return explicit;\n\n const ancestors = Array.isArray(assertion.ancestorTitles)\n ? assertion.ancestorTitles.filter((item): item is string => typeof item === \"string\")\n : [];\n return [...ancestors, title].join(\" \");\n}\n\nfunction readStatus(assertion: object): AgentInspectJestStatus | undefined {\n const raw = readOptionalString(assertion, \"status\");\n if (raw === undefined) return undefined;\n\n const normalized = raw.toLowerCase();\n if (normalized === \"failed\" || normalized === \"fail\") return \"failed\";\n if (normalized === \"passed\" || normalized === \"pass\") return \"passed\";\n if (\n normalized === \"pending\" ||\n normalized === \"todo\" ||\n normalized === \"skipped\" ||\n normalized === \"skip\" ||\n normalized === \"disabled\"\n ) {\n return \"skipped\";\n }\n return undefined;\n}\n\nasync function writeSafeArtifact(input: {\n readonly artifactDir: string;\n readonly association: AgentInspectJestTraceAssociation;\n readonly generatedAt: string;\n readonly redactionProfile: TraceArtifactRedactionProfile;\n readonly reserveArtifactName: (seed: string) => string;\n readonly status: AgentInspectJestStatus;\n readonly testCase: AgentInspectJestTestCase;\n}): Promise<AgentInspectJestArtifact> {\n const artifactSeed =\n input.association.artifactLabel ??\n input.testCase.id ??\n input.testCase.fullName ??\n input.status;\n const artifactName = input.reserveArtifactName(artifactSeed);\n const testFile =\n input.testCase.file === undefined ? undefined : path.basename(input.testCase.file);\n const safeTestId = `${testFile ?? \"unknown-file\"}::${input.testCase.fullName}`;\n const manifestPathResult = createReporterArtifactPath({\n outputDir: input.artifactDir,\n testId: artifactName,\n name: input.testCase.fullName,\n file: testFile,\n kind: \"report\",\n format: \"json\",\n });\n const summaryPathResult = createReporterArtifactPath({\n outputDir: input.artifactDir,\n testId: artifactName,\n name: input.testCase.fullName,\n file: testFile,\n kind: \"summary\",\n format: \"md\",\n });\n\n if (\n !manifestPathResult.ok ||\n manifestPathResult.absolutePath === undefined ||\n manifestPathResult.relativePath === undefined\n ) {\n throw new Error(formatPathDiagnostics(manifestPathResult.diagnostics));\n }\n if (\n !summaryPathResult.ok ||\n summaryPathResult.absolutePath === undefined ||\n summaryPathResult.relativePath === undefined\n ) {\n throw new Error(formatPathDiagnostics(summaryPathResult.diagnostics));\n }\n\n const directory = path.dirname(manifestPathResult.absolutePath);\n await mkdir(directory, { recursive: true });\n\n const traceFile =\n input.association.tracePath === undefined\n ? undefined\n : path.basename(input.association.tracePath);\n const manifestArtifact: TraceArtifact = {\n kind: \"report\",\n path: manifestPathResult.relativePath,\n format: \"json\",\n redactionProfile: input.redactionProfile,\n };\n const summaryArtifact: TraceArtifact = {\n kind: \"summary\",\n path: summaryPathResult.relativePath,\n format: \"md\",\n redactionProfile: input.redactionProfile,\n };\n const manifest = createTraceArtifactManifest({\n framework: \"jest\",\n generatedAt: input.generatedAt,\n results: [\n {\n testId: safeTestId,\n name: input.testCase.fullName,\n ...(testFile === undefined ? {} : { file: testFile }),\n status: input.status,\n tracePath: safeOptional(traceFile),\n artifacts: [manifestArtifact, summaryArtifact],\n diagnostics: [],\n },\n ],\n artifacts: [manifestArtifact, summaryArtifact],\n diagnostics: [],\n });\n const trace = {\n runId: safeOptional(input.association.runId),\n file: safeOptional(traceFile),\n };\n\n await writeFile(\n manifestPathResult.absolutePath,\n `${JSON.stringify({ package: PACKAGE_NAME, manifest, trace }, null, 2)}\\n`,\n );\n const summaryPath = summaryPathResult.absolutePath;\n await writeFile(summaryPath, renderSummary(manifest, trace), \"utf-8\");\n\n return {\n directory,\n manifest,\n manifestPath: manifestPathResult.absolutePath,\n status: input.status,\n summaryPath,\n testId: safeTestId,\n };\n}\n\nfunction renderSummary(\n manifest: TraceArtifactManifest,\n trace: { readonly runId?: string; readonly file?: string },\n): string {\n const result = manifest.results[0];\n return [\n \"# AgentInspect Jest Artifact\",\n \"\",\n `- Test: ${result?.name ?? \"unknown\"}`,\n `- Test id: ${result?.testId ?? \"unknown\"}`,\n `- Status: ${result?.status ?? \"unknown\"}`,\n `- File: ${result?.file ?? \"unknown\"}`,\n `- Trace run: ${trace.runId ?? \"unknown\"}`,\n `- Trace file: ${result?.tracePath ?? \"unknown\"}`,\n `- Manifest schema: ${manifest.schemaVersion}`,\n \"\",\n \"Trace contents are intentionally not embedded in this artifact.\",\n \"\",\n ].join(\"\\n\");\n}\n\nfunction formatPathDiagnostics(\n diagnostics: readonly TraceReporterDiagnostic[],\n): string {\n if (diagnostics.length === 0) return \"Unsafe AgentInspect Jest artifact path.\";\n return diagnostics.map((diagnostic) => diagnostic.message).join(\"; \");\n}\n\nfunction safeOptional(value: string | undefined): string | undefined {\n return value === undefined ? undefined : boundText(redactText(value));\n}\n\nfunction safeSegment(value: string): string {\n const sanitized = redactText(value)\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .slice(0, 80);\n return sanitized.length > 0 ? sanitized : \"trace\";\n}\n\nfunction boundText(value: string): string {\n const compact = value.replace(/\\s+/g, \" \").trim();\n if (compact.length <= MAX_TEXT) return compact;\n return `${compact.slice(0, MAX_TEXT - 12)}...[truncated]`;\n}\n\nfunction redactText(value: string): string {\n return value\n .replace(/\\bsk-[A-Za-z0-9_-]{8,}\\b/g, \"[REDACTED]\")\n .replace(/\\b(?:api[_-]?key|authorization|token|secret|password)\\s*[:=]\\s*[^,\\s]+/gi, \"$1=[REDACTED]\");\n}\n\nfunction readOptionalString(value: unknown, key: string): string | undefined {\n if (!isObject(value)) return undefined;\n const property = readProp(value, key);\n return typeof property === \"string\" && property.length > 0 ? property : undefined;\n}\n\nfunction readProp(value: object, key: string): unknown {\n return (value as Record<string, unknown>)[key];\n}\n\nfunction isObject(value: unknown): value is object {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@agent-inspect/jest",
3
+ "version": "2.1.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "description": "Optional Jest reporter for AgentInspect local trace artifacts",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/rajudandigam/agent-inspect.git",
10
+ "directory": "packages/jest"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/rajudandigam/agent-inspect/issues"
14
+ },
15
+ "homepage": "https://github.com/rajudandigam/agent-inspect#readme",
16
+ "sideEffects": false,
17
+ "main": "./dist/index.cjs",
18
+ "module": "./dist/index.mjs",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "import": {
23
+ "types": "./dist/index.d.ts",
24
+ "default": "./dist/index.mjs"
25
+ },
26
+ "require": {
27
+ "types": "./dist/index.d.cts",
28
+ "default": "./dist/index.cjs"
29
+ }
30
+ }
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "peerDependencies": {
36
+ "jest": "^29.0.0 || ^30.0.0"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "jest": {
40
+ "optional": true
41
+ }
42
+ },
43
+ "dependencies": {
44
+ "agent-inspect": "2.1.0"
45
+ },
46
+ "devDependencies": {
47
+ "jest": "^30.2.0"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "scripts": {
53
+ "build": "pnpm --workspace-root exec tsup --config tsup.jest.config.ts",
54
+ "test": "vitest run -c ../../vitest.config.ts"
55
+ }
56
+ }