shiplightai 0.1.34 → 0.1.35

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.
@@ -4496,7 +4496,7 @@ ${m.join(`
4496
4496
  `)}function kB(r,e){let t=[],n=e?.version||"unknown";t.push(`// @generated by shiplightai v${n}`),t.push(...Jk()),t.push(""),e?.use&&Object.keys(e.use).length>0&&(t.push(`test.use(${JSON.stringify(e.use,null,2)});`),t.push(""));let i=new Set,s={imports:i},a=e?.testName||"Test Suite",o=nw(e?.tags);t.push(`test.describe.serial('${o}${Is(a)}', () => {`),r.beforeAll&&r.beforeAll.length>0&&(t.push(...Jf("beforeAll",r.beforeAll,s,1)),t.push("")),r.beforeEach&&r.beforeEach.length>0&&(t.push(...Jf("beforeEach",r.beforeEach,s,1)),t.push(""));for(let c=0;c<r.tests.length;c++){let u=r.tests[c],p=u.timeout||u.skip!==void 0||u.fail!==void 0||u.only||u.slow?{timeout:u.timeout,skip:u.skip,fail:u.fail,only:u.only,slow:u.slow}:void 0;if(u.parameters&&u.parameters.length>0)for(let m of u.parameters){let f=Kk(u.testFlow,m.values);t.push(...Xf(f,`${Is(u.name)} [${Is(m.name)}]`,s,1,p)),t.push("")}else t.push(...Xf(u.testFlow,Is(u.name),s,1,p)),(c<r.tests.length-1||r.afterEach||r.afterAll)&&t.push("")}return r.afterEach&&r.afterEach.length>0&&(t.push(...Jf("afterEach",r.afterEach,s,1)),t.push("")),r.afterAll&&r.afterAll.length>0&&t.push(...Jf("afterAll",r.afterAll,s,1)),t.push("});"),Yk(t,i),t.join(`
4497
4497
  `)}function nw(r){return r&&r.length>0?r.map(e=>`@${e}`).join(" ")+" ":""}function Xf(r,e,t,n=0,i){let s=" ".repeat(n),a=[],o=i?.only?"test.only":"test";a.push(`${s}${o}('${e}', async ({ page, agent }) => {`),i?.skip===!0?a.push(`${s} test.skip();`):typeof i?.skip=="string"&&a.push(`${s} test.skip(true, '${Is(i.skip)}');`),i?.fail===!0?a.push(`${s} test.fail();`):typeof i?.fail=="string"&&a.push(`${s} test.fail(true, '${Is(i.fail)}');`),i?.slow&&a.push(`${s} test.slow();`),i?.timeout&&a.push(`${s} test.setTimeout(${i.timeout});`);let l=r.teardown&&r.teardown.length>0,c=n+1;if(l){if(a.push(`${s} try {`),r.statements&&r.statements.length>0){a.push(`${s} // Test steps`);let p=Mi(r.statements,c+1,t);a.push(...p)}a.push(`${s} } finally {`),a.push(`${s} // Teardown`);let u=Mi(r.teardown,c+1,t,"teardown");a.push(...u),a.push(`${s} }`)}else if(r.statements&&r.statements.length>0){a.push(`${s} // Test steps`);let u=Mi(r.statements,c,t);a.push(...u)}return a.push(`${s}});`),a}function Wk(r,e,t){let n=[],i=Vk(e);return n.push(`test.${r}(async ({ page, agent }) => {`),n.push(...Mi(i,1,t,r)),n.push("});"),n}function Jf(r,e,t,n){let i=" ".repeat(n),s=[],a=Vk(e);if(r==="beforeAll"||r==="afterAll"){let l={...t,noAgent:!0};s.push(`${i}test.${r}(async ({ browser }, workerInfo) => {`),s.push(`${i} const page = await browser.newPage({ baseURL: workerInfo.project.use.baseURL });`),s.push(...Mi(a,n+1,l,r)),s.push(`${i} await page.close();`),s.push(`${i}});`)}else s.push(`${i}test.${r}(async ({ page, agent }) => {`),s.push(...Mi(a,n+1,t,r)),s.push(`${i}});`);return s}function Vk(r){let t=(0,Gk.stringify)({goal:"_hook",statements:r});return Ri(t).statements??[]}function Kk(r,e){let t=Qb(r);for(let[n,i]of Object.entries(e))t=t.split(`<<${n}>>`).join(String(i));return Ri(t)}function Jk(){return["import { test, expect } from 'shiplightai/fixture';"]}function Yk(r,e){if(e.size>0){let t=0;for(let i=0;i<r.length;i++)r[i].startsWith("import ")&&(t=i+1);let n=Array.from(e);r.splice(t,0,...n)}}var zk=5;function Zk(r,e){let t={expandingPaths:new Set([(0,hd.resolve)(e)]),depth:0,referencedPaths:new Set},n={...r};Array.isArray(n.statements)&&(n.statements=xa(n.statements,e,t)),Array.isArray(n.teardown)&&(n.teardown=xa(n.teardown,e,t));for(let i of["beforeAll","afterAll","beforeEach","afterEach"])Array.isArray(n[i])&&(n[i]=xa(n[i],e,t));return{doc:n,referencedTemplatePaths:Array.from(t.referencedPaths)}}function xa(r,e,t){let n=[];for(let i of r)if(CB(i)){let s=IB(i,e,t);n.push(...s)}else n.push(PB(i,e,t));return n}function CB(r){return typeof r=="object"&&r!==null&&typeof r.template=="string"}function IB(r,e,t){if(t.depth>=zk)throw new Error(`Template expansion exceeded maximum depth of ${zk}. Check for deeply nested or circular template references.`);let n=(0,hd.resolve)((0,hd.dirname)(e),r.template);if(t.expandingPaths.has(n))throw new Error(`Circular template reference detected: ${n} is already being expanded. Stack: ${Array.from(t.expandingPaths).join(" \u2192 ")} \u2192 ${n}`);t.referencedPaths.add(n);let i;try{i=(0,Xk.readFileSync)(n,"utf-8")}catch(u){throw new Error(`Failed to read template file: ${n} (referenced from ${e}): ${u.message}`)}let s=(0,dd.parse)(i);if(!s||typeof s!="object")throw new Error(`Invalid template file: ${n} \u2014 expected a YAML object`);let a=s.params||[],o=r.params||{};for(let u of a)if(!(u in o))throw new Error(`Template ${r.template} requires param "${u}" but it was not provided. Required params: [${a.join(", ")}]`);let l=s.statements;if(!Array.isArray(l))throw new Error(`Template ${r.template} must have a "statements" array`);if(Object.keys(o).length>0){let p=(0,dd.stringify)(l);for(let[m,f]of Object.entries(o))p=p.split(`<<${m}>>`).join(String(f));l=(0,dd.parse)(p)}let c={expandingPaths:new Set([...t.expandingPaths,n]),depth:t.depth+1,referencedPaths:t.referencedPaths};return xa(l,n,c)}function PB(r,e,t){if(typeof r!="object"||r===null)return r;let n={...r};return Array.isArray(n.statements)&&(n.statements=xa(n.statements,e,t)),Array.isArray(n.THEN)&&(n.THEN=xa(n.THEN,e,t)),Array.isArray(n.ELSE)&&(n.ELSE=xa(n.ELSE,e,t)),Array.isArray(n.DO)&&(n.DO=xa(n.DO,e,t)),n}function sw(r,e){let t=(0,pd.parse)(r),n=t?.name,i=t?.tags,s=t?.use;if(t&&(t.name!==void 0||t.tags!==void 0||t.use!==void 0)&&(delete t.name,delete t.tags,delete t.use),t?.suite){if(t.goal||t.statements)throw new Error('YAML file cannot have both "suite" and top-level "goal"/"statements". Use either suite format or single-test format.');return OB(t,n,i,s,e)}return NB(t,n,i,s,e)}function NB(r,e,t,n,i){let s=r?.beforeEach,a=r?.afterEach,o=Qk(r?.parameters),l=r?.timeout,c=r?.skip,u=r?.fail,p=r?.only,m=r?.slow;r&&(delete r.beforeEach,delete r.afterEach,delete r.parameters,delete r.timeout,delete r.skip,delete r.fail,delete r.only,delete r.slow),r&&!r.goal&&e&&(r.goal=e);let f=[];if(i&&r&&typeof r=="object"){let x=Zk(r,i);r=x.doc,f=x.referencedTemplatePaths}let y=(0,pd.stringify)(r);return{testFlow:Ri(y),name:e,tags:t,use:n,beforeEach:s,afterEach:a,parameters:o,timeout:l,skip:c,fail:u,only:p,slow:m,referencedTemplatePaths:f}}function OB(r,e,t,n,i){let s=r.suite;if(!Array.isArray(s.tests)||s.tests.length===0)throw new Error('Suite must have a non-empty "tests" array.');let a=s.beforeAll,o=s.afterAll,l=s.beforeEach,c=s.afterEach,u=[],p=s.tests.map(y=>{if(!y.name)throw new Error('Each test in a suite must have a "name" field.');if(!Array.isArray(y.statements)||y.statements.length===0)throw new Error(`Suite test "${y.name}" must have a non-empty "statements" array.`);let b={goal:y.name,statements:y.statements};y.teardown&&(b.teardown=y.teardown);let x=[],S=b;if(i&&typeof b=="object"){let I=Zk(b,i);S=I.doc,x=I.referencedTemplatePaths,u.push(...x)}let E=(0,pd.stringify)(S),M=Ri(E),j=Qk(y.parameters);return{testFlow:M,name:y.name,parameters:j,timeout:y.timeout,skip:y.skip,fail:y.fail,only:y.only,slow:y.slow}}),m=s.base_url,f=m?{...n,baseURL:m}:n;return{suite:{beforeAll:a,afterAll:o,beforeEach:l,afterEach:c,tests:p},name:e,tags:t,use:f,referencedTemplatePaths:u}}function Qk(r){if(!(!Array.isArray(r)||r.length===0))return r.map((e,t)=>{if(!e.name)throw new Error(`Parameter set at index ${t} must have a "name" field.`);if(!e.values||typeof e.values!="object")throw new Error(`Parameter set "${e.name}" must have a "values" object.`);return{name:e.name,values:e.values}})}function t2(r,e,t){let n=/\btemplate:\s/.test(r),i=/^suite:/m.test(r),s=n||i?null:tw(r);if(s&&!s.valid)return{valid:!1,errors:s.errors,warnings:[],stats:s.stats};let a,o,l=[];try{let c=sw(r,e);l=c.referencedTemplatePaths;let u={version:t?.version},p=c.testFlow?.baseURL?{...c.use,baseURL:c.testFlow.baseURL}:c.use;c.suite?a=kB(c.suite,{...u,testName:c.name,tags:c.tags,use:c.use}):a=AB(c.testFlow,{...u,testName:c.name,tags:c.tags,use:p,beforeEach:c.beforeEach,afterEach:c.afterEach,parameters:c.parameters,timeout:c.timeout,skip:c.skip,fail:c.fail,only:c.only,slow:c.slow});let m=a.split(`
4498
4498
  `).filter(f=>!f.startsWith("import ")).join(`
4499
- `);new Function(m),o=e.replace(/\.test\.yaml$/,".yaml.spec.ts"),(0,fd.mkdirSync)((0,e2.dirname)(o),{recursive:!0}),(0,fd.writeFileSync)(o,a)}catch(c){let u=c.message.includes("Unexpected token")?" This usually means a YAML escaping issue \u2014 in double-quoted strings, use \\\\/ instead of \\/ for regex patterns, or use single quotes / block scalars.":" This may indicate a transpiler bug \u2014 please report it.";return{valid:!1,errors:[`Transpilation failed: ${c.message}.${u}`],warnings:[],stats:s?.stats??{total:0,action:0,draft:0,coverage:0},referencedTemplatePaths:l}}return{valid:!0,errors:[],warnings:s?.warnings??[],stats:s?.stats??{total:0,action:0,draft:0,coverage:0},specFile:o,referencedTemplatePaths:l}}var aw="0.1.34";function r2(r){try{return(0,Sa.statSync)(r).mtimeMs}catch{return 0}}var RB=`// @generated by shiplightai v${aw}`;function MB(r,e){if(!(0,Sa.existsSync)(r)||(0,Sa.readFileSync)(r,"utf-8").split(`
4499
+ `);new Function(m),o=e.replace(/\.test\.yaml$/,".yaml.spec.ts"),(0,fd.mkdirSync)((0,e2.dirname)(o),{recursive:!0}),(0,fd.writeFileSync)(o,a)}catch(c){let u=c.message.includes("Unexpected token")?" This usually means a YAML escaping issue \u2014 in double-quoted strings, use \\\\/ instead of \\/ for regex patterns, or use single quotes / block scalars.":" This may indicate a transpiler bug \u2014 please report it.";return{valid:!1,errors:[`Transpilation failed: ${c.message}.${u}`],warnings:[],stats:s?.stats??{total:0,action:0,draft:0,coverage:0},referencedTemplatePaths:l}}return{valid:!0,errors:[],warnings:s?.warnings??[],stats:s?.stats??{total:0,action:0,draft:0,coverage:0},specFile:o,referencedTemplatePaths:l}}var aw="0.1.35";function r2(r){try{return(0,Sa.statSync)(r).mtimeMs}catch{return 0}}var RB=`// @generated by shiplightai v${aw}`;function MB(r,e){if(!(0,Sa.existsSync)(r)||(0,Sa.readFileSync)(r,"utf-8").split(`
4500
4500
  `,1)[0]!==RB)return!1;let n=r2(r);for(let i of e)if(r2(i)>n)return!1;return!0}function DB(r){let e=process.argv.slice(2),t=[],n=(0,Zf.resolve)(r);for(let i of e){if(i.startsWith("-"))continue;let s=i.endsWith(".yaml.spec.ts")?i.replace(/\.yaml\.spec\.ts$/,".test.yaml"):i;if(!s.endsWith(".test.yaml"))continue;let a=(0,Zf.resolve)(r,s);(0,Sa.existsSync)(a)&&t.push(a.startsWith(n)?a.slice(n.length+1):s)}return t.length>0?t:null}function i2(r){let e=DB(r.cwd),t=e??(0,n2.globSync)("**/*.test.yaml",{cwd:r.cwd,ignore:["**/node_modules/**"]}),n=[];for(let i of t){let s=(0,Zf.resolve)(r.cwd,i),a=s.replace(/\.test\.yaml$/,".yaml.spec.ts"),o=(0,Sa.readFileSync)(s,"utf-8");try{let l=sw(o,s);if(MB(a,[s,...l.referencedTemplatePaths]))continue;let c=t2(o,s,{version:aw});if(!c.valid)throw new Error(c.errors.join("; "))}catch(l){console.error(`[shiplight] Failed to transpile ${i}:`,l),n.push({file:i,error:l})}}if(n.length>0){let i=`[shiplight] Transpilation failed for ${n.length} file(s):
4501
4501
  `+n.map(s=>` - ${s.file}`).join(`
4502
4502
  `);if(e)throw new Error(i);console.warn(i+" (skipped)")}}function o2(r={}){r.dotenv!==!1&&LB(r.scanDir||process.cwd());let e=r.scanDir||process.cwd();return i2({cwd:e}),r.apiKey&&(process.env.__SHIPLIGHT_API_KEY=r.apiKey),{reporter:[["list"],["shiplightai/reporter",{outputFolder:"shiplight-report",open:"never"}]]}}function LB(r){let e=[],t=Eo.resolve(r),n=Eo.resolve(process.cwd());for(;;){let i=Eo.join(t,".env");if(s2.existsSync(i)&&e.push(i),t===n)break;let s=Eo.dirname(t);if(s===t)break;t=s}for(let i of e)a2.default.config({path:i})}ir();ir();eh();Cc();var gE=require("zod"),Pne=gE.z.object({instruction:gE.z.string().describe('The instruction of the operation to perform. Can only include one operation. Do not inlcude element indexes just describe the element, e.g. "select the text "Hello, world!" in "Hello, world!""')});function F5(r){r.register({name:"perform_accurate_operation",description:"Perform an operation that requires accurate interaction like dragging or interacting with a specific area of an element. Only use this action when neccecary.",schema:Pne,usesElementIndex:!1,async execute(e,t){let{instruction:n}=e,i={page:t.page,agentServices:t.agentServices,domService:t.domService},s=await kc(n,i,{});if(s.status==="error"||!s.actionEntity)return{success:!1,actionEntity:{action_description:n,action_data:{action_name:"perform_accurate_operation",kwargs:{instruction:n}}},error:s.error||"Failed to generate action"};let{actionEntity:a}=s,o=await Zp(a,i);return{success:o.success,actionEntity:a,message:o.success?`Successfully executed action: ${a.action_data?.action_name}`:void 0,error:o.error}}})}no();ir();Wp();var At;(function(r){r.Root="root",r.Text="text",r.Directive="directive",r.Comment="comment",r.Script="script",r.Style="style",r.Tag="tag",r.CDATA="cdata",r.Doctype="doctype"})(At||(At={}));function j5(r){return r.type===At.Tag||r.type===At.Script||r.type===At.Style}var B5=At.Root,U5=At.Text,q5=At.Directive,H5=At.Comment,W5=At.Script,z5=At.Style,G5=At.Tag,V5=At.CDATA,K5=At.Doctype;var jy=class{constructor(){this.parent=null,this.prev=null,this.next=null,this.startIndex=null,this.endIndex=null}get parentNode(){return this.parent}set parentNode(e){this.parent=e}get previousSibling(){return this.prev}set previousSibling(e){this.prev=e}get nextSibling(){return this.next}set nextSibling(e){this.next=e}cloneNode(e=!1){return X5(this,e)}},Wh=class extends jy{constructor(e){super(),this.data=e}get nodeValue(){return this.data}set nodeValue(e){this.data=e}},Bu=class extends Wh{constructor(){super(...arguments),this.type=At.Text}get nodeType(){return 3}},zh=class extends Wh{constructor(){super(...arguments),this.type=At.Comment}get nodeType(){return 8}},Gh=class extends Wh{constructor(e,t){super(t),this.name=e,this.type=At.Directive}get nodeType(){return 1}},Vh=class extends jy{constructor(e){super(),this.children=e}get firstChild(){var e;return(e=this.children[0])!==null&&e!==void 0?e:null}get lastChild(){return this.children.length>0?this.children[this.children.length-1]:null}get childNodes(){return this.children}set childNodes(e){this.children=e}},Kh=class extends Vh{constructor(){super(...arguments),this.type=At.CDATA}get nodeType(){return 4}},Uu=class extends Vh{constructor(){super(...arguments),this.type=At.Root}get nodeType(){return 9}},Jh=class extends Vh{constructor(e,t,n=[],i=e==="script"?At.Script:e==="style"?At.Style:At.Tag){super(n),this.name=e,this.attribs=t,this.type=i}get nodeType(){return 1}get tagName(){return this.name}set tagName(e){this.name=e}get attributes(){return Object.keys(this.attribs).map(e=>{var t,n;return{name:e,value:this.attribs[e],namespace:(t=this["x-attribsNamespace"])===null||t===void 0?void 0:t[e],prefix:(n=this["x-attribsPrefix"])===null||n===void 0?void 0:n[e]}})}};function ca(r){return j5(r)}function bE(r){return r.type===At.CDATA}function By(r){return r.type===At.Text}function wE(r){return r.type===At.Comment}function Nne(r){return r.type===At.Directive}function Y5(r){return r.type===At.Root}function X5(r,e=!1){let t;if(By(r))t=new Bu(r.data);else if(wE(r))t=new zh(r.data);else if(ca(r)){let n=e?yE(r.children):[],i=new Jh(r.name,{...r.attribs},n);n.forEach(s=>s.parent=i),r.namespace!=null&&(i.namespace=r.namespace),r["x-attribsNamespace"]&&(i["x-attribsNamespace"]={...r["x-attribsNamespace"]}),r["x-attribsPrefix"]&&(i["x-attribsPrefix"]={...r["x-attribsPrefix"]}),t=i}else if(bE(r)){let n=e?yE(r.children):[],i=new Kh(n);n.forEach(s=>s.parent=i),t=i}else if(Y5(r)){let n=e?yE(r.children):[],i=new Uu(n);n.forEach(s=>s.parent=i),r["x-mode"]&&(i["x-mode"]=r["x-mode"]),t=i}else if(Nne(r)){let n=new Gh(r.name,r.data);r["x-name"]!=null&&(n["x-name"]=r["x-name"],n["x-publicId"]=r["x-publicId"],n["x-systemId"]=r["x-systemId"]),t=n}else throw new Error(`Not implemented yet: ${r.type}`);return t.startIndex=r.startIndex,t.endIndex=r.endIndex,r.sourceCodeLocation!=null&&(t.sourceCodeLocation=r.sourceCodeLocation),t}function yE(r){let e=r.map(t=>X5(t,!0));for(let t=1;t<e.length;t++)e[t].prev=e[t-1],e[t-1].next=e[t];return e}var Z5={withStartIndices:!1,withEndIndices:!1,xmlMode:!1},qu=class{constructor(e,t,n){this.dom=[],this.root=new Uu(this.dom),this.done=!1,this.tagStack=[this.root],this.lastNode=null,this.parser=null,typeof t=="function"&&(n=t,t=Z5),typeof e=="object"&&(t=e,e=void 0),this.callback=e??null,this.options=t??Z5,this.elementCB=n??null}onparserinit(e){this.parser=e}onreset(){this.dom=[],this.root=new Uu(this.dom),this.done=!1,this.tagStack=[this.root],this.lastNode=null,this.parser=null}onend(){this.done||(this.done=!0,this.parser=null,this.handleCallback(null))}onerror(e){this.handleCallback(e)}onclosetag(){this.lastNode=null;let e=this.tagStack.pop();this.options.withEndIndices&&(e.endIndex=this.parser.endIndex),this.elementCB&&this.elementCB(e)}onopentag(e,t){let n=this.options.xmlMode?At.Tag:void 0,i=new Jh(e,t,void 0,n);this.addNode(i),this.tagStack.push(i)}ontext(e){let{lastNode:t}=this;if(t&&t.type===At.Text)t.data+=e,this.options.withEndIndices&&(t.endIndex=this.parser.endIndex);else{let n=new Bu(e);this.addNode(n),this.lastNode=n}}oncomment(e){if(this.lastNode&&this.lastNode.type===At.Comment){this.lastNode.data+=e;return}let t=new zh(e);this.addNode(t),this.lastNode=t}oncommentend(){this.lastNode=null}oncdatastart(){let e=new Bu(""),t=new Kh([e]);this.addNode(t),e.parent=t,this.lastNode=e}oncdataend(){this.lastNode=null}onprocessinginstruction(e,t){let n=new Gh(e,t);this.addNode(n)}handleCallback(e){if(typeof this.callback=="function")this.callback(e,this.dom);else if(e)throw e}addNode(e){let t=this.tagStack[this.tagStack.length-1],n=t.children[t.children.length-1];this.options.withStartIndices&&(e.startIndex=this.parser.startIndex),this.options.withEndIndices&&(e.endIndex=this.parser.endIndex),t.children.push(e),n&&(e.prev=n,n.next=e),e.parent=t,this.lastNode=null}};var One=/\n/g;function Rne(r){let e=[...r.matchAll(One)].map(n=>n.index||0);e.unshift(-1);let t=_E(e,0,e.length);return n=>e$(t,n)}function _E(r,e,t){if(t-e==1)return{offset:r[e],index:e+1};let n=Math.ceil((e+t)/2),i=_E(r,e,n),s=_E(r,n,t);return{offset:i.offset,low:i,high:s}}function e$(r,e){return function(t){return Object.prototype.hasOwnProperty.call(t,"index")}(r)?{line:r.index,column:e-r.offset}:e$(r.high.offset<e?r.high:r.low,e)}function vE(r,e="",t={}){let n=typeof e!="string"?e:t,i=typeof e=="string"?e:"",s=r.map(Mne),a=!!n.lineNumbers;return function(o,l=0){let c=a?Rne(o):()=>({line:0,column:0}),u=l,p=[];e:for(;u<o.length;){let m=!1;for(let f of s){f.regex.lastIndex=u;let y=f.regex.exec(o);if(y&&y[0].length>0){if(!f.discard){let b=c(u),x=typeof f.replace=="string"?y[0].replace(new RegExp(f.regex.source,f.regex.flags),f.replace):y[0];p.push({state:i,name:f.name,text:x,offset:u,len:y[0].length,line:b.line,column:b.column})}if(u=f.regex.lastIndex,m=!0,f.push){let b=f.push(o,u);p.push(...b.tokens),u=b.offset}if(f.pop)break e;break}}if(!m)break}return{tokens:p,offset:u,complete:o.length<=u}}}function Mne(r,e){return{...r,regex:Dne(r,e)}}function Dne(r,e){if(r.name.length===0)throw new Error(`Rule #${e} has empty name, which is not allowed.`);if(function(t){return Object.prototype.hasOwnProperty.call(t,"regex")}(r))return function(t){if(t.global)throw new Error(`Regular expression /${t.source}/${t.flags} contains the global flag, which is not allowed.`);return t.sticky?t:new RegExp(t.source,t.flags+"y")}(r.regex);if(function(t){return Object.prototype.hasOwnProperty.call(t,"str")}(r)){if(r.str.length===0)throw new Error(`Rule #${e} ("${r.name}") has empty "str" property, which is not allowed.`);return new RegExp(Q5(r.str),"y")}return new RegExp(Q5(r.name),"y")}function Q5(r){return r.replace(/[-[\]{}()*+!<=:?./\\^$|#\s,]/g,"\\$&")}function _s(r,e){return(t,n)=>{let i=n,s;return n<t.tokens.length?(s=r(t.tokens[n],t,n),s!==void 0&&i++):e?.(t,n),s===void 0?{matched:!1}:{matched:!0,position:i,value:s}}}function xE(r,e){return r.matched?{matched:!0,position:r.position,value:e(r.value,r.position)}:r}function Uy(r,e){return r.matched?e(r):r}function Dr(r,e){return(t,n)=>xE(r(t,n),(i,s)=>e(i,t,n,s))}function Yh(r,e){return(t,n)=>{let i=r(t,n);return i.matched?i:{matched:!0,position:n,value:e}}}function Hu(...r){return(e,t)=>{for(let n of r){let i=n(e,t);if(i.matched)return i}return{matched:!1}}}function ho(r,e){return(t,n)=>{let i=r(t,n);return i.matched?i:e(t,n)}}function Lne(r,e){return(t,n)=>{let i=[],s=!0;do{let a=r(t,n);a.matched&&e(a.value,i.length+1,t,n,a.position)?(i.push(a.value),n=a.position):s=!1}while(s);return{matched:!0,position:n,value:i}}}function qy(r){return Lne(r,()=>!0)}function t$(r){return Ur(r,qy(r),(e,t)=>[e,...t])}function Ur(r,e,t){return(n,i)=>Uy(r(n,i),s=>xE(e(n,s.position),(a,o)=>t(s.value,a,n,i,o)))}function r$(r,e){return Ur(r,e,t=>t)}function SE(r,e){return Ur(r,e,(t,n)=>n)}function Hy(r,e,t,n){return(i,s)=>Uy(r(i,s),a=>Uy(e(i,a.position),o=>xE(t(i,o.position),(l,c)=>n(a.value,o.value,l,i,s,c))))}function TE(r,e,t){return Hy(r,e,t,(n,i)=>i)}function $ne(...r){return(e,t)=>{let n=[],i=t;for(let s of r){let a=s(e,i);if(a.matched)n.push(a.value),i=a.position;else return{matched:!1}}return{matched:!0,position:i,value:n}}}function n$(...r){return Fne($ne(...r))}function Fne(r){return Dr(r,e=>e.flatMap(t=>t))}function jne(r,e){return(t,n)=>{let i=!0,s=r,a=n;do{let o=e(s,t,a)(t,a);o.matched?(s=o.value,a=o.position):i=!1}while(i);return{matched:!0,position:a,value:s}}}function Bne(r,e,t){return jne(r,n=>Dr(e,(i,s,a,o)=>t(n,i,s,a,o)))}function EE(r,e,t){return Une(r,n=>Bne(n,Ur(e,t,(i,s)=>[i,s]),(i,[s,a])=>s(i,a)))}function Une(r,e){return(t,n)=>Uy(r(t,n),i=>e(i.value,t,n,i.position)(t,i.position))}var Hne="(?:[ \\t\\r\\n\\f]*)",c$="(?:\\n|\\r\\n|\\r|\\f)",Gy="[^\\x00-\\x7F]",Qh="(?:\\\\[0-9a-f]{1,6}(?:\\r\\n|[ \\n\\r\\t\\f])?)",ef="(?:\\\\[^\\n\\r\\f0-9a-f])",Wne=`(?:[_a-z]|${Gy}|${Qh}|${ef})`,u$=`(?:[_a-z0-9-]|${Gy}|${Qh}|${ef})`,zne=`(?:${u$}+)`,Gne=`(?:[-]?${Wne}${u$}*)`,Vne=`'([^\\n\\r\\f\\\\']|\\\\${c$}|${Gy}|${Qh}|${ef})*'`,Kne=`"([^\\n\\r\\f\\\\"]|\\\\${c$}|${Gy}|${Qh}|${ef})*"`,Jne=vE([{name:"ws",regex:new RegExp(Hne)},{name:"hash",regex:new RegExp(`#${zne}`,"i")},{name:"ident",regex:new RegExp(Gne,"i")},{name:"str1",regex:new RegExp(Vne,"i")},{name:"str2",regex:new RegExp(Kne,"i")},{name:"*"},{name:"."},{name:","},{name:"["},{name:"]"},{name:"="},{name:">"},{name:"|"},{name:"+"},{name:"~"},{name:"^"},{name:"$"}]),Yne=vE([{name:"unicode",regex:new RegExp(Qh,"i")},{name:"escape",regex:new RegExp(ef,"i")},{name:"any",regex:new RegExp("[\\s\\S]","i")}]);function d$([r,e,t],[n,i,s]){return[r+n,e+i,t+s]}function Xne(r){return r.reduce(d$,[0,0,0])}var Zne=_s(r=>r.name==="unicode"?String.fromCodePoint(parseInt(r.text.slice(1),16)):void 0),Qne=_s(r=>r.name==="escape"?r.text.slice(1):void 0),eie=_s(r=>r.name==="any"?r.text:void 0),tie=Dr(qy(Hu(Zne,Qne,eie)),r=>r.join(""));function CE(r){let e=Yne(r);return tie({tokens:e.tokens,options:void 0},0).value}function tr(r){return _s(e=>e.name===r?!0:void 0)}var IE=_s(r=>r.name==="ws"?null:void 0),AE=Yh(IE,null);function zu(r){return TE(AE,r,AE)}var Zh=_s(r=>r.name==="ident"?CE(r.text):void 0),rie=_s(r=>r.name==="hash"?CE(r.text.slice(1)):void 0),nie=_s(r=>r.name.startsWith("str")?CE(r.text.slice(1,-1)):void 0),p$=r$(Yh(Zh,""),tr("|")),PE=ho(Ur(p$,Zh,(r,e)=>({name:e,namespace:r})),Dr(Zh,r=>({name:r,namespace:null}))),iie=ho(Ur(p$,tr("*"),r=>({type:"universal",namespace:r,specificity:[0,0,0]})),Dr(tr("*"),()=>({type:"universal",namespace:null,specificity:[0,0,0]}))),sie=Dr(PE,({name:r,namespace:e})=>({type:"tag",name:r,namespace:e,specificity:[0,0,1]})),aie=Ur(tr("."),Zh,(r,e)=>({type:"class",name:e,specificity:[0,1,0]})),oie=Dr(rie,r=>({type:"id",name:r,specificity:[1,0,0]})),i$=_s(r=>{if(r.name==="ident"){if(r.text==="i"||r.text==="I")return"i";if(r.text==="s"||r.text==="S")return"s"}}),lie=ho(Ur(nie,Yh(SE(AE,i$),null),(r,e)=>({value:r,modifier:e})),Ur(Zh,Yh(SE(IE,i$),null),(r,e)=>({value:r,modifier:e}))),cie=Hu(Dr(tr("="),()=>"="),Ur(tr("~"),tr("="),()=>"~="),Ur(tr("|"),tr("="),()=>"|="),Ur(tr("^"),tr("="),()=>"^="),Ur(tr("$"),tr("="),()=>"$="),Ur(tr("*"),tr("="),()=>"*=")),uie=Hy(tr("["),zu(PE),tr("]"),(r,{name:e,namespace:t})=>({type:"attrPresence",name:e,namespace:t,specificity:[0,1,0]})),die=TE(tr("["),Hy(zu(PE),cie,zu(lie),({name:r,namespace:e},t,{value:n,modifier:i})=>({type:"attrValue",name:r,namespace:e,matcher:t,value:n,modifier:i,specificity:[0,1,0]})),tr("]")),pie=ho(uie,die),hie=ho(iie,sie),s$=Hu(oie,aie,pie),a$=Dr(ho(n$(hie,qy(s$)),t$(s$)),r=>({type:"compound",list:r,specificity:Xne(r.map(e=>e.specificity))})),fie=Hu(Dr(tr(">"),()=>">"),Dr(tr("+"),()=>"+"),Dr(tr("~"),()=>"~"),Ur(tr("|"),tr("|"),()=>"||")),mie=ho(zu(fie),Dr(IE,()=>" ")),kE=EE(a$,Dr(mie,r=>(e,t)=>({type:"compound",list:[...t.list,{type:"combinator",combinator:r,left:e,specificity:e.specificity}],specificity:d$(e.specificity,t.specificity)})),a$),WIe=EE(Dr(kE,r=>({type:"list",list:[r]})),Dr(zu(tr(",")),()=>(r,e)=>({type:"list",list:[...r.list,e]})),kE);function gie(r,e){if(!(typeof e=="string"||e instanceof String))throw new Error("Expected a selector string. Actual input is not a string!");let t=Jne(e);if(!t.complete)throw new Error(`The input "${e}" was only partially tokenized, stopped at offset ${t.offset}!
package/dist/cli.js CHANGED
@@ -805,9 +805,9 @@ Merged ${l.length} tests from ${u} shards into: ${y}`),r&&Ii(l),t)try{let g=(awa
805
805
  `;for(let n of i){let{name:l}=qt(n);a+=`- <sub>${l}</sub>
806
806
  `}a+=`
807
807
  </details>
808
- `}x.appendFileSync(t,a),console.log("GitHub step summary written.")}var er=v(()=>{"use strict";Yt()});var tr,rr=v(()=>{"use strict";tr="0.1.34"});var ir={};U(ir,{runTranspile:()=>Li});import*as le from"path";import{glob as Oi}from"glob";async function Li(e){(e.includes("--help")||e.includes("-h"))&&(console.log("Usage: shiplight transpile [glob]"),console.log(""),console.log("Transpiles YAML test files to Playwright spec files (.yaml.spec.ts)."),console.log("Validates syntax and reports action coverage warnings."),console.log("Default glob: **/*.test.yaml"),console.log(""),console.log("Examples:"),console.log(" shiplight transpile # transpile all YAML tests"),console.log(' shiplight transpile "tests/**/*.test.yaml" # transpile specific directory'),console.log(" shiplight transpile tests/login.test.yaml # transpile a single file"),process.exit(0));let t=e[0]||"**/*.test.yaml",r=process.cwd(),i=await Oi(t,{cwd:r,ignore:["node_modules/**","*.yaml.spec.ts"]});i.length===0&&(console.log(`No files matched: ${t}`),process.exit(0));let o=0,s=0,a=0;for(let n of i.sort()){let l=le.resolve(r,n),c=Ot(l,{version:tr});if(!c.valid){o++,console.log(`
808
+ `}x.appendFileSync(t,a),console.log("GitHub step summary written.")}var er=v(()=>{"use strict";Yt()});var tr,rr=v(()=>{"use strict";tr="0.1.35"});var ir={};U(ir,{runTranspile:()=>Li});import*as le from"path";import{glob as Oi}from"glob";async function Li(e){(e.includes("--help")||e.includes("-h"))&&(console.log("Usage: shiplight transpile [glob]"),console.log(""),console.log("Transpiles YAML test files to Playwright spec files (.yaml.spec.ts)."),console.log("Validates syntax and reports action coverage warnings."),console.log("Default glob: **/*.test.yaml"),console.log(""),console.log("Examples:"),console.log(" shiplight transpile # transpile all YAML tests"),console.log(' shiplight transpile "tests/**/*.test.yaml" # transpile specific directory'),console.log(" shiplight transpile tests/login.test.yaml # transpile a single file"),process.exit(0));let t=e[0]||"**/*.test.yaml",r=process.cwd(),i=await Oi(t,{cwd:r,ignore:["node_modules/**","*.yaml.spec.ts"]});i.length===0&&(console.log(`No files matched: ${t}`),process.exit(0));let o=0,s=0,a=0;for(let n of i.sort()){let l=le.resolve(r,n),c=Ot(l,{version:tr});if(!c.valid){o++,console.log(`
809
809
  \u2717 ${n}`);for(let d of c.errors)console.log(` ERROR: ${d}`);continue}a++;let u=le.basename(c.specFile);if(c.warnings.length>0){s++,console.log(`\u26A0 ${n} \u2192 ${u}`);for(let d of c.warnings)console.log(` WARNING: ${d}`)}else console.log(`\u2713 ${n} \u2192 ${u}`)}console.log(`
810
- ${i.length} file(s): ${a} transpiled, ${o} error(s), ${s} warning(s)`),process.exit(o>0?1:0)}var or=v(()=>{"use strict";ke();rr()});var ar={};U(ar,{runInspect:()=>Ci});import*as ce from"fs";import*as sr from"path";async function Ci(e){(e.includes("--help")||e.includes("-h")||e.length===0)&&(console.log("Usage: shiplight inspect <file.test.yaml> [options]"),console.log(""),console.log("Parse a YAML test file and output the resulting TestFlow JSON."),console.log("Useful for verifying YAML \u2192 JSON conversion."),console.log(""),console.log("Options:"),console.log(" --pretty Pretty-print JSON (default)"),console.log(" --compact Compact JSON output"),console.log(" --stats Show statement statistics only"),console.log(""),console.log("Examples:"),console.log(" shiplight inspect tests/login.test.yaml"),console.log(" shiplight inspect tests/suite.test.yaml --stats"),console.log(" shiplight inspect tests/login.test.yaml --compact | jq ."),process.exit(e.length===0?1:0));let t=e.includes("--compact"),r=e.includes("--stats"),i=e.find(a=>!a.startsWith("--"));i||(console.error("Error: no file specified"),process.exit(1));let o=sr.resolve(process.cwd(),i);ce.existsSync(o)||(console.error(`Error: file not found: ${o}`),process.exit(1));let s=ce.readFileSync(o,"utf-8");try{let a=Z(s),n=M(s);if(r)Di(n,a);else{let l={...a.test_case_id!==void 0?{test_case_id:a.test_case_id}:{},...a.name?{name:a.name}:{},testFlow:n};console.log(JSON.stringify(l,null,t?0:2))}}catch(a){console.error(`Error parsing ${i}: ${a.message}`),process.exit(1)}}function Di(e,t){if(console.log(`File: ${t.name||"(unnamed)"}`),t.test_case_id!==void 0&&console.log(`Cloud ID: ${t.test_case_id}`),console.log(`Version: ${e.version||"unknown"}`),e.testGroup){let r=e.testGroup;console.log("Type: suite (testGroup)"),console.log(`Tests: ${r.tests.length}`);for(let i of r.tests){let o=i.skip?` [SKIP${typeof i.skip=="string"?`: ${i.skip}`:""}]`:"";console.log(` - ${i.name}: ${i.statements.length} statements${i.teardown?`, ${i.teardown.length} teardown`:""}${o}`)}r.beforeAll?.length&&console.log(`Hooks: beforeAll (${r.beforeAll.length})`),r.afterAll?.length&&console.log(`Hooks: afterAll (${r.afterAll.length})`),r.beforeEach?.length&&console.log(`Hooks: beforeEach (${r.beforeEach.length})`),r.afterEach?.length&&console.log(`Hooks: afterEach (${r.afterEach.length})`)}else{console.log("Type: single test"),console.log(`Goal: ${e.goal}`),e.url&&console.log(`URL: ${e.url}`),e.baseURL&&console.log(`Base URL: ${e.baseURL}`),console.log(`Statements: ${e.statements?.length??0}`),e.teardown?.length&&console.log(`Teardown: ${e.teardown.length}`);let r=nr(e.statements??[]);console.log(` DRAFT: ${r.drafts}, ACTION: ${r.actions}, STEP: ${r.steps}`)}}function nr(e){let t={drafts:0,actions:0,steps:0};for(let r of e)if(r.type==="DRAFT")t.drafts++;else if(r.type==="ACTION")t.actions++;else if(r.type==="STEP"){t.steps++;let i=nr(r.statements??[]);t.drafts+=i.drafts,t.actions+=i.actions,t.steps+=i.steps}return t}var lr=v(()=>{"use strict";V()});var cr=dr((Un,Ni)=>{Ni.exports={name:"shiplightai",version:"0.1.34",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"},"./reporter":{types:"./dist/reporter.d.ts",import:"./dist/reporter.js",require:"./dist/cjs/reporter.cjs",default:"./dist/reporter.js"}},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org",access:"public"},scripts:{build:"tsup && cd ../frontend && npx vite build --config vite.debugger.config.ts",pack:"pnpm build && pnpm pack",clean:"rm -rf dist",dev:"tsup --watch",test:"playwright test","test:unit":"tsx --test 'src/**/*.test.ts'",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.58.2","@types/express":"^4.17.21","@types/node":"^24.0.0",copilot3:"workspace:*","mcp-tools":"workspace:*","sdk-core":"workspace:*","sdk-internal":"workspace:*","shiplight-tools":"workspace:*","shiplight-types":"workspace:*",tsup:"^8.3.5",typescript:"5.5.4","web-session":"workspace:*"},peerDependencies:{"@playwright/test":"1.58.2"},engines:{node:">=22.0.0"},keywords:["playwright","yaml","testing","automation","ai","shiplight","mcp"],author:"Shiplight",license:"MIT"}});import Fi from"dotenv";Fi.config();function ur(){console.log(`
810
+ ${i.length} file(s): ${a} transpiled, ${o} error(s), ${s} warning(s)`),process.exit(o>0?1:0)}var or=v(()=>{"use strict";ke();rr()});var ar={};U(ar,{runInspect:()=>Ci});import*as ce from"fs";import*as sr from"path";async function Ci(e){(e.includes("--help")||e.includes("-h")||e.length===0)&&(console.log("Usage: shiplight inspect <file.test.yaml> [options]"),console.log(""),console.log("Parse a YAML test file and output the resulting TestFlow JSON."),console.log("Useful for verifying YAML \u2192 JSON conversion."),console.log(""),console.log("Options:"),console.log(" --pretty Pretty-print JSON (default)"),console.log(" --compact Compact JSON output"),console.log(" --stats Show statement statistics only"),console.log(""),console.log("Examples:"),console.log(" shiplight inspect tests/login.test.yaml"),console.log(" shiplight inspect tests/suite.test.yaml --stats"),console.log(" shiplight inspect tests/login.test.yaml --compact | jq ."),process.exit(e.length===0?1:0));let t=e.includes("--compact"),r=e.includes("--stats"),i=e.find(a=>!a.startsWith("--"));i||(console.error("Error: no file specified"),process.exit(1));let o=sr.resolve(process.cwd(),i);ce.existsSync(o)||(console.error(`Error: file not found: ${o}`),process.exit(1));let s=ce.readFileSync(o,"utf-8");try{let a=Z(s),n=M(s);if(r)Di(n,a);else{let l={...a.test_case_id!==void 0?{test_case_id:a.test_case_id}:{},...a.name?{name:a.name}:{},testFlow:n};console.log(JSON.stringify(l,null,t?0:2))}}catch(a){console.error(`Error parsing ${i}: ${a.message}`),process.exit(1)}}function Di(e,t){if(console.log(`File: ${t.name||"(unnamed)"}`),t.test_case_id!==void 0&&console.log(`Cloud ID: ${t.test_case_id}`),console.log(`Version: ${e.version||"unknown"}`),e.testGroup){let r=e.testGroup;console.log("Type: suite (testGroup)"),console.log(`Tests: ${r.tests.length}`);for(let i of r.tests){let o=i.skip?` [SKIP${typeof i.skip=="string"?`: ${i.skip}`:""}]`:"";console.log(` - ${i.name}: ${i.statements.length} statements${i.teardown?`, ${i.teardown.length} teardown`:""}${o}`)}r.beforeAll?.length&&console.log(`Hooks: beforeAll (${r.beforeAll.length})`),r.afterAll?.length&&console.log(`Hooks: afterAll (${r.afterAll.length})`),r.beforeEach?.length&&console.log(`Hooks: beforeEach (${r.beforeEach.length})`),r.afterEach?.length&&console.log(`Hooks: afterEach (${r.afterEach.length})`)}else{console.log("Type: single test"),console.log(`Goal: ${e.goal}`),e.url&&console.log(`URL: ${e.url}`),e.baseURL&&console.log(`Base URL: ${e.baseURL}`),console.log(`Statements: ${e.statements?.length??0}`),e.teardown?.length&&console.log(`Teardown: ${e.teardown.length}`);let r=nr(e.statements??[]);console.log(` DRAFT: ${r.drafts}, ACTION: ${r.actions}, STEP: ${r.steps}`)}}function nr(e){let t={drafts:0,actions:0,steps:0};for(let r of e)if(r.type==="DRAFT")t.drafts++;else if(r.type==="ACTION")t.actions++;else if(r.type==="STEP"){t.steps++;let i=nr(r.statements??[]);t.drafts+=i.drafts,t.actions+=i.actions,t.steps+=i.steps}return t}var lr=v(()=>{"use strict";V()});var cr=dr((Un,Ni)=>{Ni.exports={name:"shiplightai",version:"0.1.35",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"},"./reporter":{types:"./dist/reporter.d.ts",import:"./dist/reporter.js",require:"./dist/cjs/reporter.cjs",default:"./dist/reporter.js"}},files:["dist","README.md"],publishConfig:{registry:"https://registry.npmjs.org",access:"public"},scripts:{build:"tsup && cd ../frontend && npx vite build --config vite.debugger.config.ts",pack:"pnpm build && pnpm pack",clean:"rm -rf dist",dev:"tsup --watch",test:"playwright test","test:unit":"tsx --test 'src/**/*.test.ts'",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.58.2","@types/express":"^4.17.21","@types/node":"^24.0.0",copilot3:"workspace:*","mcp-tools":"workspace:*","sdk-core":"workspace:*","sdk-internal":"workspace:*","shiplight-tools":"workspace:*","shiplight-types":"workspace:*",tsup:"^8.3.5",typescript:"5.5.4","web-session":"workspace:*"},peerDependencies:{"@playwright/test":"1.58.2"},engines:{node:">=22.0.0"},keywords:["playwright","yaml","testing","automation","ai","shiplight","mcp"],author:"Shiplight",license:"MIT"}});import Fi from"dotenv";Fi.config();function ur(){console.log(`
811
811
  Usage: shiplight <command> [options]
812
812
 
813
813
  Commands:
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 d from"path";import*as F from"fs";import{test as G,expect as I,chromium as Y}from"@playwright/test";import*as a from"fs";import*as h from"path";import{randomUUID as _}from"crypto";import{tmpdir as P}from"os";function D(t){return[`--disable-extensions-except=${t}`,`--load-extension=${t}`,"--no-first-run","--disable-default-apps"]}function T(t){if(!a.existsSync(t))return console.warn(`[fixture] extensionStorageState file not found: ${t}`),null;let o;try{o=JSON.parse(a.readFileSync(t,"utf-8"))}catch(s){throw new Error(`[fixture] Failed to parse extensionStorageState at ${t}: ${s}`)}let n=o;if(!Array.isArray(n.cookies))return null;let e=(Date.now()+365*24*60*60*1e3)/1e3,r=n.cookies.filter(s=>s&&typeof s=="object"&&typeof s.name=="string"&&typeof s.domain=="string");return r.length<n.cookies.length&&console.warn(`[fixture] Skipped ${n.cookies.length-r.length} malformed cookies (missing name or domain)`),r.map(s=>({...s,expires:e}))}function O(t){if(t){let n=h.resolve(process.cwd(),t),e=h.join(P(),`ext-profile-${_()}`);if(a.existsSync(n)){try{a.cpSync(n,e,{recursive:!0})}catch(s){try{a.rmSync(e,{recursive:!0,force:!0})}catch(i){console.warn("[fixture] Failed to clean up partial profile copy:",e,i)}throw new Error(`[fixture] Failed to copy extension profile from ${n}: ${s}`)}let r=h.join(e,"SingletonLock");a.existsSync(r)&&a.rmSync(r,{force:!0})}else a.mkdirSync(e,{recursive:!0});return e}let o=h.join(P(),`ext-profile-${_()}`);return a.mkdirSync(o,{recursive:!0}),o}async function H(t){let n=await import(d.resolve(process.cwd(),t.auth)),e=n.login||n.default;if(typeof e!="function")throw new Error(`auth module "${t.auth}" must export a login(args) function that returns a storageState file path`);let r=await e(t.args||{});if(typeof r!="string")throw new Error(`auth module "${t.auth}" login() must return a storageState file path (got ${typeof r})`);return r}function j(t){return!(!t||t==="off")}function L(t,o){return!t||t==="off"?!1:t==="on"?!0:t==="retain-on-failure"?o.status!==o.expectedStatus:t==="on-first-retry"?o.retry>0:typeof t=="object"&&t!==null&&"mode"in t?L(t.mode,o):!0}async function R(t,o,n){let e=L(o,n);for(let r of t.pages()){let s=r.video();if(!s)continue;let i=await s.path()?.catch(()=>null);i&&(e?await n.attach("video",{path:i,contentType:"video/webm"}):await s.delete().catch(()=>{}))}}var S;async function $(){return S||(S=await import("./dist-ZGT6WF2R.js"),S)}var M=new Set(["get","set","getAll","has","__variableStore"]);function N(t){let o={__variableStore:t,get(n){return t.get(n)},set(n,e,r=!1){t.set(n,e,r)},getAll(){return t.getAll()}};return new Proxy(o,{get(n,e,r){if(e in n)return Reflect.get(n,e,r);if(typeof e=="string")return n.get(e)},set(n,e,r){return typeof e!="string"||M.has(e)?Reflect.set(n,e,r):(n.set(e,r),!0)},has(n,e){return e in n?!0:typeof e=="string"?t.has?.(e)??!1:!1}})}var J=G.extend({account:[void 0,{option:!0}],autoDismissModal:[!1,{option:!0}],extensionDir:[void 0,{option:!0}],userDataDir:[void 0,{option:!0}],extensionStorageState:[void 0,{option:!0}],context:async({browser:t,account:o,extensionDir:n,userDataDir:e,extensionStorageState:r},s,i)=>{if(n||e){if(o||i.project.use.auth)throw new Error('Cannot use both "extensionDir"/"userDataDir" and "auth" \u2014 persistent context tests manage their own context. Use extensionStorageState for authentication instead.');let c=i.project.use?.browserName;c&&c!=="chromium"&&console.warn(`[fixture] Persistent context requires Chromium but project is configured for "${c}". Forcing Chromium.`);let f=process.env.PLAYWRIGHT_HEADLESS==="true";n&&f&&console.warn("[fixture] PLAYWRIGHT_HEADLESS=true with extensionDir \u2014 Chrome extensions will not function in headless mode.");let l=O(e),g=n?D(d.resolve(process.cwd(),n)):[],p={...i.project.use},{storageState:k,account:m,extensionDir:x,userDataDir:v,extensionStorageState:V,video:b,...C}=p,A=j(b)?{dir:i.outputDir}:void 0,w;try{if(w=await Y.launchPersistentContext(l,{...C,headless:f,args:g,viewport:C.viewport??{width:1280,height:720},...A?{recordVideo:A}:{}}),r){let y=d.resolve(process.cwd(),r),E=T(y);E&&await w.addCookies(E)}await s(w),await R(w,b,i)}finally{if(await w?.close().catch(y=>{console.warn("[fixture] Failed to close persistent context:",y)}),!e)try{F.rmSync(l,{recursive:!0,force:!0})}catch(y){console.warn("[fixture] Failed to clean up temp profile dir:",l,y)}}}else{let c={...i.project.use},f=i.project.use,l=f.auth?{auth:f.auth,args:f.args}:o;if(l){if(!l.auth)throw new Error("Auth is declared but missing the script path. Provide auth in playwright.config.ts: use: { auth: './auth.login.ts' }");c.storageState=await H(l)}let g=c.video;j(g)&&!c.recordVideo&&(c.recordVideo={dir:i.outputDir});let p=await t.newContext(c);try{await s(p),await R(p,g,i)}finally{await p.close()}}},page:async({context:t},o)=>{let n=await t.newPage();await o(n)},testContext:async({},t,o)=>{let{VariableStore:n}=await $(),e=new n,r=o.project.use.variables;if(r)for(let[i,u]of Object.entries(r))typeof u=="string"?e.set(i,u,!1):u&&typeof u=="object"&&"value"in u&&e.set(i,u.value,u.sensitive===!0);let s=N(e);global.testContext=s,global.$=s,global.ctx=s,await t(s),delete global.testContext,delete global.$,delete global.ctx},$:async({testContext:t},o)=>{await o(t)},ctx:async({testContext:t},o)=>{await o(t)},agent:async({testContext:t,autoDismissModal:o},n,e)=>{let{WebAgent:r,createAgentContext:s,configureSdk:i,parseSdkLogLevelFromEnv:u}=await $(),c=u();i({env:{GOOGLE_API_KEY:process.env.GOOGLE_API_KEY??"",ANTHROPIC_API_KEY:process.env.ANTHROPIC_API_KEY??""},...c!==void 0&&{logLevel:c}});let{resolveModelFromEnv:f}=await import("./dist-PL6NUZP6.js"),l=f(process.env);if(!l)throw new Error("No AI model configured. Set WEB_AGENT_MODEL, ANTHROPIC_API_KEY, or GOOGLE_API_KEY.");let g=t.__variableStore,p=s({model:l,variableStore:g,autoDisableModal:o}),k=d.join(e.outputDir,"artifacts");p.stepTracking={results:{},artifactsDir:k};let m=new r(p);global.agent=m,await n(m),delete global.agent;try{let x=e.outputDir;await m.writeExecutionResults(x);let v=d.join(x,"test-results.json");await(await import("fs/promises")).stat(v).catch(()=>null)&&await e.attach("shiplight-results",{path:v,contentType:"application/json"})}catch(x){console.error("[Shiplight] Failed to attach step results:",x)}}});export{N as createTestContext,I as expect,H as resolveAuthState,J as test};
3
+ import"./chunk-CSINHOOD.js";import*as g from"path";import*as F from"fs";import{test as G,expect as I,chromium as Y}from"@playwright/test";import*as a from"fs";import*as y from"path";import{randomUUID as _}from"crypto";import{tmpdir as P}from"os";function D(e){return[`--disable-extensions-except=${e}`,`--load-extension=${e}`,"--no-first-run","--disable-default-apps"]}function T(e){if(!a.existsSync(e))return console.warn(`[fixture] extensionStorageState file not found: ${e}`),null;let r;try{r=JSON.parse(a.readFileSync(e,"utf-8"))}catch(s){throw new Error(`[fixture] Failed to parse extensionStorageState at ${e}: ${s}`)}let o=r;if(!Array.isArray(o.cookies))return null;let t=(Date.now()+365*24*60*60*1e3)/1e3,n=o.cookies.filter(s=>s&&typeof s=="object"&&typeof s.name=="string"&&typeof s.domain=="string");return n.length<o.cookies.length&&console.warn(`[fixture] Skipped ${o.cookies.length-n.length} malformed cookies (missing name or domain)`),n.map(s=>({...s,expires:t}))}function O(e){if(e){let o=y.resolve(process.cwd(),e),t=y.join(P(),`ext-profile-${_()}`);if(a.existsSync(o)){try{a.cpSync(o,t,{recursive:!0})}catch(s){try{a.rmSync(t,{recursive:!0,force:!0})}catch(i){console.warn("[fixture] Failed to clean up partial profile copy:",t,i)}throw new Error(`[fixture] Failed to copy extension profile from ${o}: ${s}`)}let n=y.join(t,"SingletonLock");a.existsSync(n)&&a.rmSync(n,{force:!0})}else a.mkdirSync(t,{recursive:!0});return t}let r=y.join(P(),`ext-profile-${_()}`);return a.mkdirSync(r,{recursive:!0}),r}async function B(e){let o=await import(g.resolve(process.cwd(),e.auth)),t=o.login||o.default;if(typeof t!="function")throw new Error(`auth module "${e.auth}" must export a login(args) function that returns a storageState file path`);let n=await t(e.args||{});if(typeof n!="string")throw new Error(`auth module "${e.auth}" login() must return a storageState file path (got ${typeof n})`);return n}function j(e){return!(!e||e==="off")}function L(e,r){return!e||e==="off"?!1:e==="on"?!0:e==="retain-on-failure"?r.status!==r.expectedStatus:e==="on-first-retry"?r.retry>0:typeof e=="object"&&e!==null&&"mode"in e?L(e.mode,r):!0}async function R(e,r,o){let t=L(r,o);for(let n of e)if(n)try{if(t){let s=await n.path();await o.attach("video",{path:s,contentType:"video/webm"})}else await n.delete()}catch{}}var v;async function $(){return v||(v=await import("./dist-ZGT6WF2R.js"),v)}var H=new Set(["get","set","getAll","has","__variableStore"]);function M(e){let r={__variableStore:e,get(o){return e.get(o)},set(o,t,n=!1){e.set(o,t,n)},getAll(){return e.getAll()}};return new Proxy(r,{get(o,t,n){if(t in o)return Reflect.get(o,t,n);if(typeof t=="string")return o.get(t)},set(o,t,n){return typeof t!="string"||H.has(t)?Reflect.set(o,t,n):(o.set(t,n),!0)},has(o,t){return t in o?!0:typeof t=="string"?e.has?.(t)??!1:!1}})}var J=G.extend({account:[void 0,{option:!0}],autoDismissModal:[!1,{option:!0}],extensionDir:[void 0,{option:!0}],userDataDir:[void 0,{option:!0}],extensionStorageState:[void 0,{option:!0}],context:async({browser:e,account:r,extensionDir:o,userDataDir:t,extensionStorageState:n},s,i)=>{if(o||t){if(r||i.project.use.auth)throw new Error('Cannot use both "extensionDir"/"userDataDir" and "auth" \u2014 persistent context tests manage their own context. Use extensionStorageState for authentication instead.');let c=i.project.use?.browserName;c&&c!=="chromium"&&console.warn(`[fixture] Persistent context requires Chromium but project is configured for "${c}". Forcing Chromium.`);let f=process.env.PLAYWRIGHT_HEADLESS==="true";o&&f&&console.warn("[fixture] PLAYWRIGHT_HEADLESS=true with extensionDir \u2014 Chrome extensions will not function in headless mode.");let l=O(t),h=o?D(g.resolve(process.cwd(),o)):[],p={...i.project.use},{storageState:S,account:x,extensionDir:w,userDataDir:b,extensionStorageState:V,video:k,...C}=p,E=j(k)?{dir:i.outputDir}:void 0,m;try{if(m=await Y.launchPersistentContext(l,{...C,headless:f,args:h,viewport:C.viewport??{width:1280,height:720},...E?{recordVideo:E}:{}}),n){let A=g.resolve(process.cwd(),n),d=T(A);d&&await m.addCookies(d)}await s(m)}finally{let A=m?.pages().map(d=>d.video()).filter(Boolean)??[];if(await m?.close().catch(d=>{console.warn("[fixture] Failed to close persistent context:",d)}),await R(A,k,i),!t)try{F.rmSync(l,{recursive:!0,force:!0})}catch(d){console.warn("[fixture] Failed to clean up temp profile dir:",l,d)}}}else{let c={...i.project.use},f=i.project.use,l=f.auth?{auth:f.auth,args:f.args}:r;if(l){if(!l.auth)throw new Error("Auth is declared but missing the script path. Provide auth in playwright.config.ts: use: { auth: './auth.login.ts' }");c.storageState=await B(l)}let h=c.video;j(h)&&!c.recordVideo&&(c.recordVideo={dir:i.outputDir});let p=await e.newContext(c);try{await s(p)}finally{let S=p.pages().map(x=>x.video()).filter(Boolean);await p.close(),await R(S,h,i)}}},page:async({context:e},r)=>{let o=await e.newPage();await r(o)},testContext:async({},e,r)=>{let{VariableStore:o}=await $(),t=new o,n=r.project.use.variables;if(n)for(let[i,u]of Object.entries(n))typeof u=="string"?t.set(i,u,!1):u&&typeof u=="object"&&"value"in u&&t.set(i,u.value,u.sensitive===!0);let s=M(t);global.testContext=s,global.$=s,global.ctx=s,await e(s),delete global.testContext,delete global.$,delete global.ctx},$:async({testContext:e},r)=>{await r(e)},ctx:async({testContext:e},r)=>{await r(e)},agent:async({testContext:e,autoDismissModal:r},o,t)=>{let{WebAgent:n,createAgentContext:s,configureSdk:i,parseSdkLogLevelFromEnv:u}=await $(),c=u();i({env:{GOOGLE_API_KEY:process.env.GOOGLE_API_KEY??"",ANTHROPIC_API_KEY:process.env.ANTHROPIC_API_KEY??""},...c!==void 0&&{logLevel:c}});let{resolveModelFromEnv:f}=await import("./dist-PL6NUZP6.js"),l=f(process.env);if(!l)throw new Error("No AI model configured. Set WEB_AGENT_MODEL, ANTHROPIC_API_KEY, or GOOGLE_API_KEY.");let h=e.__variableStore,p=s({model:l,variableStore:h,autoDisableModal:r}),S=g.join(t.outputDir,"artifacts");p.stepTracking={results:{},artifactsDir:S};let x=new n(p);global.agent=x,await o(x),delete global.agent;try{let w=t.outputDir;await x.writeExecutionResults(w);let b=g.join(w,"test-results.json");await(await import("fs/promises")).stat(b).catch(()=>null)&&await t.attach("shiplight-results",{path:b,contentType:"application/json"})}catch(w){console.error("[Shiplight] Failed to attach step results:",w)}}});export{M as createTestContext,I as expect,B as resolveAuthState,J as test};
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  const require = __createRequire(import.meta.url);
3
- import{r as w,s as R}from"./chunk-CJCWHXDQ.js";import{m as I}from"./chunk-7CDBI7NF.js";import"./chunk-BSQEKK2N.js";import"./chunk-HK7CBJJX.js";import"./chunk-DUXKECDI.js";import"./chunk-C6AYGFJ5.js";import"./chunk-T3H4NEVX.js";import"./chunk-YU3XZJIJ.js";import"./chunk-LWNM7LR6.js";import{a as v}from"./chunk-T2JTBHI7.js";import{a as g,b as h}from"./chunk-XRX4MOU6.js";import"./chunk-2SPCVSYL.js";import"./chunk-CSINHOOD.js";import*as S from"fs";import*as o from"path";import H from"dotenv";import{readFileSync as u,statSync as E,existsSync as y}from"fs";import{resolve as p}from"path";import{globSync as A}from"glob";var c="0.1.34";function d(t){try{return E(t).mtimeMs}catch{return 0}}var T=`// @generated by shiplightai v${c}`;function b(t,s){if(!y(t)||u(t,"utf-8").split(`
3
+ import{r as w,s as R}from"./chunk-CJCWHXDQ.js";import{m as I}from"./chunk-7CDBI7NF.js";import"./chunk-BSQEKK2N.js";import"./chunk-HK7CBJJX.js";import"./chunk-DUXKECDI.js";import"./chunk-C6AYGFJ5.js";import"./chunk-T3H4NEVX.js";import"./chunk-YU3XZJIJ.js";import"./chunk-LWNM7LR6.js";import{a as v}from"./chunk-T2JTBHI7.js";import{a as g,b as h}from"./chunk-XRX4MOU6.js";import"./chunk-2SPCVSYL.js";import"./chunk-CSINHOOD.js";import*as S from"fs";import*as o from"path";import H from"dotenv";import{readFileSync as u,statSync as E,existsSync as y}from"fs";import{resolve as p}from"path";import{globSync as A}from"glob";var c="0.1.35";function d(t){try{return E(t).mtimeMs}catch{return 0}}var T=`// @generated by shiplightai v${c}`;function b(t,s){if(!y(t)||u(t,"utf-8").split(`
4
4
  `,1)[0]!==T)return!1;let i=d(t);for(let e of s)if(d(e)>i)return!1;return!0}function x(t){let s=process.argv.slice(2),n=[],i=p(t);for(let e of s){if(e.startsWith("-"))continue;let r=e.endsWith(".yaml.spec.ts")?e.replace(/\.yaml\.spec\.ts$/,".test.yaml"):e;if(!r.endsWith(".test.yaml"))continue;let l=p(t,r);y(l)&&n.push(l.startsWith(i)?l.slice(i.length+1):r)}return n.length>0?n:null}function _(t){let s=x(t.cwd),n=s??A("**/*.test.yaml",{cwd:t.cwd,ignore:["**/node_modules/**"]}),i=[];for(let e of n){let r=p(t.cwd,e),l=r.replace(/\.test\.yaml$/,".yaml.spec.ts"),f=u(r,"utf-8");try{let a=g(f,r);if(b(l,[r,...a.referencedTemplatePaths]))continue;let m=h(f,r,{version:c});if(!m.valid)throw new Error(m.errors.join("; "))}catch(a){console.error(`[shiplight] Failed to transpile ${e}:`,a),i.push({file:e,error:a})}}if(i.length>0){let e=`[shiplight] Transpilation failed for ${i.length} file(s):
5
5
  `+i.map(r=>` - ${r.file}`).join(`
6
6
  `);if(s)throw new Error(e);console.warn(e+" (skipped)")}}function O(t={}){t.dotenv!==!1&&P(t.scanDir||process.cwd());let s=t.scanDir||process.cwd();return _({cwd:s}),t.apiKey&&(process.env.__SHIPLIGHT_API_KEY=t.apiKey),{reporter:[["list"],["shiplightai/reporter",{outputFolder:"shiplight-report",open:"never"}]]}}function P(t){let s=[],n=o.resolve(t),i=o.resolve(process.cwd());for(;;){let e=o.join(n,".env");if(S.existsSync(e)&&s.push(e),n===i)break;let r=o.dirname(n);if(r===n)break;n=r}for(let e of s)H.config({path:e})}export{I as VariableStore,w as WebAgent,v as configureSdk,R as createAgentContext,O as shiplightConfig};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shiplightai",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "type": "module",
5
5
  "description": "Shiplight CLI for running and debugging .test.yaml files",
6
6
  "main": "dist/index.js",