@minicor/mcp-server 2.0.2 → 2.0.4

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 (50) hide show
  1. package/README.md +102 -124
  2. package/dist/__tests__/helpers.test.js +3 -3
  3. package/dist/config.d.ts +3 -13
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +4 -30
  6. package/dist/config.js.map +1 -1
  7. package/dist/helpers.d.ts +2 -5
  8. package/dist/helpers.d.ts.map +1 -1
  9. package/dist/helpers.js +7 -35
  10. package/dist/helpers.js.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +3 -36
  14. package/dist/index.js.map +1 -1
  15. package/dist/inspect-scripts.d.ts +1 -1
  16. package/dist/inspect-scripts.js +1 -1
  17. package/dist/lds-client.d.ts +1 -1
  18. package/dist/lds-client.js +2 -2
  19. package/dist/prompts/build-nerve-rpa.d.ts +3 -0
  20. package/dist/prompts/build-nerve-rpa.d.ts.map +1 -0
  21. package/dist/prompts/build-nerve-rpa.js +148 -0
  22. package/dist/prompts/build-nerve-rpa.js.map +1 -0
  23. package/dist/prompts/build-rpa.d.ts.map +1 -1
  24. package/dist/prompts/build-rpa.js +153 -22
  25. package/dist/prompts/build-rpa.js.map +1 -1
  26. package/dist/prompts/debug-execution.d.ts.map +1 -1
  27. package/dist/prompts/debug-execution.js +22 -1
  28. package/dist/prompts/debug-execution.js.map +1 -1
  29. package/dist/prompts/workflow-guide.d.ts.map +1 -1
  30. package/dist/prompts/workflow-guide.js +3 -14
  31. package/dist/prompts/workflow-guide.js.map +1 -1
  32. package/dist/setup.js +19 -83
  33. package/dist/setup.js.map +1 -1
  34. package/dist/state.d.ts +0 -9
  35. package/dist/state.d.ts.map +1 -1
  36. package/dist/state.js +0 -9
  37. package/dist/state.js.map +1 -1
  38. package/dist/tools/core.d.ts.map +1 -1
  39. package/dist/tools/core.js +0 -7
  40. package/dist/tools/core.js.map +1 -1
  41. package/dist/tools/vm-rpa.d.ts.map +1 -1
  42. package/dist/tools/vm-rpa.js +72 -15
  43. package/dist/tools/vm-rpa.js.map +1 -1
  44. package/dist/tools/vm.d.ts.map +1 -1
  45. package/dist/tools/vm.js +19 -8
  46. package/dist/tools/vm.js.map +1 -1
  47. package/dist/tools/workflow-ops.js +1 -1
  48. package/dist/types.d.ts +0 -3
  49. package/dist/types.d.ts.map +1 -1
  50. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Stateless HTTP client for the Laminar Desktop Service (LDS).
2
+ * Stateless HTTP client for the Minicor Desktop Service (MDS).
3
3
  *
4
4
  * Every method receives the base URL (Cloudflare Tunnel) and optional auth
5
5
  * credentials so the caller (tool handler) can pull them from session state.
@@ -19,7 +19,7 @@ async function request(url, init) {
19
19
  const res = await fetch(url, init);
20
20
  if (!res.ok) {
21
21
  const body = await res.text().catch(() => "");
22
- throw new Error(`LDS ${init?.method ?? "GET"} ${url} returned ${res.status}: ${body}`);
22
+ throw new Error(`MDS ${init?.method ?? "GET"} ${url} returned ${res.status}: ${body}`);
23
23
  }
24
24
  return res.json();
25
25
  }
@@ -0,0 +1,3 @@
1
+ import type { ToolDeps } from "../types.js";
2
+ export declare function register({ server }: ToolDeps): void;
3
+ //# sourceMappingURL=build-nerve-rpa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-nerve-rpa.d.ts","sourceRoot":"","sources":["../../src/prompts/build-nerve-rpa.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,QAAQ,QAsJ5C"}
@@ -0,0 +1,148 @@
1
+ import { z } from "zod";
2
+ export function register({ server }) {
3
+ server.prompt("build-nerve-rpa-workflow", "Build an RPA workflow using NERVE's atomic operations: annotated screenshots, element clicking/typing, CDP browser control, OCR, and self-healing. Optimized for NERVE (not legacy LDS).", {
4
+ workspaceId: z.string().describe("Laminar workspace ID"),
5
+ task: z.string().describe("What to automate"),
6
+ appName: z.string().describe("Target application name"),
7
+ workflowId: z.string().optional().describe("Existing workflow ID to add steps to"),
8
+ }, async ({ workspaceId, task, appName, workflowId }) => ({
9
+ messages: [
10
+ {
11
+ role: "user",
12
+ content: {
13
+ type: "text",
14
+ text: `You are building an RPA workflow using NERVE on the Laminar platform. NERVE gives you direct atomic control over the Windows desktop — you do NOT need to write Python scripts for simple interactions.
15
+
16
+ ## Task
17
+ ${task}
18
+
19
+ ## Target Application
20
+ ${appName}
21
+
22
+ ## Workspace
23
+ ID: ${workspaceId}${workflowId ? `\nExisting workflow ID: ${workflowId}` : "\nCreate a new workflow for this automation."}
24
+
25
+ ## How NERVE Works
26
+
27
+ NERVE runs on the VM and exposes the full OS via HTTP APIs. When you call \`vm_connect\`, check the \`capabilities\` array in the response to see what's available.
28
+
29
+ Key capabilities:
30
+ - \`annotated_screenshots\` — X-Ray Vision: screenshot with numbered element overlays
31
+ - \`ui_tree_cache\` — Persistent accessibility tree
32
+ - \`atomic_input\` — Click/type/invoke by element ID
33
+ - \`script_execution\` — Run Python scripts
34
+ - \`cdp\` — Chrome DevTools Protocol for browser control
35
+ - \`ocr\` / \`template_matching\` — For Citrix/pixel-based apps
36
+ - \`self_healing\` — Pause on error + intervention
37
+
38
+ ## Step 1: Connect and Survey
39
+
40
+ 1. \`vm_connect\` — connect to the VM
41
+ 2. Check \`capabilities\` in the response
42
+ 3. \`vm_annotated_screenshot\` — see the desktop with numbered elements
43
+ 4. \`vm_system_info\` — get OS, RAM, CPU info
44
+ 5. \`vm_processes\` — see what's running
45
+
46
+ ## Step 2: Understand the UI
47
+
48
+ Use the annotated screenshot to understand the screen. Each interactive element has a number:
49
+ \`\`\`
50
+ [1] Username field (Edit)
51
+ [2] Password field (Edit)
52
+ [3] OK button (Button)
53
+ [4] Cancel button (Button)
54
+ \`\`\`
55
+
56
+ For deeper inspection:
57
+ - \`vm_inspect_ui\` mode \`element_tree\` — full accessibility tree
58
+ - \`vm_inspect_ui\` mode \`element_at_point\` — inspect specific coordinates
59
+
60
+ ## Step 3: Interact with Atomic Operations
61
+
62
+ **DO NOT write Python scripts for simple click/type operations.** Use atomic tools:
63
+
64
+ - \`vm_click_element\` {element_id: 3} — click element #3 from annotated screenshot
65
+ - \`vm_type_into_element\` {element_id: 1, text: "admin"} — type into element #1
66
+ - \`vm_set_value\` {element_id: 2, value: "password"} — set value directly
67
+ - \`vm_invoke_element\` {element_id: 3} — invoke button via accessibility pattern
68
+ - \`vm_shell\` {command: "Start-Process notepad"} — run commands
69
+
70
+ After each action, take another \`vm_annotated_screenshot\` to verify it worked.
71
+
72
+ ## Step 4: For Web Apps — Use CDP
73
+
74
+ If the target is a browser or Electron app:
75
+
76
+ 1. \`cdp_connect\` — connect to Chrome/Edge DevTools
77
+ 2. \`cdp_dom\` — get the full DOM tree
78
+ 3. \`cdp_query\` {selector: "#username"} — find elements by CSS
79
+ 4. \`cdp_click\` {selector: "#login-btn"} — click via DOM
80
+ 5. \`cdp_type\` {selector: "#email", text: "user@example.com"} — type via DOM
81
+ 6. \`cdp_js\` — execute arbitrary JavaScript
82
+ 7. \`cdp_network\` — see API calls the app makes
83
+
84
+ CDP is MORE RELIABLE than screen-based automation for web apps.
85
+
86
+ ## Step 5: For Citrix / Legacy Apps — Use OCR + Template Matching
87
+
88
+ When there's no accessibility tree (Citrix, RDP, custom-rendered apps):
89
+
90
+ 1. \`vm_ocr\` {x, y, width, height} — read text from a screen region
91
+ 2. \`vm_template_match\` {template_b64: "..."} — find a visual element
92
+ 3. \`vm_wait_for_text\` {text: "Login", region: {...}} — wait for text to appear
93
+ 4. \`vm_wait_for_change\` {region: {...}} — wait for visual change (replaces sleep)
94
+ 5. \`vm_region_ocr\` {regions: [...]} — batch OCR multiple fields
95
+ 6. Click by coordinates from template match results
96
+
97
+ ## Step 6: Build Production Scripts
98
+
99
+ Once you understand the UI and have tested atomic operations, consolidate into Python scripts for production:
100
+
101
+ 1. Write a Python script that performs the full sequence
102
+ 2. Test with \`debug_rpa_step\` — returns before/after screenshots + timeline
103
+ 3. Save with \`create_rpa_flow\` — wraps Python in Laminar workflow format
104
+
105
+ ## Step 7: Self-Healing Pattern
106
+
107
+ For robust automations, enable self-healing:
108
+
109
+ 1. Execute with \`on_error: "pause"\` — script pauses at failure instead of crashing
110
+ 2. \`vm_failure_context\` — get screenshot, UI tree, error details at failure point
111
+ 3. \`vm_annotated_screenshot\` — see current screen state
112
+ 4. Fix with atomic operations (\`vm_click_element\`, etc.)
113
+ 5. Resume execution
114
+
115
+ ## Step 8: End-to-End Validation
116
+
117
+ 1. \`execute_workflow\` to run the full sequence
118
+ 2. \`vm_annotated_screenshot\` to verify final state
119
+ 3. \`vm_execution_timeline\` to review frame-by-frame what happened
120
+ 4. \`diagnose_execution\` if anything fails
121
+
122
+ ## Data Extraction Priority
123
+
124
+ When you need to READ data from the screen:
125
+
126
+ 1. **Accessibility tree** — \`vm_inspect_ui\` with \`element_tree\` (most reliable)
127
+ 2. **Focused element** — Tab through fields, read via \`vm_inspect_ui\` \`focused_element\`
128
+ 3. **Clipboard** — Click field, Ctrl+A, Ctrl+C, then \`vm_read_clipboard\`
129
+ 4. **OCR** — \`vm_ocr\` on a specific region
130
+ 5. **CDP extraction** — \`cdp_js\` to read DOM values (for web apps)
131
+ 6. **Region screenshot** — \`vm_screenshot\` of a specific area (last resort)
132
+
133
+ ## Key Rules
134
+
135
+ - **Annotated screenshots FIRST** — always start by seeing the screen with element IDs
136
+ - **Atomic ops for exploration** — use click/type tools to test, scripts for production
137
+ - **Verify after every action** — take another annotated screenshot
138
+ - **Never hardcode coordinates** — use element IDs or accessibility patterns
139
+ - **Use wait_for_text/wait_for_change** — never use time.sleep() for synchronization
140
+ - **Use \`create_rpa_flow\`** to save steps — never construct JS wrappers manually
141
+ - **Use \`{{config.variables}}\`** for secrets — never hardcode credentials
142
+ `,
143
+ },
144
+ },
145
+ ],
146
+ }));
147
+ }
148
+ //# sourceMappingURL=build-nerve-rpa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-nerve-rpa.js","sourceRoot":"","sources":["../../src/prompts/build-nerve-rpa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAY;IAC3C,MAAM,CAAC,MAAM,CACX,0BAA0B,EAC1B,0LAA0L,EAC1L;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACxD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAC7C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QACvD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;KACnF,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;QACrD,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;EAGhB,IAAI;;;EAGJ,OAAO;;;MAGH,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,2BAA2B,UAAU,EAAE,CAAC,CAAC,CAAC,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuHxH;iBACU;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"build-rpa.d.ts","sourceRoot":"","sources":["../../src/prompts/build-rpa.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,QAAQ,QAgL5C"}
1
+ {"version":3,"file":"build-rpa.d.ts","sourceRoot":"","sources":["../../src/prompts/build-rpa.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,QAAQ,QAmT5C"}
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  export function register({ server }) {
3
- server.prompt("build-rpa-workflow", "Iteratively build an RPA workflow on a VM using the Laminar Desktop Service. Guides you through connecting to the VM, researching the target app's UI framework, taking screenshots, inspecting UI elements, writing and testing RPA scripts, and saving each working step as a Laminar workflow flow.", {
4
- workspaceId: z.string().describe("Laminar workspace ID"),
3
+ server.prompt("build-rpa-workflow", "Iteratively build an RPA workflow on a VM using the Minicor Desktop Service. Guides you through connecting to the VM, researching the target app's UI framework, taking screenshots, inspecting UI elements, writing and testing RPA scripts, and saving each working step as a Minicor workflow flow.", {
4
+ workspaceId: z.string().describe("Minicor workspace ID"),
5
5
  task: z
6
6
  .string()
7
7
  .describe("Description of what to automate (e.g. 'Log into Centricity, navigate to Documents, download the latest report')"),
@@ -18,7 +18,7 @@ export function register({ server }) {
18
18
  role: "user",
19
19
  content: {
20
20
  type: "text",
21
- text: `You are building an RPA workflow on the Laminar platform. Your goal is to iteratively create automation steps that run on a VM via the Laminar Desktop Service (LDS).
21
+ text: `You are building an RPA workflow on the Minicor platform. Your goal is to iteratively create automation steps that run on a VM via the Minicor Desktop Service (MDS).
22
22
 
23
23
  ## Task
24
24
  ${task}
@@ -38,26 +38,112 @@ ID: ${workspaceId}${workflowId ? `\nExisting workflow ID: ${workflowId} (add ste
38
38
  3. Only then → save via \`create_rpa_flow\`
39
39
 
40
40
  ### Rule 2 — USE \`create_rpa_flow\` TO SAVE (NOT \`create_flow\`)
41
- When saving an RPA step, call **\`create_rpa_flow\`** — it automatically wraps your Python script in the correct Laminar JS format. You only pass the Python script; the tool handles the \`lam.httpRequest\` / \`lam.rpa\` wrapper.
41
+ When saving an RPA step, call **\`create_rpa_flow\`** — it automatically wraps your Python script in the correct Minicor JS format. You only pass the Python script; the tool handles the \`lam.httpRequest\` / \`lam.rpa\` wrapper.
42
42
 
43
43
  **NEVER** call \`create_flow\` with raw Python for an RPA step. **NEVER** try to construct the JS wrapper yourself.
44
44
 
45
45
  ### Rule 3 — COMBINE ui_inspect + screenshots + clipboard
46
46
  Screenshots alone are unreliable for reading data (resolution issues, misreads). ALWAYS combine multiple methods. See the Data Extraction Strategy section below.
47
47
 
48
- ## Procedure
48
+ ## Strategy Selection (BEFORE writing any automation)
49
49
 
50
- ### 1. Connect to the VM
51
- If no VM is connected, ask for the **Cloudflare Tunnel URL** and call \`vm_connect\`.
50
+ ### For Web/Browser Targets:
51
+ - Use **CDP via Python websocket** for page manipulation (fastest, most reliable for anti-bot sites)
52
+ - The MDS provides an isolated Chrome instance per execution via \`/execute/browser\`
53
+ - Multiple browser automations run **in parallel** on the same VM — each gets its own Chrome
54
+ - Scripts always use \`127.0.0.1:9222\` — the MDS transparently routes to the correct Chrome instance
55
+ - Use CDP \`Page.captureScreenshot\` for screenshots within the browser tab
56
+ - Check if the site has usable internal APIs (inspect network traffic via CDP \`fetch\` interception)
57
+ - If clean APIs exist and are stable → consider direct \`requests\`/\`httpx\` instead of UI automation
58
+ - If anti-bot protection exists (Cloudflare, reCAPTCHA) → CDP through the VM browser avoids detection
52
59
 
53
- ### 2. Research the Target Application
54
- Based on "${appName}", pick the UI automation framework:
60
+ ### For Desktop Targets:
55
61
  - **.NET / WPF / WinForms** → \`uiautomation\` (default) or \`pywinauto\`
56
62
  - **Java / Swing** → \`jab\` (Java Access Bridge)
57
- - **Electron / web-based desktop** → \`pywinauto\` or pyautogui
63
+ - **Electron / web-based desktop** → \`pywinauto\` or \`pyautogui\`
58
64
  - **Legacy Win32** → \`uiautomation\`
65
+ - Start with \`uiautomation\` if unsure.
66
+ - Desktop scripts use \`/execute\` and run **one at a time** per VM (the physical screen is shared)
67
+
68
+ ### Mixed Browser + Desktop (IMPORTANT)
69
+ Some browser automations need to interact with the physical screen — for example:
70
+ - Clicking OS-level alerts or confirmation dialogs
71
+ - File upload/download dialogs (native file picker)
72
+ - Browser notifications or permission prompts
73
+ - CAPTCHA solving that requires clicking outside the browser
74
+
75
+ **These automations CANNOT use \`/execute/browser\`** because they need the screen, which is shared.
76
+ Use \`/execute\` instead and treat them like desktop automations — they run one at a time per VM.
77
+
78
+ When building a workflow, determine which category it falls into:
79
+ - **Pure CDP** (all interaction via \`Runtime.evaluate\`, \`Page.navigate\`, etc.) → \`/execute/browser\` — parallel-safe
80
+ - **Needs screen interaction** (any \`pyautogui\`, OS dialogs, file pickers) → \`/execute\` — one at a time
81
+
82
+ ## Browser Automation via CDP (Python WebSocket)
83
+
84
+ Your Python scripts connect to Chrome via the Chrome DevTools Protocol. The MDS handles Chrome lifecycle and port routing transparently — scripts always use port 9222.
85
+
86
+ **Dispatch:** Use \`dispatchPattern: "browser"\` when saving with \`create_rpa_flow\`. This routes to \`/execute/browser\` which provides an isolated Chrome instance.
87
+
88
+ ### How CDP Works:
89
+ 1. Discover tabs: \`GET http://127.0.0.1:9222/json\`
90
+ 2. Connect via WebSocket to the target tab's \`webSocketDebuggerUrl\`
91
+ 3. Use \`Runtime.evaluate\` to execute JavaScript in the page context
92
+ 4. Use CDP \`Page.captureScreenshot\` for screenshots
93
+
94
+ ### CDP Starter Template:
95
+ \`\`\`python
96
+ import json, websocket, time
97
+ from urllib.request import urlopen
98
+
99
+ tabs = json.loads(urlopen('http://127.0.0.1:9222/json').read())
100
+ page_tab = [t for t in tabs if t.get('type') == 'page'][0]
101
+ ws = websocket.create_connection(page_tab['webSocketDebuggerUrl'])
102
+ cmd_id = 0
103
+
104
+ def cdp_eval(ws, js):
105
+ global cmd_id; cmd_id += 1
106
+ ws.send(json.dumps({'id': cmd_id, 'method': 'Runtime.evaluate', 'params': {'expression': js}}))
107
+ while True:
108
+ msg = json.loads(ws.recv())
109
+ if msg.get('id') == cmd_id: return msg
110
+
111
+ # Navigate
112
+ cdp_eval(ws, 'window.location.href="https://example.com"')
113
+ time.sleep(8)
114
+
115
+ # Fill input using React-safe setter (ALWAYS use this for React/Angular/Vue apps)
116
+ cdp_eval(ws, 'var s=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set;var inp=document.querySelector("input[type=email]");if(inp){s.call(inp,"user@example.com");inp.dispatchEvent(new Event("input",{bubbles:true}));inp.dispatchEvent(new Event("change",{bubbles:true}))}')
117
+
118
+ # Click button by text content (more resilient than CSS selectors)
119
+ cdp_eval(ws, 'document.querySelectorAll("button").forEach(function(b){if(b.textContent.trim()==="Submit"){b.click()}})')
120
+
121
+ ws.close()
122
+ \`\`\`
123
+
124
+ ### Key CDP Patterns:
125
+ - **React-safe value setter**: Always use \`Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set\` — direct \`.value=\` assignment does NOT trigger React/Angular change detection
126
+ - **Button clicks by text**: Use \`querySelectorAll("button").forEach()\` + \`textContent.trim()\` matching — more resilient than IDs or classes that change
127
+ - **Credentials**: Use \`\\\${username}\` / \`\\\${password}\` interpolated from JS wrapper variables sourced from \`{{config.xxx}}\` — NEVER hardcode
128
+ - **Waits**: \`time.sleep()\` between navigations (8-15s for page loads, 1-3s for UI actions)
129
+ - **Verification**: Use CDP \`Page.captureScreenshot\` for per-tab screenshots
130
+ - **Dropdown handling**: Click to open, then use \`querySelectorAll\` to find options by text and click
131
+ - **Tab management**: If multiple tabs open, filter \`/json\` response by URL or title
132
+
133
+ ### Parallel Execution Notes:
134
+ - \`/execute/browser\` runs your script with its own Chrome instance — multiple workflows can run at the same time on one VM
135
+ - \`/execute\` runs your script without Chrome — for desktop automation or mixed browser+desktop scripts
136
+ - The MDS transparently rewrites \`127.0.0.1:9222\` in your script to the correct Chrome port — you never need to handle ports
137
+ - Recordings from \`/execute/browser\` capture only the browser tab (CDP screencast), not the full desktop
138
+ - Recordings from \`/execute\` capture the full desktop (MSS screen recording)
139
+
140
+ ## Procedure
59
141
 
60
- Start with \`uiautomation\` if unsure.
142
+ ### 1. Connect to the VM
143
+ If no VM is connected, ask for the **Cloudflare Tunnel URL** and call \`vm_connect\`.
144
+
145
+ ### 2. Research the Target Application
146
+ Based on "${appName}", determine if it's a **web/browser** target or a **desktop** target using the Strategy Selection above.
61
147
 
62
148
  ### 3. Initial Survey (ALWAYS do this first)
63
149
  Before writing any automation:
@@ -90,17 +176,58 @@ Before writing any automation:
90
176
  **e. SAVE — Call \`create_rpa_flow\` (only after c + d pass)**
91
177
  - Pass the validated Python script, step name, description, flowId, and executionOrder
92
178
  - The tool handles all JS wrapping automatically
93
- - Default dispatch: \`cloudflare_tunnel\` (uses \`lam.httpRequest\`)
179
+ - For browser/CDP automations: set \`dispatchPattern: "browser"\` routes to \`/execute/browser\` (parallel-safe)
180
+ - For desktop automations: use default \`dispatchPattern: "cloudflare_tunnel"\` — routes to \`/execute\`
181
+ - For mixed browser+desktop: use default \`dispatchPattern: "cloudflare_tunnel"\` — runs one at a time
182
+
183
+ ### 5. Data Passing Between Steps (CRITICAL)
184
+
185
+ Workflow input is available as \`data.input\` in the **JS wrapper**, NOT in Python directly. Dynamic values must be interpolated in the JS layer, then embedded into the Python template literal.
186
+
187
+ **CORRECT — JS-layer interpolation (how the existing SOAP workflow does it):**
188
+ \`\`\`javascript
189
+ (data) => {
190
+ const mrn = data?.input?.mrn || "DEFAULT";
191
+ const pythonScript = \\\`
192
+ mrn = "\${mrn}"
193
+ # ... rest of Python script uses mrn variable
194
+ \\\`;
195
+ return { "lam.httpRequest": { ... body: { script: pythonScript } } };
196
+ }
197
+ \`\`\`
198
+
199
+ **WRONG — Python template vars (will show literal text, not resolved):**
200
+ \`\`\`python
201
+ mrn = "{{input.mrn}}" # WRONG — this is not a config variable
202
+ mrn = data.input.mrn # WRONG — data object doesn't exist in Python
203
+ \`\`\`
204
+
205
+ \`create_rpa_flow\` generates the JS wrapper automatically, but if the script needs dynamic input from \`data.input\` or \`data.step_N\`, you must construct the JS wrapper yourself or update the flow after creation to add JS-layer const declarations that interpolate values into the Python template literal.
206
+
207
+ **Config variables** like \`{{config.username}}\` ARE resolved by the workflow engine and work in both JS and Python layers. Use these for credentials and environment URLs.
208
+
209
+ **Previous step outputs** are at \`data.step_N.response\` (for HTTP/RPA steps) or \`data.step_N.data\` (for GENERAL_FUNCTION steps).
210
+
211
+ ### 6. Test Through Minicor (REQUIRED — vm_execute_script is NOT enough)
212
+
213
+ \`vm_execute_script\` is for **prototyping only**. Scripts that pass on the VM may FAIL when run through Minicor because:
214
+ - \`{{config.xxx}}\` variables only resolve in the workflow engine
215
+ - \`data.input\` interpolation only works through the JS wrapper
216
+ - Step-to-step data flow (\`data.step_N\`) only works in the real executor
217
+
218
+ **After saving ALL steps, you MUST test through Minicor:**
219
+
220
+ a. \`execute_workflow\` with **real input data** and a **configurationId** pointing to the correct config store
221
+ b. If a step fails → \`diagnose_execution\` to identify the issue
222
+ c. Use \`test_workflow_step\` to re-run individual failing steps through Minicor (NOT \`vm_execute_script\`)
223
+ d. Fix with \`update_flow\`, then re-test through \`execute_workflow\` again
224
+ e. Iterate until the **full workflow passes end-to-end** through \`execute_workflow\`
94
225
 
95
- ### 5. End-to-End Validation
96
- After all steps are built:
97
- - \`execute_workflow\` to run the full sequence
98
- - \`vm_screenshot\` to verify final state
99
- - \`diagnose_execution\` if anything fails
226
+ **Do NOT declare a workflow complete until it passes \`execute_workflow\` with real inputs.**
100
227
 
101
- ### 6. Iterate with the User
102
- - Present completed workflow summary
103
- - Make adjustments, re-validate changed steps
228
+ ### 7. Iterate with the User
229
+ - Present completed workflow summary with execution results from Minicor
230
+ - Make adjustments, re-validate changed steps through \`execute_workflow\`
104
231
 
105
232
  ## Data Extraction Strategy
106
233
 
@@ -146,15 +273,19 @@ When you need to READ data from the screen (not just click/type), follow this pr
146
273
  ## Debugging Tools
147
274
 
148
275
  - **\`debug_rpa_step\`** — runs a script with before/after screenshots and full diagnostics (stdout, stderr, exit code). Use during development.
149
- - **\`vm_reset_state\`** — Smart Launch: close dialogs, reset app to known state. Use before testing.
276
+ - **\`vm_reset_state\`** — Manage windows: focus an app, minimize all, close dialogs, or close an app. Use before testing.
150
277
  - **\`vm_read_clipboard\`** — read clipboard after a copy operation.
151
- - **\`vm_screenshot_region\`** — crop/zoom a region for better text reading.
278
+ - **\`vm_screenshot_region\`** — crop/zoom a specific screen region for better text reading or verifying specific UI elements.
152
279
  - **\`batch_test_rpa\`** — run the workflow with multiple test inputs.
280
+ - **Video Recordings** — Minicor records MP4 videos of each RPA step execution. Use \`get_full_execution\` to see recording references (\`recording.blobName\`). These can be viewed in the Minicor platform for visual debugging.
153
281
 
154
282
  ## Important Rules
155
283
  - **VALIDATE BEFORE SAVING** — no exceptions unless user explicitly opts out
284
+ - **TEST THROUGH MINICOR** — \`vm_execute_script\` is for prototyping. Always run \`execute_workflow\` with real inputs before declaring done.
156
285
  - **Use \`create_rpa_flow\`** — never construct JS wrappers manually
157
286
  - **Use \`{{config.variables}}\` for secrets** — never hardcode credentials
287
+ - **Last step = workflow output** — The workflow returns whatever the FINAL step produces. If you need structured data returned (JSON, extracted records), the last step must output it. Don't put meaningful data in step N and cleanup in step N+1. Combine cleanup + data return in the last step, or add a GENERAL_FUNCTION step after RPA that formats the final result.
288
+ - **Study existing workflows first** — Before building, check if similar workflows exist in the workspace via \`get_workflow_overview\`. Reuse proven patterns for JS wrapper data passing, coordinate discovery, and framework selection. Existing workflows are battle-tested — copy their interpolation patterns.
158
289
  - **Combine extraction methods** — accessibility tree + clipboard + screenshots
159
290
  - **Start simple** — get basic automation working before adding sophistication
160
291
  - **Add waits** — use \`time.sleep()\` or element-wait patterns between actions
@@ -1 +1 @@
1
- {"version":3,"file":"build-rpa.js","sourceRoot":"","sources":["../../src/prompts/build-rpa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAY;IAC3C,MAAM,CAAC,MAAM,CACX,oBAAoB,EACpB,wSAAwS,EACxS;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACxD,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,CACP,iHAAiH,CAClH;QACH,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,CACP,uFAAuF,CACxF;QACH,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,sEAAsE,CACvE;KACJ,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;QACrD,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;EAGhB,IAAI;;;EAGJ,OAAO;;;MAGH,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,2BAA2B,UAAU,+BAA+B,CAAC,CAAC,CAAC,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;YAwB1I,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDA4GsC;iBAC9C;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"build-rpa.js","sourceRoot":"","sources":["../../src/prompts/build-rpa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAY;IAC3C,MAAM,CAAC,MAAM,CACX,oBAAoB,EACpB,wSAAwS,EACxS;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACxD,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,CACP,iHAAiH,CAClH;QACH,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,CACP,uFAAuF,CACxF;QACH,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,sEAAsE,CACvE;KACJ,EACD,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC;QACrD,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;EAGhB,IAAI;;;EAGJ,OAAO;;;MAGH,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,2BAA2B,UAAU,+BAA+B,CAAC,CAAC,CAAC,8CAA8C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAoH1I,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDAmJsC;iBAC9C;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"debug-execution.d.ts","sourceRoot":"","sources":["../../src/prompts/debug-execution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,QAoDpD"}
1
+ {"version":3,"file":"debug-execution.d.ts","sourceRoot":"","sources":["../../src/prompts/debug-execution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,QAyEpD"}
@@ -40,7 +40,28 @@ ${json(flowsData)}
40
40
  ## Execution Details:
41
41
  ${json(executionData)}
42
42
 
43
- Analyze the execution, identify failures, explain root causes, and suggest specific code fixes for the failing steps. Use the Laminar workflow specification (available via the laminar-workflow-guide prompt) for correct syntax.`,
43
+ Analyze the execution, identify failures, explain root causes, and suggest specific code fixes for the failing steps. Use the Minicor workflow specification (available via the minicor-workflow-guide prompt) for correct syntax.
44
+
45
+ ## Debugging Strategy
46
+
47
+ ### 1. Analyze the execution data above
48
+ - Identify which steps failed and their error messages
49
+ - Check the transformation (input) data for each failed step
50
+ - Look at preceding successful steps for context
51
+
52
+ ### 2. Check for video recordings
53
+ - RPA step executions include \`recording.blobName\` in their response data (e.g. \`rpa_1_step-name.mp4\`)
54
+ - These MP4 recordings can be viewed in the Minicor platform for visual debugging
55
+
56
+ ### 3. If a VM is connected — reproduce on the live VM
57
+ - Use \`replay_execution_step\` with the failed flow run ID to re-run the exact script with before/after screenshots
58
+ - Use \`vm_screenshot\` + \`vm_inspect_ui\` to compare expected vs actual VM state
59
+ - Use \`debug_rpa_step\` with a modified script to test fixes
60
+
61
+ ### 4. Fix and redeploy
62
+ - After identifying the fix, use \`debug_rpa_step\` to validate the corrected script
63
+ - Use \`update_flow\` to deploy the fixed step code
64
+ - Use \`execute_workflow\` to verify the full workflow works end-to-end`,
44
65
  },
45
66
  },
46
67
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"debug-execution.js","sourceRoot":"","sources":["../../src/prompts/debug-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,EAAY;IACnD,MAAM,CAAC,MAAM,CACX,0BAA0B,EAC1B,uDAAuD,EACvD;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACvD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;KACxD,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,EAAE;QACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;QAClC,IAAI,aAAkB,CAAC;QACvB,IAAI,SAAc,CAAC;QAEnB,IAAI,CAAC;YACH,aAAa,GAAG,MAAM,MAAM,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACtD,SAAS,GAAG,MAAM,MAAM,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,IAAI,EAAE,MAAe;wBACrB,OAAO,EAAE;4BACP,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,mCAAmC,CAAC,CAAC,OAAO,EAAE;yBACrD;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;QAED,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAe;oBACrB,OAAO,EAAE;wBACP,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE;;;EAGlB,IAAI,CAAC,SAAS,CAAC;;;EAGf,IAAI,CAAC,aAAa,CAAC;;mOAE8M;qBACtN;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"debug-execution.js","sourceRoot":"","sources":["../../src/prompts/debug-execution.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,EAAY;IACnD,MAAM,CAAC,MAAM,CACX,0BAA0B,EAC1B,uDAAuD,EACvD;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACvD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC;KACxD,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,EAAE;QACpC,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;QAClC,IAAI,aAAkB,CAAC;QACvB,IAAI,SAAc,CAAC;QAEnB,IAAI,CAAC;YACH,aAAa,GAAG,MAAM,MAAM,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACtD,SAAS,GAAG,MAAM,MAAM,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,IAAI,EAAE,MAAe;wBACrB,OAAO,EAAE;4BACP,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,mCAAmC,CAAC,CAAC,OAAO,EAAE;yBACrD;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;QAED,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAe;oBACrB,OAAO,EAAE;wBACP,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE;;;EAGlB,IAAI,CAAC,SAAS,CAAC;;;EAGf,IAAI,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;;wEAuBmD;qBAC3D;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-guide.d.ts","sourceRoot":"","sources":["../../src/prompts/workflow-guide.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,QAAQ,QAkL5C"}
1
+ {"version":3,"file":"workflow-guide.d.ts","sourceRoot":"","sources":["../../src/prompts/workflow-guide.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,wBAAgB,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,QAAQ,QAuK5C"}
@@ -1,13 +1,13 @@
1
1
  export function register({ server }) {
2
- server.prompt("laminar-workflow-guide", "Comprehensive guide for creating and editing Laminar workflows — step types, data access patterns, available libraries, and best practices", {}, async () => ({
2
+ server.prompt("minicor-workflow-guide", "Comprehensive guide for creating and editing Minicor workflows — step types, data access patterns, available libraries, and best practices", {}, async () => ({
3
3
  messages: [
4
4
  {
5
5
  role: "user",
6
6
  content: {
7
7
  type: "text",
8
- text: `Please use this Laminar platform specification when creating or editing workflows:
8
+ text: `Please use this Minicor platform specification when creating or editing workflows:
9
9
 
10
- # Laminar Workflow Specification
10
+ # Minicor Workflow Specification
11
11
 
12
12
  ## Step Structure
13
13
  Every step is a JSON object with these fields:
@@ -70,17 +70,6 @@ def transform(data):
70
70
 
71
71
  Multiple requests: use \`"lam.httpRequests"\` (plural) with an array.
72
72
 
73
- ### SHELL_SCRIPT
74
- \`\`\`json
75
- {
76
- "lam.shell": {
77
- "script": "Bash script as string",
78
- "environment": {},
79
- "timeout": 300,
80
- "binaryDataIds": []
81
- }
82
- }
83
- \`\`\`
84
73
 
85
74
  ### RPA (Desktop Automation)
86
75
  **IMPORTANT: Use the \`create_rpa_flow\` tool to save RPA steps.** It accepts your validated Python script and automatically wraps it in the correct JS format. You do NOT need to construct the wrapper yourself.
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-guide.js","sourceRoot":"","sources":["../../src/prompts/workflow-guide.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAY;IAC3C,MAAM,CAAC,MAAM,CACX,wBAAwB,EACxB,4IAA4I,EAC5I,EAAE,EACF,KAAK,IAAI,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gGAiK8E;iBACrF;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"workflow-guide.js","sourceRoot":"","sources":["../../src/prompts/workflow-guide.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,QAAQ,CAAC,EAAE,MAAM,EAAY;IAC3C,MAAM,CAAC,MAAM,CACX,wBAAwB,EACxB,4IAA4I,EAC5I,EAAE,EACF,KAAK,IAAI,EAAE,CAAC,CAAC;QACX,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gGAsJ8E;iBACrF;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}