testchimp-runner-core 0.0.26 → 0.0.29

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 (43) hide show
  1. package/CREDIT_CALLBACK_ARCHITECTURE.md +253 -0
  2. package/INTEGRATION_COMPLETE.md +322 -0
  3. package/RELEASE_0.0.26.md +165 -0
  4. package/RELEASE_0.0.27.md +236 -0
  5. package/RELEASE_0.0.28.md +286 -0
  6. package/dist/credit-usage-service.d.ts +28 -2
  7. package/dist/credit-usage-service.d.ts.map +1 -1
  8. package/dist/credit-usage-service.js +60 -24
  9. package/dist/credit-usage-service.js.map +1 -1
  10. package/dist/execution-service.d.ts.map +1 -1
  11. package/dist/execution-service.js +134 -10
  12. package/dist/execution-service.js.map +1 -1
  13. package/dist/index.d.ts +13 -6
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +19 -7
  16. package/dist/index.js.map +1 -1
  17. package/dist/progress-reporter.d.ts +30 -0
  18. package/dist/progress-reporter.d.ts.map +1 -1
  19. package/dist/prompts.d.ts.map +1 -1
  20. package/dist/prompts.js +5 -4
  21. package/dist/prompts.js.map +1 -1
  22. package/dist/scenario-service.d.ts +1 -1
  23. package/dist/scenario-service.d.ts.map +1 -1
  24. package/dist/scenario-service.js +7 -4
  25. package/dist/scenario-service.js.map +1 -1
  26. package/dist/scenario-worker-class.d.ts +2 -10
  27. package/dist/scenario-worker-class.d.ts.map +1 -1
  28. package/dist/scenario-worker-class.js +88 -26
  29. package/dist/scenario-worker-class.js.map +1 -1
  30. package/dist/types.d.ts +9 -0
  31. package/dist/types.d.ts.map +1 -1
  32. package/dist/types.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/credit-usage-service.ts +81 -26
  35. package/src/execution-service.ts +158 -11
  36. package/src/index.ts +42 -10
  37. package/src/progress-reporter.ts +35 -0
  38. package/src/prompts.ts +5 -4
  39. package/src/scenario-service.ts +16 -4
  40. package/src/scenario-worker-class.ts +102 -28
  41. package/src/types.ts +16 -0
  42. package/testchimp-runner-core-0.0.27.tgz +0 -0
  43. package/testchimp-runner-core-0.0.26.tgz +0 -0
package/src/index.ts CHANGED
@@ -10,9 +10,9 @@ import { ScenarioWorker } from './scenario-worker-class';
10
10
  import { PlaywrightMCPService } from './playwright-mcp-service';
11
11
  import { LLMFacade } from './llm-facade';
12
12
  import { AuthConfig } from './auth-config';
13
- import { CreditUsageService } from './credit-usage-service';
13
+ import { CreditUsageService, CreditUsageCallback, CreditUsage, CreditUsageReason } from './credit-usage-service';
14
14
 
15
- export { ExecutionService, ScenarioService, ScenarioWorker, PlaywrightMCPService, LLMFacade, CreditUsageService };
15
+ export { ExecutionService, ScenarioService, ScenarioWorker, PlaywrightMCPService, LLMFacade, CreditUsageService, CreditUsageCallback, CreditUsage, CreditUsageReason };
16
16
 
17
17
  // File handlers
18
18
  import { FileHandler, LocalFileHandler, CIFileHandler, NoOpFileHandler } from './file-handler';
@@ -20,12 +20,12 @@ export { FileHandler, LocalFileHandler, CIFileHandler, NoOpFileHandler };
20
20
 
21
21
  // LLM Provider interfaces
22
22
  import { LLMProvider, LLMRequest, LLMResponse } from './llm-provider';
23
- import { ProgressReporter, StepProgress, JobProgress, StepExecutionStatus } from './progress-reporter';
23
+ import { ProgressReporter, StepProgress, JobProgress, StepExecutionStatus, StepInfo } from './progress-reporter';
24
24
  import { BackendProxyLLMProvider } from './providers/backend-proxy-llm-provider';
25
25
  import { LocalLLMProvider } from './providers/local-llm-provider';
26
26
 
27
27
  export { LLMProvider, LLMRequest, LLMResponse };
28
- export { ProgressReporter, StepProgress, JobProgress, StepExecutionStatus };
28
+ export { ProgressReporter, StepProgress, JobProgress, StepExecutionStatus, StepInfo };
29
29
  export { BackendProxyLLMProvider, LocalLLMProvider };
30
30
 
31
31
  // Orchestrator (tool-using agent)
@@ -81,6 +81,7 @@ export class TestChimpService {
81
81
  private logger?: (message: string, level?: 'log' | 'error' | 'warn') => void;
82
82
  private orchestratorOptions?: { useOrchestrator?: boolean; orchestratorConfig?: Partial<AgentConfig>; debugMode?: boolean };
83
83
  private outputChannel?: any; // Store outputChannel to preserve it across service recreations
84
+ private creditUsageCallback?: CreditUsageCallback; // Store credit callback to preserve it across service recreations
84
85
 
85
86
  constructor(
86
87
  fileHandler?: FileHandler,
@@ -89,19 +90,22 @@ export class TestChimpService {
89
90
  maxWorkers?: number,
90
91
  llmProvider?: LLMProvider,
91
92
  progressReporter?: ProgressReporter,
92
- orchestratorOptions?: { useOrchestrator?: boolean; orchestratorConfig?: Partial<AgentConfig>; debugMode?: boolean }
93
+ orchestratorOptions?: { useOrchestrator?: boolean; orchestratorConfig?: Partial<AgentConfig>; debugMode?: boolean },
94
+ creditUsageCallback?: CreditUsageCallback
93
95
  ) {
94
96
  this.fileHandler = fileHandler || new NoOpFileHandler();
95
97
  this.authConfig = authConfig || null;
96
98
  this.backendUrl = backendUrl || 'https://featureservice.testchimp.io'; // Default to production
97
99
  this.progressReporter = progressReporter;
98
100
  this.orchestratorOptions = orchestratorOptions;
101
+ this.creditUsageCallback = creditUsageCallback;
99
102
 
100
103
  // Use provided LLM provider or default to backend proxy (backward compatible)
101
104
  this.llmProvider = llmProvider || new BackendProxyLLMProvider(authConfig, backendUrl);
102
105
 
103
106
  this.playwrightService = new PlaywrightMCPService();
104
- this.creditUsageService = new CreditUsageService(this.authConfig || undefined, this.backendUrl);
107
+ // Pass credit callback to constructor - preserved across recreations via this.creditUsageCallback
108
+ this.creditUsageService = new CreditUsageService(this.authConfig || undefined, this.backendUrl, this.creditUsageCallback);
105
109
 
106
110
  // Create services with providers
107
111
  this.executionService = new ExecutionService(
@@ -189,8 +193,8 @@ export class TestChimpService {
189
193
  this.llmProvider.setLogger?.(this.logger);
190
194
  }
191
195
 
192
- // Recreate services with new provider
193
- this.creditUsageService = new CreditUsageService(this.authConfig || undefined, this.backendUrl);
196
+ // Recreate services with new provider (preserve credit callback)
197
+ this.creditUsageService = new CreditUsageService(this.authConfig || undefined, this.backendUrl, this.creditUsageCallback);
194
198
  this.executionService = new ExecutionService(
195
199
  this.authConfig || undefined,
196
200
  this.backendUrl,
@@ -243,6 +247,16 @@ export class TestChimpService {
243
247
  }
244
248
  }
245
249
 
250
+ /**
251
+ * Set credit usage callback
252
+ * Server-side: Use callback to update DB directly (no axios calls)
253
+ * Client-side: Don't set callback, uses auth for axios calls to backend
254
+ */
255
+ setCreditUsageCallback(callback: CreditUsageCallback): void {
256
+ this.creditUsageCallback = callback; // Store for future service recreations
257
+ this.creditUsageService.setCreditUsageCallback(callback);
258
+ }
259
+
246
260
  /**
247
261
  * Log a message using the configured logger
248
262
  */
@@ -271,8 +285,26 @@ export class TestChimpService {
271
285
  }
272
286
 
273
287
  // Scenario generation
274
- async generateScript(scenario: string, testName?: string, config?: string, model?: string, scenarioFileName?: string): Promise<string> {
275
- return this.scenarioService.processScenario(scenario, testName, config, model, scenarioFileName);
288
+ async generateScript(
289
+ scenario: string,
290
+ testName?: string,
291
+ config?: string,
292
+ model?: string,
293
+ scenarioFileName?: string,
294
+ existingBrowser?: any,
295
+ existingContext?: any,
296
+ existingPage?: any
297
+ ): Promise<string> {
298
+ return this.scenarioService.processScenario(
299
+ scenario,
300
+ testName,
301
+ config,
302
+ model,
303
+ scenarioFileName,
304
+ existingBrowser,
305
+ existingContext,
306
+ existingPage
307
+ );
276
308
  }
277
309
 
278
310
  // Test execution
@@ -66,6 +66,16 @@ export interface TokenUsage {
66
66
  timestamp: number;
67
67
  }
68
68
 
69
+ /**
70
+ * Additional step info for lifecycle callbacks
71
+ */
72
+ export interface StepInfo {
73
+ stepId?: string;
74
+ stepNumber: number;
75
+ description: string;
76
+ code?: string;
77
+ }
78
+
69
79
  /**
70
80
  * Progress reporter interface for external consumers
71
81
  */
@@ -105,5 +115,30 @@ export interface ProgressReporter {
105
115
  * Generic logging (for environments that don't need structured progress)
106
116
  */
107
117
  log?(message: string, level?: 'log' | 'error' | 'warn'): void;
118
+
119
+ /**
120
+ * LIFECYCLE CALLBACKS (optional - used by scriptservice, ignored by local clients)
121
+ */
122
+
123
+ /**
124
+ * Called before test execution starts
125
+ * - Script Service: Initialize browser context, set up DB records
126
+ * - VS Extension/GitHub: Not used (ignore)
127
+ */
128
+ beforeStartTest?(page: any, browser: any, context: any): Promise<void>;
129
+
130
+ /**
131
+ * Called before each step execution
132
+ * - Script Service: Update step status to IN_PROGRESS in DB
133
+ * - VS Extension/GitHub: Not used (ignore)
134
+ */
135
+ beforeStepStart?(step: StepInfo, page: any): Promise<void>;
136
+
137
+ /**
138
+ * Called after test execution completes (success or failure)
139
+ * - Script Service: Write final status to DB, cleanup resources
140
+ * - VS Extension/GitHub: Not used (return value is sufficient)
141
+ */
142
+ afterEndTest?(status: 'passed' | 'failed', error?: string, page?: any): Promise<void>;
108
143
  }
109
144
 
package/src/prompts.ts CHANGED
@@ -757,12 +757,13 @@ ${script}
757
757
 
758
758
  YOUR TASK (MINOR ADJUSTMENTS ONLY):
759
759
  1. Remove duplicate/redundant expect() assertions (e.g., same assertion repeated twice)
760
- 2. Remove duplicate step comments without code
761
- 3. Fix obvious formatting issues (inconsistent spacing, etc.)
762
- 4. Consolidate multiple identical assertions into one
763
- 5. Remove any obviously redundant waits or checks
760
+ 2. Fix obvious formatting issues (inconsistent spacing, etc.)
761
+ 3. Consolidate multiple identical assertions into one
762
+ 4. Remove any obviously redundant waits or checks
764
763
 
765
764
  DO NOT:
765
+ - Remove the TestChimp header comment (/* This is a TestChimp Smart Test... */) - this must be preserved
766
+ - Remove step comments (e.g., "// Step 1: ..." or "// Navigate to...") - these are important for readability
766
767
  - Change the test logic or flow
767
768
  - Remove legitimate assertions
768
769
  - Restructure the code
@@ -111,16 +111,25 @@ export class ScenarioService extends EventEmitter {
111
111
  });
112
112
 
113
113
  this.workers.push(worker);
114
- this.log(`Scenario worker initialized${this.useOrchestrator ? ' (Orchestrator Mode)' : ''} with session: ${worker['sessionId']}`);
114
+ // Internal initialization - no need to log worker details
115
115
  }
116
116
 
117
117
  async initialize(): Promise<void> {
118
118
  // Wait for workers to be initialized
119
119
  await this.initializeWorkers();
120
- this.log('Scenario service initialized');
120
+ // Internal initialization - consumer doesn't need to see this
121
121
  }
122
122
 
123
- processScenario(scenario: string, testName?: string, config?: PlaywrightConfig, model?: string, scenarioFileName?: string): string {
123
+ processScenario(
124
+ scenario: string,
125
+ testName?: string,
126
+ config?: PlaywrightConfig,
127
+ model?: string,
128
+ scenarioFileName?: string,
129
+ existingBrowser?: any,
130
+ existingContext?: any,
131
+ existingPage?: any
132
+ ): string {
124
133
  const jobId = `scenario_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
125
134
 
126
135
  // Add job to queue
@@ -130,7 +139,10 @@ export class ScenarioService extends EventEmitter {
130
139
  testName,
131
140
  playwrightConfig: config,
132
141
  model,
133
- scenarioFileName
142
+ scenarioFileName,
143
+ existingBrowser,
144
+ existingContext,
145
+ existingPage
134
146
  };
135
147
 
136
148
  this.jobQueue.push(job);
@@ -97,8 +97,6 @@ export class ScenarioWorker extends EventEmitter {
97
97
  * Initialize orchestrator mode with tools
98
98
  */
99
99
  private initializeOrchestrator(): void {
100
- this.log('🤖 Initializing Orchestrator Mode');
101
-
102
100
  // Create tool registry
103
101
  this.toolRegistry = new ToolRegistry();
104
102
 
@@ -135,12 +133,12 @@ export class ScenarioWorker extends EventEmitter {
135
133
  this.debugMode // Pass debug mode
136
134
  );
137
135
 
138
- this.log(`✓ Orchestrator initialized with 5 tools${this.debugMode ? ' (DEBUG MODE)' : ''} (information-gathering only)`);
136
+ // Minimal initialization logging - internal details not needed by consumer
139
137
  }
140
138
 
141
139
  private log(message: string): void {
142
- const timestamp = new Date().toISOString().substring(11, 23); // HH:MM:SS.mmm
143
- const formattedMessage = `[${timestamp}] [ScenarioWorker] ${message}`;
140
+ // Let consumer add timestamps - just report the raw message
141
+ const formattedMessage = `[ScenarioWorker] ${message}`;
144
142
  // Always log to console for debug visibility
145
143
  console.log(formattedMessage);
146
144
  // Also route to outputChannel if provided
@@ -150,8 +148,8 @@ export class ScenarioWorker extends EventEmitter {
150
148
  }
151
149
 
152
150
  private logError(message: string): void {
153
- const timestamp = new Date().toISOString().substring(11, 23); // HH:MM:SS.mmm
154
- const formattedMessage = `[${timestamp}] [ScenarioWorker] ERROR: ${message}`;
151
+ // Let consumer add timestamps - just report the raw message
152
+ const formattedMessage = `[ScenarioWorker] ERROR: ${message}`;
155
153
  // Always log to console for debug visibility
156
154
  console.error(formattedMessage);
157
155
  // Also route to outputChannel if provided
@@ -246,21 +244,16 @@ export class ScenarioWorker extends EventEmitter {
246
244
 
247
245
  async initialize(): Promise<void> {
248
246
  try {
249
- const RUNNER_CORE_VERSION = "v1.5.0-vision-preserve-values";
250
- this.log('═══════════════════════════════════════════════════════');
251
- this.log(`🚀 RUNNER-CORE VERSION: ${RUNNER_CORE_VERSION}`);
252
- this.log('═══════════════════════════════════════════════════════');
253
- this.log('Initializing Scenario worker...');
254
247
  this.sessionId = `scenario_worker_${Date.now()}`;
255
248
  this.initialized = true;
256
- this.log(`Scenario worker initialized with session: ${this.sessionId}`);
249
+ // Minimal initialization - consumer doesn't need to see internal details
257
250
  } catch (error) {
258
251
  this.logError(`Scenario worker initialization error: ${error}`);
259
252
  throw error;
260
253
  }
261
254
  }
262
255
 
263
- async processScenarioJob(job: ScenarioJob): Promise<ScenarioResponse> {
256
+ async processScenarioJob(job: ScenarioRunJob): Promise<ScenarioResponse> {
264
257
  if (!this.initialized) {
265
258
  throw new Error('Scenario worker not initialized');
266
259
  }
@@ -268,9 +261,9 @@ export class ScenarioWorker extends EventEmitter {
268
261
  // Set current job ID for progress reporting
269
262
  this.currentJobId = job.id;
270
263
 
271
- // VERSION MARKER - increment this number with each significant change
272
- const RUNNER_CORE_VERSION = "v1.5.0-vision-preserve-values";
273
- this.log(`🚀 RUNNER-CORE VERSION: ${RUNNER_CORE_VERSION}`);
264
+ // Log library version once (read from package.json)
265
+ const packageJson = require('../package.json');
266
+ this.log(`testchimp-runner-core v${packageJson.version}`);
274
267
  this.log(`📋 Processing scenario: ${job.scenario}`);
275
268
 
276
269
  const startTime = Date.now();
@@ -310,16 +303,30 @@ export class ScenarioWorker extends EventEmitter {
310
303
  }
311
304
  this.emit('log', job.id, `\n## Execution Progress\n\n`);
312
305
 
313
- // 2. Start a new browser session using centralized utility
314
- // Default to headed mode (headless: false) for better debugging
315
- // Create logger function from outputChannel for browser initialization
316
- const logger = this.outputChannel ? (message: string, level?: 'log' | 'error' | 'warn') => {
317
- this.outputChannel!.appendLine(`[Browser] ${message}`);
318
- } : undefined;
319
- const browserInstance = await initializeBrowser(job.playwrightConfig, false, undefined, logger);
320
- browser = browserInstance.browser;
321
- context = browserInstance.context;
322
- page = browserInstance.page;
306
+ // 2. Start a new browser session or use existing one
307
+ if (job.existingBrowser && job.existingContext && job.existingPage) {
308
+ // Use existing browser provided by caller (e.g., scriptservice)
309
+ this.log('Using existing browser/page provided by caller');
310
+ browser = job.existingBrowser;
311
+ context = job.existingContext;
312
+ page = job.existingPage;
313
+ } else {
314
+ // Create new browser (default behavior for local clients)
315
+ // Default to headed mode (headless: false) for better debugging
316
+ // Create logger function from outputChannel for browser initialization
317
+ const logger = this.outputChannel ? (message: string, level?: 'log' | 'error' | 'warn') => {
318
+ this.outputChannel!.appendLine(`[Browser] ${message}`);
319
+ } : undefined;
320
+ const browserInstance = await initializeBrowser(job.playwrightConfig, false, undefined, logger);
321
+ browser = browserInstance.browser;
322
+ context = browserInstance.context;
323
+ page = browserInstance.page;
324
+ }
325
+
326
+ // LIFECYCLE: Call beforeStartTest if provided
327
+ if (this.progressReporter?.beforeStartTest) {
328
+ await this.progressReporter.beforeStartTest(page, browser, context);
329
+ }
323
330
 
324
331
  // Set reasonable timeout for most operations
325
332
  // 5 seconds for element interactions (fast feedback on wrong selectors)
@@ -367,6 +374,17 @@ export class ScenarioWorker extends EventEmitter {
367
374
  step.stepNumber = i + 1;
368
375
 
369
376
  try {
377
+ // LIFECYCLE: Call beforeStepStart if provided
378
+ if (this.progressReporter?.beforeStepStart) {
379
+ await this.progressReporter.beforeStepStart(
380
+ {
381
+ stepNumber: step.stepNumber,
382
+ description: step.description
383
+ },
384
+ page
385
+ );
386
+ }
387
+
370
388
  // Use orchestrator to execute this step
371
389
  const result = await this.orchestratorAgent.executeStep(
372
390
  page,
@@ -405,6 +423,18 @@ export class ScenarioWorker extends EventEmitter {
405
423
  }
406
424
  }
407
425
 
426
+ // REPORT FINAL STEP RESULT (after orchestrator completes all iterations)
427
+ // This gives the complete accumulated commands, not just one iteration
428
+ await this.reportStepProgress({
429
+ jobId: job.id,
430
+ stepNumber: step.stepNumber,
431
+ description: step.description,
432
+ code: step.playwrightCommands?.join('\n') || '', // All accumulated commands
433
+ status: step.success ? StepExecutionStatus.SUCCESS : StepExecutionStatus.FAILURE,
434
+ error: step.error,
435
+ agentIteration: result.iterations
436
+ });
437
+
408
438
  } catch (error: any) {
409
439
  this.logError(`Orchestrator execution failed for step ${step.stepNumber}: ${error.message}`);
410
440
  step.success = false;
@@ -858,7 +888,17 @@ export class ScenarioWorker extends EventEmitter {
858
888
  }
859
889
 
860
890
  // Generate clean script with TestChimp comment and code
891
+ this.log(`[ScenarioWorker] Generating script from ${steps.length} steps`);
892
+ steps.forEach((s, i) => {
893
+ this.log(`[ScenarioWorker] Step ${i+1}: ${s.description}`);
894
+ this.log(`[ScenarioWorker] Commands: ${s.playwrightCommands?.length || 0}`);
895
+ if (s.playwrightCommands && s.playwrightCommands.length > 0) {
896
+ this.log(`[ScenarioWorker] First command: ${s.playwrightCommands[0]}`);
897
+ }
898
+ });
899
+
861
900
  generatedScript = generateTestScript(testName, steps, undefined, hashtags);
901
+ this.log(`[ScenarioWorker] Generated script length: ${generatedScript.length}`);
862
902
 
863
903
  // Perform final cleanup pass to remove redundancies and make minor adjustments
864
904
  this.log(`[ScenarioWorker] Performing final script cleanup...`);
@@ -931,6 +971,15 @@ export class ScenarioWorker extends EventEmitter {
931
971
 
932
972
  const executionLog = logLines.join('\n');
933
973
 
974
+ // Report job completion
975
+ await this.reportJobProgress({
976
+ jobId: job.id,
977
+ status: overallSuccess ? 'completed' : 'failed',
978
+ testName,
979
+ script: generatedScript,
980
+ error: overallSuccess ? undefined : 'Some steps failed during execution'
981
+ });
982
+
934
983
  return {
935
984
  success: overallSuccess,
936
985
  steps,
@@ -944,6 +993,16 @@ export class ScenarioWorker extends EventEmitter {
944
993
  } catch (error: any) {
945
994
  overallSuccess = false;
946
995
  this.logError(`Overall scenario processing error: ${error}`);
996
+
997
+ // Report job failure
998
+ await this.reportJobProgress({
999
+ jobId: job.id,
1000
+ status: 'failed',
1001
+ testName: job.testName || 'test',
1002
+ script: generatedScript,
1003
+ error: error instanceof Error ? error.message : 'Unknown error during scenario processing'
1004
+ });
1005
+
947
1006
  return {
948
1007
  success: false,
949
1008
  steps,
@@ -955,7 +1014,22 @@ export class ScenarioWorker extends EventEmitter {
955
1014
  error: error instanceof Error ? error.message : 'Unknown error during scenario processing'
956
1015
  };
957
1016
  } finally {
958
- if (browser) {
1017
+ // LIFECYCLE: Call afterEndTest if provided
1018
+ if (browser && this.progressReporter?.afterEndTest) {
1019
+ try {
1020
+ await this.progressReporter.afterEndTest(
1021
+ overallSuccess ? 'passed' : 'failed',
1022
+ overallSuccess ? undefined : 'Test execution had failures',
1023
+ page
1024
+ );
1025
+ } catch (callbackError) {
1026
+ this.log(`afterEndTest callback failed: ${callbackError}`);
1027
+ }
1028
+ }
1029
+
1030
+ // Only close browser if we created it (not provided by caller)
1031
+ const usingExternalBrowser = !!(job.existingBrowser && job.existingContext && job.existingPage);
1032
+ if (browser && !usingExternalBrowser) {
959
1033
  await browser.close();
960
1034
  }
961
1035
  }
package/src/types.ts CHANGED
@@ -83,6 +83,11 @@ export interface ScenarioRunJob {
83
83
  playwrightConfig?: PlaywrightConfig;
84
84
  model?: string;
85
85
  scenarioFileName?: string;
86
+
87
+ // Optional: Provide existing browser/page/context (for server-side usage)
88
+ existingBrowser?: any;
89
+ existingContext?: any;
90
+ existingPage?: any;
86
91
  }
87
92
 
88
93
  /**
@@ -139,6 +144,11 @@ export interface ScenarioJob {
139
144
  config?: PlaywrightConfig;
140
145
  resolve: (result: ScenarioResponse) => void;
141
146
  reject: (error: Error) => void;
147
+
148
+ // Optional: Provide existing browser/page/context (for server-side usage)
149
+ existingBrowser?: any;
150
+ existingContext?: any;
151
+ existingPage?: any;
142
152
  }
143
153
 
144
154
  // ============================================================================
@@ -166,6 +176,12 @@ export interface ScriptExecutionRequest {
166
176
  model?: string;
167
177
  headless?: boolean; // defaults to false (headed)
168
178
  deflake_run_count?: number; // defaults to 1
179
+
180
+ // Optional: Provide existing browser/page/context (for server-side usage)
181
+ // If not provided, runner-core will create its own
182
+ existingBrowser?: any; // Browser instance
183
+ existingContext?: any; // BrowserContext instance
184
+ existingPage?: any; // Page instance
169
185
  }
170
186
 
171
187
  /**
Binary file
Binary file