@leveragent/e2e-testing 0.1.7 → 0.1.8
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.
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import{CopilotClient as qt}from"@github/copilot-sdk";import*as wt from"readline";import{approveAll as kt}from"@github/copilot-sdk";import{readFile as Ot}from"fs/promises";var Q=(t,e)=>t===void 0?e:/^(1|true|yes|on)$/i.test(t.trim()),Z=t=>{let e=(t??"high").trim().toLowerCase();switch(e){case"low":case"medium":case"high":case"xhigh":return e;default:return"high"}},tt=async(t,e={})=>{let{trim:s=!0,onError:n}=e;try{let o=await Ot(t,"utf8");return(s?o.trim():o)||""}catch(o){return n?.(o),""}},I=t=>typeof t=="number"&&Number.isFinite(t)?t:0,et=t=>new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",minimumFractionDigits:4,maximumFractionDigits:6}).format(t);var Rt="",j="basic",st=`You are a senior frontend engineer, specialized on E2E testing in a local CLI. Be concise but highly useful.
|
|
3
3
|
Prefer concrete steps, ask clarifying questions only when necessary, and use tools when needed.
|
|
4
|
-
If a tool returns uncertain data, state assumptions clearly. ${Rt}`,ot=1e9,N=Number(process.env.COPILOT_USD_PER_AIU??"0");var Ct="gpt-5.3-codex";var M=1e6,D="\x1B[0m",$="\x1B[38;5;110m",v=1e4,nt=1e6,rt=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".go",".py",".java",".rb",".rs",".php",".swift",".kt",".kts",".cs",".c",".h",".hpp",".cpp",".cc"]);var It="0.1.
|
|
4
|
+
If a tool returns uncertain data, state assumptions clearly. ${Rt}`,ot=1e9,N=Number(process.env.COPILOT_USD_PER_AIU??"0");var Ct="gpt-5.3-codex";var M=1e6,D="\x1B[0m",$="\x1B[38;5;110m",v=1e4,nt=1e6,rt=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".go",".py",".java",".rb",".rs",".php",".swift",".kt",".kts",".cs",".c",".h",".hpp",".cpp",".cc"]);var It="0.1.8",it=It||process.env.npm_package_version||"unknown";var k=process.env.COPILOT_MODEL??Ct,G=Z(process.env.COPILOT_REASONING_EFFORT),at=Q(process.env.COPILOT_RESUME_LAST,!0),q=process.env.COPILOT_SDK_AUTH_TOKEN??process.env.GITHUB_TOKEN??process.env.GH_TOKEN;var Lt="\x1B[0m",Pt="\x1B[38;5;245m",B=t=>`${Pt}${t}${Lt}`,Ut=t=>{if(t===void 0)return"{}";try{return JSON.stringify(t,null,2)}catch{return"[unserializable arguments]"}},Ft=(t,e,s)=>{if(s){if(t&&typeof t=="object"){let n=t;if(typeof n.detailedContent=="string")return n.detailedContent;if(typeof n.content=="string")return n.content}return"[no response content]"}if(e&&typeof e=="object"){let n=e;if(typeof n.message=="string")return n.message}return"[tool failed without error details]"},ct=(t,e)=>{if(t.waitingForAssistantOutput){if(t.waitingForAssistantOutput=!1,t.waitingForToolResult){e.start("Tool");return}e.stop(!0)}},lt=(t,e)=>{let{uiState:s,spinner:n}=e,o=[];return o.push(t.on("assistant.message_delta",r=>{ct(s,n),process.stdout.write(r.data.deltaContent)})),o.push(t.on("assistant.message",()=>{ct(s,n)})),o.push(t.on("session.idle",()=>{s.waitingForToolResult=!1,s.waitingForAssistantOutput&&(s.waitingForAssistantOutput=!1,n.stop(!1)),process.stdout.write(`
|
|
5
5
|
`)})),o.push(t.on("session.error",r=>{s.waitingForToolResult=!1,s.waitingForAssistantOutput&&(s.waitingForAssistantOutput=!1,n.stop(!1)),console.error(`
|
|
6
|
-
[session error]`,r.data)})),o.push(t.on("tool.execution_start",r=>{let
|
|
7
|
-
[tool] ${
|
|
8
|
-
`)),process.stdout.write(B(`[tool args] ${
|
|
9
|
-
`)),n.start(`Tool: ${
|
|
6
|
+
[session error]`,r.data)})),o.push(t.on("tool.execution_start",r=>{let _=r.data.toolName??"unknown_tool",w=Ut(r.data.arguments);s.waitingForToolResult=!0,n.stop(!1),process.stdout.write(B(`
|
|
7
|
+
[tool] ${_}
|
|
8
|
+
`)),process.stdout.write(B(`[tool args] ${w}
|
|
9
|
+
`)),n.start(`Tool: ${_}`)})),o.push(t.on("tool.execution_complete",r=>{s.waitingForToolResult=!1;let _=Ft(r.data.result,r.data.error,r.data.success),w=r.data.success?"[tool response]":"[tool error]";if(process.stdout.write(B(`${w} ${_}
|
|
10
10
|
`)),s.waitingForAssistantOutput){n.start("Assistant");return}n.stop(!1)})),o.push(t.on("assistant.usage",r=>{e.usageTotals.events+=1,e.usageTotals.inputTokens+=I(r.data.inputTokens),e.usageTotals.outputTokens+=I(r.data.outputTokens),e.usageTotals.cacheReadTokens+=I(r.data.cacheReadTokens),e.usageTotals.cacheWriteTokens+=I(r.data.cacheWriteTokens),e.usageTotals.totalNanoAiu+=I(r.data.copilotUsage?.totalNanoAiu)})),o};var Nt=async(t,e)=>new Promise(s=>{t.rl.question(`${$}${e}`,n=>{process.stdout.write(D),s(n)})}),X=(t,e)=>{t.detachSessionHandlers.forEach(s=>s()),t.detachSessionHandlers=lt(e,t)},ut=t=>({model:k,reasoningEffort:G,streaming:!0,tools:t.tools,onPermissionRequest:kt,onUserInputRequest:async e=>{process.stdout.write(`
|
|
11
11
|
Agent asks: ${e.question}
|
|
12
12
|
`),e.choices&&e.choices.length>0&&process.stdout.write(`Choices: ${e.choices.join(" | ")}
|
|
13
13
|
`);let s=await Nt(t,"You (for agent): ");return{answer:s,wasFreeform:!e.choices?.includes(s)}},workingDirectory:process.cwd(),infiniteSessions:{enabled:!0,backgroundCompactionThreshold:.8,bufferExhaustionThreshold:.95},systemMessage:{content:st}}),pt=async t=>{let e=ut(t);if(at){let n=await t.client.getLastSessionId();if(n)try{let o=await t.client.resumeSession(n,e);return X(t,o),process.stdout.write(`[session] Resumed ${o.sessionId}
|
|
14
14
|
`),o}catch(o){console.error("[session] Resume failed, creating a new session:",o)}}let s=await t.client.createSession(e);return X(t,s),process.stdout.write(`[session] Started ${s.sessionId}
|
|
15
15
|
`),s},dt=async t=>{let e=ut(t),s=t.requireSession(),n=s.sessionId;await s.disconnect();let o=await t.client.createSession(e);return X(t,o),process.stdout.write(`[session] Switched from ${n} to ${o.sessionId}
|
|
16
|
-
`),o};var mt=["|","/","-","\\"],ft=t=>{let e=null,s=0,n="Assistant"
|
|
16
|
+
`),o};var mt=["|","/","-","\\"],ft=t=>{let e=null,s=0,n="Assistant",o=()=>{let w=mt[s%mt.length];s+=1,process.stdout.write(`\r${n}: ${w}`)};return{start:w=>{n=w,t()&&(e||(o(),e=setInterval(()=>{o()},90)))},stop:(w=!1)=>{e&&(clearInterval(e),e=null),s=0,process.stdout.write("\r\x1B[K"),w&&process.stdout.write(`${n}: `)}}};import{spawn as Mt}from"child_process";import{promises as E}from"fs";import*as u from"path";var Dt=t=>t.split(u.sep).join("/"),ht=async t=>{let e=await E.realpath(t),s=a=>{let i=u.relative(e,a);return i.length===0?".":i},n=a=>{let i=u.relative(e,a);if(i.startsWith("..")||u.isAbsolute(i))throw new Error(`Path is outside the working directory: ${a}`)},o=a=>{let i=a.trim();if(!i)throw new Error("Path must be a non-empty string.");let l=u.resolve(e,i);return n(l),l},r=async a=>{let i=o(a),l=await E.realpath(i);return n(l),l},_=async a=>{let i=await r(a),l=await E.stat(i);if(!l.isFile())throw new Error(`Path is not a regular file: ${s(i)}`);return{absolutePath:i,stats:l}},w=async a=>{let i=o(a),l=u.dirname(i);await E.mkdir(l,{recursive:!0});let h=await E.realpath(l);return n(h),i},bt=async({command:a,args:i,commandCwd:l,timeoutMs:h,maxOutputBytes:S})=>new Promise((R,g)=>{let d=Mt(a,i,{cwd:l,shell:!1,env:{...process.env,GIT_PAGER:"cat"}}),b="",T="",A=!1,y=!1,m=!1,p,O=(c,f,L)=>{if(c.length>=L)return{text:c,truncated:!0};let P=L-c.length;return f.length<=P?{text:c+f,truncated:!1}:{text:c+f.slice(0,P),truncated:!0}};d.stdout&&d.stdout.on("data",c=>{let f=O(b,c.toString(),S);b=f.text,f.truncated&&(A=!0)}),d.stderr&&d.stderr.on("data",c=>{let f=O(T,c.toString(),S);T=f.text,f.truncated&&(y=!0)}),d.on("error",c=>{p&&clearTimeout(p),g(c)}),p=setTimeout(()=>{m=!0,d.pid&&(process.kill(d.pid,"SIGTERM"),setTimeout(()=>{d.pid&&process.kill(d.pid,"SIGKILL")},1e3))},h),d.on("close",(c,f)=>{p&&clearTimeout(p),R({exitCode:c,signal:f,stdout:b,stderr:T,stdoutTruncated:A,stderrTruncated:y,timedOut:m})})}),Y=async({rootDirectory:a,maxEntries:i,includeHidden:l,maxDepth:h,includeDirectories:S,includeFiles:R})=>{let g=[],d=!1,b=async(T,A)=>{if(g.length>=i||g.length>=v){d=!0;return}let y=await E.readdir(T,{withFileTypes:!0});y.sort((m,p)=>m.name.localeCompare(p.name));for(let m of y){if(g.length>=i||g.length>=v){d=!0;return}if(!l&&m.name.startsWith("."))continue;let p=u.join(T,m.name),O=s(p);if(m.isDirectory()){S&&g.push({path:O,type:"directory"}),A<h&&await b(p,A+1);continue}if(m.isFile()){if(R){let c=await E.stat(p);g.push({path:O,type:"file",sizeBytes:c.size})}continue}if(m.isSymbolicLink()){let c=await E.realpath(p);n(c),(R||S)&&g.push({path:O,type:"symlink",target:s(c)})}}};return await b(a,0),{entries:g,truncated:d}},yt=async a=>{let i=await r(a),l=await E.stat(i);if(l.isFile())return{files:[i],truncated:!1};if(l.isDirectory()){let h=await Y({rootDirectory:i,maxEntries:v,includeHidden:!1,maxDepth:100,includeDirectories:!1,includeFiles:!0});return{files:h.entries.map(S=>u.resolve(e,S.path)),truncated:h.truncated}}throw new Error(`Path is neither a file nor a directory: ${a}`)};return{workspaceRoot:e,toWorkspacePath:s,resolveExistingPath:r,resolveReadableFile:_,resolveWritableFile:w,executeCommand:bt,walkDirectory:Y,collectTextMatches:async({query:a,searchPath:i,maxResults:l,caseSensitive:h,useRegex:S,globPattern:R,requireCodeFiles:g})=>{let{files:d,truncated:b}=await yt(i),T=[],A=S?new RegExp(a,h?"g":"gi"):void 0,y=h?a:a.toLowerCase(),m=!1;for(let p of d){if(m)break;let O=u.extname(p).toLowerCase();if(g&&!rt.has(O))continue;let c=s(p);if(!u.matchesGlob(Dt(c),R))continue;let f=await E.stat(p);if(!f.isFile()||f.size>nt)continue;let L=await E.readFile(p,"utf8");if(L.includes("\0"))continue;let P=L.split(/\r?\n/u);for(let U=0;U<P.length&&!m;U+=1){let C=P[U];if(C.length===0)continue;if(A){A.lastIndex=0;for(let F of C.matchAll(A)){let V=F.index;if(V!==void 0&&(T.push({path:c,line:U+1,column:V+1,preview:C}),T.length>=l)){m=!0;break}}continue}let J=h?C:C.toLowerCase(),W=0;for(;W<J.length;){let F=J.indexOf(y,W);if(F===-1)break;if(T.push({path:c,line:U+1,column:F+1,preview:C}),T.length>=l){m=!0;break}W=F+Math.max(y.length,1)}}}return{matches:T,truncated:b||m}}}};var gt=async t=>{let e=await ht(t);return{tools:[]}};var Tt=t=>{let e=t.usageTotals.inputTokens+t.usageTotals.outputTokens+t.usageTotals.cacheReadTokens+t.usageTotals.cacheWriteTokens,s=t.usageTotals.totalNanoAiu/ot,n=s*N;j!=="none"&&(process.stdout.write(`
|
|
17
17
|
Session usage summary:
|
|
18
18
|
`),process.stdout.write(` Input tokens: ${t.usageTotals.inputTokens}
|
|
19
19
|
`),process.stdout.write(` Output tokens: ${t.usageTotals.outputTokens}
|
|
@@ -31,14 +31,14 @@ System Commands:`),console.log(" /help Show commands"),console.log("
|
|
|
31
31
|
`),console.log("----------------------------------------------------------------"),console.log(`
|
|
32
32
|
Test Generation Commands:`),console.log(" /init Init E2E tests from zero"),console.log(" /custom-tests Add custom E2E test based on your input"),console.log(" /diff-test Add E2E test based on code diff")},xt=()=>{console.log(`
|
|
33
33
|
|
|
34
|
-
Welcome to LeverAgent, your E2E testing assistant!`),console.log(`You're currently using version: ${it} with the following model: ${k}`),console.log("Type your message and press Enter. Use 'exit', 'quit', or 'q' to quit."),At()},Et=async t=>{let e=Gt(new URL(`../prompts/${t}`,import.meta.url));return await tt(e,{onError:n=>{console.error(`[prompt] could not read ${e}; continuing without startup prompt`,n)}})},_t=async t=>{try{let e=await fetch(t);return e.ok?await e.text():(console.error(`[prompt] could not fetch ${t}; HTTP ${e.status} ${e.statusText}`),"")}catch(e){return console.error(`[prompt] could not fetch ${t}`,e),""}},
|
|
34
|
+
Welcome to LeverAgent, your E2E testing assistant!`),console.log(`You're currently using version: ${it} with the following model: ${k}`),console.log("Type your message and press Enter. Use 'exit', 'quit', or 'q' to quit."),At()},Et=async t=>{let e=Gt(new URL(`../prompts/${t}`,import.meta.url));return await tt(e,{onError:n=>{console.error(`[prompt] could not read ${e}; continuing without startup prompt`,n)}})},_t=async t=>{try{let e=await fetch(t);return e.ok?await e.text():(console.error(`[prompt] could not fetch ${t}; HTTP ${e.status} ${e.statusText}`),"")}catch(e){return console.error(`[prompt] could not fetch ${t}`,e),""}},x=t=>{if(!(t.isShuttingDown||t.isInputClosed)){if(process.stdin.readableEnded||process.stdin.destroyed){t.isInputClosed=!0,t.cleanupAndExit();return}try{t.rl.question(`${$}You: `,async e=>{if(process.stdout.write(D),t.isShuttingDown||t.isInputClosed)return;let s=e.trim().toLowerCase();if(s==="exit"||s==="quit"||s==="q"){await t.cleanupAndExit();return}if(s==="/help"){At(),x(t);return}if(s==="/new"){try{t.setSession(await dt(t))}catch(o){console.error("[request failed] could not start a new session",o)}x(t);return}if(s==="/status"){try{let o=await t.client.getAuthStatus(),r=t.requireSession();console.log(`
|
|
35
35
|
Status`),console.log(` Session: ${r.sessionId}`),console.log(` Model: ${k}`),console.log(` Reasoning: ${G}`),console.log(` Request timeout: ${M}ms`),console.log(` Authenticated: ${o.isAuthenticated}`),o.login&&console.log(` Login: ${o.login}`)}catch(o){console.error("[request failed] could not read status",o)}process.stdout.write(`
|
|
36
|
-
`),
|
|
37
|
-
Available models (first 20):`),r.forEach(
|
|
38
|
-
`),
|
|
36
|
+
`),x(t);return}if(s==="/models"){try{let r=(await t.client.listModels()).slice(0,20);console.log(`
|
|
37
|
+
Available models (first 20):`),r.forEach(_=>{console.log(` - ${_.id}`)})}catch(o){console.error("[request failed] could not list models",o)}process.stdout.write(`
|
|
38
|
+
`),x(t);return}if(!e.trim()){x(t);return}let n=e;if(s==="/init")n=await Et("init.md");else if(s.startsWith("/custom-tests")){let o=e.slice(13).trim();n=await _t("https://gist.githubusercontent.com/marcellkiss/029ff544f3ed720971e47b8306e8853c/raw/ff7d36b86193a9e314cb2935968c9ccc0e3bd9ef/custom-test.md"),n+=`
|
|
39
39
|
|
|
40
40
|
<<USER_INPUT>>
|
|
41
|
-
${o}`}else s==="/diff-test"?n=await _t("https://gist.githubusercontent.com/marcellkiss/fbe9294d4de00c2ef11f1437919353b7/raw/16a8ae53a9019386ef5fea5d321934d5bec70188/diff-test.md"):s==="/t"&&(n=await Et("test.md"));if(!n.trim()){console.error("[prompt] loaded prompt is empty; request was not sent"),
|
|
41
|
+
${o}`}else s==="/diff-test"?n=await _t("https://gist.githubusercontent.com/marcellkiss/fbe9294d4de00c2ef11f1437919353b7/raw/16a8ae53a9019386ef5fea5d321934d5bec70188/diff-test.md"):s==="/t"&&(n=await Et("test.md"));if(!n.trim()){console.error("[prompt] loaded prompt is empty; request was not sent"),x(t);return}process.stdout.write("Assistant: "),t.uiState.waitingForAssistantOutput=!0,t.spinner.start("Assistant");try{await t.requireSession().sendAndWait({prompt:n},M)}catch(o){t.uiState.waitingForAssistantOutput=!1,t.spinner.stop(!1),o instanceof Error&&o.message.includes("Timeout after")?console.error(`
|
|
42
42
|
[request failed] ${o.message}. Increase COPILOT_REQUEST_TIMEOUT_MS (current: ${M}ms).`):console.error(`
|
|
43
43
|
[request failed]`,o)}process.stdout.write(`
|
|
44
|
-
`),!t.isShuttingDown&&!t.isInputClosed&&
|
|
44
|
+
`),!t.isShuttingDown&&!t.isInputClosed&&x(t)})}catch(e){if(e&&typeof e=="object"&&"code"in e&&e.code==="ERR_USE_AFTER_CLOSE"){t.isInputClosed=!0,t.cleanupAndExit();return}throw e}}};var K=new qt({githubToken:q,useLoggedInUser:!0,autoRestart:!1});await K.start();await St(K);var z=new H(K);await z.init();xt();x(z);z.listenToShutdownSignals();
|
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{existsSync as n}from"fs";import{copyFile as c}from"fs/promises";import{createRequire as a}from"module";import{dirname as p,join as s}from"path";var m=async()=>{let i=a(import.meta.url).resolve("vscode-jsonrpc/package.json"),r=p(i),e=s(r,"node"),t=s(r,"node.js");n(e)||!n(t)||await c(t,e)};try{await m()}catch(o){console.error("[bootstrap warning] could not prepare vscode-jsonrpc compatibility shim",o)}await import("./agentRunner-
|
|
2
|
+
import{existsSync as n}from"fs";import{copyFile as c}from"fs/promises";import{createRequire as a}from"module";import{dirname as p,join as s}from"path";var m=async()=>{let i=a(import.meta.url).resolve("vscode-jsonrpc/package.json"),r=p(i),e=s(r,"node"),t=s(r,"node.js");n(e)||!n(t)||await c(t,e)};try{await m()}catch(o){console.error("[bootstrap warning] could not prepare vscode-jsonrpc compatibility shim",o)}await import("./agentRunner-6GC3KHLQ.js");
|