@canaryai/cli 0.1.11 → 0.1.13

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 @@
1
+ {"version":3,"sources":["../src/local-browser/host.ts"],"sourcesContent":["/**\n * Local Browser Host\n *\n * Manages a local browser instance and handles commands from the cloud API\n * via WebSocket. This enables cloud agents to control a browser running\n * on the user's local machine.\n */\n\nimport { chromium, type Browser, type BrowserContext, type Page, type Dialog } from \"playwright\";\nimport type {\n BrowserCommand,\n BrowserResponse,\n HeartbeatMessage,\n SessionMessage,\n LocalBrowserMode,\n} from \"./protocol\";\n\nconst HEARTBEAT_INTERVAL_MS = 30_000;\nconst RECONNECT_DELAY_MS = 1000;\nconst MAX_RECONNECT_DELAY_MS = 30_000;\nconst MAX_RECONNECT_ATTEMPTS = 10;\n\nexport interface LocalBrowserHostOptions {\n apiUrl: string;\n wsToken: string;\n sessionId: string;\n browserMode: LocalBrowserMode;\n cdpUrl?: string;\n headless?: boolean;\n storageStatePath?: string;\n onLog?: (level: \"info\" | \"warn\" | \"error\" | \"debug\", message: string, data?: unknown) => void;\n}\n\ninterface PageWithAISnapshot extends Page {\n _snapshotForAI(options: { mode: \"full\" | \"compact\" }): Promise<string>;\n}\n\n/**\n * LocalBrowserHost manages the browser and WebSocket connection to the cloud.\n */\ntype ContextSlot = {\n context: BrowserContext;\n page: Page;\n pendingDialogs: Dialog[];\n};\n\nexport class LocalBrowserHost {\n private options: LocalBrowserHostOptions;\n private ws: WebSocket | null = null;\n private browser: Browser | null = null;\n private contexts = new Map<string, ContextSlot>();\n private static DEFAULT_CONTEXT_ID = \"__default__\";\n private heartbeatTimer: NodeJS.Timeout | null = null;\n private reconnectAttempts = 0;\n private isShuttingDown = false;\n private lastSnapshotYaml = \"\";\n\n constructor(options: LocalBrowserHostOptions) {\n this.options = options;\n }\n\n private log(level: \"info\" | \"warn\" | \"error\" | \"debug\", message: string, data?: unknown) {\n if (this.options.onLog) {\n this.options.onLog(level, message, data);\n } else {\n const fn = level === \"error\" ? console.error : level === \"warn\" ? console.warn : console.log;\n fn(`[LocalBrowserHost] ${message}`, data ?? \"\");\n }\n }\n\n // =========================================================================\n // Lifecycle\n // =========================================================================\n\n async start(): Promise<void> {\n this.log(\"info\", \"Starting local browser host\", {\n browserMode: this.options.browserMode,\n sessionId: this.options.sessionId,\n });\n\n // Connect to WebSocket first\n await this.connectWebSocket();\n\n // Then launch browser\n await this.launchBrowser();\n\n // Notify cloud that browser is ready\n this.sendSessionEvent(\"browser_ready\");\n }\n\n async stop(): Promise<void> {\n this.isShuttingDown = true;\n this.log(\"info\", \"Stopping local browser host\");\n\n this.stopHeartbeat();\n\n if (this.ws) {\n try {\n this.ws.close(1000, \"Shutdown\");\n } catch {}\n this.ws = null;\n }\n\n for (const [id, slot] of this.contexts) {\n try {\n await slot.context.close();\n } catch {}\n }\n this.contexts.clear();\n\n if (this.browser) {\n try {\n await this.browser.close();\n } catch {}\n this.browser = null;\n }\n this.log(\"info\", \"Local browser host stopped\");\n }\n\n // =========================================================================\n // WebSocket Connection\n // =========================================================================\n\n private async connectWebSocket(): Promise<void> {\n return new Promise((resolve, reject) => {\n const wsUrl = `${this.options.apiUrl.replace(\"http\", \"ws\")}/local-browser/sessions/${this.options.sessionId}/connect?token=${this.options.wsToken}`;\n\n this.log(\"info\", \"Connecting to cloud API\", { url: wsUrl.replace(/token=.*/, \"token=***\") });\n\n const ws = new WebSocket(wsUrl);\n\n ws.onopen = () => {\n this.log(\"info\", \"Connected to cloud API\");\n this.ws = ws;\n this.reconnectAttempts = 0;\n this.startHeartbeat();\n resolve();\n };\n\n ws.onmessage = (event) => {\n this.handleMessage(event.data as string);\n };\n\n ws.onerror = (event) => {\n this.log(\"error\", \"WebSocket error\", event);\n };\n\n ws.onclose = () => {\n this.log(\"info\", \"WebSocket closed\");\n this.stopHeartbeat();\n this.ws = null;\n\n if (!this.isShuttingDown) {\n this.scheduleReconnect();\n }\n };\n\n // Timeout after 30 seconds\n setTimeout(() => {\n if (!this.ws) {\n reject(new Error(\"WebSocket connection timeout\"));\n }\n }, 30_000);\n });\n }\n\n private scheduleReconnect(): void {\n if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {\n this.log(\"error\", \"Max reconnection attempts reached, giving up\");\n this.stop();\n return;\n }\n\n const delay = Math.min(\n RECONNECT_DELAY_MS * Math.pow(2, this.reconnectAttempts),\n MAX_RECONNECT_DELAY_MS\n );\n\n this.reconnectAttempts++;\n this.log(\"info\", `Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);\n\n setTimeout(async () => {\n try {\n await this.connectWebSocket();\n this.sendSessionEvent(\"connected\");\n if (this.page) {\n this.sendSessionEvent(\"browser_ready\");\n }\n } catch (error) {\n this.log(\"error\", \"Reconnection failed\", error);\n this.scheduleReconnect();\n }\n }, delay);\n }\n\n // =========================================================================\n // Heartbeat\n // =========================================================================\n\n private startHeartbeat(): void {\n this.stopHeartbeat();\n this.heartbeatTimer = setInterval(() => {\n if (this.ws?.readyState === WebSocket.OPEN) {\n const ping: HeartbeatMessage = {\n type: \"heartbeat\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n direction: \"pong\",\n };\n this.ws.send(JSON.stringify(ping));\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n // =========================================================================\n // Browser Management\n // =========================================================================\n\n private async launchBrowser(): Promise<void> {\n const { browserMode, cdpUrl, headless = true, storageStatePath } = this.options;\n\n if (browserMode === \"cdp\" && cdpUrl) {\n this.log(\"info\", \"Connecting to existing Chrome via CDP\", { cdpUrl });\n this.browser = await chromium.connectOverCDP(cdpUrl);\n const existingContexts = this.browser.contexts();\n const ctx = existingContexts[0] ?? (await this.browser.newContext());\n const pages = ctx.pages();\n const pg = pages[0] ?? (await ctx.newPage());\n const slot: ContextSlot = { context: ctx, page: pg, pendingDialogs: [] };\n pg.on(\"dialog\", (dialog) => slot.pendingDialogs.push(dialog));\n this.contexts.set(LocalBrowserHost.DEFAULT_CONTEXT_ID, slot);\n } else {\n this.log(\"info\", \"Launching new Playwright browser\", { headless });\n this.browser = await chromium.launch({\n headless,\n args: [\"--no-sandbox\"],\n });\n\n const contextOptions: { viewport: { width: number; height: number }; storageState?: string } =\n {\n viewport: { width: 1920, height: 1080 },\n };\n\n if (storageStatePath) {\n try {\n await Bun.file(storageStatePath).exists();\n contextOptions.storageState = storageStatePath;\n this.log(\"info\", \"Loading storage state\", { storageStatePath });\n } catch {\n this.log(\"debug\", \"Storage state file not found, starting fresh\");\n }\n }\n\n const ctx = await this.browser.newContext(contextOptions);\n const pg = await ctx.newPage();\n const slot: ContextSlot = { context: ctx, page: pg, pendingDialogs: [] };\n pg.on(\"dialog\", (dialog) => slot.pendingDialogs.push(dialog));\n this.contexts.set(LocalBrowserHost.DEFAULT_CONTEXT_ID, slot);\n }\n\n this.log(\"info\", \"Browser ready\");\n }\n\n // =========================================================================\n // Message Handling\n // =========================================================================\n\n private handleMessage(data: string): void {\n try {\n const message = JSON.parse(data);\n\n if (message.type === \"heartbeat\" && message.direction === \"ping\") {\n // Respond to ping with pong\n const pong: HeartbeatMessage = {\n type: \"heartbeat\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n direction: \"pong\",\n };\n this.ws?.send(JSON.stringify(pong));\n return;\n }\n\n if (message.type === \"command\") {\n this.handleCommand(message as BrowserCommand);\n return;\n }\n\n this.log(\"debug\", \"Received unknown message type\", message);\n } catch (error) {\n this.log(\"error\", \"Failed to parse message\", { error, data });\n }\n }\n\n private async handleCommand(command: BrowserCommand): Promise<void> {\n const startTime = Date.now();\n const contextId = command.contextId;\n this.log(\"debug\", `Executing command: ${command.method}`, { id: command.id, contextId });\n\n try {\n const result = await this.executeMethod(command.method, command.args, contextId);\n const response: BrowserResponse = {\n type: \"response\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n requestId: command.id,\n success: true,\n result,\n contextId,\n };\n this.ws?.send(JSON.stringify(response));\n\n this.log(\"debug\", `Command completed: ${command.method}`, {\n id: command.id,\n contextId,\n durationMs: Date.now() - startTime,\n });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const response: BrowserResponse = {\n type: \"response\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n requestId: command.id,\n success: false,\n error: errorMessage,\n stack: error instanceof Error ? error.stack : undefined,\n contextId,\n };\n this.ws?.send(JSON.stringify(response));\n\n this.log(\"error\", `Command failed: ${command.method}`, {\n id: command.id,\n contextId,\n error: errorMessage,\n });\n }\n }\n\n private sendSessionEvent(\n event: \"connected\" | \"disconnected\" | \"browser_ready\" | \"browser_closed\" | \"error\",\n error?: string\n ): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;\n\n const message: SessionMessage = {\n type: \"session\",\n id: crypto.randomUUID(),\n timestamp: Date.now(),\n event,\n browserMode: this.options.browserMode,\n error,\n };\n this.ws.send(JSON.stringify(message));\n }\n\n // =========================================================================\n // Method Execution\n // =========================================================================\n\n private getSlot(contextId?: string): ContextSlot {\n const id = contextId ?? LocalBrowserHost.DEFAULT_CONTEXT_ID;\n const slot = this.contexts.get(id);\n if (!slot) throw new Error(`Context not found: ${id}`);\n return slot;\n }\n\n private async createContextSlot(\n contextId: string,\n options?: { storageState?: unknown }\n ): Promise<void> {\n if (!this.browser) throw new Error(\"No browser available\");\n if (this.contexts.has(contextId)) throw new Error(`Context already exists: ${contextId}`);\n\n const contextOptions: { viewport: { width: number; height: number }; storageState?: string } = {\n viewport: { width: 1920, height: 1080 },\n };\n\n if (options?.storageState) {\n const tmpPath = `/tmp/storage-state-${crypto.randomUUID()}.json`;\n await Bun.write(tmpPath, JSON.stringify(options.storageState));\n contextOptions.storageState = tmpPath;\n this.log(\"info\", \"Loaded inline storage state for new context\", { contextId });\n }\n\n const ctx = await this.browser.newContext(contextOptions);\n const pg = await ctx.newPage();\n const slot: ContextSlot = { context: ctx, page: pg, pendingDialogs: [] };\n pg.on(\"dialog\", (dialog) => slot.pendingDialogs.push(dialog));\n this.contexts.set(contextId, slot);\n this.log(\"info\", \"Created new context slot\", { contextId });\n }\n\n private async destroyContextSlot(contextId: string): Promise<void> {\n if (contextId === LocalBrowserHost.DEFAULT_CONTEXT_ID) {\n throw new Error(\"Cannot destroy the default context\");\n }\n const slot = this.contexts.get(contextId);\n if (!slot) throw new Error(`Context not found: ${contextId}`);\n\n try {\n await slot.context.close();\n } catch {}\n this.contexts.delete(contextId);\n this.log(\"info\", \"Destroyed context slot\", { contextId });\n }\n\n private async executeMethod(method: string, args: unknown[], contextId?: string): Promise<unknown> {\n // Context lifecycle commands\n switch (method) {\n case \"createContext\":\n return this.createContextSlot(args[0] as string, args[1] as any);\n case \"destroyContext\":\n return this.destroyContextSlot(args[0] as string);\n }\n\n // Route to appropriate handler\n switch (method) {\n // Lifecycle\n case \"connect\":\n return this.connect(args[0] as any);\n case \"disconnect\":\n return this.disconnect();\n\n // Navigation\n case \"navigate\":\n return this.navigate(args[0] as string, args[1] as any, contextId);\n case \"navigateBack\":\n return this.navigateBack(args[0] as any, contextId);\n\n // Page Inspection\n case \"snapshot\":\n return this.snapshot(args[0] as any, contextId);\n case \"takeScreenshot\":\n return this.takeScreenshot(args[0] as any, contextId);\n case \"evaluate\":\n return this.evaluate(args[0] as string, args[1] as any, contextId);\n case \"runCode\":\n return this.runCode(args[0] as string, args[1] as any, contextId);\n case \"consoleMessages\":\n return this.consoleMessages(args[0] as any);\n case \"networkRequests\":\n return this.networkRequests(args[0] as any);\n\n // Interaction\n case \"click\":\n return this.click(args[0] as string, args[1] as string, args[2] as any, contextId);\n case \"clickAtCoordinates\":\n return this.clickAtCoordinates(\n args[0] as number,\n args[1] as number,\n args[2] as string,\n args[3] as any,\n contextId\n );\n case \"moveToCoordinates\":\n return this.moveToCoordinates(\n args[0] as number,\n args[1] as number,\n args[2] as string,\n args[3] as any,\n contextId\n );\n case \"dragCoordinates\":\n return this.dragCoordinates(\n args[0] as number,\n args[1] as number,\n args[2] as number,\n args[3] as number,\n args[4] as string,\n args[5] as any,\n contextId\n );\n case \"hover\":\n return this.hover(args[0] as string, args[1] as string, args[2] as any, contextId);\n case \"drag\":\n return this.drag(\n args[0] as string,\n args[1] as string,\n args[2] as string,\n args[3] as string,\n args[4] as any,\n contextId\n );\n case \"type\":\n return this.type(\n args[0] as string,\n args[1] as string,\n args[2] as string,\n args[3] as boolean,\n args[4] as any,\n contextId\n );\n case \"pressKey\":\n return this.pressKey(args[0] as string, args[1] as any, contextId);\n case \"fillForm\":\n return this.fillForm(args[0] as any[], args[1] as any, contextId);\n case \"selectOption\":\n return this.selectOption(\n args[0] as string,\n args[1] as string,\n args[2] as string,\n args[3] as any,\n contextId\n );\n case \"fileUpload\":\n return this.fileUpload(args[0] as string[], args[1] as any, contextId);\n\n // Dialogs\n case \"handleDialog\":\n return this.handleDialog(args[0] as \"accept\" | \"dismiss\", args[1] as string, args[2] as any, contextId);\n\n // Waiting\n case \"waitFor\":\n return this.waitFor(args[0] as any, contextId);\n\n // Browser Management\n case \"close\":\n return this.closePage(args[0] as any, contextId);\n case \"resize\":\n return this.resize(args[0] as number, args[1] as number, args[2] as any, contextId);\n case \"tabs\":\n return this.tabs(args[0] as any, args[1] as number, args[2] as any, contextId);\n\n // Context Management\n case \"swapContext\":\n return this.handleSwapContext(args[0] as any, contextId);\n\n // Storage\n case \"getStorageState\":\n return this.getStorageState(args[0] as any, contextId);\n case \"getCurrentUrl\":\n return this.getCurrentUrl(args[0] as any, contextId);\n case \"getTitle\":\n return this.getTitle(args[0] as any, contextId);\n case \"getLinks\":\n return this.getLinks(args[0] as any, contextId);\n case \"getElementBoundingBox\":\n return this.getElementBoundingBox(args[0] as string, args[1] as any, contextId);\n\n // Tracing\n case \"startTracing\":\n return this.startTracing(args[0] as any, contextId);\n case \"stopTracing\":\n return this.stopTracing(args[0] as any, contextId);\n\n // Video\n case \"isVideoRecordingEnabled\":\n return false; // Video not supported in CLI host currently\n case \"saveVideo\":\n return null;\n case \"getVideoPath\":\n return null;\n\n default:\n throw new Error(`Unknown method: ${method}`);\n }\n }\n\n // =========================================================================\n // IBrowserClient Method Implementations\n // =========================================================================\n\n private async handleSwapContext(options: {\n storageState?: unknown;\n storageStatePath?: string;\n recordVideo?: boolean;\n }, contextId?: string): Promise<void> {\n if (!this.browser) throw new Error(\"No browser available\");\n\n const slotId = contextId ?? LocalBrowserHost.DEFAULT_CONTEXT_ID;\n const existing = this.contexts.get(slotId);\n\n // Close existing context (and its pages)\n if (existing) {\n await existing.context.close();\n this.contexts.delete(slotId);\n }\n\n // Build context options\n const contextOptions: { viewport: { width: number; height: number }; storageState?: string } = {\n viewport: { width: 1920, height: 1080 },\n };\n\n if (options.storageState) {\n const tmpPath = `/tmp/storage-state-${crypto.randomUUID()}.json`;\n await Bun.write(tmpPath, JSON.stringify(options.storageState));\n contextOptions.storageState = tmpPath;\n this.log(\"info\", \"Loaded inline storage state for context swap\");\n } else if (options.storageStatePath) {\n try {\n const exists = await Bun.file(options.storageStatePath).exists();\n if (exists) {\n contextOptions.storageState = options.storageStatePath;\n this.log(\"info\", \"Loading storage state from file for context swap\", {\n storageStatePath: options.storageStatePath,\n });\n }\n } catch {\n this.log(\"debug\", \"Storage state file not found, starting fresh context\");\n }\n }\n\n const ctx = await this.browser.newContext(contextOptions);\n const pg = await ctx.newPage();\n const slot: ContextSlot = { context: ctx, page: pg, pendingDialogs: [] };\n pg.on(\"dialog\", (dialog) => slot.pendingDialogs.push(dialog));\n this.contexts.set(slotId, slot);\n\n this.log(\"info\", \"Browser context swapped successfully\", { contextId: slotId });\n }\n\n private getPage(contextId?: string): Page {\n return this.getSlot(contextId).page;\n }\n\n private resolveRef(ref: string, contextId?: string) {\n return this.getPage(contextId).locator(`aria-ref=${ref}`);\n }\n\n private async connect(_options: any): Promise<void> {\n // Browser already launched in start()\n return;\n }\n\n private async disconnect(): Promise<void> {\n await this.stop();\n }\n\n private async navigate(url: string, _opts?: any, contextId?: string): Promise<string> {\n const page = this.getPage(contextId);\n await page.goto(url, { waitUntil: \"domcontentloaded\" });\n await page.waitForLoadState(\"load\", { timeout: 5000 }).catch(() => {});\n return this.captureSnapshot(contextId);\n }\n\n private async navigateBack(_opts?: any, contextId?: string): Promise<string> {\n await this.getPage(contextId).goBack();\n return this.captureSnapshot(contextId);\n }\n\n private async snapshot(_opts?: any, contextId?: string): Promise<string> {\n return this.captureSnapshot(contextId);\n }\n\n private async captureSnapshot(contextId?: string): Promise<string> {\n const page = this.getPage(contextId) as PageWithAISnapshot;\n this.lastSnapshotYaml = await page._snapshotForAI({ mode: \"full\" });\n return this.lastSnapshotYaml;\n }\n\n private async takeScreenshot(opts?: any, contextId?: string): Promise<string | null> {\n const page = this.getPage(contextId);\n const buffer = await page.screenshot({\n type: opts?.type ?? \"jpeg\",\n fullPage: opts?.fullPage ?? false,\n });\n const mime = opts?.type === \"png\" ? \"image/png\" : \"image/jpeg\";\n return `data:${mime};base64,${buffer.toString(\"base64\")}`;\n }\n\n private async evaluate<T>(fn: string, _opts?: any, contextId?: string): Promise<T> {\n const page = this.getPage(contextId);\n return page.evaluate(new Function(`return (${fn})()`) as () => T);\n }\n\n private async runCode(code: string, _opts?: any, contextId?: string): Promise<unknown> {\n const page = this.getPage(contextId);\n const fn = new Function(\"page\", `return (async () => { ${code} })()`) as (\n p: Page\n ) => Promise<unknown>;\n return fn(page);\n }\n\n private async consoleMessages(_opts?: any): Promise<string> {\n return \"Console message capture not implemented in CLI host\";\n }\n\n private async networkRequests(_opts?: any): Promise<string> {\n return \"Network request capture not implemented in CLI host\";\n }\n\n private async click(ref: string, _elementDesc?: string, opts?: any, contextId?: string): Promise<void> {\n const locator = this.resolveRef(ref, contextId);\n await locator.scrollIntoViewIfNeeded({ timeout: 5000 }).catch(() => {});\n\n const box = await locator.boundingBox();\n if (box) {\n const centerX = box.x + box.width / 2;\n const centerY = box.y + box.height / 2;\n const page = this.getPage(contextId);\n\n if (opts?.modifiers?.length) {\n for (const mod of opts.modifiers) {\n await page.keyboard.down(mod);\n }\n }\n\n if (opts?.doubleClick) {\n await page.mouse.dblclick(centerX, centerY);\n } else {\n await page.mouse.click(centerX, centerY);\n }\n\n if (opts?.modifiers?.length) {\n for (const mod of opts.modifiers) {\n await page.keyboard.up(mod);\n }\n }\n } else {\n if (opts?.doubleClick) {\n await locator.dblclick({ timeout: opts?.timeoutMs ?? 30000 });\n } else {\n await locator.click({ timeout: opts?.timeoutMs ?? 30000 });\n }\n }\n }\n\n private async clickAtCoordinates(\n x: number,\n y: number,\n _elementDesc: string,\n opts?: any,\n contextId?: string\n ): Promise<void> {\n const page = this.getPage(contextId);\n if (opts?.doubleClick) {\n await page.mouse.dblclick(x, y);\n } else {\n await page.mouse.click(x, y);\n }\n }\n\n private async moveToCoordinates(\n x: number,\n y: number,\n _elementDesc: string,\n _opts?: any,\n contextId?: string\n ): Promise<void> {\n await this.getPage(contextId).mouse.move(x, y);\n }\n\n private async dragCoordinates(\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n _elementDesc: string,\n _opts?: any,\n contextId?: string\n ): Promise<void> {\n const page = this.getPage(contextId);\n await page.mouse.move(startX, startY);\n await page.mouse.down();\n await page.mouse.move(endX, endY);\n await page.mouse.up();\n }\n\n private async hover(ref: string, _elementDesc?: string, opts?: any, contextId?: string): Promise<void> {\n await this.resolveRef(ref, contextId).hover({ timeout: opts?.timeoutMs ?? 30000 });\n }\n\n private async drag(\n startRef: string,\n _startElement: string,\n endRef: string,\n _endElement: string,\n opts?: any,\n contextId?: string\n ): Promise<void> {\n const startLocator = this.resolveRef(startRef, contextId);\n const endLocator = this.resolveRef(endRef, contextId);\n await startLocator.dragTo(endLocator, { timeout: opts?.timeoutMs ?? 60000 });\n }\n\n private async type(\n ref: string,\n text: string,\n _elementDesc?: string,\n submit?: boolean,\n opts?: any,\n contextId?: string\n ): Promise<void> {\n const locator = this.resolveRef(ref, contextId);\n await locator.clear();\n await locator.pressSequentially(text, {\n delay: opts?.delay ?? 0,\n timeout: opts?.timeoutMs ?? 30000,\n });\n if (submit) {\n await locator.press(\"Enter\");\n }\n }\n\n private async pressKey(key: string, _opts?: any, contextId?: string): Promise<void> {\n await this.getPage(contextId).keyboard.press(key);\n }\n\n private async fillForm(fields: any[], opts?: any, contextId?: string): Promise<void> {\n for (const field of fields) {\n const locator = this.resolveRef(field.ref, contextId);\n const fieldType = field.type ?? \"textbox\";\n\n switch (fieldType) {\n case \"checkbox\": {\n const isChecked = await locator.isChecked();\n const shouldBeChecked = field.value === \"true\";\n if (shouldBeChecked !== isChecked) {\n await locator.click({ timeout: opts?.timeoutMs ?? 30000 });\n }\n break;\n }\n case \"radio\":\n await locator.check({ timeout: opts?.timeoutMs ?? 30000 });\n break;\n case \"combobox\":\n await locator.selectOption(field.value, { timeout: opts?.timeoutMs ?? 30000 });\n break;\n default:\n await locator.fill(field.value, { timeout: opts?.timeoutMs ?? 30000 });\n }\n }\n }\n\n private async selectOption(\n ref: string,\n value: string,\n _elementDesc?: string,\n opts?: any,\n contextId?: string\n ): Promise<void> {\n await this.resolveRef(ref, contextId).selectOption(value, { timeout: opts?.timeoutMs ?? 30000 });\n }\n\n private async fileUpload(paths: string[], opts?: any, contextId?: string): Promise<void> {\n const fileChooser = await this.getPage(contextId).waitForEvent(\"filechooser\", {\n timeout: opts?.timeoutMs ?? 30000,\n });\n await fileChooser.setFiles(paths);\n }\n\n private async handleDialog(\n action: \"accept\" | \"dismiss\",\n promptText?: string,\n _opts?: any,\n contextId?: string\n ): Promise<void> {\n const slot = this.getSlot(contextId);\n const dialog = slot.pendingDialogs.shift();\n if (dialog) {\n if (action === \"accept\") {\n await dialog.accept(promptText);\n } else {\n await dialog.dismiss();\n }\n }\n }\n\n private async waitFor(opts?: any, contextId?: string): Promise<void> {\n const page = this.getPage(contextId);\n const timeout = opts?.timeout ?? opts?.timeoutMs ?? 30000;\n\n if (opts?.timeSec) {\n await page.waitForTimeout(opts.timeSec * 1000);\n return;\n }\n if (opts?.text) {\n await page.getByText(opts.text).first().waitFor({ state: \"visible\", timeout });\n return;\n }\n if (opts?.textGone) {\n await page.getByText(opts.textGone).first().waitFor({ state: \"hidden\", timeout });\n return;\n }\n if (opts?.selector) {\n await page.locator(opts.selector).waitFor({\n state: opts.state ?? \"visible\",\n timeout,\n });\n }\n }\n\n private async closePage(_opts?: any, contextId?: string): Promise<void> {\n const slot = this.getSlot(contextId);\n await slot.page.close();\n // If context still has pages, use the first one\n const remaining = slot.context.pages();\n if (remaining.length > 0) {\n slot.page = remaining[0];\n }\n }\n\n private async resize(width: number, height: number, _opts?: any, contextId?: string): Promise<void> {\n await this.getPage(contextId).setViewportSize({ width, height });\n }\n\n private async tabs(action: string, index?: number, _opts?: any, contextId?: string): Promise<unknown> {\n const slot = this.getSlot(contextId);\n const pages = slot.context.pages();\n\n switch (action) {\n case \"list\":\n return Promise.all(\n pages.map(async (p, i) => ({\n index: i,\n url: p.url(),\n title: await p.title().catch(() => \"\"),\n }))\n );\n case \"new\": {\n const newPage = await slot.context.newPage();\n slot.page = newPage;\n newPage.on(\"dialog\", (dialog) => slot.pendingDialogs.push(dialog));\n return { index: pages.length };\n }\n case \"close\":\n if (index !== undefined && pages[index]) {\n await pages[index].close();\n } else {\n await slot.page.close();\n }\n slot.page = slot.context.pages()[0] ?? slot.page;\n break;\n case \"select\":\n if (index !== undefined && pages[index]) {\n slot.page = pages[index];\n }\n break;\n }\n return null;\n }\n\n private async getStorageState(_opts?: any, contextId?: string): Promise<unknown> {\n const slot = this.getSlot(contextId);\n return slot.context.storageState();\n }\n\n private async getCurrentUrl(_opts?: any, contextId?: string): Promise<string> {\n return this.getPage(contextId).url();\n }\n\n private async getTitle(_opts?: any, contextId?: string): Promise<string> {\n return this.getPage(contextId).title();\n }\n\n private async getLinks(_opts?: any, contextId?: string): Promise<string[]> {\n const page = this.getPage(contextId);\n return page.$$eval(\"a[href]\", (links) =>\n links\n .map((a) => (a as HTMLAnchorElement).href)\n .filter((h): h is string => !!h && (h.startsWith(\"http://\") || h.startsWith(\"https://\")))\n );\n }\n\n private async getElementBoundingBox(\n ref: string,\n _opts?: any,\n contextId?: string\n ): Promise<{ x: number; y: number; width: number; height: number } | null> {\n const locator = this.resolveRef(ref, contextId);\n const box = await locator.boundingBox();\n if (!box) return null;\n return { x: box.x, y: box.y, width: box.width, height: box.height };\n }\n\n private async startTracing(_opts?: any, contextId?: string): Promise<void> {\n const slot = this.getSlot(contextId);\n await slot.context.tracing.start({ screenshots: true, snapshots: true });\n }\n\n private async stopTracing(_opts?: any, contextId?: string): Promise<{\n trace: string;\n network: string;\n resources: string;\n directory: string | null;\n legend: string | null;\n }> {\n const slot = this.getSlot(contextId);\n const tracePath = `/tmp/trace-${Date.now()}.zip`;\n await slot.context.tracing.stop({ path: tracePath });\n return {\n trace: tracePath,\n network: \"\",\n resources: \"\",\n directory: null,\n legend: `Trace saved to ${tracePath}`,\n };\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  readStoredToken
3
- } from "./chunk-HJ2JWIJ7.js";
3
+ } from "./chunk-2T64Z2NI.js";
4
4
 
5
5
  // src/local-run.ts
6
6
  import process from "process";
@@ -331,4 +331,4 @@ export {
331
331
  createTunnel,
332
332
  connectTunnel
333
333
  };
334
- //# sourceMappingURL=chunk-VYBCH4ZP.js.map
334
+ //# sourceMappingURL=chunk-V7U52ISX.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  readStoredApiUrl,
3
3
  readStoredToken
4
- } from "./chunk-HJ2JWIJ7.js";
4
+ } from "./chunk-2T64Z2NI.js";
5
5
  import "./chunk-DGUM43GV.js";
6
6
 
7
7
  // src/feature-flag.ts
@@ -223,4 +223,4 @@ async function runFeatureFlag(argv) {
223
223
  export {
224
224
  runFeatureFlag
225
225
  };
226
- //# sourceMappingURL=feature-flag-PN5IFFQR.js.map
226
+ //# sourceMappingURL=feature-flag-MFTRYRYX.js.map
package/dist/index.js CHANGED
@@ -4,14 +4,15 @@ import {
4
4
  createTunnel,
5
5
  runLocalTest,
6
6
  runTunnel
7
- } from "./chunk-VYBCH4ZP.js";
7
+ } from "./chunk-V7U52ISX.js";
8
8
  import {
9
9
  ENV_URLS,
10
+ readAllStoredTokens,
10
11
  readStoredApiUrl,
11
12
  readStoredAuth,
12
13
  readStoredToken,
13
14
  saveAuth
14
- } from "./chunk-HJ2JWIJ7.js";
15
+ } from "./chunk-2T64Z2NI.js";
15
16
  import {
16
17
  __require
17
18
  } from "./chunk-DGUM43GV.js";
@@ -956,8 +957,8 @@ function isSuperadminToken(token) {
956
957
  // src/index.ts
957
958
  var require2 = createRequire2(import.meta.url);
958
959
  var pkg = require2("../package.json");
959
- var loadMcp = () => import("./mcp-I6FCGDDR.js").then((m) => m.runMcp);
960
- var loadLocalBrowser = () => import("./local-browser-VOBIUIGT.js").then((m) => m.runLocalBrowser);
960
+ var loadMcp = () => import("./mcp-TMD2R5Z6.js").then((m) => m.runMcp);
961
+ var loadLocalBrowser = () => import("./local-browser-SYPTG6IQ.js").then((m) => m.runLocalBrowser);
961
962
  var canary = { run };
962
963
  var baseDir = typeof __dirname !== "undefined" ? __dirname : path4.dirname(fileURLToPath2(import.meta.url));
963
964
  var preloadPath = path4.join(baseDir, "runner", "preload.js");
@@ -1001,6 +1002,9 @@ function printHelp({ isSuperadmin }) {
1001
1002
  " canary login [--org <name>] [--app-url https://app.trycanary.ai] [--no-open]",
1002
1003
  " canary orgs List organizations"
1003
1004
  ];
1005
+ lines.push(
1006
+ " canary release <sub-command> Release QA gate (CI/CD)"
1007
+ );
1004
1008
  if (isSuperadmin) {
1005
1009
  lines.push(
1006
1010
  " canary debug-session [--env dev|local] [--json] Create browser debug session",
@@ -1039,6 +1043,13 @@ function printHelp({ isSuperadmin }) {
1039
1043
  " Or set CANARY_API_URL env var for non-production environments:",
1040
1044
  " export CANARY_API_URL=http://localhost:3000"
1041
1045
  );
1046
+ lines.push(
1047
+ "",
1048
+ "Release sub-commands:",
1049
+ " trigger --property-id <uuid> Trigger a Release QA run",
1050
+ " status <run-id> [--json] Check run status",
1051
+ " run --property-id <uuid> [--timeout N] Trigger and poll until complete"
1052
+ );
1042
1053
  if (isSuperadmin) {
1043
1054
  lines.push(
1044
1055
  "",
@@ -1107,8 +1118,11 @@ function printTestHelp() {
1107
1118
  );
1108
1119
  }
1109
1120
  var COMMANDS_WITH_HELP = /* @__PURE__ */ new Set(["test"]);
1110
- async function resolveToken() {
1111
- return process7.env.CANARY_API_TOKEN ?? await readStoredToken();
1121
+ async function resolveIsSuperadmin() {
1122
+ const envToken = process7.env.CANARY_API_TOKEN;
1123
+ if (envToken) return isSuperadminToken(envToken);
1124
+ const tokens = await readAllStoredTokens();
1125
+ return tokens.some((t) => isSuperadminToken(t));
1112
1126
  }
1113
1127
  async function main(argv) {
1114
1128
  if (argv.includes("--version") || argv.includes("-V")) {
@@ -1118,13 +1132,11 @@ async function main(argv) {
1118
1132
  const [command, ...rest] = argv;
1119
1133
  const hasHelpFlag = argv.includes("--help") || argv.includes("-h");
1120
1134
  if (hasHelpFlag && (!command || !COMMANDS_WITH_HELP.has(command))) {
1121
- const token2 = await resolveToken();
1122
- printHelp({ isSuperadmin: isSuperadminToken(token2) });
1135
+ printHelp({ isSuperadmin: await resolveIsSuperadmin() });
1123
1136
  return;
1124
1137
  }
1125
1138
  if (!command || command === "help") {
1126
- const token2 = await resolveToken();
1127
- printHelp({ isSuperadmin: isSuperadminToken(token2) });
1139
+ printHelp({ isSuperadmin: await resolveIsSuperadmin() });
1128
1140
  return;
1129
1141
  }
1130
1142
  if (command === "version") {
@@ -1179,28 +1191,32 @@ async function main(argv) {
1179
1191
  return;
1180
1192
  }
1181
1193
  if (command === "psql") {
1182
- const { runPsql } = await import("./psql-A3BADRQN.js");
1194
+ const { runPsql } = await import("./psql-6IFVXM3A.js");
1183
1195
  await runPsql(rest);
1184
1196
  return;
1185
1197
  }
1186
1198
  if (command === "redis") {
1187
- const { runRedis } = await import("./redis-N2DSDDQU.js");
1199
+ const { runRedis } = await import("./redis-HZC32IEO.js");
1188
1200
  await runRedis(rest);
1189
1201
  return;
1190
1202
  }
1203
+ if (command === "release") {
1204
+ const { runRelease } = await import("./release-WOD3DAX4.js");
1205
+ await runRelease(rest);
1206
+ return;
1207
+ }
1191
1208
  if (command === "feature-flag") {
1192
- const { runFeatureFlag } = await import("./feature-flag-PN5IFFQR.js");
1209
+ const { runFeatureFlag } = await import("./feature-flag-MFTRYRYX.js");
1193
1210
  await runFeatureFlag(rest);
1194
1211
  return;
1195
1212
  }
1196
1213
  if (command === "knobs") {
1197
- const { runKnobs } = await import("./knobs-DAG7HD2F.js");
1214
+ const { runKnobs } = await import("./knobs-T3O4Z3ZB.js");
1198
1215
  await runKnobs(rest);
1199
1216
  return;
1200
1217
  }
1201
1218
  console.log(`Unknown command "${command}".`);
1202
- const token = await resolveToken();
1203
- printHelp({ isSuperadmin: isSuperadminToken(token) });
1219
+ printHelp({ isSuperadmin: await resolveIsSuperadmin() });
1204
1220
  process7.exit(1);
1205
1221
  }
1206
1222
  if (import.meta.url === pathToFileURL2(process7.argv[1]).href) {