@sreetej510/pi-shipd-checks 0.9.12 → 0.9.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,9 +34,9 @@ The agent-callable `quality-check` tool runs `create_patches.sh` in the current
|
|
|
34
34
|
`agent_prompt.md`, `test.patch`, and `solution.patch`, first runs a Fargate patch precheck against a clean `HEAD`, then
|
|
35
35
|
fills the authenticated Shipd draft fields, runs fresh checks with a `Run` button, reruns checks marked `Stale`, skips
|
|
36
36
|
current checks, starts Test Quality before Solution Quality in one browser tab, waits for any started jobs, and returns only the useful report data:
|
|
37
|
-
`details.testQuality.coverageSuggestions`, `details.testQuality.tests` filtered to
|
|
38
|
-
|
|
39
|
-
shows live elapsed time, and only displays
|
|
37
|
+
`details.testQuality.coverageSuggestions`, `details.testQuality.tests` filtered to test blocks whose `concerns` array is
|
|
38
|
+
non-empty, and the complete `details.solutionQuality.evaluation` block. Its compact UI is labeled `Quality Checks`,
|
|
39
|
+
shows live elapsed time, and only displays test-concern count, suggestion count, code-quality score, and
|
|
40
40
|
comprehensiveness score. It takes no parameters. It uses one fresh headless browser tab at a time: it closes the
|
|
41
41
|
browser after starting the needed jobs, checks after 5 minutes, then reopens every 90 seconds until those jobs finish, with no
|
|
42
42
|
client-side overall timeout. If
|
package/dist/index.js
CHANGED
|
@@ -107,13 +107,13 @@ ${t instanceof Error?t.message:String(t)}`)}}function wxo(e,t,s){let a=e.fargate
|
|
|
107
107
|
Required behavior: ${s.requiredBehavior}
|
|
108
108
|
Recommendation: ${s.recommendation}`)].join(`
|
|
109
109
|
`)}import{spawn as mPo}from"node:child_process";import{randomUUID as fPo}from"node:crypto";import{existsSync as VAe,mkdirSync as gPo}from"node:fs";import{mkdtemp as hEn,readFile as LAe,rm as MAe,writeFile as vEn}from"node:fs/promises";import{createServer as RPo}from"node:net";import{homedir as SPo,tmpdir as CEn}from"node:os";import{dirname as yPo,join as ol}from"node:path";import{Text as mL}from"@earendil-works/pi-tui";import{chromium as wEn}from"playwright-core";var Yee="quality-check",GAe="shipd:link",OAe="shipd_job_link",TEn=ol(SPo(),".pi","agent","shipd-auth","shipd.ai.json"),IPo=15,AEn="https://shipd.ai/",_Po=12e4,hPo=3e5,vPo=9e4,Jy=5e3,NAe=["Test Quality","Solution Quality"],CPo=Ct.Object({});function fL(e){return(e??"").trim().replace(/\s+/g," ")}function TPo(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function km(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function gL(e,t){return new Promise((s,a)=>{if(t?.aborted){a(new Error("Cancelled by user."));return}let c=()=>{clearTimeout(l),t?.removeEventListener("abort",c),a(new Error("Cancelled by user."))},l=setTimeout(()=>{t?.removeEventListener("abort",c),s()},e);t?.addEventListener("abort",c,{once:!0})})}function $i(e){if(e?.aborted)throw new Error("Cancelled by user.")}function DEn(){return[process.env.SHIPD_CHROME_PATH,process.env.PROGRAMFILES&&ol(process.env.PROGRAMFILES,"Google","Chrome","Application","chrome.exe"),process.env["PROGRAMFILES(X86)"]&&ol(process.env["PROGRAMFILES(X86)"],"Google","Chrome","Application","chrome.exe"),process.env.LOCALAPPDATA&&ol(process.env.LOCALAPPDATA,"Google","Chrome","Application","chrome.exe"),"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome","/usr/bin/google-chrome","/usr/bin/chromium","/usr/bin/chromium-browser"].filter(t=>!!t).find(t=>VAe(t))}function APo(){let e=RPo();return new Promise((t,s)=>{e.once("error",s),e.listen(0,"127.0.0.1",()=>{let a=e.address();if(!a||typeof a=="string"){e.close(),s(new Error("Could not allocate a local Chrome debugging port."));return}e.close(c=>c?s(c):t(a.port))})})}async function DPo(e,t,s=15e3){let a=Date.now()+s;for(;Date.now()<a;){if(t.exitCode!==null)throw new Error("Chrome exited before its debugging connection became available.");try{if((await fetch(`http://127.0.0.1:${e}/json/version`)).ok)return}catch{}await gL(250)}throw new Error("Timed out waiting for Chrome to start.")}async function bPo(e,t=3e4){let s=Date.now()+t;for(;Date.now()<s;){let a=e.pages();for(let c of a){if(!kC(c.url()))continue;if(await c.locator('button[aria-label="Open user menu"]').isVisible({timeout:1e3}).catch(()=>!1))return c}for(let c of a)kC(c.url())&&await c.reload({waitUntil:"domcontentloaded",timeout:15e3}).catch(()=>{});await gL(1e3)}}function kC(e){try{let t=new URL(e),s=t.hostname.toLowerCase();return t.protocol==="https:"&&(s==="shipd.ai"||s.endsWith(".shipd.ai"))}catch{return!1}}function EPo(e){let t;for(let s of e){if(!km(s)||s.type!=="custom"||s.customType!==OAe)continue;let a=s.data;km(a)&&(typeof a.url=="string"&&kC(a.url)?t=a.url:a.url===null&&(t=void 0))}return t}function kEn(e,t){return e.locator("span").filter({hasText:new RegExp(`^${TPo(t)}$`)}).first()}function Xee(e,t){return kEn(e,t).locator("..")}function xPo(e,t){return e.locator("div.fixed").filter({hasText:t}).last()}function LEn(e){return/(?:starting|queued|pending|running|processing|reviewing|finalizing|building|evaluating|checking|\d+%)/i.test(e)}function PPo(e){return/\bstale\b/i.test(e)}function $Po(e,t){let s=e.trim().replace(/^```(?:json)?\s*/i,"").replace(/\s*```$/i,"").trim(),a;try{a=JSON.parse(s)}catch(c){throw new Error(`${t} raw output was not valid JSON: ${c instanceof Error?c.message:String(c)}`)}if(!km(a))throw new Error(`${t} raw output was not a JSON object.`);return a}async function wPo(e,t,s){let a=ol(t,"create_patches.sh"),c=ol(t,"agent_prompt.md"),l=ol(t,"test.patch"),u=ol(t,"solution.patch"),p=[["create_patches.sh",a],["agent_prompt.md",c],["test.patch",l],["solution.patch",u]].filter(([,T])=>!VAe(T)).map(([T])=>T);if(p.length)throw new Error(`Missing required file(s) in the working directory: ${p.join(", ")}`);$i(s);let d=await e.exec(OC(),["create_patches.sh"],{cwd:t,timeout:_Po,signal:s});if(d.killed||d.code!==0){let T=(d.stderr||d.stdout||"").trim().slice(-2e3);throw new Error(`create_patches.sh failed${d.killed?" or timed out":` (exit ${d.code})`}.${T?`
|
|
110
|
-
${T}`:""}`)}$i(s);let[m,S,v]=await Promise.all([LAe(c,"utf8"),LAe(l,"utf8"),LAe(u,"utf8")]);return{taskPrompt:m,testPatch:S,solutionPatch:v}}async function kPo(e,t,s){$i(s);let a=await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4});if($i(s),!kC(e.url()))throw new Error("Shipd authentication or job-link navigation failed. Check the saved job link and auth state.");if(a&&a.status()>=400)throw new Error(`Shipd job-link navigation returned HTTP ${a.status()}.`);await e.waitForTimeout(4e3),$i(s)}async function bEn(e,t,s,a){$i(a);let c=await wEn.launch({executablePath:e,headless:!0});try{let l=await c.newContext({storageState:t});await l.route("**/*",async p=>{let d=p.request().resourceType();d==="image"||d==="font"||d==="media"?await p.abort():await p.continue()});let u=await l.newPage();return await kPo(u,s,a),{browser:c,page:u}}catch(l){throw await c.close().catch(()=>{}),l}}async function EEn(e,t,s){await t.click({timeout:Jy}),await e.keyboard.press(`${process.platform==="darwin"?"Meta":"Control"}+A`),await e.keyboard.insertText(s)}async function LPo(e,t,s){$i(s);let a=e.locator("#problem-description"),c=e.locator('#problem-test-patch [contenteditable="true"][role="textbox"]'),l=e.locator('#problem-solution-patch [contenteditable="true"][role="textbox"]');for(let u of[a,c,l])if(await u.count()!==1)throw new Error("Shipd challenge form selectors were not found exactly once.");await a.fill(t.taskPrompt),await EEn(e,c,t.testPatch),await EEn(e,l,t.solutionPatch),await Xee(e,"Test Quality").hover(),await gL(1e3,s)}async function MPo(e,t,s){$i(s);let a=Xee(e,t),c=fL(await a.innerText());if(LEn(c))return{quality:t,status:"already-running",rowTextAfterConfirm:c};let l=a.locator('button[title^="Re-run"]').or(a.locator('button[title^="Run"]')),u=await l.count();if(u!==1)throw new Error(`${t}: expected one Run button, found ${u}`);if(!await l.isEnabled())throw new Error(`${t}: Run button is disabled.`);let p=await l.getAttribute("title");await l.click();let d=e.getByRole("dialog").last();await d.waitFor({state:"visible",timeout:Jy});let m=fL(await d.innerText()),S=d.getByRole("button",{name:/confirm/i});if(await S.count()!==1)throw new Error(`${t}: rerun confirmation button was not found.`);return await S.click(),await gL(500,s),{quality:t,status:"started",rerunTitle:p,confirmation:m}}async function xEn(e,t,s=NAe){let a=[];for(let c of s){$i(t);let l=kEn(e,c);if(await l.count()!==1)throw new Error(`${c}: quality status row was not found.`);await l.waitFor({state:"visible",timeout:Jy});let u=l.locator(".."),p=fL(await u.innerText()),d=await u.locator('button[title^="Run"]').count()>0;a.push({quality:c,rowText:p,busy:LEn(p),shouldRun:d||PPo(p)})}return a}async function GPo(e,t){return await Xee(e,t).locator('button[title^="Re-run"]').count()>0}async function OPo(e,t){await Xee(e,t).hover();let s=xPo(e,t);await s.waitFor({state:"visible",timeout:Jy});let a=s.locator('button[title="Expand to full view"]'),c=await a.count();if(c!==1)throw new Error(`${t}: expected one quality expander, found ${c}`);return a.first()}async function NPo(e,t,s){$i(s),await(await OPo(e,t)).click();let c=e.getByRole("dialog").last();await c.waitFor({state:"visible",timeout:Jy});let l=fL(await c.locator("h2").first().innerText().catch(()=>""));if(l!==t)throw new Error(`${t}: expanded the wrong report dialog (${l||"unknown"}).`);let u=c.locator("pre code").last();if(!await u.isVisible().catch(()=>!1)){let m=c.locator("button").filter({hasText:/raw output/i}).first();try{await m.waitFor({state:"visible",timeout:Jy})}catch{let S=fL(await c.innerText());throw new Error(`${t}: raw output control did not appear; dialog text: ${S.slice(0,1e3)}`)}await m.click()}await u.waitFor({state:"visible",timeout:Jy});let p=await u.innerText(),d=$Po(p,t);return await e.keyboard.press("Escape").catch(()=>{}),{quality:t,parsed:d}}function VPo(e,t){let s=Array.isArray(e?.coverageSuggestions)?e.coverageSuggestions:[],a=Array.isArray(e?.tests)?e.tests.filter(c=>km(c)&&c.
|
|
110
|
+
${T}`:""}`)}$i(s);let[m,S,v]=await Promise.all([LAe(c,"utf8"),LAe(l,"utf8"),LAe(u,"utf8")]);return{taskPrompt:m,testPatch:S,solutionPatch:v}}async function kPo(e,t,s){$i(s);let a=await e.goto(t,{waitUntil:"domcontentloaded",timeout:6e4});if($i(s),!kC(e.url()))throw new Error("Shipd authentication or job-link navigation failed. Check the saved job link and auth state.");if(a&&a.status()>=400)throw new Error(`Shipd job-link navigation returned HTTP ${a.status()}.`);await e.waitForTimeout(4e3),$i(s)}async function bEn(e,t,s,a){$i(a);let c=await wEn.launch({executablePath:e,headless:!0});try{let l=await c.newContext({storageState:t});await l.route("**/*",async p=>{let d=p.request().resourceType();d==="image"||d==="font"||d==="media"?await p.abort():await p.continue()});let u=await l.newPage();return await kPo(u,s,a),{browser:c,page:u}}catch(l){throw await c.close().catch(()=>{}),l}}async function EEn(e,t,s){await t.click({timeout:Jy}),await e.keyboard.press(`${process.platform==="darwin"?"Meta":"Control"}+A`),await e.keyboard.insertText(s)}async function LPo(e,t,s){$i(s);let a=e.locator("#problem-description"),c=e.locator('#problem-test-patch [contenteditable="true"][role="textbox"]'),l=e.locator('#problem-solution-patch [contenteditable="true"][role="textbox"]');for(let u of[a,c,l])if(await u.count()!==1)throw new Error("Shipd challenge form selectors were not found exactly once.");await a.fill(t.taskPrompt),await EEn(e,c,t.testPatch),await EEn(e,l,t.solutionPatch),await Xee(e,"Test Quality").hover(),await gL(1e3,s)}async function MPo(e,t,s){$i(s);let a=Xee(e,t),c=fL(await a.innerText());if(LEn(c))return{quality:t,status:"already-running",rowTextAfterConfirm:c};let l=a.locator('button[title^="Re-run"]').or(a.locator('button[title^="Run"]')),u=await l.count();if(u!==1)throw new Error(`${t}: expected one Run button, found ${u}`);if(!await l.isEnabled())throw new Error(`${t}: Run button is disabled.`);let p=await l.getAttribute("title");await l.click();let d=e.getByRole("dialog").last();await d.waitFor({state:"visible",timeout:Jy});let m=fL(await d.innerText()),S=d.getByRole("button",{name:/confirm/i});if(await S.count()!==1)throw new Error(`${t}: rerun confirmation button was not found.`);return await S.click(),await gL(500,s),{quality:t,status:"started",rerunTitle:p,confirmation:m}}async function xEn(e,t,s=NAe){let a=[];for(let c of s){$i(t);let l=kEn(e,c);if(await l.count()!==1)throw new Error(`${c}: quality status row was not found.`);await l.waitFor({state:"visible",timeout:Jy});let u=l.locator(".."),p=fL(await u.innerText()),d=await u.locator('button[title^="Run"]').count()>0;a.push({quality:c,rowText:p,busy:LEn(p),shouldRun:d||PPo(p)})}return a}async function GPo(e,t){return await Xee(e,t).locator('button[title^="Re-run"]').count()>0}async function OPo(e,t){await Xee(e,t).hover();let s=xPo(e,t);await s.waitFor({state:"visible",timeout:Jy});let a=s.locator('button[title="Expand to full view"]'),c=await a.count();if(c!==1)throw new Error(`${t}: expected one quality expander, found ${c}`);return a.first()}async function NPo(e,t,s){$i(s),await(await OPo(e,t)).click();let c=e.getByRole("dialog").last();await c.waitFor({state:"visible",timeout:Jy});let l=fL(await c.locator("h2").first().innerText().catch(()=>""));if(l!==t)throw new Error(`${t}: expanded the wrong report dialog (${l||"unknown"}).`);let u=c.locator("pre code").last();if(!await u.isVisible().catch(()=>!1)){let m=c.locator("button").filter({hasText:/raw output/i}).first();try{await m.waitFor({state:"visible",timeout:Jy})}catch{let S=fL(await c.innerText());throw new Error(`${t}: raw output control did not appear; dialog text: ${S.slice(0,1e3)}`)}await m.click()}await u.waitFor({state:"visible",timeout:Jy});let p=await u.innerText(),d=$Po(p,t);return await e.keyboard.press("Escape").catch(()=>{}),{quality:t,parsed:d}}function VPo(e,t){let s=Array.isArray(e?.coverageSuggestions)?e.coverageSuggestions:[],a=Array.isArray(e?.tests)?e.tests.filter(c=>km(c)&&Array.isArray(c.concerns)&&c.concerns.length>0):[];return{testQuality:{verdict:e?.verdict??null,completed:e?.completed??!1,skipped:!e,coverageSuggestions:s,tests:a},solutionQuality:{verdict:t?.verdict??null,completed:t?.completed??!1,skipped:!t,evaluation:t?.evaluation??null}}}function PEn(e,t){if(!km(e)||!km(e[t]))return"\u2014";let s=e[t].score,a=e[t].max_score;return typeof s=="number"&&typeof a=="number"?`${s}/${a}`:"\u2014"}function qPo(e,t){let s=km(e)?e:{},a=km(s.testQuality)?s.testQuality:{},c=km(s.solutionQuality)?s.solutionQuality:{},l=Array.isArray(a.tests)?a.tests.length:0,u=Array.isArray(a.coverageSuggestions)?a.coverageSuggestions.length:0,p=c.evaluation,d=a.skipped===!0?"skipped":`${l} concerns \xB7 ${u} suggestions`,m=c.skipped===!0?"skipped":`quality ${PEn(p,"code_quality")} \xB7 comprehensiveness ${PEn(p,"solution_comprehensiveness")}`;return[` ${t.fg("accent","Test Quality")} ${t.fg("muted",d)}`,` ${t.fg("accent","Solution Quality")} ${t.fg("muted",m)}`]}function $En(e,t){let a=e.find(c=>new RegExp(`^${t}:`,"i").test(c))?.match(/:\s*(\d+)/)?.[1];return a===void 0?void 0:Number.parseInt(a,10)}function FPo(e,t,s,a,c){return e==="new tests before solution"?t!==void 0&&t>0?"Some new tests pass before the solution; add assertions for behavior introduced by the solution.":t===0&&/:\s*none$/i.test(a)&&/:\s*none$/i.test(c)?"The test file did not produce individual failures or errors; use lazy imports so every test executes separately.":"Every new test must fail or error individually before the solution.":e==="new tests after solution"?s!==void 0&&s>0?"New tests were skipped after the solution; every new test must execute and pass.":"The solution does not make every new test pass.":e==="base tests after solution"?"Base-test regression: existing base tests fail after the solution.":e==="base tests before solution"?"Base tests fail before the solution; review the test patch and test setup.":"The patch precheck did not meet the required test outcomes."}function BPo(e){let t=(e.content??[]).map(c=>c.type==="text"?c.text??"":"").join(" "),s=t.split(/\r?\n/).map(c=>c.trim().replace(/\s+/g," ")).filter(Boolean),a=s.find(c=>/^phase:/i.test(c));if(/patch precheck/i.test(t)){if(a){let c=a.replace(/^phase:\s*/i,""),l=$En(s,"passed tests"),u=$En(s,"skipped tests"),p=s.find(m=>/^failed tests:/i.test(m))??"",d=s.find(m=>/^errored tests:/i.test(m))??"";return["Patch precheck failed.",`Phase: ${c}`,`Problem: ${FPo(c,l,u,p,d)}`].join(`
|
|
111
111
|
`)}return`Patch precheck failed.
|
|
112
112
|
Problem: The precheck task could not be completed.`}return s.map(c=>c.replace(/\bFargate\b\s*/gi,"").trim()).slice(0,4).join(`
|
|
113
113
|
`)||"Quality checks failed"}function UPo(e){let t=`Fargate patch precheck failed:
|
|
114
114
|
platform: ${e.platform}`;if(e.error)return`${t}
|
|
115
115
|
${e.error}`;let s=e.phases.find(a=>!a.passed);return`${t}${s?`
|
|
116
|
-
phase: ${s.phase}`:""}.`}function MEn(e){let t;e.on("session_start",(s,a)=>{t=EPo(a.sessionManager.getBranch())}),e.registerCommand("shipd:auth",{description:"Open Shipd in a browser so you can sign in and save authentication.",handler:async(s,a)=>{if(a.mode!=="tui"){a.ui.notify("/shipd:auth requires interactive mode.","error");return}let c=DEn();if(!c){a.ui.notify("Could not find Chrome/Chromium. Set SHIPD_CHROME_PATH and retry.","error");return}let l=process.env.SHIPD_STORAGE_STATE??TEn,u,p,d;try{gPo(yPo(l),{recursive:!0}),d=await hEn(ol(CEn(),"shipd-auth-"));let m=await APo();p=mPo(c,[`--remote-debugging-port=${m}`,`--user-data-dir=${d}`,"--no-first-run","--no-default-browser-check",AEn],{stdio:"ignore",windowsHide:!1}),await DPo(m,p),u=await wEn.connectOverCDP(`http://127.0.0.1:${m}`);let S=u.contexts()[0]??await u.newContext(),v=S.pages()[0]??await S.newPage();if(await v.waitForLoadState("domcontentloaded",{timeout:6e4}).catch(()=>{}),kC(v.url())||await v.goto(AEn,{waitUntil:"domcontentloaded",timeout:6e4}),a.ui.notify("A Shipd browser window is open. Sign in there, then return here.","info"),!await a.ui.confirm("Shipd sign-in","After you finish signing in in the browser, press OK to save the session.")){a.ui.notify("Shipd sign-in cancelled; nothing was saved.","info");return}await S.storageState({path:l}),await bPo(S)?(await S.storageState({path:l}),a.ui.notify(`Shipd authentication saved to ${l}. quality-check is ready to use.`,"info")):a.ui.notify(`Shipd state was saved to ${l}, but the signed-in page could not be verified. Try quality-check; if it reports an authentication error, run /shipd:auth again and wait for Shipd to return before confirming.`,"warning")}catch(m){a.ui.notify(`Shipd authentication failed: ${m instanceof Error?m.message:String(m)}`,"error")}finally{await u?.close().catch(()=>{}),p&&p.exitCode===null&&p.kill(),d&&await MAe(d,{recursive:!0,force:!0}).catch(()=>{})}}}),e.registerCommand(GAe,{description:"Save the Shipd job link for this chat session.",handler:async(s,a)=>{let c=s.trim();if(c.toLowerCase()==="clear"){t=void 0,e.appendEntry(OAe,{url:null}),a.ui.notify("Shipd job link cleared for this chat session.","info");return}if(!kC(c)){a.ui.notify(`Usage: /${GAe} <https://shipd.ai/...>`,"warning");return}t=c,e.appendEntry(OAe,{url:c}),a.ui.notify("Shipd job link saved for this chat session.","info")}}),e.registerTool({name:Yee,label:"Quality Checks",description:
|
|
116
|
+
phase: ${s.phase}`:""}.`}function MEn(e){let t;e.on("session_start",(s,a)=>{t=EPo(a.sessionManager.getBranch())}),e.registerCommand("shipd:auth",{description:"Open Shipd in a browser so you can sign in and save authentication.",handler:async(s,a)=>{if(a.mode!=="tui"){a.ui.notify("/shipd:auth requires interactive mode.","error");return}let c=DEn();if(!c){a.ui.notify("Could not find Chrome/Chromium. Set SHIPD_CHROME_PATH and retry.","error");return}let l=process.env.SHIPD_STORAGE_STATE??TEn,u,p,d;try{gPo(yPo(l),{recursive:!0}),d=await hEn(ol(CEn(),"shipd-auth-"));let m=await APo();p=mPo(c,[`--remote-debugging-port=${m}`,`--user-data-dir=${d}`,"--no-first-run","--no-default-browser-check",AEn],{stdio:"ignore",windowsHide:!1}),await DPo(m,p),u=await wEn.connectOverCDP(`http://127.0.0.1:${m}`);let S=u.contexts()[0]??await u.newContext(),v=S.pages()[0]??await S.newPage();if(await v.waitForLoadState("domcontentloaded",{timeout:6e4}).catch(()=>{}),kC(v.url())||await v.goto(AEn,{waitUntil:"domcontentloaded",timeout:6e4}),a.ui.notify("A Shipd browser window is open. Sign in there, then return here.","info"),!await a.ui.confirm("Shipd sign-in","After you finish signing in in the browser, press OK to save the session.")){a.ui.notify("Shipd sign-in cancelled; nothing was saved.","info");return}await S.storageState({path:l}),await bPo(S)?(await S.storageState({path:l}),a.ui.notify(`Shipd authentication saved to ${l}. quality-check is ready to use.`,"info")):a.ui.notify(`Shipd state was saved to ${l}, but the signed-in page could not be verified. Try quality-check; if it reports an authentication error, run /shipd:auth again and wait for Shipd to return before confirming.`,"warning")}catch(m){a.ui.notify(`Shipd authentication failed: ${m instanceof Error?m.message:String(m)}`,"error")}finally{await u?.close().catch(()=>{}),p&&p.exitCode===null&&p.kill(),d&&await MAe(d,{recursive:!0,force:!0}).catch(()=>{})}}}),e.registerCommand(GAe,{description:"Save the Shipd job link for this chat session.",handler:async(s,a)=>{let c=s.trim();if(c.toLowerCase()==="clear"){t=void 0,e.appendEntry(OAe,{url:null}),a.ui.notify("Shipd job link cleared for this chat session.","info");return}if(!kC(c)){a.ui.notify(`Usage: /${GAe} <https://shipd.ai/...>`,"warning");return}t=c,e.appendEntry(OAe,{url:c}),a.ui.notify("Shipd job link saved for this chat session.","info")}}),e.registerTool({name:Yee,label:"Quality Checks",description:"Run create_patches.sh in the current working directory, read agent_prompt.md, test.patch, and solution.patch, run the Fargate patch precheck, then fill the Shipd challenge draft fields, run fresh checks with a Run button, rerun checks marked Stale, and skip current checks. Start Test Quality then Solution Quality in one browser tab. Wait for any started jobs and return agent-focused JSON. details.testQuality contains coverageSuggestions and test blocks whose concerns array is non-empty; details.solutionQuality contains the complete evaluation block. This consumes Shipd tokens and does not click the final challenge-submit button.",promptSnippet:"Submit the working-directory patches to Shipd",promptGuidelines:["Use quality-check when the user explicitly asks to submit or evaluate the current Shipd task.","quality-check has no parameters.","quality-check first runs the Fargate patch precheck; only after all four test phases meet their expectations does it upload the draft to Shipd. It runs fresh checks with a Run button, reruns checks marked Stale after the draft update, skips current checks, then waits using scheduled browser reopen checks.","Read details.testQuality.coverageSuggestions and details.testQuality.tests for test-quality feedback.","Read details.solutionQuality.evaluation for the complete solution-quality feedback."],parameters:CPo,renderCall(s,a,c){let l=c.state;c.executionStarted&&l.startedAt===void 0&&(l.startedAt=Date.now());let u=c.lastComponent instanceof mL?c.lastComponent:new mL("",0,0);return u.setText(""),u},renderResult(s,a,c,l){let u=l.state;u.startedAt??=Date.now(),u.startedAt!==void 0&&a.isPartial&&!u.interval&&(u.interval=setInterval(()=>l.invalidate(),1e3)),(!a.isPartial||l.isError)&&(u.endedAt??=Date.now(),u.interval&&(clearInterval(u.interval),u.interval=void 0));let p=u.endedAt??Date.now(),d=Xy(p-u.startedAt),m=a.isPartial?`Elapsed ${d}`:`Took ${d}`,S=c.fg("toolTitle",c.bold("Quality Checks"))+c.fg("muted",` ${m}`);return a.isPartial?new mL(`${S}
|
|
117
117
|
${c.fg("muted","Running quality checks...")}`,0,0):l.isError?new mL(`${S}
|
|
118
118
|
${c.fg("error",BPo(s))}`,0,0):new mL([S,...qPo(s.details,c)].join(`
|
|
119
119
|
`),0,0)},async execute(s,a,c,l,u){if(!t)throw new Error(`No Shipd job link is set for this chat session. Provide the job link with /${GAe} <job-link>.`);let p=t,d=process.env.SHIPD_STORAGE_STATE??TEn;if(!VAe(d))throw new Error(`Shipd authentication state not found at ${d}. Run /shipd:auth first.`);let m=DEn();if(!m)throw new Error("Could not find Chrome/Chromium. Set SHIPD_CHROME_PATH and retry.");let S,v,T,x=()=>{S?.close().catch(()=>{})};c?.addEventListener("abort",x,{once:!0});try{$i(c),l?.({content:[{type:"text",text:"Running create_patches.sh..."}],details:void 0});let w=await wPo(e,u.cwd,c);$i(c),l?.({content:[{type:"text",text:"Running patch prechecks before opening Shipd..."}],details:void 0}),T=await hEn(ol(CEn(),"shipd-patch-precheck-"));let L=await qC(e,u.cwd,T,c);if(L.status==="error")throw new Error(`Fargate patch precheck snapshot failed on linux: ${L.error}`);await Promise.all([vEn(ol(T,"test.patch"),w.testPatch,"utf8"),vEn(ol(T,"solution.patch"),w.solutionPatch,"utf8")]);let G=await lEn({pi:e,repoDir:u.cwd,snapshotDir:T,config:{provider:"patch-precheck",modelId:"patch-precheck",thinkingLevel:"off",fargate:dte()},cancelSignal:c??new AbortController().signal,runId:`quality-precheck-${fPo()}`,precheckTimeoutMinutes:IPo,onPhase:Se=>l?.({content:[{type:"text",text:`Patch precheck: ${Se}...`}],details:void 0})});if(!G.passed)throw new Error(UPo(G));await MAe(T,{recursive:!0,force:!0}),T=void 0,l?.({content:[{type:"text",text:"Patch prechecks passed; opening Shipd and filling draft fields..."}],details:void 0}),$i(c);let O=await bEn(m,d,p,c);S=O.browser,v=O.page,await LPo(v,w,c),l?.({content:[{type:"text",text:"Checking which quality checks are stale..."}],details:void 0});let U=await xEn(v,c),J=U.filter(Se=>Se.busy||Se.shouldRun).map(Se=>Se.quality),ce=[];for(let Se of NAe){let He=U.find(oe=>oe.quality===Se);if(!He)throw new Error(`${Se}: quality status was not available after updating the draft.`);He.shouldRun?ce.push(await MPo(v,Se,c)):He.busy&&ce.push({quality:Se,status:"already-running",rowTextAfterConfirm:He.rowText})}let ke=U.map(({quality:Se,rowText:He})=>({quality:Se,rowText:He}));if(J.length>0){l?.({content:[{type:"text",text:`Quality checks queued (${J.join(", ")}); closing the browser until the first check in 5 minutes...`}],details:void 0}),await S.close(),S=void 0,v=void 0;let Se=Date.now()+hPo;for(;;){let He=Se-Date.now();He>0&&(l?.({content:[{type:"text",text:`Browser closed; next quality check in ${Xy(He)}...`}],details:void 0}),await gL(He,c)),$i(c),l?.({content:[{type:"text",text:"Reopening Shipd to check quality job status..."}],details:void 0});let oe=await bEn(m,d,p,c);S=oe.browser,v=oe.page;let M=await xEn(v,c,J);if(M.every(Xn=>!Xn.busy)){ke=[...U.filter(Xn=>!J.includes(Xn.quality)).map(({quality:Xn,rowText:Lm})=>({quality:Xn,rowText:Lm})),...M.map(({quality:Xn,rowText:Lm})=>({quality:Xn,rowText:Lm}))];break}let se=M.map(Xn=>`${Xn.quality}: ${Xn.rowText}`).join("; ");l?.({content:[{type:"text",text:`Quality jobs still running (${se}); closing browser until the next check...`}],details:void 0}),await S.close(),S=void 0,v=void 0,Se=Date.now()+vPo}}else l?.({content:[{type:"text",text:"No quality checks need to run; using the current reports."}],details:void 0});if(!v)throw new Error("Shipd quality status page was closed before report extraction.");l?.({content:[{type:"text",text:"Extracting quality reports..."}],details:void 0});let Ee=[],_e=[];for(let Se of NAe){if(!await GPo(v,Se)){_e.push(Se);continue}Ee.push(await NPo(v,Se,c))}let Ce=Ee.find(Se=>Se.quality==="Test Quality")?.parsed,Ne=Ee.find(Se=>Se.quality==="Solution Quality")?.parsed,Ve=VPo(Ce,Ne);return{content:[{type:"text",text:JSON.stringify(Ve,null,2)}],details:{...Ve,started:ce,completed:ke,skipped:_e,precheck:G}}}catch(w){throw c?.aborted?new Error("Cancelled by user."):w}finally{c?.removeEventListener("abort",x),await S?.close().catch(()=>{}),T&&await MAe(T,{recursive:!0,force:!0}).catch(()=>{})}}})}var Jee=[wAe,kAe],OEn=["analyze_task_tests","analyze_test_gaps","submit_shipd"],ete=!1,GEn=!1,eI=!1;function qAe(e){return e.getActiveTools().map(s=>typeof s=="string"?s:s.name)}function FAe(){return ete}function tte(e){let t=qAe(e),s=OEn.some(l=>t.includes(l)),a=Jee.every(l=>t.includes(l)),c=Jee.some(l=>t.includes(l));return s||(FAe()?!a:c)}function HPo(e){GEn||(_En(e),GEn=!0)}function jPo(e,t){let s=qAe(e);if(t&&s.length===0){eI=!0;return}let a=s.includes("submit_shipd"),l=s.filter(d=>!OEn.includes(d)).filter(d=>!Jee.includes(d)),u=t?[...l,...Jee]:[...l];a&&!u.includes(Yee)&&u.push(Yee),(u.length!==s.length||u.some((d,m)=>d!==s[m]))&&e.setActiveTools(u),eI=tte(e)}function LC(e){let t=FAe();t&&HPo(e),jPo(e,t)}function BAe(e,t){ete=DL(t),eI=!0,NEn(e)}function NEn(e,t=0){let s=FAe(),a=qAe(e);if(s&&a.length===0&&t<8){queueMicrotask(()=>NEn(e,t+1));return}LC(e)}function VEn(e){for(let t of[0,50,150,400])setTimeout(()=>{(eI||tte(e))&&LC(e)},t)}function qEn(){return eI}function UAe(e,t,s){ete=s,bL(t,s),eI=!0,LC(e)}function FEn(e,t){ete=DL(t),eI=!0,LC(e)}var t$o="Ctrl+Shift+X",jEn=[{value:"--config",label:"--config",description:"Configure reviewer, solver, and analysis models"},{value:"--solver-gap-finder",label:"--solver-gap-finder",description:"Use TDD solver attempts to find behavioral gaps"}],n$o=["config","solver-gap-finder"];function s$o(e){let t=e.trimStart(),s=/\s$/.test(t),a=t.trimEnd().split(/\s+/).filter(Boolean),c=s?"":a.at(-1)??"",l=new Set(s?a:a.slice(0,-1)),u=s?t:t.slice(0,t.length-c.length),p=l.has("--config"),d=[...l].some(S=>S!=="--config"),m=jEn.filter(S=>!l.has(S.value)&&!p&&!(d&&S.value==="--config")&&S.value.startsWith(c));return m.length?m.map(S=>({...S,value:`${u}${S.value}`})):null}async function HAe(e,t,s){let a=iDe();if(a.length===0)return e.ui.notify("No enabledModels configured in settings.json.","error"),null;let c=e.modelRegistry.getAll(),l=a.map(m=>{let S=cDe(m);if(!S)return null;let v=c.find(w=>w.provider===S.provider&&w.id===S.modelId),T=t?.provider===S.provider&&t?.modelId===S.modelId,x=v?`${v.name} (${m})`:m;return{ref:m,parsed:S,display:T?`${x} [current]`:x,isCurrent:T}}).filter(m=>m!==null);if(l.length===0)return e.ui.notify("Could not resolve any enabledModels entries.","error"),null;let u=[...l].sort((m,S)=>m.isCurrent===S.isCurrent?0:m.isCurrent?-1:1),p=await e.ui.select(s,u.map(m=>m.display));if(!p)return null;let d=l.find(m=>m.display===p);return d?{provider:d.parsed.provider,modelId:d.parsed.modelId}:null}function MC(e,t,s){let a=e.modelRegistry.getAll().find(c=>c.provider===t&&c.id===s);return nDe(a)}var nte={provider:"",modelId:"",thinkingLevel:"off",timeoutMinutes:ite,solverCount:lte,saveArtifacts:ute},r$o={provider:"",modelId:"",thinkingLevel:"off",timeoutMinutes:rI};function ste(e){let t=e?.analyzeGap,s=t?.timeoutMinutes,a=typeof s=="number"&&Number.isFinite(s)?Math.min(AL,Math.max(TL,s)):rI;return{...r$o,...t,timeoutMinutes:a}}function HEn(e,t,s,a){let c=t?MC(e,t.provider,t.modelId):["off"],l=s.provider?MC(e,s.provider,s.modelId):["off"],u=a.provider?MC(e,a.provider,a.modelId):["off"];return[{id:"solver-model",section:"Solver",label:"Solver model",value:s.provider?`${s.provider}/${s.modelId}`:"not set",kind:"model"},{id:"solver-thinking",section:"Solver",label:"Solver thinking",value:s.thinkingLevel,kind:"cycle",values:l},{id:"solvergap-timeout",section:"Solver",label:"Timeout",value:`${s.timeoutMinutes} min`,kind:"cycle",values:[10,20,30,40,50,XAe].filter((p,d,m)=>p>=YAe&&m.indexOf(p)===d).map(p=>`${p} min`)},{id:"solvergap-solver-count",section:"Solver",label:"Parallel agents",value:String(s.solverCount),kind:"cycle",values:Array.from({length:JAe-cte+1},(p,d)=>`${cte+d}`)},{id:"solvergap-save-artifacts",section:"Solver",label:"Save artifacts",value:s.saveArtifacts?"on":"off",kind:"cycle",values:["on","off"]},{id:"reviewer-model",section:"Solver",label:"Reviewer model",value:t?`${t.provider}/${t.modelId}`:"not set",kind:"model"},{id:"reviewer-thinking",section:"Solver",label:"Reviewer thinking",value:t?.thinkingLevel??"off",kind:"cycle",values:c},{id:"analyze-enabled",section:"Analysis Tools",label:"Enabled here",value:EL(e.cwd)?"on":"off",kind:"cycle",values:["on","off"]},{id:"analyze-timeout",section:"Analysis Tools",label:"Timeout",value:`${a.timeoutMinutes} min`,kind:"cycle",values:[10,15,20,25,AL].filter((p,d,m)=>p>=TL&&m.indexOf(p)===d).map(p=>`${p} min`)},{id:"analyze-gap-model",section:"Analysis Tools",label:"Analysis model",value:a.provider?`${a.provider}/${a.modelId}`:"not set",kind:"model"},{id:"analyze-gap-thinking",section:"Analysis Tools",label:"Analysis thinking",value:a.thinkingLevel,kind:"cycle",values:u}]}var jAe=class{constructor(t,s,a,c,l,u){this.ctx=t;this.settingsListTheme=s;this.theme=a;this.onCycleSaved=c;this.onActivateModel=l;this.onExit=u;this.rows=HEn(t,Xo(),Xo()?.solverGap??nte,ste(Xo()))}selectedIndex=0;rows;refresh(){let t=Xo();this.rows=HEn(this.ctx,t,t?.solverGap??nte,ste(t)),this.selectedIndex=Math.min(this.selectedIndex,this.rows.length-1)}invalidate(){}render(t){let s=[],a=Math.min(30,Math.max(...this.rows.map(l=>l.label.length))),c;for(let l=0;l<this.rows.length;l++){let u=this.rows[l];if(!u)continue;u.section!==c&&(c!==void 0&&s.push(""),s.push(this.theme.bold(this.theme.fg("accent",u.section))),c=u.section);let p=l===this.selectedIndex,d=p?this.settingsListTheme.cursor:" ",m=u.label+" ".repeat(Math.max(0,a-u.label.length)),S=this.settingsListTheme.label(m,p),v=this.settingsListTheme.value(u.value,p);s.push(`${d}${S} ${v}`)}return s}handleInput(t){if(sI(t,nI.ctrl("s"))||sI(t,nI.escape)||sI(t,nI.ctrl("c"))){this.onExit();return}if(sI(t,nI.up)){this.selectedIndex=this.selectedIndex===0?this.rows.length-1:this.selectedIndex-1;return}if(sI(t,nI.down)){this.selectedIndex=this.selectedIndex===this.rows.length-1?0:this.selectedIndex+1;return}if(sI(t,nI.enter)||sI(t,nI.return)||t===" "){let s=this.rows[this.selectedIndex];if(!s)return;if(s.kind==="model"){this.onActivateModel(s.id);return}if(!s.values||s.values.length===0)return;let a=Xo();if(!a){this.ctx.ui.notify("Set the reviewer model first \u2014 it's required before solver settings","warning");return}let c=a.solverGap??nte,l=ste(a),u=s.values.indexOf(s.value),p=s.values[(u+1)%s.values.length];if(p===void 0)return;s.id==="reviewer-thinking"?wi({...a,thinkingLevel:p,solverGap:c,analyzeGap:l}):s.id==="solver-thinking"?wi({...a,solverGap:{...c,thinkingLevel:p}}):s.id==="solvergap-timeout"?wi({...a,solverGap:{...c,timeoutMinutes:Number.parseInt(p,10)}}):s.id==="solvergap-solver-count"?wi({...a,solverGap:{...c,solverCount:Number.parseInt(p,10)}}):s.id==="solvergap-save-artifacts"?wi({...a,solverGap:{...c,saveArtifacts:p==="on"}}):s.id==="analyze-enabled"?bL(this.ctx.cwd,p==="on"):s.id==="analyze-timeout"?wi({...a,analyzeGap:{...l,timeoutMinutes:Number.parseInt(p,10)}}):s.id==="analyze-gap-thinking"&&wi({...a,analyzeGap:{...l,thinkingLevel:p}}),this.refresh(),this.onCycleSaved()}}};async function o$o(e,t){if(t.mode!=="tui"){t.ui.notify("/checks --config requires interactive mode","error");return}let s=0;for(;;){let a=await t.ui.custom((p,d,m,S)=>{let v=new jAe(t,XPo(),d,()=>{FEn(e,t.cwd),p.requestRender()},x=>S(x),()=>S(void 0));v.selectedIndex=s;let T=new JPo;return T.addChild(new UEn(d.bold(d.fg("accent","Checks settings")))),T.addChild({render:x=>v.render(x),invalidate:()=>v.invalidate()}),T.addChild(new e$o(1)),T.addChild(new UEn(d.fg("dim","\u2191\u2193 navigate enter select ctrl+s save & exit esc cancel"))),{render(x){return T.render(x)},invalidate(){T.invalidate()},handleInput(x){v.handleInput(x),s=v.selectedIndex,p.requestRender()}}});if(!a)return;let c=Xo(),l=c?.solverGap??nte,u=ste(c);if(a==="reviewer-model"){let p=await HAe(t,c,"Select reviewer model");if(!p)continue;let d=MC(t,p.provider,p.modelId),m=d.includes(c?.thinkingLevel??"off")?c?.thinkingLevel??"off":d[0]??"off";wi({...p,thinkingLevel:m,solverGap:l,analyzeGap:u,enabledProjects:c?.enabledProjects??mte(),enableAnalyzeTool:c?.enableAnalyzeTool}),t.ui.notify(`Reviewer model saved: ${p.provider}/${p.modelId}`,"info");continue}if(a==="solver-model"){if(!c){t.ui.notify("Set the reviewer model first \u2014 it's required before solver settings.","warning");continue}let p=await HAe(t,l.provider?l:null,"Select solver model");if(!p)continue;let d=MC(t,p.provider,p.modelId),m=d.includes(l.thinkingLevel)?l.thinkingLevel:d[0]??"off";wi({...c,solverGap:{...l,...p,thinkingLevel:m}}),t.ui.notify(`Solver model saved: ${p.provider}/${p.modelId}`,"info");continue}if(a==="analyze-gap-model"){if(!c){t.ui.notify("Set the reviewer model first \u2014 it's required before analyze-tool settings.","warning");continue}let p=await HAe(t,u.provider?u:null,"Select gap-finder model");if(!p)continue;let d=MC(t,p.provider,p.modelId),m=d.includes(u.thinkingLevel)?u.thinkingLevel:d[0]??"off";wi({...c,analyzeGap:{...u,...p,thinkingLevel:m}}),t.ui.notify(`Gap-finder model saved: ${p.provider}/${p.modelId}`,"info")}}}function zEn(e){e.registerCommand("checks",{description:"Configure checks or run the solver-based behavioral gap finder.",getArgumentCompletions:s$o,handler:async(t,s)=>{let a=t.trim();if(!a){let _e=await s.ui.select("Choose a checks action",[...n$o]);if(!_e)return;a=`--${_e}`}let c=[...new Set(a.split(/\s+/).filter(Boolean))],l=new Set(jEn.map(_e=>_e.value)),u=c.filter(_e=>!l.has(_e));if(u.length){s.ui.notify(`Unknown option(s): ${u.join(", ")}. Run /checks with no arguments to see options.`,"warning");return}if(c.includes("--config")){c.length>1?s.ui.notify("--config cannot be combined with other options.","warning"):await o$o(e,s);return}let p=c.includes("--solver-gap-finder");if(!p)return;if(Qee()){s.ui.notify("A checks run is already in progress.","warning");return}let d=Xo();if(!d){s.ui.notify("No gap-finder model configured. Run /checks --config first.","error");return}let m=s.modelRegistry.find(d.provider,d.modelId);if(!m||!s.modelRegistry.hasConfiguredAuth(m)){s.ui.notify("Configured behavioral gap-finder model is unavailable or unauthenticated. Run /checks --config.","error");return}let S=PAe.filter(_e=>!BEn(tI(s.cwd,_e)));if(S.length){s.ui.notify(`Missing required file(s): ${S.join(", ")}`,"error");return}let v=null,T;if(p){if(v=oDe(),!v||!BEn(tI(s.cwd,"test.sh"))){s.ui.notify("Configure solver gap finder and provide test.sh before running it.","error");return}if(T=s.modelRegistry.find(v.provider,v.modelId),!T||!s.modelRegistry.hasConfiguredAuth(T)){s.ui.notify("Configured solver gap-finder model is unavailable or unauthenticated.","error");return}}let x=gEn(),w=v?.solverCount??0,L=w+1,G=Date.now(),O=p?"preparing image":"preparing clean snapshot",U=0,J=!p,ce=(_e=O,Ce=U,Ne=J)=>{O=_e,U=Ce,J=Ne,s.ui.setWidget(dL,uEn(_e,Ce,L,{showBar:Ne,startedAt:G}))},ke=setInterval(()=>ce(),1e3);ce(),s.ui.notify(`checks (${c.join(" ")}) started. Press ${t$o} to cancel.`,"info");let Ee;try{let _e=tI(YPo(),`checks-${zPo()}`);WPo(_e,{recursive:!0}),Ee=_e;let Ce=await qC(e,s.cwd,_e,x.signal);if(Ce.status==="error"){s.ui.notify(`checks: ${Ce.error}`,"error");return}if(x.signal.aborted)return;for(let fc of PAe)KPo(tI(s.cwd,fc),tI(_e,fc));let Ne=jee(),Ve=Kee(),Se=zee(),He=0,oe=[],M,se={status:"ok",gaps:[]};if(p&&v){if(x.signal.aborted){s.ui.notify("checks: cancelled.","warning");return}let fc=new Map,SL=!1,Za=()=>Array.from({length:w},(_o,Gm)=>{let IL=fc.get(Gm+1);return IL?`${Gm+1}${IL.passed?"\u2713":"\u2717"}`:`${Gm+1}\u2026`}).join(" "),Mm=_o=>{_o==="running agents"&&(SL=!0);let Gm=SL&&(_o==="running agents"||_o==="finalizing"),IL=_o==="running agents"?`${_o} (${Za()})`:_o,ZEn=[...fc.values()];ce(IL,He+ZEn.length,Gm)},yL=_o=>{for(let Gm of _o)fc.set(Gm.index,Gm);Mm("running agents")},WEn=_o=>{fc.set(_o.index,_o),Mm("finalizing")};Mm("preparing image");let QEn=$Ae().replace(/[:.]/g,"-");if(oe=await cEn({pi:e,repoDir:s.cwd,snapshotDir:_e,config:d,solverConfig:v,cancelSignal:x.signal,runId:QEn,onSolverCompleted:WEn,onSolverProgress:yL,onResourceUsage:_o=>{M=_o},onPhase:Mm}),x.signal.aborted){s.ui.notify("checks: cancelled.","warning");return}if(oe.some(_o=>_o.status!=="patchFailed"&&_o.status!=="error")&&(Mm("finalizing"),fDe(_e,oe),se=await Hke({tempDir:_e,model:m,thinkingLevel:d.thinkingLevel,solverResults:oe,testRubric:Ne,gapRules:Ve,fairnessRules:Se,cancelSignal:x.signal})),He+=1,Mm("finalizing"),M&&rDe(s.cwd,M),x.signal.aborted){s.ui.notify("checks: cancelled.","warning");return}}let Xn=dEn({existingReport:pEn(tI(s.cwd,"shipd_report.json")),config:d,runGapFinder:!1,testGaps:[],gapAnalysisIncomplete:!1,gapFinderStatus:"ok",gapFilterStatus:"ok",runSolverGapFinder:p,solverResults:oe,fargateResourceUsage:M,solverGaps:se.gaps,solverGapAnalysisIncomplete:p&&(oe.some(fc=>fc.status==="error")||se.status!=="ok"),solverComparisonStatus:se.status}),Lm=mEn({merged:Xn,runGapFinder:!1,runSolverGapFinder:p});e.sendMessage({customType:"shipd_checks_report",content:Lm.content,display:!0,details:Lm.details});let RL=tI(s.cwd,"shipd_report.json");ZPo(RL,JSON.stringify(Xn,null,2),"utf-8"),s.ui.notify(`checks: wrote details to ${RL}`,"info")}catch(_e){s.ui.notify(`checks failed: ${_e instanceof Error?_e.message:String(_e)}`,"error")}finally{clearInterval(ke),s.ui.setWidget(dL,void 0),Ee&&QPo(Ee,{recursive:!0,force:!0}),REn()}}})}var KEn=i$o.ctrlShift("x");function l$o(e){e.registerCommand("analyze:on",{description:"Enable the gap-finder and solution-precheck tools for this project folder",handler:async(t,s)=>{UAe(e,s.cwd,!0),s.ui.notify("Gap-finder and solution-precheck tools ON in this project","info")}}),e.registerCommand("analyze:off",{description:"Disable the gap-finder and solution-precheck tools for this project folder",handler:async(t,s)=>{UAe(e,s.cwd,!1),s.ui.notify("Gap-finder and solution-precheck tools OFF in this project","info")}}),e.registerMessageRenderer("shipd_checks_report",(t,s,a)=>{let c=t.details??{},l=new a$o;l.addChild(new zAe(a.bold(a.fg("accent","Checks")),0,0));let u=!1,p=d=>{l.addChild(new zAe(d,0,0)),u=!0};if(c.showGaps){let d=c.gapsCount??0;p(d>0?a.fg("warning",` \u26A0 ${d} test gap(s) found`):a.fg("success"," \u2713 no test gaps found"))}if(c.showSolverGaps){let d=c.solverDetails??[],m=d.filter(x=>x.passed).length,S=c.solverGapsCount??0;l.addChild(new c$o(1)),p(a.bold(a.fg("accent","Solver gap finder")));for(let x of d){let w=x.passed?a.fg("success","\u2713"):a.fg("error","\u2717"),L=x.passed?"passed":x.status==="ok"?"failed tests":x.status;p(` ${w} Solver ${x.index}: ${L} (${Xy(x.durationMs)})`)}let v=m===d.length&&d.length>0?a.fg("success",`${m}/${d.length} solvers passed`):a.fg("warning",`${m}/${d.length} solvers passed`),T=S>0?a.fg("warning",`${S} behavioral gap(s) found`):a.fg("success","no behavioral gaps found");p(` ${v}, ${T}`)}return u||l.addChild(new zAe(a.fg("dim"," nothing to report"),0,0)),l}),e.registerShortcut(KEn,{description:"Cancel an in-progress /checks run",handler:t=>{Qee()&&SEn()&&(t.ui.setWidget(dL,[`checks: cancelling (${KEn})...`]),t.ui.notify("checks: cancelling...","warning"))}}),u$o(e),MEn(e),zEn(e)}function u$o(e){e.on("session_start",(t,s)=>{BAe(e,s.cwd),(t.reason==="resume"||t.reason==="reload"||t.reason==="startup")&&VEn(e)}),e.on("session_tree",async(t,s)=>{BAe(e,s.cwd)}),e.on("before_agent_start",()=>{!qEn()&&!tte(e)||LC(e)})}export{l$o as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sreetej510/pi-shipd-checks",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.13",
|
|
4
4
|
"description": "Pi extension that runs a strict, multi-agent fairness review of a benchmark task's agent_prompt.md, test.patch, and solution.patch, plus behavioral test-gap analysis, via /checks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|