@mintlify/cli 4.0.1654 → 4.0.1656

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 (54) hide show
  1. package/bin/cli.js +1 -7
  2. package/bin/tsconfig.build.tsbuildinfo +1 -1
  3. package/package.json +9 -13
  4. package/src/cli.tsx +1 -12
  5. package/__test__/mintTestFilePreview.test.ts +0 -35
  6. package/__test__/mintTestOutput.test.ts +0 -256
  7. package/__test__/runHistory.test.ts +0 -240
  8. package/bin/agent-harness/agentPreflight.js +0 -24
  9. package/bin/agent-harness/buildTaskPrompt.js +0 -86
  10. package/bin/agent-harness/countReport.js +0 -10
  11. package/bin/agent-harness/discoverCodeBlocks.js +0 -101
  12. package/bin/agent-harness/executeCodeBlocks.js +0 -263
  13. package/bin/agent-harness/filterSelectedPages.js +0 -10
  14. package/bin/agent-harness/generateTestCode.js +0 -337
  15. package/bin/agent-harness/index.js +0 -95
  16. package/bin/agent-harness/loadAgentSdk.js +0 -46
  17. package/bin/agent-harness/manifest.js +0 -113
  18. package/bin/agent-harness/mapWithConcurrency.js +0 -26
  19. package/bin/agent-harness/runHistory.js +0 -256
  20. package/bin/agent-harness/runSave.js +0 -47
  21. package/bin/agent-harness/setupFolders.js +0 -73
  22. package/bin/agent-harness/tasks/checkTestability.js +0 -228
  23. package/bin/agent-harness/types.js +0 -66
  24. package/bin/mintTest.js +0 -122
  25. package/bin/mintTestFilePreview.js +0 -39
  26. package/bin/mintTestNav.js +0 -35
  27. package/bin/mintTestTelemetry.js +0 -63
  28. package/bin/mintTestText.js +0 -31
  29. package/bin/mintTestTree.js +0 -94
  30. package/bin/mintTestUi.js +0 -818
  31. package/src/agent-harness/MINT_TEST_SYSTEM_DESIGN.md +0 -64
  32. package/src/agent-harness/agentPreflight.ts +0 -13
  33. package/src/agent-harness/buildTaskPrompt.ts +0 -93
  34. package/src/agent-harness/countReport.ts +0 -17
  35. package/src/agent-harness/discoverCodeBlocks.ts +0 -90
  36. package/src/agent-harness/executeCodeBlocks.ts +0 -351
  37. package/src/agent-harness/filterSelectedPages.ts +0 -14
  38. package/src/agent-harness/generateTestCode.ts +0 -396
  39. package/src/agent-harness/index.ts +0 -127
  40. package/src/agent-harness/loadAgentSdk.ts +0 -35
  41. package/src/agent-harness/manifest.ts +0 -116
  42. package/src/agent-harness/mapWithConcurrency.ts +0 -21
  43. package/src/agent-harness/runHistory.ts +0 -255
  44. package/src/agent-harness/runSave.ts +0 -38
  45. package/src/agent-harness/setupFolders.ts +0 -87
  46. package/src/agent-harness/tasks/checkTestability.ts +0 -256
  47. package/src/agent-harness/types.ts +0 -239
  48. package/src/mintTest.tsx +0 -138
  49. package/src/mintTestFilePreview.ts +0 -32
  50. package/src/mintTestNav.ts +0 -31
  51. package/src/mintTestTelemetry.ts +0 -101
  52. package/src/mintTestText.ts +0 -35
  53. package/src/mintTestTree.ts +0 -134
  54. package/src/mintTestUi.tsx +0 -1378
@@ -1,337 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- var __asyncValues = (this && this.__asyncValues) || function (o) {
11
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
12
- var m = o[Symbol.asyncIterator], i;
13
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
14
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
15
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
16
- };
17
- import fs from 'node:fs/promises';
18
- import path from 'node:path';
19
- import { SYSTEM_PROMPT, buildTaskPrompt } from './buildTaskPrompt.js';
20
- import { loadClaudeAgentSdk, loadCodexSdk } from './loadAgentSdk.js';
21
- import { MANIFEST_FILENAME, SAFE_EXECUTABLES, appendAgentReply, readManifest, writeErrorDetails, } from './manifest.js';
22
- import { mapWithConcurrency } from './mapWithConcurrency.js';
23
- import { checkFileTestability } from './tasks/checkTestability.js';
24
- const SCAFFOLD_FILENAMES = new Set([MANIFEST_FILENAME, 'package.json']);
25
- const IGNORED_GENERATED_DIRECTORIES = new Set(['.git', 'node_modules']);
26
- function promptClaude(_a) {
27
- return __awaiter(this, arguments, void 0, function* ({ prompt, systemPrompt, model, workingDirectory, docsRoot, tools, signal, }) {
28
- var _b, e_1, _c, _d;
29
- const { query } = yield loadClaudeAgentSdk();
30
- const abortController = new AbortController();
31
- const abort = () => abortController.abort(signal.reason);
32
- if (signal.aborted)
33
- abort();
34
- else
35
- signal.addEventListener('abort', abort, { once: true });
36
- const session = query({
37
- prompt,
38
- options: {
39
- abortController,
40
- additionalDirectories: [docsRoot],
41
- allowedTools: tools,
42
- cwd: workingDirectory,
43
- model,
44
- permissionMode: 'dontAsk',
45
- persistSession: false,
46
- settingSources: [],
47
- strictMcpConfig: true,
48
- systemPrompt,
49
- tools,
50
- },
51
- });
52
- try {
53
- try {
54
- for (var _e = true, session_1 = __asyncValues(session), session_1_1; session_1_1 = yield session_1.next(), _b = session_1_1.done, !_b; _e = true) {
55
- _d = session_1_1.value;
56
- _e = false;
57
- const message = _d;
58
- if (message.type !== 'result')
59
- continue;
60
- if (message.subtype !== 'success' || message.is_error) {
61
- const details = message.subtype === 'success' ? message.result : message.errors.join('; ');
62
- throw new Error(details || `Claude stopped with ${message.subtype}`);
63
- }
64
- const usage = message.usage;
65
- return {
66
- tokens: usage.input_tokens +
67
- usage.output_tokens +
68
- usage.cache_creation_input_tokens +
69
- usage.cache_read_input_tokens,
70
- result: message.result,
71
- };
72
- }
73
- }
74
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
75
- finally {
76
- try {
77
- if (!_e && !_b && (_c = session_1.return)) yield _c.call(session_1);
78
- }
79
- finally { if (e_1) throw e_1.error; }
80
- }
81
- throw new Error('Claude finished without returning a result');
82
- }
83
- finally {
84
- signal.removeEventListener('abort', abort);
85
- session.close();
86
- }
87
- });
88
- }
89
- const AGENT_TOOLS = ['Read', 'Glob', 'Grep', 'Write', 'Edit', 'Bash'];
90
- function isPathInside(root, candidate) {
91
- const relative = path.relative(root, candidate);
92
- return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
93
- }
94
- function validateManifest(manifest, directory) {
95
- return __awaiter(this, void 0, void 0, function* () {
96
- var _a;
97
- const errors = [];
98
- const realDirectory = yield fs.realpath(directory);
99
- for (const file of manifest.generatedFiles) {
100
- if (path.isAbsolute(file)) {
101
- errors.push(`Generated file path must be relative: ${file}`);
102
- continue;
103
- }
104
- const resolved = path.resolve(directory, file);
105
- if (!isPathInside(directory, resolved)) {
106
- errors.push(`Generated file leaves its task: ${file}`);
107
- continue;
108
- }
109
- const realPath = yield fs.realpath(resolved).catch(() => undefined);
110
- if (!realPath || !isPathInside(realDirectory, realPath)) {
111
- errors.push(`Generated file leaves its task through a link: ${file}`);
112
- continue;
113
- }
114
- const stats = yield fs.stat(realPath).catch(() => undefined);
115
- if (!(stats === null || stats === void 0 ? void 0 : stats.isFile()))
116
- errors.push(`Generated file does not exist: ${file}`);
117
- }
118
- const commandIds = new Set();
119
- for (const command of [...manifest.setupCommands, ...manifest.testCommands]) {
120
- if (commandIds.has(command.id))
121
- errors.push(`Duplicate command ID: ${command.id}`);
122
- commandIds.add(command.id);
123
- if (path.isAbsolute(command.executable) || command.executable.split(/[\\/]/).includes('..')) {
124
- errors.push(`Unsafe command executable: ${command.executable}`);
125
- continue;
126
- }
127
- if (!SAFE_EXECUTABLES.has(command.executable) && !command.executable.startsWith('./')) {
128
- errors.push(`Unsupported command executable: ${command.executable}`);
129
- continue;
130
- }
131
- if (command.executable.startsWith('./')) {
132
- const executablePath = yield fs
133
- .realpath(path.resolve(directory, command.executable))
134
- .catch(() => undefined);
135
- const stats = executablePath
136
- ? yield fs.stat(executablePath).catch(() => undefined)
137
- : undefined;
138
- if (!executablePath || !isPathInside(realDirectory, executablePath) || !(stats === null || stats === void 0 ? void 0 : stats.isFile())) {
139
- errors.push(`Command executable leaves its task or is not a file: ${command.executable}`);
140
- }
141
- }
142
- const cwd = (_a = command.cwd) !== null && _a !== void 0 ? _a : '.';
143
- if (path.isAbsolute(cwd)) {
144
- errors.push(`Command cwd must be relative: ${cwd}`);
145
- continue;
146
- }
147
- const resolvedCwd = path.resolve(directory, cwd);
148
- const realCwd = yield fs.realpath(resolvedCwd).catch(() => undefined);
149
- const stats = realCwd ? yield fs.stat(realCwd).catch(() => undefined) : undefined;
150
- if (!isPathInside(directory, resolvedCwd) ||
151
- !realCwd ||
152
- !isPathInside(realDirectory, realCwd) ||
153
- !(stats === null || stats === void 0 ? void 0 : stats.isDirectory())) {
154
- errors.push(`Command cwd is missing or leaves its task: ${cwd}`);
155
- }
156
- }
157
- return errors;
158
- });
159
- }
160
- function readValidManifest(directory) {
161
- return __awaiter(this, void 0, void 0, function* () {
162
- try {
163
- const manifest = yield readManifest(directory);
164
- const errors = yield validateManifest(manifest, directory);
165
- return errors.length === 0 ? manifest : null;
166
- }
167
- catch (_a) {
168
- return null;
169
- }
170
- });
171
- }
172
- function discoverGeneratedFiles(directory) {
173
- return __awaiter(this, void 0, void 0, function* () {
174
- const realDirectory = yield fs.realpath(directory);
175
- const files = [];
176
- function walk(currentDirectory) {
177
- return __awaiter(this, void 0, void 0, function* () {
178
- const entries = yield fs.readdir(currentDirectory, { withFileTypes: true }).catch(() => []);
179
- for (const entry of entries) {
180
- if (files.length >= 1000)
181
- return;
182
- if (currentDirectory === directory && SCAFFOLD_FILENAMES.has(entry.name))
183
- continue;
184
- const candidate = path.join(currentDirectory, entry.name);
185
- if (entry.isDirectory()) {
186
- if (IGNORED_GENERATED_DIRECTORIES.has(entry.name))
187
- continue;
188
- yield walk(candidate);
189
- continue;
190
- }
191
- if (!entry.isFile())
192
- continue;
193
- const realPath = yield fs.realpath(candidate).catch(() => undefined);
194
- if (realPath && isPathInside(realDirectory, realPath))
195
- files.push(path.resolve(candidate));
196
- }
197
- });
198
- }
199
- yield walk(directory);
200
- return files.sort((left, right) => left.localeCompare(right));
201
- });
202
- }
203
- export const CHECK_CONCURRENCY = 20;
204
- export function checkTestability(_a) {
205
- return __awaiter(this, arguments, void 0, function* ({ tasks, runDirectory, signal, onTaskUpdate, }) {
206
- const folderOrdered = [...tasks].sort((left, right) => path.dirname(left.file).localeCompare(path.dirname(right.file)) ||
207
- left.file.localeCompare(right.file) ||
208
- left.agent.localeCompare(right.agent));
209
- return mapWithConcurrency(folderOrdered, CHECK_CONCURRENCY, checkFileTestability, {
210
- signal,
211
- onTaskUpdate,
212
- runDirectory,
213
- });
214
- });
215
- }
216
- export function generateTestCode(_a) {
217
- return __awaiter(this, arguments, void 0, function* ({ tasks, docsRoot, model, concurrency, signal, onTaskUpdate, onGenerationResult, }) {
218
- const generateTask = (task) => __awaiter(this, void 0, void 0, function* () {
219
- if (task.error || !task.testable)
220
- return task;
221
- const emit = (phase, tokens, generatedFiles = [], error) => onTaskUpdate(Object.assign({ id: task.id, agent: task.agent, file: task.file, directory: task.directory, generatedFiles,
222
- phase,
223
- tokens }, (error ? { error } : {})));
224
- let attempts = task.attempts;
225
- let tokens = task.tokens;
226
- let lastError = 'run cancelled';
227
- const attemptErrors = [];
228
- const existing = yield readValidManifest(task.directory);
229
- if (existing) {
230
- emit('generated', tokens, existing.generatedFiles.map((file) => path.resolve(task.directory, file)));
231
- return Object.assign(Object.assign({}, task), { manifest: existing });
232
- }
233
- const startedAt = Date.now();
234
- const startingTokens = tokens;
235
- let generationAttempts = 0;
236
- const emitGenerationResult = (result) => {
237
- try {
238
- onGenerationResult === null || onGenerationResult === void 0 ? void 0 : onGenerationResult(result);
239
- }
240
- catch (_a) { }
241
- };
242
- for (let attempt = 1; attempt <= 2 && !signal.aborted; attempt++) {
243
- attempts += 1;
244
- generationAttempts += 1;
245
- if (attempt === 1)
246
- emit('generating', tokens);
247
- try {
248
- const prompt = buildTaskPrompt(docsRoot, task.file, task.directory);
249
- const reply = task.agent === 'claude'
250
- ? yield promptClaude({
251
- prompt,
252
- systemPrompt: SYSTEM_PROMPT,
253
- model,
254
- workingDirectory: task.directory,
255
- docsRoot,
256
- tools: AGENT_TOOLS,
257
- signal,
258
- })
259
- : yield promptCodex({
260
- prompt,
261
- systemPrompt: SYSTEM_PROMPT,
262
- workingDirectory: task.directory,
263
- docsRoot,
264
- signal,
265
- });
266
- tokens += reply.tokens;
267
- yield appendAgentReply(task.directory, attempt, reply.result);
268
- const manifest = yield readManifest(task.directory);
269
- const errors = yield validateManifest(manifest, task.directory);
270
- if (errors.length > 0) {
271
- const [first = '', ...rest] = errors;
272
- throw new Error([`${MANIFEST_FILENAME} has problems: ${first}`, ...rest].join('\n'));
273
- }
274
- const generatedFiles = manifest.generatedFiles.map((file) => path.resolve(task.directory, file));
275
- emit('generated', tokens, generatedFiles);
276
- emitGenerationResult({
277
- status: 'succeeded',
278
- agent: task.agent,
279
- model,
280
- attemptCount: generationAttempts,
281
- tokenCount: tokens - startingTokens,
282
- durationMs: Date.now() - startedAt,
283
- generatedFileCount: generatedFiles.length,
284
- });
285
- return Object.assign(Object.assign({}, task), { attempts, tokens, manifest });
286
- }
287
- catch (error) {
288
- lastError = error instanceof Error ? error.message : String(error);
289
- attemptErrors.push(`Attempt ${attempt}: ${lastError}`);
290
- }
291
- }
292
- if (signal.aborted) {
293
- const generatedFiles = yield discoverGeneratedFiles(task.directory);
294
- emit('cancelled', tokens, generatedFiles, 'run cancelled');
295
- return Object.assign(Object.assign({}, task), { attempts, tokens, generatedFiles, error: 'run cancelled' });
296
- }
297
- const generatedFiles = yield discoverGeneratedFiles(task.directory);
298
- emitGenerationResult({
299
- status: 'failed',
300
- agent: task.agent,
301
- model,
302
- attemptCount: generationAttempts,
303
- tokenCount: tokens - startingTokens,
304
- durationMs: Date.now() - startedAt,
305
- generatedFileCount: generatedFiles.length,
306
- });
307
- const detailsPath = yield writeErrorDetails(task.directory, attemptErrors);
308
- const error = detailsPath ? `${lastError}\nDetails: ${detailsPath}` : lastError;
309
- emit('agent_error', tokens, generatedFiles, error);
310
- return Object.assign(Object.assign({}, task), { attempts, tokens, generatedFiles, error });
311
- });
312
- return mapWithConcurrency(tasks, concurrency, generateTask);
313
- });
314
- }
315
- function promptCodex(_a) {
316
- return __awaiter(this, arguments, void 0, function* ({ prompt, systemPrompt, workingDirectory, docsRoot, signal, }) {
317
- const { Codex } = yield loadCodexSdk();
318
- const thread = new Codex().startThread({
319
- additionalDirectories: [docsRoot],
320
- approvalPolicy: 'never',
321
- networkAccessEnabled: true,
322
- sandboxMode: 'workspace-write',
323
- skipGitRepoCheck: true,
324
- workingDirectory,
325
- });
326
- const result = yield thread.run(`${systemPrompt}\n\n${prompt}`, { signal });
327
- const usage = result.usage;
328
- const tokens = usage
329
- ? usage.input_tokens +
330
- usage.cached_input_tokens +
331
- usage.cache_write_input_tokens +
332
- usage.output_tokens +
333
- usage.reasoning_output_tokens
334
- : 0;
335
- return { tokens, result: result.finalResponse };
336
- });
337
- }
@@ -1,95 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import fs from 'node:fs/promises';
11
- import { ensureAgentSdks } from './agentPreflight.js';
12
- import { discoverCodeBlocks } from './discoverCodeBlocks.js';
13
- import { executeCodeBlocks } from './executeCodeBlocks.js';
14
- import { filterSelectedPages } from './filterSelectedPages.js';
15
- import { checkTestability, generateTestCode } from './generateTestCode.js';
16
- import { recordTestRun, testRunReportPath } from './runHistory.js';
17
- import { clearRunSave, writeRunSave } from './runSave.js';
18
- import { scaffoldTaskDirectories, setupFolders } from './setupFolders.js';
19
- export const DEFAULT_CONCURRENCY = 5;
20
- export const DEFAULT_COMMAND_TIMEOUT_MS = 2 * 60 * 1000;
21
- export { discoverCodeBlocks } from './discoverCodeBlocks.js';
22
- export { countReport } from './countReport.js';
23
- export { loadLatestTestRun, loadTestRuns } from './runHistory.js';
24
- export { clearRunSave, loadRunSave } from './runSave.js';
25
- export function runCodeTests(_a) {
26
- return __awaiter(this, arguments, void 0, function* ({ path: docsPath, agents, model, selectedFiles, outputDirectory, runId: savedRunId, concurrency, commandTimeoutMs, signal, onTaskUpdate, onGenerationResult, }) {
27
- const startedAt = new Date();
28
- const uniqueAgents = [...new Set(agents)];
29
- const { docsRoot, pages: allPages } = yield discoverCodeBlocks(docsPath);
30
- const pages = filterSelectedPages(allPages, selectedFiles);
31
- if (pages.length > 0)
32
- yield ensureAgentSdks(uniqueAgents);
33
- const { runId, runDirectory, reportPath: legacyReportPath, tasks, } = yield setupFolders({
34
- pages,
35
- agents: uniqueAgents,
36
- docsRoot,
37
- outputDirectory,
38
- runId: savedRunId,
39
- });
40
- const reportPath = testRunReportPath(docsRoot, runId);
41
- yield writeRunSave(outputDirectory, {
42
- version: 1,
43
- runId,
44
- agents: uniqueAgents,
45
- model,
46
- selectedFiles: pages.map((page) => page.file),
47
- createdAt: startedAt.toISOString(),
48
- });
49
- const checked = yield checkTestability({ tasks, runDirectory, signal, onTaskUpdate });
50
- yield scaffoldTaskDirectories(checked.filter((task) => task.testable === true));
51
- const generated = yield generateTestCode({
52
- tasks: checked,
53
- docsRoot,
54
- model,
55
- concurrency,
56
- signal,
57
- onTaskUpdate,
58
- onGenerationResult,
59
- });
60
- const results = yield executeCodeBlocks({
61
- tasks: generated,
62
- docsRoot,
63
- concurrency,
64
- commandTimeoutMs,
65
- signal,
66
- onTaskUpdate,
67
- });
68
- const completedAt = new Date();
69
- const report = {
70
- version: 1,
71
- runId,
72
- status: signal.aborted
73
- ? 'cancelled'
74
- : results.every((task) => task.status === 'passed')
75
- ? 'passed'
76
- : results.some((task) => task.status === 'passed')
77
- ? 'completed'
78
- : 'failed',
79
- docsRoot,
80
- outputDirectory: runDirectory,
81
- reportPath,
82
- agents: uniqueAgents,
83
- model,
84
- selectedFiles: pages.map((page) => page.file),
85
- startedAt: startedAt.toISOString(),
86
- completedAt: completedAt.toISOString(),
87
- durationMs: completedAt.getTime() - startedAt.getTime(),
88
- tasks: results,
89
- };
90
- yield fs.writeFile(legacyReportPath, `${JSON.stringify(report, null, 2)}\n`);
91
- if (!signal.aborted)
92
- yield clearRunSave(outputDirectory);
93
- return recordTestRun(docsRoot, report, legacyReportPath);
94
- });
95
- }
@@ -1,46 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- const INSTALL_HINTS = {
11
- '@anthropic-ai/claude-agent-sdk': 'npm install @anthropic-ai/claude-agent-sdk @anthropic-ai/sdk @modelcontextprotocol/sdk',
12
- '@openai/codex-sdk': 'npm install @openai/codex-sdk',
13
- };
14
- function isModuleNotFound(error) {
15
- if (typeof error !== 'object' || error === null)
16
- return false;
17
- const { code } = error;
18
- return code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND';
19
- }
20
- function missingSdkError(packageName) {
21
- return new Error(`mint test requires the optional dependency ${packageName}, which is not installed. Install it with: ${INSTALL_HINTS[packageName]}`);
22
- }
23
- export function loadClaudeAgentSdk() {
24
- return __awaiter(this, void 0, void 0, function* () {
25
- try {
26
- return yield import('@anthropic-ai/claude-agent-sdk');
27
- }
28
- catch (error) {
29
- if (isModuleNotFound(error))
30
- throw missingSdkError('@anthropic-ai/claude-agent-sdk');
31
- throw error;
32
- }
33
- });
34
- }
35
- export function loadCodexSdk() {
36
- return __awaiter(this, void 0, void 0, function* () {
37
- try {
38
- return yield import('@openai/codex-sdk');
39
- }
40
- catch (error) {
41
- if (isModuleNotFound(error))
42
- throw missingSdkError('@openai/codex-sdk');
43
- throw error;
44
- }
45
- });
46
- }
@@ -1,113 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import fs from 'node:fs/promises';
11
- import path from 'node:path';
12
- import { manifestSchema } from './types.js';
13
- export const MANIFEST_FILENAME = 'mint-test.json';
14
- export const AGENT_REPLY_FILENAME = 'mint-test-agent.md';
15
- export const ERROR_FILENAME = 'mint-test-error.txt';
16
- export const SAFE_EXECUTABLES = new Set([
17
- 'bun',
18
- 'bunx',
19
- 'bundle',
20
- 'cargo',
21
- 'composer',
22
- 'deno',
23
- 'dotnet',
24
- 'go',
25
- 'gradle',
26
- 'java',
27
- 'javac',
28
- 'mvn',
29
- 'node',
30
- 'npm',
31
- 'npx',
32
- 'php',
33
- 'pip',
34
- 'pip3',
35
- 'pnpm',
36
- 'python',
37
- 'python3',
38
- 'pytest',
39
- 'ruby',
40
- 'rustc',
41
- 'uv',
42
- 'vitest',
43
- 'yarn',
44
- ]);
45
- function isMissingFile(error) {
46
- return (typeof error === 'object' && error !== null && error.code === 'ENOENT');
47
- }
48
- /** Turn a schema failure into one readable line per problem, e.g. `testCommands.0.id: expected string`. */
49
- export function formatManifestIssues(error) {
50
- return error.issues
51
- .map((issue) => {
52
- const location = issue.path.map(String).join('.');
53
- return `${location || MANIFEST_FILENAME}: ${issue.message}`;
54
- })
55
- .join('\n');
56
- }
57
- /**
58
- * Read and schema-check the manifest an agent wrote. Every failure mode has a message a
59
- * documentation author can act on, because it is what `mint test` shows for the page.
60
- */
61
- export function readManifest(directory) {
62
- return __awaiter(this, void 0, void 0, function* () {
63
- const manifestPath = path.join(directory, MANIFEST_FILENAME);
64
- let raw;
65
- try {
66
- raw = yield fs.readFile(manifestPath, 'utf8');
67
- }
68
- catch (error) {
69
- if (isMissingFile(error)) {
70
- throw new Error(`The agent finished without writing ${MANIFEST_FILENAME}`);
71
- }
72
- throw error;
73
- }
74
- let parsed;
75
- try {
76
- parsed = JSON.parse(raw);
77
- }
78
- catch (error) {
79
- const reason = error instanceof Error ? error.message : String(error);
80
- throw new Error(`${MANIFEST_FILENAME} is not valid JSON: ${reason}`);
81
- }
82
- const result = manifestSchema.safeParse(parsed);
83
- if (!result.success) {
84
- const [first = '', ...rest] = formatManifestIssues(result.error).split('\n');
85
- throw new Error([`${MANIFEST_FILENAME} does not match the expected shape: ${first}`, ...rest].join('\n'));
86
- }
87
- return result.data;
88
- });
89
- }
90
- /** Keep the agent's final message next to its output so a failure can be traced later. */
91
- export function appendAgentReply(directory, attempt, reply) {
92
- return __awaiter(this, void 0, void 0, function* () {
93
- const body = reply.trim() || '(no summary)';
94
- yield fs
95
- .appendFile(path.join(directory, AGENT_REPLY_FILENAME), `## Attempt ${attempt}\n\n${body}\n\n`)
96
- .catch(() => { });
97
- });
98
- }
99
- /** Persist every attempt's failure reason. Returns the file path, or undefined if it could not be written. */
100
- export function writeErrorDetails(directory, errors) {
101
- return __awaiter(this, void 0, void 0, function* () {
102
- if (errors.length === 0)
103
- return undefined;
104
- const errorPath = path.join(directory, ERROR_FILENAME);
105
- try {
106
- yield fs.writeFile(errorPath, `${errors.join('\n\n')}\n`);
107
- return errorPath;
108
- }
109
- catch (_a) {
110
- return undefined;
111
- }
112
- });
113
- }
@@ -1,26 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- export function mapWithConcurrency(items, concurrency, fn, ...args) {
11
- return __awaiter(this, void 0, void 0, function* () {
12
- const results = new Array(items.length);
13
- let nextIndex = 0;
14
- const worker = () => __awaiter(this, void 0, void 0, function* () {
15
- for (;;) {
16
- const index = nextIndex++;
17
- const item = items[index];
18
- if (index >= items.length || item === undefined)
19
- return;
20
- results[index] = yield fn(item, ...args);
21
- }
22
- });
23
- yield Promise.all(Array.from({ length: Math.min(Math.max(1, concurrency), items.length) }, () => worker()));
24
- return results;
25
- });
26
- }