shiplightai 0.1.12 → 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,5 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ const require = __createRequire(import.meta.url);
3
+ import"./chunk-CSINHOOD.js";import{Router as u}from"express";function p(i){let n=u();return n.post("/api/int-runner/copilot/init",async(o,s)=>{try{let{session:e,initialTestFlow:t}=o.body;if(!e?.sessionId)return s.status(400).json({success:!1,message:"Missing session"});await i.initializeCopilot(e.sessionId,t),s.json({success:!0,status:"success"})}catch(e){console.error("[debugger] copilot/init error:",e),s.status(500).json({success:!1,message:e.message})}}),n.post("/api/int-runner/copilot/send",async(o,s)=>{let{session:e,message:t,testFlow:c}=o.body;if(!e?.sessionId||!t)return s.status(400).json({success:!1,message:"Session and message required"});s.setHeader("Content-Type","text/event-stream"),s.setHeader("Cache-Control","no-cache"),s.setHeader("Connection","keep-alive"),s.flushHeaders();let a=r=>{s.write(`data: ${JSON.stringify(r)}
4
+
5
+ `)};try{await i.sendCopilotMessage(e.sessionId,t,a,c)}catch(r){a({type:"copilot_message",data:{type:"error",message:r.message},sequenceNumber:0,timestamp:new Date().toISOString()})}finally{s.end()}}),n.post("/api/int-runner/copilot/abort",async(o,s)=>{try{let{session:e}=o.body;if(!e?.sessionId)return s.status(400).json({success:!1,message:"Missing session"});let t=i.abortCopilot(e.sessionId);s.json({success:!0,status:"success",aborted:t})}catch(e){console.error("[debugger] copilot/abort error:",e),s.status(500).json({success:!1,message:e.message})}}),n.post("/api/int-runner/copilot/status",async(o,s)=>{try{let{session:e}=o.body;if(!e?.sessionId)return s.status(400).json({status:"error",message:"Missing session"});let t=i.getCopilotTestFlow(e.sessionId);s.json({status:"success",copilotInitialized:!0,testFlow:t})}catch(e){s.status(500).json({status:"error",details:e.message})}}),n}export{p as createCopilotRouter};
@@ -0,0 +1,145 @@
1
+ import { Page } from 'playwright';
2
+ import { WebAgent } from './agent/webAgent.js';
3
+ import { ActionEntity } from './test-flow/actionEntity.js';
4
+ import { TestFlow } from './test-flow/testFlow.js';
5
+ import { AgentStepEvent } from 'sdk-internal';
6
+
7
+ /**
8
+ * SandboxService Interface
9
+ *
10
+ * Common interface for debugger sandbox services.
11
+ * Implemented by LocalSandboxService (standalone) and PlaywrightSandboxService (Playwright-bootstrapped).
12
+ */
13
+
14
+ type AgentStepEventCallback = (event: AgentStepEvent) => void;
15
+ interface DebugInfo {
16
+ sessionId: string;
17
+ liveviewUrl: string;
18
+ browserWsUrl: string;
19
+ }
20
+ interface RunStepResult {
21
+ success: boolean;
22
+ actions: ActionEntity[];
23
+ details?: string;
24
+ }
25
+ interface SandboxService {
26
+ createSession(config?: {
27
+ startingUrl?: string;
28
+ }): Promise<{
29
+ sessionId: string;
30
+ }>;
31
+ executeLogin(sessionId: string): Promise<{
32
+ status: string;
33
+ details?: string;
34
+ }>;
35
+ ensureBrowser(sessionId: string): Promise<{
36
+ page: Page;
37
+ liveviewUrl: string;
38
+ }>;
39
+ startDebug(sessionId: string): Promise<DebugInfo>;
40
+ terminateSession(sessionId: string): Promise<void>;
41
+ cleanupAll(): Promise<void>;
42
+ executeAction(sessionId: string, actionEntity: ActionEntity, stepId: string, options?: {
43
+ withSelfHealing?: boolean;
44
+ stmtUid?: string;
45
+ executionHistory?: Array<[string, string]>;
46
+ }): Promise<any>;
47
+ runStep(sessionId: string, statement: string, stepId: string, onEvent: AgentStepEventCallback, executionHistory?: Array<[string, string]>): Promise<RunStepResult>;
48
+ stopRunStep(sessionId: string): boolean;
49
+ evaluate(sessionId: string, statement: string, executionHistory?: Array<[string, string]>): Promise<Record<string, any>>;
50
+ generateAction(sessionId: string, statement: string, stepId: string, options?: {
51
+ executionHistory?: Array<[string, string]>;
52
+ usePureVision?: boolean;
53
+ includeDebugInfo?: boolean;
54
+ }): Promise<any>;
55
+ takeScreenshot(sessionId: string): Promise<{
56
+ screenshot: string;
57
+ screenshotPath?: string;
58
+ }>;
59
+ initializeCopilot(sessionId: string, initialTestFlow?: TestFlow): Promise<void>;
60
+ sendCopilotMessage(sessionId: string, message: string, onEvent: any, testFlow?: TestFlow): Promise<void>;
61
+ abortCopilot(sessionId: string): boolean;
62
+ getCopilotTestFlow(sessionId: string): TestFlow | undefined;
63
+ }
64
+
65
+ /**
66
+ * Playwright Sandbox Service
67
+ *
68
+ * Lightweight sandbox that wraps an externally-provided Playwright page and
69
+ * WebAgent. Used when the debugger runs inside a Playwright test context,
70
+ * inheriting all Playwright config features (baseURL, storageState, viewport, etc.).
71
+ */
72
+
73
+ /**
74
+ * A sandbox backed by a Playwright-provided page and agent.
75
+ * Since Playwright handles browser lifecycle, auth, baseURL, etc.,
76
+ * this service just delegates to the agent for test operations.
77
+ */
78
+ declare class PlaywrightSandboxService implements SandboxService {
79
+ private page;
80
+ private agent;
81
+ private sessionId;
82
+ private abortController;
83
+ constructor(page: Page, agent: WebAgent);
84
+ createSession(_config?: {
85
+ startingUrl?: string;
86
+ }): Promise<{
87
+ sessionId: string;
88
+ }>;
89
+ executeLogin(_sessionId: string): Promise<{
90
+ status: string;
91
+ details?: string;
92
+ }>;
93
+ ensureBrowser(_sessionId: string): Promise<{
94
+ page: Page;
95
+ liveviewUrl: string;
96
+ }>;
97
+ startDebug(_sessionId: string): Promise<DebugInfo>;
98
+ executeAction(_sessionId: string, actionEntity: ActionEntity, stepId: string, options?: {
99
+ withSelfHealing?: boolean;
100
+ stmtUid?: string;
101
+ executionHistory?: Array<[string, string]>;
102
+ }): Promise<any>;
103
+ runStep(_sessionId: string, statement: string, stepId: string, onEvent: AgentStepEventCallback, executionHistory?: Array<[string, string]>): Promise<RunStepResult>;
104
+ stopRunStep(_sessionId: string): boolean;
105
+ evaluate(_sessionId: string, statement: string, _executionHistory?: Array<[string, string]>): Promise<Record<string, any>>;
106
+ generateAction(_sessionId: string, statement: string, stepId: string, options?: {
107
+ executionHistory?: Array<[string, string]>;
108
+ usePureVision?: boolean;
109
+ includeDebugInfo?: boolean;
110
+ }): Promise<any>;
111
+ takeScreenshot(_sessionId: string): Promise<{
112
+ screenshot: string;
113
+ screenshotPath?: string;
114
+ }>;
115
+ initializeCopilot(_sessionId: string, _initialTestFlow?: TestFlow): Promise<void>;
116
+ sendCopilotMessage(_sessionId: string, _message: string, _onEvent: any, _testFlow?: TestFlow): Promise<void>;
117
+ abortCopilot(_sessionId: string): boolean;
118
+ getCopilotTestFlow(_sessionId: string): TestFlow | undefined;
119
+ terminateSession(_sessionId: string): Promise<void>;
120
+ cleanupAll(): Promise<void>;
121
+ }
122
+
123
+ /**
124
+ * Playwright Debugger — public entry point for `shiplightai/debugger-pw`.
125
+ *
126
+ * Imported by the generated debug test file inside a Playwright test context.
127
+ * Starts an internal HTTP server with int-runner and copilot routes,
128
+ * backed by PlaywrightSandboxService.
129
+ */
130
+
131
+ interface PlaywrightDebugOptions {
132
+ yamlFilePath: string;
133
+ port: number;
134
+ page: Page;
135
+ agent: WebAgent;
136
+ }
137
+ /**
138
+ * Start the internal sandbox server backed by a Playwright-provided page and agent.
139
+ */
140
+ declare function startPlaywrightDebugServer(options: PlaywrightDebugOptions): Promise<{
141
+ url: string;
142
+ close: () => Promise<void>;
143
+ }>;
144
+
145
+ export { type PlaywrightDebugOptions, PlaywrightSandboxService, startPlaywrightDebugServer };
@@ -0,0 +1,3 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ const require = __createRequire(import.meta.url);
3
+ import"./chunk-CSINHOOD.js";import w from"express";import*as m from"path";import*as h from"fs/promises";import*as y from"os";var g=class{page;agent;sessionId="pw-"+Math.random().toString(36).slice(2,10);abortController=null;constructor(e,t){this.page=e,this.agent=t}async createSession(e){return{sessionId:this.sessionId}}async executeLogin(e){return{status:"success",details:"Handled by Playwright"}}async ensureBrowser(e){return{page:this.page,liveviewUrl:""}}async startDebug(e){return{sessionId:this.sessionId,liveviewUrl:"",browserWsUrl:""}}async executeAction(e,t,s,n){let r=t.action_data||t.action;if(!r)throw new Error("ActionEntity has no action_data");if(console.error(`[pw-sandbox] executeAction stepId=${JSON.stringify(s)} action_name=${JSON.stringify(r.action_name)} locator=${JSON.stringify(t.locator)} kwargs=${JSON.stringify(r.kwargs)}`),r.action_name==="js_code"&&s==="prelude"){if(this.page.url()==="about:blank"){let l=r.kwargs?.code?.match(/PLAYWRIGHT_STARTING_URL \|\| '([^']*)'/)?.[1];l&&await this.page.goto(l,{waitUntil:"domcontentloaded"})}return{status:"success"}}let o=t.action_description||r.action_name;return{status:"success",...await this.agent.step(this.page,async()=>{await this.agent.execAction(r.action_name,this.page,t)},o,s,n?.stmtUid,!!n?.withSelfHealing)}}async runStep(e,t,s,n,r){let o=[],p={},l=this.agent._actionHandler;this.abortController=new AbortController;try{let u=await this.agent.execute(this.page,t,s,!1);return{success:u?.success??!0,actions:o,details:u?.details}}finally{this.abortController=null}}stopRunStep(e){return this.abortController?(this.abortController.abort(),!0):!1}async evaluate(e,t,s){try{let n=await this.agent.assert(this.page,t);return{conclusion:n?"pass":"fail",explanation:n?"Assertion passed":"Assertion failed"}}catch(n){return{conclusion:"fail",explanation:n.message}}}async generateAction(e,t,s,n){return this.agent.generate(this.page,t,s,n?.usePureVision)}async takeScreenshot(e){let t=await this.page.screenshot(),s=m.join(y.tmpdir(),`shiplight-screenshot-${Date.now()}.png`);return await h.writeFile(s,t),{screenshot:t.toString("base64"),screenshotPath:s}}async initializeCopilot(e,t){}async sendCopilotMessage(e,t,s,n){throw new Error("Copilot not supported in Playwright debug mode")}abortCopilot(e){return!1}getCopilotTestFlow(e){}async terminateSession(e){console.error("[debugger] Playwright session released")}async cleanupAll(){}};async function S(d){let{yamlFilePath:e,port:t,page:s,agent:n}=d,r=new g(s,n),o=w();o.use(w.json({limit:"10mb"})),o.use((c,i,a)=>{if(i.setHeader("Access-Control-Allow-Origin","*"),i.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS"),i.setHeader("Access-Control-Allow-Headers","Content-Type"),c.method==="OPTIONS")return i.sendStatus(204);a()});let{createTestFlowRouter:p}=await import("./testFlow-OQWWSEQT.js"),{createIntRunnerRouter:l}=await import("./intRunner-5A6M6JSJ.js"),{createCopilotRouter:u}=await import("./copilot-7JTVJQXP.js");o.use(p(e)),o.use(l(r)),o.use(u(r));let b=await new Promise((c,i)=>{let a=o.listen(t,"localhost",()=>c(a));a.on("error",i)});return{url:`http://localhost:${t}`,close:async()=>{await r.cleanupAll(),await new Promise((c,i)=>{b.close(a=>a?i(a):c())})}}}export{g as PlaywrightSandboxService,S as startPlaywrightDebugServer};
@@ -1,3 +1,3 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  const require = __createRequire(import.meta.url);
3
- import{a as d,b as e,c as f,d as g,e as h,f as O,g as P,h as Q,i as R,j as S,k as T,l as U,m as Z,n as _,o as $,p as aa,q as ba,r as ca,s as da,t as ea,u as fa}from"./chunk-6WY2ENBF.js";import{C,E as D}from"./chunk-THBA6CDP.js";import{a as V,j as W,k as X,l as Y}from"./chunk-HECRJRKW.js";import{a as E,c as F,d as G,e as H,f as I,g as J}from"./chunk-FL4TL6US.js";import{b as i,e as K,f as L,g as M,h as N}from"./chunk-T3YFBZB6.js";import{a as m,b as n,c as o,d as p,g as s,h as t,i as u,j as v,k as w,l as x,m as y,n as z,o as A}from"./chunk-RP6LTE6E.js";import{a as c,h as j,i as k,j as l,l as q,m as r}from"./chunk-CYBAFQLF.js";import"./chunk-BVOD5VWH.js";import{b as a,c as b,i as B}from"./chunk-FBJSHHRD.js";import"./chunk-YU3XZJIJ.js";import"./chunk-CSINHOOD.js";export{D as ActionHandler,C as ActionHelper,ca as Agent,$ as AgentServices,aa as AgentStepEventTypes,ba as AgentTaskFailedError,Z as BrowserManager,v as DEFAULT_EVENT_LISTENER_LIMIT,z as DomService,u as EVENT_LISTENER_CANDIDATE_SELECTORS,A as HistoryTreeProcessor,E as INIT_SCRIPT,t as INTERACTION_EVENT_TYPES,s as INTERACTIVE_ROLES,B as LogLevel,W as LoginType,T as MCPToolProvider,i as OpenAIToolProvider,fa as SDK_VERSION,m as ToolRegistry,X as TwoFactorAuthType,Y as VariableStore,ca as WebAgent,a as configureSdk,ea as createAgent,da as createAgentContext,Q as createToolRegistry,R as createToolRegistryWithCapabilities,O as ensureToolsRegistered,M as evaluateStatement,L as executeStep,U as exportMCPTools,y as filterInteractionListeners,K as generateActionStep,r as getActionEntityLocatorInfo,G as getBrowserCdpUrl,S as getCapabilitySummary,q as getFramePath,o as getModel,I as getPageInfo,H as getPageWsUrl,_ as getPlatformFromDeviceName,p as getProviderOptions,b as getSdkConfig,P as getToolRegistry,d as injectUserFunction,x as isInteractionEventType,w as isInteractiveRole,g as loadKnowledgeMappings,f as loadKnowledges,e as loadUserFunctions,c as logger,F as newBrowserContext,h as parseSSEStream,j as pickBestLocator,k as pickBestLocatorForElement,l as pickBestLocators,V as replaceVariables,N as runTask,J as setWindowBounds,n as toolRegistry};
3
+ import{a as d,b as e,c as f,d as g,e as h,f as O,g as P,h as Q,i as R,j as S,k as T,l as U,m as Z,n as _,o as $,p as aa,q as ba,r as ca,s as da,t as ea,u as fa}from"./chunk-NDYQF4WM.js";import{b as i,e as K,f as L,g as M,h as N}from"./chunk-JY6U4L7Q.js";import{C,E as D}from"./chunk-ESJGKHJ4.js";import{a as m,b as n,c as o,d as p,g as s,h as t,i as u,j as v,k as w,l as x,m as y,n as z,o as A}from"./chunk-VXL4KP4U.js";import"./chunk-YU3XZJIJ.js";import{a as c,h as j,i as k,j as l,l as q,m as r}from"./chunk-QU5HYOUM.js";import{a as V,j as W,k as X,l as Y}from"./chunk-4JBGAENP.js";import{a as E,c as F,d as G,e as H,f as I,g as J}from"./chunk-FL4TL6US.js";import"./chunk-BVOD5VWH.js";import{b as a,c as b,i as B}from"./chunk-FBJSHHRD.js";import"./chunk-CSINHOOD.js";export{D as ActionHandler,C as ActionHelper,ca as Agent,$ as AgentServices,aa as AgentStepEventTypes,ba as AgentTaskFailedError,Z as BrowserManager,v as DEFAULT_EVENT_LISTENER_LIMIT,z as DomService,u as EVENT_LISTENER_CANDIDATE_SELECTORS,A as HistoryTreeProcessor,E as INIT_SCRIPT,t as INTERACTION_EVENT_TYPES,s as INTERACTIVE_ROLES,B as LogLevel,W as LoginType,T as MCPToolProvider,i as OpenAIToolProvider,fa as SDK_VERSION,m as ToolRegistry,X as TwoFactorAuthType,Y as VariableStore,ca as WebAgent,a as configureSdk,ea as createAgent,da as createAgentContext,Q as createToolRegistry,R as createToolRegistryWithCapabilities,O as ensureToolsRegistered,M as evaluateStatement,L as executeStep,U as exportMCPTools,y as filterInteractionListeners,K as generateActionStep,r as getActionEntityLocatorInfo,G as getBrowserCdpUrl,S as getCapabilitySummary,q as getFramePath,o as getModel,I as getPageInfo,H as getPageWsUrl,_ as getPlatformFromDeviceName,p as getProviderOptions,b as getSdkConfig,P as getToolRegistry,d as injectUserFunction,x as isInteractionEventType,w as isInteractiveRole,g as loadKnowledgeMappings,f as loadKnowledges,e as loadUserFunctions,c as logger,F as newBrowserContext,h as parseSSEStream,j as pickBestLocator,k as pickBestLocatorForElement,l as pickBestLocators,V as replaceVariables,N as runTask,J as setWindowBounds,n as toolRegistry};
@@ -1,3 +1,3 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  const require = __createRequire(import.meta.url);
3
- import{$,A,Aa,B,Ba,C,Ca,D,Da,E,Ea,F,Fa,G,Ga,H,Ha,I,Ia,J,Ja,K,Ka,L,La,M,Ma,N,Na,O,Oa,P,Pa,Q,Qa,R,Ra,S,Sa,T,Ta,U,Ua,V,Va,W,X,Y,Z,_,a,aa,b,ba,c,ca,d,da,e,ea,f,fa,g,ga,h,ha,i,ia,j,ja,k,ka,l,la,m,ma,n,na,o,oa,p,pa,q,qa,r,ra,s,sa,t,ta,u,ua,v,va,w,wa,x,xa,y,ya,z,za}from"./chunk-JQXTDNAE.js";import"./chunk-CSINHOOD.js";export{u as ADDRESS_BAR_HEIGHT,d as ANDROID_DEVICE_PREFIX,Y as ActionEntitySchema,_ as ActionSchema,Sa as AgentStatus,X as BaseStatementSchema,E as BrowserType,V as ConditionSchema,Ja as ConditionType,U as ConditionTypeSchema,Oa as DEFAULT_ANTHROPIC_MODEL,Ma as DEFAULT_COPILOT_MODEL,D as DEFAULT_DEVICE_NAME,Pa as DEFAULT_GOOGLE_MODEL,Na as DEFAULT_WEBAGENT_MODEL,Ka as DEFAULT_WHILE_LOOP_TIMEOUT_MS,H as DEVICE_CATEGORIES,G as DeviceType,Z as DraftSchema,e as IOS_DEVICE_PREFIX,S as LoginType,C as MIN_WINDOW_HEIGHT,B as MIN_WINDOW_WIDTH,c as NodeJSCodeCommon,F as PLAYWRIGHT_DEVICES,A as RECORD_VIDEO_HEIGHT,z as RECORD_VIDEO_WIDTH,$ as StatementSchema,Ia as StatementType,W as StatementTypeSchema,aa as TestFlowSchema,T as TwoFactorAuthType,L as UI_DEVICE_CATEGORIES,M as UI_DEVICE_CATEGORIES_ELECTRON,t as USER_AGENT,y as VIEWPORT_HEIGHT,x as VIEWPORT_WIDTH,La as VariableStore,w as WINDOW_HEIGHT,v as WINDOW_WIDTH,ya as actionStepsMapToTestFlowSections,va as allowPureVisionAction,ia as applyPatchToYaml,ja as applyPatchToYamlString,wa as collectActionSteps,k as createAndroidDeviceName,Aa as createEmptyStore,l as createIOSDeviceName,Ba as createRunnerStoreEntry,xa as extractActionStepsFromTestFlow,j as extractDeviceIdentifier,fa as extractYamlMetadata,oa as findNextAfterContainer,na as findNextSibling,ma as findNextStatement,ra as findPathBetweenStatements,la as findStatementPathById,J as getAllDeviceNames,ta as getAllReferenceIds,pa as getAllStatementsInOrder,Va as getAndroidDeviceDisplayName,O as getBrowserWindowSize,o as getCompatiblePlatforms,R as getDeviceBrowserType,K as getDeviceByName,Q as getDeviceChannel,N as getDeviceOptions,I as getDevicesByCategory,r as getIOSDeviceDisplayName,a as getLoginConfigPlatform,P as getRecordVideoSize,ka as getStatementContainers,Ga as getStoreSize,f as getTestPlatformFromDeviceName,sa as hasReferenceIds,h as isAndroidDevice,n as isAppPackage,ua as isDynamicAction,qa as isExecutableStatement,i as isIOSDevice,g as isNativeDevice,s as isPhysicalDeviceUDID,p as isPlatformCompatibleWithUrl,Fa as isStoreEmpty,m as isWebUrl,Ha as mergeActionEntitiesIntoTestFlow,Ea as mergeStoreUpdates,Ta as parseAdbDeviceLine,ea as parseYamlArrayItems,b as replaceVariables,Ca as resolveActionEntity,Ra as resolveModelFromEnv,Qa as resolveModels,ca as testFlowToYaml,ba as testFlowToYamlObject,Ua as toAndroidDeviceName,q as toIOSDeviceName,Da as updateStoreEntry,ha as validatePatch,za as validateTestYaml,da as yamlObjectsToString,ga as yamlToTestFlow};
3
+ import{$,A,Aa,B,Ba,C,Ca,D,Da,E,Ea,F,Fa,G,Ga,H,Ha,I,Ia,J,Ja,K,Ka,L,La,M,Ma,N,Na,O,Oa,P,Pa,Q,Qa,R,Ra,S,Sa,T,Ta,U,Ua,V,Va,W,X,Y,Z,_,a,aa,b,ba,c,ca,d,da,e,ea,f,fa,g,ga,h,ha,i,ia,j,ja,k,ka,l,la,m,ma,n,na,o,oa,p,pa,q,qa,r,ra,s,sa,t,ta,u,ua,v,va,w,wa,x,xa,y,ya,z,za}from"./chunk-SUZXLRAA.js";import"./chunk-CSINHOOD.js";export{u as ADDRESS_BAR_HEIGHT,d as ANDROID_DEVICE_PREFIX,Y as ActionEntitySchema,_ as ActionSchema,Sa as AgentStatus,X as BaseStatementSchema,E as BrowserType,V as ConditionSchema,Ja as ConditionType,U as ConditionTypeSchema,Oa as DEFAULT_ANTHROPIC_MODEL,Ma as DEFAULT_COPILOT_MODEL,D as DEFAULT_DEVICE_NAME,Pa as DEFAULT_GOOGLE_MODEL,Na as DEFAULT_WEBAGENT_MODEL,Ka as DEFAULT_WHILE_LOOP_TIMEOUT_MS,H as DEVICE_CATEGORIES,G as DeviceType,Z as DraftSchema,e as IOS_DEVICE_PREFIX,S as LoginType,C as MIN_WINDOW_HEIGHT,B as MIN_WINDOW_WIDTH,c as NodeJSCodeCommon,F as PLAYWRIGHT_DEVICES,A as RECORD_VIDEO_HEIGHT,z as RECORD_VIDEO_WIDTH,$ as StatementSchema,Ia as StatementType,W as StatementTypeSchema,aa as TestFlowSchema,T as TwoFactorAuthType,L as UI_DEVICE_CATEGORIES,M as UI_DEVICE_CATEGORIES_ELECTRON,t as USER_AGENT,y as VIEWPORT_HEIGHT,x as VIEWPORT_WIDTH,La as VariableStore,w as WINDOW_HEIGHT,v as WINDOW_WIDTH,ya as actionStepsMapToTestFlowSections,va as allowPureVisionAction,ia as applyPatchToYaml,ja as applyPatchToYamlString,wa as collectActionSteps,k as createAndroidDeviceName,Aa as createEmptyStore,l as createIOSDeviceName,Ba as createRunnerStoreEntry,xa as extractActionStepsFromTestFlow,j as extractDeviceIdentifier,fa as extractYamlMetadata,oa as findNextAfterContainer,na as findNextSibling,ma as findNextStatement,ra as findPathBetweenStatements,la as findStatementPathById,J as getAllDeviceNames,ta as getAllReferenceIds,pa as getAllStatementsInOrder,Va as getAndroidDeviceDisplayName,O as getBrowserWindowSize,o as getCompatiblePlatforms,R as getDeviceBrowserType,K as getDeviceByName,Q as getDeviceChannel,N as getDeviceOptions,I as getDevicesByCategory,r as getIOSDeviceDisplayName,a as getLoginConfigPlatform,P as getRecordVideoSize,ka as getStatementContainers,Ga as getStoreSize,f as getTestPlatformFromDeviceName,sa as hasReferenceIds,h as isAndroidDevice,n as isAppPackage,ua as isDynamicAction,qa as isExecutableStatement,i as isIOSDevice,g as isNativeDevice,s as isPhysicalDeviceUDID,p as isPlatformCompatibleWithUrl,Fa as isStoreEmpty,m as isWebUrl,Ha as mergeActionEntitiesIntoTestFlow,Ea as mergeStoreUpdates,Ta as parseAdbDeviceLine,ea as parseYamlArrayItems,b as replaceVariables,Ca as resolveActionEntity,Ra as resolveModelFromEnv,Qa as resolveModels,ca as testFlowToYaml,ba as testFlowToYamlObject,Ua as toAndroidDeviceName,q as toIOSDeviceName,Da as updateStoreEntry,ha as validatePatch,za as validateTestYaml,da as yamlObjectsToString,ga as yamlToTestFlow};
package/dist/fixture.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  const require = __createRequire(import.meta.url);
3
- import"./chunk-CSINHOOD.js";import*as u from"path";import{test as w,expect as I}from"@playwright/test";import*as c from"fs";import*as o from"path";function v(s){let e=o.resolve(s),r=o.resolve(process.cwd());for(;;){for(let n of["shiplight.config.json","login.config.json"]){let a=o.join(e,n);if(c.existsSync(a)){try{let i=JSON.parse(c.readFileSync(a,"utf-8"));if(i.variables&&typeof i.variables=="object")return _(i.variables)}catch{}return[]}}if(e===r)break;let t=o.dirname(e);if(t===e)break;e=t}return[]}function _(s){let e=[];for(let[r,t]of Object.entries(s))if(typeof t=="string")e.push({key:r,value:t,sensitive:!1});else if(t&&typeof t=="object"&&"value"in t){let n=t;e.push({key:r,value:String(n.value),sensitive:n.sensitive===!0})}return e}var f;async function k(){return f||(f=await import("./dist-4ZMHICD4.js"),f)}var j=w.extend({agent:async({},s,e)=>{let{WebAgent:r,createAgentContext:t,configureSdk:n,VariableStore:a}=await k();n({env:{GOOGLE_API_KEY:process.env.GOOGLE_API_KEY??"",ANTHROPIC_API_KEY:process.env.ANTHROPIC_API_KEY??""}});let{resolveModelFromEnv:i}=await import("./dist-3WNQHYT3.js"),l=i(process.env);if(!l)throw new Error("No AI model configured. Set WEB_AGENT_MODEL, ANTHROPIC_API_KEY, or GOOGLE_API_KEY.");let p=new a,b=e.project.testDir||process.cwd(),g=e.file,m=g?u.dirname(g):b,d=v(m);for(let{key:h,value:y,sensitive:E}of d)p.set(h,y,E);let A=new r(t({model:l,variableStore:p}));await s(A)}});export{I as expect,j as test};
3
+ import"./chunk-CSINHOOD.js";import*as u from"path";import{test as w,expect as I}from"@playwright/test";import*as c from"fs";import*as o from"path";function v(s){let e=o.resolve(s),r=o.resolve(process.cwd());for(;;){for(let n of["shiplight.config.json","login.config.json"]){let a=o.join(e,n);if(c.existsSync(a)){try{let i=JSON.parse(c.readFileSync(a,"utf-8"));if(i.variables&&typeof i.variables=="object")return _(i.variables)}catch{}return[]}}if(e===r)break;let t=o.dirname(e);if(t===e)break;e=t}return[]}function _(s){let e=[];for(let[r,t]of Object.entries(s))if(typeof t=="string")e.push({key:r,value:t,sensitive:!1});else if(t&&typeof t=="object"&&"value"in t){let n=t;e.push({key:r,value:String(n.value),sensitive:n.sensitive===!0})}return e}var f;async function k(){return f||(f=await import("./dist-OOFTSMK3.js"),f)}var j=w.extend({agent:async({},s,e)=>{let{WebAgent:r,createAgentContext:t,configureSdk:n,VariableStore:a}=await k();n({env:{GOOGLE_API_KEY:process.env.GOOGLE_API_KEY??"",ANTHROPIC_API_KEY:process.env.ANTHROPIC_API_KEY??""}});let{resolveModelFromEnv:i}=await import("./dist-WQ66EMT6.js"),l=i(process.env);if(!l)throw new Error("No AI model configured. Set WEB_AGENT_MODEL, ANTHROPIC_API_KEY, or GOOGLE_API_KEY.");let p=new a,b=e.project.testDir||process.cwd(),g=e.file,m=g?u.dirname(g):b,d=v(m);for(let{key:h,value:y,sensitive:E}of d)p.set(h,y,E);let A=new r(t({model:l,variableStore:p}));await s(A)}});export{I as expect,j as test};
@@ -1,3 +1,3 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  const require = __createRequire(import.meta.url);
3
- import{D as o,E as r}from"./chunk-THBA6CDP.js";import"./chunk-CYBAFQLF.js";import"./chunk-FBJSHHRD.js";import"./chunk-CSINHOOD.js";export{o as ActionHandler,r as default};
3
+ import{D as o,E as r}from"./chunk-ESJGKHJ4.js";import"./chunk-QU5HYOUM.js";import"./chunk-FBJSHHRD.js";import"./chunk-CSINHOOD.js";export{o as ActionHandler,r as default};
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  const require = __createRequire(import.meta.url);
3
- import{r as de,s as me}from"./chunk-6WY2ENBF.js";import"./chunk-THBA6CDP.js";import{l as ge}from"./chunk-HECRJRKW.js";import"./chunk-FL4TL6US.js";import{Ka as W,ga as v}from"./chunk-JQXTDNAE.js";import"./chunk-T3YFBZB6.js";import"./chunk-RP6LTE6E.js";import"./chunk-CYBAFQLF.js";import"./chunk-BVOD5VWH.js";import{b as fe}from"./chunk-FBJSHHRD.js";import"./chunk-YU3XZJIJ.js";import"./chunk-CSINHOOD.js";import*as x from"fs";import*as b from"path";import Ke from"dotenv";import{globSync as qe}from"glob";import{readFileSync as pe,writeFileSync as Je,statSync as Re,existsSync as He}from"fs";import{resolve as Me}from"path";import{globSync as Ge}from"glob";import{parse as be,stringify as V}from"yaml";import{readFileSync as he}from"fs";import{resolve as D,dirname as _e}from"path";import{parse as Y,stringify as $e}from"yaml";var U=5;function J(e,t){let n={expandingPaths:new Set([D(t)]),depth:0,referencedPaths:new Set},s={...e};Array.isArray(s.statements)&&(s.statements=A(s.statements,t,n)),Array.isArray(s.teardown)&&(s.teardown=A(s.teardown,t,n));for(let r of["beforeAll","afterAll","beforeEach","afterEach"])Array.isArray(s[r])&&(s[r]=A(s[r],t,n));return{doc:s,referencedTemplatePaths:Array.from(n.referencedPaths)}}function A(e,t,n){let s=[];for(let r of e)if(ye(r)){let a=we(r,t,n);s.push(...a)}else s.push(Se(r,t,n));return s}function ye(e){return typeof e=="object"&&e!==null&&typeof e.template=="string"}function we(e,t,n){if(n.depth>=U)throw new Error(`Template expansion exceeded maximum depth of ${U}. Check for deeply nested or circular template references.`);let s=D(_e(t),e.template);if(n.expandingPaths.has(s))throw new Error(`Circular template reference detected: ${s} is already being expanded. Stack: ${Array.from(n.expandingPaths).join(" \u2192 ")} \u2192 ${s}`);n.referencedPaths.add(s);let r;try{r=he(s,"utf-8")}catch(u){throw new Error(`Failed to read template file: ${s} (referenced from ${t}): ${u.message}`)}let a=Y(r);if(!a||typeof a!="object")throw new Error(`Invalid template file: ${s} \u2014 expected a YAML object`);let i=a.params||[],o=e.params||{};for(let u of i)if(!(u in o))throw new Error(`Template ${e.template} requires param "${u}" but it was not provided. Required params: [${i.join(", ")}]`);let l=a.statements;if(!Array.isArray(l))throw new Error(`Template ${e.template} must have a "statements" array`);if(Object.keys(o).length>0){let f=$e(l);for(let[_,g]of Object.entries(o))f=f.replaceAll(`<<${_}>>`,String(g));l=Y(f)}let c={expandingPaths:new Set([...n.expandingPaths,s]),depth:n.depth+1,referencedPaths:n.referencedPaths};return A(l,s,c)}function Se(e,t,n){if(typeof e!="object"||e===null)return e;let s={...e};return Array.isArray(s.statements)&&(s.statements=A(s.statements,t,n)),Array.isArray(s.THEN)&&(s.THEN=A(s.THEN,t,n)),Array.isArray(s.ELSE)&&(s.ELSE=A(s.ELSE,t,n)),Array.isArray(s.DO)&&(s.DO=A(s.DO,t,n)),s}function K(e,t){let n=be(e),s=n?.name,r=n?.tags,a=n?.use;if(n&&(n.name!==void 0||n.tags!==void 0||n.use!==void 0)&&(delete n.name,delete n.tags,delete n.use),n?.suite){if(n.goal||n.statements)throw new Error('YAML file cannot have both "suite" and top-level "goal"/"statements". Use either suite format or single-test format.');return Ae(n,s,r,a,t)}return xe(n,s,r,a,t)}function xe(e,t,n,s,r){let a=e?.beforeEach,i=e?.afterEach,o=q(e?.parameters),l=e?.timeout,c=e?.skip,u=e?.fail,f=e?.only,_=e?.slow;e&&(delete e.beforeEach,delete e.afterEach,delete e.parameters,delete e.timeout,delete e.skip,delete e.fail,delete e.only,delete e.slow),e&&!e.goal&&t&&(e.goal=t);let g=[];if(r&&e&&typeof e=="object"){let S=J(e,r);e=S.doc,g=S.referencedTemplatePaths}let $=V(e);return{testFlow:v($),name:t,tags:n,use:s,beforeEach:a,afterEach:i,parameters:o,timeout:l,skip:c,fail:u,only:f,slow:_,referencedTemplatePaths:g}}function Ae(e,t,n,s,r){let a=e.suite;if(!Array.isArray(a.tests)||a.tests.length===0)throw new Error('Suite must have a non-empty "tests" array.');let i=a.serial,o=a.beforeAll,l=a.afterAll,c=a.beforeEach,u=a.afterEach,f=[],_=a.tests.map(g=>{if(!g.name)throw new Error('Each test in a suite must have a "name" field.');if(!Array.isArray(g.statements)||g.statements.length===0)throw new Error(`Suite test "${g.name}" must have a non-empty "statements" array.`);let $={goal:g.name,statements:g.statements};g.teardown&&($.teardown=g.teardown);let k=[],S=$;if(r&&typeof $=="object"){let E=J($,r);S=E.doc,k=E.referencedTemplatePaths,f.push(...k)}let P=V(S),C=v(P),h=q(g.parameters);return{testFlow:C,name:g.name,parameters:h,timeout:g.timeout,skip:g.skip,fail:g.fail,only:g.only,slow:g.slow}});return{suite:{serial:i,beforeAll:o,afterAll:l,beforeEach:c,afterEach:u,tests:_},name:t,tags:n,use:s,referencedTemplatePaths:f}}function q(e){if(!(!Array.isArray(e)||e.length===0))return e.map((t,n)=>{if(!t.name)throw new Error(`Parameter set at index ${n} must have a "name" field.`);if(!t.values||typeof t.values!="object")throw new Error(`Parameter set "${t.name}" must have a "values" object.`);return{name:t.name,values:t.values}})}import{stringify as te}from"yaml";function w(e){return e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}function d(e){return e.replace(/\r\n/g," ").replace(/\n/g," ").replace(/\r/g," ").trim()}function ke(e){let t=e.frame_path;return!t||t.length===0?"page":`page.frameLocator('${t[0]}')`}function Te(e){let t=e.xpath;return typeof t=="string"&&t.trim()?!t.startsWith("xpath=")&&!t.startsWith("/")&&!t.startsWith("//")?`xpath=//${t}`:t.startsWith("xpath=")?t:`xpath=${t}`:null}function R(e){let t=ke(e),n=e.locator;if(typeof n=="string"&&n.trim())return n=n.trim(),n.endsWith("first()")?`${t}.${n}`:`${t}.${n}.first()`;let s=Te(e);if(s){let r=JSON.stringify(s);return`${t}.locator(${r}).first()`}return null}var Oe=["ai_action","ai_step","ai_assert","ai_extract","ai_wait_until","verify","assert"],Ee=["js_code","function","wait","wait_for_download_complete","wait_for_page_ready","extract_email_content","extract_activation_code"];function H(e){let t=e.action_data?.action_name;return!t||(t==="verify"||t==="ai_assert"||t==="assert")&&e.action_data?.kwargs?.code?!1:Oe.includes(t)}function B(e){let t=e.action_data?.action_name;return!t||(t==="verify"||t==="ai_assert"||t==="assert")&&e.action_data?.kwargs?.code?!1:!Ee.includes(t)}var m=new Map;function p(e,t){m.set(e,t)}function Q(e){return m.get(e)}function T(e,t,n=[]){let s=[...n];return t.locator?s.push(`locator: ${JSON.stringify(t.locator)}`):t.xpath&&s.push(`xpath: ${JSON.stringify(t.xpath)}`),t.frame_path&&t.frame_path.length>0&&s.push(`frame_path: ${JSON.stringify(t.frame_path)}`),s.length===0?[`await agent.execAction("${e}", page, {});`]:[`await agent.execAction("${e}", page, {`,...s.map(r=>` ${r},`),"});"]}p("click",e=>{let t=R(e);return t?[`await ${t}.click({ timeout: ${5e3} });`]:['await agent.execAction("click", page, {});']});p("click_element",m.get("click"));p("click_element_by_index",m.get("click"));p("double_click",e=>T("double_click",e));p("double_click_on_element",m.get("double_click"));p("right_click",e=>T("right_click",e));p("right_click_on_element",m.get("right_click"));p("hover",e=>T("hover",e));p("hover_element_by_index",m.get("hover"));p("input_text",e=>{let t=e.action_data?.kwargs?.text??e.action_data?.kwargs?.value??"";return T("input_text",e,[`action_data: { kwargs: { text: ${JSON.stringify(t)} } }`])});p("fill",m.get("input_text"));p("clear_input",e=>T("clear_input",e));p("press",e=>{let t=e.action_data?.kwargs?.keys;return[`await page.keyboard.press(${JSON.stringify(t)});`]});p("send_keys",m.get("press"));p("send_keys_on_element",e=>{let t=R(e),n=e.action_data?.kwargs?.keys||"";return t?[`await ${t}.press(${JSON.stringify(n)}, { timeout: ${5e3} });`]:['await agent.execAction("send_keys_on_element", page, {',` action_data: { kwargs: { keys: ${JSON.stringify(n)} } },`,"});"]});p("select_dropdown_option",e=>{let t=e.action_data?.kwargs?.text||e.action_data?.kwargs?.option||"";return T("select_dropdown_option",e,[`action_data: { kwargs: { text: ${JSON.stringify(t)} } }`])});p("scroll",e=>{let t=e.action_data?.kwargs?.down??!0;return[`await page.evaluate('window.scrollBy(0, window.innerHeight * ${(e.action_data?.kwargs?.num_pages??1)*(t?1:-1)})');`]});p("scroll_down",m.get("scroll"));p("scroll_up",m.get("scroll"));p("scroll_element",m.get("scroll"));p("scroll_to_text",e=>{let t=e.action_data?.kwargs?.text||"";return[`await page.getByText(${JSON.stringify(t)}, { exact: false }).first().scrollIntoViewIfNeeded();`]});p("scroll_on_element",e=>T("scroll_on_element",e,[`action_data: { kwargs: ${JSON.stringify(e.action_data?.kwargs||{})} }`]));p("go_to_url",e=>{let t=e.action_data?.kwargs?.url||"";return e.action_data?.kwargs?.new_tab===!0?['await agent.execAction("go_to_url", page, {',` action_data: { kwargs: { url: ${JSON.stringify(t)}, new_tab: true } },`,"});"]:['await agent.execAction("go_to_url", page, {',` action_data: { kwargs: { url: ${JSON.stringify(t)} } },`,"});"]});p("open_tab",m.get("go_to_url"));p("go_back",()=>['await agent.execAction("go_back", page, {});']);p("reload_page",()=>['await agent.execAction("reload_page", page, {});']);p("wait",e=>[`await page.waitForTimeout(${(e.action_data?.kwargs?.seconds||1)*1e3});`]);p("wait_for_page_ready",()=>["await page.waitForLoadState('domcontentloaded');"]);p("verify",(e,t)=>{let n=e.action_data?.kwargs;if(n?.code)return n.code.split(`
3
+ import{r as $e,s as ye}from"./chunk-NDYQF4WM.js";import"./chunk-JY6U4L7Q.js";import"./chunk-ESJGKHJ4.js";import"./chunk-VXL4KP4U.js";import"./chunk-YU3XZJIJ.js";import"./chunk-QU5HYOUM.js";import{l as _e}from"./chunk-4JBGAENP.js";import"./chunk-FL4TL6US.js";import"./chunk-BVOD5VWH.js";import{b as he}from"./chunk-FBJSHHRD.js";import{Ka as D,ga as N}from"./chunk-SUZXLRAA.js";import"./chunk-CSINHOOD.js";import*as x from"fs";import*as S from"path";import Xe from"dotenv";import{globSync as Qe}from"glob";import{readFileSync as pe,writeFileSync as Ue,statSync as De,existsSync as Ge}from"fs";import{resolve as We}from"path";import{globSync as Ye}from"glob";import{parse as Te,stringify as V}from"yaml";import{readFileSync as we}from"fs";import{resolve as Y,dirname as Se}from"path";import{parse as G,stringify as be}from"yaml";var W=5;function R(e,t){let n={expandingPaths:new Set([Y(t)]),depth:0,referencedPaths:new Set},s={...e};Array.isArray(s.statements)&&(s.statements=k(s.statements,t,n)),Array.isArray(s.teardown)&&(s.teardown=k(s.teardown,t,n));for(let r of["beforeAll","afterAll","beforeEach","afterEach"])Array.isArray(s[r])&&(s[r]=k(s[r],t,n));return{doc:s,referencedTemplatePaths:Array.from(n.referencedPaths)}}function k(e,t,n){let s=[];for(let r of e)if(Ae(r)){let a=xe(r,t,n);s.push(...a)}else s.push(ke(r,t,n));return s}function Ae(e){return typeof e=="object"&&e!==null&&typeof e.template=="string"}function xe(e,t,n){if(n.depth>=W)throw new Error(`Template expansion exceeded maximum depth of ${W}. Check for deeply nested or circular template references.`);let s=Y(Se(t),e.template);if(n.expandingPaths.has(s))throw new Error(`Circular template reference detected: ${s} is already being expanded. Stack: ${Array.from(n.expandingPaths).join(" \u2192 ")} \u2192 ${s}`);n.referencedPaths.add(s);let r;try{r=we(s,"utf-8")}catch(u){throw new Error(`Failed to read template file: ${s} (referenced from ${t}): ${u.message}`)}let a=G(r);if(!a||typeof a!="object")throw new Error(`Invalid template file: ${s} \u2014 expected a YAML object`);let i=a.params||[],o=e.params||{};for(let u of i)if(!(u in o))throw new Error(`Template ${e.template} requires param "${u}" but it was not provided. Required params: [${i.join(", ")}]`);let l=a.statements;if(!Array.isArray(l))throw new Error(`Template ${e.template} must have a "statements" array`);if(Object.keys(o).length>0){let f=be(l);for(let[h,g]of Object.entries(o))f=f.replaceAll(`<<${h}>>`,String(g));l=G(f)}let c={expandingPaths:new Set([...n.expandingPaths,s]),depth:n.depth+1,referencedPaths:n.referencedPaths};return k(l,s,c)}function ke(e,t,n){if(typeof e!="object"||e===null)return e;let s={...e};return Array.isArray(s.statements)&&(s.statements=k(s.statements,t,n)),Array.isArray(s.THEN)&&(s.THEN=k(s.THEN,t,n)),Array.isArray(s.ELSE)&&(s.ELSE=k(s.ELSE,t,n)),Array.isArray(s.DO)&&(s.DO=k(s.DO,t,n)),s}function K(e,t){let n=Te(e),s=n?.name,r=n?.tags,a=n?.use;if(n&&(n.name!==void 0||n.tags!==void 0||n.use!==void 0)&&(delete n.name,delete n.tags,delete n.use),n?.suite){if(n.goal||n.statements)throw new Error('YAML file cannot have both "suite" and top-level "goal"/"statements". Use either suite format or single-test format.');return Oe(n,s,r,a,t)}return Ee(n,s,r,a,t)}function Ee(e,t,n,s,r){let a=e?.beforeEach,i=e?.afterEach,o=q(e?.parameters),l=e?.timeout,c=e?.skip,u=e?.fail,f=e?.only,h=e?.slow;e&&(delete e.beforeEach,delete e.afterEach,delete e.parameters,delete e.timeout,delete e.skip,delete e.fail,delete e.only,delete e.slow),e&&!e.goal&&t&&(e.goal=t);let g=[];if(r&&e&&typeof e=="object"){let b=R(e,r);e=b.doc,g=b.referencedTemplatePaths}let _=V(e);return{testFlow:N(_),name:t,tags:n,use:s,beforeEach:a,afterEach:i,parameters:o,timeout:l,skip:c,fail:u,only:f,slow:h,referencedTemplatePaths:g}}function Oe(e,t,n,s,r){let a=e.suite;if(!Array.isArray(a.tests)||a.tests.length===0)throw new Error('Suite must have a non-empty "tests" array.');let i=a.serial,o=a.beforeAll,l=a.afterAll,c=a.beforeEach,u=a.afterEach,f=[],h=a.tests.map(g=>{if(!g.name)throw new Error('Each test in a suite must have a "name" field.');if(!Array.isArray(g.statements)||g.statements.length===0)throw new Error(`Suite test "${g.name}" must have a non-empty "statements" array.`);let _={goal:g.name,statements:g.statements};g.teardown&&(_.teardown=g.teardown);let T=[],b=_;if(r&&typeof _=="object"){let A=R(_,r);b=A.doc,T=A.referencedTemplatePaths,f.push(...T)}let P=V(b),L=N(P),y=q(g.parameters);return{testFlow:L,name:g.name,parameters:y,timeout:g.timeout,skip:g.skip,fail:g.fail,only:g.only,slow:g.slow}});return{suite:{serial:i,beforeAll:o,afterAll:l,beforeEach:c,afterEach:u,tests:h},name:t,tags:n,use:s,referencedTemplatePaths:f}}function q(e){if(!(!Array.isArray(e)||e.length===0))return e.map((t,n)=>{if(!t.name)throw new Error(`Parameter set at index ${n} must have a "name" field.`);if(!t.values||typeof t.values!="object")throw new Error(`Parameter set "${t.name}" must have a "values" object.`);return{name:t.name,values:t.values}})}import{stringify as te}from"yaml";function w(e){return e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t")}function d(e){return e.replace(/\r\n/g," ").replace(/\n/g," ").replace(/\r/g," ").trim()}function ve(e){let t=e.frame_path;return!t||t.length===0?"page":`page.frameLocator('${t[0]}')`}function Pe(e){let t=e.xpath;return typeof t=="string"&&t.trim()?!t.startsWith("xpath=")&&!t.startsWith("/")&&!t.startsWith("//")?`xpath=//${t}`:t.startsWith("xpath=")?t:`xpath=${t}`:null}function J(e){let t=ve(e),n=e.locator;if(typeof n=="string"&&n.trim())return n=n.trim(),n.endsWith("first()")?`${t}.${n}`:`${t}.${n}.first()`;let s=Pe(e);if(s){let r=JSON.stringify(s);return`${t}.locator(${r}).first()`}return null}var Ne=["ai_action","ai_step","ai_assert","ai_extract","ai_wait_until","verify","assert"],Le=["js_code","function","wait","wait_for_download_complete","wait_for_page_ready","extract_email_content","extract_activation_code"];function H(e){let t=e.action_data?.action_name;return!t||(t==="verify"||t==="ai_assert"||t==="assert")&&e.action_data?.kwargs?.code?!1:Ne.includes(t)}function B(e){let t=e.action_data?.action_name;return!t||(t==="verify"||t==="ai_assert"||t==="assert")&&e.action_data?.kwargs?.code?!1:!Le.includes(t)}var m=new Map;function p(e,t){m.set(e,t)}function Q(e){return m.get(e)}function E(e,t,n=[]){let s=[...n];return t.locator?s.push(`locator: ${JSON.stringify(t.locator)}`):t.xpath&&s.push(`xpath: ${JSON.stringify(t.xpath)}`),t.frame_path&&t.frame_path.length>0&&s.push(`frame_path: ${JSON.stringify(t.frame_path)}`),s.length===0?[`await agent.execAction("${e}", page, {});`]:[`await agent.execAction("${e}", page, {`,...s.map(r=>` ${r},`),"});"]}p("click",e=>{let t=J(e);return t?[`await ${t}.click({ timeout: ${5e3} });`]:['await agent.execAction("click", page, {});']});p("click_element",m.get("click"));p("click_element_by_index",m.get("click"));p("double_click",e=>E("double_click",e));p("double_click_on_element",m.get("double_click"));p("right_click",e=>E("right_click",e));p("right_click_on_element",m.get("right_click"));p("hover",e=>E("hover",e));p("hover_element_by_index",m.get("hover"));p("input_text",e=>{let t=e.action_data?.kwargs?.text??e.action_data?.kwargs?.value??"";return E("input_text",e,[`action_data: { kwargs: { text: ${JSON.stringify(t)} } }`])});p("fill",m.get("input_text"));p("clear_input",e=>E("clear_input",e));p("press",e=>{let t=e.action_data?.kwargs?.keys;return[`await page.keyboard.press(${JSON.stringify(t)});`]});p("send_keys",m.get("press"));p("send_keys_on_element",e=>{let t=J(e),n=e.action_data?.kwargs?.keys||"";return t?[`await ${t}.press(${JSON.stringify(n)}, { timeout: ${5e3} });`]:['await agent.execAction("send_keys_on_element", page, {',` action_data: { kwargs: { keys: ${JSON.stringify(n)} } },`,"});"]});p("select_dropdown_option",e=>{let t=e.action_data?.kwargs?.text||e.action_data?.kwargs?.option||"";return E("select_dropdown_option",e,[`action_data: { kwargs: { text: ${JSON.stringify(t)} } }`])});p("scroll",e=>{let t=e.action_data?.kwargs?.down??!0;return[`await page.evaluate('window.scrollBy(0, window.innerHeight * ${(e.action_data?.kwargs?.num_pages??1)*(t?1:-1)})');`]});p("scroll_down",m.get("scroll"));p("scroll_up",m.get("scroll"));p("scroll_element",m.get("scroll"));p("scroll_to_text",e=>{let t=e.action_data?.kwargs?.text||"";return[`await page.getByText(${JSON.stringify(t)}, { exact: false }).first().scrollIntoViewIfNeeded();`]});p("scroll_on_element",e=>E("scroll_on_element",e,[`action_data: { kwargs: ${JSON.stringify(e.action_data?.kwargs||{})} }`]));p("go_to_url",e=>{let t=e.action_data?.kwargs?.url||"";return e.action_data?.kwargs?.new_tab===!0?['await agent.execAction("go_to_url", page, {',` action_data: { kwargs: { url: ${JSON.stringify(t)}, new_tab: true } },`,"});"]:['await agent.execAction("go_to_url", page, {',` action_data: { kwargs: { url: ${JSON.stringify(t)} } },`,"});"]});p("open_tab",m.get("go_to_url"));p("go_back",()=>['await agent.execAction("go_back", page, {});']);p("reload_page",()=>['await agent.execAction("reload_page", page, {});']);p("wait",e=>[`await page.waitForTimeout(${(e.action_data?.kwargs?.seconds||1)*1e3});`]);p("wait_for_page_ready",()=>["await page.waitForLoadState('domcontentloaded');"]);p("verify",(e,t)=>{let n=e.action_data?.kwargs;if(n?.code)return n.code.split(`
4
4
  `);let s=n?.statement||e.action_description;return s?[`await agent.assert(page, ${JSON.stringify(s)}, '${t||""}');`]:["// Skipping verify: missing statement or code"]});p("ai_assert",m.get("verify"));p("assert",m.get("verify"));p("ai_action",(e,t)=>{let n=e.action_data?.kwargs?.statement;if(!n)return["// Skipping ai_action: missing statement"];let s=JSON.stringify(n),r=e.action_data?.kwargs?.use_pure_vision;return[`await agent.execute(page, ${s}, '${t||""}', ${r});`]});p("ai_step",(e,t)=>{let n=e.action_data?.kwargs?.statement;return n?[`await agent.run(page, ${JSON.stringify(n)}, '${t||""}');`]:["// Skipping ai_step: missing statement"]});p("ai_extract",(e,t)=>{let n=e.action_data?.kwargs?.element_description,s=e.action_data?.kwargs?.variable_name;if(!n||!s)return["// Skipping ai_extract: missing element_description or variable_name"];let r=JSON.stringify(n),a=JSON.stringify(s);return[`await agent.extract(page, ${r}, ${a}, '${t||""}');`]});p("ai_wait_until",(e,t)=>{let n=e.action_data?.kwargs?.condition,s=e.action_data?.kwargs?.timeout_seconds||60;return n?[`await agent.waitUntilCondition(page, ${JSON.stringify(n)}, ${s}, '${t||""}');`]:["// Skipping ai_wait_until: missing condition"]});p("save_variable",e=>{let t=e.action_data?.kwargs?.name||"",n=e.action_data?.kwargs?.value;return['await agent.execAction("save_variable", page, {',` action_data: { kwargs: { name: ${JSON.stringify(t)}, value: ${JSON.stringify(n)} } },`,"});"]});p("js_code",e=>{let t=e.action_data?.kwargs?.code;if(!t)return["// Skipping js_code: missing code"];let n=["{"],s=t.split(`
5
- `);for(let r of s)n.push(` ${r}`);return n.push("}"),n});p("function",(e,t,n)=>{let s=e.action_data?.kwargs||{},r=s.functionName;if(r&&r.includes("#")){let[i,o]=r.split("#");if(i&&o){let l=i.replace(/\.(ts|js|mjs)$/,""),c=`import { ${o} } from '${l}';`;n?.imports?.add(c);let u={...s,functionName:o},f=z(u);return f?[f.endsWith(";")?f:`${f};`]:["// Skipping function: invalid export pattern"]}}let a=z(s);return a?[a.endsWith(";")?a:`${a};`]:["// Skipping function: missing functionName"]});p("generate_2fa_code",e=>{let t=e.action_data?.kwargs?.otp_secret_key||"";return['await agent.execAction("generate_2fa_code", page, {',` action_data: { kwargs: { otp_secret_key: ${JSON.stringify(t)} } },`,"});"]});p("upload_file",e=>{let t=e.action_data?.kwargs||{},n=[],s={};return t.paths?s.paths=t.paths:t.path&&(s.path=t.path),t.use_file_input&&(s.use_file_input=!0),n.push(`action_data: { kwargs: ${JSON.stringify(s)} }`),e.locator?n.push(`locator: ${JSON.stringify(e.locator)}`):e.xpath&&n.push(`xpath: ${JSON.stringify(e.xpath)}`),e.frame_path&&e.frame_path.length>0&&n.push(`frame_path: ${JSON.stringify(e.frame_path)}`),['await agent.execAction("upload_file", page, {',...n.map(r=>` ${r},`),"});"]});p("wait_for_download_complete",e=>['await agent.execAction("wait_for_download_complete", page, {',` action_data: { kwargs: { timeout_seconds: ${e.action_data?.kwargs?.timeout_seconds||10} } },`,"});"]);p("switch_tab",e=>['await agent.execAction("switch_tab", page, {',` action_data: { kwargs: { page_id: ${e.action_data?.kwargs?.page_id??0} } },`,"});"]);p("close_tab",e=>{let t=e.action_data?.kwargs?.page_id;return t=t??e.action_data?.kwargs?.index,['await agent.execAction("close_tab", page, {',` action_data: { kwargs: { page_id: ${t} } },`,"});"]});p("set_date_for_native_date_picker",e=>{let t=e.action_data?.kwargs?.date??"",n=[];return n.push(`action_data: { kwargs: { date: ${JSON.stringify(t)} } }`),e.locator?n.push(`locator: ${JSON.stringify(e.locator)}`):e.xpath&&n.push(`xpath: ${JSON.stringify(e.xpath)}`),e.frame_path&&e.frame_path.length>0&&n.push(`frame_path: ${JSON.stringify(e.frame_path)}`),['await agent.execAction("set_date_for_native_date_picker", page, {',...n.map(s=>` ${s},`),"});"]});p("done",()=>["// Done - no action needed"]);function z(e){let t=e.functionName;if(!t)return null;let n={},s=e.parameterNames||[],r=e.parameterValues||e.args||[];if(s.forEach((l,c)=>{c<r.length&&(n[l]=r[c])}),Object.keys(n).length===0)return`await ${t}()`;let a=["page","testContext","request","agentServices"],i=["undefined","null","true","false"],o=Object.entries(n).map(([l,c])=>{let u=String(c);return c==null?"undefined":a.includes(l)&&a.includes(u)||i.includes(u)||/^-?\d+(\.\d+)?$/.test(u)?u:u.startsWith("$")?`agent.agentServices.readVariable('${u.substring(1)}')`:`"${u}"`});return`await ${t}(${o.join(", ")})`}function y(e,t,n,s="main"){let r=[];for(let a=0;a<e.length;a++){let i=e[a],o=`${s}.${a}`,l=ve(i,t,o,n);l.length>0&&(r.push(...l),a<e.length-1&&r.push(""))}return r}function ve(e,t,n,s){let r=" ".repeat(t);switch(e.type){case"DRAFT":return Pe(e,t,n,s);case"ACTION":return Ne(e,t,n,s);case"STEP":return Le(e,t,n,s);case"IF_ELSE":return Ce(e,t,n,s);case"WHILE_LOOP":return Ie(e,t,n,s);default:return[`${r}// Unknown statement type: ${e.type}`]}}function Pe(e,t,n,s){let r=" ".repeat(t),a=e.description?.trim()||"";if(!a)return[`${r}// ${n}: Skipping - no description`];if(s.noAgent)return[`${r}// ${n}: ${d(a)}`,`${r}// DRAFT: ${d(a)} (requires agent - skipped in hook)`];let i=JSON.stringify(a);return[`${r}// ${n}: ${d(a)}`,`${r}// \u26A0 DRAFT: AI-resolved at runtime (~5-10s). Add a locator to make this <1s.`,`${r}page = agent.agentServices.validatePage(page);`,`${r}await agent.run(page, ${i}, '${n}');`]}function Ne(e,t,n,s){let r=" ".repeat(t),a=e.description,i=e.uid,l=s.actionEntityStore?.entries[e.uid]?.action_entity??e.action_entity;if(!l){if(!a)return[`${r}// ${n}: Skipping - no description`];if(s.noAgent)return[`${r}// ${n}: ${d(a)}`,`${r}// DRAFT: ${d(a)} (requires agent - skipped in hook)`];let h=JSON.stringify(a),E=!!e.use_pure_vision;return[`${r}// ${n}: ${d(a)}`,`${r}// \u26A0 DRAFT: AI-resolved at runtime (~5-10s). Add a locator to make this <1s.`,`${r}page = agent.agentServices.validatePage(page);`,`${r}await agent.execute(page, ${h}, '${n}', ${E});`]}let c=e.locator?{...l,locator:e.locator}:l;a&&a!==c.action_description&&(c={...c,action_description:a});let u=c.action_data?.action_name||"",f=c.action_description||"",_=Q(u);if(!_)return[`${r}// ${n}: Unknown action: ${u}`];let g={imports:s.imports},$=_(c,n,g);if(s.noAgent){if(H(c))return[`${r}// ${n}: ${d(f)}`,`${r}// AI action: ${d(f)} (requires agent - skipped in hook)`];let h=je(c,u,r,n);return h||[`${r}// ${n}: ${d(f)}`,...$.map(E=>`${r}${E}`)]}if(H(c))return[`${r}// ${n}: ${d(f)}`,`${r}page = agent.agentServices.validatePage(page);`,...$.map(h=>`${r}${h}`)];let k=JSON.stringify(f),S=$.map(h=>`${r} ${h}`),P=B(c),C=i?`'${i}'`:"undefined";return[`${r}// ${n}: ${d(f)}`,`${r}page = agent.agentServices.validatePage(page);`,`${r}await agent.step(page, async () => {`,...S,`${r}}, ${k}, '${n}', ${C}, ${P});`]}function Le(e,t,n,s){let r=" ".repeat(t),a=[];e.description&&e.description.trim()&&a.push(`${r}// Step: ${d(e.description)}`);let i=y(e.statements,t,s,n);return a.push(...i),a}function Ce(e,t,n,s){let r=" ".repeat(t),a=[];if(a.push(`${r}// ${n}: Conditional check`),e.condition.type==="JS_CODE")a.push(`${r}if (${e.condition.expression}) {`);else{a.push(`${r}// AI Condition: ${d(e.condition.expression)}`);let o=JSON.stringify(e.condition.expression);a.push(`${r}if (await agent.evaluate(page, ${o}, "${n}")) {`)}let i=y(e.then,t+1,s,`${n}.then`);if(a.push(...i),e.else&&e.else.length>0){a.push(`${r}} else {`);let o=y(e.else,t+1,s,`${n}.else`);a.push(...o)}return a.push(`${r}}`),a}function Ie(e,t,n,s){let r=" ".repeat(t),a=[];a.push(`${r}// ${n}: Loop`);let i=e.timeout_ms??W,o=i/1e3,l=e.timeout_ms?`While loop exceeded timeout of ${o}s`:`While loop exceeded default timeout of ${o}s`,c=`loop_${n.replace(/\./g,"_")}`;if(a.push(`${r}const ${c}_start = Date.now();`),a.push(`${r}const ${c}_timeout = ${i};`),a.push(`${r}const ${c}_check = () => {`),a.push(`${r} if (Date.now() - ${c}_start > ${c}_timeout) {`),a.push(`${r} throw new Error('${l}');`),a.push(`${r} }`),a.push(`${r} return true;`),a.push(`${r}};`),e.condition.type==="JS_CODE")a.push(`${r}while (${c}_check() && (${e.condition.expression})) {`);else{a.push(`${r}// AI Loop Condition: ${d(e.condition.expression)}`);let f=JSON.stringify(e.condition.expression);a.push(`${r}while (${c}_check() && await agent.evaluate(page, ${f}, "${n}")) {`)}let u=y(e.body,t+1,s,`${n}.body`);return a.push(...u),a.push(`${r}}`),a}function je(e,t,n,s){let r=e.action_description||"",a=e.action_data?.kwargs||{};switch(t){case"go_to_url":case"open_tab":{let i=a.url||"";return[`${n}// ${s}: ${d(r)}`,`${n}await page.goto(${JSON.stringify(i)}, { waitUntil: 'domcontentloaded' });`]}case"go_back":return[`${n}// ${s}: ${d(r)}`,`${n}await page.goBack();`];case"go_forward":return[`${n}// ${s}: ${d(r)}`,`${n}await page.goForward();`];case"input_text":{let i=a.text||"",o=getPageLocatorExpression(e);return o?[`${n}// ${s}: ${d(r)}`,`${n}await ${o}.fill(${JSON.stringify(i)}, { timeout: ${ACTION_TIMEOUT} });`]:null}case"select_dropdown_option":{let i=a.text||a.label||"",o=getPageLocatorExpression(e);return o?[`${n}// ${s}: ${d(r)}`,`${n}await ${o}.selectOption({ label: ${JSON.stringify(i)} }, { timeout: ${ACTION_TIMEOUT} });`]:null}default:return null}}var Z={name:"shiplightai",version:"0.1.12",type:"module",description:"Shiplight CLI for running and debugging .test.yaml files",main:"dist/index.js",types:"dist/index.d.ts",bin:{shiplight:"dist/cli.js"},exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/cjs/index.cjs",default:"./dist/index.js"},"./fixture":{types:"./dist/fixture.d.ts",import:"./dist/fixture.js",require:"./dist/cjs/fixture.cjs",default:"./dist/fixture.js"}},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org",access:"public"},scripts:{build:"tsup","build:cli":"tsup",clean:"rm -rf dist",dev:"tsup --watch",test:"playwright test",typecheck:"tsc --noEmit"},dependencies:{"@babel/plugin-transform-typescript":"^7.27.0","@babel/preset-env":"^7.26.9","@babel/preset-typescript":"^7.27.0","@anthropic-ai/claude-agent-sdk":"^0.1.72","@modelcontextprotocol/sdk":"^0.5.0",axios:"^1.6.0",dotenv:"^16.0.3",express:"^4.21.0",glob:"^13.0.0",open:"^10.1.0",sharp:"^0.34.5",uuid:"^11.1.0",yaml:"^2.8.0",zod:"^3.22.0","zod-to-json-schema":"^3.24.6"},devDependencies:{"@playwright/test":"1.55.0","@types/express":"^4.17.21","@types/node":"^24.0.0",copilot3:"workspace:*","mcp-tools":"workspace:*","sdk-core":"workspace:*","sdk-internal":"workspace:*","shiplight-types":"workspace:*",tsup:"^8.3.5",typescript:"5.5.4","web-session":"workspace:*"},peerDependencies:{"@playwright/test":">=1.40.0"},engines:{node:">=22.0.0"},keywords:["playwright","yaml","testing","automation","ai","shiplight","mcp"],author:"Shiplight",license:"MIT"};var N=Z.version;function ne(e,t){let n=[];n.push(`// @generated by shiplightai v${N}`),n.push(...ie()),n.push(""),t?.use&&Object.keys(t.use).length>0&&(n.push(`test.use(${JSON.stringify(t.use,null,2)});`),n.push(""));let s=new Set,r={imports:s};t?.beforeEach&&t.beforeEach.length>0&&(n.push(...ee("beforeEach",t.beforeEach,r)),n.push(""));let a=t?.timeout||t?.skip!==void 0||t?.fail!==void 0||t?.only||t?.slow?{timeout:t.timeout,skip:t.skip,fail:t.fail,only:t.only,slow:t.slow}:void 0;if(t?.parameters&&t.parameters.length>0){let i=t?.testName||e.goal||"Generated test",o=M(t?.tags);for(let l of t.parameters){let c=ae(e,l.values);n.push(...j(c,`${o}${w(i)} [${w(l.name)}]`,r,0,a)),n.push("")}}else{let i=t?.testName||e.goal||"Generated test",o=M(t?.tags);n.push(...j(e,`${o}${w(i)}`,r,0,a))}return t?.afterEach&&t.afterEach.length>0&&(n.push(""),n.push(...ee("afterEach",t.afterEach,r))),oe(n,s),n.join(`
6
- `)}function re(e,t){let n=[];n.push(`// @generated by shiplightai v${N}`),n.push(...ie()),n.push(""),t?.use&&Object.keys(t.use).length>0&&(n.push(`test.use(${JSON.stringify(t.use,null,2)});`),n.push(""));let s=new Set,r={imports:s},a=t?.testName||"Test Suite",i=M(t?.tags),o=e.serial?"test.describe.serial":"test.describe";n.push(`${o}('${i}${w(a)}', () => {`),e.beforeAll&&e.beforeAll.length>0&&(n.push(...I("beforeAll",e.beforeAll,r,1)),n.push("")),e.beforeEach&&e.beforeEach.length>0&&(n.push(...I("beforeEach",e.beforeEach,r,1)),n.push(""));for(let l=0;l<e.tests.length;l++){let c=e.tests[l],u=c.timeout||c.skip!==void 0||c.fail!==void 0||c.only||c.slow?{timeout:c.timeout,skip:c.skip,fail:c.fail,only:c.only,slow:c.slow}:void 0;if(c.parameters&&c.parameters.length>0)for(let f of c.parameters){let _=ae(c.testFlow,f.values);n.push(...j(_,`${w(c.name)} [${w(f.name)}]`,r,1,u)),n.push("")}else n.push(...j(c.testFlow,w(c.name),r,1,u)),(l<e.tests.length-1||e.afterEach||e.afterAll)&&n.push("")}return e.afterEach&&e.afterEach.length>0&&(n.push(...I("afterEach",e.afterEach,r,1)),n.push("")),e.afterAll&&e.afterAll.length>0&&n.push(...I("afterAll",e.afterAll,r,1)),n.push("});"),oe(n,s),n.join(`
7
- `)}function M(e){return e&&e.length>0?e.map(t=>`@${t}`).join(" ")+" ":""}function j(e,t,n,s=0,r){let a=" ".repeat(s),i=[],o=r?.only?"test.only":"test";i.push(`${a}${o}('${t}', async ({ page, agent }) => {`),r?.skip===!0?i.push(`${a} test.skip();`):typeof r?.skip=="string"&&i.push(`${a} test.skip(true, '${w(r.skip)}');`),r?.fail===!0?i.push(`${a} test.fail();`):typeof r?.fail=="string"&&i.push(`${a} test.fail(true, '${w(r.fail)}');`),r?.slow&&i.push(`${a} test.slow();`),r?.timeout&&i.push(`${a} test.setTimeout(${r.timeout});`);let l=e.teardown&&e.teardown.length>0,c=s+1;if(l){if(i.push(`${a} try {`),e.statements&&e.statements.length>0){i.push(`${a} // Test steps`);let f=y(e.statements,c+1,n);i.push(...f)}i.push(`${a} } finally {`),i.push(`${a} // Teardown`);let u=y(e.teardown,c+1,n,"teardown");i.push(...u),i.push(`${a} }`)}else if(e.statements&&e.statements.length>0){i.push(`${a} // Test steps`);let u=y(e.statements,c,n);i.push(...u)}return i.push(`${a}});`),i}function ee(e,t,n){let s=[],r=se(t);return s.push(`test.${e}(async ({ page, agent }) => {`),s.push(...y(r,1,n,e)),s.push("});"),s}function I(e,t,n,s){let r=" ".repeat(s),a=[],i=se(t);if(e==="beforeAll"||e==="afterAll"){let l={...n,noAgent:!0};a.push(`${r}test.${e}(async ({ browser }, workerInfo) => {`),a.push(`${r} const page = await browser.newPage({ baseURL: workerInfo.project.use.baseURL });`),a.push(...y(i,s+1,l,e)),a.push(`${r} await page.close();`),a.push(`${r}});`)}else a.push(`${r}test.${e}(async ({ page, agent }) => {`),a.push(...y(i,s+1,n,e)),a.push(`${r}});`);return a}function se(e){let n=te({goal:"_hook",statements:e});return v(n).statements}function ae(e,t){let n=te({goal:e.goal,statements:e.statements,teardown:e.teardown});for(let[s,r]of Object.entries(t))n=n.replaceAll(`<<${s}>>`,String(r));return v(n)}function ie(){return["import { test, expect } from 'shiplightai/fixture';"]}function oe(e,t){if(t.size>0){let n=0;for(let r=0;r<e.length;r++)e[r].startsWith("import ")&&(n=r+1);let s=Array.from(t);e.splice(n,0,...s)}}function ce(e){try{return Re(e).mtimeMs}catch{return 0}}var We=`// @generated by shiplightai v${N}`;function Ye(e,t){if(!He(e)||pe(e,"utf-8").split(`
8
- `,1)[0]!==We)return!1;let s=ce(e);for(let r of t)if(ce(r)>s)return!1;return!0}function le(e){let t=Ge("**/*.test.yaml",{cwd:e.cwd,ignore:["**/node_modules/**"]}),n=[];for(let s of t){let r=Me(e.cwd,s),a=r.replace(/\.test\.yaml$/,".yaml.spec.ts"),i=pe(r,"utf-8");try{let o=K(i,r);if(Ye(a,[r,...o.referencedTemplatePaths]))continue;let l;o.suite?l=re(o.suite,{testName:o.name,tags:o.tags,use:o.use}):l=ne(o.testFlow,{testName:o.name,tags:o.tags,use:o.use,beforeEach:o.beforeEach,afterEach:o.afterEach,parameters:o.parameters,timeout:o.timeout,skip:o.skip,fail:o.fail,only:o.only,slow:o.slow}),Je(a,l)}catch(o){console.error(`[shiplight] Failed to transpile ${s}:`,o),n.push({file:s,error:o})}}if(n.length>0)throw new Error(`[shiplight] Transpilation failed for ${n.length} file(s):
5
+ `);for(let r of s)n.push(` ${r}`);return n.push("}"),n});p("function",(e,t,n)=>{let s=e.action_data?.kwargs||{},r=s.functionName;if(r&&r.includes("#")){let[i,o]=r.split("#");if(i&&o){let l=i.replace(/\.(ts|js|mjs)$/,""),c=`import { ${o} } from '${l}';`;n?.imports?.add(c);let u={...s,functionName:o},f=z(u);return f?[f.endsWith(";")?f:`${f};`]:["// Skipping function: invalid export pattern"]}}let a=z(s);return a?[a.endsWith(";")?a:`${a};`]:["// Skipping function: missing functionName"]});p("generate_2fa_code",e=>{let t=e.action_data?.kwargs?.otp_secret_key||"";return['await agent.execAction("generate_2fa_code", page, {',` action_data: { kwargs: { otp_secret_key: ${JSON.stringify(t)} } },`,"});"]});p("upload_file",e=>{let t=e.action_data?.kwargs||{},n=[],s={};return t.paths?s.paths=t.paths:t.path&&(s.path=t.path),t.use_file_input&&(s.use_file_input=!0),n.push(`action_data: { kwargs: ${JSON.stringify(s)} }`),e.locator?n.push(`locator: ${JSON.stringify(e.locator)}`):e.xpath&&n.push(`xpath: ${JSON.stringify(e.xpath)}`),e.frame_path&&e.frame_path.length>0&&n.push(`frame_path: ${JSON.stringify(e.frame_path)}`),['await agent.execAction("upload_file", page, {',...n.map(r=>` ${r},`),"});"]});p("wait_for_download_complete",e=>['await agent.execAction("wait_for_download_complete", page, {',` action_data: { kwargs: { timeout_seconds: ${e.action_data?.kwargs?.timeout_seconds||10} } },`,"});"]);p("switch_tab",e=>['await agent.execAction("switch_tab", page, {',` action_data: { kwargs: { page_id: ${e.action_data?.kwargs?.page_id??0} } },`,"});"]);p("close_tab",e=>{let t=e.action_data?.kwargs?.page_id;return t=t??e.action_data?.kwargs?.index,['await agent.execAction("close_tab", page, {',` action_data: { kwargs: { page_id: ${t} } },`,"});"]});p("set_date_for_native_date_picker",e=>{let t=e.action_data?.kwargs?.date??"",n=[];return n.push(`action_data: { kwargs: { date: ${JSON.stringify(t)} } }`),e.locator?n.push(`locator: ${JSON.stringify(e.locator)}`):e.xpath&&n.push(`xpath: ${JSON.stringify(e.xpath)}`),e.frame_path&&e.frame_path.length>0&&n.push(`frame_path: ${JSON.stringify(e.frame_path)}`),['await agent.execAction("set_date_for_native_date_picker", page, {',...n.map(s=>` ${s},`),"});"]});p("done",()=>["// Done - no action needed"]);function z(e){let t=e.functionName;if(!t)return null;let n={},s=e.parameterNames||[],r=e.parameterValues||e.args||[];if(s.forEach((l,c)=>{c<r.length&&(n[l]=r[c])}),Object.keys(n).length===0)return`await ${t}()`;let a=["page","testContext","request","agentServices"],i=["undefined","null","true","false"],o=Object.entries(n).map(([l,c])=>{let u=String(c);return c==null?"undefined":a.includes(l)&&a.includes(u)||i.includes(u)||/^-?\d+(\.\d+)?$/.test(u)?u:u.startsWith("$")?`agent.agentServices.readVariable('${u.substring(1)}')`:`"${u}"`});return`await ${t}(${o.join(", ")})`}function $(e,t,n,s="main"){let r=[];for(let a=0;a<e.length;a++){let i=e[a],o=`${s}.${a}`,l=Ce(i,t,o,n);l.length>0&&(r.push(...l),a<e.length-1&&r.push(""))}return r}function Ce(e,t,n,s){let r=" ".repeat(t);switch(e.type){case"DRAFT":return Ie(e,t,n,s);case"ACTION":return je(e,t,n,s);case"STEP":return Fe(e,t,n,s);case"IF_ELSE":return Re(e,t,n,s);case"WHILE_LOOP":return Je(e,t,n,s);default:return[`${r}// Unknown statement type: ${e.type}`]}}function Ie(e,t,n,s){let r=" ".repeat(t),a=e.description?.trim()||"";if(!a)return[`${r}// ${n}: Skipping - no description`];if(s.noAgent)return[`${r}// ${n}: ${d(a)}`,`${r}// DRAFT: ${d(a)} (requires agent - skipped in hook)`];let i=JSON.stringify(a);return[`${r}// ${n}: ${d(a)}`,`${r}// \u26A0 DRAFT: AI-resolved at runtime (~5-10s). Add a locator to make this <1s.`,`${r}page = agent.agentServices.validatePage(page);`,`${r}await agent.run(page, ${i}, '${n}');`]}function je(e,t,n,s){let r=" ".repeat(t),a=e.description,i=e.uid,l=s.actionEntityStore?.entries[e.uid]?.action_entity??e.action_entity;if(!l){if(!a)return[`${r}// ${n}: Skipping - no description`];if(s.noAgent)return[`${r}// ${n}: ${d(a)}`,`${r}// DRAFT: ${d(a)} (requires agent - skipped in hook)`];let y=JSON.stringify(a),A=!!e.use_pure_vision;return[`${r}// ${n}: ${d(a)}`,`${r}// \u26A0 DRAFT: AI-resolved at runtime (~5-10s). Add a locator to make this <1s.`,`${r}page = agent.agentServices.validatePage(page);`,`${r}await agent.execute(page, ${y}, '${n}', ${A});`]}let c=e.locator?{...l,locator:e.locator}:l;a&&a!==c.action_description&&(c={...c,action_description:a});let u=c.action_data?.action_name||"",f=c.action_description||"",h=Q(u);if(!h)return[`${r}// ${n}: Unknown action: ${u}`];let g={imports:s.imports},_=h(c,n,g);if(s.noAgent){if(H(c))return[`${r}// ${n}: ${d(f)}`,`${r}// AI action: ${d(f)} (requires agent - skipped in hook)`];let y=He(c,u,r,n);return y||[`${r}// ${n}: ${d(f)}`,..._.map(A=>`${r}${A}`)]}if(H(c))return[`${r}// ${n}: ${d(f)}`,`${r}page = agent.agentServices.validatePage(page);`,..._.map(y=>`${r}${y}`)];let T=JSON.stringify(f),b=_.map(y=>`${r} ${y}`),P=B(c),L=i?`'${i}'`:"undefined";return[`${r}// ${n}: ${d(f)}`,`${r}page = agent.agentServices.validatePage(page);`,`${r}await agent.step(page, async () => {`,...b,`${r}}, ${T}, '${n}', ${L}, ${P});`]}function Fe(e,t,n,s){let r=" ".repeat(t),a=[];e.description&&e.description.trim()&&a.push(`${r}// Step: ${d(e.description)}`);let i=$(e.statements,t,s,n);return a.push(...i),a}function Re(e,t,n,s){let r=" ".repeat(t),a=[];if(a.push(`${r}// ${n}: Conditional check`),e.condition.type==="JS_CODE")a.push(`${r}if (${e.condition.expression}) {`);else{a.push(`${r}// AI Condition: ${d(e.condition.expression)}`);let o=JSON.stringify(e.condition.expression);a.push(`${r}if (await agent.evaluate(page, ${o}, "${n}")) {`)}let i=$(e.then,t+1,s,`${n}.then`);if(a.push(...i),e.else&&e.else.length>0){a.push(`${r}} else {`);let o=$(e.else,t+1,s,`${n}.else`);a.push(...o)}return a.push(`${r}}`),a}function Je(e,t,n,s){let r=" ".repeat(t),a=[];a.push(`${r}// ${n}: Loop`);let i=e.timeout_ms??D,o=i/1e3,l=e.timeout_ms?`While loop exceeded timeout of ${o}s`:`While loop exceeded default timeout of ${o}s`,c=`loop_${n.replace(/\./g,"_")}`;if(a.push(`${r}const ${c}_start = Date.now();`),a.push(`${r}const ${c}_timeout = ${i};`),a.push(`${r}const ${c}_check = () => {`),a.push(`${r} if (Date.now() - ${c}_start > ${c}_timeout) {`),a.push(`${r} throw new Error('${l}');`),a.push(`${r} }`),a.push(`${r} return true;`),a.push(`${r}};`),e.condition.type==="JS_CODE")a.push(`${r}while (${c}_check() && (${e.condition.expression})) {`);else{a.push(`${r}// AI Loop Condition: ${d(e.condition.expression)}`);let f=JSON.stringify(e.condition.expression);a.push(`${r}while (${c}_check() && await agent.evaluate(page, ${f}, "${n}")) {`)}let u=$(e.body,t+1,s,`${n}.body`);return a.push(...u),a.push(`${r}}`),a}function He(e,t,n,s){let r=e.action_description||"",a=e.action_data?.kwargs||{};switch(t){case"go_to_url":case"open_tab":{let i=a.url||"";return[`${n}// ${s}: ${d(r)}`,`${n}await page.goto(${JSON.stringify(i)}, { waitUntil: 'domcontentloaded' });`]}case"go_back":return[`${n}// ${s}: ${d(r)}`,`${n}await page.goBack();`];case"go_forward":return[`${n}// ${s}: ${d(r)}`,`${n}await page.goForward();`];case"input_text":{let i=a.text||"",o=getPageLocatorExpression(e);return o?[`${n}// ${s}: ${d(r)}`,`${n}await ${o}.fill(${JSON.stringify(i)}, { timeout: ${ACTION_TIMEOUT} });`]:null}case"select_dropdown_option":{let i=a.text||a.label||"",o=getPageLocatorExpression(e);return o?[`${n}// ${s}: ${d(r)}`,`${n}await ${o}.selectOption({ label: ${JSON.stringify(i)} }, { timeout: ${ACTION_TIMEOUT} });`]:null}default:return null}}var Z={name:"shiplightai",version:"0.1.13",type:"module",description:"Shiplight CLI for running and debugging .test.yaml files",main:"dist/index.js",types:"dist/index.d.ts",bin:{shiplight:"dist/cli.js"},exports:{".":{types:"./dist/index.d.ts",import:"./dist/index.js",require:"./dist/cjs/index.cjs",default:"./dist/index.js"},"./fixture":{types:"./dist/fixture.d.ts",import:"./dist/fixture.js",require:"./dist/cjs/fixture.cjs",default:"./dist/fixture.js"},"./debugger-pw":{types:"./dist/debugger-pw.d.ts",import:"./dist/debugger-pw.js",require:"./dist/cjs/debugger-pw.cjs",default:"./dist/debugger-pw.js"}},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org",access:"public"},scripts:{build:"tsup","build:cli":"tsup",clean:"rm -rf dist",dev:"tsup --watch",test:"playwright test",typecheck:"tsc --noEmit"},dependencies:{"@babel/plugin-transform-typescript":"^7.27.0","@babel/preset-env":"^7.26.9","@babel/preset-typescript":"^7.27.0","@anthropic-ai/claude-agent-sdk":"^0.1.72","@modelcontextprotocol/sdk":"^0.5.0",axios:"^1.6.0",dotenv:"^16.0.3",express:"^4.21.0",glob:"^13.0.0",open:"^10.1.0",sharp:"^0.34.5",uuid:"^11.1.0",yaml:"^2.8.0",zod:"^3.22.0","zod-to-json-schema":"^3.24.6"},devDependencies:{"@playwright/test":"1.55.0","@types/express":"^4.17.21","@types/node":"^24.0.0",copilot3:"workspace:*","mcp-tools":"workspace:*","sdk-core":"workspace:*","sdk-internal":"workspace:*","shiplight-types":"workspace:*",tsup:"^8.3.5",typescript:"5.5.4","web-session":"workspace:*"},peerDependencies:{"@playwright/test":">=1.40.0"},engines:{node:">=22.0.0"},keywords:["playwright","yaml","testing","automation","ai","shiplight","mcp"],author:"Shiplight",license:"MIT"};var C=Z.version;function ne(e,t){let n=[];n.push(`// @generated by shiplightai v${C}`),n.push(...ie()),n.push(""),t?.use&&Object.keys(t.use).length>0&&(n.push(`test.use(${JSON.stringify(t.use,null,2)});`),n.push(""));let s=new Set,r={imports:s};t?.beforeEach&&t.beforeEach.length>0&&(n.push(...ee("beforeEach",t.beforeEach,r)),n.push(""));let a=t?.timeout||t?.skip!==void 0||t?.fail!==void 0||t?.only||t?.slow?{timeout:t.timeout,skip:t.skip,fail:t.fail,only:t.only,slow:t.slow}:void 0;if(t?.parameters&&t.parameters.length>0){let i=t?.testName||e.goal||"Generated test",o=M(t?.tags);for(let l of t.parameters){let c=ae(e,l.values);n.push(...j(c,`${o}${w(i)} [${w(l.name)}]`,r,0,a)),n.push("")}}else{let i=t?.testName||e.goal||"Generated test",o=M(t?.tags);n.push(...j(e,`${o}${w(i)}`,r,0,a))}return t?.afterEach&&t.afterEach.length>0&&(n.push(""),n.push(...ee("afterEach",t.afterEach,r))),oe(n,s),n.join(`
6
+ `)}function re(e,t){let n=[];n.push(`// @generated by shiplightai v${C}`),n.push(...ie()),n.push(""),t?.use&&Object.keys(t.use).length>0&&(n.push(`test.use(${JSON.stringify(t.use,null,2)});`),n.push(""));let s=new Set,r={imports:s},a=t?.testName||"Test Suite",i=M(t?.tags),o=e.serial?"test.describe.serial":"test.describe";n.push(`${o}('${i}${w(a)}', () => {`),e.beforeAll&&e.beforeAll.length>0&&(n.push(...I("beforeAll",e.beforeAll,r,1)),n.push("")),e.beforeEach&&e.beforeEach.length>0&&(n.push(...I("beforeEach",e.beforeEach,r,1)),n.push(""));for(let l=0;l<e.tests.length;l++){let c=e.tests[l],u=c.timeout||c.skip!==void 0||c.fail!==void 0||c.only||c.slow?{timeout:c.timeout,skip:c.skip,fail:c.fail,only:c.only,slow:c.slow}:void 0;if(c.parameters&&c.parameters.length>0)for(let f of c.parameters){let h=ae(c.testFlow,f.values);n.push(...j(h,`${w(c.name)} [${w(f.name)}]`,r,1,u)),n.push("")}else n.push(...j(c.testFlow,w(c.name),r,1,u)),(l<e.tests.length-1||e.afterEach||e.afterAll)&&n.push("")}return e.afterEach&&e.afterEach.length>0&&(n.push(...I("afterEach",e.afterEach,r,1)),n.push("")),e.afterAll&&e.afterAll.length>0&&n.push(...I("afterAll",e.afterAll,r,1)),n.push("});"),oe(n,s),n.join(`
7
+ `)}function M(e){return e&&e.length>0?e.map(t=>`@${t}`).join(" ")+" ":""}function j(e,t,n,s=0,r){let a=" ".repeat(s),i=[],o=r?.only?"test.only":"test";i.push(`${a}${o}('${t}', async ({ page, agent }) => {`),r?.skip===!0?i.push(`${a} test.skip();`):typeof r?.skip=="string"&&i.push(`${a} test.skip(true, '${w(r.skip)}');`),r?.fail===!0?i.push(`${a} test.fail();`):typeof r?.fail=="string"&&i.push(`${a} test.fail(true, '${w(r.fail)}');`),r?.slow&&i.push(`${a} test.slow();`),r?.timeout&&i.push(`${a} test.setTimeout(${r.timeout});`);let l=e.teardown&&e.teardown.length>0,c=s+1;if(l){if(i.push(`${a} try {`),e.statements&&e.statements.length>0){i.push(`${a} // Test steps`);let f=$(e.statements,c+1,n);i.push(...f)}i.push(`${a} } finally {`),i.push(`${a} // Teardown`);let u=$(e.teardown,c+1,n,"teardown");i.push(...u),i.push(`${a} }`)}else if(e.statements&&e.statements.length>0){i.push(`${a} // Test steps`);let u=$(e.statements,c,n);i.push(...u)}return i.push(`${a}});`),i}function ee(e,t,n){let s=[],r=se(t);return s.push(`test.${e}(async ({ page, agent }) => {`),s.push(...$(r,1,n,e)),s.push("});"),s}function I(e,t,n,s){let r=" ".repeat(s),a=[],i=se(t);if(e==="beforeAll"||e==="afterAll"){let l={...n,noAgent:!0};a.push(`${r}test.${e}(async ({ browser }, workerInfo) => {`),a.push(`${r} const page = await browser.newPage({ baseURL: workerInfo.project.use.baseURL });`),a.push(...$(i,s+1,l,e)),a.push(`${r} await page.close();`),a.push(`${r}});`)}else a.push(`${r}test.${e}(async ({ page, agent }) => {`),a.push(...$(i,s+1,n,e)),a.push(`${r}});`);return a}function se(e){let n=te({goal:"_hook",statements:e});return N(n).statements}function ae(e,t){let n=te({goal:e.goal,statements:e.statements,teardown:e.teardown});for(let[s,r]of Object.entries(t))n=n.replaceAll(`<<${s}>>`,String(r));return N(n)}function ie(){return["import { test, expect } from 'shiplightai/fixture';"]}function oe(e,t){if(t.size>0){let n=0;for(let r=0;r<e.length;r++)e[r].startsWith("import ")&&(n=r+1);let s=Array.from(t);e.splice(n,0,...s)}}function ce(e){try{return De(e).mtimeMs}catch{return 0}}var Ve=`// @generated by shiplightai v${C}`;function Ke(e,t){if(!Ge(e)||pe(e,"utf-8").split(`
8
+ `,1)[0]!==Ve)return!1;let s=ce(e);for(let r of t)if(ce(r)>s)return!1;return!0}function le(e){let t=Ye("**/*.test.yaml",{cwd:e.cwd,ignore:["**/node_modules/**"]}),n=[];for(let s of t){let r=We(e.cwd,s),a=r.replace(/\.test\.yaml$/,".yaml.spec.ts"),i=pe(r,"utf-8");try{let o=K(i,r);if(Ke(a,[r,...o.referencedTemplatePaths]))continue;let l;o.suite?l=re(o.suite,{testName:o.name,tags:o.tags,use:o.use}):l=ne(o.testFlow,{testName:o.name,tags:o.tags,use:o.use,beforeEach:o.beforeEach,afterEach:o.afterEach,parameters:o.parameters,timeout:o.timeout,skip:o.skip,fail:o.fail,only:o.only,slow:o.slow}),Ue(a,l)}catch(o){console.error(`[shiplight] Failed to transpile ${s}:`,o),n.push({file:s,error:o})}}if(n.length>0)throw new Error(`[shiplight] Transpilation failed for ${n.length} file(s):
9
9
  `+n.map(s=>` - ${s.file}`).join(`
10
- `))}import*as L from"path";import{mkdir as De}from"fs/promises";import*as F from"fs";import*as O from"path";function G(e){let t=null,n=process.env.SHIPLIGHT_LOGIN_EMAIL,s=process.env.SHIPLIGHT_LOGIN_PASSWORD;return n&&s&&(t={username:n,password:s}),t||(t=Ue(e)),t?(process.env.SHIPLIGHT_LOGIN_URL&&(t.loginUrl=process.env.SHIPLIGHT_LOGIN_URL),process.env.SHIPLIGHT_LOGIN_TOTP_SECRET&&(t.totpSecret=process.env.SHIPLIGHT_LOGIN_TOTP_SECRET),t):null}function Ue(e){let t=O.resolve(e),n=O.resolve(process.cwd());for(;;){for(let r of["shiplight.config.json","login.config.json"]){let a=O.join(t,r);if(F.existsSync(a))try{let i=JSON.parse(F.readFileSync(a,"utf-8"));if(i.username&&i.password)return{username:i.username,password:i.password,loginUrl:i.url,totpSecret:i.totp_secret}}catch{}}if(t===n)break;let s=O.dirname(t);if(s===t)break;t=s}return null}async function Ve(e,t){let n=L.resolve(t),s=G(n);if(!s)return;let{WebAgent:r,createAgentContext:a,configureSdk:i,VariableStore:o,LoginType:l,TwoFactorAuthType:c}=await import("./dist-4ZMHICD4.js");i({env:{GOOGLE_API_KEY:process.env.GOOGLE_API_KEY??"",ANTHROPIC_API_KEY:process.env.ANTHROPIC_API_KEY??""}});let{resolveModelFromEnv:u}=await import("./dist-3WNQHYT3.js"),f=u(process.env);if(!f)throw new Error("No AI model configured. Set WEB_AGENT_MODEL, ANTHROPIC_API_KEY, or GOOGLE_API_KEY.");let _=new r(a({model:f,variableStore:new o})),{username:g,password:$,loginUrl:k,totpSecret:S}=s,P=k||e.url()||"about:blank";if(!(await _.loginPage(e,{site_url:P,num_verification_exprs:0,account:{type:l.PASSWORD,username:g,password:$,...S&&{two_factor_auth_config:{type:c.TOTP,data:S}}}})).success)throw new Error("Login failed.");let h=L.join(n,".auth");await De(h,{recursive:!0}),await e.context().storageState({path:L.join(h,"storage-state.json")})}function ue(){return`// @generated by shiplightai \u2014 do not edit
10
+ `))}import*as v from"path";import*as ge from"fs";import{mkdir as Be}from"fs/promises";import*as F from"fs";import*as O from"path";function U(e){let t=null,n=process.env.SHIPLIGHT_LOGIN_EMAIL,s=process.env.SHIPLIGHT_LOGIN_PASSWORD;return n&&s&&(t={username:n,password:s}),t||(t=qe(e)),t?(process.env.SHIPLIGHT_LOGIN_URL&&(t.loginUrl=process.env.SHIPLIGHT_LOGIN_URL),process.env.SHIPLIGHT_LOGIN_TOTP_SECRET&&(t.totpSecret=process.env.SHIPLIGHT_LOGIN_TOTP_SECRET),t):null}function qe(e){let t=O.resolve(e),n=O.resolve(process.cwd());for(;;){for(let r of["shiplight.config.json","login.config.json"]){let a=O.join(t,r);if(F.existsSync(a))try{let i=JSON.parse(F.readFileSync(a,"utf-8"));if(i.username&&i.password)return{username:i.username,password:i.password,loginUrl:i.url,totpSecret:i.totp_secret}}catch{}}if(t===n)break;let s=O.dirname(t);if(s===t)break;t=s}return null}var de="auth.setup.ts",ue=".auth",fe="storage-state.json";async function ze(e,t){let n=v.resolve(t),s=v.join(n,ue,fe);if(ge.existsSync(s)){console.log("[INFO] Storage state exists, skipping login. Delete",s,"to force re-auth.");return}let r=U(n);if(!r)return;let{WebAgent:a,createAgentContext:i,configureSdk:o,VariableStore:l,LoginType:c,TwoFactorAuthType:u}=await import("./dist-OOFTSMK3.js");o({env:{GOOGLE_API_KEY:process.env.GOOGLE_API_KEY??"",ANTHROPIC_API_KEY:process.env.ANTHROPIC_API_KEY??""}});let{resolveModelFromEnv:f}=await import("./dist-WQ66EMT6.js"),h=f(process.env);if(!h)throw new Error("No AI model configured. Set WEB_AGENT_MODEL, ANTHROPIC_API_KEY, or GOOGLE_API_KEY.");let g=new a(i({model:h,variableStore:new l})),{username:_,password:T,loginUrl:b,totpSecret:P}=r,L=b||e.url()||"about:blank";if(!(await g.loginPage(e,{site_url:L,num_verification_exprs:0,account:{type:c.PASSWORD,username:_,password:T,...P&&{two_factor_auth_config:{type:u.TOTP,data:P}}}})).success)throw new Error("Login failed.");let A=v.join(n,ue);await Be(A,{recursive:!0}),await e.context().storageState({path:v.join(A,fe)})}function me(){return`// @generated by shiplightai \u2014 do not edit
11
11
  import { test as setup } from '@playwright/test';
12
+ import { authSetup } from 'shiplightai';
12
13
 
13
14
  setup('authenticate', async ({ page }) => {
14
- const { authSetup } = await import('shiplightai');
15
- await authSetup(page, __dirname);
15
+ await authSetup(page, import.meta.dirname);
16
16
  });
17
- `}function Be(e={}){e.dotenv!==!1&&ze(e.scanDir||process.cwd());let t=e.scanDir||process.cwd();return le({cwd:t}),Xe(t),e.apiKey&&(process.env.__SHIPLIGHT_API_KEY=e.apiKey),{}}function ze(e){let t=[],n=b.resolve(e),s=b.resolve(process.cwd());for(;;){let r=b.join(n,".env");if(x.existsSync(r)&&t.push(r),n===s)break;let a=b.dirname(n);if(a===n)break;n=a}for(let r of t)Ke.config({path:r})}function Xe(e){let t=qe("**/shiplight.config.json",{cwd:e,ignore:["**/node_modules/**"]});for(let n of t){let s=b.resolve(e,n),r=b.dirname(s),a=b.join(r,"auth.setup.ts"),i=!1;try{let o=JSON.parse(x.readFileSync(s,"utf-8"));i=!!(o.username&&o.password)}catch{}if(!i&&process.env.SHIPLIGHT_LOGIN_EMAIL&&process.env.SHIPLIGHT_LOGIN_PASSWORD&&(i=!0),!!i){try{let o=x.statSync(s).mtimeMs;if(x.statSync(a).mtimeMs>o)continue}catch{}x.writeFileSync(a,ue())}}}export{ge as VariableStore,de as WebAgent,Ve as authSetup,fe as configureSdk,me as createAgentContext,G as resolveLoginConfig,Be as shiplightConfig};
17
+ `}function Ze(e={}){e.dotenv!==!1&&et(e.scanDir||process.cwd());let t=e.scanDir||process.cwd();return le({cwd:t}),tt(t),e.apiKey&&(process.env.__SHIPLIGHT_API_KEY=e.apiKey),{}}function et(e){let t=[],n=S.resolve(e),s=S.resolve(process.cwd());for(;;){let r=S.join(n,".env");if(x.existsSync(r)&&t.push(r),n===s)break;let a=S.dirname(n);if(a===n)break;n=a}for(let r of t)Xe.config({path:r})}function tt(e){let t=Qe("**/shiplight.config.json",{cwd:e,ignore:["**/node_modules/**"]});for(let n of t){let s=S.resolve(e,n),r=S.dirname(s),a=S.join(r,de),i=!1;try{let o=JSON.parse(x.readFileSync(s,"utf-8"));i=!!(o.username&&o.password)}catch{}if(!i&&process.env.SHIPLIGHT_LOGIN_EMAIL&&process.env.SHIPLIGHT_LOGIN_PASSWORD&&(i=!0),!!i){try{let o=x.statSync(s).mtimeMs;if(x.statSync(a).mtimeMs>o)continue}catch{}x.writeFileSync(a,me())}}}export{_e as VariableStore,$e as WebAgent,ze as authSetup,he as configureSdk,ye as createAgentContext,U as resolveLoginConfig,Ze as shiplightConfig};
@@ -0,0 +1,7 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ const require = __createRequire(import.meta.url);
3
+ import"./chunk-CSINHOOD.js";import{Router as g}from"express";function p(o){let r=g();return r.post("/api/int-runner/create-session",async(t,e)=>{try{let s=t.body.startingUrl||t.body.testFlow?.url||t.body.urlOverride,n=await o.createSession({startingUrl:s});e.json({status:"success",sessionId:n.sessionId,searchParams:""})}catch(s){console.error("[debugger] create-session error:",s),e.status(500).json({status:"error",message:s.message})}}),r.post("/api/int-runner/login",async(t,e)=>{try{let{session:s}=t.body;if(!s?.sessionId)return e.status(400).json({status:"error",message:"Missing session"});let n=await o.executeLogin(s.sessionId);e.json(n)}catch(s){console.error("[debugger] login error:",s),e.status(500).json({status:"error",details:s.message})}}),r.post("/api/int-runner/liveview-url",async(t,e)=>{let{session:s}=t.body;if(!s?.sessionId)return e.status(400).json({status:"error",message:"Missing session"});e.json({liveviewUrl:"",browserWsUrl:""})}),r.post("/api/int-runner/end-debug",async(t,e)=>{let{session:s}=t.body;if(!s?.sessionId)return e.status(400).json({status:"error",message:"Missing session"});e.json({status:"success"})}),r.post("/api/int-runner/start-debug",async(t,e)=>{try{let{session:s}=t.body;if(!s?.sessionId)return e.status(400).json({status:"error",message:"Missing session"});let n=await o.startDebug(s.sessionId);e.json({status:"success",...n})}catch(s){console.error("[debugger] start-debug error:",s),e.status(500).json({status:"error",message:s.message})}}),r.post("/api/int-runner/execute-action",async(t,e)=>{try{let{session:s,actionEntity:n,stepId:c,withSelfHealing:i,stmtUid:u,executionHistory:a}=t.body;if(!s?.sessionId||!n)return e.status(400).json({status:"error",message:"Missing session or actionEntity"});let d=await o.executeAction(s.sessionId,n,c,{withSelfHealing:i,stmtUid:u,executionHistory:a});e.json(d)}catch(s){console.error("[debugger] execute-action error:",s),e.status(500).json({status:"error",details:s.message})}}),r.post("/api/int-runner/run-step",async(t,e)=>{let{session:s,statement:n,stepId:c,executionHistory:i}=t.body;if(!s?.sessionId||!n)return e.status(400).json({success:!1,message:"Session and statement required"});e.setHeader("Content-Type","text/event-stream"),e.setHeader("Cache-Control","no-cache"),e.setHeader("Connection","keep-alive"),e.flushHeaders();let u=a=>{e.write(`data: ${JSON.stringify(a)}
4
+
5
+ `)};try{await o.runStep(s.sessionId,n,c,u,i)}catch(a){u({type:"error",data:{message:a.message}})}finally{e.end()}}),r.post("/api/int-runner/execute-step",async(t,e)=>{let{session:s,statement:n,stepId:c,executionHistory:i,maxSteps:u}=t.body;if(!s?.sessionId||!n)return e.status(400).json({success:!1,message:"Session and statement required"});e.setHeader("Content-Type","text/event-stream"),e.setHeader("Cache-Control","no-cache"),e.setHeader("Connection","keep-alive"),e.flushHeaders();let a=d=>{e.write(`data: ${JSON.stringify(d)}
6
+
7
+ `)};try{await o.runStep(s.sessionId,n,c,a,i)}catch(d){a({type:"error",data:{message:d.message}})}finally{e.end()}}),r.post("/api/int-runner/stop-run-step",async(t,e)=>{try{let{session:s}=t.body;if(!s?.sessionId)return e.status(400).json({status:"error",message:"Missing session"});let n=o.stopRunStep(s.sessionId);e.json({status:"success",aborted:n})}catch(s){console.error("[debugger] stop-run-step error:",s),e.status(500).json({status:"error",aborted:!1,details:s.message})}}),r.post("/api/int-runner/evaluate",async(t,e)=>{try{let{session:s,statement:n,stepId:c,executionHistory:i}=t.body;if(!s?.sessionId||!n)return e.status(400).json({status:"error",message:"Missing session or statement"});let u=await o.evaluate(s.sessionId,n,i);e.json(u)}catch(s){console.error("[debugger] evaluate error:",s),e.status(500).json({status:"error",conclusion:"unknown",explanation:s.message})}}),r.post("/api/int-runner/generate-action",async(t,e)=>{try{let{session:s,statement:n,stepId:c,executionHistory:i,usePureVision:u,includeDebugInfo:a}=t.body;if(!s?.sessionId||!n)return e.status(400).json({status:"error",message:"Missing session or statement"});let d=await o.generateAction(s.sessionId,n,c,{executionHistory:i,usePureVision:u,includeDebugInfo:a});e.json(d)}catch(s){console.error("[debugger] generate-action error:",s),e.status(500).json({status:"error",details:s.message})}}),r.post("/api/int-runner/screenshot",async(t,e)=>{try{let{session:s}=t.body;if(!s?.sessionId)return e.status(400).json({status:"error",message:"Missing session"});let n=await o.takeScreenshot(s.sessionId);e.json({status:"success",...n})}catch(s){console.error("[debugger] screenshot error:",s),e.status(500).json({status:"error",message:s.message})}}),r.post("/api/int-runner/terminate-session",async(t,e)=>{try{let{session:s}=t.body;if(!s?.sessionId)return e.status(400).json({status:"error",message:"Missing session"});await o.terminateSession(s.sessionId),e.json({status:"success",details:`Session ${s.sessionId} terminated`})}catch(s){console.error("[debugger] terminate-session error:",s),e.status(500).json({status:"error",details:s.message})}}),r.post("/api/int-runner/session-status",async(t,e)=>{let{session:s}=t.body;if(!s?.sessionId)return e.status(400).json({status:"timed_out"});e.json({status:"active",remainingSeconds:9999})}),r}export{p as createIntRunnerRouter};
@@ -1,6 +1,6 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  const require = __createRequire(import.meta.url);
3
- import{h as E}from"./chunk-FL4TL6US.js";import{b as $,c as N,d as O,f as U,n as M}from"./chunk-RP6LTE6E.js";import{m as R}from"./chunk-CYBAFQLF.js";import{a as i}from"./chunk-BVOD5VWH.js";import"./chunk-FBJSHHRD.js";import"./chunk-YU3XZJIJ.js";import"./chunk-CSINHOOD.js";import{z as b}from"zod";function _(t,o,e){let s=()=>t.stepHistory.length===0?"":`**Recent Steps**:
3
+ import{b as $,c as N,d as O,f as U,n as M}from"./chunk-VXL4KP4U.js";import"./chunk-YU3XZJIJ.js";import{m as R}from"./chunk-QU5HYOUM.js";import{h as E}from"./chunk-FL4TL6US.js";import{a as i}from"./chunk-BVOD5VWH.js";import"./chunk-FBJSHHRD.js";import"./chunk-CSINHOOD.js";import{z as b}from"zod";function _(t,o,e){let s=()=>t.stepHistory.length===0?"":`**Recent Steps**:
4
4
  ${t.stepHistory.slice(-3).map(a=>{let n=`${a.outcome.success?"\u2713":"\u2717"} Step ${a.stepNumber}: ${a.goal}`;if(a.actions.length>1)a.actions.forEach((c,l)=>{let h=c.action_description||"Unknown action";n+=`
5
5
  \u2192 Action ${l+1}: ${h}`});else if(a.actions.length===1){let c=a.actions[0]?.action_description||"Unknown action";n+=`
6
6
  \u2192 ${c}`}if(!a.outcome.success&&a.outcome.error){let c=a.outcome.error.substring(0,100);n+=`
@@ -0,0 +1,3 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ const require = __createRequire(import.meta.url);
3
+ import{ca as c,fa as u,ga as m}from"./chunk-SUZXLRAA.js";import"./chunk-CSINHOOD.js";import{Router as g}from"express";import*as o from"fs/promises";import*as w from"path";function j(r){let a=g();return a.get("/api/test-flow",async(f,s)=>{try{let t=await o.readFile(r,"utf-8"),n=m(t),i=u(t),e=await o.stat(r);s.json({testFlow:n,metadata:i,filePath:r,fileName:w.basename(r),lastModified:e.mtimeMs})}catch(t){if(t.code==="ENOENT")return s.status(404).json({error:`File not found: ${r}`});console.error("[debugger] Error loading test flow:",t),s.status(500).json({error:t.message})}}),a.put("/api/test-flow",async(f,s)=>{try{let{testFlow:t,metadata:n}=f.body;if(!t)return s.status(400).json({error:"testFlow is required"});let i=c(t,n),e=r+".tmp";await o.writeFile(e,i,"utf-8"),await o.rename(e,r);let d=await o.stat(r);s.json({success:!0,lastModified:d.mtimeMs})}catch(t){console.error("[debugger] Error saving test flow:",t),s.status(500).json({error:t.message})}}),a}export{j as createTestFlowRouter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shiplightai",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "type": "module",
5
5
  "description": "Shiplight CLI for running and debugging .test.yaml files",
6
6
  "main": "dist/index.js",
@@ -20,6 +20,12 @@
20
20
  "import": "./dist/fixture.js",
21
21
  "require": "./dist/cjs/fixture.cjs",
22
22
  "default": "./dist/fixture.js"
23
+ },
24
+ "./debugger-pw": {
25
+ "types": "./dist/debugger-pw.d.ts",
26
+ "import": "./dist/debugger-pw.js",
27
+ "require": "./dist/cjs/debugger-pw.cjs",
28
+ "default": "./dist/debugger-pw.js"
23
29
  }
24
30
  },
25
31
  "files": [
@@ -1,3 +0,0 @@
1
- import { createRequire as __createRequire } from "module";
2
- const require = __createRequire(import.meta.url);
3
- import{d as t,e as o,f as r,g as p,h as i}from"./chunk-T3YFBZB6.js";import"./chunk-RP6LTE6E.js";import"./chunk-CYBAFQLF.js";import"./chunk-BVOD5VWH.js";import"./chunk-FBJSHHRD.js";import"./chunk-YU3XZJIJ.js";import"./chunk-CSINHOOD.js";export{p as evaluateStatement,t as executeAction,r as executeStep,o as generateActionStep,i as runTask};
@@ -1,5 +0,0 @@
1
- import { createRequire as __createRequire } from "module";
2
- const require = __createRequire(import.meta.url);
3
- import{a as f,d,e as w}from"./chunk-FBJSHHRD.js";var L=class{getLevel(){return f.get("logLevel")}debug(...e){this.getLevel()<=0&&console.error("[DEBUG]",...e)}info(...e){this.getLevel()<=1&&console.error("[INFO]",...e)}log(...e){this.info(...e)}warn(...e){this.getLevel()<=2&&console.warn("[WARN]",...e)}error(...e){this.getLevel()<=3&&console.error("[ERROR]",...e)}setLevel(e){f.set("logLevel",e)}},v=new L,s=v;var _={};w(_,{ACTION_TIMEOUT:()=>h,GOTO_TIMEOUT:()=>y,LOCATOR_TIMEOUT:()=>u,getActionTimeoutMs:()=>E,getFrameContext:()=>p,getLocator:()=>W,getMinimalActionEntity:()=>A,getPageLocatorExpression:()=>$,sanitizeForComment:()=>O});function E(e){return e?.getActionSettings()?.action_timeout_ms??h}function O(e){return e.replace(/\r\n/g," ").replace(/\n/g," ").replace(/\r/g," ").trim()}function W(e,t){let a=$(t);return a?new Function("page",`return ${a}`)(e):null}async function p(e,t=[]){let a=e;for(let l of t){let r=await a.locator(l).elementHandle();if(!r)return null;let n=await r.contentFrame();if(await r.dispose(),!n)return null;a=n}return a}function A(e){let t={action_data:e.action_data};return e.locator&&(t.locator=e.locator),e.xpath&&(t.xpath=e.xpath),e.frame_path&&(t.frame_path=e.frame_path),t}function M(e){let t=e.frame_path;return!t||t.length===0?"page":`page.frameLocator('${t[0]}')`}function T(e){let t=e.xpath;return typeof t=="string"&&t.trim()?!t.startsWith("xpath=")&&!t.startsWith("/")&&!t.startsWith("//")?`xpath=//${t}`:t.startsWith("xpath=")?t:`xpath=${t}`:null}function $(e){let t=M(e),a=e.locator;if(typeof a=="string"&&a.trim())return a=a.trim(),a.endsWith("first()")?`${t}.${a}`:`${t}.${a}.first()`;let l=T(e);if(l){let r=JSON.stringify(l);return`${t}.locator(${r}).first()`}return null}var u,h,y,x=d(()=>{u=1e4,h=1e4,y=2e4});x();async function g(e,t,a=[],l=[]){try{let r=null;if(l.length>0){let o=await p(e,a);if(!o)return s.warn(`Could not find frame context for shadow DOM element with xpath: ${t}`),null;let i=l[0];if(!i)return s.warn(`Missing shadow host xpath for element: ${t}`),null;let c=o.locator(`xpath=${b(i)}`),m=C(t);if(r=await(m?c.locator(`css=${m}`):c.locator(`xpath=${b(t)}`)).elementHandle({timeout:u}),!r)return s.warn(`Could not find shadow DOM element with xpath: ${t}`),null}else{let o=e;for(let i of a)o=o.frameLocator(i);if(r=await o.locator(`xpath=${t}`).elementHandle({timeout:u}),!r)return s.warn(`Could not find element with xpath: ${t}`),null}let n=await e.evaluate(o=>typeof playwright<"u"&&playwright.generateLocator?playwright.generateLocator(o):null,r);return await r.dispose(),n?(s.debug(`Generated locator for ${t}: ${n}`),n):(s.debug("playwright.generateLocator is not available (PWDEBUG=console not set), using xpath fallback"),null)}catch(r){return s.error(`Error in pickBestLocator: ${r}`),null}}async function S(e,t){try{let a=await e.evaluate(l=>typeof playwright<"u"&&playwright.generateLocator?playwright.generateLocator(l):null,t);return await t.dispose(),a?(s.debug(`Generated locator: ${a}`),a):(s.debug("playwright.generateLocator is not available (PWDEBUG=console not set), using xpath fallback"),null)}catch(a){return s.error(`Error in pickBestLocator: ${a}`),null}}async function z(e,t){let a=new Map;return await Promise.all(t.map(async l=>{let r=await g(e,l);a.set(l,r)})),a}function b(e){let t=e.trim();return t.startsWith("/")||t.startsWith("(")||t.startsWith(".")?t:`//${t}`}function C(e){let t=e.trim().replace(/^\/+/,"");if(!t)return null;let a=t.split("/").filter(Boolean),l=[];for(let r of a){let n=r.match(/^([a-zA-Z][\w-]*)(?:\[(\d+)\])?$/);if(!n)return null;let o=n[1].toLowerCase(),i=n[2]?`:nth-of-type(${n[2]})`:"";l.push(`${o}${i}`)}return l.join(" > ")}async function Z(e,t){if(t<0)return;let{page:a,domService:l}=e;return(e.domState||await l.getClickableElements(a)).selectorMap.get(t)}function k(e){let t=e.split("/").filter(r=>r);if(t.length===0)return"*";let a=t[t.length-1],l=a.match(/^(\w+)(?:\[(\d+)\])?$/);if(l){let[,r,n]=l;return n?`${r}:nth-of-type(${n})`:r}return a}function B(e,t=!0){try{let a=k(e.xpath);if(e.attributes.class&&t){let r=/^[a-zA-Z_][a-zA-Z0-9_-]*$/,n=e.attributes.class.split(/\s+/);for(let o of n)o.trim()&&r.test(o)&&(a+=`.${o}`)}let l=new Set(["id","name","type","placeholder","aria-label","aria-labelledby","aria-describedby","role","for","autocomplete","required","readonly","alt","title","target"]);t&&["data-id","data-qa","data-cy","data-testid","data-handlepos"].forEach(r=>l.add(r));for(let[r,n]of Object.entries(e.attributes)){if(r==="class"||!r.trim()||!l.has(r))continue;let o=r.replace(/:/g,"\\:");if(n==="")a+=`[${o}]`;else if(/["'<>`\n\r\t]/.test(n)){let i=n;n.includes(`
4
- `)&&(i=n.split(`
5
- `)[0]),i=i.replace(/\s+/g," ").trim();let c=i.replace(/"/g,'\\"');a+=`[${o}*="${c}"]`}else a+=`[${o}="${n}"]`}return a}catch{return`${e.tagName||"*"}[highlight_index='${e.highlightIndex}']`}}function F(e){let t=[],a=e;for(;a&&a.parent!==null;){let n=a.parent;t.push(n),a=n}t.reverse();let l=[],r=t.filter(n=>n.tagName==="iframe");for(let n of r){let o=B(n,!0);l.push(o)}return l}async function q(e,t){let a=null,l=F(t);return t.xpath&&(a=await g(e,t.xpath,l,t.shadowHostXPaths??[])),{locator:a||void 0,xpath:t.xpath,frame_path:l}}export{s as a,_ as b,E as c,W as d,$ as e,y as f,x as g,g as h,S as i,z as j,Z as k,F as l,q as m};