@browserflow-ai/exploration 0.0.6
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/dist/adapters/claude-cli.d.ts +57 -0
- package/dist/adapters/claude-cli.d.ts.map +1 -0
- package/dist/adapters/claude-cli.js +195 -0
- package/dist/adapters/claude-cli.js.map +1 -0
- package/dist/adapters/claude.d.ts +54 -0
- package/dist/adapters/claude.d.ts.map +1 -0
- package/dist/adapters/claude.js +160 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/index.d.ts +6 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +4 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/types.d.ts +196 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +3 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/agent-browser-session.d.ts +62 -0
- package/dist/agent-browser-session.d.ts.map +1 -0
- package/dist/agent-browser-session.js +272 -0
- package/dist/agent-browser-session.js.map +1 -0
- package/dist/evidence.d.ts +111 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +144 -0
- package/dist/evidence.js.map +1 -0
- package/dist/explorer.d.ts +180 -0
- package/dist/explorer.d.ts.map +1 -0
- package/dist/explorer.js +393 -0
- package/dist/explorer.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/locator-candidates.d.ts +127 -0
- package/dist/locator-candidates.d.ts.map +1 -0
- package/dist/locator-candidates.js +358 -0
- package/dist/locator-candidates.js.map +1 -0
- package/dist/step-executor.d.ts +99 -0
- package/dist/step-executor.d.ts.map +1 -0
- package/dist/step-executor.js +646 -0
- package/dist/step-executor.js.map +1 -0
- package/package.json +34 -0
- package/src/adapters/claude-cli.test.ts +134 -0
- package/src/adapters/claude-cli.ts +240 -0
- package/src/adapters/claude.test.ts +195 -0
- package/src/adapters/claude.ts +190 -0
- package/src/adapters/index.ts +21 -0
- package/src/adapters/types.ts +207 -0
- package/src/agent-browser-session.test.ts +369 -0
- package/src/agent-browser-session.ts +349 -0
- package/src/evidence.test.ts +239 -0
- package/src/evidence.ts +203 -0
- package/src/explorer.test.ts +321 -0
- package/src/explorer.ts +565 -0
- package/src/index.ts +51 -0
- package/src/locator-candidates.test.ts +602 -0
- package/src/locator-candidates.ts +441 -0
- package/src/step-executor.test.ts +696 -0
- package/src/step-executor.ts +783 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for EvidenceCollector - Screenshot and trace evidence capture
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, test, expect, beforeEach, afterEach, mock } from 'bun:test';
|
|
6
|
+
import { promises as fs } from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { EvidenceCollector } from './evidence';
|
|
9
|
+
import type { BrowserSession } from './explorer';
|
|
10
|
+
|
|
11
|
+
describe('EvidenceCollector', () => {
|
|
12
|
+
let collector: EvidenceCollector;
|
|
13
|
+
let mockSession: BrowserSession;
|
|
14
|
+
let tempDir: string;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
// Create temp directory for test outputs
|
|
18
|
+
tempDir = `/tmp/evidence-test-${Date.now()}`;
|
|
19
|
+
await fs.mkdir(tempDir, { recursive: true });
|
|
20
|
+
|
|
21
|
+
collector = new EvidenceCollector({
|
|
22
|
+
outputDir: tempDir,
|
|
23
|
+
screenshotFormat: 'png',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Mock browser session
|
|
27
|
+
mockSession = {
|
|
28
|
+
isLaunched: () => true,
|
|
29
|
+
launch: mock(async () => {}),
|
|
30
|
+
navigate: mock(async () => {}),
|
|
31
|
+
screenshot: mock(async () => Buffer.from('fake-png-data')),
|
|
32
|
+
getSnapshot: mock(async () => ({ refs: {}, elements: [] })),
|
|
33
|
+
close: mock(async () => {}),
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
afterEach(async () => {
|
|
38
|
+
// Clean up temp directory
|
|
39
|
+
try {
|
|
40
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
41
|
+
} catch {
|
|
42
|
+
// Ignore cleanup errors
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('Session Management', () => {
|
|
47
|
+
test('registerSession stores a browser session', () => {
|
|
48
|
+
collector.registerSession('test-session-1', mockSession);
|
|
49
|
+
// If this doesn't throw, registration worked
|
|
50
|
+
expect(true).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('registerSession allows multiple sessions', () => {
|
|
54
|
+
const mockSession2: BrowserSession = {
|
|
55
|
+
...mockSession,
|
|
56
|
+
screenshot: mock(async () => Buffer.from('fake-png-data-2')),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
collector.registerSession('session-1', mockSession);
|
|
60
|
+
collector.registerSession('session-2', mockSession2);
|
|
61
|
+
// Should not throw
|
|
62
|
+
expect(true).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('unregisterSession removes a session', () => {
|
|
66
|
+
collector.registerSession('test-session', mockSession);
|
|
67
|
+
collector.unregisterSession('test-session');
|
|
68
|
+
// Should not throw
|
|
69
|
+
expect(true).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('Screenshot Capture', () => {
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
collector.registerSession('test-session', mockSession);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('captureScreenshot creates screenshots directory', async () => {
|
|
79
|
+
const filepath = await collector.captureScreenshot('test-session', 'test-screenshot');
|
|
80
|
+
|
|
81
|
+
const screenshotsDir = path.join(tempDir, 'screenshots');
|
|
82
|
+
const dirExists = await fs
|
|
83
|
+
.stat(screenshotsDir)
|
|
84
|
+
.then((s) => s.isDirectory())
|
|
85
|
+
.catch(() => false);
|
|
86
|
+
|
|
87
|
+
expect(dirExists).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('captureScreenshot writes file to disk', async () => {
|
|
91
|
+
const filepath = await collector.captureScreenshot('test-session', 'test-screenshot');
|
|
92
|
+
|
|
93
|
+
const fileExists = await fs
|
|
94
|
+
.stat(filepath)
|
|
95
|
+
.then(() => true)
|
|
96
|
+
.catch(() => false);
|
|
97
|
+
|
|
98
|
+
expect(fileExists).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('captureScreenshot returns correct file path', async () => {
|
|
102
|
+
const filepath = await collector.captureScreenshot('test-session', 'my-screenshot');
|
|
103
|
+
|
|
104
|
+
const expectedPath = path.join(tempDir, 'screenshots', 'my-screenshot.png');
|
|
105
|
+
expect(filepath).toBe(expectedPath);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('captureScreenshot writes actual screenshot buffer', async () => {
|
|
109
|
+
const testBuffer = Buffer.from('test-screenshot-data');
|
|
110
|
+
mockSession.screenshot = mock(async () => testBuffer);
|
|
111
|
+
|
|
112
|
+
const filepath = await collector.captureScreenshot('test-session', 'test-screenshot');
|
|
113
|
+
|
|
114
|
+
const fileContent = await fs.readFile(filepath);
|
|
115
|
+
expect(fileContent).toEqual(testBuffer);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('captureScreenshot records metadata', async () => {
|
|
119
|
+
await collector.captureScreenshot('test-session', 'test-screenshot');
|
|
120
|
+
|
|
121
|
+
const evidence = collector.getEvidence();
|
|
122
|
+
expect(evidence.length).toBe(1);
|
|
123
|
+
expect(evidence[0].type).toBe('screenshot');
|
|
124
|
+
expect(evidence[0].sessionId).toBe('test-session');
|
|
125
|
+
expect(evidence[0].path).toContain('test-screenshot.png');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('captureScreenshot throws error for unknown session', async () => {
|
|
129
|
+
await expect(
|
|
130
|
+
collector.captureScreenshot('unknown-session', 'test')
|
|
131
|
+
).rejects.toThrow('No browser session found: unknown-session');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('captureScreenshot respects screenshot format (jpeg)', async () => {
|
|
135
|
+
const jpegCollector = new EvidenceCollector({
|
|
136
|
+
outputDir: tempDir,
|
|
137
|
+
screenshotFormat: 'jpeg',
|
|
138
|
+
});
|
|
139
|
+
jpegCollector.registerSession('test-session', mockSession);
|
|
140
|
+
|
|
141
|
+
const filepath = await jpegCollector.captureScreenshot('test-session', 'test-jpeg');
|
|
142
|
+
|
|
143
|
+
expect(filepath).toContain('.jpeg');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('captureScreenshot passes options to browser session', async () => {
|
|
147
|
+
const screenshotMock = mock(async () => Buffer.from('data'));
|
|
148
|
+
mockSession.screenshot = screenshotMock;
|
|
149
|
+
|
|
150
|
+
const options = {
|
|
151
|
+
fullPage: true,
|
|
152
|
+
clip: { x: 0, y: 0, width: 100, height: 100 },
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
await collector.captureScreenshot('test-session', 'test', options);
|
|
156
|
+
|
|
157
|
+
expect(screenshotMock).toHaveBeenCalledWith(options);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('captureScreenshot handles multiple screenshots', async () => {
|
|
161
|
+
await collector.captureScreenshot('test-session', 'screenshot-1');
|
|
162
|
+
await collector.captureScreenshot('test-session', 'screenshot-2');
|
|
163
|
+
await collector.captureScreenshot('test-session', 'screenshot-3');
|
|
164
|
+
|
|
165
|
+
const evidence = collector.getEvidence();
|
|
166
|
+
expect(evidence.length).toBe(3);
|
|
167
|
+
expect(evidence[0].path).toContain('screenshot-1');
|
|
168
|
+
expect(evidence[1].path).toContain('screenshot-2');
|
|
169
|
+
expect(evidence[2].path).toContain('screenshot-3');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('captureScreenshot creates nested directories if needed', async () => {
|
|
173
|
+
// Even if screenshots dir doesn't exist, it should be created
|
|
174
|
+
const screenshotsDir = path.join(tempDir, 'screenshots');
|
|
175
|
+
const dirExistsBefore = await fs
|
|
176
|
+
.stat(screenshotsDir)
|
|
177
|
+
.then(() => true)
|
|
178
|
+
.catch(() => false);
|
|
179
|
+
|
|
180
|
+
expect(dirExistsBefore).toBe(false);
|
|
181
|
+
|
|
182
|
+
await collector.captureScreenshot('test-session', 'test');
|
|
183
|
+
|
|
184
|
+
const dirExistsAfter = await fs
|
|
185
|
+
.stat(screenshotsDir)
|
|
186
|
+
.then((s) => s.isDirectory())
|
|
187
|
+
.catch(() => false);
|
|
188
|
+
|
|
189
|
+
expect(dirExistsAfter).toBe(true);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe('Evidence Metadata', () => {
|
|
194
|
+
beforeEach(() => {
|
|
195
|
+
collector.registerSession('test-session', mockSession);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
test('getEvidence returns all captured evidence', async () => {
|
|
199
|
+
await collector.captureScreenshot('test-session', 'shot-1');
|
|
200
|
+
await collector.captureScreenshot('test-session', 'shot-2');
|
|
201
|
+
|
|
202
|
+
const evidence = collector.getEvidence();
|
|
203
|
+
expect(evidence.length).toBe(2);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test('clearEvidence removes all metadata', async () => {
|
|
207
|
+
await collector.captureScreenshot('test-session', 'shot-1');
|
|
208
|
+
await collector.captureScreenshot('test-session', 'shot-2');
|
|
209
|
+
|
|
210
|
+
collector.clearEvidence();
|
|
211
|
+
|
|
212
|
+
const evidence = collector.getEvidence();
|
|
213
|
+
expect(evidence.length).toBe(0);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('evidence metadata includes timestamp', async () => {
|
|
217
|
+
const beforeTime = new Date().toISOString();
|
|
218
|
+
await collector.captureScreenshot('test-session', 'test');
|
|
219
|
+
const afterTime = new Date().toISOString();
|
|
220
|
+
|
|
221
|
+
const evidence = collector.getEvidence();
|
|
222
|
+
expect(evidence[0].timestamp).toBeDefined();
|
|
223
|
+
expect(evidence[0].timestamp >= beforeTime).toBe(true);
|
|
224
|
+
expect(evidence[0].timestamp <= afterTime).toBe(true);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe('Configuration', () => {
|
|
229
|
+
test('getOutputDir returns configured directory', () => {
|
|
230
|
+
expect(collector.getOutputDir()).toBe(tempDir);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test('setOutputDir updates directory', () => {
|
|
234
|
+
const newDir = '/tmp/new-dir';
|
|
235
|
+
collector.setOutputDir(newDir);
|
|
236
|
+
expect(collector.getOutputDir()).toBe(newDir);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
package/src/evidence.ts
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// @browserflow-ai/exploration - Evidence collection (screenshots and traces)
|
|
2
|
+
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import type { BrowserSession } from './explorer';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Evidence metadata
|
|
9
|
+
*/
|
|
10
|
+
export interface EvidenceMetadata {
|
|
11
|
+
timestamp: string;
|
|
12
|
+
sessionId: string;
|
|
13
|
+
stepIndex?: number;
|
|
14
|
+
type: 'screenshot' | 'trace' | 'snapshot';
|
|
15
|
+
path: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Screenshot capture options
|
|
20
|
+
*/
|
|
21
|
+
export interface ScreenshotOptions {
|
|
22
|
+
fullPage?: boolean;
|
|
23
|
+
clip?: { x: number; y: number; width: number; height: number };
|
|
24
|
+
mask?: string[];
|
|
25
|
+
quality?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Configuration for the evidence collector
|
|
30
|
+
*/
|
|
31
|
+
export interface EvidenceCollectorConfig {
|
|
32
|
+
outputDir?: string;
|
|
33
|
+
screenshotFormat?: 'png' | 'jpeg';
|
|
34
|
+
screenshotQuality?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* EvidenceCollector - Captures screenshots and traces during exploration
|
|
39
|
+
*
|
|
40
|
+
* Provides:
|
|
41
|
+
* - Screenshot capture (full page, clipped, masked)
|
|
42
|
+
* - Browser snapshot capture
|
|
43
|
+
* - Trace/HAR file generation
|
|
44
|
+
* - Evidence metadata tracking
|
|
45
|
+
*/
|
|
46
|
+
export class EvidenceCollector {
|
|
47
|
+
private outputDir: string;
|
|
48
|
+
private screenshotFormat: 'png' | 'jpeg';
|
|
49
|
+
private screenshotQuality: number;
|
|
50
|
+
private evidence: EvidenceMetadata[] = [];
|
|
51
|
+
private sessions: Map<string, BrowserSession> = new Map();
|
|
52
|
+
|
|
53
|
+
constructor(config: EvidenceCollectorConfig = {}) {
|
|
54
|
+
this.outputDir = config.outputDir ?? './evidence';
|
|
55
|
+
this.screenshotFormat = config.screenshotFormat ?? 'png';
|
|
56
|
+
this.screenshotQuality = config.screenshotQuality ?? 90;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Register a browser session for screenshot capture
|
|
61
|
+
*
|
|
62
|
+
* @param sessionId - Unique identifier for the session
|
|
63
|
+
* @param session - Browser session instance
|
|
64
|
+
*/
|
|
65
|
+
registerSession(sessionId: string, session: BrowserSession): void {
|
|
66
|
+
this.sessions.set(sessionId, session);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Unregister a browser session
|
|
71
|
+
*
|
|
72
|
+
* @param sessionId - Session identifier to remove
|
|
73
|
+
*/
|
|
74
|
+
unregisterSession(sessionId: string): void {
|
|
75
|
+
this.sessions.delete(sessionId);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Capture a screenshot from the browser session
|
|
80
|
+
*
|
|
81
|
+
* @param sessionId - Browser session ID
|
|
82
|
+
* @param name - Screenshot name/identifier
|
|
83
|
+
* @param options - Screenshot options
|
|
84
|
+
* @returns Promise resolving to screenshot file path
|
|
85
|
+
*/
|
|
86
|
+
async captureScreenshot(
|
|
87
|
+
sessionId: string,
|
|
88
|
+
name: string,
|
|
89
|
+
options: ScreenshotOptions = {}
|
|
90
|
+
): Promise<string> {
|
|
91
|
+
// Get browser session
|
|
92
|
+
const session = this.sessions.get(sessionId);
|
|
93
|
+
if (!session) {
|
|
94
|
+
throw new Error(`No browser session found: ${sessionId}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Build file path
|
|
98
|
+
const filename = `${name}.${this.screenshotFormat}`;
|
|
99
|
+
const filepath = path.join(this.outputDir, 'screenshots', filename);
|
|
100
|
+
|
|
101
|
+
// Ensure directory exists
|
|
102
|
+
await fs.mkdir(path.dirname(filepath), { recursive: true });
|
|
103
|
+
|
|
104
|
+
// Capture screenshot from browser session
|
|
105
|
+
const buffer = await session.screenshot(options);
|
|
106
|
+
await fs.writeFile(filepath, buffer);
|
|
107
|
+
|
|
108
|
+
// Record metadata
|
|
109
|
+
const metadata: EvidenceMetadata = {
|
|
110
|
+
timestamp: new Date().toISOString(),
|
|
111
|
+
sessionId,
|
|
112
|
+
type: 'screenshot',
|
|
113
|
+
path: filepath,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
this.evidence.push(metadata);
|
|
117
|
+
return filepath;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Capture a browser snapshot (DOM state with element refs)
|
|
122
|
+
*
|
|
123
|
+
* @param sessionId - Browser session ID
|
|
124
|
+
* @param name - Snapshot name/identifier
|
|
125
|
+
* @returns Promise resolving to snapshot data
|
|
126
|
+
*/
|
|
127
|
+
async captureSnapshot(
|
|
128
|
+
sessionId: string,
|
|
129
|
+
name: string
|
|
130
|
+
): Promise<Record<string, unknown>> {
|
|
131
|
+
// TODO: Implement actual snapshot capture via agent-browser
|
|
132
|
+
const path = `${this.outputDir}/snapshots/${name}.json`;
|
|
133
|
+
|
|
134
|
+
const metadata: EvidenceMetadata = {
|
|
135
|
+
timestamp: new Date().toISOString(),
|
|
136
|
+
sessionId,
|
|
137
|
+
type: 'snapshot',
|
|
138
|
+
path,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
this.evidence.push(metadata);
|
|
142
|
+
return { elements: [], path };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Start trace recording
|
|
147
|
+
*
|
|
148
|
+
* @param sessionId - Browser session ID
|
|
149
|
+
* @param name - Trace name/identifier
|
|
150
|
+
*/
|
|
151
|
+
async startTrace(sessionId: string, name: string): Promise<void> {
|
|
152
|
+
// TODO: Implement trace recording via agent-browser
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Stop trace recording and save
|
|
157
|
+
*
|
|
158
|
+
* @param sessionId - Browser session ID
|
|
159
|
+
* @returns Promise resolving to trace file path
|
|
160
|
+
*/
|
|
161
|
+
async stopTrace(sessionId: string): Promise<string> {
|
|
162
|
+
// TODO: Implement trace recording via agent-browser
|
|
163
|
+
const path = `${this.outputDir}/traces/trace.zip`;
|
|
164
|
+
|
|
165
|
+
const metadata: EvidenceMetadata = {
|
|
166
|
+
timestamp: new Date().toISOString(),
|
|
167
|
+
sessionId,
|
|
168
|
+
type: 'trace',
|
|
169
|
+
path,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
this.evidence.push(metadata);
|
|
173
|
+
return path;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get all collected evidence metadata
|
|
178
|
+
*/
|
|
179
|
+
getEvidence(): EvidenceMetadata[] {
|
|
180
|
+
return [...this.evidence];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Clear collected evidence metadata
|
|
185
|
+
*/
|
|
186
|
+
clearEvidence(): void {
|
|
187
|
+
this.evidence = [];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Get the output directory
|
|
192
|
+
*/
|
|
193
|
+
getOutputDir(): string {
|
|
194
|
+
return this.outputDir;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Set the output directory
|
|
199
|
+
*/
|
|
200
|
+
setOutputDir(dir: string): void {
|
|
201
|
+
this.outputDir = dir;
|
|
202
|
+
}
|
|
203
|
+
}
|