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.
Files changed (3) hide show
  1. package/README.md +56 -315
  2. package/index.js +36 -10
  3. 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
- ### Core Workflows: From Interaction to Structured Data
230
+ ## Tool Documentation
231
231
 
232
- The Terminator MCP agent offers two primary workflows for automating desktop tasks. Both paths lead to the same goal: creating a >95% accuracy, 10000x faster than humans, automation.
232
+ All tool documentation is maintained as **source of truth in the codebase** to ensure accuracy and prevent duplication.
233
233
 
234
- #### 1. Iterative Development with `execute_sequence`
234
+ ### Where to Find Tool Documentation
235
235
 
236
- This is the most powerful and flexible method. You build a workflow step-by-step, using MCP tools to inspect the UI and refine your actions.
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
- 1. **Inspect the UI**: Start by using `get_focused_window_tree` to understand the structure of your target application. This gives you the roles, names, and IDs of all elements. For performance optimization:
239
- - Use `tree_max_depth: 30` to limit tree depth when you only need shallow inspection
240
- - Use `tree_from_selector: "role:Dialog"` to get subtree from a specific element
241
- - Use `tree_from_selector: "true"` to start from the currently focused element
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
- Here is an example of an `output_parser` that extracts insurance quote data from a web page:
246
+ **Tool Index**:
247
+ - See [**Tool Reference Guide**](../../docs/TOOL_REFERENCE.md) for a complete index with line numbers
248
248
 
249
- ```yaml
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
- #### 2. Recording Human Actions with `record_workflow`
251
+ **Find a tool**: Search `server.rs` for the tool name (e.g., `click_element`, `run_command`)
305
252
 
306
- For simpler tasks, you can record your own actions to generate a baseline workflow.
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
- 1. **Start Recording**: Call `record_workflow` with `action: "start"`.
309
- 2. **Perform the Task**: Manually perform the clicks, typing, and other interactions in the target application.
310
- 3. **Stop and Save**: Call `record_workflow` with `action: "stop"`. This returns a complete workflow JSON file containing all your recorded actions.
311
- 4. **Refine and Parse**: The recorded workflow is a great starting point. You can then refine the selectors for robustness, add a final step to capture the UI tree, and attach an `output_parser` to extract structured data, just as you would in the iterative workflow.
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
- ### Browser DOM Inspection
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
- The `execute_browser_script` tool enables direct JavaScript execution in browser contexts, providing access to the full HTML DOM. This is particularly useful when you need information not available in the accessibility tree.
268
+ ### Why Source Code Documentation?
316
269
 
317
- #### When to Use DOM vs Accessibility Tree
318
-
319
- **Use Accessibility Tree (default) when:**
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", // Start from this step ID
863
- "end_at_step": "fill_journal_entries", // Stop after this step (inclusive)
864
- "follow_fallback": false, // Don't follow fallback_id beyond end_at_step (default: false)
865
- "execute_jumps_at_end": false // Don't execute jumps at end_at_step boundary (default: 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 `.workflow_state` folder:
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**: `.workflow_state/<workflow_hash>.json` in the workflow's directory
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; // Direct access, no {{env.}} needed!
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", // or "info", "warn", "error"
1064
- "RUST_BACKTRACE": "1" // for stack traces on errors
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 | What to Look For in Logs |
1074
- |-------|--------------------------|
1075
- | Workflow failures | Search for `fallback_id` triggers and `critical_error_occurred` |
1076
- | Element not found | Look for selector resolution attempts, `find_element` timeouts |
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 | Check for panic messages, ensure binary path is correct |
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
- const child = spawn(binary, agentArgs, {
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
- child.on("exit", (code, signal) => {
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 !== 0 && !shuttingDown) {
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
- process.stdin.unpipe(child.stdin);
227
- process.stdin.pipe(newChild.stdin);
228
- newChild.stdout.pipe(process.stdout);
229
- newChild.stderr.pipe(process.stderr);
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 with same logic
235
- child.on("exit", arguments.callee);
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.16",
20
- "terminator-mcp-darwin-x64": "0.22.16",
21
- "terminator-mcp-linux-x64-gnu": "0.22.16",
22
- "terminator-mcp-win32-arm64-msvc": "0.22.16",
23
- "terminator-mcp-win32-x64-msvc": "0.22.16"
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.16"
35
+ "version": "0.22.20"
36
36
  }