@skyramp/testbot-core 0.13.0-v3.62 → 0.13.0-v3.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/VERSION.json CHANGED
@@ -1 +1 @@
1
- {"version":"0.13.0-v3.62","commit":"2519ef1efcb41022cd492f4b60b0a0015168c66d"}
1
+ {"version":"0.13.0-v3.63","commit":"48f95629afa819fab9e119439639b7abee0bb650"}
package/dist/main.js CHANGED
@@ -241,7 +241,7 @@ additional repositories analyzed in a multi-repo run).`,devPrMergedBreadcrumb:(t
241
241
  `+b.slice(V,J),V=J+1),W=ee;return ie+=`
242
242
  `,b.length-V>P&&W>V?ie+=b.slice(V,W)+`
243
243
  `+b.slice(W+1):ie+=b.slice(V),ie.slice(1)}function Kr(b){let P="",U=0;for(let G=0;G<b.length;U>=65536?G+=2:G++){U=Et(b,G);let V=q[U];!V&&Se(U)?(P+=b[G],U>=65536&&(P+=b[G+1])):P+=V||ae(U)}return P}function Ai(b,P,U){let G="",V=b.tag;for(let J=0,W=U.length;J<W;J+=1){let ee=U[J];b.replacer&&(ee=b.replacer.call(U,String(J),ee)),(R(b,P,ee,!1,!1)||typeof ee>"u"&&R(b,P,null,!1,!1))&&(G!==""&&(G+=","+(b.condenseFlow?"":" ")),G+=b.dump)}b.tag=V,b.dump="["+G+"]"}function Ws(b,P,U,G){let V="",J=b.tag;for(let W=0,ee=U.length;W<ee;W+=1){let ie=U[W];b.replacer&&(ie=b.replacer.call(U,String(W),ie)),(R(b,P+1,ie,!0,!0,!1,!0)||typeof ie>"u"&&R(b,P+1,null,!0,!0,!1,!0))&&((!G||V!=="")&&(V+=le(b,P)),b.dump&&a===b.dump.charCodeAt(0)?V+="-":V+="- ",V+=b.dump)}b.tag=J,b.dump=V||"[]"}function oc(b,P,U){let G="",V=b.tag,J=Object.keys(U);for(let W=0,ee=J.length;W<ee;W+=1){let ie="";G!==""&&(ie+=", "),b.condenseFlow&&(ie+='"');let de=J[W],pe=U[de];b.replacer&&(pe=b.replacer.call(U,de,pe)),R(b,P,de,!1,!1)&&(b.dump.length>1024&&(ie+="? "),ie+=b.dump+(b.condenseFlow?'"':"")+":"+(b.condenseFlow?"":" "),R(b,P,pe,!1,!1)&&(ie+=b.dump,G+=ie))}b.tag=V,b.dump="{"+G+"}"}function x(b,P,U,G){let V="",J=b.tag,W=Object.keys(U);if(b.sortKeys===!0)W.sort();else if(typeof b.sortKeys=="function")W.sort(b.sortKeys);else if(b.sortKeys)throw new e("sortKeys must be a boolean or a function");for(let ee=0,ie=W.length;ee<ie;ee+=1){let de="";(!G||V!=="")&&(de+=le(b,P));let pe=W[ee],Ce=U[pe];if(b.replacer&&(Ce=b.replacer.call(U,pe,Ce)),!R(b,P+1,pe,!0,!0,!0))continue;let je=b.tag!==null&&b.tag!=="?"||b.dump&&b.dump.length>1024;je&&(b.dump&&a===b.dump.charCodeAt(0)?de+="?":de+="? "),de+=b.dump,je&&(de+=le(b,P)),R(b,P+1,Ce,!0,je)&&(b.dump&&a===b.dump.charCodeAt(0)?de+=":":de+=": ",de+=b.dump,V+=de)}b.tag=J,b.dump=V||"{}"}function g(b,P,U){let G=U?b.explicitTypes:b.implicitTypes;for(let V=0,J=G.length;V<J;V+=1){let W=G[V];if((W.instanceOf||W.predicate)&&(!W.instanceOf||typeof P=="object"&&P instanceof W.instanceOf)&&(!W.predicate||W.predicate(P))){if(U?W.multi&&W.representName?b.tag=W.representName(P):b.tag=W.tag:b.tag="?",W.represent){let ee=b.styleMap[W.tag]||W.defaultStyle,ie;if(n.call(W.represent)==="[object Function]")ie=W.represent(P,ee);else if(s.call(W.represent,ee))ie=W.represent[ee](P,ee);else throw new e("!<"+W.tag+'> tag resolver accepts not "'+ee+'" style');b.dump=ie}return!0}}return!1}function R(b,P,U,G,V,J,W){b.tag=null,b.dump=U,g(b,U,!1)||g(b,U,!0);let ee=n.call(b.dump),ie=G;G&&(G=b.flowLevel<0||b.flowLevel>P);let de=ee==="[object Object]"||ee==="[object Array]",pe,Ce;if(de&&(pe=b.duplicates.indexOf(U),Ce=pe!==-1),(b.tag!==null&&b.tag!=="?"||Ce||b.indent!==2&&P>0)&&(V=!1),Ce&&b.usedDuplicates[pe])b.dump="*ref_"+pe;else{if(de&&Ce&&!b.usedDuplicates[pe]&&(b.usedDuplicates[pe]=!0),ee==="[object Object]")G&&Object.keys(b.dump).length!==0?(x(b,P,b.dump,V),Ce&&(b.dump="&ref_"+pe+b.dump)):(oc(b,P,b.dump),Ce&&(b.dump="&ref_"+pe+" "+b.dump));else if(ee==="[object Array]")G&&b.dump.length!==0?(b.noArrayIndent&&!W&&P>0?Ws(b,P-1,b.dump,V):Ws(b,P,b.dump,V),Ce&&(b.dump="&ref_"+pe+b.dump)):(Ai(b,P,b.dump),Ce&&(b.dump="&ref_"+pe+" "+b.dump));else if(ee==="[object String]")b.tag!=="?"&&vt(b,b.dump,P,J,ie);else{if(ee==="[object Undefined]")return!1;if(b.skipInvalid)return!1;throw new e("unacceptable kind of an object to dump "+ee)}if(b.tag!==null&&b.tag!=="?"){let je=encodeURI(b.tag[0]==="!"?b.tag.slice(1):b.tag).replace(/!/g,"%21");b.tag[0]==="!"?je="!"+je:je.slice(0,18)==="tag:yaml.org,2002:"?je="!!"+je.slice(18):je="!<"+je+">",b.dump=je+" "+b.dump}}return!0}function D(b,P){let U=[],G=[];k(b,U,G);let V=G.length;for(let J=0;J<V;J+=1)P.duplicates.push(U[G[J]]);P.usedDuplicates=new Array(V)}function k(b,P,U){if(b!==null&&typeof b=="object"){let G=P.indexOf(b);if(G!==-1)U.indexOf(G)===-1&&U.push(G);else if(P.push(b),Array.isArray(b))for(let V=0,J=b.length;V<J;V+=1)k(b[V],P,U);else{let V=Object.keys(b);for(let J=0,W=V.length;J<W;J+=1)k(b[V[J]],P,U)}}}function M(b,P){P=P||{};let U=new Ie(P);U.noRefs||D(b,U);let G=b;return U.replacer&&(G=U.replacer.call({"":G},"",G)),R(U,0,G,!0,!0)?U.dump+`
244
- `:""}return Tse.dump=M,Tse}var m5e;function eJt(){if(m5e)return Yi;m5e=1;let t=X4t(),e=Z4t();function r(n,s){return function(){throw new Error("Function yaml."+n+" is removed in js-yaml 4. Use yaml."+s+" instead, which is now safe by default.")}}return Yi.Type=No(),Yi.Schema=f5e(),Yi.FAILSAFE_SCHEMA=y5e(),Yi.JSON_SCHEMA=C5e(),Yi.CORE_SCHEMA=S5e(),Yi.DEFAULT_SCHEMA=Bse(),Yi.load=t.load,Yi.loadAll=t.loadAll,Yi.dump=e.dump,Yi.YAMLException=zT(),Yi.types={binary:v5e(),float:x5e(),map:A5e(),null:E5e(),pairs:T5e(),set:B5e(),timestamp:I5e(),bool:b5e(),int:w5e(),merge:R5e(),omap:N5e(),seq:g5e(),str:h5e()},Yi.safeLoad=r("safeLoad","load"),Yi.safeLoadAll=r("safeLoadAll","loadAll"),Yi.safeDump=r("safeDump","dump"),Yi}var tJt=eJt(),rJt=J4t(tJt),{Type:G8r,Schema:j8r,FAILSAFE_SCHEMA:V8r,JSON_SCHEMA:P5e,CORE_SCHEMA:W8r,DEFAULT_SCHEMA:Y8r,load:ng,loadAll:J8r,dump:K8r,YAMLException:X8r,types:Z8r,safeLoad:eKr,safeLoadAll:tKr,safeDump:rKr}=rJt;var _m=t=>typeof t=="string"?t:void 0;function _5e(t){let e={services:[]},r;try{let c=k5e.readFileSync(t,"utf8");r=ng(c,{schema:P5e})}catch(c){return K(`Lenient parse: failed to read/parse ${t}: ${c.message}`),e}if(!r||typeof r!="object"||Array.isArray(r))return K(`Lenient parse: ${t} did not contain a YAML object`),e;let n=r,s=n.metadata&&typeof n.metadata=="object"?n.metadata:void 0,i=s?{executorVersion:_m(s.executorVersion),mcpVersion:_m(s.mcpVersion)}:void 0,a=(Array.isArray(n.services)?n.services:[]).reduce((c,l,u)=>{if(!l||typeof l!="object"||Array.isArray(l))return K(`Lenient parse: services[${u}] is not an object \u2014 skipping`),c;let d=l,p=_m(d.serviceName);if(!p)return K(`Lenient parse: services[${u}] missing or non-string serviceName \u2014 skipping`),c;let m=d.api&&typeof d.api=="object"?d.api:void 0,h=d.runtimeDetails&&typeof d.runtimeDetails=="object"?d.runtimeDetails:void 0;return c.push({serviceName:p,language:_m(d.language),framework:_m(d.framework),testDirectory:_m(d.testDirectory),api:m?{baseUrl:_m(m.baseUrl)}:void 0,runtimeDetails:h?{serverStartCommand:_m(h.serverStartCommand),serverTeardownCommand:_m(h.serverTeardownCommand)}:void 0}),c},[]);return{metadata:i,services:a}}async function GT(t){let e=D5e.resolve(t.workingDirectory),r=new f$(e),n=[],s=t.targetSetupCommand,i=t.targetTeardownCommand,o=t.skyrampExecutorVersion,a=t.skyrampMcpVersion;if(await r.exists()){te(`Found ${r.getConfigPath()}, loading workspace configuration...`);try{let l;try{l=await r.read()}catch(d){K(`${r.getConfigPath()} failed strict validation: ${d.message}. Re-reading with per-field lenient parse \u2014 invalid fields will fall back to action input defaults.`),l=_5e(r.getConfigPath())}l.metadata&&(!o&&l.metadata.executorVersion&&(o=l.metadata.executorVersion),!a&&l.metadata.mcpVersion&&(a=l.metadata.mcpVersion));for(let d of l.services??[])n.push({serviceName:d.serviceName,language:d.language,framework:d.framework,baseUrl:d.api?.baseUrl,testDirectory:d.testDirectory});let u=(l.services??[])[0];if(u){!s&&u.runtimeDetails?.serverStartCommand&&(s=u.runtimeDetails.serverStartCommand);let d=u.runtimeDetails?.serverTeardownCommand;!i&&typeof d=="string"&&(i=d)}}catch(l){K(`Failed to parse ${r.getConfigPath()}: ${l.message} \u2014 falling back to action input defaults`)}}else Re("No .skyramp/workspace.yml found, using action input defaults");o||(o="v1.3.51"),a||(a="latest"),s||(s="docker compose up -d --build");let c={targetSetupCommand:s,authTokenCommand:t.authTokenCommand,targetTeardownCommand:i,skipTargetTeardown:t.skipTargetTeardown,skyrampExecutorVersion:o,skyrampMcpVersion:a,skyrampMcpSource:t.skyrampMcpSource,skyrampMcpGithubRef:t.skyrampMcpGithubRef,nodeVersion:t.nodeVersion,skipTargetSetup:t.skipTargetSetup,targetReadyCheckCommand:t.targetReadyCheckCommand,targetReadyCheckTimeout:t.targetReadyCheckTimeout,targetReadyCheckInterval:t.targetReadyCheckInterval,targetReadyCheckDiagnosticsCommand:t.targetReadyCheckDiagnosticsCommand,autoCommit:t.autoCommit,commitMessage:t.commitMessage,generatedTestsMode:t.generatedTestsMode,postPrComment:t.postPrComment,testExecutionTimeout:t.testExecutionTimeout,maxRecommendations:t.maxRecommendations,maxGenerate:t.maxGenerate,perTestMaxFixAttempts:t.perTestMaxFixAttempts,testbotMaxRetries:t.testbotMaxRetries,testbotRetryDelay:t.testbotRetryDelay,testbotTimeout:t.testbotTimeout,targetSetupRetries:t.targetSetupRetries,targetSetupRetryDelay:t.targetSetupRetryDelay,authTokenRetries:t.authTokenRetries,authTokenRetryDelay:t.authTokenRetryDelay,reportCollapsed:t.reportCollapsed,language:t.language,enableDebug:t.enableDebug,testRepoPath:t.testRepoPath,relatedRepoPaths:t.relatedRepoPaths,services:n};Ks("Resolved configuration");for(let[l,u]of Object.entries(c))l==="authTokenCommand"?te(` ${l}: [REDACTED]`):l==="services"?te(` ${l}: ${JSON.stringify(u)}`):te(` ${l}: ${u}`);return qn(),c}Je();Uc();async function M5e(t,e){let r=LT(e),n=async i=>{try{return await r(i,{silent:!0,ignoreReturnCode:!0})}catch(o){return te(`Self-trigger git read failed (treating as unknown author): ${o instanceof Error?o.message:String(o)}`),{exitCode:1,stdout:"",stderr:""}}},s={skip:!1,botName:Us,botEmail:Fc};return await Dn("Checking for self-triggered execution",async()=>{let i=t.rawPayload,o=i.pull_request?.user;if(t.kind==="code_review"&&o?.login===bd){Re(`Detected Testbot PR opened by ${bd}. Skipping to prevent recursion.`),s={skip:!0,botName:Us,botEmail:Fc};return}let a="",c="",l=i.head_commit;if(l?.author?.name&&(a=l.author.name,c=l.author.email??""),!a){let h=i.pull_request?.head?.sha,f=h||"HEAD";h&&te(`Using pull_request head SHA: ${h}`),a=(await n(["log","-1","--pretty=format:%an",f])).stdout.trim(),c=(await n(["log","-1","--pretty=format:%ae",f])).stdout.trim()}te(`Commit author: ${a}`),te(`Commit email: ${c}`),te(`Expected name: ${Us}`),te(`Expected email: ${Fc}`);let u=a===Us&&c===Fc,d=t.kind==="code_review"&&t.action==="updated",p=u&&d;if(!p&&d){let f=i.pull_request?.head?.sha||"HEAD",A=(await n(["log","-1","--pretty=format:%s",f])).stdout.trim();(/^Merge pull request #\d+ from [^/]+\/skyramp-testbot\/pr-\d+$/.test(A)||a===bd)&&(Re(`Detected merge of testbot test PR into dev PR (commit: "${A}", author: "${a}"). Skipping \u2014 tests already generated.`),p=!0)}p?u&&Re(`Detected self-triggered execution (commit by ${Us} on synchronize event). Skipping to prevent recursion.`):u?Re(`Head commit is by ${Us} but event is '${t.kind}' action='${t.action}' (not code_review/updated). Proceeding normally.`):Re("Not a self-triggered execution. Proceeding with test maintenance."),s={skip:p,botName:Us,botEmail:Fc}}),s}Je();var nJt=6e4,Pse="skipped_pr_closed";function Q5e(t){return t.state==="closed"}async function O5e(t,e){try{return Q5e(await t.getCodeReview(e))}catch(r){return K(`Could not read the state of PR #${e} (${r instanceof Error?r.message:String(r)}) \u2014 proceeding as if it is still open.`),!1}}function L5e(t){let{platform:e,prNumber:r,pollIntervalMs:n=nJt,onAbandoned:s}=t,i=null,o=!1,a=!1;function c(){o=!0,i&&(clearInterval(i),i=null)}async function l(){if(!(o||a)){a=!0;try{let u=await e.getCodeReview(r);if(o)return;Q5e(u)&&(c(),K(`PR #${r} was closed without merging while this run was in progress \u2014 stopping so the shared concurrency lane is released for other PRs.`),s())}catch(u){wt(`PR state poll for #${r} failed (ignored): ${u instanceof Error?u.message:String(u)}`)}finally{a=!1}}}return{start(){o=!1,i=setInterval(()=>{l()},n),i.unref?.()},stop:c}}Je();var XC=$(require("fs"));function VT(t){let e=Math.floor(t/1e3);if(e<60)return`${e}s`;let r=Math.floor(e/60),n=e%60;return`${r}m ${n}s`}function F5e(t=!1){return[{step:"setup",label:he().stepSettingUpEnvironment,status:"pending"},{step:"analyzing",label:t?he().stepAnalyzingUserRequest:he().stepAnalyzingCodeChanges,status:"pending"},{step:"maintaining",label:he().stepRecommendingTests,status:"pending"},{step:"generating",label:he().stepGeneratingTests,status:"pending"},{step:"executing",label:he().stepExecutingTests,status:"pending"},{step:"reporting",label:he().stepGeneratingReport,status:"pending"}]}var jT=null;function U5e(t){jT=t}var kse="";function $5e(t){kse=t}function ZC(){if(jT)return jT;if(kse){let{GitHubPlatform:t}=(zN(),F2(DHe)),{BOT_GITHUB_LOGIN:e}=(Uc(),F2(MHe));return jT=new t(kse,e),jT}throw new Error("No platform available. Call setPlatform() or setGitHubToken() before using progress functions.")}function _se(t,e,r=!1){let s=ZC().getRunUrl();if(e){let o=e.replace(/^\s*<!--\s*skyramp-testbot\s*-->\s*\n?/,""),a=o.includes(s)?[]:["",`<sub>[${he().workflowRunLinkLabel}](${s})</sub>`];return["<!-- skyramp-testbot -->","### Skyramp Testbot","",o,...a].join(`
244
+ `:""}return Tse.dump=M,Tse}var m5e;function eJt(){if(m5e)return Yi;m5e=1;let t=X4t(),e=Z4t();function r(n,s){return function(){throw new Error("Function yaml."+n+" is removed in js-yaml 4. Use yaml."+s+" instead, which is now safe by default.")}}return Yi.Type=No(),Yi.Schema=f5e(),Yi.FAILSAFE_SCHEMA=y5e(),Yi.JSON_SCHEMA=C5e(),Yi.CORE_SCHEMA=S5e(),Yi.DEFAULT_SCHEMA=Bse(),Yi.load=t.load,Yi.loadAll=t.loadAll,Yi.dump=e.dump,Yi.YAMLException=zT(),Yi.types={binary:v5e(),float:x5e(),map:A5e(),null:E5e(),pairs:T5e(),set:B5e(),timestamp:I5e(),bool:b5e(),int:w5e(),merge:R5e(),omap:N5e(),seq:g5e(),str:h5e()},Yi.safeLoad=r("safeLoad","load"),Yi.safeLoadAll=r("safeLoadAll","loadAll"),Yi.safeDump=r("safeDump","dump"),Yi}var tJt=eJt(),rJt=J4t(tJt),{Type:G8r,Schema:j8r,FAILSAFE_SCHEMA:V8r,JSON_SCHEMA:P5e,CORE_SCHEMA:W8r,DEFAULT_SCHEMA:Y8r,load:ng,loadAll:J8r,dump:K8r,YAMLException:X8r,types:Z8r,safeLoad:eKr,safeLoadAll:tKr,safeDump:rKr}=rJt;var _m=t=>typeof t=="string"?t:void 0;function _5e(t){let e={services:[]},r;try{let c=k5e.readFileSync(t,"utf8");r=ng(c,{schema:P5e})}catch(c){return K(`Lenient parse: failed to read/parse ${t}: ${c.message}`),e}if(!r||typeof r!="object"||Array.isArray(r))return K(`Lenient parse: ${t} did not contain a YAML object`),e;let n=r,s=n.metadata&&typeof n.metadata=="object"?n.metadata:void 0,i=s?{executorVersion:_m(s.executorVersion),mcpVersion:_m(s.mcpVersion)}:void 0,a=(Array.isArray(n.services)?n.services:[]).reduce((c,l,u)=>{if(!l||typeof l!="object"||Array.isArray(l))return K(`Lenient parse: services[${u}] is not an object \u2014 skipping`),c;let d=l,p=_m(d.serviceName);if(!p)return K(`Lenient parse: services[${u}] missing or non-string serviceName \u2014 skipping`),c;let m=d.api&&typeof d.api=="object"?d.api:void 0,h=d.runtimeDetails&&typeof d.runtimeDetails=="object"?d.runtimeDetails:void 0;return c.push({serviceName:p,language:_m(d.language),framework:_m(d.framework),testDirectory:_m(d.testDirectory),api:m?{baseUrl:_m(m.baseUrl)}:void 0,runtimeDetails:h?{serverStartCommand:_m(h.serverStartCommand),serverTeardownCommand:_m(h.serverTeardownCommand)}:void 0}),c},[]);return{metadata:i,services:a}}async function GT(t){let e=D5e.resolve(t.workingDirectory),r=new f$(e),n=[],s=t.targetSetupCommand,i=t.targetTeardownCommand,o=t.skyrampExecutorVersion,a=t.skyrampMcpVersion;if(await r.exists()){te(`Found ${r.getConfigPath()}, loading workspace configuration...`);try{let l;try{l=await r.read()}catch(d){K(`${r.getConfigPath()} failed strict validation: ${d.message}. Re-reading with per-field lenient parse \u2014 invalid fields will fall back to action input defaults.`),l=_5e(r.getConfigPath())}l.metadata&&(!o&&l.metadata.executorVersion&&(o=l.metadata.executorVersion),!a&&l.metadata.mcpVersion&&(a=l.metadata.mcpVersion));for(let d of l.services??[])n.push({serviceName:d.serviceName,language:d.language,framework:d.framework,baseUrl:d.api?.baseUrl,testDirectory:d.testDirectory});let u=(l.services??[])[0];if(u){!s&&u.runtimeDetails?.serverStartCommand&&(s=u.runtimeDetails.serverStartCommand);let d=u.runtimeDetails?.serverTeardownCommand;!i&&typeof d=="string"&&(i=d)}}catch(l){K(`Failed to parse ${r.getConfigPath()}: ${l.message} \u2014 falling back to action input defaults`)}}else Re("No .skyramp/workspace.yml found, using action input defaults");o||(o="v1.3.52"),a||(a="latest"),s||(s="docker compose up -d --build");let c={targetSetupCommand:s,authTokenCommand:t.authTokenCommand,targetTeardownCommand:i,skipTargetTeardown:t.skipTargetTeardown,skyrampExecutorVersion:o,skyrampMcpVersion:a,skyrampMcpSource:t.skyrampMcpSource,skyrampMcpGithubRef:t.skyrampMcpGithubRef,nodeVersion:t.nodeVersion,skipTargetSetup:t.skipTargetSetup,targetReadyCheckCommand:t.targetReadyCheckCommand,targetReadyCheckTimeout:t.targetReadyCheckTimeout,targetReadyCheckInterval:t.targetReadyCheckInterval,targetReadyCheckDiagnosticsCommand:t.targetReadyCheckDiagnosticsCommand,autoCommit:t.autoCommit,commitMessage:t.commitMessage,generatedTestsMode:t.generatedTestsMode,postPrComment:t.postPrComment,testExecutionTimeout:t.testExecutionTimeout,maxRecommendations:t.maxRecommendations,maxGenerate:t.maxGenerate,perTestMaxFixAttempts:t.perTestMaxFixAttempts,testbotMaxRetries:t.testbotMaxRetries,testbotRetryDelay:t.testbotRetryDelay,testbotTimeout:t.testbotTimeout,targetSetupRetries:t.targetSetupRetries,targetSetupRetryDelay:t.targetSetupRetryDelay,authTokenRetries:t.authTokenRetries,authTokenRetryDelay:t.authTokenRetryDelay,reportCollapsed:t.reportCollapsed,language:t.language,enableDebug:t.enableDebug,testRepoPath:t.testRepoPath,relatedRepoPaths:t.relatedRepoPaths,services:n};Ks("Resolved configuration");for(let[l,u]of Object.entries(c))l==="authTokenCommand"?te(` ${l}: [REDACTED]`):l==="services"?te(` ${l}: ${JSON.stringify(u)}`):te(` ${l}: ${u}`);return qn(),c}Je();Uc();async function M5e(t,e){let r=LT(e),n=async i=>{try{return await r(i,{silent:!0,ignoreReturnCode:!0})}catch(o){return te(`Self-trigger git read failed (treating as unknown author): ${o instanceof Error?o.message:String(o)}`),{exitCode:1,stdout:"",stderr:""}}},s={skip:!1,botName:Us,botEmail:Fc};return await Dn("Checking for self-triggered execution",async()=>{let i=t.rawPayload,o=i.pull_request?.user;if(t.kind==="code_review"&&o?.login===bd){Re(`Detected Testbot PR opened by ${bd}. Skipping to prevent recursion.`),s={skip:!0,botName:Us,botEmail:Fc};return}let a="",c="",l=i.head_commit;if(l?.author?.name&&(a=l.author.name,c=l.author.email??""),!a){let h=i.pull_request?.head?.sha,f=h||"HEAD";h&&te(`Using pull_request head SHA: ${h}`),a=(await n(["log","-1","--pretty=format:%an",f])).stdout.trim(),c=(await n(["log","-1","--pretty=format:%ae",f])).stdout.trim()}te(`Commit author: ${a}`),te(`Commit email: ${c}`),te(`Expected name: ${Us}`),te(`Expected email: ${Fc}`);let u=a===Us&&c===Fc,d=t.kind==="code_review"&&t.action==="updated",p=u&&d;if(!p&&d){let f=i.pull_request?.head?.sha||"HEAD",A=(await n(["log","-1","--pretty=format:%s",f])).stdout.trim();(/^Merge pull request #\d+ from [^/]+\/skyramp-testbot\/pr-\d+$/.test(A)||a===bd)&&(Re(`Detected merge of testbot test PR into dev PR (commit: "${A}", author: "${a}"). Skipping \u2014 tests already generated.`),p=!0)}p?u&&Re(`Detected self-triggered execution (commit by ${Us} on synchronize event). Skipping to prevent recursion.`):u?Re(`Head commit is by ${Us} but event is '${t.kind}' action='${t.action}' (not code_review/updated). Proceeding normally.`):Re("Not a self-triggered execution. Proceeding with test maintenance."),s={skip:p,botName:Us,botEmail:Fc}}),s}Je();var nJt=6e4,Pse="skipped_pr_closed";function Q5e(t){return t.state==="closed"}async function O5e(t,e){try{return Q5e(await t.getCodeReview(e))}catch(r){return K(`Could not read the state of PR #${e} (${r instanceof Error?r.message:String(r)}) \u2014 proceeding as if it is still open.`),!1}}function L5e(t){let{platform:e,prNumber:r,pollIntervalMs:n=nJt,onAbandoned:s}=t,i=null,o=!1,a=!1;function c(){o=!0,i&&(clearInterval(i),i=null)}async function l(){if(!(o||a)){a=!0;try{let u=await e.getCodeReview(r);if(o)return;Q5e(u)&&(c(),K(`PR #${r} was closed without merging while this run was in progress \u2014 stopping so the shared concurrency lane is released for other PRs.`),s())}catch(u){wt(`PR state poll for #${r} failed (ignored): ${u instanceof Error?u.message:String(u)}`)}finally{a=!1}}}return{start(){o=!1,i=setInterval(()=>{l()},n),i.unref?.()},stop:c}}Je();var XC=$(require("fs"));function VT(t){let e=Math.floor(t/1e3);if(e<60)return`${e}s`;let r=Math.floor(e/60),n=e%60;return`${r}m ${n}s`}function F5e(t=!1){return[{step:"setup",label:he().stepSettingUpEnvironment,status:"pending"},{step:"analyzing",label:t?he().stepAnalyzingUserRequest:he().stepAnalyzingCodeChanges,status:"pending"},{step:"maintaining",label:he().stepRecommendingTests,status:"pending"},{step:"generating",label:he().stepGeneratingTests,status:"pending"},{step:"executing",label:he().stepExecutingTests,status:"pending"},{step:"reporting",label:he().stepGeneratingReport,status:"pending"}]}var jT=null;function U5e(t){jT=t}var kse="";function $5e(t){kse=t}function ZC(){if(jT)return jT;if(kse){let{GitHubPlatform:t}=(zN(),F2(DHe)),{BOT_GITHUB_LOGIN:e}=(Uc(),F2(MHe));return jT=new t(kse,e),jT}throw new Error("No platform available. Call setPlatform() or setGitHubToken() before using progress functions.")}function _se(t,e,r=!1){let s=ZC().getRunUrl();if(e){let o=e.replace(/^\s*<!--\s*skyramp-testbot\s*-->\s*\n?/,""),a=o.includes(s)?[]:["",`<sub>[${he().workflowRunLinkLabel}](${s})</sub>`];return["<!-- skyramp-testbot -->","### Skyramp Testbot","",o,...a].join(`
245
245
  `)}let i=t.map(o=>{if(o.status==="completed"){let a=o.startedAt!=null&&o.completedAt!=null?` (${VT(o.completedAt-o.startedAt)})`:"";return`- [x] ${o.label}${a}`}return o.status==="active"?`- \u23F3 ${o.label}...`:`- [ ] ${o.label}`});return`<!-- skyramp-testbot -->
246
246
  ### Skyramp Testbot
247
247
  ${he().defaultProgressHeadline}
package/dist/post.js CHANGED
@@ -205,7 +205,7 @@ additional repositories analyzed in a multi-repo run).`,devPrMergedBreadcrumb:(t
205
205
  `+g.slice(G,$),G=$+1),q=V;return Y+=`
206
206
  `,g.length-G>v&&q>G?Y+=g.slice(G,q)+`
207
207
  `+g.slice(q+1):Y+=g.slice(G),Y.slice(1)}function fr(g){let v="",D=0;for(let U=0;U<g.length;D>=65536?U+=2:U++){D=wr(g,U);let G=J[D];!G&&br(D)?(v+=g[U],D>=65536&&(v+=g[U+1])):v+=G||ae(D)}return v}function Co(g,v,D){let U="",G=g.tag;for(let $=0,q=D.length;$<q;$+=1){let V=D[$];g.replacer&&(V=g.replacer.call(D,String($),V)),(I(g,v,V,!1,!1)||typeof V>"u"&&I(g,v,null,!1,!1))&&(U!==""&&(U+=","+(g.condenseFlow?"":" ")),U+=g.dump)}g.tag=G,g.dump="["+U+"]"}function Hi(g,v,D,U){let G="",$=g.tag;for(let q=0,V=D.length;q<V;q+=1){let Y=D[q];g.replacer&&(Y=g.replacer.call(D,String(q),Y)),(I(g,v+1,Y,!0,!0,!1,!0)||typeof Y>"u"&&I(g,v+1,null,!0,!0,!1,!0))&&((!U||G!=="")&&(G+=Ln(g,v)),g.dump&&a===g.dump.charCodeAt(0)?G+="-":G+="- ",G+=g.dump)}g.tag=$,g.dump=G||"[]"}function Nc(g,v,D){let U="",G=g.tag,$=Object.keys(D);for(let q=0,V=$.length;q<V;q+=1){let Y="";U!==""&&(Y+=", "),g.condenseFlow&&(Y+='"');let ee=$[q],te=D[ee];g.replacer&&(te=g.replacer.call(D,ee,te)),I(g,v,ee,!1,!1)&&(g.dump.length>1024&&(Y+="? "),Y+=g.dump+(g.condenseFlow?'"':"")+":"+(g.condenseFlow?"":" "),I(g,v,te,!1,!1)&&(Y+=g.dump,U+=Y))}g.tag=G,g.dump="{"+U+"}"}function E(g,v,D,U){let G="",$=g.tag,q=Object.keys(D);if(g.sortKeys===!0)q.sort();else if(typeof g.sortKeys=="function")q.sort(g.sortKeys);else if(g.sortKeys)throw new e("sortKeys must be a boolean or a function");for(let V=0,Y=q.length;V<Y;V+=1){let ee="";(!U||G!=="")&&(ee+=Ln(g,v));let te=q[V],oe=D[te];if(g.replacer&&(oe=g.replacer.call(D,te,oe)),!I(g,v+1,te,!0,!0,!0))continue;let Ee=g.tag!==null&&g.tag!=="?"||g.dump&&g.dump.length>1024;Ee&&(g.dump&&a===g.dump.charCodeAt(0)?ee+="?":ee+="? "),ee+=g.dump,Ee&&(ee+=Ln(g,v)),I(g,v+1,oe,!0,Ee)&&(g.dump&&a===g.dump.charCodeAt(0)?ee+=":":ee+=": ",ee+=g.dump,G+=ee)}g.tag=$,g.dump=G||"{}"}function h(g,v,D){let U=D?g.explicitTypes:g.implicitTypes;for(let G=0,$=U.length;G<$;G+=1){let q=U[G];if((q.instanceOf||q.predicate)&&(!q.instanceOf||typeof v=="object"&&v instanceof q.instanceOf)&&(!q.predicate||q.predicate(v))){if(D?q.multi&&q.representName?g.tag=q.representName(v):g.tag=q.tag:g.tag="?",q.represent){let V=g.styleMap[q.tag]||q.defaultStyle,Y;if(n.call(q.represent)==="[object Function]")Y=q.represent(v,V);else if(i.call(q.represent,V))Y=q.represent[V](v,V);else throw new e("!<"+q.tag+'> tag resolver accepts not "'+V+'" style');g.dump=Y}return!0}}return!1}function I(g,v,D,U,G,$,q){g.tag=null,g.dump=D,h(g,D,!1)||h(g,D,!0);let V=n.call(g.dump),Y=U;U&&(U=g.flowLevel<0||g.flowLevel>v);let ee=V==="[object Object]"||V==="[object Array]",te,oe;if(ee&&(te=g.duplicates.indexOf(D),oe=te!==-1),(g.tag!==null&&g.tag!=="?"||oe||g.indent!==2&&v>0)&&(G=!1),oe&&g.usedDuplicates[te])g.dump="*ref_"+te;else{if(ee&&oe&&!g.usedDuplicates[te]&&(g.usedDuplicates[te]=!0),V==="[object Object]")U&&Object.keys(g.dump).length!==0?(E(g,v,g.dump,G),oe&&(g.dump="&ref_"+te+g.dump)):(Nc(g,v,g.dump),oe&&(g.dump="&ref_"+te+" "+g.dump));else if(V==="[object Array]")U&&g.dump.length!==0?(g.noArrayIndent&&!q&&v>0?Hi(g,v-1,g.dump,G):Hi(g,v,g.dump,G),oe&&(g.dump="&ref_"+te+g.dump)):(Co(g,v,g.dump),oe&&(g.dump="&ref_"+te+" "+g.dump));else if(V==="[object String]")g.tag!=="?"&&Qs(g,g.dump,v,$,Y);else{if(V==="[object Undefined]")return!1;if(g.skipInvalid)return!1;throw new e("unacceptable kind of an object to dump "+V)}if(g.tag!==null&&g.tag!=="?"){let Ee=encodeURI(g.tag[0]==="!"?g.tag.slice(1):g.tag).replace(/!/g,"%21");g.tag[0]==="!"?Ee="!"+Ee:Ee.slice(0,18)==="tag:yaml.org,2002:"?Ee="!!"+Ee.slice(18):Ee="!<"+Ee+">",g.dump=Ee+" "+g.dump}}return!0}function B(g,v){let D=[],U=[];R(g,D,U);let G=U.length;for(let $=0;$<G;$+=1)v.duplicates.push(D[U[$]]);v.usedDuplicates=new Array(G)}function R(g,v,D){if(g!==null&&typeof g=="object"){let U=v.indexOf(g);if(U!==-1)D.indexOf(U)===-1&&D.push(U);else if(v.push(g),Array.isArray(g))for(let G=0,$=g.length;G<$;G+=1)R(g[G],v,D);else{let G=Object.keys(g);for(let $=0,q=G.length;$<q;$+=1)R(g[G[$]],v,D)}}}function N(g,v){v=v||{};let D=new Yr(v);D.noRefs||B(g,D);let U=g;return D.replacer&&(U=D.replacer.call({"":U},"",U)),I(D,0,U,!0,!0)?D.dump+`
208
- `:""}return Nz.dump=N,Nz}var eye;function Pst(){if(eye)return Jn;eye=1;let t=_st(),e=Qst();function r(n,i){return function(){throw new Error("Function yaml."+n+" is removed in js-yaml 4. Use yaml."+i+" instead, which is now safe by default.")}}return Jn.Type=yi(),Jn.Schema=tye(),Jn.FAILSAFE_SCHEMA=sye(),Jn.JSON_SCHEMA=uye(),Jn.CORE_SCHEMA=dye(),Jn.DEFAULT_SCHEMA=_z(),Jn.load=t.load,Jn.loadAll=t.loadAll,Jn.dump=e.dump,Jn.YAMLException=Mw(),Jn.types={binary:hye(),float:lye(),map:iye(),null:oye(),pairs:gye(),set:Aye(),timestamp:pye(),bool:aye(),int:cye(),merge:fye(),omap:mye(),seq:nye(),str:rye()},Jn.safeLoad=r("safeLoad","load"),Jn.safeLoadAll=r("safeLoadAll","loadAll"),Jn.safeDump=r("safeDump","dump"),Jn}var Dst=Pst(),Ost=kst(Dst),{Type:H$t,Schema:z$t,FAILSAFE_SCHEMA:j$t,JSON_SCHEMA:yye,CORE_SCHEMA:V$t,DEFAULT_SCHEMA:W$t,load:pd,loadAll:Y$t,dump:J$t,YAMLException:K$t,types:Z$t,safeLoad:X$t,safeLoadAll:eHt,safeDump:tHt}=Ost;var kl=t=>typeof t=="string"?t:void 0;function bye(t){let e={services:[]},r;try{let c=Eye.readFileSync(t,"utf8");r=pd(c,{schema:yye})}catch(c){return Me(`Lenient parse: failed to read/parse ${t}: ${c.message}`),e}if(!r||typeof r!="object"||Array.isArray(r))return Me(`Lenient parse: ${t} did not contain a YAML object`),e;let n=r,i=n.metadata&&typeof n.metadata=="object"?n.metadata:void 0,s=i?{executorVersion:kl(i.executorVersion),mcpVersion:kl(i.mcpVersion)}:void 0,a=(Array.isArray(n.services)?n.services:[]).reduce((c,l,u)=>{if(!l||typeof l!="object"||Array.isArray(l))return Me(`Lenient parse: services[${u}] is not an object \u2014 skipping`),c;let d=l,p=kl(d.serviceName);if(!p)return Me(`Lenient parse: services[${u}] missing or non-string serviceName \u2014 skipping`),c;let f=d.api&&typeof d.api=="object"?d.api:void 0,A=d.runtimeDetails&&typeof d.runtimeDetails=="object"?d.runtimeDetails:void 0;return c.push({serviceName:p,language:kl(d.language),framework:kl(d.framework),testDirectory:kl(d.testDirectory),api:f?{baseUrl:kl(f.baseUrl)}:void 0,runtimeDetails:A?{serverStartCommand:kl(A.serverStartCommand),serverTeardownCommand:kl(A.serverTeardownCommand)}:void 0}),c},[]);return{metadata:s,services:a}}async function Cye(t){let e=wye.resolve(t.workingDirectory),r=new vT(e),n=[],i=t.targetSetupCommand,s=t.targetTeardownCommand,o=t.skyrampExecutorVersion,a=t.skyrampMcpVersion;if(await r.exists()){Re(`Found ${r.getConfigPath()}, loading workspace configuration...`);try{let l;try{l=await r.read()}catch(d){Me(`${r.getConfigPath()} failed strict validation: ${d.message}. Re-reading with per-field lenient parse \u2014 invalid fields will fall back to action input defaults.`),l=bye(r.getConfigPath())}l.metadata&&(!o&&l.metadata.executorVersion&&(o=l.metadata.executorVersion),!a&&l.metadata.mcpVersion&&(a=l.metadata.mcpVersion));for(let d of l.services??[])n.push({serviceName:d.serviceName,language:d.language,framework:d.framework,baseUrl:d.api?.baseUrl,testDirectory:d.testDirectory});let u=(l.services??[])[0];if(u){!i&&u.runtimeDetails?.serverStartCommand&&(i=u.runtimeDetails.serverStartCommand);let d=u.runtimeDetails?.serverTeardownCommand;!s&&typeof d=="string"&&(s=d)}}catch(l){Me(`Failed to parse ${r.getConfigPath()}: ${l.message} \u2014 falling back to action input defaults`)}}else Do("No .skyramp/workspace.yml found, using action input defaults");o||(o="v1.3.51"),a||(a="latest"),i||(i="docker compose up -d --build");let c={targetSetupCommand:i,authTokenCommand:t.authTokenCommand,targetTeardownCommand:s,skipTargetTeardown:t.skipTargetTeardown,skyrampExecutorVersion:o,skyrampMcpVersion:a,skyrampMcpSource:t.skyrampMcpSource,skyrampMcpGithubRef:t.skyrampMcpGithubRef,nodeVersion:t.nodeVersion,skipTargetSetup:t.skipTargetSetup,targetReadyCheckCommand:t.targetReadyCheckCommand,targetReadyCheckTimeout:t.targetReadyCheckTimeout,targetReadyCheckInterval:t.targetReadyCheckInterval,targetReadyCheckDiagnosticsCommand:t.targetReadyCheckDiagnosticsCommand,autoCommit:t.autoCommit,commitMessage:t.commitMessage,generatedTestsMode:t.generatedTestsMode,postPrComment:t.postPrComment,testExecutionTimeout:t.testExecutionTimeout,maxRecommendations:t.maxRecommendations,maxGenerate:t.maxGenerate,perTestMaxFixAttempts:t.perTestMaxFixAttempts,testbotMaxRetries:t.testbotMaxRetries,testbotRetryDelay:t.testbotRetryDelay,testbotTimeout:t.testbotTimeout,targetSetupRetries:t.targetSetupRetries,targetSetupRetryDelay:t.targetSetupRetryDelay,authTokenRetries:t.authTokenRetries,authTokenRetryDelay:t.authTokenRetryDelay,reportCollapsed:t.reportCollapsed,language:t.language,enableDebug:t.enableDebug,testRepoPath:t.testRepoPath,relatedRepoPaths:t.relatedRepoPaths,services:n};gp("Resolved configuration");for(let[l,u]of Object.entries(c))l==="authTokenCommand"?Re(` ${l}: [REDACTED]`):l==="services"?Re(` ${l}: ${JSON.stringify(u)}`):Re(` ${l}: ${u}`);return Ap(),c}dt();dt();xD();var Sye=j(require("child_process")),TT=class extends Error{constructor(e){super(e),this.name="ExecTimeoutError"}},kT=class extends Error{constructor(e){super(e),this.name="ExecAbortedError"}};function Iye(t,e){if(!(!t||t.destroyed||t.writableEnded))try{t.write(e)}catch(r){Me(`stream write failed: ${r instanceof Error?r.message:String(r)}`)}}async function Fw(t,e=[],r={}){let n="",i="",s={cwd:r.cwd,silent:r.silent??!1,ignoreReturnCode:r.ignoreReturnCode??!1,env:r.env?{...process.env,...r.env}:void 0,input:r.input,listeners:{stdout:a=>{n+=a.toString(),Iye(r.stdoutStream,a)},stderr:a=>{i+=a.toString()}}};if(r.timeout||r.signal){let a=r.signal;return a?.aborted?Promise.reject(new kT(`Command aborted before start: ${t}`)):new Promise((c,l)=>{let u=Sye.spawn(t,e,{cwd:r.cwd,env:r.env?{...process.env,...r.env}:process.env,stdio:["pipe","pipe","pipe"],shell:!1});u.stdout?.on("data",m=>{n+=m.toString(),r.silent||process.stdout.write(m),Iye(r.stdoutStream,m)}),u.stderr?.on("data",m=>{i+=m.toString(),r.silent||process.stderr.write(m)}),r.input&&u.stdin?.end(r.input);let d=()=>{A&&clearTimeout(A),a?.removeEventListener("abort",f)},p=m=>{d();try{u.kill("SIGTERM")}catch{}l(m)},f=()=>p(new kT(`Command aborted: ${t}`)),A=r.timeout?setTimeout(()=>p(new TT(`Command timed out after ${Math.round(r.timeout/6e4)}m: ${t}`)),r.timeout):void 0;a?.addEventListener("abort",f,{once:!0}),u.on("close",m=>{d();let w=m??1;w!==0&&!r.ignoreReturnCode?l(new Error(`The process '${t}' failed with exit code ${w}`)):c({exitCode:w,stdout:n,stderr:i})}),u.on("error",m=>{d(),l(m)})})}return{exitCode:await oK(t,e,s),stdout:n,stderr:i}}async function NT(t,e){gp(t);try{return await e()}finally{Ap()}}function Qz(t){let e=t.split("/");return e.length===2&&e[0]&&e[1]?{owner:e[0],repo:e[1]}:null}async function Bye(t,e){await NT("Tearing down services",async()=>{if(t.skipTargetTeardown){Do("Skipping service teardown (skipTargetTeardown=true)");return}if(!t.targetTeardownCommand){Re("No targetTeardownCommand configured, skipping teardown");return}Re(`Running teardown command: ${t.targetTeardownCommand}`);try{await Fw("bash",["-c",t.targetTeardownCommand],{cwd:e}),Do("Services torn down successfully")}catch(r){let n=r instanceof Error?r.message:String(r);Me(`Service teardown command failed (non-fatal): ${n}`)}})}dt();function Mst(t){let e=Math.floor(t/1e3);if(e<60)return`${e}s`;let r=Math.floor(e/60),n=e%60;return`${r}m ${n}s`}var Fst=null;function Rye(t){Fst=t}function Tye(t,e,r="cancelled"){let n=t.filter(a=>a.status==="completed"),i=t.find(a=>a.status==="active"),s=[];for(let a of n){let c=a.startedAt!=null&&a.completedAt!=null?` (${Mst(a.completedAt-a.startedAt)})`:"";s.push(`- [x] ${a.label}${c}`)}let o=r==="abandoned";if(i){let a=o?Et().abandonedStepSuffix:Et().cancelledStepSuffix;s.push(`- :x: ${i.label} \u2014 ${a}`)}for(let a of t.filter(c=>c.status==="pending"))s.push(`- [ ] ~~${a.label}~~`);return`<!-- skyramp-testbot -->
208
+ `:""}return Nz.dump=N,Nz}var eye;function Pst(){if(eye)return Jn;eye=1;let t=_st(),e=Qst();function r(n,i){return function(){throw new Error("Function yaml."+n+" is removed in js-yaml 4. Use yaml."+i+" instead, which is now safe by default.")}}return Jn.Type=yi(),Jn.Schema=tye(),Jn.FAILSAFE_SCHEMA=sye(),Jn.JSON_SCHEMA=uye(),Jn.CORE_SCHEMA=dye(),Jn.DEFAULT_SCHEMA=_z(),Jn.load=t.load,Jn.loadAll=t.loadAll,Jn.dump=e.dump,Jn.YAMLException=Mw(),Jn.types={binary:hye(),float:lye(),map:iye(),null:oye(),pairs:gye(),set:Aye(),timestamp:pye(),bool:aye(),int:cye(),merge:fye(),omap:mye(),seq:nye(),str:rye()},Jn.safeLoad=r("safeLoad","load"),Jn.safeLoadAll=r("safeLoadAll","loadAll"),Jn.safeDump=r("safeDump","dump"),Jn}var Dst=Pst(),Ost=kst(Dst),{Type:H$t,Schema:z$t,FAILSAFE_SCHEMA:j$t,JSON_SCHEMA:yye,CORE_SCHEMA:V$t,DEFAULT_SCHEMA:W$t,load:pd,loadAll:Y$t,dump:J$t,YAMLException:K$t,types:Z$t,safeLoad:X$t,safeLoadAll:eHt,safeDump:tHt}=Ost;var kl=t=>typeof t=="string"?t:void 0;function bye(t){let e={services:[]},r;try{let c=Eye.readFileSync(t,"utf8");r=pd(c,{schema:yye})}catch(c){return Me(`Lenient parse: failed to read/parse ${t}: ${c.message}`),e}if(!r||typeof r!="object"||Array.isArray(r))return Me(`Lenient parse: ${t} did not contain a YAML object`),e;let n=r,i=n.metadata&&typeof n.metadata=="object"?n.metadata:void 0,s=i?{executorVersion:kl(i.executorVersion),mcpVersion:kl(i.mcpVersion)}:void 0,a=(Array.isArray(n.services)?n.services:[]).reduce((c,l,u)=>{if(!l||typeof l!="object"||Array.isArray(l))return Me(`Lenient parse: services[${u}] is not an object \u2014 skipping`),c;let d=l,p=kl(d.serviceName);if(!p)return Me(`Lenient parse: services[${u}] missing or non-string serviceName \u2014 skipping`),c;let f=d.api&&typeof d.api=="object"?d.api:void 0,A=d.runtimeDetails&&typeof d.runtimeDetails=="object"?d.runtimeDetails:void 0;return c.push({serviceName:p,language:kl(d.language),framework:kl(d.framework),testDirectory:kl(d.testDirectory),api:f?{baseUrl:kl(f.baseUrl)}:void 0,runtimeDetails:A?{serverStartCommand:kl(A.serverStartCommand),serverTeardownCommand:kl(A.serverTeardownCommand)}:void 0}),c},[]);return{metadata:s,services:a}}async function Cye(t){let e=wye.resolve(t.workingDirectory),r=new vT(e),n=[],i=t.targetSetupCommand,s=t.targetTeardownCommand,o=t.skyrampExecutorVersion,a=t.skyrampMcpVersion;if(await r.exists()){Re(`Found ${r.getConfigPath()}, loading workspace configuration...`);try{let l;try{l=await r.read()}catch(d){Me(`${r.getConfigPath()} failed strict validation: ${d.message}. Re-reading with per-field lenient parse \u2014 invalid fields will fall back to action input defaults.`),l=bye(r.getConfigPath())}l.metadata&&(!o&&l.metadata.executorVersion&&(o=l.metadata.executorVersion),!a&&l.metadata.mcpVersion&&(a=l.metadata.mcpVersion));for(let d of l.services??[])n.push({serviceName:d.serviceName,language:d.language,framework:d.framework,baseUrl:d.api?.baseUrl,testDirectory:d.testDirectory});let u=(l.services??[])[0];if(u){!i&&u.runtimeDetails?.serverStartCommand&&(i=u.runtimeDetails.serverStartCommand);let d=u.runtimeDetails?.serverTeardownCommand;!s&&typeof d=="string"&&(s=d)}}catch(l){Me(`Failed to parse ${r.getConfigPath()}: ${l.message} \u2014 falling back to action input defaults`)}}else Do("No .skyramp/workspace.yml found, using action input defaults");o||(o="v1.3.52"),a||(a="latest"),i||(i="docker compose up -d --build");let c={targetSetupCommand:i,authTokenCommand:t.authTokenCommand,targetTeardownCommand:s,skipTargetTeardown:t.skipTargetTeardown,skyrampExecutorVersion:o,skyrampMcpVersion:a,skyrampMcpSource:t.skyrampMcpSource,skyrampMcpGithubRef:t.skyrampMcpGithubRef,nodeVersion:t.nodeVersion,skipTargetSetup:t.skipTargetSetup,targetReadyCheckCommand:t.targetReadyCheckCommand,targetReadyCheckTimeout:t.targetReadyCheckTimeout,targetReadyCheckInterval:t.targetReadyCheckInterval,targetReadyCheckDiagnosticsCommand:t.targetReadyCheckDiagnosticsCommand,autoCommit:t.autoCommit,commitMessage:t.commitMessage,generatedTestsMode:t.generatedTestsMode,postPrComment:t.postPrComment,testExecutionTimeout:t.testExecutionTimeout,maxRecommendations:t.maxRecommendations,maxGenerate:t.maxGenerate,perTestMaxFixAttempts:t.perTestMaxFixAttempts,testbotMaxRetries:t.testbotMaxRetries,testbotRetryDelay:t.testbotRetryDelay,testbotTimeout:t.testbotTimeout,targetSetupRetries:t.targetSetupRetries,targetSetupRetryDelay:t.targetSetupRetryDelay,authTokenRetries:t.authTokenRetries,authTokenRetryDelay:t.authTokenRetryDelay,reportCollapsed:t.reportCollapsed,language:t.language,enableDebug:t.enableDebug,testRepoPath:t.testRepoPath,relatedRepoPaths:t.relatedRepoPaths,services:n};gp("Resolved configuration");for(let[l,u]of Object.entries(c))l==="authTokenCommand"?Re(` ${l}: [REDACTED]`):l==="services"?Re(` ${l}: ${JSON.stringify(u)}`):Re(` ${l}: ${u}`);return Ap(),c}dt();dt();xD();var Sye=j(require("child_process")),TT=class extends Error{constructor(e){super(e),this.name="ExecTimeoutError"}},kT=class extends Error{constructor(e){super(e),this.name="ExecAbortedError"}};function Iye(t,e){if(!(!t||t.destroyed||t.writableEnded))try{t.write(e)}catch(r){Me(`stream write failed: ${r instanceof Error?r.message:String(r)}`)}}async function Fw(t,e=[],r={}){let n="",i="",s={cwd:r.cwd,silent:r.silent??!1,ignoreReturnCode:r.ignoreReturnCode??!1,env:r.env?{...process.env,...r.env}:void 0,input:r.input,listeners:{stdout:a=>{n+=a.toString(),Iye(r.stdoutStream,a)},stderr:a=>{i+=a.toString()}}};if(r.timeout||r.signal){let a=r.signal;return a?.aborted?Promise.reject(new kT(`Command aborted before start: ${t}`)):new Promise((c,l)=>{let u=Sye.spawn(t,e,{cwd:r.cwd,env:r.env?{...process.env,...r.env}:process.env,stdio:["pipe","pipe","pipe"],shell:!1});u.stdout?.on("data",m=>{n+=m.toString(),r.silent||process.stdout.write(m),Iye(r.stdoutStream,m)}),u.stderr?.on("data",m=>{i+=m.toString(),r.silent||process.stderr.write(m)}),r.input&&u.stdin?.end(r.input);let d=()=>{A&&clearTimeout(A),a?.removeEventListener("abort",f)},p=m=>{d();try{u.kill("SIGTERM")}catch{}l(m)},f=()=>p(new kT(`Command aborted: ${t}`)),A=r.timeout?setTimeout(()=>p(new TT(`Command timed out after ${Math.round(r.timeout/6e4)}m: ${t}`)),r.timeout):void 0;a?.addEventListener("abort",f,{once:!0}),u.on("close",m=>{d();let w=m??1;w!==0&&!r.ignoreReturnCode?l(new Error(`The process '${t}' failed with exit code ${w}`)):c({exitCode:w,stdout:n,stderr:i})}),u.on("error",m=>{d(),l(m)})})}return{exitCode:await oK(t,e,s),stdout:n,stderr:i}}async function NT(t,e){gp(t);try{return await e()}finally{Ap()}}function Qz(t){let e=t.split("/");return e.length===2&&e[0]&&e[1]?{owner:e[0],repo:e[1]}:null}async function Bye(t,e){await NT("Tearing down services",async()=>{if(t.skipTargetTeardown){Do("Skipping service teardown (skipTargetTeardown=true)");return}if(!t.targetTeardownCommand){Re("No targetTeardownCommand configured, skipping teardown");return}Re(`Running teardown command: ${t.targetTeardownCommand}`);try{await Fw("bash",["-c",t.targetTeardownCommand],{cwd:e}),Do("Services torn down successfully")}catch(r){let n=r instanceof Error?r.message:String(r);Me(`Service teardown command failed (non-fatal): ${n}`)}})}dt();function Mst(t){let e=Math.floor(t/1e3);if(e<60)return`${e}s`;let r=Math.floor(e/60),n=e%60;return`${r}m ${n}s`}var Fst=null;function Rye(t){Fst=t}function Tye(t,e,r="cancelled"){let n=t.filter(a=>a.status==="completed"),i=t.find(a=>a.status==="active"),s=[];for(let a of n){let c=a.startedAt!=null&&a.completedAt!=null?` (${Mst(a.completedAt-a.startedAt)})`:"";s.push(`- [x] ${a.label}${c}`)}let o=r==="abandoned";if(i){let a=o?Et().abandonedStepSuffix:Et().cancelledStepSuffix;s.push(`- :x: ${i.label} \u2014 ${a}`)}for(let a of t.filter(c=>c.status==="pending"))s.push(`- [ ] ~~${a.label}~~`);return`<!-- skyramp-testbot -->
209
209
  ${o?Et().abandonedHeader:Et().cancelledHeader}
210
210
  ${o?Et().abandonedBody:Et().cancelledBody}
211
211
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyramp/testbot-core",
3
- "version": "0.13.0-v3.62",
3
+ "version": "0.13.0-v3.63",
4
4
  "description": "Skyramp Testbot engine: AI-powered deterministic test generation, execution and maintenance",
5
5
  "main": "dist/main.js",
6
6
  "//files": "An explicit allowlist, never a glob. `dist/` is gitignored, so without this key npm's .gitignore fallback would publish a package with no engine in it; with a glob it would publish the sourcemaps, whose sourcesContent embeds every src/*.ts verbatim. eval-entry.js is a development entry and must not ship. dist/VERSION.json exists only in a release-engine.yml build. assets/gen-reference/ is the staged codegen reference corpus, which generate.ts finds at ../assets from dist/.",