@compilr-dev/agents-coding 0.0.1
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/README.md +788 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +75 -0
- package/dist/skills/index.d.ts +39 -0
- package/dist/skills/index.js +322 -0
- package/dist/tools/git/branch.d.ts +17 -0
- package/dist/tools/git/branch.js +264 -0
- package/dist/tools/git/commit.d.ts +23 -0
- package/dist/tools/git/commit.js +280 -0
- package/dist/tools/git/diff.d.ts +19 -0
- package/dist/tools/git/diff.js +221 -0
- package/dist/tools/git/index.d.ts +10 -0
- package/dist/tools/git/index.js +11 -0
- package/dist/tools/git/log.d.ts +19 -0
- package/dist/tools/git/log.js +235 -0
- package/dist/tools/git/stash.d.ts +17 -0
- package/dist/tools/git/stash.js +294 -0
- package/dist/tools/git/status.d.ts +19 -0
- package/dist/tools/git/status.js +160 -0
- package/dist/tools/git/types.d.ts +293 -0
- package/dist/tools/git/types.js +4 -0
- package/dist/tools/git/utils.d.ts +58 -0
- package/dist/tools/git/utils.js +197 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/project/detect.d.ts +19 -0
- package/dist/tools/project/detect.js +341 -0
- package/dist/tools/project/find-root.d.ts +21 -0
- package/dist/tools/project/find-root.js +239 -0
- package/dist/tools/project/index.d.ts +6 -0
- package/dist/tools/project/index.js +5 -0
- package/dist/tools/project/types.d.ts +83 -0
- package/dist/tools/project/types.js +4 -0
- package/dist/tools/runners/build.d.ts +19 -0
- package/dist/tools/runners/build.js +306 -0
- package/dist/tools/runners/format.d.ts +19 -0
- package/dist/tools/runners/format.js +376 -0
- package/dist/tools/runners/index.d.ts +9 -0
- package/dist/tools/runners/index.js +9 -0
- package/dist/tools/runners/lint.d.ts +19 -0
- package/dist/tools/runners/lint.js +356 -0
- package/dist/tools/runners/test.d.ts +19 -0
- package/dist/tools/runners/test.js +386 -0
- package/dist/tools/runners/types.d.ts +97 -0
- package/dist/tools/runners/types.js +4 -0
- package/dist/tools/runners/utils.d.ts +69 -0
- package/dist/tools/runners/utils.js +179 -0
- package/dist/tools/search/definition.d.ts +19 -0
- package/dist/tools/search/definition.js +305 -0
- package/dist/tools/search/index.d.ts +8 -0
- package/dist/tools/search/index.js +8 -0
- package/dist/tools/search/references.d.ts +19 -0
- package/dist/tools/search/references.js +179 -0
- package/dist/tools/search/todos.d.ts +19 -0
- package/dist/tools/search/todos.js +269 -0
- package/dist/tools/search/types.d.ts +132 -0
- package/dist/tools/search/types.js +4 -0
- package/dist/tools/search/utils.d.ts +45 -0
- package/dist/tools/search/utils.js +152 -0
- package/package.json +88 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run Tests Tool
|
|
3
|
+
* Auto-detect and run tests using the appropriate framework
|
|
4
|
+
*/
|
|
5
|
+
import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
|
|
6
|
+
import { isDirectory, readPackageJson, listDirectory, hasFile, hasDependency, hasScript, runCommand, buildCommand, formatCommand, DEFAULT_TIMEOUT, } from './utils.js';
|
|
7
|
+
const TEST_FRAMEWORKS = [
|
|
8
|
+
// Vitest (Node.js)
|
|
9
|
+
{
|
|
10
|
+
name: 'vitest',
|
|
11
|
+
detect: (entries, pkg) => hasFile(entries, 'vitest.config.ts') ||
|
|
12
|
+
hasFile(entries, 'vitest.config.js') ||
|
|
13
|
+
hasFile(entries, 'vitest.config.mts') ||
|
|
14
|
+
hasDependency(pkg, 'vitest'),
|
|
15
|
+
getCommand: (input) => {
|
|
16
|
+
const args = ['vitest'];
|
|
17
|
+
if (!input.watch)
|
|
18
|
+
args.push('run');
|
|
19
|
+
if (input.pattern)
|
|
20
|
+
args.push(input.pattern);
|
|
21
|
+
if (input.coverage)
|
|
22
|
+
args.push('--coverage');
|
|
23
|
+
if (input.updateSnapshots)
|
|
24
|
+
args.push('-u');
|
|
25
|
+
return { command: 'npx', args, useNpx: false };
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
// Jest (Node.js)
|
|
29
|
+
{
|
|
30
|
+
name: 'jest',
|
|
31
|
+
detect: (entries, pkg) => hasFile(entries, 'jest.config.ts') ||
|
|
32
|
+
hasFile(entries, 'jest.config.js') ||
|
|
33
|
+
hasFile(entries, 'jest.config.json') ||
|
|
34
|
+
hasDependency(pkg, 'jest'),
|
|
35
|
+
getCommand: (input) => {
|
|
36
|
+
const args = ['jest'];
|
|
37
|
+
if (input.pattern)
|
|
38
|
+
args.push(input.pattern);
|
|
39
|
+
if (!input.watch)
|
|
40
|
+
args.push('--runInBand');
|
|
41
|
+
if (input.watch)
|
|
42
|
+
args.push('--watch');
|
|
43
|
+
if (input.coverage)
|
|
44
|
+
args.push('--coverage');
|
|
45
|
+
if (input.updateSnapshots)
|
|
46
|
+
args.push('-u');
|
|
47
|
+
if (input.verbose)
|
|
48
|
+
args.push('--verbose');
|
|
49
|
+
return { command: 'npx', args, useNpx: false };
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
// Mocha (Node.js)
|
|
53
|
+
{
|
|
54
|
+
name: 'mocha',
|
|
55
|
+
detect: (entries, pkg) => hasFile(entries, '.mocharc.json') ||
|
|
56
|
+
hasFile(entries, '.mocharc.js') ||
|
|
57
|
+
hasFile(entries, '.mocharc.yaml') ||
|
|
58
|
+
hasDependency(pkg, 'mocha'),
|
|
59
|
+
getCommand: (input) => {
|
|
60
|
+
const args = ['mocha'];
|
|
61
|
+
if (input.pattern)
|
|
62
|
+
args.push(input.pattern);
|
|
63
|
+
if (input.watch)
|
|
64
|
+
args.push('--watch');
|
|
65
|
+
return { command: 'npx', args, useNpx: false };
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
// AVA (Node.js)
|
|
69
|
+
{
|
|
70
|
+
name: 'ava',
|
|
71
|
+
detect: (entries, pkg) => hasFile(entries, 'ava.config.js') ||
|
|
72
|
+
hasFile(entries, 'ava.config.cjs') ||
|
|
73
|
+
hasDependency(pkg, 'ava'),
|
|
74
|
+
getCommand: (input) => {
|
|
75
|
+
const args = ['ava'];
|
|
76
|
+
if (input.pattern)
|
|
77
|
+
args.push(input.pattern);
|
|
78
|
+
if (input.watch)
|
|
79
|
+
args.push('--watch');
|
|
80
|
+
if (input.verbose)
|
|
81
|
+
args.push('--verbose');
|
|
82
|
+
if (input.updateSnapshots)
|
|
83
|
+
args.push('-u');
|
|
84
|
+
return { command: 'npx', args, useNpx: false };
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
// npm test script fallback (Node.js)
|
|
88
|
+
{
|
|
89
|
+
name: 'npm test',
|
|
90
|
+
detect: (_entries, pkg) => hasScript(pkg, 'test'),
|
|
91
|
+
getCommand: () => ({
|
|
92
|
+
command: 'npm',
|
|
93
|
+
args: ['test'],
|
|
94
|
+
useScript: true,
|
|
95
|
+
scriptName: 'test',
|
|
96
|
+
}),
|
|
97
|
+
},
|
|
98
|
+
// pytest (Python)
|
|
99
|
+
{
|
|
100
|
+
name: 'pytest',
|
|
101
|
+
detect: (entries) => hasFile(entries, 'pytest.ini') ||
|
|
102
|
+
hasFile(entries, 'pyproject.toml') ||
|
|
103
|
+
hasFile(entries, 'conftest.py'),
|
|
104
|
+
getCommand: (input) => {
|
|
105
|
+
const args = [];
|
|
106
|
+
if (input.pattern)
|
|
107
|
+
args.push(input.pattern);
|
|
108
|
+
if (input.verbose)
|
|
109
|
+
args.push('-v');
|
|
110
|
+
if (input.coverage)
|
|
111
|
+
args.push('--cov');
|
|
112
|
+
return { command: 'pytest', args };
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
// Python unittest
|
|
116
|
+
{
|
|
117
|
+
name: 'unittest',
|
|
118
|
+
detect: (entries) => hasFile(entries, 'setup.py') || hasFile(entries, 'setup.cfg'),
|
|
119
|
+
getCommand: (input) => {
|
|
120
|
+
const args = ['-m', 'unittest'];
|
|
121
|
+
if (input.pattern)
|
|
122
|
+
args.push('discover', '-p', input.pattern);
|
|
123
|
+
else
|
|
124
|
+
args.push('discover');
|
|
125
|
+
if (input.verbose)
|
|
126
|
+
args.push('-v');
|
|
127
|
+
return { command: 'python', args };
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
// Cargo test (Rust)
|
|
131
|
+
{
|
|
132
|
+
name: 'cargo test',
|
|
133
|
+
detect: (entries) => hasFile(entries, 'Cargo.toml'),
|
|
134
|
+
getCommand: (input) => {
|
|
135
|
+
const args = ['test'];
|
|
136
|
+
if (input.pattern)
|
|
137
|
+
args.push(input.pattern);
|
|
138
|
+
if (input.verbose)
|
|
139
|
+
args.push('--', '--nocapture');
|
|
140
|
+
return { command: 'cargo', args };
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
// Go test
|
|
144
|
+
{
|
|
145
|
+
name: 'go test',
|
|
146
|
+
detect: (entries) => hasFile(entries, 'go.mod'),
|
|
147
|
+
getCommand: (input) => {
|
|
148
|
+
const args = ['test'];
|
|
149
|
+
if (input.pattern)
|
|
150
|
+
args.push(input.pattern);
|
|
151
|
+
else
|
|
152
|
+
args.push('./...');
|
|
153
|
+
if (input.verbose)
|
|
154
|
+
args.push('-v');
|
|
155
|
+
if (input.coverage)
|
|
156
|
+
args.push('-cover');
|
|
157
|
+
return { command: 'go', args };
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
];
|
|
161
|
+
/**
|
|
162
|
+
* Run Tests Tool
|
|
163
|
+
*/
|
|
164
|
+
export const runTestsTool = defineTool({
|
|
165
|
+
name: 'run_tests',
|
|
166
|
+
description: 'Run tests using the auto-detected test framework. ' +
|
|
167
|
+
'Supports vitest, jest, mocha, pytest, cargo test, go test, and npm test scripts. ' +
|
|
168
|
+
'Options: pattern (filter tests), watch, coverage, verbose, updateSnapshots.',
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
path: {
|
|
173
|
+
type: 'string',
|
|
174
|
+
description: 'Working directory (default: current directory)',
|
|
175
|
+
},
|
|
176
|
+
pattern: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
description: 'Test file pattern or test name filter',
|
|
179
|
+
},
|
|
180
|
+
watch: {
|
|
181
|
+
type: 'boolean',
|
|
182
|
+
description: 'Run in watch mode (if supported)',
|
|
183
|
+
},
|
|
184
|
+
verbose: {
|
|
185
|
+
type: 'boolean',
|
|
186
|
+
description: 'Verbose output',
|
|
187
|
+
},
|
|
188
|
+
coverage: {
|
|
189
|
+
type: 'boolean',
|
|
190
|
+
description: 'Generate coverage report',
|
|
191
|
+
},
|
|
192
|
+
updateSnapshots: {
|
|
193
|
+
type: 'boolean',
|
|
194
|
+
description: 'Update test snapshots (jest/vitest)',
|
|
195
|
+
},
|
|
196
|
+
timeout: {
|
|
197
|
+
type: 'number',
|
|
198
|
+
description: 'Timeout in milliseconds (default: 300000)',
|
|
199
|
+
},
|
|
200
|
+
dryRun: {
|
|
201
|
+
type: 'boolean',
|
|
202
|
+
description: 'Detect test framework and return command without executing (default: false)',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
required: [],
|
|
206
|
+
},
|
|
207
|
+
execute: executeRunTests,
|
|
208
|
+
});
|
|
209
|
+
/**
|
|
210
|
+
* Execute run tests
|
|
211
|
+
*/
|
|
212
|
+
async function executeRunTests(input) {
|
|
213
|
+
const targetPath = input.path ?? process.cwd();
|
|
214
|
+
const timeout = input.timeout ?? DEFAULT_TIMEOUT;
|
|
215
|
+
// Check if directory exists
|
|
216
|
+
if (!(await isDirectory(targetPath))) {
|
|
217
|
+
return createErrorResult(`Directory not found: ${targetPath}`);
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
// Read directory and package.json
|
|
221
|
+
const entries = await listDirectory(targetPath);
|
|
222
|
+
const packageJson = await readPackageJson(targetPath);
|
|
223
|
+
// Detect test framework
|
|
224
|
+
let framework;
|
|
225
|
+
for (const fw of TEST_FRAMEWORKS) {
|
|
226
|
+
if (fw.detect(entries, packageJson)) {
|
|
227
|
+
framework = fw;
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (!framework) {
|
|
232
|
+
return createErrorResult('No test framework detected. Supported: vitest, jest, mocha, ava, pytest, cargo test, go test, npm test script.');
|
|
233
|
+
}
|
|
234
|
+
// Build command
|
|
235
|
+
const template = framework.getCommand(input);
|
|
236
|
+
const { command, args } = buildCommand(template);
|
|
237
|
+
const commandString = formatCommand(command, args);
|
|
238
|
+
// Dry run - return detected info without executing
|
|
239
|
+
if (input.dryRun) {
|
|
240
|
+
const testResult = {
|
|
241
|
+
command: commandString,
|
|
242
|
+
output: '(dry run - command not executed)',
|
|
243
|
+
exitCode: 0,
|
|
244
|
+
duration: 0,
|
|
245
|
+
success: true,
|
|
246
|
+
framework: framework.name,
|
|
247
|
+
};
|
|
248
|
+
return createSuccessResult(testResult);
|
|
249
|
+
}
|
|
250
|
+
// Run tests
|
|
251
|
+
const result = await runCommand(command, args, {
|
|
252
|
+
cwd: targetPath,
|
|
253
|
+
timeout,
|
|
254
|
+
env: {
|
|
255
|
+
FORCE_COLOR: '1',
|
|
256
|
+
CI: 'true',
|
|
257
|
+
},
|
|
258
|
+
});
|
|
259
|
+
// Combine output
|
|
260
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join('\n');
|
|
261
|
+
// Parse test counts from output (best effort)
|
|
262
|
+
const counts = parseTestCounts(output, framework.name);
|
|
263
|
+
const testResult = {
|
|
264
|
+
command: commandString,
|
|
265
|
+
output,
|
|
266
|
+
exitCode: result.exitCode,
|
|
267
|
+
duration: result.duration,
|
|
268
|
+
success: result.exitCode === 0,
|
|
269
|
+
framework: framework.name,
|
|
270
|
+
...counts,
|
|
271
|
+
};
|
|
272
|
+
return createSuccessResult(testResult);
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
return createErrorResult(error instanceof Error ? error.message : String(error));
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Parse test counts from output (best effort)
|
|
280
|
+
*/
|
|
281
|
+
function parseTestCounts(output, _framework) {
|
|
282
|
+
const counts = {};
|
|
283
|
+
// Vitest pattern: "✓ 70 tests passed"
|
|
284
|
+
const vitestMatch = output.match(/(\d+)\s+tests?\s+passed/i);
|
|
285
|
+
if (vitestMatch)
|
|
286
|
+
counts.passed = parseInt(vitestMatch[1], 10);
|
|
287
|
+
const vitestFailMatch = output.match(/(\d+)\s+tests?\s+failed/i);
|
|
288
|
+
if (vitestFailMatch)
|
|
289
|
+
counts.failed = parseInt(vitestFailMatch[1], 10);
|
|
290
|
+
// Jest pattern: "Tests: 5 passed, 1 failed, 6 total"
|
|
291
|
+
const jestMatch = output.match(/Tests:\s+(\d+)\s+passed,?\s*(\d+)?\s*failed?,?\s*(\d+)?\s*skipped?,?\s*(\d+)?\s*total/i);
|
|
292
|
+
if (jestMatch) {
|
|
293
|
+
counts.passed = parseInt(jestMatch[1], 10);
|
|
294
|
+
if (jestMatch[2])
|
|
295
|
+
counts.failed = parseInt(jestMatch[2], 10);
|
|
296
|
+
if (jestMatch[3])
|
|
297
|
+
counts.skipped = parseInt(jestMatch[3], 10);
|
|
298
|
+
if (jestMatch[4])
|
|
299
|
+
counts.total = parseInt(jestMatch[4], 10);
|
|
300
|
+
}
|
|
301
|
+
// pytest pattern: "5 passed, 1 failed"
|
|
302
|
+
const pytestPassMatch = output.match(/(\d+)\s+passed/i);
|
|
303
|
+
if (pytestPassMatch)
|
|
304
|
+
counts.passed = parseInt(pytestPassMatch[1], 10);
|
|
305
|
+
const pytestFailMatch = output.match(/(\d+)\s+failed/i);
|
|
306
|
+
if (pytestFailMatch)
|
|
307
|
+
counts.failed = parseInt(pytestFailMatch[1], 10);
|
|
308
|
+
const pytestSkipMatch = output.match(/(\d+)\s+skipped/i);
|
|
309
|
+
if (pytestSkipMatch)
|
|
310
|
+
counts.skipped = parseInt(pytestSkipMatch[1], 10);
|
|
311
|
+
// Go test pattern: "ok" or "FAIL"
|
|
312
|
+
const goOkMatch = output.match(/^ok\s+/gm);
|
|
313
|
+
if (goOkMatch)
|
|
314
|
+
counts.passed = goOkMatch.length;
|
|
315
|
+
const goFailMatch = output.match(/^FAIL\s+/gm);
|
|
316
|
+
if (goFailMatch)
|
|
317
|
+
counts.failed = goFailMatch.length;
|
|
318
|
+
// Cargo test pattern: "test result: ok. 10 passed; 0 failed"
|
|
319
|
+
const cargoMatch = output.match(/(\d+)\s+passed;\s+(\d+)\s+failed/);
|
|
320
|
+
if (cargoMatch) {
|
|
321
|
+
counts.passed = parseInt(cargoMatch[1], 10);
|
|
322
|
+
counts.failed = parseInt(cargoMatch[2], 10);
|
|
323
|
+
}
|
|
324
|
+
// Calculate total if we have passed and failed
|
|
325
|
+
if (counts.passed !== undefined || counts.failed !== undefined) {
|
|
326
|
+
counts.total = (counts.passed ?? 0) + (counts.failed ?? 0) + (counts.skipped ?? 0);
|
|
327
|
+
}
|
|
328
|
+
return counts;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Factory function to create run tests tool with custom options
|
|
332
|
+
*/
|
|
333
|
+
export function createRunTestsTool(options) {
|
|
334
|
+
return defineTool({
|
|
335
|
+
name: 'run_tests',
|
|
336
|
+
description: 'Run tests using the auto-detected test framework. ' +
|
|
337
|
+
'Supports vitest, jest, mocha, ava, pytest, cargo test, go test.',
|
|
338
|
+
inputSchema: {
|
|
339
|
+
type: 'object',
|
|
340
|
+
properties: {
|
|
341
|
+
path: {
|
|
342
|
+
type: 'string',
|
|
343
|
+
description: 'Working directory (default: current directory)',
|
|
344
|
+
},
|
|
345
|
+
pattern: {
|
|
346
|
+
type: 'string',
|
|
347
|
+
description: 'Test file pattern or test name filter',
|
|
348
|
+
},
|
|
349
|
+
watch: {
|
|
350
|
+
type: 'boolean',
|
|
351
|
+
description: 'Run in watch mode',
|
|
352
|
+
},
|
|
353
|
+
verbose: {
|
|
354
|
+
type: 'boolean',
|
|
355
|
+
description: 'Verbose output',
|
|
356
|
+
},
|
|
357
|
+
coverage: {
|
|
358
|
+
type: 'boolean',
|
|
359
|
+
description: 'Generate coverage report',
|
|
360
|
+
},
|
|
361
|
+
updateSnapshots: {
|
|
362
|
+
type: 'boolean',
|
|
363
|
+
description: 'Update test snapshots',
|
|
364
|
+
},
|
|
365
|
+
timeout: {
|
|
366
|
+
type: 'number',
|
|
367
|
+
description: 'Timeout in milliseconds',
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
required: [],
|
|
371
|
+
},
|
|
372
|
+
execute: async (input) => {
|
|
373
|
+
let targetPath = input.path ?? '.';
|
|
374
|
+
// Resolve relative paths
|
|
375
|
+
if (options?.baseDir && !targetPath.startsWith('/')) {
|
|
376
|
+
const nodePath = await import('node:path');
|
|
377
|
+
targetPath = nodePath.join(options.baseDir, targetPath);
|
|
378
|
+
}
|
|
379
|
+
return executeRunTests({
|
|
380
|
+
...input,
|
|
381
|
+
path: targetPath,
|
|
382
|
+
timeout: input.timeout ?? options?.defaultTimeout,
|
|
383
|
+
});
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for Smart Runner Tools
|
|
3
|
+
*/
|
|
4
|
+
export interface BaseRunnerInput {
|
|
5
|
+
/** Working directory path (default: current directory) */
|
|
6
|
+
path?: string;
|
|
7
|
+
/** Timeout in milliseconds (default: 300000 = 5 min) */
|
|
8
|
+
timeout?: number;
|
|
9
|
+
/** Dry run - detect and return command without executing (default: false) */
|
|
10
|
+
dryRun?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface BaseRunnerResult {
|
|
13
|
+
/** Command that was executed */
|
|
14
|
+
command: string;
|
|
15
|
+
/** Command output (stdout + stderr) */
|
|
16
|
+
output: string;
|
|
17
|
+
/** Exit code */
|
|
18
|
+
exitCode: number;
|
|
19
|
+
/** Duration in milliseconds */
|
|
20
|
+
duration: number;
|
|
21
|
+
/** Whether the command succeeded (exitCode === 0) */
|
|
22
|
+
success: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface RunTestsInput extends BaseRunnerInput {
|
|
25
|
+
/** Specific test file or pattern to run */
|
|
26
|
+
pattern?: string;
|
|
27
|
+
/** Run in watch mode (if supported) */
|
|
28
|
+
watch?: boolean;
|
|
29
|
+
/** Verbose output */
|
|
30
|
+
verbose?: boolean;
|
|
31
|
+
/** Generate coverage report */
|
|
32
|
+
coverage?: boolean;
|
|
33
|
+
/** Update snapshots (for jest/vitest) */
|
|
34
|
+
updateSnapshots?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface RunTestsResult extends BaseRunnerResult {
|
|
37
|
+
/** Number of tests passed (if parseable) */
|
|
38
|
+
passed?: number;
|
|
39
|
+
/** Number of tests failed (if parseable) */
|
|
40
|
+
failed?: number;
|
|
41
|
+
/** Number of tests skipped (if parseable) */
|
|
42
|
+
skipped?: number;
|
|
43
|
+
/** Total number of tests (if parseable) */
|
|
44
|
+
total?: number;
|
|
45
|
+
/** Detected test framework */
|
|
46
|
+
framework: string;
|
|
47
|
+
}
|
|
48
|
+
export interface RunLintInput extends BaseRunnerInput {
|
|
49
|
+
/** Specific files to lint */
|
|
50
|
+
files?: string[];
|
|
51
|
+
/** Auto-fix issues (if supported) */
|
|
52
|
+
fix?: boolean;
|
|
53
|
+
/** Output format (json, stylish, etc.) */
|
|
54
|
+
format?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface RunLintResult extends BaseRunnerResult {
|
|
57
|
+
/** Number of errors (if parseable) */
|
|
58
|
+
errors?: number;
|
|
59
|
+
/** Number of warnings (if parseable) */
|
|
60
|
+
warnings?: number;
|
|
61
|
+
/** Detected linter */
|
|
62
|
+
linter: string;
|
|
63
|
+
}
|
|
64
|
+
export interface RunBuildInput extends BaseRunnerInput {
|
|
65
|
+
/** Build for production (optimized) */
|
|
66
|
+
production?: boolean;
|
|
67
|
+
/** Clean before build */
|
|
68
|
+
clean?: boolean;
|
|
69
|
+
}
|
|
70
|
+
export interface RunBuildResult extends BaseRunnerResult {
|
|
71
|
+
/** Detected build tool */
|
|
72
|
+
buildTool: string;
|
|
73
|
+
}
|
|
74
|
+
export interface RunFormatInput extends BaseRunnerInput {
|
|
75
|
+
/** Specific files to format */
|
|
76
|
+
files?: string[];
|
|
77
|
+
/** Check only, don't write changes */
|
|
78
|
+
check?: boolean;
|
|
79
|
+
}
|
|
80
|
+
export interface RunFormatResult extends BaseRunnerResult {
|
|
81
|
+
/** Number of files formatted/checked (if parseable) */
|
|
82
|
+
filesProcessed?: number;
|
|
83
|
+
/** Detected formatter */
|
|
84
|
+
formatter: string;
|
|
85
|
+
}
|
|
86
|
+
export interface CommandTemplate {
|
|
87
|
+
/** Base command */
|
|
88
|
+
command: string;
|
|
89
|
+
/** Arguments to add */
|
|
90
|
+
args: string[];
|
|
91
|
+
/** Whether this uses npm/npx */
|
|
92
|
+
useNpx?: boolean;
|
|
93
|
+
/** Whether this uses package.json scripts */
|
|
94
|
+
useScript?: boolean;
|
|
95
|
+
/** Script name for npm run */
|
|
96
|
+
scriptName?: string;
|
|
97
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for Smart Runner Tools
|
|
3
|
+
*/
|
|
4
|
+
import type { CommandTemplate } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Default timeout for runner commands (5 minutes)
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_TIMEOUT = 300000;
|
|
9
|
+
/**
|
|
10
|
+
* Maximum output size (50KB)
|
|
11
|
+
*/
|
|
12
|
+
export declare const MAX_OUTPUT_SIZE: number;
|
|
13
|
+
/**
|
|
14
|
+
* Package.json content type
|
|
15
|
+
*/
|
|
16
|
+
export interface PackageJsonContent {
|
|
17
|
+
name?: string;
|
|
18
|
+
dependencies?: Record<string, string>;
|
|
19
|
+
devDependencies?: Record<string, string>;
|
|
20
|
+
scripts?: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if directory exists
|
|
24
|
+
*/
|
|
25
|
+
export declare function isDirectory(path: string): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Read package.json from a directory
|
|
28
|
+
*/
|
|
29
|
+
export declare function readPackageJson(dirPath: string): Promise<PackageJsonContent | null>;
|
|
30
|
+
/**
|
|
31
|
+
* List directory entries
|
|
32
|
+
*/
|
|
33
|
+
export declare function listDirectory(dirPath: string): Promise<string[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Check if a file exists in directory
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasFile(entries: string[], pattern: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Check if a dependency exists in package.json
|
|
40
|
+
*/
|
|
41
|
+
export declare function hasDependency(packageJson: PackageJsonContent | null, dep: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Check if a script exists in package.json
|
|
44
|
+
*/
|
|
45
|
+
export declare function hasScript(packageJson: PackageJsonContent | null, script: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Run a command and capture output
|
|
48
|
+
*/
|
|
49
|
+
export declare function runCommand(command: string, args: string[], options: {
|
|
50
|
+
cwd: string;
|
|
51
|
+
timeout: number;
|
|
52
|
+
env?: Record<string, string>;
|
|
53
|
+
}): Promise<{
|
|
54
|
+
stdout: string;
|
|
55
|
+
stderr: string;
|
|
56
|
+
exitCode: number;
|
|
57
|
+
duration: number;
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* Build command from template
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildCommand(template: CommandTemplate): {
|
|
63
|
+
command: string;
|
|
64
|
+
args: string[];
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Format command for display
|
|
68
|
+
*/
|
|
69
|
+
export declare function formatCommand(command: string, args: string[]): string;
|