terminator-mcp-agent 0.22.16 → 0.22.20
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 +56 -315
- package/index.js +36 -10
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -227,316 +227,50 @@ steps:
|
|
|
227
227
|
|
|
228
228
|
For complete CLI documentation, see [Terminator CLI README](../terminator-cli/README.md).
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
## Tool Documentation
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
All tool documentation is maintained as **source of truth in the codebase** to ensure accuracy and prevent duplication.
|
|
233
233
|
|
|
234
|
-
|
|
234
|
+
### Where to Find Tool Documentation
|
|
235
235
|
|
|
236
|
-
|
|
236
|
+
**System Instructions (Strategic Guidance)**:
|
|
237
|
+
- **File**: [`src/prompt.rs`](src/prompt.rs)
|
|
238
|
+
- **What**: High-level patterns, common pitfalls, environment variable safety, focus management
|
|
239
|
+
- **Lines**: 4-44
|
|
237
240
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
- Use `tree_output_format: "compact_yaml"` (default) for readable format or `"verbose_json"` for full data
|
|
243
|
-
2. **Build a Sequence**: Create an `execute_sequence` tool call with a series of actions (`click_element`, `type_into_element`, etc.). Use robust selectors (like `role|name` or stable `properties:AutomationId:value` selectors) whenever possible.
|
|
244
|
-
3. **Capture the Final State**: Ensure the last step in your sequence is an action that returns a UI tree. The `wait_for_element` tool with `include_tree: true` is perfect for this, as it captures the application's state after your automation has run.
|
|
245
|
-
4. **Extract Structured Data with `output_parser`**: Add the `output_parser` argument to your `execute_sequence` call. Write JavaScript code to parse the final UI tree and extract structured data. If successful, the tool result will contain a `parsed_output` field with your clean JSON data.
|
|
241
|
+
**Tool Descriptions (Complete API Reference)**:
|
|
242
|
+
- **File**: [`src/server.rs`](src/server.rs)
|
|
243
|
+
- **What**: Complete descriptions of all 35 tools including parameters, examples, error handling, and usage patterns
|
|
244
|
+
- **Each tool has**: Inline documentation in `#[tool(description = "...")]` macros
|
|
246
245
|
|
|
247
|
-
|
|
246
|
+
**Tool Index**:
|
|
247
|
+
- See [**Tool Reference Guide**](../../docs/TOOL_REFERENCE.md) for a complete index with line numbers
|
|
248
248
|
|
|
249
|
-
|
|
250
|
-
output_parser:
|
|
251
|
-
ui_tree_source_step_id: capture_quotes_tree
|
|
252
|
-
javascript_code: |
|
|
253
|
-
// Find all quote groups with Image and Text children
|
|
254
|
-
const results = [];
|
|
255
|
-
|
|
256
|
-
function findElementsRecursively(element) {
|
|
257
|
-
if (element.attributes && element.attributes.role === 'Group') {
|
|
258
|
-
const children = element.children || [];
|
|
259
|
-
const hasImage = children.some(child =>
|
|
260
|
-
child.attributes && child.attributes.role === 'Image'
|
|
261
|
-
);
|
|
262
|
-
const hasText = children.some(child =>
|
|
263
|
-
child.attributes && child.attributes.role === 'Text'
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
if (hasImage && hasText) {
|
|
267
|
-
const textElements = children.filter(child =>
|
|
268
|
-
child.attributes && child.attributes.role === 'Text' && child.attributes.name
|
|
269
|
-
);
|
|
270
|
-
|
|
271
|
-
let carrierProduct = '';
|
|
272
|
-
let monthlyPrice = '';
|
|
273
|
-
|
|
274
|
-
for (const textEl of textElements) {
|
|
275
|
-
const text = textEl.attributes.name;
|
|
276
|
-
if (text.includes(':')) {
|
|
277
|
-
carrierProduct = text;
|
|
278
|
-
}
|
|
279
|
-
if (text.startsWith('$')) {
|
|
280
|
-
monthlyPrice = text;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (carrierProduct && monthlyPrice) {
|
|
285
|
-
results.push({
|
|
286
|
-
carrierProduct: carrierProduct,
|
|
287
|
-
monthlyPrice: monthlyPrice
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (element.children) {
|
|
294
|
-
for (const child of element.children) {
|
|
295
|
-
findElementsRecursively(child);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
findElementsRecursively(tree);
|
|
301
|
-
return results;
|
|
302
|
-
```
|
|
249
|
+
### Quick Examples
|
|
303
250
|
|
|
304
|
-
|
|
251
|
+
**Find a tool**: Search `server.rs` for the tool name (e.g., `click_element`, `run_command`)
|
|
305
252
|
|
|
306
|
-
|
|
253
|
+
**Example - Click Element** ([server.rs:1250](src/server.rs#L1250)):
|
|
254
|
+
- Comprehensive actionability validation documentation
|
|
255
|
+
- Error types explained (ElementNotVisible, NotEnabled, NotStable, etc.)
|
|
256
|
+
- When to use `invoke_element` instead
|
|
307
257
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
258
|
+
**Example - Run Command** ([server.rs:1659](src/server.rs#L1659)):
|
|
259
|
+
- Shell vs engine mode
|
|
260
|
+
- Optional element detection patterns
|
|
261
|
+
- Variable safety and data passing
|
|
312
262
|
|
|
313
|
-
|
|
263
|
+
**Example - Execute Browser Script** ([server.rs:4789](src/server.rs#L4789)):
|
|
264
|
+
- Browser DOM access
|
|
265
|
+
- Variable injection patterns
|
|
266
|
+
- Script file loading
|
|
314
267
|
|
|
315
|
-
|
|
268
|
+
### Why Source Code Documentation?
|
|
316
269
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
**
|
|
320
|
-
|
|
321
|
-
- Navigating and interacting with UI elements
|
|
322
|
-
- Working with semantic page structure
|
|
323
|
-
- Building reliable automation workflows
|
|
324
|
-
- Performance is critical (faster, cleaner data)
|
|
325
|
-
|
|
326
|
-
**Use DOM Inspection when:**
|
|
327
|
-
|
|
328
|
-
- Extracting data attributes, meta tags, or hidden inputs
|
|
329
|
-
- Debugging why elements aren't appearing in accessibility tree
|
|
330
|
-
- Scraping structured data from specific HTML patterns
|
|
331
|
-
- Validating complete page structure or SEO elements
|
|
332
|
-
|
|
333
|
-
#### Basic DOM Retrieval Patterns
|
|
334
|
-
|
|
335
|
-
```javascript
|
|
336
|
-
// Get full HTML DOM (be mindful of size limits)
|
|
337
|
-
execute_browser_script({
|
|
338
|
-
selector: "role:Window|name:Google Chrome",
|
|
339
|
-
script: "document.documentElement.outerHTML",
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// Get structured page information
|
|
343
|
-
execute_browser_script({
|
|
344
|
-
selector: "role:Window|name:Google Chrome",
|
|
345
|
-
script: `({
|
|
346
|
-
url: window.location.href,
|
|
347
|
-
title: document.title,
|
|
348
|
-
html: document.documentElement.outerHTML,
|
|
349
|
-
bodyText: document.body.innerText.substring(0, 1000)
|
|
350
|
-
})`,
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
// Extract specific data (forms, hidden inputs, meta tags)
|
|
354
|
-
execute_browser_script({
|
|
355
|
-
selector: "role:Window|name:Google Chrome",
|
|
356
|
-
script: `({
|
|
357
|
-
forms: Array.from(document.forms).map(f => ({
|
|
358
|
-
id: f.id,
|
|
359
|
-
action: f.action,
|
|
360
|
-
method: f.method,
|
|
361
|
-
inputs: Array.from(f.elements).map(e => ({
|
|
362
|
-
name: e.name,
|
|
363
|
-
type: e.type,
|
|
364
|
-
value: e.type === 'password' ? '[REDACTED]' : e.value
|
|
365
|
-
}))
|
|
366
|
-
})),
|
|
367
|
-
hiddenInputs: Array.from(document.querySelectorAll('input[type="hidden"]')).map(e => ({
|
|
368
|
-
name: e.name,
|
|
369
|
-
value: e.value
|
|
370
|
-
})),
|
|
371
|
-
metaTags: Array.from(document.querySelectorAll('meta')).map(m => ({
|
|
372
|
-
name: m.name || m.property,
|
|
373
|
-
content: m.content
|
|
374
|
-
}))
|
|
375
|
-
})`,
|
|
376
|
-
});
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
#### Handling Large DOMs
|
|
380
|
-
|
|
381
|
-
The MCP protocol has response size limits (~30KB). For large DOMs, use truncation strategies:
|
|
382
|
-
|
|
383
|
-
```javascript
|
|
384
|
-
execute_browser_script({
|
|
385
|
-
selector: "role:Window|name:Google Chrome",
|
|
386
|
-
script: `
|
|
387
|
-
const html = document.documentElement.outerHTML;
|
|
388
|
-
const maxLength = 30000;
|
|
389
|
-
|
|
390
|
-
({
|
|
391
|
-
url: window.location.href,
|
|
392
|
-
title: document.title,
|
|
393
|
-
html: html.length > maxLength
|
|
394
|
-
? html.substring(0, maxLength) + '... [truncated at ' + maxLength + ' chars]'
|
|
395
|
-
: html,
|
|
396
|
-
totalLength: html.length,
|
|
397
|
-
truncated: html.length > maxLength
|
|
398
|
-
})
|
|
399
|
-
`,
|
|
400
|
-
});
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
#### Advanced DOM Analysis
|
|
404
|
-
|
|
405
|
-
```javascript
|
|
406
|
-
// Analyze page structure and extract semantic content
|
|
407
|
-
execute_browser_script({
|
|
408
|
-
selector: "role:Window|name:Google Chrome",
|
|
409
|
-
script: `
|
|
410
|
-
// Remove scripts and styles for cleaner analysis
|
|
411
|
-
const clonedDoc = document.documentElement.cloneNode(true);
|
|
412
|
-
clonedDoc.querySelectorAll('script, style, noscript').forEach(el => el.remove());
|
|
413
|
-
|
|
414
|
-
({
|
|
415
|
-
// Page metrics
|
|
416
|
-
domElementCount: document.querySelectorAll('*').length,
|
|
417
|
-
formCount: document.forms.length,
|
|
418
|
-
linkCount: document.links.length,
|
|
419
|
-
imageCount: document.images.length,
|
|
420
|
-
|
|
421
|
-
// Semantic structure
|
|
422
|
-
headings: Array.from(document.querySelectorAll('h1,h2,h3')).map(h => ({
|
|
423
|
-
level: h.tagName,
|
|
424
|
-
text: h.innerText.substring(0, 100)
|
|
425
|
-
})),
|
|
426
|
-
|
|
427
|
-
// Clean HTML without scripts/styles
|
|
428
|
-
cleanHtml: clonedDoc.outerHTML.substring(0, 20000),
|
|
429
|
-
|
|
430
|
-
// Data extraction
|
|
431
|
-
jsonLd: Array.from(document.querySelectorAll('script[type="application/ld+json"]'))
|
|
432
|
-
.map(s => { try { return JSON.parse(s.textContent); } catch { return null; } })
|
|
433
|
-
.filter(Boolean)
|
|
434
|
-
})
|
|
435
|
-
`,
|
|
436
|
-
});
|
|
437
|
-
```
|
|
438
|
-
|
|
439
|
-
#### Passing Data with Environment Variables
|
|
440
|
-
|
|
441
|
-
The `execute_browser_script` tool now supports passing data through `env` and `outputs` parameters:
|
|
442
|
-
|
|
443
|
-
```javascript
|
|
444
|
-
// Step 1: Set environment variables in JavaScript
|
|
445
|
-
run_command({
|
|
446
|
-
engine: "javascript",
|
|
447
|
-
run: `
|
|
448
|
-
return {
|
|
449
|
-
set_env: {
|
|
450
|
-
userName: 'John Doe',
|
|
451
|
-
userId: '12345',
|
|
452
|
-
apiKey: 'secret-key'
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
`,
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
// Step 2: Use environment variables in browser script
|
|
459
|
-
execute_browser_script({
|
|
460
|
-
selector: "role:Window",
|
|
461
|
-
env: {
|
|
462
|
-
userName: "{{env.userName}}",
|
|
463
|
-
userId: "{{env.userId}}",
|
|
464
|
-
},
|
|
465
|
-
script: `
|
|
466
|
-
// Parse env if it's a JSON string (for backward compatibility)
|
|
467
|
-
const parsedEnv = typeof env === 'string' ? JSON.parse(env) : env;
|
|
468
|
-
|
|
469
|
-
// Use the data - traditional way
|
|
470
|
-
console.log('Processing user:', parsedEnv.userName);
|
|
471
|
-
|
|
472
|
-
// NEW: Direct variable access also works!
|
|
473
|
-
console.log('Processing user:', userName); // Direct access
|
|
474
|
-
console.log('User ID:', userId); // No env prefix needed
|
|
475
|
-
|
|
476
|
-
// Fill form with data
|
|
477
|
-
document.querySelector('#username').value = userName;
|
|
478
|
-
document.querySelector('#userid').value = userId;
|
|
479
|
-
|
|
480
|
-
// Return result and set new variables
|
|
481
|
-
JSON.stringify({
|
|
482
|
-
status: 'form_filled',
|
|
483
|
-
set_env: {
|
|
484
|
-
form_submitted: 'true',
|
|
485
|
-
timestamp: new Date().toISOString()
|
|
486
|
-
}
|
|
487
|
-
});
|
|
488
|
-
`,
|
|
489
|
-
});
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
#### Loading Scripts from Files
|
|
493
|
-
|
|
494
|
-
You can load JavaScript from external files using the `script_file` parameter:
|
|
495
|
-
|
|
496
|
-
```javascript
|
|
497
|
-
// browser_scripts/extract_data.js
|
|
498
|
-
const parsedEnv = typeof env === "string" ? JSON.parse(env) : env;
|
|
499
|
-
const parsedOutputs =
|
|
500
|
-
typeof outputs === "string" ? JSON.parse(outputs) : outputs;
|
|
501
|
-
|
|
502
|
-
console.log("Script loaded from file");
|
|
503
|
-
console.log("User:", parsedEnv?.userName);
|
|
504
|
-
console.log("Previous result:", parsedOutputs?.previousStep);
|
|
505
|
-
|
|
506
|
-
// Extract and return data
|
|
507
|
-
JSON.stringify({
|
|
508
|
-
extractedData: {
|
|
509
|
-
url: window.location.href,
|
|
510
|
-
title: document.title,
|
|
511
|
-
forms: document.forms.length,
|
|
512
|
-
},
|
|
513
|
-
set_env: {
|
|
514
|
-
extraction_complete: "true",
|
|
515
|
-
},
|
|
516
|
-
});
|
|
517
|
-
|
|
518
|
-
// In your workflow:
|
|
519
|
-
execute_browser_script({
|
|
520
|
-
selector: "role:Window",
|
|
521
|
-
script_file: "browser_scripts/extract_data.js",
|
|
522
|
-
env: {
|
|
523
|
-
userName: "{{env.userName}}",
|
|
524
|
-
previousStep: "{{env.previousStep}}",
|
|
525
|
-
},
|
|
526
|
-
});
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
#### Important Notes
|
|
530
|
-
|
|
531
|
-
1. **Chrome Extension Required**: The `execute_browser_script` tool requires the Terminator browser extension to be installed. See the installation workflow examples for automated setup.
|
|
532
|
-
|
|
533
|
-
2. **Security Considerations**: Be cautious when extracting sensitive data. The examples above redact password fields and you should follow similar practices.
|
|
534
|
-
|
|
535
|
-
3. **Performance**: DOM operations are synchronous and can be slow on large pages. Consider using specific selectors rather than traversing the entire DOM.
|
|
536
|
-
|
|
537
|
-
4. **Error Handling**: Always wrap complex DOM operations in try-catch blocks and return meaningful error messages.
|
|
538
|
-
|
|
539
|
-
5. **Data Injection**: When using `env` or `outputs` parameters, they are injected as JavaScript variables at the beginning of your script. Always parse them if they might be JSON strings.
|
|
270
|
+
1. **Single Source of Truth**: Documentation stays synchronized with implementation
|
|
271
|
+
2. **No Duplication**: Update once, accurate everywhere
|
|
272
|
+
3. **Always Current**: Code changes include documentation updates
|
|
273
|
+
4. **Type Safe**: Parameter schemas embedded in code
|
|
540
274
|
|
|
541
275
|
## Local Development
|
|
542
276
|
|
|
@@ -859,15 +593,16 @@ You can run specific portions of a workflow using `start_from_step` and `end_at_
|
|
|
859
593
|
"tool_name": "execute_sequence",
|
|
860
594
|
"arguments": {
|
|
861
595
|
"url": "file://path/to/workflow.yml",
|
|
862
|
-
"start_from_step": "read_json_file",
|
|
863
|
-
"end_at_step": "fill_journal_entries",
|
|
864
|
-
"follow_fallback": false,
|
|
865
|
-
"execute_jumps_at_end": false
|
|
596
|
+
"start_from_step": "read_json_file", // Start from this step ID
|
|
597
|
+
"end_at_step": "fill_journal_entries", // Stop after this step (inclusive)
|
|
598
|
+
"follow_fallback": false, // Don't follow fallback_id beyond end_at_step (default: false)
|
|
599
|
+
"execute_jumps_at_end": false // Don't execute jumps at end_at_step boundary (default: false)
|
|
866
600
|
}
|
|
867
601
|
}
|
|
868
602
|
```
|
|
869
603
|
|
|
870
604
|
**Examples:**
|
|
605
|
+
|
|
871
606
|
- Run single step: Set both `start_from_step` and `end_at_step` to the same ID
|
|
872
607
|
- Run step range: Set different IDs for start and end
|
|
873
608
|
- Run from step to end: Only set `start_from_step`
|
|
@@ -877,14 +612,15 @@ You can run specific portions of a workflow using `start_from_step` and `end_at_
|
|
|
877
612
|
|
|
878
613
|
#### Automatic State Persistence
|
|
879
614
|
|
|
880
|
-
When using `file://` URLs, the workflow state (environment variables) is automatically saved to a `.
|
|
615
|
+
When using `file://` URLs, the workflow state (environment variables) is automatically saved to a `.mediar` folder:
|
|
881
616
|
|
|
882
617
|
1. **State is saved** after each step that modifies environment variables via `set_env` or has a tool result with an ID
|
|
883
618
|
2. **State is loaded** when starting from a specific step
|
|
884
|
-
3. **Location**: `.
|
|
619
|
+
3. **Location**: `.mediar/workflows/<workflow_name>/state.json` in the workflow's directory
|
|
885
620
|
4. **Tool results** from all tools (not just scripts) are automatically stored as `{step_id}_result` and `{step_id}_status`
|
|
886
621
|
|
|
887
622
|
This enables:
|
|
623
|
+
|
|
888
624
|
- **Debugging**: Run steps individually to inspect state between executions
|
|
889
625
|
- **Recovery**: Resume failed workflows from the last successful step
|
|
890
626
|
- **Testing**: Test specific steps without re-running the entire workflow
|
|
@@ -947,12 +683,12 @@ return {
|
|
|
947
683
|
set_env: {
|
|
948
684
|
file_path: "C:/data/input.json",
|
|
949
685
|
journal_entries: JSON.stringify(entries),
|
|
950
|
-
total_debit: "100.50"
|
|
951
|
-
}
|
|
686
|
+
total_debit: "100.50",
|
|
687
|
+
},
|
|
952
688
|
};
|
|
953
689
|
|
|
954
690
|
// Step 13: Use the data (NEW - simplified access!)
|
|
955
|
-
const filePath = file_path;
|
|
691
|
+
const filePath = file_path; // Direct access, no {{env.}} needed!
|
|
956
692
|
const entries = JSON.parse(journal_entries);
|
|
957
693
|
const debit = total_debit;
|
|
958
694
|
```
|
|
@@ -1023,6 +759,7 @@ steps:
|
|
|
1023
759
|
```
|
|
1024
760
|
|
|
1025
761
|
Tool results are accessible as:
|
|
762
|
+
|
|
1026
763
|
- `{step_id}_result`: The tool's return value (content, element info, etc.)
|
|
1027
764
|
- `{step_id}_status`: Either "success" or "error"
|
|
1028
765
|
|
|
@@ -1039,6 +776,7 @@ Tool results are accessible as:
|
|
|
1039
776
|
### Finding MCP Server Logs
|
|
1040
777
|
|
|
1041
778
|
MCP logs are saved to:
|
|
779
|
+
|
|
1042
780
|
- **Windows:** `%LOCALAPPDATA%\claude-cli-nodejs\Cache\<encoded-project-path>\mcp-logs-terminator-mcp-agent\`
|
|
1043
781
|
- **macOS/Linux:** `~/.local/share/claude-cli-nodejs/Cache/<encoded-project-path>/mcp-logs-terminator-mcp-agent/`
|
|
1044
782
|
|
|
@@ -1046,6 +784,7 @@ Where `<encoded-project-path>` is your project path with special chars replaced
|
|
|
1046
784
|
Note: Logs are saved as `.txt` files, not `.log` files.
|
|
1047
785
|
|
|
1048
786
|
**Read logs:**
|
|
787
|
+
|
|
1049
788
|
```powershell
|
|
1050
789
|
# Windows - Find and read latest logs (run in PowerShell)
|
|
1051
790
|
Get-ChildItem (Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'claude-cli-nodejs\Cache\*\mcp-logs-terminator-mcp-agent\*.txt') | Sort-Object LastWriteTime -Descending | Select-Object -First 1 | Get-Content -Tail 50
|
|
@@ -1054,14 +793,15 @@ Get-ChildItem (Join-Path ([Environment]::GetFolderPath('LocalApplicationData'))
|
|
|
1054
793
|
### Enable Debug Logging
|
|
1055
794
|
|
|
1056
795
|
In your Claude MCP configuration (`claude_desktop_config.json`):
|
|
796
|
+
|
|
1057
797
|
```json
|
|
1058
798
|
{
|
|
1059
799
|
"mcpServers": {
|
|
1060
800
|
"terminator-mcp-agent": {
|
|
1061
801
|
"command": "path/to/terminator-mcp-agent",
|
|
1062
802
|
"env": {
|
|
1063
|
-
"LOG_LEVEL": "debug",
|
|
1064
|
-
"RUST_BACKTRACE": "1"
|
|
803
|
+
"LOG_LEVEL": "debug", // or "info", "warn", "error"
|
|
804
|
+
"RUST_BACKTRACE": "1" // for stack traces on errors
|
|
1065
805
|
}
|
|
1066
806
|
}
|
|
1067
807
|
}
|
|
@@ -1070,17 +810,18 @@ In your Claude MCP configuration (`claude_desktop_config.json`):
|
|
|
1070
810
|
|
|
1071
811
|
### Common Debug Scenarios
|
|
1072
812
|
|
|
1073
|
-
| Issue
|
|
1074
|
-
|
|
1075
|
-
| Workflow failures
|
|
1076
|
-
| Element not found
|
|
813
|
+
| Issue | What to Look For in Logs |
|
|
814
|
+
| --------------------- | ----------------------------------------------------------------- |
|
|
815
|
+
| Workflow failures | Search for `fallback_id` triggers and `critical_error_occurred` |
|
|
816
|
+
| Element not found | Look for selector resolution attempts, `find_element` timeouts |
|
|
1077
817
|
| Browser script errors | Check for `EVAL_ERROR`, Promise rejections, JavaScript exceptions |
|
|
1078
|
-
| Binary version issues | Startup logs show binary path and build timestamp
|
|
1079
|
-
| MCP connection lost
|
|
818
|
+
| Binary version issues | Startup logs show binary path and build timestamp |
|
|
819
|
+
| MCP connection lost | Check for panic messages, ensure binary path is correct |
|
|
1080
820
|
|
|
1081
821
|
### Fallback Mechanism
|
|
1082
822
|
|
|
1083
823
|
Workflows support `fallback_id` to handle errors gracefully:
|
|
824
|
+
|
|
1084
825
|
- If a step fails and has `fallback_id`, it jumps to that step instead of stopping
|
|
1085
826
|
- Without `fallback_id`, errors may set `critical_error_occurred` and skip remaining steps
|
|
1086
827
|
- Use `troubleshooting:` section for recovery steps only accessed via fallback
|
package/index.js
CHANGED
|
@@ -138,7 +138,7 @@ if (argv.includes("--add-to-app")) {
|
|
|
138
138
|
// Filter out --start if it exists, as it's for the wrapper script
|
|
139
139
|
const agentArgs = argv.filter((arg) => arg !== "--start");
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
let child = spawn(binary, agentArgs, {
|
|
142
142
|
stdio: ["pipe", "pipe", "pipe"],
|
|
143
143
|
shell: false,
|
|
144
144
|
detached: process.platform !== "win32",
|
|
@@ -195,11 +195,17 @@ if (argv.includes("--add-to-app")) {
|
|
|
195
195
|
const MAX_RESTART_ATTEMPTS = 3;
|
|
196
196
|
const RESTART_DELAY = 1000; // 1 second
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
// Named function for exit handler so it can be reused
|
|
199
|
+
function handleChildExit(code, signal) {
|
|
199
200
|
// Check for stack overflow exit code on Windows (3221225725 = 0xC00000FD)
|
|
200
201
|
const isStackOverflow = code === 3221225725 || code === -1073741571;
|
|
201
202
|
|
|
202
|
-
if (code
|
|
203
|
+
// Restart if process exited abnormally (non-zero code or killed by signal)
|
|
204
|
+
// Don't restart on normal exit (code === 0) or if we're shutting down
|
|
205
|
+
// Note: code can be null when killed by signal, and signal is set
|
|
206
|
+
const isAbnormalExit = code !== 0 || signal !== null;
|
|
207
|
+
|
|
208
|
+
if (isAbnormalExit && !shuttingDown) {
|
|
203
209
|
console.error(`[MCP exited with code ${code}${signal ? ` (signal: ${signal})` : ''}]`);
|
|
204
210
|
|
|
205
211
|
// Auto-restart on crash if under max attempts
|
|
@@ -213,8 +219,22 @@ if (argv.includes("--add-to-app")) {
|
|
|
213
219
|
console.error(`[Attempting to restart MCP server (attempt ${restartAttempts}/${MAX_RESTART_ATTEMPTS})...]`);
|
|
214
220
|
|
|
215
221
|
setTimeout(() => {
|
|
222
|
+
if (shuttingDown) {
|
|
223
|
+
// Don't restart if we're shutting down
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
216
227
|
console.error(`[Restarting MCP server...]`);
|
|
217
228
|
|
|
229
|
+
// Clean up old pipes safely
|
|
230
|
+
try {
|
|
231
|
+
if (child && child.stdin) {
|
|
232
|
+
process.stdin.unpipe(child.stdin);
|
|
233
|
+
}
|
|
234
|
+
} catch (e) {
|
|
235
|
+
// Ignore errors if pipes are already closed
|
|
236
|
+
}
|
|
237
|
+
|
|
218
238
|
// Spawn new process
|
|
219
239
|
const newChild = spawn(binary, agentArgs, {
|
|
220
240
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -223,16 +243,20 @@ if (argv.includes("--add-to-app")) {
|
|
|
223
243
|
});
|
|
224
244
|
|
|
225
245
|
// Reconnect pipes
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
246
|
+
try {
|
|
247
|
+
process.stdin.pipe(newChild.stdin);
|
|
248
|
+
newChild.stdout.pipe(process.stdout);
|
|
249
|
+
newChild.stderr.pipe(process.stderr);
|
|
250
|
+
} catch (e) {
|
|
251
|
+
console.error(`[Error reconnecting pipes: ${e.message}]`);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
230
254
|
|
|
231
255
|
// Replace child reference
|
|
232
256
|
child = newChild;
|
|
233
257
|
|
|
234
|
-
// Reattach exit handler
|
|
235
|
-
child.on("exit",
|
|
258
|
+
// Reattach exit handler
|
|
259
|
+
child.on("exit", handleChildExit);
|
|
236
260
|
|
|
237
261
|
console.error(`[MCP server restarted successfully]`);
|
|
238
262
|
}, RESTART_DELAY);
|
|
@@ -244,5 +268,7 @@ if (argv.includes("--add-to-app")) {
|
|
|
244
268
|
}
|
|
245
269
|
|
|
246
270
|
process.exit(code);
|
|
247
|
-
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
child.on("exit", handleChildExit);
|
|
248
274
|
}
|
package/package.json
CHANGED
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
],
|
|
17
17
|
"name": "terminator-mcp-agent",
|
|
18
18
|
"optionalDependencies": {
|
|
19
|
-
"terminator-mcp-darwin-arm64": "0.22.
|
|
20
|
-
"terminator-mcp-darwin-x64": "0.22.
|
|
21
|
-
"terminator-mcp-linux-x64-gnu": "0.22.
|
|
22
|
-
"terminator-mcp-win32-arm64-msvc": "0.22.
|
|
23
|
-
"terminator-mcp-win32-x64-msvc": "0.22.
|
|
19
|
+
"terminator-mcp-darwin-arm64": "0.22.20",
|
|
20
|
+
"terminator-mcp-darwin-x64": "0.22.20",
|
|
21
|
+
"terminator-mcp-linux-x64-gnu": "0.22.20",
|
|
22
|
+
"terminator-mcp-win32-arm64-msvc": "0.22.20",
|
|
23
|
+
"terminator-mcp-win32-x64-msvc": "0.22.20"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
@@ -32,5 +32,5 @@
|
|
|
32
32
|
"sync-version": "node ./utils/sync-version.js",
|
|
33
33
|
"update-badges": "node ./utils/update-badges.js"
|
|
34
34
|
},
|
|
35
|
-
"version": "0.22.
|
|
35
|
+
"version": "0.22.20"
|
|
36
36
|
}
|