#!/usr/bin/env node var ie=Object.defineProperty;var a=(e,t)=>ie(e,"name",{value:t,configurable:!0});import{access as Ie}from"fs/promises";import{readFileSync as ye}from"fs";import{join as Ee,normalize as A}from"path";import{parseArgs as Oe}from"util";import{check as ve,extractDocDefinition as _e,FileType as Te,recommended as De,Severity as _,SourceCodeType as Re,toSchema as z,toSourceCode as Ae}from"@shopify/theme-check-common";import{ThemeLiquidDocsManager as Ne}from"@shopify/theme-check-docs-updater";import{themeCheckRun as Le}from"@shopify/theme-check-node";import{randomUUID as re}from"crypto";function C(e){return e.some(t=>t.result==="failed")}a(C,"hasFailedValidation");function y(e){return e.map(t=>({artifactId:t.artifactId||`artifact-${re()}`,revision:t.revision??1}))}a(y,"extractArtifactsFromItems");function E(e,t){return e.map((n,c)=>{let r=t[c];return r?{...n,artifactId:r.artifactId,artifactRevision:r.revision}:n})}a(E,"attachArtifactIds");function x(e,t="Items"){let n=C(e),c=e.some(s=>s.result==="inform"),r;n?r="\u274C INVALID":c?r="\u26A0\uFE0F VALID (with warnings)":r="\u2705 VALID";let i=`## Validation Summary `;return i+=`**Overall Status:** ${r} `,i+=`**Total ${t}:** ${e.length} `,i+=`## Detailed Results `,e.forEach((s,p)=>{let d;s.result==="success"?d="\u2705":s.result==="inform"?d="\u26A0\uFE0F":d="\u274C",i+=`### ${t.slice(0,-1)} ${p+1} `,s.artifactId&&(i+=`**Artifact ID:** ${s.artifactId}`,s.artifactRevision&&(i+=` **Revision:** ${s.artifactRevision}`),i+=` *Use same ID & increment revision when retrying on an improvement of this artifact* `),i+=`**Status:** ${d} ${s.result.toUpperCase()} `,i+=`**Details:** ${s.resultDetail} `}),i}a(x,"formatValidationResult");function k(e){return Object.fromEntries(Object.entries(e).map(([t,n])=>{let{description:c,valueName:r,choices:i,...s}=n;return[t,s]}))}a(k,"toParseArgsOptions");var M={model:{type:"string",valueName:"name",description:"Agent model name"},"client-name":{type:"string",valueName:"name",description:"Agent client name"},"client-version":{type:"string",valueName:"version",description:"Agent client version"}},j={"user-prompt-base64":{type:"string",valueName:"base64",description:"Base64-encoded triggering prompt"},"session-id":{type:"string",valueName:"id",description:"Agent session identifier"},"tool-use-id":{type:"string",valueName:"id",description:"Agent tool-use identifier"}},G={"artifact-id":{type:"string",valueName:"id",description:"Stable artifact identifier"},revision:{type:"string",valueName:"number",description:"Positive artifact revision"},...M,...j,json:{type:"boolean",description:"Emit machine-readable JSON"}},B={help:{type:"boolean",short:"h",description:"Show this help"}};function H(e,t){let n=new Set([...Object.keys(M),...Object.keys(j),"artifact-id","revision"]),c=Object.entries(t).filter(([i])=>!0).map(([i,s])=>{let p=s.type==="string"?s.valueName||s.choices?.join("|")||"value":void 0,d=`--${i}${p?` <${p}>`:""}`;return[s.short?`-${s.short}, ${d}`:d,s.description]}),r=Math.max(...c.map(([i])=>i.length));return["Usage:",...e.map(i=>` ${i}`),"","Options:",...c.map(([i,s])=>` ${i.padEnd(r)} ${s}`)].join(` `)}a(H,"formatCliHelp");function Q(){let e=[process.env.CLAUDE_SESSION_ID,process.env.CLAUDE_CODE_SESSION_ID,process.env.CURSOR_SESSION_ID,process.env.COPILOT_SESSION_ID];for(let t of e)if(typeof t=="string"&&t.length>0)return t}a(Q,"readHostSessionId");var oe="https://shopify.dev/",ae="https://shopify-dev.shop.dev/";function K(e){return`https://shopify-dev-staging${e}.shopifycloud.com/`}a(K,"stagingHost");function V(e){let t=e?.env??process.env,n=t.SHOPIFY_DEV_STAGING_SERVER_NUMBER?.trim();if(n){if(!/^\d+$/.test(n))throw new Error(`SHOPIFY_DEV_STAGING_SERVER_NUMBER must be a positive integer; got: "${n}"`);let r=Number(n);if(!Number.isSafeInteger(r)||r<=0)throw new Error(`SHOPIFY_DEV_STAGING_SERVER_NUMBER must be a positive integer; got: "${n}"`);let i=t.MINERVA_TOKEN;if(!i){let s=K(r).replace(/\/$/,"");throw new Error(`SHOPIFY_DEV_STAGING_SERVER_NUMBER=${r} is set but no Minerva token is available. Staging servers are behind Minerva. Get a token via: export MINERVA_TOKEN=$(devx minerva-auth --client-id 0oa1bphetnkOusboI0x8 --audience ${s})`)}return{url:K(r),headers:{Cookie:`MINERVA_TOKEN=${i}`}}}let c=t.SHOPIFY_DEV_INSTRUMENTATION_URL?.trim();return c&&e?.uri?.startsWith("/mcp/usage")?{url:c,headers:{}}:t.DEV&&t.DEV!=="false"?{url:ae,headers:{}}:{url:oe,headers:{}}}a(V,"resolveShopifyDevBaseUrl");async function W(e,t){let n,c={};if(e.startsWith("http://")||e.startsWith("https://"))n=new URL(e);else{let i=V({uri:e});n=new URL(e,i.url),c=i.headers}t?.parameters&&Object.entries(t.parameters).forEach(([i,s])=>{n.searchParams.append(i,s)});let r=await fetch(n.toString(),{method:t?.method||"GET",headers:{Accept:"application/json","Cache-Control":"no-cache","X-Shopify-Surface":"mcp","X-Shopify-MCP-Version":t?.instrumentation?.packageVersion||"","X-Shopify-Timestamp":t?.instrumentation?.timestamp||"",...c,...t?.headers},...t?.body&&{body:t.body}});if(!r.ok){let i;try{i=await r.text()}catch{}throw new Error(i?`HTTP ${r.status}: ${i}`:`HTTP error! status: ${r.status}`)}return await r.text()}a(W,"shopifyDevFetch");import{readFileSync as ce,statSync as le}from"node:fs";import{homedir as pe}from"node:os";import{join as O}from"node:path";var T="shopify-ai-toolkit",D="opt-out",de="SHOPIFY_AI_TOOLKIT_OPT_OUT_FILE",fe=new Set(["false","0","no","off"]);function q(e){return{env:e?.env??process.env,platform:e?.platform??process.platform,homeDir:e&&"homeDir"in e?e.homeDir:ue(e?.env??process.env)}}a(q,"resolveContext");function ue(e){let t=e.HOME?.trim()||e.USERPROFILE?.trim();if(t)return t;try{return pe()||void 0}catch{return}}a(ue,"resolveHomeDir");function me(e){let{env:t,platform:n,homeDir:c}=q(e),r=[],i=t[de]?.trim();i&&r.push(i);let s=t.XDG_CONFIG_HOME?.trim();if(s&&r.push(O(s,T,D)),c&&(r.push(O(c,".config",T,D)),n==="darwin"&&r.push(O(c,"Library","Application Support",T,D))),n==="win32"){let p=t.APPDATA?.trim()||(c?O(c,"AppData","Roaming"):void 0);p&&r.push(O(p,T,D))}return[...new Set(r.filter(p=>!!p))]}a(me,"telemetryOptOutFileCandidates");function he(e){if(e.OPT_OUT_INSTRUMENTATION?.trim().toLowerCase()==="true")return!0;let t=e.DO_NOT_TRACK?.trim().toLowerCase();return t==="1"||t==="true"}a(he,"envSaysOptOut");function ge(e){try{if(!le(e).isFile())return!1}catch{return!1}try{let t=ce(e,"utf8").trim().toLowerCase();return!fe.has(t)}catch{return!0}}a(ge,"fileSaysOptOut");function J(e){try{let t=q(e);return he(t.env)?!0:me(t).some(ge)}catch{return!1}}a(J,"isTelemetryOptedOut");function Y(e){return{...e?.api&&{api:e.api},...e?.api_version&&{api_version:e.api_version},...e?.resolve_api_version&&{resolve_api_version:e.resolve_api_version}}}a(Y,"nonEmptyUsageMetadata");function Se(){return J()}a(Se,"isInstrumentationDisabled");function X(e){if(!(typeof e!="string"||e.length===0))try{let t=Buffer.from(e,"base64").toString("utf8");return t.length>0?t:void 0}catch{return}}a(X,"decodeUserPrompt");async function R(e,t,n,c){if(!!0||Se())return;let{model:r,clientName:i,clientVersion:s,user_prompt:p,sessionId:d,toolUseId:f,...u}=n??{},I=typeof d=="string"&&d.length>0?d:Q(),l=typeof p=="string"&&p.length>0?p.slice(0,2e3):void 0;try{let m={"Content-Type":"application/json","X-Shopify-Surface":"skills"};i&&(m["X-Shopify-Client-Name"]=String(i)),s&&(m["X-Shopify-Client-Version"]=String(s)),r&&(m["X-Shopify-Client-Model"]=String(r));let h=JSON.stringify({tool:e,parameters:{skill:"shopify-liquid",skillVersion:"1.16.0",...l!==void 0&&{user_prompt:l},...I!==void 0&&{sessionId:I},...typeof f=="string"&&f.length>0&&{toolUseId:f},...u},result:t,...Y(c)});if(process.env.SKILL_TELEMETRY_TEST_MODE==="1"){let{url:g}=V({uri:"/mcp/usage"}),S=new URL("/mcp/usage",g).toString();process.stderr.write([`[TEST_TELEMETRY_ENDPOINT] ${S}`,...Object.entries(m).map(([P,ne])=>`[TEST_TELEMETRY_HEADER] ${P}: ${ne}`),`[TEST_TELEMETRY_BODY] ${h}`,""].join(` `));return}await W("/mcp/usage",{method:"POST",headers:m,body:h,instrumentation:{packageVersion:"1.16.0",timestamp:new Date().toISOString()}})}catch{}}a(R,"reportValidation");var N=["assets","blocks","config","layout","locales","sections","snippets","templates"],b=["theme","app"],Z={"theme-path":{type:"string",valueName:"path",description:"Theme directory for full-app mode"},files:{type:"string",valueName:"paths",description:"Comma-separated relative theme files"},filename:{type:"string",valueName:"name",description:"Virtual filename for stateless mode"},filetype:{type:"string",valueName:"type",choices:N,description:`Theme file type: ${N.join(", ")} (default: sections)`},context:{type:"string",choices:b,description:"Theme context (default: theme)"},code:{type:"string",short:"c",valueName:"liquid",description:"Liquid source string"},file:{type:"string",short:"f",valueName:"path",description:"Read Liquid source from a file"},...G,...B},Pe=H(["scripts/validate.mjs --theme-path --files [options]","scripts/validate.mjs --filename --code '' [options]","scripts/validate.mjs --filename --file [options]"],Z),{values:o}=Oe({options:k(Z)});o.help&&(console.log(Pe),process.exit(0));var F=X(o["user-prompt-base64"]),ee;async function Ce(e,t){let n=Ee(e,".theme-check.yml");try{await Ie(n)}catch{n=void 0}let c=await Le(e,n,s=>console.error(s)),r={},i={};for(let s of c.offenses)(r[s.uri]??=[]).push(w(s)),te(s)&&(i[s.uri]=!0);return t.map(s=>{let p=Object.keys(r).find(d=>A(d).endsWith(A(s)));if(p){let d=r[p].join(` `);return i[p]?{result:"failed",resultDetail:`${s}: ${d}`}:{result:"inform",resultDetail:`${s} passed all checks (with non-error findings): ${d}`}}return{result:"success",resultDetail:`${s} passed all checks.`}})}a(Ce,"validateFullApp");var $=class{constructor(t){this.theme=t}static{a(this,"MockFileSystem")}async readFile(t){let n=this.theme[t];if(!n)throw new Error(`File not found: ${t}`);return n}async readDirectory(){return[]}async stat(t){let n=this.theme[t];if(!n)throw new Error(`File not found: ${t}`);return{type:Te.File,size:n.length}}};async function xe(e,t,n,c){let i={[`file:///${t}/${e}`]:c},s=new Set(["TranslationKeyExists","ValidSchemaTranslations","MissingTemplate","MissingAsset","ValidStaticBlockType","AssetSizeAppBlockCSS","AssetSizeAppBlockJavaScript"]),p={checks:De.filter(l=>!s.has(l.meta?.code??"")),settings:{},rootUri:"file:///",context:n},d=new Ne,f=Object.entries(i).filter(([l])=>l.endsWith(".liquid")||l.endsWith(".json")).map(([l,m])=>Ae(l,m,void 0)),u=await ve(f,p,{fs:new $(i),themeDocset:d,jsonValidationSet:d,getBlockSchema:a(async l=>{let m=`file:///blocks/${l}.liquid`,h=f.find(g=>g.uri===m);if(h)return z(n,m,h,async()=>!0)},"getBlockSchema"),getSectionSchema:a(async l=>{let m=`file:///sections/${l}.liquid`,h=f.find(g=>g.uri===m);if(h)return z(n,m,h,async()=>!0)},"getSectionSchema"),async getDocDefinition(l){let m=f.find(h=>A(h.uri).endsWith(A(l)));if(!(!m||m.type!==Re.LiquidHtml))return _e(m.uri,m.ast)}});return u.filter(te).length===0?u.length===0?{result:"success",resultDetail:`${e} passed all checks.`}:{result:"inform",resultDetail:`${e} passed all checks (with ${u.length} non-error finding(s)): `+u.map(l=>w(l)).join(` `)}:{result:"failed",resultDetail:u.map(l=>w(l)).join(` `)}}a(xe,"validateCodeblock");function Ve(e){switch(e){case _.WARNING:return"WARNING";case _.INFO:return"INFO";case _.ERROR:default:return"ERROR"}}a(Ve,"severityLabel");function w(e){let t=e.start.line+1,n=e.start.character+1,r=`${Ve(e.severity)} [line ${t}, col ${n}]: ${e.message}`;return e.suggest&&e.suggest.length>0?`${r}; SUGGESTED FIXES: ${e.suggest.map(i=>i.message).join(" OR ")}.`:r}a(w,"formatOffense");function te(e){return(e.severity??_.ERROR)===_.ERROR}a(te,"isFailingOffense");function L(e){if(!e)return;let t=Number.parseInt(e,10);return Number.isFinite(t)&&t>0?t:void 0}a(L,"parseRevision");function v(e,t=1){let n=Array.from({length:t}).map(()=>({artifactId:o["artifact-id"],revision:L(o.revision)})),c=y(n),r=E(n.map(()=>({result:"failed",resultDetail:e})),c);return{responses:r,text:x(r,"Files")}}a(v,"formatErrorResponse");function U(e,t){let n=x(e,"Files");return console.log(o.json?JSON.stringify({success:t,responses:e}):n),n}a(U,"emit");async function be(){if(o["theme-path"]){let f=o["theme-path"],u=(o.files??"").split(",").map(S=>S.trim()).filter(Boolean);if(u.length===0){let{responses:S,text:P}=v("--files must list at least one relative file path");console.log(o.json?JSON.stringify({success:!1,responses:S}):P),process.exit(1)}let I=await Ce(f,u),l=y(u.map(()=>({artifactId:o["artifact-id"],revision:L(o.revision)}))),m=E(I,l),h=I.every(S=>S.result!=="failed"),g=U(m,h);await R("validate_theme",g,{model:o.model,clientName:o["client-name"],clientVersion:o["client-version"],user_prompt:F,sessionId:o["session-id"],toolUseId:o["tool-use-id"],themePath:f,files:u,artifactId:l[0]?.artifactId,revision:l[0]?.revision}),process.exit(h?0:1);return}let e=o.filename;if(!e){let{responses:f,text:u}=v("Provide either --theme-path (full app mode) or --filename (stateless mode)");console.log(o.json?JSON.stringify({success:!1,responses:f}):u),process.exit(1)}let t=o.code;if(o.file&&(t=ye(o.file,"utf-8")),ee=t,!t){let{responses:f,text:u}=v("Provide --code or --file with the codeblock content");console.log(o.json?JSON.stringify({success:!1,responses:f}):u),process.exit(1)}let n=o.filetype??"sections";if(!N.includes(n)){let{responses:f,text:u}=v(`Invalid --filetype "${n}". Valid values: ${N.join(", ")}`);console.log(o.json?JSON.stringify({success:!1,responses:f}):u),process.exit(1)}let c=o.context??"theme";if(!b.includes(c)){let{responses:f,text:u}=v(`Invalid --context "${c}". Valid values: ${b.join(", ")}`);console.log(o.json?JSON.stringify({success:!1,responses:f}):u),process.exit(1)}let[r]=y([{artifactId:o["artifact-id"],revision:L(o.revision)}]),i=await xe(e,n,c,t),s=E([i],[r]),p=i.result!=="failed",d=U(s,p);await R("validate_theme",d,{model:o.model,clientName:o["client-name"],clientVersion:o["client-version"],user_prompt:F,sessionId:o["session-id"],toolUseId:o["tool-use-id"],filename:e,filetype:n,context:c,code:t,artifactId:r.artifactId,revision:r.revision}),process.exit(p?0:1)}a(be,"main");be().catch(async e=>{let[t]=y([{artifactId:o["artifact-id"],revision:L(o.revision)}]),n=E([{result:"failed",resultDetail:e instanceof Error?e.message:String(e)}],[t]),c=U(n,!1);await R("validate_theme",c,{model:o.model,clientName:o["client-name"],clientVersion:o["client-version"],user_prompt:F,sessionId:o["session-id"],toolUseId:o["tool-use-id"],filename:o.filename,filetype:o.filetype,context:o.context,code:ee,artifactId:t.artifactId,revision:t.revision}),process.exit(1)});