sf-builder-agent 0.7.0

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.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Browser — Puppeteer launcher and command executor.
3
+ *
4
+ * Handles all CommandType operations including shadow-DOM traversal,
5
+ * label-based element lookup, and screenshot capture.
6
+ */
7
+ import { type Browser, type Page } from "puppeteer";
8
+ export declare function launchBrowser(): Promise<{
9
+ browser: Browser;
10
+ page: Page;
11
+ }>;
12
+ export interface CommandResult {
13
+ success: boolean;
14
+ result?: unknown;
15
+ error?: string;
16
+ screenshot?: string;
17
+ shutdown?: boolean;
18
+ }
19
+ export declare function executeCommand(page: Page, commandType: string, payload: Record<string, unknown>): Promise<CommandResult>;
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Browser — Puppeteer launcher and command executor.
3
+ *
4
+ * Handles all CommandType operations including shadow-DOM traversal,
5
+ * label-based element lookup, and screenshot capture.
6
+ */
7
+ import puppeteer from "puppeteer";
8
+ // ─── Launch ──────────────────────────────────────────────────────────
9
+ export async function launchBrowser() {
10
+ const browser = await puppeteer.launch({
11
+ headless: false,
12
+ defaultViewport: { width: 1440, height: 900 },
13
+ args: [
14
+ "--start-maximized",
15
+ "--disable-blink-features=AutomationControlled",
16
+ ],
17
+ });
18
+ const pages = await browser.pages();
19
+ const page = pages[0] ?? (await browser.newPage());
20
+ return { browser, page };
21
+ }
22
+ // ─── Helpers ─────────────────────────────────────────────────────────
23
+ /**
24
+ * Walk through shadow roots and resolve the final selector.
25
+ */
26
+ async function findElement(page, selector, shadowPath) {
27
+ if (shadowPath && shadowPath.length > 0) {
28
+ // Walk shadow DOM tree
29
+ let root = await page.evaluateHandle(() => document);
30
+ for (const pathSelector of shadowPath) {
31
+ root = await page.evaluateHandle((el, sel) => {
32
+ const host = el.querySelector(sel);
33
+ if (!host)
34
+ throw new Error(`Shadow host not found: ${sel}`);
35
+ return host.shadowRoot ?? host;
36
+ }, root, pathSelector);
37
+ }
38
+ const handle = await page.evaluateHandle((el, sel) => {
39
+ const found = el.querySelector(sel);
40
+ if (!found)
41
+ throw new Error(`Element not found in shadow DOM: ${sel}`);
42
+ return found;
43
+ }, root, selector);
44
+ return handle;
45
+ }
46
+ const el = await page.$(selector);
47
+ if (!el)
48
+ throw new Error(`Element not found: ${selector}`);
49
+ return el;
50
+ }
51
+ /**
52
+ * Try to locate an input/textarea/select by its associated <label> text.
53
+ */
54
+ async function findByLabel(page, label) {
55
+ const handle = await page.evaluateHandle((labelText) => {
56
+ const labels = [...document.querySelectorAll("label")];
57
+ const match = labels.find((l) => l.textContent?.trim().includes(labelText));
58
+ if (!match)
59
+ return null;
60
+ // If the label has a `for` attribute, use it
61
+ if (match.htmlFor) {
62
+ return document.getElementById(match.htmlFor);
63
+ }
64
+ // Otherwise look for an input nested inside the label
65
+ return match.querySelector("input, textarea, select");
66
+ }, label);
67
+ // evaluateHandle returns a JSHandle — check if the inner value is null
68
+ const element = handle.asElement();
69
+ if (!element) {
70
+ await handle.dispose();
71
+ return null;
72
+ }
73
+ return element;
74
+ }
75
+ /**
76
+ * Find an element by its visible text content.
77
+ */
78
+ async function findByText(page, selector, text) {
79
+ const handle = await page.evaluateHandle((sel, txt) => {
80
+ const candidates = [...document.querySelectorAll(sel || "*")];
81
+ const match = candidates.find((el) => el.textContent?.trim().includes(txt));
82
+ if (!match)
83
+ throw new Error(`No element with text "${txt}" found`);
84
+ return match;
85
+ }, selector, text);
86
+ return handle;
87
+ }
88
+ export async function executeCommand(page, commandType, payload) {
89
+ try {
90
+ switch (commandType) {
91
+ // ── navigate ──
92
+ case "navigate": {
93
+ const url = payload.url;
94
+ await page.goto(url, { waitUntil: "networkidle2", timeout: 30_000 });
95
+ return { success: true, result: { url } };
96
+ }
97
+ // ── click ──
98
+ case "click": {
99
+ const selector = payload.selector;
100
+ const shadowPath = payload.shadowPath;
101
+ const text = payload.text;
102
+ let el;
103
+ if (text) {
104
+ el = await findByText(page, selector, text);
105
+ }
106
+ else {
107
+ el = await findElement(page, selector, shadowPath);
108
+ }
109
+ await el.click();
110
+ return { success: true };
111
+ }
112
+ // ── fill ──
113
+ case "fill": {
114
+ const selector = payload.selector;
115
+ const value = payload.value;
116
+ const shadowPath = payload.shadowPath;
117
+ const label = payload.label;
118
+ let el = null;
119
+ // Try label-based lookup first
120
+ if (label) {
121
+ el = await findByLabel(page, label);
122
+ }
123
+ // Fall back to selector / shadow path
124
+ if (!el) {
125
+ el = await findElement(page, selector, shadowPath);
126
+ }
127
+ // Clear existing value then type the new one
128
+ await el.click({ clickCount: 3 }); // select all
129
+ await el.press("Backspace");
130
+ await el.type(value);
131
+ return { success: true };
132
+ }
133
+ // ── select ──
134
+ case "select": {
135
+ const selector = payload.selector;
136
+ const value = payload.value;
137
+ const shadowPath = payload.shadowPath;
138
+ if (shadowPath && shadowPath.length > 0) {
139
+ const el = await findElement(page, selector, shadowPath);
140
+ await page.evaluate((selectEl, val) => {
141
+ selectEl.value = val;
142
+ selectEl.dispatchEvent(new Event("change", { bubbles: true }));
143
+ }, el, value);
144
+ }
145
+ else {
146
+ await page.select(selector, value);
147
+ }
148
+ return { success: true };
149
+ }
150
+ // ── screenshot ──
151
+ case "screenshot": {
152
+ const fullPage = payload.fullPage ?? false;
153
+ const buf = await page.screenshot({
154
+ fullPage,
155
+ encoding: "base64",
156
+ });
157
+ return { success: true, screenshot: buf };
158
+ }
159
+ // ── evaluate ──
160
+ case "evaluate": {
161
+ const script = payload.script;
162
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
163
+ const result = await page.evaluate(script);
164
+ return { success: true, result };
165
+ }
166
+ // ── waitForSelector ──
167
+ case "waitForSelector": {
168
+ const selector = payload.selector;
169
+ const timeout = payload.timeout ?? 10_000;
170
+ const shadowPath = payload.shadowPath;
171
+ if (shadowPath && shadowPath.length > 0) {
172
+ // Poll for element inside shadow DOM
173
+ const deadline = Date.now() + timeout;
174
+ let found = false;
175
+ while (Date.now() < deadline) {
176
+ try {
177
+ await findElement(page, selector, shadowPath);
178
+ found = true;
179
+ break;
180
+ }
181
+ catch {
182
+ await new Promise((r) => setTimeout(r, 250));
183
+ }
184
+ }
185
+ if (!found) {
186
+ throw new Error(`Timed out waiting for ${selector} in shadow DOM`);
187
+ }
188
+ }
189
+ else {
190
+ await page.waitForSelector(selector, { timeout });
191
+ }
192
+ return { success: true };
193
+ }
194
+ // ── waitForNavigation ──
195
+ case "waitForNavigation": {
196
+ const timeout = payload.timeout ?? 15_000;
197
+ await page.waitForNavigation({ timeout });
198
+ return { success: true };
199
+ }
200
+ // ── keyboard ──
201
+ case "keyboard": {
202
+ const key = payload.key;
203
+ await page.keyboard.press(key);
204
+ return { success: true };
205
+ }
206
+ // ── scroll ──
207
+ case "scroll": {
208
+ const selector = payload.selector ?? null;
209
+ const direction = payload.direction;
210
+ const amount = payload.amount ?? 300;
211
+ await page.evaluate((sel, dir, amt) => {
212
+ const target = sel ? document.querySelector(sel) : window;
213
+ if (!target)
214
+ throw new Error(`Scroll target not found: ${sel}`);
215
+ const delta = dir === "down" ? amt : -amt;
216
+ if (target === window) {
217
+ window.scrollBy(0, delta);
218
+ }
219
+ else {
220
+ target.scrollBy(0, delta);
221
+ }
222
+ }, selector, direction, amount);
223
+ return { success: true };
224
+ }
225
+ // ── hover ──
226
+ case "hover": {
227
+ const selector = payload.selector;
228
+ const shadowPath = payload.shadowPath;
229
+ const el = await findElement(page, selector, shadowPath);
230
+ await el.hover();
231
+ return { success: true };
232
+ }
233
+ // ── delay ──
234
+ case "delay": {
235
+ const ms = payload.ms ?? 1_000;
236
+ await new Promise((r) => setTimeout(r, ms));
237
+ return { success: true };
238
+ }
239
+ // ── ping ──
240
+ case "ping": {
241
+ return { success: true };
242
+ }
243
+ // ── shutdown ──
244
+ case "shutdown": {
245
+ return { success: true, shutdown: true };
246
+ }
247
+ default:
248
+ return { success: false, error: `Unknown command type: ${commandType}` };
249
+ }
250
+ }
251
+ catch (err) {
252
+ return {
253
+ success: false,
254
+ error: err instanceof Error ? err.message : String(err),
255
+ };
256
+ }
257
+ }
258
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Heartbeat — periodically pings the server so it knows we're alive.
3
+ */
4
+ export declare function startHeartbeat(baseUrl: string, sessionId: string, token: string, intervalMs?: number): {
5
+ stop: () => void;
6
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Heartbeat — periodically pings the server so it knows we're alive.
3
+ */
4
+ export function startHeartbeat(baseUrl, sessionId, token, intervalMs = 10_000) {
5
+ let timer = null;
6
+ const tick = async () => {
7
+ try {
8
+ const res = await fetch(`${baseUrl}/api/sessions/${sessionId}/agent/heartbeat`, {
9
+ method: "POST",
10
+ headers: { Authorization: `Bearer ${token}` },
11
+ });
12
+ if (res.ok) {
13
+ console.log("\uD83D\uDC93 Heartbeat sent");
14
+ }
15
+ else {
16
+ console.error(`\u274C Heartbeat rejected (${res.status})`);
17
+ }
18
+ }
19
+ catch (err) {
20
+ console.error("\u274C Heartbeat error:", err instanceof Error ? err.message : err);
21
+ }
22
+ };
23
+ timer = setInterval(tick, intervalMs);
24
+ // Send an initial heartbeat immediately
25
+ tick();
26
+ return {
27
+ stop() {
28
+ if (timer) {
29
+ clearInterval(timer);
30
+ timer = null;
31
+ }
32
+ },
33
+ };
34
+ }
35
+ //# sourceMappingURL=heartbeat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartbeat.js","sourceRoot":"","sources":["../src/heartbeat.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,SAAiB,EACjB,KAAa,EACb,UAAU,GAAG,MAAM;IAEnB,IAAI,KAAK,GAA0C,IAAI,CAAC;IAExD,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,OAAO,iBAAiB,SAAS,kBAAkB,EACtD;gBACE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;aAC9C,CACF,CAAC;YACF,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACX,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,8BAA8B,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CACX,yBAAyB,EACzB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACzC,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAEtC,wCAAwC;IACxC,IAAI,EAAE,CAAC;IAEP,OAAO;QACL,IAAI;YACF,IAAI,KAAK,EAAE,CAAC;gBACV,aAAa,CAAC,KAAK,CAAC,CAAC;gBACrB,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * sf-builder-agent — Desktop CLI for SalesForce Agent Creator.
4
+ *
5
+ * Connects to the web app, receives browser automation commands via SSE,
6
+ * executes them in a visible Chrome window, and reports results back.
7
+ */
8
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * sf-builder-agent — Desktop CLI for SalesForce Agent Creator.
4
+ *
5
+ * Connects to the web app, receives browser automation commands via SSE,
6
+ * executes them in a visible Chrome window, and reports results back.
7
+ */
8
+ import { createInterface } from "node:readline/promises";
9
+ import { stdin, stdout } from "node:process";
10
+ import { pair } from "./pairing.js";
11
+ import { connectSSE } from "./sse-client.js";
12
+ import { launchBrowser, executeCommand } from "./browser.js";
13
+ import { reportResult } from "./reporter.js";
14
+ import { startHeartbeat } from "./heartbeat.js";
15
+ // ─── Arg Parsing ─────────────────────────────────────────────────────
16
+ function parseArgs(argv) {
17
+ const args = {};
18
+ for (let i = 2; i < argv.length; i++) {
19
+ const key = argv[i];
20
+ const val = argv[i + 1];
21
+ if (key === "--code" && val) {
22
+ args.code = val;
23
+ i++;
24
+ }
25
+ else if (key === "--session" && val) {
26
+ args.session = val;
27
+ i++;
28
+ }
29
+ else if (key === "--url" && val) {
30
+ args.url = val;
31
+ i++;
32
+ }
33
+ }
34
+ return {
35
+ code: args.code,
36
+ session: args.session,
37
+ url: args.url ?? "https://sf-builder.cmgfinancial.ai",
38
+ };
39
+ }
40
+ // ─── Prompt Helper ───────────────────────────────────────────────────
41
+ async function prompt(question) {
42
+ const rl = createInterface({ input: stdin, output: stdout });
43
+ try {
44
+ const answer = await rl.question(question);
45
+ return answer.trim();
46
+ }
47
+ finally {
48
+ rl.close();
49
+ }
50
+ }
51
+ // ─── Main ────────────────────────────────────────────────────────────
52
+ async function main() {
53
+ const args = parseArgs(process.argv);
54
+ let code = args.code;
55
+ let sessionId = args.session;
56
+ const baseUrl = args.url;
57
+ // Interactive prompts if args are missing
58
+ if (!sessionId) {
59
+ sessionId = await prompt("Enter session ID: ");
60
+ if (!sessionId) {
61
+ console.error("\u274C Session ID is required");
62
+ process.exit(1);
63
+ }
64
+ }
65
+ if (!code) {
66
+ code = await prompt("Enter pairing code: ");
67
+ if (!code) {
68
+ console.error("\u274C Pairing code is required");
69
+ process.exit(1);
70
+ }
71
+ }
72
+ // ── Step 1: Pair ──
73
+ console.log("\uD83D\uDD17 Pairing...");
74
+ let token;
75
+ try {
76
+ const pairResult = await pair(baseUrl, sessionId, code);
77
+ token = pairResult.token;
78
+ sessionId = pairResult.sessionId;
79
+ console.log("\u2705 Paired successfully");
80
+ }
81
+ catch (err) {
82
+ console.error("\u274C Pairing failed:", err instanceof Error ? err.message : err);
83
+ process.exit(1);
84
+ }
85
+ // ── Step 2: Launch Browser ──
86
+ console.log("\uD83C\uDF10 Launching browser...");
87
+ let browser;
88
+ let page;
89
+ try {
90
+ const launched = await launchBrowser();
91
+ browser = launched.browser;
92
+ page = launched.page;
93
+ console.log("\u2705 Browser ready");
94
+ }
95
+ catch (err) {
96
+ console.error("\u274C Browser launch failed:", err instanceof Error ? err.message : err);
97
+ process.exit(1);
98
+ }
99
+ // ── Step 3: Start Heartbeat ──
100
+ const heartbeat = startHeartbeat(baseUrl, sessionId, token);
101
+ // ── Step 4: Connect to command stream ──
102
+ console.log("\uD83D\uDCE1 Connecting to command stream...");
103
+ const sse = connectSSE(baseUrl, sessionId, token, async (command) => {
104
+ const label = command.stepKey
105
+ ? `${command.commandType} (step: ${command.stepKey})`
106
+ : command.commandType;
107
+ const payloadHint = command.commandType === "navigate"
108
+ ? ` \u2192 ${command.payload.url}`
109
+ : "";
110
+ console.log(`\u26A1 Executing: ${label}${payloadHint}`);
111
+ const result = await executeCommand(page, command.commandType, command.payload);
112
+ if (result.success) {
113
+ console.log(`\u2705 Command complete: ${command.commandType}`);
114
+ }
115
+ else {
116
+ console.error(`\u274C Command failed: ${command.commandType} \u2014 ${result.error}`);
117
+ }
118
+ // Report back to server
119
+ const resultPayload = {};
120
+ if (result.result !== undefined)
121
+ resultPayload.result = result.result;
122
+ if (result.screenshot)
123
+ resultPayload.screenshot = result.screenshot;
124
+ if (result.error)
125
+ resultPayload.error = result.error;
126
+ await reportResult(baseUrl, sessionId, token, command.id, result.success ? "success" : "error", Object.keys(resultPayload).length > 0 ? resultPayload : undefined);
127
+ // Handle shutdown command
128
+ if (result.shutdown) {
129
+ console.log("\uD83D\uDC4B Shutting down (server requested)...");
130
+ shutdown();
131
+ }
132
+ }, (err) => {
133
+ console.error(`\u274C SSE error: ${err.message}`);
134
+ });
135
+ // ── Graceful Shutdown ──
136
+ let shuttingDown = false;
137
+ function shutdown() {
138
+ if (shuttingDown)
139
+ return;
140
+ shuttingDown = true;
141
+ console.log("\uD83D\uDC4B Shutting down...");
142
+ sse.close();
143
+ heartbeat.stop();
144
+ browser
145
+ .close()
146
+ .catch(() => { })
147
+ .finally(() => {
148
+ process.exit(0);
149
+ });
150
+ }
151
+ process.on("SIGINT", shutdown);
152
+ process.on("SIGTERM", shutdown);
153
+ // Keep alive
154
+ process.stdin.resume();
155
+ }
156
+ main().catch((err) => {
157
+ console.error("\u274C Fatal error:", err instanceof Error ? err.message : err);
158
+ process.exit(1);
159
+ });
160
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Pairing — exchange a one-time code for a persistent auth token.
3
+ */
4
+ export declare function pair(baseUrl: string, sessionId: string, code: string): Promise<{
5
+ token: string;
6
+ sessionId: string;
7
+ }>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Pairing — exchange a one-time code for a persistent auth token.
3
+ */
4
+ export async function pair(baseUrl, sessionId, code) {
5
+ const url = `${baseUrl}/api/sessions/${sessionId}/agent/pair`;
6
+ const res = await fetch(url, {
7
+ method: "POST",
8
+ headers: { "Content-Type": "application/json" },
9
+ body: JSON.stringify({ code }),
10
+ });
11
+ if (!res.ok) {
12
+ const body = await res.text().catch(() => "");
13
+ throw new Error(`Pairing failed (${res.status}): ${body || res.statusText}`);
14
+ }
15
+ const data = (await res.json());
16
+ if (!data.token) {
17
+ throw new Error("Pairing response did not include a token");
18
+ }
19
+ return { token: data.token, sessionId: data.sessionId ?? sessionId };
20
+ }
21
+ //# sourceMappingURL=pairing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairing.js","sourceRoot":"","sources":["../src/pairing.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,OAAe,EACf,SAAiB,EACjB,IAAY;IAEZ,MAAM,GAAG,GAAG,GAAG,OAAO,iBAAiB,SAAS,aAAa,CAAC;IAE9D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;KAC/B,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,KAAK,CACb,mBAAmB,GAAG,CAAC,MAAM,MAAM,IAAI,IAAI,GAAG,CAAC,UAAU,EAAE,CAC5D,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA2C,CAAC;IAE1E,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,SAAS,EAAE,CAAC;AACvE,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Reporter — POST command results back to the web app.
3
+ */
4
+ export declare function reportResult(baseUrl: string, sessionId: string, token: string, commandId: string, status: "success" | "error", result?: Record<string, unknown>): Promise<void>;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Reporter — POST command results back to the web app.
3
+ */
4
+ export async function reportResult(baseUrl, sessionId, token, commandId, status, result) {
5
+ const url = `${baseUrl}/api/sessions/${sessionId}/agent/result`;
6
+ try {
7
+ const res = await fetch(url, {
8
+ method: "POST",
9
+ headers: {
10
+ Authorization: `Bearer ${token}`,
11
+ "Content-Type": "application/json",
12
+ },
13
+ body: JSON.stringify({ commandId, status, result }),
14
+ });
15
+ if (!res.ok) {
16
+ const body = await res.text().catch(() => "");
17
+ console.error(`\u274C Report failed (${res.status}): ${body || res.statusText}`);
18
+ }
19
+ }
20
+ catch (err) {
21
+ console.error(`\u274C Report error:`, err instanceof Error ? err.message : err);
22
+ }
23
+ }
24
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,SAAiB,EACjB,KAAa,EACb,SAAiB,EACjB,MAA2B,EAC3B,MAAgC;IAEhC,MAAM,GAAG,GAAG,GAAG,OAAO,iBAAiB,SAAS,eAAe,CAAC;IAEhE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,KAAK,EAAE;gBAChC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;SACpD,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,OAAO,CAAC,KAAK,CAAC,yBAAyB,GAAG,CAAC,MAAM,MAAM,IAAI,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CACX,sBAAsB,EACtB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACzC,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * SSE client — listens for browser-automation commands from the server.
3
+ */
4
+ interface IncomingCommand {
5
+ id: string;
6
+ commandType: string;
7
+ stepKey: string | null;
8
+ payload: Record<string, unknown>;
9
+ }
10
+ export declare function connectSSE(baseUrl: string, sessionId: string, token: string, onCommand: (command: IncomingCommand) => void, onError: (error: Error) => void): {
11
+ close: () => void;
12
+ };
13
+ export {};