@minicor/mcp-server 2.0.3 → 2.0.5

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 CHANGED
@@ -1,20 +1,12 @@
1
1
  # Minicor MCP Server
2
2
 
3
- > Formerly known as Laminar
3
+ Build, deploy, and debug VM-based browser and desktop automations from **Cursor** or **Claude Code**. The AI agent connects to your Windows VM, writes Python automation scripts, tests them live, and saves them as Minicor workflows.
4
4
 
5
- Desktop and browser RPA automation, workflow management, and AI-powered debugging for the Minicor platform -- all from **Cursor** or **Claude Code**.
5
+ ## Quick Start
6
6
 
7
- ## Add to Claude Code
7
+ ### Cursor
8
8
 
9
- ```bash
10
- npm install -g @minicor/mcp-server
11
- minicor-mcp-setup
12
- claude mcp add minicor -- minicor-mcp
13
- ```
14
-
15
- ## Add to Cursor
16
-
17
- Run the setup, then add to your Cursor MCP config (`~/.cursor/mcp.json`):
9
+ Run the setup wizard, then add to your Cursor MCP config (`~/.cursor/mcp.json`):
18
10
 
19
11
  ```json
20
12
  {
@@ -27,119 +19,149 @@ Run the setup, then add to your Cursor MCP config (`~/.cursor/mcp.json`):
27
19
  }
28
20
  ```
29
21
 
30
- Or if you ran `minicor-mcp-setup`, it writes this automatically. Just restart Cursor.
22
+ If you run `minicor-mcp-setup`, it writes this config automatically.
31
23
 
32
- ## Setup
24
+ ### Claude Code
33
25
 
34
26
  ```bash
35
27
  npm install -g @minicor/mcp-server
36
28
  minicor-mcp-setup
29
+ claude mcp add minicor -- minicor-mcp
37
30
  ```
38
31
 
39
- This opens a browser where you can **sign in** or **create an account**, set up workspaces, and optionally configure advanced services (Elasticsearch, CRON). Tokens are stored at `~/.minicor/tokens.json` and auto-refresh.
40
-
41
- For headless environments:
32
+ ### Authenticate
42
33
 
43
34
  ```bash
44
- minicor-mcp-setup --cli
35
+ npx @minicor/mcp-server-setup
45
36
  ```
46
37
 
47
- No API keys needed -- authentication is handled by your stored session token.
38
+ Opens a browser to sign in or create an account. Tokens are stored at `~/.minicor/tokens.json` and auto-refresh. For headless environments: `npx @minicor/mcp-server-setup --cli`.
48
39
 
49
- ## Features
40
+ ### Update
50
41
 
51
- - **Workspaces** -- list, inspect, manage workspace members
52
- - **Workflows** -- create, update, clone, delete, restore workflows
53
- - **Flows (Steps)** -- read/write individual steps, view version history, bulk update
54
- - **Executions** -- list, search, filter by date/status, inspect full payloads, view per-step results
55
- - **Execute** -- trigger workflows synchronously or async, poll for status
56
- - **Configuration Stores** -- manage key-value configs used by `{{config.xxx}}` references
57
- - **Issues** -- create and manage workspace issues
58
- - **Desktop RPA** -- connect to a VM, take screenshots, inspect UI, run scripts, build RPA workflows iteratively
59
- - **Browser RPA** -- session-based browser automation with natural-language actions
60
- - **RPA Debugging** -- before/after screenshots, batch testing, state reset, execution diagnosis
61
- - **Log Search** _(advanced)_ -- full-text Elasticsearch search across execution logs
62
- - **Incident Investigation** -- correlate failures across workflows with timeline analysis
63
- - **CRON Management** _(advanced)_ -- scheduled job management
64
- - **Workflow File Sync** -- pull/push workflows to local files for git version control
42
+ `npx` users: just restart your editor (fetches latest automatically). Global install: `npm update -g @minicor/mcp-server`.
65
43
 
66
- ## Desktop RPA
44
+ ## How It Works
67
45
 
68
- Connect to a VM running the Laminar Desktop Service (LDS) and iteratively build RPA workflows.
46
+ 1. **Connect to a VM** — The agent connects to your Windows VM running the Laminar Desktop Service (LDS) via a Cloudflare tunnel
47
+ 2. **Build automations** — The agent takes screenshots, inspects UI elements, writes Python scripts, and tests them on the VM in real time
48
+ 3. **Deploy as workflows** — Validated scripts are saved as step-based Minicor workflows with credentials stored in config stores
49
+ 4. **Debug failures** — Before/after screenshots, video recordings of each step, execution diagnosis, and replay on live VMs
69
50
 
70
- ### Setup LDS on a VM
51
+ ## What You Can Automate
71
52
 
72
- Use the `get_lds_setup_guide` tool for step-by-step instructions, or:
53
+ - **Web portals** — Chrome on the VM controlled via CDP (Chrome DevTools Protocol). Works on React/Angular SPAs, anti-bot protected sites, payor portals, EHR web apps.
54
+ - **Desktop applications** — Native Windows apps driven via uiautomation, pywinauto, or pyautogui. EMR clients, billing software, legacy systems.
55
+ - **APIs** — Direct HTTP calls when the agent discovers usable REST endpoints behind a web portal.
56
+ - **Hybrid workflows** — Mix browser, desktop, and API steps in a single workflow.
73
57
 
74
- 1. Install LDS on the target Windows VM
75
- 2. Start it on port 1016
76
- 3. Expose via Cloudflare Tunnel: `cloudflared tunnel --url http://localhost:1016`
77
- 4. In Cursor: `vm_connect` with the tunnel URL
78
-
79
- ### RPA Tools
80
-
81
- | Tool | Description |
82
- |---|---|
83
- | `vm_connect` | Connect to LDS via Cloudflare Tunnel URL |
84
- | `vm_screenshot` | Capture VM desktop screenshot |
85
- | `vm_inspect_ui` | Inspect UI elements (accessibility tree, element at point, etc.) |
86
- | `vm_execute_script` | Run Python script on the VM |
87
- | `create_rpa_flow` | Save validated Python script as an RPA step (auto-wraps in correct format) |
88
- | `vm_read_clipboard` | Read clipboard text after copy operations |
89
- | `vm_screenshot_region` | Crop and zoom a specific screen region |
90
- | `debug_rpa_step` | Run script with before/after screenshots |
91
- | `vm_reset_state` | Smart Launch -- reset app to known state |
92
- | `batch_test_rpa` | Run workflow with multiple test inputs |
93
- | `get_lds_setup_guide` | Full LDS installation walkthrough |
94
-
95
- ## Browser RPA
96
-
97
- Session-based browser automation for web applications.
98
-
99
- | Tool | Description |
100
- |---|---|
101
- | `browser_connect` | Connect to browser RPA service |
102
- | `browser_create_session` | Start a new browser session |
103
- | `browser_act` | Natural-language browser actions |
104
- | `browser_extract` | Extract data from the current page |
105
- | `browser_screenshot` | Screenshot the browser |
106
- | `browser_close_session` | Clean up session |
107
- | `create_browser_rpa_flow` | Save browser action as a workflow step |
108
-
109
- ## Workflow Tools
110
-
111
- | Tool | Description |
112
- |---|---|
113
- | `preview_flow_changes` | Diff current vs proposed code before pushing |
114
- | `get_workflow_overview` | Full workflow snapshot with code + executions |
115
- | `test_workflow_step` | Run up to / from / only a specific step |
116
- | `diagnose_execution` | Find failures with RPA-specific error analysis |
117
- | `compare_flow_versions` | Diff between two step versions |
118
-
119
- ## Advanced Setup
120
-
121
- Elasticsearch (log search) and CRON (scheduling) are configured during `minicor-mcp-setup` under Advanced Settings, or via `~/.minicor/config.json`:
58
+ ## VM Setup
122
59
 
123
- ```json
124
- {
125
- "elasticsearch": {
126
- "endpoint": "https://your-es-cluster.cloud.io",
127
- "apiKey": "your-es-api-key"
128
- },
129
- "cron": {
130
- "apiKey": "your-cron-api-key"
131
- }
132
- }
133
- ```
60
+ 1. Install LDS on a Windows 10/11 or Server VM with Python 3.11+
61
+ 2. Start LDS on port 1016
62
+ 3. Expose via Cloudflare Tunnel: `cloudflared tunnel --url http://localhost:1016`
63
+ 4. For browser automation: start Chrome with `--remote-debugging-port=9222`
64
+ 5. In your editor, tell the agent: "Connect to my VM at https://your-tunnel-url.com"
65
+
66
+ Use the `get_lds_setup_guide` tool for detailed step-by-step instructions.
67
+
68
+ ## Tools
69
+
70
+ ### VM Tools
71
+
72
+ | Tool | What it does |
73
+ | ---------------------- | ------------------------------------------------------------------------------------------ |
74
+ | `vm_connect` | Connect to VM via LDS Cloudflare tunnel URL |
75
+ | `vm_disconnect` | Disconnect from VM |
76
+ | `vm_status` | Health check for the connected VM |
77
+ | `vm_screenshot` | Full-screen capture of the VM desktop |
78
+ | `vm_screenshot_region` | Zoom into a specific screen area |
79
+ | `vm_execute_script` | Run a Python script on the VM |
80
+ | `vm_execution_status` | Check status of a running script |
81
+ | `vm_execution_control` | Pause, resume, stop, or skip a running script |
82
+ | `vm_inspect_ui` | Inspect Windows UI elements (window list, element tree, element at point, focused element) |
83
+ | `vm_read_clipboard` | Read VM clipboard contents |
84
+
85
+ ### Automation Building
86
+
87
+ | Tool | What it does |
88
+ | ----------------------- | --------------------------------------------------------- |
89
+ | `create_rpa_flow` | Save a validated Python script as a Minicor workflow step |
90
+ | `debug_rpa_step` | Test a script with before/after screenshots |
91
+ | `vm_reset_state` | Manage windows: focus app, minimize all, close dialogs |
92
+ | `batch_test_rpa` | Run a workflow with multiple test inputs |
93
+ | `replay_execution_step` | Re-run a step from a failed execution on the VM |
94
+ | `get_lds_setup_guide` | LDS installation walkthrough |
95
+
96
+ ### Workflows and Executions
97
+
98
+ | Tool | What it does |
99
+ | ---------------------------------------------------------- | --------------------------------------------------- |
100
+ | `create_workflow` / `update_workflow` / `delete_workflow` | Workflow CRUD |
101
+ | `create_flow` / `update_flow` / `delete_flow` | Step CRUD |
102
+ | `execute_workflow` / `execute_workflow_async` | Run workflows synchronously or async |
103
+ | `list_executions` / `get_execution` / `get_full_execution` | View execution history and details |
104
+ | `diagnose_execution` | Analyze failures with RPA-specific pattern matching |
105
+ | `get_workflow_overview` | Full snapshot: steps, code, recent executions |
106
+ | `test_workflow_step` | Run a single step in isolation |
107
+ | `preview_flow_changes` / `compare_flow_versions` | Diff code before deploying |
108
+
109
+ ### 2FA / OTP
110
+
111
+ | Tool | What it does |
112
+ | --------------------- | -------------------------------------------------------------------- |
113
+ | `tfa_provision_phone` | Buy a Twilio phone number for the workspace (SMS webhook auto-configured) |
114
+ | `tfa_provision_email` | Generate a Mailgun email address for OTP capture |
115
+ | `tfa_list_channels` | List all provisioned phone numbers and email addresses |
116
+ | `tfa_delete_channel` | Remove a channel (releases Twilio number if phone) |
117
+ | `tfa_register_secret` | Store a TOTP secret (base32 or otpauth:// URI), encrypted at rest |
118
+ | `tfa_list_secrets` | List stored TOTP secrets for the workspace |
119
+ | `tfa_delete_secret` | Remove a stored TOTP secret |
120
+ | `tfa_generate_totp` | Get the current 6-digit TOTP code + seconds until expiry |
121
+ | `tfa_verify_totp` | Verify a TOTP code against a stored secret |
122
+ | `tfa_parse_qr` | Parse a QR code image to extract TOTP parameters |
123
+ | `tfa_request_sms_otp` | Wait for an SMS OTP (blocks until SMS arrives or timeout) |
124
+ | `tfa_request_email_otp` | Wait for an email OTP (blocks until email arrives or timeout) |
125
+ | `tfa_get_challenge` | Check the status of a pending challenge |
126
+ | `tfa_resolve_challenge` | Manually resolve a challenge (for captchas or Slack-provided codes)|
127
+ | `tfa_cancel_challenge`| Cancel a pending challenge |
128
+
129
+ Workflows that encounter 2FA prompts use these tools to auto-resolve OTP challenges. Provision channels once per workspace, store the IDs in config stores, and reference them with `{{config.sms_channel_id}}` or `{{config.totp_secret_id}}` at runtime.
130
+
131
+ ### Config Stores
132
+
133
+ | Tool | What it does |
134
+ | --------------------------------------------------- | --------------------------------------------------- |
135
+ | `create_config_store` | Create a credential store with key-value properties |
136
+ | `list_config_stores` / `get_config_store` | Browse stores |
137
+ | `update_config_property` / `remove_config_property` | Manage individual properties |
138
+
139
+ Scripts reference credentials as `{{config.propertyKey}}` — resolved at runtime by the workflow engine.
140
+
141
+ ### Workflow Sync
142
+
143
+ | Tool | What it does |
144
+ | --------------------------------- | --------------------------------------------- |
145
+ | `init_project` | Scaffold a git-ready project from a workspace |
146
+ | `pull_workflow` / `push_workflow` | Sync individual workflows |
147
+ | `pull_all` / `push_changed` | Bulk sync |
148
+ | `sync_status` | Diff local vs deployed |
149
+
150
+ ## Prompts
151
+
152
+ | Prompt | What it does |
153
+ | -------------------------- | ------------------------------------------------------------------------------------------------- |
154
+ | `build-rpa-workflow` | Guided automation building: strategy selection, iterative build loop, Minicor testing, deployment |
155
+ | `debug-workflow-execution` | Analyze a failed execution with VM-aware debugging and replay |
156
+ | `minicor-workflow-guide` | Full workflow specification: step types, data access, keywords, libraries |
157
+ | `2fa-workflow-guide` | Handling 2FA in workflows: provisioning channels, TOTP secrets, auto-resolving OTP codes |
134
158
 
135
159
  ## Auth
136
160
 
137
- Authentication uses stored session tokens only. No API keys.
138
-
139
- - **Sign in / sign up**: `minicor-mcp-setup` (browser) or `minicor-mcp-setup --cli`
140
- - **Token storage**: `~/.minicor/tokens.json` (falls back to `~/.laminar/tokens.json` for existing users)
141
- - **Auto-refresh**: tokens refresh automatically before expiry
142
- - **Region**: US (default) or Canada, selected during setup
161
+ - **Sign in**: `minicor-mcp-setup` (browser) or `minicor-mcp-setup --cli`
162
+ - **Token storage**: `~/.minicor/tokens.json`
163
+ - **Auto-refresh**: tokens refresh before expiry
164
+ - **Regions**: US (default) or Canada
143
165
 
144
166
  ## Development
145
167
 
@@ -147,25 +169,4 @@ Authentication uses stored session tokens only. No API keys.
147
169
  npm install
148
170
  npm run build
149
171
  npm test
150
- npm run dev # watch mode
151
- npm run test:watch # test watch mode
152
172
  ```
153
-
154
- ### Project Structure
155
-
156
- ```
157
- src/
158
- index.ts -- server orchestrator (auth, init, registration)
159
- helpers.ts -- shared response helpers (ok, text, safe, buildRpaProgram)
160
- state.ts -- session state (VM + browser connections)
161
- paths.ts -- token/config path resolution with ~/.minicor/ + ~/.laminar/ fallback
162
- types.ts -- shared ToolDeps interface
163
- setup.ts -- interactive setup (browser + CLI modes)
164
- tools/ -- tool modules (each exports register())
165
- prompts/ -- prompt modules (each exports register())
166
- __tests__/ -- vitest unit tests
167
- ```
168
-
169
- ## License
170
-
171
- MIT
@@ -40,9 +40,9 @@ describe("buildRpaProgram", () => {
40
40
  it("generates cloudflare_tunnel pattern with lam.httpRequest", () => {
41
41
  const program = buildRpaProgram('print("hello")', "cloudflare_tunnel", "test-step", "Test Step", "A test step");
42
42
  expect(program).toContain("lam.httpRequest");
43
- expect(program).toContain("{{config.laminar_desktop_service_url}}/execute");
44
- expect(program).toContain("{{config.laminar_desktop_service_api_key}}");
45
- expect(program).toContain("{{config.laminar_desktop_service_id}}");
43
+ expect(program).toContain("{{config.minicor_desktop_service_url}}/execute");
44
+ expect(program).toContain("{{config.minicor_desktop_service_api_key}}");
45
+ expect(program).toContain("{{config.minicor_desktop_service_id}}");
46
46
  expect(program).toContain('"flowId": "test-step"');
47
47
  expect(program).toContain('print("hello")');
48
48
  expect(program).toMatch(/^\(data\) =>/);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tfa-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tfa-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tfa-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,191 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import * as tfa from "../tfa-client.js";
3
+ describe("getTfaBaseUrl", () => {
4
+ const original = process.env.TFA_OTP_URL;
5
+ afterEach(() => {
6
+ if (original !== undefined) {
7
+ process.env.TFA_OTP_URL = original;
8
+ }
9
+ else {
10
+ delete process.env.TFA_OTP_URL;
11
+ }
12
+ });
13
+ it("returns default when env var is unset", () => {
14
+ delete process.env.TFA_OTP_URL;
15
+ expect(tfa.getTfaBaseUrl()).toBe("https://tfa-otp.minicor.com");
16
+ });
17
+ it("returns env var when set", () => {
18
+ process.env.TFA_OTP_URL = "http://localhost:3847";
19
+ expect(tfa.getTfaBaseUrl()).toBe("http://localhost:3847");
20
+ });
21
+ });
22
+ describe("tfa-client HTTP calls", () => {
23
+ const BASE = "https://tfa-otp.minicor.com";
24
+ const API_KEY = "test-key-123";
25
+ beforeEach(() => {
26
+ vi.stubGlobal("fetch", vi.fn());
27
+ });
28
+ afterEach(() => {
29
+ vi.restoreAllMocks();
30
+ });
31
+ function mockFetch(status, body) {
32
+ fetch.mockResolvedValue({
33
+ ok: status >= 200 && status < 300,
34
+ status,
35
+ json: () => Promise.resolve(body),
36
+ text: () => Promise.resolve(JSON.stringify(body)),
37
+ headers: new Headers({ "content-type": "application/json" }),
38
+ });
39
+ }
40
+ function lastFetchCall() {
41
+ const calls = fetch.mock.calls;
42
+ return { url: calls[0][0], init: calls[0][1] };
43
+ }
44
+ // ── Channels ──
45
+ it("provisionPhone calls POST /channels/phone with API key header", async () => {
46
+ mockFetch(201, { id: "ch_123", address: "+15551234567" });
47
+ const result = await tfa.provisionPhone(BASE, API_KEY);
48
+ const { url, init } = lastFetchCall();
49
+ expect(url).toBe(`${BASE}/channels/phone`);
50
+ expect(init.method).toBe("POST");
51
+ expect(init.headers["X-API-Key"]).toBe(API_KEY);
52
+ expect(result).toEqual({ id: "ch_123", address: "+15551234567" });
53
+ });
54
+ it("provisionEmail calls POST /channels/email", async () => {
55
+ mockFetch(201, { id: "ch_456", address: "rpa-abc@otp.minicor.com" });
56
+ await tfa.provisionEmail(BASE, API_KEY);
57
+ const { url, init } = lastFetchCall();
58
+ expect(url).toBe(`${BASE}/channels/email`);
59
+ expect(init.method).toBe("POST");
60
+ });
61
+ it("listChannels calls GET /channels with optional type filter", async () => {
62
+ mockFetch(200, []);
63
+ await tfa.listChannels(BASE, API_KEY, { type: "phone" });
64
+ const { url } = lastFetchCall();
65
+ expect(url).toBe(`${BASE}/channels?type=phone`);
66
+ });
67
+ it("listChannels omits query string when no filter", async () => {
68
+ mockFetch(200, []);
69
+ await tfa.listChannels(BASE, API_KEY);
70
+ const { url } = lastFetchCall();
71
+ expect(url).toBe(`${BASE}/channels`);
72
+ });
73
+ it("deleteChannel calls DELETE /channels/:id", async () => {
74
+ fetch.mockResolvedValue({
75
+ ok: true,
76
+ status: 204,
77
+ json: () => Promise.resolve(undefined),
78
+ text: () => Promise.resolve(""),
79
+ headers: new Headers(),
80
+ });
81
+ await tfa.deleteChannel(BASE, API_KEY, "ch_123");
82
+ const { url, init } = lastFetchCall();
83
+ expect(url).toBe(`${BASE}/channels/ch_123`);
84
+ expect(init.method).toBe("DELETE");
85
+ });
86
+ // ── Secrets ──
87
+ it("createSecret sends TOTP secret data", async () => {
88
+ mockFetch(201, { id: "sec_123" });
89
+ await tfa.createSecret(BASE, API_KEY, {
90
+ type: "totp",
91
+ name: "Acme",
92
+ value: "JBSWY3DPEHPK3PXP",
93
+ site: "acme.com",
94
+ });
95
+ const { url, init } = lastFetchCall();
96
+ expect(url).toBe(`${BASE}/secrets`);
97
+ expect(init.method).toBe("POST");
98
+ const body = JSON.parse(init.body);
99
+ expect(body.type).toBe("totp");
100
+ expect(body.name).toBe("Acme");
101
+ expect(body.value).toBe("JBSWY3DPEHPK3PXP");
102
+ });
103
+ it("createSecret supports otpauth URI", async () => {
104
+ mockFetch(201, { id: "sec_456" });
105
+ await tfa.createSecret(BASE, API_KEY, {
106
+ type: "totp",
107
+ name: "Acme",
108
+ uri: "otpauth://totp/Acme:user@example.com?secret=JBSWY3DPEHPK3PXP",
109
+ });
110
+ const body = JSON.parse(lastFetchCall().init.body);
111
+ expect(body.uri).toContain("otpauth://");
112
+ expect(body.value).toBeUndefined();
113
+ });
114
+ it("listSecrets with site filter", async () => {
115
+ mockFetch(200, []);
116
+ await tfa.listSecrets(BASE, API_KEY, { site: "acme.com" });
117
+ expect(lastFetchCall().url).toBe(`${BASE}/secrets?site=acme.com`);
118
+ });
119
+ it("generateTotp calls POST /secrets/:id/generate", async () => {
120
+ mockFetch(200, { code: "482901", expiresIn: 14 });
121
+ const result = await tfa.generateTotp(BASE, API_KEY, "sec_123");
122
+ expect(lastFetchCall().url).toBe(`${BASE}/secrets/sec_123/generate`);
123
+ expect(result).toEqual({ code: "482901", expiresIn: 14 });
124
+ });
125
+ it("verifyTotp sends code in body", async () => {
126
+ mockFetch(200, { valid: true, delta: 0 });
127
+ await tfa.verifyTotp(BASE, API_KEY, "sec_123", "482901");
128
+ const { url, init } = lastFetchCall();
129
+ expect(url).toBe(`${BASE}/secrets/sec_123/verify`);
130
+ expect(JSON.parse(init.body)).toEqual({ code: "482901" });
131
+ });
132
+ it("parseQr sends imageUrl", async () => {
133
+ mockFetch(200, { uri: "otpauth://totp/...", secretPreview: "****PXP" });
134
+ await tfa.parseQr(BASE, API_KEY, { imageUrl: "https://example.com/qr.png" });
135
+ const body = JSON.parse(lastFetchCall().init.body);
136
+ expect(body.imageUrl).toBe("https://example.com/qr.png");
137
+ });
138
+ // ── Challenges ──
139
+ it("requestSmsOtp sends channelId and timeout", async () => {
140
+ mockFetch(200, { status: "resolved", resolution: { value: "123456" } });
141
+ await tfa.requestSmsOtp(BASE, API_KEY, {
142
+ channelId: "ch_phone1",
143
+ timeoutSeconds: 60,
144
+ });
145
+ const body = JSON.parse(lastFetchCall().init.body);
146
+ expect(body.channelId).toBe("ch_phone1");
147
+ expect(body.timeoutSeconds).toBe(60);
148
+ });
149
+ it("requestEmailOtp hits /challenges/email-otp", async () => {
150
+ mockFetch(200, { status: "resolved" });
151
+ await tfa.requestEmailOtp(BASE, API_KEY, { channelId: "ch_email1" });
152
+ expect(lastFetchCall().url).toBe(`${BASE}/challenges/email-otp`);
153
+ });
154
+ it("getChallenge hits GET /challenges/:id", async () => {
155
+ mockFetch(200, { id: "chal_1", status: "pending" });
156
+ await tfa.getChallenge(BASE, API_KEY, "chal_1");
157
+ expect(lastFetchCall().url).toBe(`${BASE}/challenges/chal_1`);
158
+ });
159
+ it("resolveChallenge sends value and resolvedBy", async () => {
160
+ mockFetch(200, { status: "resolved" });
161
+ await tfa.resolveChallenge(BASE, API_KEY, "chal_1", {
162
+ value: "xK9mP2",
163
+ resolvedBy: "manual",
164
+ });
165
+ const { url, init } = lastFetchCall();
166
+ expect(url).toBe(`${BASE}/challenges/chal_1/resolve`);
167
+ expect(JSON.parse(init.body)).toEqual({
168
+ value: "xK9mP2",
169
+ resolvedBy: "manual",
170
+ });
171
+ });
172
+ it("cancelChallenge calls DELETE /challenges/:id", async () => {
173
+ mockFetch(200, { status: "cancelled" });
174
+ await tfa.cancelChallenge(BASE, API_KEY, "chal_1");
175
+ const { url, init } = lastFetchCall();
176
+ expect(url).toBe(`${BASE}/challenges/chal_1`);
177
+ expect(init.method).toBe("DELETE");
178
+ });
179
+ // ── Error handling ──
180
+ it("throws on non-ok response with status and body", async () => {
181
+ mockFetch(404, { error: "Not found" });
182
+ await expect(tfa.getChallenge(BASE, API_KEY, "bad_id")).rejects.toThrow(/2FA API.*404/);
183
+ });
184
+ // ── URL normalization ──
185
+ it("strips trailing slashes from base URL", async () => {
186
+ mockFetch(200, []);
187
+ await tfa.listChannels("https://example.com///", API_KEY);
188
+ expect(lastFetchCall().url).toBe("https://example.com/channels");
189
+ });
190
+ });
191
+ //# sourceMappingURL=tfa-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tfa-client.test.js","sourceRoot":"","sources":["../../src/__tests__/tfa-client.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAExC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IAEzC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QACjC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,uBAAuB,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,MAAM,IAAI,GAAG,6BAA6B,CAAC;IAC3C,MAAM,OAAO,GAAG,cAAc,CAAC;IAE/B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,eAAe,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,SAAS,SAAS,CAAC,MAAc,EAAE,IAAa;QAC7C,KAAkC,CAAC,iBAAiB,CAAC;YACpD,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG;YACjC,MAAM;YACN,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;YACjC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACjD,OAAO,EAAE,IAAI,OAAO,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;SAC7D,CAAC,CAAC;IACL,CAAC;IAED,SAAS,aAAa;QACpB,MAAM,KAAK,GAAI,KAAkC,CAAC,IAAI,CAAC,KAAK,CAAC;QAC7D,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAgB,EAAE,CAAC;IAC1E,CAAC;IAED,iBAAiB;IAEjB,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,iBAAiB,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,CAAE,IAAI,CAAC,OAAkC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5E,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACrE,MAAM,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,iBAAiB,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnB,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,MAAM,EAAE,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,sBAAsB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnB,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QACvD,KAAkC,CAAC,iBAAiB,CAAC;YACpD,EAAE,EAAE,IAAI;YACR,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;YACtC,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,OAAO,EAAE,IAAI,OAAO,EAAE;SACvB,CAAC,CAAC;QACH,MAAM,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACjD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,kBAAkB,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,gBAAgB;IAEhB,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAClC,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE;YACpC,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,KAAK,EAAE,kBAAkB;YACzB,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAClC,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE;YACpC,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,GAAG,EAAE,8DAA8D;SACpE,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnB,MAAM,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAC3D,MAAM,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,wBAAwB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,SAAS,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAChE,MAAM,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,2BAA2B,CAAC,CAAC;QACrE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,SAAS,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1C,MAAM,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QACzD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,yBAAyB,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;QACtC,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,oBAAoB,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC;QACxE,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,4BAA4B,EAAE,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,mBAAmB;IAEnB,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,SAAS,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QACxE,MAAM,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE;YACrC,SAAS,EAAE,WAAW;YACtB,cAAc,EAAE,EAAE;SACnB,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC1D,SAAS,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QACvC,MAAM,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,uBAAuB,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QACpD,MAAM,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,oBAAoB,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,SAAS,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QACvC,MAAM,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE;YAClD,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE,QAAQ;SACrB,CAAC,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,4BAA4B,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9C,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE,QAAQ;SACrB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,SAAS,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QACxC,MAAM,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACnD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,aAAa,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,oBAAoB,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,uBAAuB;IAEvB,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,SAAS,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QACvC,MAAM,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACrE,cAAc,CACf,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,0BAA0B;IAE1B,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACnB,MAAM,GAAG,CAAC,YAAY,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;QAC1D,MAAM,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
package/dist/helpers.d.ts CHANGED
@@ -20,6 +20,6 @@ export declare function safe<T>(fn: () => Promise<T>): Promise<{
20
20
  text: string;
21
21
  }[];
22
22
  }>;
23
- export declare const NOT_CONNECTED_VM = "No VM connected. Ask the user for their Cloudflare Tunnel URL for the Laminar Desktop Service, then call vm_connect.";
24
- export declare function buildRpaProgram(pythonScript: string, pattern: "cloudflare_tunnel" | "channel", flowId: string, stepName: string, stepDescription: string): string;
23
+ export declare const NOT_CONNECTED_VM = "No VM connected. Ask the user for their Cloudflare Tunnel URL for the Minicor Desktop Service, then call vm_connect.";
24
+ export declare function buildRpaProgram(pythonScript: string, pattern: "cloudflare_tunnel" | "channel" | "browser", flowId: string, stepName: string, stepDescription: string): string;
25
25
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAE1C;AAED,wBAAgB,EAAE,CAAC,IAAI,EAAE,OAAO;;;;;EAE/B;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM;;;;;EAE/B;AAED,wBAAsB,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC;;;;;GAMjD;AAED,eAAO,MAAM,gBAAgB,yHAAyH,CAAC;AAEvJ,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,mBAAmB,GAAG,SAAS,EACxC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GACtB,MAAM,CAqCR"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAE1C;AAED,wBAAgB,EAAE,CAAC,IAAI,EAAE,OAAO;;;;;EAE/B;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM;;;;;EAE/B;AAED,wBAAsB,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC;;;;;GAMjD;AAED,eAAO,MAAM,gBAAgB,yHAAyH,CAAC;AAEvJ,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,mBAAmB,GAAG,SAAS,GAAG,SAAS,EACpD,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,GACtB,MAAM,CAwCR"}
package/dist/helpers.js CHANGED
@@ -18,7 +18,7 @@ export async function safe(fn) {
18
18
  return text(`Error: ${e.message}`);
19
19
  }
20
20
  }
21
- export const NOT_CONNECTED_VM = `No VM connected. Ask the user for their Cloudflare Tunnel URL for the Laminar Desktop Service, then call vm_connect.`;
21
+ export const NOT_CONNECTED_VM = `No VM connected. Ask the user for their Cloudflare Tunnel URL for the Minicor Desktop Service, then call vm_connect.`;
22
22
  export function buildRpaProgram(pythonScript, pattern, flowId, stepName, stepDescription) {
23
23
  const escaped = pythonScript.replace(/`/g, "\\`").replace(/\$/g, "\\$");
24
24
  if (pattern === "channel") {
@@ -34,6 +34,9 @@ ${escaped}
34
34
  };
35
35
  }`;
36
36
  }
37
+ // Browser scripts go to /execute/browser — MDS provides an isolated Chrome tab
38
+ // Desktop scripts go to /execute — no Chrome, just runs the script
39
+ const endpoint = pattern === "browser" ? "/execute/browser" : "/execute";
37
40
  return `(data) => {
38
41
  const pythonScript = \`
39
42
  ${escaped}
@@ -41,11 +44,11 @@ ${escaped}
41
44
  return {
42
45
  "lam.httpRequest": {
43
46
  "method": "POST",
44
- "url": "{{config.laminar_desktop_service_url}}/execute",
47
+ "url": "{{config.minicor_desktop_service_url}}${endpoint}",
45
48
  "headers": {
46
49
  "Content-Type": "application/json",
47
- "X-API-Key": "{{config.laminar_desktop_service_api_key}}",
48
- "X-Service-ID": "{{config.laminar_desktop_service_id}}"
50
+ "X-API-Key": "{{config.minicor_desktop_service_api_key}}",
51
+ "X-Service-ID": "{{config.minicor_desktop_service_id}}"
49
52
  },
50
53
  "body": {
51
54
  "flowId": "${flowId}",
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,IAAI,CAAC,IAAa;IAChC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,EAAE,CAAC,IAAa;IAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAI,EAAoB;IAChD,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,sHAAsH,CAAC;AAEvJ,MAAM,UAAU,eAAe,CAC7B,YAAoB,EACpB,OAAwC,EACxC,MAAc,EACd,QAAgB,EAChB,eAAuB;IAEvB,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACxE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO;;EAET,OAAO;;;;;;;;EAQP,CAAC;IACD,CAAC;IACD,OAAO;;EAEP,OAAO;;;;;;;;;;;;qBAYY,MAAM;;;2BAGA,MAAM,eAAe,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,sBAAsB,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;;;;EAIrI,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,IAAI,CAAC,IAAa;IAChC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,EAAE,CAAC,IAAa;IAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CAAI,EAAoB;IAChD,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,sHAAsH,CAAC;AAEvJ,MAAM,UAAU,eAAe,CAC7B,YAAoB,EACpB,OAAoD,EACpD,MAAc,EACd,QAAgB,EAChB,eAAuB;IAEvB,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACxE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO;;EAET,OAAO;;;;;;;;EAQP,CAAC;IACD,CAAC;IACD,+EAA+E;IAC/E,mEAAmE;IACnE,MAAM,QAAQ,GAAG,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,UAAU,CAAC;IACzE,OAAO;;EAEP,OAAO;;;;;sDAK6C,QAAQ;;;;;;;qBAOzC,MAAM;;;2BAGA,MAAM,eAAe,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,sBAAsB,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;;;;EAIrI,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AA0DH,wBAAgB,UAAU,IAAI,MAAM,CAKnC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AA4DH,wBAAgB,UAAU,IAAI,MAAM,CAKnC"}
package/dist/index.js CHANGED
@@ -17,9 +17,11 @@ import { register as registerConfigStores } from "./tools/config-stores.js";
17
17
  import { register as registerSyncTools } from "./tools/sync-tools.js";
18
18
  import { register as registerVm } from "./tools/vm.js";
19
19
  import { register as registerVmRpa } from "./tools/vm-rpa.js";
20
+ import { register as registerTfa } from "./tools/tfa.js";
20
21
  import { register as registerWorkflowGuide } from "./prompts/workflow-guide.js";
21
22
  import { register as registerDebugExecution } from "./prompts/debug-execution.js";
22
23
  import { register as registerBuildRpa } from "./prompts/build-rpa.js";
24
+ import { register as registerTfaGuide } from "./prompts/tfa-guide.js";
23
25
  // ─── Token management ────────────────────────────────────────
24
26
  const REFRESH_BUFFER_MS = 5 * 60 * 1000;
25
27
  function readStoredTokens() {
@@ -152,9 +154,11 @@ function registerAll() {
152
154
  registerSyncTools(deps);
153
155
  registerVm(deps);
154
156
  registerVmRpa(deps);
157
+ registerTfa(deps);
155
158
  registerWorkflowGuide(deps);
156
159
  registerDebugExecution(deps);
157
160
  registerBuildRpa(deps);
161
+ registerTfaGuide(deps);
158
162
  }
159
163
  // ─── Main ────────────────────────────────────────────────────
160
164
  async function main() {