@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,86 +0,0 @@
1
- import path from 'node:path';
2
- import { SAFE_EXECUTABLES } from './manifest.js';
3
- export const SYSTEM_PROMPT = `# Mint test generator
4
-
5
- You will be given a markdown documentation page that contains code blocks. Follow the page and
6
- implement the code as the page instructs, inside the given output directory.
7
-
8
- Once finished, create a mint-test.json file in the current working directory with this shape:
9
-
10
- {
11
- "version": 1,
12
- "generatedFiles": ["tests/example.test.js", "tests/test_example.py"],
13
- "setupCommands": [],
14
- "testCommands": [
15
- {
16
- "id": "node-tests",
17
- "executable": "node",
18
- "args": ["--test"],
19
- "cwd": ".",
20
- "timeoutMs": 120000
21
- },
22
- {
23
- "id": "python-tests",
24
- "executable": "python3",
25
- "args": ["-m", "unittest", "discover", "-s", "tests"],
26
- "cwd": ".",
27
- "timeoutMs": 120000
28
- }
29
- ]
30
- }
31
-
32
- Manifest rules:
33
- - "generatedFiles" lists every file you wrote, as paths relative to the current working directory. Each one must exist.
34
- - Every command has a unique "id" (letters, digits, dashes). Command "cwd" values are relative to the current working directory.
35
- - "executable" must be one of: ${[...SAFE_EXECUTABLES].join(', ')}, or a "./" script inside the current working directory. Do not use a shell, pipes, or "&&".
36
- - Do not add any other keys to the manifest.
37
-
38
- Finish with a short plain-text summary of what you tested and anything you could not test.
39
-
40
- Rules:
41
- - Read only the page named in the task. You may also read docs.json and an OpenAPI file referenced by that page.
42
- - The output directory is already scaffolded: package.json exists with "npm test" wired to "node --test", and a tests/ directory is ready. Do not recreate or rewrite this scaffolding.
43
- - Run JavaScript tests with "node" and args ["--test"] from the task directory (no directory argument: on Node 21+ a path like "tests/" is treated as a glob and finds nothing). Node discovers tests/*.test.js on its own.
44
- - Write JavaScript and TypeScript tests as ES modules named tests/*.test.js using the Node built-in test runner (node:test and node:assert). Write Python tests as tests/test_*.py using the standard library unittest module, run with python3 -m unittest discover -s tests.
45
- - Prefer the standard library over installing dependencies; add a setup command only when a test truly cannot run without one.
46
- - Never write README, docs, or explanation files.
47
- - Keep helpers inline in the test file; do not create separate helper modules.
48
- - Write one test file per page unless the page genuinely needs more.
49
- - Create every additional source file and fixture inside the current working directory.
50
- - Never modify the documentation source. Do not commit, push, or open a pull request.
51
- - Cover fenced code blocks inside Mintlify components such as CodeGroup, Tabs, Steps, RequestExample, and ResponseExample.
52
- - If the page has openapi frontmatter, you may resolve its spec relative to the docs root and add tests for request snippets.
53
- - Do not install dependencies or run the generated tests. The Mint CLI handles setup and execution.
54
- - Never copy secrets into a file. In your code pull secrets from .env
55
- `;
56
- export function buildTaskPrompt(docsRoot, file, directory) {
57
- return `
58
- Use the guide at "${JSON.stringify(path.join(docsRoot, file))}"
59
-
60
- Write the required tests and mint-test.json output in the "${JSON.stringify(directory)}" directory.
61
- Record your report here "${JSON.stringify(file)}"`;
62
- }
63
- export const CHECK_SYSTEM_PROMPT = `# Mint test triage
64
- You are given a markdown page guide. Decide if the given file is able to be tested.
65
-
66
- Testable pages are pages that include any runnable code (python, typescript, bash) and any logic that could fail if the documented code was wrong
67
-
68
- Code blocks are not testable when it is used for formatting, showing logs, configuration, pseudo-code or a diff, an illustrative request or response shape, or a UI-only example.
69
-
70
- When unsure, mark it not testable.
71
-
72
- Include "reason" only when the page is not testable; omit it entirely when testable is true.`;
73
- export const CHECK_TOOL_INSTRUCTION = `
74
-
75
- Report your classification by calling the report_testability tool`;
76
- export const CHECK_JSON_INSTRUCTION = `
77
-
78
- Respond with only this JSON object and nothing else:
79
- { "version": 1, "testable": false, "reason": "expected output, not runnable code" }`;
80
- export function buildCheckPrompt(file, fileContent) {
81
- return `Report if the file at filePath ${JSON.stringify(file)} is testable
82
-
83
- <file>
84
- ${fileContent}
85
- </file>`;
86
- }
@@ -1,10 +0,0 @@
1
- export function countReport(tasks) {
2
- const counts = { passed: 0, failed: 0, cancelled: 0, agentErrors: 0 };
3
- for (const task of tasks) {
4
- if (task.status === 'agent_error')
5
- counts.agentErrors++;
6
- else
7
- counts[task.status]++;
8
- }
9
- return counts;
10
- }
@@ -1,101 +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
- const PAGE_EXTENSIONS = new Set(['.md', '.mdx']);
13
- const IGNORED_DIRECTORIES = new Set(['.git', '.next', 'build', 'dist', 'node_modules']);
14
- const OPENING_FENCE_PATTERN = /^\s*(`{3,}|~{3,})/;
15
- function countFencedBlocks(content) {
16
- var _a, _b;
17
- const lines = content.split(/\r?\n/);
18
- let count = 0;
19
- for (let index = 0; index < lines.length; index++) {
20
- const opening = OPENING_FENCE_PATTERN.exec((_a = lines[index]) !== null && _a !== void 0 ? _a : '');
21
- const marker = opening === null || opening === void 0 ? void 0 : opening[1];
22
- if (!marker)
23
- continue;
24
- const closingPattern = new RegExp(`^\\s*${marker[0]}{${marker.length},}\\s*$`);
25
- let closingIndex = index + 1;
26
- while (closingIndex < lines.length && !closingPattern.test((_b = lines[closingIndex]) !== null && _b !== void 0 ? _b : '')) {
27
- closingIndex++;
28
- }
29
- if (closingIndex >= lines.length)
30
- break;
31
- count++;
32
- index = closingIndex;
33
- }
34
- return count;
35
- }
36
- function findSiteRoot(startDirectory) {
37
- return __awaiter(this, void 0, void 0, function* () {
38
- const { root } = path.parse(startDirectory);
39
- let directory = startDirectory;
40
- let previous = null;
41
- while (directory !== previous) {
42
- for (const configName of ['docs.json', 'mint.json']) {
43
- const stats = yield fs.stat(path.join(directory, configName)).catch(() => null);
44
- if (stats === null || stats === void 0 ? void 0 : stats.isFile())
45
- return directory;
46
- }
47
- if (directory === root)
48
- return null;
49
- previous = directory;
50
- directory = path.dirname(directory);
51
- }
52
- return null;
53
- });
54
- }
55
- export function discoverCodeBlocks(inputPath) {
56
- return __awaiter(this, void 0, void 0, function* () {
57
- var _a;
58
- const resolvedPath = path.resolve(inputPath);
59
- const stats = yield fs.stat(resolvedPath);
60
- const baseDirectory = stats.isDirectory() ? resolvedPath : path.dirname(resolvedPath);
61
- const docsRoot = (_a = (yield findSiteRoot(baseDirectory))) !== null && _a !== void 0 ? _a : baseDirectory;
62
- const filePaths = [];
63
- if (stats.isDirectory()) {
64
- const directories = [resolvedPath];
65
- while (directories.length > 0) {
66
- const directory = directories.pop();
67
- if (!directory)
68
- break;
69
- for (const entry of yield fs.readdir(directory, { withFileTypes: true })) {
70
- const entryPath = path.join(directory, entry.name);
71
- if (entry.isDirectory() &&
72
- !IGNORED_DIRECTORIES.has(entry.name) &&
73
- !(entry.name === 'mint-test' && path.basename(directory) === 'tests')) {
74
- directories.push(entryPath);
75
- }
76
- else if (entry.isFile() && PAGE_EXTENSIONS.has(path.extname(entry.name).toLowerCase())) {
77
- filePaths.push(entryPath);
78
- }
79
- }
80
- }
81
- }
82
- else if (stats.isFile() && PAGE_EXTENSIONS.has(path.extname(resolvedPath).toLowerCase())) {
83
- filePaths.push(resolvedPath);
84
- }
85
- else {
86
- throw new Error(`Expected a docs directory or an MD/MDX file: ${resolvedPath}`);
87
- }
88
- const pages = [];
89
- for (const filePath of filePaths.sort()) {
90
- const content = yield fs.readFile(filePath, 'utf8');
91
- const blockCount = countFencedBlocks(content);
92
- if (blockCount > 0) {
93
- pages.push({
94
- file: path.relative(docsRoot, filePath).split(path.sep).join('/'),
95
- blockCount,
96
- });
97
- }
98
- }
99
- return { docsRoot, pages };
100
- });
101
- }
@@ -1,263 +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 { spawn } from 'node:child_process';
11
- import path from 'node:path';
12
- import { mapWithConcurrency } from './mapWithConcurrency.js';
13
- const MAX_STREAM_BYTES = 128 * 1024;
14
- const KILL_GRACE_MS = 2000;
15
- const FAILURE_PRECEDENCE = ['failed', 'cancelled'];
16
- const SECRET_NAME_PATTERN = /(TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY|CREDENTIAL)/i;
17
- function redactSecrets(value) {
18
- let redacted = value;
19
- const secrets = Object.entries(process.env)
20
- .filter(([name, secret]) => SECRET_NAME_PATTERN.test(name) && typeof secret === 'string' && secret.length >= 8)
21
- .map(([, secret]) => secret)
22
- .sort((left, right) => right.length - left.length);
23
- for (const secret of secrets)
24
- redacted = redacted.split(secret).join('[REDACTED]');
25
- return redacted
26
- .replace(/\bBearer\s+[A-Za-z0-9._~+/-]+=*/gi, 'Bearer [REDACTED]')
27
- .replace(/\b(?:sk|sess)-[A-Za-z0-9._-]{12,}\b/gi, '[REDACTED]');
28
- }
29
- function outputCollector() {
30
- let output = '';
31
- let bytes = 0;
32
- let truncated = false;
33
- return {
34
- append(chunk) {
35
- if (truncated)
36
- return;
37
- const value = chunk.toString();
38
- const remaining = MAX_STREAM_BYTES - bytes;
39
- if (Buffer.byteLength(value) <= remaining) {
40
- output += value;
41
- bytes += Buffer.byteLength(value);
42
- return;
43
- }
44
- output += Buffer.from(value).subarray(0, Math.max(0, remaining)).toString();
45
- output += '\n[mint test: output truncated]\n';
46
- truncated = true;
47
- },
48
- value: () => output,
49
- };
50
- }
51
- const MAX_FAILURE_LINE_LENGTH = 200;
52
- const TAP_SUMMARY_PATTERN = /^#\s*(tests|suites|pass|fail|cancelled|skipped|todo|duration_ms)\b|^1\.\.\d+$|^TAP version/;
53
- const ERROR_LINE_PATTERN = /\b(?:[A-Za-z]*Error|Traceback|FAILED|ModuleNotFoundError)\b/;
54
- const TAP_METADATA_PATTERN = /^(name|code|failureType|location|stack)\s*:/;
55
- /**
56
- * The most useful single line from a failed command's output: the first thrown error, else the
57
- * first failing TAP assertion, else the last line that is not a TAP summary.
58
- */
59
- export function pickFailureLine(text) {
60
- var _a, _b, _c, _d, _e, _f;
61
- const lines = text
62
- .split(/\r?\n/)
63
- .map((raw) => raw.trim())
64
- .filter((raw) => raw.length > 0 && !raw.startsWith('[mint test:'))
65
- .map((raw) => ({ raw, text: raw.replace(/^#\s?/, '').trim() }))
66
- .filter((line) => line.text.length > 0);
67
- const thrown = lines.find(({ text: candidate }) => ERROR_LINE_PATTERN.test(candidate) &&
68
- !candidate.startsWith('at ') &&
69
- !/^(ok|Traceback)\b/.test(candidate) &&
70
- !TAP_METADATA_PATTERN.test(candidate));
71
- const assertion = lines.find(({ text: candidate }) => candidate.startsWith('not ok'));
72
- const informative = lines.filter(({ raw }) => !TAP_SUMMARY_PATTERN.test(raw));
73
- const line = (_f = (_d = (_b = (_a = thrown === null || thrown === void 0 ? void 0 : thrown.text) !== null && _a !== void 0 ? _a : assertion === null || assertion === void 0 ? void 0 : assertion.text) !== null && _b !== void 0 ? _b : (_c = informative[informative.length - 1]) === null || _c === void 0 ? void 0 : _c.text) !== null && _d !== void 0 ? _d : (_e = lines[lines.length - 1]) === null || _e === void 0 ? void 0 : _e.text) !== null && _f !== void 0 ? _f : '';
74
- return line.length > MAX_FAILURE_LINE_LENGTH
75
- ? `${line.slice(0, MAX_FAILURE_LINE_LENGTH - 1)}…`
76
- : line;
77
- }
78
- /** One line explaining the first command that did not pass, for the UI and the report. */
79
- export function summarizeCommandFailure(commands) {
80
- var _a;
81
- const failed = commands.find((command) => command.status !== 'passed');
82
- if (!failed)
83
- return undefined;
84
- const invocation = [failed.executable, ...failed.args].join(' ');
85
- const reason = (_a = failed.error) !== null && _a !== void 0 ? _a : (failed.exitCode === null ? 'did not exit cleanly' : `exited with code ${failed.exitCode}`);
86
- const detail = pickFailureLine(failed.stderr) || pickFailureLine(failed.stdout);
87
- return `${failed.phase} command \`${invocation}\` ${reason}${detail ? `: ${detail}` : ''}`;
88
- }
89
- function unrunCommandResult(command, phase, cwd, status, error) {
90
- return {
91
- id: command.id,
92
- phase,
93
- status,
94
- executable: command.executable,
95
- args: command.args,
96
- cwd,
97
- durationMs: 0,
98
- exitCode: null,
99
- stdout: '',
100
- stderr: '',
101
- error,
102
- };
103
- }
104
- function spawnCommand({ command, phase, cwd, timeoutMs, signal, docsRootForCommands, }) {
105
- var _a;
106
- const startedAt = Date.now();
107
- const base = {
108
- id: command.id,
109
- phase,
110
- executable: command.executable,
111
- args: command.args,
112
- cwd,
113
- };
114
- const commandTimeoutMs = (_a = command.timeoutMs) !== null && _a !== void 0 ? _a : timeoutMs;
115
- return new Promise((resolve) => {
116
- const stdout = outputCollector();
117
- const stderr = outputCollector();
118
- let completed = false;
119
- let timedOut = false;
120
- let cancelled = false;
121
- let forceKillTimer;
122
- const child = spawn(command.executable, command.args, {
123
- cwd,
124
- detached: true,
125
- env: Object.assign(Object.assign({}, process.env), { MINT_DOCS_ROOT: docsRootForCommands }),
126
- shell: false,
127
- stdio: ['ignore', 'pipe', 'pipe'],
128
- });
129
- child.stdout.on('data', stdout.append);
130
- child.stderr.on('data', stderr.append);
131
- const killTree = (killSignal) => {
132
- if (child.pid) {
133
- try {
134
- process.kill(-child.pid, killSignal);
135
- return;
136
- }
137
- catch (_a) {
138
- /* noop */
139
- }
140
- }
141
- child.kill(killSignal);
142
- };
143
- const kill = () => {
144
- killTree('SIGTERM');
145
- forceKillTimer = setTimeout(() => killTree('SIGKILL'), KILL_GRACE_MS);
146
- };
147
- const timeout = setTimeout(() => {
148
- timedOut = true;
149
- kill();
150
- }, commandTimeoutMs);
151
- const abort = () => {
152
- cancelled = true;
153
- kill();
154
- };
155
- signal.addEventListener('abort', abort, { once: true });
156
- const finish = (exitCode, spawnError) => {
157
- if (completed)
158
- return;
159
- completed = true;
160
- clearTimeout(timeout);
161
- if (forceKillTimer)
162
- clearTimeout(forceKillTimer);
163
- signal.removeEventListener('abort', abort);
164
- const error = cancelled
165
- ? 'run cancelled'
166
- : timedOut
167
- ? `command timed out after ${commandTimeoutMs}ms`
168
- : spawnError;
169
- resolve(Object.assign(Object.assign(Object.assign({}, base), { status: cancelled ? 'cancelled' : exitCode === 0 && !error ? 'passed' : 'failed', durationMs: Date.now() - startedAt, exitCode, stdout: redactSecrets(stdout.value()), stderr: redactSecrets(stderr.value()) }), (error ? { error } : {})));
170
- };
171
- child.once('error', (error) => finish(null, error.message));
172
- child.once('close', (exitCode) => finish(exitCode));
173
- });
174
- }
175
- export function executeCodeBlocks(_a) {
176
- return __awaiter(this, arguments, void 0, function* ({ tasks, docsRoot, concurrency, commandTimeoutMs, signal, onTaskUpdate, }) {
177
- return mapWithConcurrency(tasks, concurrency, (task) => __awaiter(this, void 0, void 0, function* () {
178
- var _a, _b, _c, _d;
179
- const generatedFiles = (_c = (_b = (_a = task.manifest) === null || _a === void 0 ? void 0 : _a.generatedFiles.map((file) => path.resolve(task.directory, file))) !== null && _b !== void 0 ? _b : task.generatedFiles) !== null && _c !== void 0 ? _c : [];
180
- const base = {
181
- id: task.id,
182
- agent: task.agent,
183
- file: task.file,
184
- directory: task.directory,
185
- generatedFiles,
186
- testable: task.testable === true,
187
- attempts: task.attempts,
188
- tokens: task.tokens,
189
- };
190
- const manifest = task.manifest;
191
- if (!manifest) {
192
- if (!task.error) {
193
- onTaskUpdate({
194
- id: task.id,
195
- agent: task.agent,
196
- file: task.file,
197
- directory: task.directory,
198
- generatedFiles,
199
- phase: 'not_testable',
200
- tokens: task.tokens,
201
- });
202
- return Object.assign(Object.assign({}, base), { status: 'passed', commands: [] });
203
- }
204
- const status = signal.aborted ? 'cancelled' : 'agent_error';
205
- onTaskUpdate({
206
- id: task.id,
207
- agent: task.agent,
208
- file: task.file,
209
- directory: task.directory,
210
- generatedFiles,
211
- phase: status,
212
- tokens: task.tokens,
213
- error: task.error,
214
- });
215
- return Object.assign(Object.assign({}, base), { status, error: task.error, commands: [] });
216
- }
217
- onTaskUpdate({
218
- id: task.id,
219
- agent: task.agent,
220
- file: task.file,
221
- directory: task.directory,
222
- generatedFiles,
223
- phase: 'running',
224
- tokens: task.tokens,
225
- });
226
- const commands = [];
227
- let setupFailure;
228
- const run = (command, phase) => __awaiter(this, void 0, void 0, function* () {
229
- var _a;
230
- const cwd = path.resolve(task.directory, (_a = command.cwd) !== null && _a !== void 0 ? _a : '.');
231
- if (signal.aborted) {
232
- return unrunCommandResult(command, phase, cwd, 'cancelled', 'run cancelled');
233
- }
234
- if (phase === 'test' && setupFailure) {
235
- return unrunCommandResult(command, phase, cwd, setupFailure, `a setup command ${setupFailure === 'cancelled' ? 'was cancelled' : 'failed'}`);
236
- }
237
- return spawnCommand({
238
- command,
239
- phase,
240
- cwd,
241
- timeoutMs: commandTimeoutMs,
242
- signal,
243
- docsRootForCommands: docsRoot,
244
- });
245
- });
246
- for (const command of manifest.setupCommands) {
247
- const result = yield run(command, 'setup');
248
- commands.push(result);
249
- if (result.status !== 'passed') {
250
- setupFailure = result.status;
251
- break;
252
- }
253
- }
254
- for (const command of manifest.testCommands) {
255
- commands.push(yield run(command, 'test'));
256
- }
257
- const status = (_d = FAILURE_PRECEDENCE.find((candidate) => commands.some((command) => command.status === candidate))) !== null && _d !== void 0 ? _d : 'passed';
258
- const error = status === 'passed' ? undefined : summarizeCommandFailure(commands);
259
- onTaskUpdate(Object.assign({ id: task.id, agent: task.agent, file: task.file, directory: task.directory, generatedFiles, phase: status, tokens: task.tokens }, (error ? { error } : {})));
260
- return Object.assign(Object.assign(Object.assign(Object.assign({}, base), { status }), (error ? { error } : {})), { commands });
261
- }));
262
- });
263
- }
@@ -1,10 +0,0 @@
1
- import path from 'node:path';
2
- export function filterSelectedPages(pages, selectedFiles) {
3
- const selected = new Set(selectedFiles.map((file) => file.split(path.sep).join('/').replace(/^\.\//, '')));
4
- const known = new Set(pages.map((page) => page.file));
5
- for (const file of selected) {
6
- if (!known.has(file))
7
- throw new Error(`Selected docs file was not found: ${file}`);
8
- }
9
- return pages.filter((page) => selected.has(page.file));
10
- }